123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- 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),
- }
- }
|