mirror of
https://github.com/usememos/memos.git
synced 2025-02-16 03:12:13 +01:00
chore: update object in s3
This commit is contained in:
parent
26545c855c
commit
775b79338d
@ -45,10 +45,10 @@ func NewClient(ctx context.Context, s3Config *storepb.WorkspaceStorageSetting_S3
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UploadObject uploads an object to S3.
|
// UploadObject uploads an object to S3.
|
||||||
func (client *Client) UploadObject(ctx context.Context, key string, fileType string, content io.Reader) (string, error) {
|
func (c *Client) UploadObject(ctx context.Context, key string, fileType string, content io.Reader) (string, error) {
|
||||||
uploader := manager.NewUploader(client.Client)
|
uploader := manager.NewUploader(c.Client)
|
||||||
putInput := s3.PutObjectInput{
|
putInput := s3.PutObjectInput{
|
||||||
Bucket: client.Bucket,
|
Bucket: c.Bucket,
|
||||||
Key: aws.String(key),
|
Key: aws.String(key),
|
||||||
ContentType: aws.String(fileType),
|
ContentType: aws.String(fileType),
|
||||||
Body: content,
|
Body: content,
|
||||||
@ -66,10 +66,10 @@ func (client *Client) UploadObject(ctx context.Context, key string, fileType str
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PresignGetObject presigns an object in S3.
|
// PresignGetObject presigns an object in S3.
|
||||||
func (client *Client) PresignGetObject(ctx context.Context, bucket, key string) (string, error) {
|
func (c *Client) PresignGetObject(ctx context.Context, key string) (string, error) {
|
||||||
presignClient := s3.NewPresignClient(client.Client)
|
presignClient := s3.NewPresignClient(c.Client)
|
||||||
presignResult, err := presignClient.PresignGetObject(context.TODO(), &s3.GetObjectInput{
|
presignResult, err := presignClient.PresignGetObject(context.TODO(), &s3.GetObjectInput{
|
||||||
Bucket: aws.String(bucket),
|
Bucket: aws.String(*c.Bucket),
|
||||||
Key: aws.String(key),
|
Key: aws.String(key),
|
||||||
}, func(opts *s3.PresignOptions) {
|
}, func(opts *s3.PresignOptions) {
|
||||||
opts.Expires = time.Duration(presignLifetimeSecs * int64(time.Second))
|
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
|
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
|
||||||
|
}
|
||||||
|
@ -8,6 +8,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
v1pb "github.com/usememos/memos/proto/gen/api/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -22,44 +24,19 @@ type Memo struct {
|
|||||||
UpdatedTs int64 `json:"updatedTs"`
|
UpdatedTs int64 `json:"updatedTs"`
|
||||||
|
|
||||||
// Domain specific fields
|
// Domain specific fields
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
Visibility string `json:"visibility"`
|
Visibility string `json:"visibility"`
|
||||||
Pinned bool `json:"pinned"`
|
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"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebhookPayload is the payload of webhook request.
|
// WebhookPayload is the payload of webhook request.
|
||||||
// nolint
|
// nolint
|
||||||
type WebhookPayload struct {
|
type WebhookPayload struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
ActivityType string `json:"activityType"`
|
ActivityType string `json:"activityType"`
|
||||||
CreatorID int32 `json:"creatorId"`
|
CreatorID int32 `json:"creatorId"`
|
||||||
CreatedTs int64 `json:"createdTs"`
|
CreatedTs int64 `json:"createdTs"`
|
||||||
Memo *Memo `json:"memo"`
|
Memo *v1pb.Memo `json:"memo"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebhookResponse is the response of webhook request.
|
// WebhookResponse is the response of webhook request.
|
||||||
|
@ -314,6 +314,17 @@ func (s *APIV1Service) DeleteMemo(ctx context.Context, request *v1pb.DeleteMemoR
|
|||||||
return nil, status.Errorf(codes.Internal, "failed to delete memo")
|
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
|
return &emptypb.Empty{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -841,34 +852,9 @@ func convertMemoToWebhookPayload(memo *v1pb.Memo) (*webhook.WebhookPayload, erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "invalid memo creator")
|
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{
|
return &webhook.WebhookPayload{
|
||||||
CreatorID: creatorID,
|
CreatorID: creatorID,
|
||||||
CreatedTs: time.Now().Unix(),
|
CreatedTs: time.Now().Unix(),
|
||||||
Memo: &webhook.Memo{
|
Memo: 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
|
|
||||||
}(),
|
|
||||||
},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -365,7 +365,7 @@ func SaveResourceBlob(ctx context.Context, s *store.Store, create *store.Resourc
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed to upload via s3 client")
|
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 {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Failed to presign via s3 client")
|
return errors.Wrap(err, "Failed to presign via s3 client")
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,14 @@ package store
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/usememos/memos/internal/util"
|
"github.com/usememos/memos/internal/util"
|
||||||
|
"github.com/usememos/memos/plugin/storage/s3"
|
||||||
storepb "github.com/usememos/memos/proto/gen/store"
|
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")
|
return errors.Wrap(nil, "resource not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the local file.
|
|
||||||
if resource.StorageType == storepb.ResourceStorageType_LOCAL {
|
if resource.StorageType == storepb.ResourceStorageType_LOCAL {
|
||||||
p := filepath.FromSlash(resource.Reference)
|
if err := func() error {
|
||||||
if !filepath.IsAbs(p) {
|
p := filepath.FromSlash(resource.Reference)
|
||||||
p = filepath.Join(s.Profile.Data, p)
|
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)
|
return s.driver.DeleteResource(ctx, delete)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user