code.gitea.io/gitea@v1.21.7/models/git/lfs_lock.go (about) 1 // Copyright 2017 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package git 5 6 import ( 7 "context" 8 "fmt" 9 "strings" 10 "time" 11 12 "code.gitea.io/gitea/models/db" 13 "code.gitea.io/gitea/models/perm" 14 access_model "code.gitea.io/gitea/models/perm/access" 15 repo_model "code.gitea.io/gitea/models/repo" 16 "code.gitea.io/gitea/models/unit" 17 user_model "code.gitea.io/gitea/models/user" 18 "code.gitea.io/gitea/modules/setting" 19 "code.gitea.io/gitea/modules/util" 20 ) 21 22 // LFSLock represents a git lfs lock of repository. 23 type LFSLock struct { 24 ID int64 `xorm:"pk autoincr"` 25 RepoID int64 `xorm:"INDEX NOT NULL"` 26 OwnerID int64 `xorm:"INDEX NOT NULL"` 27 Path string `xorm:"TEXT"` 28 Created time.Time `xorm:"created"` 29 } 30 31 func init() { 32 db.RegisterModel(new(LFSLock)) 33 } 34 35 // BeforeInsert is invoked from XORM before inserting an object of this type. 36 func (l *LFSLock) BeforeInsert() { 37 l.Path = util.PathJoinRel(l.Path) 38 } 39 40 // CreateLFSLock creates a new lock. 41 func CreateLFSLock(ctx context.Context, repo *repo_model.Repository, lock *LFSLock) (*LFSLock, error) { 42 dbCtx, committer, err := db.TxContext(ctx) 43 if err != nil { 44 return nil, err 45 } 46 defer committer.Close() 47 48 if err := CheckLFSAccessForRepo(dbCtx, lock.OwnerID, repo, perm.AccessModeWrite); err != nil { 49 return nil, err 50 } 51 52 lock.Path = util.PathJoinRel(lock.Path) 53 lock.RepoID = repo.ID 54 55 l, err := GetLFSLock(dbCtx, repo, lock.Path) 56 if err == nil { 57 return l, ErrLFSLockAlreadyExist{lock.RepoID, lock.Path} 58 } 59 if !IsErrLFSLockNotExist(err) { 60 return nil, err 61 } 62 63 if err := db.Insert(dbCtx, lock); err != nil { 64 return nil, err 65 } 66 67 return lock, committer.Commit() 68 } 69 70 // GetLFSLock returns release by given path. 71 func GetLFSLock(ctx context.Context, repo *repo_model.Repository, path string) (*LFSLock, error) { 72 path = util.PathJoinRel(path) 73 rel := &LFSLock{RepoID: repo.ID} 74 has, err := db.GetEngine(ctx).Where("lower(path) = ?", strings.ToLower(path)).Get(rel) 75 if err != nil { 76 return nil, err 77 } 78 if !has { 79 return nil, ErrLFSLockNotExist{0, repo.ID, path} 80 } 81 return rel, nil 82 } 83 84 // GetLFSLockByID returns release by given id. 85 func GetLFSLockByID(ctx context.Context, id int64) (*LFSLock, error) { 86 lock := new(LFSLock) 87 has, err := db.GetEngine(ctx).ID(id).Get(lock) 88 if err != nil { 89 return nil, err 90 } else if !has { 91 return nil, ErrLFSLockNotExist{id, 0, ""} 92 } 93 return lock, nil 94 } 95 96 // GetLFSLockByRepoID returns a list of locks of repository. 97 func GetLFSLockByRepoID(ctx context.Context, repoID int64, page, pageSize int) ([]*LFSLock, error) { 98 e := db.GetEngine(ctx) 99 if page >= 0 && pageSize > 0 { 100 start := 0 101 if page > 0 { 102 start = (page - 1) * pageSize 103 } 104 e.Limit(pageSize, start) 105 } 106 lfsLocks := make([]*LFSLock, 0, pageSize) 107 return lfsLocks, e.Find(&lfsLocks, &LFSLock{RepoID: repoID}) 108 } 109 110 // GetTreePathLock returns LSF lock for the treePath 111 func GetTreePathLock(ctx context.Context, repoID int64, treePath string) (*LFSLock, error) { 112 if !setting.LFS.StartServer { 113 return nil, nil 114 } 115 116 locks, err := GetLFSLockByRepoID(ctx, repoID, 0, 0) 117 if err != nil { 118 return nil, err 119 } 120 for _, lock := range locks { 121 if lock.Path == treePath { 122 return lock, nil 123 } 124 } 125 return nil, nil 126 } 127 128 // CountLFSLockByRepoID returns a count of all LFSLocks associated with a repository. 129 func CountLFSLockByRepoID(ctx context.Context, repoID int64) (int64, error) { 130 return db.GetEngine(ctx).Count(&LFSLock{RepoID: repoID}) 131 } 132 133 // DeleteLFSLockByID deletes a lock by given ID. 134 func DeleteLFSLockByID(ctx context.Context, id int64, repo *repo_model.Repository, u *user_model.User, force bool) (*LFSLock, error) { 135 dbCtx, committer, err := db.TxContext(ctx) 136 if err != nil { 137 return nil, err 138 } 139 defer committer.Close() 140 141 lock, err := GetLFSLockByID(dbCtx, id) 142 if err != nil { 143 return nil, err 144 } 145 146 if err := CheckLFSAccessForRepo(dbCtx, u.ID, repo, perm.AccessModeWrite); err != nil { 147 return nil, err 148 } 149 150 if !force && u.ID != lock.OwnerID { 151 return nil, fmt.Errorf("user doesn't own lock and force flag is not set") 152 } 153 154 if _, err := db.GetEngine(dbCtx).ID(id).Delete(new(LFSLock)); err != nil { 155 return nil, err 156 } 157 158 return lock, committer.Commit() 159 } 160 161 // CheckLFSAccessForRepo check needed access mode base on action 162 func CheckLFSAccessForRepo(ctx context.Context, ownerID int64, repo *repo_model.Repository, mode perm.AccessMode) error { 163 if ownerID == 0 { 164 return ErrLFSUnauthorizedAction{repo.ID, "undefined", mode} 165 } 166 u, err := user_model.GetUserByID(ctx, ownerID) 167 if err != nil { 168 return err 169 } 170 perm, err := access_model.GetUserRepoPermission(ctx, repo, u) 171 if err != nil { 172 return err 173 } 174 if !perm.CanAccess(mode, unit.TypeCode) { 175 return ErrLFSUnauthorizedAction{repo.ID, u.DisplayName(), mode} 176 } 177 return nil 178 }