diff --git a/api/v2/memo_resource_service.go b/api/v2/memo_resource_service.go index 6d0937a4..9071d115 100644 --- a/api/v2/memo_resource_service.go +++ b/api/v2/memo_resource_service.go @@ -48,7 +48,7 @@ func (s *APIV2Service) SetMemoResources(ctx context.Context, request *apiv2pb.Se MemoID: &request.Id, UpdatedTs: &updatedTs, }); err != nil { - return nil, status.Errorf(codes.Internal, "failed to update resource") + return nil, status.Errorf(codes.Internal, "failed to update resource: %v", err) } } diff --git a/api/v2/resource_service.go b/api/v2/resource_service.go index 0b8bb709..27dc7916 100644 --- a/api/v2/resource_service.go +++ b/api/v2/resource_service.go @@ -2,6 +2,7 @@ package v2 import ( "context" + "net/url" "time" "google.golang.org/grpc/codes" @@ -12,6 +13,40 @@ import ( "github.com/usememos/memos/store" ) +func (s *APIV2Service) CreateResource(ctx context.Context, request *apiv2pb.CreateResourceRequest) (*apiv2pb.CreateResourceResponse, error) { + user, err := getCurrentUser(ctx, s.Store) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err) + } + if request.ExternalLink != "" { + // Only allow those external links scheme with http/https + linkURL, err := url.Parse(request.ExternalLink) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid external link: %v", err) + } + if linkURL.Scheme != "http" && linkURL.Scheme != "https" { + return nil, status.Errorf(codes.InvalidArgument, "invalid external link scheme: %v", linkURL.Scheme) + } + } + + create := &store.Resource{ + CreatorID: user.ID, + Filename: request.Filename, + ExternalLink: request.ExternalLink, + Type: request.Type, + } + if request.MemoId != nil { + create.MemoID = request.MemoId + } + resource, err := s.Store.CreateResource(ctx, create) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed to create resource: %v", err) + } + return &apiv2pb.CreateResourceResponse{ + Resource: s.convertResourceFromStore(ctx, resource), + }, nil +} + func (s *APIV2Service) ListResources(ctx context.Context, _ *apiv2pb.ListResourcesRequest) (*apiv2pb.ListResourcesResponse, error) { user, err := getCurrentUser(ctx, s.Store) if err != nil { diff --git a/web/src/helpers/api.ts b/web/src/helpers/api.ts index 18384b81..9728ec6c 100644 --- a/web/src/helpers/api.ts +++ b/web/src/helpers/api.ts @@ -44,10 +44,6 @@ export function signout() { return axios.post("/api/v1/auth/signout"); } -export function createResource(resourceCreate: ResourceCreate) { - return axios.post("/api/v1/resource", resourceCreate); -} - export function createResourceWithBlob(formData: FormData) { return axios.post("/api/v1/resource/blob", formData); } diff --git a/web/src/store/module/resource.ts b/web/src/store/module/resource.ts index 3731ea80..eddcd736 100644 --- a/web/src/store/module/resource.ts +++ b/web/src/store/module/resource.ts @@ -1,6 +1,6 @@ import { resourceServiceClient } from "@/grpcweb"; import * as api from "@/helpers/api"; -import { Resource, UpdateResourceRequest } from "@/types/proto/api/v2/resource_service"; +import { CreateResourceRequest, Resource, UpdateResourceRequest } from "@/types/proto/api/v2/resource_service"; import { useTranslate } from "@/utils/i18n"; import store, { useAppSelector } from "../"; import { patchResource, setResources } from "../reducer/resource"; @@ -17,8 +17,11 @@ export const useResourceStore = () => { getState: () => { return store.getState().resource; }, - async createResource(resourceCreate: ResourceCreate): Promise { - const { data: resource } = await api.createResource(resourceCreate); + async createResource(create: CreateResourceRequest): Promise { + const { resource } = await resourceServiceClient.createResource(create); + if (!resource) { + throw new Error("resource is null"); + } const resourceList = state.resources; store.dispatch(setResources([resource, ...resourceList])); return resource; @@ -36,8 +39,8 @@ export const useResourceStore = () => { store.dispatch(setResources([resource, ...resourceList])); return resource; }, - async updateResource(request: UpdateResourceRequest): Promise { - const { resource } = await resourceServiceClient.updateResource(request); + async updateResource(update: UpdateResourceRequest): Promise { + const { resource } = await resourceServiceClient.updateResource(update); if (!resource) { throw new Error("resource is null"); }