chore: update object in s3

This commit is contained in:
Steven 2024-05-02 21:44:17 +08:00
parent 26545c855c
commit 775b79338d
5 changed files with 80 additions and 71 deletions

View File

@ -45,10 +45,10 @@ func NewClient(ctx context.Context, s3Config *storepb.WorkspaceStorageSetting_S3
}
// UploadObject uploads an object to S3.
func (client *Client) UploadObject(ctx context.Context, key string, fileType string, content io.Reader) (string, error) {
uploader := manager.NewUploader(client.Client)
func (c *Client) UploadObject(ctx context.Context, key string, fileType string, content io.Reader) (string, error) {
uploader := manager.NewUploader(c.Client)
putInput := s3.PutObjectInput{
Bucket: client.Bucket,
Bucket: c.Bucket,
Key: aws.String(key),
ContentType: aws.String(fileType),
Body: content,
@ -66,10 +66,10 @@ func (client *Client) UploadObject(ctx context.Context, key string, fileType str
}
// PresignGetObject presigns an object in S3.
func (client *Client) PresignGetObject(ctx context.Context, bucket, key string) (string, error) {
presignClient := s3.NewPresignClient(client.Client)
func (c *Client) PresignGetObject(ctx context.Context, key string) (string, error) {
presignClient := s3.NewPresignClient(c.Client)
presignResult, err := presignClient.PresignGetObject(context.TODO(), &s3.GetObjectInput{
Bucket: aws.String(bucket),
Bucket: aws.String(*c.Bucket),
Key: aws.String(key),
}, func(opts *s3.PresignOptions) {
opts.Expires = time.Duration(presignLifetimeSecs * int64(time.Second))
@ -79,3 +79,15 @@ func (client *Client) PresignGetObject(ctx context.Context, bucket, key string)
}
return presignResult.URL, nil
}
// DeleteObject deletes an object in S3.
func (c *Client) DeleteObject(ctx context.Context, key string) error {
_, err := c.Client.DeleteObject(ctx, &s3.DeleteObjectInput{
Bucket: c.Bucket,
Key: aws.String(key),
})
if err != nil {
return errors.Wrap(err, "failed to delete object")
}
return nil
}

View File

@ -8,6 +8,8 @@ import (
"time"
"github.com/pkg/errors"
v1pb "github.com/usememos/memos/proto/gen/api/v1"
)
var (
@ -22,44 +24,19 @@ type Memo struct {
UpdatedTs int64 `json:"updatedTs"`
// Domain specific fields
Content string `json:"content"`
Visibility string `json:"visibility"`
Pinned bool `json:"pinned"`
ResourceList []*Resource `json:"resourceList"`
RelationList []*MemoRelation `json:"relationList"`
}
type Resource struct {
ID int32 `json:"id"`
UID string `json:"uid"`
// Standard fields
CreatorID int32 `json:"creatorId"`
CreatedTs int64 `json:"createdTs"`
UpdatedTs int64 `json:"updatedTs"`
// Domain specific fields
Filename string `json:"filename"`
InternalPath string `json:"internalPath"`
ExternalLink string `json:"externalLink"`
Type string `json:"type"`
Size int64 `json:"size"`
}
type MemoRelation struct {
MemoID int32 `json:"memoId"`
RelatedMemoID int32 `json:"relatedMemoId"`
Type string `json:"type"`
Content string `json:"content"`
Visibility string `json:"visibility"`
Pinned bool `json:"pinned"`
}
// WebhookPayload is the payload of webhook request.
// nolint
type WebhookPayload struct {
URL string `json:"url"`
ActivityType string `json:"activityType"`
CreatorID int32 `json:"creatorId"`
CreatedTs int64 `json:"createdTs"`
Memo *Memo `json:"memo"`
URL string `json:"url"`
ActivityType string `json:"activityType"`
CreatorID int32 `json:"creatorId"`
CreatedTs int64 `json:"createdTs"`
Memo *v1pb.Memo `json:"memo"`
}
// WebhookResponse is the response of webhook request.

View File

@ -314,6 +314,17 @@ func (s *APIV1Service) DeleteMemo(ctx context.Context, request *v1pb.DeleteMemoR
return nil, status.Errorf(codes.Internal, "failed to delete memo")
}
// Delete related resources.
resources, err := s.Store.ListResources(ctx, &store.FindResource{MemoID: &id})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list resources")
}
for _, resource := range resources {
if err := s.Store.DeleteResource(ctx, &store.DeleteResource{ID: resource.ID}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to delete resource")
}
}
return &emptypb.Empty{}, nil
}
@ -841,34 +852,9 @@ func convertMemoToWebhookPayload(memo *v1pb.Memo) (*webhook.WebhookPayload, erro
if err != nil {
return nil, errors.Wrap(err, "invalid memo creator")
}
id, err := ExtractMemoIDFromName(memo.Name)
if err != nil {
return nil, errors.Wrap(err, "invalid memo name")
}
return &webhook.WebhookPayload{
CreatorID: creatorID,
CreatedTs: time.Now().Unix(),
Memo: &webhook.Memo{
ID: id,
CreatorID: creatorID,
CreatedTs: memo.CreateTime.Seconds,
UpdatedTs: memo.UpdateTime.Seconds,
Content: memo.Content,
Visibility: memo.Visibility.String(),
Pinned: memo.Pinned,
ResourceList: func() []*webhook.Resource {
resources := []*webhook.Resource{}
for _, resource := range memo.Resources {
resources = append(resources, &webhook.Resource{
UID: resource.Uid,
Filename: resource.Filename,
ExternalLink: resource.ExternalLink,
Type: resource.Type,
Size: resource.Size,
})
}
return resources
}(),
},
Memo: memo,
}, nil
}

View File

@ -365,7 +365,7 @@ func SaveResourceBlob(ctx context.Context, s *store.Store, create *store.Resourc
if err != nil {
return errors.Wrap(err, "Failed to upload via s3 client")
}
presignURL, err := s3Client.PresignGetObject(ctx, s3Config.Bucket, key)
presignURL, err := s3Client.PresignGetObject(ctx, key)
if err != nil {
return errors.Wrap(err, "Failed to presign via s3 client")
}

View File

@ -2,12 +2,14 @@ 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"
)
@ -100,13 +102,45 @@ func (s *Store) DeleteResource(ctx context.Context, delete *DeleteResource) erro
return errors.Wrap(nil, "resource not found")
}
// Delete the local file.
if resource.StorageType == storepb.ResourceStorageType_LOCAL {
p := filepath.FromSlash(resource.Reference)
if !filepath.IsAbs(p) {
p = filepath.Join(s.Profile.Data, p)
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 := workspaceStorageSetting.S3Config
if s3Config == nil {
return errors.Errorf("No actived external storage found")
}
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", err)
}
_ = os.Remove(p)
}
return s.driver.DeleteResource(ctx, delete)