|
@ -3,10 +3,15 @@ package services |
|
|
import ( |
|
|
import ( |
|
|
"context" |
|
|
"context" |
|
|
"errors" |
|
|
"errors" |
|
|
|
|
|
"git.aiterp.net/rpdata/api/internal/generate" |
|
|
"git.aiterp.net/rpdata/api/models" |
|
|
"git.aiterp.net/rpdata/api/models" |
|
|
|
|
|
"git.aiterp.net/rpdata/api/models/changekeys" |
|
|
"git.aiterp.net/rpdata/api/repositories" |
|
|
"git.aiterp.net/rpdata/api/repositories" |
|
|
|
|
|
"git.aiterp.net/rpdata/api/space" |
|
|
"github.com/h2non/filetype" |
|
|
"github.com/h2non/filetype" |
|
|
"io" |
|
|
"io" |
|
|
|
|
|
"log" |
|
|
|
|
|
"time" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
var ErrPrivateNoAuthor = errors.New("cannot search for private files without an author") |
|
|
var ErrPrivateNoAuthor = errors.New("cannot search for private files without an author") |
|
@ -20,6 +25,8 @@ var ErrCouldNotUploadFile = errors.New("could not upload file") |
|
|
type FileService struct { |
|
|
type FileService struct { |
|
|
files repositories.FileRepository |
|
|
files repositories.FileRepository |
|
|
authService *AuthService |
|
|
authService *AuthService |
|
|
|
|
|
changeService *ChangeService |
|
|
|
|
|
space *space.Client |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (s *FileService) Find(ctx context.Context, id string) (*models.File, error) { |
|
|
func (s *FileService) Find(ctx context.Context, id string) (*models.File, error) { |
|
@ -56,13 +63,18 @@ func (s *FileService) List(ctx context.Context, filter models.FileFilter) ([]*mo |
|
|
return s.files.List(ctx, filter) |
|
|
return s.files.List(ctx, filter) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (s *FileService) Upload(ctx context.Context, reader io.Reader, name string, size int64) (*models.File, error) { |
|
|
|
|
|
|
|
|
func (s *FileService) Upload(ctx context.Context, reader io.Reader, name string, public bool, size int64) (*models.File, error) { |
|
|
if name == "" { |
|
|
if name == "" { |
|
|
return nil, ErrInvalidName |
|
|
return nil, ErrInvalidName |
|
|
} else if size < 320 || size > 16777216 { |
|
|
} else if size < 320 || size > 16777216 { |
|
|
return nil, ErrInvalidFileSize |
|
|
return nil, ErrInvalidFileSize |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
token := s.authService.TokenFromContext(ctx) |
|
|
|
|
|
if token == nil || !token.Permitted("file.upload", "member") { |
|
|
|
|
|
return nil, ErrUnauthorized |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
head := make([]byte, 320) |
|
|
head := make([]byte, 320) |
|
|
n, err := reader.Read(head) |
|
|
n, err := reader.Read(head) |
|
|
if err != nil || n < 320 { |
|
|
if err != nil || n < 320 { |
|
@ -74,7 +86,35 @@ func (s *FileService) Upload(ctx context.Context, reader io.Reader, name string, |
|
|
return nil, ErrInvalidFileType |
|
|
return nil, ErrInvalidFileType |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
panic("implement rest of me") |
|
|
|
|
|
|
|
|
reader2 := &concatReader{head: head, body: reader} |
|
|
|
|
|
|
|
|
|
|
|
path := generate.FileUploadID() + "." + fileType.Extension |
|
|
|
|
|
err = s.space.UploadFile(ctx, path, fileType.MIME.Value, reader2, size) |
|
|
|
|
|
if err != nil || !allowedMimeTypes[fileType.MIME.Value] { |
|
|
|
|
|
log.Println("File upload failed:", err) |
|
|
|
|
|
|
|
|
|
|
|
return nil, ErrCouldNotUploadFile |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
file := &models.File{ |
|
|
|
|
|
Size: size, |
|
|
|
|
|
Name: name, |
|
|
|
|
|
URL: s.space.URLFromPath(path), |
|
|
|
|
|
Time: time.Now(), |
|
|
|
|
|
Author: token.UserID, |
|
|
|
|
|
Kind: "upload", |
|
|
|
|
|
MimeType: fileType.MIME.Value, |
|
|
|
|
|
Public: public, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
file, err = s.files.Insert(ctx, *file) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return nil, err |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
s.changeService.Submit(ctx, models.ChangeModelFile, "upload", file.Public, changekeys.Listed(file), file) |
|
|
|
|
|
|
|
|
|
|
|
return file, nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (s *FileService) Edit(ctx context.Context, id string, name *string, public *bool) (*models.File, error) { |
|
|
func (s *FileService) Edit(ctx context.Context, id string, name *string, public *bool) (*models.File, error) { |
|
@ -122,7 +162,7 @@ func (r *concatReader) Read(p []byte) (n int, err error) { |
|
|
r.headPos = len(r.head) |
|
|
r.headPos = len(r.head) |
|
|
copy(p, remainder) |
|
|
copy(p, remainder) |
|
|
|
|
|
|
|
|
return len(p), nil |
|
|
|
|
|
|
|
|
return len(remainder), nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return r.body.Read(p) |
|
|
return r.body.Read(p) |
|
|