Skip to content

Commit

Permalink
feat: add user-defined name to memo
Browse files Browse the repository at this point in the history
  • Loading branch information
boojack committed Jan 20, 2024
1 parent 264e6e6 commit 8382354
Show file tree
Hide file tree
Showing 19 changed files with 929 additions and 524 deletions.
6 changes: 1 addition & 5 deletions api/v1/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down Expand Up @@ -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)
}

Expand Down
4 changes: 2 additions & 2 deletions api/v1/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
36 changes: 33 additions & 3 deletions api/v2/memo_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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),
Expand Down
10 changes: 3 additions & 7 deletions api/v2/user_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"net/http"
"regexp"
"strings"
"time"

Expand All @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
7 changes: 7 additions & 0 deletions internal/util/resource_name.go
Original file line number Diff line number Diff line change
@@ -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])$")
)
43 changes: 30 additions & 13 deletions proto/api/v2/memo_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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) = {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -163,6 +172,14 @@ message GetMemoResponse {
Memo memo = 1;
}

message GetMemoByNameRequest {
string name = 1;
}

message GetMemoByNameResponse {
Memo memo = 1;
}

message UpdateMemoRequest {
int32 id = 1;

Expand Down
36 changes: 35 additions & 1 deletion proto/gen/api/v2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) | | |
Expand Down Expand Up @@ -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. |
Expand Down
Loading

0 comments on commit 8382354

Please sign in to comment.