memo_relation_service.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package v1
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/pkg/errors"
  6. "google.golang.org/grpc/codes"
  7. "google.golang.org/grpc/status"
  8. "google.golang.org/protobuf/types/known/emptypb"
  9. v1pb "github.com/usememos/memos/proto/gen/api/v1"
  10. "github.com/usememos/memos/store"
  11. )
  12. func (s *APIV1Service) SetMemoRelations(ctx context.Context, request *v1pb.SetMemoRelationsRequest) (*emptypb.Empty, error) {
  13. id, err := ExtractMemoIDFromName(request.Name)
  14. if err != nil {
  15. return nil, status.Errorf(codes.InvalidArgument, "invalid memo name: %v", err)
  16. }
  17. referenceType := store.MemoRelationReference
  18. // Delete all reference relations first.
  19. if err := s.Store.DeleteMemoRelation(ctx, &store.DeleteMemoRelation{
  20. MemoID: &id,
  21. Type: &referenceType,
  22. }); err != nil {
  23. return nil, status.Errorf(codes.Internal, "failed to delete memo relation")
  24. }
  25. for _, relation := range request.Relations {
  26. // Ignore reflexive relations.
  27. if request.Name == relation.RelatedMemo.Name {
  28. continue
  29. }
  30. // Ignore comment relations as there's no need to update a comment's relation.
  31. // Inserting/Deleting a comment is handled elsewhere.
  32. if relation.Type == v1pb.MemoRelation_COMMENT {
  33. continue
  34. }
  35. relatedMemoID, err := ExtractMemoIDFromName(relation.RelatedMemo.Name)
  36. if err != nil {
  37. return nil, status.Errorf(codes.InvalidArgument, "invalid related memo name: %v", err)
  38. }
  39. if _, err := s.Store.UpsertMemoRelation(ctx, &store.MemoRelation{
  40. MemoID: id,
  41. RelatedMemoID: relatedMemoID,
  42. Type: convertMemoRelationTypeToStore(relation.Type),
  43. }); err != nil {
  44. return nil, status.Errorf(codes.Internal, "failed to upsert memo relation")
  45. }
  46. }
  47. return &emptypb.Empty{}, nil
  48. }
  49. func (s *APIV1Service) ListMemoRelations(ctx context.Context, request *v1pb.ListMemoRelationsRequest) (*v1pb.ListMemoRelationsResponse, error) {
  50. id, err := ExtractMemoIDFromName(request.Name)
  51. if err != nil {
  52. return nil, status.Errorf(codes.InvalidArgument, "invalid memo name: %v", err)
  53. }
  54. relationList := []*v1pb.MemoRelation{}
  55. tempList, err := s.Store.ListMemoRelations(ctx, &store.FindMemoRelation{
  56. MemoID: &id,
  57. })
  58. if err != nil {
  59. return nil, err
  60. }
  61. for _, raw := range tempList {
  62. relation, err := s.convertMemoRelationFromStore(ctx, raw)
  63. if err != nil {
  64. return nil, status.Errorf(codes.Internal, "failed to convert memo relation")
  65. }
  66. relationList = append(relationList, relation)
  67. }
  68. tempList, err = s.Store.ListMemoRelations(ctx, &store.FindMemoRelation{
  69. RelatedMemoID: &id,
  70. })
  71. if err != nil {
  72. return nil, err
  73. }
  74. for _, raw := range tempList {
  75. relation, err := s.convertMemoRelationFromStore(ctx, raw)
  76. if err != nil {
  77. return nil, status.Errorf(codes.Internal, "failed to convert memo relation")
  78. }
  79. relationList = append(relationList, relation)
  80. }
  81. response := &v1pb.ListMemoRelationsResponse{
  82. Relations: relationList,
  83. }
  84. return response, nil
  85. }
  86. func (s *APIV1Service) convertMemoRelationFromStore(ctx context.Context, memoRelation *store.MemoRelation) (*v1pb.MemoRelation, error) {
  87. memo, err := s.Store.GetMemo(ctx, &store.FindMemo{ID: &memoRelation.MemoID})
  88. if err != nil {
  89. return nil, err
  90. }
  91. memoSnippet, err := getMemoContentSnippet(memo.Content)
  92. if err != nil {
  93. return nil, errors.Wrap(err, "failed to get memo content snippet")
  94. }
  95. relatedMemo, err := s.Store.GetMemo(ctx, &store.FindMemo{ID: &memoRelation.RelatedMemoID})
  96. if err != nil {
  97. return nil, err
  98. }
  99. relatedMemoSnippet, err := getMemoContentSnippet(relatedMemo.Content)
  100. if err != nil {
  101. return nil, errors.Wrap(err, "failed to get related memo content snippet")
  102. }
  103. return &v1pb.MemoRelation{
  104. Memo: &v1pb.MemoRelation_Memo{
  105. Name: fmt.Sprintf("%s%d", MemoNamePrefix, memo.ID),
  106. Uid: memo.UID,
  107. Snippet: memoSnippet,
  108. },
  109. RelatedMemo: &v1pb.MemoRelation_Memo{
  110. Name: fmt.Sprintf("%s%d", MemoNamePrefix, relatedMemo.ID),
  111. Uid: relatedMemo.UID,
  112. Snippet: relatedMemoSnippet,
  113. },
  114. Type: convertMemoRelationTypeFromStore(memoRelation.Type),
  115. }, nil
  116. }
  117. func convertMemoRelationTypeFromStore(relationType store.MemoRelationType) v1pb.MemoRelation_Type {
  118. switch relationType {
  119. case store.MemoRelationReference:
  120. return v1pb.MemoRelation_REFERENCE
  121. case store.MemoRelationComment:
  122. return v1pb.MemoRelation_COMMENT
  123. default:
  124. return v1pb.MemoRelation_TYPE_UNSPECIFIED
  125. }
  126. }
  127. func convertMemoRelationTypeToStore(relationType v1pb.MemoRelation_Type) store.MemoRelationType {
  128. switch relationType {
  129. case v1pb.MemoRelation_REFERENCE:
  130. return store.MemoRelationReference
  131. case v1pb.MemoRelation_COMMENT:
  132. return store.MemoRelationComment
  133. default:
  134. return store.MemoRelationReference
  135. }
  136. }