resource.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package store
  2. import (
  3. "context"
  4. "log/slog"
  5. "os"
  6. "path/filepath"
  7. "github.com/pkg/errors"
  8. "github.com/usememos/memos/internal/util"
  9. "github.com/usememos/memos/plugin/storage/s3"
  10. storepb "github.com/usememos/memos/proto/gen/store"
  11. )
  12. type Resource struct {
  13. // ID is the system generated unique identifier for the resource.
  14. ID int32
  15. // UID is the user defined unique identifier for the resource.
  16. UID string
  17. // Standard fields
  18. CreatorID int32
  19. CreatedTs int64
  20. UpdatedTs int64
  21. // Domain specific fields
  22. Filename string
  23. Blob []byte
  24. Type string
  25. Size int64
  26. StorageType storepb.ResourceStorageType
  27. Reference string
  28. Payload *storepb.ResourcePayload
  29. // The related memo ID.
  30. MemoID *int32
  31. }
  32. type FindResource struct {
  33. GetBlob bool
  34. ID *int32
  35. UID *string
  36. CreatorID *int32
  37. Filename *string
  38. FilenameSearch *string
  39. MemoID *int32
  40. HasRelatedMemo bool
  41. StorageType *storepb.ResourceStorageType
  42. Limit *int
  43. Offset *int
  44. }
  45. type UpdateResource struct {
  46. ID int32
  47. UID *string
  48. UpdatedTs *int64
  49. Filename *string
  50. MemoID *int32
  51. Reference *string
  52. Payload *storepb.ResourcePayload
  53. }
  54. type DeleteResource struct {
  55. ID int32
  56. MemoID *int32
  57. }
  58. func (s *Store) CreateResource(ctx context.Context, create *Resource) (*Resource, error) {
  59. if !util.UIDMatcher.MatchString(create.UID) {
  60. return nil, errors.New("invalid uid")
  61. }
  62. return s.driver.CreateResource(ctx, create)
  63. }
  64. func (s *Store) ListResources(ctx context.Context, find *FindResource) ([]*Resource, error) {
  65. return s.driver.ListResources(ctx, find)
  66. }
  67. func (s *Store) GetResource(ctx context.Context, find *FindResource) (*Resource, error) {
  68. resources, err := s.ListResources(ctx, find)
  69. if err != nil {
  70. return nil, err
  71. }
  72. if len(resources) == 0 {
  73. return nil, nil
  74. }
  75. return resources[0], nil
  76. }
  77. func (s *Store) UpdateResource(ctx context.Context, update *UpdateResource) error {
  78. if update.UID != nil && !util.UIDMatcher.MatchString(*update.UID) {
  79. return errors.New("invalid uid")
  80. }
  81. return s.driver.UpdateResource(ctx, update)
  82. }
  83. func (s *Store) DeleteResource(ctx context.Context, delete *DeleteResource) error {
  84. resource, err := s.GetResource(ctx, &FindResource{ID: &delete.ID})
  85. if err != nil {
  86. return errors.Wrap(err, "failed to get resource")
  87. }
  88. if resource == nil {
  89. return errors.Wrap(nil, "resource not found")
  90. }
  91. if resource.StorageType == storepb.ResourceStorageType_LOCAL {
  92. if err := func() error {
  93. p := filepath.FromSlash(resource.Reference)
  94. if !filepath.IsAbs(p) {
  95. p = filepath.Join(s.Profile.Data, p)
  96. }
  97. err := os.Remove(p)
  98. if err != nil {
  99. return errors.Wrap(err, "failed to delete local file")
  100. }
  101. return nil
  102. }(); err != nil {
  103. return errors.Wrap(err, "failed to delete local file")
  104. }
  105. } else if resource.StorageType == storepb.ResourceStorageType_S3 {
  106. if err := func() error {
  107. s3ObjectPayload := resource.Payload.GetS3Object()
  108. if s3ObjectPayload == nil {
  109. return errors.Errorf("No s3 object found")
  110. }
  111. workspaceStorageSetting, err := s.GetWorkspaceStorageSetting(ctx)
  112. if err != nil {
  113. return errors.Wrap(err, "failed to get workspace storage setting")
  114. }
  115. s3Config := s3ObjectPayload.S3Config
  116. if s3Config == nil {
  117. if workspaceStorageSetting.S3Config == nil {
  118. return errors.Errorf("S3 config is not found")
  119. }
  120. s3Config = workspaceStorageSetting.S3Config
  121. }
  122. s3Client, err := s3.NewClient(ctx, s3Config)
  123. if err != nil {
  124. return errors.Wrap(err, "Failed to create s3 client")
  125. }
  126. if err := s3Client.DeleteObject(ctx, s3ObjectPayload.Key); err != nil {
  127. return errors.Wrap(err, "Failed to delete s3 object")
  128. }
  129. return nil
  130. }(); err != nil {
  131. slog.Warn("Failed to delete s3 object", slog.Any("err", err))
  132. }
  133. }
  134. return s.driver.DeleteResource(ctx, delete)
  135. }