refactor: update memo tags

This commit is contained in:
Steven 2024-05-08 20:03:01 +08:00
parent 2c270438ec
commit d0655ece53
61 changed files with 1815 additions and 2855 deletions

View File

@ -11,7 +11,6 @@ tags:
- name: MarkdownService
- name: ResourceService
- name: MemoService
- name: TagService
- name: WebhookService
- name: WorkspaceService
- name: WorkspaceSettingService
@ -494,137 +493,6 @@ paths:
type: string
tags:
- ResourceService
/api/v1/tags:
get:
summary: ListTags lists tags.
operationId: TagService_ListTags
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ListTagsResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/googlerpcStatus'
tags:
- TagService
delete:
summary: DeleteTag deletes a tag.
operationId: TagService_DeleteTag
responses:
"200":
description: A successful response.
schema:
type: object
properties: {}
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/googlerpcStatus'
parameters:
- name: tag.name
in: query
required: false
type: string
- name: tag.creator
description: |-
The creator of tags.
Format: users/{id}
in: query
required: false
type: string
tags:
- TagService
post:
summary: UpsertTag upserts a tag.
operationId: TagService_UpsertTag
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1Tag'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/googlerpcStatus'
parameters:
- name: body
in: body
required: true
schema:
$ref: '#/definitions/v1UpsertTagRequest'
tags:
- TagService
/api/v1/tags/suggestion:
get:
summary: GetTagSuggestions gets tag suggestions from the user's memos.
operationId: TagService_GetTagSuggestions
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1GetTagSuggestionsResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/googlerpcStatus'
parameters:
- name: user
description: |-
The creator of tags.
Format: users/{id}
in: query
required: false
type: string
tags:
- TagService
/api/v1/tags:batchUpsert:
post:
summary: BatchUpsertTag upserts multiple tags.
operationId: TagService_BatchUpsertTag
responses:
"200":
description: A successful response.
schema:
type: object
properties: {}
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/googlerpcStatus'
parameters:
- name: body
in: body
required: true
schema:
$ref: '#/definitions/v1BatchUpsertTagRequest'
tags:
- TagService
/api/v1/tags:rename:
patch:
summary: |-
RenameTag renames a tag.
All related memos will be updated.
operationId: TagService_RenameTag
responses:
"200":
description: A successful response.
schema:
type: object
properties: {}
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/googlerpcStatus'
parameters:
- name: body
in: body
required: true
schema:
$ref: '#/definitions/v1RenameTagRequest'
tags:
- TagService
/api/v1/users:
get:
summary: ListUsers returns a list of users.
@ -1044,6 +912,10 @@ paths:
readOnly: true
visibility:
$ref: '#/definitions/v1Visibility'
tags:
type: array
items:
type: string
pinned:
type: boolean
parentId:
@ -1605,6 +1477,98 @@ paths:
pattern: users/[^/]+
tags:
- UserService
/api/v1/{parent}/tags:
get:
summary: ListMemoTags lists tags for a memo.
operationId: MemoService_ListMemoTags
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/v1ListMemoTagsResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/googlerpcStatus'
parameters:
- name: parent
description: |-
The parent, who owns the tags.
Format: memos/{id}. Use "memos/-" to list all tags.
in: path
required: true
type: string
pattern: memos/[^/]+
- name: rebuild
description: Rebuild the tags.
in: query
required: false
type: boolean
tags:
- MemoService
/api/v1/{parent}/tags/{tag}:
delete:
summary: DeleteMemoTag deletes a tag for a memo.
operationId: MemoService_DeleteMemoTag
responses:
"200":
description: A successful response.
schema:
type: object
properties: {}
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/googlerpcStatus'
parameters:
- name: parent
description: |-
The parent, who owns the tags.
Format: memos/{id}. Use "memos/-" to delete all tags.
in: path
required: true
type: string
pattern: memos/[^/]+
- name: tag
in: path
required: true
type: string
- name: deleteRelatedMemos
in: query
required: false
type: boolean
tags:
- MemoService
/api/v1/{parent}/tags:rename:
patch:
summary: RenameMemoTag renames a tag for a memo.
operationId: MemoService_RenameMemoTag
responses:
"200":
description: A successful response.
schema:
type: object
properties: {}
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/googlerpcStatus'
parameters:
- name: parent
description: |-
The parent, who owns the tags.
Format: memos/{id}. Use "memos/-" to rename all tags.
in: path
required: true
type: string
pattern: memos/[^/]+
- name: body
in: body
required: true
schema:
$ref: '#/definitions/MemoServiceRenameMemoTagBody'
tags:
- MemoService
/api/v1/{resource.name}:
patch:
summary: UpdateResource updates a resource.
@ -1850,6 +1814,13 @@ paths:
tags:
- ResourceService
definitions:
MemoServiceRenameMemoTagBody:
type: object
properties:
oldTag:
type: string
newTag:
type: string
MemoServiceSetMemoRelationsBody:
type: object
properties:
@ -2323,14 +2294,6 @@ definitions:
type: string
isRawText:
type: boolean
v1BatchUpsertTagRequest:
type: object
properties:
requests:
type: array
items:
type: object
$ref: '#/definitions/v1UpsertTagRequest'
v1BlockquoteNode:
type: object
properties:
@ -2406,13 +2369,6 @@ definitions:
content:
type: string
format: byte
v1GetTagSuggestionsResponse:
type: object
properties:
tags:
type: array
items:
type: string
v1GetUserMemosStatsResponse:
type: object
properties:
@ -2563,6 +2519,18 @@ definitions:
items:
type: object
$ref: '#/definitions/v1Resource'
v1ListMemoTagsResponse:
type: object
properties:
tagAmounts:
type: object
additionalProperties:
type: integer
format: int32
description: |-
tag_amounts is the amount of tags.
key is the tag name. e.g. "tag1".
value is the amount of the tag.
v1ListMemosResponse:
type: object
properties:
@ -2584,14 +2552,6 @@ definitions:
items:
type: object
$ref: '#/definitions/v1Resource'
v1ListTagsResponse:
type: object
properties:
tags:
type: array
items:
type: object
$ref: '#/definitions/v1Tag'
v1ListUserAccessTokensResponse:
type: object
properties:
@ -2672,6 +2632,10 @@ definitions:
readOnly: true
visibility:
$ref: '#/definitions/v1Visibility'
tags:
type: array
items:
type: string
pinned:
type: boolean
parentId:
@ -2888,18 +2852,6 @@ definitions:
type: string
params:
type: string
v1RenameTagRequest:
type: object
properties:
user:
type: string
title: |-
The creator of tags.
Format: users/{id}
oldName:
type: string
newName:
type: string
v1Resource:
type: object
properties:
@ -3013,16 +2965,6 @@ definitions:
items:
type: object
$ref: '#/definitions/TableNodeRow'
v1Tag:
type: object
properties:
name:
type: string
creator:
type: string
title: |-
The creator of tags.
Format: users/{id}
v1TagNode:
type: object
properties:
@ -3061,11 +3003,6 @@ definitions:
items:
type: object
$ref: '#/definitions/v1Node'
v1UpsertTagRequest:
type: object
properties:
name:
type: string
v1User:
type: object
properties:

View File

@ -61,3 +61,13 @@ func RandomString(n int) (string, error) {
}
return sb.String(), nil
}
// ReplaceString replaces all occurrences of old in slice with new.
func ReplaceString(slice []string, old, new string) []string {
for i, s := range slice {
if s == old {
slice[i] = new
}
}
return slice
}

View File

@ -57,6 +57,21 @@ service MemoService {
body: "*"
};
}
// ListMemoTags lists tags for a memo.
rpc ListMemoTags(ListMemoTagsRequest) returns (ListMemoTagsResponse) {
option (google.api.http) = {get: "/api/v1/{parent=memos/*}/tags"};
}
// RenameMemoTag renames a tag for a memo.
rpc RenameMemoTag(RenameMemoTagRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
patch: "/api/v1/{parent=memos/*}/tags:rename"
body: "*"
};
}
// DeleteMemoTag deletes a tag for a memo.
rpc DeleteMemoTag(DeleteMemoTagRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {delete: "/api/v1/{parent=memos/*}/tags/{tag}"};
}
// SetMemoResources sets resources for a memo.
rpc SetMemoResources(SetMemoResourcesRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
@ -155,15 +170,17 @@ message Memo {
Visibility visibility = 10;
bool pinned = 11;
repeated string tags = 11;
optional int32 parent_id = 12 [(google.api.field_behavior) = OUTPUT_ONLY];
bool pinned = 12;
repeated Resource resources = 13 [(google.api.field_behavior) = OUTPUT_ONLY];
optional int32 parent_id = 13 [(google.api.field_behavior) = OUTPUT_ONLY];
repeated MemoRelation relations = 14 [(google.api.field_behavior) = OUTPUT_ONLY];
repeated Resource resources = 14 [(google.api.field_behavior) = OUTPUT_ONLY];
repeated Reaction reactions = 15 [(google.api.field_behavior) = OUTPUT_ONLY];
repeated MemoRelation relations = 15 [(google.api.field_behavior) = OUTPUT_ONLY];
repeated Reaction reactions = 16 [(google.api.field_behavior) = OUTPUT_ONLY];
}
message CreateMemoRequest {
@ -230,6 +247,38 @@ message ExportMemosResponse {
bytes content = 1;
}
message ListMemoTagsRequest {
// The parent, who owns the tags.
// Format: memos/{id}. Use "memos/-" to list all tags.
string parent = 1;
// Rebuild the tags.
bool rebuild = 2;
}
message ListMemoTagsResponse {
// tag_amounts is the amount of tags.
// key is the tag name. e.g. "tag1".
// value is the amount of the tag.
map<string, int32> tag_amounts = 1;
}
message RenameMemoTagRequest {
// The parent, who owns the tags.
// Format: memos/{id}. Use "memos/-" to rename all tags.
string parent = 1;
string old_tag = 2;
string new_tag = 3;
}
message DeleteMemoTagRequest {
// The parent, who owns the tags.
// Format: memos/{id}. Use "memos/-" to delete all tags.
string parent = 1;
string tag = 2;
bool delete_related_memos = 3;
}
message SetMemoResourcesRequest {
// The name of the memo.
// Format: memos/{id}

View File

@ -1,88 +0,0 @@
syntax = "proto3";
package memos.api.v1;
import "google/api/annotations.proto";
import "google/protobuf/empty.proto";
option go_package = "gen/api/v1";
service TagService {
// UpsertTag upserts a tag.
rpc UpsertTag(UpsertTagRequest) returns (Tag) {
option (google.api.http) = {
post: "/api/v1/tags",
body: "*"
};
}
// BatchUpsertTag upserts multiple tags.
rpc BatchUpsertTag(BatchUpsertTagRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
post: "/api/v1/tags:batchUpsert",
body: "*"
};
}
// ListTags lists tags.
rpc ListTags(ListTagsRequest) returns (ListTagsResponse) {
option (google.api.http) = {get: "/api/v1/tags"};
}
// RenameTag renames a tag.
// All related memos will be updated.
rpc RenameTag(RenameTagRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
patch: "/api/v1/tags:rename",
body: "*"
};
}
// DeleteTag deletes a tag.
rpc DeleteTag(DeleteTagRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {delete: "/api/v1/tags"};
}
// GetTagSuggestions gets tag suggestions from the user's memos.
rpc GetTagSuggestions(GetTagSuggestionsRequest) returns (GetTagSuggestionsResponse) {
option (google.api.http) = {get: "/api/v1/tags/suggestion"};
}
}
message Tag {
string name = 1;
// The creator of tags.
// Format: users/{id}
string creator = 2;
}
message UpsertTagRequest {
string name = 1;
}
message BatchUpsertTagRequest {
repeated UpsertTagRequest requests = 1;
}
message ListTagsRequest {}
message ListTagsResponse {
repeated Tag tags = 1;
}
message RenameTagRequest {
// The creator of tags.
// Format: users/{id}
string user = 1;
string old_name = 2;
string new_name = 3;
}
message DeleteTagRequest {
Tag tag = 1;
}
message GetTagSuggestionsRequest {
// The creator of tags.
// Format: users/{id}
string user = 1;
}
message GetTagSuggestionsResponse {
repeated string tags = 1;
}

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: api/v1/activity_service.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: api/v1/auth_service.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: api/v1/common.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: api/v1/idp_service.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: api/v1/inbox_service.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: api/v1/markdown_service.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: api/v1/memo_relation_service.proto

File diff suppressed because it is too large Load Diff

View File

@ -359,6 +359,226 @@ func local_request_MemoService_ExportMemos_0(ctx context.Context, marshaler runt
}
var (
filter_MemoService_ListMemoTags_0 = &utilities.DoubleArray{Encoding: map[string]int{"parent": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
)
func request_MemoService_ListMemoTags_0(ctx context.Context, marshaler runtime.Marshaler, client MemoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListMemoTagsRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["parent"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "parent")
}
protoReq.Parent, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "parent", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_MemoService_ListMemoTags_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ListMemoTags(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_MemoService_ListMemoTags_0(ctx context.Context, marshaler runtime.Marshaler, server MemoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListMemoTagsRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["parent"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "parent")
}
protoReq.Parent, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "parent", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_MemoService_ListMemoTags_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ListMemoTags(ctx, &protoReq)
return msg, metadata, err
}
func request_MemoService_RenameMemoTag_0(ctx context.Context, marshaler runtime.Marshaler, client MemoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq RenameMemoTagRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["parent"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "parent")
}
protoReq.Parent, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "parent", err)
}
msg, err := client.RenameMemoTag(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_MemoService_RenameMemoTag_0(ctx context.Context, marshaler runtime.Marshaler, server MemoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq RenameMemoTagRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["parent"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "parent")
}
protoReq.Parent, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "parent", err)
}
msg, err := server.RenameMemoTag(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_MemoService_DeleteMemoTag_0 = &utilities.DoubleArray{Encoding: map[string]int{"parent": 0, "tag": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}}
)
func request_MemoService_DeleteMemoTag_0(ctx context.Context, marshaler runtime.Marshaler, client MemoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DeleteMemoTagRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["parent"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "parent")
}
protoReq.Parent, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "parent", err)
}
val, ok = pathParams["tag"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "tag")
}
protoReq.Tag, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "tag", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_MemoService_DeleteMemoTag_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.DeleteMemoTag(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_MemoService_DeleteMemoTag_0(ctx context.Context, marshaler runtime.Marshaler, server MemoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DeleteMemoTagRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["parent"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "parent")
}
protoReq.Parent, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "parent", err)
}
val, ok = pathParams["tag"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "tag")
}
protoReq.Tag, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "tag", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_MemoService_DeleteMemoTag_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.DeleteMemoTag(ctx, &protoReq)
return msg, metadata, err
}
func request_MemoService_SetMemoResources_0(ctx context.Context, marshaler runtime.Marshaler, client MemoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SetMemoResourcesRequest
var metadata runtime.ServerMetadata
@ -1076,6 +1296,81 @@ func RegisterMemoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux
})
mux.Handle("GET", pattern_MemoService_ListMemoTags_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.MemoService/ListMemoTags", runtime.WithHTTPPathPattern("/api/v1/{parent=memos/*}/tags"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_MemoService_ListMemoTags_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_MemoService_ListMemoTags_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("PATCH", pattern_MemoService_RenameMemoTag_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.MemoService/RenameMemoTag", runtime.WithHTTPPathPattern("/api/v1/{parent=memos/*}/tags:rename"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_MemoService_RenameMemoTag_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_MemoService_RenameMemoTag_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_MemoService_DeleteMemoTag_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.MemoService/DeleteMemoTag", runtime.WithHTTPPathPattern("/api/v1/{parent=memos/*}/tags/{tag}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_MemoService_DeleteMemoTag_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_MemoService_DeleteMemoTag_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("PATCH", pattern_MemoService_SetMemoResources_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@ -1521,6 +1816,72 @@ func RegisterMemoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux
})
mux.Handle("GET", pattern_MemoService_ListMemoTags_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.MemoService/ListMemoTags", runtime.WithHTTPPathPattern("/api/v1/{parent=memos/*}/tags"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_MemoService_ListMemoTags_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_MemoService_ListMemoTags_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("PATCH", pattern_MemoService_RenameMemoTag_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.MemoService/RenameMemoTag", runtime.WithHTTPPathPattern("/api/v1/{parent=memos/*}/tags:rename"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_MemoService_RenameMemoTag_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_MemoService_RenameMemoTag_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_MemoService_DeleteMemoTag_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.MemoService/DeleteMemoTag", runtime.WithHTTPPathPattern("/api/v1/{parent=memos/*}/tags/{tag}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_MemoService_DeleteMemoTag_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_MemoService_DeleteMemoTag_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("PATCH", pattern_MemoService_SetMemoResources_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@ -1759,6 +2120,12 @@ var (
pattern_MemoService_ExportMemos_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "memos"}, "export"))
pattern_MemoService_ListMemoTags_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", "parent", "tags"}, ""))
pattern_MemoService_RenameMemoTag_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", "parent", "tags"}, "rename"))
pattern_MemoService_DeleteMemoTag_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"api", "v1", "memos", "parent", "tags", "tag"}, ""))
pattern_MemoService_SetMemoResources_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", "resources"}, ""))
pattern_MemoService_ListMemoResources_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", "resources"}, ""))
@ -1795,6 +2162,12 @@ var (
forward_MemoService_ExportMemos_0 = runtime.ForwardResponseMessage
forward_MemoService_ListMemoTags_0 = runtime.ForwardResponseMessage
forward_MemoService_RenameMemoTag_0 = runtime.ForwardResponseMessage
forward_MemoService_DeleteMemoTag_0 = runtime.ForwardResponseMessage
forward_MemoService_SetMemoResources_0 = runtime.ForwardResponseMessage
forward_MemoService_ListMemoResources_0 = runtime.ForwardResponseMessage

View File

@ -27,6 +27,9 @@ const (
MemoService_UpdateMemo_FullMethodName = "/memos.api.v1.MemoService/UpdateMemo"
MemoService_DeleteMemo_FullMethodName = "/memos.api.v1.MemoService/DeleteMemo"
MemoService_ExportMemos_FullMethodName = "/memos.api.v1.MemoService/ExportMemos"
MemoService_ListMemoTags_FullMethodName = "/memos.api.v1.MemoService/ListMemoTags"
MemoService_RenameMemoTag_FullMethodName = "/memos.api.v1.MemoService/RenameMemoTag"
MemoService_DeleteMemoTag_FullMethodName = "/memos.api.v1.MemoService/DeleteMemoTag"
MemoService_SetMemoResources_FullMethodName = "/memos.api.v1.MemoService/SetMemoResources"
MemoService_ListMemoResources_FullMethodName = "/memos.api.v1.MemoService/ListMemoResources"
MemoService_SetMemoRelations_FullMethodName = "/memos.api.v1.MemoService/SetMemoRelations"
@ -57,6 +60,12 @@ type MemoServiceClient interface {
DeleteMemo(ctx context.Context, in *DeleteMemoRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// ExportMemos exports memos.
ExportMemos(ctx context.Context, in *ExportMemosRequest, opts ...grpc.CallOption) (*ExportMemosResponse, error)
// ListMemoTags lists tags for a memo.
ListMemoTags(ctx context.Context, in *ListMemoTagsRequest, opts ...grpc.CallOption) (*ListMemoTagsResponse, error)
// RenameMemoTag renames a tag for a memo.
RenameMemoTag(ctx context.Context, in *RenameMemoTagRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// DeleteMemoTag deletes a tag for a memo.
DeleteMemoTag(ctx context.Context, in *DeleteMemoTagRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// SetMemoResources sets resources for a memo.
SetMemoResources(ctx context.Context, in *SetMemoResourcesRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// ListMemoResources lists resources for a memo.
@ -150,6 +159,33 @@ func (c *memoServiceClient) ExportMemos(ctx context.Context, in *ExportMemosRequ
return out, nil
}
func (c *memoServiceClient) ListMemoTags(ctx context.Context, in *ListMemoTagsRequest, opts ...grpc.CallOption) (*ListMemoTagsResponse, error) {
out := new(ListMemoTagsResponse)
err := c.cc.Invoke(ctx, MemoService_ListMemoTags_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *memoServiceClient) RenameMemoTag(ctx context.Context, in *RenameMemoTagRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, MemoService_RenameMemoTag_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *memoServiceClient) DeleteMemoTag(ctx context.Context, in *DeleteMemoTagRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, MemoService_DeleteMemoTag_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *memoServiceClient) SetMemoResources(ctx context.Context, in *SetMemoResourcesRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, MemoService_SetMemoResources_FullMethodName, in, out, opts...)
@ -258,6 +294,12 @@ type MemoServiceServer interface {
DeleteMemo(context.Context, *DeleteMemoRequest) (*emptypb.Empty, error)
// ExportMemos exports memos.
ExportMemos(context.Context, *ExportMemosRequest) (*ExportMemosResponse, error)
// ListMemoTags lists tags for a memo.
ListMemoTags(context.Context, *ListMemoTagsRequest) (*ListMemoTagsResponse, error)
// RenameMemoTag renames a tag for a memo.
RenameMemoTag(context.Context, *RenameMemoTagRequest) (*emptypb.Empty, error)
// DeleteMemoTag deletes a tag for a memo.
DeleteMemoTag(context.Context, *DeleteMemoTagRequest) (*emptypb.Empty, error)
// SetMemoResources sets resources for a memo.
SetMemoResources(context.Context, *SetMemoResourcesRequest) (*emptypb.Empty, error)
// ListMemoResources lists resources for a memo.
@ -306,6 +348,15 @@ func (UnimplementedMemoServiceServer) DeleteMemo(context.Context, *DeleteMemoReq
func (UnimplementedMemoServiceServer) ExportMemos(context.Context, *ExportMemosRequest) (*ExportMemosResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ExportMemos not implemented")
}
func (UnimplementedMemoServiceServer) ListMemoTags(context.Context, *ListMemoTagsRequest) (*ListMemoTagsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListMemoTags not implemented")
}
func (UnimplementedMemoServiceServer) RenameMemoTag(context.Context, *RenameMemoTagRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method RenameMemoTag not implemented")
}
func (UnimplementedMemoServiceServer) DeleteMemoTag(context.Context, *DeleteMemoTagRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteMemoTag not implemented")
}
func (UnimplementedMemoServiceServer) SetMemoResources(context.Context, *SetMemoResourcesRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method SetMemoResources not implemented")
}
@ -475,6 +526,60 @@ func _MemoService_ExportMemos_Handler(srv interface{}, ctx context.Context, dec
return interceptor(ctx, in, info, handler)
}
func _MemoService_ListMemoTags_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListMemoTagsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MemoServiceServer).ListMemoTags(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MemoService_ListMemoTags_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MemoServiceServer).ListMemoTags(ctx, req.(*ListMemoTagsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _MemoService_RenameMemoTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RenameMemoTagRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MemoServiceServer).RenameMemoTag(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MemoService_RenameMemoTag_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MemoServiceServer).RenameMemoTag(ctx, req.(*RenameMemoTagRequest))
}
return interceptor(ctx, in, info, handler)
}
func _MemoService_DeleteMemoTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteMemoTagRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MemoServiceServer).DeleteMemoTag(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MemoService_DeleteMemoTag_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MemoServiceServer).DeleteMemoTag(ctx, req.(*DeleteMemoTagRequest))
}
return interceptor(ctx, in, info, handler)
}
func _MemoService_SetMemoResources_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SetMemoResourcesRequest)
if err := dec(in); err != nil {
@ -690,6 +795,18 @@ var MemoService_ServiceDesc = grpc.ServiceDesc{
MethodName: "ExportMemos",
Handler: _MemoService_ExportMemos_Handler,
},
{
MethodName: "ListMemoTags",
Handler: _MemoService_ListMemoTags_Handler,
},
{
MethodName: "RenameMemoTag",
Handler: _MemoService_RenameMemoTag_Handler,
},
{
MethodName: "DeleteMemoTag",
Handler: _MemoService_DeleteMemoTag_Handler,
},
{
MethodName: "SetMemoResources",
Handler: _MemoService_SetMemoResources_Handler,

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: api/v1/reaction_service.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: api/v1/resource_service.proto

View File

@ -1,745 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc (unknown)
// source: api/v1/tag_service.proto
package apiv1
import (
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Tag struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// The creator of tags.
// Format: users/{id}
Creator string `protobuf:"bytes,2,opt,name=creator,proto3" json:"creator,omitempty"`
}
func (x *Tag) Reset() {
*x = Tag{}
if protoimpl.UnsafeEnabled {
mi := &file_api_v1_tag_service_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Tag) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Tag) ProtoMessage() {}
func (x *Tag) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_tag_service_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Tag.ProtoReflect.Descriptor instead.
func (*Tag) Descriptor() ([]byte, []int) {
return file_api_v1_tag_service_proto_rawDescGZIP(), []int{0}
}
func (x *Tag) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *Tag) GetCreator() string {
if x != nil {
return x.Creator
}
return ""
}
type UpsertTagRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
}
func (x *UpsertTagRequest) Reset() {
*x = UpsertTagRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_api_v1_tag_service_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *UpsertTagRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UpsertTagRequest) ProtoMessage() {}
func (x *UpsertTagRequest) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_tag_service_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UpsertTagRequest.ProtoReflect.Descriptor instead.
func (*UpsertTagRequest) Descriptor() ([]byte, []int) {
return file_api_v1_tag_service_proto_rawDescGZIP(), []int{1}
}
func (x *UpsertTagRequest) GetName() string {
if x != nil {
return x.Name
}
return ""
}
type BatchUpsertTagRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Requests []*UpsertTagRequest `protobuf:"bytes,1,rep,name=requests,proto3" json:"requests,omitempty"`
}
func (x *BatchUpsertTagRequest) Reset() {
*x = BatchUpsertTagRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_api_v1_tag_service_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BatchUpsertTagRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BatchUpsertTagRequest) ProtoMessage() {}
func (x *BatchUpsertTagRequest) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_tag_service_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BatchUpsertTagRequest.ProtoReflect.Descriptor instead.
func (*BatchUpsertTagRequest) Descriptor() ([]byte, []int) {
return file_api_v1_tag_service_proto_rawDescGZIP(), []int{2}
}
func (x *BatchUpsertTagRequest) GetRequests() []*UpsertTagRequest {
if x != nil {
return x.Requests
}
return nil
}
type ListTagsRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ListTagsRequest) Reset() {
*x = ListTagsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_api_v1_tag_service_proto_msgTypes[3]
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_api_v1_tag_service_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && 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_api_v1_tag_service_proto_rawDescGZIP(), []int{3}
}
type ListTagsResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tags []*Tag `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"`
}
func (x *ListTagsResponse) Reset() {
*x = ListTagsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_api_v1_tag_service_proto_msgTypes[4]
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_api_v1_tag_service_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && 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_api_v1_tag_service_proto_rawDescGZIP(), []int{4}
}
func (x *ListTagsResponse) GetTags() []*Tag {
if x != nil {
return x.Tags
}
return nil
}
type RenameTagRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The creator of tags.
// Format: users/{id}
User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"`
OldName string `protobuf:"bytes,2,opt,name=old_name,json=oldName,proto3" json:"old_name,omitempty"`
NewName string `protobuf:"bytes,3,opt,name=new_name,json=newName,proto3" json:"new_name,omitempty"`
}
func (x *RenameTagRequest) Reset() {
*x = RenameTagRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_api_v1_tag_service_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *RenameTagRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RenameTagRequest) ProtoMessage() {}
func (x *RenameTagRequest) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_tag_service_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RenameTagRequest.ProtoReflect.Descriptor instead.
func (*RenameTagRequest) Descriptor() ([]byte, []int) {
return file_api_v1_tag_service_proto_rawDescGZIP(), []int{5}
}
func (x *RenameTagRequest) GetUser() string {
if x != nil {
return x.User
}
return ""
}
func (x *RenameTagRequest) GetOldName() string {
if x != nil {
return x.OldName
}
return ""
}
func (x *RenameTagRequest) GetNewName() string {
if x != nil {
return x.NewName
}
return ""
}
type DeleteTagRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tag *Tag `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
}
func (x *DeleteTagRequest) Reset() {
*x = DeleteTagRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_api_v1_tag_service_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DeleteTagRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteTagRequest) ProtoMessage() {}
func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_tag_service_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteTagRequest.ProtoReflect.Descriptor instead.
func (*DeleteTagRequest) Descriptor() ([]byte, []int) {
return file_api_v1_tag_service_proto_rawDescGZIP(), []int{6}
}
func (x *DeleteTagRequest) GetTag() *Tag {
if x != nil {
return x.Tag
}
return nil
}
type GetTagSuggestionsRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The creator of tags.
// Format: users/{id}
User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"`
}
func (x *GetTagSuggestionsRequest) Reset() {
*x = GetTagSuggestionsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_api_v1_tag_service_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetTagSuggestionsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetTagSuggestionsRequest) ProtoMessage() {}
func (x *GetTagSuggestionsRequest) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_tag_service_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetTagSuggestionsRequest.ProtoReflect.Descriptor instead.
func (*GetTagSuggestionsRequest) Descriptor() ([]byte, []int) {
return file_api_v1_tag_service_proto_rawDescGZIP(), []int{7}
}
func (x *GetTagSuggestionsRequest) GetUser() string {
if x != nil {
return x.User
}
return ""
}
type GetTagSuggestionsResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tags []string `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"`
}
func (x *GetTagSuggestionsResponse) Reset() {
*x = GetTagSuggestionsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_api_v1_tag_service_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetTagSuggestionsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetTagSuggestionsResponse) ProtoMessage() {}
func (x *GetTagSuggestionsResponse) ProtoReflect() protoreflect.Message {
mi := &file_api_v1_tag_service_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetTagSuggestionsResponse.ProtoReflect.Descriptor instead.
func (*GetTagSuggestionsResponse) Descriptor() ([]byte, []int) {
return file_api_v1_tag_service_proto_rawDescGZIP(), []int{8}
}
func (x *GetTagSuggestionsResponse) GetTags() []string {
if x != nil {
return x.Tags
}
return nil
}
var File_api_v1_tag_service_proto protoreflect.FileDescriptor
var file_api_v1_tag_service_proto_rawDesc = []byte{
0x0a, 0x18, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x67, 0x5f, 0x73, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x6d, 0x65, 0x6d, 0x6f,
0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0x33, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18,
0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x26, 0x0a, 0x10, 0x55, 0x70, 0x73, 0x65,
0x72, 0x74, 0x54, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x22, 0x53, 0x0a, 0x15, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x54,
0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3a, 0x0a, 0x08, 0x72, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6d, 0x65,
0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72,
0x74, 0x54, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x08, 0x72, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x67,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x39, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74,
0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x04,
0x74, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6d, 0x65, 0x6d,
0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74,
0x61, 0x67, 0x73, 0x22, 0x5c, 0x0a, 0x10, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x6f,
0x6c, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f,
0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61,
0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x4e, 0x61, 0x6d,
0x65, 0x22, 0x37, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x61, 0x67, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76,
0x31, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x03, 0x74, 0x61, 0x67, 0x22, 0x2e, 0x0a, 0x18, 0x47, 0x65,
0x74, 0x54, 0x61, 0x67, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x2f, 0x0a, 0x19, 0x47, 0x65,
0x74, 0x54, 0x61, 0x67, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 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, 0x32, 0x82, 0x05, 0x0a, 0x0a,
0x54, 0x61, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x57, 0x0a, 0x09, 0x55, 0x70,
0x73, 0x65, 0x72, 0x74, 0x54, 0x61, 0x67, 0x12, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e,
0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x54, 0x61, 0x67,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e,
0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x22, 0x17, 0x82, 0xd3, 0xe4, 0x93,
0x02, 0x11, 0x3a, 0x01, 0x2a, 0x22, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x74,
0x61, 0x67, 0x73, 0x12, 0x72, 0x0a, 0x0e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x73, 0x65,
0x72, 0x74, 0x54, 0x61, 0x67, 0x12, 0x23, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74,
0x54, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70,
0x74, 0x79, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x3a, 0x01, 0x2a, 0x22, 0x18, 0x2f,
0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x67, 0x73, 0x3a, 0x62, 0x61, 0x74, 0x63,
0x68, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0x5f, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x54,
0x61, 0x67, 0x73, 0x12, 0x1d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76,
0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69,
0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x67, 0x73, 0x12, 0x63, 0x0a, 0x09, 0x52, 0x65, 0x6e, 0x61,
0x6d, 0x65, 0x54, 0x61, 0x67, 0x12, 0x1e, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x67, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x1e, 0x82,
0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x32, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76,
0x31, 0x2f, 0x74, 0x61, 0x67, 0x73, 0x3a, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x59, 0x0a,
0x09, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x61, 0x67, 0x12, 0x1e, 0x2e, 0x6d, 0x65, 0x6d,
0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x54, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70,
0x74, 0x79, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x2a, 0x0c, 0x2f, 0x61, 0x70, 0x69,
0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x67, 0x73, 0x12, 0x85, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x74,
0x54, 0x61, 0x67, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x26,
0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
0x74, 0x54, 0x61, 0x67, 0x53, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x67, 0x53, 0x75, 0x67, 0x67,
0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31,
0x2f, 0x74, 0x61, 0x67, 0x73, 0x2f, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e,
0x42, 0xa7, 0x01, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x76, 0x31, 0x42, 0x0f, 0x54, 0x61, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65,
0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x70,
0x69, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x70, 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x4d, 0x41, 0x58,
0xaa, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca,
0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02,
0x18, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x41, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50,
0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0e, 0x4d, 0x65, 0x6d, 0x6f,
0x73, 0x3a, 0x3a, 0x41, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
file_api_v1_tag_service_proto_rawDescOnce sync.Once
file_api_v1_tag_service_proto_rawDescData = file_api_v1_tag_service_proto_rawDesc
)
func file_api_v1_tag_service_proto_rawDescGZIP() []byte {
file_api_v1_tag_service_proto_rawDescOnce.Do(func() {
file_api_v1_tag_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_v1_tag_service_proto_rawDescData)
})
return file_api_v1_tag_service_proto_rawDescData
}
var file_api_v1_tag_service_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_api_v1_tag_service_proto_goTypes = []interface{}{
(*Tag)(nil), // 0: memos.api.v1.Tag
(*UpsertTagRequest)(nil), // 1: memos.api.v1.UpsertTagRequest
(*BatchUpsertTagRequest)(nil), // 2: memos.api.v1.BatchUpsertTagRequest
(*ListTagsRequest)(nil), // 3: memos.api.v1.ListTagsRequest
(*ListTagsResponse)(nil), // 4: memos.api.v1.ListTagsResponse
(*RenameTagRequest)(nil), // 5: memos.api.v1.RenameTagRequest
(*DeleteTagRequest)(nil), // 6: memos.api.v1.DeleteTagRequest
(*GetTagSuggestionsRequest)(nil), // 7: memos.api.v1.GetTagSuggestionsRequest
(*GetTagSuggestionsResponse)(nil), // 8: memos.api.v1.GetTagSuggestionsResponse
(*emptypb.Empty)(nil), // 9: google.protobuf.Empty
}
var file_api_v1_tag_service_proto_depIdxs = []int32{
1, // 0: memos.api.v1.BatchUpsertTagRequest.requests:type_name -> memos.api.v1.UpsertTagRequest
0, // 1: memos.api.v1.ListTagsResponse.tags:type_name -> memos.api.v1.Tag
0, // 2: memos.api.v1.DeleteTagRequest.tag:type_name -> memos.api.v1.Tag
1, // 3: memos.api.v1.TagService.UpsertTag:input_type -> memos.api.v1.UpsertTagRequest
2, // 4: memos.api.v1.TagService.BatchUpsertTag:input_type -> memos.api.v1.BatchUpsertTagRequest
3, // 5: memos.api.v1.TagService.ListTags:input_type -> memos.api.v1.ListTagsRequest
5, // 6: memos.api.v1.TagService.RenameTag:input_type -> memos.api.v1.RenameTagRequest
6, // 7: memos.api.v1.TagService.DeleteTag:input_type -> memos.api.v1.DeleteTagRequest
7, // 8: memos.api.v1.TagService.GetTagSuggestions:input_type -> memos.api.v1.GetTagSuggestionsRequest
0, // 9: memos.api.v1.TagService.UpsertTag:output_type -> memos.api.v1.Tag
9, // 10: memos.api.v1.TagService.BatchUpsertTag:output_type -> google.protobuf.Empty
4, // 11: memos.api.v1.TagService.ListTags:output_type -> memos.api.v1.ListTagsResponse
9, // 12: memos.api.v1.TagService.RenameTag:output_type -> google.protobuf.Empty
9, // 13: memos.api.v1.TagService.DeleteTag:output_type -> google.protobuf.Empty
8, // 14: memos.api.v1.TagService.GetTagSuggestions:output_type -> memos.api.v1.GetTagSuggestionsResponse
9, // [9:15] is the sub-list for method output_type
3, // [3:9] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_api_v1_tag_service_proto_init() }
func file_api_v1_tag_service_proto_init() {
if File_api_v1_tag_service_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_api_v1_tag_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Tag); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_v1_tag_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*UpsertTagRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_v1_tag_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BatchUpsertTagRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_v1_tag_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ListTagsRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_v1_tag_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ListTagsResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_v1_tag_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RenameTagRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_v1_tag_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeleteTagRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_v1_tag_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetTagSuggestionsRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_api_v1_tag_service_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetTagSuggestionsResponse); 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_api_v1_tag_service_proto_rawDesc,
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_api_v1_tag_service_proto_goTypes,
DependencyIndexes: file_api_v1_tag_service_proto_depIdxs,
MessageInfos: file_api_v1_tag_service_proto_msgTypes,
}.Build()
File_api_v1_tag_service_proto = out.File
file_api_v1_tag_service_proto_rawDesc = nil
file_api_v1_tag_service_proto_goTypes = nil
file_api_v1_tag_service_proto_depIdxs = nil
}

View File

@ -1,560 +0,0 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: api/v1/tag_service.proto
/*
Package apiv1 is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package apiv1
import (
"context"
"io"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = metadata.Join
func request_TagService_UpsertTag_0(ctx context.Context, marshaler runtime.Marshaler, client TagServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq UpsertTagRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.UpsertTag(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_TagService_UpsertTag_0(ctx context.Context, marshaler runtime.Marshaler, server TagServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq UpsertTagRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.UpsertTag(ctx, &protoReq)
return msg, metadata, err
}
func request_TagService_BatchUpsertTag_0(ctx context.Context, marshaler runtime.Marshaler, client TagServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq BatchUpsertTagRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.BatchUpsertTag(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_TagService_BatchUpsertTag_0(ctx context.Context, marshaler runtime.Marshaler, server TagServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq BatchUpsertTagRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.BatchUpsertTag(ctx, &protoReq)
return msg, metadata, err
}
func request_TagService_ListTags_0(ctx context.Context, marshaler runtime.Marshaler, client TagServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListTagsRequest
var metadata runtime.ServerMetadata
msg, err := client.ListTags(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_TagService_ListTags_0(ctx context.Context, marshaler runtime.Marshaler, server TagServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListTagsRequest
var metadata runtime.ServerMetadata
msg, err := server.ListTags(ctx, &protoReq)
return msg, metadata, err
}
func request_TagService_RenameTag_0(ctx context.Context, marshaler runtime.Marshaler, client TagServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq RenameTagRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.RenameTag(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_TagService_RenameTag_0(ctx context.Context, marshaler runtime.Marshaler, server TagServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq RenameTagRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.RenameTag(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_TagService_DeleteTag_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_TagService_DeleteTag_0(ctx context.Context, marshaler runtime.Marshaler, client TagServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DeleteTagRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_TagService_DeleteTag_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.DeleteTag(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_TagService_DeleteTag_0(ctx context.Context, marshaler runtime.Marshaler, server TagServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq DeleteTagRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_TagService_DeleteTag_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.DeleteTag(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_TagService_GetTagSuggestions_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_TagService_GetTagSuggestions_0(ctx context.Context, marshaler runtime.Marshaler, client TagServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetTagSuggestionsRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_TagService_GetTagSuggestions_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.GetTagSuggestions(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_TagService_GetTagSuggestions_0(ctx context.Context, marshaler runtime.Marshaler, server TagServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetTagSuggestionsRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_TagService_GetTagSuggestions_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.GetTagSuggestions(ctx, &protoReq)
return msg, metadata, err
}
// RegisterTagServiceHandlerServer registers the http handlers for service TagService to "mux".
// UnaryRPC :call TagServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterTagServiceHandlerFromEndpoint instead.
func RegisterTagServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server TagServiceServer) error {
mux.Handle("POST", pattern_TagService_UpsertTag_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.TagService/UpsertTag", runtime.WithHTTPPathPattern("/api/v1/tags"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_TagService_UpsertTag_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_TagService_UpsertTag_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_TagService_BatchUpsertTag_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.TagService/BatchUpsertTag", runtime.WithHTTPPathPattern("/api/v1/tags:batchUpsert"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_TagService_BatchUpsertTag_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_TagService_BatchUpsertTag_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_TagService_ListTags_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.TagService/ListTags", runtime.WithHTTPPathPattern("/api/v1/tags"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_TagService_ListTags_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_TagService_ListTags_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("PATCH", pattern_TagService_RenameTag_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.TagService/RenameTag", runtime.WithHTTPPathPattern("/api/v1/tags:rename"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_TagService_RenameTag_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_TagService_RenameTag_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_TagService_DeleteTag_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.TagService/DeleteTag", runtime.WithHTTPPathPattern("/api/v1/tags"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_TagService_DeleteTag_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_TagService_DeleteTag_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_TagService_GetTagSuggestions_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.TagService/GetTagSuggestions", runtime.WithHTTPPathPattern("/api/v1/tags/suggestion"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_TagService_GetTagSuggestions_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_TagService_GetTagSuggestions_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterTagServiceHandlerFromEndpoint is same as RegisterTagServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterTagServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.DialContext(ctx, endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterTagServiceHandler(ctx, mux, conn)
}
// RegisterTagServiceHandler registers the http handlers for service TagService to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterTagServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterTagServiceHandlerClient(ctx, mux, NewTagServiceClient(conn))
}
// RegisterTagServiceHandlerClient registers the http handlers for service TagService
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "TagServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "TagServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "TagServiceClient" to call the correct interceptors.
func RegisterTagServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client TagServiceClient) error {
mux.Handle("POST", pattern_TagService_UpsertTag_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.TagService/UpsertTag", runtime.WithHTTPPathPattern("/api/v1/tags"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_TagService_UpsertTag_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_TagService_UpsertTag_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_TagService_BatchUpsertTag_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.TagService/BatchUpsertTag", runtime.WithHTTPPathPattern("/api/v1/tags:batchUpsert"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_TagService_BatchUpsertTag_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_TagService_BatchUpsertTag_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_TagService_ListTags_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.TagService/ListTags", runtime.WithHTTPPathPattern("/api/v1/tags"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_TagService_ListTags_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_TagService_ListTags_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("PATCH", pattern_TagService_RenameTag_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.TagService/RenameTag", runtime.WithHTTPPathPattern("/api/v1/tags:rename"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_TagService_RenameTag_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_TagService_RenameTag_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_TagService_DeleteTag_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.TagService/DeleteTag", runtime.WithHTTPPathPattern("/api/v1/tags"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_TagService_DeleteTag_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_TagService_DeleteTag_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_TagService_GetTagSuggestions_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.TagService/GetTagSuggestions", runtime.WithHTTPPathPattern("/api/v1/tags/suggestion"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_TagService_GetTagSuggestions_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_TagService_GetTagSuggestions_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_TagService_UpsertTag_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "tags"}, ""))
pattern_TagService_BatchUpsertTag_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "tags"}, "batchUpsert"))
pattern_TagService_ListTags_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "tags"}, ""))
pattern_TagService_RenameTag_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "tags"}, "rename"))
pattern_TagService_DeleteTag_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "tags"}, ""))
pattern_TagService_GetTagSuggestions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "tags", "suggestion"}, ""))
)
var (
forward_TagService_UpsertTag_0 = runtime.ForwardResponseMessage
forward_TagService_BatchUpsertTag_0 = runtime.ForwardResponseMessage
forward_TagService_ListTags_0 = runtime.ForwardResponseMessage
forward_TagService_RenameTag_0 = runtime.ForwardResponseMessage
forward_TagService_DeleteTag_0 = runtime.ForwardResponseMessage
forward_TagService_GetTagSuggestions_0 = runtime.ForwardResponseMessage
)

View File

@ -1,309 +0,0 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.3.0
// - protoc (unknown)
// source: api/v1/tag_service.proto
package apiv1
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
const (
TagService_UpsertTag_FullMethodName = "/memos.api.v1.TagService/UpsertTag"
TagService_BatchUpsertTag_FullMethodName = "/memos.api.v1.TagService/BatchUpsertTag"
TagService_ListTags_FullMethodName = "/memos.api.v1.TagService/ListTags"
TagService_RenameTag_FullMethodName = "/memos.api.v1.TagService/RenameTag"
TagService_DeleteTag_FullMethodName = "/memos.api.v1.TagService/DeleteTag"
TagService_GetTagSuggestions_FullMethodName = "/memos.api.v1.TagService/GetTagSuggestions"
)
// TagServiceClient is the client API for TagService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type TagServiceClient interface {
// UpsertTag upserts a tag.
UpsertTag(ctx context.Context, in *UpsertTagRequest, opts ...grpc.CallOption) (*Tag, error)
// BatchUpsertTag upserts multiple tags.
BatchUpsertTag(ctx context.Context, in *BatchUpsertTagRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// ListTags lists tags.
ListTags(ctx context.Context, in *ListTagsRequest, opts ...grpc.CallOption) (*ListTagsResponse, error)
// RenameTag renames a tag.
// All related memos will be updated.
RenameTag(ctx context.Context, in *RenameTagRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// DeleteTag deletes a tag.
DeleteTag(ctx context.Context, in *DeleteTagRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// GetTagSuggestions gets tag suggestions from the user's memos.
GetTagSuggestions(ctx context.Context, in *GetTagSuggestionsRequest, opts ...grpc.CallOption) (*GetTagSuggestionsResponse, error)
}
type tagServiceClient struct {
cc grpc.ClientConnInterface
}
func NewTagServiceClient(cc grpc.ClientConnInterface) TagServiceClient {
return &tagServiceClient{cc}
}
func (c *tagServiceClient) UpsertTag(ctx context.Context, in *UpsertTagRequest, opts ...grpc.CallOption) (*Tag, error) {
out := new(Tag)
err := c.cc.Invoke(ctx, TagService_UpsertTag_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tagServiceClient) BatchUpsertTag(ctx context.Context, in *BatchUpsertTagRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, TagService_BatchUpsertTag_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tagServiceClient) ListTags(ctx context.Context, in *ListTagsRequest, opts ...grpc.CallOption) (*ListTagsResponse, error) {
out := new(ListTagsResponse)
err := c.cc.Invoke(ctx, TagService_ListTags_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tagServiceClient) RenameTag(ctx context.Context, in *RenameTagRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, TagService_RenameTag_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tagServiceClient) DeleteTag(ctx context.Context, in *DeleteTagRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, TagService_DeleteTag_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tagServiceClient) GetTagSuggestions(ctx context.Context, in *GetTagSuggestionsRequest, opts ...grpc.CallOption) (*GetTagSuggestionsResponse, error) {
out := new(GetTagSuggestionsResponse)
err := c.cc.Invoke(ctx, TagService_GetTagSuggestions_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// TagServiceServer is the server API for TagService service.
// All implementations must embed UnimplementedTagServiceServer
// for forward compatibility
type TagServiceServer interface {
// UpsertTag upserts a tag.
UpsertTag(context.Context, *UpsertTagRequest) (*Tag, error)
// BatchUpsertTag upserts multiple tags.
BatchUpsertTag(context.Context, *BatchUpsertTagRequest) (*emptypb.Empty, error)
// ListTags lists tags.
ListTags(context.Context, *ListTagsRequest) (*ListTagsResponse, error)
// RenameTag renames a tag.
// All related memos will be updated.
RenameTag(context.Context, *RenameTagRequest) (*emptypb.Empty, error)
// DeleteTag deletes a tag.
DeleteTag(context.Context, *DeleteTagRequest) (*emptypb.Empty, error)
// GetTagSuggestions gets tag suggestions from the user's memos.
GetTagSuggestions(context.Context, *GetTagSuggestionsRequest) (*GetTagSuggestionsResponse, error)
mustEmbedUnimplementedTagServiceServer()
}
// UnimplementedTagServiceServer must be embedded to have forward compatible implementations.
type UnimplementedTagServiceServer struct {
}
func (UnimplementedTagServiceServer) UpsertTag(context.Context, *UpsertTagRequest) (*Tag, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpsertTag not implemented")
}
func (UnimplementedTagServiceServer) BatchUpsertTag(context.Context, *BatchUpsertTagRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method BatchUpsertTag not implemented")
}
func (UnimplementedTagServiceServer) ListTags(context.Context, *ListTagsRequest) (*ListTagsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListTags not implemented")
}
func (UnimplementedTagServiceServer) RenameTag(context.Context, *RenameTagRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method RenameTag not implemented")
}
func (UnimplementedTagServiceServer) DeleteTag(context.Context, *DeleteTagRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteTag not implemented")
}
func (UnimplementedTagServiceServer) GetTagSuggestions(context.Context, *GetTagSuggestionsRequest) (*GetTagSuggestionsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetTagSuggestions not implemented")
}
func (UnimplementedTagServiceServer) mustEmbedUnimplementedTagServiceServer() {}
// UnsafeTagServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to TagServiceServer will
// result in compilation errors.
type UnsafeTagServiceServer interface {
mustEmbedUnimplementedTagServiceServer()
}
func RegisterTagServiceServer(s grpc.ServiceRegistrar, srv TagServiceServer) {
s.RegisterService(&TagService_ServiceDesc, srv)
}
func _TagService_UpsertTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpsertTagRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TagServiceServer).UpsertTag(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: TagService_UpsertTag_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TagServiceServer).UpsertTag(ctx, req.(*UpsertTagRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TagService_BatchUpsertTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(BatchUpsertTagRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TagServiceServer).BatchUpsertTag(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: TagService_BatchUpsertTag_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TagServiceServer).BatchUpsertTag(ctx, req.(*BatchUpsertTagRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TagService_ListTags_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListTagsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TagServiceServer).ListTags(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: TagService_ListTags_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TagServiceServer).ListTags(ctx, req.(*ListTagsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TagService_RenameTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RenameTagRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TagServiceServer).RenameTag(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: TagService_RenameTag_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TagServiceServer).RenameTag(ctx, req.(*RenameTagRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TagService_DeleteTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteTagRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TagServiceServer).DeleteTag(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: TagService_DeleteTag_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TagServiceServer).DeleteTag(ctx, req.(*DeleteTagRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TagService_GetTagSuggestions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetTagSuggestionsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TagServiceServer).GetTagSuggestions(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: TagService_GetTagSuggestions_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TagServiceServer).GetTagSuggestions(ctx, req.(*GetTagSuggestionsRequest))
}
return interceptor(ctx, in, info, handler)
}
// TagService_ServiceDesc is the grpc.ServiceDesc for TagService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var TagService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "memos.api.v1.TagService",
HandlerType: (*TagServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "UpsertTag",
Handler: _TagService_UpsertTag_Handler,
},
{
MethodName: "BatchUpsertTag",
Handler: _TagService_BatchUpsertTag_Handler,
},
{
MethodName: "ListTags",
Handler: _TagService_ListTags_Handler,
},
{
MethodName: "RenameTag",
Handler: _TagService_RenameTag_Handler,
},
{
MethodName: "DeleteTag",
Handler: _TagService_DeleteTag_Handler,
},
{
MethodName: "GetTagSuggestions",
Handler: _TagService_GetTagSuggestions_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "api/v1/tag_service.proto",
}

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: api/v1/user_service.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: api/v1/webhook_service.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: api/v1/workspace_service.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: api/v1/workspace_setting_service.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: store/activity.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: store/idp.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: store/inbox.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: store/reaction.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: store/resource.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: store/user_setting.proto

View File

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.34.0
// protoc-gen-go v1.34.1
// protoc (unknown)
// source: store/workspace_setting.proto

View File

@ -6,13 +6,16 @@ import (
"context"
"fmt"
"log/slog"
"slices"
"time"
"github.com/google/cel-go/cel"
"github.com/lithammer/shortuuid/v4"
"github.com/pkg/errors"
"github.com/yourselfhosted/gomark/ast"
"github.com/yourselfhosted/gomark/parser"
"github.com/yourselfhosted/gomark/parser/tokenizer"
"github.com/yourselfhosted/gomark/restore"
expr "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
@ -59,6 +62,11 @@ func (s *APIV1Service) CreateMemo(ctx context.Context, request *v1pb.CreateMemoR
if len(create.Content) > contentLengthLimit {
return nil, status.Errorf(codes.InvalidArgument, "content too long (max %d characters)", contentLengthLimit)
}
tags, err := ExtractTagsFromContent(create.Content)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "failed to extract tags")
}
create.Tags = tags
memo, err := s.Store.CreateMemo(ctx, create)
if err != nil {
@ -215,7 +223,10 @@ func (s *APIV1Service) UpdateMemo(ctx context.Context, request *v1pb.UpdateMemoR
return nil, status.Errorf(codes.NotFound, "memo not found")
}
user, _ := getCurrentUser(ctx, s.Store)
user, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get current user")
}
if memo.CreatorID != user.ID {
return nil, status.Errorf(codes.PermissionDenied, "permission denied")
}
@ -227,7 +238,19 @@ func (s *APIV1Service) UpdateMemo(ctx context.Context, request *v1pb.UpdateMemoR
}
for _, path := range request.UpdateMask.Paths {
if path == "content" {
contentLengthLimit, err := s.getContentLengthLimit(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get content length limit")
}
if len(request.Memo.Content) > contentLengthLimit {
return nil, status.Errorf(codes.InvalidArgument, "content too long (max %d characters)", contentLengthLimit)
}
update.Content = &request.Memo.Content
tags, err := ExtractTagsFromContent(*update.Content)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "failed to extract tags")
}
update.Tags = &tags
} else if path == "uid" {
update.UID = &request.Memo.Name
if !util.UIDMatcher.MatchString(*update.UID) {
@ -259,13 +282,6 @@ func (s *APIV1Service) UpdateMemo(ctx context.Context, request *v1pb.UpdateMemoR
}
}
}
contentLengthLimit, err := s.getContentLengthLimit(ctx)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get content length limit")
}
if update.Content != nil && len(*update.Content) > contentLengthLimit {
return nil, status.Errorf(codes.InvalidArgument, "content too long (max %d characters)", contentLengthLimit)
}
if err = s.Store.UpdateMemo(ctx, update); err != nil {
return nil, status.Errorf(codes.Internal, "failed to update memo")
@ -531,6 +547,158 @@ func (s *APIV1Service) ExportMemos(ctx context.Context, request *v1pb.ExportMemo
}, nil
}
func (s *APIV1Service) ListMemoTags(ctx context.Context, request *v1pb.ListMemoTagsRequest) (*v1pb.ListMemoTagsResponse, error) {
user, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get current user")
}
normalRowStatus := store.Normal
memoFind := &store.FindMemo{
CreatorID: &user.ID,
RowStatus: &normalRowStatus,
ExcludeComments: true,
// Default exclude content for performance.
ExcludeContent: true,
}
if (request.Parent) != "memos/-" {
memoID, err := ExtractMemoIDFromName(request.Parent)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid memo name: %v", err)
}
memoFind.ID = &memoID
}
if request.Rebuild {
// If rebuild is true, include content to extract tags.
memoFind.ExcludeContent = false
}
memos, err := s.Store.ListMemos(ctx, memoFind)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list memos")
}
if request.Rebuild {
for _, memo := range memos {
tags, err := ExtractTagsFromContent(memo.Content)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to extract tags")
}
memo.Tags = tags
if err := s.Store.UpdateMemo(ctx, &store.UpdateMemo{
ID: memo.ID,
Tags: &tags,
}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to update memo")
}
}
}
tagAmounts := map[string]int32{}
for _, memo := range memos {
for _, tag := range memo.Tags {
tagAmounts[tag]++
}
}
return &v1pb.ListMemoTagsResponse{
TagAmounts: tagAmounts,
}, nil
}
func (s *APIV1Service) RenameMemoTag(ctx context.Context, request *v1pb.RenameMemoTagRequest) (*emptypb.Empty, error) {
user, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get current user")
}
memoFind := &store.FindMemo{
CreatorID: &user.ID,
Tag: &request.OldTag,
ExcludeComments: true,
}
if (request.Parent) != "memos/-" {
memoID, err := ExtractMemoIDFromName(request.Parent)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid memo name: %v", err)
}
memoFind.ID = &memoID
}
memos, err := s.Store.ListMemos(ctx, memoFind)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list memos")
}
for _, memo := range memos {
nodes, err := parser.Parse(tokenizer.Tokenize(memo.Content))
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to parse memo: %v", err)
}
TraverseASTNodes(nodes, func(node ast.Node) {
if tag, ok := node.(*ast.Tag); ok && tag.Content == request.OldTag {
tag.Content = request.NewTag
}
})
content := restore.Restore(nodes)
tags := util.ReplaceString(memo.Tags, request.OldTag, request.NewTag)
if err := s.Store.UpdateMemo(ctx, &store.UpdateMemo{
ID: memo.ID,
Content: &content,
Tags: &tags,
}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to update memo: %v", err)
}
}
return &emptypb.Empty{}, nil
}
func (s *APIV1Service) DeleteMemoTag(ctx context.Context, request *v1pb.DeleteMemoTagRequest) (*emptypb.Empty, error) {
user, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get current user")
}
memoFind := &store.FindMemo{
CreatorID: &user.ID,
Tag: &request.Tag,
ExcludeContent: true,
ExcludeComments: true,
}
if (request.Parent) != "memos/-" {
memoID, err := ExtractMemoIDFromName(request.Parent)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid memo name: %v", err)
}
memoFind.ID = &memoID
}
memos, err := s.Store.ListMemos(ctx, memoFind)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list memos")
}
for _, memo := range memos {
if request.DeleteRelatedMemos {
err := s.Store.DeleteMemo(ctx, &store.DeleteMemo{ID: memo.ID})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to delete memo")
}
} else {
archived := store.Archived
err := s.Store.UpdateMemo(ctx, &store.UpdateMemo{
ID: memo.ID,
RowStatus: &archived,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to update memo")
}
}
}
return &emptypb.Empty{}, nil
}
func (s *APIV1Service) convertMemoFromStore(ctx context.Context, memo *store.Memo) (*v1pb.Memo, error) {
displayTs := memo.CreatedTs
workspaceMemoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
@ -578,6 +746,7 @@ func (s *APIV1Service) convertMemoFromStore(ctx context.Context, memo *store.Mem
Content: memo.Content,
Nodes: convertFromASTNodes(nodes),
Visibility: convertVisibilityFromStore(memo.Visibility),
Tags: memo.Tags,
Pinned: memo.Pinned,
ParentId: memo.ParentID,
Relations: listMemoRelationsResponse.Relations,
@ -628,6 +797,9 @@ func (s *APIV1Service) buildMemoFindWithFilter(ctx context.Context, find *store.
if len(filter.Visibilities) > 0 {
find.VisibilityList = filter.Visibilities
}
if filter.Tag != nil {
find.Tag = filter.Tag
}
if filter.OrderByPinned {
find.OrderByPinned = filter.OrderByPinned
}
@ -720,6 +892,7 @@ func (s *APIV1Service) getContentLengthLimit(ctx context.Context) (int, error) {
var SearchMemosFilterCELAttributes = []cel.EnvOption{
cel.Variable("content_search", cel.ListType(cel.StringType)),
cel.Variable("visibilities", cel.ListType(cel.StringType)),
cel.Variable("tag", cel.StringType),
cel.Variable("order_by_pinned", cel.BoolType),
cel.Variable("display_time_before", cel.IntType),
cel.Variable("display_time_after", cel.IntType),
@ -734,6 +907,7 @@ var SearchMemosFilterCELAttributes = []cel.EnvOption{
type SearchMemosFilter struct {
ContentSearch []string
Visibilities []store.Visibility
Tag *string
OrderByPinned bool
DisplayTimeBefore *int64
DisplayTimeAfter *int64
@ -782,6 +956,9 @@ func findSearchMemosField(callExpr *expr.Expr_Call, filter *SearchMemosFilter) {
visibilities = append(visibilities, store.Visibility(value))
}
filter.Visibilities = visibilities
} else if idExpr.Name == "tag" {
tag := callExpr.Args[1].GetConstExpr().GetStringValue()
filter.Tag = &tag
} else if idExpr.Name == "order_by_pinned" {
value := callExpr.Args[1].GetConstExpr().GetBoolValue()
filter.OrderByPinned = value
@ -821,6 +998,45 @@ func findSearchMemosField(callExpr *expr.Expr_Call, filter *SearchMemosFilter) {
}
}
func ExtractTagsFromContent(content string) ([]string, error) {
nodes, err := parser.Parse(tokenizer.Tokenize(content))
if err != nil {
return nil, errors.Wrap(err, "failed to parse content")
}
tags := []string{}
TraverseASTNodes(nodes, func(node ast.Node) {
if tagNode, ok := node.(*ast.Tag); ok {
tag := tagNode.Content
if !slices.Contains(tags, tag) {
tags = append(tags, tag)
}
}
})
return tags, nil
}
func TraverseASTNodes(nodes []ast.Node, fn func(ast.Node)) {
for _, node := range nodes {
fn(node)
switch n := node.(type) {
case *ast.Paragraph:
TraverseASTNodes(n.Children, fn)
case *ast.Heading:
TraverseASTNodes(n.Children, fn)
case *ast.Blockquote:
TraverseASTNodes(n.Children, fn)
case *ast.OrderedList:
TraverseASTNodes(n.Children, fn)
case *ast.UnorderedList:
TraverseASTNodes(n.Children, fn)
case *ast.TaskList:
TraverseASTNodes(n.Children, fn)
case *ast.Bold:
TraverseASTNodes(n.Children, fn)
}
}
}
// DispatchMemoCreatedWebhook dispatches webhook when memo is created.
func (s *APIV1Service) DispatchMemoCreatedWebhook(ctx context.Context, memo *v1pb.Memo) error {
return s.dispatchMemoRelatedWebhook(ctx, memo, "memos.memo.created")

View File

@ -1,254 +0,0 @@
package v1
import (
"context"
"fmt"
"slices"
"sort"
"github.com/pkg/errors"
"github.com/yourselfhosted/gomark/ast"
"github.com/yourselfhosted/gomark/parser"
"github.com/yourselfhosted/gomark/parser/tokenizer"
"github.com/yourselfhosted/gomark/restore"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
v1pb "github.com/usememos/memos/proto/gen/api/v1"
"github.com/usememos/memos/store"
)
func (s *APIV1Service) UpsertTag(ctx context.Context, request *v1pb.UpsertTagRequest) (*v1pb.Tag, error) {
user, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get user")
}
tag, err := s.Store.UpsertTag(ctx, &store.Tag{
Name: request.Name,
CreatorID: user.ID,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to upsert tag: %v", err)
}
tagMessage, err := s.convertTagFromStore(ctx, tag)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to convert tag: %v", err)
}
return tagMessage, nil
}
func (s *APIV1Service) BatchUpsertTag(ctx context.Context, request *v1pb.BatchUpsertTagRequest) (*emptypb.Empty, error) {
for _, r := range request.Requests {
if _, err := s.UpsertTag(ctx, r); err != nil {
return nil, status.Errorf(codes.Internal, "failed to batch upsert tags: %v", err)
}
}
return &emptypb.Empty{}, nil
}
func (s *APIV1Service) ListTags(ctx context.Context, _ *v1pb.ListTagsRequest) (*v1pb.ListTagsResponse, error) {
user, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get user")
}
if user == nil {
return nil, status.Errorf(codes.PermissionDenied, "permission denied")
}
tagFind := &store.FindTag{
CreatorID: user.ID,
}
tags, err := s.Store.ListTags(ctx, tagFind)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list tags: %v", err)
}
response := &v1pb.ListTagsResponse{}
for _, tag := range tags {
t, err := s.convertTagFromStore(ctx, tag)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to convert tag: %v", err)
}
response.Tags = append(response.Tags, t)
}
return response, nil
}
func (s *APIV1Service) RenameTag(ctx context.Context, request *v1pb.RenameTagRequest) (*emptypb.Empty, error) {
userID, err := ExtractUserIDFromName(request.User)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid user name: %v", err)
}
user, err := s.Store.GetUser(ctx, &store.FindUser{
ID: &userID,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
}
if user == nil {
return nil, status.Errorf(codes.NotFound, "user not found")
}
// Find all related memos.
memos, err := s.Store.ListMemos(ctx, &store.FindMemo{
CreatorID: &user.ID,
ContentSearch: []string{fmt.Sprintf("#%s", request.OldName)},
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list memos: %v", err)
}
// Replace tag name in memo content.
for _, memo := range memos {
nodes, err := parser.Parse(tokenizer.Tokenize(memo.Content))
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to parse memo: %v", err)
}
TraverseASTNodes(nodes, func(node ast.Node) {
if tag, ok := node.(*ast.Tag); ok && tag.Content == request.OldName {
tag.Content = request.NewName
}
})
content := restore.Restore(nodes)
if err := s.Store.UpdateMemo(ctx, &store.UpdateMemo{
ID: memo.ID,
Content: &content,
}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to update memo: %v", err)
}
}
// Delete old tag and create new tag.
if err := s.Store.DeleteTag(ctx, &store.DeleteTag{
CreatorID: user.ID,
Name: request.OldName,
}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to delete tag: %v", err)
}
if _, err := s.Store.UpsertTag(ctx, &store.Tag{
CreatorID: user.ID,
Name: request.NewName,
}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to upsert tag: %v", err)
}
return &emptypb.Empty{}, nil
}
func (s *APIV1Service) DeleteTag(ctx context.Context, request *v1pb.DeleteTagRequest) (*emptypb.Empty, error) {
user, err := getCurrentUser(ctx, s.Store)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
}
if user == nil {
return nil, status.Errorf(codes.NotFound, "user not found")
}
if err := s.Store.DeleteTag(ctx, &store.DeleteTag{
Name: request.Tag.Name,
CreatorID: user.ID,
}); err != nil {
return nil, status.Errorf(codes.Internal, "failed to delete tag: %v", err)
}
return &emptypb.Empty{}, nil
}
func (s *APIV1Service) GetTagSuggestions(ctx context.Context, request *v1pb.GetTagSuggestionsRequest) (*v1pb.GetTagSuggestionsResponse, error) {
userID, err := ExtractUserIDFromName(request.User)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid user name: %v", err)
}
user, err := s.Store.GetUser(ctx, &store.FindUser{
ID: &userID,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
}
if user == nil {
return nil, status.Errorf(codes.NotFound, "user not found")
}
normalRowStatus := store.Normal
memoFind := &store.FindMemo{
CreatorID: &user.ID,
ContentSearch: []string{"#"},
RowStatus: &normalRowStatus,
}
memos, err := s.Store.ListMemos(ctx, memoFind)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list memos: %v", err)
}
tagList, err := s.Store.ListTags(ctx, &store.FindTag{
CreatorID: user.ID,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list tags: %v", err)
}
tagNameList := []string{}
for _, tag := range tagList {
tagNameList = append(tagNameList, tag.Name)
}
tagMapSet := make(map[string]bool)
for _, memo := range memos {
nodes, err := parser.Parse(tokenizer.Tokenize(memo.Content))
if err != nil {
return nil, errors.Wrap(err, "failed to parse memo content")
}
// Dynamically upsert tags from memo content.
TraverseASTNodes(nodes, func(node ast.Node) {
if tagNode, ok := node.(*ast.Tag); ok {
tag := tagNode.Content
if !slices.Contains(tagNameList, tag) {
tagMapSet[tag] = true
}
}
})
}
suggestions := []string{}
for tag := range tagMapSet {
suggestions = append(suggestions, tag)
}
sort.Strings(suggestions)
return &v1pb.GetTagSuggestionsResponse{
Tags: suggestions,
}, nil
}
func (s *APIV1Service) convertTagFromStore(ctx context.Context, tag *store.Tag) (*v1pb.Tag, error) {
user, err := s.Store.GetUser(ctx, &store.FindUser{
ID: &tag.CreatorID,
})
if err != nil {
return nil, errors.Wrap(err, "failed to get user")
}
return &v1pb.Tag{
Name: tag.Name,
Creator: fmt.Sprintf("%s%d", UserNamePrefix, user.ID),
}, nil
}
func TraverseASTNodes(nodes []ast.Node, fn func(ast.Node)) {
for _, node := range nodes {
fn(node)
switch n := node.(type) {
case *ast.Paragraph:
TraverseASTNodes(n.Children, fn)
case *ast.Heading:
TraverseASTNodes(n.Children, fn)
case *ast.Blockquote:
TraverseASTNodes(n.Children, fn)
case *ast.OrderedList:
TraverseASTNodes(n.Children, fn)
case *ast.UnorderedList:
TraverseASTNodes(n.Children, fn)
case *ast.TaskList:
TraverseASTNodes(n.Children, fn)
case *ast.Bold:
TraverseASTNodes(n.Children, fn)
}
}
}

View File

@ -23,7 +23,6 @@ type APIV1Service struct {
v1pb.UnimplementedUserServiceServer
v1pb.UnimplementedMemoServiceServer
v1pb.UnimplementedResourceServiceServer
v1pb.UnimplementedTagServiceServer
v1pb.UnimplementedInboxServiceServer
v1pb.UnimplementedActivityServiceServer
v1pb.UnimplementedWebhookServiceServer
@ -50,7 +49,6 @@ func NewAPIV1Service(secret string, profile *profile.Profile, store *store.Store
v1pb.RegisterAuthServiceServer(grpcServer, apiv1Service)
v1pb.RegisterUserServiceServer(grpcServer, apiv1Service)
v1pb.RegisterMemoServiceServer(grpcServer, apiv1Service)
v1pb.RegisterTagServiceServer(grpcServer, apiv1Service)
v1pb.RegisterResourceServiceServer(grpcServer, apiv1Service)
v1pb.RegisterInboxServiceServer(grpcServer, apiv1Service)
v1pb.RegisterActivityServiceServer(grpcServer, apiv1Service)
@ -102,9 +100,6 @@ func (s *APIV1Service) RegisterGateway(ctx context.Context, echoServer *echo.Ech
if err := v1pb.RegisterMemoServiceHandler(context.Background(), gwMux, conn); err != nil {
return err
}
if err := v1pb.RegisterTagServiceHandler(context.Background(), gwMux, conn); err != nil {
return err
}
if err := v1pb.RegisterResourceServiceHandler(context.Background(), gwMux, conn); err != nil {
return err
}

View File

@ -2,6 +2,7 @@ package mysql
import (
"context"
"encoding/json"
"fmt"
"strings"
@ -11,9 +12,17 @@ import (
)
func (d *DB) CreateMemo(ctx context.Context, create *store.Memo) (*store.Memo, error) {
fields := []string{"`uid`", "`creator_id`", "`content`", "`visibility`"}
placeholder := []string{"?", "?", "?", "?"}
args := []any{create.UID, create.CreatorID, create.Content, create.Visibility}
fields := []string{"`uid`", "`creator_id`", "`content`", "`visibility`", "`tags`"}
placeholder := []string{"?", "?", "?", "?", "?"}
tags := "[]"
if len(create.Tags) != 0 {
tagsBytes, err := json.Marshal(create.Tags)
if err != nil {
return nil, err
}
tags = string(tagsBytes)
}
args := []any{create.UID, create.CreatorID, create.Content, create.Visibility, tags}
stmt := "INSERT INTO `memo` (" + strings.Join(fields, ", ") + ") VALUES (" + strings.Join(placeholder, ", ") + ")"
result, err := d.db.ExecContext(ctx, stmt, args...)
@ -76,6 +85,9 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
}
where = append(where, fmt.Sprintf("`memo`.`visibility` in (%s)", strings.Join(placeholder, ",")))
}
if v := find.Tag; v != nil {
where, args = append(where, "JSON_CONTAINS(`memo`.`tags`, ?, '$')"), append(args, *v)
}
if find.ExcludeComments {
having = append(having, "`parent_id` IS NULL")
}
@ -102,6 +114,7 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
"UNIX_TIMESTAMP(`memo`.`updated_ts`) AS `updated_ts`",
"`memo`.`row_status` AS `row_status`",
"`memo`.`visibility` AS `visibility`",
"`memo`.`tags` AS `tags`",
"IFNULL(`memo_organizer`.`pinned`, 0) AS `pinned`",
"`memo_relation`.`related_memo_id` AS `parent_id`",
}
@ -126,6 +139,7 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
list := make([]*store.Memo, 0)
for rows.Next() {
var memo store.Memo
var tagsBytes []byte
dests := []any{
&memo.ID,
&memo.UID,
@ -134,6 +148,7 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
&memo.UpdatedTs,
&memo.RowStatus,
&memo.Visibility,
&tagsBytes,
&memo.Pinned,
&memo.ParentID,
}
@ -143,6 +158,9 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
if err := rows.Scan(dests...); err != nil {
return nil, err
}
if err := json.Unmarshal(tagsBytes, &memo.Tags); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal tags")
}
list = append(list, &memo)
}
@ -186,6 +204,13 @@ func (d *DB) UpdateMemo(ctx context.Context, update *store.UpdateMemo) error {
if v := update.Visibility; v != nil {
set, args = append(set, "`visibility` = ?"), append(args, *v)
}
if v := update.Tags; v != nil {
tagsBytes, err := json.Marshal(v)
if err != nil {
return err
}
set, args = append(set, "`tags` = ?"), append(args, string(tagsBytes))
}
args = append(args, update.ID)
stmt := "UPDATE `memo` SET " + strings.Join(set, ", ") + " WHERE `id` = ?"

View File

@ -43,7 +43,8 @@ CREATE TABLE `memo` (
`updated_ts` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`row_status` VARCHAR(256) NOT NULL DEFAULT 'NORMAL',
`content` TEXT NOT NULL,
`visibility` VARCHAR(256) NOT NULL DEFAULT 'PRIVATE'
`visibility` VARCHAR(256) NOT NULL DEFAULT 'PRIVATE',
`tags` JSON NOT NULL
);
-- memo_organizer

View File

@ -0,0 +1,4 @@
ALTER TABLE `memo` ADD COLUMN `tags_temp` JSON;
UPDATE `memo` SET `tags_temp` = '[]';
ALTER TABLE `memo` DROP COLUMN `tags`;
ALTER TABLE `memo` CHANGE COLUMN `tags_temp` `tags` JSON NOT NULL;

View File

@ -2,6 +2,7 @@ package postgres
import (
"context"
"encoding/json"
"fmt"
"strings"
@ -11,8 +12,16 @@ import (
)
func (d *DB) CreateMemo(ctx context.Context, create *store.Memo) (*store.Memo, error) {
fields := []string{"uid", "creator_id", "content", "visibility"}
args := []any{create.UID, create.CreatorID, create.Content, create.Visibility}
fields := []string{"uid", "creator_id", "content", "visibility", "tags"}
tags := "[]"
if len(create.Tags) != 0 {
tagsBytes, err := json.Marshal(create.Tags)
if err != nil {
return nil, err
}
tags = string(tagsBytes)
}
args := []any{create.UID, create.CreatorID, create.Content, create.Visibility, tags}
stmt := "INSERT INTO memo (" + strings.Join(fields, ", ") + ") VALUES (" + placeholders(len(args)) + ") RETURNING id, created_ts, updated_ts, row_status"
if err := d.db.QueryRowContext(ctx, stmt, args...).Scan(
@ -67,6 +76,10 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
}
where = append(where, fmt.Sprintf("memo.visibility in (%s)", strings.Join(holders, ", ")))
}
if v := find.Tag; v != nil {
where = append(where, "memo.tags @> "+placeholder(len(args)+1))
args = append(args, fmt.Sprintf(`["%s"]`, *v))
}
if find.ExcludeComments {
where = append(where, "memo_relation.related_memo_id IS NULL")
}
@ -93,6 +106,7 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
`memo.updated_ts AS updated_ts`,
`memo.row_status AS row_status`,
`memo.visibility AS visibility`,
`memo.tags AS tags`,
`COALESCE(memo_organizer.pinned, 0) AS pinned`,
`memo_relation.related_memo_id AS parent_id`,
}
@ -122,6 +136,7 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
list := make([]*store.Memo, 0)
for rows.Next() {
var memo store.Memo
var tagsBytes []byte
dests := []any{
&memo.ID,
&memo.UID,
@ -130,6 +145,7 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
&memo.UpdatedTs,
&memo.RowStatus,
&memo.Visibility,
&tagsBytes,
&memo.Pinned,
&memo.ParentID,
}
@ -139,6 +155,9 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
if err := rows.Scan(dests...); err != nil {
return nil, err
}
if err := json.Unmarshal(tagsBytes, &memo.Tags); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal tags")
}
list = append(list, &memo)
}
@ -182,6 +201,13 @@ func (d *DB) UpdateMemo(ctx context.Context, update *store.UpdateMemo) error {
if v := update.Visibility; v != nil {
set, args = append(set, "visibility = "+placeholder(len(args)+1)), append(args, *v)
}
if v := update.Tags; v != nil {
tagsBytes, err := json.Marshal(v)
if err != nil {
return err
}
set, args = append(set, "tags = "+placeholder(len(args)+1)), append(args, string(tagsBytes))
}
stmt := `UPDATE memo SET ` + strings.Join(set, ", ") + ` WHERE id = ` + placeholder(len(args)+1)
args = append(args, update.ID)
if _, err := d.db.ExecContext(ctx, stmt, args...); err != nil {

View File

@ -43,7 +43,8 @@ CREATE TABLE memo (
updated_ts BIGINT NOT NULL DEFAULT EXTRACT(EPOCH FROM NOW()),
row_status TEXT NOT NULL DEFAULT 'NORMAL',
content TEXT NOT NULL,
visibility TEXT NOT NULL DEFAULT 'PRIVATE'
visibility TEXT NOT NULL DEFAULT 'PRIVATE',
tags JSONB NOT NULL DEFAULT '[]'
);
-- memo_organizer

View File

@ -0,0 +1 @@
ALTER TABLE memo ADD COLUMN tags JSONB NOT NULL DEFAULT '[]';

View File

@ -2,16 +2,26 @@ package sqlite
import (
"context"
"encoding/json"
"fmt"
"strings"
"github.com/pkg/errors"
"github.com/usememos/memos/store"
)
func (d *DB) CreateMemo(ctx context.Context, create *store.Memo) (*store.Memo, error) {
fields := []string{"`uid`", "`creator_id`", "`content`", "`visibility`"}
placeholder := []string{"?", "?", "?", "?"}
args := []any{create.UID, create.CreatorID, create.Content, create.Visibility}
fields := []string{"`uid`", "`creator_id`", "`content`", "`visibility`, `tags`"}
placeholder := []string{"?", "?", "?", "?", "?"}
tags := "[]"
if len(create.Tags) != 0 {
tagsBytes, err := json.Marshal(create.Tags)
if err != nil {
return nil, err
}
tags = string(tagsBytes)
}
args := []any{create.UID, create.CreatorID, create.Content, create.Visibility, tags}
stmt := "INSERT INTO `memo` (" + strings.Join(fields, ", ") + ") VALUES (" + strings.Join(placeholder, ", ") + ") RETURNING `id`, `created_ts`, `updated_ts`, `row_status`"
if err := d.db.QueryRowContext(ctx, stmt, args...).Scan(
@ -66,6 +76,9 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
}
where = append(where, fmt.Sprintf("`memo`.`visibility` IN (%s)", strings.Join(placeholder, ",")))
}
if v := find.Tag; v != nil {
where, args = append(where, "JSON_EXTRACT(`memo`.`tags`, '$') LIKE ?"), append(args, fmt.Sprintf(`%%"%s"%%`, *v))
}
if find.ExcludeComments {
where = append(where, "`parent_id` IS NULL")
}
@ -92,6 +105,7 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
"`memo`.`updated_ts` AS `updated_ts`",
"`memo`.`row_status` AS `row_status`",
"`memo`.`visibility` AS `visibility`",
"`memo`.`tags` AS `tags`",
"IFNULL(`memo_organizer`.`pinned`, 0) AS `pinned`",
"`memo_relation`.`related_memo_id` AS `parent_id`",
}
@ -120,6 +134,7 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
list := make([]*store.Memo, 0)
for rows.Next() {
var memo store.Memo
var tagsBytes []byte
dests := []any{
&memo.ID,
&memo.UID,
@ -128,6 +143,7 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
&memo.UpdatedTs,
&memo.RowStatus,
&memo.Visibility,
&tagsBytes,
&memo.Pinned,
&memo.ParentID,
}
@ -137,6 +153,9 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
if err := rows.Scan(dests...); err != nil {
return nil, err
}
if err := json.Unmarshal(tagsBytes, &memo.Tags); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal tags")
}
list = append(list, &memo)
}
@ -167,6 +186,13 @@ func (d *DB) UpdateMemo(ctx context.Context, update *store.UpdateMemo) error {
if v := update.Visibility; v != nil {
set, args = append(set, "`visibility` = ?"), append(args, *v)
}
if v := update.Tags; v != nil {
tagsBytes, err := json.Marshal(v)
if err != nil {
return err
}
set, args = append(set, "`tags` = ?"), append(args, string(tagsBytes))
}
args = append(args, update.ID)
stmt := "UPDATE `memo` SET " + strings.Join(set, ", ") + " WHERE `id` = ?"

View File

@ -46,12 +46,14 @@ CREATE TABLE memo (
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL',
content TEXT NOT NULL DEFAULT '',
visibility TEXT NOT NULL CHECK (visibility IN ('PUBLIC', 'PROTECTED', 'PRIVATE')) DEFAULT 'PRIVATE'
visibility TEXT NOT NULL CHECK (visibility IN ('PUBLIC', 'PROTECTED', 'PRIVATE')) DEFAULT 'PRIVATE',
tags TEXT NOT NULL DEFAULT '[]'
);
CREATE INDEX idx_memo_creator_id ON memo (creator_id);
CREATE INDEX idx_memo_content ON memo (content);
CREATE INDEX idx_memo_visibility ON memo (visibility);
CREATE INDEX idx_memo_tags ON memo (tags);
-- memo_organizer
CREATE TABLE memo_organizer (

View File

@ -0,0 +1,3 @@
ALTER TABLE memo ADD COLUMN tags TEXT NOT NULL DEFAULT '[]';
CREATE INDEX idx_memo_tags ON memo (tags);

View File

@ -46,6 +46,7 @@ type Memo struct {
// Domain specific fields
Content string
Visibility Visibility
Tags []string
// Composed fields
Pinned bool
@ -67,6 +68,7 @@ type FindMemo struct {
// Domain specific fields
ContentSearch []string
VisibilityList []Visibility
Tag *string
ExcludeContent bool
ExcludeComments bool
Random bool
@ -86,6 +88,7 @@ type UpdateMemo struct {
RowStatus *RowStatus
Content *string
Visibility *Visibility
Tags *[]string
}
type DeleteMemo struct {

View File

@ -1,175 +0,0 @@
import { Button, IconButton, Input } from "@mui/joy";
import React, { useEffect, useState } from "react";
import { toast } from "react-hot-toast";
import { tagServiceClient } from "@/grpcweb";
import useCurrentUser from "@/hooks/useCurrentUser";
import { useTagStore } from "@/store/v1";
import { useTranslate } from "@/utils/i18n";
import { TAG_REG } from "@/utils/tag";
import { generateDialog } from "./Dialog";
import Icon from "./Icon";
import OverflowTip from "./kit/OverflowTip";
type Props = DialogProps;
const validateTagName = (tagName: string): boolean => {
const matchResult = `#${tagName}`.match(TAG_REG);
if (!matchResult || matchResult[1] !== tagName) {
return false;
}
return true;
};
const CreateTagDialog: React.FC<Props> = (props: Props) => {
const { destroy } = props;
const t = useTranslate();
const currentUser = useCurrentUser();
const tagStore = useTagStore();
const [tagName, setTagName] = useState<string>("");
const [suggestTags, setSuggestTags] = useState<string[]>([]);
const [showTagSuggestions, setShowTagSuggestions] = useState<boolean>(false);
const tags = Array.from(tagStore.getState().tags);
const shownSuggestTags = suggestTags.filter((tag) => !tags.includes(tag));
useEffect(() => {
tagServiceClient
.getTagSuggestions({
user: currentUser.name,
})
.then(({ tags }) => {
setSuggestTags(tags.filter((tag) => validateTagName(tag)));
});
}, [tags]);
const handleTagNameInputKeyDown = (event: React.KeyboardEvent) => {
if (event.key === "Enter") {
handleSaveBtnClick();
}
};
const handleTagNameChanged = (event: React.ChangeEvent<HTMLInputElement>) => {
const tag = event.target.value;
setTagName(tag.trim());
};
const handleUpsertTag = async (tag: string) => {
await tagStore.upsertTag(tag);
};
const handleToggleShowSuggestionTags = () => {
setShowTagSuggestions((state) => !state);
};
const handleSaveBtnClick = async () => {
if (!validateTagName(tagName)) {
toast.error(t("tag.invalid-tag-name"));
return;
}
try {
await tagStore.upsertTag(tagName);
setTagName("");
} catch (error: any) {
console.error(error);
toast.error(error.response.data.message);
}
};
const handleDeleteTag = async (tag: string) => {
await tagStore.deleteTag(tag);
};
const handleSaveSuggestTagList = async () => {
for (const tagName of suggestTags) {
if (validateTagName(tagName)) {
await tagStore.upsertTag(tagName);
}
}
};
return (
<>
<div className="dialog-header-container">
<p className="title-text">{t("tag.create-tag")}</p>
<IconButton size="sm" onClick={() => destroy()}>
<Icon.X className="w-5 h-auto" />
</IconButton>
</div>
<div className="dialog-content-container !w-80">
<Input
className="mb-2"
size="md"
placeholder={t("tag.tag-name")}
value={tagName}
onChange={handleTagNameChanged}
onKeyDown={handleTagNameInputKeyDown}
fullWidth
startDecorator={<Icon.Hash className="w-4 h-auto" />}
endDecorator={<Icon.Check onClick={handleSaveBtnClick} className="w-4 h-auto cursor-pointer hover:opacity-80" />}
/>
{tags.length > 0 && (
<>
<p className="w-full mt-2 mb-1 text-sm text-gray-400">{t("tag.all-tags")}</p>
<div className="w-full flex flex-row justify-start items-start flex-wrap">
{tags.sort().map((tag) => (
<OverflowTip
key={tag}
className="max-w-[120px] text-sm mr-2 mt-1 font-mono cursor-pointer dark:text-gray-300 hover:opacity-60 hover:line-through"
>
<span className="w-full" onClick={() => handleDeleteTag(tag)}>
#{tag}
</span>
</OverflowTip>
))}
</div>
</>
)}
{shownSuggestTags.length > 0 && (
<>
<div className="mt-4 mb-1 text-sm w-full flex flex-row justify-start items-center">
<span className="text-gray-400 mr-2">{t("tag.tag-suggestions")}</span>
<span
className="text-xs border border-gray-200 rounded-md px-1 leading-5 cursor-pointer text-gray-600 hover:shadow dark:border-zinc-700 dark:text-gray-400"
onClick={handleToggleShowSuggestionTags}
>
{showTagSuggestions ? t("tag.hide") : t("tag.show")}
</span>
</div>
{showTagSuggestions && (
<>
<div className="w-full flex flex-row justify-start items-start flex-wrap mb-2">
{shownSuggestTags.map((tag) => (
<OverflowTip
key={tag}
className="max-w-[120px] text-sm mr-2 mt-1 font-mono cursor-pointer dark:text-gray-300 hover:opacity-60"
>
<span className="w-full" onClick={() => handleUpsertTag(tag)}>
#{tag}
</span>
</OverflowTip>
))}
</div>
<Button size="sm" variant="outlined" onClick={handleSaveSuggestTagList}>
{t("tag.save-all")}
</Button>
</>
)}
</>
)}
</div>
</>
);
};
function showCreateTagDialog() {
generateDialog(
{
className: "create-tag-dialog",
dialogName: "create-tag-dialog",
},
CreateTagDialog,
);
}
export default showCreateTagDialog;

View File

@ -1,9 +1,10 @@
import { Dropdown, Menu, MenuButton, MenuItem } from "@mui/joy";
import { Dropdown, Menu, MenuButton, MenuItem, Tooltip } from "@mui/joy";
import toast from "react-hot-toast";
import useDebounce from "react-use/lib/useDebounce";
import { memoServiceClient } from "@/grpcweb";
import { useFilterStore } from "@/store/module";
import { useMemoList, useTagStore } from "@/store/v1";
import { useTranslate } from "@/utils/i18n";
import showCreateTagDialog from "../CreateTagDialog";
import { showCommonDialog } from "../Dialog/CommonDialog";
import Icon from "../Icon";
import showRenameTagDialog from "../RenameTagDialog";
@ -14,7 +15,9 @@ const TagsSection = () => {
const tagStore = useTagStore();
const memoList = useMemoList();
const filter = filterStore.state;
const tags = tagStore.tags;
const tagAmounts = Object.entries(tagStore.getState().tagAmounts)
.sort((a, b) => a[0].localeCompare(b[0]))
.sort((a, b) => b[1] - a[1]);
useDebounce(
() => {
@ -24,22 +27,42 @@ const TagsSection = () => {
[memoList.size()],
);
const handleRebuildMemoTags = () => {
showCommonDialog({
title: "Rebuild tags",
content: "It will rebuild tags for all memos, are you sure?",
style: "warning",
dialogName: "rebuild-memo-tags-dialog",
onConfirm: async () => {
await memoServiceClient.listMemoTags({
parent: "memos/-",
rebuild: true,
});
await tagStore.fetchTags({ skipCache: true });
toast.success("Rebuild tags successfully");
},
});
};
return (
<div className="flex flex-col justify-start items-start w-full mt-3 px-1 h-auto shrink-0 flex-nowrap hide-scrollbar">
<div className="flex flex-row justify-start items-center w-full">
<span className="text-sm leading-6 font-mono text-gray-400 select-none" onDoubleClick={() => showCreateTagDialog()}>
{t("common.tags")}
</span>
<div className="flex flex-row justify-between items-center w-full mb-1">
<span className="text-sm leading-6 font-mono text-gray-400 select-none">{t("common.tags")}</span>
<div>
<Tooltip title={"Rebuild"} placement="top">
<Icon.RefreshCcw className="text-gray-400 w-4 h-auto cursor-pointer hover:opacity-80" onClick={handleRebuildMemoTags} />
</Tooltip>
</div>
</div>
{tags.size > 0 ? (
<div className="flex flex-col justify-start items-start relative w-full h-auto flex-nowrap gap-2 mt-1">
{Array.from(tags).map((tag) => (
<TagItemContainer key={tag} tag={tag} tagQuery={filter.tag} />
{tagAmounts.length > 0 ? (
<div className="w-full flex flex-row justify-start items-center relative flex-wrap gap-1">
{tagAmounts.map(([tag, amount]) => (
<TagContainer key={tag} tag={tag} amount={amount} tagQuery={filter.tag} />
))}
</div>
) : (
<div className="p-2 border rounded-md flex flex-row justify-start items-start gap-1 text-gray-400 dark:text-gray-500">
<Icon.ThumbsUp />
<div className="p-2 border border-dashed rounded-md flex flex-row justify-start items-start gap-1 text-gray-400 dark:text-gray-500">
<Icon.Tags />
<p className="mt-0.5 text-sm leading-snug italic">{t("tag.create-tags-guide")}</p>
</div>
)}
@ -47,16 +70,17 @@ const TagsSection = () => {
);
};
interface TagItemContainerProps {
interface TagContainerProps {
tag: string;
amount: number;
tagQuery?: string;
}
const TagItemContainer: React.FC<TagItemContainerProps> = (props: TagItemContainerProps) => {
const TagContainer: React.FC<TagContainerProps> = (props: TagContainerProps) => {
const t = useTranslate();
const filterStore = useFilterStore();
const tagStore = useTagStore();
const { tag, tagQuery } = props;
const { tag, amount, tagQuery } = props;
const isActive = tagQuery === tag;
const handleTagClick = () => {
@ -81,37 +105,34 @@ const TagItemContainer: React.FC<TagItemContainerProps> = (props: TagItemContain
};
return (
<>
<div className="relative flex flex-row justify-between items-center w-full leading-6 py-0 mt-px rounded-lg text-sm select-none shrink-0">
<div
className={`flex flex-row justify-start items-center truncate shrink leading-5 mr-1 text-gray-600 dark:text-gray-400 ${
isActive && "!text-blue-600"
}`}
>
<Dropdown>
<MenuButton slots={{ root: "div" }}>
<div className="shrink-0 group">
<Icon.Hash className="group-hover:hidden w-4 h-auto shrink-0 opacity-60 mr-1" />
<Icon.MoreVertical className="hidden group-hover:block w-4 h-auto shrink-0 opacity-60 mr-1" />
</div>
</MenuButton>
<Menu size="sm" placement="bottom">
<MenuItem onClick={() => showRenameTagDialog({ tag: tag })}>
<Icon.Edit3 className="w-4 h-auto" />
{t("common.rename")}
</MenuItem>
<MenuItem color="danger" onClick={handleDeleteTag}>
<Icon.Trash className="w-4 h-auto" />
{t("common.delete")}
</MenuItem>
</Menu>
</Dropdown>
<span className="truncate cursor-pointer hover:opacity-80" onClick={handleTagClick}>
{tag}
</span>
</div>
<div
className={`shrink-0 w-auto max-w-full border text-sm rounded-md leading-6 flex flex-row justify-start items-center select-none hover:shadow-sm dark:hover:opacity-80 text-gray-600 dark:text-gray-400 dark:border-zinc-800 ${
isActive && "bg-blue-50 dark:bg-zinc-800"
}`}
>
<Dropdown>
<MenuButton slots={{ root: "div" }}>
<div className="shrink-0 group ml-1">
<Icon.Hash className="group-hover:hidden w-4 h-auto shrink-0 opacity-60" />
<Icon.MoreVertical className="hidden group-hover:block w-4 h-auto shrink-0 opacity-60" />
</div>
</MenuButton>
<Menu size="sm" placement="bottom-start">
<MenuItem onClick={() => showRenameTagDialog({ tag: tag })}>
<Icon.Edit3 className="w-4 h-auto" />
{t("common.rename")}
</MenuItem>
<MenuItem color="danger" onClick={handleDeleteTag}>
<Icon.Trash className="w-4 h-auto" />
{t("common.delete")}
</MenuItem>
</Menu>
</Dropdown>
<div className="inline-flex flex-nowrap pl-0.5 pr-1 gap-1 cursor-pointer max-w-[calc(100%-20px)]" onClick={handleTagClick}>
<span className="truncate">{tag}</span>
<span className="opacity-60 shrink-0">({amount})</span>
</div>
</>
</div>
);
};

View File

@ -13,13 +13,11 @@ const LearnMore: React.FC<Props> = (props: Props) => {
const t = useTranslate();
return (
<>
<Tooltip title={title ?? t("common.learn-more")} placement="top">
<a className={`text-gray-500 dark:text-gray-400 hover:text-blue-600 ${className}`} href={url} target="_blank">
<Icon.ExternalLink className="w-4 h-auto" />
</a>
</Tooltip>
</>
<Tooltip title={title ?? t("common.learn-more")} placement="top">
<a className={`text-gray-500 dark:text-gray-400 hover:text-blue-600 ${className}`} href={url} target="_blank">
<Icon.ExternalLink className="w-4 h-auto" />
</a>
</Tooltip>
);
};

View File

@ -17,7 +17,7 @@ const TagSelector = (props: Props) => {
const tagStore = useTagStore();
const [open, setOpen] = useState(false);
const containerRef = useRef<HTMLDivElement>(null);
const tags = Array.from(tagStore.getState().tags);
const tags = tagStore.sortedTags();
useEffect(() => {
(async () => {

View File

@ -16,8 +16,7 @@ type Position = { left: number; top: number; height: number };
const TagSuggestions = ({ editorRef, editorActions }: Props) => {
const [position, setPosition] = useState<Position | null>(null);
const tagStore = useTagStore();
const tagsRef = useRef(Array.from(tagStore.getState().tags));
tagsRef.current = Array.from(tagStore.getState().tags);
const tags = tagStore.sortedTags();
const [selected, select] = useState(0);
const selectedRef = useRef(selected);
@ -37,7 +36,7 @@ const TagSuggestions = ({ editorRef, editorActions }: Props) => {
const suggestionsRef = useRef<string[]>([]);
suggestionsRef.current = (() => {
const search = getCurrentWord()[0].slice(1).toLowerCase();
const fuse = new Fuse(tagsRef.current);
const fuse = new Fuse(tags);
return fuse.search(search).map((result) => result.item);
})();

View File

@ -7,7 +7,7 @@ import { memoServiceClient } from "@/grpcweb";
import { TAB_SPACE_WIDTH } from "@/helpers/consts";
import { isValidUrl } from "@/helpers/utils";
import useCurrentUser from "@/hooks/useCurrentUser";
import { useMemoStore, useResourceStore, useUserStore, useWorkspaceSettingStore, useTagStore } from "@/store/v1";
import { useMemoStore, useResourceStore, useUserStore, useWorkspaceSettingStore } from "@/store/v1";
import { MemoRelation, MemoRelation_Type } from "@/types/proto/api/v1/memo_relation_service";
import { Visibility } from "@/types/proto/api/v1/memo_service";
import { Resource } from "@/types/proto/api/v1/resource_service";
@ -16,7 +16,6 @@ import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_sett
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import { useTranslate } from "@/utils/i18n";
import { convertVisibilityFromString, convertVisibilityToString } from "@/utils/memo";
import { extractTagsFromContent } from "@/utils/tag";
import Icon from "../Icon";
import VisibilityIcon from "../VisibilityIcon";
import AddMemoRelationButton from "./ActionButton/AddMemoRelationButton";
@ -58,7 +57,6 @@ const MemoEditor = (props: Props) => {
const userStore = useUserStore();
const memoStore = useMemoStore();
const resourceStore = useResourceStore();
const tagStore = useTagStore();
const currentUser = useCurrentUser();
const [state, setState] = useState<State>({
memoVisibility: Visibility.PRIVATE,
@ -352,10 +350,6 @@ const MemoEditor = (props: Props) => {
toast.error(error.details);
}
// Batch upsert tags.
const tags = await extractTagsFromContent(content);
await tagStore.batchUpsertTag(tags);
setState((state) => {
return {
...state,
@ -447,6 +441,7 @@ const MemoEditor = (props: Props) => {
</div>
<div className="shrink-0 flex flex-row justify-end items-center">
<Button
className="!font-normal"
disabled={!allowSave}
loading={state.isRequesting}
endDecorator={<Icon.Send className="w-4 h-auto" />}

View File

@ -1,8 +1,7 @@
import { Button, IconButton, Input, List, ListItem } from "@mui/joy";
import React, { useState } from "react";
import { toast } from "react-hot-toast";
import { tagServiceClient } from "@/grpcweb";
import useCurrentUser from "@/hooks/useCurrentUser";
import { memoServiceClient } from "@/grpcweb";
import useLoading from "@/hooks/useLoading";
import { useFilterStore } from "@/store/module";
import { useTagStore } from "@/store/v1";
@ -19,7 +18,6 @@ const RenameTagDialog: React.FC<Props> = (props: Props) => {
const t = useTranslate();
const tagStore = useTagStore();
const filterStore = useFilterStore();
const currentUser = useCurrentUser();
const [newName, setNewName] = useState(tag);
const requestState = useLoading(false);
@ -38,10 +36,10 @@ const RenameTagDialog: React.FC<Props> = (props: Props) => {
}
try {
await tagServiceClient.renameTag({
user: currentUser.name,
oldName: tag,
newName: newName,
await memoServiceClient.renameMemoTag({
parent: "memos/-",
oldTag: tag,
newTag: newName,
});
toast.success("Rename tag successfully");
filterStore.setTagFilter(newName);

View File

@ -1,4 +1,3 @@
import { Input } from "@mui/joy";
import { useEffect, useState } from "react";
import useDebounce from "react-use/lib/useDebounce";
import { useFilterStore } from "@/store/module";
@ -28,11 +27,10 @@ const SearchBar = () => {
};
return (
<div className="w-full h-9 flex flex-row justify-start items-center">
<Input
className="w-full !text-sm !shadow-none !border-gray-200 dark:!border-zinc-800"
size="md"
startDecorator={<Icon.Search className="w-4 h-auto opacity-30" />}
<div className="relative w-full h-auto flex flex-row justify-start items-center">
<Icon.Search className="absolute left-3 w-4 h-auto opacity-30" />
<input
className="w-full text-gray-500 dark:text-gray-400 bg-zinc-50 dark:bg-zinc-900 border dark:border-zinc-800 text-sm leading-6 rounded-lg p-1 pl-8 outline-none"
placeholder={t("memo.search-placeholder")}
value={queryText}
onChange={handleTextQueryInput}

View File

@ -18,7 +18,7 @@ const UserStatisticsView = (props: Props) => {
const [isRequesting, setIsRequesting] = useState(false);
const days = Math.ceil((Date.now() - user.createTime!.getTime()) / 86400000);
const memos = Object.values(memoStore.getState().memoMapByName);
const tags = tagStore.getState().tags.size;
const tags = tagStore.sortedTags().length;
useEffect(() => {
if (memos.length === 0) {
@ -37,7 +37,7 @@ const UserStatisticsView = (props: Props) => {
}, [memos.length, user.name]);
return (
<div className="w-full border mt-2 py-2 px-3 rounded-md space-y-0.5 text-gray-500 dark:text-gray-400 bg-zinc-50 dark:bg-zinc-900 dark:border-zinc-800">
<div className="w-full border mt-2 py-2 px-3 rounded-lg space-y-0.5 text-gray-500 dark:text-gray-400 bg-zinc-50 dark:bg-zinc-900 dark:border-zinc-800">
<div className="mb-1 w-full flex flex-row justify-between items-center">
<p className="text-sm font-medium leading-6 dark:text-gray-500">{t("common.statistics")}</p>
</div>

View File

@ -6,7 +6,6 @@ import { InboxServiceDefinition } from "./types/proto/api/v1/inbox_service";
import { MarkdownServiceDefinition } from "./types/proto/api/v1/markdown_service";
import { MemoServiceDefinition } from "./types/proto/api/v1/memo_service";
import { ResourceServiceDefinition } from "./types/proto/api/v1/resource_service";
import { TagServiceDefinition } from "./types/proto/api/v1/tag_service";
import { UserServiceDefinition } from "./types/proto/api/v1/user_service";
import { WebhookServiceDefinition } from "./types/proto/api/v1/webhook_service";
import { WorkspaceServiceDefinition } from "./types/proto/api/v1/workspace_service";
@ -33,8 +32,6 @@ export const memoServiceClient = clientFactory.create(MemoServiceDefinition, cha
export const resourceServiceClient = clientFactory.create(ResourceServiceDefinition, channel);
export const tagServiceClient = clientFactory.create(TagServiceDefinition, channel);
export const inboxServiceClient = clientFactory.create(InboxServiceDefinition, channel);
export const activityServiceClient = clientFactory.create(ActivityServiceDefinition, channel);

View File

@ -1,13 +1,4 @@
{
"about": {
"about-memos": "About memos",
"memos-description": "memos is a web-based note-taking application that you can use to write, organize, and share notes.",
"no-server-description": "No description configured for this server.",
"other-projects": "Other Projects"
},
"amount-text": {
"memo": "MEMO"
},
"auth": {
"create-your-account": "Create your account",
"host-tip": "You are registering as the Site Host.",
@ -328,7 +319,6 @@
"locale": "Server Locale",
"title": "Customize Server"
},
"database-file-size": "Database File Size",
"disable-password-login": "Disable password login",
"disable-password-login-final-warning": "Please type \"CONFIRM\" if you know what you are doing.",
"disable-password-login-warning": "This will disable password login for all users. It is not possible to log in without reverting this setting in the database if your configured identity providers fail. Youll also have to be extra carefull when removing an identity provider",
@ -338,24 +328,16 @@
"enable-password-login-warning": "This will enable password login for all users. Continue only if you want to users to be able to log in using both SSO and password",
"max-upload-size": "Maximum upload size (MiB)",
"max-upload-size-hint": "Recommended value is 32 MiB.",
"server-name": "Server Name",
"vacuum-hint": "Cleans up unused data."
"server-name": "Server Name"
}
},
"tag": {
"all-tags": "All Tags",
"create-tag": "Create Tag",
"create-tags-guide": "You can create tags by inputting `#tag`.",
"delete-confirm": "Are you sure to delete this tag?",
"delete-confirm": "Are you sure to delete this tag? All related memos will be archived.",
"delete-tag": "Delete Tag",
"hide": "Hide",
"invalid-tag-name": "Invalid tag name",
"no-tag-found": "No tag found",
"save-all": "Save all",
"show": "Show",
"tag-name": "TAG_NAME",
"tag-suggestions": "Tag suggestions",
"tip-text": "Input `#tag` to create"
"no-tag-found": "No tag found"
},
"timeline": {
"title": "Timeline"

View File

@ -39,15 +39,15 @@ const Archived = () => {
const fetchMemos = async () => {
const filters = [`creator == "${user.name}"`, `row_status == "ARCHIVED"`];
const contentSearch: string[] = [];
if (tagQuery) {
contentSearch.push(JSON.stringify(`#${tagQuery}`));
}
if (textQuery) {
contentSearch.push(JSON.stringify(textQuery));
}
if (contentSearch.length > 0) {
filters.push(`content_search == [${contentSearch.join(", ")}]`);
}
if (tagQuery) {
filters.push(`tag == "${tagQuery}"`);
}
setIsRequesting(true);
const data = await memoStore.fetchMemos({
pageSize: DEFAULT_LIST_MEMOS_PAGE_SIZE,

View File

@ -35,15 +35,15 @@ const Explore = () => {
const fetchMemos = async () => {
const filters = [`row_status == "NORMAL"`, `visibilities == [${user ? "'PUBLIC', 'PROTECTED'" : "'PUBLIC'"}]`];
const contentSearch: string[] = [];
if (tagQuery) {
contentSearch.push(JSON.stringify(`#${tagQuery}`));
}
if (textQuery) {
contentSearch.push(JSON.stringify(textQuery));
}
if (contentSearch.length > 0) {
filters.push(`content_search == [${contentSearch.join(", ")}]`);
}
if (tagQuery) {
filters.push(`tag == "${tagQuery}"`);
}
setIsRequesting(true);
const data = await memoStore.fetchMemos({
pageSize: DEFAULT_LIST_MEMOS_PAGE_SIZE,

View File

@ -41,15 +41,15 @@ const Home = () => {
const fetchMemos = async () => {
const filters = [`creator == "${user.name}"`, `row_status == "NORMAL"`, `order_by_pinned == true`];
const contentSearch: string[] = [];
if (tagQuery) {
contentSearch.push(JSON.stringify(`#${tagQuery}`));
}
if (textQuery) {
contentSearch.push(JSON.stringify(textQuery));
}
if (contentSearch.length > 0) {
filters.push(`content_search == [${contentSearch.join(", ")}]`);
}
if (tagQuery) {
filters.push(`tag == "${tagQuery}"`);
}
setIsRequesting(true);
const data = await memoStore.fetchMemos({
pageSize: DEFAULT_LIST_MEMOS_PAGE_SIZE,

View File

@ -68,15 +68,15 @@ const Timeline = () => {
(async () => {
const filters = [`row_status == "NORMAL"`];
const contentSearch: string[] = [];
if (tagQuery) {
contentSearch.push(JSON.stringify(`#${tagQuery}`));
}
if (textQuery) {
contentSearch.push(JSON.stringify(textQuery));
}
if (contentSearch.length > 0) {
filters.push(`content_search == [${contentSearch.join(", ")}]`);
}
if (tagQuery) {
filters.push(`tag == "${tagQuery}"`);
}
const { stats } = await memoServiceClient.getUserMemosStats({
name: user.name,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
@ -89,15 +89,15 @@ const Timeline = () => {
const fetchMemos = async () => {
const filters = [`creator == "${user.name}"`, `row_status == "NORMAL"`];
const contentSearch: string[] = [];
if (tagQuery) {
contentSearch.push(JSON.stringify(`#${tagQuery}`));
}
if (textQuery) {
contentSearch.push(JSON.stringify(textQuery));
}
if (contentSearch.length > 0) {
filters.push(`content_search == [${contentSearch.join(", ")}]`);
}
if (tagQuery) {
filters.push(`tag == "${tagQuery}"`);
}
if (selectedDay) {
const selectedDateStamp = getTimeStampByDate(selectedDay) + new Date().getTimezoneOffset() * 60 * 1000;
filters.push(

View File

@ -71,15 +71,15 @@ const UserProfile = () => {
const filters = [`creator == "${user.name}"`, `row_status == "NORMAL"`, `order_by_pinned == true`];
const contentSearch: string[] = [];
if (tagQuery) {
contentSearch.push(JSON.stringify(`#${tagQuery}`));
}
if (textQuery) {
contentSearch.push(JSON.stringify(textQuery));
}
if (contentSearch.length > 0) {
filters.push(`content_search == [${contentSearch.join(", ")}]`);
}
if (tagQuery) {
filters.push(`tag == "${tagQuery}"`);
}
setIsRequesting(true);
const data = await memoStore.fetchMemos({
pageSize: DEFAULT_LIST_MEMOS_PAGE_SIZE,

View File

@ -1,53 +1,41 @@
import { create } from "zustand";
import { combine } from "zustand/middleware";
import { tagServiceClient } from "@/grpcweb";
import { memoServiceClient } from "@/grpcweb";
interface State {
tags: Set<string>;
tagAmounts: Record<string, number>;
}
const getDefaultState = (): State => ({
tags: new Set(),
tagAmounts: {},
});
export const useTagStore = create(
combine(getDefaultState(), (set, get) => ({
setState: (state: State) => set(state),
getState: () => get(),
sortedTags: () => {
return Object.entries(get().tagAmounts)
.sort((a, b) => a[0].localeCompare(b[0]))
.sort((a, b) => b[1] - a[1])
.map(([tag]) => tag);
},
fetchTags: async (options?: { skipCache: boolean }) => {
const { tags: tagsCache } = get();
if (tagsCache.size && !options?.skipCache) {
return tagsCache;
const { tagAmounts: cache } = get();
if (cache.length > 0 && !options?.skipCache) {
return cache;
}
const { tags } = await tagServiceClient.listTags({});
set({ tags: new Set(tags.map((tag) => tag.name)) });
return tags;
},
upsertTag: async (tagName: string) => {
await tagServiceClient.upsertTag({
name: tagName,
});
const { tags } = get();
set({ tags: new Set([...tags, tagName]) });
},
batchUpsertTag: async (tagNames: string[]) => {
await tagServiceClient.batchUpsertTag({
requests: tagNames.map((name) => ({
name,
})),
});
const { tags } = get();
set({ tags: new Set([...tags, ...tagNames]) });
const { tagAmounts } = await memoServiceClient.listMemoTags({ parent: "memos/-" });
set({ tagAmounts });
},
deleteTag: async (tagName: string) => {
await tagServiceClient.deleteTag({
tag: {
name: tagName,
},
await memoServiceClient.deleteMemoTag({
parent: "memos/-",
tag: tagName,
});
const { tags } = get();
tags.delete(tagName);
set({ tags });
const { tagAmounts } = get();
delete tagAmounts[tagName];
set({ tagAmounts });
},
})),
);

View File

@ -1,34 +0,0 @@
import { markdownServiceClient } from "@/grpcweb";
import { Node, NodeType, TagNode } from "@/types/proto/api/v1/markdown_service";
export const TAG_REG = /#([^\s#,]+)/;
// extractTagsFromContent extracts tags from content.
export const extractTagsFromContent = async (content: string) => {
const { nodes } = await markdownServiceClient.parseMarkdown({ markdown: content });
const tags = new Set<string>();
const traverse = (nodes: Node[], handle: (node: Node) => void) => {
for (const node of nodes) {
if (!node) {
continue;
}
handle(node);
if (node.type === "PARAGRAPH" || node.type === "ORDERED_LIST" || node.type === "UNORDERED_LIST") {
const children = node.paragraphNode?.children || node.orderedListNode?.children || node.unorderedListNode?.children;
if (Array.isArray(children)) {
traverse(children, handle);
}
}
}
};
traverse(nodes, (node) => {
if (node.type === NodeType.TAG && node.tagNode) {
tags.add((node.tagNode as TagNode).content);
}
});
return Array.from(tags);
};