From 1ce82ba0d6e25d8d53119873170de5b115ae6b53 Mon Sep 17 00:00:00 2001 From: boojack Date: Thu, 3 Aug 2023 23:33:45 +0800 Subject: [PATCH] chore: remove shortcut related api (#2072) --- api/v1/activity.go | 14 --- api/v1/shortcut.go | 242 --------------------------------------------- api/v1/v1.go | 1 - store/shortcut.go | 211 --------------------------------------- store/store.go | 4 - 5 files changed, 472 deletions(-) delete mode 100644 api/v1/shortcut.go delete mode 100644 store/shortcut.go diff --git a/api/v1/activity.go b/api/v1/activity.go index 3b554e18..a5d1bc5b 100644 --- a/api/v1/activity.go +++ b/api/v1/activity.go @@ -30,15 +30,6 @@ const ( // ActivityMemoDelete is the type for deleting memos. ActivityMemoDelete ActivityType = "memo.delete" - // Shortcut related. - - // ActivityShortcutCreate is the type for creating shortcuts. - ActivityShortcutCreate ActivityType = "shortcut.create" - // ActivityShortcutUpdate is the type for updating shortcuts. - ActivityShortcutUpdate ActivityType = "shortcut.update" - // ActivityShortcutDelete is the type for deleting shortcuts. - ActivityShortcutDelete ActivityType = "shortcut.delete" - // Resource related. // ActivityResourceCreate is the type for creating resources. @@ -100,11 +91,6 @@ type ActivityMemoCreatePayload struct { Visibility string `json:"visibility"` } -type ActivityShortcutCreatePayload struct { - Title string `json:"title"` - Payload string `json:"payload"` -} - type ActivityResourceCreatePayload struct { Filename string `json:"filename"` Type string `json:"type"` diff --git a/api/v1/shortcut.go b/api/v1/shortcut.go deleted file mode 100644 index 96734cfb..00000000 --- a/api/v1/shortcut.go +++ /dev/null @@ -1,242 +0,0 @@ -package v1 - -import ( - "encoding/json" - "fmt" - "net/http" - "strconv" - "time" - - "github.com/labstack/echo/v4" - "github.com/pkg/errors" - "github.com/usememos/memos/api/auth" - "github.com/usememos/memos/store" -) - -type Shortcut struct { - ID int `json:"id"` - - // Standard fields - RowStatus RowStatus `json:"rowStatus"` - CreatorID int `json:"creatorId"` - CreatedTs int64 `json:"createdTs"` - UpdatedTs int64 `json:"updatedTs"` - - // Domain specific fields - Title string `json:"title"` - Payload string `json:"payload"` -} - -type CreateShortcutRequest struct { - Title string `json:"title"` - Payload string `json:"payload"` -} - -type UpdateShortcutRequest struct { - RowStatus *RowStatus `json:"rowStatus"` - Title *string `json:"title"` - Payload *string `json:"payload"` -} - -type ShortcutFind struct { - ID *int - - // Standard fields - CreatorID *int - - // Domain specific fields - Title *string `json:"title"` -} - -type ShortcutDelete struct { - ID *int - - // Standard fields - CreatorID *int -} - -func (s *APIV1Service) registerShortcutRoutes(g *echo.Group) { - g.POST("/shortcut", func(c echo.Context) error { - ctx := c.Request().Context() - userID, ok := c.Get(auth.UserIDContextKey).(int) - if !ok { - return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session") - } - shortcutCreate := &CreateShortcutRequest{} - if err := json.NewDecoder(c.Request().Body).Decode(shortcutCreate); err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post shortcut request").SetInternal(err) - } - - shortcut, err := s.Store.CreateShortcut(ctx, &store.Shortcut{ - CreatorID: userID, - Title: shortcutCreate.Title, - Payload: shortcutCreate.Payload, - }) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create shortcut").SetInternal(err) - } - - shortcutMessage := convertShortcutFromStore(shortcut) - if err := s.createShortcutCreateActivity(c, shortcutMessage); err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err) - } - return c.JSON(http.StatusOK, shortcutMessage) - }) - - g.PATCH("/shortcut/:shortcutId", func(c echo.Context) error { - ctx := c.Request().Context() - userID, ok := c.Get(auth.UserIDContextKey).(int) - if !ok { - return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session") - } - shortcutID, err := strconv.Atoi(c.Param("shortcutId")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("shortcutId"))).SetInternal(err) - } - - shortcut, err := s.Store.GetShortcut(ctx, &store.FindShortcut{ - ID: &shortcutID, - }) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find shortcut").SetInternal(err) - } - if shortcut == nil { - return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("Shortcut not found: %d", shortcutID)) - } - if shortcut.CreatorID != userID { - return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized") - } - - request := &UpdateShortcutRequest{} - if err := json.NewDecoder(c.Request().Body).Decode(request); err != nil { - return echo.NewHTTPError(http.StatusBadRequest, "Malformatted patch shortcut request").SetInternal(err) - } - - currentTs := time.Now().Unix() - shortcutUpdate := &store.UpdateShortcut{ - ID: shortcutID, - UpdatedTs: ¤tTs, - } - if request.RowStatus != nil { - rowStatus := store.RowStatus(*request.RowStatus) - shortcutUpdate.RowStatus = &rowStatus - } - if request.Title != nil { - shortcutUpdate.Title = request.Title - } - if request.Payload != nil { - shortcutUpdate.Payload = request.Payload - } - - shortcut, err = s.Store.UpdateShortcut(ctx, shortcutUpdate) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch shortcut").SetInternal(err) - } - return c.JSON(http.StatusOK, convertShortcutFromStore(shortcut)) - }) - - g.GET("/shortcut", func(c echo.Context) error { - ctx := c.Request().Context() - userID, ok := c.Get(auth.UserIDContextKey).(int) - if !ok { - return echo.NewHTTPError(http.StatusBadRequest, "Missing user id to find shortcut") - } - - list, err := s.Store.ListShortcuts(ctx, &store.FindShortcut{ - CreatorID: &userID, - }) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to get shortcut list").SetInternal(err) - } - shortcutMessageList := make([]*Shortcut, 0, len(list)) - for _, shortcut := range list { - shortcutMessageList = append(shortcutMessageList, convertShortcutFromStore(shortcut)) - } - return c.JSON(http.StatusOK, shortcutMessageList) - }) - - g.GET("/shortcut/:shortcutId", func(c echo.Context) error { - ctx := c.Request().Context() - shortcutID, err := strconv.Atoi(c.Param("shortcutId")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("shortcutId"))).SetInternal(err) - } - - shortcut, err := s.Store.GetShortcut(ctx, &store.FindShortcut{ - ID: &shortcutID, - }) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to fetch shortcut by ID %d", shortcutID)).SetInternal(err) - } - if shortcut == nil { - return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("Shortcut not found: %d", shortcutID)) - } - return c.JSON(http.StatusOK, convertShortcutFromStore(shortcut)) - }) - - g.DELETE("/shortcut/:shortcutId", func(c echo.Context) error { - ctx := c.Request().Context() - userID, ok := c.Get(auth.UserIDContextKey).(int) - if !ok { - return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session") - } - shortcutID, err := strconv.Atoi(c.Param("shortcutId")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("shortcutId"))).SetInternal(err) - } - - shortcut, err := s.Store.GetShortcut(ctx, &store.FindShortcut{ - ID: &shortcutID, - }) - if err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find shortcut").SetInternal(err) - } - if shortcut == nil { - return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("Shortcut not found: %d", shortcutID)) - } - if shortcut.CreatorID != userID { - return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized") - } - - if err := s.Store.DeleteShortcut(ctx, &store.DeleteShortcut{ - ID: &shortcutID, - }); err != nil { - return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete shortcut").SetInternal(err) - } - return c.JSON(http.StatusOK, true) - }) -} - -func (s *APIV1Service) createShortcutCreateActivity(c echo.Context, shortcut *Shortcut) error { - ctx := c.Request().Context() - payload := ActivityShortcutCreatePayload{ - Title: shortcut.Title, - Payload: shortcut.Payload, - } - payloadBytes, err := json.Marshal(payload) - if err != nil { - return errors.Wrap(err, "failed to marshal activity payload") - } - activity, err := s.Store.CreateActivity(ctx, &store.Activity{ - CreatorID: shortcut.CreatorID, - Type: ActivityShortcutCreate.String(), - Level: ActivityInfo.String(), - Payload: string(payloadBytes), - }) - if err != nil || activity == nil { - return errors.Wrap(err, "failed to create activity") - } - return err -} - -func convertShortcutFromStore(shortcut *store.Shortcut) *Shortcut { - return &Shortcut{ - ID: shortcut.ID, - RowStatus: RowStatus(shortcut.RowStatus), - CreatorID: shortcut.CreatorID, - Title: shortcut.Title, - Payload: shortcut.Payload, - CreatedTs: shortcut.CreatedTs, - UpdatedTs: shortcut.UpdatedTs, - } -} diff --git a/api/v1/v1.go b/api/v1/v1.go index 215385fb..581cafe2 100644 --- a/api/v1/v1.go +++ b/api/v1/v1.go @@ -36,7 +36,6 @@ func (s *APIV1Service) Register(rootGroup *echo.Group) { s.registerUserRoutes(apiV1Group) s.registerUserSettingRoutes(apiV1Group) s.registerTagRoutes(apiV1Group) - s.registerShortcutRoutes(apiV1Group) s.registerStorageRoutes(apiV1Group) s.registerResourceRoutes(apiV1Group) s.registerMemoRoutes(apiV1Group) diff --git a/store/shortcut.go b/store/shortcut.go deleted file mode 100644 index 969e8b96..00000000 --- a/store/shortcut.go +++ /dev/null @@ -1,211 +0,0 @@ -package store - -import ( - "context" - "database/sql" - "strings" -) - -type Shortcut struct { - ID int - - // Standard fields - RowStatus RowStatus - CreatorID int - CreatedTs int64 - UpdatedTs int64 - - // Domain specific fields - Title string - Payload string -} - -type UpdateShortcut struct { - ID int - - UpdatedTs *int64 - RowStatus *RowStatus - Title *string - Payload *string -} - -type FindShortcut struct { - ID *int - CreatorID *int - Title *string -} - -type DeleteShortcut struct { - ID *int - CreatorID *int -} - -func (s *Store) CreateShortcut(ctx context.Context, create *Shortcut) (*Shortcut, error) { - stmt := ` - INSERT INTO shortcut ( - title, - payload, - creator_id - ) - VALUES (?, ?, ?) - RETURNING id, created_ts, updated_ts, row_status - ` - if err := s.db.QueryRowContext(ctx, stmt, create.Title, create.Payload, create.CreatorID).Scan( - &create.ID, - &create.CreatedTs, - &create.UpdatedTs, - &create.RowStatus, - ); err != nil { - return nil, err - } - - shortcut := create - return shortcut, nil -} - -func (s *Store) ListShortcuts(ctx context.Context, find *FindShortcut) ([]*Shortcut, error) { - where, args := []string{"1 = 1"}, []any{} - - if v := find.ID; v != nil { - where, args = append(where, "id = ?"), append(args, *v) - } - if v := find.CreatorID; v != nil { - where, args = append(where, "creator_id = ?"), append(args, *v) - } - if v := find.Title; v != nil { - where, args = append(where, "title = ?"), append(args, *v) - } - - rows, err := s.db.QueryContext(ctx, ` - SELECT - id, - title, - payload, - creator_id, - created_ts, - updated_ts, - row_status - FROM shortcut - WHERE `+strings.Join(where, " AND ")+` - ORDER BY created_ts DESC`, - args..., - ) - if err != nil { - return nil, err - } - defer rows.Close() - - list := make([]*Shortcut, 0) - for rows.Next() { - var shortcut Shortcut - if err := rows.Scan( - &shortcut.ID, - &shortcut.Title, - &shortcut.Payload, - &shortcut.CreatorID, - &shortcut.CreatedTs, - &shortcut.UpdatedTs, - &shortcut.RowStatus, - ); err != nil { - return nil, err - } - list = append(list, &shortcut) - } - - if err := rows.Err(); err != nil { - return nil, err - } - - return list, nil -} - -func (s *Store) GetShortcut(ctx context.Context, find *FindShortcut) (*Shortcut, error) { - list, err := s.ListShortcuts(ctx, find) - if err != nil { - return nil, err - } - - if len(list) == 0 { - return nil, nil - } - - shortcut := list[0] - return shortcut, nil -} - -func (s *Store) UpdateShortcut(ctx context.Context, update *UpdateShortcut) (*Shortcut, error) { - set, args := []string{}, []any{} - if v := update.UpdatedTs; v != nil { - set, args = append(set, "updated_ts = ?"), append(args, *v) - } - if v := update.Title; v != nil { - set, args = append(set, "title = ?"), append(args, *v) - } - if v := update.Payload; v != nil { - set, args = append(set, "payload = ?"), append(args, *v) - } - if v := update.RowStatus; v != nil { - set, args = append(set, "row_status = ?"), append(args, *v) - } - args = append(args, update.ID) - - stmt := ` - UPDATE shortcut - SET ` + strings.Join(set, ", ") + ` - WHERE id = ? - RETURNING id, title, payload, creator_id, created_ts, updated_ts, row_status - ` - shortcut := &Shortcut{} - if err := s.db.QueryRowContext(ctx, stmt, args...).Scan( - &shortcut.ID, - &shortcut.Title, - &shortcut.Payload, - &shortcut.CreatorID, - &shortcut.CreatedTs, - &shortcut.UpdatedTs, - &shortcut.RowStatus, - ); err != nil { - return nil, err - } - - return shortcut, nil -} - -func (s *Store) DeleteShortcut(ctx context.Context, delete *DeleteShortcut) error { - where, args := []string{}, []any{} - if v := delete.ID; v != nil { - where, args = append(where, "id = ?"), append(args, *v) - } - if v := delete.CreatorID; v != nil { - where, args = append(where, "creator_id = ?"), append(args, *v) - } - stmt := `DELETE FROM shortcut WHERE ` + strings.Join(where, " AND ") - result, err := s.db.ExecContext(ctx, stmt, args...) - if err != nil { - return err - } - if _, err := result.RowsAffected(); err != nil { - return err - } - s.shortcutCache.Delete(*delete.ID) - return nil -} - -func vacuumShortcut(ctx context.Context, tx *sql.Tx) error { - stmt := ` - DELETE FROM - shortcut - WHERE - creator_id NOT IN ( - SELECT - id - FROM - user - )` - _, err := tx.ExecContext(ctx, stmt) - if err != nil { - return err - } - - return nil -} diff --git a/store/store.go b/store/store.go index a902d6fb..ca0fad8c 100644 --- a/store/store.go +++ b/store/store.go @@ -17,7 +17,6 @@ type Store struct { systemSettingCache sync.Map // map[string]*SystemSetting userCache sync.Map // map[int]*User userSettingCache sync.Map // map[string]*UserSetting - shortcutCache sync.Map // map[int]*Shortcut idpCache sync.Map // map[int]*IdentityProvider } @@ -100,9 +99,6 @@ func (*Store) vacuumImpl(ctx context.Context, tx *sql.Tx) error { if err := vacuumResource(ctx, tx); err != nil { return err } - if err := vacuumShortcut(ctx, tx); err != nil { - return err - } if err := vacuumUserSetting(ctx, tx); err != nil { return err }