diff --git a/README.md b/README.md index 9963a0c..8edbcf7 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ A simple blog system using microservices architecture with go-micro v5. The project consists of the following microservices: 1. **Users Service**: User management (create, read, update, delete) -2. **Posts Service**: Post management (create, read, delete, list) +2. **Posts Service**: Post management (create, read, delete, list, tag management) 3. **Comments Service**: Comment management (create, read, delete, list) 4. **Web Service**: REST API that uses all other services @@ -29,6 +29,14 @@ Just start the web service as shown below, then open http://localhost:42096 in y Authentication and profile features are available via the UI. The static UI interacts with the REST API provided by the web service. +### Tag Features + +The blog allows you to: +- Add tags to posts +- Remove tags from posts +- Filter the feed to show posts with a specific tag +- Browse all available tags + ## Getting Started ### Prerequisites @@ -129,6 +137,19 @@ The REST API and web interface will be available at http://localhost:42096 - `POST /logout`: Log out the current user - `GET /users/me`: Get the current session user info +### Tags + +- `POST /posts/:id/tags`: Add a tag to a post + ```json + { + "tag": "tagname" + } + ``` +- `DELETE /posts/:id/tags/:tag`: Remove a tag from a post +- `GET /tags`: Get all available tags +- `GET /tags?post_id=:id`: Get tags for a specific post +- `GET /posts/by-tag/:tag`: Get posts with a specific tag + ## Project Structure ``` diff --git a/posts/handler/posts.go b/posts/handler/posts.go index 534a25c..7bf0be6 100644 --- a/posts/handler/posts.go +++ b/posts/handler/posts.go @@ -118,3 +118,136 @@ func (h *Handler) List(ctx context.Context, req *pb.ListRequest, res *pb.ListRes res.Total = 0 return nil } + +func (h *Handler) TagPost(ctx context.Context, req *pb.TagPostRequest, res *pb.TagPostResponse) error { + if req.PostId == "" || req.Tag == "" { + return nil + } + + rec, err := postStore.Read("post-" + req.PostId) + if err != nil || len(rec) == 0 { + return nil + } + + var post pb.Post + if err := json.Unmarshal(rec[0].Value, &post); err != nil { + return nil + } + + // Initialize tags slice if it doesn't exist + if post.Tags == nil { + post.Tags = []string{} + } + + // Check if tag already exists for this post + for _, tag := range post.Tags { + if tag == req.Tag { + // Tag already exists, return the post as is + res.Post = &post + return nil + } + } + + // Add the new tag + post.Tags = append(post.Tags, req.Tag) + post.UpdatedAt = time.Now().Unix() + + // Save the updated post + b, err := json.Marshal(&post) + if err == nil { + _ = postStore.Write(&store.Record{Key: "post-" + post.Id, Value: b}) + } + + res.Post = &post + return nil +} + +func (h *Handler) UntagPost(ctx context.Context, req *pb.UntagPostRequest, res *pb.UntagPostResponse) error { + if req.PostId == "" || req.Tag == "" { + return nil + } + + rec, err := postStore.Read("post-" + req.PostId) + if err != nil || len(rec) == 0 { + return nil + } + + var post pb.Post + if err := json.Unmarshal(rec[0].Value, &post); err != nil { + return nil + } + + if len(post.Tags) == 0 { + res.Post = &post + return nil + } + + updatedTags := []string{} + for _, tag := range post.Tags { + if tag != req.Tag { + updatedTags = append(updatedTags, tag) + } + } + + // Update the post only if tags were changed + if len(updatedTags) != len(post.Tags) { + post.Tags = updatedTags + post.UpdatedAt = time.Now().Unix() + + // Save the updated post + b, err := json.Marshal(&post) + if err == nil { + _ = postStore.Write(&store.Record{Key: "post-" + post.Id, Value: b}) + } + } + + res.Post = &post + return nil +} + +func (h *Handler) ListTags(ctx context.Context, req *pb.ListTagsRequest, res *pb.ListTagsResponse) error { + // If postId is specified, get tags for that specific post + if req.PostId != "" { + rec, err := postStore.Read("post-" + req.PostId) + if err != nil || len(rec) == 0 { + return nil + } + + var post pb.Post + if err := json.Unmarshal(rec[0].Value, &post); err != nil { + return nil + } + + res.Tags = post.Tags + return nil + } + + // Otherwise, collect all unique tags across all posts + allTags := make(map[string]struct{}) + + rec, err := postStore.Read("post-", store.ReadPrefix()) + if err != nil || len(rec) == 0 { + return nil + } + + for _, r := range rec { + var post pb.Post + if err := json.Unmarshal(r.Value, &post); err == nil { + for _, tag := range post.Tags { + allTags[tag] = struct{}{} + } + } + } + + // Convert map keys to slice + uniqueTags := make([]string, 0, len(allTags)) + for tag := range allTags { + uniqueTags = append(uniqueTags, tag) + } + + // Sort tags alphabetically for consistent output + sort.Strings(uniqueTags) + + res.Tags = uniqueTags + return nil +} diff --git a/posts/proto/posts.pb.go b/posts/proto/posts.pb.go index 9cb0caa..0cdd92d 100644 --- a/posts/proto/posts.pb.go +++ b/posts/proto/posts.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.3 +// protoc-gen-go v1.36.1 +// protoc v3.21.12 // source: posts/proto/posts.proto package posts @@ -21,23 +21,20 @@ const ( ) type LinkPreview struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + Image string `protobuf:"bytes,4,opt,name=image,proto3" json:"image,omitempty"` unknownFields protoimpl.UnknownFields - - Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` - Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` - Image string `protobuf:"bytes,4,opt,name=image,proto3" json:"image,omitempty"` + sizeCache protoimpl.SizeCache } func (x *LinkPreview) Reset() { *x = LinkPreview{} - if protoimpl.UnsafeEnabled { - mi := &file_posts_proto_posts_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_posts_proto_posts_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *LinkPreview) String() string { @@ -48,7 +45,7 @@ func (*LinkPreview) ProtoMessage() {} func (x *LinkPreview) ProtoReflect() protoreflect.Message { mi := &file_posts_proto_posts_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -92,27 +89,25 @@ func (x *LinkPreview) GetImage() string { } type Post struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + Content string `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` + AuthorId string `protobuf:"bytes,4,opt,name=author_id,json=authorId,proto3" json:"author_id,omitempty"` + AuthorName string `protobuf:"bytes,5,opt,name=author_name,json=authorName,proto3" json:"author_name,omitempty"` + CreatedAt int64 `protobuf:"varint,6,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + UpdatedAt int64 `protobuf:"varint,7,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` + LinkPreview *LinkPreview `protobuf:"bytes,8,opt,name=link_preview,json=linkPreview,proto3" json:"link_preview,omitempty"` + Tags []string `protobuf:"bytes,9,rep,name=tags,proto3" json:"tags,omitempty"` unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` - Content string `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` - AuthorId string `protobuf:"bytes,4,opt,name=author_id,json=authorId,proto3" json:"author_id,omitempty"` - AuthorName string `protobuf:"bytes,5,opt,name=author_name,json=authorName,proto3" json:"author_name,omitempty"` - CreatedAt int64 `protobuf:"varint,6,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - UpdatedAt int64 `protobuf:"varint,7,opt,name=updated_at,json=updatedAt,proto3" json:"updated_at,omitempty"` - LinkPreview *LinkPreview `protobuf:"bytes,8,opt,name=link_preview,json=linkPreview,proto3" json:"link_preview,omitempty"` + sizeCache protoimpl.SizeCache } func (x *Post) Reset() { *x = Post{} - if protoimpl.UnsafeEnabled { - mi := &file_posts_proto_posts_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_posts_proto_posts_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Post) String() string { @@ -123,7 +118,7 @@ func (*Post) ProtoMessage() {} func (x *Post) ProtoReflect() protoreflect.Message { mi := &file_posts_proto_posts_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -194,24 +189,28 @@ func (x *Post) GetLinkPreview() *LinkPreview { return nil } +func (x *Post) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + type CreateRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + Content string `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` + AuthorId string `protobuf:"bytes,3,opt,name=author_id,json=authorId,proto3" json:"author_id,omitempty"` + AuthorName string `protobuf:"bytes,4,opt,name=author_name,json=authorName,proto3" json:"author_name,omitempty"` unknownFields protoimpl.UnknownFields - - Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` - Content string `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` - AuthorId string `protobuf:"bytes,3,opt,name=author_id,json=authorId,proto3" json:"author_id,omitempty"` - AuthorName string `protobuf:"bytes,4,opt,name=author_name,json=authorName,proto3" json:"author_name,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreateRequest) Reset() { *x = CreateRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_posts_proto_posts_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_posts_proto_posts_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateRequest) String() string { @@ -222,7 +221,7 @@ func (*CreateRequest) ProtoMessage() {} func (x *CreateRequest) ProtoReflect() protoreflect.Message { mi := &file_posts_proto_posts_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -266,20 +265,17 @@ func (x *CreateRequest) GetAuthorName() string { } type CreateResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Post *Post `protobuf:"bytes,1,opt,name=post,proto3" json:"post,omitempty"` unknownFields protoimpl.UnknownFields - - Post *Post `protobuf:"bytes,1,opt,name=post,proto3" json:"post,omitempty"` + sizeCache protoimpl.SizeCache } func (x *CreateResponse) Reset() { *x = CreateResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_posts_proto_posts_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_posts_proto_posts_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *CreateResponse) String() string { @@ -290,7 +286,7 @@ func (*CreateResponse) ProtoMessage() {} func (x *CreateResponse) ProtoReflect() protoreflect.Message { mi := &file_posts_proto_posts_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -313,20 +309,17 @@ func (x *CreateResponse) GetPost() *Post { } type ReadRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ReadRequest) Reset() { *x = ReadRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_posts_proto_posts_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_posts_proto_posts_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReadRequest) String() string { @@ -337,7 +330,7 @@ func (*ReadRequest) ProtoMessage() {} func (x *ReadRequest) ProtoReflect() protoreflect.Message { mi := &file_posts_proto_posts_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -360,20 +353,17 @@ func (x *ReadRequest) GetId() string { } type ReadResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Post *Post `protobuf:"bytes,1,opt,name=post,proto3" json:"post,omitempty"` unknownFields protoimpl.UnknownFields - - Post *Post `protobuf:"bytes,1,opt,name=post,proto3" json:"post,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ReadResponse) Reset() { *x = ReadResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_posts_proto_posts_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_posts_proto_posts_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReadResponse) String() string { @@ -384,7 +374,7 @@ func (*ReadResponse) ProtoMessage() {} func (x *ReadResponse) ProtoReflect() protoreflect.Message { mi := &file_posts_proto_posts_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -407,22 +397,19 @@ func (x *ReadResponse) GetPost() *Post { } type UpdateRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` + Content string `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` - Content string `protobuf:"bytes,3,opt,name=content,proto3" json:"content,omitempty"` + sizeCache protoimpl.SizeCache } func (x *UpdateRequest) Reset() { *x = UpdateRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_posts_proto_posts_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_posts_proto_posts_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *UpdateRequest) String() string { @@ -433,7 +420,7 @@ func (*UpdateRequest) ProtoMessage() {} func (x *UpdateRequest) ProtoReflect() protoreflect.Message { mi := &file_posts_proto_posts_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -470,20 +457,17 @@ func (x *UpdateRequest) GetContent() string { } type UpdateResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Post *Post `protobuf:"bytes,1,opt,name=post,proto3" json:"post,omitempty"` unknownFields protoimpl.UnknownFields - - Post *Post `protobuf:"bytes,1,opt,name=post,proto3" json:"post,omitempty"` + sizeCache protoimpl.SizeCache } func (x *UpdateResponse) Reset() { *x = UpdateResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_posts_proto_posts_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_posts_proto_posts_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *UpdateResponse) String() string { @@ -494,7 +478,7 @@ func (*UpdateResponse) ProtoMessage() {} func (x *UpdateResponse) ProtoReflect() protoreflect.Message { mi := &file_posts_proto_posts_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -517,20 +501,17 @@ func (x *UpdateResponse) GetPost() *Post { } type DeleteRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields - - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + sizeCache protoimpl.SizeCache } func (x *DeleteRequest) Reset() { *x = DeleteRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_posts_proto_posts_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_posts_proto_posts_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DeleteRequest) String() string { @@ -541,7 +522,7 @@ func (*DeleteRequest) ProtoMessage() {} func (x *DeleteRequest) ProtoReflect() protoreflect.Message { mi := &file_posts_proto_posts_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -564,18 +545,16 @@ func (x *DeleteRequest) GetId() string { } type DeleteResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *DeleteResponse) Reset() { *x = DeleteResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_posts_proto_posts_proto_msgTypes[9] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_posts_proto_posts_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *DeleteResponse) String() string { @@ -586,7 +565,7 @@ func (*DeleteResponse) ProtoMessage() {} func (x *DeleteResponse) ProtoReflect() protoreflect.Message { mi := &file_posts_proto_posts_proto_msgTypes[9] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -602,21 +581,18 @@ func (*DeleteResponse) Descriptor() ([]byte, []int) { } type ListRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Page int32 `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"` + Limit int32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` unknownFields protoimpl.UnknownFields - - Page int32 `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"` - Limit int32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListRequest) Reset() { *x = ListRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_posts_proto_posts_proto_msgTypes[10] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_posts_proto_posts_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListRequest) String() string { @@ -627,7 +603,7 @@ func (*ListRequest) ProtoMessage() {} func (x *ListRequest) ProtoReflect() protoreflect.Message { mi := &file_posts_proto_posts_proto_msgTypes[10] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -657,22 +633,19 @@ func (x *ListRequest) GetLimit() int32 { } type ListResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Posts []*Post `protobuf:"bytes,1,rep,name=posts,proto3" json:"posts,omitempty"` + Total int32 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` + Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` unknownFields protoimpl.UnknownFields - - Posts []*Post `protobuf:"bytes,1,rep,name=posts,proto3" json:"posts,omitempty"` - Total int32 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` - Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ListResponse) Reset() { *x = ListResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_posts_proto_posts_proto_msgTypes[11] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_posts_proto_posts_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ListResponse) String() string { @@ -683,7 +656,7 @@ func (*ListResponse) ProtoMessage() {} func (x *ListResponse) ProtoReflect() protoreflect.Message { mi := &file_posts_proto_posts_proto_msgTypes[11] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -719,6 +692,294 @@ func (x *ListResponse) GetMessage() string { return "" } +type TagPostRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + PostId string `protobuf:"bytes,1,opt,name=post_id,json=postId,proto3" json:"post_id,omitempty"` + Tag string `protobuf:"bytes,2,opt,name=tag,proto3" json:"tag,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TagPostRequest) Reset() { + *x = TagPostRequest{} + mi := &file_posts_proto_posts_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TagPostRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TagPostRequest) ProtoMessage() {} + +func (x *TagPostRequest) ProtoReflect() protoreflect.Message { + mi := &file_posts_proto_posts_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TagPostRequest.ProtoReflect.Descriptor instead. +func (*TagPostRequest) Descriptor() ([]byte, []int) { + return file_posts_proto_posts_proto_rawDescGZIP(), []int{12} +} + +func (x *TagPostRequest) GetPostId() string { + if x != nil { + return x.PostId + } + return "" +} + +func (x *TagPostRequest) GetTag() string { + if x != nil { + return x.Tag + } + return "" +} + +type TagPostResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Post *Post `protobuf:"bytes,1,opt,name=post,proto3" json:"post,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TagPostResponse) Reset() { + *x = TagPostResponse{} + mi := &file_posts_proto_posts_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TagPostResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TagPostResponse) ProtoMessage() {} + +func (x *TagPostResponse) ProtoReflect() protoreflect.Message { + mi := &file_posts_proto_posts_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TagPostResponse.ProtoReflect.Descriptor instead. +func (*TagPostResponse) Descriptor() ([]byte, []int) { + return file_posts_proto_posts_proto_rawDescGZIP(), []int{13} +} + +func (x *TagPostResponse) GetPost() *Post { + if x != nil { + return x.Post + } + return nil +} + +type UntagPostRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + PostId string `protobuf:"bytes,1,opt,name=post_id,json=postId,proto3" json:"post_id,omitempty"` + Tag string `protobuf:"bytes,2,opt,name=tag,proto3" json:"tag,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UntagPostRequest) Reset() { + *x = UntagPostRequest{} + mi := &file_posts_proto_posts_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UntagPostRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UntagPostRequest) ProtoMessage() {} + +func (x *UntagPostRequest) ProtoReflect() protoreflect.Message { + mi := &file_posts_proto_posts_proto_msgTypes[14] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UntagPostRequest.ProtoReflect.Descriptor instead. +func (*UntagPostRequest) Descriptor() ([]byte, []int) { + return file_posts_proto_posts_proto_rawDescGZIP(), []int{14} +} + +func (x *UntagPostRequest) GetPostId() string { + if x != nil { + return x.PostId + } + return "" +} + +func (x *UntagPostRequest) GetTag() string { + if x != nil { + return x.Tag + } + return "" +} + +type UntagPostResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Post *Post `protobuf:"bytes,1,opt,name=post,proto3" json:"post,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UntagPostResponse) Reset() { + *x = UntagPostResponse{} + mi := &file_posts_proto_posts_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UntagPostResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UntagPostResponse) ProtoMessage() {} + +func (x *UntagPostResponse) ProtoReflect() protoreflect.Message { + mi := &file_posts_proto_posts_proto_msgTypes[15] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UntagPostResponse.ProtoReflect.Descriptor instead. +func (*UntagPostResponse) Descriptor() ([]byte, []int) { + return file_posts_proto_posts_proto_rawDescGZIP(), []int{15} +} + +func (x *UntagPostResponse) GetPost() *Post { + if x != nil { + return x.Post + } + return nil +} + +type ListTagsRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + PostId string `protobuf:"bytes,1,opt,name=post_id,json=postId,proto3" json:"post_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListTagsRequest) Reset() { + *x = ListTagsRequest{} + mi := &file_posts_proto_posts_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListTagsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListTagsRequest) ProtoMessage() {} + +func (x *ListTagsRequest) ProtoReflect() protoreflect.Message { + mi := &file_posts_proto_posts_proto_msgTypes[16] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListTagsRequest.ProtoReflect.Descriptor instead. +func (*ListTagsRequest) Descriptor() ([]byte, []int) { + return file_posts_proto_posts_proto_rawDescGZIP(), []int{16} +} + +func (x *ListTagsRequest) GetPostId() string { + if x != nil { + return x.PostId + } + return "" +} + +type ListTagsResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Tags []string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"` + Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListTagsResponse) Reset() { + *x = ListTagsResponse{} + mi := &file_posts_proto_posts_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListTagsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListTagsResponse) ProtoMessage() {} + +func (x *ListTagsResponse) ProtoReflect() protoreflect.Message { + mi := &file_posts_proto_posts_proto_msgTypes[17] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListTagsResponse.ProtoReflect.Descriptor instead. +func (*ListTagsResponse) Descriptor() ([]byte, []int) { + return file_posts_proto_posts_proto_rawDescGZIP(), []int{17} +} + +func (x *ListTagsResponse) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +func (x *ListTagsResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + var File_posts_proto_posts_proto protoreflect.FileDescriptor var file_posts_proto_posts_proto_rawDesc = []byte{ @@ -731,7 +992,7 @@ var file_posts_proto_posts_proto_rawDesc = []byte{ 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x22, - 0xf9, 0x01, 0x0a, 0x04, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x8d, 0x02, 0x0a, 0x04, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, @@ -746,64 +1007,98 @@ var file_posts_proto_posts_proto_rawDesc = []byte{ 0x65, 0x64, 0x41, 0x74, 0x12, 0x35, 0x0a, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x0b, - 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x22, 0x7d, 0x0a, 0x0d, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, - 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, - 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, - 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x75, 0x74, - 0x68, 0x6f, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x31, 0x0a, 0x0e, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x04, - 0x70, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x6f, 0x73, - 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x22, 0x1d, 0x0a, - 0x0b, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x2f, 0x0a, 0x0c, - 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x04, - 0x70, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x6f, 0x73, - 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x22, 0x4f, 0x0a, - 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, - 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, - 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x31, - 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12, 0x12, 0x0a, 0x04, 0x74, + 0x61, 0x67, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, + 0x7d, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x1f, 0x0a, + 0x0b, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x31, + 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x04, 0x70, 0x6f, 0x73, - 0x74, 0x22, 0x1f, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x74, 0x22, 0x1d, 0x0a, 0x0b, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x22, 0x2f, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x1f, 0x0a, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, + 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x04, 0x70, 0x6f, 0x73, + 0x74, 0x22, 0x4f, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x22, 0x10, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x37, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x61, 0x0a, - 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, - 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, - 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, - 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x32, 0x98, 0x02, 0x0a, 0x05, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x06, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x6f, 0x73, - 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x12, 0x2e, 0x70, 0x6f, - 0x73, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x13, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x12, 0x14, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x37, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x70, 0x6f, 0x73, 0x74, - 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x15, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, - 0x12, 0x12, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0f, 0x5a, 0x0d, 0x2e, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x22, 0x31, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, + 0x04, 0x70, 0x6f, 0x73, 0x74, 0x22, 0x1f, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x10, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x37, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x22, 0x61, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x21, 0x0a, 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0b, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x05, 0x70, + 0x6f, 0x73, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x22, 0x3b, 0x0a, 0x0e, 0x54, 0x61, 0x67, 0x50, 0x6f, 0x73, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x6f, 0x73, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, + 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61, + 0x67, 0x22, 0x32, 0x0a, 0x0f, 0x54, 0x61, 0x67, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x52, + 0x04, 0x70, 0x6f, 0x73, 0x74, 0x22, 0x3d, 0x0a, 0x10, 0x55, 0x6e, 0x74, 0x61, 0x67, 0x50, 0x6f, + 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x6f, 0x73, + 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x73, 0x74, + 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x74, 0x61, 0x67, 0x22, 0x34, 0x0a, 0x11, 0x55, 0x6e, 0x74, 0x61, 0x67, 0x50, 0x6f, 0x73, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x04, 0x70, 0x6f, 0x73, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, + 0x50, 0x6f, 0x73, 0x74, 0x52, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x22, 0x2a, 0x0a, 0x0f, 0x4c, 0x69, + 0x73, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, + 0x07, 0x70, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x70, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x22, 0x40, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, + 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, + 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x18, + 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0xd5, 0x03, 0x0a, 0x05, 0x50, 0x6f, 0x73, + 0x74, 0x73, 0x12, 0x37, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x70, + 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x52, + 0x65, 0x61, 0x64, 0x12, 0x12, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, + 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, + 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, + 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x12, 0x14, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x31, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, + 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, + 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x07, 0x54, 0x61, 0x67, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x15, + 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x61, 0x67, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x54, 0x61, + 0x67, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x40, 0x0a, 0x09, 0x55, 0x6e, 0x74, 0x61, 0x67, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x17, 0x2e, 0x70, + 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x55, 0x6e, 0x74, 0x61, 0x67, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x55, 0x6e, + 0x74, 0x61, 0x67, 0x50, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x3d, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x67, 0x73, 0x12, 0x16, 0x2e, + 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x42, 0x0f, 0x5a, 0x0d, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x70, 0x6f, 0x73, 0x74, + 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -818,20 +1113,26 @@ func file_posts_proto_posts_proto_rawDescGZIP() []byte { return file_posts_proto_posts_proto_rawDescData } -var file_posts_proto_posts_proto_msgTypes = make([]protoimpl.MessageInfo, 12) -var file_posts_proto_posts_proto_goTypes = []interface{}{ - (*LinkPreview)(nil), // 0: posts.LinkPreview - (*Post)(nil), // 1: posts.Post - (*CreateRequest)(nil), // 2: posts.CreateRequest - (*CreateResponse)(nil), // 3: posts.CreateResponse - (*ReadRequest)(nil), // 4: posts.ReadRequest - (*ReadResponse)(nil), // 5: posts.ReadResponse - (*UpdateRequest)(nil), // 6: posts.UpdateRequest - (*UpdateResponse)(nil), // 7: posts.UpdateResponse - (*DeleteRequest)(nil), // 8: posts.DeleteRequest - (*DeleteResponse)(nil), // 9: posts.DeleteResponse - (*ListRequest)(nil), // 10: posts.ListRequest - (*ListResponse)(nil), // 11: posts.ListResponse +var file_posts_proto_posts_proto_msgTypes = make([]protoimpl.MessageInfo, 18) +var file_posts_proto_posts_proto_goTypes = []any{ + (*LinkPreview)(nil), // 0: posts.LinkPreview + (*Post)(nil), // 1: posts.Post + (*CreateRequest)(nil), // 2: posts.CreateRequest + (*CreateResponse)(nil), // 3: posts.CreateResponse + (*ReadRequest)(nil), // 4: posts.ReadRequest + (*ReadResponse)(nil), // 5: posts.ReadResponse + (*UpdateRequest)(nil), // 6: posts.UpdateRequest + (*UpdateResponse)(nil), // 7: posts.UpdateResponse + (*DeleteRequest)(nil), // 8: posts.DeleteRequest + (*DeleteResponse)(nil), // 9: posts.DeleteResponse + (*ListRequest)(nil), // 10: posts.ListRequest + (*ListResponse)(nil), // 11: posts.ListResponse + (*TagPostRequest)(nil), // 12: posts.TagPostRequest + (*TagPostResponse)(nil), // 13: posts.TagPostResponse + (*UntagPostRequest)(nil), // 14: posts.UntagPostRequest + (*UntagPostResponse)(nil), // 15: posts.UntagPostResponse + (*ListTagsRequest)(nil), // 16: posts.ListTagsRequest + (*ListTagsResponse)(nil), // 17: posts.ListTagsResponse } var file_posts_proto_posts_proto_depIdxs = []int32{ 0, // 0: posts.Post.link_preview:type_name -> posts.LinkPreview @@ -839,21 +1140,29 @@ var file_posts_proto_posts_proto_depIdxs = []int32{ 1, // 2: posts.ReadResponse.post:type_name -> posts.Post 1, // 3: posts.UpdateResponse.post:type_name -> posts.Post 1, // 4: posts.ListResponse.posts:type_name -> posts.Post - 2, // 5: posts.Posts.Create:input_type -> posts.CreateRequest - 4, // 6: posts.Posts.Read:input_type -> posts.ReadRequest - 6, // 7: posts.Posts.Update:input_type -> posts.UpdateRequest - 8, // 8: posts.Posts.Delete:input_type -> posts.DeleteRequest - 10, // 9: posts.Posts.List:input_type -> posts.ListRequest - 3, // 10: posts.Posts.Create:output_type -> posts.CreateResponse - 5, // 11: posts.Posts.Read:output_type -> posts.ReadResponse - 7, // 12: posts.Posts.Update:output_type -> posts.UpdateResponse - 9, // 13: posts.Posts.Delete:output_type -> posts.DeleteResponse - 11, // 14: posts.Posts.List:output_type -> posts.ListResponse - 10, // [10:15] is the sub-list for method output_type - 5, // [5:10] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 1, // 5: posts.TagPostResponse.post:type_name -> posts.Post + 1, // 6: posts.UntagPostResponse.post:type_name -> posts.Post + 2, // 7: posts.Posts.Create:input_type -> posts.CreateRequest + 4, // 8: posts.Posts.Read:input_type -> posts.ReadRequest + 6, // 9: posts.Posts.Update:input_type -> posts.UpdateRequest + 8, // 10: posts.Posts.Delete:input_type -> posts.DeleteRequest + 10, // 11: posts.Posts.List:input_type -> posts.ListRequest + 12, // 12: posts.Posts.TagPost:input_type -> posts.TagPostRequest + 14, // 13: posts.Posts.UntagPost:input_type -> posts.UntagPostRequest + 16, // 14: posts.Posts.ListTags:input_type -> posts.ListTagsRequest + 3, // 15: posts.Posts.Create:output_type -> posts.CreateResponse + 5, // 16: posts.Posts.Read:output_type -> posts.ReadResponse + 7, // 17: posts.Posts.Update:output_type -> posts.UpdateResponse + 9, // 18: posts.Posts.Delete:output_type -> posts.DeleteResponse + 11, // 19: posts.Posts.List:output_type -> posts.ListResponse + 13, // 20: posts.Posts.TagPost:output_type -> posts.TagPostResponse + 15, // 21: posts.Posts.UntagPost:output_type -> posts.UntagPostResponse + 17, // 22: posts.Posts.ListTags:output_type -> posts.ListTagsResponse + 15, // [15:23] is the sub-list for method output_type + 7, // [7:15] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name } func init() { file_posts_proto_posts_proto_init() } @@ -861,159 +1170,13 @@ func file_posts_proto_posts_proto_init() { if File_posts_proto_posts_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_posts_proto_posts_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LinkPreview); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_posts_proto_posts_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Post); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_posts_proto_posts_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_posts_proto_posts_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_posts_proto_posts_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReadRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_posts_proto_posts_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReadResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_posts_proto_posts_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_posts_proto_posts_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_posts_proto_posts_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_posts_proto_posts_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_posts_proto_posts_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_posts_proto_posts_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_posts_proto_posts_proto_rawDesc, NumEnums: 0, - NumMessages: 12, + NumMessages: 18, NumExtensions: 0, NumServices: 1, }, diff --git a/posts/proto/posts.pb.micro.go b/posts/proto/posts.pb.micro.go index 349932f..40a7d7a 100644 --- a/posts/proto/posts.pb.micro.go +++ b/posts/proto/posts.pb.micro.go @@ -33,6 +33,10 @@ type PostsService interface { Update(ctx context.Context, in *UpdateRequest, opts ...client.CallOption) (*UpdateResponse, error) Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error) List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) + // == Tags == + TagPost(ctx context.Context, in *TagPostRequest, opts ...client.CallOption) (*TagPostResponse, error) + UntagPost(ctx context.Context, in *UntagPostRequest, opts ...client.CallOption) (*UntagPostResponse, error) + ListTags(ctx context.Context, in *ListTagsRequest, opts ...client.CallOption) (*ListTagsResponse, error) } type postsService struct { @@ -97,6 +101,36 @@ func (c *postsService) List(ctx context.Context, in *ListRequest, opts ...client return out, nil } +func (c *postsService) TagPost(ctx context.Context, in *TagPostRequest, opts ...client.CallOption) (*TagPostResponse, error) { + req := c.c.NewRequest(c.name, "Posts.TagPost", in) + out := new(TagPostResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *postsService) UntagPost(ctx context.Context, in *UntagPostRequest, opts ...client.CallOption) (*UntagPostResponse, error) { + req := c.c.NewRequest(c.name, "Posts.UntagPost", in) + out := new(UntagPostResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *postsService) ListTags(ctx context.Context, in *ListTagsRequest, opts ...client.CallOption) (*ListTagsResponse, error) { + req := c.c.NewRequest(c.name, "Posts.ListTags", in) + out := new(ListTagsResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // Server API for Posts service type PostsHandler interface { @@ -105,6 +139,10 @@ type PostsHandler interface { Update(context.Context, *UpdateRequest, *UpdateResponse) error Delete(context.Context, *DeleteRequest, *DeleteResponse) error List(context.Context, *ListRequest, *ListResponse) error + // == Tags == + TagPost(context.Context, *TagPostRequest, *TagPostResponse) error + UntagPost(context.Context, *UntagPostRequest, *UntagPostResponse) error + ListTags(context.Context, *ListTagsRequest, *ListTagsResponse) error } func RegisterPostsHandler(s server.Server, hdlr PostsHandler, opts ...server.HandlerOption) error { @@ -114,6 +152,9 @@ func RegisterPostsHandler(s server.Server, hdlr PostsHandler, opts ...server.Han Update(ctx context.Context, in *UpdateRequest, out *UpdateResponse) error Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error List(ctx context.Context, in *ListRequest, out *ListResponse) error + TagPost(ctx context.Context, in *TagPostRequest, out *TagPostResponse) error + UntagPost(ctx context.Context, in *UntagPostRequest, out *UntagPostResponse) error + ListTags(ctx context.Context, in *ListTagsRequest, out *ListTagsResponse) error } type Posts struct { posts @@ -145,3 +186,15 @@ func (h *postsHandler) Delete(ctx context.Context, in *DeleteRequest, out *Delet func (h *postsHandler) List(ctx context.Context, in *ListRequest, out *ListResponse) error { return h.PostsHandler.List(ctx, in, out) } + +func (h *postsHandler) TagPost(ctx context.Context, in *TagPostRequest, out *TagPostResponse) error { + return h.PostsHandler.TagPost(ctx, in, out) +} + +func (h *postsHandler) UntagPost(ctx context.Context, in *UntagPostRequest, out *UntagPostResponse) error { + return h.PostsHandler.UntagPost(ctx, in, out) +} + +func (h *postsHandler) ListTags(ctx context.Context, in *ListTagsRequest, out *ListTagsResponse) error { + return h.PostsHandler.ListTags(ctx, in, out) +} diff --git a/posts/proto/posts.proto b/posts/proto/posts.proto index 72ea770..9f8eb09 100644 --- a/posts/proto/posts.proto +++ b/posts/proto/posts.proto @@ -10,6 +10,11 @@ service Posts { rpc Update(UpdateRequest) returns (UpdateResponse) {}; rpc Delete(DeleteRequest) returns (DeleteResponse) {}; rpc List(ListRequest) returns (ListResponse) {}; + + // == Tags == + rpc TagPost(TagPostRequest) returns (TagPostResponse) {}; + rpc UntagPost(UntagPostRequest) returns (UntagPostResponse) {}; + rpc ListTags(ListTagsRequest) returns (ListTagsResponse) {}; } message LinkPreview { @@ -28,6 +33,7 @@ message Post { int64 created_at = 6; int64 updated_at = 7; LinkPreview link_preview = 8; + repeated string tags = 9; } message CreateRequest { @@ -74,4 +80,28 @@ message ListResponse { repeated Post posts = 1; int32 total = 2; string message = 3; +} + +message TagPostRequest { + string post_id = 1; + string tag = 2; +} + +message TagPostResponse { + Post post = 1; +} + +message UntagPostRequest { + string post_id = 1; + string tag = 2; +} +message UntagPostResponse { + Post post = 1; +} +message ListTagsRequest { + string post_id = 1; +} +message ListTagsResponse { + repeated string tags = 1; + string message = 2; } \ No newline at end of file diff --git a/web/main.go b/web/main.go index a1141d3..50b240f 100644 --- a/web/main.go +++ b/web/main.go @@ -297,6 +297,102 @@ func main() { c.JSON(http.StatusOK, gin.H{"user": gin.H{"id": userID, "name": userName}}) }) + // === Tags endpoints === + // Add tag to post + router.POST("/posts/:id/tags", func(c *gin.Context) { + postID := c.Param("id") + var req struct { + Tag string `json:"tag"` + } + if err := c.BindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + // Authenticate user + _, exists := c.Get("user_id") + if !exists { + c.JSON(http.StatusUnauthorized, gin.H{"error": "login required"}) + return + } + + resp, err := postClient.TagPost(context.Background(), &postProto.TagPostRequest{ + PostId: postID, + Tag: req.Tag, + }) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, resp) + }) + + // Remove tag from post + router.DELETE("/posts/:id/tags/:tag", func(c *gin.Context) { + postID := c.Param("id") + tag := c.Param("tag") + + // Authenticate user + _, exists := c.Get("user_id") + if !exists { + c.JSON(http.StatusUnauthorized, gin.H{"error": "login required"}) + return + } + + resp, err := postClient.UntagPost(context.Background(), &postProto.UntagPostRequest{ + PostId: postID, + Tag: tag, + }) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, resp) + }) + + // Get all tags (or tags for a specific post) + router.GET("/tags", func(c *gin.Context) { + postID := c.Query("post_id") + + resp, err := postClient.ListTags(context.Background(), &postProto.ListTagsRequest{ + PostId: postID, + }) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + c.JSON(http.StatusOK, resp) + }) + + // Get posts by tag + router.GET("/posts/by-tag/:tag", func(c *gin.Context) { + tag := c.Param("tag") + + // First get all posts + resp, err := postClient.List(context.Background(), &postProto.ListRequest{}) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + // Filter posts with the requested tag + var taggedPosts []*postProto.Post + for _, post := range resp.Posts { + for _, postTag := range post.Tags { + if postTag == tag { + taggedPosts = append(taggedPosts, post) + break + } + } + } + + c.JSON(http.StatusOK, gin.H{ + "posts": taggedPosts, + "total": len(taggedPosts), + "tag": tag, + }) + }) + // Serve all static files (css, js, etc.) from /static router.Static("/static", "./static") diff --git a/web/static/index.html b/web/static/index.html index 8e4c7e8..a4072e1 100644 --- a/web/static/index.html +++ b/web/static/index.html @@ -1,17 +1,23 @@ +