mirror of
https://github.com/usememos/memos.git
synced 2024-12-26 07:01:17 +08:00
feat: add user-defined name to memo
This commit is contained in:
parent
264e6e6e9c
commit
8382354ef7
19 changed files with 929 additions and 524 deletions
|
@ -21,10 +21,6 @@ import (
|
|||
"github.com/usememos/memos/store"
|
||||
)
|
||||
|
||||
var (
|
||||
usernameMatcher = regexp.MustCompile("^[a-z0-9]([a-z0-9-]{1,30}[a-z0-9])$")
|
||||
)
|
||||
|
||||
type SignIn struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
|
@ -293,7 +289,7 @@ func (s *APIV1Service) SignUp(c echo.Context) error {
|
|||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "Failed to find users").SetInternal(err)
|
||||
}
|
||||
if !usernameMatcher.MatchString(strings.ToLower(signup.Username)) {
|
||||
if !util.ResourceNameMatcher.MatchString(strings.ToLower(signup.Username)) {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid username %s", signup.Username)).SetInternal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -158,7 +158,7 @@ func (s *APIV1Service) CreateUser(c echo.Context) error {
|
|||
if err := userCreate.Validate(); err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "Invalid user create format").SetInternal(err)
|
||||
}
|
||||
if !usernameMatcher.MatchString(strings.ToLower(userCreate.Username)) {
|
||||
if !util.ResourceNameMatcher.MatchString(strings.ToLower(userCreate.Username)) {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid username %s", userCreate.Username)).SetInternal(err)
|
||||
}
|
||||
// Disallow host user to be created.
|
||||
|
@ -379,7 +379,7 @@ func (s *APIV1Service) UpdateUser(c echo.Context) error {
|
|||
}
|
||||
}
|
||||
if request.Username != nil {
|
||||
if !usernameMatcher.MatchString(strings.ToLower(*request.Username)) {
|
||||
if !util.ResourceNameMatcher.MatchString(strings.ToLower(*request.Username)) {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid username %s", *request.Username)).SetInternal(err)
|
||||
}
|
||||
userUpdate.Username = request.Username
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/lithammer/shortuuid/v4"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
expr "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
|
||||
|
@ -16,6 +17,7 @@ import (
|
|||
|
||||
apiv1 "github.com/usememos/memos/api/v1"
|
||||
"github.com/usememos/memos/internal/log"
|
||||
"github.com/usememos/memos/internal/util"
|
||||
"github.com/usememos/memos/plugin/gomark/ast"
|
||||
"github.com/usememos/memos/plugin/gomark/parser"
|
||||
"github.com/usememos/memos/plugin/gomark/parser/tokenizer"
|
||||
|
@ -49,9 +51,10 @@ func (s *APIV2Service) CreateMemo(ctx context.Context, request *apiv2pb.CreateMe
|
|||
}
|
||||
|
||||
create := &store.Memo{
|
||||
CreatorID: user.ID,
|
||||
Content: request.Content,
|
||||
Visibility: store.Visibility(request.Visibility.String()),
|
||||
ResourceName: shortuuid.New(),
|
||||
CreatorID: user.ID,
|
||||
Content: request.Content,
|
||||
Visibility: store.Visibility(request.Visibility.String()),
|
||||
}
|
||||
// Find disable public memos system setting.
|
||||
disablePublicMemosSystem, err := s.getDisablePublicMemosSystemSettingValue(ctx)
|
||||
|
@ -234,6 +237,27 @@ func (s *APIV2Service) GetMemo(ctx context.Context, request *apiv2pb.GetMemoRequ
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (s *APIV2Service) GetMemoByName(ctx context.Context, request *apiv2pb.GetMemoByNameRequest) (*apiv2pb.GetMemoByNameResponse, error) {
|
||||
memo, err := s.Store.GetMemo(ctx, &store.FindMemo{
|
||||
ResourceName: &request.Name,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if memo == nil {
|
||||
return nil, status.Errorf(codes.NotFound, "memo not found")
|
||||
}
|
||||
|
||||
memoMessage, err := s.convertMemoFromStore(ctx, memo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert memo")
|
||||
}
|
||||
response := &apiv2pb.GetMemoByNameResponse{
|
||||
Memo: memoMessage,
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *APIV2Service) UpdateMemo(ctx context.Context, request *apiv2pb.UpdateMemoRequest) (*apiv2pb.UpdateMemoResponse, error) {
|
||||
if request.UpdateMask == nil || len(request.UpdateMask.Paths) == 0 {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "update mask is required")
|
||||
|
@ -282,6 +306,11 @@ func (s *APIV2Service) UpdateMemo(ctx context.Context, request *apiv2pb.UpdateMe
|
|||
nodes := convertToASTNodes(request.Memo.Nodes)
|
||||
content := restore.Restore(nodes)
|
||||
update.Content = &content
|
||||
} else if path == "resource_name" {
|
||||
update.ResourceName = &request.Memo.Name
|
||||
if !util.ResourceNameMatcher.MatchString(*update.ResourceName) {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid resource name")
|
||||
}
|
||||
} else if path == "visibility" {
|
||||
visibility := convertVisibilityToStore(request.Memo.Visibility)
|
||||
update.Visibility = &visibility
|
||||
|
@ -574,6 +603,7 @@ func (s *APIV2Service) convertMemoFromStore(ctx context.Context, memo *store.Mem
|
|||
|
||||
return &apiv2pb.Memo{
|
||||
Id: int32(memo.ID),
|
||||
Name: memo.ResourceName,
|
||||
RowStatus: convertRowStatusFromStore(memo.RowStatus),
|
||||
Creator: fmt.Sprintf("%s%s", UserNamePrefix, creator.Username),
|
||||
CreatorId: int32(memo.CreatorID),
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -18,15 +17,12 @@ import (
|
|||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/usememos/memos/api/auth"
|
||||
"github.com/usememos/memos/internal/util"
|
||||
apiv2pb "github.com/usememos/memos/proto/gen/api/v2"
|
||||
storepb "github.com/usememos/memos/proto/gen/store"
|
||||
"github.com/usememos/memos/store"
|
||||
)
|
||||
|
||||
var (
|
||||
usernameMatcher = regexp.MustCompile("^[a-z0-9]([a-z0-9-]{1,30}[a-z0-9])$")
|
||||
)
|
||||
|
||||
func (s *APIV2Service) ListUsers(ctx context.Context, _ *apiv2pb.ListUsersRequest) (*apiv2pb.ListUsersResponse, error) {
|
||||
currentUser, err := getCurrentUser(ctx, s.Store)
|
||||
if err != nil {
|
||||
|
@ -85,7 +81,7 @@ func (s *APIV2Service) CreateUser(ctx context.Context, request *apiv2pb.CreateUs
|
|||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "name is required")
|
||||
}
|
||||
if !usernameMatcher.MatchString(strings.ToLower(username)) {
|
||||
if !util.ResourceNameMatcher.MatchString(strings.ToLower(username)) {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid username: %s", username)
|
||||
}
|
||||
passwordHash, err := bcrypt.GenerateFromPassword([]byte(request.User.Password), bcrypt.DefaultCost)
|
||||
|
@ -141,7 +137,7 @@ func (s *APIV2Service) UpdateUser(ctx context.Context, request *apiv2pb.UpdateUs
|
|||
}
|
||||
for _, field := range request.UpdateMask.Paths {
|
||||
if field == "username" {
|
||||
if !usernameMatcher.MatchString(strings.ToLower(request.User.Username)) {
|
||||
if !util.ResourceNameMatcher.MatchString(strings.ToLower(request.User.Username)) {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid username: %s", request.User.Username)
|
||||
}
|
||||
update.Username = &request.User.Username
|
||||
|
|
1
go.mod
1
go.mod
|
@ -18,6 +18,7 @@ require (
|
|||
github.com/joho/godotenv v1.5.1
|
||||
github.com/labstack/echo/v4 v4.11.4
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/lithammer/shortuuid/v4 v4.0.0
|
||||
github.com/microcosm-cc/bluemonday v1.0.26
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/spf13/cobra v1.8.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -286,6 +286,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
|||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/lithammer/shortuuid/v4 v4.0.0 h1:QRbbVkfgNippHOS8PXDkti4NaWeyYfcBTHtw7k08o4c=
|
||||
github.com/lithammer/shortuuid/v4 v4.0.0/go.mod h1:Zs8puNcrvf2rV9rTH51ZLLcj7ZXqQI3lv67aw4KiB1Y=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
|
|
7
internal/util/resource_name.go
Normal file
7
internal/util/resource_name.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package util
|
||||
|
||||
import "regexp"
|
||||
|
||||
var (
|
||||
ResourceNameMatcher = regexp.MustCompile("^[a-zA-Z0-9]([a-zA-Z0-9-]{1,30}[a-zA-Z0-9])$")
|
||||
)
|
|
@ -31,6 +31,11 @@ service MemoService {
|
|||
option (google.api.http) = {get: "/api/v2/memos/{id}"};
|
||||
option (google.api.method_signature) = "id";
|
||||
}
|
||||
// GetMemoByName gets a memo by name.
|
||||
rpc GetMemoByName(GetMemoByNameRequest) returns (GetMemoByNameResponse) {
|
||||
option (google.api.http) = {get: "/api/v2/memos/{name}"};
|
||||
option (google.api.method_signature) = "name";
|
||||
}
|
||||
// UpdateMemo updates a memo.
|
||||
rpc UpdateMemo(UpdateMemoRequest) returns (UpdateMemoResponse) {
|
||||
option (google.api.http) = {
|
||||
|
@ -98,35 +103,39 @@ enum Visibility {
|
|||
}
|
||||
|
||||
message Memo {
|
||||
// id is the unique auto-incremented id.
|
||||
int32 id = 1;
|
||||
|
||||
RowStatus row_status = 2;
|
||||
// name is the user-defined name.
|
||||
string name = 2;
|
||||
|
||||
RowStatus row_status = 3;
|
||||
|
||||
// The name of the creator.
|
||||
// Format: users/{username}
|
||||
string creator = 3;
|
||||
string creator = 4;
|
||||
|
||||
int32 creator_id = 4;
|
||||
int32 creator_id = 5;
|
||||
|
||||
google.protobuf.Timestamp create_time = 5;
|
||||
google.protobuf.Timestamp create_time = 6;
|
||||
|
||||
google.protobuf.Timestamp update_time = 6;
|
||||
google.protobuf.Timestamp update_time = 7;
|
||||
|
||||
google.protobuf.Timestamp display_time = 7;
|
||||
google.protobuf.Timestamp display_time = 8;
|
||||
|
||||
string content = 8;
|
||||
string content = 9;
|
||||
|
||||
repeated Node nodes = 9;
|
||||
repeated Node nodes = 10;
|
||||
|
||||
Visibility visibility = 10;
|
||||
Visibility visibility = 11;
|
||||
|
||||
bool pinned = 11;
|
||||
bool pinned = 12;
|
||||
|
||||
optional int32 parent_id = 12;
|
||||
optional int32 parent_id = 13 [(google.api.field_behavior) = OUTPUT_ONLY];
|
||||
|
||||
repeated Resource resources = 13 [(google.api.field_behavior) = OUTPUT_ONLY];
|
||||
repeated Resource resources = 14 [(google.api.field_behavior) = OUTPUT_ONLY];
|
||||
|
||||
repeated MemoRelation relations = 14 [(google.api.field_behavior) = OUTPUT_ONLY];
|
||||
repeated MemoRelation relations = 15 [(google.api.field_behavior) = OUTPUT_ONLY];
|
||||
}
|
||||
|
||||
message CreateMemoRequest {
|
||||
|
@ -163,6 +172,14 @@ message GetMemoResponse {
|
|||
Memo memo = 1;
|
||||
}
|
||||
|
||||
message GetMemoByNameRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message GetMemoByNameResponse {
|
||||
Memo memo = 1;
|
||||
}
|
||||
|
||||
message UpdateMemoRequest {
|
||||
int32 id = 1;
|
||||
|
||||
|
|
|
@ -129,6 +129,8 @@
|
|||
- [CreateMemoResponse](#memos-api-v2-CreateMemoResponse)
|
||||
- [DeleteMemoRequest](#memos-api-v2-DeleteMemoRequest)
|
||||
- [DeleteMemoResponse](#memos-api-v2-DeleteMemoResponse)
|
||||
- [GetMemoByNameRequest](#memos-api-v2-GetMemoByNameRequest)
|
||||
- [GetMemoByNameResponse](#memos-api-v2-GetMemoByNameResponse)
|
||||
- [GetMemoRequest](#memos-api-v2-GetMemoRequest)
|
||||
- [GetMemoResponse](#memos-api-v2-GetMemoResponse)
|
||||
- [GetUserMemosStatsRequest](#memos-api-v2-GetUserMemosStatsRequest)
|
||||
|
@ -1864,6 +1866,36 @@
|
|||
|
||||
|
||||
|
||||
<a name="memos-api-v2-GetMemoByNameRequest"></a>
|
||||
|
||||
### GetMemoByNameRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| name | [string](#string) | | |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="memos-api-v2-GetMemoByNameResponse"></a>
|
||||
|
||||
### GetMemoByNameResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| memo | [Memo](#memos-api-v2-Memo) | | |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a name="memos-api-v2-GetMemoRequest"></a>
|
||||
|
||||
### GetMemoRequest
|
||||
|
@ -2072,7 +2104,8 @@
|
|||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| id | [int32](#int32) | | |
|
||||
| id | [int32](#int32) | | id is the unique auto-incremented id. |
|
||||
| name | [string](#string) | | name is the user-defined name. |
|
||||
| row_status | [RowStatus](#memos-api-v2-RowStatus) | | |
|
||||
| creator | [string](#string) | | The name of the creator. Format: users/{username} |
|
||||
| creator_id | [int32](#int32) | | |
|
||||
|
@ -2206,6 +2239,7 @@
|
|||
| CreateMemo | [CreateMemoRequest](#memos-api-v2-CreateMemoRequest) | [CreateMemoResponse](#memos-api-v2-CreateMemoResponse) | CreateMemo creates a memo. |
|
||||
| ListMemos | [ListMemosRequest](#memos-api-v2-ListMemosRequest) | [ListMemosResponse](#memos-api-v2-ListMemosResponse) | ListMemos lists memos with pagination and filter. |
|
||||
| GetMemo | [GetMemoRequest](#memos-api-v2-GetMemoRequest) | [GetMemoResponse](#memos-api-v2-GetMemoResponse) | GetMemo gets a memo by id. |
|
||||
| GetMemoByName | [GetMemoByNameRequest](#memos-api-v2-GetMemoByNameRequest) | [GetMemoByNameResponse](#memos-api-v2-GetMemoByNameResponse) | GetMemoByName gets a memo by name. |
|
||||
| UpdateMemo | [UpdateMemoRequest](#memos-api-v2-UpdateMemoRequest) | [UpdateMemoResponse](#memos-api-v2-UpdateMemoResponse) | UpdateMemo updates a memo. |
|
||||
| DeleteMemo | [DeleteMemoRequest](#memos-api-v2-DeleteMemoRequest) | [DeleteMemoResponse](#memos-api-v2-DeleteMemoResponse) | DeleteMemo deletes a memo by id. |
|
||||
| SetMemoResources | [SetMemoResourcesRequest](#memos-api-v2-SetMemoResourcesRequest) | [SetMemoResourcesResponse](#memos-api-v2-SetMemoResourcesResponse) | SetMemoResources sets resources for a memo. |
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -153,6 +153,58 @@ func local_request_MemoService_GetMemo_0(ctx context.Context, marshaler runtime.
|
|||
|
||||
}
|
||||
|
||||
func request_MemoService_GetMemoByName_0(ctx context.Context, marshaler runtime.Marshaler, client MemoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetMemoByNameRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
|
||||
protoReq.Name, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
msg, err := client.GetMemoByName(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_MemoService_GetMemoByName_0(ctx context.Context, marshaler runtime.Marshaler, server MemoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetMemoByNameRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
|
||||
protoReq.Name, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
msg, err := server.GetMemoByName(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_MemoService_UpdateMemo_0(ctx context.Context, marshaler runtime.Marshaler, client MemoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq UpdateMemoRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
@ -752,6 +804,31 @@ func RegisterMemoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux
|
|||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_MemoService_GetMemoByName_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.v2.MemoService/GetMemoByName", runtime.WithHTTPPathPattern("/api/v2/memos/{name}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_MemoService_GetMemoByName_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_GetMemoByName_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("PATCH", pattern_MemoService_UpdateMemo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
|
@ -1084,6 +1161,28 @@ func RegisterMemoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux
|
|||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_MemoService_GetMemoByName_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.v2.MemoService/GetMemoByName", runtime.WithHTTPPathPattern("/api/v2/memos/{name}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_MemoService_GetMemoByName_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_GetMemoByName_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("PATCH", pattern_MemoService_UpdateMemo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
|
@ -1292,6 +1391,8 @@ var (
|
|||
|
||||
pattern_MemoService_GetMemo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v2", "memos", "id"}, ""))
|
||||
|
||||
pattern_MemoService_GetMemoByName_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v2", "memos", "name"}, ""))
|
||||
|
||||
pattern_MemoService_UpdateMemo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v2", "memos", "id"}, ""))
|
||||
|
||||
pattern_MemoService_DeleteMemo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v2", "memos", "id"}, ""))
|
||||
|
@ -1318,6 +1419,8 @@ var (
|
|||
|
||||
forward_MemoService_GetMemo_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_MemoService_GetMemoByName_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_MemoService_UpdateMemo_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_MemoService_DeleteMemo_0 = runtime.ForwardResponseMessage
|
||||
|
|
|
@ -22,6 +22,7 @@ const (
|
|||
MemoService_CreateMemo_FullMethodName = "/memos.api.v2.MemoService/CreateMemo"
|
||||
MemoService_ListMemos_FullMethodName = "/memos.api.v2.MemoService/ListMemos"
|
||||
MemoService_GetMemo_FullMethodName = "/memos.api.v2.MemoService/GetMemo"
|
||||
MemoService_GetMemoByName_FullMethodName = "/memos.api.v2.MemoService/GetMemoByName"
|
||||
MemoService_UpdateMemo_FullMethodName = "/memos.api.v2.MemoService/UpdateMemo"
|
||||
MemoService_DeleteMemo_FullMethodName = "/memos.api.v2.MemoService/DeleteMemo"
|
||||
MemoService_SetMemoResources_FullMethodName = "/memos.api.v2.MemoService/SetMemoResources"
|
||||
|
@ -43,6 +44,8 @@ type MemoServiceClient interface {
|
|||
ListMemos(ctx context.Context, in *ListMemosRequest, opts ...grpc.CallOption) (*ListMemosResponse, error)
|
||||
// GetMemo gets a memo by id.
|
||||
GetMemo(ctx context.Context, in *GetMemoRequest, opts ...grpc.CallOption) (*GetMemoResponse, error)
|
||||
// GetMemoByName gets a memo by name.
|
||||
GetMemoByName(ctx context.Context, in *GetMemoByNameRequest, opts ...grpc.CallOption) (*GetMemoByNameResponse, error)
|
||||
// UpdateMemo updates a memo.
|
||||
UpdateMemo(ctx context.Context, in *UpdateMemoRequest, opts ...grpc.CallOption) (*UpdateMemoResponse, error)
|
||||
// DeleteMemo deletes a memo by id.
|
||||
|
@ -98,6 +101,15 @@ func (c *memoServiceClient) GetMemo(ctx context.Context, in *GetMemoRequest, opt
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (c *memoServiceClient) GetMemoByName(ctx context.Context, in *GetMemoByNameRequest, opts ...grpc.CallOption) (*GetMemoByNameResponse, error) {
|
||||
out := new(GetMemoByNameResponse)
|
||||
err := c.cc.Invoke(ctx, MemoService_GetMemoByName_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *memoServiceClient) UpdateMemo(ctx context.Context, in *UpdateMemoRequest, opts ...grpc.CallOption) (*UpdateMemoResponse, error) {
|
||||
out := new(UpdateMemoResponse)
|
||||
err := c.cc.Invoke(ctx, MemoService_UpdateMemo_FullMethodName, in, out, opts...)
|
||||
|
@ -189,6 +201,8 @@ type MemoServiceServer interface {
|
|||
ListMemos(context.Context, *ListMemosRequest) (*ListMemosResponse, error)
|
||||
// GetMemo gets a memo by id.
|
||||
GetMemo(context.Context, *GetMemoRequest) (*GetMemoResponse, error)
|
||||
// GetMemoByName gets a memo by name.
|
||||
GetMemoByName(context.Context, *GetMemoByNameRequest) (*GetMemoByNameResponse, error)
|
||||
// UpdateMemo updates a memo.
|
||||
UpdateMemo(context.Context, *UpdateMemoRequest) (*UpdateMemoResponse, error)
|
||||
// DeleteMemo deletes a memo by id.
|
||||
|
@ -223,6 +237,9 @@ func (UnimplementedMemoServiceServer) ListMemos(context.Context, *ListMemosReque
|
|||
func (UnimplementedMemoServiceServer) GetMemo(context.Context, *GetMemoRequest) (*GetMemoResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetMemo not implemented")
|
||||
}
|
||||
func (UnimplementedMemoServiceServer) GetMemoByName(context.Context, *GetMemoByNameRequest) (*GetMemoByNameResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetMemoByName not implemented")
|
||||
}
|
||||
func (UnimplementedMemoServiceServer) UpdateMemo(context.Context, *UpdateMemoRequest) (*UpdateMemoResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateMemo not implemented")
|
||||
}
|
||||
|
@ -317,6 +334,24 @@ func _MemoService_GetMemo_Handler(srv interface{}, ctx context.Context, dec func
|
|||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _MemoService_GetMemoByName_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetMemoByNameRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(MemoServiceServer).GetMemoByName(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: MemoService_GetMemoByName_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MemoServiceServer).GetMemoByName(ctx, req.(*GetMemoByNameRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _MemoService_UpdateMemo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UpdateMemoRequest)
|
||||
if err := dec(in); err != nil {
|
||||
|
@ -498,6 +533,10 @@ var MemoService_ServiceDesc = grpc.ServiceDesc{
|
|||
MethodName: "GetMemo",
|
||||
Handler: _MemoService_GetMemo_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetMemoByName",
|
||||
Handler: _MemoService_GetMemoByName_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateMemo",
|
||||
Handler: _MemoService_UpdateMemo_Handler,
|
||||
|
|
|
@ -10,11 +10,11 @@ import (
|
|||
)
|
||||
|
||||
func (d *DB) CreateMemo(ctx context.Context, create *store.Memo) (*store.Memo, error) {
|
||||
fields := []string{"`creator_id`", "`content`", "`visibility`"}
|
||||
placeholder := []string{"?", "?", "?"}
|
||||
args := []any{create.CreatorID, create.Content, create.Visibility}
|
||||
fields := []string{"`resource_name`", "`creator_id`", "`content`", "`visibility`"}
|
||||
placeholder := []string{"?", "?", "?", "?"}
|
||||
args := []any{create.ResourceName, create.CreatorID, create.Content, create.Visibility}
|
||||
|
||||
stmt := "INSERT INTO memo (" + strings.Join(fields, ", ") + ") VALUES (" + strings.Join(placeholder, ", ") + ") RETURNING `id`, `created_ts`, `updated_ts`, `row_status`"
|
||||
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(
|
||||
&create.ID,
|
||||
&create.CreatedTs,
|
||||
|
@ -31,29 +31,32 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
|
|||
where, args := []string{"1 = 1"}, []any{}
|
||||
|
||||
if v := find.ID; v != nil {
|
||||
where, args = append(where, "memo.id = ?"), append(args, *v)
|
||||
where, args = append(where, "`memo`.`id` = ?"), append(args, *v)
|
||||
}
|
||||
if v := find.ResourceName; v != nil {
|
||||
where, args = append(where, "`memo`.`resource_name` = ?"), append(args, *v)
|
||||
}
|
||||
if v := find.CreatorID; v != nil {
|
||||
where, args = append(where, "memo.creator_id = ?"), append(args, *v)
|
||||
where, args = append(where, "`memo`.`creator_id` = ?"), append(args, *v)
|
||||
}
|
||||
if v := find.RowStatus; v != nil {
|
||||
where, args = append(where, "memo.row_status = ?"), append(args, *v)
|
||||
where, args = append(where, "`memo`.`row_status` = ?"), append(args, *v)
|
||||
}
|
||||
if v := find.CreatedTsBefore; v != nil {
|
||||
where, args = append(where, "memo.created_ts < ?"), append(args, *v)
|
||||
where, args = append(where, "`memo`.`created_ts` < ?"), append(args, *v)
|
||||
}
|
||||
if v := find.CreatedTsAfter; v != nil {
|
||||
where, args = append(where, "memo.created_ts > ?"), append(args, *v)
|
||||
where, args = append(where, "`memo`.`created_ts` > ?"), append(args, *v)
|
||||
}
|
||||
if v := find.UpdatedTsBefore; v != nil {
|
||||
where, args = append(where, "memo.updated_ts < ?"), append(args, *v)
|
||||
where, args = append(where, "`memo`.`updated_ts` < ?"), append(args, *v)
|
||||
}
|
||||
if v := find.UpdatedTsAfter; v != nil {
|
||||
where, args = append(where, "memo.updated_ts > ?"), append(args, *v)
|
||||
where, args = append(where, "`memo`.`updated_ts` > ?"), append(args, *v)
|
||||
}
|
||||
if v := find.ContentSearch; len(v) != 0 {
|
||||
for _, s := range v {
|
||||
where, args = append(where, "memo.content LIKE ?"), append(args, fmt.Sprintf("%%%s%%", s))
|
||||
where, args = append(where, "`memo`.`content` LIKE ?"), append(args, fmt.Sprintf("%%%s%%", s))
|
||||
}
|
||||
}
|
||||
if v := find.VisibilityList; len(v) != 0 {
|
||||
|
@ -62,43 +65,43 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
|
|||
placeholder = append(placeholder, "?")
|
||||
args = append(args, visibility.String())
|
||||
}
|
||||
where = append(where, fmt.Sprintf("memo.visibility in (%s)", strings.Join(placeholder, ",")))
|
||||
where = append(where, fmt.Sprintf("`memo`.`visibility` IN (%s)", strings.Join(placeholder, ",")))
|
||||
}
|
||||
if find.ExcludeComments {
|
||||
where = append(where, "parent_id IS NULL")
|
||||
where = append(where, "`parent_id` IS NULL")
|
||||
}
|
||||
|
||||
orders := []string{}
|
||||
if find.OrderByPinned {
|
||||
orders = append(orders, "pinned DESC")
|
||||
orders = append(orders, "`pinned` DESC")
|
||||
}
|
||||
if find.OrderByUpdatedTs {
|
||||
orders = append(orders, "updated_ts DESC")
|
||||
orders = append(orders, "`updated_ts` DESC")
|
||||
} else {
|
||||
orders = append(orders, "created_ts DESC")
|
||||
orders = append(orders, "`created_ts` DESC")
|
||||
}
|
||||
orders = append(orders, "id DESC")
|
||||
orders = append(orders, "`id` DESC")
|
||||
|
||||
fields := []string{
|
||||
`memo.id AS id`,
|
||||
`memo.creator_id AS creator_id`,
|
||||
`memo.created_ts AS created_ts`,
|
||||
`memo.updated_ts AS updated_ts`,
|
||||
`memo.row_status AS row_status`,
|
||||
`memo.visibility AS visibility`,
|
||||
`IFNULL(memo_organizer.pinned, 0) AS pinned`,
|
||||
`memo_relation.related_memo_id AS parent_id`,
|
||||
"`memo`.`id` AS `id`",
|
||||
"`memo`.`resource_name` AS `resource_name`",
|
||||
"`memo`.`creator_id` AS `creator_id`",
|
||||
"`memo`.`created_ts` AS `created_ts`",
|
||||
"`memo`.`updated_ts` AS `updated_ts`",
|
||||
"`memo`.`row_status` AS `row_status`",
|
||||
"`memo`.`visibility` AS `visibility`",
|
||||
"IFNULL(`memo_organizer`.`pinned`, 0) AS `pinned`",
|
||||
"`memo_relation`.`related_memo_id` AS `parent_id`",
|
||||
}
|
||||
if !find.ExcludeContent {
|
||||
fields = append(fields, `memo.content AS content`)
|
||||
fields = append(fields, "`memo`.`content` AS `content`")
|
||||
}
|
||||
|
||||
query := `SELECT ` + strings.Join(fields, ", ") + `
|
||||
FROM memo
|
||||
LEFT JOIN memo_organizer ON memo.id = memo_organizer.memo_id AND memo.creator_id = memo_organizer.user_id
|
||||
FULL JOIN memo_relation ON memo.id = memo_relation.memo_id AND memo_relation.type = "COMMENT"
|
||||
WHERE ` + strings.Join(where, " AND ") + `
|
||||
ORDER BY ` + strings.Join(orders, ", ")
|
||||
query := "SELECT " + strings.Join(fields, ", ") + "FROM `memo` " +
|
||||
"LEFT JOIN `memo_organizer` ON `memo`.`id` = `memo_organizer`.`memo_id` AND `memo`.`creator_id` = `memo_organizer`.`user_id` " +
|
||||
"FULL JOIN `memo_relation` ON `memo`.`id` = `memo_relation`.`memo_id` AND `memo_relation`.`type` = \"COMMENT\"" + " " +
|
||||
"WHERE " + strings.Join(where, " AND ") + " " +
|
||||
"ORDER BY " + strings.Join(orders, ", ")
|
||||
if find.Limit != nil {
|
||||
query = fmt.Sprintf("%s LIMIT %d", query, *find.Limit)
|
||||
if find.Offset != nil {
|
||||
|
@ -117,6 +120,7 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
|
|||
var memo store.Memo
|
||||
dests := []any{
|
||||
&memo.ID,
|
||||
&memo.ResourceName,
|
||||
&memo.CreatorID,
|
||||
&memo.CreatedTs,
|
||||
&memo.UpdatedTs,
|
||||
|
@ -143,24 +147,27 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
|
|||
|
||||
func (d *DB) UpdateMemo(ctx context.Context, update *store.UpdateMemo) error {
|
||||
set, args := []string{}, []any{}
|
||||
if v := update.ResourceName; v != nil {
|
||||
set, args = append(set, "`resource_name` = ?"), append(args, *v)
|
||||
}
|
||||
if v := update.CreatedTs; v != nil {
|
||||
set, args = append(set, "created_ts = ?"), append(args, *v)
|
||||
set, args = append(set, "`created_ts` = ?"), append(args, *v)
|
||||
}
|
||||
if v := update.UpdatedTs; v != nil {
|
||||
set, args = append(set, "updated_ts = ?"), append(args, *v)
|
||||
set, args = append(set, "`updated_ts` = ?"), append(args, *v)
|
||||
}
|
||||
if v := update.RowStatus; v != nil {
|
||||
set, args = append(set, "row_status = ?"), append(args, *v)
|
||||
set, args = append(set, "`row_status` = ?"), append(args, *v)
|
||||
}
|
||||
if v := update.Content; v != nil {
|
||||
set, args = append(set, "content = ?"), append(args, *v)
|
||||
set, args = append(set, "`content` = ?"), append(args, *v)
|
||||
}
|
||||
if v := update.Visibility; v != nil {
|
||||
set, args = append(set, "visibility = ?"), append(args, *v)
|
||||
set, args = append(set, "`visibility` = ?"), append(args, *v)
|
||||
}
|
||||
args = append(args, update.ID)
|
||||
|
||||
stmt := `UPDATE memo SET ` + strings.Join(set, ", ") + ` WHERE id = ?`
|
||||
stmt := "UPDATE `memo` SET " + strings.Join(set, ", ") + " WHERE `id` = ?"
|
||||
if _, err := d.db.ExecContext(ctx, stmt, args...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -168,8 +175,8 @@ func (d *DB) UpdateMemo(ctx context.Context, update *store.UpdateMemo) error {
|
|||
}
|
||||
|
||||
func (d *DB) DeleteMemo(ctx context.Context, delete *store.DeleteMemo) error {
|
||||
where, args := []string{"id = ?"}, []any{delete.ID}
|
||||
stmt := `DELETE FROM memo WHERE ` + strings.Join(where, " AND ")
|
||||
where, args := []string{"`id` = ?"}, []any{delete.ID}
|
||||
stmt := "DELETE FROM `memo` WHERE " + strings.Join(where, " AND ")
|
||||
result, err := d.db.ExecContext(ctx, stmt, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -186,16 +193,7 @@ func (d *DB) DeleteMemo(ctx context.Context, delete *store.DeleteMemo) error {
|
|||
}
|
||||
|
||||
func vacuumMemo(ctx context.Context, tx *sql.Tx) error {
|
||||
stmt := `
|
||||
DELETE FROM
|
||||
memo
|
||||
WHERE
|
||||
creator_id NOT IN (
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
user
|
||||
)`
|
||||
stmt := "DELETE FROM `memo` WHERE `creator_id` NOT IN (SELECT `id` FROM `user`)"
|
||||
_, err := tx.ExecContext(ctx, stmt)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -55,6 +55,7 @@ CREATE TABLE user_setting (
|
|||
-- memo
|
||||
CREATE TABLE memo (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
resource_name TEXT NOT NULL UNIQUE,
|
||||
creator_id INTEGER NOT NULL,
|
||||
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
INSERT INTO
|
||||
memo (`id`, `content`, `creator_id`)
|
||||
memo (
|
||||
`id`,
|
||||
`resource_name`,
|
||||
`content`,
|
||||
`creator_id`
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
1,
|
||||
"hello",
|
||||
"#Hello 👋 Welcome to memos.",
|
||||
101
|
||||
);
|
||||
|
@ -10,6 +16,7 @@ VALUES
|
|||
INSERT INTO
|
||||
memo (
|
||||
`id`,
|
||||
`resource_name`,
|
||||
`content`,
|
||||
`creator_id`,
|
||||
`visibility`
|
||||
|
@ -17,6 +24,7 @@ INSERT INTO
|
|||
VALUES
|
||||
(
|
||||
2,
|
||||
"todo",
|
||||
'#TODO
|
||||
- [x] Take more photos about **🌄 sunset**;
|
||||
- [x] Clean the room;
|
||||
|
@ -28,6 +36,7 @@ VALUES
|
|||
INSERT INTO
|
||||
memo (
|
||||
`id`,
|
||||
`resource_name`,
|
||||
`content`,
|
||||
`creator_id`,
|
||||
`visibility`
|
||||
|
@ -35,6 +44,7 @@ INSERT INTO
|
|||
VALUES
|
||||
(
|
||||
3,
|
||||
"links",
|
||||
'**[Memos](https://github.com/usememos/memos)**: A lightweight, self-hosted memo hub. Open Source and Free forever.
|
||||
**[Slash](https://github.com/yourselfhosted/slash)**: An open source, self-hosted bookmarks and link sharing platform. Save and share your links very easily.',
|
||||
101,
|
||||
|
@ -44,6 +54,7 @@ VALUES
|
|||
INSERT INTO
|
||||
memo (
|
||||
`id`,
|
||||
`resource_name`,
|
||||
`content`,
|
||||
`creator_id`,
|
||||
`visibility`
|
||||
|
@ -51,6 +62,7 @@ INSERT INTO
|
|||
VALUES
|
||||
(
|
||||
4,
|
||||
"todo2",
|
||||
'#TODO
|
||||
- [x] Take more photos about **🌄 sunset**;
|
||||
- [ ] Clean the classroom;
|
||||
|
@ -62,6 +74,7 @@ VALUES
|
|||
INSERT INTO
|
||||
memo (
|
||||
`id`,
|
||||
`resource_name`,
|
||||
`content`,
|
||||
`creator_id`,
|
||||
`visibility`
|
||||
|
@ -69,6 +82,7 @@ INSERT INTO
|
|||
VALUES
|
||||
(
|
||||
5,
|
||||
"words",
|
||||
'三人行,必有我师焉!👨🏫',
|
||||
102,
|
||||
'PUBLIC'
|
||||
|
|
|
@ -2,6 +2,9 @@ package store
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/usememos/memos/internal/util"
|
||||
)
|
||||
|
||||
// Visibility is the type of a visibility.
|
||||
|
@ -29,7 +32,8 @@ func (v Visibility) String() string {
|
|||
}
|
||||
|
||||
type Memo struct {
|
||||
ID int32
|
||||
ID int32
|
||||
ResourceName string
|
||||
|
||||
// Standard fields
|
||||
RowStatus RowStatus
|
||||
|
@ -47,7 +51,8 @@ type Memo struct {
|
|||
}
|
||||
|
||||
type FindMemo struct {
|
||||
ID *int32
|
||||
ID *int32
|
||||
ResourceName *string
|
||||
|
||||
// Standard fields
|
||||
RowStatus *RowStatus
|
||||
|
@ -71,12 +76,13 @@ type FindMemo struct {
|
|||
}
|
||||
|
||||
type UpdateMemo struct {
|
||||
ID int32
|
||||
CreatedTs *int64
|
||||
UpdatedTs *int64
|
||||
RowStatus *RowStatus
|
||||
Content *string
|
||||
Visibility *Visibility
|
||||
ID int32
|
||||
ResourceName *string
|
||||
CreatedTs *int64
|
||||
UpdatedTs *int64
|
||||
RowStatus *RowStatus
|
||||
Content *string
|
||||
Visibility *Visibility
|
||||
}
|
||||
|
||||
type DeleteMemo struct {
|
||||
|
@ -84,6 +90,9 @@ type DeleteMemo struct {
|
|||
}
|
||||
|
||||
func (s *Store) CreateMemo(ctx context.Context, create *Memo) (*Memo, error) {
|
||||
if !util.ResourceNameMatcher.MatchString(create.ResourceName) {
|
||||
return nil, errors.New("resource name is invalid")
|
||||
}
|
||||
return s.driver.CreateMemo(ctx, create)
|
||||
}
|
||||
|
||||
|
@ -105,6 +114,9 @@ func (s *Store) GetMemo(ctx context.Context, find *FindMemo) (*Memo, error) {
|
|||
}
|
||||
|
||||
func (s *Store) UpdateMemo(ctx context.Context, update *UpdateMemo) error {
|
||||
if update.ResourceName != nil && !util.ResourceNameMatcher.MatchString(*update.ResourceName) {
|
||||
return errors.New("resource name is invalid")
|
||||
}
|
||||
return s.driver.UpdateMemo(ctx, update)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,9 +15,10 @@ func TestMemoOrganizerStore(t *testing.T) {
|
|||
user, err := createTestingHostUser(ctx, ts)
|
||||
require.NoError(t, err)
|
||||
memoCreate := &store.Memo{
|
||||
CreatorID: user.ID,
|
||||
Content: "main memo content",
|
||||
Visibility: store.Public,
|
||||
ResourceName: "main-memo",
|
||||
CreatorID: user.ID,
|
||||
Content: "main memo content",
|
||||
Visibility: store.Public,
|
||||
}
|
||||
memo, err := ts.CreateMemo(ctx, memoCreate)
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -15,25 +15,28 @@ func TestMemoRelationStore(t *testing.T) {
|
|||
user, err := createTestingHostUser(ctx, ts)
|
||||
require.NoError(t, err)
|
||||
memoCreate := &store.Memo{
|
||||
CreatorID: user.ID,
|
||||
Content: "main memo content",
|
||||
Visibility: store.Public,
|
||||
ResourceName: "main-memo",
|
||||
CreatorID: user.ID,
|
||||
Content: "main memo content",
|
||||
Visibility: store.Public,
|
||||
}
|
||||
memo, err := ts.CreateMemo(ctx, memoCreate)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, memoCreate.Content, memo.Content)
|
||||
relatedMemoCreate := &store.Memo{
|
||||
CreatorID: user.ID,
|
||||
Content: "related memo content",
|
||||
Visibility: store.Public,
|
||||
ResourceName: "related-memo",
|
||||
CreatorID: user.ID,
|
||||
Content: "related memo content",
|
||||
Visibility: store.Public,
|
||||
}
|
||||
relatedMemo, err := ts.CreateMemo(ctx, relatedMemoCreate)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, relatedMemoCreate.Content, relatedMemo.Content)
|
||||
commentMemoCreate := &store.Memo{
|
||||
CreatorID: user.ID,
|
||||
Content: "comment memo content",
|
||||
Visibility: store.Public,
|
||||
ResourceName: "comment-memo",
|
||||
CreatorID: user.ID,
|
||||
Content: "comment memo content",
|
||||
Visibility: store.Public,
|
||||
}
|
||||
commentMemo, err := ts.CreateMemo(ctx, commentMemoCreate)
|
||||
require.NoError(t, err)
|
||||
|
|
|
@ -15,9 +15,10 @@ func TestMemoStore(t *testing.T) {
|
|||
user, err := createTestingHostUser(ctx, ts)
|
||||
require.NoError(t, err)
|
||||
memoCreate := &store.Memo{
|
||||
CreatorID: user.ID,
|
||||
Content: "test_content",
|
||||
Visibility: store.Public,
|
||||
ResourceName: "test-resource-name",
|
||||
CreatorID: user.ID,
|
||||
Content: "test_content",
|
||||
Visibility: store.Public,
|
||||
}
|
||||
memo, err := ts.CreateMemo(ctx, memoCreate)
|
||||
require.NoError(t, err)
|
||||
|
@ -67,9 +68,10 @@ func TestDeleteMemoStore(t *testing.T) {
|
|||
user, err := createTestingHostUser(ctx, ts)
|
||||
require.NoError(t, err)
|
||||
memoCreate := &store.Memo{
|
||||
CreatorID: user.ID,
|
||||
Content: "test_content",
|
||||
Visibility: store.Public,
|
||||
ResourceName: "test-resource-name",
|
||||
CreatorID: user.ID,
|
||||
Content: "test_content",
|
||||
Visibility: store.Public,
|
||||
}
|
||||
memo, err := ts.CreateMemo(ctx, memoCreate)
|
||||
require.NoError(t, err)
|
||||
|
|
Loading…
Reference in a new issue