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

Commit 98001e5

Browse files
committed
Merge branch 'flag-enhance' into dev
2 parents 76c20a5 + 01c91fd commit 98001e5

Some content is hidden

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

45 files changed

+1534
-336
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: 30 additions & 2 deletions
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
@@ -74,12 +87,27 @@ defmodule Helper.Certification do
7487
"post.tag.delete",
7588
"post.tag.set",
7689
"post.tag.unset",
90+
# post flag
91+
"post.pin",
92+
"post.undo_pin",
93+
"post.trash",
94+
"post.undo_trash",
7795
# job tag
7896
"job.tag.create",
7997
"job.tag.update",
8098
"job.tag.delete",
8199
"job.tag.set",
82-
"job.tag.unset"
100+
"job.tag.unset",
101+
# job flag
102+
"job.pin",
103+
"job.undo_pin",
104+
"job.trash",
105+
"job.undo_trash",
106+
# video flag
107+
"video.pin",
108+
"video.undo_pin",
109+
"video.trash",
110+
"video.undo_trash"
83111
]
84112
}
85113
end

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: 70 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,39 +21,69 @@ 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+
# NOTE: this case judge is used for test case
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+
queryable
44+
end
45+
end
46+
3147
# only first page need pin contents
3248
defp add_pin_contents_ifneed(contents, queryable, filter) do
3349
with {:ok, normal_contents} <- contents,
50+
true <- Map.has_key?(filter, :community),
3451
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)
52+
{:ok, pined_content} =
53+
queryable
54+
|> flag_query(filter, %{pin: true})
55+
|> ORM.find_all(filter)
56+
57+
# TODO: add hot post pin/trash state ?
58+
# don't by flag_changeset, dataloader make things complex
59+
concat_contents(pined_content, normal_contents)
60+
else
61+
_error ->
62+
contents
63+
end
64+
end
3765

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

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

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

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
80+
normal_count = normal_contents |> Map.get(:total_count)
81+
pind_count = pined_content |> Map.get(:total_count)
82+
83+
normal_contents
84+
|> Map.put(:entries, pind_entries ++ normal_entries)
85+
|> Map.put(:total_count, pind_count + normal_count)
86+
|> done
5787
end
5888
end
5989

@@ -84,6 +114,21 @@ defmodule MastaniServer.CMS.Delegate.ArticleCURD do
84114
|> Multi.run(:set_community, fn %{add_content_author: content} ->
85115
ArticleOperation.set_community(community, thread, content.id)
86116
end)
117+
|> Multi.run(:set_community_flag, fn %{add_content_author: content} ->
118+
# TODO: remove this judge, as content should have a flag
119+
case action |> Map.has_key?(:flag) do
120+
true ->
121+
ArticleOperation.set_community_flags(content, community.id, %{
122+
pin: false,
123+
trash: false
124+
})
125+
126+
false ->
127+
{:ok, "pass"}
128+
end
129+
130+
# Repo.insert(%CMS.PostCommunityFlag{post_id: content.id, community_id: community.id, })
131+
end)
87132
|> Multi.run(:set_tag, fn %{add_content_author: content} ->
88133
case attrs |> Map.has_key?(:tags) do
89134
true -> set_tags(community, thread, content.id, attrs.tags)
@@ -108,6 +153,10 @@ defmodule MastaniServer.CMS.Delegate.ArticleCURD do
108153
{:error, [message: "set community", code: ecode(:create_fails)]}
109154
end
110155

156+
defp create_content_result({:error, :set_community_flag, _result, _steps}) do
157+
{:error, [message: "set community flag", code: ecode(:create_fails)]}
158+
end
159+
111160
defp create_content_result({:error, :set_tag, result, _steps}) do
112161
{:error, result}
113162
end

lib/mastani_server/cms/delegates/article_operation.ex

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,72 @@ 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+
13+
alias MastaniServer.CMS.{
14+
Community,
15+
Post,
16+
PostCommunityFlag,
17+
Job,
18+
JobCommunityFlag,
19+
RepoCommunityFlag,
20+
Video,
21+
VideoCommunityFlag,
22+
Tag
23+
}
24+
25+
alias MastaniServer.CMS.Repo, as: CMSRepo
1226
alias MastaniServer.Repo
1327

1428
@doc """
1529
pin / unpin, trash / untrash articles
1630
"""
17-
def set_flag(queryable, id, %{pin: _} = attrs, %User{} = _user) do
18-
queryable |> ORM.find_update(id, attrs)
31+
def set_community_flags(%Post{id: _} = content, community_id, attrs),
32+
do: do_set_flag(content, community_id, attrs)
33+
34+
def set_community_flags(%Job{id: _} = content, community_id, attrs),
35+
do: do_set_flag(content, community_id, attrs)
36+
37+
def set_community_flags(%CMSRepo{id: _} = content, community_id, attrs),
38+
do: do_set_flag(content, community_id, attrs)
39+
40+
def set_community_flags(%Video{id: _} = content, community_id, attrs),
41+
do: do_set_flag(content, community_id, attrs)
42+
43+
defp do_set_flag(content, community_id, attrs) do
44+
with {:ok, content} <- ORM.find(content.__struct__, content.id),
45+
{:ok, community} <- ORM.find(Community, community_id),
46+
{:ok, record} <- insert_flag_record(content, community_id, attrs) do
47+
{:ok, struct(content, %{pin: record.pin, trash: record.trash})}
48+
end
1949
end
2050

21-
def set_flag(queryable, id, %{trash: _} = attrs, %User{} = _user) do
22-
queryable |> ORM.find_update(id, attrs)
51+
defp insert_flag_record(%Post{id: post_id}, community_id, attrs) do
52+
clauses = ~m(post_id community_id)a
53+
PostCommunityFlag |> ORM.upsert_by(clauses, Map.merge(attrs, clauses))
2354
end
2455

56+
defp insert_flag_record(%Job{id: job_id}, community_id, attrs) do
57+
clauses = ~m(job_id community_id)a
58+
JobCommunityFlag |> ORM.upsert_by(clauses, Map.merge(attrs, clauses))
59+
end
60+
61+
defp insert_flag_record(%CMSRepo{id: repo_id}, community_id, attrs) do
62+
clauses = ~m(repo_id community_id)a
63+
RepoCommunityFlag |> ORM.upsert_by(clauses, Map.merge(attrs, clauses))
64+
end
65+
66+
defp insert_flag_record(%Video{id: video_id}, community_id, attrs) do
67+
clauses = ~m(video_id community_id)a
68+
VideoCommunityFlag |> ORM.upsert_by(clauses, Map.merge(attrs, clauses))
69+
end
70+
71+
@doc """
72+
set content to diffent community
73+
"""
2574
def set_community(%Community{id: community_id}, thread, content_id) when valid_thread(thread) do
2675
with {:ok, action} <- match_action(thread, :community),
2776
{:ok, content} <- ORM.find(action.target, content_id, preload: :communities),
@@ -49,7 +98,7 @@ defmodule MastaniServer.CMS.Delegate.ArticleOperation do
4998
set tag for post / tuts / videos ...
5099
"""
51100
# check community first
52-
def set_tag(%Community{id: communitId}, thread, %Tag{id: tag_id}, content_id) do
101+
def set_tag(%Community{id: _communitId}, thread, %Tag{id: tag_id}, content_id) do
53102
with {:ok, action} <- match_action(thread, :tag),
54103
{:ok, content} <- ORM.find(action.target, content_id, preload: :tags),
55104
{:ok, tag} <- ORM.find(action.reactor, tag_id) do

lib/mastani_server/cms/job.ex

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ defmodule MastaniServer.CMS.Job do
44

55
use Ecto.Schema
66
import Ecto.Changeset
7-
alias MastaniServer.CMS.{Author, Community, JobFavorite, Tag}
7+
alias MastaniServer.CMS.{Author, Community, JobFavorite, JobCommunityFlag, Tag}
88

99
@required_fields ~w(title company company_logo location body digest length)a
1010
@optional_fields ~w(link_addr link_source min_education)a
@@ -35,6 +35,12 @@ defmodule MastaniServer.CMS.Job do
3535
field(:digest, :string)
3636
field(:length, :integer)
3737

38+
has_many(:community_flags, {"jobs_communities_flags", JobCommunityFlag})
39+
40+
# NOTE: this one is tricky, pin is dynamic changed when return by func: add_pin_contents_ifneed
41+
field(:pin, :boolean, default_value: false, virtual: true)
42+
field(:trash, :boolean, default_value: false, virtual: true)
43+
3844
# has_many(:comments, {"jobs_comments", JobComment})
3945
has_many(:favorites, {"jobs_favorites", JobFavorite})
4046
# has_many(:stars, {"posts_stars", PostStar})
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
defmodule MastaniServer.CMS.JobCommunityFlag 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, Job}
10+
11+
@required_fields ~w(job_id community_id)a
12+
@optional_fields ~w(pin trash)a
13+
14+
@type t :: %JobCommunityFlag{}
15+
16+
schema "jobs_communities_flags" do
17+
belongs_to(:job, Job, foreign_key: :job_id)
18+
belongs_to(:community, Community, foreign_key: :community_id)
19+
20+
field(:pin, :boolean)
21+
field(:trash, :boolean)
22+
23+
timestamps(type: :utc_datetime)
24+
end
25+
26+
@doc false
27+
def changeset(%JobCommunityFlag{} = job_community_flag, attrs) do
28+
job_community_flag
29+
|> cast(attrs, @optional_fields ++ @required_fields)
30+
|> validate_required(@required_fields)
31+
|> foreign_key_constraint(:job_id)
32+
|> foreign_key_constraint(:community_id)
33+
|> unique_constraint(:job_id, name: :jobs_communities_flags_job_id_community_id_index)
34+
end
35+
end

0 commit comments

Comments
 (0)