diff options
author | Antoine GIRARD <sapk@users.noreply.github.com> | 2017-11-28 21:58:37 +0100 |
---|---|---|
committer | Lauris BH <lauris@nix.lv> | 2017-11-28 22:58:37 +0200 |
commit | d99f4ab0035631aacc44739af0a936e59daf83b7 (patch) | |
tree | 607cde54661ad07cb15f1ee5f4d9e836de6ff034 /models/lfs_lock.go | |
parent | 6ad4990a65462af770e15330da4777ea59bcc5ad (diff) | |
download | gitea-d99f4ab0035631aacc44739af0a936e59daf83b7.tar.gz gitea-d99f4ab0035631aacc44739af0a936e59daf83b7.zip |
Git LFS lock api (#2938)
* Implement routes
* move to api/sdk and create model
* Implement add + list
* List return 200 empty list no 404
* Add verify lfs lock api
* Add delete and start implementing auth control
* Revert to code.gitea.io/sdk/gitea vendor
* Apply needed check for all lfs locks route
* Add simple tests
* fix lint
* Improve tests
* Add delete test + fix
* Add lfs ascii header
* Various fixes from review + remove useless code + add more corner case testing
* Remove repo link since only id is needed.
Save a little of memory and cpu time.
* Improve tests
* Use TEXT column format for path + test
* fix mispell
* Use NewRequestWithJSON for POST tests
* Clean path
* Improve DB format
* Revert uniquess repoid+path
* (Re)-setup uniqueness + max path length
* Fixed TEXT in place of VARCHAR
* Settle back to maximum VARCHAR(3072)
* Let place for repoid in key
* Let place for repoid in key
* Let place for repoid in key
* Revert back
Diffstat (limited to 'models/lfs_lock.go')
-rw-r--r-- | models/lfs_lock.go | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/models/lfs_lock.go b/models/lfs_lock.go new file mode 100644 index 0000000000..83811bc7bd --- /dev/null +++ b/models/lfs_lock.go @@ -0,0 +1,146 @@ +// Copyright 2017 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package models + +import ( + "fmt" + "path" + "strconv" + "strings" + "time" + + api "code.gitea.io/sdk/gitea" +) + +// LFSLock represents a git lfs lock of repository. +type LFSLock struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX NOT NULL"` + Owner *User `xorm:"-"` + OwnerID int64 `xorm:"INDEX NOT NULL"` + Path string `xorm:"TEXT"` + Created time.Time `xorm:"created"` +} + +// BeforeInsert is invoked from XORM before inserting an object of this type. +func (l *LFSLock) BeforeInsert() { + l.OwnerID = l.Owner.ID + l.Path = cleanPath(l.Path) +} + +// AfterLoad is invoked from XORM after setting the values of all fields of this object. +func (l *LFSLock) AfterLoad() { + l.Owner, _ = GetUserByID(l.OwnerID) +} + +func cleanPath(p string) string { + return strings.ToLower(path.Clean(p)) +} + +// APIFormat convert a Release to lfs.LFSLock +func (l *LFSLock) APIFormat() *api.LFSLock { + return &api.LFSLock{ + ID: strconv.FormatInt(l.ID, 10), + Path: l.Path, + LockedAt: l.Created, + Owner: &api.LFSLockOwner{ + Name: l.Owner.DisplayName(), + }, + } +} + +// CreateLFSLock creates a new lock. +func CreateLFSLock(lock *LFSLock) (*LFSLock, error) { + err := CheckLFSAccessForRepo(lock.Owner, lock.RepoID, "create") + if err != nil { + return nil, err + } + + l, err := GetLFSLock(lock.RepoID, lock.Path) + if err == nil { + return l, ErrLFSLockAlreadyExist{lock.RepoID, lock.Path} + } + if !IsErrLFSLockNotExist(err) { + return nil, err + } + + _, err = x.InsertOne(lock) + return lock, err +} + +// GetLFSLock returns release by given path. +func GetLFSLock(repoID int64, path string) (*LFSLock, error) { + path = cleanPath(path) + rel := &LFSLock{RepoID: repoID, Path: path} + has, err := x.Get(rel) + if err != nil { + return nil, err + } + if !has { + return nil, ErrLFSLockNotExist{0, repoID, path} + } + return rel, nil +} + +// GetLFSLockByID returns release by given id. +func GetLFSLockByID(id int64) (*LFSLock, error) { + lock := new(LFSLock) + has, err := x.ID(id).Get(lock) + if err != nil { + return nil, err + } else if !has { + return nil, ErrLFSLockNotExist{id, 0, ""} + } + return lock, nil +} + +// GetLFSLockByRepoID returns a list of locks of repository. +func GetLFSLockByRepoID(repoID int64) (locks []*LFSLock, err error) { + err = x.Where("repo_id = ?", repoID).Find(&locks) + return +} + +// DeleteLFSLockByID deletes a lock by given ID. +func DeleteLFSLockByID(id int64, u *User, force bool) (*LFSLock, error) { + lock, err := GetLFSLockByID(id) + if err != nil { + return nil, err + } + + err = CheckLFSAccessForRepo(u, lock.RepoID, "delete") + if err != nil { + return nil, err + } + + if !force && u.ID != lock.OwnerID { + return nil, fmt.Errorf("user doesn't own lock and force flag is not set") + } + + _, err = x.ID(id).Delete(new(LFSLock)) + return lock, err +} + +//CheckLFSAccessForRepo check needed access mode base on action +func CheckLFSAccessForRepo(u *User, repoID int64, action string) error { + if u == nil { + return ErrLFSLockUnauthorizedAction{repoID, "undefined", action} + } + mode := AccessModeRead + if action == "create" || action == "delete" || action == "verify" { + mode = AccessModeWrite + } + + repo, err := GetRepositoryByID(repoID) + if err != nil { + return err + } + has, err := HasAccess(u.ID, repo, mode) + if err != nil { + return err + } else if !has { + return ErrLFSLockUnauthorizedAction{repo.ID, u.DisplayName(), action} + } + return nil +} |