Skip to content

[Proposal] a way to limit org and org repo number #15950

Open
@a1012112796

Description

@a1012112796

Proposal sollution about limit org's repo number.

Add a new identity named as main owner in a org, which is the creater of org, and can be changed but should be only one in a org, The orgs repo will be calculate as main owner's repo to limit repo number. Only when the main owner can create repo can this org create repo. and we can also limit the number of org one user can main owned to limit org create.

main logic:

diff --git a/models/user.go b/models/user.go
index c7b44bdb7..efedcc38b 100644
--- a/models/user.go
+++ b/models/user.go
@@ -161,6 +161,8 @@ type User struct {
 	MembersIsPublic           map[int64]bool      `xorm:"-"`
 	Visibility                structs.VisibleType `xorm:"NOT NULL DEFAULT 0"`
 	RepoAdminChangeTeamAccess bool                `xorm:"NOT NULL DEFAULT false"`
+	MainOwnerID               int64               `xorm:"INDEX"`
+	MainOwner                 *User               `xorm:"-"`
 
 	// Preferences
 	DiffViewStyle       string `xorm:"NOT NULL DEFAULT ''"`
@@ -264,19 +266,51 @@ func (u *User) MaxCreationLimit() int {
 	return u.MaxRepoCreation
 }
 
+// LoadMainOwner load main owner of a org
+func (u *User) LoadMainOwner() (err error) {
+	if !u.IsOrganization() || u.MainOwner != nil {
+		return nil
+	}
+
+	u.MainOwner, err = GetUserByID(u.MainOwnerID)
+	return err
+}
+
 // CanCreateRepo returns if user login can create a repository
 // NOTE: functions calling this assume a failure due to repository count limit; if new checks are added, those functions should be revised
 func (u *User) CanCreateRepo() bool {
 	if u.IsAdmin {
 		return true
 	}
+
+	total := 0
+	var err error
+	if u.IsOrganization() {
+		err = u.LoadMainOwner()
+		if err != nil {
+			log.Error("LoadMainOwner(): %v", err)
+			return false
+		}
+		if !u.MainOwner.CanCreateRepo() {
+			return false
+		}
+	} else {
+		total, err = u.TotalRepoNumInMainOwnedOrgs()
+		if err != nil {
+			log.Error("TotalRepoNumInMainOwnedOrgs(): %v", err)
+			return false
+		}
+	}
+
+	total += u.NumRepos
+
 	if u.MaxRepoCreation <= -1 {
 		if setting.Repository.MaxCreationLimit <= -1 {
 			return true
 		}
-		return u.NumRepos < setting.Repository.MaxCreationLimit
+		return total < setting.Repository.MaxCreationLimit
 	}
-	return u.NumRepos < u.MaxRepoCreation
+	return total < u.MaxRepoCreation
 }
 
 // CanCreateOrganization returns true if user can create organisation.
@@ -2035,3 +2069,10 @@ func IterateUser(f func(user *User) error) error {
 		}
 	}
 }
+
+// TotalRepoNumInMainOwnedOrgs calculate all repo number in org that
+// user main owned
+func (u *User) TotalRepoNumInMainOwnedOrgs() (int, error) {
+	total, err := x.Where("main_owner_id").SumInt(new(User), "num_repos")
+	return int(total), err
+}

Originally posted by @a1012112796 in #15924 (comment)

  • test issue todo list item

Metadata

Metadata

Assignees

No one assigned

    Labels

    type/proposalThe new feature has not been accepted yet but needs to be discussed first.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions