@@ -3,7 +3,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do
33 CURD and operations for article comments
44 """
55 import Ecto.Query , warn: false
6- import Helper.Utils , only: [ done: 1 , ensure: 2 ]
6+ import Helper.Utils , only: [ done: 1 , ensure: 2 , get_config: 2 ]
77 import Helper.ErrorCode
88
99 import GroupherServer.CMS.Delegate.Helper , only: [ mark_viewer_emotion_states: 3 ]
@@ -13,11 +13,14 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do
1313 alias Helper.Types , as: T
1414 alias Helper . { ORM , QueryBuilder }
1515 alias GroupherServer . { Accounts , CMS , Repo }
16+ alias CMS.Post
1617
1718 alias Accounts.User
1819 alias CMS . { ArticleComment , ArticlePinnedComment , Embeds }
1920 alias Ecto.Multi
2021
22+ @ article_threads get_config ( :article , :threads )
23+
2124 @ max_participator_count ArticleComment . max_participator_count ( )
2225 @ default_emotions Embeds.ArticleCommentEmotion . default_emotions ( )
2326 @ delete_hint ArticleComment . delete_hint ( )
@@ -102,9 +105,10 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do
102105 |> Multi . run ( :update_article_comments_count , fn _ , % { create_article_comment: comment } ->
103106 update_article_comments_count ( comment , :inc )
104107 end )
105- |> Multi . run ( :add_participator , fn _ , _ ->
106- add_participator_to_article ( article , user )
108+ |> Multi . run ( :set_question_flag_ifneed , fn _ , % { create_article_comment: comment } ->
109+ set_question_flag_ifneed ( article , comment )
107110 end )
111+ |> Multi . run ( :add_participator , fn _ , _ -> add_participator_to_article ( article , user ) end )
108112 |> Multi . run ( :update_article_active_timestamp , fn _ , % { create_article_comment: comment } ->
109113 case comment . author_id == article . author . user . id do
110114 true -> { :ok , :pass }
@@ -130,10 +134,74 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do
130134 @ doc """
131135 update a comment for article like psot, job ...
132136 """
137+ # 如果是 solution, 那么要更新对应的 post 的 solution_digest
138+ def update_article_comment ( % ArticleComment { is_solution: true } = article_comment , content ) do
139+ with { :ok , post } <- ORM . find ( Post , article_comment . post_id ) do
140+ post |> ORM . update ( % { solution_digest: content } )
141+ article_comment |> ORM . update ( % { body_html: content } )
142+ end
143+ end
144+
133145 def update_article_comment ( % ArticleComment { } = article_comment , content ) do
134146 article_comment |> ORM . update ( % { body_html: content } )
135147 end
136148
149+ @ doc """
150+ mark a comment as question post's best solution
151+ """
152+ def mark_comment_solution ( comment_id , user ) do
153+ with { :ok , article_comment } <- ORM . find ( ArticleComment , comment_id ) ,
154+ { :ok , post } <- ORM . find ( Post , article_comment . post_id , preload: [ author: :user ] ) do
155+ # 确保只有一个最佳答案
156+ batch_update_solution_flag ( post , false )
157+ CMS . pin_article_comment ( article_comment . id )
158+ do_mark_comment_solution ( post , article_comment , user , true )
159+ end
160+ end
161+
162+ @ doc """
163+ undo mark a comment as question post's best solution
164+ """
165+ def undo_mark_comment_solution ( comment_id , user ) do
166+ with { :ok , article_comment } <- ORM . find ( ArticleComment , comment_id ) ,
167+ { :ok , post } <- ORM . find ( Post , article_comment . post_id , preload: [ author: :user ] ) do
168+ do_mark_comment_solution ( post , article_comment , user , false )
169+ end
170+ end
171+
172+ defp do_mark_comment_solution ( post , % ArticleComment { } = article_comment , user , is_solution ) do
173+ # check if user is questioner
174+ with true <- user . id == post . author . user . id do
175+ Multi . new ( )
176+ |> Multi . run ( :mark_solution , fn _ , _ ->
177+ ORM . update ( article_comment , % { is_solution: is_solution , is_for_question: true } )
178+ end )
179+ |> Multi . run ( :update_post_state , fn _ , _ ->
180+ ORM . update ( post , % { is_solved: is_solution , solution_digest: article_comment . body_html } )
181+ end )
182+ |> Repo . transaction ( )
183+ |> result ( )
184+ else
185+ false -> raise_error ( :require_questioner , "oops, questioner only" )
186+ { :error , error } -> { :error , error }
187+ end
188+ end
189+
190+ @ doc """
191+ batch update is_question flag for post-only article
192+ """
193+ def batch_update_question_flag ( % Post { is_question: is_question } = post ) do
194+ from ( c in ArticleComment ,
195+ where: c . post_id == ^ post . id ,
196+ update: [ set: [ is_for_question: ^ is_question ] ]
197+ )
198+ |> Repo . update_all ( [ ] )
199+
200+ { :ok , :pass }
201+ end
202+
203+ def batch_update_question_flag ( _ ) , do: { :ok , :pass }
204+
137205 @ doc "delete article comment"
138206 def delete_article_comment ( % ArticleComment { } = comment ) do
139207 Multi . new ( )
@@ -155,7 +223,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do
155223 % { article_comments_participators: article_comments_participators } = article ,
156224 % User { } = user
157225 ) do
158- total_participators = article_comments_participators |> List . insert_at ( 0 , user ) |> Enum . uniq ( )
226+ total_participators =
227+ article_comments_participators |> List . insert_at ( 0 , user ) |> Enum . uniq_by ( & & 1 . id )
228+
159229 new_comment_participators = total_participators |> Enum . slice ( 0 , @ max_participator_count )
160230 total_participators_count = length ( total_participators )
161231
@@ -225,10 +295,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do
225295 query
226296 |> where ( ^ thread_query )
227297 |> where ( ^ where_query )
228- # |> QueryBuilder.filter_pack(Map.merge(filters, %{sort: :asc_inserted}))
229298 |> QueryBuilder . filter_pack ( Map . merge ( filters , % { sort: sort } ) )
230299 |> ORM . paginater ( ~m( page size) a )
231- |> add_pined_comments_ifneed ( thread , article_id , filters )
300+ |> add_pinned_comments_ifneed ( thread , article_id , filters )
232301 |> mark_viewer_emotion_states ( user , :comment )
233302 |> mark_viewer_has_upvoted ( user )
234303 |> done ( )
@@ -250,37 +319,57 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do
250319 |> done ( )
251320 end
252321
253- defp add_pined_comments_ifneed ( % { entries: entries } = paged_comments , thread , article_id , % {
254- page: 1
255- } ) do
322+ defp add_pinned_comments_ifneed ( paged_comments , thread , article_id , % { page: 1 } ) do
256323 with { :ok , info } <- match ( thread ) ,
257- query <-
258- from ( p in ArticlePinnedComment ,
259- join: c in ArticleComment ,
260- on: p . article_comment_id == c . id ,
261- where: field ( p , ^ info . foreign_key ) == ^ article_id ,
262- select: c
263- ) ,
264- { :ok , pined_comments } <- Repo . all ( query ) |> done ( ) do
265- case pined_comments do
324+ { :ok , pinned_comments } <- list_pinned_comments ( info , article_id ) do
325+ case pinned_comments do
266326 [ ] ->
267327 paged_comments
268328
269329 _ ->
270- preloaded_pined_comments =
271- Enum . slice ( pined_comments , 0 , @ pinned_comment_limit )
330+ pinned_comments =
331+ sort_solution_to_front ( thread , pinned_comments )
332+ |> Enum . slice ( 0 , @ pinned_comment_limit )
272333 |> Repo . preload ( reply_to: :author )
273334
274- entries = Enum . concat ( preloaded_pined_comments , entries )
275- pined_comment_count = length ( pined_comments )
335+ entries = pinned_comments ++ paged_comments . entries
336+ pinned_comment_count = length ( pinned_comments )
276337
277- total_count = paged_comments . total_count + pined_comment_count
338+ total_count = paged_comments . total_count + pinned_comment_count
278339 paged_comments |> Map . merge ( % { entries: entries , total_count: total_count } )
279340 end
280341 end
281342 end
282343
283- defp add_pined_comments_ifneed ( paged_comments , _thread , _article_id , _ ) , do: paged_comments
344+ defp add_pinned_comments_ifneed ( paged_comments , _thread , _article_id , _ ) , do: paged_comments
345+
346+ defp list_pinned_comments ( % { foreign_key: foreign_key } , article_id ) do
347+ from ( p in ArticlePinnedComment ,
348+ join: c in ArticleComment ,
349+ on: p . article_comment_id == c . id ,
350+ where: field ( p , ^ foreign_key ) == ^ article_id ,
351+ order_by: [ desc: p . inserted_at ] ,
352+ select: c
353+ )
354+ |> Repo . all ( )
355+ |> done
356+ end
357+
358+ # only support post
359+ defp sort_solution_to_front ( :post , pinned_comments ) do
360+ solution_index = Enum . find_index ( pinned_comments , & & 1 . is_solution )
361+
362+ case is_nil ( solution_index ) do
363+ true ->
364+ pinned_comments
365+
366+ false ->
367+ { solution_comment , rest_comments } = List . pop_at ( pinned_comments , solution_index )
368+ [ solution_comment ] ++ rest_comments
369+ end
370+ end
371+
372+ defp sort_solution_to_front ( _ , pinned_comments ) , do: pinned_comments
284373
285374 defp mark_viewer_has_upvoted ( paged_comments , nil ) , do: paged_comments
286375
@@ -294,8 +383,26 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do
294383 Map . merge ( paged_comments , % { entries: entries } )
295384 end
296385
297- defp result ( { :ok , % { create_article_comment: result } } ) , do: { :ok , result }
386+ defp set_question_flag_ifneed ( % { is_question: true } = article , % ArticleComment { } = comment ) do
387+ ORM . update ( comment , % { is_for_question: true } )
388+ end
389+
390+ defp set_question_flag_ifneed ( _ , comment ) , do: ORM . update ( comment , % { is_for_question: false } )
391+
392+ # batch update is_solution flag for artilce comment
393+ defp batch_update_solution_flag ( % Post { } = post , is_question ) do
394+ from ( c in ArticleComment ,
395+ where: c . post_id == ^ post . id ,
396+ update: [ set: [ is_solution: ^ is_question ] ]
397+ )
398+ |> Repo . update_all ( [ ] )
399+
400+ { :ok , :pass }
401+ end
402+
403+ defp result ( { :ok , % { set_question_flag_ifneed: result } } ) , do: { :ok , result }
298404 defp result ( { :ok , % { delete_article_comment: result } } ) , do: { :ok , result }
405+ defp result ( { :ok , % { mark_solution: result } } ) , do: { :ok , result }
299406
300407 defp result ( { :error , :create_article_comment , result , _steps } ) do
301408 raise_error ( :create_comment , result )
0 commit comments