diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2022-06-06 16:01:49 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-06 16:01:49 +0800 |
commit | 26095115f4ae90e3fdc6ab695978efd16e317f75 (patch) | |
tree | 92ec1c7ff54e0a65f4f0662baa8c0244dd9f324b /models/repo.go | |
parent | ebeb6e7c71a0c763b52153f4eb427e7c5b89a95e (diff) | |
download | gitea-26095115f4ae90e3fdc6ab695978efd16e317f75.tar.gz gitea-26095115f4ae90e3fdc6ab695978efd16e317f75.zip |
Move some repository related code into sub package (#19711)
* Move some repository related code into sub package
* Move more repository functions out of models
* Fix lint
* Some performance optimization for webhooks and others
* some refactors
* Fix lint
* Fix
* Update modules/repository/delete.go
Co-authored-by: delvh <dev.lh@web.de>
* Fix test
* Merge
* Fix test
* Fix test
* Fix test
* Fix test
Co-authored-by: delvh <dev.lh@web.de>
Diffstat (limited to 'models/repo.go')
-rw-r--r-- | models/repo.go | 403 |
1 files changed, 7 insertions, 396 deletions
diff --git a/models/repo.go b/models/repo.go index 6c3dca41be..fff9cc5271 100644 --- a/models/repo.go +++ b/models/repo.go @@ -8,11 +8,7 @@ package models import ( "context" "fmt" - "os" - "path" "strconv" - "strings" - "unicode/utf8" _ "image/jpeg" // Needed for jpeg support @@ -47,11 +43,7 @@ func NewRepoContext() { } // CheckRepoUnitUser check whether user could visit the unit of this repository -func CheckRepoUnitUser(repo *repo_model.Repository, user *user_model.User, unitType unit.Type) bool { - return checkRepoUnitUser(db.DefaultContext, repo, user, unitType) -} - -func checkRepoUnitUser(ctx context.Context, repo *repo_model.Repository, user *user_model.User, unitType unit.Type) bool { +func CheckRepoUnitUser(ctx context.Context, repo *repo_model.Repository, user *user_model.User, unitType unit.Type) bool { if user != nil && user.IsAdmin { return true } @@ -64,241 +56,6 @@ func checkRepoUnitUser(ctx context.Context, repo *repo_model.Repository, user *u return perm.CanRead(unitType) } -func getRepoAssignees(ctx context.Context, repo *repo_model.Repository) (_ []*user_model.User, err error) { - if err = repo.GetOwner(ctx); err != nil { - return nil, err - } - - e := db.GetEngine(ctx) - userIDs := make([]int64, 0, 10) - if err = e.Table("access"). - Where("repo_id = ? AND mode >= ?", repo.ID, perm.AccessModeWrite). - Select("user_id"). - Find(&userIDs); err != nil { - return nil, err - } - - additionalUserIDs := make([]int64, 0, 10) - if err = e.Table("team_user"). - Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id"). - Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id"). - Where("`team_repo`.repo_id = ? AND `team_unit`.access_mode >= ?", repo.ID, perm.AccessModeWrite). - Distinct("`team_user`.uid"). - Select("`team_user`.uid"). - Find(&additionalUserIDs); err != nil { - return nil, err - } - - uidMap := map[int64]bool{} - i := 0 - for _, uid := range userIDs { - if uidMap[uid] { - continue - } - uidMap[uid] = true - userIDs[i] = uid - i++ - } - userIDs = userIDs[:i] - userIDs = append(userIDs, additionalUserIDs...) - - for _, uid := range additionalUserIDs { - if uidMap[uid] { - continue - } - userIDs[i] = uid - i++ - } - userIDs = userIDs[:i] - - // Leave a seat for owner itself to append later, but if owner is an organization - // and just waste 1 unit is cheaper than re-allocate memory once. - users := make([]*user_model.User, 0, len(userIDs)+1) - if len(userIDs) > 0 { - if err = e.In("id", userIDs).Find(&users); err != nil { - return nil, err - } - } - if !repo.Owner.IsOrganization() && !uidMap[repo.OwnerID] { - users = append(users, repo.Owner) - } - - return users, nil -} - -// GetRepoAssignees returns all users that have write access and can be assigned to issues -// of the repository, -func GetRepoAssignees(repo *repo_model.Repository) (_ []*user_model.User, err error) { - return getRepoAssignees(db.DefaultContext, repo) -} - -func getReviewers(ctx context.Context, repo *repo_model.Repository, doerID, posterID int64) ([]*user_model.User, error) { - // Get the owner of the repository - this often already pre-cached and if so saves complexity for the following queries - if err := repo.GetOwner(ctx); err != nil { - return nil, err - } - - cond := builder.And(builder.Neq{"`user`.id": posterID}) - - if repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate { - // This a private repository: - // Anyone who can read the repository is a requestable reviewer - - cond = cond.And(builder.In("`user`.id", - builder.Select("user_id").From("access").Where( - builder.Eq{"repo_id": repo.ID}. - And(builder.Gte{"mode": perm.AccessModeRead}), - ), - )) - - if repo.Owner.Type == user_model.UserTypeIndividual && repo.Owner.ID != posterID { - // as private *user* repos don't generate an entry in the `access` table, - // the owner of a private repo needs to be explicitly added. - cond = cond.Or(builder.Eq{"`user`.id": repo.Owner.ID}) - } - - } else { - // This is a "public" repository: - // Any user that has read access, is a watcher or organization member can be requested to review - cond = cond.And(builder.And(builder.In("`user`.id", - builder.Select("user_id").From("access"). - Where(builder.Eq{"repo_id": repo.ID}. - And(builder.Gte{"mode": perm.AccessModeRead})), - ).Or(builder.In("`user`.id", - builder.Select("user_id").From("watch"). - Where(builder.Eq{"repo_id": repo.ID}. - And(builder.In("mode", repo_model.WatchModeNormal, repo_model.WatchModeAuto))), - ).Or(builder.In("`user`.id", - builder.Select("uid").From("org_user"). - Where(builder.Eq{"org_id": repo.OwnerID}), - ))))) - } - - users := make([]*user_model.User, 0, 8) - return users, db.GetEngine(ctx).Where(cond).OrderBy("name").Find(&users) -} - -// GetReviewers get all users can be requested to review: -// * for private repositories this returns all users that have read access or higher to the repository. -// * for public repositories this returns all users that have read access or higher to the repository, -// all repo watchers and all organization members. -// TODO: may be we should have a busy choice for users to block review request to them. -func GetReviewers(repo *repo_model.Repository, doerID, posterID int64) ([]*user_model.User, error) { - return getReviewers(db.DefaultContext, repo, doerID, posterID) -} - -// GetReviewerTeams get all teams can be requested to review -func GetReviewerTeams(repo *repo_model.Repository) ([]*organization.Team, error) { - if err := repo.GetOwner(db.DefaultContext); err != nil { - return nil, err - } - if !repo.Owner.IsOrganization() { - return nil, nil - } - - teams, err := organization.GetTeamsWithAccessToRepo(db.DefaultContext, repo.OwnerID, repo.ID, perm.AccessModeRead) - if err != nil { - return nil, err - } - - return teams, err -} - -// UpdateRepoSize updates the repository size, calculating it using util.GetDirectorySize -func UpdateRepoSize(ctx context.Context, repo *repo_model.Repository) error { - size, err := util.GetDirectorySize(repo.RepoPath()) - if err != nil { - return fmt.Errorf("updateSize: %v", err) - } - - lfsSize, err := db.GetEngine(ctx).Where("repository_id = ?", repo.ID).SumInt(new(LFSMetaObject), "size") - if err != nil { - return fmt.Errorf("updateSize: GetLFSMetaObjects: %v", err) - } - - repo.Size = size + lfsSize - _, err = db.GetEngine(ctx).ID(repo.ID).Cols("size").NoAutoTime().Update(repo) - return err -} - -// CanUserForkRepo returns true if specified user can fork repository. -func CanUserForkRepo(user *user_model.User, repo *repo_model.Repository) (bool, error) { - if user == nil { - return false, nil - } - if repo.OwnerID != user.ID && !repo_model.HasForkedRepo(user.ID, repo.ID) { - return true, nil - } - ownedOrgs, err := organization.GetOrgsCanCreateRepoByUserID(user.ID) - if err != nil { - return false, err - } - for _, org := range ownedOrgs { - if repo.OwnerID != org.ID && !repo_model.HasForkedRepo(org.ID, repo.ID) { - return true, nil - } - } - return false, nil -} - -// FindUserOrgForks returns the forked repositories for one user from a repository -func FindUserOrgForks(ctx context.Context, repoID, userID int64) ([]*repo_model.Repository, error) { - cond := builder.And( - builder.Eq{"fork_id": repoID}, - builder.In("owner_id", - builder.Select("org_id"). - From("org_user"). - Where(builder.Eq{"uid": userID}), - ), - ) - - var repos []*repo_model.Repository - return repos, db.GetEngine(ctx).Table("repository").Where(cond).Find(&repos) -} - -// GetForksByUserAndOrgs return forked repos of the user and owned orgs -func GetForksByUserAndOrgs(ctx context.Context, user *user_model.User, repo *repo_model.Repository) ([]*repo_model.Repository, error) { - var repoList []*repo_model.Repository - if user == nil { - return repoList, nil - } - forkedRepo, err := repo_model.GetUserFork(ctx, repo.ID, user.ID) - if err != nil { - return repoList, err - } - if forkedRepo != nil { - repoList = append(repoList, forkedRepo) - } - orgForks, err := FindUserOrgForks(ctx, repo.ID, user.ID) - if err != nil { - return nil, err - } - repoList = append(repoList, orgForks...) - return repoList, nil -} - -// CanUserDelete returns true if user could delete the repository -func CanUserDelete(repo *repo_model.Repository, user *user_model.User) (bool, error) { - if user.IsAdmin || user.ID == repo.OwnerID { - return true, nil - } - - if err := repo.GetOwner(db.DefaultContext); err != nil { - return false, err - } - - if repo.Owner.IsOrganization() { - isOwner, err := organization.OrgFromUser(repo.Owner).IsOwnedBy(user.ID) - if err != nil { - return false, err - } else if isOwner { - return true, nil - } - } - - return false, nil -} - // CreateRepoOptions contains the create repository options type CreateRepoOptions struct { Name string @@ -441,126 +198,6 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_ return nil } -// CheckDaemonExportOK creates/removes git-daemon-export-ok for git-daemon... -func CheckDaemonExportOK(ctx context.Context, repo *repo_model.Repository) error { - if err := repo.GetOwner(ctx); err != nil { - return err - } - - // Create/Remove git-daemon-export-ok for git-daemon... - daemonExportFile := path.Join(repo.RepoPath(), `git-daemon-export-ok`) - - isExist, err := util.IsExist(daemonExportFile) - if err != nil { - log.Error("Unable to check if %s exists. Error: %v", daemonExportFile, err) - return err - } - - isPublic := !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePublic - if !isPublic && isExist { - if err = util.Remove(daemonExportFile); err != nil { - log.Error("Failed to remove %s: %v", daemonExportFile, err) - } - } else if isPublic && !isExist { - if f, err := os.Create(daemonExportFile); err != nil { - log.Error("Failed to create %s: %v", daemonExportFile, err) - } else { - f.Close() - } - } - - return nil -} - -// IncrementRepoForkNum increment repository fork number -func IncrementRepoForkNum(ctx context.Context, repoID int64) error { - _, err := db.GetEngine(ctx).Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", repoID) - return err -} - -// DecrementRepoForkNum decrement repository fork number -func DecrementRepoForkNum(ctx context.Context, repoID int64) error { - _, err := db.GetEngine(ctx).Exec("UPDATE `repository` SET num_forks=num_forks-1 WHERE id=?", repoID) - return err -} - -// UpdateRepositoryCtx updates a repository with db context -func UpdateRepositoryCtx(ctx context.Context, repo *repo_model.Repository, visibilityChanged bool) (err error) { - repo.LowerName = strings.ToLower(repo.Name) - - if utf8.RuneCountInString(repo.Description) > 255 { - repo.Description = string([]rune(repo.Description)[:255]) - } - if utf8.RuneCountInString(repo.Website) > 255 { - repo.Website = string([]rune(repo.Website)[:255]) - } - - e := db.GetEngine(ctx) - - if _, err = e.ID(repo.ID).AllCols().Update(repo); err != nil { - return fmt.Errorf("update: %v", err) - } - - if err = UpdateRepoSize(ctx, repo); err != nil { - log.Error("Failed to update size for repository: %v", err) - } - - if visibilityChanged { - if err = repo.GetOwner(ctx); err != nil { - return fmt.Errorf("getOwner: %v", err) - } - if repo.Owner.IsOrganization() { - // Organization repository need to recalculate access table when visibility is changed. - if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil { - return fmt.Errorf("recalculateTeamAccesses: %v", err) - } - } - - // If repo has become private, we need to set its actions to private. - if repo.IsPrivate { - _, err = e.Where("repo_id = ?", repo.ID).Cols("is_private").Update(&Action{ - IsPrivate: true, - }) - if err != nil { - return err - } - } - - // Create/Remove git-daemon-export-ok for git-daemon... - if err := CheckDaemonExportOK(ctx, repo); err != nil { - return err - } - - forkRepos, err := repo_model.GetRepositoriesByForkID(ctx, repo.ID) - if err != nil { - return fmt.Errorf("GetRepositoriesByForkID: %v", err) - } - for i := range forkRepos { - forkRepos[i].IsPrivate = repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate - if err = UpdateRepositoryCtx(ctx, forkRepos[i], true); err != nil { - return fmt.Errorf("updateRepository[%d]: %v", forkRepos[i].ID, err) - } - } - } - - return nil -} - -// UpdateRepository updates a repository -func UpdateRepository(repo *repo_model.Repository, visibilityChanged bool) (err error) { - ctx, committer, err := db.TxContext() - if err != nil { - return err - } - defer committer.Close() - - if err = UpdateRepositoryCtx(ctx, repo, visibilityChanged); err != nil { - return fmt.Errorf("updateRepository: %v", err) - } - - return committer.Commit() -} - // DeleteRepository deletes a repository for a user or organization. // make sure if you call this func to close open sessions (sqlite will otherwise get a deadlock) func DeleteRepository(doer *user_model.User, uid, repoID int64) error { @@ -1052,14 +689,14 @@ func CheckRepoStats(ctx context.Context) error { continue } - rawResult, err := db.GetEngine(db.DefaultContext).Query("SELECT COUNT(*) FROM `repository` WHERE fork_id=?", repo.ID) + rawResult, err := e.Query("SELECT COUNT(*) FROM `repository` WHERE fork_id=?", repo.ID) if err != nil { log.Error("Select count of forks[%d]: %v", repo.ID, err) continue } repo.NumForks = int(parseCountResult(rawResult)) - if err = UpdateRepository(repo, false); err != nil { + if _, err = e.ID(repo.ID).Cols("num_forks").Update(repo); err != nil { log.Error("UpdateRepository[%d]: %v", id, err) continue } @@ -1130,30 +767,6 @@ func DoctorUserStarNum() (err error) { return } -// LinkedRepository returns the linked repo if any -func LinkedRepository(a *repo_model.Attachment) (*repo_model.Repository, unit.Type, error) { - if a.IssueID != 0 { - iss, err := GetIssueByID(a.IssueID) - if err != nil { - return nil, unit.TypeIssues, err - } - repo, err := repo_model.GetRepositoryByID(iss.RepoID) - unitType := unit.TypeIssues - if iss.IsPull { - unitType = unit.TypePullRequests - } - return repo, unitType, err - } else if a.ReleaseID != 0 { - rel, err := GetReleaseByID(db.DefaultContext, a.ReleaseID) - if err != nil { - return nil, unit.TypeReleases, err - } - repo, err := repo_model.GetRepositoryByID(rel.RepoID) - return repo, unit.TypeReleases, err - } - return nil, -1, nil -} - // DeleteDeployKey delete deploy keys func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error { key, err := asymkey_model.GetDeployKeyByID(ctx, id) @@ -1164,8 +777,6 @@ func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error return fmt.Errorf("GetDeployKeyByID: %v", err) } - sess := db.GetEngine(ctx) - // Check if user has access to delete this key. if !doer.IsAdmin { repo, err := repo_model.GetRepositoryByIDCtx(ctx, key.RepoID) @@ -1184,14 +795,14 @@ func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error } } - if _, err = sess.ID(key.ID).Delete(new(asymkey_model.DeployKey)); err != nil { + if _, err := db.DeleteByBean(ctx, &asymkey_model.DeployKey{ + ID: key.ID, + }); err != nil { return fmt.Errorf("delete deploy key [%d]: %v", key.ID, err) } // Check if this is the last reference to same key content. - has, err := sess. - Where("key_id = ?", key.KeyID). - Get(new(asymkey_model.DeployKey)) + has, err := asymkey_model.IsDeployKeyExistByKeyID(ctx, key.KeyID) if err != nil { return err } else if !has { |