}
return util.Iif(slices.Contains(allowed, m), m, AccessModeNone)
}
+
+// ErrInvalidAccessMode is returned when an invalid access mode is used
+var ErrInvalidAccessMode = util.NewInvalidArgumentErrorf("Invalid access mode")
+++ /dev/null
-// Copyright 2022 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package repository
-
-import (
- "context"
-
- "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 AddCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_model.User) error {
- 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 {
- has, err := db.Exist[repo_model.Collaboration](ctx, builder.Eq{
- "repo_id": repo.ID,
- "user_id": u.ID,
- })
- if err != nil {
- return err
- } else if has {
- return nil
- }
-
- if err = db.Insert(ctx, &repo_model.Collaboration{
- RepoID: repo.ID,
- UserID: u.ID,
- Mode: perm.AccessModeWrite,
- }); err != nil {
- return err
- }
-
- return access_model.RecalculateUserAccess(ctx, repo, u.ID)
- })
-}
+++ /dev/null
-// Copyright 2019 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package repository
-
-import (
- "testing"
-
- "code.gitea.io/gitea/models/db"
- "code.gitea.io/gitea/models/organization"
- perm_model "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"
- "code.gitea.io/gitea/models/unittest"
- user_model "code.gitea.io/gitea/models/user"
-
- "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, AddCollaborator(db.DefaultContext, repo, user))
- unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}, &user_model.User{ID: userID})
- }
- testSuccess(1, 4)
- testSuccess(1, 4)
- testSuccess(3, 4)
-}
-
-func TestRepoPermissionPublicNonOrgRepo(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- // public non-organization repo
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
- assert.NoError(t, repo.LoadUnits(db.DefaultContext))
-
- // plain user
- user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
- perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.False(t, perm.CanWrite(unit.Type))
- }
-
- // change to collaborator
- assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user))
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-
- // collaborator
- collaborator := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, collaborator)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-
- // owner
- owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-
- // admin
- admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-}
-
-func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- // private non-organization repo
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
- assert.NoError(t, repo.LoadUnits(db.DefaultContext))
-
- // plain user
- user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
- perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.False(t, perm.CanRead(unit.Type))
- assert.False(t, perm.CanWrite(unit.Type))
- }
-
- // change to collaborator to default write access
- assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user))
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-
- assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead))
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.False(t, perm.CanWrite(unit.Type))
- }
-
- // owner
- owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-
- // admin
- admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-}
-
-func TestRepoPermissionPublicOrgRepo(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- // public organization repo
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 32})
- assert.NoError(t, repo.LoadUnits(db.DefaultContext))
-
- // plain user
- user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
- perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.False(t, perm.CanWrite(unit.Type))
- }
-
- // change to collaborator to default write access
- assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user))
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-
- assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead))
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.False(t, perm.CanWrite(unit.Type))
- }
-
- // org member team owner
- owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-
- // org member team tester
- member := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15})
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, member)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- }
- assert.True(t, perm.CanWrite(unit.TypeIssues))
- assert.False(t, perm.CanWrite(unit.TypeCode))
-
- // admin
- admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-}
-
-func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- // private organization repo
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 24})
- assert.NoError(t, repo.LoadUnits(db.DefaultContext))
-
- // plain user
- user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
- perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.False(t, perm.CanRead(unit.Type))
- assert.False(t, perm.CanWrite(unit.Type))
- }
-
- // change to collaborator to default write access
- assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user))
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-
- assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead))
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.False(t, perm.CanWrite(unit.Type))
- }
-
- // org member team owner
- owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15})
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-
- // update team information and then check permission
- team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5})
- err = organization.UpdateTeamUnits(db.DefaultContext, team, nil)
- assert.NoError(t, err)
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-
- // org member team tester
- tester := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, tester)
- assert.NoError(t, err)
- assert.True(t, perm.CanWrite(unit.TypeIssues))
- assert.False(t, perm.CanWrite(unit.TypeCode))
- assert.False(t, perm.CanRead(unit.TypeCode))
-
- // org member team reviewer
- reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20})
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, reviewer)
- assert.NoError(t, err)
- assert.False(t, perm.CanRead(unit.TypeIssues))
- assert.False(t, perm.CanWrite(unit.TypeCode))
- assert.True(t, perm.CanRead(unit.TypeCode))
-
- // admin
- admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
- perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin)
- assert.NoError(t, err)
- for _, unit := range repo.Units {
- assert.True(t, perm.CanRead(unit.Type))
- assert.True(t, perm.CanWrite(unit.Type))
- }
-}
"path/filepath"
"strings"
- "code.gitea.io/gitea/models"
activities_model "code.gitea.io/gitea/models/activities"
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
- "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"
issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
"code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
)
-// 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 = AddCollaborator(ctx, repo, doer); err != nil {
- return fmt.Errorf("AddCollaborator: %w", err)
- }
- if err = repo_model.ChangeCollaborationAccessMode(ctx, repo, doer.ID, perm.AccessModeAdmin); err != nil {
- return fmt.Errorf("ChangeCollaborationAccessModeCtx: %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
-}
-
const notRegularFileMode = os.ModeSymlink | os.ModeNamedPipe | os.ModeSocket | os.ModeDevice | os.ModeCharDevice | os.ModeIrregular
// getDirectorySize returns the disk consumption for a given path
"code.gitea.io/gitea/models/unittest"
+ _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions"
)
m.Get("", reqAnyRepoReader(), repo.ListCollaborators)
m.Group("/{collaborator}", func() {
m.Combo("").Get(reqAnyRepoReader(), repo.IsCollaborator).
- Put(reqAdmin(), bind(api.AddCollaboratorOption{}), repo.AddCollaborator).
+ Put(reqAdmin(), bind(api.AddCollaboratorOption{}), repo.AddOrUpdateCollaborator).
Delete(reqAdmin(), repo.DeleteCollaborator)
m.Get("/permission", repo.GetRepoPermissions)
})
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"
- repo_module "code.gitea.io/gitea/modules/repository"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
}
}
-// AddCollaborator add a collaborator to a repository
-func AddCollaborator(ctx *context.APIContext) {
+// AddOrUpdateCollaborator add or update a collaborator to a repository
+func AddOrUpdateCollaborator(ctx *context.APIContext) {
// swagger:operation PUT /repos/{owner}/{repo}/collaborators/{collaborator} repository repoAddCollaborator
// ---
- // summary: Add a collaborator to a repository
+ // summary: Add or Update a collaborator to a repository
// produces:
// - application/json
// parameters:
return
}
- if err := repo_module.AddCollaborator(ctx, ctx.Repo.Repository, collaborator); err != nil {
+ p := perm.AccessModeWrite
+ if form.Permission != nil {
+ p = perm.ParseAccessMode(*form.Permission)
+ }
+
+ if err := repo_service.AddOrUpdateCollaborator(ctx, ctx.Repo.Repository, collaborator, p); err != nil {
if errors.Is(err, user_model.ErrBlockedUser) {
- ctx.Error(http.StatusForbidden, "AddCollaborator", err)
+ ctx.Error(http.StatusForbidden, "AddOrUpdateCollaborator", err)
} else {
- ctx.Error(http.StatusInternalServerError, "AddCollaborator", err)
+ ctx.Error(http.StatusInternalServerError, "AddOrUpdateCollaborator", err)
}
return
}
- if form.Permission != nil {
- if err := repo_model.ChangeCollaborationAccessMode(ctx, ctx.Repo.Repository, collaborator.ID, perm.ParseAccessMode(*form.Permission)); err != nil {
- ctx.Error(http.StatusInternalServerError, "ChangeCollaborationAccessMode", err)
- return
- }
- }
-
ctx.Status(http.StatusNoContent)
}
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
- repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/mailer"
}
}
- if err = repo_module.AddCollaborator(ctx, ctx.Repo.Repository, u); err != nil {
+ if err = repo_service.AddOrUpdateCollaborator(ctx, ctx.Repo.Repository, u, perm.AccessModeWrite); err != nil {
if errors.Is(err, user_model.ErrBlockedUser) {
ctx.Flash.Error(ctx.Tr("repo.settings.add_collaborator.blocked_user"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
} else {
- ctx.ServerError("AddCollaborator", err)
+ ctx.ServerError("AddOrUpdateCollaborator", err)
}
return
}
"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"
"code.gitea.io/gitea/models/unittest"
+ _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions"
)
"code.gitea.io/gitea/models/unittest"
+ _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions"
)
}
}
- 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
}
"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{
"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"
"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())
"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"
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
}
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
+}
}()
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
}
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
}
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"
)
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
}
}
"tags": [
"repository"
],
- "summary": "Add a collaborator to a repository",
+ "summary": "Add or Update a collaborator to a repository",
"operationId": "repoAddCollaborator",
"parameters": [
{