mirror of
https://github.com/usememos/memos.git
synced 2025-06-05 22:09:59 +02:00
refactor: shortcut service
This commit is contained in:
257
server/router/api/v1/shortcuts_service.go
Normal file
257
server/router/api/v1/shortcuts_service.go
Normal file
@@ -0,0 +1,257 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
|
||||
"github.com/usememos/memos/internal/util"
|
||||
"github.com/usememos/memos/plugin/filter"
|
||||
v1pb "github.com/usememos/memos/proto/gen/api/v1"
|
||||
storepb "github.com/usememos/memos/proto/gen/store"
|
||||
"github.com/usememos/memos/store"
|
||||
)
|
||||
|
||||
func (s *APIV1Service) ListShortcuts(ctx context.Context, request *v1pb.ListShortcutsRequest) (*v1pb.ListShortcutsResponse, error) {
|
||||
userID, err := ExtractUserIDFromName(request.Parent)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid user name: %v", err)
|
||||
}
|
||||
|
||||
currentUser, err := s.GetCurrentUser(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
|
||||
}
|
||||
if currentUser == nil || currentUser.ID != userID {
|
||||
return nil, status.Errorf(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
|
||||
userSetting, err := s.Store.GetUserSetting(ctx, &store.FindUserSetting{
|
||||
UserID: &userID,
|
||||
Key: storepb.UserSettingKey_SHORTCUTS,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userSetting == nil {
|
||||
return &v1pb.ListShortcutsResponse{
|
||||
Shortcuts: []*v1pb.Shortcut{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
shortcutsUserSetting := userSetting.GetShortcuts()
|
||||
shortcuts := []*v1pb.Shortcut{}
|
||||
for _, shortcut := range shortcutsUserSetting.GetShortcuts() {
|
||||
shortcuts = append(shortcuts, &v1pb.Shortcut{
|
||||
Id: shortcut.GetId(),
|
||||
Title: shortcut.GetTitle(),
|
||||
Filter: shortcut.GetFilter(),
|
||||
})
|
||||
}
|
||||
|
||||
return &v1pb.ListShortcutsResponse{
|
||||
Shortcuts: shortcuts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *APIV1Service) CreateShortcut(ctx context.Context, request *v1pb.CreateShortcutRequest) (*v1pb.Shortcut, error) {
|
||||
userID, err := ExtractUserIDFromName(request.Parent)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid user name: %v", err)
|
||||
}
|
||||
|
||||
currentUser, err := s.GetCurrentUser(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
|
||||
}
|
||||
if currentUser == nil || currentUser.ID != userID {
|
||||
return nil, status.Errorf(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
|
||||
newShortcut := &storepb.ShortcutsUserSetting_Shortcut{
|
||||
Id: util.GenUUID(),
|
||||
Title: request.Shortcut.GetTitle(),
|
||||
Filter: request.Shortcut.GetFilter(),
|
||||
}
|
||||
if newShortcut.Title == "" {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "title is required")
|
||||
}
|
||||
if err := s.validateFilter(ctx, newShortcut.Filter); err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid filter: %v", err)
|
||||
}
|
||||
if request.ValidateOnly {
|
||||
return &v1pb.Shortcut{
|
||||
Id: newShortcut.GetId(),
|
||||
Title: newShortcut.GetTitle(),
|
||||
Filter: newShortcut.GetFilter(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
userSetting, err := s.Store.GetUserSetting(ctx, &store.FindUserSetting{
|
||||
UserID: &userID,
|
||||
Key: storepb.UserSettingKey_SHORTCUTS,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userSetting == nil {
|
||||
userSetting = &storepb.UserSetting{
|
||||
UserId: userID,
|
||||
Key: storepb.UserSettingKey_SHORTCUTS,
|
||||
Value: &storepb.UserSetting_Shortcuts{
|
||||
Shortcuts: &storepb.ShortcutsUserSetting{
|
||||
Shortcuts: []*storepb.ShortcutsUserSetting_Shortcut{},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
shortcutsUserSetting := userSetting.GetShortcuts()
|
||||
shortcuts := shortcutsUserSetting.GetShortcuts()
|
||||
shortcuts = append(shortcuts, newShortcut)
|
||||
shortcutsUserSetting.Shortcuts = shortcuts
|
||||
|
||||
userSetting.Value = &storepb.UserSetting_Shortcuts{
|
||||
Shortcuts: shortcutsUserSetting,
|
||||
}
|
||||
|
||||
_, err = s.Store.UpsertUserSetting(ctx, userSetting)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1pb.Shortcut{
|
||||
Id: request.Shortcut.GetId(),
|
||||
Title: request.Shortcut.GetTitle(),
|
||||
Filter: request.Shortcut.GetFilter(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *APIV1Service) UpdateShortcut(ctx context.Context, request *v1pb.UpdateShortcutRequest) (*v1pb.Shortcut, error) {
|
||||
userID, err := ExtractUserIDFromName(request.Parent)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid user name: %v", err)
|
||||
}
|
||||
|
||||
currentUser, err := s.GetCurrentUser(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
|
||||
}
|
||||
if currentUser == nil || currentUser.ID != userID {
|
||||
return nil, status.Errorf(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
if request.UpdateMask == nil || len(request.UpdateMask.Paths) == 0 {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "update mask is required")
|
||||
}
|
||||
|
||||
userSetting, err := s.Store.GetUserSetting(ctx, &store.FindUserSetting{
|
||||
UserID: &userID,
|
||||
Key: storepb.UserSettingKey_SHORTCUTS,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userSetting == nil {
|
||||
return nil, status.Errorf(codes.NotFound, "shortcut not found")
|
||||
}
|
||||
|
||||
shortcutsUserSetting := userSetting.GetShortcuts()
|
||||
shortcuts := shortcutsUserSetting.GetShortcuts()
|
||||
newShortcuts := make([]*storepb.ShortcutsUserSetting_Shortcut, 0, len(shortcuts))
|
||||
for _, shortcut := range shortcuts {
|
||||
if shortcut.GetId() == request.Shortcut.GetId() {
|
||||
for _, field := range request.UpdateMask.Paths {
|
||||
if field == "title" {
|
||||
if request.Shortcut.GetTitle() == "" {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "title is required")
|
||||
}
|
||||
shortcut.Title = request.Shortcut.GetTitle()
|
||||
} else if field == "filter" {
|
||||
if err := s.validateFilter(ctx, request.Shortcut.GetFilter()); err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid filter: %v", err)
|
||||
}
|
||||
shortcut.Filter = request.Shortcut.GetFilter()
|
||||
}
|
||||
}
|
||||
}
|
||||
newShortcuts = append(newShortcuts, shortcut)
|
||||
}
|
||||
shortcutsUserSetting.Shortcuts = newShortcuts
|
||||
userSetting.Value = &storepb.UserSetting_Shortcuts{
|
||||
Shortcuts: shortcutsUserSetting,
|
||||
}
|
||||
_, err = s.Store.UpsertUserSetting(ctx, userSetting)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1pb.Shortcut{
|
||||
Id: request.Shortcut.GetId(),
|
||||
Title: request.Shortcut.GetTitle(),
|
||||
Filter: request.Shortcut.GetFilter(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *APIV1Service) DeleteShortcut(ctx context.Context, request *v1pb.DeleteShortcutRequest) (*emptypb.Empty, error) {
|
||||
userID, err := ExtractUserIDFromName(request.Parent)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid user name: %v", err)
|
||||
}
|
||||
|
||||
currentUser, err := s.GetCurrentUser(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to get current user: %v", err)
|
||||
}
|
||||
if currentUser == nil || currentUser.ID != userID {
|
||||
return nil, status.Errorf(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
|
||||
userSetting, err := s.Store.GetUserSetting(ctx, &store.FindUserSetting{
|
||||
UserID: &userID,
|
||||
Key: storepb.UserSettingKey_SHORTCUTS,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userSetting == nil {
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
shortcutsUserSetting := userSetting.GetShortcuts()
|
||||
shortcuts := shortcutsUserSetting.GetShortcuts()
|
||||
newShortcuts := make([]*storepb.ShortcutsUserSetting_Shortcut, 0, len(shortcuts))
|
||||
for _, shortcut := range shortcuts {
|
||||
if shortcut.GetId() != request.Id {
|
||||
newShortcuts = append(newShortcuts, shortcut)
|
||||
}
|
||||
}
|
||||
shortcutsUserSetting.Shortcuts = newShortcuts
|
||||
userSetting.Value = &storepb.UserSetting_Shortcuts{
|
||||
Shortcuts: shortcutsUserSetting,
|
||||
}
|
||||
_, err = s.Store.UpsertUserSetting(ctx, userSetting)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *APIV1Service) validateFilter(_ context.Context, filterStr string) error {
|
||||
if filterStr == "" {
|
||||
return errors.New("filter cannot be empty")
|
||||
}
|
||||
// Validate the filter.
|
||||
parsedExpr, err := filter.Parse(filterStr, filter.MemoFilterCELAttributes...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to parse filter")
|
||||
}
|
||||
convertCtx := filter.NewConvertContext()
|
||||
err = s.Store.GetDriver().ConvertExprToSQL(convertCtx, parsedExpr.GetExpr())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to convert filter to SQL")
|
||||
}
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user