mirror of
https://github.com/usememos/memos.git
synced 2024-11-11 01:12:40 +08:00
156 lines
5.7 KiB
Go
156 lines
5.7 KiB
Go
package v1
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
|
|
"github.com/usememos/memos/internal/util"
|
|
"github.com/usememos/memos/store"
|
|
)
|
|
|
|
type MemoRelationType string
|
|
|
|
const (
|
|
MemoRelationReference MemoRelationType = "REFERENCE"
|
|
MemoRelationComment MemoRelationType = "COMMENT"
|
|
)
|
|
|
|
func (t MemoRelationType) String() string {
|
|
return string(t)
|
|
}
|
|
|
|
type MemoRelation struct {
|
|
MemoID int32 `json:"memoId"`
|
|
RelatedMemoID int32 `json:"relatedMemoId"`
|
|
Type MemoRelationType `json:"type"`
|
|
}
|
|
|
|
type UpsertMemoRelationRequest struct {
|
|
RelatedMemoID int32 `json:"relatedMemoId"`
|
|
Type MemoRelationType `json:"type"`
|
|
}
|
|
|
|
func (s *APIV1Service) registerMemoRelationRoutes(g *echo.Group) {
|
|
g.GET("/memo/:memoId/relation", s.GetMemoRelationList)
|
|
g.POST("/memo/:memoId/relation", s.CreateMemoRelation)
|
|
g.DELETE("/memo/:memoId/relation/:relatedMemoId/type/:relationType", s.DeleteMemoRelation)
|
|
}
|
|
|
|
// GetMemoRelationList godoc
|
|
//
|
|
// @Summary Get a list of Memo Relations
|
|
// @Tags memo-relation
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param memoId path int true "ID of memo to find relations"
|
|
// @Success 200 {object} []store.MemoRelation "Memo relation information list"
|
|
// @Failure 400 {object} nil "ID is not a number: %s"
|
|
// @Failure 500 {object} nil "Failed to list memo relations"
|
|
// @Router /api/v1/memo/{memoId}/relation [GET]
|
|
func (s *APIV1Service) GetMemoRelationList(c echo.Context) error {
|
|
ctx := c.Request().Context()
|
|
memoID, err := util.ConvertStringToInt32(c.Param("memoId"))
|
|
if err != nil {
|
|
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("memoId"))).SetInternal(err)
|
|
}
|
|
|
|
memoRelationList, err := s.Store.ListMemoRelations(ctx, &store.FindMemoRelation{
|
|
MemoID: &memoID,
|
|
})
|
|
if err != nil {
|
|
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to list memo relations").SetInternal(err)
|
|
}
|
|
return c.JSON(http.StatusOK, memoRelationList)
|
|
}
|
|
|
|
// CreateMemoRelation godoc
|
|
//
|
|
// @Summary Create Memo Relation
|
|
// @Description Create a relation between two memos
|
|
// @Tags memo-relation
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param memoId path int true "ID of memo to relate"
|
|
// @Param body body UpsertMemoRelationRequest true "Memo relation object"
|
|
// @Success 200 {object} store.MemoRelation "Memo relation information"
|
|
// @Failure 400 {object} nil "ID is not a number: %s | Malformatted post memo relation request"
|
|
// @Failure 500 {object} nil "Failed to upsert memo relation"
|
|
// @Router /api/v1/memo/{memoId}/relation [POST]
|
|
//
|
|
// NOTES:
|
|
// - Currently not secured
|
|
// - It's possible to create relations to memos that doesn't exist, which will trigger 404 errors when the frontend tries to load them.
|
|
// - It's possible to create multiple relations, though the interface only shows first.
|
|
func (s *APIV1Service) CreateMemoRelation(c echo.Context) error {
|
|
ctx := c.Request().Context()
|
|
memoID, err := util.ConvertStringToInt32(c.Param("memoId"))
|
|
if err != nil {
|
|
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("ID is not a number: %s", c.Param("memoId"))).SetInternal(err)
|
|
}
|
|
|
|
request := &UpsertMemoRelationRequest{}
|
|
if err := json.NewDecoder(c.Request().Body).Decode(request); err != nil {
|
|
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post memo relation request").SetInternal(err)
|
|
}
|
|
|
|
memoRelation, err := s.Store.UpsertMemoRelation(ctx, &store.MemoRelation{
|
|
MemoID: memoID,
|
|
RelatedMemoID: request.RelatedMemoID,
|
|
Type: store.MemoRelationType(request.Type),
|
|
})
|
|
if err != nil {
|
|
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to upsert memo relation").SetInternal(err)
|
|
}
|
|
return c.JSON(http.StatusOK, memoRelation)
|
|
}
|
|
|
|
// DeleteMemoRelation godoc
|
|
//
|
|
// @Summary Delete a Memo Relation
|
|
// @Description Removes a relation between two memos
|
|
// @Tags memo-relation
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param memoId path int true "ID of memo to find relations"
|
|
// @Param relatedMemoId path int true "ID of memo to remove relation to"
|
|
// @Param relationType path MemoRelationType true "Type of relation to remove"
|
|
// @Success 200 {boolean} true "Memo relation deleted"
|
|
// @Failure 400 {object} nil "Memo ID is not a number: %s | Related memo ID is not a number: %s"
|
|
// @Failure 500 {object} nil "Failed to delete memo relation"
|
|
// @Router /api/v1/memo/{memoId}/relation/{relatedMemoId}/type/{relationType} [DELETE]
|
|
//
|
|
// NOTES:
|
|
// - Currently not secured.
|
|
// - Will always return true, even if the relation doesn't exist.
|
|
func (s *APIV1Service) DeleteMemoRelation(c echo.Context) error {
|
|
ctx := c.Request().Context()
|
|
memoID, err := util.ConvertStringToInt32(c.Param("memoId"))
|
|
if err != nil {
|
|
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Memo ID is not a number: %s", c.Param("memoId"))).SetInternal(err)
|
|
}
|
|
relatedMemoID, err := util.ConvertStringToInt32(c.Param("relatedMemoId"))
|
|
if err != nil {
|
|
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Related memo ID is not a number: %s", c.Param("relatedMemoId"))).SetInternal(err)
|
|
}
|
|
relationType := store.MemoRelationType(c.Param("relationType"))
|
|
|
|
if err := s.Store.DeleteMemoRelation(ctx, &store.DeleteMemoRelation{
|
|
MemoID: &memoID,
|
|
RelatedMemoID: &relatedMemoID,
|
|
Type: &relationType,
|
|
}); err != nil {
|
|
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to delete memo relation").SetInternal(err)
|
|
}
|
|
return c.JSON(http.StatusOK, true)
|
|
}
|
|
|
|
func convertMemoRelationFromStore(memoRelation *store.MemoRelation) *MemoRelation {
|
|
return &MemoRelation{
|
|
MemoID: memoRelation.MemoID,
|
|
RelatedMemoID: memoRelation.RelatedMemoID,
|
|
Type: MemoRelationType(memoRelation.Type),
|
|
}
|
|
}
|