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.

168 lines
4.7 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"
pb "moredoc/api/v1"
"moredoc/middleware/auth"
"moredoc/model"
"moredoc/util"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
"gorm.io/gorm"
)
type ArticleAPIService struct {
pb.UnimplementedArticleAPIServer
dbModel *model.DBModel
logger *zap.Logger
}
func NewArticleAPIService(dbModel *model.DBModel, logger *zap.Logger) (service *ArticleAPIService) {
return &ArticleAPIService{dbModel: dbModel, logger: logger.Named("ArticleAPIService")}
}
func (s *ArticleAPIService) checkPermission(ctx context.Context) (userClaims *auth.UserClaims, err error) {
return checkGRPCPermission(s.dbModel, ctx)
}
// CreateArticle 创建文章
func (s *ArticleAPIService) CreateArticle(ctx context.Context, req *pb.Article) (*emptypb.Empty, error) {
_, err := s.checkPermission(ctx)
if err != nil {
return nil, err
}
existArticle, _ := s.dbModel.GetArticleByIdentifier(req.Identifier, "id")
if existArticle.Id > 0 {
return nil, status.Errorf(codes.AlreadyExists, "文章标识符已存在")
}
article := &model.Article{}
err = util.CopyStruct(req, article)
if err != nil {
s.logger.Error("CreateArticle", zap.Error(err))
return nil, status.Errorf(codes.Internal, "创建文章失败")
}
err = s.dbModel.CreateArticle(article)
if err != nil {
s.logger.Error("CreateArticle", zap.Error(err))
return nil, status.Errorf(codes.Internal, "创建文章失败")
}
return &emptypb.Empty{}, nil
}
// UpdateArticle 更新文章。注意不支持更新identifier
func (s *ArticleAPIService) UpdateArticle(ctx context.Context, req *pb.Article) (*emptypb.Empty, error) {
_, err := s.checkPermission(ctx)
if err != nil {
return nil, err
}
article := &model.Article{}
err = util.CopyStruct(req, article)
if err != nil {
s.logger.Error("UpdateArticle", zap.Error(err))
return nil, status.Errorf(codes.Internal, "更新文章失败")
}
err = s.dbModel.UpdateArticle(article)
if err != nil {
s.logger.Error("UpdateArticle", zap.Error(err))
return nil, status.Errorf(codes.Internal, "更新文章失败")
}
return &emptypb.Empty{}, nil
}
// DeleteArticle 删除文章
func (s *ArticleAPIService) DeleteArticle(ctx context.Context, req *pb.DeleteArticleRequest) (*emptypb.Empty, error) {
_, err := s.checkPermission(ctx)
if err != nil {
return nil, err
}
err = s.dbModel.DeleteArticle(req.Id)
if err != nil {
s.logger.Error("DeleteArticle", zap.Error(err))
return nil, status.Errorf(codes.Internal, "删除文章失败")
}
return &emptypb.Empty{}, nil
}
// GetArticle 根据id或文章标识获取文章
// 不需要鉴权
func (s *ArticleAPIService) GetArticle(ctx context.Context, req *pb.GetArticleRequest) (*pb.Article, error) {
var (
article model.Article
err error
)
if req.Id > 0 {
article, err = s.dbModel.GetArticle(req.Id)
if err != nil && err != gorm.ErrRecordNotFound {
s.logger.Error("GetArticle", zap.Error(err))
return nil, status.Errorf(codes.Internal, "获取文章失败")
}
} else {
article, err = s.dbModel.GetArticleByIdentifier(req.Identifier)
if err != nil && err != gorm.ErrRecordNotFound {
s.logger.Error("GetArticle", zap.Error(err))
return nil, status.Errorf(codes.Internal, "获取文章失败")
}
article.ViewCount += 1
s.dbModel.UpdateArticleViewCount(article.Id, article.ViewCount)
}
if article.Id == 0 {
return nil, status.Errorf(codes.NotFound, "文章不存在")
}
pbArticle := &pb.Article{}
util.CopyStruct(article, pbArticle)
return pbArticle, nil
}
// ListArticles 获取文章列表。
// 如果是有权限,则可以根据关键字来查询,否则只能简单查询
func (s *ArticleAPIService) ListArticle(ctx context.Context, req *pb.ListArticleRequest) (*pb.ListArticleReply, error) {
opt := &model.OptionGetArticleList{
Page: int(req.Page),
Size: int(req.Size_),
WithCount: true,
QueryLike: make(map[string][]interface{}),
Sort: []string{req.Order},
}
_, err := s.checkPermission(ctx)
if err == nil && req.Wd != "" {
opt.QueryLike["title"] = []interface{}{req.Wd}
opt.QueryLike["keywords"] = []interface{}{req.Wd}
opt.QueryLike["description"] = []interface{}{req.Wd}
opt.QueryLike["content"] = []interface{}{req.Wd}
}
articles, total, err := s.dbModel.GetArticleList(opt)
if err != nil && err != gorm.ErrRecordNotFound {
s.logger.Error("ListArticle", zap.Error(err))
return nil, status.Errorf(codes.Internal, "获取文章列表失败")
}
var pbArticle []*pb.Article
err = util.CopyStruct(articles, &pbArticle)
if err != nil {
s.logger.Error("ListArticle", zap.Error(err))
return nil, status.Errorf(codes.Internal, "获取文章列表失败"+err.Error())
}
return &pb.ListArticleReply{
Total: total,
Article: pbArticle,
}, nil
}