作者 yangfu

用户关注

@@ -16,7 +16,7 @@ info( @@ -16,7 +16,7 @@ info(
16 service Core { 16 service Core {
17 @doc "用户申请加入公司" 17 @doc "用户申请加入公司"
18 @handler miniUserApplyJoinCompany 18 @handler miniUserApplyJoinCompany
19 - post /mini/user/apply-join-company(MiniUserApplyJoinCompanyRequest) returns (MiniUserApplyJoinCompanyResponse) 19 + post /mini/user/apply_join_company(MiniUserApplyJoinCompanyRequest) returns (MiniUserApplyJoinCompanyResponse)
20 @doc "用户登录" 20 @doc "用户登录"
21 @handler miniUserLogin 21 @handler miniUserLogin
22 post /mini/user/login (MiniUserLoginRequest) returns (MiniUserLoginResponse) 22 post /mini/user/login (MiniUserLoginRequest) returns (MiniUserLoginResponse)
@@ -29,7 +29,7 @@ service Core { @@ -29,7 +29,7 @@ service Core {
29 service Core { 29 service Core {
30 @doc "切换账号" 30 @doc "切换账号"
31 @handler miniUserSwitchAccount 31 @handler miniUserSwitchAccount
32 - post /mini/user/switch-account (MiniUserSwitchAccountRequest) returns (MiniUserLoginResponse) 32 + post /mini/user/switch_account (MiniUserSwitchAccountRequest) returns (MiniUserLoginResponse)
33 @doc "用户信息" 33 @doc "用户信息"
34 @handler miniUserInfo 34 @handler miniUserInfo
35 post /mini/user/info (MiniUserInfoRequest) returns (MiniUserInfoResponse) 35 post /mini/user/info (MiniUserInfoRequest) returns (MiniUserInfoResponse)
@@ -38,22 +38,31 @@ service Core { @@ -38,22 +38,31 @@ service Core {
38 post /mini/user/statistics (UserStatisticsRequest) returns (UserStatisticsResponse) 38 post /mini/user/statistics (UserStatisticsRequest) returns (UserStatisticsResponse)
39 @doc "用户审核列表" 39 @doc "用户审核列表"
40 @handler miniUserAuditList 40 @handler miniUserAuditList
41 - post /mini/user/audit-list (UserSearchRequest)returns(UserSearchResponse) 41 + post /mini/user/audit_list (UserSearchRequest)returns(UserSearchResponse)
42 @doc "用户审核" 42 @doc "用户审核"
43 @handler miniUserAudit 43 @handler miniUserAudit
44 post /mini/user/audit (MiniUserAuditRequest) 44 post /mini/user/audit (MiniUserAuditRequest)
45 @doc "部门用户列表" 45 @doc "部门用户列表"
46 @handler miniUserDepartmentUsers 46 @handler miniUserDepartmentUsers
47 - post /mini/user/department-users (MiniUserDepartmentUsersRequest) 47 + post /mini/user/department_users (MiniUserDepartmentUsersRequest)
48 @doc "用户列表" 48 @doc "用户列表"
49 @handler miniUsersList 49 @handler miniUsersList
50 - post /mini/user/user-list (MiniUsersListRequest) 50 + post /mini/user/user_list (MiniUsersListRequest)
  51 + @doc "用户快讯"
  52 + @handler miniUserNews
  53 + post /mini/user/news (MiniUserNewsRequest)returns(MiniUserNewsResposne)
51 @doc "关注我的人" 54 @doc "关注我的人"
52 @handler miniUserFollower 55 @handler miniUserFollower
53 post /mini/user/follower (MiniUserFollowedSearchRequest)returns(MiniUserFollowedSearchResponse) 56 post /mini/user/follower (MiniUserFollowedSearchRequest)returns(MiniUserFollowedSearchResponse)
54 @doc "我关注的人" 57 @doc "我关注的人"
55 @handler miniUserFollowing 58 @handler miniUserFollowing
56 post /mini/user/following (MiniUserFollowedSearchRequest)returns(MiniUserFollowedSearchResponse) 59 post /mini/user/following (MiniUserFollowedSearchRequest)returns(MiniUserFollowedSearchResponse)
  60 + @doc "我关注的人-最新未读列表(未读标红)"
  61 + @handler miniUserFollowingLatestUnreadList
  62 + post /mini/user/following/latest_unread_list (MiniUserFollowedSearchRequest)returns(MiniUserFollowedSearchResponse)
  63 + @doc "我关注的人-标记已读"
  64 + @handler miniUserFollowingMarkRead
  65 + post /mini/user/following/mark_read (MiniUserFollowingMarkReadRequest)
57 @doc "关注" 66 @doc "关注"
58 @handler miniUserFollow 67 @handler miniUserFollow
59 post /mini/user/follow (FollowRequest) 68 post /mini/user/follow (FollowRequest)
@@ -115,6 +124,23 @@ type( @@ -115,6 +124,23 @@ type(
115 ArticleId int64 `json:"articleId,optional"` // 按文章ID(返回文章可见的用户) 124 ArticleId int64 `json:"articleId,optional"` // 按文章ID(返回文章可见的用户)
116 RoleId int64 `json:"roleId,optional"` // 按角色角色关联的用户 125 RoleId int64 `json:"roleId,optional"` // 按角色角色关联的用户
117 } 126 }
  127 + MiniUserNewsRequest{
  128 + AuthorId int64 `json:"authorId,optional"` // 特定作者ID
  129 + LastArticleId int64 `json:"lastArticleId,optional"`// 最后文章ID
  130 + Size int `json:"size"` // 数量
  131 + }
  132 + MiniUserNewsResposne{
  133 + List []UserNewsItem `json:"list"`
  134 + Total int64 `json:"total"`
  135 + }
  136 + UserNewsItem{
  137 + NewsId int64 `json:"newsId"` // 快讯ID
  138 + Type string `json:"type"` // 快讯类型 文章:Article 讨论:Discuss ...
  139 + Title string `json:"title"` // 标题
  140 + Summary string `json:"summary"` // 快讯概要
  141 + Time int64 `json:"time"` // 时间
  142 + ReadFlag bool `json:"readFlag"` // 已读标识 true:已读 false:未读
  143 + }
118 MiniUserFollowedSearchRequest{ 144 MiniUserFollowedSearchRequest{
119 Page int `json:"page,optional"` 145 Page int `json:"page,optional"`
120 Size int `json:"size,optional"` 146 Size int `json:"size,optional"`
@@ -123,6 +149,11 @@ type( @@ -123,6 +149,11 @@ type(
123 List []*UserFollowItem `json:"users"` 149 List []*UserFollowItem `json:"users"`
124 Total int64 `json:"total"` 150 Total int64 `json:"total"`
125 } 151 }
  152 +
  153 + MiniUserFollowingMarkReadRequest{
  154 + UserId int64 `json:"userId"`
  155 + }
  156 +
126 UserItem { 157 UserItem {
127 Id int64 `json:"id,omitempty"` // 用户ID 158 Id int64 `json:"id,omitempty"` // 用户ID
128 CompanyId int64 `json:"companyId,omitempty"` // 公司ID 159 CompanyId int64 `json:"companyId,omitempty"` // 公司ID
@@ -176,6 +207,7 @@ type( @@ -176,6 +207,7 @@ type(
176 Position string `json:"position"` // 职位 207 Position string `json:"position"` // 职位
177 Followed bool `json:"followed"` // 关注 208 Followed bool `json:"followed"` // 关注
178 MutualFollowed bool `json:"mutualFollowed"` // 互相关注标识 209 MutualFollowed bool `json:"mutualFollowed"` // 互相关注标识
  210 + ReadFlag bool `json:"readFlag"` // 已读标识 true:已读 false:未读(小红点)
179 } 211 }
180 ) 212 )
181 213
@@ -229,7 +261,7 @@ service Core { @@ -229,7 +261,7 @@ service Core {
229 post /system/user/statistics (UserStatisticsRequest) returns (UserStatisticsResponse) 261 post /system/user/statistics (UserStatisticsRequest) returns (UserStatisticsResponse)
230 @doc "用户列表" 262 @doc "用户列表"
231 @handler systemUsersList 263 @handler systemUsersList
232 - post /system/user/user-list (MiniUsersListRequest) 264 + post /system/user/user_list (MiniUsersListRequest)
233 265
234 @doc "用户详情" 266 @doc "用户详情"
235 @handler systemUserGet 267 @handler systemUserGet
@@ -123,7 +123,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { @@ -123,7 +123,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
123 []rest.Route{ 123 []rest.Route{
124 { 124 {
125 Method: http.MethodPost, 125 Method: http.MethodPost,
126 - Path: "/mini/user/apply-join-company", 126 + Path: "/mini/user/apply_join_company",
127 Handler: user.MiniUserApplyJoinCompanyHandler(serverCtx), 127 Handler: user.MiniUserApplyJoinCompanyHandler(serverCtx),
128 }, 128 },
129 { 129 {
@@ -139,7 +139,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { @@ -139,7 +139,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
139 []rest.Route{ 139 []rest.Route{
140 { 140 {
141 Method: http.MethodPost, 141 Method: http.MethodPost,
142 - Path: "/mini/user/switch-account", 142 + Path: "/mini/user/switch_account",
143 Handler: user.MiniUserSwitchAccountHandler(serverCtx), 143 Handler: user.MiniUserSwitchAccountHandler(serverCtx),
144 }, 144 },
145 { 145 {
@@ -154,7 +154,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { @@ -154,7 +154,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
154 }, 154 },
155 { 155 {
156 Method: http.MethodPost, 156 Method: http.MethodPost,
157 - Path: "/mini/user/audit-list", 157 + Path: "/mini/user/audit_list",
158 Handler: user.MiniUserAuditListHandler(serverCtx), 158 Handler: user.MiniUserAuditListHandler(serverCtx),
159 }, 159 },
160 { 160 {
@@ -164,16 +164,21 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { @@ -164,16 +164,21 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
164 }, 164 },
165 { 165 {
166 Method: http.MethodPost, 166 Method: http.MethodPost,
167 - Path: "/mini/user/department-users", 167 + Path: "/mini/user/department_users",
168 Handler: user.MiniUserDepartmentUsersHandler(serverCtx), 168 Handler: user.MiniUserDepartmentUsersHandler(serverCtx),
169 }, 169 },
170 { 170 {
171 Method: http.MethodPost, 171 Method: http.MethodPost,
172 - Path: "/mini/user/user-list", 172 + Path: "/mini/user/user_list",
173 Handler: user.MiniUsersListHandler(serverCtx), 173 Handler: user.MiniUsersListHandler(serverCtx),
174 }, 174 },
175 { 175 {
176 Method: http.MethodPost, 176 Method: http.MethodPost,
  177 + Path: "/mini/user/news",
  178 + Handler: user.MiniUserNewsHandler(serverCtx),
  179 + },
  180 + {
  181 + Method: http.MethodPost,
177 Path: "/mini/user/follower", 182 Path: "/mini/user/follower",
178 Handler: user.MiniUserFollowerHandler(serverCtx), 183 Handler: user.MiniUserFollowerHandler(serverCtx),
179 }, 184 },
@@ -184,6 +189,16 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { @@ -184,6 +189,16 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
184 }, 189 },
185 { 190 {
186 Method: http.MethodPost, 191 Method: http.MethodPost,
  192 + Path: "/mini/user/following/latest_unread_list",
  193 + Handler: user.MiniUserFollowingLatestUnreadListHandler(serverCtx),
  194 + },
  195 + {
  196 + Method: http.MethodPost,
  197 + Path: "/mini/user/following/mark_read",
  198 + Handler: user.MiniUserFollowingMarkReadHandler(serverCtx),
  199 + },
  200 + {
  201 + Method: http.MethodPost,
187 Path: "/mini/user/follow", 202 Path: "/mini/user/follow",
188 Handler: user.MiniUserFollowHandler(serverCtx), 203 Handler: user.MiniUserFollowHandler(serverCtx),
189 }, 204 },
@@ -218,7 +233,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { @@ -218,7 +233,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
218 }, 233 },
219 { 234 {
220 Method: http.MethodPost, 235 Method: http.MethodPost,
221 - Path: "/system/user/user-list", 236 + Path: "/system/user/user_list",
222 Handler: user.SystemUsersListHandler(serverCtx), 237 Handler: user.SystemUsersListHandler(serverCtx),
223 }, 238 },
224 { 239 {
  1 +package user
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/result"
  5 + "net/http"
  6 +
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/user"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
  11 +)
  12 +
  13 +func MiniUserFollowingLatestUnreadListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14 + return func(w http.ResponseWriter, r *http.Request) {
  15 + var req types.MiniUserFollowedSearchRequest
  16 + if err := httpx.Parse(r, &req); err != nil {
  17 + httpx.ErrorCtx(r.Context(), w, err)
  18 + return
  19 + }
  20 +
  21 + l := user.NewMiniUserFollowingLatestUnreadListLogic(r.Context(), svcCtx)
  22 + resp, err := l.MiniUserFollowingLatestUnreadList(&req)
  23 + result.HttpResult(r, w, resp, err)
  24 + }
  25 +}
  1 +package user
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/result"
  5 + "net/http"
  6 +
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/user"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
  11 +)
  12 +
  13 +func MiniUserFollowingMarkReadHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14 + return func(w http.ResponseWriter, r *http.Request) {
  15 + var req types.MiniUserFollowingMarkReadRequest
  16 + if err := httpx.Parse(r, &req); err != nil {
  17 + httpx.ErrorCtx(r.Context(), w, err)
  18 + return
  19 + }
  20 +
  21 + l := user.NewMiniUserFollowingMarkReadLogic(r.Context(), svcCtx)
  22 + resp, err := l.MiniUserFollowingMarkRead(&req)
  23 + result.HttpResult(r, w, resp, err)
  24 + }
  25 +}
  1 +package user
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/result"
  5 + "net/http"
  6 +
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/user"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
  11 +)
  12 +
  13 +func MiniUserNewsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14 + return func(w http.ResponseWriter, r *http.Request) {
  15 + var req types.MiniUserNewsRequest
  16 + if err := httpx.Parse(r, &req); err != nil {
  17 + httpx.ErrorCtx(r.Context(), w, err)
  18 + return
  19 + }
  20 +
  21 + l := user.NewMiniUserNewsLogic(r.Context(), svcCtx)
  22 + resp, err := l.MiniUserNews(&req)
  23 + result.HttpResult(r, w, resp, err)
  24 + }
  25 +}
@@ -6,6 +6,7 @@ import ( @@ -6,6 +6,7 @@ import (
6 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain" 6 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
7 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/contextdata" 7 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/contextdata"
8 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/xerr" 8 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/xerr"
  9 + "time"
9 10
10 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc" 11 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
11 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types" 12 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
@@ -32,6 +33,7 @@ func (l *MiniUserFollowLogic) MiniUserFollow(req *types.FollowRequest) (err erro @@ -32,6 +33,7 @@ func (l *MiniUserFollowLogic) MiniUserFollow(req *types.FollowRequest) (err erro
32 conn = l.svcCtx.DefaultDBConn() 33 conn = l.svcCtx.DefaultDBConn()
33 user *domain.User 34 user *domain.User
34 targetUser *domain.User 35 targetUser *domain.User
  36 + userFollow *domain.UserFollow
35 userToken = contextdata.GetUserTokenFromCtx(l.ctx) 37 userToken = contextdata.GetUserTokenFromCtx(l.ctx)
36 ) 38 )
37 if user, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, userToken.UserId); err != nil { 39 if user, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, userToken.UserId); err != nil {
@@ -40,6 +42,9 @@ func (l *MiniUserFollowLogic) MiniUserFollow(req *types.FollowRequest) (err erro @@ -40,6 +42,9 @@ func (l *MiniUserFollowLogic) MiniUserFollow(req *types.FollowRequest) (err erro
40 if targetUser, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, req.UserId); err != nil { 42 if targetUser, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, req.UserId); err != nil {
41 return xerr.NewErrMsgErr("关注的用户不存在", err) 43 return xerr.NewErrMsgErr("关注的用户不存在", err)
42 } 44 }
  45 + if userFollow, err = l.svcCtx.UserFollowRepository.FindOneUserFollowing(l.ctx, conn, user.Id, targetUser.Id); err == nil && userFollow != nil {
  46 + return xerr.NewErrMsgErr("用户已关注", err)
  47 + }
43 if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error { 48 if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
44 if err = user.Follow(targetUser); err != nil { 49 if err = user.Follow(targetUser); err != nil {
45 return err 50 return err
@@ -50,6 +55,14 @@ func (l *MiniUserFollowLogic) MiniUserFollow(req *types.FollowRequest) (err erro @@ -50,6 +55,14 @@ func (l *MiniUserFollowLogic) MiniUserFollow(req *types.FollowRequest) (err erro
50 if targetUser, err = l.svcCtx.UserRepository.UpdateWithVersion(ctx, conn, targetUser); err != nil { 55 if targetUser, err = l.svcCtx.UserRepository.UpdateWithVersion(ctx, conn, targetUser); err != nil {
51 return err 56 return err
52 } 57 }
  58 + userFollow = &domain.UserFollow{
  59 + FromUserId: user.Id,
  60 + ToUserId: targetUser.Id,
  61 + LastReadAt: time.Now().Unix(),
  62 + }
  63 + if userFollow, err = l.svcCtx.UserFollowRepository.Insert(ctx, conn, userFollow); err != nil {
  64 + return err
  65 + }
53 return nil 66 return nil
54 }, true); err != nil { 67 }, true); err != nil {
55 return xerr.NewErrMsgErr("关注用户失败", err) 68 return xerr.NewErrMsgErr("关注用户失败", err)
  1 +package user
  2 +
  3 +import (
  4 + "context"
  5 + "github.com/samber/lo"
  6 + "github.com/zeromicro/go-zero/core/collection"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/contextdata"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/xerr"
  10 +
  11 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
  12 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
  13 +
  14 + "github.com/zeromicro/go-zero/core/logx"
  15 +)
  16 +
  17 +type MiniUserFollowingLatestUnreadListLogic struct {
  18 + logx.Logger
  19 + ctx context.Context
  20 + svcCtx *svc.ServiceContext
  21 +}
  22 +
  23 +func NewMiniUserFollowingLatestUnreadListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MiniUserFollowingLatestUnreadListLogic {
  24 + return &MiniUserFollowingLatestUnreadListLogic{
  25 + Logger: logx.WithContext(ctx),
  26 + ctx: ctx,
  27 + svcCtx: svcCtx,
  28 + }
  29 +}
  30 +
  31 +func (l *MiniUserFollowingLatestUnreadListLogic) MiniUserFollowingLatestUnreadList(req *types.MiniUserFollowedSearchRequest) (resp *types.MiniUserFollowedSearchResponse, err error) {
  32 + var (
  33 + conn = l.svcCtx.DefaultDBConn()
  34 + user *domain.User
  35 + userToken = contextdata.GetUserTokenFromCtx(l.ctx)
  36 + limit = 6
  37 + )
  38 + if user, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, userToken.UserId); err != nil {
  39 + return nil, xerr.NewErrMsgErr("用户不存在", err)
  40 + }
  41 + var (
  42 + users = user.Following
  43 + setUsers = collection.NewSet()
  44 + )
  45 + _, userArticlesUnread, _ := l.svcCtx.ArticleRepository.FindAuthorsLatestFirstUnreadArticle(l.ctx, conn, user.CompanyId, users, user.Id, limit)
  46 + _, userArticlesLatest, _ := l.svcCtx.ArticleRepository.FindAuthorsLatestFirstArticle(l.ctx, conn, user.CompanyId, users, user.Id, limit)
  47 + _, userFollows, _ := l.svcCtx.UserFollowRepository.Find(l.ctx, conn, domain.IndexCompanyId(userToken.CompanyId)().WithKV("fromUserId", user.Id).WithFindOnly())
  48 + resp = &types.MiniUserFollowedSearchResponse{
  49 + Total: int64(len(users)),
  50 + List: make([]*types.UserFollowItem, 0),
  51 + }
  52 + addUser := func(userId int64, readFlag bool) {
  53 + if setUsers.Contains(userId) {
  54 + return
  55 + }
  56 + if len(resp.List) == limit {
  57 + return
  58 + }
  59 + setUsers.Add(userId)
  60 + if foundUser, _ := l.svcCtx.UserRepository.FindOne(l.ctx, conn, userId); foundUser != nil {
  61 + resp.List = append(resp.List, &types.UserFollowItem{
  62 + Id: foundUser.Id,
  63 + Name: foundUser.Name,
  64 + Avatar: foundUser.Avatar,
  65 + Position: foundUser.Position,
  66 + ReadFlag: readFlag,
  67 + })
  68 + }
  69 + return
  70 + }
  71 + userFollowsMap := lo.KeyBy(userFollows, func(item *domain.UserFollow) int64 {
  72 + return item.ToUserId
  73 + })
  74 + lo.ForEach(userArticlesUnread, func(item *domain.Article, index int) {
  75 + var readFlag = true
  76 + if v, ok := userFollowsMap[item.AuthorId]; ok && v.LastReadAt < item.CreatedAt {
  77 + readFlag = false
  78 + }
  79 + addUser(item.AuthorId, readFlag)
  80 + })
  81 + lo.ForEach(userArticlesLatest, func(item *domain.Article, index int) {
  82 + addUser(item.AuthorId, true)
  83 + })
  84 + lo.ForEach(users, func(item int64, index int) {
  85 + addUser(item, true)
  86 + })
  87 + return
  88 +}
  1 +package user
  2 +
  3 +import (
  4 + "context"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/transaction"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/contextdata"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/xerr"
  9 + "time"
  10 +
  11 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
  12 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
  13 +
  14 + "github.com/zeromicro/go-zero/core/logx"
  15 +)
  16 +
  17 +type MiniUserFollowingMarkReadLogic struct {
  18 + logx.Logger
  19 + ctx context.Context
  20 + svcCtx *svc.ServiceContext
  21 +}
  22 +
  23 +func NewMiniUserFollowingMarkReadLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MiniUserFollowingMarkReadLogic {
  24 + return &MiniUserFollowingMarkReadLogic{
  25 + Logger: logx.WithContext(ctx),
  26 + ctx: ctx,
  27 + svcCtx: svcCtx,
  28 + }
  29 +}
  30 +
  31 +func (l *MiniUserFollowingMarkReadLogic) MiniUserFollowingMarkRead(req *types.MiniUserFollowingMarkReadRequest) (resp interface{}, err error) {
  32 + var (
  33 + conn = l.svcCtx.DefaultDBConn()
  34 + user *domain.User
  35 + userFollow *domain.UserFollow
  36 + userToken = contextdata.GetUserTokenFromCtx(l.ctx)
  37 + )
  38 + if user, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, req.UserId); err != nil {
  39 + return nil, xerr.NewErrMsgErr("用户不存在", err)
  40 + }
  41 + if userFollow, err = l.svcCtx.UserFollowRepository.FindOneUserFollowing(l.ctx, conn, userToken.UserId, user.Id); err != nil {
  42 + return nil, xerr.NewErrMsgErr("用户还未关注", err)
  43 + }
  44 + if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
  45 + userFollow.LastReadAt = time.Now().Unix()
  46 + if userFollow, err = l.svcCtx.UserFollowRepository.UpdateWithVersion(ctx, conn, userFollow); err != nil {
  47 + return err
  48 + }
  49 + return nil
  50 + }, true); err != nil {
  51 + return nil, xerr.NewErrMsgErr("关注用户标记已读失败", err)
  52 + }
  53 + resp = struct{}{}
  54 + return
  55 +}
  1 +package user
  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 +
  9 + "github.com/zeromicro/go-zero/core/logx"
  10 +)
  11 +
  12 +type MiniUserNewsLogic struct {
  13 + logx.Logger
  14 + ctx context.Context
  15 + svcCtx *svc.ServiceContext
  16 +}
  17 +
  18 +func NewMiniUserNewsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MiniUserNewsLogic {
  19 + return &MiniUserNewsLogic{
  20 + Logger: logx.WithContext(ctx),
  21 + ctx: ctx,
  22 + svcCtx: svcCtx,
  23 + }
  24 +}
  25 +
  26 +func (l *MiniUserNewsLogic) MiniUserNews(req *types.MiniUserNewsRequest) (resp *types.MiniUserNewsResposne, err error) {
  27 + // todo: add your logic here and delete this line
  28 +
  29 + return
  30 +}
@@ -32,6 +32,7 @@ func (l *MiniUserUnFollowLogic) MiniUserUnFollow(req *types.FollowRequest) (err @@ -32,6 +32,7 @@ func (l *MiniUserUnFollowLogic) MiniUserUnFollow(req *types.FollowRequest) (err
32 conn = l.svcCtx.DefaultDBConn() 32 conn = l.svcCtx.DefaultDBConn()
33 user *domain.User 33 user *domain.User
34 targetUser *domain.User 34 targetUser *domain.User
  35 + userFollow *domain.UserFollow
35 userToken = contextdata.GetUserTokenFromCtx(l.ctx) 36 userToken = contextdata.GetUserTokenFromCtx(l.ctx)
36 ) 37 )
37 if user, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, userToken.UserId); err != nil { 38 if user, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, userToken.UserId); err != nil {
@@ -40,6 +41,9 @@ func (l *MiniUserUnFollowLogic) MiniUserUnFollow(req *types.FollowRequest) (err @@ -40,6 +41,9 @@ func (l *MiniUserUnFollowLogic) MiniUserUnFollow(req *types.FollowRequest) (err
40 if targetUser, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, req.UserId); err != nil { 41 if targetUser, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, req.UserId); err != nil {
41 return xerr.NewErrMsgErr("关注的用户不存在", err) 42 return xerr.NewErrMsgErr("关注的用户不存在", err)
42 } 43 }
  44 + if userFollow, err = l.svcCtx.UserFollowRepository.FindOneUserFollowing(l.ctx, conn, user.Id, targetUser.Id); err != nil {
  45 + return xerr.NewErrMsgErr("用户还未关注", err)
  46 + }
43 if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error { 47 if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
44 if err = user.Unfollow(targetUser); err != nil { 48 if err = user.Unfollow(targetUser); err != nil {
45 return err 49 return err
@@ -50,6 +54,9 @@ func (l *MiniUserUnFollowLogic) MiniUserUnFollow(req *types.FollowRequest) (err @@ -50,6 +54,9 @@ func (l *MiniUserUnFollowLogic) MiniUserUnFollow(req *types.FollowRequest) (err
50 if targetUser, err = l.svcCtx.UserRepository.UpdateWithVersion(ctx, conn, targetUser); err != nil { 54 if targetUser, err = l.svcCtx.UserRepository.UpdateWithVersion(ctx, conn, targetUser); err != nil {
51 return err 55 return err
52 } 56 }
  57 + if userFollow, err = l.svcCtx.UserFollowRepository.Delete(ctx, conn, userFollow); err != nil {
  58 + return err
  59 + }
53 return nil 60 return nil
54 }, true); err != nil { 61 }, true); err != nil {
55 return xerr.NewErrMsgErr("关注用户失败", err) 62 return xerr.NewErrMsgErr("关注用户失败", err)
@@ -330,6 +330,26 @@ type MiniUsersListRequest struct { @@ -330,6 +330,26 @@ type MiniUsersListRequest struct {
330 RoleId int64 `json:"roleId,optional"` // 按角色角色关联的用户 330 RoleId int64 `json:"roleId,optional"` // 按角色角色关联的用户
331 } 331 }
332 332
  333 +type MiniUserNewsRequest struct {
  334 + AuthorId int64 `json:"authorId,optional"` // 特定作者ID
  335 + LastArticleId int64 `json:"lastArticleId,optional"` // 最后文章ID
  336 + Size int `json:"size"` // 数量
  337 +}
  338 +
  339 +type MiniUserNewsResposne struct {
  340 + List []UserNewsItem `json:"list"`
  341 + Total int64 `json:"total"`
  342 +}
  343 +
  344 +type UserNewsItem struct {
  345 + NewsId int64 `json:"newsId"` // 快讯ID
  346 + Type string `json:"type"` // 快讯类型 文章:Article 讨论:Discuss ...
  347 + Title string `json:"title"` // 标题
  348 + Summary string `json:"summary"` // 快讯概要
  349 + Time int64 `json:"time"` // 时间
  350 + ReadFlag bool `json:"readFlag"` // 已读标识 true:已读 false:未读
  351 +}
  352 +
333 type MiniUserFollowedSearchRequest struct { 353 type MiniUserFollowedSearchRequest struct {
334 Page int `json:"page,optional"` 354 Page int `json:"page,optional"`
335 Size int `json:"size,optional"` 355 Size int `json:"size,optional"`
@@ -340,6 +360,10 @@ type MiniUserFollowedSearchResponse struct { @@ -340,6 +360,10 @@ type MiniUserFollowedSearchResponse struct {
340 Total int64 `json:"total"` 360 Total int64 `json:"total"`
341 } 361 }
342 362
  363 +type MiniUserFollowingMarkReadRequest struct {
  364 + UserId int64 `json:"userId"`
  365 +}
  366 +
343 type UserItem struct { 367 type UserItem struct {
344 Id int64 `json:"id,omitempty"` // 用户ID 368 Id int64 `json:"id,omitempty"` // 用户ID
345 CompanyId int64 `json:"companyId,omitempty"` // 公司ID 369 CompanyId int64 `json:"companyId,omitempty"` // 公司ID
@@ -397,6 +421,7 @@ type UserFollowItem struct { @@ -397,6 +421,7 @@ type UserFollowItem struct {
397 Position string `json:"position"` // 职位 421 Position string `json:"position"` // 职位
398 Followed bool `json:"followed"` // 关注 422 Followed bool `json:"followed"` // 关注
399 MutualFollowed bool `json:"mutualFollowed"` // 互相关注标识 423 MutualFollowed bool `json:"mutualFollowed"` // 互相关注标识
  424 + ReadFlag bool `json:"readFlag"` // 已读标识 true:已读 false:未读(小红点)
400 } 425 }
401 426
402 type MiniMyLikeRequest struct { 427 type MiniMyLikeRequest struct {
@@ -10,11 +10,13 @@ import ( @@ -10,11 +10,13 @@ import (
10 10
11 type UserFollow struct { 11 type UserFollow struct {
12 Id int64 // 唯一标识 12 Id int64 // 唯一标识
13 -  
14 - CreatedAt int64 `json:"createdAt,omitempty"`  
15 - UpdatedAt int64 `json:"updatedAt,omitempty"`  
16 - DeletedAt int64 `json:"deletedAt,omitempty"`  
17 - Version int `json:"version,omitempty"` 13 + FromUserId int64
  14 + ToUserId int64
  15 + LastReadAt int64
  16 + CreatedAt int64
  17 + UpdatedAt int64
  18 + DeletedAt int64
  19 + Version int
18 } 20 }
19 21
20 func (m *UserFollow) TableName() string { 22 func (m *UserFollow) TableName() string {
@@ -156,6 +156,127 @@ func (repository *ArticleRepository) Find(ctx context.Context, conn transaction. @@ -156,6 +156,127 @@ func (repository *ArticleRepository) Find(ctx context.Context, conn transaction.
156 return total, dms, nil 156 return total, dms, nil
157 } 157 }
158 158
  159 +// FindAuthorsLatestArticle 作者最新的文章
  160 +func (repository *ArticleRepository) FindAuthorsLatestArticle(ctx context.Context, conn transaction.Conn,
  161 + companyId int64, authors []int64, whoRead int64, lastId int64, limit int) (int64, []*domain.Article, error) {
  162 + var (
  163 + tx = conn.DB()
  164 + ms []*models.Article
  165 + dms = make([]*domain.Article, 0)
  166 + total int64
  167 + )
  168 + queryFunc := func() (interface{}, error) {
  169 + tx = tx.Model(&ms).
  170 + Where("id < ?", lastId).
  171 + Where("company_id=?", companyId).
  172 + Where("author_id in (?)", authors).
  173 + Where("target_user=0 or who_read @>'[?]'", whoRead).
  174 + Where("show = 1").
  175 + Order("id desc")
  176 + if limit > 0 {
  177 + tx.Limit(limit)
  178 + }
  179 + if total, tx = transaction.PaginationAndCount(ctx, tx, domain.NewQueryOptions().WithFindOnly(), &ms); tx.Error != nil {
  180 + return dms, tx.Error
  181 + }
  182 + return dms, nil
  183 + }
  184 +
  185 + if _, err := repository.Query(queryFunc); err != nil {
  186 + return 0, nil, err
  187 + }
  188 +
  189 + for _, item := range ms {
  190 + if dm, err := repository.ModelToDomainModel(item); err != nil {
  191 + return 0, dms, err
  192 + } else {
  193 + dms = append(dms, dm)
  194 + }
  195 + }
  196 + return total, dms, nil
  197 +}
  198 +
  199 +// FindAuthorsLatestFirstArticle 作者最新的第一篇文章
  200 +func (repository *ArticleRepository) FindAuthorsLatestFirstArticle(ctx context.Context, conn transaction.Conn,
  201 + companyId int64, authors []int64, whoRead int64, limit int) (int64, []*domain.Article, error) {
  202 + var (
  203 + tx = conn.DB()
  204 + ms []*models.Article
  205 + dms = make([]*domain.Article, 0)
  206 + total int64
  207 + )
  208 + queryFunc := func() (interface{}, error) {
  209 + tx = tx.Model(&ms).Select("max(id) id", "max(author_id) author_id", "max(created_at) created_at").
  210 + Where("company_id=?", companyId).
  211 + Where("author_id in (?)", authors).
  212 + Where("target_user=0 or who_read @>'[?]'", whoRead).
  213 + Where("show = 1").
  214 + Group("author_id").
  215 + Order("id desc")
  216 + if limit > 0 {
  217 + tx.Limit(limit)
  218 + }
  219 + if total, tx = transaction.PaginationAndCount(ctx, tx, domain.NewQueryOptions().WithFindOnly(), &ms); tx.Error != nil {
  220 + return dms, tx.Error
  221 + }
  222 + return dms, nil
  223 + }
  224 +
  225 + if _, err := repository.Query(queryFunc); err != nil {
  226 + return 0, nil, err
  227 + }
  228 +
  229 + for _, item := range ms {
  230 + if dm, err := repository.ModelToDomainModel(item); err != nil {
  231 + return 0, dms, err
  232 + } else {
  233 + dms = append(dms, dm)
  234 + }
  235 + }
  236 + return total, dms, nil
  237 +}
  238 +
  239 +// FindAuthorsLatestFirstUnreadArticle 作者最新的第一篇未读文章
  240 +func (repository *ArticleRepository) FindAuthorsLatestFirstUnreadArticle(ctx context.Context, conn transaction.Conn,
  241 + companyId int64, authors []int64, whoRead int64, limit int) (int64, []*domain.Article, error) {
  242 + var (
  243 + tx = conn.DB()
  244 + ms []*models.Article
  245 + dms = make([]*domain.Article, 0)
  246 + total int64
  247 + )
  248 + queryFunc := func() (interface{}, error) {
  249 + tx = tx.Model(&ms).Select("max(id) id", "max(author_id) author_id", "max(created_at) created_at").
  250 + Where("company_id=?", companyId).
  251 + Where("author_id in (?)", authors).
  252 + Where("target_user=0 or who_read @>'[?]'", whoRead).
  253 + Where("show = 1").
  254 + Where("id not in (select article_id from user_read_article where user_id = ?)", whoRead).
  255 + Group("author_id").
  256 + Order("id desc")
  257 + if limit > 0 {
  258 + tx.Limit(limit)
  259 + }
  260 + if total, tx = transaction.PaginationAndCount(ctx, tx, domain.NewQueryOptions().WithFindOnly(), &ms); tx.Error != nil {
  261 + return dms, tx.Error
  262 + }
  263 + return dms, nil
  264 + }
  265 +
  266 + if _, err := repository.Query(queryFunc); err != nil {
  267 + return 0, nil, err
  268 + }
  269 +
  270 + for _, item := range ms {
  271 + if dm, err := repository.ModelToDomainModel(item); err != nil {
  272 + return 0, dms, err
  273 + } else {
  274 + dms = append(dms, dm)
  275 + }
  276 + }
  277 + return total, dms, nil
  278 +}
  279 +
159 func (repository *ArticleRepository) ModelToDomainModel(from *models.Article) (*domain.Article, error) { 280 func (repository *ArticleRepository) ModelToDomainModel(from *models.Article) (*domain.Article, error) {
160 to := &domain.Article{ 281 to := &domain.Article{
161 Id: from.Id, 282 Id: from.Id,
@@ -111,6 +111,26 @@ func (repository *UserFollowRepository) FindOne(ctx context.Context, conn transa @@ -111,6 +111,26 @@ func (repository *UserFollowRepository) FindOne(ctx context.Context, conn transa
111 return repository.ModelToDomainModel(m) 111 return repository.ModelToDomainModel(m)
112 } 112 }
113 113
  114 +func (repository *UserFollowRepository) FindOneUserFollowing(ctx context.Context, conn transaction.Conn, userId int64, followingId int64) (*domain.UserFollow, error) {
  115 + var (
  116 + err error
  117 + tx = conn.DB()
  118 + m = new(models.UserFollow)
  119 + )
  120 + queryFunc := func() (interface{}, error) {
  121 + tx = tx.Model(m).Where("from_user_id = ?", userId).Where("to_user_id = ?", followingId).First(m)
  122 + if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
  123 + return nil, domain.ErrNotFound
  124 + }
  125 + return m, tx.Error
  126 + }
  127 + cacheModel := new(models.UserFollow)
  128 + if err = repository.QueryCache(cacheModel.CacheKeyFunc, m, queryFunc); err != nil {
  129 + return nil, err
  130 + }
  131 + return repository.ModelToDomainModel(m)
  132 +}
  133 +
114 func (repository *UserFollowRepository) Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*domain.UserFollow, error) { 134 func (repository *UserFollowRepository) Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*domain.UserFollow, error) {
115 var ( 135 var (
116 tx = conn.DB() 136 tx = conn.DB()
@@ -120,6 +140,12 @@ func (repository *UserFollowRepository) Find(ctx context.Context, conn transacti @@ -120,6 +140,12 @@ func (repository *UserFollowRepository) Find(ctx context.Context, conn transacti
120 ) 140 )
121 queryFunc := func() (interface{}, error) { 141 queryFunc := func() (interface{}, error) {
122 tx = tx.Model(&ms).Order("id desc") 142 tx = tx.Model(&ms).Order("id desc")
  143 + if v, ok := queryOptions["fromUserId"]; ok {
  144 + tx.Where("from_user_id = ?", v)
  145 + }
  146 + if v, ok := queryOptions["toUserIds"]; ok {
  147 + tx.Where("to_user_id in (?)", v)
  148 + }
123 if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil { 149 if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
124 return dms, tx.Error 150 return dms, tx.Error
125 } 151 }
@@ -38,6 +38,8 @@ type ArticleRepository interface { @@ -38,6 +38,8 @@ type ArticleRepository interface {
38 UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *Article) (*Article, error) 38 UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *Article) (*Article, error)
39 FindOne(ctx context.Context, conn transaction.Conn, id int64) (*Article, error) 39 FindOne(ctx context.Context, conn transaction.Conn, id int64) (*Article, error)
40 Find(ctx context.Context, conn transaction.Conn, companyId int64, queryOptions map[string]interface{}) (int64, []*Article, error) 40 Find(ctx context.Context, conn transaction.Conn, companyId int64, queryOptions map[string]interface{}) (int64, []*Article, error)
  41 + FindAuthorsLatestFirstArticle(ctx context.Context, conn transaction.Conn, companyId int64, authors []int64, whoRead int64, limit int) (int64, []*Article, error)
  42 + FindAuthorsLatestFirstUnreadArticle(ctx context.Context, conn transaction.Conn, companyId int64, authors []int64, whoRead int64, limit int) (int64, []*Article, error)
41 IncreaseCountLove(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error //点赞数量变动 43 IncreaseCountLove(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error //点赞数量变动
42 IncreaseCountComment(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error //评论数量变动 44 IncreaseCountComment(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error //评论数量变动
43 IncreaseCountRead(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error //浏览数量变动 45 IncreaseCountRead(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error //浏览数量变动
@@ -7,8 +7,9 @@ import ( @@ -7,8 +7,9 @@ import (
7 7
8 type UserFollow struct { 8 type UserFollow struct {
9 Id int64 `json:"id,omitempty"` // 唯一标识 9 Id int64 `json:"id,omitempty"` // 唯一标识
10 - FromUserId int64 `json:"fromUserId,omitempty"` /// 发起关注的人  
11 - ToUserId int64 `json:"toUserId,omitempty"` /// 被关注的人 10 + FromUserId int64 `json:"fromUserId,omitempty"` // 发起关注的人
  11 + ToUserId int64 `json:"toUserId,omitempty"` // 被关注的人
  12 + LastReadAt int64 `json:"lastReadAt,omitempty"` // 上一次读取信息时间
12 CreatedAt int64 `json:"createdAt,omitempty"` 13 CreatedAt int64 `json:"createdAt,omitempty"`
13 UpdatedAt int64 `json:"updatedAt,omitempty"` 14 UpdatedAt int64 `json:"updatedAt,omitempty"`
14 DeletedAt int64 `json:"deletedAt,omitempty"` 15 DeletedAt int64 `json:"deletedAt,omitempty"`
@@ -21,6 +22,7 @@ type UserFollowRepository interface { @@ -21,6 +22,7 @@ type UserFollowRepository interface {
21 UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *UserFollow) (*UserFollow, error) 22 UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *UserFollow) (*UserFollow, error)
22 Delete(ctx context.Context, conn transaction.Conn, dm *UserFollow) (*UserFollow, error) 23 Delete(ctx context.Context, conn transaction.Conn, dm *UserFollow) (*UserFollow, error)
23 FindOne(ctx context.Context, conn transaction.Conn, id int64) (*UserFollow, error) 24 FindOne(ctx context.Context, conn transaction.Conn, id int64) (*UserFollow, error)
  25 + FindOneUserFollowing(ctx context.Context, conn transaction.Conn, userId int64, followingId int64) (*UserFollow, error)
24 Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*UserFollow, error) 26 Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*UserFollow, error)
25 } 27 }
26 28