2019-02-12 16:07:31 +03:00
// Copyright 2016 The Gogs Authors. All rights reserved.
// Copyright 2019 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"
"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
)
// ____ ___ .__ .___ ___________.___.__
// | | \______ | | _________ __| _/ \_ _____/| | | ____ ______
// | | /\____ \| | / _ \__ \ / __ | | __) | | | _/ __ \ / ___/
// | | / | |_> > |_( <_> ) __ \_/ /_/ | | \ | | |_\ ___/ \___ \
// |______/ | __/|____/\____(____ /\____ | \___ / |___|____/\___ >____ >
// |__| \/ \/ \/ \/ \/
//
// 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.
func NewUpload ( name string , buf [ ] byte , file multipart . File ) ( _ * Upload , err error ) {
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 {
return nil , fmt . Errorf ( "MkdirAll: %v" , err )
}
fw , err := os . Create ( localPath )
if err != nil {
return nil , fmt . Errorf ( "Create: %v" , err )
}
defer fw . Close ( )
if _ , err = fw . Write ( buf ) ; err != nil {
return nil , fmt . Errorf ( "Write: %v" , err )
} else if _ , err = io . Copy ( fw , file ) ; err != nil {
return nil , fmt . Errorf ( "Copy: %v" , err )
}
2021-09-23 18:45:36 +03:00
if _ , err := db . GetEngine ( db . DefaultContext ) . Insert ( upload ) ; err != nil {
2019-02-12 16:07:31 +03:00
return nil , err
}
return upload , nil
}
// GetUploadByUUID returns the Upload by UUID
func GetUploadByUUID ( uuid string ) ( * Upload , error ) {
2020-06-17 20:50:11 +03:00
upload := & Upload { }
2021-09-23 18:45:36 +03:00
has , err := db . GetEngine ( db . DefaultContext ) . 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
func GetUploadsByUUIDs ( uuids [ ] string ) ( [ ] * Upload , error ) {
if len ( uuids ) == 0 {
return [ ] * Upload { } , nil
}
// Silently drop invalid uuids.
uploads := make ( [ ] * Upload , 0 , len ( uuids ) )
2021-09-23 18:45:36 +03:00
return uploads , db . GetEngine ( db . DefaultContext ) . In ( "uuid" , uuids ) . Find ( & uploads )
2019-02-12 16:07:31 +03:00
}
// DeleteUploads deletes multiple uploads
func DeleteUploads ( uploads ... * Upload ) ( err error ) {
if len ( uploads ) == 0 {
return nil
}
2021-11-21 18:41:00 +03:00
ctx , committer , err := db . TxContext ( )
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
}
2021-11-21 18:41:00 +03:00
if _ , err = db . GetEngine ( ctx ) .
2019-02-12 16:07:31 +03:00
In ( "id" , ids ) .
Delete ( new ( Upload ) ) ; err != nil {
return fmt . Errorf ( "delete uploads: %v" , err )
}
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 {
2019-02-12 16:07:31 +03:00
return fmt . Errorf ( "remove upload: %v" , err )
}
}
return nil
}
// DeleteUploadByUUID deletes a upload by UUID
func DeleteUploadByUUID ( uuid string ) error {
upload , err := GetUploadByUUID ( uuid )
if err != nil {
if IsErrUploadNotExist ( err ) {
return nil
}
return fmt . Errorf ( "GetUploadByUUID: %v" , err )
}
if err := DeleteUploads ( upload ) ; err != nil {
return fmt . Errorf ( "DeleteUpload: %v" , err )
}
return nil
}