diff --git a/lib/groupher_server/cms/cms.ex b/lib/groupher_server/cms/cms.ex index 43ead789f..5ec24cfeb 100644 --- a/lib/groupher_server/cms/cms.ex +++ b/lib/groupher_server/cms/cms.ex @@ -12,8 +12,9 @@ defmodule GroupherServer.CMS do ArticleCURD, ArticleOperation, ArticleEmotion, - ArticleReaction, ArticleComment, + ArticleCollect, + ArticleUpvote, ArticleCommentAction, ArticleCommentEmotion, CommentCURD, @@ -81,21 +82,20 @@ defmodule GroupherServer.CMS do defdelegate create_content(community, thread, attrs, user), to: ArticleCURD defdelegate update_content(content, attrs), to: ArticleCURD - # ArticleReaction - defdelegate upvote_article(thread, article_id, user), to: ArticleReaction - defdelegate undo_upvote_article(thread, article_id, user), to: ArticleReaction + defdelegate upvote_article(thread, article_id, user), to: ArticleUpvote + defdelegate undo_upvote_article(thread, article_id, user), to: ArticleUpvote - defdelegate upvoted_users(thread, article_id, filter), to: ArticleReaction + defdelegate upvoted_users(thread, article_id, filter), to: ArticleUpvote - defdelegate collect_article(thread, article_id, user), to: ArticleReaction - defdelegate collect_article_ifneed(thread, article_id, user), to: ArticleReaction + defdelegate collect_article(thread, article_id, user), to: ArticleCollect + defdelegate collect_article_ifneed(thread, article_id, user), to: ArticleCollect - defdelegate undo_collect_article(thread, article_id, user), to: ArticleReaction - defdelegate undo_collect_article_ifneed(thread, article_id, user), to: ArticleReaction - defdelegate collected_users(thread, article_id, filter), to: ArticleReaction + defdelegate undo_collect_article(thread, article_id, user), to: ArticleCollect + defdelegate undo_collect_article_ifneed(thread, article_id, user), to: ArticleCollect + defdelegate collected_users(thread, article_id, filter), to: ArticleCollect - defdelegate set_collect_folder(collect, folder), to: ArticleReaction - defdelegate undo_set_collect_folder(collect, folder), to: ArticleReaction + defdelegate set_collect_folder(collect, folder), to: ArticleCollect + defdelegate undo_set_collect_folder(collect, folder), to: ArticleCollect # ArticleOperation # >> set flag on article, like: pin / unpin article diff --git a/lib/groupher_server/cms/delegates/article_collect.ex b/lib/groupher_server/cms/delegates/article_collect.ex new file mode 100644 index 000000000..7e158aaa5 --- /dev/null +++ b/lib/groupher_server/cms/delegates/article_collect.ex @@ -0,0 +1,143 @@ +defmodule GroupherServer.CMS.Delegate.ArticleCollect do + @moduledoc """ + reaction[upvote, collect, watch ...] on article [post, job...] + """ + import GroupherServer.CMS.Helper.Matcher2 + import Ecto.Query, warn: false + import Helper.Utils, only: [done: 1] + + import GroupherServer.CMS.Delegate.Helper, + only: [ + load_reaction_users: 4, + update_article_reactions_count: 4, + update_article_reaction_user_list: 4 + ] + + # import Helper.ErrorCode + alias Helper.{ORM} + alias GroupherServer.{Accounts, CMS, Repo} + + alias Accounts.User + alias CMS.ArticleCollect + + alias Ecto.Multi + + @doc """ + get paged collected users + """ + def collected_users(thread, article_id, filter) do + load_reaction_users(ArticleCollect, thread, article_id, filter) + end + + @doc """ + collect an article + """ + def collect_article(thread, article_id, %User{id: user_id}) do + with {:ok, info} <- match(thread), + {:ok, article} <- ORM.find(info.model, article_id, preload: [author: :user]) do + Multi.new() + |> Multi.run(:inc_author_achieve, fn _, _ -> + Accounts.achieve(article.author.user, :inc, :collect) + end) + |> Multi.run(:inc_article_collects_count, fn _, _ -> + update_article_reactions_count(info, article, :collects_count, :inc) + end) + |> Multi.run(:update_article_reaction_user_list, fn _, _ -> + update_article_reaction_user_list(:collect, article, user_id, :add) + end) + |> Multi.run(:create_collect, fn _, _ -> + thread_upcase = thread |> to_string |> String.upcase() + args = Map.put(%{user_id: user_id, thread: thread_upcase}, info.foreign_key, article.id) + + ORM.create(ArticleCollect, args) + end) + |> Repo.transaction() + |> result() + end + end + + # 用于在收藏时,用户添加文章到不同的收藏夹中的情况 + # 如果是同一篇文章,只创建一次,collect_article 不创建记录,只是后续设置不同的收藏夹即可 + # 如果是第一次收藏,那么才创建文章收藏记录 + # 避免因为同一篇文章在不同收藏夹内造成的统计和用户成就系统的混乱 + def collect_article_ifneed(thread, article_id, %User{id: user_id} = user) do + with findby_args <- collection_findby_args(thread, article_id, user_id) do + already_collected = ORM.find_by(ArticleCollect, findby_args) + + case already_collected do + {:ok, article_collect} -> {:ok, article_collect} + {:error, _} -> collect_article(thread, article_id, user) + end + end + end + + def undo_collect_article(thread, article_id, %User{id: user_id}) do + with {:ok, info} <- match(thread), + {:ok, article} <- ORM.find(info.model, article_id, preload: [author: :user]) do + Multi.new() + |> Multi.run(:dec_author_achieve, fn _, _ -> + Accounts.achieve(article.author.user, :dec, :collect) + end) + |> Multi.run(:inc_article_collects_count, fn _, _ -> + update_article_reactions_count(info, article, :collects_count, :dec) + end) + |> Multi.run(:update_article_reaction_user_list, fn _, _ -> + update_article_reaction_user_list(:collect, article, user_id, :remove) + end) + |> Multi.run(:undo_collect, fn _, _ -> + args = Map.put(%{user_id: user_id}, info.foreign_key, article.id) + + ORM.findby_delete(ArticleCollect, args) + end) + |> Repo.transaction() + |> result() + end + end + + def undo_collect_article_ifneed(thread, article_id, %User{id: user_id} = user) do + with findby_args <- collection_findby_args(thread, article_id, user_id), + {:ok, article_collect} = ORM.find_by(ArticleCollect, findby_args) do + case article_collect.collect_folders |> length <= 1 do + true -> undo_collect_article(thread, article_id, user) + false -> {:ok, article_collect} + end + end + end + + def set_collect_folder(%ArticleCollect{} = collect, folder) do + collect_folders = (collect.collect_folders ++ [folder]) |> Enum.uniq() + + collect + |> Ecto.Changeset.change() + |> Ecto.Changeset.put_embed(:collect_folders, collect_folders) + |> Repo.update() + end + + def undo_set_collect_folder(%ArticleCollect{} = collect, folder) do + collect_folders = Enum.reject(collect.collect_folders, &(&1.id == folder.id)) + + case collect_folders do + # means collect already delete + [] -> + {:ok, :pass} + + _ -> + collect + |> Ecto.Changeset.change() + |> Ecto.Changeset.put_embed(:collect_folders, collect_folders) + |> Repo.update() + end + end + + defp collection_findby_args(thread, article_id, user_id) do + with {:ok, info} <- match(thread) do + thread_upcase = thread |> to_string |> String.upcase() + %{thread: thread_upcase, user_id: user_id} |> Map.put(info.foreign_key, article_id) + end + end + + ############# + defp result({:ok, %{create_collect: result}}), do: result |> done() + defp result({:ok, %{undo_collect: result}}), do: result |> done() + defp result({:error, _, result, _steps}), do: {:error, result} +end diff --git a/lib/groupher_server/cms/delegates/article_comment_action.ex b/lib/groupher_server/cms/delegates/article_comment_action.ex index 644933c5c..c91d2115b 100644 --- a/lib/groupher_server/cms/delegates/article_comment_action.ex +++ b/lib/groupher_server/cms/delegates/article_comment_action.ex @@ -63,7 +63,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleCommentAction do ) end) |> Repo.transaction() - |> upsert_comment_result() + |> result() end end @@ -77,7 +77,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleCommentAction do ORM.findby_delete(ArticlePinedComment, %{article_comment_id: comment.id}) end) |> Repo.transaction() - |> upsert_comment_result() + |> result() end end @@ -141,7 +141,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleCommentAction do |> Repo.update() end) |> Repo.transaction() - |> upsert_comment_result() + |> result() end end @@ -166,7 +166,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleCommentAction do update_article_author_upvoted_info(comment, user_id) end) |> Repo.transaction() - |> upsert_comment_result() + |> result() end end @@ -194,7 +194,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleCommentAction do update_article_author_upvoted_info(updated_comment, user_id) end) |> Repo.transaction() - |> upsert_comment_result() + |> result() end end @@ -324,24 +324,24 @@ defmodule GroupherServer.CMS.Delegate.ArticleCommentAction do ORM.update_meta(comment, meta) end - defp upsert_comment_result({:ok, %{create_article_comment: result}}), do: {:ok, result} - defp upsert_comment_result({:ok, %{add_reply_to: result}}), do: {:ok, result} - defp upsert_comment_result({:ok, %{check_article_author_upvoted: result}}), do: {:ok, result} - defp upsert_comment_result({:ok, %{fold_comment_report_too_many: result}}), do: {:ok, result} - defp upsert_comment_result({:ok, %{update_comment_flag: result}}), do: {:ok, result} - defp upsert_comment_result({:ok, %{delete_article_comment: result}}), do: {:ok, result} + defp result({:ok, %{create_article_comment: result}}), do: {:ok, result} + defp result({:ok, %{add_reply_to: result}}), do: {:ok, result} + defp result({:ok, %{check_article_author_upvoted: result}}), do: {:ok, result} + defp result({:ok, %{fold_comment_report_too_many: result}}), do: {:ok, result} + defp result({:ok, %{update_comment_flag: result}}), do: {:ok, result} + defp result({:ok, %{delete_article_comment: result}}), do: {:ok, result} - defp upsert_comment_result({:error, :create_article_comment, result, _steps}) do + defp result({:error, :create_article_comment, result, _steps}) do raise_error(:create_comment, result) end - defp upsert_comment_result({:error, :add_participator, result, _steps}) do + defp result({:error, :add_participator, result, _steps}) do {:error, result} end - defp upsert_comment_result({:error, :create_abuse_report, result, _steps}) do + defp result({:error, :create_abuse_report, result, _steps}) do {:error, result} end - defp upsert_comment_result({:error, _, result, _steps}), do: {:error, result} + defp result({:error, _, result, _steps}), do: {:error, result} end diff --git a/lib/groupher_server/cms/delegates/article_reaction.ex b/lib/groupher_server/cms/delegates/article_reaction.ex deleted file mode 100644 index a2cae6b03..000000000 --- a/lib/groupher_server/cms/delegates/article_reaction.ex +++ /dev/null @@ -1,260 +0,0 @@ -defmodule GroupherServer.CMS.Delegate.ArticleReaction do - @moduledoc """ - reaction[upvote, collect, watch ...] on article [post, job...] - """ - import GroupherServer.CMS.Helper.Matcher2 - import Ecto.Query, warn: false - import Helper.Utils, only: [done: 1, strip_struct: 1] - # import Helper.ErrorCode - import ShortMaps - - alias Helper.{ORM, QueryBuilder} - alias GroupherServer.{Accounts, CMS, Repo} - - alias Accounts.User - alias CMS.{ArticleUpvote, ArticleCollect, Embeds} - - alias Ecto.Multi - - @default_article_meta Embeds.ArticleMeta.default_meta() - - def upvoted_users(thread, article_id, filter) do - load_reaction_users(ArticleUpvote, thread, article_id, filter) - end - - def collected_users(thread, article_id, filter) do - load_reaction_users(ArticleCollect, thread, article_id, filter) - end - - defp load_reaction_users(schema, thread, article_id, %{page: page, size: size} = filter) do - with {:ok, info} <- match(thread) do - schema - |> where([u], field(u, ^info.foreign_key) == ^article_id) - |> QueryBuilder.load_inner_users(filter) - |> ORM.paginater(~m(page size)a) - |> done() - end - end - - def collect_article(thread, article_id, %User{id: user_id}) do - with {:ok, info} <- match(thread), - {:ok, article} <- ORM.find(info.model, article_id, preload: [author: :user]) do - Multi.new() - |> Multi.run(:inc_author_achieve, fn _, _ -> - Accounts.achieve(article.author.user, :inc, :collect) - end) - |> Multi.run(:inc_article_collects_count, fn _, _ -> - update_article_upvotes_count(info, article, :collects_count, :inc) - end) - |> Multi.run(:update_article_reaction_user_list, fn _, _ -> - update_article_reaction_user_list(:collect, article, user_id, :add) - end) - |> Multi.run(:create_collect, fn _, _ -> - thread_upcase = thread |> to_string |> String.upcase() - args = Map.put(%{user_id: user_id, thread: thread_upcase}, info.foreign_key, article.id) - - ORM.create(ArticleCollect, args) - end) - |> Repo.transaction() - |> reaction_result() - end - end - - # 用于在收藏时,用户添加文章到不同的收藏夹中的情况 - # 如果是同一篇文章,只创建一次,collect_article 不创建记录,只是后续设置不同的收藏夹即可 - # 如果是第一次收藏,那么才创建文章收藏记录 - # 避免因为同一篇文章在不同收藏夹内造成的统计和用户成就系统的混乱 - def collect_article_ifneed(thread, article_id, %User{id: user_id} = user) do - with findby_args <- collection_findby_args(thread, article_id, user_id) do - already_collected = ORM.find_by(ArticleCollect, findby_args) - - case already_collected do - {:ok, article_collect} -> {:ok, article_collect} - {:error, _} -> collect_article(thread, article_id, user) - end - end - end - - def undo_collect_article(thread, article_id, %User{id: user_id}) do - with {:ok, info} <- match(thread), - {:ok, article} <- ORM.find(info.model, article_id, preload: [author: :user]) do - Multi.new() - |> Multi.run(:dec_author_achieve, fn _, _ -> - Accounts.achieve(article.author.user, :dec, :collect) - end) - |> Multi.run(:inc_article_collects_count, fn _, _ -> - update_article_upvotes_count(info, article, :collects_count, :dec) - end) - |> Multi.run(:update_article_reaction_user_list, fn _, _ -> - update_article_reaction_user_list(:collect, article, user_id, :remove) - end) - |> Multi.run(:undo_collect, fn _, _ -> - args = Map.put(%{user_id: user_id}, info.foreign_key, article.id) - - ORM.findby_delete(ArticleCollect, args) - end) - |> Repo.transaction() - |> reaction_result() - end - end - - def undo_collect_article_ifneed(thread, article_id, %User{id: user_id} = user) do - with findby_args <- collection_findby_args(thread, article_id, user_id), - {:ok, article_collect} = ORM.find_by(ArticleCollect, findby_args) do - case article_collect.collect_folders |> length <= 1 do - true -> undo_collect_article(thread, article_id, user) - false -> {:ok, article_collect} - end - end - end - - defp collection_findby_args(thread, article_id, user_id) do - with {:ok, info} <- match(thread) do - thread_upcase = thread |> to_string |> String.upcase() - %{thread: thread_upcase, user_id: user_id} |> Map.put(info.foreign_key, article_id) - end - end - - def set_collect_folder(%ArticleCollect{} = collect, folder) do - collect_folders = (collect.collect_folders ++ [folder]) |> Enum.uniq() - - collect - |> Ecto.Changeset.change() - |> Ecto.Changeset.put_embed(:collect_folders, collect_folders) - |> Repo.update() - end - - def undo_set_collect_folder(%ArticleCollect{} = collect, folder) do - collect_folders = Enum.reject(collect.collect_folders, &(&1.id == folder.id)) - - case collect_folders do - # means collect already delete - [] -> - {:ok, :pass} - - _ -> - collect - |> Ecto.Changeset.change() - |> Ecto.Changeset.put_embed(:collect_folders, collect_folders) - |> Repo.update() - end - end - - @doc "upvote to a article-like content" - def upvote_article(thread, article_id, %User{id: user_id}) do - with {:ok, info} <- match(thread), - {:ok, article} <- ORM.find(info.model, article_id, preload: [author: :user]) do - Multi.new() - |> Multi.run(:inc_article_upvotes_count, fn _, _ -> - update_article_upvotes_count(info, article, :upvotes_count, :inc) - end) - |> Multi.run(:update_article_reaction_user_list, fn _, _ -> - update_article_reaction_user_list(:upvot, article, user_id, :add) - end) - |> Multi.run(:add_achievement, fn _, _ -> - achiever_id = article.author.user_id - Accounts.achieve(%User{id: achiever_id}, :inc, :upvote) - end) - |> Multi.run(:create_upvote, fn _, _ -> - thread_upcase = thread |> to_string |> String.upcase() - args = Map.put(%{user_id: user_id, thread: thread_upcase}, info.foreign_key, article.id) - - with {:ok, _} <- ORM.create(ArticleUpvote, args) do - ORM.find(info.model, article.id) - end - end) - |> Repo.transaction() - |> reaction_result() - end - end - - @doc "upvote to a article-like content" - def undo_upvote_article(thread, article_id, %User{id: user_id}) do - with {:ok, info} <- match(thread), - {:ok, article} <- ORM.find(info.model, article_id) do - Multi.new() - |> Multi.run(:inc_article_upvotes_count, fn _, _ -> - update_article_upvotes_count(info, article, :upvotes_count, :dec) - end) - |> Multi.run(:update_article_reaction_user_list, fn _, _ -> - update_article_reaction_user_list(:upvot, article, user_id, :remove) - end) - |> Multi.run(:undo_upvote, fn _, _ -> - args = Map.put(%{user_id: user_id}, info.foreign_key, article.id) - - ORM.findby_delete(ArticleUpvote, args) - ORM.find(info.model, article.id) - end) - |> Repo.transaction() - |> reaction_result() - end - end - - defp update_article_upvotes_count(info, article, field, opt) do - schema = - case field do - :upvotes_count -> ArticleUpvote - :collects_count -> ArticleCollect - end - - count_query = from(u in schema, where: field(u, ^info.foreign_key) == ^article.id) - cur_count = Repo.aggregate(count_query, :count) - - case opt do - :inc -> - new_count = Enum.max([0, cur_count]) - ORM.update(article, Map.put(%{}, field, new_count + 1)) - - :dec -> - new_count = Enum.max([1, cur_count]) - ORM.update(article, Map.put(%{}, field, new_count - 1)) - end - end - - @doc """ - add or remove artilce's reaction users is list history - e.g: - add/remove user_id to upvoted_user_ids in article meta - """ - @spec update_article_reaction_user_list( - :upvot | :collect, - T.article_common(), - String.t(), - :add | :remove - ) :: T.article_common() - defp update_article_reaction_user_list(action, %{meta: nil} = article, user_id, opt) do - cur_user_ids = [] - - updated_user_ids = - case opt do - :add -> [user_id] ++ cur_user_ids - :remove -> cur_user_ids -- [user_id] - end - - meta = @default_article_meta |> Map.merge(%{"#{action}ed_user_ids": updated_user_ids}) - ORM.update_meta(article, meta) - end - - defp update_article_reaction_user_list(action, article, user_id, opt) do - cur_user_ids = get_in(article, [:meta, :"#{action}ed_user_ids"]) - - updated_user_ids = - case opt do - :add -> [user_id] ++ cur_user_ids - :remove -> cur_user_ids -- [user_id] - end - - meta = article.meta |> Map.merge(%{"#{action}ed_user_ids": updated_user_ids}) |> strip_struct - ORM.update_meta(article, meta) - end - - defp reaction_result({:ok, %{create_upvote: result}}), do: result |> done() - defp reaction_result({:ok, %{undo_upvote: result}}), do: result |> done() - - defp reaction_result({:ok, %{create_collect: result}}), do: result |> done() - defp reaction_result({:ok, %{undo_collect: result}}), do: result |> done() - - defp reaction_result({:error, _, result, _steps}) do - {:error, result} - end -end diff --git a/lib/groupher_server/cms/delegates/article_upvote.ex b/lib/groupher_server/cms/delegates/article_upvote.ex new file mode 100644 index 000000000..247aa0986 --- /dev/null +++ b/lib/groupher_server/cms/delegates/article_upvote.ex @@ -0,0 +1,83 @@ +defmodule GroupherServer.CMS.Delegate.ArticleUpvote do + @moduledoc """ + reaction[upvote, collect, watch ...] on article [post, job...] + """ + import GroupherServer.CMS.Helper.Matcher2 + import Ecto.Query, warn: false + import Helper.Utils, only: [done: 1] + + import GroupherServer.CMS.Delegate.Helper, + only: [ + load_reaction_users: 4, + update_article_reactions_count: 4, + update_article_reaction_user_list: 4 + ] + + # import Helper.ErrorCode + + alias Helper.ORM + alias GroupherServer.{Accounts, CMS, Repo} + + alias Accounts.User + alias CMS.ArticleUpvote + + alias Ecto.Multi + + def upvoted_users(thread, article_id, filter) do + load_reaction_users(ArticleUpvote, thread, article_id, filter) + end + + @doc "upvote to a article-like content" + def upvote_article(thread, article_id, %User{id: user_id}) do + with {:ok, info} <- match(thread), + {:ok, article} <- ORM.find(info.model, article_id, preload: [author: :user]) do + Multi.new() + |> Multi.run(:inc_article_upvotes_count, fn _, _ -> + update_article_reactions_count(info, article, :upvotes_count, :inc) + end) + |> Multi.run(:update_article_reaction_user_list, fn _, _ -> + update_article_reaction_user_list(:upvot, article, user_id, :add) + end) + |> Multi.run(:add_achievement, fn _, _ -> + achiever_id = article.author.user_id + Accounts.achieve(%User{id: achiever_id}, :inc, :upvote) + end) + |> Multi.run(:create_upvote, fn _, _ -> + thread_upcase = thread |> to_string |> String.upcase() + args = Map.put(%{user_id: user_id, thread: thread_upcase}, info.foreign_key, article.id) + + with {:ok, _} <- ORM.create(ArticleUpvote, args) do + ORM.find(info.model, article.id) + end + end) + |> Repo.transaction() + |> result() + end + end + + @doc "upvote to a article-like content" + def undo_upvote_article(thread, article_id, %User{id: user_id}) do + with {:ok, info} <- match(thread), + {:ok, article} <- ORM.find(info.model, article_id) do + Multi.new() + |> Multi.run(:inc_article_upvotes_count, fn _, _ -> + update_article_reactions_count(info, article, :upvotes_count, :dec) + end) + |> Multi.run(:update_article_reaction_user_list, fn _, _ -> + update_article_reaction_user_list(:upvot, article, user_id, :remove) + end) + |> Multi.run(:undo_upvote, fn _, _ -> + args = Map.put(%{user_id: user_id}, info.foreign_key, article.id) + + ORM.findby_delete(ArticleUpvote, args) + ORM.find(info.model, article.id) + end) + |> Repo.transaction() + |> result() + end + end + + defp result({:ok, %{create_upvote: result}}), do: result |> done() + defp result({:ok, %{undo_upvote: result}}), do: result |> done() + defp result({:error, _, result, _steps}), do: {:error, result} +end diff --git a/lib/groupher_server/cms/delegates/helper.ex b/lib/groupher_server/cms/delegates/helper.ex index 93b5f3b7d..2a1ce15f8 100644 --- a/lib/groupher_server/cms/delegates/helper.ex +++ b/lib/groupher_server/cms/delegates/helper.ex @@ -2,23 +2,34 @@ defmodule GroupherServer.CMS.Delegate.Helper do @moduledoc """ helpers for GroupherServer.CMS.Delegate """ - import Helper.Utils, only: [get_config: 2, done: 1] + import Helper.Utils, only: [get_config: 2, done: 1, strip_struct: 1] + import Ecto.Query, warn: false + import GroupherServer.CMS.Helper.Matcher2 + import ShortMaps - alias GroupherServer.{Accounts, Repo} + alias Helper.{ORM, QueryBuilder} + alias GroupherServer.{Accounts, Repo, CMS} + + alias CMS.{ArticleUpvote, ArticleCollect} alias Accounts.User + @default_article_meta CMS.Embeds.ArticleMeta.default_meta() + # TODO: # @max_latest_emotion_users_count ArticleComment.max_latest_emotion_users_count() @max_latest_emotion_users_count 4 @supported_emotions get_config(:article, :supported_emotions) @supported_comment_emotions get_config(:article, :comment_supported_emotions) + ####### + # emotion related + ####### defp get_supported_mentions(:comment), do: @supported_comment_emotions defp get_supported_mentions(_), do: @supported_emotions def mark_viewer_emotion_states(paged_contents, nil), do: paged_contents - def mark_viewer_emotion_states(paged_contents, nil, :comment), do: paged_contents def mark_viewer_emotion_states(%{entries: []} = paged_contents, _), do: paged_contents + def mark_viewer_emotion_states(paged_contents, nil, :comment), do: paged_contents @doc """ mark viewer emotions status for article or comment @@ -82,4 +93,89 @@ defmodule GroupherServer.CMS.Delegate.Helper do defp user_in_logins?([], _), do: false defp user_in_logins?(ids_list, %User{login: login}), do: Enum.member?(ids_list, login) + + ####### + # emotion related end + ####### + + ###### + # reaction related end, include upvote && collect + ####### + @doc """ + paged [reaction] users list + """ + def load_reaction_users(queryable, thread, article_id, filter) do + %{page: page, size: size} = filter + + with {:ok, info} <- match(thread) do + queryable + |> where([u], field(u, ^info.foreign_key) == ^article_id) + |> QueryBuilder.load_inner_users(filter) + |> ORM.paginater(~m(page size)a) + |> done() + end + end + + @doc """ + update the [reaction]s_count for article + e.g: + inc/dec upvotes_count of article + """ + def update_article_reactions_count(info, article, field, opt) do + schema = + case field do + :upvotes_count -> ArticleUpvote + :collects_count -> ArticleCollect + end + + count_query = from(u in schema, where: field(u, ^info.foreign_key) == ^article.id) + cur_count = Repo.aggregate(count_query, :count) + + case opt do + :inc -> + new_count = Enum.max([0, cur_count]) + ORM.update(article, Map.put(%{}, field, new_count + 1)) + + :dec -> + new_count = Enum.max([1, cur_count]) + ORM.update(article, Map.put(%{}, field, new_count - 1)) + end + end + + @doc """ + add or remove artilce's reaction users is list history + e.g: + add/remove user_id to upvoted_user_ids in article meta + """ + @spec update_article_reaction_user_list( + :upvot | :collect, + T.article_common(), + String.t(), + :add | :remove + ) :: T.article_common() + def update_article_reaction_user_list(action, %{meta: nil} = article, user_id, opt) do + cur_user_ids = [] + + updated_user_ids = + case opt do + :add -> [user_id] ++ cur_user_ids + :remove -> cur_user_ids -- [user_id] + end + + meta = @default_article_meta |> Map.merge(%{"#{action}ed_user_ids": updated_user_ids}) + ORM.update_meta(article, meta) + end + + def update_article_reaction_user_list(action, article, user_id, opt) do + cur_user_ids = get_in(article, [:meta, :"#{action}ed_user_ids"]) + + updated_user_ids = + case opt do + :add -> [user_id] ++ cur_user_ids + :remove -> cur_user_ids -- [user_id] + end + + meta = article.meta |> Map.merge(%{"#{action}ed_user_ids": updated_user_ids}) |> strip_struct + ORM.update_meta(article, meta) + end end diff --git a/test/groupher_server/cms/abuse_reports/post_report_test.exs b/test/groupher_server/cms/abuse_reports/post_report_test.exs index fcd638368..743fd1b0d 100644 --- a/test/groupher_server/cms/abuse_reports/post_report_test.exs +++ b/test/groupher_server/cms/abuse_reports/post_report_test.exs @@ -79,7 +79,6 @@ defmodule GroupherServer.Test.CMS.AbuseReports.PostReport do assert user.id not in post.meta.reported_user_ids end - @tag :wip2 test "can undo a report with other user report it too", ~m(community user user2 post_attrs)a do {:ok, post} = CMS.create_content(community, :post, post_attrs, user) diff --git a/test/groupher_server/cms/upvotes/job_upvote_test.exs b/test/groupher_server/cms/upvotes/job_upvote_test.exs index 8320df575..b7d5e4e24 100644 --- a/test/groupher_server/cms/upvotes/job_upvote_test.exs +++ b/test/groupher_server/cms/upvotes/job_upvote_test.exs @@ -27,6 +27,7 @@ defmodule GroupherServer.Test.Upvotes.JobUpvote do assert article.upvotes_count == 2 end + @tag :wip2 test "job can be undo upvote && upvotes_count should dec by 1", ~m(user user2 community job_attrs)a do {:ok, job} = CMS.create_content(community, :job, job_attrs, user) diff --git a/test/groupher_server_web/query/cms/flags/posts_flags_test.exs b/test/groupher_server_web/query/cms/flags/posts_flags_test.exs index 90671a222..9d71db79f 100644 --- a/test/groupher_server_web/query/cms/flags/posts_flags_test.exs +++ b/test/groupher_server_web/query/cms/flags/posts_flags_test.exs @@ -89,7 +89,6 @@ defmodule GroupherServer.Test.Query.Flags.PostsFlags do assert results["entries"] |> Enum.any?(&(&1["id"] !== random_id)) end - @tag :wip2 test "if have trashed posts, the trashed posts should not appears in result", ~m(guest_conn community)a do variables = %{filter: %{community: community.raw}}