2017-11-28 23:58:37 +03:00
// Copyright 2017 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2017-11-28 23:58:37 +03:00
2022-06-12 18:51:54 +03:00
package git
2017-11-28 23:58:37 +03:00
import (
2022-04-28 14:48:48 +03:00
"context"
2024-04-21 22:44:03 +03:00
"errors"
2024-08-11 17:48:20 +03:00
"fmt"
2017-11-28 23:58:37 +03:00
"strings"
"time"
2021-09-19 14:49:59 +03:00
"code.gitea.io/gitea/models/db"
2021-11-28 14:58:28 +03:00
"code.gitea.io/gitea/models/perm"
2022-05-11 13:09:36 +03:00
access_model "code.gitea.io/gitea/models/perm/access"
2021-12-10 04:27:50 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2021-11-09 22:57:58 +03:00
"code.gitea.io/gitea/models/unit"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2021-12-10 04:27:50 +03:00
"code.gitea.io/gitea/modules/setting"
2023-03-08 15:17:39 +03:00
"code.gitea.io/gitea/modules/util"
2017-11-28 23:58:37 +03:00
)
// LFSLock represents a git lfs lock of repository.
type LFSLock struct {
2024-08-11 17:48:20 +03:00
ID int64 ` xorm:"pk autoincr" `
RepoID int64 ` xorm:"INDEX NOT NULL" `
OwnerID int64 ` xorm:"INDEX NOT NULL" `
Owner * user_model . User ` xorm:"-" `
Path string ` xorm:"TEXT" `
Created time . Time ` xorm:"created" `
2017-11-28 23:58:37 +03:00
}
2021-09-19 14:49:59 +03:00
func init ( ) {
db . RegisterModel ( new ( LFSLock ) )
}
2017-11-28 23:58:37 +03:00
// BeforeInsert is invoked from XORM before inserting an object of this type.
func ( l * LFSLock ) BeforeInsert ( ) {
2023-03-21 23:02:49 +03:00
l . Path = util . PathJoinRel ( l . Path )
2017-11-28 23:58:37 +03:00
}
2024-08-11 17:48:20 +03:00
// LoadAttributes loads attributes of the lock.
func ( l * LFSLock ) LoadAttributes ( ctx context . Context ) error {
// Load owner
if err := l . LoadOwner ( ctx ) ; err != nil {
return fmt . Errorf ( "load owner: %w" , err )
}
return nil
}
// LoadOwner loads owner of the lock.
func ( l * LFSLock ) LoadOwner ( ctx context . Context ) error {
if l . Owner != nil {
return nil
}
owner , err := user_model . GetUserByID ( ctx , l . OwnerID )
if err != nil {
if user_model . IsErrUserNotExist ( err ) {
l . Owner = user_model . NewGhostUser ( )
return nil
}
return err
}
l . Owner = owner
return nil
}
2017-11-28 23:58:37 +03:00
// CreateLFSLock creates a new lock.
2023-01-09 06:50:54 +03:00
func CreateLFSLock ( ctx context . Context , repo * repo_model . Repository , lock * LFSLock ) ( * LFSLock , error ) {
dbCtx , committer , err := db . TxContext ( ctx )
2017-11-28 23:58:37 +03:00
if err != nil {
return nil , err
}
2022-04-28 14:48:48 +03:00
defer committer . Close ( )
if err := CheckLFSAccessForRepo ( dbCtx , lock . OwnerID , repo , perm . AccessModeWrite ) ; err != nil {
return nil , err
}
2017-11-28 23:58:37 +03:00
2023-03-21 23:02:49 +03:00
lock . Path = util . PathJoinRel ( lock . Path )
2021-12-10 04:27:50 +03:00
lock . RepoID = repo . ID
2019-12-12 16:18:07 +03:00
2022-04-28 14:48:48 +03:00
l , err := GetLFSLock ( dbCtx , 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
}
2022-04-28 14:48:48 +03:00
if err := db . Insert ( dbCtx , lock ) ; err != nil {
return nil , err
}
return lock , committer . Commit ( )
2017-11-28 23:58:37 +03:00
}
// GetLFSLock returns release by given path.
2022-04-28 14:48:48 +03:00
func GetLFSLock ( ctx context . Context , repo * repo_model . Repository , path string ) ( * LFSLock , error ) {
2023-03-21 23:02:49 +03:00
path = util . PathJoinRel ( path )
2018-01-27 19:48:15 +03:00
rel := & LFSLock { RepoID : repo . ID }
2022-04-28 14:48:48 +03:00
has , err := db . GetEngine ( ctx ) . 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.
2022-04-28 14:48:48 +03:00
func GetLFSLockByID ( ctx context . Context , id int64 ) ( * LFSLock , error ) {
2017-11-28 23:58:37 +03:00
lock := new ( LFSLock )
2022-04-28 14:48:48 +03:00
has , err := db . GetEngine ( ctx ) . ID ( id ) . Get ( lock )
2017-11-28 23:58:37 +03:00
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.
2024-08-11 17:48:20 +03:00
func GetLFSLockByRepoID ( ctx context . Context , repoID int64 , page , pageSize int ) ( LFSLockList , error ) {
2023-01-09 06:50:54 +03:00
e := db . GetEngine ( ctx )
2019-12-12 16:18:07 +03:00
if page >= 0 && pageSize > 0 {
start := 0
if page > 0 {
start = ( page - 1 ) * pageSize
}
2021-11-21 18:41:00 +03:00
e . Limit ( pageSize , start )
2019-12-12 16:18:07 +03:00
}
2024-08-11 17:48:20 +03:00
lfsLocks := make ( LFSLockList , 0 , pageSize )
2021-11-21 18:41:00 +03:00
return lfsLocks , e . Find ( & lfsLocks , & LFSLock { RepoID : repoID } )
2019-12-12 16:18:07 +03:00
}
2021-12-10 04:27:50 +03:00
// GetTreePathLock returns LSF lock for the treePath
2023-01-09 06:50:54 +03:00
func GetTreePathLock ( ctx context . Context , repoID int64 , treePath string ) ( * LFSLock , error ) {
2021-12-10 04:27:50 +03:00
if ! setting . LFS . StartServer {
return nil , nil
}
2023-01-09 06:50:54 +03:00
locks , err := GetLFSLockByRepoID ( ctx , repoID , 0 , 0 )
2021-12-10 04:27:50 +03:00
if err != nil {
return nil , err
}
for _ , lock := range locks {
if lock . Path == treePath {
return lock , nil
}
}
return nil , nil
}
2019-12-12 16:18:07 +03:00
// CountLFSLockByRepoID returns a count of all LFSLocks associated with a repository.
2023-01-09 06:50:54 +03:00
func CountLFSLockByRepoID ( ctx context . Context , repoID int64 ) ( int64 , error ) {
return db . GetEngine ( ctx ) . Count ( & LFSLock { RepoID : repoID } )
2017-11-28 23:58:37 +03:00
}
// DeleteLFSLockByID deletes a lock by given ID.
2023-01-09 06:50:54 +03:00
func DeleteLFSLockByID ( ctx context . Context , id int64 , repo * repo_model . Repository , u * user_model . User , force bool ) ( * LFSLock , error ) {
dbCtx , committer , err := db . TxContext ( ctx )
2017-11-28 23:58:37 +03:00
if err != nil {
return nil , err
}
2022-04-28 14:48:48 +03:00
defer committer . Close ( )
2017-11-28 23:58:37 +03:00
2022-04-28 14:48:48 +03:00
lock , err := GetLFSLockByID ( dbCtx , id )
2017-11-28 23:58:37 +03:00
if err != nil {
return nil , err
}
2022-04-28 14:48:48 +03:00
if err := CheckLFSAccessForRepo ( dbCtx , u . ID , repo , perm . AccessModeWrite ) ; err != nil {
return nil , err
}
2017-11-28 23:58:37 +03:00
if ! force && u . ID != lock . OwnerID {
2024-04-21 22:44:03 +03:00
return nil , errors . New ( "user doesn't own lock and force flag is not set" )
2017-11-28 23:58:37 +03:00
}
2022-04-28 14:48:48 +03:00
if _ , err := db . GetEngine ( dbCtx ) . ID ( id ) . Delete ( new ( LFSLock ) ) ; err != nil {
return nil , err
}
return lock , committer . Commit ( )
2017-11-28 23:58:37 +03:00
}
2021-03-14 21:52:12 +03:00
// CheckLFSAccessForRepo check needed access mode base on action
2022-04-28 14:48:48 +03:00
func CheckLFSAccessForRepo ( ctx context . Context , ownerID int64 , repo * repo_model . Repository , mode perm . AccessMode ) error {
2021-11-24 12:49:20 +03:00
if ownerID == 0 {
2018-01-27 19:48:15 +03:00
return ErrLFSUnauthorizedAction { repo . ID , "undefined" , mode }
2017-11-28 23:58:37 +03:00
}
2022-12-03 05:48:26 +03:00
u , err := user_model . GetUserByID ( ctx , ownerID )
2021-11-24 12:49:20 +03:00
if err != nil {
return err
}
2022-05-11 13:09:36 +03:00
perm , err := access_model . GetUserRepoPermission ( ctx , repo , u )
2017-11-28 23:58:37 +03:00
if err != nil {
return err
2018-11-28 14:26:14 +03:00
}
2021-11-09 22:57:58 +03:00
if ! perm . CanAccess ( mode , unit . TypeCode ) {
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
}