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
6 changes: 6 additions & 0 deletions models/user/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,12 @@ 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 {
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: 1 addition & 1 deletion routers/api/v1/repo/fork.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,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
11 changes: 11 additions & 0 deletions routers/web/repo/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
func Fork(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("new_fork")

if !ctx.Doer.CanForkRepo() {
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 @@ -255,6 +262,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 @@ -52,6 +52,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 @@ -30,4 +30,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>
<a class="ui button" href="{{.ForkRepo.Link}}">{{.locale.Tr "cancel"}}</a>
Expand Down