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

Commit 479a4b2

Browse files
committed
refactor: pin & trash system for posts
1 parent 76c20a5 commit 479a4b2

29 files changed

+635
-334
lines changed

Makefile

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,24 @@ launch.dev:
4040
launch.mock:
4141
MIX_ENV=mock mix phx.server
4242
launch.prod:
43-
mix phx.server
43+
MIX_ENV=prod mix phx.server
4444

4545
migrate:
4646
mix ecto.migrate
4747
migrate.mock:
4848
MIX_ENV=mock mix ecto.migrate
4949
rollback:
5050
mix ecto.rollback
51-
migrate.mock:
52-
MIX_ENV=mock mix ecto.migrate
5351
rollback.mock:
54-
MIX_ENV=mock mix ecto.rollback
52+
MIX_ENV=mock mix ecto.rollback
53+
rollback.test:
54+
MIX_ENV=test mix ecto.rollback
5555
migrate.dev:
5656
MIX_ENV=dev mix ecto.migrate
57+
migrate.test:
58+
MIX_ENV=test mix ecto.migrate
5759
rollback.dev:
58-
MIX_ENV=dev mix ecto.rollback
60+
MIX_ENV=dev mix ecto.rollback
5961

6062
gen.help:
6163
$(call gen.help)

lib/helper/certification.ex

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,23 @@ defmodule Helper.Certification do
5353
"post.community.unset",
5454
"job.community.set",
5555
"job.community.unset",
56+
# flag on content
5657
"post.pin",
5758
"post.undo_pin",
5859
"post.trash",
59-
"post.undo_trash"
60+
"post.undo_trash",
61+
"job.pin",
62+
"job.undo_pin",
63+
"job.trash",
64+
"job.undo_trash",
65+
"video.pin",
66+
"video.undo_pin",
67+
"video.trash",
68+
"video.undo_trash",
69+
"repo.pin",
70+
"repo.undo_pin",
71+
"repo.trash",
72+
"repo.undo_trash"
6073
],
6174
community: [
6275
# thread

lib/helper/query_builder.ex

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ defmodule Helper.QueryBuilder do
8888
|> order_by([_, s], {^direction, fragment("count(?)", s.id)})
8989
end
9090

91-
def default_article_filters, do: %{pin: false, trash: false}
92-
9391
def filter_pack(queryable, filter) when is_map(filter) do
9492
Enum.reduce(filter, queryable, fn
9593
{:sort, :desc_inserted}, queryable ->
@@ -186,13 +184,13 @@ defmodule Helper.QueryBuilder do
186184
{:first, first}, queryable ->
187185
queryable |> limit(^first)
188186

189-
{:pin, bool}, queryable ->
190-
queryable
191-
|> where([p], p.pin == ^bool)
187+
# {:pin, bool}, queryable ->
188+
# queryable
189+
# |> where([p], p.pin == ^bool)
192190

193-
{:trash, bool}, queryable ->
194-
queryable
195-
|> where([p], p.trash == ^bool)
191+
# {:trash, bool}, queryable ->
192+
# queryable
193+
# |> where([p], p.trash == ^bool)
196194

197195
{_, _}, queryable ->
198196
queryable

lib/mastani_server/cms/cms.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ defmodule MastaniServer.CMS do
5959

6060
# ArticleOperation
6161
# >> set flag on article, like: pin / unpin article
62-
defdelegate set_flag(queryable, id, attrs, user), to: ArticleOperation
62+
defdelegate set_community_flags(queryable, community_id, attrs), to: ArticleOperation
63+
6364
# >> tag: set / unset
6465
defdelegate set_tag(community, thread, tag, content_id), to: ArticleOperation
6566
defdelegate unset_tag(thread, tag, content_id), to: ArticleOperation

lib/mastani_server/cms/delegates/article_curd.ex

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,39 +21,70 @@ defmodule MastaniServer.CMS.Delegate.ArticleCURD do
2121
get paged post / job ...
2222
"""
2323
def paged_contents(queryable, filter) do
24-
normal_content_fr = filter |> Map.merge(QueryBuilder.default_article_filters())
25-
2624
queryable
27-
|> ORM.find_all(normal_content_fr)
25+
|> flag_query(filter)
26+
|> ORM.find_all(filter)
2827
|> add_pin_contents_ifneed(queryable, filter)
2928
end
3029

30+
defp flag_query(queryable, filter, flag \\ %{}) do
31+
flag = %{pin: false, trash: false} |> Map.merge(flag)
32+
33+
# TODO: remove case judge ?
34+
case filter |> Map.has_key?(:community) do
35+
true ->
36+
queryable
37+
|> join(:inner, [q], f in assoc(q, :community_flags))
38+
|> where([q, f], f.pin == ^flag.pin and f.trash == ^flag.trash)
39+
|> join(:inner, [q, f], c in assoc(f, :community))
40+
|> where([q, f, c], c.raw == ^filter.community)
41+
42+
false ->
43+
# for runing tests usage, no flag when db_insert
44+
queryable
45+
end
46+
end
47+
3148
# only first page need pin contents
3249
defp add_pin_contents_ifneed(contents, queryable, filter) do
3350
with {:ok, normal_contents} <- contents,
51+
true <- Map.has_key?(filter, :community),
3452
true <- 1 == Map.get(normal_contents, :page_number) do
35-
pin_content_fr = filter |> Map.merge(%{pin: true})
36-
{:ok, pined_content} = queryable |> ORM.find_all(pin_content_fr)
53+
{:ok, pined_content} =
54+
queryable
55+
|> flag_query(filter, %{pin: true})
56+
|> ORM.find_all(filter)
57+
58+
# TODO: add hot post pin/trash state ?
59+
# don't by flag_changeset, dataloader make things complex
60+
concat_contents(pined_content, normal_contents)
61+
else
62+
_error ->
63+
contents
64+
end
65+
end
3766

38-
case pined_content |> Map.get(:total_count) do
39-
0 ->
40-
contents
67+
defp concat_contents(pined_content, normal_contents) do
68+
case pined_content |> Map.get(:total_count) do
69+
0 ->
70+
{:ok, normal_contents}
4171

42-
_ ->
43-
pind_entries = pined_content |> Map.get(:entries)
44-
normal_entries = normal_contents |> Map.get(:entries)
72+
_ ->
73+
# NOTE: this is tricy, should use dataloader refactor
74+
pind_entries =
75+
pined_content
76+
|> Map.get(:entries)
77+
|> Enum.map(&struct(&1, %{pin: true}))
4578

46-
normal_count = normal_contents |> Map.get(:total_count)
47-
pind_count = pined_content |> Map.get(:total_count)
79+
normal_entries = normal_contents |> Map.get(:entries)
4880

49-
normal_contents
50-
|> Map.put(:entries, pind_entries ++ normal_entries)
51-
|> Map.put(:total_count, pind_count + normal_count)
52-
|> done
53-
end
54-
else
55-
_error ->
56-
contents
81+
normal_count = normal_contents |> Map.get(:total_count)
82+
pind_count = pined_content |> Map.get(:total_count)
83+
84+
normal_contents
85+
|> Map.put(:entries, pind_entries ++ normal_entries)
86+
|> Map.put(:total_count, pind_count + normal_count)
87+
|> done
5788
end
5889
end
5990

@@ -84,6 +115,21 @@ defmodule MastaniServer.CMS.Delegate.ArticleCURD do
84115
|> Multi.run(:set_community, fn %{add_content_author: content} ->
85116
ArticleOperation.set_community(community, thread, content.id)
86117
end)
118+
|> Multi.run(:set_community_flag, fn %{add_content_author: content} ->
119+
# TODO: remove this judge, as content should have a flag
120+
case action |> Map.has_key?(:flag) do
121+
true ->
122+
ArticleOperation.set_community_flags(content, community.id, %{
123+
pin: false,
124+
trash: false
125+
})
126+
127+
false ->
128+
{:ok, "pass"}
129+
end
130+
131+
# Repo.insert(%CMS.PostCommunityFlags{post_id: content.id, community_id: community.id, })
132+
end)
87133
|> Multi.run(:set_tag, fn %{add_content_author: content} ->
88134
case attrs |> Map.has_key?(:tags) do
89135
true -> set_tags(community, thread, content.id, attrs.tags)
@@ -108,6 +154,10 @@ defmodule MastaniServer.CMS.Delegate.ArticleCURD do
108154
{:error, [message: "set community", code: ecode(:create_fails)]}
109155
end
110156

157+
defp create_content_result({:error, :set_community_flag, _result, _steps}) do
158+
{:error, [message: "set community flag", code: ecode(:create_fails)]}
159+
end
160+
111161
defp create_content_result({:error, :set_tag, result, _steps}) do
112162
{:error, result}
113163
end

lib/mastani_server/cms/delegates/article_operation.ex

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,33 @@ defmodule MastaniServer.CMS.Delegate.ArticleOperation do
55
import MastaniServer.CMS.Utils.Matcher
66
import Ecto.Query, warn: false
77
import Helper.ErrorCode
8+
# import ShortMaps
89

910
alias Helper.ORM
1011
alias MastaniServer.Accounts.User
11-
alias MastaniServer.CMS.{Community, Tag}
12+
alias MastaniServer.CMS.{Community, PinState, Post, PostCommunityFlags, Tag}
1213
alias MastaniServer.Repo
1314

1415
@doc """
1516
pin / unpin, trash / untrash articles
1617
"""
17-
def set_flag(queryable, id, %{pin: _} = attrs, %User{} = _user) do
18-
queryable |> ORM.find_update(id, attrs)
18+
def set_community_flags(%Post{id: post_id}, community_id, attrs) do
19+
with {:ok, post} <- ORM.find(Post, post_id),
20+
{:ok, community} <- ORM.find(Community, community_id),
21+
{:ok, _} <- insert_flag_record(post, community_id, attrs) do
22+
ORM.find(Post, post.id)
23+
end
1924
end
2025

21-
def set_flag(queryable, id, %{trash: _} = attrs, %User{} = _user) do
22-
queryable |> ORM.find_update(id, attrs)
26+
defp insert_flag_record(%Post{id: id}, community_id, attrs) do
27+
clauses = %{
28+
post_id: id,
29+
community_id: community_id
30+
}
31+
32+
attrs = attrs |> Map.merge(clauses)
33+
34+
PostCommunityFlags |> ORM.upsert_by(clauses, attrs)
2335
end
2436

2537
def set_community(%Community{id: community_id}, thread, content_id) when valid_thread(thread) do

lib/mastani_server/cms/post.ex

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,19 @@ defmodule MastaniServer.CMS.Post do
44

55
use Ecto.Schema
66
import Ecto.Changeset
7-
alias MastaniServer.CMS.{Author, Community, PostComment, PostFavorite, PostStar, Tag}
7+
8+
alias MastaniServer.CMS.{
9+
Author,
10+
Community,
11+
PostComment,
12+
PostCommunityFlags,
13+
PostFavorite,
14+
PostStar,
15+
Tag
16+
}
817

918
@required_fields ~w(title body digest length)a
10-
@optional_fields ~w(link_addr pin trash)
19+
@optional_fields ~w(link_addr)a
1120

1221
@type t :: %Post{}
1322
schema "cms_posts" do
@@ -18,14 +27,18 @@ defmodule MastaniServer.CMS.Post do
1827
field(:length, :integer)
1928
field(:views, :integer, default: 0)
2029

21-
field(:pin, :boolean, default_value: false)
22-
field(:trash, :boolean, default_value: false)
30+
# has_many(:pins, {"posts_pins", PostPin})
31+
has_many(:community_flags, {"posts_communities_flags", PostCommunityFlags})
32+
33+
# NOTE: this one is tricky, pin is dynamic changed when return by func: add_pin_contents_ifneed
34+
field(:pin, :boolean, default_value: false, virtual: true)
35+
field(:trash, :boolean, default_value: false, virtual: true)
36+
2337
belongs_to(:author, Author)
2438

2539
# TODO
2640
# 相关文章
2741
# has_may(:related_post, ...)
28-
2942
has_many(:comments, {"posts_comments", PostComment})
3043
has_many(:favorites, {"posts_favorites", PostFavorite})
3144
has_many(:stars, {"posts_stars", PostStar})
@@ -60,4 +73,12 @@ defmodule MastaniServer.CMS.Post do
6073
# |> foreign_key_constraint(:posts_tags, name: :posts_tags_tag_id_fkey)
6174
# |> foreign_key_constraint(name: :posts_tags_tag_id_fkey)
6275
end
76+
77+
@doc """
78+
for update flag
79+
"""
80+
# def flag_changeset(%Post{} = post, attrs) do
81+
# post
82+
# |> cast(attrs, ~w(pin trash)a)
83+
# end
6384
end
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
defmodule MastaniServer.CMS.PostCommunityFlags do
2+
@moduledoc false
3+
alias __MODULE__
4+
5+
use Ecto.Schema
6+
import Ecto.Changeset
7+
alias Helper.Certification
8+
alias MastaniServer.Accounts
9+
alias MastaniServer.CMS.{Community, Post}
10+
11+
@required_fields ~w(post_id community_id)a
12+
@optional_fields ~w(pin trash refined)a
13+
14+
@type t :: %PostCommunityFlags{}
15+
16+
schema "posts_communities_flags" do
17+
belongs_to(:post, Post, foreign_key: :post_id)
18+
belongs_to(:community, Community, foreign_key: :community_id)
19+
20+
field(:pin, :boolean)
21+
field(:refined, :boolean)
22+
field(:trash, :boolean)
23+
24+
timestamps(type: :utc_datetime)
25+
end
26+
27+
@doc false
28+
def changeset(%PostCommunityFlags{} = post_community_flags, attrs) do
29+
post_community_flags
30+
|> cast(attrs, @optional_fields ++ @required_fields)
31+
|> validate_required(@required_fields)
32+
|> foreign_key_constraint(:post_id)
33+
|> foreign_key_constraint(:community_id)
34+
|> unique_constraint(:post_id, name: :posts_communities_flags_post_id_community_id_index)
35+
end
36+
end

lib/mastani_server/cms/utils/matcher.ex

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ defmodule MastaniServer.CMS.Utils.Matcher do
1919
Tag,
2020
Community,
2121
PostCommentLike,
22-
PostCommentDislike
22+
PostCommentDislike,
23+
PostCommunityFlags
2324
}
2425

2526
@support_thread [:post, :video, :repo, :job]
@@ -44,7 +45,9 @@ defmodule MastaniServer.CMS.Utils.Matcher do
4445

4546
def match_action(:post, :star), do: {:ok, %{target: Post, reactor: PostStar, preload: :user}}
4647
def match_action(:post, :tag), do: {:ok, %{target: Post, reactor: Tag}}
47-
def match_action(:post, :community), do: {:ok, %{target: Post, reactor: Community}}
48+
49+
def match_action(:post, :community),
50+
do: {:ok, %{target: Post, reactor: Community, flag: PostCommunityFlags}}
4851

4952
def match_action(:post, :comment),
5053
do: {:ok, %{target: Post, reactor: PostComment, preload: :author}}

0 commit comments

Comments
 (0)