作者 tangxvhui

更新接口

@@ -30,6 +30,10 @@ service Core { @@ -30,6 +30,10 @@ service Core {
30 @handler MiniSetUserLike 30 @handler MiniSetUserLike
31 post /article/user_like/set (MiniSetUserLikeRequset) returns (MiniSetUserLikeResponse) 31 post /article/user_like/set (MiniSetUserLikeRequset) returns (MiniSetUserLikeResponse)
32 32
  33 + @doc "小程序标记当前人员查看的文章"
  34 + @handler MiniArticleMarkUserRead
  35 + post /article/mark/user_read (MiniArticleMarkUserReadRequest) returns (MiniArticleMarkUserReadResponse)
  36 +
33 @doc "小程序获取我发布的文章" 37 @doc "小程序获取我发布的文章"
34 @handler MiniArticleSearchMe 38 @handler MiniArticleSearchMe
35 post /article/search/me (MiniArticleSearchMeRequest) returns (MiniArticleSearchMeResponse) 39 post /article/search/me (MiniArticleSearchMeRequest) returns (MiniArticleSearchMeResponse)
@@ -148,6 +148,18 @@ type ( @@ -148,6 +148,18 @@ type (
148 } 148 }
149 ) 149 )
150 150
  151 +type (
  152 + MiniArticleMarkUserReadRequest {
  153 + UserId int64 `json:",optional"` // 当前操作人
  154 + CompanyId int64 `json:",optional"` // 当前公司
  155 + ArticleId int64 `json:"articleId"` // 文章id
  156 + }
  157 +
  158 + MiniArticleMarkUserReadResponse {
  159 + Id int64 `json:"id"`
  160 + }
  161 +)
  162 +
151 //管理后台获取文章详情 163 //管理后台获取文章详情
152 type ( 164 type (
153 SystemArticleGetRequest { 165 SystemArticleGetRequest {
  1 +package article
  2 +
  3 +import (
  4 + "net/http"
  5 +
  6 + "github.com/zeromicro/go-zero/rest/httpx"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/article"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/contextdata"
  11 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/result"
  12 +)
  13 +
  14 +// 标记人员当前浏览的文章
  15 +func MiniArticleMarkUserReadHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  16 + return func(w http.ResponseWriter, r *http.Request) {
  17 + var req types.MiniArticleMarkUserReadRequest
  18 + if err := httpx.Parse(r, &req); err != nil {
  19 + httpx.ErrorCtx(r.Context(), w, err)
  20 + return
  21 + }
  22 +
  23 + l := article.NewMiniArticleMarkUserReadLogic(r.Context(), svcCtx)
  24 + token := contextdata.GetUserTokenFromCtx(r.Context())
  25 + req.CompanyId = token.CompanyId
  26 + req.UserId = token.UserId
  27 + resp, err := l.MiniArticleMarkUserRead(&req)
  28 + result.HttpResult(r, w, resp, err)
  29 + }
  30 +}
@@ -210,6 +210,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { @@ -210,6 +210,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
210 }, 210 },
211 { 211 {
212 Method: http.MethodPost, 212 Method: http.MethodPost,
  213 + Path: "/article/mark/user_read",
  214 + Handler: article.MiniArticleMarkUserReadHandler(serverCtx),
  215 + },
  216 + {
  217 + Method: http.MethodPost,
213 Path: "/article/search/me", 218 Path: "/article/search/me",
214 Handler: article.MiniArticleSearchMeHandler(serverCtx), 219 Handler: article.MiniArticleSearchMeHandler(serverCtx),
215 }, 220 },
  1 +package article
  2 +
  3 +import (
  4 + "context"
  5 +
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/transaction"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/xerr"
  11 +
  12 + "github.com/zeromicro/go-zero/core/logx"
  13 +)
  14 +
  15 +type MiniArticleMarkUserReadLogic struct {
  16 + logx.Logger
  17 + ctx context.Context
  18 + svcCtx *svc.ServiceContext
  19 +}
  20 +
  21 +func NewMiniArticleMarkUserReadLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MiniArticleMarkUserReadLogic {
  22 + return &MiniArticleMarkUserReadLogic{
  23 + Logger: logx.WithContext(ctx),
  24 + ctx: ctx,
  25 + svcCtx: svcCtx,
  26 + }
  27 +}
  28 +
  29 +func (l *MiniArticleMarkUserReadLogic) MiniArticleMarkUserRead(req *types.MiniArticleMarkUserReadRequest) (resp *types.MiniArticleMarkUserReadResponse, err error) {
  30 + var conn = l.svcCtx.DefaultDBConn()
  31 +
  32 + articleData, err := l.svcCtx.ArticleRepository.FindOne(l.ctx, conn, req.ArticleId)
  33 + if err != nil {
  34 + return nil, xerr.NewErrMsgErr("标记浏览记录失败", err)
  35 + }
  36 +
  37 + if articleData.CompanyId != req.CompanyId {
  38 + return nil, xerr.NewErrMsg("标记浏览记录失败")
  39 + }
  40 +
  41 + //查找旧的记录
  42 + queryOption := domain.NewQueryOptions().
  43 + WithFindOnly().
  44 + WithOffsetLimit(1, 1).
  45 + MustWithKV("articleId", req.ArticleId).
  46 + MustWithKV("userId", req.UserId)
  47 +
  48 + _, markRecord, err := l.svcCtx.UserReadArticleRepository.Find(l.ctx, conn, queryOption)
  49 + if err != nil {
  50 + return nil, xerr.NewErrMsgErr("标记浏览记录失败", err)
  51 + }
  52 + if len(markRecord) > 0 {
  53 + _, err = l.svcCtx.UserReadArticleRepository.Update(l.ctx, conn, markRecord[0])
  54 + if err != nil {
  55 + return nil, xerr.NewErrMsgErr("标记浏览记录失败", err)
  56 + }
  57 + resp = &types.MiniArticleMarkUserReadResponse{Id: markRecord[0].Id}
  58 + return resp, nil
  59 + }
  60 + // 新建一个标记
  61 +
  62 + articleInfo, err := l.svcCtx.ArticleRepository.FindOne(l.ctx, conn, req.ArticleId)
  63 + if err != nil {
  64 + return nil, xerr.NewErrMsgErr("标记浏览记录失败", err)
  65 + }
  66 + if articleInfo.CompanyId != req.CompanyId {
  67 + return nil, xerr.NewErrMsg("标记浏览记录失败")
  68 + }
  69 + newMark := domain.UserReadArticle{
  70 + Id: 0,
  71 + CompanyId: req.CompanyId,
  72 + UserId: req.UserId,
  73 + ArticleId: articleData.Id,
  74 + Title: articleData.Title,
  75 + Author: articleData.Author,
  76 + CreatedAt: 0,
  77 + UpdatedAt: 0,
  78 + DeletedAt: 0,
  79 + Version: 0,
  80 + }
  81 + err = transaction.UseTrans(l.ctx, conn.DB(), func(ctx context.Context, c transaction.Conn) error {
  82 + _, err = l.svcCtx.UserReadArticleRepository.Insert(ctx, c, &newMark)
  83 + if err != nil {
  84 + return err
  85 + }
  86 + err = l.svcCtx.ArticleRepository.IncreaseCountRead(ctx, c, 1, articleInfo)
  87 + return err
  88 + }, true)
  89 + if err != nil {
  90 + return nil, xerr.NewErrMsg("标记浏览记录失败")
  91 + }
  92 + resp = &types.MiniArticleMarkUserReadResponse{Id: newMark.Id}
  93 + return
  94 +}
@@ -194,7 +194,7 @@ func (l *MiniSetUserLikeLogic) setUserLikeArticle(req *types.MiniSetUserLikeRequ @@ -194,7 +194,7 @@ func (l *MiniSetUserLikeLogic) setUserLikeArticle(req *types.MiniSetUserLikeRequ
194 // 检查id 194 // 检查id
195 userInfo, err := l.svcCtx.UserRepository.FindOne(l.ctx, conn, req.UserId) 195 userInfo, err := l.svcCtx.UserRepository.FindOne(l.ctx, conn, req.UserId)
196 if err != nil { 196 if err != nil {
197 - //无法确认 文章的id 197 + //无法确认 操作人id
198 return nil, xerr.NewErrMsgErr("无法确认操作人员信息", err) 198 return nil, xerr.NewErrMsgErr("无法确认操作人员信息", err)
199 } 199 }
200 articleInfo, err := l.svcCtx.ArticleRepository.FindOne(l.ctx, conn, req.ArticleId) 200 articleInfo, err := l.svcCtx.ArticleRepository.FindOne(l.ctx, conn, req.ArticleId)
@@ -31,6 +31,7 @@ type ServiceContext struct { @@ -31,6 +31,7 @@ type ServiceContext struct {
31 RoleRepository domain.RoleRepository 31 RoleRepository domain.RoleRepository
32 UserFollowRepository domain.UserFollowRepository 32 UserFollowRepository domain.UserFollowRepository
33 UserLoveFlagRepository domain.UserLoveFlagRepository 33 UserLoveFlagRepository domain.UserLoveFlagRepository
  34 + UserReadArticleRepository domain.UserReadArticleRepository
34 UserRepository domain.UserRepository 35 UserRepository domain.UserRepository
35 } 36 }
36 37
@@ -59,6 +60,7 @@ func NewServiceContext(c config.Config) *ServiceContext { @@ -59,6 +60,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
59 UserFollowRepository: repository.NewUserFollowRepository(cache.NewCachedRepository(mlCache)), 60 UserFollowRepository: repository.NewUserFollowRepository(cache.NewCachedRepository(mlCache)),
60 UserLoveFlagRepository: repository.NewUserLoveFlagRepository(cache.NewCachedRepository(mlCache)), 61 UserLoveFlagRepository: repository.NewUserLoveFlagRepository(cache.NewCachedRepository(mlCache)),
61 UserRepository: repository.NewUserRepository(cache.NewCachedRepository(mlCache)), 62 UserRepository: repository.NewUserRepository(cache.NewCachedRepository(mlCache)),
  63 + UserReadArticleRepository: repository.NewUserReadArticleRepository(cache.NewCachedRepository(mlCache)),
62 ArticleTagRepository: repository.NewArticleTagRepository(cache.NewCachedRepository(mlCache)), 64 ArticleTagRepository: repository.NewArticleTagRepository(cache.NewCachedRepository(mlCache)),
63 } 65 }
64 } 66 }
@@ -449,6 +449,16 @@ type MiniArticleBackupItem struct { @@ -449,6 +449,16 @@ type MiniArticleBackupItem struct {
449 Location Location `json:"location"` 449 Location Location `json:"location"`
450 } 450 }
451 451
  452 +type MiniArticleMarkUserReadRequest struct {
  453 + UserId int64 `json:",optional"` // 当前操作人
  454 + CompanyId int64 `json:",optional"` // 当前公司
  455 + ArticleId int64 `json:"articleId"` // 文章id
  456 +}
  457 +
  458 +type MiniArticleMarkUserReadResponse struct {
  459 + Id int64 `json:"id"`
  460 +}
  461 +
452 type SystemArticleGetRequest struct { 462 type SystemArticleGetRequest struct {
453 Id int64 `path:"id"` //id 463 Id int64 `path:"id"` //id
454 CompanyId int64 `path:",optional"` 464 CompanyId int64 `path:",optional"`
@@ -14,6 +14,7 @@ func Migrate(db *gorm.DB) { @@ -14,6 +14,7 @@ func Migrate(db *gorm.DB) {
14 &models.ArticleComment{}, 14 &models.ArticleComment{},
15 &models.ArticleTag{}, 15 &models.ArticleTag{},
16 &models.UserLoveFlag{}, 16 &models.UserLoveFlag{},
  17 + &models.UserReadArticle{},
17 &models.User{}, 18 &models.User{},
18 &models.Role{}, 19 &models.Role{},
19 &models.Company{}, 20 &models.Company{},
  1 +package models
  2 +
  3 +import (
  4 + "fmt"
  5 + "time"
  6 +
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
  8 + "gorm.io/gorm"
  9 +)
  10 +
  11 +type UserReadArticle struct {
  12 + Id int64 `gorm:"primaryKey"` // 唯一标识
  13 + CreatedAt int64
  14 + UpdatedAt int64
  15 + DeletedAt int64
  16 + Version int
  17 + CompanyId int64
  18 + UserId int64
  19 + ArticleId int64
  20 + Title string
  21 + Author domain.UserSimple `gorm:"type:jsonb;serializer:json"` // 发布人
  22 +}
  23 +
  24 +func (m *UserReadArticle) TableName() string {
  25 + return "user_read_article"
  26 +}
  27 +
  28 +func (m *UserReadArticle) BeforeCreate(tx *gorm.DB) (err error) {
  29 + nowTime := time.Now().Unix()
  30 + m.CreatedAt = nowTime
  31 + m.UpdatedAt = nowTime
  32 + return
  33 +}
  34 +
  35 +func (m *UserReadArticle) BeforeUpdate(tx *gorm.DB) (err error) {
  36 + m.UpdatedAt = time.Now().Unix()
  37 + return
  38 +}
  39 +
  40 +func (m *UserReadArticle) CacheKeyFunc() string {
  41 + if m.Id == 0 {
  42 + return ""
  43 + }
  44 + return fmt.Sprintf("%v:cache:%v:id:%v", domain.ProjectName, m.TableName(), m.Id)
  45 +}
  46 +
  47 +func (m *UserReadArticle) CacheKeyFuncByObject(obj interface{}) string {
  48 + if v, ok := obj.(*UserReadArticle); ok {
  49 + return v.CacheKeyFunc()
  50 + }
  51 + return ""
  52 +}
  53 +
  54 +func (m *UserReadArticle) CachePrimaryKeyFunc() string {
  55 + if len("") == 0 {
  56 + return ""
  57 + }
  58 + return fmt.Sprintf("%v:cache:%v:primarykey:%v", domain.ProjectName, m.TableName(), "key")
  59 +}
  1 +package repository
  2 +
  3 +import (
  4 + "context"
  5 +
  6 + "github.com/jinzhu/copier"
  7 + "github.com/pkg/errors"
  8 + "github.com/tiptok/gocomm/pkg/cache"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/models"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/transaction"
  11 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
  12 + "gorm.io/gorm"
  13 +)
  14 +
  15 +type UserReadArticleRepository struct {
  16 + *cache.CachedRepository
  17 +}
  18 +
  19 +func (repository *UserReadArticleRepository) Insert(ctx context.Context, conn transaction.Conn, dm *domain.UserReadArticle) (*domain.UserReadArticle, error) {
  20 + var (
  21 + err error
  22 + m = &models.UserReadArticle{}
  23 + tx = conn.DB()
  24 + )
  25 + if m, err = repository.DomainModelToModel(dm); err != nil {
  26 + return nil, err
  27 + }
  28 + if tx = tx.Model(m).Save(m); tx.Error != nil {
  29 + return nil, tx.Error
  30 + }
  31 + dm.Id = m.Id
  32 + return repository.ModelToDomainModel(m)
  33 +
  34 +}
  35 +
  36 +func (repository *UserReadArticleRepository) Update(ctx context.Context, conn transaction.Conn, dm *domain.UserReadArticle) (*domain.UserReadArticle, error) {
  37 + var (
  38 + err error
  39 + m *models.UserReadArticle
  40 + tx = conn.DB()
  41 + )
  42 + if m, err = repository.DomainModelToModel(dm); err != nil {
  43 + return nil, err
  44 + }
  45 + queryFunc := func() (interface{}, error) {
  46 + tx = tx.Model(m).Updates(m)
  47 + return nil, tx.Error
  48 + }
  49 + if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
  50 + return nil, err
  51 + }
  52 + return repository.ModelToDomainModel(m)
  53 +}
  54 +
  55 +func (repository *UserReadArticleRepository) UpdateWithVersion(ctx context.Context, transaction transaction.Conn, dm *domain.UserReadArticle) (*domain.UserReadArticle, error) {
  56 + var (
  57 + err error
  58 + m *models.UserReadArticle
  59 + tx = transaction.DB()
  60 + )
  61 + if m, err = repository.DomainModelToModel(dm); err != nil {
  62 + return nil, err
  63 + }
  64 + oldVersion := dm.Version
  65 + m.Version += 1
  66 + queryFunc := func() (interface{}, error) {
  67 + tx = tx.Model(m).Select("*").Where("id = ?", m.Id).Where("version = ?", oldVersion).Updates(m)
  68 + if tx.RowsAffected == 0 {
  69 + return nil, domain.ErrUpdateFail
  70 + }
  71 + return nil, tx.Error
  72 + }
  73 + if _, err = repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
  74 + return nil, err
  75 + }
  76 + return repository.ModelToDomainModel(m)
  77 +}
  78 +
  79 +func (repository *UserReadArticleRepository) Delete(ctx context.Context, conn transaction.Conn, dm *domain.UserReadArticle) (*domain.UserReadArticle, error) {
  80 + var (
  81 + tx = conn.DB()
  82 + m = &models.UserReadArticle{Id: dm.Id}
  83 + )
  84 + queryFunc := func() (interface{}, error) {
  85 + tx = tx.Where("id = ?", m.Id).Delete(m)
  86 + return m, tx.Error
  87 + }
  88 + if _, err := repository.Query(queryFunc, m.CacheKeyFunc()); err != nil {
  89 + return dm, err
  90 + }
  91 + return repository.ModelToDomainModel(m)
  92 +}
  93 +
  94 +func (repository *UserReadArticleRepository) FindOne(ctx context.Context, conn transaction.Conn, id int64) (*domain.UserReadArticle, error) {
  95 + var (
  96 + err error
  97 + tx = conn.DB()
  98 + m = new(models.UserReadArticle)
  99 + )
  100 + queryFunc := func() (interface{}, error) {
  101 + tx = tx.Model(m).Where("id = ?", id).First(m)
  102 + if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
  103 + return nil, domain.ErrNotFound
  104 + }
  105 + return m, tx.Error
  106 + }
  107 + cacheModel := new(models.UserReadArticle)
  108 + cacheModel.Id = id
  109 + if err = repository.QueryCache(cacheModel.CacheKeyFunc, m, queryFunc); err != nil {
  110 + return nil, err
  111 + }
  112 + return repository.ModelToDomainModel(m)
  113 +}
  114 +
  115 +func (repository *UserReadArticleRepository) Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*domain.UserReadArticle, error) {
  116 + var (
  117 + tx = conn.DB()
  118 + ms []*models.UserReadArticle
  119 + dms = make([]*domain.UserReadArticle, 0)
  120 + total int64
  121 + )
  122 + queryFunc := func() (interface{}, error) {
  123 + tx = tx.Model(&ms).Order("id desc")
  124 + if v, ok := queryOptions["userId"]; ok {
  125 + tx = tx.Where("user_id=?", v)
  126 + }
  127 + if v, ok := queryOptions["articleId"]; ok {
  128 + tx = tx.Where("article_id=?", v)
  129 + }
  130 + if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
  131 + return dms, tx.Error
  132 + }
  133 + return dms, nil
  134 + }
  135 +
  136 + if _, err := repository.Query(queryFunc); err != nil {
  137 + return 0, nil, err
  138 + }
  139 +
  140 + for _, item := range ms {
  141 + if dm, err := repository.ModelToDomainModel(item); err != nil {
  142 + return 0, dms, err
  143 + } else {
  144 + dms = append(dms, dm)
  145 + }
  146 + }
  147 + return total, dms, nil
  148 +}
  149 +
  150 +func (repository *UserReadArticleRepository) ModelToDomainModel(from *models.UserReadArticle) (*domain.UserReadArticle, error) {
  151 + to := &domain.UserReadArticle{}
  152 + err := copier.Copy(to, from)
  153 + return to, err
  154 +}
  155 +
  156 +func (repository *UserReadArticleRepository) DomainModelToModel(from *domain.UserReadArticle) (*models.UserReadArticle, error) {
  157 + to := &models.UserReadArticle{}
  158 + err := copier.Copy(to, from)
  159 + return to, err
  160 +}
  161 +
  162 +func NewUserReadArticleRepository(cache *cache.CachedRepository) domain.UserReadArticleRepository {
  163 + return &UserReadArticleRepository{CachedRepository: cache}
  164 +}
@@ -38,3 +38,11 @@ type UserSimple struct { @@ -38,3 +38,11 @@ type UserSimple struct {
38 Company string `json:"company,omitempty"` // 公司 38 Company string `json:"company,omitempty"` // 公司
39 CompanyId int64 `json:"companyId"` 39 CompanyId int64 `json:"companyId"`
40 } 40 }
  41 +
  42 +// 记录数据的操作人
  43 +// type Operator struct {
  44 +// From string `json:"from"` // 操作来源
  45 +// Id int `json:"id"` // 人员id
  46 +// Name string `json:"name"` // 人员名字
  47 +// UpdatedAt int64 `json:"updatedAt"` // 时间
  48 +// }
@@ -11,6 +11,7 @@ import ( @@ -11,6 +11,7 @@ import (
11 11
12 type UserReadArticle struct { 12 type UserReadArticle struct {
13 Id int64 `json:"id"` 13 Id int64 `json:"id"`
  14 + CompanyId int64 `json:"companyId"`
14 UserId int64 `json:"userId"` 15 UserId int64 `json:"userId"`
15 ArticleId int64 `json:"articleId"` 16 ArticleId int64 `json:"articleId"`
16 Title string `json:"title"` 17 Title string `json:"title"`