1
1
mirror of https://github.com/go-gitea/gitea synced 2025-07-03 09:07:19 +00:00

Move AddCollabrator and CreateRepositoryByExample to service layer (#32419)

- [x] Move `CreateRepositoryByExample` to service layer
- [x] Move `AddCollabrator` to service layer
- [x] Add a new parameter for `AddCollabrator` so that changing mode
immediately after that will become unnecessary.
This commit is contained in:
Lunny Xiao
2024-11-06 19:28:11 -08:00
committed by GitHub
parent 913be9e8ac
commit 276500c314
19 changed files with 232 additions and 500 deletions

View File

@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
_ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions"
"github.com/stretchr/testify/assert"

View File

@ -8,6 +8,7 @@ import (
"code.gitea.io/gitea/models/unittest"
_ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions"
)

View File

@ -8,6 +8,7 @@ import (
"code.gitea.io/gitea/models/unittest"
_ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions"
)

View File

@ -66,7 +66,7 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR
}
}
if err := repo_module.CreateRepositoryByExample(ctx, doer, u, repo, true, false); err != nil {
if err := CreateRepositoryByExample(ctx, doer, u, repo, true, false); err != nil {
return err
}

View File

@ -9,11 +9,60 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"xorm.io/builder"
)
func AddOrUpdateCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_model.User, mode perm.AccessMode) error {
// only allow valid access modes, read, write and admin
if mode < perm.AccessModeRead || mode > perm.AccessModeAdmin {
return perm.ErrInvalidAccessMode
}
if err := repo.LoadOwner(ctx); err != nil {
return err
}
if user_model.IsUserBlockedBy(ctx, u, repo.OwnerID) || user_model.IsUserBlockedBy(ctx, repo.Owner, u.ID) {
return user_model.ErrBlockedUser
}
return db.WithTx(ctx, func(ctx context.Context) error {
collaboration, has, err := db.Get[repo_model.Collaboration](ctx, builder.Eq{
"repo_id": repo.ID,
"user_id": u.ID,
})
if err != nil {
return err
} else if has {
if collaboration.Mode == mode {
return nil
}
if _, err = db.GetEngine(ctx).
Where("repo_id=?", repo.ID).
And("user_id=?", u.ID).
Cols("mode").
Update(&repo_model.Collaboration{
Mode: mode,
}); err != nil {
return err
}
} else if err = db.Insert(ctx, &repo_model.Collaboration{
RepoID: repo.ID,
UserID: u.ID,
Mode: mode,
}); err != nil {
return err
}
return access_model.RecalculateUserAccess(ctx, repo, u.ID)
})
}
// DeleteCollaboration removes collaboration relation between the user and repository.
func DeleteCollaboration(ctx context.Context, repo *repo_model.Repository, collaborator *user_model.User) (err error) {
collaboration := &repo_model.Collaboration{

View File

@ -7,6 +7,7 @@ import (
"testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
@ -14,6 +15,21 @@ import (
"github.com/stretchr/testify/assert"
)
func TestRepository_AddCollaborator(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
testSuccess := func(repoID, userID int64) {
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
assert.NoError(t, repo.LoadOwner(db.DefaultContext))
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID})
assert.NoError(t, AddOrUpdateCollaborator(db.DefaultContext, repo, user, perm.AccessModeWrite))
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}, &user_model.User{ID: userID})
}
testSuccess(1, 4)
testSuccess(1, 4)
testSuccess(3, 4)
}
func TestRepository_DeleteCollaboration(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())

View File

@ -12,9 +12,15 @@ import (
"strings"
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/log"
@ -243,7 +249,7 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
var rollbackRepo *repo_model.Repository
if err := db.WithTx(ctx, func(ctx context.Context) error {
if err := repo_module.CreateRepositoryByExample(ctx, doer, u, repo, false, false); err != nil {
if err := CreateRepositoryByExample(ctx, doer, u, repo, false, false); err != nil {
return err
}
@ -335,3 +341,136 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
return repo, nil
}
// CreateRepositoryByExample creates a repository for the user/organization.
func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository, overwriteOrAdopt, isFork bool) (err error) {
if err = repo_model.IsUsableRepoName(repo.Name); err != nil {
return err
}
has, err := repo_model.IsRepositoryModelExist(ctx, u, repo.Name)
if err != nil {
return fmt.Errorf("IsRepositoryExist: %w", err)
} else if has {
return repo_model.ErrRepoAlreadyExist{
Uname: u.Name,
Name: repo.Name,
}
}
repoPath := repo_model.RepoPath(u.Name, repo.Name)
isExist, err := util.IsExist(repoPath)
if err != nil {
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
return err
}
if !overwriteOrAdopt && isExist {
log.Error("Files already exist in %s and we are not going to adopt or delete.", repoPath)
return repo_model.ErrRepoFilesAlreadyExist{
Uname: u.Name,
Name: repo.Name,
}
}
if err = db.Insert(ctx, repo); err != nil {
return err
}
if err = repo_model.DeleteRedirect(ctx, u.ID, repo.Name); err != nil {
return err
}
// insert units for repo
defaultUnits := unit.DefaultRepoUnits
if isFork {
defaultUnits = unit.DefaultForkRepoUnits
}
units := make([]repo_model.RepoUnit, 0, len(defaultUnits))
for _, tp := range defaultUnits {
if tp == unit.TypeIssues {
units = append(units, repo_model.RepoUnit{
RepoID: repo.ID,
Type: tp,
Config: &repo_model.IssuesConfig{
EnableTimetracker: setting.Service.DefaultEnableTimetracking,
AllowOnlyContributorsToTrackTime: setting.Service.DefaultAllowOnlyContributorsToTrackTime,
EnableDependencies: setting.Service.DefaultEnableDependencies,
},
})
} else if tp == unit.TypePullRequests {
units = append(units, repo_model.RepoUnit{
RepoID: repo.ID,
Type: tp,
Config: &repo_model.PullRequestsConfig{
AllowMerge: true, AllowRebase: true, AllowRebaseMerge: true, AllowSquash: true, AllowFastForwardOnly: true,
DefaultMergeStyle: repo_model.MergeStyle(setting.Repository.PullRequest.DefaultMergeStyle),
AllowRebaseUpdate: true,
},
})
} else if tp == unit.TypeProjects {
units = append(units, repo_model.RepoUnit{
RepoID: repo.ID,
Type: tp,
Config: &repo_model.ProjectsConfig{ProjectsMode: repo_model.ProjectsModeAll},
})
} else {
units = append(units, repo_model.RepoUnit{
RepoID: repo.ID,
Type: tp,
})
}
}
if err = db.Insert(ctx, units); err != nil {
return err
}
// Remember visibility preference.
u.LastRepoVisibility = repo.IsPrivate
if err = user_model.UpdateUserCols(ctx, u, "last_repo_visibility"); err != nil {
return fmt.Errorf("UpdateUserCols: %w", err)
}
if err = user_model.IncrUserRepoNum(ctx, u.ID); err != nil {
return fmt.Errorf("IncrUserRepoNum: %w", err)
}
u.NumRepos++
// Give access to all members in teams with access to all repositories.
if u.IsOrganization() {
teams, err := organization.FindOrgTeams(ctx, u.ID)
if err != nil {
return fmt.Errorf("FindOrgTeams: %w", err)
}
for _, t := range teams {
if t.IncludesAllRepositories {
if err := models.AddRepository(ctx, t, repo); err != nil {
return fmt.Errorf("AddRepository: %w", err)
}
}
}
if isAdmin, err := access_model.IsUserRepoAdmin(ctx, repo, doer); err != nil {
return fmt.Errorf("IsUserRepoAdmin: %w", err)
} else if !isAdmin {
// Make creator repo admin if it wasn't assigned automatically
if err = AddOrUpdateCollaborator(ctx, repo, doer, perm.AccessModeAdmin); err != nil {
return fmt.Errorf("AddCollaborator: %w", err)
}
}
} else if err = access_model.RecalculateAccesses(ctx, repo); err != nil {
// Organization automatically called this in AddRepository method.
return fmt.Errorf("RecalculateAccesses: %w", err)
}
if setting.Service.AutoWatchNewRepos {
if err = repo_model.WatchRepo(ctx, doer, repo, true); err != nil {
return fmt.Errorf("WatchRepo: %w", err)
}
}
if err = webhook.CopyDefaultWebhooksToRepo(ctx, repo.ID); err != nil {
return fmt.Errorf("CopyDefaultWebhooksToRepo: %w", err)
}
return nil
}

View File

@ -134,7 +134,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
}()
err = db.WithTx(ctx, func(txCtx context.Context) error {
if err = repo_module.CreateRepositoryByExample(txCtx, doer, owner, repo, false, true); err != nil {
if err = CreateRepositoryByExample(txCtx, doer, owner, repo, false, true); err != nil {
return err
}

View File

@ -343,7 +343,7 @@ func generateRepository(ctx context.Context, doer, owner *user_model.User, templ
ObjectFormatName: templateRepo.ObjectFormatName,
}
if err = repo_module.CreateRepositoryByExample(ctx, doer, owner, generateRepo, false, false); err != nil {
if err = CreateRepositoryByExample(ctx, doer, owner, generateRepo, false, false); err != nil {
return nil, err
}

View File

@ -20,7 +20,6 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/globallock"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/util"
notify_service "code.gitea.io/gitea/services/notify"
)
@ -419,10 +418,7 @@ func StartRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.Use
return err
}
if !hasAccess {
if err := repo_module.AddCollaborator(ctx, repo, newOwner); err != nil {
return err
}
if err := repo_model.ChangeCollaborationAccessMode(ctx, repo, newOwner.ID, perm.AccessModeRead); err != nil {
if err := AddOrUpdateCollaborator(ctx, repo, newOwner, perm.AccessModeRead); err != nil {
return err
}
}