2019-02-12 16:07:31 +03:00
// Copyright 2016 The Gogs Authors. All rights reserved.
// Copyright 2019 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2019-02-12 16:07:31 +03:00
2022-08-25 05:31:57 +03:00
package repo
2019-02-12 16:07:31 +03:00
import (
2023-09-15 09:13:19 +03:00
"context"
2019-02-12 16:07:31 +03:00
"fmt"
"io"
"mime/multipart"
"os"
"path"
2021-09-19 14:49:59 +03:00
"code.gitea.io/gitea/models/db"
2020-11-28 05:42:08 +03:00
"code.gitea.io/gitea/modules/log"
2019-02-12 16:07:31 +03:00
"code.gitea.io/gitea/modules/setting"
2020-08-11 23:05:34 +03:00
"code.gitea.io/gitea/modules/util"
2019-08-23 19:40:30 +03:00
2020-06-18 12:18:44 +03:00
gouuid "github.com/google/uuid"
2019-02-12 16:07:31 +03:00
)
2022-08-25 05:31:57 +03:00
// ErrUploadNotExist represents a "UploadNotExist" kind of error.
type ErrUploadNotExist struct {
ID int64
UUID string
}
// IsErrUploadNotExist checks if an error is a ErrUploadNotExist.
func IsErrUploadNotExist ( err error ) bool {
_ , ok := err . ( ErrUploadNotExist )
return ok
}
func ( err ErrUploadNotExist ) Error ( ) string {
return fmt . Sprintf ( "attachment does not exist [id: %d, uuid: %s]" , err . ID , err . UUID )
}
2019-02-12 16:07:31 +03:00
2022-10-18 08:50:37 +03:00
func ( err ErrUploadNotExist ) Unwrap ( ) error {
return util . ErrNotExist
}
2019-02-12 16:07:31 +03:00
// Upload represent a uploaded file to a repo to be deleted when moved
type Upload struct {
ID int64 ` xorm:"pk autoincr" `
UUID string ` xorm:"uuid UNIQUE" `
Name string
}
2021-09-19 14:49:59 +03:00
func init ( ) {
db . RegisterModel ( new ( Upload ) )
}
2019-02-12 16:07:31 +03:00
// UploadLocalPath returns where uploads is stored in local file system based on given UUID.
func UploadLocalPath ( uuid string ) string {
return path . Join ( setting . Repository . Upload . TempPath , uuid [ 0 : 1 ] , uuid [ 1 : 2 ] , uuid )
}
// LocalPath returns where uploads are temporarily stored in local file system.
func ( upload * Upload ) LocalPath ( ) string {
return UploadLocalPath ( upload . UUID )
}
// NewUpload creates a new upload object.
2023-09-15 09:13:19 +03:00
func NewUpload ( ctx context . Context , name string , buf [ ] byte , file multipart . File ) ( _ * Upload , err error ) {
2019-02-12 16:07:31 +03:00
upload := & Upload {
2020-06-18 12:18:44 +03:00
UUID : gouuid . New ( ) . String ( ) ,
2019-02-12 16:07:31 +03:00
Name : name ,
}
localPath := upload . LocalPath ( )
if err = os . MkdirAll ( path . Dir ( localPath ) , os . ModePerm ) ; err != nil {
2022-10-24 22:29:17 +03:00
return nil , fmt . Errorf ( "MkdirAll: %w" , err )
2019-02-12 16:07:31 +03:00
}
fw , err := os . Create ( localPath )
if err != nil {
2022-10-24 22:29:17 +03:00
return nil , fmt . Errorf ( "Create: %w" , err )
2019-02-12 16:07:31 +03:00
}
defer fw . Close ( )
if _ , err = fw . Write ( buf ) ; err != nil {
2022-10-24 22:29:17 +03:00
return nil , fmt . Errorf ( "Write: %w" , err )
2019-02-12 16:07:31 +03:00
} else if _ , err = io . Copy ( fw , file ) ; err != nil {
2022-10-24 22:29:17 +03:00
return nil , fmt . Errorf ( "Copy: %w" , err )
2019-02-12 16:07:31 +03:00
}
2023-09-15 09:13:19 +03:00
if _ , err := db . GetEngine ( ctx ) . Insert ( upload ) ; err != nil {
2019-02-12 16:07:31 +03:00
return nil , err
}
return upload , nil
}
// GetUploadByUUID returns the Upload by UUID
2023-09-15 09:13:19 +03:00
func GetUploadByUUID ( ctx context . Context , uuid string ) ( * Upload , error ) {
2020-06-17 20:50:11 +03:00
upload := & Upload { }
2023-09-15 09:13:19 +03:00
has , err := db . GetEngine ( ctx ) . Where ( "uuid=?" , uuid ) . Get ( upload )
2019-02-12 16:07:31 +03:00
if err != nil {
return nil , err
} else if ! has {
return nil , ErrUploadNotExist { 0 , uuid }
}
return upload , nil
}
// GetUploadsByUUIDs returns multiple uploads by UUIDS
2023-09-15 09:13:19 +03:00
func GetUploadsByUUIDs ( ctx context . Context , uuids [ ] string ) ( [ ] * Upload , error ) {
2019-02-12 16:07:31 +03:00
if len ( uuids ) == 0 {
return [ ] * Upload { } , nil
}
// Silently drop invalid uuids.
uploads := make ( [ ] * Upload , 0 , len ( uuids ) )
2023-09-15 09:13:19 +03:00
return uploads , db . GetEngine ( ctx ) . In ( "uuid" , uuids ) . Find ( & uploads )
2019-02-12 16:07:31 +03:00
}
// DeleteUploads deletes multiple uploads
2023-09-15 09:13:19 +03:00
func DeleteUploads ( ctx context . Context , uploads ... * Upload ) ( err error ) {
2019-02-12 16:07:31 +03:00
if len ( uploads ) == 0 {
return nil
}
2023-09-15 09:13:19 +03:00
ctx , committer , err := db . TxContext ( ctx )
2021-11-21 18:41:00 +03:00
if err != nil {
2019-02-12 16:07:31 +03:00
return err
}
2021-11-21 18:41:00 +03:00
defer committer . Close ( )
2019-02-12 16:07:31 +03:00
ids := make ( [ ] int64 , len ( uploads ) )
for i := 0 ; i < len ( uploads ) ; i ++ {
ids [ i ] = uploads [ i ] . ID
}
2023-12-25 23:25:29 +03:00
if err = db . DeleteByIDs [ Upload ] ( ctx , ids ... ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "delete uploads: %w" , err )
2019-02-12 16:07:31 +03:00
}
2021-11-21 18:41:00 +03:00
if err = committer . Commit ( ) ; err != nil {
2019-02-12 16:07:31 +03:00
return err
}
for _ , upload := range uploads {
localPath := upload . LocalPath ( )
2020-11-28 05:42:08 +03:00
isFile , err := util . IsFile ( localPath )
if err != nil {
log . Error ( "Unable to check if %s is a file. Error: %v" , localPath , err )
}
if ! isFile {
2019-02-12 16:07:31 +03:00
continue
}
2020-08-11 23:05:34 +03:00
if err := util . Remove ( localPath ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "remove upload: %w" , err )
2019-02-12 16:07:31 +03:00
}
}
return nil
}
// DeleteUploadByUUID deletes a upload by UUID
2023-09-15 09:13:19 +03:00
func DeleteUploadByUUID ( ctx context . Context , uuid string ) error {
upload , err := GetUploadByUUID ( ctx , uuid )
2019-02-12 16:07:31 +03:00
if err != nil {
if IsErrUploadNotExist ( err ) {
return nil
}
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "GetUploadByUUID: %w" , err )
2019-02-12 16:07:31 +03:00
}
2023-09-15 09:13:19 +03:00
if err := DeleteUploads ( ctx , upload ) ; err != nil {
2022-10-24 22:29:17 +03:00
return fmt . Errorf ( "DeleteUpload: %w" , err )
2019-02-12 16:07:31 +03:00
}
return nil
}