2017-11-28 23:58:37 +03:00
// 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"
2018-01-27 19:48:15 +03:00
"code.gitea.io/gitea/modules/log"
2019-05-11 13:21:34 +03:00
api "code.gitea.io/gitea/modules/structs"
2019-08-23 19:40:30 +03:00
2019-10-17 12:26:49 +03:00
"xorm.io/xorm"
2017-11-28 23:58:37 +03:00
)
// LFSLock represents a git lfs lock of repository.
type LFSLock struct {
2018-01-27 19:48:15 +03:00
ID int64 ` xorm:"pk autoincr" `
Repo * Repository ` xorm:"-" `
RepoID int64 ` xorm:"INDEX NOT NULL" `
Owner * User ` xorm:"-" `
OwnerID int64 ` xorm:"INDEX NOT NULL" `
Path string ` xorm:"TEXT" `
Created time . Time ` xorm:"created" `
2017-11-28 23:58:37 +03:00
}
// BeforeInsert is invoked from XORM before inserting an object of this type.
func ( l * LFSLock ) BeforeInsert ( ) {
l . OwnerID = l . Owner . ID
2018-01-27 19:48:15 +03:00
l . RepoID = l . Repo . ID
2017-11-28 23:58:37 +03:00
l . Path = cleanPath ( l . Path )
}
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
2018-01-27 19:48:15 +03:00
func ( l * LFSLock ) AfterLoad ( session * xorm . Session ) {
var err error
l . Owner , err = getUserByID ( session , l . OwnerID )
if err != nil {
2019-04-02 10:48:31 +03:00
log . Error ( "LFS lock AfterLoad failed OwnerId[%d] not found: %v" , l . OwnerID , err )
2018-01-27 19:48:15 +03:00
}
l . Repo , err = getRepositoryByID ( session , l . RepoID )
if err != nil {
2019-04-02 10:48:31 +03:00
log . Error ( "LFS lock AfterLoad failed RepoId[%d] not found: %v" , l . RepoID , err )
2018-01-27 19:48:15 +03:00
}
2017-11-28 23:58:37 +03:00
}
func cleanPath ( p string ) string {
2019-12-12 16:18:07 +03:00
return path . Clean ( "/" + p ) [ 1 : ]
2017-11-28 23:58:37 +03:00
}
// 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 ,
2019-08-15 13:53:28 +03:00
LockedAt : l . Created . Round ( time . Second ) ,
2017-11-28 23:58:37 +03:00
Owner : & api . LFSLockOwner {
Name : l . Owner . DisplayName ( ) ,
} ,
}
}
// CreateLFSLock creates a new lock.
func CreateLFSLock ( lock * LFSLock ) ( * LFSLock , error ) {
2018-01-27 19:48:15 +03:00
err := CheckLFSAccessForRepo ( lock . Owner , lock . Repo , AccessModeWrite )
2017-11-28 23:58:37 +03:00
if err != nil {
return nil , err
}
2019-12-12 16:18:07 +03:00
lock . Path = cleanPath ( lock . Path )
2018-01-27 19:48:15 +03:00
l , err := GetLFSLock ( lock . Repo , lock . Path )
2017-11-28 23:58:37 +03:00
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.
2018-01-27 19:48:15 +03:00
func GetLFSLock ( repo * Repository , path string ) ( * LFSLock , error ) {
2017-11-28 23:58:37 +03:00
path = cleanPath ( path )
2018-01-27 19:48:15 +03:00
rel := & LFSLock { RepoID : repo . ID }
2017-12-08 15:21:37 +03:00
has , err := x . Where ( "lower(path) = ?" , strings . ToLower ( path ) ) . Get ( rel )
2017-11-28 23:58:37 +03:00
if err != nil {
return nil , err
}
if ! has {
2018-01-27 19:48:15 +03:00
return nil , ErrLFSLockNotExist { 0 , repo . ID , path }
2017-11-28 23:58:37 +03:00
}
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.
2019-12-12 16:18:07 +03:00
func GetLFSLockByRepoID ( repoID int64 , page , pageSize int ) ( [ ] * LFSLock , error ) {
sess := x . NewSession ( )
defer sess . Close ( )
if page >= 0 && pageSize > 0 {
start := 0
if page > 0 {
start = ( page - 1 ) * pageSize
}
sess . Limit ( pageSize , start )
}
lfsLocks := make ( [ ] * LFSLock , 0 , pageSize )
return lfsLocks , sess . Find ( & lfsLocks , & LFSLock { RepoID : repoID } )
}
// CountLFSLockByRepoID returns a count of all LFSLocks associated with a repository.
func CountLFSLockByRepoID ( repoID int64 ) ( int64 , error ) {
return x . Count ( & LFSLock { RepoID : repoID } )
2017-11-28 23:58:37 +03:00
}
// 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
}
2018-01-27 19:48:15 +03:00
err = CheckLFSAccessForRepo ( u , lock . Repo , AccessModeWrite )
2017-11-28 23:58:37 +03:00
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
2018-01-27 19:48:15 +03:00
func CheckLFSAccessForRepo ( u * User , repo * Repository , mode AccessMode ) error {
2017-11-28 23:58:37 +03:00
if u == nil {
2018-01-27 19:48:15 +03:00
return ErrLFSUnauthorizedAction { repo . ID , "undefined" , mode }
2017-11-28 23:58:37 +03:00
}
2018-11-28 14:26:14 +03:00
perm , err := GetUserRepoPermission ( repo , u )
2017-11-28 23:58:37 +03:00
if err != nil {
return err
2018-11-28 14:26:14 +03:00
}
if ! perm . CanAccess ( mode , UnitTypeCode ) {
2018-01-27 19:48:15 +03:00
return ErrLFSUnauthorizedAction { repo . ID , u . DisplayName ( ) , mode }
2017-11-28 23:58:37 +03:00
}
return nil
}