Skip to content

Commit

Permalink
chore: initial memo service definition (#2077)
Browse files Browse the repository at this point in the history
* chore: initial memo service definition

* chore: update

* chore: update

* chore: update
  • Loading branch information
boojack authored Aug 5, 2023
1 parent 7c5296c commit 57dd1fc
Show file tree
Hide file tree
Showing 14 changed files with 1,483 additions and 402 deletions.
130 changes: 0 additions & 130 deletions api/v1/openai.go

This file was deleted.

1 change: 0 additions & 1 deletion api/v1/v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ func (s *APIV1Service) Register(rootGroup *echo.Group) {
s.registerMemoOrganizerRoutes(apiV1Group)
s.registerMemoResourceRoutes(apiV1Group)
s.registerMemoRelationRoutes(apiV1Group)
s.registerOpenAIRoutes(apiV1Group)

// Register public routes.
publicGroup := rootGroup.Group("/o")
Expand Down
21 changes: 11 additions & 10 deletions api/v2/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,18 @@ import (
"google.golang.org/grpc/status"
)

// ContextKey is the key type of context value.
type ContextKey int

const (
// The key name used to store user id in the context
// user id is extracted from the jwt token subject field.
UserIDContextKey ContextKey = iota
)

var authenticationAllowlistMethods = map[string]bool{
"/memos.api.v2.UserService/GetUser": true,
"/memos.api.v2.UserService/GetUser": true,
"/memos.api.v2.MemoService/ListMemos": true,
}

// IsAuthenticationAllowed returns whether the method is exempted from authentication.
Expand All @@ -30,15 +40,6 @@ func IsAuthenticationAllowed(fullMethodName string) bool {
return authenticationAllowlistMethods[fullMethodName]
}

// ContextKey is the key type of context value.
type ContextKey int

const (
// The key name used to store user id in the context
// user id is extracted from the jwt token subject field.
UserIDContextKey ContextKey = iota
)

// GRPCAuthInterceptor is the auth interceptor for gRPC server.
type GRPCAuthInterceptor struct {
store *store.Store
Expand Down
119 changes: 119 additions & 0 deletions api/v2/memo_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package v2

import (
"context"

"github.com/google/cel-go/cel"
"github.com/pkg/errors"
apiv2pb "github.com/usememos/memos/proto/gen/api/v2"
"github.com/usememos/memos/store"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

type MemoService struct {
apiv2pb.UnimplementedMemoServiceServer

Store *store.Store
}

// NewMemoService creates a new MemoService.
func NewMemoService(store *store.Store) *MemoService {
return &MemoService{
Store: store,
}
}

func (s *MemoService) ListMemos(ctx context.Context, request *apiv2pb.ListMemosRequest) (*apiv2pb.ListMemosResponse, error) {
memoFind := &store.FindMemo{}
if request.PageSize != 0 {
offset := int(request.Page * request.PageSize)
limit := int(request.PageSize)
memoFind.Offset = &offset
memoFind.Limit = &limit
}
if request.Filter != "" {
visibilityString, err := getVisibilityFilter(request.Filter)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid filter: %v", err)
}
memoFind.VisibilityList = []store.Visibility{store.Visibility(visibilityString)}
}
memos, err := s.Store.ListMemos(ctx, memoFind)
if err != nil {
return nil, err
}

memoMessages := make([]*apiv2pb.Memo, len(memos))
for i, memo := range memos {
memoMessages[i] = convertMemoFromStore(memo)
}

response := &apiv2pb.ListMemosResponse{
Memos: memoMessages,
}
return response, nil
}

const visibilityFilterExample = `visibility == "PRIVATE"`

// getVisibilityFilter will parse the simple filter such as `visibility = "PRIVATE"` to "PRIVATE" .
func getVisibilityFilter(filter string) (string, error) {
formatInvalidErr := errors.Errorf("invalid filter %q, example %q", filter, visibilityFilterExample)
e, err := cel.NewEnv(cel.Variable("visibility", cel.StringType))
if err != nil {
return "", err
}
ast, issues := e.Compile(filter)
if issues != nil {
return "", status.Errorf(codes.InvalidArgument, issues.String())
}
expr := ast.Expr()
if expr == nil {
return "", formatInvalidErr
}
callExpr := expr.GetCallExpr()
if callExpr == nil {
return "", formatInvalidErr
}
if callExpr.Function != "_==_" {
return "", formatInvalidErr
}
if len(callExpr.Args) != 2 {
return "", formatInvalidErr
}
if callExpr.Args[0].GetIdentExpr() == nil || callExpr.Args[0].GetIdentExpr().Name != "visibility" {
return "", formatInvalidErr
}
constExpr := callExpr.Args[1].GetConstExpr()
if constExpr == nil {
return "", formatInvalidErr
}
return constExpr.GetStringValue(), nil
}

func convertMemoFromStore(memo *store.Memo) *apiv2pb.Memo {
return &apiv2pb.Memo{
Id: int32(memo.ID),
RowStatus: convertRowStatusFromStore(memo.RowStatus),
CreatedTs: memo.CreatedTs,
UpdatedTs: memo.UpdatedTs,
CreatorId: int32(memo.CreatorID),
Content: memo.Content,
Visibility: convertVisibilityFromStore(memo.Visibility),
Pinned: memo.Pinned,
}
}

func convertVisibilityFromStore(visibility store.Visibility) apiv2pb.Visibility {
switch visibility {
case store.Private:
return apiv2pb.Visibility_PRIVATE
case store.Protected:
return apiv2pb.Visibility_PROTECTED
case store.Public:
return apiv2pb.Visibility_PUBLIC
default:
return apiv2pb.Visibility_VISIBILITY_UNSPECIFIED
}
}
31 changes: 3 additions & 28 deletions api/v2/user_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,6 @@ func (s *UserService) GetUser(ctx context.Context, request *apiv2pb.GetUserReque
// Data desensitization.
userMessage.OpenId = ""

userSettings, err := s.Store.ListUserSettings(ctx, &store.FindUserSetting{
UserID: &userMessage.Id,
})
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list user settings: %v", err)
}

userID, ok := ctx.Value(UserIDContextKey).(int)
if ok && userID == int(userMessage.Id) {
for _, userSetting := range userSettings {
userMessage.Settings = append(userMessage.Settings, convertUserSettingFromStore(userSetting))
}
}

response := &apiv2pb.GetUserResponse{
User: userMessage,
}
Expand All @@ -69,7 +55,6 @@ func convertUserFromStore(user *store.User) *apiv2pb.User {
Nickname: user.Nickname,
OpenId: user.OpenID,
AvatarUrl: user.AvatarURL,
Settings: []*apiv2pb.UserSetting{},
}
}

Expand All @@ -86,7 +71,8 @@ func convertUserRoleFromStore(role store.Role) apiv2pb.Role {
}
}

func convertUserSettingFromStore(userSetting *store.UserSetting) *apiv2pb.UserSetting {
// ConvertUserSettingFromStore converts a user setting from store to protobuf.
func ConvertUserSettingFromStore(userSetting *store.UserSetting) *apiv2pb.UserSetting {
userSettingKey := apiv2pb.UserSetting_KEY_UNSPECIFIED
userSettingValue := &apiv2pb.UserSettingValue{}
switch userSetting.Key {
Expand All @@ -103,7 +89,7 @@ func convertUserSettingFromStore(userSetting *store.UserSetting) *apiv2pb.UserSe
case "memo-visibility":
userSettingKey = apiv2pb.UserSetting_MEMO_VISIBILITY
userSettingValue.Value = &apiv2pb.UserSettingValue_VisibilityValue{
VisibilityValue: convertVisibilityFromString(userSetting.Value),
VisibilityValue: convertVisibilityFromStore(store.Visibility(userSetting.Value)),
}
case "telegram-user-id":
userSettingKey = apiv2pb.UserSetting_TELEGRAM_USER_ID
Expand All @@ -117,14 +103,3 @@ func convertUserSettingFromStore(userSetting *store.UserSetting) *apiv2pb.UserSe
Value: userSettingValue,
}
}

func convertVisibilityFromString(visibility string) apiv2pb.Visibility {
switch visibility {
case "public":
return apiv2pb.Visibility_PUBLIC
case "private":
return apiv2pb.Visibility_PRIVATE
default:
return apiv2pb.Visibility_VISIBILITY_UNSPECIFIED
}
}
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ module github.com/usememos/memos
go 1.19

require (
github.com/CorrectRoadH/echo-sse v0.1.4
github.com/PullRequestInc/go-gpt3 v1.1.15
github.com/aws/aws-sdk-go-v2 v1.17.4
github.com/aws/aws-sdk-go-v2/config v1.18.12
github.com/aws/aws-sdk-go-v2/credentials v1.13.12
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.51
github.com/aws/aws-sdk-go-v2/service/s3 v1.30.3
github.com/disintegration/imaging v1.6.2
github.com/google/cel-go v0.17.1
github.com/google/uuid v1.3.0
github.com/gorilla/feeds v1.1.1
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2
Expand All @@ -32,10 +31,12 @@ require (
)

require (
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
golang.org/x/image v0.7.0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
Expand Down
Loading

0 comments on commit 57dd1fc

Please sign in to comment.