diff --git a/api/v1/memo.go b/api/v1/memo.go index f72a8b27d..7534dbb36 100644 --- a/api/v1/memo.go +++ b/api/v1/memo.go @@ -319,9 +319,9 @@ func (s *APIV1Service) CreateMemo(c echo.Context) error { } for _, resourceID := range createMemoRequest.ResourceIDList { - if _, err := s.Store.UpsertMemoResource(ctx, &store.UpsertMemoResource{ - MemoID: memo.ID, - ResourceID: resourceID, + if _, err := s.Store.UpdateResource(ctx, &store.UpdateResource{ + ID: resourceID, + MemoID: &memo.ID, }); err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert memo resource").SetInternal(err) } @@ -694,19 +694,18 @@ func (s *APIV1Service) UpdateMemo(c echo.Context) error { if patchMemoRequest.ResourceIDList != nil { addedResourceIDList, removedResourceIDList := getIDListDiff(memo.ResourceIDList, patchMemoRequest.ResourceIDList) for _, resourceID := range addedResourceIDList { - if _, err := s.Store.UpsertMemoResource(ctx, &store.UpsertMemoResource{ - MemoID: memo.ID, - ResourceID: resourceID, + if _, err := s.Store.UpdateResource(ctx, &store.UpdateResource{ + ID: resourceID, + MemoID: &memo.ID, }); err != nil { return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert memo resource").SetInternal(err) } } for _, resourceID := range removedResourceIDList { - if err := s.Store.DeleteMemoResource(ctx, &store.DeleteMemoResource{ - MemoID: &memo.ID, - ResourceID: &resourceID, + if err := s.Store.DeleteResource(ctx, &store.DeleteResource{ + ID: resourceID, }); err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete memo resource").SetInternal(err) + return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete resource").SetInternal(err) } } } diff --git a/api/v1/memo_resource.go b/api/v1/memo_resource.go deleted file mode 100644 index fddc46882..000000000 --- a/api/v1/memo_resource.go +++ /dev/null @@ -1,179 +0,0 @@ -package v1 - -import ( - "encoding/json" - "fmt" - "net/http" - "time" - - "github.com/labstack/echo/v4" - - "github.com/usememos/memos/common/util" - "github.com/usememos/memos/store" -) - -type MemoResource struct { - MemoID int32 `json:"memoId"` - ResourceID int32 `json:"resourceId"` - CreatedTs int64 `json:"createdTs"` - UpdatedTs int64 `json:"updatedTs"` -} - -type UpsertMemoResourceRequest struct { - ResourceID int32 `json:"resourceId"` - UpdatedTs *int64 `json:"updatedTs"` -} - -type MemoResourceFind struct { - MemoID *int32 - ResourceID *int32 -} - -type MemoResourceDelete struct { - MemoID *int32 - ResourceID *int32 -} - -func (s *APIV1Service) registerMemoResourceRoutes(g *echo.Group) { - g.GET("/memo/:memoId/resource", s.GetMemoResourceList) - g.POST("/memo/:memoId/resource", s.BindMemoResource) - g.DELETE("/memo/:memoId/resource/:resourceId", s.UnbindMemoResource) -} - -// GetMemoResourceList godoc -// -// @Summary Get resource list of a memo -// @Tags memo-resource -// @Accept json -// @Produce json -// @Param memoId path int true "ID of memo to fetch resource list from" -// @Success 200 {object} []Resource "Memo resource list" -// @Failure 400 {object} nil "ID is not a number: %s" -// @Failure 500 {object} nil "Failed to fetch resource list" -// @Router /api/v1/memo/{memoId}/resource [GET] -func (s *APIV1Service) GetMemoResourceList(c echo.Context) error { - ctx := c.Request().Context() - memoID, err := util.ConvertStringToInt32(c.Param("memoId")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("memoId"))).SetInternal(err) - } - - list, err := s.Store.ListResources(ctx, &store.FindResource{ - MemoID: &memoID, - }) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch resource list").SetInternal(err) - } - resourceList := []*Resource{} - for _, resource := range list { - resourceList = append(resourceList, convertResourceFromStore(resource)) - } - return c.JSON(http.StatusOK, resourceList) -} - -// BindMemoResource godoc -// -// @Summary Bind resource to memo -// @Tags memo-resource -// @Accept json -// @Produce json -// @Param memoId path int true "ID of memo to bind resource to" -// @Param body body UpsertMemoResourceRequest true "Memo resource request object" -// @Success 200 {boolean} true "Memo resource binded" -// @Failure 400 {object} nil "ID is not a number: %s | Malformatted post memo resource request | Resource not found" -// @Failure 401 {object} nil "Missing user in session | Unauthorized to bind this resource" -// @Failure 500 {object} nil "Failed to fetch resource | Failed to upsert memo resource" -// @Router /api/v1/memo/{memoId}/resource [POST] -// -// NOTES: -// - Passing 0 to updatedTs will set it to 0 in the database, which is probably unwanted. -func (s *APIV1Service) BindMemoResource(c echo.Context) error { - ctx := c.Request().Context() - memoID, err := util.ConvertStringToInt32(c.Param("memoId")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("memoId"))).SetInternal(err) - } - - userID, ok := c.Get(userIDContextKey).(int32) - if !ok { - return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session") - } - request := &UpsertMemoResourceRequest{} - if err := json.NewDecoder(c.Request().Body).Decode(request); err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post memo resource request").SetInternal(err) - } - resource, err := s.Store.GetResource(ctx, &store.FindResource{ - ID: &request.ResourceID, - }) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch resource").SetInternal(err) - } - if resource == nil { - return echo.NewHTTPError(http.StatusBadRequest, "Resource not found").SetInternal(err) - } else if resource.CreatorID != userID { - return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized to bind this resource").SetInternal(err) - } - - upsert := &store.UpsertMemoResource{ - MemoID: memoID, - ResourceID: request.ResourceID, - CreatedTs: time.Now().Unix(), - } - if request.UpdatedTs != nil { - upsert.UpdatedTs = request.UpdatedTs - } - if _, err := s.Store.UpsertMemoResource(ctx, upsert); err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert memo resource").SetInternal(err) - } - return c.JSON(http.StatusOK, true) -} - -// UnbindMemoResource godoc -// -// @Summary Unbind resource from memo -// @Tags memo-resource -// @Accept json -// @Produce json -// @Param memoId path int true "ID of memo to unbind resource from" -// @Param resourceId path int true "ID of resource to unbind from memo" -// @Success 200 {boolean} true "Memo resource unbinded. *200 is returned even if the reference doesn't exists " -// @Failure 400 {object} nil "Memo ID is not a number: %s | Resource ID is not a number: %s | Memo not found" -// @Failure 401 {object} nil "Missing user in session | Unauthorized" -// @Failure 500 {object} nil "Failed to find memo | Failed to fetch resource list" -// @Router /api/v1/memo/{memoId}/resource/{resourceId} [DELETE] -func (s *APIV1Service) UnbindMemoResource(c echo.Context) error { - ctx := c.Request().Context() - userID, ok := c.Get(userIDContextKey).(int32) - if !ok { - return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session") - } - memoID, err := util.ConvertStringToInt32(c.Param("memoId")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Memo ID is not a number: %s", c.Param("memoId"))).SetInternal(err) - } - resourceID, err := util.ConvertStringToInt32(c.Param("resourceId")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Resource ID is not a number: %s", c.Param("resourceId"))).SetInternal(err) - } - - memo, err := s.Store.GetMemo(ctx, &store.FindMemo{ - ID: &memoID, - }) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find memo").SetInternal(err) - } - if memo == nil { - return echo.NewHTTPError(http.StatusBadRequest, "Memo not found") - } - if memo.CreatorID != userID { - return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized") - } - - if err := s.Store.DeleteMemoResource(ctx, &store.DeleteMemoResource{ - MemoID: &memoID, - ResourceID: &resourceID, - }); err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to fetch resource list").SetInternal(err) - } - return c.JSON(http.StatusOK, true) -} diff --git a/api/v1/resource.go b/api/v1/resource.go index 63f7e610a..a297cfa60 100644 --- a/api/v1/resource.go +++ b/api/v1/resource.go @@ -384,17 +384,6 @@ func (s *APIV1Service) streamResource(c echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("resourceId"))).SetInternal(err) } - resourceVisibility, err := checkResourceVisibility(ctx, s.Store, resourceID) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Failed to get resource visibility").SetInternal(err) - } - - // Protected resource require a logined user - userID, ok := c.Get(userIDContextKey).(int32) - if resourceVisibility == store.Protected && (!ok || userID <= 0) { - return echo.NewHTTPError(http.StatusUnauthorized, "Resource visibility not match").SetInternal(err) - } - resource, err := s.Store.GetResource(ctx, &store.FindResource{ ID: &resourceID, GetBlob: true, @@ -405,10 +394,20 @@ func (s *APIV1Service) streamResource(c echo.Context) error { if resource == nil { return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("Resource not found: %d", resourceID)) } - - // Private resource require logined user is the creator - if resourceVisibility == store.Private && (!ok || userID != resource.CreatorID) { - return echo.NewHTTPError(http.StatusUnauthorized, "Resource visibility not match").SetInternal(err) + // Check the related memo visibility. + if resource.MemoID != nil { + memo, err := s.Store.GetMemo(ctx, &store.FindMemo{ + ID: resource.MemoID, + }) + if err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to find memo by ID: %v", resource.MemoID)).SetInternal(err) + } + if memo != nil && memo.Visibility != store.Public { + userID, ok := c.Get(userIDContextKey).(int32) + if !ok || (memo.Visibility == store.Private && userID != resource.CreatorID) { + return echo.NewHTTPError(http.StatusUnauthorized, "Resource visibility not match") + } + } } blob := resource.Blob @@ -542,47 +541,6 @@ func getOrGenerateThumbnailImage(srcBlob []byte, dstPath string) ([]byte, error) return dstBlob, nil } -func checkResourceVisibility(ctx context.Context, s *store.Store, resourceID int32) (store.Visibility, error) { - memoResources, err := s.ListMemoResources(ctx, &store.FindMemoResource{ - ResourceID: &resourceID, - }) - if err != nil { - return store.Private, err - } - - // If resource is belongs to no memo, it'll always PRIVATE. - if len(memoResources) == 0 { - return store.Private, nil - } - - memoIDs := make([]int32, 0, len(memoResources)) - for _, memoResource := range memoResources { - memoIDs = append(memoIDs, memoResource.MemoID) - } - visibilityList, err := s.FindMemosVisibilityList(ctx, memoIDs) - if err != nil { - return store.Private, err - } - - var isProtected bool - for _, visibility := range visibilityList { - // If any memo is PUBLIC, resource should be PUBLIC too. - if visibility == store.Public { - return store.Public, nil - } - - if visibility == store.Protected { - isProtected = true - } - } - - if isProtected { - return store.Protected, nil - } - - return store.Private, nil -} - func convertResourceFromStore(resource *store.Resource) *Resource { return &Resource{ ID: resource.ID, diff --git a/api/v1/v1.go b/api/v1/v1.go index 862298cd4..1bb5fd4bc 100644 --- a/api/v1/v1.go +++ b/api/v1/v1.go @@ -58,7 +58,6 @@ func (s *APIV1Service) Register(rootGroup *echo.Group) { s.registerResourceRoutes(apiV1Group) s.registerMemoRoutes(apiV1Group) s.registerMemoOrganizerRoutes(apiV1Group) - s.registerMemoResourceRoutes(apiV1Group) s.registerMemoRelationRoutes(apiV1Group) // Register public routes. diff --git a/api/v2/resource_service.go b/api/v2/resource_service.go index 0f75cbe73..58d485d2f 100644 --- a/api/v2/resource_service.go +++ b/api/v2/resource_service.go @@ -47,12 +47,12 @@ func (s *ResourceService) ListResources(ctx context.Context, _ *apiv2pb.ListReso func convertResourceFromStore(resource *store.Resource) *apiv2pb.Resource { return &apiv2pb.Resource{ - Id: resource.ID, - CreatedTs: timestamppb.New(time.Unix(resource.CreatedTs, 0)), - Filename: resource.Filename, - ExternalLink: resource.ExternalLink, - Type: resource.Type, - Size: resource.Size, - RelatedMemoId: resource.RelatedMemoID, + Id: resource.ID, + CreatedTs: timestamppb.New(time.Unix(resource.CreatedTs, 0)), + Filename: resource.Filename, + ExternalLink: resource.ExternalLink, + Type: resource.Type, + Size: resource.Size, + MemoId: resource.MemoID, } } diff --git a/proto/api/v2/resource_service.proto b/proto/api/v2/resource_service.proto index 43786551f..cd45b9bff 100644 --- a/proto/api/v2/resource_service.proto +++ b/proto/api/v2/resource_service.proto @@ -20,7 +20,7 @@ message Resource { string external_link = 4; string type = 5; int64 size = 6; - optional int32 related_memo_id = 7; + optional int32 memo_id = 7; } message ListResourcesRequest {} diff --git a/proto/gen/api/v2/README.md b/proto/gen/api/v2/README.md index 5eb6f0ca5..a74981403 100644 --- a/proto/gen/api/v2/README.md +++ b/proto/gen/api/v2/README.md @@ -262,7 +262,7 @@ | external_link | [string](#string) | | | | type | [string](#string) | | | | size | [int64](#int64) | | | -| related_memo_id | [int32](#int32) | optional | | +| memo_id | [int32](#int32) | optional | | diff --git a/proto/gen/api/v2/resource_service.pb.go b/proto/gen/api/v2/resource_service.pb.go index 08c6058de..fe998bbbb 100644 --- a/proto/gen/api/v2/resource_service.pb.go +++ b/proto/gen/api/v2/resource_service.pb.go @@ -27,13 +27,13 @@ type Resource struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - CreatedTs *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=created_ts,json=createdTs,proto3" json:"created_ts,omitempty"` - Filename string `protobuf:"bytes,3,opt,name=filename,proto3" json:"filename,omitempty"` - ExternalLink string `protobuf:"bytes,4,opt,name=external_link,json=externalLink,proto3" json:"external_link,omitempty"` - Type string `protobuf:"bytes,5,opt,name=type,proto3" json:"type,omitempty"` - Size int64 `protobuf:"varint,6,opt,name=size,proto3" json:"size,omitempty"` - RelatedMemoId *int32 `protobuf:"varint,7,opt,name=related_memo_id,json=relatedMemoId,proto3,oneof" json:"related_memo_id,omitempty"` + Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + CreatedTs *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=created_ts,json=createdTs,proto3" json:"created_ts,omitempty"` + Filename string `protobuf:"bytes,3,opt,name=filename,proto3" json:"filename,omitempty"` + ExternalLink string `protobuf:"bytes,4,opt,name=external_link,json=externalLink,proto3" json:"external_link,omitempty"` + Type string `protobuf:"bytes,5,opt,name=type,proto3" json:"type,omitempty"` + Size int64 `protobuf:"varint,6,opt,name=size,proto3" json:"size,omitempty"` + MemoId *int32 `protobuf:"varint,7,opt,name=memo_id,json=memoId,proto3,oneof" json:"memo_id,omitempty"` } func (x *Resource) Reset() { @@ -110,9 +110,9 @@ func (x *Resource) GetSize() int64 { return 0 } -func (x *Resource) GetRelatedMemoId() int32 { - if x != nil && x.RelatedMemoId != nil { - return *x.RelatedMemoId +func (x *Resource) GetMemoId() int32 { + if x != nil && x.MemoId != nil { + return *x.MemoId } return 0 } @@ -211,7 +211,7 @@ var file_api_v2_resource_service_proto_rawDesc = []byte{ 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xff, 0x01, 0x0a, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe8, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, @@ -223,38 +223,36 @@ var file_api_v2_resource_service_proto_rawDesc = []byte{ 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x2b, 0x0a, - 0x0f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x5f, 0x69, 0x64, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x65, - 0x64, 0x4d, 0x65, 0x6d, 0x6f, 0x49, 0x64, 0x88, 0x01, 0x01, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x72, - 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x5f, 0x69, 0x64, 0x22, 0x16, - 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4d, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x34, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, - 0x32, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x32, 0x86, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x73, 0x0a, 0x0d, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x6d, 0x65, 0x6d, - 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, - 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x42, 0xac, - 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x76, 0x32, 0x42, 0x14, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, - 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x32, 0xa2, 0x02, 0x03, - 0x4d, 0x41, 0x58, 0xaa, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, - 0x56, 0x32, 0xca, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, - 0x32, 0xe2, 0x02, 0x18, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, - 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, - 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1c, 0x0a, + 0x07, 0x6d, 0x65, 0x6d, 0x6f, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, + 0x52, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x49, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, + 0x6d, 0x65, 0x6d, 0x6f, 0x5f, 0x69, 0x64, 0x22, 0x16, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, + 0x4d, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x65, + 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x32, 0x86, + 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x73, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x42, 0xac, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, + 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x32, 0x42, 0x14, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, + 0x3b, 0x61, 0x70, 0x69, 0x76, 0x32, 0xa2, 0x02, 0x03, 0x4d, 0x41, 0x58, 0xaa, 0x02, 0x0c, 0x4d, + 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x32, 0xca, 0x02, 0x0c, 0x4d, 0x65, + 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0xe2, 0x02, 0x18, 0x4d, 0x65, 0x6d, + 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x32, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x41, + 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/server/integration/telegram.go b/server/integration/telegram.go index 4ffa90f68..3eae87baa 100644 --- a/server/integration/telegram.go +++ b/server/integration/telegram.go @@ -92,6 +92,7 @@ func (t *TelegramHandler) MessageHandle(ctx context.Context, bot *telegram.Bot, Filename: attachment.FileName, Type: attachment.GetMimeType(), Size: attachment.FileSize, + MemoID: &memoMessage.ID, } err := apiv1.SaveResourceBlob(ctx, t.store, &create, bytes.NewReader(attachment.Data)) @@ -100,20 +101,11 @@ func (t *TelegramHandler) MessageHandle(ctx context.Context, bot *telegram.Bot, return err } - resource, err := t.store.CreateResource(ctx, &create) + _, err = t.store.CreateResource(ctx, &create) if err != nil { _, err := bot.EditMessage(ctx, message.Chat.ID, reply.MessageID, fmt.Sprintf("Failed to CreateResource: %s", err), nil) return err } - - _, err = t.store.UpsertMemoResource(ctx, &store.UpsertMemoResource{ - MemoID: memoMessage.ID, - ResourceID: resource.ID, - }) - if err != nil { - _, err := bot.EditMessage(ctx, message.Chat.ID, reply.MessageID, fmt.Sprintf("Failed to UpsertMemoResource: %s", err), nil) - return err - } } keyboard := generateKeyboardForMemoID(memoMessage.ID) diff --git a/store/db/migration/dev/LATEST__SCHEMA.sql b/store/db/migration/dev/LATEST__SCHEMA.sql index 225eef376..a3a909f19 100644 --- a/store/db/migration/dev/LATEST__SCHEMA.sql +++ b/store/db/migration/dev/LATEST__SCHEMA.sql @@ -81,19 +81,13 @@ CREATE TABLE resource ( external_link TEXT NOT NULL DEFAULT '', type TEXT NOT NULL DEFAULT '', size INTEGER NOT NULL DEFAULT 0, - internal_path TEXT NOT NULL DEFAULT '' + internal_path TEXT NOT NULL DEFAULT '', + memo_id INTEGER ); CREATE INDEX idx_resource_creator_id ON resource (creator_id); --- memo_resource -CREATE TABLE memo_resource ( - memo_id INTEGER NOT NULL, - resource_id INTEGER NOT NULL, - created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')), - updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')), - UNIQUE(memo_id, resource_id) -); +CREATE INDEX idx_resource_memo_id ON resource (memo_id); -- tag CREATE TABLE tag ( diff --git a/store/db/migration/prod/0.16/00__add_memo_id_to_resource.sql b/store/db/migration/prod/0.16/00__add_memo_id_to_resource.sql new file mode 100644 index 000000000..a4d780bca --- /dev/null +++ b/store/db/migration/prod/0.16/00__add_memo_id_to_resource.sql @@ -0,0 +1,13 @@ +ALTER TABLE resource ADD COLUMN memo_id INTEGER; + +UPDATE resource +SET memo_id = ( + SELECT memo_id + FROM memo_resource + WHERE resource.id = memo_resource.resource_id + LIMIT 1 +); + +DROP TABLE memo_resource; + +CREATE INDEX idx_resource_memo_id ON resource (memo_id); diff --git a/store/memo.go b/store/memo.go index 42bc4129d..ad0ae2555 100644 --- a/store/memo.go +++ b/store/memo.go @@ -175,7 +175,7 @@ func (s *Store) ListMemos(ctx context.Context, find *FindMemo) ([]*Memo, error) memo.content AS content, memo.visibility AS visibility, CASE WHEN memo_organizer.pinned = 1 THEN 1 ELSE 0 END AS pinned, - GROUP_CONCAT(memo_resource.resource_id) AS resource_id_list, + GROUP_CONCAT(resource.id) AS resource_id_list, ( SELECT GROUP_CONCAT(related_memo_id || ':' || type) @@ -191,7 +191,7 @@ func (s *Store) ListMemos(ctx context.Context, find *FindMemo) ([]*Memo, error) LEFT JOIN memo_organizer ON memo.id = memo_organizer.memo_id LEFT JOIN - memo_resource ON memo.id = memo_resource.memo_id + resource ON memo.id = resource.memo_id WHERE ` + strings.Join(where, " AND ") + ` GROUP BY memo.id ORDER BY ` + strings.Join(orders, ", ") + ` diff --git a/store/memo_resource.go b/store/memo_resource.go deleted file mode 100644 index 6bde5ee63..000000000 --- a/store/memo_resource.go +++ /dev/null @@ -1,168 +0,0 @@ -package store - -import ( - "context" - "database/sql" - "strings" -) - -type MemoResource struct { - MemoID int32 - ResourceID int32 - CreatedTs int64 - UpdatedTs int64 -} - -type UpsertMemoResource struct { - MemoID int32 - ResourceID int32 - CreatedTs int64 - UpdatedTs *int64 -} - -type FindMemoResource struct { - MemoID *int32 - ResourceID *int32 -} - -type DeleteMemoResource struct { - MemoID *int32 - ResourceID *int32 -} - -func (s *Store) UpsertMemoResource(ctx context.Context, upsert *UpsertMemoResource) (*MemoResource, error) { - set := []string{"memo_id", "resource_id"} - args := []any{upsert.MemoID, upsert.ResourceID} - placeholder := []string{"?", "?"} - - if v := upsert.UpdatedTs; v != nil { - set, args, placeholder = append(set, "updated_ts"), append(args, v), append(placeholder, "?") - } - - query := ` - INSERT INTO memo_resource ( - ` + strings.Join(set, ", ") + ` - ) - VALUES (` + strings.Join(placeholder, ",") + `) - ON CONFLICT(memo_id, resource_id) DO UPDATE - SET - updated_ts = EXCLUDED.updated_ts - RETURNING memo_id, resource_id, created_ts, updated_ts - ` - memoResource := &MemoResource{} - if err := s.db.QueryRowContext(ctx, query, args...).Scan( - &memoResource.MemoID, - &memoResource.ResourceID, - &memoResource.CreatedTs, - &memoResource.UpdatedTs, - ); err != nil { - return nil, err - } - - return memoResource, nil -} - -func (s *Store) ListMemoResources(ctx context.Context, find *FindMemoResource) ([]*MemoResource, error) { - where, args := []string{"1 = 1"}, []any{} - - if v := find.MemoID; v != nil { - where, args = append(where, "memo_id = ?"), append(args, *v) - } - if v := find.ResourceID; v != nil { - where, args = append(where, "resource_id = ?"), append(args, *v) - } - - query := ` - SELECT - memo_id, - resource_id, - created_ts, - updated_ts - FROM memo_resource - WHERE ` + strings.Join(where, " AND ") + ` - ORDER BY updated_ts DESC - ` - rows, err := s.db.QueryContext(ctx, query, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - list := make([]*MemoResource, 0) - for rows.Next() { - var memoResource MemoResource - if err := rows.Scan( - &memoResource.MemoID, - &memoResource.ResourceID, - &memoResource.CreatedTs, - &memoResource.UpdatedTs, - ); err != nil { - return nil, err - } - - list = append(list, &memoResource) - } - - if err := rows.Err(); err != nil { - return nil, err - } - - return list, nil -} - -func (s *Store) GetMemoResource(ctx context.Context, find *FindMemoResource) (*MemoResource, error) { - list, err := s.ListMemoResources(ctx, find) - if err != nil { - return nil, err - } - if len(list) == 0 { - return nil, nil - } - - memoResource := list[0] - return memoResource, nil -} - -func (s *Store) DeleteMemoResource(ctx context.Context, delete *DeleteMemoResource) error { - where, args := []string{}, []any{} - if v := delete.MemoID; v != nil { - where, args = append(where, "memo_id = ?"), append(args, *v) - } - if v := delete.ResourceID; v != nil { - where, args = append(where, "resource_id = ?"), append(args, *v) - } - stmt := `DELETE FROM memo_resource WHERE ` + strings.Join(where, " AND ") - result, err := s.db.ExecContext(ctx, stmt, args...) - if err != nil { - return err - } - if _, err = result.RowsAffected(); err != nil { - return err - } - return nil -} - -func vacuumMemoResource(ctx context.Context, tx *sql.Tx) error { - stmt := ` - DELETE FROM - memo_resource - WHERE - memo_id NOT IN ( - SELECT - id - FROM - memo - ) - OR resource_id NOT IN ( - SELECT - id - FROM - resource - )` - _, err := tx.ExecContext(ctx, stmt) - if err != nil { - return err - } - - return nil -} diff --git a/store/resource.go b/store/resource.go index a30228528..8e66df93f 100644 --- a/store/resource.go +++ b/store/resource.go @@ -20,9 +20,7 @@ type Resource struct { ExternalLink string Type string Size int64 - - // Related fields - RelatedMemoID *int32 + MemoID *int32 } type FindResource struct { @@ -41,11 +39,14 @@ type UpdateResource struct { UpdatedTs *int64 Filename *string InternalPath *string + MemoID *int32 + UnbindMemo bool Blob []byte } type DeleteResource struct { - ID int32 + ID int32 + MemoID *int32 } func (s *Store) CreateResource(ctx context.Context, create *Resource) (*Resource, error) { diff --git a/store/sqlite/resource.go b/store/sqlite/resource.go index c64b56612..b71802a77 100644 --- a/store/sqlite/resource.go +++ b/store/sqlite/resource.go @@ -4,7 +4,6 @@ import ( "context" "database/sql" "fmt" - "strconv" "strings" "github.com/usememos/memos/store" @@ -45,35 +44,33 @@ func (d *Driver) ListResources(ctx context.Context, find *store.FindResource) ([ where, args := []string{"1 = 1"}, []any{} if v := find.ID; v != nil { - where, args = append(where, "resource.id = ?"), append(args, *v) + where, args = append(where, "id = ?"), append(args, *v) } if v := find.CreatorID; v != nil { - where, args = append(where, "resource.creator_id = ?"), append(args, *v) + where, args = append(where, "creator_id = ?"), append(args, *v) } if v := find.Filename; v != nil { - where, args = append(where, "resource.filename = ?"), append(args, *v) + where, args = append(where, "filename = ?"), append(args, *v) } if v := find.MemoID; v != nil { - where, args = append(where, "resource.id in (SELECT resource_id FROM memo_resource WHERE memo_id = ?)"), append(args, *v) + where, args = append(where, "memo_id = ?"), append(args, *v) } if find.HasRelatedMemo { - where = append(where, "memo_resource.memo_id IS NOT NULL") + where = append(where, "memo_id IS NOT NULL") } - fields := []string{"resource.id", "resource.filename", "resource.external_link", "resource.type", "resource.size", "resource.creator_id", "resource.created_ts", "resource.updated_ts", "internal_path"} + fields := []string{"id", "filename", "external_link", "type", "size", "creator_id", "created_ts", "updated_ts", "internal_path", "memo_id"} if find.GetBlob { - fields = append(fields, "resource.blob") + fields = append(fields, "blob") } query := fmt.Sprintf(` SELECT - GROUP_CONCAT(memo_resource.memo_id) as related_memo_ids, %s FROM resource - LEFT JOIN memo_resource ON resource.id = memo_resource.resource_id WHERE %s - GROUP BY resource.id - ORDER BY resource.created_ts DESC + GROUP BY id + ORDER BY created_ts DESC `, strings.Join(fields, ", "), strings.Join(where, " AND ")) if find.Limit != nil { query = fmt.Sprintf("%s LIMIT %d", query, *find.Limit) @@ -91,9 +88,8 @@ func (d *Driver) ListResources(ctx context.Context, find *store.FindResource) ([ list := make([]*store.Resource, 0) for rows.Next() { resource := store.Resource{} - var relatedMemoIDs sql.NullString + var memoID sql.NullInt32 dests := []any{ - &relatedMemoIDs, &resource.ID, &resource.Filename, &resource.ExternalLink, @@ -103,6 +99,7 @@ func (d *Driver) ListResources(ctx context.Context, find *store.FindResource) ([ &resource.CreatedTs, &resource.UpdatedTs, &resource.InternalPath, + &memoID, } if find.GetBlob { dests = append(dests, &resource.Blob) @@ -110,17 +107,8 @@ func (d *Driver) ListResources(ctx context.Context, find *store.FindResource) ([ if err := rows.Scan(dests...); err != nil { return nil, err } - if relatedMemoIDs.Valid { - relatedMemoIDList := strings.Split(relatedMemoIDs.String, ",") - if len(relatedMemoIDList) > 0 { - // Only take the first related memo ID. - relatedMemoIDInt, err := strconv.ParseInt(relatedMemoIDList[0], 10, 32) - if err != nil { - return nil, err - } - relatedMemoID := int32(relatedMemoIDInt) - resource.RelatedMemoID = &relatedMemoID - } + if memoID.Valid { + resource.MemoID = &memoID.Int32 } list = append(list, &resource) } @@ -144,6 +132,12 @@ func (d *Driver) UpdateResource(ctx context.Context, update *store.UpdateResourc if v := update.InternalPath; v != nil { set, args = append(set, "internal_path = ?"), append(args, *v) } + if v := update.MemoID; v != nil { + set, args = append(set, "memo_id = ?"), append(args, *v) + } + if update.UnbindMemo { + set = append(set, "memo_id = NULL") + } if v := update.Blob; v != nil { set, args = append(set, "blob = ?"), append(args, v) } diff --git a/store/store.go b/store/store.go index 9beb55a86..d4287b252 100644 --- a/store/store.go +++ b/store/store.go @@ -109,9 +109,6 @@ func (*Store) vacuumImpl(ctx context.Context, tx *sql.Tx) error { if err := vacuumMemoOrganizer(ctx, tx); err != nil { return err } - if err := vacuumMemoResource(ctx, tx); err != nil { - return err - } if err := vacuumMemoRelations(ctx, tx); err != nil { return err } diff --git a/test/store/resource_test.go b/test/store/resource_test.go index 10dde0791..11f12903b 100644 --- a/test/store/resource_test.go +++ b/test/store/resource_test.go @@ -31,17 +31,6 @@ func TestResourceStore(t *testing.T) { require.NoError(t, err) require.Equal(t, correctFilename, resource.Filename) require.Equal(t, int32(1), resource.ID) - _, err = ts.UpsertMemoResource(ctx, &store.UpsertMemoResource{ - MemoID: 1, - ResourceID: resource.ID, - }) - require.NoError(t, err) - - resource, err = ts.GetResource(ctx, &store.FindResource{ - ID: &resource.ID, - }) - require.NoError(t, err) - require.Equal(t, *resource.RelatedMemoID, int32(1)) notFoundResource, err := ts.GetResource(ctx, &store.FindResource{ Filename: &incorrectFilename, diff --git a/web/src/components/MemoEditor/index.tsx b/web/src/components/MemoEditor/index.tsx index e5a232052..3f08e77fd 100644 --- a/web/src/components/MemoEditor/index.tsx +++ b/web/src/components/MemoEditor/index.tsx @@ -3,7 +3,6 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react" import { toast } from "react-hot-toast"; import { useTranslation } from "react-i18next"; import useLocalStorage from "react-use/lib/useLocalStorage"; -import { upsertMemoResource } from "@/helpers/api"; import { TAB_SPACE_WIDTH, UNKNOWN_ID } from "@/helpers/consts"; import { clearContentQueryParam } from "@/helpers/utils"; import { getMatchedNodes } from "@/labs/marked"; @@ -223,7 +222,10 @@ const MemoEditor = (props: Props) => { if (resource) { uploadedResourceList.push(resource); if (memoId) { - await upsertMemoResource(memoId, resource.id); + await resourceStore.patchResource({ + id: resource.id, + memoId, + }); } } } diff --git a/web/src/helpers/api.ts b/web/src/helpers/api.ts index f2849480a..c68c679cd 100644 --- a/web/src/helpers/api.ts +++ b/web/src/helpers/api.ts @@ -155,20 +155,6 @@ export function deleteResourceById(id: ResourceId) { return axios.delete(`/api/v1/resource/${id}`); } -export function getMemoResourceList(memoId: MemoId) { - return axios.get(`/api/v1/memo/${memoId}/resource`); -} - -export function upsertMemoResource(memoId: MemoId, resourceId: ResourceId) { - return axios.post(`/api/v1/memo/${memoId}/resource`, { - resourceId, - }); -} - -export function deleteMemoResource(memoId: MemoId, resourceId: ResourceId) { - return axios.delete(`/api/v1/memo/${memoId}/resource/${resourceId}`); -} - export function getTagList() { return axios.get(`/api/v1/tag`); } diff --git a/web/src/store/module/resource.ts b/web/src/store/module/resource.ts index 9c1b495d9..a5666db1f 100644 --- a/web/src/store/module/resource.ts +++ b/web/src/store/module/resource.ts @@ -40,31 +40,14 @@ export const useResourceStore = () => { store.dispatch(setResources([resource, ...resourceList])); return resource; }, - async createResourcesWithBlob(files: FileList): Promise> { - let newResourceList: Array = []; - for (const file of files) { - const { name: filename, size } = file; - if (size > maxUploadSizeMiB * 1024 * 1024) { - return Promise.reject(t("message.file-exceeds-upload-limit-of", { file: filename, size: maxUploadSizeMiB })); - } - - const formData = new FormData(); - formData.append("file", file, filename); - const { data: resource } = await api.createResourceWithBlob(formData); - newResourceList = [resource, ...newResourceList]; - } - const resourceList = state.resources; - store.dispatch(setResources([...newResourceList, ...resourceList])); - return newResourceList; - }, - async deleteResourceById(id: ResourceId) { - await api.deleteResourceById(id); - store.dispatch(deleteResource(id)); - }, async patchResource(resourcePatch: ResourcePatch): Promise { const { data: resource } = await api.patchResource(resourcePatch); store.dispatch(patchResource(resource)); return resource; }, + async deleteResourceById(id: ResourceId) { + await api.deleteResourceById(id); + store.dispatch(deleteResource(id)); + }, }; }; diff --git a/web/src/types/modules/resource.d.ts b/web/src/types/modules/resource.d.ts index 722b5ee4b..b37e2bec4 100644 --- a/web/src/types/modules/resource.d.ts +++ b/web/src/types/modules/resource.d.ts @@ -9,6 +9,7 @@ interface ResourceCreate { interface ResourcePatch { id: ResourceId; filename?: string; + memoId?: number; } interface ResourceFind {