refactor: nest reaction resource names under memos
This commit is contained in:
parent
c2aea5a4b7
commit
d7284fe867
8 changed files with 63 additions and 53 deletions
|
|
@ -100,7 +100,7 @@ service MemoService {
|
||||||
}
|
}
|
||||||
// DeleteMemoReaction deletes a reaction for a memo.
|
// DeleteMemoReaction deletes a reaction for a memo.
|
||||||
rpc DeleteMemoReaction(DeleteMemoReactionRequest) returns (google.protobuf.Empty) {
|
rpc DeleteMemoReaction(DeleteMemoReactionRequest) returns (google.protobuf.Empty) {
|
||||||
option (google.api.http) = {delete: "/api/v1/{name=reactions/*}"};
|
option (google.api.http) = {delete: "/api/v1/{name=memos/*/reactions/*}"};
|
||||||
option (google.api.method_signature) = "name";
|
option (google.api.method_signature) = "name";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -115,14 +115,14 @@ enum Visibility {
|
||||||
message Reaction {
|
message Reaction {
|
||||||
option (google.api.resource) = {
|
option (google.api.resource) = {
|
||||||
type: "memos.api.v1/Reaction"
|
type: "memos.api.v1/Reaction"
|
||||||
pattern: "reactions/{reaction}"
|
pattern: "memos/{memo}/reactions/{reaction}"
|
||||||
name_field: "name"
|
name_field: "name"
|
||||||
singular: "reaction"
|
singular: "reaction"
|
||||||
plural: "reactions"
|
plural: "reactions"
|
||||||
};
|
};
|
||||||
|
|
||||||
// The resource name of the reaction.
|
// The resource name of the reaction.
|
||||||
// Format: reactions/{reaction}
|
// Format: memos/{memo}/reactions/{reaction}
|
||||||
string name = 1 [
|
string name = 1 [
|
||||||
(google.api.field_behavior) = OUTPUT_ONLY,
|
(google.api.field_behavior) = OUTPUT_ONLY,
|
||||||
(google.api.field_behavior) = IDENTIFIER
|
(google.api.field_behavior) = IDENTIFIER
|
||||||
|
|
@ -501,7 +501,7 @@ message UpsertMemoReactionRequest {
|
||||||
|
|
||||||
message DeleteMemoReactionRequest {
|
message DeleteMemoReactionRequest {
|
||||||
// Required. The resource name of the reaction to delete.
|
// Required. The resource name of the reaction to delete.
|
||||||
// Format: reactions/{reaction}
|
// Format: memos/{memo}/reactions/{reaction}
|
||||||
string name = 1 [
|
string name = 1 [
|
||||||
(google.api.field_behavior) = REQUIRED,
|
(google.api.field_behavior) = REQUIRED,
|
||||||
(google.api.resource_reference) = {type: "memos.api.v1/Reaction"}
|
(google.api.resource_reference) = {type: "memos.api.v1/Reaction"}
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ func (MemoRelation_Type) EnumDescriptor() ([]byte, []int) {
|
||||||
type Reaction struct {
|
type Reaction struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
// The resource name of the reaction.
|
// The resource name of the reaction.
|
||||||
// Format: reactions/{reaction}
|
// Format: memos/{memo}/reactions/{reaction}
|
||||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
// The resource name of the creator.
|
// The resource name of the creator.
|
||||||
// Format: users/{user}
|
// Format: users/{user}
|
||||||
|
|
@ -1627,7 +1627,7 @@ func (x *UpsertMemoReactionRequest) GetReaction() *Reaction {
|
||||||
type DeleteMemoReactionRequest struct {
|
type DeleteMemoReactionRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
// Required. The resource name of the reaction to delete.
|
// Required. The resource name of the reaction to delete.
|
||||||
// Format: reactions/{reaction}
|
// Format: memos/{memo}/reactions/{reaction}
|
||||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
|
|
@ -1799,7 +1799,7 @@ var File_api_v1_memo_service_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_api_v1_memo_service_proto_rawDesc = "" +
|
const file_api_v1_memo_service_proto_rawDesc = "" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"\x19api/v1/memo_service.proto\x12\fmemos.api.v1\x1a\x1fapi/v1/attachment_service.proto\x1a\x13api/v1/common.proto\x1a\x1cgoogle/api/annotations.proto\x1a\x17google/api/client.proto\x1a\x1fgoogle/api/field_behavior.proto\x1a\x19google/api/resource.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xce\x02\n" +
|
"\x19api/v1/memo_service.proto\x12\fmemos.api.v1\x1a\x1fapi/v1/attachment_service.proto\x1a\x13api/v1/common.proto\x1a\x1cgoogle/api/annotations.proto\x1a\x17google/api/client.proto\x1a\x1fgoogle/api/field_behavior.proto\x1a\x19google/api/resource.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xdb\x02\n" +
|
||||||
"\bReaction\x12\x1a\n" +
|
"\bReaction\x12\x1a\n" +
|
||||||
"\x04name\x18\x01 \x01(\tB\x06\xe0A\x03\xe0A\bR\x04name\x123\n" +
|
"\x04name\x18\x01 \x01(\tB\x06\xe0A\x03\xe0A\bR\x04name\x123\n" +
|
||||||
"\acreator\x18\x02 \x01(\tB\x19\xe0A\x03\xfaA\x13\n" +
|
"\acreator\x18\x02 \x01(\tB\x19\xe0A\x03\xfaA\x13\n" +
|
||||||
|
|
@ -1809,8 +1809,8 @@ const file_api_v1_memo_service_proto_rawDesc = "" +
|
||||||
"\x11memos.api.v1/MemoR\tcontentId\x12(\n" +
|
"\x11memos.api.v1/MemoR\tcontentId\x12(\n" +
|
||||||
"\rreaction_type\x18\x04 \x01(\tB\x03\xe0A\x02R\freactionType\x12@\n" +
|
"\rreaction_type\x18\x04 \x01(\tB\x03\xe0A\x02R\freactionType\x12@\n" +
|
||||||
"\vcreate_time\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampB\x03\xe0A\x03R\n" +
|
"\vcreate_time\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampB\x03\xe0A\x03R\n" +
|
||||||
"createTime:K\xeaAH\n" +
|
"createTime:X\xeaAU\n" +
|
||||||
"\x15memos.api.v1/Reaction\x12\x14reactions/{reaction}\x1a\x04name*\treactions2\breaction\"\xd8\b\n" +
|
"\x15memos.api.v1/Reaction\x12!memos/{memo}/reactions/{reaction}\x1a\x04name*\treactions2\breaction\"\xd8\b\n" +
|
||||||
"\x04Memo\x12\x17\n" +
|
"\x04Memo\x12\x17\n" +
|
||||||
"\x04name\x18\x01 \x01(\tB\x03\xe0A\bR\x04name\x12.\n" +
|
"\x04name\x18\x01 \x01(\tB\x03\xe0A\bR\x04name\x12.\n" +
|
||||||
"\x05state\x18\x02 \x01(\x0e2\x13.memos.api.v1.StateB\x03\xe0A\x02R\x05state\x123\n" +
|
"\x05state\x18\x02 \x01(\x0e2\x13.memos.api.v1.StateB\x03\xe0A\x02R\x05state\x123\n" +
|
||||||
|
|
@ -1953,7 +1953,7 @@ const file_api_v1_memo_service_proto_rawDesc = "" +
|
||||||
"\aPRIVATE\x10\x01\x12\r\n" +
|
"\aPRIVATE\x10\x01\x12\r\n" +
|
||||||
"\tPROTECTED\x10\x02\x12\n" +
|
"\tPROTECTED\x10\x02\x12\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"\x06PUBLIC\x10\x032\xcb\x0e\n" +
|
"\x06PUBLIC\x10\x032\xd3\x0e\n" +
|
||||||
"\vMemoService\x12e\n" +
|
"\vMemoService\x12e\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"CreateMemo\x12\x1f.memos.api.v1.CreateMemoRequest\x1a\x12.memos.api.v1.Memo\"\"\xdaA\x04memo\x82\xd3\xe4\x93\x02\x15:\x04memo\"\r/api/v1/memos\x12f\n" +
|
"CreateMemo\x12\x1f.memos.api.v1.CreateMemoRequest\x1a\x12.memos.api.v1.Memo\"\"\xdaA\x04memo\x82\xd3\xe4\x93\x02\x15:\x04memo\"\r/api/v1/memos\x12f\n" +
|
||||||
|
|
@ -1970,8 +1970,8 @@ const file_api_v1_memo_service_proto_rawDesc = "" +
|
||||||
"\x11CreateMemoComment\x12&.memos.api.v1.CreateMemoCommentRequest\x1a\x12.memos.api.v1.Memo\"?\xdaA\fname,comment\x82\xd3\xe4\x93\x02*:\acomment\"\x1f/api/v1/{name=memos/*}/comments\x12\x91\x01\n" +
|
"\x11CreateMemoComment\x12&.memos.api.v1.CreateMemoCommentRequest\x1a\x12.memos.api.v1.Memo\"?\xdaA\fname,comment\x82\xd3\xe4\x93\x02*:\acomment\"\x1f/api/v1/{name=memos/*}/comments\x12\x91\x01\n" +
|
||||||
"\x10ListMemoComments\x12%.memos.api.v1.ListMemoCommentsRequest\x1a&.memos.api.v1.ListMemoCommentsResponse\".\xdaA\x04name\x82\xd3\xe4\x93\x02!\x12\x1f/api/v1/{name=memos/*}/comments\x12\x95\x01\n" +
|
"\x10ListMemoComments\x12%.memos.api.v1.ListMemoCommentsRequest\x1a&.memos.api.v1.ListMemoCommentsResponse\".\xdaA\x04name\x82\xd3\xe4\x93\x02!\x12\x1f/api/v1/{name=memos/*}/comments\x12\x95\x01\n" +
|
||||||
"\x11ListMemoReactions\x12&.memos.api.v1.ListMemoReactionsRequest\x1a'.memos.api.v1.ListMemoReactionsResponse\"/\xdaA\x04name\x82\xd3\xe4\x93\x02\"\x12 /api/v1/{name=memos/*}/reactions\x12\x89\x01\n" +
|
"\x11ListMemoReactions\x12&.memos.api.v1.ListMemoReactionsRequest\x1a'.memos.api.v1.ListMemoReactionsResponse\"/\xdaA\x04name\x82\xd3\xe4\x93\x02\"\x12 /api/v1/{name=memos/*}/reactions\x12\x89\x01\n" +
|
||||||
"\x12UpsertMemoReaction\x12'.memos.api.v1.UpsertMemoReactionRequest\x1a\x16.memos.api.v1.Reaction\"2\xdaA\x04name\x82\xd3\xe4\x93\x02%:\x01*\" /api/v1/{name=memos/*}/reactions\x12\x80\x01\n" +
|
"\x12UpsertMemoReaction\x12'.memos.api.v1.UpsertMemoReactionRequest\x1a\x16.memos.api.v1.Reaction\"2\xdaA\x04name\x82\xd3\xe4\x93\x02%:\x01*\" /api/v1/{name=memos/*}/reactions\x12\x88\x01\n" +
|
||||||
"\x12DeleteMemoReaction\x12'.memos.api.v1.DeleteMemoReactionRequest\x1a\x16.google.protobuf.Empty\")\xdaA\x04name\x82\xd3\xe4\x93\x02\x1c*\x1a/api/v1/{name=reactions/*}B\xa8\x01\n" +
|
"\x12DeleteMemoReaction\x12'.memos.api.v1.DeleteMemoReactionRequest\x1a\x16.google.protobuf.Empty\"1\xdaA\x04name\x82\xd3\xe4\x93\x02$*\"/api/v1/{name=memos/*/reactions/*}B\xa8\x01\n" +
|
||||||
"\x10com.memos.api.v1B\x10MemoServiceProtoP\x01Z0github.com/usememos/memos/proto/gen/api/v1;apiv1\xa2\x02\x03MAX\xaa\x02\fMemos.Api.V1\xca\x02\fMemos\\Api\\V1\xe2\x02\x18Memos\\Api\\V1\\GPBMetadata\xea\x02\x0eMemos::Api::V1b\x06proto3"
|
"\x10com.memos.api.v1B\x10MemoServiceProtoP\x01Z0github.com/usememos/memos/proto/gen/api/v1;apiv1\xa2\x02\x03MAX\xaa\x02\fMemos.Api.V1\xca\x02\fMemos\\Api\\V1\xe2\x02\x18Memos\\Api\\V1\\GPBMetadata\xea\x02\x0eMemos::Api::V1b\x06proto3"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -1001,7 +1001,7 @@ func RegisterMemoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux
|
||||||
var stream runtime.ServerTransportStream
|
var stream runtime.ServerTransportStream
|
||||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.MemoService/DeleteMemoReaction", runtime.WithHTTPPathPattern("/api/v1/{name=reactions/*}"))
|
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.MemoService/DeleteMemoReaction", runtime.WithHTTPPathPattern("/api/v1/{name=memos/*/reactions/*}"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
return
|
return
|
||||||
|
|
@ -1280,7 +1280,7 @@ func RegisterMemoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.MemoService/DeleteMemoReaction", runtime.WithHTTPPathPattern("/api/v1/{name=reactions/*}"))
|
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.MemoService/DeleteMemoReaction", runtime.WithHTTPPathPattern("/api/v1/{name=memos/*/reactions/*}"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
return
|
return
|
||||||
|
|
@ -1310,7 +1310,7 @@ var (
|
||||||
pattern_MemoService_ListMemoComments_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "memos", "name", "comments"}, ""))
|
pattern_MemoService_ListMemoComments_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "memos", "name", "comments"}, ""))
|
||||||
pattern_MemoService_ListMemoReactions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "memos", "name", "reactions"}, ""))
|
pattern_MemoService_ListMemoReactions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "memos", "name", "reactions"}, ""))
|
||||||
pattern_MemoService_UpsertMemoReaction_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "memos", "name", "reactions"}, ""))
|
pattern_MemoService_UpsertMemoReaction_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4}, []string{"api", "v1", "memos", "name", "reactions"}, ""))
|
||||||
pattern_MemoService_DeleteMemoReaction_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "reactions", "name"}, ""))
|
pattern_MemoService_DeleteMemoReaction_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 2, 3, 1, 0, 4, 4, 5, 4}, []string{"api", "v1", "memos", "reactions", "name"}, ""))
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -960,6 +960,35 @@ paths:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/Status'
|
$ref: '#/components/schemas/Status'
|
||||||
|
/api/v1/memos/{memo}/reactions/{reaction}:
|
||||||
|
delete:
|
||||||
|
tags:
|
||||||
|
- MemoService
|
||||||
|
description: DeleteMemoReaction deletes a reaction for a memo.
|
||||||
|
operationId: MemoService_DeleteMemoReaction
|
||||||
|
parameters:
|
||||||
|
- name: memo
|
||||||
|
in: path
|
||||||
|
description: The memo id.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: reaction
|
||||||
|
in: path
|
||||||
|
description: The reaction id.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
content: {}
|
||||||
|
default:
|
||||||
|
description: Default error response
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Status'
|
||||||
/api/v1/memos/{memo}/relations:
|
/api/v1/memos/{memo}/relations:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
|
@ -1025,29 +1054,6 @@ paths:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/Status'
|
$ref: '#/components/schemas/Status'
|
||||||
/api/v1/reactions/{reaction}:
|
|
||||||
delete:
|
|
||||||
tags:
|
|
||||||
- MemoService
|
|
||||||
description: DeleteMemoReaction deletes a reaction for a memo.
|
|
||||||
operationId: MemoService_DeleteMemoReaction
|
|
||||||
parameters:
|
|
||||||
- name: reaction
|
|
||||||
in: path
|
|
||||||
description: The reaction id.
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
content: {}
|
|
||||||
default:
|
|
||||||
description: Default error response
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: '#/components/schemas/Status'
|
|
||||||
/api/v1/users:
|
/api/v1/users:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
|
@ -2640,7 +2646,7 @@ components:
|
||||||
type: string
|
type: string
|
||||||
description: |-
|
description: |-
|
||||||
The resource name of the reaction.
|
The resource name of the reaction.
|
||||||
Format: reactions/{reaction}
|
Format: memos/{memo}/reactions/{reaction}
|
||||||
creator:
|
creator:
|
||||||
readOnly: true
|
readOnly: true
|
||||||
type: string
|
type: string
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ func (s *APIV1Service) DeleteMemoReaction(ctx context.Context, request *v1pb.Del
|
||||||
return nil, status.Errorf(codes.Unauthenticated, "user not authenticated")
|
return nil, status.Errorf(codes.Unauthenticated, "user not authenticated")
|
||||||
}
|
}
|
||||||
|
|
||||||
reactionID, err := ExtractReactionIDFromName(request.Name)
|
_, reactionID, err := ExtractMemoReactionIDFromName(request.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Errorf(codes.InvalidArgument, "invalid reaction name: %v", err)
|
return nil, status.Errorf(codes.InvalidArgument, "invalid reaction name: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -95,8 +95,10 @@ func (s *APIV1Service) DeleteMemoReaction(ctx context.Context, request *v1pb.Del
|
||||||
|
|
||||||
func convertReactionFromStore(reaction *store.Reaction) *v1pb.Reaction {
|
func convertReactionFromStore(reaction *store.Reaction) *v1pb.Reaction {
|
||||||
reactionUID := fmt.Sprintf("%d", reaction.ID)
|
reactionUID := fmt.Sprintf("%d", reaction.ID)
|
||||||
|
// Generate nested resource name: memos/{memo}/reactions/{reaction}
|
||||||
|
// reaction.ContentID already contains "memos/{memo}"
|
||||||
return &v1pb.Reaction{
|
return &v1pb.Reaction{
|
||||||
Name: fmt.Sprintf("%s%s", ReactionNamePrefix, reactionUID),
|
Name: fmt.Sprintf("%s/%s%s", reaction.ContentID, ReactionNamePrefix, reactionUID),
|
||||||
Creator: fmt.Sprintf("%s%d", UserNamePrefix, reaction.CreatorID),
|
Creator: fmt.Sprintf("%s%d", UserNamePrefix, reaction.CreatorID),
|
||||||
ContentId: reaction.ContentID,
|
ContentId: reaction.ContentID,
|
||||||
ReactionType: reaction.ReactionType,
|
ReactionType: reaction.ReactionType,
|
||||||
|
|
|
||||||
|
|
@ -105,18 +105,19 @@ func ExtractAttachmentUIDFromName(name string) (string, error) {
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractReactionIDFromName returns the reaction ID from a resource name.
|
// ExtractMemoReactionIDFromName returns the memo UID and reaction ID from a resource name.
|
||||||
// e.g., "reactions/123" -> 123.
|
// e.g., "memos/abc/reactions/123" -> ("abc", 123).
|
||||||
func ExtractReactionIDFromName(name string) (int32, error) {
|
func ExtractMemoReactionIDFromName(name string) (string, int32, error) {
|
||||||
tokens, err := GetNameParentTokens(name, ReactionNamePrefix)
|
tokens, err := GetNameParentTokens(name, MemoNamePrefix, ReactionNamePrefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
id, err := util.ConvertStringToInt32(tokens[0])
|
memoUID := tokens[0]
|
||||||
|
reactionID, err := util.ConvertStringToInt32(tokens[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errors.Errorf("invalid reaction ID %q", tokens[0])
|
return "", 0, errors.Errorf("invalid reaction ID %q", tokens[1])
|
||||||
}
|
}
|
||||||
return id, nil
|
return memoUID, reactionID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractInboxIDFromName returns the inbox ID from a resource name.
|
// ExtractInboxIDFromName returns the inbox ID from a resource name.
|
||||||
|
|
|
||||||
|
|
@ -183,8 +183,9 @@ func TestDeleteMemoReaction(t *testing.T) {
|
||||||
|
|
||||||
// Try to delete non-existent reaction - should fail with permission denied
|
// Try to delete non-existent reaction - should fail with permission denied
|
||||||
// (not "not found" to avoid information disclosure)
|
// (not "not found" to avoid information disclosure)
|
||||||
|
// Use new nested resource format: memos/{memo}/reactions/{reaction}
|
||||||
_, err = ts.Service.DeleteMemoReaction(userCtx, &apiv1.DeleteMemoReactionRequest{
|
_, err = ts.Service.DeleteMemoReaction(userCtx, &apiv1.DeleteMemoReactionRequest{
|
||||||
Name: "reactions/99999",
|
Name: "memos/nonexistent/reactions/99999",
|
||||||
})
|
})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Contains(t, err.Error(), "permission denied")
|
require.Contains(t, err.Error(), "permission denied")
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue