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"
2018-01-27 19:48:15 +03:00
"github.com/go-xorm/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 {
2017-12-08 15:21:37 +03:00
return path . Clean ( p )
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 ,
LockedAt : l . Created ,
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
}
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.
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
}
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
}