mirror of https://github.com/usememos/memos
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
4.9 KiB
Go
172 lines
4.9 KiB
Go
package v1
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
|
|
v1pb "github.com/usememos/memos/proto/gen/api/v1"
|
|
"github.com/usememos/memos/store"
|
|
)
|
|
|
|
func (s *APIV1Service) ListAllUserStats(ctx context.Context, _ *v1pb.ListAllUserStatsRequest) (*v1pb.ListAllUserStatsResponse, error) {
|
|
workspaceMemoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to get workspace memo related setting")
|
|
}
|
|
|
|
normalStatus := store.Normal
|
|
memoFind := &store.FindMemo{
|
|
// Exclude comments by default.
|
|
ExcludeComments: true,
|
|
ExcludeContent: true,
|
|
RowStatus: &normalStatus,
|
|
}
|
|
|
|
currentUser, err := s.GetCurrentUser(ctx)
|
|
if err != nil {
|
|
return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
|
|
}
|
|
if currentUser == nil {
|
|
memoFind.VisibilityList = []store.Visibility{store.Public}
|
|
} else {
|
|
if memoFind.CreatorID == nil {
|
|
internalFilter := fmt.Sprintf(`creator_id == %d || visibility in ["PUBLIC", "PROTECTED"]`, currentUser.ID)
|
|
if memoFind.Filter != nil {
|
|
filter := fmt.Sprintf("(%s) && (%s)", *memoFind.Filter, internalFilter)
|
|
memoFind.Filter = &filter
|
|
} else {
|
|
memoFind.Filter = &internalFilter
|
|
}
|
|
} else if *memoFind.CreatorID != currentUser.ID {
|
|
memoFind.VisibilityList = []store.Visibility{store.Public, store.Protected}
|
|
}
|
|
}
|
|
memos, err := s.Store.ListMemos(ctx, memoFind)
|
|
if err != nil {
|
|
return nil, status.Errorf(codes.Internal, "failed to list memos: %v", err)
|
|
}
|
|
|
|
userMemoStatMap := make(map[int32]*v1pb.UserStats)
|
|
for _, memo := range memos {
|
|
displayTs := memo.CreatedTs
|
|
if workspaceMemoRelatedSetting.DisplayWithUpdateTime {
|
|
displayTs = memo.UpdatedTs
|
|
}
|
|
userMemoStatMap[memo.CreatorID] = &v1pb.UserStats{
|
|
Name: fmt.Sprintf("users/%d/stats", memo.CreatorID),
|
|
}
|
|
userMemoStatMap[memo.CreatorID].MemoDisplayTimestamps = append(userMemoStatMap[memo.CreatorID].MemoDisplayTimestamps, timestamppb.New(time.Unix(displayTs, 0)))
|
|
}
|
|
|
|
userMemoStats := []*v1pb.UserStats{}
|
|
for _, userMemoStat := range userMemoStatMap {
|
|
userMemoStats = append(userMemoStats, userMemoStat)
|
|
}
|
|
|
|
response := &v1pb.ListAllUserStatsResponse{
|
|
UserStats: userMemoStats,
|
|
}
|
|
return response, nil
|
|
}
|
|
|
|
func (s *APIV1Service) GetUserStats(ctx context.Context, request *v1pb.GetUserStatsRequest) (*v1pb.UserStats, error) {
|
|
userID, err := ExtractUserIDFromName(request.Name)
|
|
if err != nil {
|
|
return nil, status.Errorf(codes.InvalidArgument, "invalid user name: %v", err)
|
|
}
|
|
|
|
currentUser, err := s.GetCurrentUser(ctx)
|
|
if err != nil {
|
|
return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
|
|
}
|
|
|
|
normalStatus := store.Normal
|
|
memoFind := &store.FindMemo{
|
|
CreatorID: &userID,
|
|
// Exclude comments by default.
|
|
ExcludeComments: true,
|
|
ExcludeContent: true,
|
|
RowStatus: &normalStatus,
|
|
}
|
|
|
|
if currentUser == nil {
|
|
memoFind.VisibilityList = []store.Visibility{store.Public}
|
|
} else if currentUser.ID != userID {
|
|
memoFind.VisibilityList = []store.Visibility{store.Public, store.Protected}
|
|
}
|
|
|
|
memos, err := s.Store.ListMemos(ctx, memoFind)
|
|
if err != nil {
|
|
return nil, status.Errorf(codes.Internal, "failed to list memos: %v", err)
|
|
}
|
|
|
|
workspaceMemoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to get workspace memo related setting")
|
|
}
|
|
|
|
displayTimestamps := []*timestamppb.Timestamp{}
|
|
tagCount := make(map[string]int32)
|
|
linkCount := int32(0)
|
|
codeCount := int32(0)
|
|
todoCount := int32(0)
|
|
undoCount := int32(0)
|
|
pinnedMemos := []string{}
|
|
|
|
for _, memo := range memos {
|
|
displayTs := memo.CreatedTs
|
|
if workspaceMemoRelatedSetting.DisplayWithUpdateTime {
|
|
displayTs = memo.UpdatedTs
|
|
}
|
|
displayTimestamps = append(displayTimestamps, timestamppb.New(time.Unix(displayTs, 0)))
|
|
// Count different memo types based on content.
|
|
if memo.Payload != nil {
|
|
for _, tag := range memo.Payload.Tags {
|
|
if tagCount[tag] == 0 {
|
|
tagCount[tag] = 1
|
|
}
|
|
tagCount[tag]++
|
|
}
|
|
if memo.Payload.Property != nil {
|
|
if memo.Payload.Property.HasLink {
|
|
linkCount++
|
|
}
|
|
if memo.Payload.Property.HasCode {
|
|
codeCount++
|
|
}
|
|
if memo.Payload.Property.HasTaskList {
|
|
todoCount++
|
|
}
|
|
if memo.Payload.Property.HasIncompleteTasks {
|
|
undoCount++
|
|
}
|
|
}
|
|
}
|
|
if memo.Pinned {
|
|
pinnedMemos = append(pinnedMemos, fmt.Sprintf("users/%d/memos/%d", userID, memo.ID))
|
|
}
|
|
}
|
|
|
|
userStats := &v1pb.UserStats{
|
|
Name: fmt.Sprintf("users/%d/stats", userID),
|
|
MemoDisplayTimestamps: displayTimestamps,
|
|
TagCount: tagCount,
|
|
PinnedMemos: pinnedMemos,
|
|
TotalMemoCount: int32(len(memos)),
|
|
MemoTypeStats: &v1pb.UserStats_MemoTypeStats{
|
|
LinkCount: linkCount,
|
|
CodeCount: codeCount,
|
|
TodoCount: todoCount,
|
|
UndoCount: undoCount,
|
|
},
|
|
}
|
|
|
|
return userStats, nil
|
|
}
|