作者 庄敏学

文章编辑增加视频字段和标签定性

@@ -10,9 +10,9 @@ type Location { @@ -10,9 +10,9 @@ type Location {
10 10
11 type Video { 11 type Video {
12 Url string `json:"url"` //视频文件的地址 12 Url string `json:"url"` //视频文件的地址
13 - Cover string `json:"cover"` //封面  
14 - Width int `json:"width"` //封面图片宽  
15 - Height int `json:"height"` //封面图片长 13 + Cover string `json:"cover,optional"` //封面
  14 + Width int `json:"width,optional"` //封面图片宽
  15 + Height int `json:"height,optional"` //封面图片长
16 } 16 }
17 17
18 18
@@ -2,6 +2,8 @@ package article @@ -2,6 +2,8 @@ package article
2 2
3 import ( 3 import (
4 "context" 4 "context"
  5 + "github.com/jinzhu/copier"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/message"
5 "strconv" 7 "strconv"
6 "unicode/utf8" 8 "unicode/utf8"
7 9
@@ -25,6 +27,7 @@ type SystemUpdateArticleLogic struct { @@ -25,6 +27,7 @@ type SystemUpdateArticleLogic struct {
25 logx.Logger 27 logx.Logger
26 ctx context.Context 28 ctx context.Context
27 svcCtx *svc.ServiceContext 29 svcCtx *svc.ServiceContext
  30 + conn transaction.Conn
28 } 31 }
29 32
30 func NewSystemUpdateArticleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SystemUpdateArticleLogic { 33 func NewSystemUpdateArticleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SystemUpdateArticleLogic {
@@ -32,11 +35,12 @@ func NewSystemUpdateArticleLogic(ctx context.Context, svcCtx *svc.ServiceContext @@ -32,11 +35,12 @@ func NewSystemUpdateArticleLogic(ctx context.Context, svcCtx *svc.ServiceContext
32 Logger: logx.WithContext(ctx), 35 Logger: logx.WithContext(ctx),
33 ctx: ctx, 36 ctx: ctx,
34 svcCtx: svcCtx, 37 svcCtx: svcCtx,
  38 + conn: svcCtx.DefaultDBConn(),
35 } 39 }
36 } 40 }
37 41
38 func (l *SystemUpdateArticleLogic) SystemUpdateArticle(req *types.SystemArticleUpdateRequest) (resp *types.SystemArticleUpdateResponse, err error) { 42 func (l *SystemUpdateArticleLogic) SystemUpdateArticle(req *types.SystemArticleUpdateRequest) (resp *types.SystemArticleUpdateResponse, err error) {
39 - var conn = l.svcCtx.DefaultDBConn() 43 + //var conn = l.svcCtx.DefaultDBConn()
40 userToken := contextdata.GetUserTokenFromCtx(l.ctx) 44 userToken := contextdata.GetUserTokenFromCtx(l.ctx)
41 // 预处理参数 45 // 预处理参数
42 if req.TargetUser == 0 { 46 if req.TargetUser == 0 {
@@ -44,26 +48,20 @@ func (l *SystemUpdateArticleLogic) SystemUpdateArticle(req *types.SystemArticleU @@ -44,26 +48,20 @@ func (l *SystemUpdateArticleLogic) SystemUpdateArticle(req *types.SystemArticleU
44 req.WhoRead = make([]int64, 0) 48 req.WhoRead = make([]int64, 0)
45 } 49 }
46 // 检查文字数量 50 // 检查文字数量
47 - wordNum := 0  
48 - for i := range req.Section {  
49 - num := utf8.RuneCountInString(req.Section[i].Content)  
50 - wordNum += num 51 + if err = l.validateTextLimit(req); err != nil {
  52 + return nil, err
51 } 53 }
52 - if wordNum >= 1000 {  
53 - return nil, xerr.NewErrMsgErr("最多只能输入1000字", err)  
54 - }  
55 -  
56 // 获取当前用户信息 54 // 获取当前用户信息
57 userMe, err := l.svcCtx.ApiAuthService.MeInfo(l.ctx, authlib.RequestUserMeQuery{Token: req.AccessToken}) 55 userMe, err := l.svcCtx.ApiAuthService.MeInfo(l.ctx, authlib.RequestUserMeQuery{Token: req.AccessToken})
58 if err != nil { 56 if err != nil {
59 return nil, xerr.NewErrMsgErr("获取当前用户信息失败", err) 57 return nil, xerr.NewErrMsgErr("获取当前用户信息失败", err)
60 } 58 }
61 // 文章数据 59 // 文章数据
62 - article, err := l.svcCtx.ArticleRepository.FindOne(l.ctx, conn, req.Id) 60 + article, err := l.svcCtx.ArticleRepository.FindOne(l.ctx, l.conn, req.Id)
63 if err != nil { 61 if err != nil {
64 return nil, xerr.NewErrMsgErr("帖子不存在", err) 62 return nil, xerr.NewErrMsgErr("帖子不存在", err)
65 } 63 }
66 - _, sectionList, err := l.svcCtx.ArticleSectionRepository.Find(l.ctx, conn, map[string]interface{}{"articleId": article.Id}) 64 + _, sectionList, err := l.svcCtx.ArticleSectionRepository.Find(l.ctx, l.conn, map[string]interface{}{"articleId": article.Id})
67 if err != nil { 65 if err != nil {
68 return nil, xerr.NewErrMsgErr("获取文章段落内容失败", err) 66 return nil, xerr.NewErrMsgErr("获取文章段落内容失败", err)
69 } 67 }
@@ -78,110 +76,44 @@ func (l *SystemUpdateArticleLogic) SystemUpdateArticle(req *types.SystemArticleU @@ -78,110 +76,44 @@ func (l *SystemUpdateArticleLogic) SystemUpdateArticle(req *types.SystemArticleU
78 backup.Action = "编辑" 76 backup.Action = "编辑"
79 77
80 // 获取图片的尺寸大小 78 // 获取图片的尺寸大小
81 - images := []domain.Image{}  
82 - for _, val := range req.Images {  
83 - fInfo, _ := oss.GetImageInfo(val)  
84 - w, _ := strconv.Atoi(fInfo.ImageWidth.Value)  
85 - h, _ := strconv.Atoi(fInfo.ImageHeight.Value)  
86 - images = append(images, domain.Image{  
87 - Url: val,  
88 - Width: w,  
89 - Height: h,  
90 - }) 79 + images, err := l.getImages(req)
  80 + if err != nil {
  81 + return nil, err
  82 + }
  83 + //视频
  84 + videos, err := l.getVideos(req)
  85 + if err != nil {
  86 + return nil, err
91 } 87 }
92 //检查文章可被哪些人查看 88 //检查文章可被哪些人查看
93 - whoRead := []int64{}  
94 - if len(req.WhoRead) > 0 {  
95 - whoRead = lo.Uniq(req.WhoRead)  
96 - var u *domain.User  
97 - for _, val := range whoRead {  
98 - u, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, val)  
99 - if err != nil {  
100 - return nil, xerr.NewErrMsgErr("文章可查看人设置错误", err)  
101 - }  
102 - if u.CompanyId != article.CompanyId {  
103 - return nil, xerr.NewErrMsg("文章可查看人设置错误")  
104 - }  
105 - } 89 + whoRead, err := l.validateAndGetWhoRead(req, article)
  90 + if err != nil {
  91 + return nil, err
106 } 92 }
107 //检查文章可被哪些人评论 93 //检查文章可被哪些人评论
108 whoReview := []int64{} 94 whoReview := []int64{}
109 if len(req.WhoReview) > 0 { 95 if len(req.WhoReview) > 0 {
110 whoReview = lo.Uniq(req.WhoReview) 96 whoReview = lo.Uniq(req.WhoReview)
111 } 97 }
112 - //有指定可查看人的情况  
113 - if len(whoRead) > 0 {  
114 - if len(whoReview) > 0 {  
115 - // 检查 whoRead 是否 完全包含 whoReview  
116 - ok := lo.Every(whoRead, whoReview)  
117 - if !ok {  
118 - return nil, xerr.NewErrMsg("文章可评论人设置错误")  
119 - }  
120 - }  
121 - if len(whoReview) == 0 {  
122 - //有指定可查看人 ,但未指定可评论人  
123 - return nil, xerr.NewErrMsg("文章可评论人设置错误")  
124 - }  
125 - }  
126 - //没有指定可查看人的情况  
127 - if len(whoRead) == 0 {  
128 - if len(whoReview) > 0 {  
129 - // 未指定可查看人(全员可看),有指定可评论人,  
130 - var u *domain.User  
131 - for _, val := range whoReview {  
132 - u, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, val)  
133 - if err != nil {  
134 - return nil, xerr.NewErrMsgErr("文章可评论人设置错误", err)  
135 - }  
136 - if u.CompanyId != article.CompanyId {  
137 - return nil, xerr.NewErrMsg("文章可评论人设置错误")  
138 - }  
139 - }  
140 - } 98 + //验证可评论
  99 + if err = l.validateWhoReview(whoRead, whoReview, article); err != nil {
  100 + return nil, err
141 } 101 }
142 //验证tag 102 //验证tag
143 - if len(req.Tags) > 0 {  
144 - req.Tags = lo.Uniq(req.Tags)  
145 - for _, value := range req.Tags {  
146 - t, err := l.svcCtx.ArticleTagRepository.FindOne(l.ctx, conn, value)  
147 - if err != nil {  
148 - return nil, xerr.NewErrMsgErr("文章标签设置错误", err)  
149 - }  
150 - if t.CompanyId != article.CompanyId {  
151 - return nil, xerr.NewErrMsgErr("文章标签设置错误", err)  
152 - }  
153 - } 103 + validTags := l.validateTags(req, article)
  104 + if validTags != nil {
  105 + return nil, validTags
154 } 106 }
155 article.Title = req.Title 107 article.Title = req.Title
156 article.Version = article.Version + 1 108 article.Version = article.Version + 1
157 article.Images = images 109 article.Images = images
  110 + article.Videos = videos
158 article.WhoRead = whoRead 111 article.WhoRead = whoRead
159 article.WhoReview = whoReview 112 article.WhoReview = whoReview
160 article.TargetUser = domain.ArticleTarget(req.TargetUser) 113 article.TargetUser = domain.ArticleTarget(req.TargetUser)
161 article.Tags = req.Tags 114 article.Tags = req.Tags
162 //文章内容 115 //文章内容
163 - articleSections := []domain.ArticleSection{}  
164 - sortBy := 1  
165 - lo.ForEach(req.Section, func(item types.ArticleSection, index int) {  
166 - strList := strings.Split(item.Content, "\n")  
167 - for key, value := range strList {  
168 - if value == "" {  
169 - continue  
170 - }  
171 - section := domain.ArticleSection{  
172 - CompanyId: article.CompanyId,  
173 - Version: article.Version,  
174 - ArticleId: article.Id,  
175 - Content: value,  
176 - SortBy: sortBy,  
177 - }  
178 - if key == 0 {  
179 - section.Id = item.Id  
180 - }  
181 - articleSections = append(articleSections, section)  
182 - sortBy++  
183 - }  
184 - }) 116 + articleSections := l.getSections(req, article)
185 //设置内容概要 117 //设置内容概要
186 if len(req.Section) > 0 { 118 if len(req.Section) > 0 {
187 // 截取内容 50个字 119 // 截取内容 50个字
@@ -197,7 +129,7 @@ func (l *SystemUpdateArticleLogic) SystemUpdateArticle(req *types.SystemArticleU @@ -197,7 +129,7 @@ func (l *SystemUpdateArticleLogic) SystemUpdateArticle(req *types.SystemArticleU
197 article.Summary = req.Section[0].Content[0:stringIndex] 129 article.Summary = req.Section[0].Content[0:stringIndex]
198 } 130 }
199 131
200 - err = transaction.UseTrans(l.ctx, conn.DB(), func(ctx context.Context, c transaction.Conn) error { 132 + err = transaction.UseTrans(l.ctx, l.conn.DB(), func(ctx context.Context, c transaction.Conn) error {
201 _, err = l.svcCtx.ArticleRepository.Update(l.ctx, c, article) 133 _, err = l.svcCtx.ArticleRepository.Update(l.ctx, c, article)
202 if err != nil { 134 if err != nil {
203 return xerr.NewErrMsgErr("保存文章失败", err) 135 return xerr.NewErrMsgErr("保存文章失败", err)
@@ -238,8 +170,9 @@ func (l *SystemUpdateArticleLogic) SystemUpdateArticle(req *types.SystemArticleU @@ -238,8 +170,9 @@ func (l *SystemUpdateArticleLogic) SystemUpdateArticle(req *types.SystemArticleU
238 return xerr.NewErrMsgErr("保存文章内容失败", err) 170 return xerr.NewErrMsgErr("保存文章内容失败", err)
239 } 171 }
240 //文章定性 172 //文章定性
241 - if len(article.Tags) > 0 {  
242 - 173 + err = l.setTags(c, article)
  174 + if err != nil {
  175 + return err
243 } 176 }
244 return nil 177 return nil
245 }, true) 178 }, true)
@@ -254,9 +187,193 @@ func (l *SystemUpdateArticleLogic) SystemUpdateArticle(req *types.SystemArticleU @@ -254,9 +187,193 @@ func (l *SystemUpdateArticleLogic) SystemUpdateArticle(req *types.SystemArticleU
254 TargetUser: int(article.TargetUser), 187 TargetUser: int(article.TargetUser),
255 Tags: article.Tags, 188 Tags: article.Tags,
256 } 189 }
  190 + _ = copier.Copy(&resp.Videos, videos)
257 return 191 return
258 } 192 }
259 193
  194 +// validateTextLimit 验证输入文本长度
  195 +func (l *SystemUpdateArticleLogic) validateTextLimit(req *types.SystemArticleUpdateRequest) error {
  196 + wordNum := 0
  197 + for i := range req.Section {
  198 + num := utf8.RuneCountInString(req.Section[i].Content)
  199 + wordNum += num
  200 + }
  201 + if wordNum >= 1000 {
  202 + return xerr.NewErrMsg("最多只能输入1000字")
  203 + }
  204 + return nil
  205 +}
  206 +
  207 +// validateAndGetWhoRead 验证并获取可阅读
  208 +func (l *SystemUpdateArticleLogic) validateAndGetWhoRead(req *types.SystemArticleUpdateRequest, article *domain.Article) ([]int64, error) {
  209 + whoRead := make([]int64, 0)
  210 + if len(req.WhoRead) > 0 {
  211 + whoRead = lo.Uniq(req.WhoRead)
  212 + var u *domain.User
  213 + var err error
  214 + for _, val := range whoRead {
  215 + u, err = l.svcCtx.UserRepository.FindOne(l.ctx, l.conn, val)
  216 + if err != nil {
  217 + return whoRead, xerr.NewErrMsgErr("文章可查看人设置错误", err)
  218 + }
  219 + if u.CompanyId != article.CompanyId {
  220 + return whoRead, xerr.NewErrMsg("文章可查看人设置错误")
  221 + }
  222 + }
  223 + }
  224 + return whoRead, nil
  225 +}
  226 +
  227 +// validateWhoReview 验证可评论
  228 +func (l *SystemUpdateArticleLogic) validateWhoReview(whoRead []int64, whoReview []int64, article *domain.Article) error {
  229 + //有指定可查看人的情况
  230 + if len(whoRead) > 0 {
  231 + if len(whoReview) > 0 {
  232 + // 检查 whoRead 是否 完全包含 whoReview
  233 + ok := lo.Every(whoRead, whoReview)
  234 + if !ok {
  235 + return xerr.NewErrMsg("文章可评论人设置错误")
  236 + }
  237 + }
  238 + if len(whoReview) == 0 {
  239 + //有指定可查看人 ,但未指定可评论人
  240 + return xerr.NewErrMsg("文章可评论人设置错误")
  241 + }
  242 + }
  243 + //没有指定可查看人的情况
  244 + if len(whoRead) == 0 {
  245 + if len(whoReview) > 0 {
  246 + // 未指定可查看人(全员可看),有指定可评论人,
  247 + var u *domain.User
  248 + var err error
  249 + for _, val := range whoReview {
  250 + u, err = l.svcCtx.UserRepository.FindOne(l.ctx, l.conn, val)
  251 + if err != nil {
  252 + return xerr.NewErrMsgErr("文章可评论人设置错误", err)
  253 + }
  254 + if u.CompanyId != article.CompanyId {
  255 + return xerr.NewErrMsg("文章可评论人设置错误")
  256 + }
  257 + }
  258 + }
  259 + }
  260 + return nil
  261 +}
  262 +
  263 +// validateTags 验证标签
  264 +func (l *SystemUpdateArticleLogic) validateTags(req *types.SystemArticleUpdateRequest, article *domain.Article) error {
  265 + if len(req.Tags) > 0 {
  266 + req.Tags = lo.Uniq(req.Tags)
  267 + for _, value := range req.Tags {
  268 + t, err := l.svcCtx.ArticleTagRepository.FindOne(l.ctx, l.conn, value)
  269 + if err != nil {
  270 + return xerr.NewErrMsgErr("文章标签设置错误", err)
  271 + }
  272 + if t.CompanyId != article.CompanyId {
  273 + return xerr.NewErrMsgErr("文章标签设置错误", err)
  274 + }
  275 + }
  276 + }
  277 + return nil
  278 +}
  279 +
  280 +// getImages 获取图片信息
  281 +func (l *SystemUpdateArticleLogic) getImages(req *types.SystemArticleUpdateRequest) ([]domain.Image, error) {
  282 + // 获取图片的尺寸大小
  283 + images := make([]domain.Image, 0)
  284 + for _, val := range req.Images {
  285 + fInfo, err := oss.GetImageInfo(val)
  286 + if err != nil {
  287 + return images, xerr.NewErrMsg("获取图片失败")
  288 + }
  289 + w, _ := strconv.Atoi(fInfo.ImageWidth.Value)
  290 + h, _ := strconv.Atoi(fInfo.ImageHeight.Value)
  291 + images = append(images, domain.Image{
  292 + Url: val,
  293 + Width: w,
  294 + Height: h,
  295 + })
  296 + }
  297 + return images, nil
  298 +}
  299 +
  300 +// getVideo 获取视频信息
  301 +func (l *SystemUpdateArticleLogic) getVideos(req *types.SystemArticleUpdateRequest) ([]domain.Video, error) {
  302 + videos := make([]domain.Video, 0)
  303 + if len(req.Videos) > 0 {
  304 + for _, item := range req.Videos {
  305 + cover, w, h, err := oss.GetVideoCover(item.Url)
  306 + if err != nil {
  307 + return videos, xerr.NewErrMsg("获取视频信息失败")
  308 + }
  309 + videos = append(videos, domain.Video{
  310 + Url: item.Url,
  311 + Cover: cover,
  312 + Width: w,
  313 + Height: h,
  314 + })
  315 + }
  316 + }
  317 + return videos, nil
  318 +}
  319 +
  320 +func (l *SystemUpdateArticleLogic) getSections(req *types.SystemArticleUpdateRequest, article *domain.Article) []domain.ArticleSection {
  321 + articleSections := make([]domain.ArticleSection, 0)
  322 + sortBy := 1
  323 + lo.ForEach(req.Section, func(item types.ArticleSection, index int) {
  324 + strList := strings.Split(item.Content, "\n")
  325 + for key, value := range strList {
  326 + if value == "" {
  327 + continue
  328 + }
  329 + section := domain.ArticleSection{
  330 + CompanyId: article.CompanyId,
  331 + Version: article.Version,
  332 + ArticleId: article.Id,
  333 + Content: value,
  334 + SortBy: sortBy,
  335 + }
  336 + if key == 0 {
  337 + section.Id = item.Id
  338 + }
  339 + articleSections = append(articleSections, section)
  340 + sortBy++
  341 + }
  342 + })
  343 + return articleSections
  344 +}
  345 +
  346 +// setTags 设置定性标签
260 func (l *SystemUpdateArticleLogic) setTags(conn transaction.Conn, article *domain.Article) error { 347 func (l *SystemUpdateArticleLogic) setTags(conn transaction.Conn, article *domain.Article) error {
  348 + _, oldTags, err := l.svcCtx.ArticleAndTagRepository.Find(l.ctx, conn, domain.NewQueryOptions().WithFindOnly().WithKV("articleId", article.Id))
  349 + if err != nil {
  350 + return xerr.NewErrMsgErr("检查文章的标签失败", err)
  351 + }
  352 + //删除旧标签
  353 + for _, v := range oldTags {
  354 + _, err = l.svcCtx.ArticleAndTagRepository.Delete(l.ctx, conn, v)
  355 + if err != nil {
  356 + return xerr.NewErrMsg(err.Error())
  357 + }
  358 + }
  359 + if len(article.Tags) > 0 {
  360 + for _, tagId := range article.Tags {
  361 + articleTag := &domain.ArticleAndTag{
  362 + CompanyId: article.CompanyId,
  363 + ArticleId: article.Id,
  364 + TagId: tagId,
  365 + }
  366 + _, err = l.svcCtx.ArticleAndTagRepository.Insert(l.ctx, conn, articleTag)
  367 + if err != nil {
  368 + return xerr.NewErrMsg(err.Error())
  369 + }
  370 + }
  371 + //发送定性通知
  372 + messageLogic := message.NewMiniSystemLogic(l.ctx, l.svcCtx)
  373 + err = messageLogic.ArticleDefined(conn, article.CompanyId, article.AuthorId, article.Title)
  374 + if err != nil {
  375 + return xerr.NewErrMsg(err.Error())
  376 + }
  377 + }
261 return nil 378 return nil
262 } 379 }
@@ -826,10 +826,10 @@ type Location struct { @@ -826,10 +826,10 @@ type Location struct {
826 } 826 }
827 827
828 type Video struct { 828 type Video struct {
829 - Url string `json:"url"` //视频文件的地址  
830 - Cover string `json:"cover"` //封面  
831 - Width int `json:"width"` //封面图片宽  
832 - Height int `json:"height"` //封面图片长 829 + Url string `json:"url"` //视频文件的地址
  830 + Cover string `json:"cover,optional"` //封面
  831 + Width int `json:"width,optional"` //封面图片宽
  832 + Height int `json:"height,optional"` //封面图片长
833 } 833 }
834 834
835 type ArticleAuthor struct { 835 type ArticleAuthor struct {