Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to prohibit fork if user reached maximum limit of repositories #21848

Merged
merged 14 commits into from Dec 27, 2022
Merged
3 changes: 3 additions & 0 deletions custom/conf/app.example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,9 @@ ROUTER = console
;; Don't allow download source archive files from UI
;DISABLE_DOWNLOAD_SOURCE_ARCHIVES = false

;; Allow fork repositories without maximum number limit
;ALLOW_FORK_WITHOUT_MAXIMUM_LIMIT = false
This conversation was marked as resolved.
Show resolved Hide resolved

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[repository.editor]
Expand Down
1 change: 1 addition & 0 deletions docs/content/doc/advanced/config-cheat-sheet.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ In addition there is _`StaticRootPath`_ which can be set as a built-in at build
- `ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES`: **false**: Allow non-admin users to adopt unadopted repositories
- `ALLOW_DELETION_OF_UNADOPTED_REPOSITORIES`: **false**: Allow non-admin users to delete unadopted repositories
- `DISABLE_DOWNLOAD_SOURCE_ARCHIVES`: **false**: Don't allow download source archive files from UI
- `ALLOW_FORK_WITHOUT_MAXIMUM_LIMIT`: **false**: Allow fork repositories without maximum number limit
This conversation was marked as resolved.
Show resolved Hide resolved

### Repository - Editor (`repository.editor`)

Expand Down
9 changes: 9 additions & 0 deletions models/user/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,15 @@ func (u *User) CanEditGitHook() bool {
return !setting.DisableGitHooks && (u.IsAdmin || u.AllowGitHook)
}

// CanForkRepo returns if user login can fork a repository
This conversation was marked as resolved.
Show resolved Hide resolved
// It checks especially that the user can create repos, and potentially more
func (u *User) CanForkRepo() bool {
if setting.Repository.AllowForkWithoutMaximumLimit {
return true
}
return u.CanCreateRepo()
}

// CanImportLocal returns true if user can migrate repository by local path.
func (u *User) CanImportLocal() bool {
if !setting.ImportLocalPaths || u == nil {
Expand Down
2 changes: 2 additions & 0 deletions modules/setting/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ var (
AllowAdoptionOfUnadoptedRepositories bool
AllowDeleteOfUnadoptedRepositories bool
DisableDownloadSourceArchives bool
AllowForkWithoutMaximumLimit bool

// Repository editor settings
Editor struct {
Expand Down Expand Up @@ -160,6 +161,7 @@ var (
DisableMigrations: false,
DisableStars: false,
DefaultBranch: "main",
AllowForkWithoutMaximumLimit: false,
This conversation was marked as resolved.
Show resolved Hide resolved

// Repository editor settings
Editor: struct {
Expand Down
2 changes: 1 addition & 1 deletion routers/api/v1/repo/fork.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func CreateFork(ctx *context.APIContext) {
Description: repo.Description,
})
if err != nil {
if repo_model.IsErrRepoAlreadyExist(err) {
if repo_model.IsErrReachLimitOfRepo(err) || repo_model.IsErrRepoAlreadyExist(err) {
ctx.Error(http.StatusConflict, "ForkRepository", err)
} else {
ctx.Error(http.StatusInternalServerError, "ForkRepository", err)
Expand Down
13 changes: 13 additions & 0 deletions routers/web/repo/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,15 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
func Fork(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("new_fork")

if ctx.Doer.CanForkRepo() {
ctx.Data["CanForkRepo"] = true
} else {
maxCreationLimit := ctx.Doer.MaxCreationLimit()
msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
ctx.Data["Flash"] = ctx.Flash
ctx.Flash.Error(msg)
}

getForkRepository(ctx)
if ctx.Written() {
return
Expand Down Expand Up @@ -254,6 +263,10 @@ func ForkPost(ctx *context.Context) {
if err != nil {
ctx.Data["Err_RepoName"] = true
switch {
case repo_model.IsErrReachLimitOfRepo(err):
maxCreationLimit := ctxUser.MaxCreationLimit()
msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
ctx.RenderWithErr(msg, tplFork, &form)
case repo_model.IsErrRepoAlreadyExist(err):
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form)
case db.IsErrNameReserved(err):
Expand Down
7 changes: 7 additions & 0 deletions services/repository/fork.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ type ForkRepoOptions struct {

// ForkRepository forks a repository
func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts ForkRepoOptions) (*repo_model.Repository, error) {
// Fork is prohibited, if user has reached maximum limit of repositories
if !owner.CanForkRepo() {
return nil, repo_model.ErrReachLimitOfRepo{
Limit: owner.MaxRepoCreation,
}
}

forkedRepo, err := repo_model.GetUserFork(ctx, opts.BaseRepo.ID, owner.ID)
if err != nil {
return nil, err
Expand Down
12 changes: 12 additions & 0 deletions services/repository/fork_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,16 @@ func TestForkRepository(t *testing.T) {
assert.Nil(t, fork)
assert.Error(t, err)
assert.True(t, IsErrForkAlreadyExist(err))

This conversation was marked as resolved.
Show resolved Hide resolved
// user not reached maximum limit of repositories
assert.False(t, repo_model.IsErrReachLimitOfRepo(err))
// user has reached maximum limit of repositories
This conversation was marked as resolved.
Show resolved Hide resolved
user.MaxRepoCreation = 0
fork2, err := ForkRepository(git.DefaultContext, user, user, ForkRepoOptions{
BaseRepo: repo,
Name: "test",
Description: "test",
})
assert.Nil(t, fork2)
assert.True(t, repo_model.IsErrReachLimitOfRepo(err))
}
2 changes: 1 addition & 1 deletion templates/repo/pulls/fork.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@

<div class="inline field">
<label></label>
<button class="ui green button">
<button class="ui green button{{if not .CanForkRepo}} disabled{{end}}">
{{.locale.Tr "repo.fork_repo"}}
</button>
</div>
Expand Down