Skip to content
This repository was archived by the owner on Nov 8, 2022. It is now read-only.

Commit 9a59768

Browse files
authored
refactor(article-tags): rewrite ... (#363)
* refactor(article-tags): wip * refactor(article-tags): wip * refactor(article-tags): use one table to handle them all * refactor(article-tags): use macro to extract * refactor(article-tags): basic tag test * refactor(article-tags): wip * refactor(article-tags): wip * refactor(article-tags): wip * refactor(article-tags): wip * refactor(article-tags): remove old tags system * refactor(article-tags): naming * refactor(article-tags): fix tests * refactor(article-tags): fix tests * refactor(article-tags): fix tests * refactor(article-tags): add group field support * refactor(article-tags): add group field support * refactor(article-tags): add article_tag & community filter test
1 parent 2b1c9f6 commit 9a59768

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1677
-1419
lines changed

cover/excoveralls.json

+1-1
Large diffs are not rendered by default.

docs/testing/unit-testing.zh-CN.md

+5-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
### 单元测试
32

43
单元测试部分全部位于 `test/groupher_server/` 目录下, 按照接口的 Context 分为
@@ -7,13 +6,13 @@
76
accounts billing cms delivery logs seeds statistics
87
```
98

10-
> Phoenix 使用 ExUnit(link) 作为测试模块,测试文件必须以 '_test.exs' 作为结尾,否则会被忽略。
9+
> Phoenix 使用 ExUnit(link) 作为测试模块,测试文件必须以 '\_test.exs' 作为结尾,否则会被忽略。
1110
1211
#### 运行测试
1312

1413
在项目根目录执行 `make test` 即可运行所有测试, 你也可以使用 `make test.watch`
1514
`make test.watch.wip` 以 watch mode 运行全部或其中一部分测试。 更多命令可以使用
16-
`make test.help` 查看:
15+
`make test.help` 查看:
1716

1817
```text
1918
@@ -38,7 +37,7 @@ accounts billing cms delivery logs seeds statistics
3837

3938
#### Helper 函数
4039

41-
以一个实际例子作为说明:
40+
以一个实际例子作为说明:
4241

4342
```elixir
4443
defmodule GroupherServer.Test.CMS do
@@ -60,9 +59,9 @@ defmodule GroupherServer.Test.CMS do
6059

6160
describe "[cms tag]" do
6261
test "create tag with valid data", ~m(community user)a do
63-
valid_attrs = mock_attrs(:tag)
62+
valid_attrs = mock_attrs(:article_tag)
6463

65-
{:ok, tag} = CMS.create_tag(community, :post, valid_attrs, %User{id: user.id})
64+
{:ok, tag} = CMS.create_article_tag(community, :post, valid_attrs, %User{id: user.id})
6665
assert tag.title == valid_attrs.title
6766
end
6867
end
@@ -81,8 +80,3 @@ use GroupherServer.TestTools
8180
3. 这里测试的都是 `lib/groupher_server` 下的模块,不涉及 Graphql
8281

8382
4. 更多的技巧你可以参照文档或现有的测试用例,通常它们都浅显易懂。
84-
85-
86-
87-
88-

lib/groupher_server/accounts/delegates/collect_folder.ex

+2-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,8 @@ defmodule GroupherServer.Accounts.Delegate.CollectFolder do
233233

234234
query
235235
|> filter_thread_ifneed(filter)
236-
|> QueryBuilder.filter_pack(filter)
236+
# delete thread in filter for now, otherwise it will crash querybuilder, because thread not exsit on CollectFolder
237+
|> QueryBuilder.filter_pack(filter |> Map.delete(:thread))
237238
|> ORM.paginater(page: page, size: size)
238239
|> done()
239240
end
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
defmodule GroupherServer.CMS.ArticleTag do
2+
@moduledoc false
3+
alias __MODULE__
4+
5+
use Ecto.Schema
6+
use Accessible
7+
8+
import Ecto.Changeset
9+
10+
alias GroupherServer.CMS
11+
alias CMS.{Author, Community}
12+
13+
@required_fields ~w(thread title color author_id community_id)a
14+
@updatable_fields ~w(thread title color community_id group)a
15+
16+
@type t :: %ArticleTag{}
17+
schema "article_tags" do
18+
field(:title, :string)
19+
field(:color, :string)
20+
field(:thread, :string)
21+
field(:group, :string)
22+
23+
belongs_to(:community, Community)
24+
belongs_to(:author, Author)
25+
26+
timestamps(type: :utc_datetime)
27+
end
28+
29+
def changeset(%ArticleTag{} = tag, attrs) do
30+
tag
31+
|> cast(attrs, @required_fields ++ @updatable_fields)
32+
|> validate_required(@required_fields)
33+
|> foreign_key_constraint(:user_id)
34+
|> foreign_key_constraint(:community_id)
35+
end
36+
37+
def update_changeset(%ArticleTag{} = tag, attrs) do
38+
tag
39+
|> cast(attrs, @updatable_fields)
40+
|> foreign_key_constraint(:user_id)
41+
|> foreign_key_constraint(:community_id)
42+
end
43+
end

lib/groupher_server/cms/cms.ex

+9-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ defmodule GroupherServer.CMS do
1717
ArticleUpvote,
1818
ArticleCommentAction,
1919
ArticleCommentEmotion,
20+
ArticleTag,
2021
CommentCURD,
2122
CommunitySync,
2223
CommunityCURD,
@@ -43,10 +44,16 @@ defmodule GroupherServer.CMS do
4344
defdelegate create_thread(attrs), to: CommunityCURD
4445
defdelegate count(community, part), to: CommunityCURD
4546
# >> tag
47+
defdelegate create_article_tag(community, thread, attrs, user), to: ArticleTag
48+
defdelegate update_article_tag(tag_id, attrs), to: ArticleTag
49+
defdelegate delete_article_tag(tag_id), to: ArticleTag
50+
defdelegate set_article_tag(thread, article_id, tag_id), to: ArticleTag
51+
defdelegate unset_article_tag(thread, article_id, tag_id), to: ArticleTag
52+
defdelegate paged_article_tags(filter), to: ArticleTag
53+
4654
defdelegate create_tag(community, thread, attrs, user), to: CommunityCURD
4755
defdelegate update_tag(attrs), to: CommunityCURD
48-
defdelegate get_tags(community, thread), to: CommunityCURD
49-
defdelegate get_tags(filter), to: CommunityCURD
56+
5057
# >> wiki & cheatsheet (sync with github)
5158
defdelegate get_wiki(community), to: CommunitySync
5259
defdelegate get_cheatsheet(community), to: CommunitySync

lib/groupher_server/cms/delegates/abuse_report.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ defmodule GroupherServer.CMS.Delegate.AbuseReport do
1313
alias GroupherServer.{Accounts, CMS, Repo}
1414

1515
alias Accounts.User
16-
alias CMS.{Community, AbuseReport, ArticleComment, Embeds}
16+
alias CMS.{AbuseReport, ArticleComment, Embeds}
1717

1818
alias Ecto.Multi
1919

lib/groupher_server/cms/delegates/article_community.ex

+1-42
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleCommunity do
1313
alias Helper.Types, as: T
1414
alias Helper.ORM
1515

16-
alias GroupherServer.CMS.{Embeds, Community, Tag, PinnedArticle}
16+
alias GroupherServer.CMS.{Embeds, Community, PinnedArticle}
1717
alias GroupherServer.Repo
1818

1919
alias Ecto.Multi
@@ -128,47 +128,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleCommunity do
128128
defp result({:ok, %{mirror_target_community: result}}), do: result |> done()
129129
defp result({:error, _, result, _steps}), do: {:error, result}
130130

131-
@doc """
132-
set general tag for post / tuts ...
133-
"""
134-
# check community first
135-
def set_tag(thread, %Tag{id: tag_id}, content_id) do
136-
with {:ok, action} <- match_action(thread, :tag),
137-
{:ok, content} <- ORM.find(action.target, content_id, preload: :tags),
138-
{:ok, tag} <- ORM.find(action.reactor, tag_id) do
139-
update_content_tag(content, tag)
140-
141-
# NOTE: this should be control by Middleware
142-
# case tag_in_community_thread?(%Community{id: communitId}, thread, tag) do
143-
# true ->
144-
# content
145-
# |> Ecto.Changeset.change()
146-
# |> Ecto.Changeset.put_assoc(:tags, content.tags ++ [tag])
147-
# |> Repo.update()
148-
149-
# _ ->
150-
# {:error, message: "Tag,Community,Thread not match", code: ecode(:custom)}
151-
# end
152-
end
153-
end
154-
155-
def unset_tag(thread, %Tag{id: tag_id}, content_id) do
156-
with {:ok, action} <- match_action(thread, :tag),
157-
{:ok, content} <- ORM.find(action.target, content_id, preload: :tags),
158-
{:ok, tag} <- ORM.find(action.reactor, tag_id) do
159-
update_content_tag(content, tag, :drop)
160-
end
161-
end
162-
163-
defp update_content_tag(content, %Tag{} = tag, opt \\ :add) do
164-
new_tags = if opt == :add, do: content.tags ++ [tag], else: content.tags -- [tag]
165-
166-
content
167-
|> Ecto.Changeset.change()
168-
|> Ecto.Changeset.put_assoc(:tags, new_tags)
169-
|> Repo.update()
170-
end
171-
172131
@doc "update isEdited meta label if needed"
173132
# TODO: diff history
174133
def update_edit_status(%{meta: %Embeds.ArticleMeta{is_edited: false} = meta} = content) do

lib/groupher_server/cms/delegates/article_curd.ex

+11-50
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do
55
import Ecto.Query, warn: false
66

77
import GroupherServer.CMS.Helper.Matcher2
8-
import GroupherServer.CMS.Helper.Matcher, only: [match_action: 2]
98

109
import Helper.Utils,
1110
only: [done: 1, pick_by: 2, integerfy: 1, strip_struct: 1, module_to_thread: 1]
@@ -18,9 +17,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do
1817
alias GroupherServer.{Accounts, CMS, Delivery, Email, Repo, Statistics}
1918

2019
alias Accounts.User
21-
alias CMS.{Author, Community, PinnedArticle, Embeds, Delegate, Tag}
20+
alias CMS.{Author, Community, PinnedArticle, Embeds, Delegate}
2221

23-
alias Delegate.ArticleCommunity
22+
alias Delegate.{ArticleCommunity, ArticleTag}
2423

2524
alias Ecto.Multi
2625

@@ -71,7 +70,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do
7170

7271
with {:ok, info} <- match(thread) do
7372
info.model
74-
# TODO: trash -> mark_delete
7573
|> domain_filter_query(filter)
7674
|> QueryBuilder.filter_pack(Map.merge(filter, %{mark_delete: false}))
7775
|> ORM.paginater(~m(page size)a)
@@ -125,17 +123,17 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do
125123
"""
126124
def create_article(%Community{id: cid}, thread, attrs, %User{id: uid}) do
127125
with {:ok, author} <- ensure_author_exists(%User{id: uid}),
128-
{:ok, action} <- match_action(thread, :community),
126+
{:ok, info} <- match(thread),
129127
{:ok, community} <- ORM.find(Community, cid) do
130128
Multi.new()
131129
|> Multi.run(:create_article, fn _, _ ->
132-
do_create_article(action.target, attrs, author, community)
130+
do_create_article(info.model, attrs, author, community)
133131
end)
134132
|> Multi.run(:mirror_article, fn _, %{create_article: article} ->
135133
ArticleCommunity.mirror_article(thread, article.id, community.id)
136134
end)
137-
|> Multi.run(:set_tag, fn _, %{create_article: article} ->
138-
exec_set_tag(thread, article.id, attrs)
135+
|> Multi.run(:set_article_tags, fn _, %{create_article: article} ->
136+
ArticleTag.set_article_tags(community, thread, article, attrs)
139137
end)
140138
|> Multi.run(:mention_users, fn _, %{create_article: article} ->
141139
Delivery.mention_from_content(community.raw, thread, article, attrs, %User{id: uid})
@@ -184,10 +182,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do
184182
|> Multi.run(:update_edit_status, fn _, %{update_article: update_article} ->
185183
ArticleCommunity.update_edit_status(update_article)
186184
end)
187-
|> Multi.run(:update_tag, fn _, _ ->
188-
# TODO: move it to ArticleCommunity module
189-
exec_update_tags(article, args)
190-
end)
191185
|> Repo.transaction()
192186
|> update_article_result()
193187
end
@@ -316,7 +310,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do
316310
defp add_pin_articles_ifneed(articles, _querable, _filter), do: articles
317311

318312
# if filter contains like: tags, sort.., then don't add pin article
319-
defp should_add_pin?(%{page: 1, tag: :all, sort: :desc_inserted} = _filter) do
313+
# TODO: tag
314+
# defp should_add_pin?(%{page: 1, article_tag: :all, sort: :desc_inserted} = _filter) do
315+
defp should_add_pin?(%{page: 1, sort: :desc_inserted} = _filter) do
320316
{:ok, :pass}
321317
end
322318

@@ -366,7 +362,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do
366362
{:error, [message: "set community flag", code: ecode(:create_fails)]}
367363
end
368364

369-
defp create_article_result({:error, :set_tag, result, _steps}) do
365+
defp create_article_result({:error, :set_article_tags, result, _steps}) do
370366
{:error, result}
371367
end
372368

@@ -386,43 +382,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do
386382
|> Repo.insert()
387383
end
388384

389-
defp exec_set_tag(thread, id, %{tags: tags}) do
390-
try do
391-
Enum.each(tags, fn tag ->
392-
{:ok, _} = ArticleCommunity.set_tag(thread, %Tag{id: tag.id}, id)
393-
end)
394-
395-
{:ok, "psss"}
396-
rescue
397-
_ -> {:error, [message: "set tag", code: ecode(:create_fails)]}
398-
end
399-
end
400-
401-
defp exec_set_tag(_thread, _id, _attrs), do: {:ok, :pass}
402-
403-
# except Job, other article will just pass, should use set_tag function instead
385+
# except Job, other article will just pass, should use set_article_tags function instead
404386
# defp exec_update_tags(_, _tags_ids), do: {:ok, :pass}
405387

406-
defp exec_update_tags(_article, %{tags: tags_ids}) when tags_ids == [], do: {:ok, :pass}
407-
408-
defp exec_update_tags(article, %{tags: tags_ids}) do
409-
with {:ok, article} <- ORM.find(article.__struct__, article.id, preload: :tags) do
410-
tags =
411-
Enum.reduce(tags_ids, [], fn t, acc ->
412-
{:ok, tag} = ORM.find(Tag, t.id)
413-
414-
acc ++ [tag]
415-
end)
416-
417-
article
418-
|> Ecto.Changeset.change()
419-
|> Ecto.Changeset.put_assoc(:tags, tags)
420-
|> Repo.update()
421-
end
422-
end
423-
424-
defp exec_update_tags(_article, _), do: {:ok, :pass}
425-
426388
defp update_viewed_user_list(%{meta: nil} = article, user_id) do
427389
new_ids = Enum.uniq([user_id] ++ @default_article_meta.viewed_user_ids)
428390
meta = @default_article_meta |> Map.merge(%{viewed_user_ids: new_ids})
@@ -446,7 +408,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do
446408

447409
defp update_article_result({:ok, %{update_edit_status: result}}), do: {:ok, result}
448410
defp update_article_result({:error, :update_article, result, _steps}), do: {:error, result}
449-
defp update_article_result({:error, :update_tag, result, _steps}), do: {:error, result}
450411

451412
defp read_result({:ok, %{inc_views: result}}), do: result |> done()
452413

0 commit comments

Comments
 (0)