mirror of
https://github.com/go-gitea/gitea.git
synced 2025-12-16 09:54:27 +01:00
Some checks failed
And by the way, remove the legacy TODO, split large functions into small ones, and add more tests
155 lines
3.8 KiB
Go
155 lines
3.8 KiB
Go
// Copyright 2016 The Gogs Authors. All rights reserved.
|
|
// Copyright 2019 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package repo
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"mime/multipart"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"code.gitea.io/gitea/models/db"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
"code.gitea.io/gitea/modules/util"
|
|
|
|
gouuid "github.com/google/uuid"
|
|
)
|
|
|
|
// 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)
|
|
}
|
|
|
|
func (err ErrUploadNotExist) Unwrap() error {
|
|
return util.ErrNotExist
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
func init() {
|
|
db.RegisterModel(new(Upload))
|
|
}
|
|
|
|
// LocalPath returns where uploads are temporarily stored in local file system based on given UUID.
|
|
func (upload *Upload) LocalPath() string {
|
|
uuid := upload.UUID
|
|
return setting.AppDataTempDir("repo-uploads").JoinPath(uuid[0:1], uuid[1:2], uuid)
|
|
}
|
|
|
|
// NewUpload creates a new upload object.
|
|
func NewUpload(ctx context.Context, name string, buf []byte, file multipart.File) (_ *Upload, err error) {
|
|
upload := &Upload{
|
|
UUID: gouuid.New().String(),
|
|
Name: name,
|
|
}
|
|
|
|
localPath := upload.LocalPath()
|
|
if err = os.MkdirAll(filepath.Dir(localPath), os.ModePerm); err != nil {
|
|
return nil, fmt.Errorf("MkdirAll: %w", err)
|
|
}
|
|
|
|
fw, err := os.Create(localPath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Create: %w", err)
|
|
}
|
|
defer fw.Close()
|
|
|
|
if _, err = fw.Write(buf); err != nil {
|
|
return nil, fmt.Errorf("Write: %w", err)
|
|
} else if _, err = io.Copy(fw, file); err != nil {
|
|
return nil, fmt.Errorf("Copy: %w", err)
|
|
}
|
|
|
|
if _, err := db.GetEngine(ctx).Insert(upload); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return upload, nil
|
|
}
|
|
|
|
// GetUploadByUUID returns the Upload by UUID
|
|
func GetUploadByUUID(ctx context.Context, uuid string) (*Upload, error) {
|
|
upload := &Upload{}
|
|
has, err := db.GetEngine(ctx).Where("uuid=?", uuid).Get(upload)
|
|
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(ctx context.Context, uuids []string) ([]*Upload, error) {
|
|
if len(uuids) == 0 {
|
|
return []*Upload{}, nil
|
|
}
|
|
|
|
// Silently drop invalid uuids.
|
|
uploads := make([]*Upload, 0, len(uuids))
|
|
return uploads, db.GetEngine(ctx).In("uuid", uuids).Find(&uploads)
|
|
}
|
|
|
|
// DeleteUploads deletes multiple uploads
|
|
func DeleteUploads(ctx context.Context, uploads ...*Upload) (err error) {
|
|
if len(uploads) == 0 {
|
|
return nil
|
|
}
|
|
|
|
ids := make([]int64, len(uploads))
|
|
for i := range uploads {
|
|
ids[i] = uploads[i].ID
|
|
}
|
|
if err = db.DeleteByIDs[Upload](ctx, ids...); err != nil {
|
|
return fmt.Errorf("delete uploads: %w", err)
|
|
}
|
|
|
|
for _, upload := range uploads {
|
|
localPath := upload.LocalPath()
|
|
if err := util.Remove(localPath); err != nil {
|
|
// just continue, don't fail the whole operation if a file is missing (removed by others)
|
|
log.Error("unable to remove upload file %s: %v", localPath, err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// DeleteUploadByUUID deletes a upload by UUID
|
|
func DeleteUploadByUUID(ctx context.Context, uuid string) error {
|
|
upload, err := GetUploadByUUID(ctx, uuid)
|
|
if err != nil {
|
|
if IsErrUploadNotExist(err) {
|
|
return nil
|
|
}
|
|
return fmt.Errorf("GetUploadByUUID: %w", err)
|
|
}
|
|
|
|
if err := DeleteUploads(ctx, upload); err != nil {
|
|
return fmt.Errorf("DeleteUpload: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|