user_service_stats.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. package v1
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "github.com/pkg/errors"
  7. "google.golang.org/grpc/codes"
  8. "google.golang.org/grpc/status"
  9. "google.golang.org/protobuf/types/known/timestamppb"
  10. v1pb "github.com/usememos/memos/proto/gen/api/v1"
  11. "github.com/usememos/memos/store"
  12. )
  13. func (s *APIV1Service) ListAllUserStats(ctx context.Context, _ *v1pb.ListAllUserStatsRequest) (*v1pb.ListAllUserStatsResponse, error) {
  14. currentUser, err := s.GetCurrentUser(ctx)
  15. if err != nil {
  16. return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
  17. }
  18. visibilities := []store.Visibility{store.Public}
  19. if currentUser != nil {
  20. visibilities = append(visibilities, store.Protected)
  21. }
  22. workspaceMemoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
  23. if err != nil {
  24. return nil, errors.Wrap(err, "failed to get workspace memo related setting")
  25. }
  26. normalStatus := store.Normal
  27. memoFind := &store.FindMemo{
  28. // Exclude comments by default.
  29. ExcludeComments: true,
  30. ExcludeContent: true,
  31. VisibilityList: visibilities,
  32. RowStatus: &normalStatus,
  33. }
  34. memos, err := s.Store.ListMemos(ctx, memoFind)
  35. if err != nil {
  36. return nil, status.Errorf(codes.Internal, "failed to list memos: %v", err)
  37. }
  38. userStatsMap := map[string]*v1pb.UserStats{}
  39. for _, memo := range memos {
  40. creator := fmt.Sprintf("%s%d", UserNamePrefix, memo.CreatorID)
  41. if _, ok := userStatsMap[creator]; !ok {
  42. userStatsMap[creator] = &v1pb.UserStats{
  43. Name: creator,
  44. MemoDisplayTimestamps: []*timestamppb.Timestamp{},
  45. MemoTypeStats: &v1pb.UserStats_MemoTypeStats{},
  46. TagCount: map[string]int32{},
  47. }
  48. }
  49. displayTs := memo.CreatedTs
  50. if workspaceMemoRelatedSetting.DisplayWithUpdateTime {
  51. displayTs = memo.UpdatedTs
  52. }
  53. userStats := userStatsMap[creator]
  54. userStats.MemoDisplayTimestamps = append(userStats.MemoDisplayTimestamps, timestamppb.New(time.Unix(displayTs, 0)))
  55. // Handle duplicated tags.
  56. for _, tag := range memo.Payload.Tags {
  57. userStats.TagCount[tag]++
  58. }
  59. if memo.Payload.Property.GetHasLink() {
  60. userStats.MemoTypeStats.LinkCount++
  61. }
  62. if memo.Payload.Property.GetHasCode() {
  63. userStats.MemoTypeStats.CodeCount++
  64. }
  65. if memo.Payload.Property.GetHasTaskList() {
  66. userStats.MemoTypeStats.TodoCount++
  67. }
  68. if memo.Payload.Property.GetHasIncompleteTasks() {
  69. userStats.MemoTypeStats.UndoCount++
  70. }
  71. }
  72. userStatsList := []*v1pb.UserStats{}
  73. for _, userStats := range userStatsMap {
  74. userStatsList = append(userStatsList, userStats)
  75. }
  76. return &v1pb.ListAllUserStatsResponse{
  77. UserStats: userStatsList,
  78. }, nil
  79. }
  80. func (s *APIV1Service) GetUserStats(ctx context.Context, request *v1pb.GetUserStatsRequest) (*v1pb.UserStats, error) {
  81. userID, err := ExtractUserIDFromName(request.Name)
  82. if err != nil {
  83. return nil, status.Errorf(codes.InvalidArgument, "invalid user name: %v", err)
  84. }
  85. user, err := s.Store.GetUser(ctx, &store.FindUser{ID: &userID})
  86. if err != nil {
  87. return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
  88. }
  89. normalStatus := store.Normal
  90. memoFind := &store.FindMemo{
  91. // Exclude comments by default.
  92. ExcludeComments: true,
  93. ExcludeContent: true,
  94. CreatorID: &userID,
  95. RowStatus: &normalStatus,
  96. }
  97. currentUser, err := s.GetCurrentUser(ctx)
  98. if err != nil {
  99. return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
  100. }
  101. visibilities := []store.Visibility{store.Public}
  102. if currentUser != nil {
  103. visibilities = append(visibilities, store.Protected)
  104. if currentUser.ID == user.ID {
  105. visibilities = append(visibilities, store.Private)
  106. }
  107. }
  108. memoFind.VisibilityList = visibilities
  109. memos, err := s.Store.ListMemos(ctx, memoFind)
  110. if err != nil {
  111. return nil, status.Errorf(codes.Internal, "failed to list memos: %v", err)
  112. }
  113. workspaceMemoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
  114. if err != nil {
  115. return nil, errors.Wrap(err, "failed to get workspace memo related setting")
  116. }
  117. userStats := &v1pb.UserStats{
  118. Name: fmt.Sprintf("%s%d", UserNamePrefix, user.ID),
  119. MemoDisplayTimestamps: []*timestamppb.Timestamp{},
  120. MemoTypeStats: &v1pb.UserStats_MemoTypeStats{},
  121. TagCount: map[string]int32{},
  122. }
  123. for _, memo := range memos {
  124. displayTs := memo.CreatedTs
  125. if workspaceMemoRelatedSetting.DisplayWithUpdateTime {
  126. displayTs = memo.UpdatedTs
  127. }
  128. userStats.MemoDisplayTimestamps = append(userStats.MemoDisplayTimestamps, timestamppb.New(time.Unix(displayTs, 0)))
  129. // Handle duplicated tags.
  130. for _, tag := range memo.Payload.Tags {
  131. userStats.TagCount[tag]++
  132. }
  133. if memo.Payload.Property.GetHasLink() {
  134. userStats.MemoTypeStats.LinkCount++
  135. }
  136. if memo.Payload.Property.GetHasCode() {
  137. userStats.MemoTypeStats.CodeCount++
  138. }
  139. if memo.Payload.Property.GetHasTaskList() {
  140. userStats.MemoTypeStats.TodoCount++
  141. }
  142. if memo.Payload.Property.GetHasIncompleteTasks() {
  143. userStats.MemoTypeStats.UndoCount++
  144. }
  145. }
  146. return userStats, nil
  147. }