memos/api/v1/shortcut.go

236 lines
7.1 KiB
Go
Raw Normal View History

package v1
2022-02-03 10:32:03 +03:00
import (
"encoding/json"
2022-02-03 10:32:03 +03:00
"fmt"
"net/http"
"strconv"
"time"
2022-02-03 10:32:03 +03:00
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
"github.com/usememos/memos/store"
2022-02-03 10:32:03 +03:00
)
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) {
2022-02-03 10:32:03 +03:00
g.POST("/shortcut", func(c echo.Context) error {
2022-08-07 05:17:12 +03:00
ctx := c.Request().Context()
2022-07-28 15:09:25 +03:00
userID, ok := c.Get(getUserIDContextKey()).(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 {
2022-02-03 10:32:03 +03:00
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,
})
2022-02-03 10:32:03 +03:00
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 {
2023-01-02 18:18:12 +03:00
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err)
}
return c.JSON(http.StatusOK, shortcutMessage)
2022-02-03 10:32:03 +03:00
})
2022-02-18 17:21:10 +03:00
2022-02-03 10:32:03 +03:00
g.PATCH("/shortcut/:shortcutId", func(c echo.Context) error {
2022-08-07 05:17:12 +03:00
ctx := c.Request().Context()
2022-12-28 15:22:52 +03:00
userID, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
}
2022-05-02 21:05:43 +03:00
shortcutID, err := strconv.Atoi(c.Param("shortcutId"))
2022-02-03 10:32:03 +03:00
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{
2022-12-28 15:22:52 +03:00
ID: &shortcutID,
})
2022-12-28 15:22:52 +03:00
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find shortcut").SetInternal(err)
}
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: &currentTs,
2022-02-03 10:32:03 +03:00
}
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
2022-02-03 10:32:03 +03:00
}
shortcut, err = s.Store.UpdateShortcut(ctx, shortcutUpdate)
2022-02-03 10:32:03 +03:00
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to patch shortcut").SetInternal(err)
}
return c.JSON(http.StatusOK, convertShortcutFromStore(shortcut))
2022-02-03 10:32:03 +03:00
})
2022-02-18 17:21:10 +03:00
2022-02-03 10:32:03 +03:00
g.GET("/shortcut", func(c echo.Context) error {
2022-08-07 05:17:12 +03:00
ctx := c.Request().Context()
2022-12-28 15:22:52 +03:00
userID, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
return echo.NewHTTPError(http.StatusBadRequest, "Missing user id to find shortcut")
}
list, err := s.Store.ListShortcuts(ctx, &store.FindShortcut{
2022-12-28 15:22:52 +03:00
CreatorID: &userID,
})
2022-02-03 10:32:03 +03:00
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to get shortcut list").SetInternal(err)
2022-02-03 10:32:03 +03:00
}
shortcutMessageList := make([]*Shortcut, 0, len(list))
for _, shortcut := range list {
shortcutMessageList = append(shortcutMessageList, convertShortcutFromStore(shortcut))
}
return c.JSON(http.StatusOK, shortcutMessageList)
2022-02-03 10:32:03 +03:00
})
2022-02-18 17:21:10 +03:00
2022-02-03 10:32:03 +03:00
g.GET("/shortcut/:shortcutId", func(c echo.Context) error {
2022-08-07 05:17:12 +03:00
ctx := c.Request().Context()
2022-05-02 21:05:43 +03:00
shortcutID, err := strconv.Atoi(c.Param("shortcutId"))
2022-02-03 10:32:03 +03:00
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{
2022-05-02 21:05:43 +03:00
ID: &shortcutID,
})
2022-02-03 10:32:03 +03:00
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 by ID %d not found", shortcutID))
2022-02-03 10:32:03 +03:00
}
return c.JSON(http.StatusOK, convertShortcutFromStore(shortcut))
2022-02-03 10:32:03 +03:00
})
2022-02-18 17:21:10 +03:00
2022-02-03 10:32:03 +03:00
g.DELETE("/shortcut/:shortcutId", func(c echo.Context) error {
2022-08-07 05:17:12 +03:00
ctx := c.Request().Context()
2022-12-28 15:22:52 +03:00
userID, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
}
2022-05-02 21:05:43 +03:00
shortcutID, err := strconv.Atoi(c.Param("shortcutId"))
2022-02-03 10:32:03 +03:00
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{
2022-12-28 15:22:52 +03:00
ID: &shortcutID,
})
2022-12-28 15:22:52 +03:00
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find shortcut").SetInternal(err)
}
if shortcut.CreatorID != userID {
return echo.NewHTTPError(http.StatusUnauthorized, "Unauthorized")
}
if err := s.Store.DeleteShortcut(ctx, &store.DeleteShortcut{
2022-11-06 07:21:58 +03:00
ID: &shortcutID,
}); err != nil {
2022-02-03 10:32:03 +03:00
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete shortcut").SetInternal(err)
}
return c.JSON(http.StatusOK, true)
2022-02-03 10:32:03 +03:00
})
}
2023-01-02 18:18:12 +03:00
func (s *APIV1Service) createShortcutCreateActivity(c echo.Context, shortcut *Shortcut) error {
2023-01-02 18:18:12 +03:00
ctx := c.Request().Context()
payload := ActivityShortcutCreatePayload{
2023-01-02 18:18:12 +03:00
Title: shortcut.Title,
Payload: shortcut.Payload,
}
payloadBytes, err := json.Marshal(payload)
2023-01-02 18:18:12 +03:00
if err != nil {
return errors.Wrap(err, "failed to marshal activity payload")
}
activity, err := s.Store.CreateActivity(ctx, &store.Activity{
2023-01-02 18:18:12 +03:00
CreatorID: shortcut.CreatorID,
Type: ActivityShortcutCreate.String(),
Level: ActivityInfo.String(),
Payload: string(payloadBytes),
2023-01-02 18:18:12 +03:00
})
2023-01-07 06:49:58 +03:00
if err != nil || activity == nil {
return errors.Wrap(err, "failed to create activity")
}
2023-01-02 18:18:12 +03:00
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,
}
}