mirror of
https://github.com/usememos/memos.git
synced 2024-11-15 11:17:58 +08:00
155 lines
3.8 KiB
Go
155 lines
3.8 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/usememos/memos/internal/util"
|
|
"github.com/usememos/memos/plugin/storage/s3"
|
|
storepb "github.com/usememos/memos/proto/gen/store"
|
|
)
|
|
|
|
type Resource struct {
|
|
// ID is the system generated unique identifier for the resource.
|
|
ID int32
|
|
// UID is the user defined unique identifier for the resource.
|
|
UID string
|
|
|
|
// Standard fields
|
|
CreatorID int32
|
|
CreatedTs int64
|
|
UpdatedTs int64
|
|
|
|
// Domain specific fields
|
|
Filename string
|
|
Blob []byte
|
|
Type string
|
|
Size int64
|
|
StorageType storepb.ResourceStorageType
|
|
Reference string
|
|
Payload *storepb.ResourcePayload
|
|
|
|
// The related memo ID.
|
|
MemoID *int32
|
|
}
|
|
|
|
type FindResource struct {
|
|
GetBlob bool
|
|
ID *int32
|
|
UID *string
|
|
CreatorID *int32
|
|
Filename *string
|
|
FilenameSearch *string
|
|
MemoID *int32
|
|
HasRelatedMemo bool
|
|
StorageType *storepb.ResourceStorageType
|
|
Limit *int
|
|
Offset *int
|
|
}
|
|
|
|
type UpdateResource struct {
|
|
ID int32
|
|
UID *string
|
|
UpdatedTs *int64
|
|
Filename *string
|
|
MemoID *int32
|
|
Reference *string
|
|
Payload *storepb.ResourcePayload
|
|
}
|
|
|
|
type DeleteResource struct {
|
|
ID int32
|
|
MemoID *int32
|
|
}
|
|
|
|
func (s *Store) CreateResource(ctx context.Context, create *Resource) (*Resource, error) {
|
|
if !util.UIDMatcher.MatchString(create.UID) {
|
|
return nil, errors.New("invalid uid")
|
|
}
|
|
return s.driver.CreateResource(ctx, create)
|
|
}
|
|
|
|
func (s *Store) ListResources(ctx context.Context, find *FindResource) ([]*Resource, error) {
|
|
return s.driver.ListResources(ctx, find)
|
|
}
|
|
|
|
func (s *Store) GetResource(ctx context.Context, find *FindResource) (*Resource, error) {
|
|
resources, err := s.ListResources(ctx, find)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(resources) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
return resources[0], nil
|
|
}
|
|
|
|
func (s *Store) UpdateResource(ctx context.Context, update *UpdateResource) error {
|
|
if update.UID != nil && !util.UIDMatcher.MatchString(*update.UID) {
|
|
return errors.New("invalid uid")
|
|
}
|
|
return s.driver.UpdateResource(ctx, update)
|
|
}
|
|
|
|
func (s *Store) DeleteResource(ctx context.Context, delete *DeleteResource) error {
|
|
resource, err := s.GetResource(ctx, &FindResource{ID: &delete.ID})
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to get resource")
|
|
}
|
|
if resource == nil {
|
|
return errors.Wrap(nil, "resource not found")
|
|
}
|
|
|
|
if resource.StorageType == storepb.ResourceStorageType_LOCAL {
|
|
if err := func() error {
|
|
p := filepath.FromSlash(resource.Reference)
|
|
if !filepath.IsAbs(p) {
|
|
p = filepath.Join(s.Profile.Data, p)
|
|
}
|
|
err := os.Remove(p)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to delete local file")
|
|
}
|
|
return nil
|
|
}(); err != nil {
|
|
return errors.Wrap(err, "failed to delete local file")
|
|
}
|
|
} else if resource.StorageType == storepb.ResourceStorageType_S3 {
|
|
if err := func() error {
|
|
s3ObjectPayload := resource.Payload.GetS3Object()
|
|
if s3ObjectPayload == nil {
|
|
return errors.Errorf("No s3 object found")
|
|
}
|
|
workspaceStorageSetting, err := s.GetWorkspaceStorageSetting(ctx)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to get workspace storage setting")
|
|
}
|
|
s3Config := s3ObjectPayload.S3Config
|
|
if s3Config == nil {
|
|
if workspaceStorageSetting.S3Config == nil {
|
|
return errors.Errorf("S3 config is not found")
|
|
}
|
|
s3Config = workspaceStorageSetting.S3Config
|
|
}
|
|
|
|
s3Client, err := s3.NewClient(ctx, s3Config)
|
|
if err != nil {
|
|
return errors.Wrap(err, "Failed to create s3 client")
|
|
}
|
|
if err := s3Client.DeleteObject(ctx, s3ObjectPayload.Key); err != nil {
|
|
return errors.Wrap(err, "Failed to delete s3 object")
|
|
}
|
|
return nil
|
|
}(); err != nil {
|
|
slog.Warn("Failed to delete s3 object", slog.Any("err", err))
|
|
}
|
|
}
|
|
|
|
return s.driver.DeleteResource(ctx, delete)
|
|
}
|