Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Nov 8, 2022. It is now read-only.

Commit617cd3d

Browse files
authored
refactor(cite-task): support cite artilce in side comment (#399)
* refactor(cite-task): support cite artilce in side comment* refactor(cite-task): support cross comment citing* refactor(cite-task): add some inline doc* refactor(cite-task): fmt naming* refactor(cite-task): fix citing self edge-case* refactor(cite-task): fmt
1 parente4e266b commit617cd3d

File tree

13 files changed

+467
-72
lines changed

13 files changed

+467
-72
lines changed

‎lib/groupher_server/cms/delegates/article_curd.ex‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,10 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do
164164
|>Multi.run(:update_user_published_meta,fn_,_->
165165
Accounts.update_published_states(uid,thread)
166166
end)
167-
|>Multi.run(:block_tasks,fn_,%{create_article:article}->
167+
|>Multi.run(:after_tasks,fn_,%{create_article:article}->
168168
Later.run({CiteTasks,:handle,[article]})
169+
Later.run({__MODULE__,:notify_admin_new_article,[article]})
169170
end)
170-
# TODO: run mini tasks
171171
|>Multi.run(:mention_users,fn_,%{create_article:article}->
172172
# article.body |> Jason.decode!() |> 各种小 task
173173
Delivery.mention_from_content(community.raw,thread,article,attrs,%User{id:uid})
@@ -223,6 +223,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do
223223
|>Multi.run(:update_edit_status,fn_,%{update_article:update_article}->
224224
ArticleCommunity.update_edit_status(update_article)
225225
end)
226+
|>Multi.run(:after_tasks,fn_,%{update_article:update_article}->
227+
Later.run({CiteTasks,:handle,[update_article]})
228+
end)
226229
|>Repo.transaction()
227230
|>result()
228231
end
@@ -449,7 +452,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do
449452

450453
# create done
451454
defpresult({:ok,%{set_active_at_timestamp:result}})do
452-
Later.run({__MODULE__,:notify_admin_new_article,[result]})
453455
{:ok,result}
454456
end
455457

‎lib/groupher_server/cms/delegates/cite_tasks.ex‎

Lines changed: 158 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do
2929
importHelper.ErrorCode
3030

3131
aliasGroupherServer.{CMS,Repo}
32-
aliasCMS.Model.CitedContent
32+
aliasCMS.Model.{CitedContent,Comment}
3333
aliasHelper.ORM
3434

3535
aliasEcto.Multi
@@ -38,16 +38,16 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do
3838
@article_threadsget_config(:article,:threads)
3939
@valid_article_prefixEnum.map(@article_threads,&"#{@site_host}/#{&1}/")
4040

41-
defhandle(%{body:body}=article)do
41+
defhandle(%{body:body}=content)do
4242
with{:ok,%{"blocks"=>blocks}}<-Jason.decode(body),
43-
article<-Repo.preload(article,author::user)do
43+
content<-preload_content_author(content)do
4444
Multi.new()
4545
|>Multi.run(:delete_all_cited_contents,fn_,_->
46-
delete_all_cited_contents(article)
46+
delete_all_cited_contents(content)
4747
end)
4848
|>Multi.run(:update_cited_info,fn_,_->
4949
blocks
50-
|>Enum.reduce([],&(&2++parse_cited_info_per_block(article,&1)))
50+
|>Enum.reduce([],&(&2++parse_cited_info_per_block(content,&1)))
5151
|>merge_same_cited_article_block
5252
|>update_cited_info
5353
end)
@@ -56,9 +56,17 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do
5656
end
5757
end
5858

59+
defpreload_content_author(%Comment{}=comment),do:comment
60+
defpreload_content_author(article),do:Repo.preload(article,author::user)
61+
5962
# delete all records before insert_all, this will dynamiclly update
6063
# those cited info when update article
6164
# 插入引用记录之前先全部清除,这样可以在更新文章的时候自动计算引用信息
65+
defpdelete_all_cited_contents(%Comment{}=comment)do
66+
query=from(cinCitedContent,where:c.comment_id==^comment.id)
67+
ORM.delete_all(query,:if_exist)
68+
end
69+
6270
defpdelete_all_cited_contents(article)do
6371
with{:ok,thread}<-thread_of_article(article),
6472
{:ok,info}<-match(thread)do
@@ -68,15 +76,18 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do
6876
end
6977
end
7078

71-
# defp batch_done
72-
79+
# batch insert CitedContent record and update citing count
7380
defpupdate_cited_info(cited_contents)do
74-
clean_cited_contents=Enum.map(cited_contents,&Map.delete(&1,:cited_article))
75-
# IO.inspect(clean_cited_contents, label: "clean_cited_contents")
76-
withtrue<-{0,nil}!==Repo.insert_all(CitedContent,clean_cited_contents)do
77-
update_citing_count(cited_contents)
78-
else
79-
_->{:error,"insert cited content error"}
81+
# see: https://github.com/elixir-ecto/ecto/issues/1932#issuecomment-314083252
82+
clean_cited_contents=
83+
cited_contents
84+
|>Enum.map(&(&1|>Map.merge(%{inserted_at:&1.citing_time,updated_at:&1.citing_time})))
85+
|>Enum.map(&Map.delete(&1,:cited_content))
86+
|>Enum.map(&Map.delete(&1,:citing_time))
87+
88+
case{0,nil}!==Repo.insert_all(CitedContent,clean_cited_contents)do
89+
true->update_citing_count(cited_contents)
90+
false->{:error,"insert cited content error"}
8091
end
8192
end
8293

@@ -85,10 +96,10 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do
8596
count_query=from(cinCitedContent,where:c.cited_by_id==^content.cited_by_id)
8697
count=Repo.aggregate(count_query,:count)
8798

88-
cited_article=content.cited_article
89-
meta=Map.merge(cited_article.meta,%{citing_count:count})
99+
cited_content=content.cited_content
100+
meta=Map.merge(cited_content.meta,%{citing_count:count})
90101

91-
casecited_article|>ORM.update_meta(meta)do
102+
casecited_content|>ORM.update_meta(meta)do
92103
{:ok,_}->true
93104
{:error,_}->false
94105
end
@@ -140,47 +151,56 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do
140151
block_linker: ["block-ZgKJs"],
141152
cited_by_id: 190057,
142153
cited_by_type: "POST",
143-
cited_article: #loaded,
154+
cited_content: #loaded,
144155
post_id: 190059,
145156
user_id: 1413053
146157
}
147158
...
148159
]
149160
"""
150-
defpparse_cited_info_per_block(article,%{"id"=>block_id,"data"=>%{"text"=>text}})do
151-
links_in_block=Floki.find(text,"a[href]")
152-
153-
Enum.reduce(links_in_block,[],fnlink,acc->
154-
with{:ok,cited_article}<-parse_cited_article(link),
155-
# do not cite artilce itself
156-
true<-article.id!==cited_article.iddo
157-
List.insert_at(acc,0,shape_cited_content(article,cited_article,block_id))
158-
else
161+
defpparse_cited_info_per_block(content,%{"id"=>block_id,"data"=>%{"text"=>text}})do
162+
links=Floki.find(text,"a[href]")
163+
164+
do_parse_cited_info_per_block(content,block_id,links)
165+
end
166+
167+
# links Floki parsed fmt
168+
# content means both article and comment
169+
# e.g:
170+
# [{"a", [{"href", "https://coderplanets.com/post/195675"}], []},]
171+
defpdo_parse_cited_info_per_block(content,block_id,links)do
172+
Enum.reduce(links,[],fnlink,acc->
173+
caseparse_valid_cited(content.id,link)do
174+
{:ok,cited}->List.insert_at(acc,0,shape_cited(content,cited,block_id))
159175
_->acc
160176
end
161177
end)
162178
|>Enum.uniq()
163179
end
164180

165-
defpshape_cited_content(article,cited_article,block_id)do
166-
{:ok,thread}=thread_of_article(article)
167-
{:ok,info}=match(thread)
168-
169-
%{
170-
cited_by_id:cited_article.id,
171-
cited_by_type:cited_article.meta.thread,
172-
# used for updating citing_count, avoid load again
173-
cited_article:cited_article,
174-
block_linker:[block_id],
175-
user_id:article.author.user.id
176-
}
177-
|>Map.put(info.foreign_key,article.id)
181+
# parse cited with check if citing link is point to itself
182+
defpparse_valid_cited(content_id,link)do
183+
with{:ok,cited}<-parse_cited(link),
184+
%{content:content}<-citeddo
185+
casecontent.id!==content_iddo
186+
true->{:ok,cited}
187+
false->{:error,"citing itself"}
188+
end
189+
end
178190
end
179191

180-
defpparse_cited_article({"a",attrs,_})do
192+
# return fmt: %{type: :comment | :article, content: %Comment{} | Article}
193+
# 要考虑是否有 comment_id 的情况,如果有,那么 就应该 load comment 而不是 article
194+
defpparse_cited({"a",attrs,_})do
181195
with{:ok,link}<-parse_link(attrs),
182196
true<-is_site_article_link?(link)do
183-
load_cited_article_from_url(link)
197+
# IO.inspect(link, label: "parse link")
198+
# IO.inspect(is_comment_link?(link), label: "is_comment_link")
199+
200+
caseis_comment_link?(link)do
201+
true->load_cited_comment_from_url(link)
202+
false->load_cited_article_from_url(link)
203+
end
184204
end
185205
end
186206

@@ -204,6 +224,26 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do
204224
Enum.any?(@valid_article_prefix,&String.starts_with?(url,&1))
205225
end
206226

227+
defpis_comment_link?(url)do
228+
with%{query:query}<-URI.parse(url)do
229+
notis_nil(query)andString.starts_with?(query,"comment_id=")
230+
end
231+
end
232+
233+
defpload_cited_comment_from_url(url)do
234+
%{query:query}=URI.parse(url)
235+
236+
trydo
237+
comment_id=URI.decode_query(query)|>Map.get("comment_id")
238+
239+
with{:ok,comment}<-ORM.find(Comment,comment_id)do
240+
{:ok,%{type::comment,content:comment}}
241+
end
242+
rescue
243+
_->{:error,"load comment error"}
244+
end
245+
end
246+
207247
# get cited article from url
208248
# e.g: https://coderplanets.com/post/189993 -> ORM.find(Post, 189993)
209249
defpload_cited_article_from_url(url)do
@@ -212,11 +252,86 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do
212252
thread=path_list|>Enum.at(1)|>String.downcase()|>String.to_atom()
213253
article_id=path_list|>Enum.at(2)
214254

215-
with{:ok,info}<-match(thread)do
216-
ORM.find(info.model,article_id)
255+
with{:ok,info}<-match(thread),
256+
{:ok,article}<-ORM.find(info.model,article_id)do
257+
{:ok,%{type::article,content:article}}
217258
end
218259
end
219260

261+
# cite article in comment
262+
# 在评论中引用文章
263+
defpshape_cited(%Comment{}=comment,%{type::article,content:cited},block_id)do
264+
%{
265+
cited_by_id:cited.id,
266+
cited_by_type:cited.meta.thread,
267+
comment_id:comment.id,
268+
block_linker:[block_id],
269+
user_id:comment.author_id,
270+
# extra fields for next-step usage
271+
# used for updating citing_count, avoid load again
272+
cited_content:cited,
273+
# for later insert all
274+
citing_time:comment.updated_at|>DateTime.truncate(:second)
275+
}
276+
end
277+
278+
# cite comment in comment
279+
# 评论中引用评论
280+
defpshape_cited(%Comment{}=comment,%{type::comment,content:cited},block_id)do
281+
%{
282+
cited_by_id:cited.id,
283+
cited_by_type:"COMMENT",
284+
comment_id:comment.id,
285+
block_linker:[block_id],
286+
user_id:comment.author_id,
287+
# extra fields for next-step usage
288+
# used for updating citing_count, avoid load again
289+
cited_content:cited,
290+
# for later insert all
291+
citing_time:comment.updated_at|>DateTime.truncate(:second)
292+
}
293+
end
294+
295+
# cite article in article
296+
# 文章之间相互引用
297+
defpshape_cited(article,%{type::article,content:cited},block_id)do
298+
{:ok,thread}=thread_of_article(article)
299+
{:ok,info}=match(thread)
300+
301+
%{
302+
cited_by_id:cited.id,
303+
cited_by_type:cited.meta.thread,
304+
block_linker:[block_id],
305+
user_id:article.author.user.id,
306+
# extra fields for next-step usage
307+
# used for updating citing_count, avoid load again
308+
cited_content:cited,
309+
# for later insert all
310+
citing_time:article.updated_at|>DateTime.truncate(:second)
311+
}
312+
|>Map.put(info.foreign_key,article.id)
313+
end
314+
315+
# cite comment in article
316+
# 文章中引用评论
317+
defpshape_cited(article,%{type::comment,content:cited},block_id)do
318+
{:ok,thread}=thread_of_article(article)
319+
{:ok,info}=match(thread)
320+
321+
%{
322+
cited_by_id:cited.id,
323+
cited_by_type:"COMMENT",
324+
block_linker:[block_id],
325+
user_id:article.author.user.id,
326+
# extra fields for next-step usage
327+
# used for updating citing_count, avoid load again
328+
cited_content:cited,
329+
# for later insert all
330+
citing_time:article.updated_at|>DateTime.truncate(:second)
331+
}
332+
|>Map.put(info.foreign_key,article.id)
333+
end
334+
220335
defpresult({:ok,%{update_cited_info:result}}),do:{:ok,result}
221336

222337
defpresult({:error,:update_cited_info,_result,_steps})do

‎lib/groupher_server/cms/delegates/comment_curd.ex‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ defmodule GroupherServer.CMS.Delegate.CommentCurd do
1111
importShortMaps
1212

1313
aliasHelper.Types,as:T
14-
aliasHelper.{ORM,QueryBuilder,Converter}
14+
aliasHelper.{Later,ORM,QueryBuilder,Converter}
1515
aliasGroupherServer.{Accounts,CMS,Repo}
1616
aliasCMS.Model.Post
1717

@@ -113,6 +113,9 @@ defmodule GroupherServer.CMS.Delegate.CommentCurd do
113113
false->CMS.update_active_timestamp(thread,article)
114114
end
115115
end)
116+
|>Multi.run(:block_tasks,fn_,%{create_comment:create_comment}->
117+
Later.run({CiteTasks,:handle,[create_comment]})
118+
end)
116119
|>Repo.transaction()
117120
|>result()
118121
else

‎lib/groupher_server/cms/models/cited_content.ex‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ defmodule GroupherServer.CMS.Model.CitedContent do
1313

1414
aliasCMS.Model.Comment
1515

16-
@timestamps_opts[type::utc_datetime_usec]
16+
@timestamps_opts[type::utc_datetime]
1717

1818
@required_fields~w(cited_by_type cited_by_id user_id)a
1919
@article_cast_fieldsgeneral_article_fields(:cast)

‎lib/groupher_server/cms/models/embeds/comment_meta.ex‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ defmodule GroupherServer.CMS.Model.Embeds.CommentMeta do
77

88
importEcto.Changeset
99

10-
@optional_fields~w(is_article_author_upvoted report_count is_reply_to_others reported_count reported_user_ids)a
10+
@optional_fields~w(is_article_author_upvoted report_count is_reply_to_others reported_count reported_user_ids citing_count)a
1111

1212
@doc"for test usage"
1313
defdefault_meta()do
@@ -17,7 +17,8 @@ defmodule GroupherServer.CMS.Model.Embeds.CommentMeta do
1717
report_count:0,
1818
upvoted_user_ids:[],
1919
reported_user_ids:[],
20-
reported_count:0
20+
reported_count:0,
21+
citing_count:0
2122
}
2223
end
2324

@@ -31,6 +32,7 @@ defmodule GroupherServer.CMS.Model.Embeds.CommentMeta do
3132
field(:upvoted_user_ids,{:array,:integer},default:[])
3233
field(:reported_user_ids,{:array,:integer},default:[])
3334
field(:reported_count,:integer,default:0)
35+
field(:citing_count,:integer,default:0)
3436
end
3537

3638
defchangeset(struct,params)do
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
defmoduleGroupherServer.Repo.Migrations.MissingTimestampForCiteContentsdo
2+
useEcto.Migration
3+
4+
defchangedo
5+
altertable(:cited_contents)do
6+
timestamps()
7+
end
8+
end
9+
end

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp