diff --git a/modules/repository/fork.go b/modules/repository/fork.go index 4acdfea6774..7236bd3ef70 100644 --- a/modules/repository/fork.go +++ b/modules/repository/fork.go @@ -35,7 +35,7 @@ func CanUserForkRepo(ctx context.Context, user *user_model.User, repo *repo_mode return false, err } for _, org := range ownedOrgs { - if repo.OwnerID != org.ID && !repo_model.HasForkedRepo(ctx, org.ID, repo.ID) { + if CanUserForkBetweenOwners(repo.OwnerID, org.ID) && !repo_model.HasForkedRepo(ctx, org.ID, repo.ID) { return true, nil } } diff --git a/modules/repository/fork_test.go b/modules/repository/fork_test.go index f9d5cf6f9a6..59b68d69d27 100644 --- a/modules/repository/fork_test.go +++ b/modules/repository/fork_test.go @@ -6,6 +6,10 @@ package repository import ( "testing" + "gitea.dev/models/db" + repo_model "gitea.dev/models/repo" + "gitea.dev/models/unittest" + user_model "gitea.dev/models/user" "gitea.dev/modules/setting" "gitea.dev/modules/test" @@ -13,7 +17,7 @@ import ( ) func TestCanUserForkBetweenOwners(t *testing.T) { - defer test.MockVariableValue(&setting.Repository.AllowForkIntoSameOwner) + defer test.MockVariableValue(&setting.Repository.AllowForkIntoSameOwner)() setting.Repository.AllowForkIntoSameOwner = true assert.True(t, CanUserForkBetweenOwners(1, 1)) @@ -23,3 +27,26 @@ func TestCanUserForkBetweenOwners(t *testing.T) { assert.False(t, CanUserForkBetweenOwners(1, 1)) assert.True(t, CanUserForkBetweenOwners(1, 2)) } + +func TestCanUserForkRepoIntoOwningOrg(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + defer test.MockVariableValue(&setting.Repository.AllowForkIntoSameOwner)() + + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) + // user2's own fork leaves org3, the owner, as the only target + assert.NoError(t, db.Insert(t.Context(), &repo_model.Repository{ + OwnerID: 2, Name: "repo3-fork", LowerName: "repo3-fork", + IsFork: true, ForkID: 3, + })) + + setting.Repository.AllowForkIntoSameOwner = true + ok, err := CanUserForkRepo(t.Context(), user2, repo3) + assert.NoError(t, err) + assert.True(t, ok) + + setting.Repository.AllowForkIntoSameOwner = false + ok, err = CanUserForkRepo(t.Context(), user2, repo3) + assert.NoError(t, err) + assert.False(t, ok) +} diff --git a/routers/web/repo/fork.go b/routers/web/repo/fork.go index 6e60a9a3d2e..d2b8559722a 100644 --- a/routers/web/repo/fork.go +++ b/routers/web/repo/fork.go @@ -7,6 +7,7 @@ import ( "errors" "net/http" "net/url" + "slices" "gitea.dev/models/db" git_model "gitea.dev/models/git" @@ -60,7 +61,7 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository { } var orgs []*organization.Organization for _, org := range ownedOrgs { - if forkRepo.OwnerID != org.ID && !repo_model.HasForkedRepo(ctx, org.ID, forkRepo.ID) { + if repository.CanUserForkBetweenOwners(forkRepo.OwnerID, org.ID) && !repo_model.HasForkedRepo(ctx, org.ID, forkRepo.ID) { orgs = append(orgs, org) } } @@ -69,14 +70,10 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository { for { if !repository.CanUserForkBetweenOwners(ctx.Doer.ID, traverseParentRepo.OwnerID) { canForkToUser = false - } else { - for i, org := range orgs { - if org.ID == traverseParentRepo.OwnerID { - orgs = append(orgs[:i], orgs[i+1:]...) - break - } - } } + orgs = slices.DeleteFunc(orgs, func(org *organization.Organization) bool { + return !repository.CanUserForkBetweenOwners(org.ID, traverseParentRepo.OwnerID) + }) if !traverseParentRepo.IsFork { break diff --git a/tests/integration/repo_fork_test.go b/tests/integration/repo_fork_test.go index 5c34b83aa1a..134155ba8dd 100644 --- a/tests/integration/repo_fork_test.go +++ b/tests/integration/repo_fork_test.go @@ -13,6 +13,7 @@ import ( org_model "gitea.dev/models/organization" "gitea.dev/models/unittest" user_model "gitea.dev/models/user" + "gitea.dev/modules/setting" "gitea.dev/modules/structs" "gitea.dev/modules/test" org_service "gitea.dev/services/org" @@ -80,6 +81,13 @@ func TestRepoForkToOrg(t *testing.T) { assert.False(t, exists, "Forking should not be allowed anymore") } +func TestRepoForkIntoSameOrg(t *testing.T) { + defer tests.PrepareTestEnv(t)() + defer test.MockVariableValue(&setting.Repository.AllowForkIntoSameOwner, true)() + session := loginUser(t, "user2") + testRepoFork(t, session, "org3", "repo3", "org3", "repo3-fork", "") +} + func TestForkListLimitedAndPrivateRepos(t *testing.T) { defer tests.PrepareTestEnv(t)() forkItemSelector := ".fork-list .item"