diff --git a/lib/groupher_server/cms/article_comment.ex b/lib/groupher_server/cms/article_comment.ex index 45116cf94..73e3191b0 100644 --- a/lib/groupher_server/cms/article_comment.ex +++ b/lib/groupher_server/cms/article_comment.ex @@ -53,6 +53,8 @@ defmodule GroupherServer.CMS.ArticleComment do @type t :: %ArticleComment{} schema "articles_comments" do + belongs_to(:author, Accounts.User, foreign_key: :author_id) + field(:body_html, :string) # 是否被折叠 field(:is_folded, :boolean, default: false) @@ -71,7 +73,6 @@ defmodule GroupherServer.CMS.ArticleComment do field(:is_pinned, :boolean, default: false) field(:viewer_has_upvoted, :boolean, default: false, virtual: true) - belongs_to(:author, Accounts.User, foreign_key: :author_id) belongs_to(:post, Post, foreign_key: :post_id) belongs_to(:job, Job, foreign_key: :job_id) belongs_to(:reply_to, ArticleComment, foreign_key: :reply_to_id) diff --git a/lib/groupher_server/cms/article_comment_user_emotion.ex b/lib/groupher_server/cms/article_comment_user_emotion.ex index fb41bf993..8bc30a8f1 100644 --- a/lib/groupher_server/cms/article_comment_user_emotion.ex +++ b/lib/groupher_server/cms/article_comment_user_emotion.ex @@ -50,4 +50,13 @@ defmodule GroupherServer.CMS.ArticleCommentUserEmotion do |> foreign_key_constraint(:user_id) |> foreign_key_constraint(:recived_user_id) end + + def update_changeset(%ArticleCommentUserEmotion{} = struct, attrs) do + struct + |> cast(attrs, @required_fields ++ @optional_fields) + |> validate_required(@required_fields) + |> foreign_key_constraint(:article_comment_id) + |> foreign_key_constraint(:user_id) + |> foreign_key_constraint(:recived_user_id) + end end diff --git a/lib/groupher_server/cms/cms.ex b/lib/groupher_server/cms/cms.ex index f2dfa3128..a689e80d4 100644 --- a/lib/groupher_server/cms/cms.ex +++ b/lib/groupher_server/cms/cms.ex @@ -13,9 +13,9 @@ defmodule GroupherServer.CMS do ArticleOperation, ArticleReaction, ArticleComment, + ArticleCommentEmotion, CommentCURD, CommunitySync, - CommentReaction, CommunityCURD, CommunityOperation, PassportCURD, @@ -126,15 +126,18 @@ defmodule GroupherServer.CMS do defdelegate list_article_comments_participators(thread, content_id, filters), to: ArticleComment defdelegate create_article_comment(thread, article_id, args, user), to: ArticleComment + defdelegate update_article_comment(comment, content), to: ArticleComment + defdelegate delete_article_comment(comment), to: ArticleComment + defdelegate upvote_article_comment(comment_id, user), to: ArticleComment defdelegate undo_upvote_article_comment(comment_id, user), to: ArticleComment - defdelegate delete_article_comment(comment_id, user), to: ArticleComment defdelegate reply_article_comment(comment_id, args, user), to: ArticleComment defdelegate pin_article_comment(comment_id), to: ArticleComment defdelegate undo_pin_article_comment(comment_id), to: ArticleComment - defdelegate emotion_to_comment(comment_id, args, user), to: ArticleComment + defdelegate emotion_to_comment(comment_id, args, user), to: ArticleCommentEmotion + defdelegate undo_emotion_to_comment(comment_id, args, user), to: ArticleCommentEmotion defdelegate fold_article_comment(comment_id, user), to: ArticleComment defdelegate unfold_article_comment(comment_id, user), to: ArticleComment defdelegate report_article_comment(comment_id, user), to: ArticleComment diff --git a/lib/groupher_server/cms/delegates/article_comment.ex b/lib/groupher_server/cms/delegates/article_comment.ex index c64e44643..3f06b5bc2 100644 --- a/lib/groupher_server/cms/delegates/article_comment.ex +++ b/lib/groupher_server/cms/delegates/article_comment.ex @@ -20,7 +20,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do ArticlePinedComment, ArticleCommentUpvote, ArticleCommentReply, - ArticleCommentUserEmotion, Embeds, Post, Job @@ -28,7 +27,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do alias Ecto.Multi - @max_latest_emotion_users_count ArticleComment.max_latest_emotion_users_count() @max_participator_count ArticleComment.max_participator_count() @max_parent_replies_count ArticleComment.max_parent_replies_count() @default_emotions Embeds.ArticleCommentEmotion.default_emotions() @@ -157,24 +155,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do end end - @doc "delete article comment" - def delete_article_comment(comment_id, %User{} = _user) do - with {:ok, comment} <- ORM.find(ArticleComment, comment_id) do - Multi.new() - |> Multi.run(:update_article_comments_count, fn _, _ -> - update_article_comments_count(comment, :dec) - end) - |> Multi.run(:remove_pined_comment, fn _, _ -> - ORM.findby_delete(ArticlePinedComment, %{article_comment_id: comment.id}) - end) - |> Multi.run(:delete_article_comment, fn _, _ -> - ORM.update(comment, %{body_html: @delete_hint, is_deleted: true}) - end) - |> Repo.transaction() - |> upsert_comment_result() - end - end - def fold_article_comment(%ArticleComment{} = comment, %User{} = _user) do comment |> ORM.update(%{is_folded: true}) end @@ -224,68 +204,8 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do end end - @doc "make emotion to a comment" - def emotion_to_comment(comment_id, emotion, %User{} = user) do - with {:ok, comment} <- - ORM.find(ArticleComment, comment_id) do - Multi.new() - |> Multi.run(:create_user_emotion, fn _, _ -> - args = - Map.put( - %{ - article_comment_id: comment.id, - recived_user_id: comment.author_id, - user_id: user.id - }, - :"#{emotion}", - true - ) - - {:ok, _} = ArticleCommentUserEmotion |> ORM.create(args) - end) - |> Multi.run(:query_emotion_status, fn _, _ -> - # 每次被 emotion 动作触发后重新查询,主要原因 - # 1.并发下保证数据准确,类似 views 阅读数的统计 - # 2. 前端使用 nickname 而非 login 展示,如果用户改了 nickname, 可以"自动纠正" - query = - from(a in ArticleCommentUserEmotion, - join: user in User, - on: a.user_id == user.id, - where: a.article_comment_id == ^comment.id, - where: field(a, ^emotion) == true, - select: %{login: user.login, nickname: user.nickname} - ) - - emotioned_user_info_list = Repo.all(query) |> Enum.uniq() - emotioned_user_count = length(emotioned_user_info_list) - - {:ok, %{user_list: emotioned_user_info_list, user_count: emotioned_user_count}} - end) - |> Multi.run(:update_comment_emotion, fn _, %{query_emotion_status: status} -> - updated_emotions = - %{} - |> Map.put(:"#{emotion}_count", status.user_count) - |> Map.put( - :"#{emotion}_user_logins", - status.user_list |> Enum.map(& &1.login) - ) - |> Map.put( - :"latest_#{emotion}_users", - Enum.slice(status.user_list, 0, @max_latest_emotion_users_count) - ) - - comment - |> Ecto.Changeset.change() - |> Ecto.Changeset.put_embed(:emotions, updated_emotions) - |> Repo.update() - end) - |> Repo.transaction() - |> upsert_comment_result - end - end - @doc """ - Creates a comment for psot, job ... + creates a comment for article like psot, job ... """ def create_article_comment(thread, article_id, content, %User{} = user) do with {:ok, info} <- match(thread), @@ -307,6 +227,29 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do end end + @doc """ + update a comment for article like psot, job ... + """ + def update_article_comment(%ArticleComment{} = article_comment, content) do + article_comment |> ORM.update(%{body_html: content}) + end + + @doc "delete article comment" + def delete_article_comment(%ArticleComment{} = comment) do + Multi.new() + |> Multi.run(:update_article_comments_count, fn _, _ -> + update_article_comments_count(comment, :dec) + end) + |> Multi.run(:remove_pined_comment, fn _, _ -> + ORM.findby_delete(ArticlePinedComment, %{article_comment_id: comment.id}) + end) + |> Multi.run(:delete_article_comment, fn _, _ -> + ORM.update(comment, %{body_html: @delete_hint, is_deleted: true}) + end) + |> Repo.transaction() + |> upsert_comment_result() + end + @doc "reply to exsiting comment" def reply_article_comment(comment_id, content, %User{} = user) do with {:ok, target_comment} <- @@ -704,7 +647,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do 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, %{update_report_flag: result}}), do: {:ok, result} - defp upsert_comment_result({:ok, %{update_comment_emotion: 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} diff --git a/lib/groupher_server/cms/delegates/article_comment_emotion.ex b/lib/groupher_server/cms/delegates/article_comment_emotion.ex new file mode 100644 index 000000000..ce33c799b --- /dev/null +++ b/lib/groupher_server/cms/delegates/article_comment_emotion.ex @@ -0,0 +1,131 @@ +defmodule GroupherServer.CMS.Delegate.ArticleCommentEmotion do + @moduledoc """ + CURD and operations for article comments + """ + import Ecto.Query, warn: false + + alias Helper.ORM + alias GroupherServer.{Accounts, CMS, Repo} + + alias Accounts.User + alias CMS.{ArticleComment, ArticleCommentUserEmotion} + + alias Ecto.Multi + + @type t_user_list :: [%{login: String.t()}] + @type t_mention_status :: %{user_list: t_user_list, user_count: Integer.t()} + + @max_latest_emotion_users_count ArticleComment.max_latest_emotion_users_count() + + @doc "make emotion to a comment" + def emotion_to_comment(comment_id, emotion, %User{} = user) do + with {:ok, comment} <- ORM.find(ArticleComment, comment_id, preload: :author) do + Multi.new() + |> Multi.run(:create_user_emotion, fn _, _ -> + target = %{ + article_comment_id: comment.id, + recived_user_id: comment.author.id, + user_id: user.id + } + + args = Map.put(target, :"#{emotion}", true) + + case ORM.find_by(ArticleCommentUserEmotion, target) do + {:ok, article_comment_user_emotion} -> article_comment_user_emotion |> ORM.update(args) + {:error, _} -> ArticleCommentUserEmotion |> ORM.create(args) + end + end) + |> Multi.run(:query_emotion_status, fn _, _ -> + query_emotion_status(comment, emotion) + end) + |> Multi.run(:update_comment_emotion, fn _, %{query_emotion_status: status} -> + update_comment_emotion(comment, emotion, status, user) + end) + |> Repo.transaction() + |> update_emotion_result + end + end + + def undo_emotion_to_comment(comment_id, emotion, %User{} = user) do + with {:ok, comment} <- ORM.find(ArticleComment, comment_id, preload: :author) do + Multi.new() + |> Multi.run(:update_user_emotion, fn _, _ -> + target = %{ + article_comment_id: comment.id, + recived_user_id: comment.author.id, + user_id: user.id + } + + {:ok, article_comment_user_emotion} = ORM.find_by(ArticleCommentUserEmotion, target) + args = Map.put(target, :"#{emotion}", false) + article_comment_user_emotion |> ORM.update(args) + end) + |> Multi.run(:query_emotion_status, fn _, _ -> + query_emotion_status(comment, emotion) + end) + |> Multi.run(:update_comment_emotion, fn _, %{query_emotion_status: status} -> + update_comment_emotion(comment, emotion, status, user) + end) + |> Repo.transaction() + |> update_emotion_result + end + end + + @spec query_emotion_status(ArticleComment.t(), Atom.t()) :: {:ok, t_mention_status} + defp query_emotion_status(comment, emotion) do + # 每次被 emotion 动作触发后重新查询,主要原因 + # 1.并发下保证数据准确,类似 views 阅读数的统计 + # 2. 前端使用 nickname 而非 login 展示,如果用户改了 nickname, 可以"自动纠正" + query = + from(a in ArticleCommentUserEmotion, + join: user in User, + on: a.user_id == user.id, + where: a.article_comment_id == ^comment.id, + where: field(a, ^emotion) == true, + select: %{login: user.login, nickname: user.nickname} + ) + + emotioned_user_info_list = Repo.all(query) |> Enum.uniq() + emotioned_user_count = length(emotioned_user_info_list) + + {:ok, %{user_list: emotioned_user_info_list, user_count: emotioned_user_count}} + end + + @spec update_comment_emotion(ArticleComment.t(), Atom.t(), t_mention_status, User.t()) :: + {:ok, ArticleComment.t()} | {:error, any} + defp update_comment_emotion(comment, emotion, status, user) do + %{user_count: user_count, user_list: user_list} = status + + emotions = + %{} + |> Map.put(:"#{emotion}_count", user_count) + |> Map.put(:"#{emotion}_user_logins", user_list |> Enum.map(& &1.login)) + |> Map.put( + :"latest_#{emotion}_users", + Enum.slice(user_list, 0, @max_latest_emotion_users_count) + ) + + viewer_has_emotioned = user.login in Map.get(emotions, :"#{emotion}_user_logins") + emotions = emotions |> Map.put(:"viewer_has_#{emotion}ed", viewer_has_emotioned) + + comment + |> Ecto.Changeset.change() + |> Ecto.Changeset.put_embed(:emotions, emotions) + |> Repo.update() + # virtual field can not be updated + |> add_viewer_emotioned_ifneed(emotions) + end + + defp add_viewer_emotioned_ifneed({:error, error}, _), do: {:error, error} + + defp add_viewer_emotioned_ifneed({:ok, comment}, emotions) do + # Map.merge(comment, %{emotion: emotions}) + {:ok, Map.merge(comment, %{emotion: emotions})} + end + + defp update_emotion_result({:ok, %{update_comment_emotion: result}}), do: {:ok, result} + + defp update_emotion_result({:error, _, result, _steps}) do + {:error, result} + end +end diff --git a/lib/groupher_server_web/middleware/passport_loader.ex b/lib/groupher_server_web/middleware/passport_loader.ex index 6e73143c7..b783c6857 100644 --- a/lib/groupher_server_web/middleware/passport_loader.ex +++ b/lib/groupher_server_web/middleware/passport_loader.ex @@ -9,8 +9,10 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do import Helper.ErrorCode import ShortMaps - alias GroupherServer.CMS alias Helper.ORM + alias GroupherServer.CMS + + alias CMS.{ArticleComment} def call(%{errors: errors} = resolution, _) when length(errors) > 0, do: resolution @@ -24,8 +26,20 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do %{resolution | arguments: arguments} {:error, err_msg} -> + resolution |> handle_absinthe_error(err_msg, ecode(:passport)) + end + end + + @doc "load article comment" + def call(%{context: %{cur_user: _}, arguments: ~m(id)a} = resolution, source: :article_comment) do + case ORM.find(ArticleComment, id, preload: :author) do + {:ok, article_comment} -> resolution - |> handle_absinthe_error(err_msg, ecode(:passport)) + |> load_owner_info(:article_comment, article_comment) + |> load_source(article_comment) + + {:error, err_msg} -> + resolution |> handle_absinthe_error(err_msg, ecode(:passport)) end end @@ -83,6 +97,9 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do def load_owner_info(%{context: %{cur_user: cur_user}} = resolution, react, content) do content_author_id = cond do + react == :article_comment -> + content.author.id + react == :comment -> content.author.id diff --git a/lib/groupher_server_web/resolvers/cms_resolver.ex b/lib/groupher_server_web/resolvers/cms_resolver.ex index 81ae3b04c..ad11ffd9a 100644 --- a/lib/groupher_server_web/resolvers/cms_resolver.ex +++ b/lib/groupher_server_web/resolvers/cms_resolver.ex @@ -308,6 +308,32 @@ defmodule GroupherServerWeb.Resolvers.CMS do CMS.list_article_comments_participators(thread, id, filter) end + def create_article_comment(_root, ~m(thread id content)a, %{context: %{cur_user: user}}) do + CMS.create_article_comment(thread, id, content, user) + end + + def update_article_comment(_root, ~m(content passport_source)a, _info) do + comment = passport_source + CMS.update_article_comment(comment, content) + end + + def delete_article_comment(_root, ~m(passport_source)a, _info) do + comment = passport_source + CMS.delete_article_comment(comment) + end + + def emotion_to_comment(_root, ~m(id emotion)a, %{context: %{cur_user: user}}) do + CMS.emotion_to_comment(id, emotion, user) + end + + def undo_emotion_to_comment(_root, ~m(id emotion)a, %{context: %{cur_user: user}}) do + CMS.undo_emotion_to_comment(id, emotion, user) + end + + ############ + ############ + ############ + def paged_comment_replies(_root, ~m(id filter)a, %{context: %{cur_user: user}}) do CMS.list_comment_replies(id, filter, user) end @@ -332,10 +358,6 @@ defmodule GroupherServerWeb.Resolvers.CMS do CMS.create_comment(thread, id, args, user) end - def create_article_comment(_root, ~m(thread id content)a, %{context: %{cur_user: user}}) do - CMS.create_article_comment(thread, id, content, user) - end - def update_comment(_root, ~m(thread id)a = args, %{context: %{cur_user: user}}) do CMS.update_comment(thread, id, args, user) end diff --git a/lib/groupher_server_web/schema/cms/cms_misc.ex b/lib/groupher_server_web/schema/cms/cms_misc.ex index c8a8c9d4e..b69323fd9 100644 --- a/lib/groupher_server_web/schema/cms/cms_misc.ex +++ b/lib/groupher_server_web/schema/cms/cms_misc.ex @@ -152,6 +152,11 @@ defmodule GroupherServerWeb.Schema.CMS.Misc do value(:grey) end + @desc "emotion options of comment" + enum :article_comment_emotion do + emotion_enum() + end + @desc "the filter mode for list comments" enum :article_comments_mode do value(:replies) diff --git a/lib/groupher_server_web/schema/cms/cms_types.ex b/lib/groupher_server_web/schema/cms/cms_types.ex index 5dabaf92f..5094eac3e 100644 --- a/lib/groupher_server_web/schema/cms/cms_types.ex +++ b/lib/groupher_server_web/schema/cms/cms_types.ex @@ -358,6 +358,7 @@ defmodule GroupherServerWeb.Schema.CMS.Types do field(:replies, list_of(:article_comment_reply)) field(:replies_count, :integer) + field(:is_deleted, :boolean) field(:viewer_has_upvoted, :boolean) timestamp_fields() diff --git a/lib/groupher_server_web/schema/cms/mutations/comment.ex b/lib/groupher_server_web/schema/cms/mutations/comment.ex index d34d15cea..d1ed51030 100644 --- a/lib/groupher_server_web/schema/cms/mutations/comment.ex +++ b/lib/groupher_server_web/schema/cms/mutations/comment.ex @@ -5,34 +5,81 @@ defmodule GroupherServerWeb.Schema.CMS.Mutations.Comment do use Helper.GqlSchemaSuite object :cms_comment_mutations do - @desc "create a comment" - field :create_comment, :comment do + @desc "write a comment" + field :create_article_comment, :article_comment do # TODO use thread and force community pass-in - arg(:community, non_null(:string)) arg(:thread, :cms_thread, default_value: :post) arg(:id, non_null(:id)) - arg(:body, non_null(:string)) - arg(:mention_users, list_of(:ids)) + arg(:content, non_null(:string)) + # arg(:mention_users, list_of(:ids)) # TDOO: use a comment resolver middleware(M.Authorize, :login) # TODO: 文章作者可以删除评论,文章可以设置禁止评论 - resolve(&R.CMS.create_comment/3) + resolve(&R.CMS.create_article_comment/3) middleware(M.Statistics.MakeContribute, for: :user) end - @desc "write a comment" - field :create_article_comment, :article_comment do - # TODO use thread and force community pass-in - arg(:thread, :cms_thread, default_value: :post) + @desc "update a comment" + field :update_article_comment, :article_comment do arg(:id, non_null(:id)) arg(:content, non_null(:string)) # arg(:mention_users, list_of(:ids)) + middleware(M.Authorize, :login) + middleware(M.PassportLoader, source: :article_comment) + middleware(M.Passport, claim: "owner") + + resolve(&R.CMS.update_article_comment/3) + end + + @desc "delete a comment" + field :delete_article_comment, :article_comment do + arg(:id, non_null(:id)) + + middleware(M.Authorize, :login) + middleware(M.PassportLoader, source: :article_comment) + middleware(M.Passport, claim: "owner") + + resolve(&R.CMS.delete_article_comment/3) + end + + @desc "emotion to a comment" + field :emotion_to_comment, :article_comment do + arg(:id, non_null(:id)) + arg(:emotion, non_null(:article_comment_emotion)) + + middleware(M.Authorize, :login) + resolve(&R.CMS.emotion_to_comment/3) + end + + @desc "undo emotion to a comment" + field :undo_emotion_to_comment, :article_comment do + arg(:id, non_null(:id)) + arg(:emotion, non_null(:article_comment_emotion)) + + middleware(M.Authorize, :login) + resolve(&R.CMS.undo_emotion_to_comment/3) + end + + ############################ + ############################ + ############################ + ############################ + + @desc "create a comment" + field :create_comment, :comment do + # TODO use thread and force community pass-in + arg(:community, non_null(:string)) + arg(:thread, :cms_thread, default_value: :post) + arg(:id, non_null(:id)) + arg(:body, non_null(:string)) + arg(:mention_users, list_of(:ids)) + # TDOO: use a comment resolver middleware(M.Authorize, :login) # TODO: 文章作者可以删除评论,文章可以设置禁止评论 - resolve(&R.CMS.create_article_comment/3) + resolve(&R.CMS.create_comment/3) middleware(M.Statistics.MakeContribute, for: :user) end diff --git a/lib/groupher_server_web/schema/utils/helper.ex b/lib/groupher_server_web/schema/utils/helper.ex index 01460849e..d06c5b6e8 100644 --- a/lib/groupher_server_web/schema/utils/helper.ex +++ b/lib/groupher_server_web/schema/utils/helper.ex @@ -224,6 +224,19 @@ defmodule GroupherServerWeb.Schema.Utils.Helper do end end + @doc """ + general emotion enum for comments + #NOTE: xxx_user_logins field is not support for gq-endpoint + """ + defmacro emotion_enum() do + @supported_emotions + |> Enum.map(fn emotion -> + quote do + value(unquote(:"#{emotion}")) + end + end) + end + @doc """ general emotions for comments #NOTE: xxx_user_logins field is not support for gq-endpoint diff --git a/test/groupher_server/cms/article_comment_emotions_test.exs b/test/groupher_server/cms/article_comment_emotions_test.exs index de7aaffea..7a6ccbad5 100644 --- a/test/groupher_server/cms/article_comment_emotions_test.exs +++ b/test/groupher_server/cms/article_comment_emotions_test.exs @@ -6,7 +6,7 @@ defmodule GroupherServer.Test.CMS.ArticleCommentEmotions do alias Helper.ORM alias GroupherServer.CMS - alias CMS.{ArticleComment, Embeds} + alias CMS.{ArticleComment, Embeds, ArticleCommentUserEmotion} @default_emotions Embeds.ArticleCommentEmotion.default_emotions() @@ -77,7 +77,7 @@ defmodule GroupherServer.Test.CMS.ArticleCommentEmotions do assert @default_emotions == emotions end - @tag :wip + @tag :wip2 test "can make emotion to comment", ~m(post user user2)a do parent_content = "parent comment" {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, parent_content, user) @@ -92,8 +92,31 @@ defmodule GroupherServer.Test.CMS.ArticleCommentEmotions do assert user_exist_in?(user2, emotions.latest_downvote_users) end - @tag :wip - test "same user make same emotion to same comment", ~m(post user)a do + @tag :wip2 + test "can undo emotion to comment", ~m(post user user2)a do + parent_content = "parent comment" + {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, parent_content, user) + + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :downvote, user) + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :downvote, user2) + + {:ok, %{emotions: emotions}} = ORM.find(ArticleComment, parent_comment.id) + + assert emotions.downvote_count == 2 + assert user_exist_in?(user, emotions.latest_downvote_users) + assert user_exist_in?(user2, emotions.latest_downvote_users) + + {:ok, _} = CMS.undo_emotion_to_comment(parent_comment.id, :downvote, user) + {:ok, _} = CMS.undo_emotion_to_comment(parent_comment.id, :downvote, user2) + + {:ok, %{emotions: emotions}} = ORM.find(ArticleComment, parent_comment.id) + assert emotions.downvote_count == 0 + assert not user_exist_in?(user, emotions.latest_downvote_users) + assert not user_exist_in?(user2, emotions.latest_downvote_users) + end + + @tag :wip2 + test "same user make same emotion to same comment.", ~m(post user)a do parent_content = "parent comment" {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, parent_content, user) @@ -106,7 +129,31 @@ defmodule GroupherServer.Test.CMS.ArticleCommentEmotions do assert user_exist_in?(user, parent_comment.emotions.latest_downvote_users) end - @tag :wip + @tag :wip2 + test "same user same emotion to same comment only have one user_emotion record", + ~m(post user)a do + parent_content = "parent comment" + {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, parent_content, user) + + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :downvote, user) + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :heart, user) + + {:ok, parent_comment} = ORM.find(ArticleComment, parent_comment.id) + + {:ok, records} = ORM.find_all(ArticleCommentUserEmotion, %{page: 1, size: 10}) + assert records.total_count == 1 + + {:ok, record} = + ORM.find_by(ArticleCommentUserEmotion, %{ + article_comment_id: parent_comment.id, + user_id: user.id + }) + + assert record.downvote + assert record.heart + end + + @tag :wip2 test "different user can make same emotions on same comment", ~m(post user user2 user3)a do {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, "parent comment", user) diff --git a/test/groupher_server/cms/article_comment_replies_test.exs b/test/groupher_server/cms/article_comment_replies_test.exs index 13cddc12e..9d9c8ce1d 100644 --- a/test/groupher_server/cms/article_comment_replies_test.exs +++ b/test/groupher_server/cms/article_comment_replies_test.exs @@ -34,13 +34,13 @@ defmodule GroupherServer.Test.CMS.ArticleCommentReplies do assert exist_in?(replyed_comment, parent_comment.replies) end - @tag :wip + @tag :wip3 test "deleted comment can not be reply", ~m(post user user2)a do parent_content = "parent comment" reply_content = "reply comment" {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, parent_content, user) - {:ok, _} = CMS.delete_article_comment(parent_comment.id, user) + {:ok, _} = CMS.delete_article_comment(parent_comment) {:error, _} = CMS.reply_article_comment(parent_comment.id, reply_content, user2) end diff --git a/test/groupher_server/cms/article_comment_test.exs b/test/groupher_server/cms/article_comment_test.exs index c8d9679fa..ee1d198c4 100644 --- a/test/groupher_server/cms/article_comment_test.exs +++ b/test/groupher_server/cms/article_comment_test.exs @@ -46,6 +46,15 @@ defmodule GroupherServer.Test.CMS.ArticleComment do {:ok, comment} = CMS.create_article_comment(:post, post.id, "post comment", user) assert comment.meta |> Map.from_struct() |> Map.delete(:id) == @default_comment_meta end + + @tag :wip3 + test "comment can be updated", ~m(post user)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "post comment", user) + + {:ok, updated_comment} = CMS.update_article_comment(comment, "updated content") + + assert updated_comment.body_html == "updated content" + end end describe "[article comment floor]" do @@ -130,7 +139,7 @@ defmodule GroupherServer.Test.CMS.ArticleComment do assert comment.meta.is_article_author_upvoted end - @tag :wip2 + @tag :wip3 test "user upvote post comment will add id to upvoted_user_ids", ~m(post user)a do comment = "post_comment" {:ok, comment} = CMS.create_article_comment(:post, post.id, comment, user) @@ -139,7 +148,7 @@ defmodule GroupherServer.Test.CMS.ArticleComment do assert user.id in comment.meta.upvoted_user_ids end - @tag :wip2 + @tag :wip3 test "user undo upvote post comment will remove id from upvoted_user_ids", ~m(post user user2)a do comment = "post_comment" @@ -556,7 +565,7 @@ defmodule GroupherServer.Test.CMS.ArticleComment do end describe "[article comment delete]" do - @tag :wip + @tag :wip3 test "delete comment still exsit in paged list and content is gone", ~m(user post)a do total_count = 10 page_number = 1 @@ -571,7 +580,7 @@ defmodule GroupherServer.Test.CMS.ArticleComment do random_comment = all_comments |> Enum.at(1) - {:ok, deleted_comment} = CMS.delete_article_comment(random_comment.id, user) + {:ok, deleted_comment} = CMS.delete_article_comment(random_comment) {:ok, paged_comments} = CMS.list_article_comments(:post, post.id, %{page: page_number, size: page_size}, :replies) @@ -581,7 +590,7 @@ defmodule GroupherServer.Test.CMS.ArticleComment do assert deleted_comment.body_html == @delete_hint end - @tag :wip + @tag :wip3 test "delete comment still update article's comments_count field", ~m(user post)a do {:ok, _comment} = CMS.create_article_comment(:post, post.id, "commment", user) {:ok, _comment} = CMS.create_article_comment(:post, post.id, "commment", user) @@ -593,13 +602,13 @@ defmodule GroupherServer.Test.CMS.ArticleComment do assert post.article_comments_count == 5 - {:ok, _} = CMS.delete_article_comment(comment.id, user) + {:ok, _} = CMS.delete_article_comment(comment) {:ok, post} = ORM.find(Post, post.id) assert post.article_comments_count == 4 end - @tag :wip + @tag :wip3 test "delete comment still delete pined record if needed", ~m(user post)a do total_count = 10 @@ -615,7 +624,7 @@ defmodule GroupherServer.Test.CMS.ArticleComment do {:ok, _comment} = CMS.pin_article_comment(random_comment.id) {:ok, _comment} = ORM.find(ArticleComment, random_comment.id) - {:ok, _} = CMS.delete_article_comment(random_comment.id, user) + {:ok, _} = CMS.delete_article_comment(random_comment) assert {:error, _comment} = ORM.find(ArticlePinedComment, random_comment.id) end end diff --git a/test/groupher_server/cms/job_test.exs b/test/groupher_server/cms/job_test.exs index 297468cd6..6d924a25f 100644 --- a/test/groupher_server/cms/job_test.exs +++ b/test/groupher_server/cms/job_test.exs @@ -25,7 +25,7 @@ defmodule GroupherServer.Test.Job do assert found.title == job.title end - @tag :wip2 + @tag :wip3 test "read job should update views and meta viewed_user_list", ~m(job_attrs community user user2)a do {:ok, job} = CMS.create_content(community, :job, job_attrs, user) diff --git a/test/groupher_server/cms/post_test.exs b/test/groupher_server/cms/post_test.exs index e333d460d..4f4743e80 100644 --- a/test/groupher_server/cms/post_test.exs +++ b/test/groupher_server/cms/post_test.exs @@ -26,7 +26,7 @@ defmodule GroupherServer.Test.CMS.Post do assert post.title == post_attrs.title end - @tag :wip2 + @tag :wip3 test "read post should update views and meta viewed_user_list", ~m(post_attrs community user user2)a do {:ok, post} = CMS.create_content(community, :post, post_attrs, user) diff --git a/test/groupher_server/cms/repo_test.exs b/test/groupher_server/cms/repo_test.exs index e54709755..f818ecea0 100644 --- a/test/groupher_server/cms/repo_test.exs +++ b/test/groupher_server/cms/repo_test.exs @@ -27,7 +27,7 @@ defmodule GroupherServer.Test.Repo do assert repo.contributors |> length !== 0 end - @tag :wip2 + @tag :wip3 test "read repo should update views and meta viewed_user_list", ~m(repo_attrs community user user2)a do {:ok, repo} = CMS.create_content(community, :repo, repo_attrs, user) diff --git a/test/groupher_server_web/mutation/cms/article_comment_test.exs b/test/groupher_server_web/mutation/cms/article_comment_test.exs new file mode 100644 index 000000000..f045bbc63 --- /dev/null +++ b/test/groupher_server_web/mutation/cms/article_comment_test.exs @@ -0,0 +1,147 @@ +defmodule GroupherServer.Test.Mutation.ArticleComment do + use GroupherServer.TestTools + + alias GroupherServer.CMS + + setup do + {:ok, post} = db_insert(:post) + {:ok, user} = db_insert(:user) + {:ok, community} = db_insert(:community) + + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user) + owner_conn = simu_conn(:user, user) + + {:ok, ~m(user_conn user guest_conn owner_conn community post)a} + end + + describe "[article comment CURD]" do + @write_comment_query """ + mutation($thread: CmsThread!, $id: ID!, $content: String!) { + createArticleComment(thread: $thread,id: $id, content: $content) { + id + bodyHtml + } + } + """ + @tag :wip3 + test "write article comment to a exsit post", ~m(post user_conn)a do + comment = "a test comment" + variables = %{thread: "POST", id: post.id, content: comment} + + result = + user_conn |> mutation_result(@write_comment_query, variables, "createArticleComment") + + assert result["bodyHtml"] == comment + end + + @update_comment_query """ + mutation($id: ID!, $content: String!) { + updateArticleComment(id: $id, content: $content) { + id + bodyHtml + } + } + """ + @tag :wip3 + test "only owner can update a exsit comment", + ~m(post user guest_conn user_conn owner_conn)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "post comment", user) + variables = %{id: comment.id, content: "updated comment"} + + assert user_conn |> mutation_get_error?(@update_comment_query, variables, ecode(:passport)) + + assert guest_conn + |> mutation_get_error?(@update_comment_query, variables, ecode(:account_login)) + + updated = + owner_conn |> mutation_result(@update_comment_query, variables, "updateArticleComment") + + assert updated["bodyHtml"] == "updated comment" + end + + @delete_comment_query """ + mutation($id: ID!) { + deleteArticleComment(id: $id) { + id + isDeleted + } + } + """ + @tag :wip3 + test "only owner can delete a exsit comment", + ~m(post user guest_conn user_conn owner_conn)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "post comment", user) + variables = %{id: comment.id} + + assert user_conn |> mutation_get_error?(@delete_comment_query, variables, ecode(:passport)) + + assert guest_conn + |> mutation_get_error?(@delete_comment_query, variables, ecode(:account_login)) + + deleted = + owner_conn |> mutation_result(@delete_comment_query, variables, "deleteArticleComment") + + assert deleted["id"] == to_string(comment.id) + assert deleted["isDeleted"] + end + end + + describe "[article comment emotion]" do + @emotion_comment_query """ + mutation($id: ID!, $emotion: ArticleCommentEmotion!) { + emotionToComment(id: $id, emotion: $emotion) { + id + emotions { + beerCount + viewerHasBeered + latestBeerUsers { + login + nickname + } + } + } + } + """ + @tag :wip3 + test "login user can emotion to a comment", ~m(post user user_conn)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "post comment", user) + variables = %{id: comment.id, emotion: "BEER"} + + comment = + user_conn |> mutation_result(@emotion_comment_query, variables, "emotionToComment") + + assert comment |> get_in(["emotions", "beerCount"]) == 1 + assert get_in(comment, ["emotions", "viewerHasBeered"]) + end + + @emotion_comment_query """ + mutation($id: ID!, $emotion: ArticleCommentEmotion!) { + undoEmotionToComment(id: $id, emotion: $emotion) { + id + emotions { + beerCount + viewerHasBeered + latestBeerUsers { + login + nickname + } + } + } + } + """ + @tag :wip2 + test "login user can undo emotion to a comment", ~m(post user owner_conn)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "post comment", user) + {:ok, _} = CMS.emotion_to_comment(comment.id, :beer, user) + + variables = %{id: comment.id, emotion: "BEER"} + + comment = + owner_conn |> mutation_result(@emotion_comment_query, variables, "undoEmotionToComment") + + assert comment |> get_in(["emotions", "beerCount"]) == 0 + assert not get_in(comment, ["emotions", "viewerHasBeered"]) + end + end +end diff --git a/test/groupher_server_web/query/cms/article_comment_test.exs b/test/groupher_server_web/query/cms/article_comment_test.exs index c67dcdc6c..35e0626b6 100644 --- a/test/groupher_server_web/query/cms/article_comment_test.exs +++ b/test/groupher_server_web/query/cms/article_comment_test.exs @@ -473,7 +473,7 @@ defmodule GroupherServer.Test.Query.ArticleComment do |> get_in(["emotions", "viewerHasDownvoteed"]) end - @tag :wip2 + @tag :wip3 test "comment should have viewer has upvoted flag", ~m(user_conn post user)a do total_count = 10 page_size = 12