123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- 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
- }
|