resource.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. MemoID *int32
  39. HasRelatedMemo bool
  40. StorageType *storepb.ResourceStorageType
  41. Limit *int
  42. Offset *int
  43. }
  44. type UpdateResource struct {
  45. ID int32
  46. UID *string
  47. UpdatedTs *int64
  48. Filename *string
  49. MemoID *int32
  50. Reference *string
  51. Payload *storepb.ResourcePayload
  52. }
  53. type DeleteResource struct {
  54. ID int32
  55. MemoID *int32
  56. }
  57. func (s *Store) CreateResource(ctx context.Context, create *Resource) (*Resource, error) {
  58. if !util.UIDMatcher.MatchString(create.UID) {
  59. return nil, errors.New("invalid uid")
  60. }
  61. return s.driver.CreateResource(ctx, create)
  62. }
  63. func (s *Store) ListResources(ctx context.Context, find *FindResource) ([]*Resource, error) {
  64. return s.driver.ListResources(ctx, find)
  65. }
  66. func (s *Store) GetResource(ctx context.Context, find *FindResource) (*Resource, error) {
  67. resources, err := s.ListResources(ctx, find)
  68. if err != nil {
  69. return nil, err
  70. }
  71. if len(resources) == 0 {
  72. return nil, nil
  73. }
  74. return resources[0], nil
  75. }
  76. func (s *Store) UpdateResource(ctx context.Context, update *UpdateResource) error {
  77. if update.UID != nil && !util.UIDMatcher.MatchString(*update.UID) {
  78. return errors.New("invalid uid")
  79. }
  80. return s.driver.UpdateResource(ctx, update)
  81. }
  82. func (s *Store) DeleteResource(ctx context.Context, delete *DeleteResource) error {
  83. resource, err := s.GetResource(ctx, &FindResource{ID: &delete.ID})
  84. if err != nil {
  85. return errors.Wrap(err, "failed to get resource")
  86. }
  87. if resource == nil {
  88. return errors.Wrap(nil, "resource not found")
  89. }
  90. if resource.StorageType == storepb.ResourceStorageType_LOCAL {
  91. if err := func() error {
  92. p := filepath.FromSlash(resource.Reference)
  93. if !filepath.IsAbs(p) {
  94. p = filepath.Join(s.Profile.Data, p)
  95. }
  96. err := os.Remove(p)
  97. if err != nil {
  98. return errors.Wrap(err, "failed to delete local file")
  99. }
  100. return nil
  101. }(); err != nil {
  102. return errors.Wrap(err, "failed to delete local file")
  103. }
  104. } else if resource.StorageType == storepb.ResourceStorageType_S3 {
  105. if err := func() error {
  106. s3ObjectPayload := resource.Payload.GetS3Object()
  107. if s3ObjectPayload == nil {
  108. return errors.Errorf("No s3 object found")
  109. }
  110. workspaceStorageSetting, err := s.GetWorkspaceStorageSetting(ctx)
  111. if err != nil {
  112. return errors.Wrap(err, "failed to get workspace storage setting")
  113. }
  114. s3Config := s3ObjectPayload.S3Config
  115. if s3Config == nil {
  116. if workspaceStorageSetting.S3Config == nil {
  117. return errors.Errorf("S3 config is not found")
  118. }
  119. s3Config = workspaceStorageSetting.S3Config
  120. }
  121. s3Client, err := s3.NewClient(ctx, s3Config)
  122. if err != nil {
  123. return errors.Wrap(err, "Failed to create s3 client")
  124. }
  125. if err := s3Client.DeleteObject(ctx, s3ObjectPayload.Key); err != nil {
  126. return errors.Wrap(err, "Failed to delete s3 object")
  127. }
  128. return nil
  129. }(); err != nil {
  130. slog.Warn("Failed to delete s3 object", err)
  131. }
  132. }
  133. return s.driver.DeleteResource(ctx, delete)
  134. }