You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

745 lines
22 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package biz
import (
"context"
"fmt"
"net/url"
"os"
"path/filepath"
"strings"
"time"
pb "moredoc/api/v1"
"moredoc/middleware/auth"
"moredoc/model"
"moredoc/util"
"moredoc/util/filetil"
"moredoc/util/segword/jieba"
"github.com/golang-jwt/jwt"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
)
type DocumentAPIService struct {
pb.UnimplementedDocumentAPIServer
dbModel *model.DBModel
logger *zap.Logger
}
func NewDocumentAPIService(dbModel *model.DBModel, logger *zap.Logger) (service *DocumentAPIService) {
return &DocumentAPIService{dbModel: dbModel, logger: logger.Named("DocumentAPIService")}
}
func (s *DocumentAPIService) checkPermission(ctx context.Context) (userClaims *auth.UserClaims, err error) {
return checkGRPCPermission(s.dbModel, ctx)
}
func (s *DocumentAPIService) checkLogin(ctx context.Context) (userClaims *auth.UserClaims, err error) {
return checkGRPCLogin(s.dbModel, ctx)
}
// CreateDocument 创建文档
// 0. 判断是否有权限
// 1. 同名覆盖找到该作者上传的相同title和ext的文档然后用新文件覆盖同时文档状态改为待转换
// 2. 相同hash的文档如果已经被转换了则该文档的状态直接改为已转换
// 3. 判断附件ID是否与用户ID匹配不匹配则跳过该文档
func (s *DocumentAPIService) CreateDocument(ctx context.Context, req *pb.CreateDocumentRequest) (*emptypb.Empty, error) {
userCliams, err := s.checkLogin(ctx)
if err != nil {
return nil, err
}
if !s.dbModel.CanIUploadDocument(userCliams.UserId) {
return nil, status.Error(codes.PermissionDenied, "没有权限上传文档")
}
var (
attachmentIds []interface{}
attachmentMap = make(map[int64]model.Attachment)
)
for _, item := range req.Document {
attachmentIds = append(attachmentIds, item.AttachmentId)
}
attachments, _, _ := s.dbModel.GetAttachmentList(&model.OptionGetAttachmentList{
Ids: attachmentIds,
QueryIn: map[string][]interface{}{"user_id": {userCliams.UserId}},
})
if len(attachments) == 0 {
return nil, status.Error(codes.InvalidArgument, "文档文件参数attachment_id不正确")
}
for _, attachment := range attachments {
attachmentMap[attachment.Id] = attachment
}
var (
documents []model.Document
docMapAttachment = make(map[int]int64)
)
for idx, doc := range req.Document {
attachment, ok := attachmentMap[doc.AttachmentId]
if !ok {
continue
}
doc := model.Document{
Title: doc.Title,
Keywords: strings.Join(jieba.SegWords(doc.Title), ","),
UserId: userCliams.UserId,
// UUID: uuid.Must(uuid.NewV4()).String(),
Score: 300,
Price: int(doc.Price),
Size: attachment.Size,
Ext: attachment.Ext,
Status: model.DocumentStatusPending,
}
docMapAttachment[idx] = attachment.Id
documents = append(documents, doc)
}
docs, err := s.dbModel.CreateDocuments(documents, req.CategoryId)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
attachIdTypeIdMap := make(map[int64]int64)
for idx, doc := range docs {
if attachmentId, ok := docMapAttachment[idx]; ok {
attachIdTypeIdMap[attachmentId] = doc.Id
}
}
s.dbModel.SetAttachmentTypeId(attachIdTypeIdMap)
return &emptypb.Empty{}, nil
}
// UpdateDocument 更新文档
// 1. 对于普通用户,可以更新自己创建的文档
// 2. 对于管理员,可以更新所有文档
func (s *DocumentAPIService) UpdateDocument(ctx context.Context, req *pb.Document) (*emptypb.Empty, error) {
s.logger.Debug("UpdateDocument", zap.Any("req", req))
userClaims, err := s.checkPermission(ctx)
if userClaims == nil { // 未登录
return nil, err
}
fields := []string{"id", "title", "keywords", "description", "price"}
doc := &model.Document{}
util.CopyStruct(req, doc)
if err != nil { // 普通用户,只能更新自己的文档
existDoc, _ := s.dbModel.GetDocument(req.Id, "id", "user_id")
if existDoc.UserId != userClaims.UserId {
return nil, status.Error(codes.PermissionDenied, "文档不存在或没有权限")
}
} else { // 管理员,可以更新所有文档
fields = append(fields, "status")
}
err = s.dbModel.UpdateDocument(doc, req.CategoryId, fields...)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &emptypb.Empty{}, nil
}
// DeleteDocument 删除文档
// 1. 对于普通用户,可以删除自己创建的文档
// 2. 对于管理员,可以删除所有文档
func (s *DocumentAPIService) DeleteDocument(ctx context.Context, req *pb.DeleteDocumentRequest) (*emptypb.Empty, error) {
userClaims, err := s.checkPermission(ctx)
s.logger.Info("DeleteDocument", zap.Any("userClaims", userClaims), zap.Error(err))
if err != nil && userClaims == nil { // 未登录
return nil, err
}
ids := req.Id
if err != nil { // 普通用户,只能删除自己创建的文档
userDocs, _, _ := s.dbModel.GetDocumentList(&model.OptionGetDocumentList{
WithCount: false,
SelectFields: []string{"id"},
Ids: util.Slice2Interface(req.Id),
})
if len(userDocs) == 0 {
return &emptypb.Empty{}, nil
}
for _, doc := range userDocs {
ids = append(ids, doc.Id)
}
}
err = s.dbModel.DeleteDocument(ids, userClaims.UserId)
if err != nil {
return nil, status.Errorf(codes.Internal, "删除文档失败:%v", err)
}
return &emptypb.Empty{}, nil
}
// GetDocument 获取文档(任何人都可以调用)。当文档禁用之后,只有管理员可以查看
func (s *DocumentAPIService) GetDocument(ctx context.Context, req *pb.GetDocumentRequest) (*pb.Document, error) {
doc, _ := s.dbModel.GetDocument(req.Id)
if doc.Id == 0 {
return nil, status.Error(codes.NotFound, "文档不存在")
}
doc.ViewCount += 1
_, err := s.checkPermission(ctx)
if err != nil && doc.Status == model.DocumentStatusDisabled {
return nil, status.Error(codes.NotFound, "文档不存在或没有权限")
}
pbDoc := &pb.Document{}
util.CopyStruct(doc, pbDoc)
docCates, _, _ := s.dbModel.GetDocumentCategoryList(
&model.OptionGetDocumentCategoryList{
WithCount: false,
SelectFields: []string{"category_id"},
QueryIn: map[string][]interface{}{"document_id": {doc.Id}},
},
)
for _, dc := range docCates {
pbDoc.CategoryId = append(pbDoc.CategoryId, dc.CategoryId)
}
if req.WithAuthor {
user, _ := s.dbModel.GetUser(doc.UserId, model.UserPublicFields...)
pbDoc.User = &pb.User{}
util.CopyStruct(&user, pbDoc.User)
s.dbModel.UpdateDocumentField(doc.Id, map[string]interface{}{"view_count": doc.ViewCount})
}
// 查找文档相关联的附件。对于列表只返回hash和id不返回其他字段
attchment := s.dbModel.GetAttachmentByTypeAndTypeId(model.AttachmentTypeDocument, doc.Id, "hash", "path")
fixedData := make(map[string]interface{})
if pbDoc.Width == 0 || pbDoc.Height == 0 {
bigCover := strings.TrimLeft(strings.TrimSuffix(attchment.Path, filepath.Ext(attchment.Path)), "./") + "/cover.big.png"
doc.Width, doc.Height, _ = util.GetImageSize(bigCover)
if doc.Width*doc.Height > 0 {
pbDoc.Width = int32(doc.Width)
pbDoc.Height = int32(doc.Height)
fixedData = map[string]interface{}{"width": doc.Width, "height": doc.Height}
}
}
if desc := strings.TrimSpace(pbDoc.Description); desc == "" {
desc = doc.Title // 默认
textFile := strings.TrimLeft(strings.TrimSuffix(attchment.Path, filepath.Ext(attchment.Path)), "./") + "/content.txt"
if content, errRead := os.ReadFile(textFile); errRead == nil { // 读取文本内容,以提取关键字和摘要
contentStr := string(content)
replacer := strings.NewReplacer("\r", " ", "\n", " ", "\t", " ")
contentStr = strings.TrimSpace(replacer.Replace(util.Substr(contentStr, 255)))
if contentStr != "" {
desc = contentStr
}
}
doc.Description = desc
fixedData["description"] = desc
}
if len(fixedData) > 0 {
s.dbModel.UpdateDocumentField(doc.Id, fixedData)
}
pbDoc.Attachment = &pb.Attachment{Hash: attchment.Hash}
return pbDoc, nil
}
// ListDocument 查询文档列表
// 1. 对于普通用户只能查询未禁用的文档且最多只能查询100页
// 2. 对于管理员,可以查询所有文档,可以根据关键字进行查询
func (s *DocumentAPIService) ListDocument(ctx context.Context, req *pb.ListDocumentRequest) (*pb.ListDocumentReply, error) {
opt := &model.OptionGetDocumentList{
WithCount: req.Limit <= 0,
Page: int(req.Page),
Size: int(req.Size_),
SelectFields: req.Field,
QueryIn: make(map[string][]interface{}),
QueryLike: make(map[string][]interface{}),
IsRecommend: req.IsRecommend,
}
if len(req.Order) > 0 {
opt.Sort = []string{req.Order}
}
if len(req.CategoryId) > 0 {
opt.QueryIn["category_id"] = util.Slice2Interface(req.CategoryId)
}
if len(req.UserId) > 0 {
opt.QueryIn["user_id"] = []interface{}{req.UserId[0]}
}
_, err := s.checkPermission(ctx)
if err == nil { // 有权限,则不限页数
if req.Wd != "" {
opt.QueryLike["title"] = []interface{}{req.Wd}
opt.QueryLike["keywords"] = []interface{}{req.Wd}
opt.QueryLike["description"] = []interface{}{req.Wd}
}
if len(req.Status) > 0 {
opt.QueryIn["status"] = util.Slice2Interface(req.Status)
}
} else {
opt.Size = util.LimitRange(opt.Size, 1, 24)
opt.Page = util.LimitRange(opt.Page, 1, 100)
if len(req.Status) == 1 && req.Status[0] == model.DocumentStatusConverted {
opt.QueryIn["status"] = []interface{}{
model.DocumentStatusConverted,
}
} else {
opt.QueryIn["status"] = []interface{}{
model.DocumentStatusPending, model.DocumentStatusConverting,
model.DocumentStatusConverted, model.DocumentStatusFailed,
}
}
}
if req.Limit > 0 {
opt.Size = int(req.Limit)
opt.Page = 1
}
s.logger.Debug("ListDocument", zap.Any("opt", opt))
return s.listDocument(opt)
}
// ListRecycleDocument 回收站文档
func (s *DocumentAPIService) ListRecycleDocument(ctx context.Context, req *pb.ListDocumentRequest) (*pb.ListDocumentReply, error) {
_, err := s.checkPermission(ctx)
if err != nil {
return nil, status.Error(codes.PermissionDenied, err.Error())
}
opt := &model.OptionGetDocumentList{
WithCount: true,
Page: int(req.Page),
Size: int(req.Size_),
SelectFields: req.Field,
QueryIn: make(map[string][]interface{}),
QueryLike: make(map[string][]interface{}),
IsRecycle: true,
}
if len(req.CategoryId) > 0 {
opt.QueryIn["category_id"] = util.Slice2Interface(req.CategoryId)
}
if len(req.UserId) > 0 {
opt.QueryIn["user_id"] = []interface{}{req.UserId[0]}
}
if req.Wd != "" {
opt.QueryLike["title"] = []interface{}{req.Wd}
opt.QueryLike["keywords"] = []interface{}{req.Wd}
opt.QueryLike["description"] = []interface{}{req.Wd}
}
if len(req.Status) > 0 {
opt.QueryIn["status"] = util.Slice2Interface(req.Status)
}
return s.listDocument(opt)
}
// RecoverRecycleDocument 恢复回收站文档
func (s *DocumentAPIService) RecoverRecycleDocument(ctx context.Context, req *pb.RecoverRecycleDocumentRequest) (*emptypb.Empty, error) {
_, err := s.checkPermission(ctx)
if err != nil {
return nil, status.Error(codes.PermissionDenied, err.Error())
}
s.logger.Debug("RecoverRecycleDocument", zap.Any("req", req))
if len(req.Id) == 0 {
return &emptypb.Empty{}, nil
}
err = s.dbModel.RecoverRecycleDocument(req.Id)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &emptypb.Empty{}, nil
}
// DeleteRecycleDocument 删除回收站文档
func (s *DocumentAPIService) DeleteRecycleDocument(ctx context.Context, req *pb.DeleteDocumentRequest) (*emptypb.Empty, error) {
userClaims, err := s.checkPermission(ctx)
if err != nil {
return nil, status.Error(codes.PermissionDenied, err.Error())
}
err = s.dbModel.DeleteDocument(req.Id, userClaims.UserId, true)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &emptypb.Empty{}, nil
}
// ClearRecycleDocument 清空回收站文档
func (s *DocumentAPIService) ClearRecycleDocument(ctx context.Context, req *emptypb.Empty) (*emptypb.Empty, error) {
_, err := s.checkPermission(ctx)
if err != nil {
return nil, status.Error(codes.PermissionDenied, err.Error())
}
err = s.dbModel.ClearRecycleDocument()
if err != nil {
s.logger.Error("ClearRecycleDocument", zap.Error(err))
return nil, status.Error(codes.Internal, err.Error())
}
return &emptypb.Empty{}, nil
}
func (s *DocumentAPIService) listDocument(opt *model.OptionGetDocumentList) (*pb.ListDocumentReply, error) {
docs, total, err := s.dbModel.GetDocumentList(opt)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
var pbDocs []*pb.Document
err = util.CopyStruct(&docs, &pbDocs)
if err != nil {
s.logger.Error("CopyStruct failed", zap.Error(err))
}
var (
docCates []model.DocumentCategory
docUsers []model.User
docIndexMap = make(map[int64]int)
userIndexesMap = make(map[int64][]int)
deletedUserIndexMap = make(map[int64][]int)
docIds []int64
userIds []int64
)
for i, doc := range pbDocs {
docIndexMap[doc.Id] = i
userIndexesMap[doc.UserId] = append(userIndexesMap[doc.UserId], i)
docIds = append(docIds, doc.Id)
if doc.UserId > 0 {
userIds = append(userIds, doc.UserId)
}
if doc.DeletedUserId > 0 {
userIds = append(userIds, doc.DeletedUserId)
deletedUserIndexMap[doc.DeletedUserId] = append(deletedUserIndexMap[doc.DeletedUserId], i)
}
}
if len(pbDocs) > 0 {
docCates, _, _ = s.dbModel.GetDocumentCategoryList(&model.OptionGetDocumentCategoryList{
WithCount: false,
SelectFields: []string{"document_id", "category_id"},
QueryIn: map[string][]interface{}{"document_id": util.Slice2Interface(docIds)},
})
for _, docCate := range docCates {
pbDocs[docIndexMap[docCate.DocumentId]].CategoryId = append(pbDocs[docIndexMap[docCate.DocumentId]].CategoryId, docCate.CategoryId)
}
docUsers, _, _ = s.dbModel.GetUserList(&model.OptionGetUserList{
WithCount: false,
SelectFields: []string{"id", "username"},
QueryIn: map[string][]interface{}{"id": util.Slice2Interface(userIds)},
})
// 查找文档相关联的附件。对于列表只返回hash和id不返回其他字段
attachments, _, _ := s.dbModel.GetAttachmentList(&model.OptionGetAttachmentList{
WithCount: false,
SelectFields: []string{"hash", "id", "type_id"},
QueryIn: map[string][]interface{}{
"type_id": util.Slice2Interface(docIds),
"type": {model.AttachmentTypeDocument},
},
})
for _, attachment := range attachments {
index := docIndexMap[attachment.TypeId]
pbDocs[index].Attachment = &pb.Attachment{
Hash: attachment.Hash,
}
}
for _, docUser := range docUsers {
indexes := userIndexesMap[docUser.Id]
for _, index := range indexes {
pbDocs[index].Username = docUser.Username
}
indexes = deletedUserIndexMap[docUser.Id]
for _, index := range indexes {
pbDocs[index].DeletedUsername = docUser.Username
}
}
}
return &pb.ListDocumentReply{
Total: total,
Document: pbDocs,
}, nil
}
// SetDocumentRecommend 推荐文档
func (s *DocumentAPIService) SetDocumentRecommend(ctx context.Context, req *pb.SetDocumentRecommendRequest) (*emptypb.Empty, error) {
_, err := s.checkPermission(ctx)
if err != nil {
return nil, status.Error(codes.PermissionDenied, err.Error())
}
err = s.dbModel.SetDocumentRecommend(req.Id, req.Type)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &emptypb.Empty{}, nil
}
func (s *DocumentAPIService) ListDocumentForHome(ctx context.Context, req *pb.ListDocumentForHomeRequest) (*pb.ListDocumentForHomeResponse, error) {
// 1. 查询启用了的分类
categories, _, _ := s.dbModel.GetCategoryList(&model.OptionGetCategoryList{
WithCount: false,
QueryIn: map[string][]interface{}{
"enable": {true},
"parent_id": {0},
},
})
if len(categories) == 0 {
return &pb.ListDocumentForHomeResponse{}, nil
}
limit := 5
if req.Limit > 0 && req.Limit <= 100 {
limit = int(req.Limit)
}
resp := &pb.ListDocumentForHomeResponse{}
for _, category := range categories {
docs, _, _ := s.dbModel.GetDocumentList(&model.OptionGetDocumentList{
WithCount: false,
QueryIn: map[string][]interface{}{
"category_id": {category.Id},
},
Page: 1,
Size: limit,
Sort: []string{"id desc"},
SelectFields: []string{"id", "title", "ext"},
})
var pbDocs []*pb.Document
util.CopyStruct(&docs, &pbDocs)
resp.Document = append(resp.Document, &pb.ListDocumentForHomeItem{
CategoryId: category.Id,
CategoryName: category.Title,
CategoryCover: category.Cover,
Document: pbDocs,
})
}
return resp, nil
}
// 搜索文档
func (s *DocumentAPIService) SearchDocument(ctx context.Context, req *pb.SearchDocumentRequest) (res *pb.SearchDocumentReply, err error) {
res = &pb.SearchDocumentReply{}
now := time.Now()
opt := &model.OptionGetDocumentList{
WithCount: true,
Page: int(req.Page),
Size: int(req.Size_),
QueryIn: make(map[string][]interface{}),
}
opt.Size = util.LimitRange(opt.Size, 10, 10)
opt.Page = util.LimitRange(opt.Page, 1, 100)
if req.Wd == "" {
return res, nil
}
opt.QueryLike = map[string][]interface{}{
"title": util.Slice2Interface(strings.Split(req.Wd, " ")),
"keywords": util.Slice2Interface(strings.Split(req.Wd, " ")),
"description": util.Slice2Interface(strings.Split(req.Wd, " ")),
}
if len(req.CategoryId) > 0 {
opt.QueryIn = map[string][]interface{}{
"category_id": util.Slice2Interface(req.CategoryId),
}
}
if req.Ext != "" {
exts := filetil.GetExts(req.Ext)
if len(exts) > 0 {
opt.QueryIn["ext"] = util.Slice2Interface(exts)
}
}
if req.Sort != "" {
opt.Sort = []string{req.Sort}
}
docs, total, err := s.dbModel.GetDocumentList(opt)
if err != nil {
return res, status.Errorf(codes.Internal, "搜索文档失败:%s", err)
}
util.CopyStruct(&docs, &res.Document)
res.Total = total
res.Spend = fmt.Sprintf("%.3f", time.Since(now).Seconds())
return res, nil
}
// 下载文档
// 0. 查询用户是否登录
// 1. 查询文档是否存在
// 2. 查询用户是否购买和下载过
// 3. 查询文档是否免费
func (s *DocumentAPIService) DownloadDocument(ctx context.Context, req *pb.Document) (res *pb.DownloadDocumentReply, err error) {
cfg := s.dbModel.GetConfigOfDownload()
userClaims, err := s.checkLogin(ctx)
if err != nil && !cfg.EnableGuestDownload {
// 未登录且不允许游客下载
return res, status.Errorf(codes.Unauthenticated, err.Error())
}
var userId int64
if userClaims != nil {
userId = userClaims.UserId
}
ip := ""
ips, _ := util.GetGRPCRemoteIP(ctx)
if len(ips) > 0 {
ip = ips[0]
}
downloadIP := s.dbModel.CountDownloadTodayForIP(ip)
if downloadIP >= int64(cfg.TimesEveryIP) {
return res, status.Errorf(codes.PermissionDenied, "您所在IP今日下载次数已达上限(%d)", cfg.TimesEveryIP)
}
downloadUser := s.dbModel.CountDownloadTodayForUser(userId)
if downloadUser >= int64(cfg.TimesEveryDay) {
return res, status.Errorf(codes.PermissionDenied, "您的账户今日下载次数已达上限(%d)", cfg.TimesEveryDay)
}
// 查询文档存不存在
doc, err := s.dbModel.GetDocument(req.Id, "id", "price", "status", "title", "ext", "user_id")
if err != nil || doc.Status == model.DocumentStatusDisabled {
return res, status.Errorf(codes.NotFound, "文档不存在")
}
// 文档不免费且未登录
if doc.Price > 0 && userId == 0 {
return res, status.Errorf(codes.PermissionDenied, "付费文档,请先登录再下载")
}
// 查询附件存不存在
attachment := s.dbModel.GetAttachmentByTypeAndTypeId(model.AttachmentTypeDocument, doc.Id, "id", "hash")
if attachment.Id == 0 {
return res, status.Errorf(codes.NotFound, "附件不存在")
}
user, _ := s.dbModel.GetUser(userId)
if doc.UserId != userId && user.CreditCount < doc.Price {
return res, status.Errorf(codes.PermissionDenied, "魔豆不足,无法下载")
}
// 用户可以免费下载自己的文档
free := doc.UserId == userId || s.dbModel.CanIFreeDownload(userId, doc.Id)
down := &model.Download{
UserId: userId,
DocumentId: doc.Id,
Ip: ip,
IsPay: !free,
}
s.logger.Debug("下载文档", zap.Any("down", down), zap.Bool("canFreeDownload", free))
// 直接返回下载地址
err = s.dbModel.CreateDownload(down)
if err != nil {
return res, status.Errorf(codes.Internal, "创建下载失败:%s", err.Error())
}
link, err := s.generateDownloadURL(doc, cfg, attachment.Hash)
if err != nil {
return res, status.Errorf(codes.Internal, "生成下载地址失败:%s", err.Error())
}
res = &pb.DownloadDocumentReply{
Url: link,
}
return res, nil
}
// 通过JWT生成下载文档的URL
func (s *DocumentAPIService) generateDownloadURL(document model.Document, cfg model.ConfigDownload, hash string) (link string, err error) {
expiredAt := time.Now().Add(time.Second * time.Duration(cfg.UrlDuration)).Unix()
claims := jwt.StandardClaims{
ExpiresAt: expiredAt,
Id: hash,
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(cfg.SecretKey))
if err != nil {
return "", err
}
return fmt.Sprintf("/download/%s?filename=%s", tokenString, url.QueryEscape(document.Title+document.Ext)), nil
}
func (s *DocumentAPIService) GetRelatedDocuments(ctx context.Context, req *pb.Document) (res *pb.ListDocumentReply, err error) {
docs, _ := s.dbModel.GetRelatedDocuments(req.Id)
res = &pb.ListDocumentReply{}
util.CopyStruct(&docs, &res.Document)
return res, nil
}
// 获取文档评分
func (s *DocumentAPIService) GetDocumentScore(ctx context.Context, req *pb.DocumentScore) (res *pb.DocumentScore, err error) {
userClaims, err := s.checkLogin(ctx)
if err != nil {
return nil, err
}
score, _ := s.dbModel.GetDocumentScore(userClaims.UserId, req.DocumentId)
res = &pb.DocumentScore{}
util.CopyStruct(&score, res)
return res, nil
}
// 设置文档评分
func (s *DocumentAPIService) SetDocumentScore(ctx context.Context, req *pb.DocumentScore) (res *emptypb.Empty, err error) {
userClaims, err := s.checkLogin(ctx)
if err != nil {
return nil, err
}
score, _ := s.dbModel.GetDocumentScore(userClaims.UserId, req.DocumentId)
if score.Id > 0 {
return nil, status.Errorf(codes.PermissionDenied, "您已经评分过了")
}
score = model.DocumentScore{
UserId: userClaims.UserId,
DocumentId: req.DocumentId,
Score: int(req.Score),
}
err = s.dbModel.CreateDocumentScore(&score)
if err != nil {
return nil, status.Errorf(codes.Internal, "评分失败:%s", err.Error())
}
return &emptypb.Empty{}, nil
}