mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-23 14:53:34 +01:00
Add option to prohibit fork if user reached maximum limit of repositories (#21848)
If user has reached the maximum limit of repositories: - Before - disallow create - allow fork without limit - This patch: - disallow create - disallow fork - Add option `ALLOW_FORK_WITHOUT_MAXIMUM_LIMIT` (Default **true**) : enable this allow user fork repositories without maximum number limit fixed https://github.com/go-gitea/gitea/issues/21847 Signed-off-by: Xinyu Zhou <i@sourcehut.net>
This commit is contained in:
parent
22a6e97597
commit
7cc7db73b9
9 changed files with 53 additions and 2 deletions
|
@ -957,6 +957,9 @@ ROUTER = console
|
||||||
;; Don't allow download source archive files from UI
|
;; Don't allow download source archive files from UI
|
||||||
;DISABLE_DOWNLOAD_SOURCE_ARCHIVES = false
|
;DISABLE_DOWNLOAD_SOURCE_ARCHIVES = false
|
||||||
|
|
||||||
|
;; Allow fork repositories without maximum number limit
|
||||||
|
;ALLOW_FORK_WITHOUT_MAXIMUM_LIMIT = true
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;[repository.editor]
|
;[repository.editor]
|
||||||
|
|
|
@ -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_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
|
- `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
|
- `DISABLE_DOWNLOAD_SOURCE_ARCHIVES`: **false**: Don't allow download source archive files from UI
|
||||||
|
- `ALLOW_FORK_WITHOUT_MAXIMUM_LIMIT`: **true**: Allow fork repositories without maximum number limit
|
||||||
|
|
||||||
### Repository - Editor (`repository.editor`)
|
### Repository - Editor (`repository.editor`)
|
||||||
|
|
||||||
|
|
|
@ -275,6 +275,15 @@ func (u *User) CanEditGitHook() bool {
|
||||||
return !setting.DisableGitHooks && (u.IsAdmin || u.AllowGitHook)
|
return !setting.DisableGitHooks && (u.IsAdmin || u.AllowGitHook)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CanForkRepo returns if user login can fork a repository
|
||||||
|
// 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.
|
// CanImportLocal returns true if user can migrate repository by local path.
|
||||||
func (u *User) CanImportLocal() bool {
|
func (u *User) CanImportLocal() bool {
|
||||||
if !setting.ImportLocalPaths || u == nil {
|
if !setting.ImportLocalPaths || u == nil {
|
||||||
|
|
|
@ -48,6 +48,7 @@ var (
|
||||||
AllowAdoptionOfUnadoptedRepositories bool
|
AllowAdoptionOfUnadoptedRepositories bool
|
||||||
AllowDeleteOfUnadoptedRepositories bool
|
AllowDeleteOfUnadoptedRepositories bool
|
||||||
DisableDownloadSourceArchives bool
|
DisableDownloadSourceArchives bool
|
||||||
|
AllowForkWithoutMaximumLimit bool
|
||||||
|
|
||||||
// Repository editor settings
|
// Repository editor settings
|
||||||
Editor struct {
|
Editor struct {
|
||||||
|
@ -160,6 +161,7 @@ var (
|
||||||
DisableMigrations: false,
|
DisableMigrations: false,
|
||||||
DisableStars: false,
|
DisableStars: false,
|
||||||
DefaultBranch: "main",
|
DefaultBranch: "main",
|
||||||
|
AllowForkWithoutMaximumLimit: true,
|
||||||
|
|
||||||
// Repository editor settings
|
// Repository editor settings
|
||||||
Editor: struct {
|
Editor: struct {
|
||||||
|
|
|
@ -141,7 +141,7 @@ func CreateFork(ctx *context.APIContext) {
|
||||||
Description: repo.Description,
|
Description: repo.Description,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if repo_model.IsErrRepoAlreadyExist(err) {
|
if repo_model.IsErrReachLimitOfRepo(err) || repo_model.IsErrRepoAlreadyExist(err) {
|
||||||
ctx.Error(http.StatusConflict, "ForkRepository", err)
|
ctx.Error(http.StatusConflict, "ForkRepository", err)
|
||||||
} else {
|
} else {
|
||||||
ctx.Error(http.StatusInternalServerError, "ForkRepository", err)
|
ctx.Error(http.StatusInternalServerError, "ForkRepository", err)
|
||||||
|
|
|
@ -182,6 +182,15 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
|
||||||
func Fork(ctx *context.Context) {
|
func Fork(ctx *context.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("new_fork")
|
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)
|
getForkRepository(ctx)
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
return
|
return
|
||||||
|
@ -254,6 +263,10 @@ func ForkPost(ctx *context.Context) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Data["Err_RepoName"] = true
|
ctx.Data["Err_RepoName"] = true
|
||||||
switch {
|
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):
|
case repo_model.IsErrRepoAlreadyExist(err):
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form)
|
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form)
|
||||||
case db.IsErrNameReserved(err):
|
case db.IsErrNameReserved(err):
|
||||||
|
|
|
@ -51,6 +51,13 @@ type ForkRepoOptions struct {
|
||||||
|
|
||||||
// ForkRepository forks a repository
|
// ForkRepository forks a repository
|
||||||
func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts ForkRepoOptions) (*repo_model.Repository, error) {
|
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)
|
forkedRepo, err := repo_model.GetUserFork(ctx, opts.BaseRepo.ID, owner.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -29,4 +30,19 @@ func TestForkRepository(t *testing.T) {
|
||||||
assert.Nil(t, fork)
|
assert.Nil(t, fork)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrForkAlreadyExist(err))
|
assert.True(t, IsErrForkAlreadyExist(err))
|
||||||
|
|
||||||
|
// user not reached maximum limit of repositories
|
||||||
|
assert.False(t, repo_model.IsErrReachLimitOfRepo(err))
|
||||||
|
|
||||||
|
// change AllowForkWithoutMaximumLimit to false for the test
|
||||||
|
setting.Repository.AllowForkWithoutMaximumLimit = false
|
||||||
|
// user has reached maximum limit of repositories
|
||||||
|
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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
|
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label></label>
|
<label></label>
|
||||||
<button class="ui green button">
|
<button class="ui green button{{if not .CanForkRepo}} disabled{{end}}">
|
||||||
{{.locale.Tr "repo.fork_repo"}}
|
{{.locale.Tr "repo.fork_repo"}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue