diff --git a/lib/groupher_server/cms/abuse_report.ex b/lib/groupher_server/cms/abuse_report.ex new file mode 100644 index 000000000..1af03eb7a --- /dev/null +++ b/lib/groupher_server/cms/abuse_report.ex @@ -0,0 +1,45 @@ +defmodule GroupherServer.CMS.AbuseReport do + @moduledoc false + alias __MODULE__ + + use Ecto.Schema + import Ecto.Changeset + + alias GroupherServer.{Accounts, CMS} + alias CMS.{ArticleComment, Embeds, Post, Job} + + # @required_fields ~w(article_comment_id user_id recived_user_id)a + @optional_fields ~w(article_comment_id post_id job_id account_id operate_user_id deal_with is_closed report_cases_count)a + @update_fields ~w(operate_user_id deal_with is_closed report_cases_count)a + + @type t :: %AbuseReport{} + schema "abuse_reports" do + belongs_to(:article_comment, ArticleComment, foreign_key: :article_comment_id) + belongs_to(:post, Post, foreign_key: :post_id) + belongs_to(:job, Job, foreign_key: :job_id) + belongs_to(:account, Accounts.User, foreign_key: :account_id) + + embeds_many(:report_cases, Embeds.AbuseReportCase, on_replace: :delete) + field(:report_cases_count, :integer, default: 0) + + belongs_to(:operate_user, Accounts.User, foreign_key: :operate_user_id) + + field(:deal_with, :string) + field(:is_closed, :boolean, default: false) + + timestamps(type: :utc_datetime) + end + + @doc false + def changeset(%AbuseReport{} = struct, attrs) do + struct + |> cast(attrs, @optional_fields) + |> cast_embed(:report_cases, required: true, with: &Embeds.AbuseReportCase.changeset/2) + end + + def update_changeset(%AbuseReport{} = struct, attrs) do + struct + |> cast(attrs, @update_fields) + |> cast_embed(:report_cases, required: true, with: &Embeds.AbuseReportCase.changeset/2) + end +end diff --git a/lib/groupher_server/cms/article_comment.ex b/lib/groupher_server/cms/article_comment.ex new file mode 100644 index 000000000..7ef734a80 --- /dev/null +++ b/lib/groupher_server/cms/article_comment.ex @@ -0,0 +1,104 @@ +defmodule GroupherServer.CMS.ArticleComment do + @moduledoc false + alias __MODULE__ + + use Ecto.Schema + use Accessible + + import Ecto.Changeset + + alias GroupherServer.{Accounts, CMS} + + alias CMS.{ + Post, + Job, + Embeds, + ArticleCommentUpvote + } + + # alias Helper.HTML + + @required_fields ~w(body_html author_id)a + @optional_fields ~w(post_id job_id reply_to_id replies_count is_folded is_reported is_deleted floor is_article_author)a + @updatable_fields ~w(is_folded is_reported is_deleted floor upvotes_count)a + + @max_participator_count 5 + @max_parent_replies_count 3 + + @supported_emotions [:downvote, :beer, :heart, :biceps, :orz, :confused, :pill] + @max_latest_emotion_users_count 5 + + @delete_hint "this comment is deleted" + # 举报超过此数评论会被自动折叠 + @report_threshold_for_fold 5 + + @doc "latest participators stores in article comment_participators field" + def max_participator_count(), do: @max_participator_count + @doc "latest replies stores in article_comment replies field, used for frontend display" + def max_parent_replies_count(), do: @max_parent_replies_count + + @doc "操作某 emotion 的最近用户" + def max_latest_emotion_users_count(), do: @max_latest_emotion_users_count + + def supported_emotions(), do: @supported_emotions + def delete_hint(), do: @delete_hint + + def report_threshold_for_fold, do: @report_threshold_for_fold + + @type t :: %ArticleComment{} + schema "articles_comments" do + field(:body_html, :string) + field(:replies_count, :integer, default: 0) + + # 是否被折叠 + field(:is_folded, :boolean, default: false) + # 是否被举报 + field(:is_reported, :boolean, default: false) + # 是否被删除 + field(:is_deleted, :boolean, default: false) + # 楼层 + field(:floor, :integer, default: 0) + + # 是否是评论文章的作者 + field(:is_article_author, :boolean, default: false) + field(:upvotes_count, :integer, default: 0) + + 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) + + embeds_many(:replies, ArticleComment, on_replace: :delete) + embeds_one(:emotions, Embeds.ArticleCommentEmotion, on_replace: :update) + embeds_one(:meta, Embeds.ArticleCommentMeta, on_replace: :update) + + has_many(:upvotes, {"articles_comments_upvotes", ArticleCommentUpvote}) + + timestamps(type: :utc_datetime) + end + + @doc false + def changeset(%ArticleComment{} = article_comment, attrs) do + article_comment + |> cast(attrs, @required_fields ++ @optional_fields) + |> cast_embed(:emotions, required: true, with: &Embeds.ArticleCommentEmotion.changeset/2) + |> validate_required(@required_fields) + |> generl_changeset + end + + # @doc false + def update_changeset(%ArticleComment{} = article_comment, attrs) do + article_comment + |> cast(attrs, @required_fields ++ @updatable_fields) + # |> cast_embed(:emotions, required: false, with: &Embeds.ArticleCommentEmotion.changeset/2) + |> generl_changeset + end + + defp generl_changeset(content) do + content + |> foreign_key_constraint(:author_id) + + # |> validate_length(:body_html, min: 3, max: 2000) + # |> HTML.safe_string(:body_html) + end +end diff --git a/lib/groupher_server/cms/article_comment_participator.ex b/lib/groupher_server/cms/article_comment_participator.ex new file mode 100644 index 000000000..213f82457 --- /dev/null +++ b/lib/groupher_server/cms/article_comment_participator.ex @@ -0,0 +1,24 @@ +defmodule GroupherServer.CMS.ArticleCommentParticipator do + @moduledoc false + + use Ecto.Schema + + alias GroupherServer.Accounts.User + + # alias CMS.{ + # Post, + # Job, + # ArticleCommentUpvote + # } + + # alias Helper.HTML + + # @required_fields ~w(user_id)a + # @optional_fields ~w(post_id job_id)a + + embedded_schema do + # field(:reply_time, :string) + + belongs_to(:user, User) + end +end diff --git a/lib/groupher_server/cms/article_comment_reply.ex b/lib/groupher_server/cms/article_comment_reply.ex new file mode 100644 index 000000000..3ee5794f2 --- /dev/null +++ b/lib/groupher_server/cms/article_comment_reply.ex @@ -0,0 +1,29 @@ +defmodule GroupherServer.CMS.ArticleCommentReply do + @moduledoc false + alias __MODULE__ + + use Ecto.Schema + import Ecto.Changeset + + alias GroupherServer.CMS + alias CMS.ArticleComment + + @required_fields ~w(article_comment_id reply_to_id)a + + @type t :: %ArticleCommentReply{} + schema "articles_comments_replies" do + belongs_to(:article_comment, ArticleComment, foreign_key: :article_comment_id) + belongs_to(:reply_to, ArticleComment, foreign_key: :reply_to_id) + + timestamps(type: :utc_datetime) + end + + @doc false + def changeset(%ArticleCommentReply{} = article_comment_reply, attrs) do + article_comment_reply + |> cast(attrs, @required_fields) + |> validate_required(@required_fields) + |> foreign_key_constraint(:article_comment_id) + |> foreign_key_constraint(:reply_to_id) + end +end diff --git a/lib/groupher_server/cms/article_comment_upvote.ex b/lib/groupher_server/cms/article_comment_upvote.ex new file mode 100644 index 000000000..837a55123 --- /dev/null +++ b/lib/groupher_server/cms/article_comment_upvote.ex @@ -0,0 +1,32 @@ +defmodule GroupherServer.CMS.ArticleCommentUpvote do + @moduledoc false + alias __MODULE__ + + use Ecto.Schema + import Ecto.Changeset + + alias GroupherServer.{Accounts, CMS} + alias CMS.ArticleComment + + @required_fields ~w(article_comment_id user_id)a + + @type t :: %ArticleCommentUpvote{} + schema "articles_comments_upvotes" do + belongs_to(:user, Accounts.User, foreign_key: :user_id) + belongs_to(:article_comment, ArticleComment, foreign_key: :article_comment_id) + + timestamps(type: :utc_datetime) + end + + @doc false + def changeset(%ArticleCommentUpvote{} = article_comment_upvote, attrs) do + article_comment_upvote + |> cast(attrs, @required_fields) + |> validate_required(@required_fields) + |> foreign_key_constraint(:article_comment_id) + |> foreign_key_constraint(:user_id) + |> unique_constraint(:user_id, + name: :articles_comments_upvotes_user_id_article_comment_id_index + ) + end +end diff --git a/lib/groupher_server/cms/article_comment_user_emotion.ex b/lib/groupher_server/cms/article_comment_user_emotion.ex new file mode 100644 index 000000000..73bf62bfe --- /dev/null +++ b/lib/groupher_server/cms/article_comment_user_emotion.ex @@ -0,0 +1,40 @@ +defmodule GroupherServer.CMS.ArticleCommentUserEmotion do + @moduledoc false + alias __MODULE__ + + use Ecto.Schema + import Ecto.Changeset + + alias GroupherServer.{Accounts, CMS} + alias CMS.ArticleComment + + @required_fields ~w(article_comment_id user_id recived_user_id)a + @optional_fields ~w(downvote beer heart biceps orz confused pill)a + + @type t :: %ArticleCommentUserEmotion{} + schema "articles_comments_users_emotions" do + belongs_to(:article_comment, ArticleComment, foreign_key: :article_comment_id) + belongs_to(:recived_user, Accounts.User, foreign_key: :recived_user_id) + belongs_to(:user, Accounts.User, foreign_key: :user_id) + + field(:downvote, :boolean, default: false) + field(:beer, :boolean, default: false) + field(:heart, :boolean, default: false) + field(:biceps, :boolean, default: false) + field(:orz, :boolean, default: false) + field(:confused, :boolean, default: false) + field(:pill, :boolean, default: false) + + timestamps(type: :utc_datetime) + end + + @doc false + def 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 c06cf2571..9ddd5ba98 100644 --- a/lib/groupher_server/cms/cms.ex +++ b/lib/groupher_server/cms/cms.ex @@ -8,10 +8,12 @@ defmodule GroupherServer.CMS do alias GroupherServer.CMS.Delegate alias Delegate.{ + AbuseReport, ArticleCURD, ArticleOperation, ArticleReaction, FavoritedContents, + ArticleComment, CommentCURD, CommunitySync, CommentReaction, @@ -106,22 +108,44 @@ defmodule GroupherServer.CMS do defdelegate unset_community(community, thread, content_id), to: ArticleOperation # Comment CURD + defdelegate list_article_comments(thread, article_id, filters), to: ArticleComment + defdelegate list_article_comments(thread, article_id, filters, user), to: ArticleComment + defdelegate list_folded_article_comments(thread, article_id, filters), to: ArticleComment + defdelegate list_folded_article_comments(thread, article_id, filters, user), to: ArticleComment + defdelegate list_reported_article_comments(thread, article_id, filters), to: ArticleComment + + defdelegate list_reported_article_comments(thread, article_id, filters, user), + to: ArticleComment + + defdelegate list_comment_replies(comment_id, filters), to: ArticleComment + defdelegate list_comments(thread, content_id, filters), to: CommentCURD defdelegate list_comments_participators(thread, content_id, filters), to: CommentCURD + defdelegate create_article_comment(thread, article_id, args, user), to: ArticleComment + defdelegate 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 make_emotion(comment_id, args, user), to: ArticleComment + 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 + defdelegate unreport_article_comment(comment_id, user), to: ArticleComment + defdelegate create_comment(thread, content_id, args, user), to: CommentCURD defdelegate update_comment(thread, id, args, user), to: CommentCURD defdelegate delete_comment(thread, content_id), to: CommentCURD defdelegate list_replies(thread, comment, user), to: CommentCURD defdelegate reply_comment(thread, comment, args, user), to: CommentCURD + # report + defdelegate create_report(type, content_id, args, user), to: AbuseReport + # Comment Reaction # >> like / undo like defdelegate like_comment(thread, comment, user), to: CommentReaction defdelegate undo_like_comment(thread, comment, user), to: CommentReaction - # >> dislike / undo dislike - defdelegate dislike_comment(thread, comment, user), to: CommentReaction - defdelegate undo_dislike_comment(thread, comment, user), to: CommentReaction # Passport CURD defdelegate stamp_passport(rules, user), to: PassportCURD diff --git a/lib/groupher_server/cms/community.ex b/lib/groupher_server/cms/community.ex index 67cf1fe50..935dd903c 100644 --- a/lib/groupher_server/cms/community.ex +++ b/lib/groupher_server/cms/community.ex @@ -10,7 +10,6 @@ defmodule GroupherServer.CMS.Community do alias CMS.{ Category, Post, - Video, Repo, Job, CommunityThread, diff --git a/lib/groupher_server/cms/delegates/abuse_report.ex b/lib/groupher_server/cms/delegates/abuse_report.ex new file mode 100644 index 000000000..dc5d6c7ba --- /dev/null +++ b/lib/groupher_server/cms/delegates/abuse_report.ex @@ -0,0 +1,79 @@ +defmodule GroupherServer.CMS.Delegate.AbuseReport do + @moduledoc """ + CURD and operations for article comments + """ + import Ecto.Query, warn: false + # import Helper.Utils, only: [done: 1] + + import GroupherServer.CMS.Utils.Matcher2 + # import ShortMaps + + alias Helper.{ORM} + alias GroupherServer.{Accounts, CMS, Repo} + + alias Accounts.User + alias CMS.{AbuseReport, Embeds} + + # alias Accounts.User + + def create_report(type, content_id, %{reason: reason}, %User{} = user) do + with {:ok, info} <- match(type), + {:ok, report} <- not_reported_before(info, content_id, user) do + case report do + nil -> + updated_report_cases = [ + %{ + reason: reason, + additional_reason: "additional_reason", + user: %{login: user.login, nickname: user.nickname} + } + ] + + args = + %{report_cases_count: 1, report_cases: updated_report_cases} + |> Map.put(info.foreign_key, content_id) + + AbuseReport |> ORM.create(args) + + _ -> + updated_report_cases = + report.report_cases + |> List.insert_at( + length(report.report_cases), + %Embeds.AbuseReportCase{ + reason: reason, + additional_reason: "additional_reason", + user: %{login: user.login, nickname: user.nickname} + } + ) + + report + |> Ecto.Changeset.change(%{report_cases_count: length(updated_report_cases)}) + |> Ecto.Changeset.put_embed(:report_cases, updated_report_cases) + |> Repo.update() + end + end + end + + defp not_reported_before(info, content_id, %User{login: login}) do + query = from(r in AbuseReport, where: field(r, ^info.foreign_key) == ^content_id) + + report = Repo.one(query) + + case report do + nil -> + {:ok, nil} + + _ -> + reported_before = + report.report_cases + |> Enum.filter(fn item -> item.user.login == login end) + |> length + |> Kernel.>(0) + + if not reported_before, + do: {:ok, report}, + else: {:error, "#{login} already reported"} + end + end +end diff --git a/lib/groupher_server/cms/delegates/article_comment.ex b/lib/groupher_server/cms/delegates/article_comment.ex new file mode 100644 index 000000000..6bc7786a2 --- /dev/null +++ b/lib/groupher_server/cms/delegates/article_comment.ex @@ -0,0 +1,478 @@ +defmodule GroupherServer.CMS.Delegate.ArticleComment do + @moduledoc """ + CURD and operations for article comments + """ + import Ecto.Query, warn: false + import Helper.Utils, only: [done: 1] + + import GroupherServer.CMS.Utils.Matcher2 + import ShortMaps + + alias Helper.{ORM, QueryBuilder} + alias GroupherServer.{Accounts, CMS, Repo} + + alias Accounts.User + + alias CMS.{ + ArticleComment, + ArticleCommentUpvote, + ArticleCommentReply, + ArticleCommentUserEmotion, + Embeds, + Post, + Job + } + + 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() + @supported_emotions ArticleComment.supported_emotions() + @delete_hint ArticleComment.delete_hint() + @report_threshold_for_fold ArticleComment.report_threshold_for_fold() + + @doc """ + list paged article comments + """ + def list_article_comments(thread, article_id, %{page: page, size: size} = filters) do + with {:ok, thread_query} <- match(thread, :query, article_id) do + ArticleComment + |> where(^thread_query) + |> where([c], c.is_folded == false and c.is_reported == false) + |> QueryBuilder.filter_pack(filters) + |> ORM.paginater(~m(page size)a) + |> done() + end + end + + def list_article_comments( + thread, + article_id, + %{page: page, size: size} = filters, + %User{} = user + ) do + with {:ok, thread_query} <- match(thread, :query, article_id) do + ArticleComment + |> where(^thread_query) + |> where([c], c.is_folded == false and c.is_reported == false) + |> QueryBuilder.filter_pack(filters) + |> ORM.paginater(~m(page size)a) + |> check_viewer_has_emotioned(user) + |> done() + end + end + + def list_folded_article_comments(thread, article_id, %{page: page, size: size} = filters) do + with {:ok, thread_query} <- match(thread, :query, article_id) do + ArticleComment + |> where(^thread_query) + |> where([c], c.is_folded == true and c.is_reported == false) + |> QueryBuilder.filter_pack(filters) + |> ORM.paginater(~m(page size)a) + |> done() + end + end + + def list_folded_article_comments( + thread, + article_id, + %{page: page, size: size} = filters, + %User{} = user + ) do + with {:ok, thread_query} <- match(thread, :query, article_id) do + ArticleComment + |> where(^thread_query) + |> where([c], c.is_folded == true and c.is_reported == false) + |> QueryBuilder.filter_pack(filters) + |> ORM.paginater(~m(page size)a) + |> check_viewer_has_emotioned(user) + |> done() + end + end + + def list_reported_article_comments(thread, article_id, %{page: page, size: size} = filters) do + with {:ok, thread_query} <- match(thread, :query, article_id) do + ArticleComment + |> where(^thread_query) + |> where([c], c.is_reported == true) + |> QueryBuilder.filter_pack(filters) + |> ORM.paginater(~m(page size)a) + |> done() + end + end + + def list_reported_article_comments( + thread, + article_id, + %{page: page, size: size} = filters, + %User{} = user + ) do + with {:ok, thread_query} <- match(thread, :query, article_id) do + ArticleComment + |> where(^thread_query) + |> where([c], c.is_reported == true) + |> QueryBuilder.filter_pack(filters) + |> ORM.paginater(~m(page size)a) + |> check_viewer_has_emotioned(user) + |> done() + end + end + + @doc """ + list paged comment replies + """ + def list_comment_replies(comment_id, %{page: page, size: size} = filters) do + ArticleComment + |> where([c], c.reply_to_id == ^comment_id) + # TODO: test reported and folded status + |> where([c], c.is_folded == false and c.is_reported == false) + |> QueryBuilder.filter_pack(filters) + |> ORM.paginater(~m(page size)a) + |> done() + end + + def delete_article_comment(comment_id, %User{} = _user) do + with {:ok, comment} <- + ORM.find(ArticleComment, comment_id) do + comment |> ORM.update(%{body_html: @delete_hint, is_deleted: true}) + end + end + + def fold_article_comment(%ArticleComment{} = comment, %User{} = _user) do + comment |> ORM.update(%{is_folded: true}) + end + + @doc "fold a comment" + def fold_article_comment(comment_id, %User{} = _user) do + with {:ok, comment} <- + ORM.find(ArticleComment, comment_id) do + comment |> ORM.update(%{is_folded: true}) + end + end + + @doc "fold a comment" + def unfold_article_comment(comment_id, %User{} = _user) do + with {:ok, comment} <- + ORM.find(ArticleComment, comment_id) do + comment |> ORM.update(%{is_folded: false}) + end + end + + @doc "fold a comment" + def report_article_comment(comment_id, %User{} = user) do + with {:ok, comment} <- + ORM.find(ArticleComment, comment_id) do + Multi.new() + |> Multi.run(:create_abuse_report, fn _, _ -> + CMS.create_report(:article_comment, comment_id, %{reason: "todo fucked"}, user) + end) + |> Multi.run(:update_report_flag, fn _, _ -> + ORM.update(comment, %{is_reported: true}) + end) + |> Multi.run(:fold_comment_report_too_many, fn _, %{create_abuse_report: abuse_report} -> + if abuse_report.report_cases_count >= @report_threshold_for_fold, + do: fold_article_comment(comment, user), + else: {:ok, comment} + end) + |> Repo.transaction() + |> upsert_comment_result() + end + end + + @doc "fold a comment" + def unreport_article_comment(comment_id, %User{} = _user) do + with {:ok, comment} <- + ORM.find(ArticleComment, comment_id) do + comment |> ORM.update(%{is_reported: false}) + end + end + + @doc "make emotion to a comment" + def make_emotion(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) |> Enum.join(",") + ) + |> 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 + + # is not work this way, why? + # updated_emotions = + # Map.merge(comment.emotions, %{ + # downvote_count: comment.emotions.downvote_count + Enum.random([1, 2, 3]), + # tada_count: comment.emotions.tada_count + Enum.random([1, 2, 3]) + # }) + end + end + + @doc """ + Creates a comment for psot, job ... + """ + def create_article_comment(thread, article_id, content, %User{} = user) do + with {:ok, info} <- match(thread), + # make sure the article exsit + # author is passed by middleware, it's exsit for sure + {:ok, article} <- ORM.find(info.model, article_id) do + Multi.new() + |> Multi.run(:create_article_comment, fn _, _ -> + do_create_comment(content, info.foreign_key, article, user) + end) + |> Multi.run(:add_participator, fn _, _ -> + add_participator_to_article(article, user) + end) + # |> Multi.run(:mention_users, fn _, %{create_comment: comment} -> + # Delivery.mention_from_comment(community, thread, content, comment, args, user) + # {:ok, :pass} + # end) + |> Repo.transaction() + |> upsert_comment_result() + end + end + + @doc "reply to exsiting comment" + def reply_article_comment(comment_id, content, %User{} = user) do + with {:ok, replying_comment} <- ORM.find(ArticleComment, comment_id, preload: :reply_to), + {thread, article} <- get_article(replying_comment), + {:ok, info} <- match(thread), + parent_comment <- get_parent_comment(replying_comment) do + Multi.new() + |> Multi.run(:create_reply_comment, fn _, _ -> + do_create_comment(content, info.foreign_key, article, user) + end) + |> Multi.run(:create_article_comment_reply, fn _, + %{create_reply_comment: replyed_comment} -> + ArticleCommentReply + |> ORM.create(%{article_comment_id: replyed_comment.id, reply_to_id: replying_comment.id}) + end) + |> Multi.run(:inc_replies_count, fn _, _ -> + ORM.inc_field(ArticleComment, replying_comment, :replies_count) + end) + |> Multi.run(:add_replies_ifneed, fn _, %{create_reply_comment: replyed_comment} -> + add_replies_ifneed(parent_comment, replyed_comment) + end) + |> Multi.run(:add_participator, fn _, _ -> + add_participator_to_article(article, user) + end) + |> Multi.run(:add_reply_to, fn _, %{create_reply_comment: replyed_comment} -> + replyed_comment + |> Repo.preload(:reply_to) + |> Ecto.Changeset.change() + |> Ecto.Changeset.put_assoc(:reply_to, replying_comment) + |> Repo.update() + end) + |> Repo.transaction() + |> upsert_comment_result() + end + end + + @doc "upvote a comment" + # TODO: user has upvoted logic, move to GraphQL + def upvote_article_comment(comment_id, %User{id: user_id}) do + with {:ok, comment} <- ORM.find(ArticleComment, comment_id), + false <- comment.is_deleted do + Multi.new() + |> Multi.run(:create_comment_upvote, fn _, _ -> + ORM.create(ArticleCommentUpvote, %{article_comment_id: comment.id, user_id: user_id}) + end) + |> Multi.run(:inc_upvotes_count, fn _, _ -> + count_query = from(c in ArticleCommentUpvote, where: c.article_comment_id == ^comment_id) + upvotes_count = Repo.aggregate(count_query, :count) + ORM.update(comment, %{upvotes_count: upvotes_count}) + end) + |> Repo.transaction() + |> upsert_comment_result() + end + end + + # creat article comment for parent or reply + # set floor + # TODO: parse editor-json + # set default emotions + defp do_create_comment( + content, + foreign_key, + %{id: article_id, author_id: article_author_id}, + %User{ + id: user_id + } + ) do + count_query = from(c in ArticleComment, where: field(c, ^foreign_key) == ^article_id) + floor = Repo.aggregate(count_query, :count) + 1 + + ArticleComment + |> ORM.create( + Map.put( + %{ + author_id: user_id, + body_html: content, + emotions: @default_emotions, + floor: floor, + is_article_author: user_id == article_author_id + }, + foreign_key, + article_id + ) + ) + end + + # 设计盖楼只保留一个层级,回复楼中的评论都会被放到顶楼的 replies 中 + defp get_parent_comment(%ArticleComment{reply_to_id: nil} = comment) do + comment + end + + defp get_parent_comment(%ArticleComment{reply_to_id: _} = comment) do + Repo.preload(comment, :reply_to) |> Map.get(:reply_to) + # get_parent_comment(Repo.preload(comment, :reply_to)) + end + + # 如果 replies 没有达到 @max_parent_replies_count, 则添加 + # "加载更多" 的逻辑使用另外的 paged 接口从 ArticleCommentReply 表中查询 + defp add_replies_ifneed( + %ArticleComment{replies: replies} = parent_comment, + %ArticleComment{} = replyed_comment + ) + when length(replies) < @max_parent_replies_count do + new_replies = + replies + |> List.insert_at(length(replies), replyed_comment) + |> Enum.slice(0, @max_parent_replies_count) + + parent_comment + |> Ecto.Changeset.change() + |> Ecto.Changeset.put_embed(:replies, new_replies) + |> Repo.update() + end + + # 如果已经有 @max_parent_replies_count 以上的回复了,直接忽略即可 + defp add_replies_ifneed(%ArticleComment{} = parent_comment, _) do + {:ok, parent_comment} + end + + # add participator to article-like content (Post, Job ...) + defp add_participator_to_article(%Post{} = article, %User{} = user) do + new_comment_participators = + article.comment_participators + |> List.insert_at(0, user) + |> Enum.uniq() + |> Enum.slice(0, @max_participator_count) + + article + |> Ecto.Changeset.change() + |> Ecto.Changeset.put_embed(:comment_participators, new_comment_participators) + |> Repo.update() + end + + defp add_participator_to_article(_, _), do: {:ok, :pass} + + defp get_article(%ArticleComment{post_id: post_id} = comment) when not is_nil(post_id) do + with {:ok, article} <- ORM.find(Post, comment.post_id) do + {:post, article} + end + end + + defp get_article(%ArticleComment{job_id: job_id} = comment) when not is_nil(job_id) do + with {:ok, article} <- ORM.find(Job, comment.job_id) do + {:job, article} + end + end + + defp user_in_logins?(nil, _), do: false + + defp user_in_logins?(ids_str, %User{login: login}) do + ids_list = ids_str |> String.split(",") + login in ids_list + end + + defp check_viewer_has_emotioned(%{entries: []} = paged_comments, _), do: paged_comments + + defp check_viewer_has_emotioned(%{entries: entries} = paged_comments, %User{} = user) do + new_entries = + Enum.map(entries, fn comment -> + update_viewed_status = + @supported_emotions + |> Enum.reduce([], fn emotion, acc -> + already_emotioned = user_in_logins?(comment.emotions[:"#{emotion}_user_logins"], user) + acc ++ ["viewer_has_#{emotion}ed": already_emotioned] + end) + |> Enum.into(%{}) + + updated_emotions = Map.merge(comment.emotions, update_viewed_status) + Map.put(comment, :emotions, updated_emotions) + end) + + %{paged_comments | entries: new_entries} + 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, %{inc_upvotes_count: 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({:error, :create_comment, result, _steps}) do + {:error, result} + end + + defp upsert_comment_result({:error, :add_participator, result, _steps}) do + {:error, result} + end + + defp upsert_comment_result({:error, :create_abuse_report, result, _steps}) do + {:error, result} + end + + defp upsert_comment_result({:error, _, result, _steps}) do + {:error, result} + end +end diff --git a/lib/groupher_server/cms/delegates/article_operation.ex b/lib/groupher_server/cms/delegates/article_operation.ex index e12ffb36a..9685281f7 100644 --- a/lib/groupher_server/cms/delegates/article_operation.ex +++ b/lib/groupher_server/cms/delegates/article_operation.ex @@ -10,7 +10,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleOperation do alias Helper.ORM alias GroupherServer.CMS.{ - ArticleMeta, + Embeds, Community, Post, PostCommunityFlag, @@ -265,27 +265,33 @@ defmodule GroupherServer.CMS.Delegate.ArticleOperation do def set_meta(_, _), do: {:ok, :pass} @doc "update isEdited meta label if needed" - def update_meta(%Post{meta: %ArticleMeta{is_edited: false} = meta} = content, :is_edited) do - new_meta = meta |> Map.from_struct() |> Map.delete(:id) |> Map.merge(%{is_edited: true}) - - content - |> Ecto.Changeset.change() - |> Ecto.Changeset.put_embed(:meta, new_meta) - |> Repo.update() + def update_meta(%Post{meta: %Embeds.ArticleMeta{is_edited: false} = meta} = content, :is_edited) do + new_meta = + meta + |> Map.from_struct() + |> Map.delete(:id) + |> Map.merge(%{is_edited: true}) + + do_update_meta(content, new_meta) end # for test or exsiting articles def update_meta(%Post{meta: nil} = content, :is_edited) do - new_meta = ArticleMeta.default_meta() |> Map.merge(%{is_edited: true}) + new_meta = Embeds.ArticleMeta.default_meta() |> Map.merge(%{is_edited: true}) + + do_update_meta(content, new_meta) + end + + def update_meta(content, _), do: {:ok, content} + # TODO: put it into ORM helper + defp do_update_meta(%{meta: _} = content, meta_params) do content |> Ecto.Changeset.change() - |> Ecto.Changeset.put_embed(:meta, new_meta) + |> Ecto.Changeset.put_embed(:meta, meta_params) |> Repo.update() end - def update_meta(content, _), do: {:ok, content} - # make sure the reuest tag is in the current community thread # example: you can't set a other thread tag to this thread's article diff --git a/lib/groupher_server/cms/delegates/comment_curd.ex b/lib/groupher_server/cms/delegates/comment_curd.ex index c27207bb4..e8b3f0afe 100644 --- a/lib/groupher_server/cms/delegates/comment_curd.ex +++ b/lib/groupher_server/cms/delegates/comment_curd.ex @@ -12,11 +12,7 @@ defmodule GroupherServer.CMS.Delegate.CommentCURD do alias Helper.{ORM, QueryBuilder} alias GroupherServer.{Accounts, Delivery, Repo} - alias GroupherServer.CMS.{ - PostCommentReply, - JobCommentReply, - RepoCommentReply - } + alias GroupherServer.CMS.PostCommentReply alias Ecto.Multi @@ -202,27 +198,6 @@ defmodule GroupherServer.CMS.Delegate.CommentCURD do end end - defp bridge_reply(:job, queryable, comment, attrs) do - with {:ok, reply} <- ORM.create(queryable, attrs) do - ORM.update(reply, %{reply_id: comment.id}) - - {:ok, _} = JobCommentReply |> ORM.create(%{job_comment_id: comment.id, reply_id: reply.id}) - - queryable |> ORM.find(reply.id) - end - end - - defp bridge_reply(:repo, queryable, comment, attrs) do - with {:ok, reply} <- ORM.create(queryable, attrs) do - ORM.update(reply, %{reply_id: comment.id}) - - {:ok, _} = - RepoCommentReply |> ORM.create(%{repo_comment_id: comment.id, reply_id: reply.id}) - - queryable |> ORM.find(reply.id) - end - end - # for create comment defp get_next_floor(thread, queryable, id) when is_integer(id) do dynamic = dynamic_comment_where(thread, id) diff --git a/lib/groupher_server/cms/delegates/comment_reaction.ex b/lib/groupher_server/cms/delegates/comment_reaction.ex index 5b6f879d4..901f4387e 100644 --- a/lib/groupher_server/cms/delegates/comment_reaction.ex +++ b/lib/groupher_server/cms/delegates/comment_reaction.ex @@ -12,14 +12,6 @@ defmodule GroupherServer.CMS.Delegate.CommentReaction do undo_feel_comment(thread, comment_id, user_id, :like) end - def dislike_comment(thread, comment_id, %Accounts.User{id: user_id}) do - feel_comment(thread, comment_id, user_id, :dislike) - end - - def undo_dislike_comment(thread, comment_id, %Accounts.User{id: user_id}) do - undo_feel_comment(thread, comment_id, user_id, :dislike) - end - defp merge_thread_comment_id(:post_comment, comment_id), do: %{post_comment_id: comment_id} defp merge_thread_comment_id(:job_comment, comment_id), do: %{job_comment_id: comment_id} defp merge_thread_comment_id(:repo_comment, comment_id), do: %{repo_comment_id: comment_id} diff --git a/lib/groupher_server/cms/delegates/search.ex b/lib/groupher_server/cms/delegates/search.ex index 366620941..6e1ed5c5f 100644 --- a/lib/groupher_server/cms/delegates/search.ex +++ b/lib/groupher_server/cms/delegates/search.ex @@ -7,7 +7,7 @@ defmodule GroupherServer.CMS.Delegate.Search do import Ecto.Query, warn: false alias Helper.ORM - alias GroupherServer.CMS.{Community, Post, Job, Video, Repo} + alias GroupherServer.CMS.{Community, Post, Job, Repo} @search_items_count 15 diff --git a/lib/groupher_server/cms/embeds/abuse_report_case.ex b/lib/groupher_server/cms/embeds/abuse_report_case.ex new file mode 100644 index 000000000..124e7900e --- /dev/null +++ b/lib/groupher_server/cms/embeds/abuse_report_case.ex @@ -0,0 +1,24 @@ +defmodule GroupherServer.CMS.Embeds.AbuseReportCase do + @moduledoc """ + abuse report user + """ + use Ecto.Schema + import Ecto.Changeset + + alias GroupherServer.CMS + alias CMS.Embeds + + embedded_schema do + field(:reason, :string) + field(:additional_reason, :string) + embeds_one(:user, Embeds.User, on_replace: :delete) + + timestamps(type: :utc_datetime) + end + + def changeset(struct, params) do + struct + |> cast(params, [:reason, :additional_reason]) + |> cast_embed(:user, required: true, with: &Embeds.User.changeset/2) + end +end diff --git a/lib/groupher_server/cms/embeds/article_comment_emotion.ex b/lib/groupher_server/cms/embeds/article_comment_emotion.ex new file mode 100644 index 000000000..cda959949 --- /dev/null +++ b/lib/groupher_server/cms/embeds/article_comment_emotion.ex @@ -0,0 +1,73 @@ +defmodule GroupherServer.CMS.Embeds.ArticleCommentEmotion.Macros do + @moduledoc """ + general fields for each emotion + + e.g: + field(:beer_count, :integer, default: 0) + field(:beer_user_logins, :string) + field(:viewer_has_beered, :boolean, default: false, virtual: true) + embeds_many(:latest_beer_users, Embeds.User, on_replace: :delete) + """ + alias GroupherServer.CMS + alias CMS.{ArticleComment, Embeds} + + @supported_emotions ArticleComment.supported_emotions() + + defmacro emotion_fields() do + @supported_emotions + |> Enum.map(fn emotion -> + quote do + field(unquote(:"#{emotion}_count"), :integer, default: 0) + field(unquote(:"#{emotion}_user_logins"), :string, default: "") + field(unquote(:"viewer_has_#{emotion}ed"), :boolean, default: false, virtual: true) + embeds_many(unquote(:"latest_#{emotion}_users"), Embeds.User, on_replace: :delete) + end + end) + end +end + +defmodule GroupherServer.CMS.Embeds.ArticleCommentEmotion do + @moduledoc """ + general article meta info for article-like content, like post, job, works ... + """ + use Ecto.Schema + use Accessible + + import Ecto.Changeset + import GroupherServer.CMS.Embeds.ArticleCommentEmotion.Macros + + alias GroupherServer.CMS.ArticleComment + + @supported_emotions ArticleComment.supported_emotions() + + @optional_fields Enum.map(@supported_emotions, &:"#{&1}_count") ++ + Enum.map(@supported_emotions, &:"#{&1}_user_logins") + + @doc "default emotion status for article comment" + # for create comment and test usage + def default_emotions() do + @supported_emotions + |> Enum.reduce([], fn emotion, acc -> + acc ++ + [ + "#{emotion}_count": 0, + "latest_#{emotion}_users": [], + "#{emotion}_user_logins": "", + "viewer_has_#{emotion}ed": false + ] + end) + |> Enum.into(%{}) + end + + embedded_schema do + emotion_fields() + end + + def changeset(struct, params) do + struct + |> cast(params, @optional_fields) + + # |> cast_embed(:latest_downvote_users, required: false, with: &Embeds.User.changeset/2) + # |> ... + end +end diff --git a/lib/groupher_server/cms/embeds/article_comment_meta.ex b/lib/groupher_server/cms/embeds/article_comment_meta.ex new file mode 100644 index 000000000..3dfb5826d --- /dev/null +++ b/lib/groupher_server/cms/embeds/article_comment_meta.ex @@ -0,0 +1,26 @@ +defmodule GroupherServer.CMS.Embeds.ArticleCommentMeta do + @moduledoc """ + general article comment meta info + """ + use Ecto.Schema + + alias CMS.Embeds + + @default_meta %{ + is_article_author_upvoted: false, + is_solution: false, + report_count: 0, + report_users: [] + } + + @doc "for test usage" + def default_meta(), do: @default_meta + + embedded_schema do + field(:is_article_author_upvoted, :boolean, default: false) + field(:is_solution, :boolean, default: false) + + field(:report_count, :integer, default: 0) + embeds_many(:report_users, Embeds.User, on_replace: :delete) + end +end diff --git a/lib/groupher_server/cms/article_meta.ex b/lib/groupher_server/cms/embeds/article_meta.ex similarity index 92% rename from lib/groupher_server/cms/article_meta.ex rename to lib/groupher_server/cms/embeds/article_meta.ex index 33e9505ef..4cf401ad2 100644 --- a/lib/groupher_server/cms/article_meta.ex +++ b/lib/groupher_server/cms/embeds/article_meta.ex @@ -1,4 +1,4 @@ -defmodule GroupherServer.CMS.ArticleMeta do +defmodule GroupherServer.CMS.Embeds.ArticleMeta do @moduledoc """ general article meta info for article-like content, like post, job, works ... """ diff --git a/lib/groupher_server/cms/embeds/user.ex b/lib/groupher_server/cms/embeds/user.ex new file mode 100644 index 000000000..8d08f92b6 --- /dev/null +++ b/lib/groupher_server/cms/embeds/user.ex @@ -0,0 +1,19 @@ +defmodule GroupherServer.CMS.Embeds.User do + @moduledoc """ + only used for embeds_many situation + """ + + use Ecto.Schema + import Ecto.Changeset + + embedded_schema do + field(:login, :string) + field(:nickname, :string) + end + + def changeset(struct, params) do + struct + |> cast(params, [:login, :nickname]) + |> validate_required([:login, :nickname]) + end +end diff --git a/lib/groupher_server/cms/job.ex b/lib/groupher_server/cms/job.ex index 4100e1525..75e387e03 100644 --- a/lib/groupher_server/cms/job.ex +++ b/lib/groupher_server/cms/job.ex @@ -9,8 +9,8 @@ defmodule GroupherServer.CMS.Job do alias CMS.{ Author, + ArticleComment, Community, - JobComment, JobFavorite, JobStar, JobViewer, @@ -53,7 +53,8 @@ defmodule GroupherServer.CMS.Job do field(:pin, :boolean, default_value: false, virtual: true) field(:trash, :boolean, default_value: false, virtual: true) - has_many(:comments, {"jobs_comments", JobComment}) + has_many(:article_comments, {"articles_comments", ArticleComment}) + has_many(:favorites, {"jobs_favorites", JobFavorite}) has_many(:stars, {"jobs_stars", JobStar}) has_many(:viewers, {"jobs_viewers", JobViewer}) diff --git a/lib/groupher_server/cms/job_comment.ex b/lib/groupher_server/cms/job_comment.ex deleted file mode 100644 index b2b4970d7..000000000 --- a/lib/groupher_server/cms/job_comment.ex +++ /dev/null @@ -1,53 +0,0 @@ -defmodule GroupherServer.CMS.JobComment do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - - alias CMS.{Job, JobCommentReply, JobCommentLike, JobCommentDislike} - alias Helper.HTML - - @required_fields ~w(body author_id job_id floor)a - @optional_fields ~w(reply_id)a - - @type t :: %JobComment{} - schema "jobs_comments" do - field(:body, :string) - field(:floor, :integer) - belongs_to(:author, Accounts.User, foreign_key: :author_id) - belongs_to(:job, Job, foreign_key: :job_id) - belongs_to(:reply_to, JobComment, foreign_key: :reply_id) - - has_many(:replies, {"jobs_comments_replies", JobCommentReply}) - has_many(:likes, {"jobs_comments_likes", JobCommentLike}) - has_many(:dislikes, {"jobs_comments_dislikes", JobCommentDislike}) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%JobComment{} = job_comment, attrs) do - job_comment - |> cast(attrs, @required_fields ++ @optional_fields) - |> validate_required(@required_fields) - |> generl_changeset - end - - @doc false - def update_changeset(%JobComment{} = job_comment, attrs) do - job_comment - |> cast(attrs, @required_fields ++ @optional_fields) - |> generl_changeset - end - - defp generl_changeset(content) do - content - |> foreign_key_constraint(:job_id) - |> foreign_key_constraint(:author_id) - |> validate_length(:body, min: 3, max: 2000) - |> HTML.safe_string(:body) - end -end diff --git a/lib/groupher_server/cms/job_comment_dislike.ex b/lib/groupher_server/cms/job_comment_dislike.ex deleted file mode 100644 index 3df68ea53..000000000 --- a/lib/groupher_server/cms/job_comment_dislike.ex +++ /dev/null @@ -1,30 +0,0 @@ -defmodule GroupherServer.CMS.JobCommentDislike do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - alias CMS.JobComment - - @required_fields ~w(job_comment_id user_id)a - - @type t :: %JobCommentDislike{} - schema "jobs_comments_dislikes" do - belongs_to(:user, Accounts.User, foreign_key: :user_id) - belongs_to(:job_comment, JobComment, foreign_key: :job_comment_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%JobCommentDislike{} = job_comment_dislike, attrs) do - job_comment_dislike - |> cast(attrs, @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:job_comment_id) - |> foreign_key_constraint(:user_id) - |> unique_constraint(:user_id, name: :jobs_comments_dislikes_user_id_job_comment_id_index) - end -end diff --git a/lib/groupher_server/cms/job_comment_like.ex b/lib/groupher_server/cms/job_comment_like.ex deleted file mode 100644 index 518d7cf48..000000000 --- a/lib/groupher_server/cms/job_comment_like.ex +++ /dev/null @@ -1,30 +0,0 @@ -defmodule GroupherServer.CMS.JobCommentLike do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - alias CMS.JobComment - - @required_fields ~w(job_comment_id user_id)a - - @type t :: %JobCommentLike{} - schema "jobs_comments_likes" do - belongs_to(:user, Accounts.User, foreign_key: :user_id) - belongs_to(:job_comment, JobComment, foreign_key: :job_comment_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%JobCommentLike{} = job_comment_like, attrs) do - job_comment_like - |> cast(attrs, @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:job_comment_id) - |> foreign_key_constraint(:user_id) - |> unique_constraint(:user_id, name: :jobs_comments_likes_user_id_job_comment_id_index) - end -end diff --git a/lib/groupher_server/cms/job_comment_reply.ex b/lib/groupher_server/cms/job_comment_reply.ex deleted file mode 100644 index 9edd1a4d1..000000000 --- a/lib/groupher_server/cms/job_comment_reply.ex +++ /dev/null @@ -1,29 +0,0 @@ -defmodule GroupherServer.CMS.JobCommentReply do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.CMS - alias CMS.JobComment - - @required_fields ~w(job_comment_id reply_id)a - - @type t :: %JobCommentReply{} - schema "jobs_comments_replies" do - belongs_to(:job_comment, JobComment, foreign_key: :job_comment_id) - belongs_to(:reply, JobComment, foreign_key: :reply_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%JobCommentReply{} = job_comment_reply, attrs) do - job_comment_reply - |> cast(attrs, @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:job_comment_id) - |> foreign_key_constraint(:reply_id) - end -end diff --git a/lib/groupher_server/cms/post.ex b/lib/groupher_server/cms/post.ex index edfbd3a28..4de03e031 100644 --- a/lib/groupher_server/cms/post.ex +++ b/lib/groupher_server/cms/post.ex @@ -5,11 +5,13 @@ defmodule GroupherServer.CMS.Post do use Ecto.Schema import Ecto.Changeset - alias GroupherServer.CMS + alias GroupherServer.{CMS, Accounts} alias CMS.{ - ArticleMeta, + Embeds, Author, + ArticleComment, + ArticleCommentParticipator, Community, PostComment, PostCommunityFlag, @@ -25,7 +27,6 @@ defmodule GroupherServer.CMS.Post do @timestamps_opts [type: :utc_datetime_usec] @required_fields ~w(title body digest length)a @optional_fields ~w(origial_community_id link_addr copy_right link_addr link_icon)a - @embed_fileds ~w(meta)a @type t :: %Post{} schema "cms_posts" do @@ -38,9 +39,9 @@ defmodule GroupherServer.CMS.Post do field(:length, :integer) field(:views, :integer, default: 0) - embeds_one(:meta, ArticleMeta, on_replace: :update) - - # field(:meta, :map) + embeds_one(:meta, Embeds.ArticleMeta, on_replace: :update) + # 评论参与者,只保留最近 5 个 + embeds_many(:comment_participators, Accounts.User, on_replace: :delete) has_many(:community_flags, {"posts_communities_flags", PostCommunityFlag}) @@ -54,6 +55,9 @@ defmodule GroupherServer.CMS.Post do # 相关文章 # has_may(:related_post, ...) has_many(:comments, {"posts_comments", PostComment}) + + has_many(:article_comments, {"articles_comments", ArticleComment}) + has_many(:favorites, {"posts_favorites", PostFavorite}) has_many(:stars, {"posts_stars", PostStar}) has_many(:viewers, {"posts_viewers", PostViewer}) diff --git a/lib/groupher_server/cms/post_comment.ex b/lib/groupher_server/cms/post_comment.ex index d7ebbf548..f136dffc8 100644 --- a/lib/groupher_server/cms/post_comment.ex +++ b/lib/groupher_server/cms/post_comment.ex @@ -9,7 +9,6 @@ defmodule GroupherServer.CMS.PostComment do alias CMS.{ Post, - PostCommentDislike, PostCommentLike, PostCommentReply } @@ -29,7 +28,6 @@ defmodule GroupherServer.CMS.PostComment do has_many(:replies, {"posts_comments_replies", PostCommentReply}) has_many(:likes, {"posts_comments_likes", PostCommentLike}) - has_many(:dislikes, {"posts_comments_dislikes", PostCommentDislike}) timestamps(type: :utc_datetime) end diff --git a/lib/groupher_server/cms/post_comment_dislike.ex b/lib/groupher_server/cms/post_comment_dislike.ex deleted file mode 100644 index 59a71fbde..000000000 --- a/lib/groupher_server/cms/post_comment_dislike.ex +++ /dev/null @@ -1,30 +0,0 @@ -defmodule GroupherServer.CMS.PostCommentDislike do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - alias CMS.PostComment - - @required_fields ~w(post_comment_id user_id)a - - @type t :: %PostCommentDislike{} - schema "posts_comments_dislikes" do - belongs_to(:user, Accounts.User, foreign_key: :user_id) - belongs_to(:post_comment, PostComment, foreign_key: :post_comment_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%PostCommentDislike{} = post_comment_dislike, attrs) do - post_comment_dislike - |> cast(attrs, @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:post_comment_id) - |> foreign_key_constraint(:user_id) - |> unique_constraint(:user_id, name: :posts_comments_dislikes_user_id_post_comment_id_index) - end -end diff --git a/lib/groupher_server/cms/repo.ex b/lib/groupher_server/cms/repo.ex index 2bcc25bb9..6300fe0d0 100644 --- a/lib/groupher_server/cms/repo.ex +++ b/lib/groupher_server/cms/repo.ex @@ -10,7 +10,6 @@ defmodule GroupherServer.CMS.Repo do alias CMS.{ Author, Community, - RepoComment, RepoContributor, RepoFavorite, RepoViewer, @@ -58,7 +57,6 @@ defmodule GroupherServer.CMS.Repo do field(:last_sync, :utc_datetime) - has_many(:comments, {"repos_comments", RepoComment}) has_many(:favorites, {"repos_favorites", RepoFavorite}) has_many(:viewers, {"repos_viewers", RepoViewer}) diff --git a/lib/groupher_server/cms/repo_comment.ex b/lib/groupher_server/cms/repo_comment.ex deleted file mode 100644 index 37d9f3568..000000000 --- a/lib/groupher_server/cms/repo_comment.ex +++ /dev/null @@ -1,59 +0,0 @@ -defmodule GroupherServer.CMS.RepoComment do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - - alias CMS.{ - Repo, - RepoCommentDislike, - RepoCommentLike, - RepoCommentReply - } - - alias Helper.HTML - - @required_fields ~w(body author_id repo_id floor)a - @optional_fields ~w(reply_id)a - - @type t :: %RepoComment{} - schema "repos_comments" do - field(:body, :string) - field(:floor, :integer) - belongs_to(:author, Accounts.User, foreign_key: :author_id) - belongs_to(:repo, Repo, foreign_key: :repo_id) - belongs_to(:reply_to, RepoComment, foreign_key: :reply_id) - - has_many(:replies, {"repos_comments_replies", RepoCommentReply}) - has_many(:likes, {"repos_comments_likes", RepoCommentLike}) - has_many(:dislikes, {"repos_comments_dislikes", RepoCommentDislike}) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%RepoComment{} = repo_comment, attrs) do - repo_comment - |> cast(attrs, @required_fields ++ @optional_fields) - |> validate_required(@required_fields) - |> generl_changeset - end - - @doc false - def update_changeset(%RepoComment{} = repo_comment, attrs) do - repo_comment - |> cast(attrs, @required_fields ++ @optional_fields) - |> generl_changeset - end - - defp generl_changeset(content) do - content - |> foreign_key_constraint(:repo_id) - |> foreign_key_constraint(:author_id) - |> validate_length(:body, min: 3, max: 2000) - |> HTML.safe_string(:body) - end -end diff --git a/lib/groupher_server/cms/repo_comment_dislike.ex b/lib/groupher_server/cms/repo_comment_dislike.ex deleted file mode 100644 index f1a9f383c..000000000 --- a/lib/groupher_server/cms/repo_comment_dislike.ex +++ /dev/null @@ -1,30 +0,0 @@ -defmodule GroupherServer.CMS.RepoCommentDislike do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - alias CMS.RepoComment - - @required_fields ~w(repo_comment_id user_id)a - - @type t :: %RepoCommentDislike{} - schema "repos_comments_dislikes" do - belongs_to(:user, Accounts.User, foreign_key: :user_id) - belongs_to(:repo_comment, RepoComment, foreign_key: :repo_comment_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%RepoCommentDislike{} = repo_comment_dislike, attrs) do - repo_comment_dislike - |> cast(attrs, @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:repo_comment_id) - |> foreign_key_constraint(:user_id) - |> unique_constraint(:user_id, name: :repos_comments_dislikes_user_id_repo_comment_id_index) - end -end diff --git a/lib/groupher_server/cms/repo_comment_like.ex b/lib/groupher_server/cms/repo_comment_like.ex deleted file mode 100644 index e23489dba..000000000 --- a/lib/groupher_server/cms/repo_comment_like.ex +++ /dev/null @@ -1,30 +0,0 @@ -defmodule GroupherServer.CMS.RepoCommentLike do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - alias CMS.RepoCommentLike - - @required_fields ~w(repo_comment_id user_id)a - - @type t :: %RepoCommentLike{} - schema "repos_comments_likes" do - belongs_to(:user, Accounts.User, foreign_key: :user_id) - belongs_to(:repo_comment, RepoCommentLike, foreign_key: :repo_comment_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%RepoCommentLike{} = repo_comment_like, attrs) do - repo_comment_like - |> cast(attrs, @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:repo_comment_id) - |> foreign_key_constraint(:user_id) - |> unique_constraint(:user_id, name: :repos_comments_likes_user_id_repo_comment_id_index) - end -end diff --git a/lib/groupher_server/cms/repo_comment_reply.ex b/lib/groupher_server/cms/repo_comment_reply.ex deleted file mode 100644 index 4d5ad40c4..000000000 --- a/lib/groupher_server/cms/repo_comment_reply.ex +++ /dev/null @@ -1,29 +0,0 @@ -defmodule GroupherServer.CMS.RepoCommentReply do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.CMS - alias CMS.RepoComment - - @required_fields ~w(repo_comment_id reply_id)a - - @type t :: %RepoCommentReply{} - schema "repos_comments_replies" do - belongs_to(:repo_comment, RepoComment, foreign_key: :repo_comment_id) - belongs_to(:reply, RepoComment, foreign_key: :reply_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%RepoCommentReply{} = repo_comment_reply, attrs) do - repo_comment_reply - |> cast(attrs, @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:repo_comment_id) - |> foreign_key_constraint(:reply_id) - end -end diff --git a/lib/groupher_server/cms/topic.ex b/lib/groupher_server/cms/topic.ex index 6fbdc5d06..8459af3bf 100644 --- a/lib/groupher_server/cms/topic.ex +++ b/lib/groupher_server/cms/topic.ex @@ -4,7 +4,6 @@ defmodule GroupherServer.CMS.Topic do use Ecto.Schema import Ecto.Changeset - # alias GroupherServer.CMS.{Author, Community, Job, Post, Video} @required_fields ~w(thread title raw)a diff --git a/lib/groupher_server/cms/utils/loader.ex b/lib/groupher_server/cms/utils/loader.ex index 0adb0488f..1335e2d4a 100644 --- a/lib/groupher_server/cms/utils/loader.ex +++ b/lib/groupher_server/cms/utils/loader.ex @@ -16,7 +16,6 @@ defmodule GroupherServer.CMS.Utils.Loader do Post, PostViewer, PostComment, - PostCommentDislike, PostCommentLike, PostCommentReply, PostFavorite, @@ -26,17 +25,9 @@ defmodule GroupherServer.CMS.Utils.Loader do JobViewer, JobFavorite, # JobStar, - JobComment, - JobCommentReply, - JobCommentDislike, - JobCommentLike, # Repo, RepoViewer, - RepoFavorite, - RepoComment, - RepoCommentReply, - RepoCommentLike, - RepoCommentDislike + RepoFavorite } alias Helper.QueryBuilder @@ -241,173 +232,6 @@ defmodule GroupherServer.CMS.Utils.Loader do |> QueryBuilder.members_pack(args) end - def query({"posts_comments_dislikes", PostCommentDislike}, %{count: _}) do - PostCommentDislike - |> group_by([f], f.post_comment_id) - |> select([f], count(f.id)) - end - - # component dislikes - def query({"posts_comments_dislikes", PostCommentDislike}, %{viewer_did: _, cur_user: cur_user}) do - PostCommentDislike |> where([f], f.user_id == ^cur_user.id) - end - - def query({"posts_comments_dislikes", PostCommentDislike}, %{filter: _filter} = args) do - PostCommentDislike - |> QueryBuilder.members_pack(args) - end - - # ---- job comments ------ - def query({"jobs_comments", JobComment}, %{filter: _filter, unique: true}) do - JobComment - # |> QueryBuilder.filter_pack(filter) - |> join(:inner, [c], a in assoc(c, :author)) - |> distinct([c, a], a.id) - |> select([c, a], a) - end - - def query({"jobs_comments", JobComment}, %{count: _, unique: true}) do - JobComment - |> join(:inner, [c], a in assoc(c, :author)) - |> distinct([c, a], a.id) - |> group_by([c, a], a.id) - |> group_by([c, a], c.job_id) - |> select([c, a], count(c.id)) - end - - def query({"jobs_comments", JobComment}, %{count: _}) do - JobComment - |> group_by([c], c.job_id) - |> select([c], count(c.id)) - end - - def query({"jobs_comments_replies", JobCommentReply}, %{count: _}) do - JobCommentReply - |> group_by([c], c.job_comment_id) - |> select([c], count(c.id)) - end - - def query({"jobs_comments_replies", JobCommentReply}, %{filter: filter}) do - JobCommentReply - |> QueryBuilder.load_inner_replies(filter) - end - - def query({"jobs_comments_replies", JobCommentReply}, %{reply_to: _}) do - JobCommentReply - |> join(:inner, [c], r in assoc(c, :job_comment)) - |> select([c, r], r) - end - - def query({"jobs_comments_likes", JobCommentLike}, %{count: _}) do - JobCommentLike - |> group_by([f], f.job_comment_id) - |> select([f], count(f.id)) - end - - def query({"jobs_comments_likes", JobCommentLike}, %{viewer_did: _, cur_user: cur_user}) do - JobCommentLike |> where([f], f.user_id == ^cur_user.id) - end - - def query({"jobs_comments_likes", JobCommentLike}, %{filter: _filter} = args) do - JobCommentLike |> QueryBuilder.members_pack(args) - end - - def query({"jobs_comments_dislikes", JobCommentDislike}, %{count: _}) do - JobCommentDislike - |> group_by([f], f.job_comment_id) - |> select([f], count(f.id)) - end - - def query({"jobs_comments_dislikes", JobCommentDislike}, %{ - viewer_did: _, - cur_user: cur_user - }) do - JobCommentDislike |> where([f], f.user_id == ^cur_user.id) - end - - def query({"jobs_comments_dislikes", JobCommentDislike}, %{filter: _filter} = args) do - JobCommentDislike |> QueryBuilder.members_pack(args) - end - - # ---- job comments end------ - - # --- repo comments ------ - def query({"repos_comments", RepoComment}, %{filter: _filter, unique: true}) do - RepoComment - # |> QueryBuilder.filter_pack(filter) - |> join(:inner, [c], a in assoc(c, :author)) - |> distinct([c, a], a.id) - |> select([c, a], a) - end - - def query({"repos_comments", RepoComment}, %{count: _, unique: true}) do - RepoComment - |> join(:inner, [c], a in assoc(c, :author)) - |> distinct([c, a], a.id) - |> group_by([c, a], a.id) - |> group_by([c, a], c.repo_id) - |> select([c, a], count(c.id)) - end - - def query({"repos_comments", RepoComment}, %{count: _}) do - RepoComment - |> group_by([c], c.repo_id) - |> select([c], count(c.id)) - end - - def query({"repos_comments_replies", RepoCommentReply}, %{count: _}) do - RepoCommentReply - |> group_by([c], c.repo_comment_id) - |> select([c], count(c.id)) - end - - def query({"repos_comments_replies", RepoCommentReply}, %{filter: filter}) do - RepoCommentReply - |> QueryBuilder.load_inner_replies(filter) - end - - def query({"repos_comments_replies", RepoCommentReply}, %{reply_to: _}) do - RepoCommentReply - |> join(:inner, [c], r in assoc(c, :repo_comment)) - |> select([c, r], r) - end - - def query({"repos_comments_likes", RepoCommentLike}, %{count: _}) do - RepoCommentLike - |> group_by([f], f.repo_comment_id) - |> select([f], count(f.id)) - end - - def query({"repos_comments_likes", RepoCommentLike}, %{viewer_did: _, cur_user: cur_user}) do - RepoCommentLike |> where([f], f.user_id == ^cur_user.id) - end - - def query({"repos_comments_likes", RepoCommentLike}, %{filter: _filter} = args) do - RepoCommentLike - |> QueryBuilder.members_pack(args) - end - - def query({"repos_comments_dislikes", RepoCommentDislike}, %{count: _}) do - RepoCommentDislike - |> group_by([f], f.repo_comment_id) - |> select([f], count(f.id)) - end - - # component dislikes - def query({"repos_comments_dislikes", RepoCommentDislike}, %{ - viewer_did: _, - cur_user: cur_user - }) do - RepoCommentDislike |> where([f], f.user_id == ^cur_user.id) - end - - def query({"repos_comments_dislikes", RepoCommentDislike}, %{filter: _filter} = args) do - RepoCommentDislike - |> QueryBuilder.members_pack(args) - end - - # --- repo ------ - # default loader def query(queryable, _args), do: queryable end diff --git a/lib/groupher_server/cms/utils/matcher.ex b/lib/groupher_server/cms/utils/matcher.ex index fcd588030..2560b6df6 100644 --- a/lib/groupher_server/cms/utils/matcher.ex +++ b/lib/groupher_server/cms/utils/matcher.ex @@ -22,15 +22,8 @@ defmodule GroupherServer.CMS.Utils.Matcher do JobStar, # comments PostComment, - JobComment, - RepoComment, # commtnes reaction PostCommentLike, - PostCommentDislike, - JobCommentLike, - JobCommentDislike, - RepoCommentLike, - RepoCommentDislike, # Tag, Community, @@ -66,9 +59,6 @@ defmodule GroupherServer.CMS.Utils.Matcher do def match_action(:post_comment, :like), do: {:ok, %{target: PostComment, reactor: PostCommentLike}} - def match_action(:post_comment, :dislike), - do: {:ok, %{target: PostComment, reactor: PostCommentDislike}} - ######################################### ## jobs ... ######################################### @@ -84,15 +74,6 @@ defmodule GroupherServer.CMS.Utils.Matcher do def match_action(:job, :star), do: {:ok, %{target: Job, reactor: JobStar, preload: :user}} def match_action(:job, :tag), do: {:ok, %{target: Job, reactor: Tag}} - def match_action(:job, :comment), - do: {:ok, %{target: Job, reactor: JobComment, preload: :author}} - - def match_action(:job_comment, :like), - do: {:ok, %{target: JobComment, reactor: JobCommentLike}} - - def match_action(:job_comment, :dislike), - do: {:ok, %{target: JobComment, reactor: JobCommentDislike}} - ######################################### ## repos ... ######################################### @@ -107,15 +88,6 @@ defmodule GroupherServer.CMS.Utils.Matcher do def match_action(:repo, :favorite), do: {:ok, %{target: Repo, reactor: RepoFavorite, preload: :user}} - def match_action(:repo, :comment), - do: {:ok, %{target: Repo, reactor: RepoComment, preload: :author}} - - def match_action(:repo_comment, :like), - do: {:ok, %{target: RepoComment, reactor: RepoCommentLike}} - - def match_action(:repo_comment, :dislike), - do: {:ok, %{target: RepoComment, reactor: RepoCommentDislike}} - # dynamic where query match def dynamic_where(thread, id) do case thread do diff --git a/lib/groupher_server/cms/utils/matcher2.ex b/lib/groupher_server/cms/utils/matcher2.ex new file mode 100644 index 000000000..865c88ce6 --- /dev/null +++ b/lib/groupher_server/cms/utils/matcher2.ex @@ -0,0 +1,26 @@ +defmodule GroupherServer.CMS.Utils.Matcher2 do + @moduledoc """ + this module defined the matches and handy guard ... + """ + + import Ecto.Query, warn: false + + alias GroupherServer.CMS + + alias CMS.{ArticleComment, Post, Job} + + def match(:article_comment) do + {:ok, %{model: ArticleComment, foreign_key: :article_comment_id}} + end + + def match(:post) do + {:ok, %{model: Post, foreign_key: :post_id}} + end + + def match(:job) do + {:ok, %{model: Job, foreign_key: :job_id}} + end + + def match(:post, :query, id), do: {:ok, dynamic([c], c.post_id == ^id)} + def match(:job, :query, id), do: {:ok, dynamic([c], c.job_id == ^id)} +end diff --git a/lib/groupher_server_web/resolvers/cms_resolver.ex b/lib/groupher_server_web/resolvers/cms_resolver.ex index 60862e9e3..53eb580c3 100644 --- a/lib/groupher_server_web/resolvers/cms_resolver.ex +++ b/lib/groupher_server_web/resolvers/cms_resolver.ex @@ -11,7 +11,6 @@ defmodule GroupherServerWeb.Resolvers.CMS do alias CMS.{Post, Repo, Job, Community, Category, Tag, Thread} alias Helper.ORM - alias Helper.Utils # ####################### # community .. @@ -342,6 +341,10 @@ defmodule GroupherServerWeb.Resolvers.CMS do # ####################### # comemnts .. # ####################### + def paged_article_comments(_root, ~m(id thread filter)a, _info) do + CMS.list_article_comments(thread, id, filter) + end + def paged_comments(_root, ~m(id thread filter)a, _info) do CMS.list_comments(thread, id, filter) end @@ -358,6 +361,10 @@ 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 @@ -378,14 +385,6 @@ defmodule GroupherServerWeb.Resolvers.CMS do CMS.undo_like_comment(thread, id, user) end - def dislike_comment(_root, ~m(thread id)a, %{context: %{cur_user: user}}) do - CMS.dislike_comment(thread, id, user) - end - - def undo_dislike_comment(_root, ~m(thread id)a, %{context: %{cur_user: user}}) do - CMS.undo_dislike_comment(thread, id, user) - end - def stamp_passport(_root, ~m(user_id rules)a, %{context: %{cur_user: _user}}) do CMS.stamp_passport(rules, %User{id: user_id}) end diff --git a/lib/groupher_server_web/schema/cms/cms_queries.ex b/lib/groupher_server_web/schema/cms/cms_queries.ex index 552f6c5e7..22d9f0c78 100644 --- a/lib/groupher_server_web/schema/cms/cms_queries.ex +++ b/lib/groupher_server_web/schema/cms/cms_queries.ex @@ -160,6 +160,16 @@ defmodule GroupherServerWeb.Schema.CMS.Queries do resolve(&R.CMS.get_tags/3) end + @desc "get paged article comments" + field :paged_article_comments, :paged_article_comments do + arg(:id, non_null(:id)) + arg(:thread, :cms_thread, default_value: :post) + arg(:filter, :comments_filter) + + middleware(M.PageSizeProof) + resolve(&R.CMS.paged_article_comments/3) + end + @desc "get paged comments" field :paged_comments, :paged_comments do arg(:id, non_null(:id)) diff --git a/lib/groupher_server_web/schema/cms/cms_types.ex b/lib/groupher_server_web/schema/cms/cms_types.ex index 56efaf7f7..101914e16 100644 --- a/lib/groupher_server_web/schema/cms/cms_types.ex +++ b/lib/groupher_server_web/schema/cms/cms_types.ex @@ -40,10 +40,7 @@ defmodule GroupherServerWeb.Schema.CMS.Types do # field(:topic) field(:meta, :article_meta) - - # field :meta, :article_meta do - # resolve(&R.CMS.get_meta/3) - # end + field(:comment_participators, list_of(:user)) field :comments, list_of(:comment) do arg(:filter, :members_filter) @@ -327,6 +324,26 @@ defmodule GroupherServerWeb.Schema.CMS.Types do timestamp_fields() end + object :article_comment do + field(:id, :id) + field(:body_html, :string) + field(:author, :user, resolve: dataloader(CMS, :author)) + + # field :upvote_users, list_of(:user) do + # arg(:filter, :members_filter) + + # middleware(M.PageSizeProof) + # resolve(dataloader(CMS, :likes)) + # end + + # field :upvotes_count, :integer do + # arg(:count, :count_type, default_value: :count) + + # resolve(dataloader(CMS, :likes)) + # middleware(M.ConvertToInt) + # end + end + object :comment do comments_fields() end @@ -372,6 +389,12 @@ defmodule GroupherServerWeb.Schema.CMS.Types do pagination_fields() end + object :paged_article_comments do + # field(:id, :string) + field(:entries, list_of(:article_comment)) + pagination_fields() + end + object :paged_post_comments do field(:entries, list_of(:post_comment)) pagination_fields() diff --git a/lib/groupher_server_web/schema/cms/mutations/comment.ex b/lib/groupher_server_web/schema/cms/mutations/comment.ex index 64d72588d..6e3cccd13 100644 --- a/lib/groupher_server_web/schema/cms/mutations/comment.ex +++ b/lib/groupher_server_web/schema/cms/mutations/comment.ex @@ -21,6 +21,21 @@ defmodule GroupherServerWeb.Schema.CMS.Mutations.Comment do 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) + arg(:id, non_null(:id)) + 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_article_comment/3) + middleware(M.Statistics.MakeContribute, for: :user) + end + @desc "update a comment" field :update_comment, :comment do arg(:id, non_null(:id)) @@ -79,21 +94,5 @@ defmodule GroupherServerWeb.Schema.CMS.Mutations.Comment do middleware(M.Authorize, :login) resolve(&R.CMS.undo_like_comment/3) end - - field :dislike_comment, :comment do - arg(:thread, non_null(:cms_comment), default_value: :post_comment) - arg(:id, non_null(:id)) - - middleware(M.Authorize, :login) - resolve(&R.CMS.dislike_comment/3) - end - - field :undo_dislike_comment, :comment do - arg(:thread, non_null(:cms_comment), default_value: :post_comment) - arg(:id, non_null(:id)) - - middleware(M.Authorize, :login) - resolve(&R.CMS.undo_dislike_comment/3) - end end end diff --git a/lib/groupher_server_web/schema/utils/helper.ex b/lib/groupher_server_web/schema/utils/helper.ex index fc8fe16ed..95b3583b6 100644 --- a/lib/groupher_server_web/schema/utils/helper.ex +++ b/lib/groupher_server_web/schema/utils/helper.ex @@ -215,30 +215,6 @@ defmodule GroupherServerWeb.Schema.Utils.Helper do middleware(M.ViewerDidConvert) end - field :dislikes, list_of(:user) do - arg(:filter, :members_filter) - - middleware(M.PageSizeProof) - resolve(dataloader(CMS, :dislikes)) - end - - field :viewer_has_disliked, :boolean do - arg(:viewer_did, :viewer_did_type, default_value: :viewer_did) - - middleware(M.Authorize, :login) - # put current user into dataloader's args - middleware(M.PutCurrentUser) - resolve(dataloader(CMS, :dislikes)) - middleware(M.ViewerDidConvert) - end - - field :dislikes_count, :integer do - arg(:count, :count_type, default_value: :count) - - resolve(dataloader(CMS, :dislikes)) - middleware(M.ConvertToInt) - end - field :replies, list_of(:comment) do arg(:filter, :members_filter) diff --git a/lib/helper/orm.ex b/lib/helper/orm.ex index aac006702..6d9129605 100644 --- a/lib/helper/orm.ex +++ b/lib/helper/orm.ex @@ -101,6 +101,20 @@ defmodule Helper.ORM do put_in(content.views, result) end + @doc "safe increase field(must be integer) by 1" + def inc_field(queryable, content, field) do + {1, [updated_count]} = + Repo.update_all( + from(c in queryable, + where: c.id == ^content.id, + select: field(c, ^field) + ), + inc: ["#{field}": 1] + ) + + put_in(content[field], updated_count) |> done + end + @doc """ NOTICE: this should be use together with Authorize/OwnerCheck etc Middleware DO NOT use it directly diff --git a/lib/helper/query_builder.ex b/lib/helper/query_builder.ex index 9c1f153fb..97c5a77b8 100644 --- a/lib/helper/query_builder.ex +++ b/lib/helper/query_builder.ex @@ -133,9 +133,6 @@ defmodule Helper.QueryBuilder do {:sort, :most_likes}, queryable -> queryable |> sort_by_count(:likes, :desc) - {:sort, :most_dislikes}, queryable -> - queryable |> sort_by_count(:dislikes, :desc) - {:length, :most_words}, queryable -> queryable |> order_by(desc: :length) diff --git a/mix.exs b/mix.exs index 1fcfd0076..e65bf6b84 100644 --- a/mix.exs +++ b/mix.exs @@ -106,7 +106,8 @@ defmodule GroupherServer.Mixfile do {:earmark, "~> 1.4.13"}, # 遵循中文排版指南 # https://github.com/cataska/pangu.ex - {:pangu, "~> 0.1.0"} + {:pangu, "~> 0.1.0"}, + {:accessible, "~> 0.3.0"} ] end diff --git a/mix.lock b/mix.lock index 8502ef674..b63e41eab 100644 --- a/mix.lock +++ b/mix.lock @@ -2,6 +2,7 @@ "absinthe": {:hex, :absinthe, "1.6.3", "f8c7a581fa2382bde1adadd405f5caf6597623b48d160367f759d0d6e6292f84", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4a11192165fb3b7566ffdd86eccd12f0a87158b0b18c00e0400899e8df0225ea"}, "absinthe_ecto": {:hex, :absinthe_ecto, "0.1.3", "420b68129e79fe4571a4838904ba03e282330d335da47729ad52ffd7b8c5fcb1", [:mix], [{:absinthe, "~> 1.3.0 or ~> 1.4.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:ecto, ">= 0.0.0", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm", "355b9db34abfab96ae1e025434b66e11002babcf4fe6b7144d26ff7548985f52"}, "absinthe_plug": {:hex, :absinthe_plug, "1.5.7", "c9954c5eff0a11be185f73987533d38d6aa44ca6bd5253de32de099f82996ce5", [:mix], [{:absinthe, "~> 1.5", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "2e7d766c5b3ec57aed06db0d420674bc0ff6998c55c85f5fb9bb0d3dcf7ad20d"}, + "accessible": {:hex, :accessible, "0.3.0", "932f6ade6ea839212fea1735ab4ffdc39a3843a622f2ea5d28f0ab41c14b4435", [:mix], [], "hexpm", "13a11b0611ab82f7b9098a88465b5674f729c02bd613216243c123c65f90f296"}, "apollo_tracing": {:hex, :apollo_tracing, "0.4.4", "de945527568e3377409377f5ed39b2f57a02adfa0ff19c33b232d201f45b83a1", [:mix], [{:absinthe, "~> 1.4", [hex: :absinthe, repo: "hexpm", optional: false]}, {:absinthe_plug, "~> 1.4", [hex: :absinthe_plug, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "9b6203b72ae582363fb5c9cabae6ed828276f2c54ee553fb11b9d5ab147db438"}, "argon2_elixir": {:hex, :argon2_elixir, "1.2.14", "0fc4bfbc1b7e459954987d3d2f3836befd72d63f3a355e3978f5005dd6e80816", [], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"}, "bamboo": {:hex, :bamboo, "1.3.0", "9ab7c054f1c3435464efcba939396c29c5e1b28f73c34e1f169e0881297a3141", [:mix], [{:hackney, ">= 1.13.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e1197188512d4a4458eaaad9a1659ce9eeb54a1b41574a9cd7507217b33e0f3e"}, diff --git a/priv/repo/migrations/20210407043645_creaet_article_comments.exs b/priv/repo/migrations/20210407043645_creaet_article_comments.exs new file mode 100644 index 000000000..45c535a6d --- /dev/null +++ b/priv/repo/migrations/20210407043645_creaet_article_comments.exs @@ -0,0 +1,28 @@ +defmodule GroupherServer.Repo.Migrations.CreaetArticleComments do + use Ecto.Migration + + def change do + create table(:articles_comments) do + add(:body_html, :text) + add(:author_id, references(:users, on_delete: :delete_all), null: false) + add(:post_id, references(:cms_posts, on_delete: :delete_all)) + add(:job_id, references(:cms_jobs, on_delete: :delete_all)) + + timestamps() + end + + create(index(:articles_comments, [:author_id])) + create(index(:articles_comments, [:post_id])) + create(index(:articles_comments, [:job_id])) + + # create table(:repos_comments_replies) do + # add(:repo_comment_id, references(:repos_comments, on_delete: :delete_all), null: false) + # add(:reply_id, references(:repos_comments, on_delete: :delete_all), null: false) + + # timestamps() + # end + + # create(index(:repos_comments_replies, [:repo_comment_id])) + # create(index(:repos_comments_replies, [:reply_id])) + end +end diff --git a/priv/repo/migrations/20210408020142_create_upvotes_for_article_comments.exs b/priv/repo/migrations/20210408020142_create_upvotes_for_article_comments.exs new file mode 100644 index 000000000..64e5a0f22 --- /dev/null +++ b/priv/repo/migrations/20210408020142_create_upvotes_for_article_comments.exs @@ -0,0 +1,15 @@ +defmodule GroupherServer.Repo.Migrations.CreateUpvotesForArticleComments do + use Ecto.Migration + + def change do + create table(:articles_comments_upvotes) do + add(:user_id, references(:users, on_delete: :delete_all), null: false) + + add(:article_comment_id, references(:articles_comments, on_delete: :delete_all), null: false) + + timestamps() + end + + create(unique_index(:articles_comments_upvotes, [:user_id, :article_comment_id])) + end +end diff --git a/priv/repo/migrations/20210409043049_create_article_comment_participator.exs b/priv/repo/migrations/20210409043049_create_article_comment_participator.exs new file mode 100644 index 000000000..7af1bc0e4 --- /dev/null +++ b/priv/repo/migrations/20210409043049_create_article_comment_participator.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.CreateArticleCommentParticipator do + use Ecto.Migration + + def change do + alter table(:cms_posts) do + add(:comment_participators, :map) + end + end +end diff --git a/priv/repo/migrations/20210412023051_create_article_comment_replies.exs b/priv/repo/migrations/20210412023051_create_article_comment_replies.exs new file mode 100644 index 000000000..28b91bedb --- /dev/null +++ b/priv/repo/migrations/20210412023051_create_article_comment_replies.exs @@ -0,0 +1,16 @@ +defmodule GroupherServer.Repo.Migrations.CreateArticleCommentReplies do + use Ecto.Migration + + def change do + create table(:articles_comments_replies) do + add(:article_comment_id, references(:articles_comments, on_delete: :delete_all), null: false) + + add(:reply_to_id, references(:articles_comments, on_delete: :delete_all), null: false) + + timestamps() + end + + create(index(:articles_comments_replies, [:article_comment_id])) + create(index(:articles_comments_replies, [:reply_to_id])) + end +end diff --git a/priv/repo/migrations/20210412032707_add_reply_to_id_to_article_comment.exs b/priv/repo/migrations/20210412032707_add_reply_to_id_to_article_comment.exs new file mode 100644 index 000000000..3c29e1080 --- /dev/null +++ b/priv/repo/migrations/20210412032707_add_reply_to_id_to_article_comment.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.AddReplyToIdToArticleComment do + use Ecto.Migration + + def change do + alter table(:articles_comments) do + add(:reply_to_id, references(:articles_comments, on_delete: :delete_all)) + end + end +end diff --git a/priv/repo/migrations/20210412070456_add_embeds_replies_to_artcile_comments.exs b/priv/repo/migrations/20210412070456_add_embeds_replies_to_artcile_comments.exs new file mode 100644 index 000000000..bbd12987f --- /dev/null +++ b/priv/repo/migrations/20210412070456_add_embeds_replies_to_artcile_comments.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.AddEmbedsRepliesToArtcileComments do + use Ecto.Migration + + def change do + alter table(:articles_comments) do + add(:replies, :map) + end + end +end diff --git a/priv/repo/migrations/20210413040429_add_replies_count_to_artcile_comments.exs b/priv/repo/migrations/20210413040429_add_replies_count_to_artcile_comments.exs new file mode 100644 index 000000000..78b5b804a --- /dev/null +++ b/priv/repo/migrations/20210413040429_add_replies_count_to_artcile_comments.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.AddRepliesCountToArtcileComments do + use Ecto.Migration + + def change do + alter table(:articles_comments) do + add(:replies_count, :integer, default: 0) + end + end +end diff --git a/priv/repo/migrations/20210413062841_add_emotions_artcile_comments.exs b/priv/repo/migrations/20210413062841_add_emotions_artcile_comments.exs new file mode 100644 index 000000000..72b869f89 --- /dev/null +++ b/priv/repo/migrations/20210413062841_add_emotions_artcile_comments.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.AddEmotionsArtcileComments do + use Ecto.Migration + + def change do + alter table(:articles_comments) do + add(:emotions, :map) + end + end +end diff --git a/priv/repo/migrations/20210413234215_create_comments_users_emotions.exs b/priv/repo/migrations/20210413234215_create_comments_users_emotions.exs new file mode 100644 index 000000000..5194dba97 --- /dev/null +++ b/priv/repo/migrations/20210413234215_create_comments_users_emotions.exs @@ -0,0 +1,26 @@ +defmodule GroupherServer.Repo.Migrations.CreateCommentsUsersEmotions do + use Ecto.Migration + + def change do + create table(:articles_comments_users_emotions) do + add(:article_comment_id, references(:articles_comments, on_delete: :delete_all), null: false) + + add(:user_id, references(:users, on_delete: :delete_all), null: false) + add(:recived_user_id, references(:users, on_delete: :delete_all), null: false) + + add(:downvote, :boolean, default: false) + add(:beer, :boolean, default: false) + add(:heart, :boolean, default: false) + add(:biceps, :boolean, default: false) + add(:orz, :boolean, default: false) + add(:confused, :boolean, default: false) + add(:pill, :boolean, default: false) + + timestamps() + end + + create(index(:articles_comments_users_emotions, [:article_comment_id])) + create(index(:articles_comments_users_emotions, [:user_id])) + create(index(:articles_comments_users_emotions, [:recived_user_id])) + end +end diff --git a/priv/repo/migrations/20210415010056_add_fold_to_article_comments.exs b/priv/repo/migrations/20210415010056_add_fold_to_article_comments.exs new file mode 100644 index 000000000..5d327fdf5 --- /dev/null +++ b/priv/repo/migrations/20210415010056_add_fold_to_article_comments.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.AddFoldToArticleComments do + use Ecto.Migration + + def change do + alter table(:articles_comments) do + add(:is_folded, :boolean, default: false) + end + end +end diff --git a/priv/repo/migrations/20210415022102_add_reported_to_article_comments.exs b/priv/repo/migrations/20210415022102_add_reported_to_article_comments.exs new file mode 100644 index 000000000..c8820ed09 --- /dev/null +++ b/priv/repo/migrations/20210415022102_add_reported_to_article_comments.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.AddReportedToArticleComments do + use Ecto.Migration + + def change do + alter table(:articles_comments) do + add(:is_reported, :boolean, default: false) + end + end +end diff --git a/priv/repo/migrations/20210415025445_add_floor_to_article_comments.exs b/priv/repo/migrations/20210415025445_add_floor_to_article_comments.exs new file mode 100644 index 000000000..97ec295bd --- /dev/null +++ b/priv/repo/migrations/20210415025445_add_floor_to_article_comments.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.AddFloorToArticleComments do + use Ecto.Migration + + def change do + alter table(:articles_comments) do + add(:floor, :integer, default: 0) + end + end +end diff --git a/priv/repo/migrations/20210415042324_add_delete_flag_to_article_comments.exs b/priv/repo/migrations/20210415042324_add_delete_flag_to_article_comments.exs new file mode 100644 index 000000000..b9a46e6a2 --- /dev/null +++ b/priv/repo/migrations/20210415042324_add_delete_flag_to_article_comments.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.AddDeleteFlagToArticleComments do + use Ecto.Migration + + def change do + alter table(:articles_comments) do + add(:is_deleted, :boolean, default: false) + end + end +end diff --git a/priv/repo/migrations/20210415053021_add_article_author_id_to_article_comments.exs b/priv/repo/migrations/20210415053021_add_article_author_id_to_article_comments.exs new file mode 100644 index 000000000..ea1d7086d --- /dev/null +++ b/priv/repo/migrations/20210415053021_add_article_author_id_to_article_comments.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.AddArticleAuthorIdToArticleComments do + use Ecto.Migration + + def change do + alter table(:articles_comments) do + add(:is_article_author, :boolean, default: false) + end + end +end diff --git a/priv/repo/migrations/20210415060232_add_upvote_count_to_article_comments.exs b/priv/repo/migrations/20210415060232_add_upvote_count_to_article_comments.exs new file mode 100644 index 000000000..f6633e1d3 --- /dev/null +++ b/priv/repo/migrations/20210415060232_add_upvote_count_to_article_comments.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.AddUpvoteCountToArticleComments do + use Ecto.Migration + + def change do + alter table(:articles_comments) do + add(:upvotes_count, :integer, default: 0) + end + end +end diff --git a/priv/repo/migrations/20210415062503_rm_old_job_comments.exs b/priv/repo/migrations/20210415062503_rm_old_job_comments.exs new file mode 100644 index 000000000..6fef51ff2 --- /dev/null +++ b/priv/repo/migrations/20210415062503_rm_old_job_comments.exs @@ -0,0 +1,10 @@ +defmodule GroupherServer.Repo.Migrations.RmOldJobComments do + use Ecto.Migration + + def change do + drop(table(:jobs_comments_replies)) + drop(table(:jobs_comments_likes)) + drop(table(:jobs_comments_dislikes)) + drop(table(:jobs_comments)) + end +end diff --git a/priv/repo/migrations/20210415063508_rm_old_repo_comments.exs b/priv/repo/migrations/20210415063508_rm_old_repo_comments.exs new file mode 100644 index 000000000..894dbf295 --- /dev/null +++ b/priv/repo/migrations/20210415063508_rm_old_repo_comments.exs @@ -0,0 +1,10 @@ +defmodule GroupherServer.Repo.Migrations.RmOldRepoComments do + use Ecto.Migration + + def change do + drop(table(:repos_comments_replies)) + drop(table(:repos_comments_likes)) + drop(table(:repos_comments_dislikes)) + drop(table(:repos_comments)) + end +end diff --git a/priv/repo/migrations/20210415084353_rm_old_post_comments_dislike.exs b/priv/repo/migrations/20210415084353_rm_old_post_comments_dislike.exs new file mode 100644 index 000000000..c47c96cd0 --- /dev/null +++ b/priv/repo/migrations/20210415084353_rm_old_post_comments_dislike.exs @@ -0,0 +1,7 @@ +defmodule GroupherServer.Repo.Migrations.RmOldPostCommentsDislike do + use Ecto.Migration + + def change do + drop(table(:posts_comments_dislikes)) + end +end diff --git a/priv/repo/migrations/20210415085842_add_meta_to_article_comment.exs b/priv/repo/migrations/20210415085842_add_meta_to_article_comment.exs new file mode 100644 index 000000000..0321923c5 --- /dev/null +++ b/priv/repo/migrations/20210415085842_add_meta_to_article_comment.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.AddMetaToArticleComment do + use Ecto.Migration + + def change do + alter table(:articles_comments) do + add(:meta, :map) + end + end +end diff --git a/priv/repo/migrations/20210415091518_add_general_reports.exs b/priv/repo/migrations/20210415091518_add_general_reports.exs new file mode 100644 index 000000000..f39727c27 --- /dev/null +++ b/priv/repo/migrations/20210415091518_add_general_reports.exs @@ -0,0 +1,43 @@ +defmodule GroupherServer.Repo.Migrations.AddGeneralReports do + use Ecto.Migration + + def change do + create table(:abuse_reports) do + # 举报人们 + add(:report_cases, :map) + # has many + # [ + # %{ + # user, + # reason, + # additional_reason, + # timestamp + # } + # ] + + # 举报用户人次 + add(:report_cases_count, :integer, default: 0) + + # 举报账户 + add(:account_id, references(:users, on_delete: :delete_all)) + add(:post_id, references(:cms_posts, on_delete: :delete_all)) + add(:job_id, references(:cms_jobs, on_delete: :delete_all)) + add(:article_comment_id, references(:articles_comments, on_delete: :delete_all)) + + # 处理人 + add(:operate_user_id, references(:users, on_delete: :delete_all)) + add(:deal_with, :string) + + # 一旦处理完就不在接受举报了 + add(:is_closed, :boolean, default: false) + + timestamps() + end + + create(index(:abuse_reports, [:account_id])) + create(index(:abuse_reports, [:post_id])) + create(index(:abuse_reports, [:job_id])) + create(index(:abuse_reports, [:article_comment_id])) + create(index(:abuse_reports, [:operate_user_id])) + end +end diff --git a/test/groupher_server/accounts/published_comments_test.exs b/test/groupher_server/accounts/published_comments_test.exs index 9a1bcab39..fcf55c368 100644 --- a/test/groupher_server/accounts/published_comments_test.exs +++ b/test/groupher_server/accounts/published_comments_test.exs @@ -51,82 +51,4 @@ defmodule GroupherServer.Test.Accounts.PublishedComments do assert results.entries |> Enum.any?(&(&1.id == random_comment_id)) end end - - describe "[Accounts Publised job comments]" do - test "fresh user get empty paged published jobs", ~m(user)a do - {:ok, results} = Accounts.published_comments(user, :job, %{page: 1, size: 20}) - - assert results |> is_valid_pagination?(:raw) - assert results.total_count == 0 - end - - test "user can get paged published jobs", ~m(user user2 community)a do - body = "this is a test comment" - {:ok, job} = db_insert(:job) - {:ok, job2} = db_insert(:job) - - pub_comments = - Enum.reduce(1..@publish_count, [], fn _, acc -> - body = "this is a test comment" - - {:ok, comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - acc ++ [comment] - end) - - {:ok, _comment} = - CMS.create_comment(:job, job2.id, %{community: community.raw, body: body}, user) - - {:ok, _comment} = - CMS.create_comment(:job, job2.id, %{community: community.raw, body: body}, user2) - - {:ok, results} = Accounts.published_comments(user, :job, %{page: 1, size: 20}) - - assert results |> is_valid_pagination?(:raw) - assert results.total_count == @publish_count + 1 - - random_comment_id = pub_comments |> Enum.random() |> Map.get(:id) - assert results.entries |> Enum.any?(&(&1.id == random_comment_id)) - end - end - - describe "[Accounts Publised repo comments]" do - test "fresh user get empty paged published repos", ~m(user)a do - {:ok, results} = Accounts.published_comments(user, :repo, %{page: 1, size: 20}) - - assert results |> is_valid_pagination?(:raw) - assert results.total_count == 0 - end - - test "user can get paged published repos", ~m(user user2 community)a do - body = "this is a test comment" - {:ok, repo} = db_insert(:repo) - {:ok, repo2} = db_insert(:repo) - - pub_comments = - Enum.reduce(1..@publish_count, [], fn _, acc -> - body = "this is a test comment" - - {:ok, comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - acc ++ [comment] - end) - - {:ok, _comment} = - CMS.create_comment(:repo, repo2.id, %{community: community.raw, body: body}, user) - - {:ok, _comment} = - CMS.create_comment(:repo, repo2.id, %{community: community.raw, body: body}, user2) - - {:ok, results} = Accounts.published_comments(user, :repo, %{page: 1, size: 20}) - - assert results |> is_valid_pagination?(:raw) - assert results.total_count == @publish_count + 1 - - random_comment_id = pub_comments |> Enum.random() |> Map.get(:id) - assert results.entries |> Enum.any?(&(&1.id == random_comment_id)) - end - end end diff --git a/test/groupher_server/cms/abuse_report_test.exs b/test/groupher_server/cms/abuse_report_test.exs new file mode 100644 index 000000000..1a5f64ce1 --- /dev/null +++ b/test/groupher_server/cms/abuse_report_test.exs @@ -0,0 +1,62 @@ +defmodule GroupherServer.Test.CMS.AbuseReport do + @moduledoc false + + use GroupherServer.TestTools + + alias Helper.ORM + alias GroupherServer.CMS + + alias CMS.AbuseReport + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, post} = db_insert(:post) + {:ok, job} = db_insert(:job) + + {:ok, ~m(user user2 post job)a} + end + + describe "[article comment report/unreport]" do + @tag :wip + test "report a comment should have a abuse report record", ~m(user post)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + {:ok, _comment} = CMS.report_article_comment(comment.id, user) + + {:ok, all_reports} = ORM.find_all(AbuseReport, %{page: 1, size: 10}) + report = List.first(all_reports.entries) + report_cases = report.report_cases + + assert all_reports.total_count == 1 + assert report.report_cases_count == 1 + assert List.first(report_cases).user.login == user.login + end + + @tag :wip + test "different user report a comment should have same report with different report cases", + ~m(user user2 post)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + {:ok, _} = CMS.report_article_comment(comment.id, user) + {:ok, _} = CMS.report_article_comment(comment.id, user2) + + {:ok, all_reports} = ORM.find_all(AbuseReport, %{page: 1, size: 10}) + + report = List.first(all_reports.entries) + report_cases = report.report_cases + + assert all_reports.total_count == 1 + assert length(report_cases) == 2 + assert report.report_cases_count == 2 + + assert List.first(report_cases).user.login == user.login + assert List.last(report_cases).user.login == user2.login + end + + @tag :wip + test "same user can not report a comment twice", ~m(user post)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + {:ok, comment} = CMS.report_article_comment(comment.id, user) + assert {:error, _} = CMS.report_article_comment(comment.id, user) + end + end +end diff --git a/test/groupher_server/cms/article_comment_emotions_test.exs b/test/groupher_server/cms/article_comment_emotions_test.exs new file mode 100644 index 000000000..19355cec9 --- /dev/null +++ b/test/groupher_server/cms/article_comment_emotions_test.exs @@ -0,0 +1,152 @@ +defmodule GroupherServer.Test.CMS.ArticleCommentEmotions do + @moduledoc false + + use GroupherServer.TestTools + + alias Helper.ORM + alias GroupherServer.CMS + + alias CMS.{ArticleComment, Embeds} + + @default_emotions Embeds.ArticleCommentEmotion.default_emotions() + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, user3} = db_insert(:user) + + {:ok, post} = db_insert(:post) + {:ok, job} = db_insert(:job) + + {:ok, ~m(user user2 user3 post job)a} + end + + describe "[emotion in paged article comment]" do + @tag :wip + test "login user should got viewer has emotioned status", ~m(post user)a do + total_count = 0 + page_number = 10 + page_size = 20 + + all_comment = + Enum.reduce(0..total_count, [], fn _, acc -> + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + acc ++ [comment] + end) + + first_comment = List.first(all_comment) + + {:ok, _} = CMS.make_emotion(first_comment.id, :downvote, user) + {:ok, _} = CMS.make_emotion(first_comment.id, :beer, user) + + {:ok, paged_comments} = + CMS.list_article_comments(:post, post.id, %{page: page_number, size: page_size}, user) + + target = Enum.find(paged_comments.entries, &(&1.id == first_comment.id)) + + # IO.inspect(target, label: "the target") + + assert target.emotions.downvote_count == 1 + assert user_exist_in?(user, target.emotions.latest_downvote_users) + assert target.emotions.viewer_has_downvoteed + + assert target.emotions.beer_count == 1 + assert user_exist_in?(user, target.emotions.latest_beer_users) + assert target.emotions.viewer_has_beered + end + end + + describe "[basic article comment emotion]" do + @tag :wip + test "comment has default emotions after created", ~m(post user)a do + parent_content = "parent comment" + + {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, parent_content, user) + {:ok, parent_comment} = ORM.find(ArticleComment, parent_comment.id) + + emotions = parent_comment.emotions |> Map.from_struct() |> Map.delete(:id) + assert @default_emotions == emotions + end + + @tag :wip + 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) + + {:ok, _} = CMS.make_emotion(parent_comment.id, :downvote, user) + {:ok, _} = CMS.make_emotion(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) + end + + @tag :wip + 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) + + {:ok, _} = CMS.make_emotion(parent_comment.id, :downvote, user) + {:ok, _} = CMS.make_emotion(parent_comment.id, :downvote, user) + + {:ok, parent_comment} = ORM.find(ArticleComment, parent_comment.id) + + assert parent_comment.emotions.downvote_count == 1 + assert user_exist_in?(user, parent_comment.emotions.latest_downvote_users) + end + + @tag :wip + 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) + + {:ok, _} = CMS.make_emotion(parent_comment.id, :beer, user) + {:ok, _} = CMS.make_emotion(parent_comment.id, :beer, user2) + {:ok, _} = CMS.make_emotion(parent_comment.id, :beer, user3) + + {:ok, %{emotions: emotions}} = ORM.find(ArticleComment, parent_comment.id) + # IO.inspect(emotions, label: "the parent_comment") + + assert emotions.beer_count == 3 + assert user_exist_in?(user, emotions.latest_beer_users) + assert user_exist_in?(user2, emotions.latest_beer_users) + assert user_exist_in?(user3, emotions.latest_beer_users) + end + + @tag :wip + test "same user can make differcent emotions on same comment", ~m(post user)a do + parent_content = "parent comment" + {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, parent_content, user) + + {:ok, _} = CMS.make_emotion(parent_comment.id, :downvote, user) + {:ok, _} = CMS.make_emotion(parent_comment.id, :downvote, user) + {:ok, _} = CMS.make_emotion(parent_comment.id, :beer, user) + {:ok, _} = CMS.make_emotion(parent_comment.id, :heart, user) + {:ok, _} = CMS.make_emotion(parent_comment.id, :orz, user) + + {:ok, %{emotions: emotions}} = ORM.find(ArticleComment, parent_comment.id) + + assert emotions.downvote_count == 1 + assert user_exist_in?(user, emotions.latest_downvote_users) + + assert emotions.beer_count == 1 + assert user_exist_in?(user, emotions.latest_beer_users) + + assert emotions.heart_count == 1 + assert user_exist_in?(user, emotions.latest_heart_users) + + assert emotions.orz_count == 1 + assert user_exist_in?(user, emotions.latest_orz_users) + + assert emotions.pill_count == 0 + assert not user_exist_in?(user, emotions.latest_pill_users) + + assert emotions.biceps_count == 0 + assert not user_exist_in?(user, emotions.latest_biceps_users) + + assert emotions.confused_count == 0 + assert not user_exist_in?(user, emotions.latest_confused_users) + end + end +end diff --git a/test/groupher_server/cms/article_comment_replies_test.exs b/test/groupher_server/cms/article_comment_replies_test.exs new file mode 100644 index 000000000..50099ec10 --- /dev/null +++ b/test/groupher_server/cms/article_comment_replies_test.exs @@ -0,0 +1,163 @@ +defmodule GroupherServer.Test.CMS.ArticleCommentReplies do + @moduledoc false + + use GroupherServer.TestTools + + alias Helper.ORM + alias GroupherServer.CMS + + alias CMS.{ArticleComment, Post} + + @max_parent_replies_count CMS.ArticleComment.max_parent_replies_count() + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, post} = db_insert(:post) + {:ok, job} = db_insert(:job) + + {:ok, ~m(user user2 post job)a} + end + + describe "[basic article comment replies]" do + @tag :wip + test "exsit comment can 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, replyed_comment} = CMS.reply_article_comment(parent_comment.id, reply_content, user2) + assert replyed_comment.reply_to.id == parent_comment.id + + {:ok, parent_comment} = ORM.find(ArticleComment, parent_comment.id) + + assert exist_in?(replyed_comment, parent_comment.replies) + end + + @tag :wip + test "multi reply should belong to one parent comment", ~m(post user user2)a do + parent_content = "parent comment" + reply_content_1 = "reply comment 1" + reply_content_2 = "reply comment 2" + + {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, parent_content, user) + + {:ok, replyed_comment_1} = + CMS.reply_article_comment(parent_comment.id, reply_content_1, user2) + + {:ok, replyed_comment_2} = + CMS.reply_article_comment(parent_comment.id, reply_content_2, user2) + + {:ok, parent_comment} = ORM.find(ArticleComment, parent_comment.id) + + assert exist_in?(replyed_comment_1, parent_comment.replies) + assert exist_in?(replyed_comment_2, parent_comment.replies) + end + + @tag :wip + test "reply to reply inside a comment should belong same parent comment", + ~m(post user user2)a do + parent_content = "parent comment" + reply_content_1 = "reply comment 1" + reply_content_2 = "reply comment 2" + + {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, parent_content, user) + + {:ok, replyed_comment_1} = + CMS.reply_article_comment(parent_comment.id, reply_content_1, user2) + + {:ok, replyed_comment_2} = + CMS.reply_article_comment(replyed_comment_1.id, reply_content_2, user2) + + # IO.inspect(replyed_comment_2, label: "replyed_comment_2") + + {:ok, parent_comment} = ORM.find(ArticleComment, parent_comment.id) + + assert exist_in?(replyed_comment_1, parent_comment.replies) + assert exist_in?(replyed_comment_2, parent_comment.replies) + + {:ok, replyed_comment_1} = ORM.find(ArticleComment, replyed_comment_1.id) + {:ok, replyed_comment_2} = ORM.find(ArticleComment, replyed_comment_2.id) + + assert replyed_comment_1.reply_to_id == parent_comment.id + assert replyed_comment_2.reply_to_id == replyed_comment_1.id + end + + @tag :wip + test "comment replies only contains @max_parent_replies_count replies", ~m(post user)a do + total_reply_count = @max_parent_replies_count + 1 + + {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, "parent_conent", user) + + reply_comment_list = + Enum.reduce(1..total_reply_count, [], fn n, acc -> + {:ok, replyed_comment} = + CMS.reply_article_comment(parent_comment.id, "reply_content_#{n}", user) + + acc ++ [replyed_comment] + end) + + {:ok, parent_comment} = ORM.find(ArticleComment, parent_comment.id) + + assert length(parent_comment.replies) == @max_parent_replies_count + assert exist_in?(Enum.at(reply_comment_list, 0), parent_comment.replies) + assert exist_in?(Enum.at(reply_comment_list, 1), parent_comment.replies) + assert exist_in?(Enum.at(reply_comment_list, 2), parent_comment.replies) + assert not exist_in?(List.last(reply_comment_list), parent_comment.replies) + end + + @tag :wip + test "replyed user should appear in article comment participators", ~m(post user user2)a do + {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, "parent_conent", user) + {:ok, _} = CMS.reply_article_comment(parent_comment.id, "reply_content", user2) + + {:ok, article} = ORM.find(Post, post.id) + + assert exist_in?(user, article.comment_participators) + assert exist_in?(user2, article.comment_participators) + end + + @tag :wip + test "replies count should inc by 1 after got replyed", ~m(post user user2)a do + {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, "parent_conent", user) + assert parent_comment.replies_count === 0 + + {:ok, _} = CMS.reply_article_comment(parent_comment.id, "reply_content", user2) + {:ok, parent_comment} = ORM.find(ArticleComment, parent_comment.id) + assert parent_comment.replies_count === 1 + + {:ok, _} = CMS.reply_article_comment(parent_comment.id, "reply_content", user2) + {:ok, parent_comment} = ORM.find(ArticleComment, parent_comment.id) + assert parent_comment.replies_count === 2 + end + end + + describe "[paged article comment replies]" do + @tag :wip + test "can get paged replies of a parent comment", ~m(post user)a do + {:ok, parent_comment} = CMS.create_article_comment(:post, post.id, "parent_conent", user) + {:ok, paged_replies} = CMS.list_comment_replies(parent_comment.id, %{page: 1, size: 20}) + assert is_valid_pagination?(paged_replies, :raw, :empty) + + total_reply_count = 30 + + reply_comment_list = + Enum.reduce(1..total_reply_count, [], fn n, acc -> + {:ok, replyed_comment} = + CMS.reply_article_comment(parent_comment.id, "reply_content_#{n}", user) + + acc ++ [replyed_comment] + end) + + {:ok, paged_replies} = CMS.list_comment_replies(parent_comment.id, %{page: 1, size: 20}) + + assert total_reply_count == paged_replies.total_count + assert is_valid_pagination?(paged_replies, :raw) + + assert exist_in?(Enum.at(reply_comment_list, 0), paged_replies.entries) + assert exist_in?(Enum.at(reply_comment_list, 1), paged_replies.entries) + assert exist_in?(Enum.at(reply_comment_list, 2), paged_replies.entries) + assert exist_in?(Enum.at(reply_comment_list, 3), paged_replies.entries) + end + end +end diff --git a/test/groupher_server/cms/article_comment_test.exs b/test/groupher_server/cms/article_comment_test.exs new file mode 100644 index 000000000..969a0b9f3 --- /dev/null +++ b/test/groupher_server/cms/article_comment_test.exs @@ -0,0 +1,411 @@ +defmodule GroupherServer.Test.CMS.ArticleComment do + @moduledoc false + + use GroupherServer.TestTools + + alias Helper.ORM + alias GroupherServer.CMS + + alias CMS.{ArticleComment, Post, Job} + + @delete_hint CMS.ArticleComment.delete_hint() + @report_threshold_for_fold ArticleComment.report_threshold_for_fold() + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, post} = db_insert(:post) + {:ok, job} = db_insert(:job) + + {:ok, ~m(user user2 post job)a} + end + + describe "[basic article comment]" do + @tag :wip2 + test "post, job are supported by article comment.", ~m(user post job)a do + post_comment_1 = "post_comment 1" + post_comment_2 = "post_comment 2" + job_comment_1 = "job_comment 1" + job_comment_2 = "job_comment 2" + + {:ok, _} = CMS.create_article_comment(:post, post.id, post_comment_1, user) + {:ok, _} = CMS.create_article_comment(:post, post.id, post_comment_2, user) + + {:ok, _} = CMS.create_article_comment(:job, job.id, job_comment_1, user) + {:ok, _} = CMS.create_article_comment(:job, job.id, job_comment_2, user) + + {:ok, post} = ORM.find(Post, post.id, preload: :article_comments) + {:ok, job} = ORM.find(Job, job.id, preload: :article_comments) + + assert List.first(post.article_comments).body_html == post_comment_1 + assert List.first(job.article_comments).body_html == job_comment_1 + end + end + + describe "[article comment floor]" do + @tag :wip + test "comment will have a floor number after created", ~m(user post job)a do + {:ok, _comment} = CMS.create_article_comment(:job, job.id, "comment", user) + {:ok, job_comment} = CMS.create_article_comment(:job, job.id, "comment", user) + {:ok, post_comment} = CMS.create_article_comment(:post, post.id, "comment", user) + + {:ok, post_comment} = ORM.find(ArticleComment, post_comment.id) + {:ok, job_comment} = ORM.find(ArticleComment, job_comment.id) + + assert post_comment.floor == 1 + assert job_comment.floor == 2 + end + end + + describe "[article comment participator]" do + @tag :wip + test "post will have participator after comment created", ~m(user post)a do + post_comment_1 = "post_comment 1" + + {:ok, _} = CMS.create_article_comment(:post, post.id, post_comment_1, user) + + {:ok, post} = ORM.find(Post, post.id) + + participator = List.first(post.comment_participators) + assert participator.id == user.id + end + + @tag :wip + test "psot participator will not contains same user", ~m(user post)a do + post_comment_1 = "post_comment 1" + + {:ok, _} = CMS.create_article_comment(:post, post.id, post_comment_1, user) + {:ok, _} = CMS.create_article_comment(:post, post.id, post_comment_1, user) + + {:ok, post} = ORM.find(Post, post.id) + + assert 1 == length(post.comment_participators) + end + + @tag :wip + test "recent comment user should appear at first of the psot participators", + ~m(user user2 post)a do + post_comment_1 = "post_comment 1" + + {:ok, _} = CMS.create_article_comment(:post, post.id, post_comment_1, user) + {:ok, _} = CMS.create_article_comment(:post, post.id, post_comment_1, user2) + + {:ok, post} = ORM.find(Post, post.id) + + participator = List.first(post.comment_participators) + + assert participator.id == user2.id + end + end + + describe "[article comment upvotes]" do + @tag :wip + test "user can upvote a post comment", ~m(user post)a do + comment = "post_comment" + {:ok, comment} = CMS.create_article_comment(:post, post.id, comment, user) + + CMS.upvote_article_comment(comment.id, user) + + {:ok, comment} = ORM.find(ArticleComment, comment.id, preload: :upvotes) + + assert 1 == length(comment.upvotes) + assert List.first(comment.upvotes).user_id == user.id + end + + @tag :wip + test "user can upvote a job comment", ~m(user job)a do + comment = "job_comment" + {:ok, comment} = CMS.create_article_comment(:job, job.id, comment, user) + + CMS.upvote_article_comment(comment.id, user) + + {:ok, comment} = ORM.find(ArticleComment, comment.id, preload: :upvotes) + + assert 1 == length(comment.upvotes) + assert List.first(comment.upvotes).user_id == user.id + end + + @tag :wip + test "user upvote a already-upvoted comment fails", ~m(user post)a do + comment = "post_comment" + {:ok, comment} = CMS.create_article_comment(:post, post.id, comment, user) + + CMS.upvote_article_comment(comment.id, user) + {:error, _} = CMS.upvote_article_comment(comment.id, user) + end + + @tag :wip + test "upvote comment should inc the comment's upvotes_count", ~m(user user2 post)a do + comment = "post_comment" + {:ok, comment} = CMS.create_article_comment(:post, post.id, comment, user) + {:ok, comment} = ORM.find(ArticleComment, comment.id) + assert comment.upvotes_count == 0 + + {:ok, _} = CMS.upvote_article_comment(comment.id, user) + {:ok, _} = CMS.upvote_article_comment(comment.id, user2) + + {:ok, comment} = ORM.find(ArticleComment, comment.id) + assert comment.upvotes_count == 2 + end + end + + describe "[article comment fold/unfold]" do + @tag :wip + test "user can fold a comment", ~m(user post)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + {:ok, comment} = ORM.find(ArticleComment, comment.id) + + assert not comment.is_folded + + {:ok, comment} = CMS.fold_article_comment(comment.id, user) + {:ok, comment} = ORM.find(ArticleComment, comment.id) + assert comment.is_folded + end + + @tag :wip + test "user can unfold a comment", ~m(user post)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + {:ok, _comment} = CMS.fold_article_comment(comment.id, user) + {:ok, comment} = ORM.find(ArticleComment, comment.id) + + assert comment.is_folded + + {:ok, _comment} = CMS.unfold_article_comment(comment.id, user) + {:ok, comment} = ORM.find(ArticleComment, comment.id) + assert not comment.is_folded + end + end + + describe "[article comment report/unreport]" do + @tag :wip + test "user can report a comment", ~m(user post)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + {:ok, comment} = ORM.find(ArticleComment, comment.id) + + assert not comment.is_reported + + {:ok, comment} = CMS.report_article_comment(comment.id, user) + {:ok, comment} = ORM.find(ArticleComment, comment.id) + assert comment.is_reported + end + + @tag :wip + test "user can unreport a comment", ~m(user post)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + {:ok, _comment} = CMS.report_article_comment(comment.id, user) + {:ok, comment} = ORM.find(ArticleComment, comment.id) + + assert comment.is_reported + + {:ok, _comment} = CMS.unreport_article_comment(comment.id, user) + {:ok, comment} = ORM.find(ArticleComment, comment.id) + assert not comment.is_reported + end + + @tag :wip + test "report user < @report_threshold_for_fold will not fold comment", ~m(user post)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + + assert not comment.is_reported + assert not comment.is_folded + + Enum.reduce(1..(@report_threshold_for_fold - 1), [], fn _, _acc -> + {:ok, user} = db_insert(:user) + {:ok, _comment} = CMS.report_article_comment(comment.id, user) + end) + + {:ok, comment} = ORM.find(ArticleComment, comment.id) + assert comment.is_reported + assert not comment.is_folded + end + + @tag :wip + test "report user > @report_threshold_for_fold will cause comment fold", ~m(user post)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + + assert not comment.is_reported + assert not comment.is_folded + + Enum.reduce(1..(@report_threshold_for_fold + 1), [], fn _, _acc -> + {:ok, user} = db_insert(:user) + {:ok, _comment} = CMS.report_article_comment(comment.id, user) + end) + + {:ok, comment} = ORM.find(ArticleComment, comment.id) + assert comment.is_reported + assert comment.is_folded + end + end + + describe "paged article comments" do + @tag :wip + test "paged article comments folded flag should be false", ~m(user post)a do + total_count = 30 + page_number = 1 + page_size = 10 + + all_comments = + Enum.reduce(1..total_count, [], fn _, acc -> + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + + acc ++ [comment] + end) + + {:ok, paged_comments} = + CMS.list_article_comments(:post, post.id, %{page: page_number, size: page_size}) + + random_comment = all_comments |> Enum.at(Enum.random(0..total_count)) + + assert not random_comment.is_folded + + assert page_number == paged_comments.page_number + assert page_size == paged_comments.page_size + assert total_count == paged_comments.total_count + end + + @tag :wip + test "paged article comments should not contains folded and repoted comments", + ~m(user post)a do + total_count = 15 + page_number = 1 + page_size = 20 + + all_comments = + Enum.reduce(1..total_count, [], fn _, acc -> + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + + acc ++ [comment] + end) + + random_comment_1 = all_comments |> Enum.at(0) + random_comment_2 = all_comments |> Enum.at(1) + random_comment_3 = all_comments |> Enum.at(3) + + random_comment_4 = all_comments |> Enum.at(2) + random_comment_5 = all_comments |> Enum.at(4) + random_comment_6 = all_comments |> Enum.at(8) + + {:ok, _comment} = CMS.fold_article_comment(random_comment_1.id, user) + {:ok, _comment} = CMS.fold_article_comment(random_comment_2.id, user) + {:ok, _comment} = CMS.fold_article_comment(random_comment_3.id, user) + + {:ok, _comment} = CMS.report_article_comment(random_comment_4.id, user) + {:ok, _comment} = CMS.report_article_comment(random_comment_5.id, user) + {:ok, _comment} = CMS.report_article_comment(random_comment_6.id, user) + + {:ok, paged_comments} = + CMS.list_article_comments(:post, post.id, %{page: page_number, size: page_size}) + + assert not exist_in?(random_comment_1, paged_comments.entries) + assert not exist_in?(random_comment_2, paged_comments.entries) + assert not exist_in?(random_comment_3, paged_comments.entries) + + assert not exist_in?(random_comment_4, paged_comments.entries) + assert not exist_in?(random_comment_5, paged_comments.entries) + assert not exist_in?(random_comment_6, paged_comments.entries) + + assert page_number == paged_comments.page_number + assert page_size == paged_comments.page_size + assert total_count - 6 == paged_comments.total_count + end + + @tag :wip + test "can loaded paged folded comment", ~m(user post)a do + total_count = 10 + page_number = 1 + page_size = 20 + + all_folded_comments = + Enum.reduce(1..total_count, [], fn _, acc -> + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + CMS.fold_article_comment(comment.id, user) + + acc ++ [comment] + end) + + random_comment_1 = all_folded_comments |> Enum.at(1) + random_comment_2 = all_folded_comments |> Enum.at(3) + random_comment_3 = all_folded_comments |> Enum.at(5) + + {:ok, paged_comments} = + CMS.list_folded_article_comments(:post, post.id, %{page: page_number, size: page_size}) + + assert exist_in?(random_comment_1, paged_comments.entries) + assert exist_in?(random_comment_2, paged_comments.entries) + assert exist_in?(random_comment_3, paged_comments.entries) + + assert page_number == paged_comments.page_number + assert page_size == paged_comments.page_size + assert total_count == paged_comments.total_count + end + + @tag :wip + test "can loaded paged reported comment", ~m(user post)a do + total_count = 10 + page_number = 1 + page_size = 20 + + all_reported_comments = + Enum.reduce(1..total_count, [], fn _, acc -> + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + CMS.report_article_comment(comment.id, user) + + acc ++ [comment] + end) + + random_comment_1 = all_reported_comments |> Enum.at(1) + random_comment_2 = all_reported_comments |> Enum.at(3) + random_comment_3 = all_reported_comments |> Enum.at(5) + + {:ok, paged_comments} = + CMS.list_reported_article_comments(:post, post.id, %{page: page_number, size: page_size}) + + assert exist_in?(random_comment_1, paged_comments.entries) + assert exist_in?(random_comment_2, paged_comments.entries) + assert exist_in?(random_comment_3, paged_comments.entries) + + assert page_number == paged_comments.page_number + assert page_size == paged_comments.page_size + assert total_count == paged_comments.total_count + end + end + + describe "[article comment delete]" do + @tag :wip + test "delete comment still exsit in paged list and content is gone", ~m(user post)a do + total_count = 10 + page_number = 1 + page_size = 20 + + all_comments = + Enum.reduce(1..total_count, [], fn _, acc -> + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + + acc ++ [comment] + end) + + random_comment = all_comments |> Enum.at(1) + + {:ok, deleted_comment} = CMS.delete_article_comment(random_comment.id, user) + + {:ok, paged_comments} = + CMS.list_article_comments(:post, post.id, %{page: page_number, size: page_size}) + + assert exist_in?(deleted_comment, paged_comments.entries) + assert deleted_comment.is_deleted + assert deleted_comment.body_html == @delete_hint + end + end + + describe "[article comment info]" do + @tag :wip + test "author of the article comment a comment should have flag", ~m(user post)a do + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", user) + assert not comment.is_article_author + + {:ok, author_user} = db_insert(:user, %{id: post.author_id}) + {:ok, comment} = CMS.create_article_comment(:post, post.id, "commment", author_user) + assert comment.is_article_author + end + end +end diff --git a/test/groupher_server/cms/job_comment_test.exs b/test/groupher_server/cms/job_comment_test.exs deleted file mode 100644 index 6388dd7dd..000000000 --- a/test/groupher_server/cms/job_comment_test.exs +++ /dev/null @@ -1,245 +0,0 @@ -defmodule GroupherServer.Test.CMS.JobComment do - # currently only test comments for job type, rename and seprherate later - use GroupherServer.TestTools - - alias Helper.ORM - alias GroupherServer.CMS - - alias CMS.{JobComment, JobCommentReply} - - setup do - {:ok, job} = db_insert(:job) - {:ok, user} = db_insert(:user) - {:ok, community} = db_insert(:community) - - body = "this is a test comment" - - {:ok, comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - {:ok, ~m(job user community comment)a} - end - - describe "[comment CURD]" do - test "login user comment to exsiting job", ~m(job community user)a do - body = "this is a test comment" - - assert {:ok, comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - assert comment.job_id == job.id - assert comment.body == body - assert comment.author_id == user.id - end - - test "created comment should have a increased floor number", ~m(job community user)a do - body = "this is a test comment" - - assert {:ok, comment1} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - {:ok, user2} = db_insert(:user) - - assert {:ok, comment2} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user2) - - assert comment1.floor == 2 - assert comment2.floor == 3 - end - - test "create comment to non-exsit job fails", ~m(user community)a do - body = "this is a test comment" - - assert {:error, _} = - CMS.create_comment( - :job, - non_exsit_id(), - %{community: community.raw, body: body}, - user - ) - end - - test "can reply a comment, and reply should be in comment replies list", - ~m(community comment user)a do - reply_body = "this is a reply comment" - - {:ok, reply} = - CMS.reply_comment(:job, comment.id, %{community: community.raw, body: reply_body}, user) - - {:ok, reply_preload} = ORM.find(JobComment, reply.id, preload: :reply_to) - {:ok, comment_preload} = ORM.find(JobComment, comment.id, preload: :replies) - - assert reply_preload.reply_to.id == comment.id - assert reply_preload.author_id == user.id - assert reply_preload.body == reply_body - # reply id should be in comments replies list - assert comment_preload.replies |> Enum.any?(&(&1.reply_id == reply.id)) - end - - test "comment can be deleted", ~m(job community user)a do - body = "this is a test comment" - - assert {:ok, comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - {:ok, deleted} = CMS.delete_comment(:job, comment.id) - assert deleted.id == comment.id - end - - test "after delete, the coments of id > deleted.id should decrease the floor number", - ~m(job community user)a do - body = "this is a test comment" - # in setup we have a comment - total = 30 + 1 - - comments = - Enum.reduce(1..total, [], fn _, acc -> - {:ok, value} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - acc ++ [value] - end) - - [comment_1, comment_2, comment_3, comment_last] = comments |> firstn_and_last(3) - - assert comment_1.floor == 2 - assert comment_2.floor == 3 - assert comment_3.floor == 4 - assert comment_last.floor == total + 1 - - {:ok, _} = CMS.delete_comment(:job, comment_1.id) - - {:ok, new_comment_2} = ORM.find(JobComment, comment_2.id) - {:ok, new_comment_3} = ORM.find(JobComment, comment_3.id) - {:ok, new_comment_last} = ORM.find(JobComment, comment_last.id) - - assert new_comment_2.floor == 2 - assert new_comment_3.floor == 3 - assert new_comment_last.floor == total - end - - test "comment with replies should be deleted together", ~m(community comment user)a do - reply_body = "this is a reply comment" - - {:ok, reply} = - CMS.reply_comment(:job, comment.id, %{community: community.raw, body: reply_body}, user) - - JobComment |> ORM.find_delete(comment.id) - - {:error, _} = ORM.find(JobComment, comment.id) - {:error, _} = ORM.find(JobComment, reply.id) - - {:error, _} = JobCommentReply |> ORM.find_by(job_comment_id: comment.id, reply_id: reply.id) - end - - test "comments pagination should work", ~m(job community user)a do - body = "fake comment" - - Enum.reduce(1..30, [], fn _, acc -> - {:ok, value} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - acc ++ [value] - end) - - {:ok, results} = CMS.list_comments(:job, job.id, %{page: 1, size: 10}) - - assert results |> is_valid_pagination?(:raw) - end - - test "comment reply can be list one-by-one --> by replied user", ~m(community comment)a do - {:ok, user1} = db_insert(:user) - {:ok, user2} = db_insert(:user) - {:ok, user3} = db_insert(:user) - - {:ok, _} = - CMS.reply_comment( - :job, - comment.id, - %{community: community.raw, body: "reply by user1"}, - user1 - ) - - {:ok, _} = - CMS.reply_comment( - :job, - comment.id, - %{community: community.raw, body: "reply by user2"}, - user2 - ) - - {:ok, _} = - CMS.reply_comment( - :job, - comment.id, - %{community: community.raw, body: "reply by user3"}, - user3 - ) - - {:ok, found_reply1} = CMS.list_replies(:job, comment.id, user1) - assert user1.id == found_reply1 |> List.first() |> Map.get(:author_id) - - {:ok, found_reply2} = CMS.list_replies(:job, comment.id, user2) - assert user2.id == found_reply2 |> List.first() |> Map.get(:author_id) - - {:ok, found_reply3} = CMS.list_replies(:job, comment.id, user3) - assert user3.id == found_reply3 |> List.first() |> Map.get(:author_id) - end - end - - describe "[comment Reactions]" do - test "user can like a comment", ~m(comment user)a do - {:ok, liked_comment} = CMS.like_comment(:job_comment, comment.id, user) - - {:ok, comment_preload} = ORM.find(JobComment, liked_comment.id, preload: :likes) - - assert comment_preload.likes |> Enum.any?(&(&1.job_comment_id == comment.id)) - end - - test "user like comment twice fails", ~m(comment user)a do - {:ok, _} = CMS.like_comment(:job_comment, comment.id, user) - {:error, _error} = CMS.like_comment(:job_comment, comment.id, user) - # TODO: fix err_msg later - end - - test "user can undo a like action", ~m(comment user)a do - {:ok, like} = CMS.like_comment(:job_comment, comment.id, user) - {:ok, _} = CMS.undo_like_comment(:job_comment, comment.id, user) - - {:ok, comment_preload} = ORM.find(JobComment, comment.id, preload: :likes) - assert false == comment_preload.likes |> Enum.any?(&(&1.id == like.id)) - end - - test "user can dislike a comment", ~m(comment user)a do - {:ok, disliked_comment} = CMS.dislike_comment(:job_comment, comment.id, user) - - {:ok, comment_preload} = ORM.find(JobComment, disliked_comment.id, preload: :dislikes) - - assert comment_preload.dislikes |> Enum.any?(&(&1.job_comment_id == comment.id)) - end - - test "user can undo a dislike action", ~m(comment user)a do - {:ok, dislike} = CMS.dislike_comment(:job_comment, comment.id, user) - {:ok, _} = CMS.undo_dislike_comment(:job_comment, comment.id, user) - - {:ok, comment_preload} = ORM.find(JobComment, comment.id, preload: :dislikes) - assert false == comment_preload.dislikes |> Enum.any?(&(&1.id == dislike.id)) - end - - test "user can get paged likes of a job comment", ~m(comment)a do - {:ok, user1} = db_insert(:user) - {:ok, user2} = db_insert(:user) - {:ok, user3} = db_insert(:user) - - {:ok, _like1} = CMS.like_comment(:job_comment, comment.id, user1) - {:ok, _like2} = CMS.like_comment(:job_comment, comment.id, user2) - {:ok, _like3} = CMS.like_comment(:job_comment, comment.id, user3) - - {:ok, results} = CMS.reaction_users(:job_comment, :like, comment.id, %{page: 1, size: 10}) - - assert results.entries |> Enum.any?(&(&1.id == user1.id)) - assert results.entries |> Enum.any?(&(&1.id == user2.id)) - assert results.entries |> Enum.any?(&(&1.id == user3.id)) - end - end -end diff --git a/test/groupher_server/cms/post_comment_test.exs b/test/groupher_server/cms/post_comment_test.exs index 2714bf818..4cba5cfe9 100644 --- a/test/groupher_server/cms/post_comment_test.exs +++ b/test/groupher_server/cms/post_comment_test.exs @@ -211,23 +211,6 @@ defmodule GroupherServer.Test.PostComment do assert false == comment_preload.likes |> Enum.any?(&(&1.id == like.id)) end - test "user can dislike a comment", ~m(comment user)a do - # {:ok, like} = CMS.reaction(:post_comment, :like, comment.id, user.id) - {:ok, disliked_comment} = CMS.dislike_comment(:post_comment, comment.id, user) - - {:ok, comment_preload} = ORM.find(PostComment, disliked_comment.id, preload: :dislikes) - - assert comment_preload.dislikes |> Enum.any?(&(&1.post_comment_id == comment.id)) - end - - test "user can undo a dislike action", ~m(comment user)a do - {:ok, dislike} = CMS.dislike_comment(:post_comment, comment.id, user) - {:ok, _} = CMS.undo_dislike_comment(:post_comment, comment.id, user) - - {:ok, comment_preload} = ORM.find(PostComment, comment.id, preload: :dislikes) - assert false == comment_preload.dislikes |> Enum.any?(&(&1.id == dislike.id)) - end - test "user can get paged likes of a post comment", ~m(comment)a do {:ok, user1} = db_insert(:user) {:ok, user2} = db_insert(:user) diff --git a/test/groupher_server/cms/post_meta_test.exs b/test/groupher_server/cms/post_meta_test.exs index ea93f41fa..27d8a8c23 100644 --- a/test/groupher_server/cms/post_meta_test.exs +++ b/test/groupher_server/cms/post_meta_test.exs @@ -5,9 +5,9 @@ defmodule GroupherServer.Test.CMS.PostMeta do alias Helper.ORM alias GroupherServer.CMS - alias CMS.{ArticleMeta, Author, Post} + alias CMS.{Embeds, Author, Post} - @default_article_meta ArticleMeta.default_meta() + @default_article_meta Embeds.ArticleMeta.default_meta() setup do {:ok, user} = db_insert(:user) @@ -20,7 +20,7 @@ defmodule GroupherServer.Test.CMS.PostMeta do end describe "[cms post meta info]" do - @tag :wip2 + @tag :wip test "can get default meta info", ~m(user community post_attrs)a do assert {:error, _} = ORM.find_by(Author, user_id: user.id) @@ -31,7 +31,7 @@ defmodule GroupherServer.Test.CMS.PostMeta do assert @default_article_meta == meta end - @tag :wip2 + @tag :wip test "is_edited flag should set to true after post updated", ~m(user community post_attrs)a do {:ok, post} = CMS.create_content(community, :post, post_attrs, user) {:ok, post} = ORM.find_by(Post, id: post.id) diff --git a/test/groupher_server/cms/repo_comment_test.exs b/test/groupher_server/cms/repo_comment_test.exs deleted file mode 100644 index 04e985b80..000000000 --- a/test/groupher_server/cms/repo_comment_test.exs +++ /dev/null @@ -1,245 +0,0 @@ -defmodule GroupherServer.Test.CMS.RepoComment do - # currently only test comments for repo type, rename and seprherate later - use GroupherServer.TestTools - - alias Helper.ORM - alias GroupherServer.CMS - - alias CMS.{RepoComment, RepoCommentReply} - - setup do - {:ok, repo} = db_insert(:repo) - {:ok, user} = db_insert(:user) - {:ok, community} = db_insert(:community) - - body = "this is a test comment" - - {:ok, comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - {:ok, ~m(repo user comment community)a} - end - - describe "[comment CURD]" do - test "login user comment to exsiting repo", ~m(repo user community)a do - body = "this is a test comment" - - assert {:ok, comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - assert comment.repo_id == repo.id - assert comment.body == body - assert comment.author_id == user.id - end - - test "created comment should have a increased floor number", ~m(repo user community)a do - body = "this is a test comment" - - assert {:ok, comment1} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - {:ok, user2} = db_insert(:user) - - assert {:ok, comment2} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user2) - - assert comment1.floor == 2 - assert comment2.floor == 3 - end - - test "create comment to non-exsit repo fails", ~m(user community)a do - body = "this is a test comment" - - assert {:error, _} = - CMS.create_comment( - :repo, - non_exsit_id(), - %{community: community.raw, body: body}, - user - ) - end - - test "can reply a comment, and reply should be in comment replies list", - ~m(community comment user)a do - reply_body = "this is a reply comment" - - {:ok, reply} = - CMS.reply_comment(:repo, comment.id, %{community: community.raw, body: reply_body}, user) - - {:ok, reply_preload} = ORM.find(RepoComment, reply.id, preload: :reply_to) - {:ok, comment_preload} = ORM.find(RepoComment, comment.id, preload: :replies) - - assert reply_preload.reply_to.id == comment.id - assert reply_preload.author_id == user.id - assert reply_preload.body == reply_body - # reply id should be in comments replies list - assert comment_preload.replies |> Enum.any?(&(&1.reply_id == reply.id)) - end - - test "comment can be deleted", ~m(repo community user)a do - body = "this is a test comment" - - assert {:ok, comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - {:ok, deleted} = CMS.delete_comment(:repo, comment.id) - assert deleted.id == comment.id - end - - test "after delete, the coments of id > deleted.id should decrease the floor number", - ~m(repo community user)a do - body = "this is a test comment" - # in setup we have a comment - total = 30 + 1 - - comments = - Enum.reduce(1..total, [], fn _, acc -> - {:ok, value} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - acc ++ [value] - end) - - [comment_1, comment_2, comment_3, comment_last] = comments |> firstn_and_last(3) - - assert comment_1.floor == 2 - assert comment_2.floor == 3 - assert comment_3.floor == 4 - assert comment_last.floor == total + 1 - - {:ok, _} = CMS.delete_comment(:repo, comment_1.id) - - {:ok, new_comment_2} = ORM.find(RepoComment, comment_2.id) - {:ok, new_comment_3} = ORM.find(RepoComment, comment_3.id) - {:ok, new_comment_last} = ORM.find(RepoComment, comment_last.id) - - assert new_comment_2.floor == 2 - assert new_comment_3.floor == 3 - assert new_comment_last.floor == total - end - - test "comment with replies should be deleted together", ~m(community comment user)a do - reply_body = "this is a reply comment" - - {:ok, reply} = - CMS.reply_comment(:repo, comment.id, %{community: community.raw, body: reply_body}, user) - - RepoComment |> ORM.find_delete(comment.id) - - {:error, _} = ORM.find(RepoComment, comment.id) - {:error, _} = ORM.find(RepoComment, reply.id) - - {:error, _} = - RepoCommentReply |> ORM.find_by(repo_comment_id: comment.id, reply_id: reply.id) - end - - test "comments pagination should work", ~m(repo community user)a do - body = "fake comment" - - Enum.reduce(1..30, [], fn _, acc -> - {:ok, value} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - acc ++ [value] - end) - - {:ok, results} = CMS.list_comments(:repo, repo.id, %{page: 1, size: 10}) - - assert results |> is_valid_pagination?(:raw) - end - - test "comment reply can be list one-by-one --> by replied user", ~m(community comment)a do - {:ok, user1} = db_insert(:user) - {:ok, user2} = db_insert(:user) - {:ok, user3} = db_insert(:user) - - {:ok, _} = - CMS.reply_comment( - :repo, - comment.id, - %{community: community.raw, body: "reply by user1"}, - user1 - ) - - {:ok, _} = - CMS.reply_comment( - :repo, - comment.id, - %{community: community.raw, body: "reply by user2"}, - user2 - ) - - {:ok, _} = - CMS.reply_comment( - :repo, - comment.id, - %{community: community.raw, body: "reply by user3"}, - user3 - ) - - {:ok, found_reply1} = CMS.list_replies(:repo, comment.id, user1) - assert user1.id == found_reply1 |> List.first() |> Map.get(:author_id) - - {:ok, found_reply2} = CMS.list_replies(:repo, comment.id, user2) - assert user2.id == found_reply2 |> List.first() |> Map.get(:author_id) - - {:ok, found_reply3} = CMS.list_replies(:repo, comment.id, user3) - assert user3.id == found_reply3 |> List.first() |> Map.get(:author_id) - end - end - - describe "[comment Reactions]" do - test "user can like a comment", ~m(comment user)a do - {:ok, liked_comment} = CMS.like_comment(:repo_comment, comment.id, user) - - {:ok, comment_preload} = ORM.find(RepoComment, liked_comment.id, preload: :likes) - - assert comment_preload.likes |> Enum.any?(&(&1.repo_comment_id == comment.id)) - end - - test "user like comment twice fails", ~m(comment user)a do - {:ok, _} = CMS.like_comment(:repo_comment, comment.id, user) - {:error, _error} = CMS.like_comment(:repo_comment, comment.id, user) - end - - test "user can undo a like action", ~m(comment user)a do - {:ok, like} = CMS.like_comment(:repo_comment, comment.id, user) - {:ok, _} = CMS.undo_like_comment(:repo_comment, comment.id, user) - - {:ok, comment_preload} = ORM.find(RepoComment, comment.id, preload: :likes) - assert false == comment_preload.likes |> Enum.any?(&(&1.id == like.id)) - end - - test "user can dislike a comment", ~m(comment user)a do - {:ok, disliked_comment} = CMS.dislike_comment(:repo_comment, comment.id, user) - - {:ok, comment_preload} = ORM.find(RepoComment, disliked_comment.id, preload: :dislikes) - - assert comment_preload.dislikes |> Enum.any?(&(&1.repo_comment_id == comment.id)) - end - - test "user can undo a dislike action", ~m(comment user)a do - {:ok, dislike} = CMS.dislike_comment(:repo_comment, comment.id, user) - {:ok, _} = CMS.undo_dislike_comment(:repo_comment, comment.id, user) - - {:ok, comment_preload} = ORM.find(RepoComment, comment.id, preload: :dislikes) - assert false == comment_preload.dislikes |> Enum.any?(&(&1.id == dislike.id)) - end - - test "user can get paged likes of a repo comment", ~m(comment)a do - {:ok, user1} = db_insert(:user) - {:ok, user2} = db_insert(:user) - {:ok, user3} = db_insert(:user) - - {:ok, _like1} = CMS.like_comment(:repo_comment, comment.id, user1) - {:ok, _like2} = CMS.like_comment(:repo_comment, comment.id, user2) - {:ok, _like3} = CMS.like_comment(:repo_comment, comment.id, user3) - - {:ok, results} = CMS.reaction_users(:repo_comment, :like, comment.id, %{page: 1, size: 10}) - - assert results.entries |> Enum.any?(&(&1.id == user1.id)) - assert results.entries |> Enum.any?(&(&1.id == user2.id)) - assert results.entries |> Enum.any?(&(&1.id == user3.id)) - end - end -end diff --git a/test/groupher_server_web/mutation/cms/job_comment_test.exs b/test/groupher_server_web/mutation/cms/job_comment_test.exs deleted file mode 100644 index 3b6e7b51f..000000000 --- a/test/groupher_server_web/mutation/cms/job_comment_test.exs +++ /dev/null @@ -1,309 +0,0 @@ -defmodule GroupherServer.Test.Mutation.JobComment do - use GroupherServer.TestTools - - alias Helper.ORM - alias GroupherServer.{CMS, Delivery} - - setup do - {:ok, job} = db_insert(:job) - {:ok, user} = db_insert(:user) - {:ok, community} = db_insert(:community) - - guest_conn = simu_conn(:guest) - user_conn = simu_conn(:user, user) - - {:ok, comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: "test comment"}, user) - - {:ok, ~m(user_conn guest_conn job user community comment)a} - end - - describe "[job comment CURD]" do - @create_comment_query """ - mutation($community: String!, $thread: CmsThread, $id: ID!, $body: String!, $mentionUsers: [Ids]) { - createComment(community: $community, thread: $thread, id: $id, body: $body, mentionUsers: $mentionUsers) { - id - body - } - } - """ - test "login user can create comment to a job", ~m(user_conn community job)a do - variables = %{community: community.raw, thread: "JOB", id: job.id, body: "this a comment"} - created = user_conn |> mutation_result(@create_comment_query, variables, "createComment") - - {:ok, found} = ORM.find(CMS.JobComment, created["id"]) - - assert created["id"] == to_string(found.id) - end - - test "can mention other user when create comment to job", ~m(user_conn community job)a do - {:ok, user2} = db_insert(:user) - - comment_body = "this is a comment" - - variables = - %{community: community.raw, thread: "JOB", id: job.id, body: comment_body} - |> Map.merge(%{mentionUsers: [%{id: user2.id}]}) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Delivery.fetch_mentions(user2, filter) - assert mentions.total_count == 0 - - _created = user_conn |> mutation_result(@create_comment_query, variables, "createComment") - - {:ok, mentions} = Delivery.fetch_mentions(user2, filter) - assert mentions.total_count == 1 - the_mention = mentions.entries |> List.first() - - assert the_mention.source_title == job.title - assert the_mention.source_type == "comment" - assert the_mention.parent_id == to_string(job.id) - assert the_mention.parent_type == "job" - assert the_mention.source_preview == comment_body - end - - test "guest user create comment fails", ~m(guest_conn job community)a do - variables = %{community: community.raw, thread: "JOB", id: job.id, body: "this a comment"} - - assert guest_conn - |> mutation_get_error?(@create_comment_query, variables, ecode(:account_login)) - end - - @delete_comment_query """ - mutation($thread: CmsThread, $id: ID!) { - deleteComment(thread: $thread, id: $id) { - id - body - } - } - """ - - test "comment owner can delete comment", ~m(user community job)a do - variables = %{community: community.raw, thread: "JOB", id: job.id, body: "this a comment"} - - user_conn = simu_conn(:user, user) - created = user_conn |> mutation_result(@create_comment_query, variables, "createComment") - - deleted = - user_conn - |> mutation_result( - @delete_comment_query, - %{thread: "JOB", id: created["id"]}, - "deleteComment" - ) - - assert deleted["id"] == created["id"] - end - - test "unauth user delete comment fails", ~m(user_conn guest_conn community job)a do - variables = %{community: community.raw, thread: "JOB", id: job.id, body: "this a comment"} - {:ok, owner} = db_insert(:user) - owner_conn = simu_conn(:user, owner) - created = owner_conn |> mutation_result(@create_comment_query, variables, "createComment") - - variables = %{id: created["id"]} - rule_conn = simu_conn(:user, cms: %{"what.ever" => true}) - - 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)) - - assert rule_conn |> mutation_get_error?(@delete_comment_query, variables, ecode(:passport)) - end - - @reply_comment_query """ - mutation( - $community: String! - $thread: CmsThread - $id: ID! - $body: String! - $mentionUsers: [Ids] - ) { - replyComment( - community: $community - thread: $thread - id: $id - body: $body - mentionUsers: $mentionUsers - ) { - id - body - replyTo { - id - } - } - } - """ - test "login user can reply to a exsit comment", ~m(user_conn community comment)a do - variables = %{community: community.raw, thread: "JOB", id: comment.id, body: "this a reply"} - replied = user_conn |> mutation_result(@reply_comment_query, variables, "replyComment") - - assert replied["replyTo"] |> Map.get("id") == to_string(comment.id) - end - - test "guest user reply comment fails", ~m(guest_conn community comment)a do - variables = %{community: community.raw, thread: "JOB", id: comment.id, body: "this a reply"} - - assert guest_conn - |> mutation_get_error?(@reply_comment_query, variables, ecode(:account_login)) - end - - test "should mention author when reply to a comment", ~m(community job user)a do - body = "this is a comment" - - {:ok, comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - variables = %{ - community: community.raw, - thread: "JOB", - id: comment.id, - body: "this a reply" - } - - {:ok, user2} = db_insert(:user) - user_conn2 = simu_conn(:user, user2) - _replied = user_conn2 |> mutation_result(@reply_comment_query, variables, "replyComment") - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Delivery.fetch_mentions(user, filter) - assert mentions.total_count == 1 - the_mention = mentions.entries |> List.first() - - assert the_mention.from_user_id == user2.id - assert the_mention.to_user_id == user.id - assert the_mention.floor != nil - assert the_mention.source_title == comment.body - assert the_mention.source_type == "comment_reply" - assert the_mention.parent_id == to_string(job.id) - assert the_mention.parent_type == "job" - end - - test "can mention others in a reply", ~m(community job user user_conn)a do - body = "this is a comment" - {:ok, user2} = db_insert(:user) - - {:ok, comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - variables = %{ - community: community.raw, - thread: "JOB", - id: comment.id, - body: "this is a reply", - mentionUsers: [%{id: user2.id}] - } - - _replied = user_conn |> mutation_result(@reply_comment_query, variables, "replyComment") - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Delivery.fetch_mentions(user2, filter) - assert mentions.total_count == 1 - the_mention = mentions.entries |> List.first() - - assert the_mention.from_user_id == user.id - assert the_mention.to_user_id == user2.id - assert the_mention.floor != nil - assert the_mention.source_title == comment.body - assert the_mention.source_type == "comment_reply" - assert the_mention.source_preview == "this is a reply" - assert the_mention.parent_id == to_string(job.id) - assert the_mention.parent_type == "job" - end - - test "TODO owner can NOT delete comment when comment has replies" do - end - - test "TODO owner can NOT edit comment when comment has replies" do - end - - test "TODO owner can NOT delete comment when comment has created after 3 hours" do - end - end - - describe "[job comment reactions]" do - @like_comment_query """ - mutation($thread: CmsComment!, $id: ID!) { - likeComment(thread: $thread, id: $id) { - id - } - } - """ - test "login user can like a comment", ~m(user_conn comment)a do - variables = %{thread: "JOB_COMMENT", id: comment.id} - user_conn |> mutation_result(@like_comment_query, variables, "likeComment") - - {:ok, found} = CMS.JobComment |> ORM.find(comment.id, preload: :likes) - - assert found.likes |> Enum.any?(&(&1.job_comment_id == comment.id)) - end - - @undo_like_comment_query """ - mutation($thread: CmsComment!, $id: ID!) { - undoLikeComment(thread: $thread, id: $id) { - id - } - } - """ - test "login user can undo a like action to comment", ~m(user comment)a do - variables = %{thread: "JOB_COMMENT", id: comment.id} - user_conn = simu_conn(:user, user) - user_conn |> mutation_result(@like_comment_query, variables, "likeComment") - - {:ok, found} = CMS.JobComment |> ORM.find(comment.id, preload: :likes) - assert found.likes |> Enum.any?(&(&1.job_comment_id == comment.id)) - - user_conn |> mutation_result(@undo_like_comment_query, variables, "undoLikeComment") - - {:ok, found} = CMS.JobComment |> ORM.find(comment.id, preload: :likes) - assert false == found.likes |> Enum.any?(&(&1.job_comment_id == comment.id)) - end - - @dislike_comment_query """ - mutation($thread: CmsComment!, $id: ID!) { - dislikeComment(thread: $thread, id: $id) { - id - } - } - """ - test "login user can dislike a comment", ~m(user_conn comment)a do - variables = %{thread: "JOB_COMMENT", id: comment.id} - user_conn |> mutation_result(@dislike_comment_query, variables, "dislikeComment") - - {:ok, found} = CMS.JobComment |> ORM.find(comment.id, preload: :dislikes) - - assert found.dislikes |> Enum.any?(&(&1.job_comment_id == comment.id)) - end - - @undo_dislike_comment_query """ - mutation($thread: CmsComment!, $id: ID!) { - undoDislikeComment(thread: $thread, id: $id) { - id - } - } - """ - test "login user can undo dislike a comment", ~m(user comment)a do - variables = %{thread: "JOB_COMMENT", id: comment.id} - user_conn = simu_conn(:user, user) - user_conn |> mutation_result(@dislike_comment_query, variables, "dislikeComment") - {:ok, found} = CMS.JobComment |> ORM.find(comment.id, preload: :dislikes) - assert found.dislikes |> Enum.any?(&(&1.job_comment_id == comment.id)) - - user_conn |> mutation_result(@undo_dislike_comment_query, variables, "undoDislikeComment") - - {:ok, found} = CMS.JobComment |> ORM.find(comment.id, preload: :dislikes) - assert false == found.dislikes |> Enum.any?(&(&1.job_comment_id == comment.id)) - end - - test "unloged user do/undo like/dislike comment fails", ~m(guest_conn comment)a do - variables = %{thread: "JOB_COMMENT", id: comment.id} - - assert guest_conn |> mutation_get_error?(@like_comment_query, variables) - assert guest_conn |> mutation_get_error?(@dislike_comment_query, variables) - - assert guest_conn |> mutation_get_error?(@undo_like_comment_query, variables) - assert guest_conn |> mutation_get_error?(@undo_dislike_comment_query, variables) - end - end -end diff --git a/test/groupher_server_web/mutation/cms/post_comment_test.exs b/test/groupher_server_web/mutation/cms/post_comment_test.exs index 233c19c7f..e55372176 100644 --- a/test/groupher_server_web/mutation/cms/post_comment_test.exs +++ b/test/groupher_server_web/mutation/cms/post_comment_test.exs @@ -267,72 +267,5 @@ defmodule GroupherServer.Test.Mutation.PostComment do assert found.likes |> Enum.any?(&(&1.post_comment_id == comment.id)) end - - @undo_like_comment_query """ - mutation($thread: CmsComment!, $id: ID!) { - undoLikeComment(thread: $thread, id: $id) { - id - } - } - """ - test "login user can undo a like action to comment", ~m(user comment)a do - variables = %{thread: "POST_COMMENT", id: comment.id} - user_conn = simu_conn(:user, user) - user_conn |> mutation_result(@like_comment_query, variables, "likeComment") - - {:ok, found} = CMS.PostComment |> ORM.find(comment.id, preload: :likes) - assert found.likes |> Enum.any?(&(&1.post_comment_id == comment.id)) - - user_conn |> mutation_result(@undo_like_comment_query, variables, "undoLikeComment") - - {:ok, found} = CMS.PostComment |> ORM.find(comment.id, preload: :likes) - assert false == found.likes |> Enum.any?(&(&1.post_comment_id == comment.id)) - end - - @dislike_comment_query """ - mutation($thread: CmsComment!, $id: ID!) { - dislikeComment(thread: $thread, id: $id) { - id - } - } - """ - test "login user can dislike a comment", ~m(user_conn comment)a do - variables = %{thread: "POST_COMMENT", id: comment.id} - user_conn |> mutation_result(@dislike_comment_query, variables, "dislikeComment") - - {:ok, found} = CMS.PostComment |> ORM.find(comment.id, preload: :dislikes) - - assert found.dislikes |> Enum.any?(&(&1.post_comment_id == comment.id)) - end - - @undo_dislike_comment_query """ - mutation($thread: CmsComment!, $id: ID!) { - undoDislikeComment(thread: $thread, id: $id) { - id - } - } - """ - test "login user can undo dislike a comment", ~m(user comment)a do - variables = %{thread: "POST_COMMENT", id: comment.id} - user_conn = simu_conn(:user, user) - user_conn |> mutation_result(@dislike_comment_query, variables, "dislikeComment") - {:ok, found} = CMS.PostComment |> ORM.find(comment.id, preload: :dislikes) - assert found.dislikes |> Enum.any?(&(&1.post_comment_id == comment.id)) - - user_conn |> mutation_result(@undo_dislike_comment_query, variables, "undoDislikeComment") - - {:ok, found} = CMS.PostComment |> ORM.find(comment.id, preload: :dislikes) - assert false == found.dislikes |> Enum.any?(&(&1.post_comment_id == comment.id)) - end - - test "unloged user do/undo like/dislike comment fails", ~m(guest_conn comment)a do - variables = %{thread: "POST_COMMENT", id: comment.id} - - assert guest_conn |> mutation_get_error?(@like_comment_query, variables) - assert guest_conn |> mutation_get_error?(@dislike_comment_query, variables) - - assert guest_conn |> mutation_get_error?(@undo_like_comment_query, variables) - assert guest_conn |> mutation_get_error?(@undo_dislike_comment_query, variables) - end end end diff --git a/test/groupher_server_web/mutation/cms/post_test.exs b/test/groupher_server_web/mutation/cms/post_test.exs index 966154c9f..2492ba243 100644 --- a/test/groupher_server_web/mutation/cms/post_test.exs +++ b/test/groupher_server_web/mutation/cms/post_test.exs @@ -196,6 +196,10 @@ defmodule GroupherServer.Test.Mutation.Post do meta { isEdited } + commentParticipators { + id + nickname + } } } """ @@ -268,7 +272,7 @@ defmodule GroupherServer.Test.Mutation.Post do assert updated_post["copyRight"] == variables.copyRight end - @tag :wip2 + @tag :wip test "update post with valid attrs should have is_edited meta info update", ~m(owner_conn post)a do unique_num = System.unique_integer([:positive, :monotonic]) @@ -618,6 +622,25 @@ defmodule GroupherServer.Test.Mutation.Post do end describe "[mutation post comment]" do + @write_comment_query """ + mutation($thread: CmsThread!, $id: ID!, $content: String!) { + createArticleComment(thread: $thread,id: $id, content: $content) { + id + bodyHtml + } + } + """ + @tag :wip + test "write 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 + @create_comment_query """ mutation($community: String!, $thread: CmsThread!, $id: ID!, $body: String!) { createComment(community: $community, thread: $thread,id: $id, body: $body) { diff --git a/test/groupher_server_web/mutation/cms/repo_comment_test.exs b/test/groupher_server_web/mutation/cms/repo_comment_test.exs deleted file mode 100644 index f8dd1f053..000000000 --- a/test/groupher_server_web/mutation/cms/repo_comment_test.exs +++ /dev/null @@ -1,309 +0,0 @@ -defmodule GroupherServer.Test.Mutation.RepoComment do - use GroupherServer.TestTools - - alias Helper.ORM - alias GroupherServer.{CMS, Delivery} - - setup do - {:ok, repo} = db_insert(:repo) - {:ok, user} = db_insert(:user) - {:ok, community} = db_insert(:community) - - guest_conn = simu_conn(:guest) - user_conn = simu_conn(:user, user) - - {:ok, comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: "test comment"}, user) - - {:ok, ~m(user_conn guest_conn repo user community comment)a} - end - - describe "[repo comment CURD]" do - @create_comment_query """ - mutation($community: String!, $thread: CmsThread, $id: ID!, $body: String!, $mentionUsers: [Ids]) { - createComment(community: $community, thread: $thread, id: $id, body: $body, mentionUsers: $mentionUsers) { - id - body - } - } - """ - test "login user can create comment to a repo", ~m(user_conn community repo)a do - variables = %{community: community.raw, thread: "REPO", id: repo.id, body: "this a comment"} - created = user_conn |> mutation_result(@create_comment_query, variables, "createComment") - - {:ok, found} = ORM.find(CMS.RepoComment, created["id"]) - - assert created["id"] == to_string(found.id) - end - - test "can mention other user when create comment to repo", ~m(user_conn community repo)a do - {:ok, user2} = db_insert(:user) - - comment_body = "this is a comment" - - variables = - %{community: community.raw, thread: "REPO", id: repo.id, body: comment_body} - |> Map.merge(%{mentionUsers: [%{id: user2.id}]}) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Delivery.fetch_mentions(user2, filter) - assert mentions.total_count == 0 - - _created = user_conn |> mutation_result(@create_comment_query, variables, "createComment") - - {:ok, mentions} = Delivery.fetch_mentions(user2, filter) - assert mentions.total_count == 1 - the_mention = mentions.entries |> List.first() - - assert the_mention.source_title == repo.title - assert the_mention.source_type == "comment" - assert the_mention.parent_id == to_string(repo.id) - assert the_mention.parent_type == "repo" - assert the_mention.source_preview == comment_body - end - - test "guest user create comment fails", ~m(guest_conn community repo)a do - variables = %{community: community.raw, thread: "REPO", id: repo.id, body: "this a comment"} - - assert guest_conn - |> mutation_get_error?(@create_comment_query, variables, ecode(:account_login)) - end - - @delete_comment_query """ - mutation($thread: CmsThread, $id: ID!) { - deleteComment(thread: $thread, id: $id) { - id - body - } - } - """ - - test "comment owner can delete comment", ~m(user community repo)a do - variables = %{community: community.raw, thread: "REPO", id: repo.id, body: "this a comment"} - - user_conn = simu_conn(:user, user) - created = user_conn |> mutation_result(@create_comment_query, variables, "createComment") - - variables = %{thread: "REPO", id: created["id"]} - deleted = user_conn |> mutation_result(@delete_comment_query, variables, "deleteComment") - - assert deleted["id"] == created["id"] - end - - test "unauth user delete comment fails", ~m(user_conn guest_conn community repo)a do - variables = %{community: community.raw, thread: "REPO", id: repo.id, body: "this a comment"} - {:ok, owner} = db_insert(:user) - owner_conn = simu_conn(:user, owner) - created = owner_conn |> mutation_result(@create_comment_query, variables, "createComment") - - variables = %{thread: "REPO", id: created["id"]} - rule_conn = simu_conn(:user, cms: %{"what.ever" => true}) - - 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)) - - assert rule_conn |> mutation_get_error?(@delete_comment_query, variables, ecode(:passport)) - end - - @reply_comment_query """ - mutation( - $community: String! - $thread: CmsThread - $id: ID! - $body: String! - $mentionUsers: [Ids] - ) { - replyComment( - community: $community - thread: $thread - id: $id - body: $body - mentionUsers: $mentionUsers - ) { - id - body - replyTo { - id - } - } - } - """ - test "login user can reply to a exsit comment", ~m(user_conn community comment)a do - variables = %{ - community: community.raw, - thread: "REPO", - id: comment.id, - body: "this a reply" - } - - replied = user_conn |> mutation_result(@reply_comment_query, variables, "replyComment") - - assert replied["replyTo"] |> Map.get("id") == to_string(comment.id) - end - - test "guest user reply comment fails", ~m(guest_conn comment)a do - variables = %{thread: "REPO", id: comment.id, body: "this a reply"} - - assert guest_conn |> mutation_get_error?(@reply_comment_query, variables) - end - - test "should mention author when reply to a comment", ~m(community repo user)a do - body = "this is a comment" - - {:ok, comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - variables = %{ - community: community.raw, - thread: "REPO", - id: comment.id, - body: "this a reply" - } - - {:ok, user2} = db_insert(:user) - user_conn2 = simu_conn(:user, user2) - _replied = user_conn2 |> mutation_result(@reply_comment_query, variables, "replyComment") - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Delivery.fetch_mentions(user, filter) - assert mentions.total_count == 1 - the_mention = mentions.entries |> List.first() - - assert the_mention.from_user_id == user2.id - assert the_mention.to_user_id == user.id - assert the_mention.floor != nil - assert the_mention.source_title == comment.body - assert the_mention.source_type == "comment_reply" - assert the_mention.parent_id == to_string(repo.id) - assert the_mention.parent_type == "repo" - end - - test "can mention others in a reply", ~m(community repo user user_conn)a do - body = "this is a comment" - {:ok, user2} = db_insert(:user) - - {:ok, comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - variables = %{ - community: community.raw, - thread: "REPO", - id: comment.id, - body: "this is a reply", - mentionUsers: [%{id: user2.id}] - } - - _replied = user_conn |> mutation_result(@reply_comment_query, variables, "replyComment") - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Delivery.fetch_mentions(user2, filter) - assert mentions.total_count == 1 - the_mention = mentions.entries |> List.first() - - assert the_mention.from_user_id == user.id - assert the_mention.to_user_id == user2.id - assert the_mention.floor != nil - assert the_mention.source_title == comment.body - assert the_mention.source_type == "comment_reply" - assert the_mention.source_preview == "this is a reply" - assert the_mention.parent_id == to_string(repo.id) - assert the_mention.parent_type == "repo" - end - - test "TODO owner can NOT delete comment when comment has replies" do - end - - test "TODO owner can NOT edit comment when comment has replies" do - end - - test "TODO owner can NOT delete comment when comment has created after 3 hours" do - end - end - - describe "[repo comment reactions]" do - @like_comment_query """ - mutation($thread: CmsComment!, $id: ID!) { - likeComment(thread: $thread, id: $id) { - id - } - } - """ - test "login user can like a comment", ~m(user_conn comment)a do - variables = %{thread: "REPO_COMMENT", id: comment.id} - user_conn |> mutation_result(@like_comment_query, variables, "likeComment") - - {:ok, found} = CMS.RepoComment |> ORM.find(comment.id, preload: :likes) - - assert found.likes |> Enum.any?(&(&1.repo_comment_id == comment.id)) - end - - @undo_like_comment_query """ - mutation($thread: CmsComment!, $id: ID!) { - undoLikeComment(thread: $thread, id: $id) { - id - } - } - """ - test "login user can undo a like action to comment", ~m(user comment)a do - variables = %{thread: "REPO_COMMENT", id: comment.id} - user_conn = simu_conn(:user, user) - user_conn |> mutation_result(@like_comment_query, variables, "likeComment") - - {:ok, found} = CMS.RepoComment |> ORM.find(comment.id, preload: :likes) - assert found.likes |> Enum.any?(&(&1.repo_comment_id == comment.id)) - - user_conn |> mutation_result(@undo_like_comment_query, variables, "undoLikeComment") - - {:ok, found} = CMS.RepoComment |> ORM.find(comment.id, preload: :likes) - assert false == found.likes |> Enum.any?(&(&1.repo_comment_id == comment.id)) - end - - @dislike_comment_query """ - mutation($thread: CmsComment!, $id: ID!) { - dislikeComment(thread: $thread, id: $id) { - id - } - } - """ - test "login user can dislike a comment", ~m(user_conn comment)a do - variables = %{thread: "REPO_COMMENT", id: comment.id} - user_conn |> mutation_result(@dislike_comment_query, variables, "dislikeComment") - - {:ok, found} = CMS.RepoComment |> ORM.find(comment.id, preload: :dislikes) - - assert found.dislikes |> Enum.any?(&(&1.repo_comment_id == comment.id)) - end - - @undo_dislike_comment_query """ - mutation($thread: CmsComment!, $id: ID!) { - undoDislikeComment(thread: $thread, id: $id) { - id - } - } - """ - test "login user can undo dislike a comment", ~m(user comment)a do - variables = %{thread: "REPO_COMMENT", id: comment.id} - user_conn = simu_conn(:user, user) - user_conn |> mutation_result(@dislike_comment_query, variables, "dislikeComment") - {:ok, found} = CMS.RepoComment |> ORM.find(comment.id, preload: :dislikes) - assert found.dislikes |> Enum.any?(&(&1.repo_comment_id == comment.id)) - - user_conn |> mutation_result(@undo_dislike_comment_query, variables, "undoDislikeComment") - - {:ok, found} = CMS.RepoComment |> ORM.find(comment.id, preload: :dislikes) - assert false == found.dislikes |> Enum.any?(&(&1.repo_comment_id == comment.id)) - end - - test "unloged user do/undo like/dislike comment fails", ~m(guest_conn comment)a do - variables = %{thread: "REPO_COMMENT", id: comment.id} - - assert guest_conn |> mutation_get_error?(@like_comment_query, variables) - assert guest_conn |> mutation_get_error?(@dislike_comment_query, variables) - - assert guest_conn |> mutation_get_error?(@undo_like_comment_query, variables) - assert guest_conn |> mutation_get_error?(@undo_dislike_comment_query, variables) - end - end -end diff --git a/test/groupher_server_web/query/accounts/published_comments_test.exs b/test/groupher_server_web/query/accounts/published_comments_test.exs index 5275f2742..0fe43c651 100644 --- a/test/groupher_server_web/query/accounts/published_comments_test.exs +++ b/test/groupher_server_web/query/accounts/published_comments_test.exs @@ -63,102 +63,4 @@ defmodule GroupherServer.Test.Query.Accounts.PublishedComments do assert results["entries"] |> Enum.any?(&(&1["id"] == random_comment_id)) end end - - describe "[account published comments on job]" do - @query """ - query($userId: ID!, $filter: PagedFilter!) { - publishedJobComments(userId: $userId, filter: $filter) { - entries { - id - body - author { - id - } - job { - id - title - } - } - totalPages - totalCount - pageSize - pageNumber - } - } - """ - test "user can get paged published comments on job", ~m(guest_conn user community)a do - {:ok, job} = db_insert(:job) - - pub_comments = - Enum.reduce(1..@publish_count, [], fn _, acc -> - body = "this is a test comment" - - {:ok, comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - acc ++ [comment] - end) - - random_comment_id = pub_comments |> Enum.random() |> Map.get(:id) |> to_string - - variables = %{userId: user.id, filter: %{page: 1, size: 20}} - results = guest_conn |> query_result(@query, variables, "publishedJobComments") - - assert results |> is_valid_pagination? - assert results["totalCount"] == @publish_count - - assert results["entries"] |> Enum.all?(&(&1["job"]["id"] == to_string(job.id))) - assert results["entries"] |> Enum.all?(&(&1["author"]["id"] == to_string(user.id))) - assert results["entries"] |> Enum.any?(&(&1["id"] == random_comment_id)) - end - end - - describe "[account published comments on repo]" do - @query """ - query($userId: ID!, $filter: PagedFilter!) { - publishedRepoComments(userId: $userId, filter: $filter) { - entries { - id - body - author { - id - } - repo { - id - title - } - } - totalPages - totalCount - pageSize - pageNumber - } - } - """ - test "user can get paged published comments on repo", ~m(guest_conn user community)a do - {:ok, repo} = db_insert(:repo) - - pub_comments = - Enum.reduce(1..@publish_count, [], fn _, acc -> - body = "this is a test comment" - - {:ok, comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - acc ++ [comment] - end) - - random_comment_id = pub_comments |> Enum.random() |> Map.get(:id) |> to_string - - variables = %{userId: user.id, filter: %{page: 1, size: 20}} - results = guest_conn |> query_result(@query, variables, "publishedRepoComments") - - assert results |> is_valid_pagination? - assert results["totalCount"] == @publish_count - - assert results["entries"] |> Enum.all?(&(&1["repo"]["id"] == to_string(repo.id))) - assert results["entries"] |> Enum.all?(&(&1["author"]["id"] == to_string(user.id))) - assert results["entries"] |> Enum.any?(&(&1["id"] == random_comment_id)) - 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 new file mode 100644 index 000000000..d4874344a --- /dev/null +++ b/test/groupher_server_web/query/cms/article_comment_test.exs @@ -0,0 +1,114 @@ +defmodule GroupherServer.Test.Query.ArticleComment do + @moduledoc false + + use GroupherServer.TestTools + + alias GroupherServer.CMS + + setup do + {:ok, post} = db_insert(:post) + {:ok, job} = db_insert(:job) + {:ok, user} = db_insert(:user) + + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user) + + {:ok, ~m(user_conn guest_conn post job user)a} + end + + describe "[article post comment]" do + @query """ + query($id: ID!) { + post(id: $id) { + id + title + body + commentParticipators{ + id + nickname + } + } + } + """ + @tag :wip + test "guest user can get comment participators after comment created", + ~m(guest_conn post user)a do + comment = "test comment" + total_count = 3 + thread = :post + + Enum.reduce(1..total_count, [], fn _, acc -> + {:ok, value} = CMS.create_article_comment(thread, post.id, comment, user) + + acc ++ [value] + end) + + variables = %{id: post.id} + results = guest_conn |> query_result(@query, variables, "post") + + comment_participators = results["commentParticipators"] + # participator = List.first(comment_participators) + + assert is_list(comment_participators) + # assert participator["id"] == user.id + end + + @query """ + query($id: ID!, $thread: CmsThread, $filter: CommentsFilter!) { + pagedArticleComments(id: $id, thread: $thread, filter: $filter) { + entries { + id + bodyHtml + author { + id + nickname + } + } + totalPages + totalCount + pageSize + pageNumber + } + } + """ + @tag :wip + test "guest user can get paged comment for post", ~m(guest_conn post user)a do + comment = "test comment" + total_count = 30 + thread = :post + + Enum.reduce(1..total_count, [], fn _, acc -> + {:ok, value} = CMS.create_article_comment(thread, post.id, comment, user) + + acc ++ [value] + end) + + variables = %{id: post.id, thread: "POST", filter: %{page: 1, size: 10}} + results = guest_conn |> query_result(@query, variables, "pagedArticleComments") + + assert results |> is_valid_pagination? + assert results["totalCount"] == total_count + end + + @tag :wip + test "guest user can get paged comment for job", ~m(guest_conn job user)a do + comment = "test comment" + total_count = 30 + thread = :job + + Enum.reduce(1..total_count, [], fn _, acc -> + {:ok, value} = CMS.create_article_comment(thread, job.id, comment, user) + + acc ++ [value] + end) + + variables = %{id: job.id, thread: "JOB", filter: %{page: 1, size: 10}} + results = guest_conn |> query_result(@query, variables, "pagedArticleComments") + + # IO.inspect(results, label: "results-") + + assert results |> is_valid_pagination? + assert results["totalCount"] == total_count + end + end +end diff --git a/test/groupher_server_web/query/cms/job_comment_test.exs b/test/groupher_server_web/query/cms/job_comment_test.exs deleted file mode 100644 index a187b38c3..000000000 --- a/test/groupher_server_web/query/cms/job_comment_test.exs +++ /dev/null @@ -1,375 +0,0 @@ -defmodule GroupherServer.Test.Query.JobComment do - use GroupherServer.TestTools - - alias GroupherServer.CMS - - setup do - {:ok, job} = db_insert(:job) - {:ok, user} = db_insert(:user) - {:ok, community} = db_insert(:community) - - guest_conn = simu_conn(:guest) - user_conn = simu_conn(:user) - - {:ok, ~m(user_conn guest_conn job user community)a} - end - - describe "[job dataloader comment]" do - @query """ - query($filter: PagedJobsFilter) { - pagedJobs(filter: $filter) { - entries { - id - title - commentsParticipators(filter: { first: 5 }) { - id - nickname - } - pagedCommentsParticipators { - entries { - id - } - totalCount - } - commentsCount - } - totalCount - } - } - """ - test "can get comments participators of a job", ~m(user guest_conn)a do - {:ok, user2} = db_insert(:user) - - {:ok, community} = db_insert(:community) - {:ok, job} = CMS.create_content(community, :job, mock_attrs(:job), user) - - variables = %{thread: "JOB", filter: %{community: community.raw}} - guest_conn |> query_result(@query, variables, "pagedJobs") - - body = "this is a test comment" - - assert {:ok, _comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - assert {:ok, _comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - assert {:ok, _comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user2) - - variables = %{filter: %{community: community.raw}} - results = guest_conn |> query_result(@query, variables, "pagedJobs") - - comments_count = results["entries"] |> List.first() |> Map.get("commentsCount") - - assert comments_count == 3 - end - - test "can get comments participators of a job with multi user", ~m(user guest_conn)a do - body = "this is a test comment" - {:ok, community} = db_insert(:community) - {:ok, job1} = CMS.create_content(community, :job, mock_attrs(:job), user) - {:ok, job2} = CMS.create_content(community, :job, mock_attrs(:job), user) - - {:ok, users_list} = db_insert_multi(:user, 10) - {:ok, users_list2} = db_insert_multi(:user, 10) - - Enum.each( - users_list, - &CMS.create_comment(:job, job1.id, %{community: community.raw, body: body}, &1) - ) - - Enum.each( - users_list2, - &CMS.create_comment(:job, job2.id, %{community: community.raw, body: body}, &1) - ) - - variables = %{thread: "JOB", filter: %{community: community.raw}} - results = guest_conn |> query_result(@query, variables, "pagedJobs") - - assert results["entries"] |> List.first() |> Map.get("commentsParticipators") |> length == 5 - - assert results["entries"] |> List.last() |> Map.get("commentsParticipators") |> length == 5 - end - - test "can get paged commetns participators of a job", ~m(user guest_conn)a do - body = "this is a test comment" - - {:ok, community} = db_insert(:community) - {:ok, job} = CMS.create_content(community, :job, mock_attrs(:job), user) - {:ok, users_list} = db_insert_multi(:user, 10) - - Enum.each( - users_list, - &CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, &1) - ) - - variables = %{filter: %{community: community.raw}} - results = guest_conn |> query_result(@query, variables, "pagedJobs") - participators = results["entries"] |> List.first() |> Map.get("pagedCommentsParticipators") - - assert participators["totalCount"] == 10 - end - end - - @query """ - query($id: ID!, $thread: CmsThread, $filter: PagedFilter!) { - pagedCommentsParticipators(id: $id, thread: $thread, filter: $filter) { - entries { - id - nickname - } - totalPages - totalCount - pageSize - pageNumber - } - } - """ - test "can get job's paged commetns participators", ~m(user guest_conn)a do - body = "this is a test comment" - - {:ok, community} = db_insert(:community) - {:ok, job} = CMS.create_content(community, :job, mock_attrs(:job), user) - {:ok, users_list} = db_insert_multi(:user, 10) - - Enum.each( - users_list, - &CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, &1) - ) - - variables = %{id: job.id, thread: "JOB", filter: %{page: 1, size: 20}} - results = guest_conn |> query_result(@query, variables, "pagedCommentsParticipators") - assert results |> is_valid_pagination?() - - assert results["totalCount"] == 10 - end - - # TODO: user can get specific user's replies :list_replies - describe "[job comment]" do - @query """ - query($filter: PagedJobsFilter) { - pagedJobs(filter: $filter) { - entries { - id - title - commentsCount - } - totalCount - } - } - """ - test "can get comments info in paged jobs", ~m(user guest_conn)a do - body = "this is a test comment" - - {:ok, community} = db_insert(:community) - {:ok, job} = CMS.create_content(community, :job, mock_attrs(:job), user) - - {:ok, _comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - variables = %{filter: %{community: community.raw}} - results = guest_conn |> query_result(@query, variables, "pagedJobs") - - assert results["entries"] |> List.first() |> Map.get("commentsCount") == 1 - end - - @query """ - query($thread: CmsThread, $id: ID!, $filter: CommentsFilter!) { - pagedComments(thread: $thread, id: $id, filter: $filter) { - entries { - id - body - likesCount - dislikesCount - } - totalPages - totalCount - pageSize - pageNumber - } - } - """ - test "guest user can get a paged comment", ~m(guest_conn job user community)a do - body = "test comment" - - Enum.reduce(1..30, [], fn _, acc -> - {:ok, value} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - acc ++ [value] - end) - - variables = %{thread: "JOB", id: job.id, filter: %{page: 1, size: 10}} - results = guest_conn |> query_result(@query, variables, "pagedComments") - - assert results |> is_valid_pagination? - assert results["totalCount"] == 30 - end - - test "MOST_LIKES filter should work", ~m(guest_conn job user community)a do - body = "test comment" - - comments = - Enum.reduce(1..10, [], fn _, acc -> - {:ok, value} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - acc ++ [value] - end) - - [comment_1, _comment_2, comment_3, _comment_last] = comments |> firstn_and_last(3) - - {:ok, [user_1, user_2, user_3, user_4, user_5]} = db_insert_multi(:user, 5) - - # comment_3 is most likes - {:ok, _} = CMS.like_comment(:job_comment, comment_3.id, user_1) - {:ok, _} = CMS.like_comment(:job_comment, comment_3.id, user_2) - {:ok, _} = CMS.like_comment(:job_comment, comment_3.id, user_3) - {:ok, _} = CMS.like_comment(:job_comment, comment_3.id, user_4) - {:ok, _} = CMS.like_comment(:job_comment, comment_3.id, user_5) - - {:ok, _} = CMS.like_comment(:job_comment, comment_1.id, user_1) - {:ok, _} = CMS.like_comment(:job_comment, comment_1.id, user_2) - {:ok, _} = CMS.like_comment(:job_comment, comment_1.id, user_3) - {:ok, _} = CMS.like_comment(:job_comment, comment_1.id, user_4) - - variables = %{ - thread: "JOB", - id: job.id, - filter: %{page: 1, size: 10, sort: "MOST_LIKES"} - } - - results = guest_conn |> query_result(@query, variables, "pagedComments") - - entries = results["entries"] - - assert entries |> Enum.at(0) |> Map.get("id") == to_string(comment_3.id) - assert entries |> Enum.at(0) |> Map.get("likesCount") == 5 - - assert entries |> Enum.at(1) |> Map.get("id") == to_string(comment_1.id) - assert entries |> Enum.at(1) |> Map.get("likesCount") == 4 - end - - test "MOST_DISLIKES filter should work", ~m(guest_conn job user community)a do - body = "test comment" - - comments = - Enum.reduce(1..10, [], fn _, acc -> - {:ok, value} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - acc ++ [value] - end) - - [comment_1, _comment_2, comment_3, _comment_last] = comments |> firstn_and_last(3) - {:ok, [user_1, user_2, user_3, user_4, user_5]} = db_insert_multi(:user, 5) - - # comment_3 is most likes - {:ok, _} = CMS.dislike_comment(:job_comment, comment_3.id, user_1) - {:ok, _} = CMS.dislike_comment(:job_comment, comment_3.id, user_2) - {:ok, _} = CMS.dislike_comment(:job_comment, comment_3.id, user_3) - {:ok, _} = CMS.dislike_comment(:job_comment, comment_3.id, user_4) - {:ok, _} = CMS.dislike_comment(:job_comment, comment_3.id, user_5) - - {:ok, _} = CMS.dislike_comment(:job_comment, comment_1.id, user_1) - {:ok, _} = CMS.dislike_comment(:job_comment, comment_1.id, user_2) - {:ok, _} = CMS.dislike_comment(:job_comment, comment_1.id, user_3) - {:ok, _} = CMS.dislike_comment(:job_comment, comment_1.id, user_4) - - variables = %{ - thread: "JOB", - id: job.id, - filter: %{page: 1, size: 10, sort: "MOST_DISLIKES"} - } - - results = guest_conn |> query_result(@query, variables, "pagedComments") - entries = results["entries"] - - assert entries |> Enum.at(0) |> Map.get("id") == to_string(comment_3.id) - assert entries |> Enum.at(0) |> Map.get("dislikesCount") == 5 - - assert entries |> Enum.at(1) |> Map.get("id") == to_string(comment_1.id) - assert entries |> Enum.at(1) |> Map.get("dislikesCount") == 4 - end - - @query """ - query($thread: CmsThread, $id: ID!, $filter: CommentsFilter!) { - pagedComments(thread: $thread, id: $id, filter: $filter) { - entries { - id - viewerHasLiked - } - } - } - """ - test "login user can get hasLiked feedBack", ~m(user_conn job user community)a do - body = "test comment" - - {:ok, comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - {:ok, _like} = CMS.like_comment(:job_comment, comment.id, user) - - variables = %{thread: "JOB", id: job.id, filter: %{page: 1, size: 10}} - results = user_conn |> query_result(@query, variables, "pagedComments") - - found = - results["entries"] |> Enum.filter(&(&1["id"] == to_string(comment.id))) |> List.first() - - assert found["viewerHasLiked"] == false - - own_like_conn = simu_conn(:user, user) - results = own_like_conn |> query_result(@query, variables, "pagedComments") - - found = - results["entries"] |> Enum.filter(&(&1["id"] == to_string(comment.id))) |> List.first() - - assert found["viewerHasLiked"] == true - end - - @query """ - query($thread: CmsThread, $id: ID!, $filter: CommentsFilter!) { - pagedComments(thread: $thread, id: $id, filter: $filter) { - entries { - id - body - replyTo { - id - body - } - repliesCount - replies { - id - body - } - } - } - } - """ - test "guest user can get replies info", ~m(guest_conn job user community)a do - body = "test comment" - - {:ok, comment} = - CMS.create_comment(:job, job.id, %{community: community.raw, body: body}, user) - - {:ok, reply} = - CMS.reply_comment(:job, comment.id, %{community: community.raw, body: "reply body"}, user) - - variables = %{thread: "JOB", id: job.id, filter: %{page: 1, size: 10}} - results = guest_conn |> query_result(@query, variables, "pagedComments") - - found = - results["entries"] |> Enum.filter(&(&1["id"] == to_string(comment.id))) |> List.first() - - found_reply = - results["entries"] |> Enum.filter(&(&1["id"] == to_string(reply.id))) |> List.first() - - # author = found |> Map.get("author") - assert found["repliesCount"] == 1 - assert found["replies"] |> Enum.any?(&(&1["id"] == to_string(reply.id))) - assert found["replyTo"] == nil - assert found_reply["replyTo"] |> Map.get("id") == to_string(comment.id) - end - end -end diff --git a/test/groupher_server_web/query/cms/post_comment_test.exs b/test/groupher_server_web/query/cms/post_comment_test.exs index 2ebaf8b82..b1496ec32 100644 --- a/test/groupher_server_web/query/cms/post_comment_test.exs +++ b/test/groupher_server_web/query/cms/post_comment_test.exs @@ -222,7 +222,6 @@ defmodule GroupherServer.Test.Query.PostComment do entries { id likesCount - dislikesCount } totalPages totalCount @@ -231,6 +230,7 @@ defmodule GroupherServer.Test.Query.PostComment do } } """ + @tag :wip test "guest user can get a paged comment", ~m(guest_conn post user community)a do body = "test comment" @@ -285,43 +285,6 @@ defmodule GroupherServer.Test.Query.PostComment do assert entries |> Enum.at(1) |> Map.get("likesCount") == 4 end - test "MOST_DISLIKES filter should work", ~m(guest_conn post user community)a do - body = "test comment" - - comments = - Enum.reduce(1..10, [], fn _, acc -> - {:ok, value} = - CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - acc ++ [value] - end) - - [comment_1, _comment_2, comment_3, _comment_last] = comments |> firstn_and_last(3) - {:ok, [user_1, user_2, user_3, user_4, user_5]} = db_insert_multi(:user, 5) - - # comment_3 is most likes - {:ok, _} = CMS.dislike_comment(:post_comment, comment_3.id, user_1) - {:ok, _} = CMS.dislike_comment(:post_comment, comment_3.id, user_2) - {:ok, _} = CMS.dislike_comment(:post_comment, comment_3.id, user_3) - {:ok, _} = CMS.dislike_comment(:post_comment, comment_3.id, user_4) - {:ok, _} = CMS.dislike_comment(:post_comment, comment_3.id, user_5) - - {:ok, _} = CMS.dislike_comment(:post_comment, comment_1.id, user_1) - {:ok, _} = CMS.dislike_comment(:post_comment, comment_1.id, user_2) - {:ok, _} = CMS.dislike_comment(:post_comment, comment_1.id, user_3) - {:ok, _} = CMS.dislike_comment(:post_comment, comment_1.id, user_4) - - variables = %{id: post.id, filter: %{page: 1, size: 10, sort: "MOST_DISLIKES"}} - results = guest_conn |> query_result(@query, variables, "pagedComments") - entries = results["entries"] - - assert entries |> Enum.at(0) |> Map.get("id") == to_string(comment_3.id) - assert entries |> Enum.at(0) |> Map.get("dislikesCount") == 5 - - assert entries |> Enum.at(1) |> Map.get("id") == to_string(comment_1.id) - assert entries |> Enum.at(1) |> Map.get("dislikesCount") == 4 - end - @query """ query($id: ID!, $filter: CommentsFilter!) { pagedComments(id: $id, filter: $filter) { @@ -398,47 +361,6 @@ defmodule GroupherServer.Test.Query.PostComment do assert found["likes"] |> Enum.any?(&(&1["id"] == to_string(user.id))) end - @query """ - query($id: ID!, $filter: CommentsFilter!) { - pagedComments(id: $id, filter: $filter) { - entries { - id - body - author { - id - nickname - } - dislikesCount - dislikes { - id - nickname - } - } - } - } - """ - test "guest user can get dislikes info", ~m(guest_conn post user community)a do - body = "test comment" - - {:ok, comment} = - CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - {:ok, _like} = CMS.dislike_comment(:post_comment, comment.id, user) - - variables = %{id: post.id, filter: %{page: 1, size: 10}} - results = guest_conn |> query_result(@query, variables, "pagedComments") - - found = - results["entries"] |> Enum.filter(&(&1["id"] == to_string(comment.id))) |> List.first() - - author = found |> Map.get("author") - - assert author["id"] == to_string(user.id) - assert found["dislikesCount"] == 1 - - assert found["dislikes"] |> Enum.any?(&(&1["id"] == to_string(user.id))) - end - @query """ query($id: ID!, $filter: CommentsFilter!) { pagedComments(id: $id, filter: $filter) { diff --git a/test/groupher_server_web/query/cms/post_test.exs b/test/groupher_server_web/query/cms/post_test.exs index 50384ffdc..3d4b9e616 100644 --- a/test/groupher_server_web/query/cms/post_test.exs +++ b/test/groupher_server_web/query/cms/post_test.exs @@ -28,7 +28,6 @@ defmodule GroupherServer.Test.Query.Post do } } """ - @tag :wip2 test "basic graphql query on post with logined user", ~m(user_conn community user post_attrs)a do {:ok, post} = CMS.create_content(community, :post, post_attrs, user) @@ -43,7 +42,6 @@ defmodule GroupherServer.Test.Query.Post do assert length(Map.keys(results)) == 4 end - # @tag :wip2 test "basic graphql query on post with stranger(unloged user)", ~m(guest_conn post)a do variables = %{id: post.id} results = guest_conn |> query_result(@query, variables, "post") diff --git a/test/groupher_server_web/query/cms/repo_comment_test.exs b/test/groupher_server_web/query/cms/repo_comment_test.exs deleted file mode 100644 index 94f004283..000000000 --- a/test/groupher_server_web/query/cms/repo_comment_test.exs +++ /dev/null @@ -1,384 +0,0 @@ -defmodule GroupherServer.Test.Query.RepoComment do - use GroupherServer.TestTools - - alias GroupherServer.CMS - - setup do - {:ok, repo} = db_insert(:repo) - {:ok, user} = db_insert(:user) - {:ok, community} = db_insert(:community) - - guest_conn = simu_conn(:guest) - user_conn = simu_conn(:user) - - {:ok, ~m(user_conn guest_conn repo community user)a} - end - - describe "[repo dataloader comment]" do - @query """ - query($filter: PagedReposFilter) { - pagedRepos(filter: $filter) { - entries { - id - title - commentsParticipators(filter: { first: 5 }) { - id - nickname - } - pagedCommentsParticipators { - entries { - id - } - totalCount - } - commentsCount - } - totalCount - } - } - """ - - test "can get comments participators of a repo", ~m(guest_conn user)a do - {:ok, user2} = db_insert(:user) - - {:ok, community} = db_insert(:community) - {:ok, repo} = CMS.create_content(community, :repo, mock_attrs(:repo), user) - - variables = %{thread: "REPO", filter: %{community: community.raw}} - guest_conn |> query_result(@query, variables, "pagedRepos") - - body = "this is a test comment" - - assert {:ok, _comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - assert {:ok, _comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - assert {:ok, _comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user2) - - variables = %{filter: %{community: community.raw}} - results = guest_conn |> query_result(@query, variables, "pagedRepos") - - comments_count = results["entries"] |> List.first() |> Map.get("commentsCount") - - assert comments_count == 3 - end - - test "can get comments participators of a repo with multi user", ~m(guest_conn user)a do - body = "this is a test comment" - {:ok, community} = db_insert(:community) - {:ok, repo1} = CMS.create_content(community, :repo, mock_attrs(:repo), user) - {:ok, repo2} = CMS.create_content(community, :repo, mock_attrs(:repo), user) - - {:ok, users_list} = db_insert_multi(:user, 10) - {:ok, users_list2} = db_insert_multi(:user, 10) - - Enum.each( - users_list, - &CMS.create_comment(:repo, repo1.id, %{community: community.raw, body: body}, &1) - ) - - Enum.each( - users_list2, - &CMS.create_comment(:repo, repo2.id, %{community: community.raw, body: body}, &1) - ) - - variables = %{thread: "REPO", filter: %{community: community.raw}} - results = guest_conn |> query_result(@query, variables, "pagedRepos") - - assert results["entries"] |> List.first() |> Map.get("commentsParticipators") |> length == 5 - - assert results["entries"] |> List.last() |> Map.get("commentsParticipators") |> length == 5 - end - - test "can get paged commetns participators of a repo", ~m(guest_conn user)a do - body = "this is a test comment" - - {:ok, community} = db_insert(:community) - {:ok, repo} = CMS.create_content(community, :repo, mock_attrs(:repo), user) - {:ok, users_list} = db_insert_multi(:user, 10) - - Enum.each( - users_list, - &CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, &1) - ) - - variables = %{filter: %{community: community.raw}} - results = guest_conn |> query_result(@query, variables, "pagedRepos") - participators = results["entries"] |> List.first() |> Map.get("pagedCommentsParticipators") - - assert participators["totalCount"] == 10 - end - end - - @query """ - query($id: ID!, $thread: CmsThread, $filter: PagedFilter!) { - pagedCommentsParticipators(id: $id, thread: $thread, filter: $filter) { - entries { - id - nickname - } - totalPages - totalCount - pageSize - pageNumber - } - } - """ - - test "can get repo's paged commetns participators", ~m(guest_conn user)a do - body = "this is a test comment" - - {:ok, community} = db_insert(:community) - {:ok, repo} = CMS.create_content(community, :repo, mock_attrs(:repo), user) - {:ok, users_list} = db_insert_multi(:user, 10) - - Enum.each( - users_list, - &CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, &1) - ) - - variables = %{id: repo.id, thread: "REPO", filter: %{page: 1, size: 20}} - results = guest_conn |> query_result(@query, variables, "pagedCommentsParticipators") - assert results |> is_valid_pagination?() - - assert results["totalCount"] == 10 - end - - # TODO: user can get specific user's replies :list_replies - describe "[repo comment]" do - @query """ - query($filter: PagedReposFilter) { - pagedRepos(filter: $filter) { - entries { - id - title - commentsCount - } - totalCount - } - } - """ - - test "can get comments info in paged repos", ~m(user guest_conn)a do - body = "this is a test comment" - - {:ok, community} = db_insert(:community) - {:ok, repo} = CMS.create_content(community, :repo, mock_attrs(:repo), user) - - {:ok, _comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - variables = %{filter: %{community: community.raw}} - results = guest_conn |> query_result(@query, variables, "pagedRepos") - - assert results["entries"] |> List.first() |> Map.get("commentsCount") == 1 - end - - @query """ - query($thread: CmsThread, $id: ID!, $filter: CommentsFilter!) { - pagedComments(thread: $thread, id: $id, filter: $filter) { - entries { - id - body - likesCount - dislikesCount - } - totalPages - totalCount - pageSize - pageNumber - } - } - """ - test "guest user can get a paged comment", ~m(guest_conn repo community user)a do - body = "test comment" - - Enum.reduce(1..30, [], fn _, acc -> - {:ok, value} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - acc ++ [value] - end) - - variables = %{thread: "REPO", id: repo.id, filter: %{page: 1, size: 10}} - results = guest_conn |> query_result(@query, variables, "pagedComments") - - assert results |> is_valid_pagination? - assert results["totalCount"] == 30 - end - - test "MOST_LIKES filter should work", ~m(guest_conn repo user community)a do - body = "test comment" - - comments = - Enum.reduce(1..10, [], fn _, acc -> - {:ok, value} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - acc ++ [value] - end) - - [comment_1, _comment_2, comment_3, _comment_last] = comments |> firstn_and_last(3) - - {:ok, [user_1, user_2, user_3, user_4, user_5]} = db_insert_multi(:user, 5) - - # comment_3 is most likes - {:ok, _} = CMS.like_comment(:repo_comment, comment_3.id, user_1) - {:ok, _} = CMS.like_comment(:repo_comment, comment_3.id, user_2) - {:ok, _} = CMS.like_comment(:repo_comment, comment_3.id, user_3) - {:ok, _} = CMS.like_comment(:repo_comment, comment_3.id, user_4) - {:ok, _} = CMS.like_comment(:repo_comment, comment_3.id, user_5) - - {:ok, _} = CMS.like_comment(:repo_comment, comment_1.id, user_1) - {:ok, _} = CMS.like_comment(:repo_comment, comment_1.id, user_2) - {:ok, _} = CMS.like_comment(:repo_comment, comment_1.id, user_3) - {:ok, _} = CMS.like_comment(:repo_comment, comment_1.id, user_4) - - variables = %{ - thread: "REPO", - id: repo.id, - filter: %{page: 1, size: 10, sort: "MOST_LIKES"} - } - - results = guest_conn |> query_result(@query, variables, "pagedComments") - - entries = results["entries"] - - assert entries |> Enum.at(0) |> Map.get("id") == to_string(comment_3.id) - assert entries |> Enum.at(0) |> Map.get("likesCount") == 5 - - assert entries |> Enum.at(1) |> Map.get("id") == to_string(comment_1.id) - assert entries |> Enum.at(1) |> Map.get("likesCount") == 4 - end - - test "MOST_DISLIKES filter should work", ~m(guest_conn repo community user)a do - body = "test comment" - - comments = - Enum.reduce(1..10, [], fn _, acc -> - {:ok, value} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - acc ++ [value] - end) - - [comment_1, _comment_2, comment_3, _comment_last] = comments |> firstn_and_last(3) - {:ok, [user_1, user_2, user_3, user_4, user_5]} = db_insert_multi(:user, 5) - - # comment_3 is most likes - {:ok, _} = CMS.dislike_comment(:repo_comment, comment_3.id, user_1) - {:ok, _} = CMS.dislike_comment(:repo_comment, comment_3.id, user_2) - {:ok, _} = CMS.dislike_comment(:repo_comment, comment_3.id, user_3) - {:ok, _} = CMS.dislike_comment(:repo_comment, comment_3.id, user_4) - {:ok, _} = CMS.dislike_comment(:repo_comment, comment_3.id, user_5) - - {:ok, _} = CMS.dislike_comment(:repo_comment, comment_1.id, user_1) - {:ok, _} = CMS.dislike_comment(:repo_comment, comment_1.id, user_2) - {:ok, _} = CMS.dislike_comment(:repo_comment, comment_1.id, user_3) - {:ok, _} = CMS.dislike_comment(:repo_comment, comment_1.id, user_4) - - variables = %{ - thread: "REPO", - id: repo.id, - filter: %{page: 1, size: 10, sort: "MOST_DISLIKES"} - } - - results = guest_conn |> query_result(@query, variables, "pagedComments") - entries = results["entries"] - - assert entries |> Enum.at(0) |> Map.get("id") == to_string(comment_3.id) - assert entries |> Enum.at(0) |> Map.get("dislikesCount") == 5 - - assert entries |> Enum.at(1) |> Map.get("id") == to_string(comment_1.id) - assert entries |> Enum.at(1) |> Map.get("dislikesCount") == 4 - end - - @query """ - query($thread: CmsThread, $id: ID!, $filter: CommentsFilter!) { - pagedComments(thread: $thread, id: $id, filter: $filter) { - entries { - id - viewerHasLiked - } - } - } - """ - - test "login user can get hasLiked feedBack", ~m(user_conn repo community user)a do - body = "test comment" - - {:ok, comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - {:ok, _like} = CMS.like_comment(:repo_comment, comment.id, user) - - variables = %{thread: "REPO", id: repo.id, filter: %{page: 1, size: 10}} - results = user_conn |> query_result(@query, variables, "pagedComments") - - found = - results["entries"] |> Enum.filter(&(&1["id"] == to_string(comment.id))) |> List.first() - - assert found["viewerHasLiked"] == false - - own_like_conn = simu_conn(:user, user) - results = own_like_conn |> query_result(@query, variables, "pagedComments") - - found = - results["entries"] |> Enum.filter(&(&1["id"] == to_string(comment.id))) |> List.first() - - assert found["viewerHasLiked"] == true - end - - @query """ - query($thread: CmsThread, $id: ID!, $filter: CommentsFilter!) { - pagedComments(thread: $thread, id: $id, filter: $filter) { - entries { - id - body - replyTo { - id - body - } - repliesCount - replies { - id - body - } - } - } - } - """ - - test "guest user can get replies info", ~m(guest_conn repo community user)a do - body = "test comment" - - {:ok, comment} = - CMS.create_comment(:repo, repo.id, %{community: community.raw, body: body}, user) - - {:ok, reply} = - CMS.reply_comment( - :repo, - comment.id, - %{community: community.raw, body: "reply body"}, - user - ) - - variables = %{thread: "REPO", id: repo.id, filter: %{page: 1, size: 10}} - results = guest_conn |> query_result(@query, variables, "pagedComments") - - found = - results["entries"] |> Enum.filter(&(&1["id"] == to_string(comment.id))) |> List.first() - - found_reply = - results["entries"] |> Enum.filter(&(&1["id"] == to_string(reply.id))) |> List.first() - - assert found["repliesCount"] == 1 - assert found["replies"] |> Enum.any?(&(&1["id"] == to_string(reply.id))) - assert found["replyTo"] == nil - assert found_reply["replyTo"] |> Map.get("id") == to_string(comment.id) - end - end -end diff --git a/test/support/assert_helper.ex b/test/support/assert_helper.ex index 6026bb1c5..e5de3a10b 100644 --- a/test/support/assert_helper.ex +++ b/test/support/assert_helper.ex @@ -194,4 +194,21 @@ defmodule GroupherServer.Test.AssertHelper do # user_conn |> mutation_result(@query, variables, "createRepo", :debug) defp log_debug_info(res, :debug), do: IO.inspect(res, label: "debug") defp log_debug_info(res, _), do: res + + @doc "check id is exsit in list of Map structure" + @spec exist_in?(Map.t(), [Map.t()], Integer.t()) :: boolean + def exist_in?(%{id: id}, list, occur_count \\ 1) when is_list(list) do + list + |> Enum.filter(fn item -> item.id == id end) + |> length + |> Kernel.==(occur_count) + end + + # for embed user situation + def user_exist_in?(%{login: login}, list) when is_list(list) do + list + |> Enum.filter(fn item -> item.login == login end) + |> length + |> Kernel.==(1) + end end