Commit 457cf92c authored by Steven's avatar Steven

feat(api): implement get resource by uid

parent 1ab2c894
......@@ -494,6 +494,27 @@ paths:
$ref: '#/definitions/v1Resource'
tags:
- ResourceService
/api/v1/resources:by-uid/{uid}:
get:
summary: GetResourceByUid returns a resource by uid.
operationId: ResourceService_GetResourceByUid
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1Resource'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/googlerpcStatus'
parameters:
- name: uid
description: The uid of the resource.
in: path
required: true
type: string
tags:
- ResourceService
/api/v1/resources:search:
get:
summary: SearchResources searches memos.
......
......@@ -33,6 +33,11 @@ service ResourceService {
option (google.api.http) = {get: "/api/v1/{name=resources/*}"};
option (google.api.method_signature) = "name";
}
// GetResourceByUid returns a resource by uid.
rpc GetResourceByUid(GetResourceByUidRequest) returns (Resource) {
option (google.api.http) = {get: "/api/v1/resources:by-uid/{uid}"};
option (google.api.method_signature) = "uid";
}
// GetResourceBinary returns a resource binary by name.
rpc GetResourceBinary(GetResourceBinaryRequest) returns (google.api.HttpBody) {
option (google.api.http) = {get: "/file/{name=resources/*}/{filename}"};
......@@ -104,6 +109,11 @@ message GetResourceRequest {
string name = 1;
}
message GetResourceByUidRequest {
// The uid of the resource.
string uid = 1;
}
message GetResourceBinaryRequest {
// The name of the resource.
// Format: resources/{id}
......
This diff is collapsed.
......@@ -163,6 +163,58 @@ func local_request_ResourceService_GetResource_0(ctx context.Context, marshaler
}
func request_ResourceService_GetResourceByUid_0(ctx context.Context, marshaler runtime.Marshaler, client ResourceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetResourceByUidRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["uid"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "uid")
}
protoReq.Uid, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "uid", err)
}
msg, err := client.GetResourceByUid(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ResourceService_GetResourceByUid_0(ctx context.Context, marshaler runtime.Marshaler, server ResourceServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetResourceByUidRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["uid"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "uid")
}
protoReq.Uid, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "uid", err)
}
msg, err := server.GetResourceByUid(ctx, &protoReq)
return msg, metadata, err
}
func request_ResourceService_GetResourceBinary_0(ctx context.Context, marshaler runtime.Marshaler, client ResourceServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetResourceBinaryRequest
var metadata runtime.ServerMetadata
......@@ -493,6 +545,31 @@ func RegisterResourceServiceHandlerServer(ctx context.Context, mux *runtime.Serv
})
mux.Handle("GET", pattern_ResourceService_GetResourceByUid_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.ResourceService/GetResourceByUid", runtime.WithHTTPPathPattern("/api/v1/resources:by-uid/{uid}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ResourceService_GetResourceByUid_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_ResourceService_GetResourceByUid_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ResourceService_GetResourceBinary_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
......@@ -697,6 +774,28 @@ func RegisterResourceServiceHandlerClient(ctx context.Context, mux *runtime.Serv
})
mux.Handle("GET", pattern_ResourceService_GetResourceByUid_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.ResourceService/GetResourceByUid", runtime.WithHTTPPathPattern("/api/v1/resources:by-uid/{uid}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ResourceService_GetResourceByUid_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_ResourceService_GetResourceByUid_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ResourceService_GetResourceBinary_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
......@@ -775,6 +874,8 @@ var (
pattern_ResourceService_GetResource_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "resources", "name"}, ""))
pattern_ResourceService_GetResourceByUid_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "resources:by-uid", "uid"}, ""))
pattern_ResourceService_GetResourceBinary_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 2, 5, 2, 1, 0, 4, 1, 5, 3}, []string{"file", "resources", "name", "filename"}, ""))
pattern_ResourceService_UpdateResource_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "resources", "resource.name"}, ""))
......@@ -791,6 +892,8 @@ var (
forward_ResourceService_GetResource_0 = runtime.ForwardResponseMessage
forward_ResourceService_GetResourceByUid_0 = runtime.ForwardResponseMessage
forward_ResourceService_GetResourceBinary_0 = runtime.ForwardResponseMessage
forward_ResourceService_UpdateResource_0 = runtime.ForwardResponseMessage
......
......@@ -25,6 +25,7 @@ const (
ResourceService_ListResources_FullMethodName = "/memos.api.v1.ResourceService/ListResources"
ResourceService_SearchResources_FullMethodName = "/memos.api.v1.ResourceService/SearchResources"
ResourceService_GetResource_FullMethodName = "/memos.api.v1.ResourceService/GetResource"
ResourceService_GetResourceByUid_FullMethodName = "/memos.api.v1.ResourceService/GetResourceByUid"
ResourceService_GetResourceBinary_FullMethodName = "/memos.api.v1.ResourceService/GetResourceBinary"
ResourceService_UpdateResource_FullMethodName = "/memos.api.v1.ResourceService/UpdateResource"
ResourceService_DeleteResource_FullMethodName = "/memos.api.v1.ResourceService/DeleteResource"
......@@ -42,6 +43,8 @@ type ResourceServiceClient interface {
SearchResources(ctx context.Context, in *SearchResourcesRequest, opts ...grpc.CallOption) (*SearchResourcesResponse, error)
// GetResource returns a resource by name.
GetResource(ctx context.Context, in *GetResourceRequest, opts ...grpc.CallOption) (*Resource, error)
// GetResourceByUid returns a resource by uid.
GetResourceByUid(ctx context.Context, in *GetResourceByUidRequest, opts ...grpc.CallOption) (*Resource, error)
// GetResourceBinary returns a resource binary by name.
GetResourceBinary(ctx context.Context, in *GetResourceBinaryRequest, opts ...grpc.CallOption) (*httpbody.HttpBody, error)
// UpdateResource updates a resource.
......@@ -98,6 +101,16 @@ func (c *resourceServiceClient) GetResource(ctx context.Context, in *GetResource
return out, nil
}
func (c *resourceServiceClient) GetResourceByUid(ctx context.Context, in *GetResourceByUidRequest, opts ...grpc.CallOption) (*Resource, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Resource)
err := c.cc.Invoke(ctx, ResourceService_GetResourceByUid_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *resourceServiceClient) GetResourceBinary(ctx context.Context, in *GetResourceBinaryRequest, opts ...grpc.CallOption) (*httpbody.HttpBody, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(httpbody.HttpBody)
......@@ -140,6 +153,8 @@ type ResourceServiceServer interface {
SearchResources(context.Context, *SearchResourcesRequest) (*SearchResourcesResponse, error)
// GetResource returns a resource by name.
GetResource(context.Context, *GetResourceRequest) (*Resource, error)
// GetResourceByUid returns a resource by uid.
GetResourceByUid(context.Context, *GetResourceByUidRequest) (*Resource, error)
// GetResourceBinary returns a resource binary by name.
GetResourceBinary(context.Context, *GetResourceBinaryRequest) (*httpbody.HttpBody, error)
// UpdateResource updates a resource.
......@@ -165,6 +180,9 @@ func (UnimplementedResourceServiceServer) SearchResources(context.Context, *Sear
func (UnimplementedResourceServiceServer) GetResource(context.Context, *GetResourceRequest) (*Resource, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetResource not implemented")
}
func (UnimplementedResourceServiceServer) GetResourceByUid(context.Context, *GetResourceByUidRequest) (*Resource, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetResourceByUid not implemented")
}
func (UnimplementedResourceServiceServer) GetResourceBinary(context.Context, *GetResourceBinaryRequest) (*httpbody.HttpBody, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetResourceBinary not implemented")
}
......@@ -259,6 +277,24 @@ func _ResourceService_GetResource_Handler(srv interface{}, ctx context.Context,
return interceptor(ctx, in, info, handler)
}
func _ResourceService_GetResourceByUid_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetResourceByUidRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResourceServiceServer).GetResourceByUid(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResourceService_GetResourceByUid_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResourceServiceServer).GetResourceByUid(ctx, req.(*GetResourceByUidRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ResourceService_GetResourceBinary_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetResourceBinaryRequest)
if err := dec(in); err != nil {
......@@ -336,6 +372,10 @@ var ResourceService_ServiceDesc = grpc.ServiceDesc{
MethodName: "GetResource",
Handler: _ResourceService_GetResource_Handler,
},
{
MethodName: "GetResourceByUid",
Handler: _ResourceService_GetResourceByUid_Handler,
},
{
MethodName: "GetResourceBinary",
Handler: _ResourceService_GetResourceBinary_Handler,
......
......@@ -111,8 +111,8 @@ func (s *APIV1Service) SearchResources(ctx context.Context, request *v1pb.Search
return nil, status.Errorf(codes.InvalidArgument, "failed to parse filter: %v", err)
}
resourceFind := &store.FindResource{}
if filter.UID != nil {
resourceFind.UID = filter.UID
if filter.Filename != nil {
resourceFind.FilenameSearch = filter.Filename
}
user, err := s.GetCurrentUser(ctx)
if err != nil {
......@@ -145,7 +145,19 @@ func (s *APIV1Service) GetResource(ctx context.Context, request *v1pb.GetResourc
if resource == nil {
return nil, status.Errorf(codes.NotFound, "resource not found")
}
return s.convertResourceFromStore(ctx, resource), nil
}
func (s *APIV1Service) GetResourceByUid(ctx context.Context, request *v1pb.GetResourceByUidRequest) (*v1pb.Resource, error) {
resource, err := s.Store.GetResource(ctx, &store.FindResource{
UID: &request.Uid,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get resource: %v", err)
}
if resource == nil {
return nil, status.Errorf(codes.NotFound, "resource not found")
}
return s.convertResourceFromStore(ctx, resource), nil
}
......@@ -427,11 +439,11 @@ func replaceFilenameWithPathTemplate(path, filename string) string {
// SearchResourcesFilterCELAttributes are the CEL attributes for SearchResourcesFilter.
var SearchResourcesFilterCELAttributes = []cel.EnvOption{
cel.Variable("uid", cel.StringType),
cel.Variable("filename", cel.StringType),
}
type SearchResourcesFilter struct {
UID *string
Filename *string
}
func parseSearchResourcesFilter(expression string) (*SearchResourcesFilter, error) {
......@@ -457,9 +469,9 @@ func findSearchResourcesField(callExpr *expr.Expr_Call, filter *SearchResourcesF
if len(callExpr.Args) == 2 {
idExpr := callExpr.Args[0].GetIdentExpr()
if idExpr != nil {
if idExpr.Name == "uid" {
uid := callExpr.Args[1].GetConstExpr().GetStringValue()
filter.UID = &uid
if idExpr.Name == "filename" {
filename := callExpr.Args[1].GetConstExpr().GetStringValue()
filter.Filename = &filename
}
return
}
......
......@@ -60,6 +60,9 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
if v := find.Filename; v != nil {
where, args = append(where, "`filename` = ?"), append(args, *v)
}
if v := find.FilenameSearch; v != nil {
where, args = append(where, "`filename` LIKE ?"), append(args, "%"+*v+"%")
}
if v := find.MemoID; v != nil {
where, args = append(where, "`memo_id` = ?"), append(args, *v)
}
......
......@@ -51,6 +51,9 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
if v := find.Filename; v != nil {
where, args = append(where, "filename = "+placeholder(len(args)+1)), append(args, *v)
}
if v := find.FilenameSearch; v != nil {
where, args = append(where, "filename LIKE "+placeholder(len(args)+1)), append(args, fmt.Sprintf("%%%s%%", *v))
}
if v := find.MemoID; v != nil {
where, args = append(where, "memo_id = "+placeholder(len(args)+1)), append(args, *v)
}
......
......@@ -53,6 +53,9 @@ func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*st
if v := find.Filename; v != nil {
where, args = append(where, "`filename` = ?"), append(args, *v)
}
if v := find.FilenameSearch; v != nil {
where, args = append(where, "`filename` LIKE ?"), append(args, fmt.Sprintf("%%%s%%", *v))
}
if v := find.MemoID; v != nil {
where, args = append(where, "`memo_id` = ?"), append(args, *v)
}
......
......@@ -43,6 +43,7 @@ type FindResource struct {
UID *string
CreatorID *int32
Filename *string
FilenameSearch *string
MemoID *int32
HasRelatedMemo bool
StorageType *storepb.ResourceStorageType
......
......@@ -35,21 +35,21 @@ const getAdditionalClassNameWithParams = (params: URLSearchParams) => {
return additionalClassNames.join(" ");
};
const EmbeddedResource = ({ resourceId, params: paramsStr }: Props) => {
const EmbeddedResource = ({ resourceId: uid, params: paramsStr }: Props) => {
const loadingState = useLoading();
const resourceStore = useResourceStore();
const resource = resourceStore.getResourceByName(resourceId);
const resource = resourceStore.getResourceByName(uid);
const params = new URLSearchParams(paramsStr);
useEffect(() => {
resourceStore.searchResources(`uid == ${resourceId}`).finally(() => loadingState.setFinish());
}, [resourceId]);
resourceStore.fetchResourceByUID(uid).finally(() => loadingState.setFinish());
}, [uid]);
if (loadingState.isLoading) {
return null;
}
if (!resource) {
return <Error message={`Resource not found: ${resourceId}`} />;
return <Error message={`Resource not found: ${uid}`} />;
}
return (
......
......@@ -26,6 +26,15 @@ export const useResourceStore = create(
set({ resourceMapByName: resourceMap });
return resources;
},
fetchResourceByUID: async (uid: string) => {
const resource = await resourceServiceClient.getResourceByUid({
uid,
});
const resourceMap = get().resourceMapByName;
resourceMap[resource.name] = resource;
set({ resourceMapByName: resourceMap });
return resource;
},
getResourceByName: (name: string) => {
const resourceMap = get().resourceMapByName;
return Object.values(resourceMap).find((r) => r.name === name);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment