From 45fa51e857d1944d2a3637213197ac5b548063e5 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 10:58:42 +0800 Subject: [PATCH 01/28] refactor(macros): basic table setup --- lib/groupher_server/cms/models/blog.ex | 53 +++++++++++++++++++ lib/groupher_server/cms/models/post.ex | 2 +- .../20210607020645_create_blogs.exs | 33 ++++++++++++ ...607021558_create_communities_join_blog.exs | 12 +++++ ...0210607022840_add_blog_to_article_tags.exs | 9 ++++ .../20210607023900_add_blog_reactions.exs | 33 ++++++++++++ 6 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 lib/groupher_server/cms/models/blog.ex create mode 100644 priv/repo/migrations/20210607020645_create_blogs.exs create mode 100644 priv/repo/migrations/20210607021558_create_communities_join_blog.exs create mode 100644 priv/repo/migrations/20210607022840_add_blog_to_article_tags.exs create mode 100644 priv/repo/migrations/20210607023900_add_blog_reactions.exs diff --git a/lib/groupher_server/cms/models/blog.ex b/lib/groupher_server/cms/models/blog.ex new file mode 100644 index 000000000..0d2646f4e --- /dev/null +++ b/lib/groupher_server/cms/models/blog.ex @@ -0,0 +1,53 @@ +defmodule GroupherServer.CMS.Model.Blog do + @moduledoc false + alias __MODULE__ + + use Ecto.Schema + use Accessible + + import Ecto.Changeset + import GroupherServer.CMS.Helper.Macros + + alias GroupherServer.CMS + alias CMS.Model.Embeds + + @timestamps_opts [type: :utc_datetime_usec] + + @required_fields ~w(title digest length)a + @article_cast_fields general_article_fields(:cast) + @optional_fields ~w(link_addr digest length)a ++ @article_cast_fields + + @type t :: %Blog{} + schema "cms_blogs" do + field(:link_addr, :string) + field(:digest, :string) + field(:length, :integer) + + article_tags_field(:blog) + article_communities_field(:blog) + general_article_fields() + end + + @doc false + def changeset(%Blog{} = blog, attrs) do + blog + |> cast(attrs, @optional_fields ++ @required_fields) + |> validate_required(@required_fields) + |> cast_embed(:meta, required: false, with: &Embeds.ArticleMeta.changeset/2) + |> generl_changeset + end + + @doc false + def update_changeset(%Blog{} = blog, attrs) do + blog + |> cast(attrs, @optional_fields ++ @required_fields) + |> generl_changeset + end + + defp generl_changeset(changeset) do + changeset + |> validate_length(:title, min: 3, max: 50) + |> cast_embed(:emotions, with: &Embeds.ArticleEmotion.changeset/2) + |> validate_length(:link_addr, min: 5, max: 400) + end +end diff --git a/lib/groupher_server/cms/models/post.ex b/lib/groupher_server/cms/models/post.ex index d71f7c826..0b5b15b5d 100644 --- a/lib/groupher_server/cms/models/post.ex +++ b/lib/groupher_server/cms/models/post.ex @@ -17,7 +17,7 @@ defmodule GroupherServer.CMS.Model.Post do @required_fields ~w(title body digest length)a @article_cast_fields general_article_fields(:cast) - @optional_fields ~w(link_addr copy_right link_addr is_question is_solved solution_digest)a ++ + @optional_fields ~w(link_addr copy_right is_question is_solved solution_digest)a ++ @article_cast_fields @type t :: %Post{} diff --git a/priv/repo/migrations/20210607020645_create_blogs.exs b/priv/repo/migrations/20210607020645_create_blogs.exs new file mode 100644 index 000000000..91dfe5e39 --- /dev/null +++ b/priv/repo/migrations/20210607020645_create_blogs.exs @@ -0,0 +1,33 @@ +defmodule GroupherServer.Repo.Migrations.CreateBlogs do + use Ecto.Migration + + def change do + create table(:cms_blogs) do + add(:title, :string) + add(:views, :integer, default: 0) + add(:mark_delete, :boolean, default: false) + add(:meta, :map) + add(:emotions, :map) + add(:original_community_id, references(:communities, on_delete: :delete_all)) + add(:author_id, references(:cms_authors, on_delete: :delete_all), null: false) + + add(:active_at, :utc_datetime) + + # reaction + add(:upvotes_count, :integer, default: 0) + add(:collects_count, :integer, default: 0) + + # comments + add(:article_comments_participators_count, :integer, default: 0) + add(:article_comments_count, :integer, default: 0) + add(:article_comments_participators, :map) + + # domain + add(:digest, :string) + add(:link_addr, :string) + add(:length, :integer) + end + + create(index(:cms_blogs, [:author_id])) + end +end diff --git a/priv/repo/migrations/20210607021558_create_communities_join_blog.exs b/priv/repo/migrations/20210607021558_create_communities_join_blog.exs new file mode 100644 index 000000000..a7ce13404 --- /dev/null +++ b/priv/repo/migrations/20210607021558_create_communities_join_blog.exs @@ -0,0 +1,12 @@ +defmodule GroupherServer.Repo.Migrations.CreateCommunitiesJoinBlog do + use Ecto.Migration + + def change do + create table(:communities_join_blogs) do + add(:community_id, references(:communities, on_delete: :delete_all), null: false) + add(:blog_id, references(:cms_blogs, on_delete: :delete_all), null: false) + end + + create(unique_index(:communities_join_blogs, [:community_id, :blog_id])) + end +end diff --git a/priv/repo/migrations/20210607022840_add_blog_to_article_tags.exs b/priv/repo/migrations/20210607022840_add_blog_to_article_tags.exs new file mode 100644 index 000000000..affb628cb --- /dev/null +++ b/priv/repo/migrations/20210607022840_add_blog_to_article_tags.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.AddBlogToArticleTags do + use Ecto.Migration + + def change do + alter table(:articles_join_tags) do + add(:blog_id, references(:cms_jobs, on_delete: :delete_all)) + end + end +end diff --git a/priv/repo/migrations/20210607023900_add_blog_reactions.exs b/priv/repo/migrations/20210607023900_add_blog_reactions.exs new file mode 100644 index 000000000..95d46a39a --- /dev/null +++ b/priv/repo/migrations/20210607023900_add_blog_reactions.exs @@ -0,0 +1,33 @@ +defmodule GroupherServer.Repo.Migrations.AddBlogReactions do + use Ecto.Migration + + def change do + alter table(:abuse_reports) do + add(:blog_id, references(:cms_blogs, on_delete: :delete_all)) + end + + alter table(:article_collects) do + add(:blog_id, references(:cms_blogs, on_delete: :delete_all)) + end + + alter table(:article_upvotes) do + add(:blog_id, references(:cms_blogs, on_delete: :delete_all)) + end + + alter table(:articles_comments) do + add(:blog_id, references(:cms_blogs, on_delete: :delete_all)) + end + + alter table(:articles_pinned_comments) do + add(:blog_id, references(:cms_blogs, on_delete: :delete_all)) + end + + alter table(:articles_users_emotions) do + add(:blog_id, references(:cms_blogs, on_delete: :delete_all)) + end + + alter table(:pinned_articles) do + add(:blog_id, references(:cms_blogs, on_delete: :delete_all)) + end + end +end From 5c2b5922104c0ccb39d7d69f875d7800a786dd18 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 12:32:41 +0800 Subject: [PATCH 02/28] feat(blog-thread): basic blog tests --- config/config.exs | 5 +- .../schema/cms/cms_types.ex | 19 +++ .../schema/cms/mutations/blog.ex | 62 ++++++++ ...10607042800_missing_timestamp_to_blogs.exs | 9 ++ .../cms/articles/blog_test.exs | 141 ++++++++++++++++++ .../groupher_server/cms/articles/job_test.exs | 4 +- .../cms/articles/repo_test.exs | 7 +- test/support/factory.ex | 22 +++ 8 files changed, 260 insertions(+), 9 deletions(-) create mode 100644 lib/groupher_server_web/schema/cms/mutations/blog.ex create mode 100644 priv/repo/migrations/20210607042800_missing_timestamp_to_blogs.exs create mode 100644 test/groupher_server/cms/articles/blog_test.exs diff --git a/config/config.exs b/config/config.exs index d461123cb..5eedcd262 100644 --- a/config/config.exs +++ b/config/config.exs @@ -62,13 +62,14 @@ config :groupher_server, :customization, config :groupher_server, :article, # NOTE: do not change unless you know what you are doing - threads: [:post, :job, :repo], + threads: [:post, :job, :repo, :blog], # in this period, paged articles will sort front if non-article-author commented # 在此时间段内,一旦有非文章作者的用户评论,该文章就会排到前面 active_period_days: %{ post: 10, job: 10, - repo: 10 + repo: 10, + blog: 10 }, # NOTE: if you want to add/remove emotion, just edit the list below diff --git a/lib/groupher_server_web/schema/cms/cms_types.ex b/lib/groupher_server_web/schema/cms/cms_types.ex index 53b6f05dc..57905285e 100644 --- a/lib/groupher_server_web/schema/cms/cms_types.ex +++ b/lib/groupher_server_web/schema/cms/cms_types.ex @@ -107,6 +107,20 @@ defmodule GroupherServerWeb.Schema.CMS.Types do timestamp_fields(:article) end + object :blog do + interface(:article) + + general_article_fields() + article_comments_fields() + + field(:digest, :string) + field(:length, :integer) + field(:link_addr, :string) + # field(:body, :string) + + timestamp_fields(:article) + end + object :repo do interface(:article) @@ -371,6 +385,11 @@ defmodule GroupherServerWeb.Schema.CMS.Types do pagination_fields() end + object :paged_blogs do + field(:entries, list_of(:blog)) + pagination_fields() + end + object :paged_comments do field(:entries, list_of(:comment)) pagination_fields() diff --git a/lib/groupher_server_web/schema/cms/mutations/blog.ex b/lib/groupher_server_web/schema/cms/mutations/blog.ex new file mode 100644 index 000000000..2df220478 --- /dev/null +++ b/lib/groupher_server_web/schema/cms/mutations/blog.ex @@ -0,0 +1,62 @@ +defmodule GroupherServerWeb.Schema.CMS.Mutations.Blog do + @moduledoc """ + CMS mutations for blog + """ + use Helper.GqlSchemaSuite + import GroupherServerWeb.Schema.Helper.Mutations + + object :cms_blog_mutations do + @desc "create a blog" + field :create_blog, :blog do + arg(:title, non_null(:string)) + arg(:digest, non_null(:string)) + arg(:length, non_null(:integer)) + arg(:community_id, non_null(:id)) + + arg(:link_addr, :string) + + arg(:thread, :thread, default_value: :blog) + arg(:article_tags, list_of(:ids)) + + middleware(M.Authorize, :login) + middleware(M.PublishThrottle) + resolve(&R.CMS.create_article/3) + middleware(M.Statistics.MakeContribute, for: [:user, :community]) + end + + @desc "update a cms/blog" + field :update_blog, :blog do + arg(:id, non_null(:id)) + arg(:title, :string) + arg(:body, :string) + arg(:digest, :string) + arg(:length, :integer) + arg(:copy_right, :string) + arg(:desc, :string) + arg(:link_addr, :string) + + arg(:company, :string) + arg(:company_link, :string) + arg(:article_tags, list_of(:ids)) + + # ... + + middleware(M.Authorize, :login) + middleware(M.PassportLoader, source: :blog) + middleware(M.Passport, claim: "owner;cms->c?->blog.edit") + + resolve(&R.CMS.update_article/3) + end + + ############# + article_upvote_mutation(:blog) + article_pin_mutation(:blog) + article_mark_delete_mutation(:blog) + article_delete_mutation(:blog) + article_emotion_mutation(:blog) + article_report_mutation(:blog) + article_sink_mutation(:blog) + article_lock_comment_mutation(:blog) + ############# + end +end diff --git a/priv/repo/migrations/20210607042800_missing_timestamp_to_blogs.exs b/priv/repo/migrations/20210607042800_missing_timestamp_to_blogs.exs new file mode 100644 index 000000000..e9758448f --- /dev/null +++ b/priv/repo/migrations/20210607042800_missing_timestamp_to_blogs.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.MissingTimestampToBlogs do + use Ecto.Migration + + def change do + alter table(:cms_blogs) do + timestamps() + end + end +end diff --git a/test/groupher_server/cms/articles/blog_test.exs b/test/groupher_server/cms/articles/blog_test.exs new file mode 100644 index 000000000..fe189dc27 --- /dev/null +++ b/test/groupher_server/cms/articles/blog_test.exs @@ -0,0 +1,141 @@ +defmodule GroupherServer.Test.Articles.Blog do + use GroupherServer.TestTools + + alias GroupherServer.CMS + alias CMS.Model.{Blog, Community} + alias Helper.ORM + + @last_year Timex.shift(Timex.beginning_of_year(Timex.now()), days: -3, seconds: -1) + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, community} = db_insert(:community) + + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + + {:ok, ~m(user user2 community blog_attrs)a} + end + + describe "[cms blogs curd]" do + @tag :wip + test "can create a blog with valid attrs", ~m(user community blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, found} = ORM.find(Blog, blog.id) + assert found.id == blog.id + assert found.title == blog.title + end + + @tag :wip + test "created blog should have a acitve_at field, same with inserted_at", + ~m(user community blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + assert blog.active_at == blog.inserted_at + end + + @tag :wip + test "read blog should update views and meta viewed_user_list", + ~m(blog_attrs community user user2)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, _} = CMS.read_article(:blog, blog.id, user) + {:ok, _created} = ORM.find(Blog, blog.id) + + # same user duplicate case + {:ok, _} = CMS.read_article(:blog, blog.id, user) + {:ok, created} = ORM.find(Blog, blog.id) + + assert created.meta.viewed_user_ids |> length == 1 + assert user.id in created.meta.viewed_user_ids + + {:ok, _} = CMS.read_article(:blog, blog.id, user2) + {:ok, created} = ORM.find(Blog, blog.id) + + assert created.meta.viewed_user_ids |> length == 2 + assert user.id in created.meta.viewed_user_ids + assert user2.id in created.meta.viewed_user_ids + end + + test "read blog should contains viewer_has_xxx state", ~m(blog_attrs community user user2)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, blog} = CMS.read_article(:blog, blog.id, user) + + assert not blog.viewer_has_collected + assert not blog.viewer_has_upvoted + assert not blog.viewer_has_reported + + {:ok, blog} = CMS.read_article(:blog, blog.id) + + assert not blog.viewer_has_collected + assert not blog.viewer_has_upvoted + assert not blog.viewer_has_reported + + {:ok, blog} = CMS.read_article(:blog, blog.id, user2) + + assert not blog.viewer_has_collected + assert not blog.viewer_has_upvoted + assert not blog.viewer_has_reported + + {:ok, _} = CMS.upvote_article(:blog, blog.id, user) + {:ok, _} = CMS.collect_article(:blog, blog.id, user) + {:ok, _} = CMS.report_article(:blog, blog.id, "reason", "attr_info", user) + + {:ok, blog} = CMS.read_article(:blog, blog.id, user) + + assert blog.viewer_has_collected + assert blog.viewer_has_upvoted + assert blog.viewer_has_reported + end + + test "create blog with an exsit community fails", ~m(user)a do + invalid_attrs = mock_attrs(:blog, %{community_id: non_exsit_id()}) + ivalid_community = %Community{id: non_exsit_id()} + + assert {:error, _} = CMS.create_article(ivalid_community, :blog, invalid_attrs, user) + end + end + + describe "[cms blog sink/undo_sink]" do + test "if a blog is too old, read blog should update can_undo_sink flag", + ~m(user community blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + assert blog.meta.can_undo_sink + + {:ok, blog_last_year} = db_insert(:blog, %{title: "last year", inserted_at: @last_year}) + {:ok, blog_last_year} = CMS.read_article(:blog, blog_last_year.id) + assert not blog_last_year.meta.can_undo_sink + + {:ok, blog_last_year} = CMS.read_article(:blog, blog_last_year.id, user) + assert not blog_last_year.meta.can_undo_sink + end + + test "can sink a blog", ~m(user community blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + assert not blog.meta.is_sinked + + {:ok, blog} = CMS.sink_article(:blog, blog.id) + assert blog.meta.is_sinked + assert blog.active_at == blog.inserted_at + end + + test "can undo sink blog", ~m(user community blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, blog} = CMS.sink_article(:blog, blog.id) + assert blog.meta.is_sinked + assert blog.meta.last_active_at == blog.active_at + + {:ok, blog} = CMS.undo_sink_article(:blog, blog.id) + assert not blog.meta.is_sinked + assert blog.active_at == blog.meta.last_active_at + end + + test "can not undo sink to old blog", ~m()a do + {:ok, blog_last_year} = db_insert(:blog, %{title: "last year", inserted_at: @last_year}) + + {:error, reason} = CMS.undo_sink_article(:blog, blog_last_year.id) + is_error?(reason, :undo_sink_old_article) + end + end +end diff --git a/test/groupher_server/cms/articles/job_test.exs b/test/groupher_server/cms/articles/job_test.exs index 8d06da2e8..aeac499be 100644 --- a/test/groupher_server/cms/articles/job_test.exs +++ b/test/groupher_server/cms/articles/job_test.exs @@ -2,7 +2,7 @@ defmodule GroupherServer.Test.Articles.Job do use GroupherServer.TestTools alias GroupherServer.CMS - alias CMS.Model.Job + alias CMS.Model.{Job, Community} alias Helper.ORM @last_year Timex.shift(Timex.beginning_of_year(Timex.now()), days: -3, seconds: -1) @@ -18,8 +18,6 @@ defmodule GroupherServer.Test.Articles.Job do end describe "[cms jobs curd]" do - alias CMS.Model.Community - test "can create a job with valid attrs", ~m(user community job_attrs)a do {:ok, job} = CMS.create_article(community, :job, job_attrs, user) diff --git a/test/groupher_server/cms/articles/repo_test.exs b/test/groupher_server/cms/articles/repo_test.exs index 3a807db9d..7d07dc3f8 100644 --- a/test/groupher_server/cms/articles/repo_test.exs +++ b/test/groupher_server/cms/articles/repo_test.exs @@ -1,9 +1,10 @@ defmodule GroupherServer.Test.Articles.Repo do use GroupherServer.TestTools - alias Helper.ORM alias GroupherServer.CMS - alias CMS.Model.Repo + alias CMS.Model.{Author, Community, Repo} + + alias Helper.ORM @last_year Timex.shift(Timex.beginning_of_year(Timex.now()), days: -3, seconds: -1) @@ -19,8 +20,6 @@ defmodule GroupherServer.Test.Articles.Repo do end describe "[cms repo curd]" do - alias CMS.Model.{Author, Community} - test "can create repo with valid attrs", ~m(user community repo_attrs)a do assert {:error, _} = ORM.find_by(Author, user_id: user.id) diff --git a/test/support/factory.ex b/test/support/factory.ex index 6772bb116..842854fb4 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -20,6 +20,7 @@ defmodule GroupherServer.Support.Factory do ArticleTag, Post, Job, + Blog, CommunityWiki, CommunityCheatsheet, Comment @@ -148,6 +149,25 @@ defmodule GroupherServer.Support.Factory do } end + defp mock_meta(:blog) do + body = Faker.Lorem.sentence(%Range{first: 80, last: 120}) + + %{ + meta: @default_article_meta, + title: String.slice(body, 1, 49), + digest: String.slice(body, 1, 150), + length: String.length(body), + author: mock(:author), + views: Enum.random(0..2000), + original_community: mock(:community), + communities: [ + mock(:community) + ], + emotions: @default_emotions, + active_at: Timex.shift(Timex.now(), seconds: +1) + } + end + defp mock_meta(:comment) do body = Faker.Lorem.sentence(%Range{first: 30, last: 80}) @@ -287,6 +307,7 @@ defmodule GroupherServer.Support.Factory do def mock_attrs(:post, attrs), do: mock_meta(:post) |> Map.merge(attrs) def mock_attrs(:repo, attrs), do: mock_meta(:repo) |> Map.merge(attrs) def mock_attrs(:job, attrs), do: mock_meta(:job) |> Map.merge(attrs) + def mock_attrs(:blog, attrs), do: mock_meta(:blog) |> Map.merge(attrs) def mock_attrs(:community, attrs), do: mock_meta(:community) |> Map.merge(attrs) def mock_attrs(:thread, attrs), do: mock_meta(:thread) |> Map.merge(attrs) def mock_attrs(:mention, attrs), do: mock_meta(:mention) |> Map.merge(attrs) @@ -316,6 +337,7 @@ defmodule GroupherServer.Support.Factory do defp mock(:post), do: Post |> struct(mock_meta(:post)) defp mock(:repo), do: CMSRepo |> struct(mock_meta(:repo)) defp mock(:job), do: Job |> struct(mock_meta(:job)) + defp mock(:blog), do: Blog |> struct(mock_meta(:blog)) defp mock(:wiki), do: CommunityWiki |> struct(mock_meta(:wiki)) defp mock(:cheatsheet), do: CommunityCheatsheet |> struct(mock_meta(:cheatsheet)) defp mock(:comment), do: Comment |> struct(mock_meta(:comment)) From a190b8f8b2954fa6a6be87de09054f6c1a37bd99 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 12:41:56 +0800 Subject: [PATCH 03/28] feat(blog-thread): extract paged_macros --- .../schema/Helper/objects.ex | 29 +++++++++++++++++ .../schema/cms/cms_types.ex | 31 +++---------------- 2 files changed, 34 insertions(+), 26 deletions(-) create mode 100644 lib/groupher_server_web/schema/Helper/objects.ex diff --git a/lib/groupher_server_web/schema/Helper/objects.ex b/lib/groupher_server_web/schema/Helper/objects.ex new file mode 100644 index 000000000..d2b6e4e50 --- /dev/null +++ b/lib/groupher_server_web/schema/Helper/objects.ex @@ -0,0 +1,29 @@ +defmodule GroupherServerWeb.Schema.Helper.Objects do + @moduledoc """ + general fields used in schema definition + """ + import Helper.Utils, only: [get_config: 2] + + @article_threads get_config(:article, :threads) + + @doc """ + paged articles helper + + e,g: + object :paged_blogs do + field(:entries, list_of(:blog)) + pagination_fields() + end + """ + defmacro paged_article_objects() do + @article_threads + |> Enum.map( + "e do + object unquote(:"paged_#{&1}s") do + field(:entries, list_of(unquote(&1))) + pagination_fields() + end + end + ) + end +end diff --git a/lib/groupher_server_web/schema/cms/cms_types.ex b/lib/groupher_server_web/schema/cms/cms_types.ex index 57905285e..fc1abcad4 100644 --- a/lib/groupher_server_web/schema/cms/cms_types.ex +++ b/lib/groupher_server_web/schema/cms/cms_types.ex @@ -5,7 +5,10 @@ defmodule GroupherServerWeb.Schema.CMS.Types do use Helper.GqlSchemaSuite import Helper.Utils, only: [get_config: 2] + import GroupherServerWeb.Schema.Helper.Fields + import GroupherServerWeb.Schema.Helper.Objects + import Ecto.Query, warn: false import Absinthe.Resolution.Helpers, only: [dataloader: 2, on_load: 2] @@ -345,6 +348,8 @@ defmodule GroupherServerWeb.Schema.CMS.Types do timestamp_fields() end + paged_article_objects() + object :paged_reports do field(:entries, list_of(:abuse_report)) pagination_fields() @@ -359,37 +364,11 @@ defmodule GroupherServerWeb.Schema.CMS.Types do field(:post, :post, resolve: dataloader(CMS, :post)) end - object :repo_comment do - comments_fields() - field(:repo, :repo, resolve: dataloader(CMS, :repo)) - end - object :paged_categories do field(:entries, list_of(:category)) pagination_fields() end - object :paged_posts do - meta(:cache, max_age: 30) - field(:entries, list_of(:post)) - pagination_fields() - end - - object :paged_repos do - field(:entries, list_of(:repo)) - pagination_fields() - end - - object :paged_jobs do - field(:entries, list_of(:job)) - pagination_fields() - end - - object :paged_blogs do - field(:entries, list_of(:blog)) - pagination_fields() - end - object :paged_comments do field(:entries, list_of(:comment)) pagination_fields() From 4e40c1787d549f1405f6ce693026fb45c82efac1 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 13:05:27 +0800 Subject: [PATCH 04/28] feat(blog-thread): extract article in mock factory --- test/support/factory.ex | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/test/support/factory.ex b/test/support/factory.ex index 842854fb4..397d4cb64 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -6,8 +6,8 @@ defmodule GroupherServer.Support.Factory do for example you can db_insert(:user) to insert user into db """ import Helper.Utils, only: [done: 1] + import GroupherServer.CMS.Helper.Matcher - alias GroupherServer.Repo alias GroupherServer.{Accounts, CMS, Delivery} alias Accounts.Model.User @@ -18,17 +18,13 @@ defmodule GroupherServer.Support.Factory do Thread, CommunityThread, ArticleTag, - Post, - Job, - Blog, CommunityWiki, CommunityCheatsheet, Comment } alias Delivery.Model.{Mention, SysNotification} - - alias CMS.Model.Repo, as: CMSRepo + alias CMS.Model.Repo @default_article_meta CMS.Model.Embeds.ArticleMeta.default_meta() @default_emotions CMS.Model.Embeds.ArticleCommentEmotion.default_emotions() @@ -304,10 +300,7 @@ defmodule GroupherServer.Support.Factory do def mock_attrs(_, attrs \\ %{}) def mock_attrs(:user, attrs), do: mock_meta(:user) |> Map.merge(attrs) def mock_attrs(:author, attrs), do: mock_meta(:author) |> Map.merge(attrs) - def mock_attrs(:post, attrs), do: mock_meta(:post) |> Map.merge(attrs) - def mock_attrs(:repo, attrs), do: mock_meta(:repo) |> Map.merge(attrs) - def mock_attrs(:job, attrs), do: mock_meta(:job) |> Map.merge(attrs) - def mock_attrs(:blog, attrs), do: mock_meta(:blog) |> Map.merge(attrs) + def mock_attrs(:community, attrs), do: mock_meta(:community) |> Map.merge(attrs) def mock_attrs(:thread, attrs), do: mock_meta(:thread) |> Map.merge(attrs) def mock_attrs(:mention, attrs), do: mock_meta(:mention) |> Map.merge(attrs) @@ -325,19 +318,15 @@ defmodule GroupherServer.Support.Factory do def mock_attrs(:sys_notification, attrs), do: mock_meta(:sys_notification) |> Map.merge(attrs) def mock_attrs(:category, attrs), do: mock_meta(:category) |> Map.merge(attrs) def mock_attrs(:github_profile, attrs), do: mock_meta(:github_profile) |> Map.merge(attrs) - def mock_attrs(:bill, attrs), do: mock_meta(:bill) |> Map.merge(attrs) + def mock_attrs(thread, attrs), do: mock_meta(thread) |> Map.merge(attrs) + # NOTICE: avoid Recursive problem # bad example: # mismatch mismatch # | | # this line of code will cause SERIOUS Recursive problem - - defp mock(:post), do: Post |> struct(mock_meta(:post)) - defp mock(:repo), do: CMSRepo |> struct(mock_meta(:repo)) - defp mock(:job), do: Job |> struct(mock_meta(:job)) - defp mock(:blog), do: Blog |> struct(mock_meta(:blog)) defp mock(:wiki), do: CommunityWiki |> struct(mock_meta(:wiki)) defp mock(:cheatsheet), do: CommunityCheatsheet |> struct(mock_meta(:cheatsheet)) defp mock(:comment), do: Comment |> struct(mock_meta(:comment)) @@ -346,6 +335,12 @@ defmodule GroupherServer.Support.Factory do defp mock(:category), do: Category |> struct(mock_meta(:category)) defp mock(:article_tag), do: ArticleTag |> struct(mock_meta(:article_tag)) + defp mock(thread) do + with {:ok, info} <- match(thread) do + info.model |> struct(mock_meta(:thread)) + end + end + defp mock(:sys_notification), do: SysNotification |> struct(mock_meta(:sys_notification)) @@ -365,7 +360,7 @@ defmodule GroupherServer.Support.Factory do # like: views, insert/update ... to test filter-sort,when ... # """ def db_insert(factory_name, attributes \\ []) do - Repo.insert(mock(factory_name, attributes)) + GroupherServer.Repo.insert(mock(factory_name, attributes)) end def db_insert_multi(factory_name, count, delay \\ 0) do From 26cbf7dc2c207c29859bd7d4bf04e51177d3648c Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 13:22:13 +0800 Subject: [PATCH 05/28] feat(blog-thread): fix broken test cause by match order --- test/groupher_server/cms/articles/blog_test.exs | 2 -- .../mutation/cms/comments/post_comment_test.exs | 2 +- test/helper/utils_test.exs | 1 - test/support/factory.ex | 12 ++++++------ 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/test/groupher_server/cms/articles/blog_test.exs b/test/groupher_server/cms/articles/blog_test.exs index fe189dc27..d172016d9 100644 --- a/test/groupher_server/cms/articles/blog_test.exs +++ b/test/groupher_server/cms/articles/blog_test.exs @@ -27,7 +27,6 @@ defmodule GroupherServer.Test.Articles.Blog do assert found.title == blog.title end - @tag :wip test "created blog should have a acitve_at field, same with inserted_at", ~m(user community blog_attrs)a do {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) @@ -35,7 +34,6 @@ defmodule GroupherServer.Test.Articles.Blog do assert blog.active_at == blog.inserted_at end - @tag :wip test "read blog should update views and meta viewed_user_list", ~m(blog_attrs community user user2)a do {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) diff --git a/test/groupher_server_web/mutation/cms/comments/post_comment_test.exs b/test/groupher_server_web/mutation/cms/comments/post_comment_test.exs index c40d226cc..8e9466a29 100644 --- a/test/groupher_server_web/mutation/cms/comments/post_comment_test.exs +++ b/test/groupher_server_web/mutation/cms/comments/post_comment_test.exs @@ -171,7 +171,7 @@ defmodule GroupherServer.Test.Mutation.Comments.PostComment do } } """ - @tag :wip + test "can lock a post's comment", ~m(community post)a do variables = %{id: post.id, communityId: community.id} passport_rules = %{community.raw => %{"post.lock_comment" => true}} diff --git a/test/helper/utils_test.exs b/test/helper/utils_test.exs index 05a9ccc6e..389e5279c 100644 --- a/test/helper/utils_test.exs +++ b/test/helper/utils_test.exs @@ -197,7 +197,6 @@ defmodule GroupherServer.Test.Helper.UtilsTest do end describe "[others]" do - @tag :wip test "module_to_atom should work" do assert :post == Post |> Utils.module_to_atom() assert :post == %Post{} |> Utils.module_to_atom() diff --git a/test/support/factory.ex b/test/support/factory.ex index 397d4cb64..39ccf3e11 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -335,12 +335,6 @@ defmodule GroupherServer.Support.Factory do defp mock(:category), do: Category |> struct(mock_meta(:category)) defp mock(:article_tag), do: ArticleTag |> struct(mock_meta(:article_tag)) - defp mock(thread) do - with {:ok, info} <- match(thread) do - info.model |> struct(mock_meta(:thread)) - end - end - defp mock(:sys_notification), do: SysNotification |> struct(mock_meta(:sys_notification)) @@ -351,6 +345,12 @@ defmodule GroupherServer.Support.Factory do defp mock(:communities_threads), do: CommunityThread |> struct(mock_meta(:communities_threads)) + defp mock(thread) do + with {:ok, info} <- match(thread) do + info.model |> struct(mock_meta(:thread)) + end + end + defp mock(factory_name, attributes) do factory_name |> mock() |> struct(attributes) end From 46a3144dbe144661ebbaf56814801707fb813ddf Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 13:53:34 +0800 Subject: [PATCH 06/28] feat(blog-thread): fix broken test --- test/support/factory.ex | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/support/factory.ex b/test/support/factory.ex index 39ccf3e11..c2ad046ba 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -251,7 +251,6 @@ defmodule GroupherServer.Support.Factory do unique_num = System.unique_integer([:positive, :monotonic]) %{ - # username: "#{Faker.Name.first_name()} #{unique_num}", login: "#{Faker.Person.first_name()}#{unique_num}" |> String.downcase(), nickname: "#{Faker.Person.first_name()}#{unique_num}", bio: Faker.Lorem.Shakespeare.romeo_and_juliet(), @@ -323,9 +322,6 @@ defmodule GroupherServer.Support.Factory do def mock_attrs(thread, attrs), do: mock_meta(thread) |> Map.merge(attrs) # NOTICE: avoid Recursive problem - # bad example: - # mismatch mismatch - # | | # this line of code will cause SERIOUS Recursive problem defp mock(:wiki), do: CommunityWiki |> struct(mock_meta(:wiki)) defp mock(:cheatsheet), do: CommunityCheatsheet |> struct(mock_meta(:cheatsheet)) @@ -347,7 +343,7 @@ defmodule GroupherServer.Support.Factory do defp mock(thread) do with {:ok, info} <- match(thread) do - info.model |> struct(mock_meta(:thread)) + info.model |> struct(mock_meta(thread)) end end From be11756a485539dc48d9e2be9a9606ab9994a461 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 14:12:20 +0800 Subject: [PATCH 07/28] feat(blog-thread): tests for blog --- .../cms/abuse_reports/blog_report_test.exs | 137 ++++ .../cms/article_community/blog_test.exs | 85 +++ .../cms/article_tags/blog_tag_test.exs | 136 ++++ .../cms/articles/blog_pin_test.exs | 54 ++ .../comments/blog_comment_emotions_test.exs | 199 ++++++ .../comments/blog_comment_replies_test.exs | 213 ++++++ .../cms/comments/blog_comment_test.exs | 671 ++++++++++++++++++ .../cms/community/community_test.exs | 5 +- .../cms/emotions/blog_emotions_test.exs | 177 +++++ .../cms/upvotes/blog_upvote_test.exs | 83 +++ 10 files changed, 1759 insertions(+), 1 deletion(-) create mode 100644 test/groupher_server/cms/abuse_reports/blog_report_test.exs create mode 100644 test/groupher_server/cms/article_community/blog_test.exs create mode 100644 test/groupher_server/cms/article_tags/blog_tag_test.exs create mode 100644 test/groupher_server/cms/articles/blog_pin_test.exs create mode 100644 test/groupher_server/cms/comments/blog_comment_emotions_test.exs create mode 100644 test/groupher_server/cms/comments/blog_comment_replies_test.exs create mode 100644 test/groupher_server/cms/comments/blog_comment_test.exs create mode 100644 test/groupher_server/cms/emotions/blog_emotions_test.exs create mode 100644 test/groupher_server/cms/upvotes/blog_upvote_test.exs diff --git a/test/groupher_server/cms/abuse_reports/blog_report_test.exs b/test/groupher_server/cms/abuse_reports/blog_report_test.exs new file mode 100644 index 000000000..5d4cbe657 --- /dev/null +++ b/test/groupher_server/cms/abuse_reports/blog_report_test.exs @@ -0,0 +1,137 @@ +defmodule GroupherServer.Test.CMS.AbuseReports.BlogReport do + @moduledoc false + + use GroupherServer.TestTools + + alias Helper.ORM + alias GroupherServer.CMS + alias CMS.Model.Blog + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + + {:ok, community} = db_insert(:community) + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + + {:ok, ~m(user user2 community blog_attrs)a} + end + + describe "[article blog report/unreport]" do + test "list article reports should work", ~m(community user user2 blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, _report} = CMS.report_article(:blog, blog.id, "reason", "attr_info", user) + {:ok, _report} = CMS.report_article(:blog, blog.id, "reason", "attr_info", user2) + + filter = %{content_type: :blog, content_id: blog.id, page: 1, size: 20} + {:ok, all_reports} = CMS.paged_reports(filter) + + report = all_reports.entries |> List.first() + assert report.article.id == blog.id + assert report.article.thread == "JOB" + end + + test "report a blog should have a abuse report record", ~m(community user blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, _report} = CMS.report_article(:blog, blog.id, "reason", "attr_info", user) + + filter = %{content_type: :blog, content_id: blog.id, page: 1, size: 20} + {:ok, all_reports} = CMS.paged_reports(filter) + + report = List.first(all_reports.entries) + report_cases = report.report_cases + + assert report.article.id == blog.id + assert all_reports.total_count == 1 + assert report.report_cases_count == 1 + assert List.first(report_cases).user.login == user.login + + {:ok, blog} = ORM.find(Blog, blog.id) + assert blog.meta.reported_count == 1 + assert user.id in blog.meta.reported_user_ids + end + + test "can undo a report", ~m(community user blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, _report} = CMS.report_article(:blog, blog.id, "reason", "attr_info", user) + {:ok, _report} = CMS.undo_report_article(:blog, blog.id, user) + + filter = %{content_type: :blog, content_id: blog.id, page: 1, size: 20} + {:ok, all_reports} = CMS.paged_reports(filter) + assert all_reports.total_count == 0 + + {:ok, blog} = ORM.find(Blog, blog.id) + assert user.id not in blog.meta.reported_user_ids + end + + test "can undo a existed report", ~m(community user user2 blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, _report} = CMS.report_article(:blog, blog.id, "reason", "attr_info", user) + {:ok, _report} = CMS.report_article(:blog, blog.id, "reason", "attr_info", user2) + {:ok, _report} = CMS.undo_report_article(:blog, blog.id, user) + + filter = %{content_type: :blog, content_id: blog.id, page: 1, size: 20} + {:ok, all_reports} = CMS.paged_reports(filter) + assert all_reports.total_count == 1 + + {:ok, blog} = ORM.find(Blog, blog.id) + + assert user2.id in blog.meta.reported_user_ids + assert user.id not in blog.meta.reported_user_ids + end + + test "can undo a report with other user report it too", + ~m(community user user2 blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, _report} = CMS.report_article(:blog, blog.id, "reason", "attr_info", user) + {:ok, _report} = CMS.report_article(:blog, blog.id, "reason", "attr_info", user2) + + filter = %{content_type: :blog, content_id: blog.id, page: 1, size: 20} + {:ok, all_reports} = CMS.paged_reports(filter) + assert all_reports.total_count == 1 + + report = all_reports.entries |> List.first() + assert report.report_cases |> length == 2 + assert Enum.any?(report.report_cases, &(&1.user.login == user.login)) + assert Enum.any?(report.report_cases, &(&1.user.login == user2.login)) + + {:ok, _report} = CMS.undo_report_article(:blog, blog.id, user) + + filter = %{content_type: :blog, content_id: blog.id, page: 1, size: 20} + {:ok, all_reports} = CMS.paged_reports(filter) + assert all_reports.total_count == 1 + + report = all_reports.entries |> List.first() + assert report.report_cases |> length == 1 + assert Enum.any?(report.report_cases, &(&1.user.login == user2.login)) + end + + test "different user report a comment should have same report with different report cases", + ~m(community user user2 blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, _report} = CMS.report_article(:blog, blog.id, "reason", "attr_info", user) + {:ok, _report} = CMS.report_article(:blog, blog.id, "reason2", "attr_info 2", user2) + + filter = %{content_type: :blog, content_id: blog.id, page: 1, size: 20} + {:ok, all_reports} = CMS.paged_reports(filter) + + 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 + + test "same user can not report a comment twice", ~m(community blog_attrs user)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, _report} = CMS.report_article(:blog, blog.id, "reason", "attr_info", user) + assert {:error, _report} = CMS.report_article(:blog, blog.id, "reason", "attr_info", user) + end + end +end diff --git a/test/groupher_server/cms/article_community/blog_test.exs b/test/groupher_server/cms/article_community/blog_test.exs new file mode 100644 index 000000000..f1c9c7d77 --- /dev/null +++ b/test/groupher_server/cms/article_community/blog_test.exs @@ -0,0 +1,85 @@ +defmodule GroupherServer.Test.CMS.ArticleCommunity.Blog do + use GroupherServer.TestTools + + alias Helper.ORM + alias GroupherServer.CMS + alias CMS.Model.Blog + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, blog} = db_insert(:blog) + {:ok, community} = db_insert(:community) + {:ok, community2} = db_insert(:community) + {:ok, community3} = db_insert(:community) + + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + + {:ok, ~m(user user2 community community2 community3 blog blog_attrs)a} + end + + describe "[article mirror/move]" do + test "created blog has origial community info", ~m(user community blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, blog} = ORM.find(Blog, blog.id, preload: :original_community) + + assert blog.original_community_id == community.id + end + + test "blog can be move to other community", ~m(user community community2 blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + assert blog.original_community_id == community.id + + {:ok, _} = CMS.move_article(:blog, blog.id, community2.id) + {:ok, blog} = ORM.find(Blog, blog.id, preload: [:original_community, :communities]) + + assert blog.original_community.id == community2.id + assert not is_nil(Enum.find(blog.communities, &(&1.id == community2.id))) + end + + test "blog can be mirror to other community", ~m(user community community2 blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, blog} = ORM.find(Blog, blog.id, preload: :communities) + assert blog.communities |> length == 1 + + assert not is_nil(Enum.find(blog.communities, &(&1.id == community.id))) + + {:ok, _} = CMS.mirror_article(:blog, blog.id, community2.id) + + {:ok, blog} = ORM.find(Blog, blog.id, preload: :communities) + assert blog.communities |> length == 2 + assert not is_nil(Enum.find(blog.communities, &(&1.id == community.id))) + assert not is_nil(Enum.find(blog.communities, &(&1.id == community2.id))) + end + + test "blog can be unmirror from community", + ~m(user community community2 community3 blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, _} = CMS.mirror_article(:blog, blog.id, community2.id) + {:ok, _} = CMS.mirror_article(:blog, blog.id, community3.id) + + {:ok, blog} = ORM.find(Blog, blog.id, preload: :communities) + assert blog.communities |> length == 3 + + {:ok, _} = CMS.unmirror_article(:blog, blog.id, community3.id) + {:ok, blog} = ORM.find(Blog, blog.id, preload: :communities) + assert blog.communities |> length == 2 + + assert is_nil(Enum.find(blog.communities, &(&1.id == community3.id))) + end + + test "blog can not unmirror from original community", + ~m(user community community2 community3 blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, _} = CMS.mirror_article(:blog, blog.id, community2.id) + {:ok, _} = CMS.mirror_article(:blog, blog.id, community3.id) + + {:ok, blog} = ORM.find(Blog, blog.id, preload: :communities) + assert blog.communities |> length == 3 + + {:error, reason} = CMS.unmirror_article(:blog, blog.id, community.id) + assert reason |> is_error?(:mirror_article) + end + end +end diff --git a/test/groupher_server/cms/article_tags/blog_tag_test.exs b/test/groupher_server/cms/article_tags/blog_tag_test.exs new file mode 100644 index 000000000..c2da1dba8 --- /dev/null +++ b/test/groupher_server/cms/article_tags/blog_tag_test.exs @@ -0,0 +1,136 @@ +defmodule GroupherServer.Test.CMS.ArticleTag.BlogTag do + use GroupherServer.TestTools + + alias GroupherServer.CMS + alias CMS.Model.{Community, ArticleTag, Blog} + alias Helper.{ORM} + + setup do + {:ok, user} = db_insert(:user) + {:ok, blog} = db_insert(:blog) + {:ok, community} = db_insert(:community) + article_tag_attrs = mock_attrs(:article_tag) + article_tag_attrs2 = mock_attrs(:article_tag) + + post_attrs = mock_attrs(:blog) + + {:ok, ~m(user community blog post_attrs article_tag_attrs article_tag_attrs2)a} + end + + describe "[blog tag CURD]" do + test "create article tag with valid data", ~m(community article_tag_attrs user)a do + {:ok, article_tag} = CMS.create_article_tag(community, :blog, article_tag_attrs, user) + assert article_tag.title == article_tag_attrs.title + assert article_tag.group == article_tag_attrs.group + end + + test "can update an article tag", ~m(community article_tag_attrs user)a do + {:ok, article_tag} = CMS.create_article_tag(community, :blog, article_tag_attrs, user) + + new_attrs = article_tag_attrs |> Map.merge(%{title: "new title"}) + + {:ok, article_tag} = CMS.update_article_tag(article_tag.id, new_attrs) + assert article_tag.title == "new title" + end + + test "create article tag with non-exsit community fails", ~m(article_tag_attrs user)a do + assert {:error, _} = + CMS.create_article_tag( + %Community{id: non_exsit_id()}, + :blog, + article_tag_attrs, + user + ) + end + + test "tag can be deleted", ~m(community article_tag_attrs user)a do + {:ok, article_tag} = CMS.create_article_tag(community, :blog, article_tag_attrs, user) + {:ok, article_tag} = ORM.find(ArticleTag, article_tag.id) + + {:ok, _} = CMS.delete_article_tag(article_tag.id) + + assert {:error, _} = ORM.find(ArticleTag, article_tag.id) + end + + test "assoc tag should be delete after tag deleted", + ~m(community blog article_tag_attrs article_tag_attrs2 user)a do + {:ok, article_tag} = CMS.create_article_tag(community, :blog, article_tag_attrs, user) + {:ok, article_tag2} = CMS.create_article_tag(community, :blog, article_tag_attrs2, user) + + {:ok, blog} = CMS.set_article_tag(:blog, blog.id, article_tag.id) + {:ok, blog} = CMS.set_article_tag(:blog, blog.id, article_tag2.id) + + {:ok, blog} = ORM.find(Blog, blog.id, preload: :article_tags) + assert exist_in?(article_tag, blog.article_tags) + assert exist_in?(article_tag2, blog.article_tags) + + {:ok, _} = CMS.delete_article_tag(article_tag.id) + + {:ok, blog} = ORM.find(Blog, blog.id, preload: :article_tags) + assert not exist_in?(article_tag, blog.article_tags) + assert exist_in?(article_tag2, blog.article_tags) + + {:ok, _} = CMS.delete_article_tag(article_tag2.id) + + {:ok, blog} = ORM.find(Blog, blog.id, preload: :article_tags) + assert not exist_in?(article_tag, blog.article_tags) + assert not exist_in?(article_tag2, blog.article_tags) + end + end + + describe "[create/update blog with tags]" do + test "can create blog with exsited article tags", + ~m(community user post_attrs article_tag_attrs article_tag_attrs2)a do + {:ok, article_tag} = CMS.create_article_tag(community, :blog, article_tag_attrs, user) + {:ok, article_tag2} = CMS.create_article_tag(community, :blog, article_tag_attrs2, user) + + post_with_tags = + Map.merge(post_attrs, %{article_tags: [%{id: article_tag.id}, %{id: article_tag2.id}]}) + + {:ok, created} = CMS.create_article(community, :blog, post_with_tags, user) + {:ok, blog} = ORM.find(Blog, created.id, preload: :article_tags) + + assert exist_in?(article_tag, blog.article_tags) + assert exist_in?(article_tag2, blog.article_tags) + end + + test "can not create blog with other community's article tags", + ~m(community user post_attrs article_tag_attrs article_tag_attrs2)a do + {:ok, community2} = db_insert(:community) + {:ok, article_tag} = CMS.create_article_tag(community, :blog, article_tag_attrs, user) + {:ok, article_tag2} = CMS.create_article_tag(community2, :blog, article_tag_attrs2, user) + + post_with_tags = + Map.merge(post_attrs, %{article_tags: [%{id: article_tag.id}, %{id: article_tag2.id}]}) + + {:error, reason} = CMS.create_article(community, :blog, post_with_tags, user) + is_error?(reason, :invalid_domain_tag) + end + end + + describe "[blog tag set /unset]" do + test "can set a tag ", ~m(community blog article_tag_attrs article_tag_attrs2 user)a do + {:ok, article_tag} = CMS.create_article_tag(community, :blog, article_tag_attrs, user) + {:ok, article_tag2} = CMS.create_article_tag(community, :blog, article_tag_attrs2, user) + + {:ok, blog} = CMS.set_article_tag(:blog, blog.id, article_tag.id) + assert blog.article_tags |> length == 1 + assert exist_in?(article_tag, blog.article_tags) + + {:ok, blog} = CMS.set_article_tag(:blog, blog.id, article_tag2.id) + assert blog.article_tags |> length == 2 + assert exist_in?(article_tag, blog.article_tags) + assert exist_in?(article_tag2, blog.article_tags) + + {:ok, blog} = CMS.unset_article_tag(:blog, blog.id, article_tag.id) + assert blog.article_tags |> length == 1 + assert not exist_in?(article_tag, blog.article_tags) + assert exist_in?(article_tag2, blog.article_tags) + + {:ok, blog} = CMS.unset_article_tag(:blog, blog.id, article_tag2.id) + assert blog.article_tags |> length == 0 + assert not exist_in?(article_tag, blog.article_tags) + assert not exist_in?(article_tag2, blog.article_tags) + end + end +end diff --git a/test/groupher_server/cms/articles/blog_pin_test.exs b/test/groupher_server/cms/articles/blog_pin_test.exs new file mode 100644 index 000000000..9b6a4a39f --- /dev/null +++ b/test/groupher_server/cms/articles/blog_pin_test.exs @@ -0,0 +1,54 @@ +defmodule GroupherServer.Test.CMS.Artilces.BlogPin do + @moduledoc false + + use GroupherServer.TestTools + + alias Helper.ORM + alias GroupherServer.CMS + + alias CMS.Model.{Community, PinnedArticle} + + @max_pinned_article_count_per_thread Community.max_pinned_article_count_per_thread() + + setup do + {:ok, user} = db_insert(:user) + {:ok, community} = db_insert(:community) + + {:ok, blog} = CMS.create_article(community, :blog, mock_attrs(:blog), user) + + {:ok, ~m(user community blog)a} + end + + describe "[cms blog pin]" do + test "can pin a blog", ~m(community blog)a do + {:ok, _} = CMS.pin_article(:blog, blog.id, community.id) + {:ok, pind_article} = ORM.find_by(PinnedArticle, %{blog_id: blog.id}) + + assert pind_article.blog_id == blog.id + end + + test "one community & thread can only pin certern count of blog", ~m(community user)a do + Enum.reduce(1..@max_pinned_article_count_per_thread, [], fn _, acc -> + {:ok, new_blog} = CMS.create_article(community, :blog, mock_attrs(:blog), user) + {:ok, _} = CMS.pin_article(:blog, new_blog.id, community.id) + acc + end) + + {:ok, new_blog} = CMS.create_article(community, :blog, mock_attrs(:blog), user) + {:error, reason} = CMS.pin_article(:blog, new_blog.id, community.id) + assert reason |> Keyword.get(:code) == ecode(:too_much_pinned_article) + end + + test "can not pin a non-exsit blog", ~m(community)a do + assert {:error, _} = CMS.pin_article(:blog, 8848, community.id) + end + + test "can undo pin to a blog", ~m(community blog)a do + {:ok, _} = CMS.pin_article(:blog, blog.id, community.id) + + assert {:ok, unpinned} = CMS.undo_pin_article(:blog, blog.id, community.id) + + assert {:error, _} = ORM.find_by(PinnedArticle, %{blog_id: blog.id}) + end + end +end diff --git a/test/groupher_server/cms/comments/blog_comment_emotions_test.exs b/test/groupher_server/cms/comments/blog_comment_emotions_test.exs new file mode 100644 index 000000000..2e2771c84 --- /dev/null +++ b/test/groupher_server/cms/comments/blog_comment_emotions_test.exs @@ -0,0 +1,199 @@ +defmodule GroupherServer.Test.CMS.Comments.BlogCommentEmotions do + @moduledoc false + + use GroupherServer.TestTools + + alias Helper.ORM + alias GroupherServer.CMS + + alias CMS.Model.{ArticleComment, Embeds, ArticleCommentUserEmotion} + + @default_emotions Embeds.ArticleCommentEmotion.default_emotions() + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, user3} = db_insert(:user) + + {:ok, blog} = db_insert(:blog) + + {:ok, ~m(user user2 user3 blog)a} + end + + describe "[emotion in paged article comment]" do + test "login user should got viewer has emotioned status", ~m(blog 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(:blog, blog.id, "commment", user) + acc ++ [comment] + end) + + first_comment = List.first(all_comment) + + {:ok, _} = CMS.emotion_to_comment(first_comment.id, :downvote, user) + {:ok, _} = CMS.emotion_to_comment(first_comment.id, :beer, user) + {:ok, _} = CMS.emotion_to_comment(first_comment.id, :popcorn, user) + + {:ok, paged_comments} = + CMS.paged_article_comments( + :blog, + blog.id, + %{page: page_number, size: page_size}, + :replies, + user + ) + + target = Enum.find(paged_comments.entries, &(&1.id == first_comment.id)) + + 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 + + assert target.emotions.popcorn_count == 1 + assert user_exist_in?(user, target.emotions.latest_popcorn_users) + assert target.emotions.viewer_has_popcorned + end + end + + describe "[basic article comment emotion]" do + test "comment has default emotions after created", ~m(blog user)a do + parent_content = "parent comment" + + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.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 + + test "can make emotion to comment", ~m(blog user user2)a do + parent_content = "parent comment" + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.id, parent_content, user) + + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :downvote, user) + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :downvote, user2) + + {:ok, %{emotions: emotions}} = ORM.find(ArticleComment, parent_comment.id) + + assert emotions.downvote_count == 2 + assert user_exist_in?(user, emotions.latest_downvote_users) + assert user_exist_in?(user2, emotions.latest_downvote_users) + end + + test "can undo emotion to comment", ~m(blog user user2)a do + parent_content = "parent comment" + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.id, parent_content, user) + + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :downvote, user) + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :downvote, user2) + + {:ok, %{emotions: emotions}} = ORM.find(ArticleComment, parent_comment.id) + + assert emotions.downvote_count == 2 + assert user_exist_in?(user, emotions.latest_downvote_users) + assert user_exist_in?(user2, emotions.latest_downvote_users) + + {:ok, _} = CMS.undo_emotion_to_comment(parent_comment.id, :downvote, user) + {:ok, _} = CMS.undo_emotion_to_comment(parent_comment.id, :downvote, user2) + + {:ok, %{emotions: emotions}} = ORM.find(ArticleComment, parent_comment.id) + assert emotions.downvote_count == 0 + assert not user_exist_in?(user, emotions.latest_downvote_users) + assert not user_exist_in?(user2, emotions.latest_downvote_users) + end + + test "same user make same emotion to same comment.", ~m(blog user)a do + parent_content = "parent comment" + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.id, parent_content, user) + + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :downvote, user) + {:ok, _} = CMS.emotion_to_comment(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 + + test "same user same emotion to same comment only have one user_emotion record", + ~m(blog user)a do + parent_content = "parent comment" + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.id, parent_content, user) + + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :downvote, user) + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :heart, user) + + {:ok, parent_comment} = ORM.find(ArticleComment, parent_comment.id) + + {:ok, records} = ORM.find_all(ArticleCommentUserEmotion, %{page: 1, size: 10}) + assert records.total_count == 1 + + {:ok, record} = + ORM.find_by(ArticleCommentUserEmotion, %{ + article_comment_id: parent_comment.id, + user_id: user.id + }) + + assert record.downvote + assert record.heart + end + + test "different user can make same emotions on same comment", ~m(blog user user2 user3)a do + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.id, "parent comment", user) + + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :beer, user) + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :beer, user2) + {:ok, _} = CMS.emotion_to_comment(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 + + test "same user can make differcent emotions on same comment", ~m(blog user)a do + parent_content = "parent comment" + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.id, parent_content, user) + + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :downvote, user) + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :downvote, user) + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :beer, user) + {:ok, _} = CMS.emotion_to_comment(parent_comment.id, :heart, user) + {:ok, _} = CMS.emotion_to_comment(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/comments/blog_comment_replies_test.exs b/test/groupher_server/cms/comments/blog_comment_replies_test.exs new file mode 100644 index 000000000..84a0299c4 --- /dev/null +++ b/test/groupher_server/cms/comments/blog_comment_replies_test.exs @@ -0,0 +1,213 @@ +defmodule GroupherServer.Test.CMS.Comments.BlogCommentReplies do + @moduledoc false + + use GroupherServer.TestTools + + alias Helper.ORM + alias GroupherServer.CMS + + alias CMS.Model.{ArticleComment, Blog} + + @max_parent_replies_count ArticleComment.max_parent_replies_count() + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, blog} = db_insert(:blog) + + {:ok, ~m(user user2 blog)a} + end + + describe "[basic article comment replies]" do + test "exsit comment can be reply", ~m(blog user user2)a do + parent_content = "parent comment" + reply_content = "reply comment" + + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.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 + + test "deleted comment can not be reply", ~m(blog user user2)a do + parent_content = "parent comment" + reply_content = "reply comment" + + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.id, parent_content, user) + {:ok, _} = CMS.delete_article_comment(parent_comment) + + {:error, _} = CMS.reply_article_comment(parent_comment.id, reply_content, user2) + end + + test "multi reply should belong to one parent comment", ~m(blog 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(:blog, blog.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 + + test "reply to reply inside a comment should belong same parent comment", + ~m(blog user user2)a do + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.id, "parent comment", user) + + {:ok, replyed_comment_1} = CMS.reply_article_comment(parent_comment.id, "reply 1", user2) + {:ok, replyed_comment_2} = CMS.reply_article_comment(replyed_comment_1.id, "reply 2", user2) + {:ok, replyed_comment_3} = CMS.reply_article_comment(replyed_comment_2.id, "reply 3", user) + + {:ok, parent_comment} = ORM.find(ArticleComment, parent_comment.id) + + # IO.inspect(parent_comment.replies, label: "parent_comment.replies") + + assert exist_in?(replyed_comment_1, parent_comment.replies) + assert exist_in?(replyed_comment_2, parent_comment.replies) + assert exist_in?(replyed_comment_3, 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) + {:ok, replyed_comment_3} = ORM.find(ArticleComment, replyed_comment_3.id) + + assert replyed_comment_1.reply_to_id == parent_comment.id + assert replyed_comment_2.reply_to_id == replyed_comment_1.id + assert replyed_comment_3.reply_to_id == replyed_comment_2.id + end + + test "reply to reply inside a comment should have is_reply_to_others flag in meta", + ~m(blog user user2)a do + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.id, "parent comment", user) + + {:ok, replyed_comment_1} = CMS.reply_article_comment(parent_comment.id, "reply 1", user2) + {:ok, replyed_comment_2} = CMS.reply_article_comment(replyed_comment_1.id, "reply 2", user2) + {:ok, replyed_comment_3} = CMS.reply_article_comment(replyed_comment_2.id, "reply 3", user) + + {:ok, _parent_comment} = ORM.find(ArticleComment, parent_comment.id) + + {:ok, replyed_comment_1} = ORM.find(ArticleComment, replyed_comment_1.id) + {:ok, replyed_comment_2} = ORM.find(ArticleComment, replyed_comment_2.id) + {:ok, replyed_comment_3} = ORM.find(ArticleComment, replyed_comment_3.id) + + assert not replyed_comment_1.meta.is_reply_to_others + assert replyed_comment_2.meta.is_reply_to_others + assert replyed_comment_3.meta.is_reply_to_others + end + + test "comment replies only contains @max_parent_replies_count replies", ~m(blog user)a do + total_reply_count = @max_parent_replies_count + 1 + + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.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 + + test "replyed user should appear in article comment participators", ~m(blog user user2)a do + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.id, "parent_conent", user) + {:ok, _} = CMS.reply_article_comment(parent_comment.id, "reply_content", user2) + + {:ok, article} = ORM.find(Blog, blog.id) + + assert exist_in?(user, article.article_comments_participators) + assert exist_in?(user2, article.article_comments_participators) + end + + test "replies count should inc by 1 after got replyed", ~m(blog user user2)a do + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.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 + test "can get paged replies of a parent comment", ~m(blog user)a do + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.id, "parent_conent", user) + {:ok, paged_replies} = CMS.paged_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.paged_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 + + test "can get reply_to info of a parent comment", ~m(blog user)a do + page_number = 1 + page_size = 10 + + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.id, "parent_conent", user) + + {:ok, reply_comment} = CMS.reply_article_comment(parent_comment.id, "reply_content_1", user) + + {:ok, reply_comment2} = + CMS.reply_article_comment(parent_comment.id, "reply_content_2", user) + + {:ok, paged_comments} = + CMS.paged_article_comments( + :blog, + blog.id, + %{page: page_number, size: page_size}, + :timeline + ) + + reply_comment = Enum.find(paged_comments.entries, &(&1.id == reply_comment.id)) + + assert reply_comment.reply_to.id == parent_comment.id + assert reply_comment.reply_to.body_html == parent_comment.body_html + assert reply_comment.reply_to.author.id == parent_comment.author_id + + reply_comment2 = Enum.find(paged_comments.entries, &(&1.id == reply_comment2.id)) + + assert reply_comment2.reply_to.id == parent_comment.id + assert reply_comment2.reply_to.body_html == parent_comment.body_html + assert reply_comment2.reply_to.author.id == parent_comment.author_id + end + end +end diff --git a/test/groupher_server/cms/comments/blog_comment_test.exs b/test/groupher_server/cms/comments/blog_comment_test.exs new file mode 100644 index 000000000..1a8f095b9 --- /dev/null +++ b/test/groupher_server/cms/comments/blog_comment_test.exs @@ -0,0 +1,671 @@ +defmodule GroupherServer.Test.CMS.Comments.BlogComment do + @moduledoc false + + use GroupherServer.TestTools + import Helper.Utils, only: [get_config: 2] + + alias Helper.ORM + alias GroupherServer.{Accounts, CMS} + alias Accounts.Model.User + alias CMS.Model.{ArticleComment, ArticlePinnedComment, Embeds, Blog} + + @active_period get_config(:article, :active_period_days) + + @delete_hint ArticleComment.delete_hint() + @report_threshold_for_fold ArticleComment.report_threshold_for_fold() + @default_comment_meta Embeds.ArticleCommentMeta.default_meta() + @pinned_comment_limit ArticleComment.pinned_comment_limit() + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, blog} = db_insert(:blog) + {:ok, community} = db_insert(:community) + + {:ok, ~m(community user user2 blog)a} + end + + describe "[basic article comment]" do + test "blog are supported by article comment.", ~m(user blog)a do + {:ok, blog_comment_1} = CMS.create_article_comment(:blog, blog.id, "blog_comment 1", user) + {:ok, blog_comment_2} = CMS.create_article_comment(:blog, blog.id, "blog_comment 2", user) + + {:ok, blog} = ORM.find(Blog, blog.id, preload: :article_comments) + + assert exist_in?(blog_comment_1, blog.article_comments) + assert exist_in?(blog_comment_2, blog.article_comments) + end + + test "comment should have default meta after create", ~m(user blog)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "blog comment", user) + assert comment.meta |> Map.from_struct() |> Map.delete(:id) == @default_comment_meta + end + + test "create comment should update active timestamp of blog", ~m(user blog)a do + Process.sleep(1000) + {:ok, _comment} = CMS.create_article_comment(:blog, blog.id, "blog comment", user) + {:ok, blog} = ORM.find(Blog, blog.id, preload: :article_comments) + + assert not is_nil(blog.active_at) + assert blog.active_at > blog.inserted_at + end + + test "blog author create comment will not update active timestamp", ~m(community user)a do + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, blog} = ORM.find(Blog, blog.id, preload: [author: :user]) + + Process.sleep(1000) + + {:ok, _comment} = + CMS.create_article_comment(:blog, blog.id, "blog comment", blog.author.user) + + {:ok, blog} = ORM.find(Blog, blog.id, preload: :article_comments) + + assert not is_nil(blog.active_at) + assert blog.active_at == blog.inserted_at + end + + test "old blog will not update active after comment created", ~m(user)a do + active_period_days = Map.get(@active_period, :blog) + + inserted_at = + Timex.shift(Timex.now(), days: -(active_period_days - 1)) |> Timex.to_datetime() + + {:ok, blog} = db_insert(:blog, %{inserted_at: inserted_at}) + Process.sleep(1000) + {:ok, _comment} = CMS.create_article_comment(:blog, blog.id, "blog comment", user) + {:ok, blog} = ORM.find(Blog, blog.id) + + assert blog.active_at |> DateTime.to_date() == DateTime.utc_now() |> DateTime.to_date() + + ##### + inserted_at = + Timex.shift(Timex.now(), days: -(active_period_days + 1)) |> Timex.to_datetime() + + {:ok, blog} = db_insert(:blog, %{inserted_at: inserted_at}) + Process.sleep(3000) + {:ok, _comment} = CMS.create_article_comment(:blog, blog.id, "blog comment", user) + {:ok, blog} = ORM.find(Blog, blog.id) + + assert blog.active_at |> DateTime.to_unix() !== DateTime.utc_now() |> DateTime.to_unix() + end + + test "comment can be updated", ~m(blog user)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "blog comment", user) + + {:ok, updated_comment} = CMS.update_article_comment(comment, "updated content") + + assert updated_comment.body_html == "updated content" + end + end + + describe "[article comment floor]" do + test "comment will have a floor number after created", ~m(user blog)a do + {:ok, blog_comment} = CMS.create_article_comment(:blog, blog.id, "comment", user) + {:ok, blog_comment2} = CMS.create_article_comment(:blog, blog.id, "comment2", user) + + {:ok, blog_comment} = ORM.find(ArticleComment, blog_comment.id) + {:ok, blog_comment2} = ORM.find(ArticleComment, blog_comment2.id) + + assert blog_comment.floor == 1 + assert blog_comment2.floor == 2 + end + end + + describe "[article comment participator for blog]" do + test "blog will have participator after comment created", ~m(user blog)a do + blog_comment_1 = "blog_comment 1" + + {:ok, _} = CMS.create_article_comment(:blog, blog.id, blog_comment_1, user) + + {:ok, blog} = ORM.find(Blog, blog.id) + + participator = List.first(blog.article_comments_participators) + assert participator.id == user.id + end + + test "psot participator will not contains same user", ~m(user blog)a do + blog_comment_1 = "blog_comment 1" + + {:ok, _} = CMS.create_article_comment(:blog, blog.id, blog_comment_1, user) + {:ok, _} = CMS.create_article_comment(:blog, blog.id, blog_comment_1, user) + + {:ok, blog} = ORM.find(Blog, blog.id) + + assert 1 == length(blog.article_comments_participators) + end + + test "recent comment user should appear at first of the psot participators", + ~m(user user2 blog)a do + blog_comment_1 = "blog_comment 1" + + {:ok, _} = CMS.create_article_comment(:blog, blog.id, blog_comment_1, user) + {:ok, _} = CMS.create_article_comment(:blog, blog.id, blog_comment_1, user2) + + {:ok, blog} = ORM.find(Blog, blog.id) + + participator = List.first(blog.article_comments_participators) + + assert participator.id == user2.id + end + end + + describe "[article comment upvotes]" do + test "user can upvote a blog comment", ~m(user blog)a do + comment = "blog_comment" + {:ok, comment} = CMS.create_article_comment(:blog, blog.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 + + test "article author upvote blog comment will have flag", ~m(blog user)a do + comment = "blog_comment" + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, comment, user) + {:ok, author_user} = ORM.find(User, blog.author.user.id) + + CMS.upvote_article_comment(comment.id, author_user) + + {:ok, comment} = ORM.find(ArticleComment, comment.id, preload: :upvotes) + assert comment.meta.is_article_author_upvoted + end + + test "user upvote blog comment will add id to upvoted_user_ids", ~m(blog user)a do + comment = "blog_comment" + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, comment, user) + {:ok, comment} = CMS.upvote_article_comment(comment.id, user) + + assert user.id in comment.meta.upvoted_user_ids + end + + test "user undo upvote blog comment will remove id from upvoted_user_ids", + ~m(blog user user2)a do + comment = "blog_comment" + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, comment, user) + {:ok, _comment} = CMS.upvote_article_comment(comment.id, user) + {:ok, comment} = CMS.upvote_article_comment(comment.id, user2) + + assert user2.id in comment.meta.upvoted_user_ids + assert user.id in comment.meta.upvoted_user_ids + + {:ok, comment} = CMS.undo_upvote_article_comment(comment.id, user2) + + assert user.id in comment.meta.upvoted_user_ids + assert user2.id not in comment.meta.upvoted_user_ids + end + + test "user upvote a already-upvoted comment fails", ~m(user blog)a do + comment = "blog_comment" + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, comment, user) + + CMS.upvote_article_comment(comment.id, user) + {:error, _} = CMS.upvote_article_comment(comment.id, user) + end + + test "upvote comment should inc the comment's upvotes_count", ~m(user user2 blog)a do + comment = "blog_comment" + {:ok, comment} = CMS.create_article_comment(:blog, blog.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 + + test "user can undo upvote a blog comment", ~m(user blog)a do + content = "blog_comment" + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, content, user) + CMS.upvote_article_comment(comment.id, user) + + {:ok, comment} = ORM.find(ArticleComment, comment.id, preload: :upvotes) + assert 1 == length(comment.upvotes) + + {:ok, comment} = CMS.undo_upvote_article_comment(comment.id, user) + assert 0 == comment.upvotes_count + end + + test "user can undo upvote a blog comment with no upvote", ~m(user blog)a do + content = "blog_comment" + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, content, user) + {:ok, comment} = CMS.undo_upvote_article_comment(comment.id, user) + assert 0 == comment.upvotes_count + + {:ok, comment} = CMS.undo_upvote_article_comment(comment.id, user) + assert 0 == comment.upvotes_count + end + end + + describe "[article comment fold/unfold]" do + test "user can fold a comment", ~m(user blog)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.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 + + test "user can unfold a comment", ~m(user blog)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.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 pin/unpin]" do + test "user can pin a comment", ~m(user blog)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + {:ok, comment} = ORM.find(ArticleComment, comment.id) + + assert not comment.is_pinned + + {:ok, comment} = CMS.pin_article_comment(comment.id) + {:ok, comment} = ORM.find(ArticleComment, comment.id) + + assert comment.is_pinned + + {:ok, pined_record} = ArticlePinnedComment |> ORM.find_by(%{blog_id: blog.id}) + assert pined_record.blog_id == blog.id + end + + test "user can unpin a comment", ~m(user blog)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + + {:ok, _comment} = CMS.pin_article_comment(comment.id) + {:ok, comment} = CMS.undo_pin_article_comment(comment.id) + + assert not comment.is_pinned + assert {:error, _} = ArticlePinnedComment |> ORM.find_by(%{article_comment_id: comment.id}) + end + + test "pinned comments has a limit for each article", ~m(user blog)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + + Enum.reduce(0..(@pinned_comment_limit - 1), [], fn _, _acc -> + {:ok, _comment} = CMS.pin_article_comment(comment.id) + end) + + assert {:error, _} = CMS.pin_article_comment(comment.id) + end + end + + describe "[article comment report/unreport]" do + # + # test "user can report a comment", ~m(user blog)a do + # {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + # {:ok, comment} = ORM.find(ArticleComment, comment.id) + + # {:ok, comment} = CMS.report_article_comment(comment.id, "reason", "attr", user) + # {:ok, comment} = ORM.find(ArticleComment, comment.id) + # end + + # + # test "user can unreport a comment", ~m(user blog)a do + # {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + # {:ok, _comment} = CMS.report_article_comment(comment.id, "reason", "attr", user) + # {:ok, comment} = ORM.find(ArticleComment, comment.id) + + # {:ok, _comment} = CMS.undo_report_article_comment(comment.id, user) + # {:ok, comment} = ORM.find(ArticleComment, comment.id) + # end + + test "can undo a report with other user report it too", ~m(user user2 blog)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + + {:ok, _comment} = CMS.report_article_comment(comment.id, "reason", "attr", user) + {:ok, _comment} = CMS.report_article_comment(comment.id, "reason", "attr", user2) + + filter = %{content_type: :article_comment, content_id: comment.id, page: 1, size: 20} + {:ok, all_reports} = CMS.paged_reports(filter) + assert all_reports.total_count == 1 + + report = all_reports.entries |> List.first() + assert report.report_cases |> length == 2 + assert Enum.any?(report.report_cases, &(&1.user.login == user.login)) + assert Enum.any?(report.report_cases, &(&1.user.login == user2.login)) + + {:ok, _report} = CMS.undo_report_article(:article_comment, comment.id, user) + + filter = %{content_type: :article_comment, content_id: comment.id, page: 1, size: 20} + {:ok, all_reports} = CMS.paged_reports(filter) + + assert all_reports.total_count == 1 + + report = all_reports.entries |> List.first() + assert report.report_cases |> length == 1 + assert Enum.any?(report.report_cases, &(&1.user.login == user2.login)) + end + + test "report user < @report_threshold_for_fold will not fold comment", ~m(user blog)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + + 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, "reason", "attr", user) + end) + + {:ok, comment} = ORM.find(ArticleComment, comment.id) + assert not comment.is_folded + end + + test "report user > @report_threshold_for_fold will cause comment fold", ~m(user blog)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + + 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, "reason", "attr", user) + end) + + {:ok, comment} = ORM.find(ArticleComment, comment.id) + assert comment.is_folded + end + end + + describe "paged article comments" do + test "can load paged comments participators of a article", ~m(user blog)a do + total_count = 30 + page_size = 10 + thread = :blog + + Enum.reduce(1..total_count, [], fn _, acc -> + {:ok, new_user} = db_insert(:user) + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", new_user) + + acc ++ [comment] + end) + + {:ok, _comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + {:ok, _comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + + {:ok, results} = + CMS.paged_article_comments_participators(thread, blog.id, %{page: 1, size: page_size}) + + assert results |> is_valid_pagination?(:raw) + assert results.total_count == total_count + 1 + end + + test "paged article comments folded flag should be false", ~m(user blog)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(:blog, blog.id, "commment", user) + + acc ++ [comment] + end) + + {:ok, paged_comments} = + CMS.paged_article_comments( + :blog, + blog.id, + %{page: page_number, size: page_size}, + :replies + ) + + 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 + + test "paged article comments should contains pinned comments at top position", + ~m(user blog)a do + total_count = 20 + page_number = 1 + page_size = 5 + + Enum.reduce(1..total_count, [], fn _, acc -> + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + + acc ++ [comment] + end) + + {:ok, random_comment_1} = CMS.create_article_comment(:blog, blog.id, "pin commment", user) + {:ok, random_comment_2} = CMS.create_article_comment(:blog, blog.id, "pin commment2", user) + + {:ok, pined_comment_1} = CMS.pin_article_comment(random_comment_1.id) + {:ok, pined_comment_2} = CMS.pin_article_comment(random_comment_2.id) + + {:ok, paged_comments} = + CMS.paged_article_comments( + :blog, + blog.id, + %{page: page_number, size: page_size}, + :replies + ) + + assert pined_comment_1.id == List.first(paged_comments.entries) |> Map.get(:id) + assert pined_comment_2.id == Enum.at(paged_comments.entries, 1) |> Map.get(:id) + + assert paged_comments.total_count == total_count + 2 + end + + test "only page 1 have pinned coments", + ~m(user blog)a do + total_count = 20 + page_number = 2 + page_size = 5 + + Enum.reduce(1..total_count, [], fn _, acc -> + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + + acc ++ [comment] + end) + + {:ok, random_comment_1} = CMS.create_article_comment(:blog, blog.id, "pin commment", user) + {:ok, random_comment_2} = CMS.create_article_comment(:blog, blog.id, "pin commment2", user) + + {:ok, pined_comment_1} = CMS.pin_article_comment(random_comment_1.id) + {:ok, pined_comment_2} = CMS.pin_article_comment(random_comment_2.id) + + {:ok, paged_comments} = + CMS.paged_article_comments( + :blog, + blog.id, + %{page: page_number, size: page_size}, + :replies + ) + + assert not exist_in?(pined_comment_1, paged_comments.entries) + assert not exist_in?(pined_comment_2, paged_comments.entries) + + assert paged_comments.total_count == total_count + end + + test "paged article comments should not contains folded and repoted comments", + ~m(user blog)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(:blog, blog.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) + + {: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, paged_comments} = + CMS.paged_article_comments( + :blog, + blog.id, + %{page: page_number, size: page_size}, + :replies + ) + + 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 page_number == paged_comments.page_number + assert page_size == paged_comments.page_size + assert total_count - 3 == paged_comments.total_count + end + + test "can loaded paged folded comment", ~m(user blog)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(:blog, blog.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.paged_folded_article_comments(:blog, blog.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 + test "delete comment still exsit in paged list and content is gone", ~m(user blog)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(:blog, blog.id, "commment", user) + + acc ++ [comment] + end) + + random_comment = all_comments |> Enum.at(1) + + {:ok, deleted_comment} = CMS.delete_article_comment(random_comment) + + {:ok, paged_comments} = + CMS.paged_article_comments( + :blog, + blog.id, + %{page: page_number, size: page_size}, + :replies + ) + + assert exist_in?(deleted_comment, paged_comments.entries) + assert deleted_comment.is_deleted + assert deleted_comment.body_html == @delete_hint + end + + test "delete comment still update article's comments_count field", ~m(user blog)a do + {:ok, _comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + {:ok, _comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + {:ok, _comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + {:ok, _comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + + {:ok, blog} = ORM.find(Blog, blog.id) + + assert blog.article_comments_count == 5 + + {:ok, _} = CMS.delete_article_comment(comment) + + {:ok, blog} = ORM.find(Blog, blog.id) + assert blog.article_comments_count == 4 + end + + test "delete comment still delete pinned record if needed", ~m(user blog)a do + total_count = 10 + + all_comments = + Enum.reduce(1..total_count, [], fn _, acc -> + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + + acc ++ [comment] + end) + + random_comment = all_comments |> Enum.at(1) + + {:ok, _comment} = CMS.pin_article_comment(random_comment.id) + {:ok, _comment} = ORM.find(ArticleComment, random_comment.id) + + {:ok, _} = CMS.delete_article_comment(random_comment) + assert {:error, _comment} = ORM.find(ArticlePinnedComment, random_comment.id) + end + end + + describe "[article comment info]" do + test "author of the article comment a comment should have flag", ~m(user blog)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + assert not comment.is_article_author + + author_user = blog.author.user + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", author_user) + assert comment.is_article_author + end + end + + describe "[lock/unlock blog comment]" do + test "locked blog can not be comment", ~m(user blog)a do + {:ok, _} = CMS.create_article_comment(:blog, blog.id, "comment", user) + {:ok, _} = CMS.lock_article_comment(:blog, blog.id) + + {:error, reason} = CMS.create_article_comment(:blog, blog.id, "comment", user) + assert reason |> is_error?(:article_comment_locked) + + {:ok, _} = CMS.undo_lock_article_comment(:blog, blog.id) + {:ok, _} = CMS.create_article_comment(:blog, blog.id, "comment", user) + end + + test "locked blog can not by reply", ~m(user blog)a do + {:ok, parent_comment} = CMS.create_article_comment(:blog, blog.id, "parent_conent", user) + {:ok, _} = CMS.reply_article_comment(parent_comment.id, "reply_content", user) + + {:ok, _} = CMS.lock_article_comment(:blog, blog.id) + + {:error, reason} = CMS.reply_article_comment(parent_comment.id, "reply_content", user) + assert reason |> is_error?(:article_comment_locked) + + {:ok, _} = CMS.undo_lock_article_comment(:blog, blog.id) + {:ok, _} = CMS.reply_article_comment(parent_comment.id, "reply_content", user) + end + end +end diff --git a/test/groupher_server/cms/community/community_test.exs b/test/groupher_server/cms/community/community_test.exs index e11d042fc..083e991ab 100644 --- a/test/groupher_server/cms/community/community_test.exs +++ b/test/groupher_server/cms/community/community_test.exs @@ -59,17 +59,20 @@ defmodule GroupherServer.Test.CMS.Community do end describe "[cms community article_tag]" do + @tag :wip test "articleTagsCount should work", ~m(community article_tag_attrs user)a do {:ok, tag} = CMS.create_article_tag(community, :post, article_tag_attrs, user) {:ok, tag2} = CMS.create_article_tag(community, :job, article_tag_attrs, user) {:ok, tag3} = CMS.create_article_tag(community, :repo, article_tag_attrs, user) + {:ok, tag4} = CMS.create_article_tag(community, :blog, article_tag_attrs, user) {:ok, community} = ORM.find(Community, community.id) - assert community.article_tags_count == 3 + assert community.article_tags_count == 4 {:ok, _} = CMS.delete_article_tag(tag.id) {:ok, _} = CMS.delete_article_tag(tag2.id) {:ok, _} = CMS.delete_article_tag(tag3.id) + {:ok, _} = CMS.delete_article_tag(tag4.id) {:ok, community} = ORM.find(Community, community.id) assert community.article_tags_count == 0 diff --git a/test/groupher_server/cms/emotions/blog_emotions_test.exs b/test/groupher_server/cms/emotions/blog_emotions_test.exs new file mode 100644 index 000000000..0eccce838 --- /dev/null +++ b/test/groupher_server/cms/emotions/blog_emotions_test.exs @@ -0,0 +1,177 @@ +defmodule GroupherServer.Test.CMS.Emotions.BlogEmotions do + @moduledoc false + + use GroupherServer.TestTools + + alias Helper.ORM + alias GroupherServer.CMS + + alias CMS.Model.{Blog, Embeds, ArticleUserEmotion} + + @default_emotions Embeds.ArticleEmotion.default_emotions() + + setup do + {:ok, user} = db_insert(:user) + {:ok, community} = db_insert(:community) + {:ok, user2} = db_insert(:user) + {:ok, user3} = db_insert(:user) + + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + + {:ok, ~m(user user2 user3 community blog_attrs)a} + end + + describe "[emotion in paged blogs]" do + test "login user should got viewer has emotioned status", + ~m(community blog_attrs user)a do + total_count = 10 + page_number = 10 + page_size = 20 + + all_blogs = + Enum.reduce(0..total_count, [], fn _, acc -> + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + acc ++ [blog] + end) + + random_blog = all_blogs |> Enum.at(3) + + {:ok, _} = CMS.emotion_to_article(:blog, random_blog.id, :downvote, user) + {:ok, _} = CMS.emotion_to_article(:blog, random_blog.id, :beer, user) + {:ok, _} = CMS.emotion_to_article(:blog, random_blog.id, :popcorn, user) + + {:ok, paged_articles} = + CMS.paged_articles(:blog, %{page: page_number, size: page_size}, user) + + target = Enum.find(paged_articles.entries, &(&1.id == random_blog.id)) + + 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 + + assert target.emotions.popcorn_count == 1 + assert user_exist_in?(user, target.emotions.latest_popcorn_users) + assert target.emotions.viewer_has_popcorned + end + end + + describe "[basic article emotion]" do + test "blog has default emotions after created", ~m(community blog_attrs user)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + emotions = blog.emotions |> Map.from_struct() |> Map.delete(:id) + assert @default_emotions == emotions + end + + test "can make emotion to blog", ~m(community blog_attrs user user2)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :downvote, user) + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :downvote, user2) + + {:ok, %{emotions: emotions}} = ORM.find(Blog, blog.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 + + test "can undo emotion to blog", ~m(community blog_attrs user user2)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :downvote, user) + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :downvote, user2) + + {:ok, _} = CMS.undo_emotion_to_article(:blog, blog.id, :downvote, user) + {:ok, _} = CMS.undo_emotion_to_article(:blog, blog.id, :downvote, user2) + + {:ok, %{emotions: emotions}} = ORM.find(Blog, blog.id) + + assert emotions.downvote_count == 0 + assert not user_exist_in?(user, emotions.latest_downvote_users) + assert not user_exist_in?(user2, emotions.latest_downvote_users) + end + + test "same user make same emotion to same blog.", ~m(community blog_attrs user)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :downvote, user) + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :downvote, user) + + {:ok, blog} = ORM.find(Blog, blog.id) + + assert blog.emotions.downvote_count == 1 + assert user_exist_in?(user, blog.emotions.latest_downvote_users) + end + + test "same user same emotion to same blog only have one user_emotion record", + ~m(community blog_attrs user)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :downvote, user) + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :heart, user) + + {:ok, blog} = ORM.find(Blog, blog.id) + + {:ok, records} = ORM.find_all(ArticleUserEmotion, %{page: 1, size: 10}) + assert records.total_count == 1 + + {:ok, record} = ORM.find_by(ArticleUserEmotion, %{blog_id: blog.id, user_id: user.id}) + assert record.downvote + assert record.heart + end + + test "different user can make same emotions on same blog", + ~m(community blog_attrs user user2 user3)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :beer, user) + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :beer, user2) + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :beer, user3) + + {:ok, %{emotions: emotions}} = ORM.find(Blog, blog.id) + + 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 + + test "same user can make differcent emotions on same blog", ~m(community blog_attrs user)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :downvote, user) + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :downvote, user) + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :beer, user) + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :heart, user) + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :orz, user) + + {:ok, %{emotions: emotions}} = ORM.find(Blog, blog.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/upvotes/blog_upvote_test.exs b/test/groupher_server/cms/upvotes/blog_upvote_test.exs new file mode 100644 index 000000000..77124c70a --- /dev/null +++ b/test/groupher_server/cms/upvotes/blog_upvote_test.exs @@ -0,0 +1,83 @@ +defmodule GroupherServer.Test.Upvotes.BlogUpvote do + @moduledoc false + use GroupherServer.TestTools + + alias GroupherServer.CMS + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, community} = db_insert(:community) + + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + + {:ok, ~m(user user2 community blog_attrs)a} + end + + describe "[cms blog upvote]" do + test "blog can be upvote && upvotes_count should inc by 1", + ~m(user user2 community blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, article} = CMS.upvote_article(:blog, blog.id, user) + assert article.id == blog.id + assert article.upvotes_count == 1 + + {:ok, article} = CMS.upvote_article(:blog, blog.id, user2) + assert article.upvotes_count == 2 + end + + test "blog can be undo upvote && upvotes_count should dec by 1", + ~m(user user2 community blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, article} = CMS.upvote_article(:blog, blog.id, user) + assert article.id == blog.id + assert article.upvotes_count == 1 + + {:ok, article} = CMS.undo_upvote_article(:blog, blog.id, user2) + assert article.upvotes_count == 0 + end + + test "can get upvotes_users", ~m(user user2 community blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, _article} = CMS.upvote_article(:blog, blog.id, user) + {:ok, _article} = CMS.upvote_article(:blog, blog.id, user2) + + {:ok, users} = CMS.upvoted_users(:blog, blog.id, %{page: 1, size: 2}) + + assert users |> is_valid_pagination?(:raw) + assert user_exist_in?(user, users.entries) + assert user_exist_in?(user2, users.entries) + end + + test "blog meta history should be updated after upvote", + ~m(user user2 community blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, article} = CMS.upvote_article(:blog, blog.id, user) + assert user.id in article.meta.upvoted_user_ids + + {:ok, article} = CMS.upvote_article(:blog, blog.id, user2) + assert user.id in article.meta.upvoted_user_ids + assert user2.id in article.meta.upvoted_user_ids + end + + test "blog meta history should be updated after undo upvote", + ~m(user user2 community blog_attrs)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, _article} = CMS.upvote_article(:blog, blog.id, user) + {:ok, article} = CMS.upvote_article(:blog, blog.id, user2) + + assert user.id in article.meta.upvoted_user_ids + assert user2.id in article.meta.upvoted_user_ids + + {:ok, article} = CMS.undo_upvote_article(:blog, blog.id, user2) + assert user2.id not in article.meta.upvoted_user_ids + + {:ok, article} = CMS.undo_upvote_article(:blog, blog.id, user) + assert user.id not in article.meta.upvoted_user_ids + end + end +end From 9ffeeabf71061c9dca0da46f6c4ce652325db940 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 14:25:00 +0800 Subject: [PATCH 08/28] feat(blog-thread): fix test --- .../repo/migrations/20210607022840_add_blog_to_article_tags.exs | 2 +- test/groupher_server/cms/article_tags/blog_tag_test.exs | 1 + test/groupher_server/cms/articles/blog_test.exs | 1 - test/groupher_server/cms/community/community_test.exs | 1 - 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/priv/repo/migrations/20210607022840_add_blog_to_article_tags.exs b/priv/repo/migrations/20210607022840_add_blog_to_article_tags.exs index affb628cb..0635f5e29 100644 --- a/priv/repo/migrations/20210607022840_add_blog_to_article_tags.exs +++ b/priv/repo/migrations/20210607022840_add_blog_to_article_tags.exs @@ -3,7 +3,7 @@ defmodule GroupherServer.Repo.Migrations.AddBlogToArticleTags do def change do alter table(:articles_join_tags) do - add(:blog_id, references(:cms_jobs, on_delete: :delete_all)) + add(:blog_id, references(:cms_blogs, on_delete: :delete_all)) end end end diff --git a/test/groupher_server/cms/article_tags/blog_tag_test.exs b/test/groupher_server/cms/article_tags/blog_tag_test.exs index c2da1dba8..faad05c05 100644 --- a/test/groupher_server/cms/article_tags/blog_tag_test.exs +++ b/test/groupher_server/cms/article_tags/blog_tag_test.exs @@ -109,6 +109,7 @@ defmodule GroupherServer.Test.CMS.ArticleTag.BlogTag do end describe "[blog tag set /unset]" do + @tag :wip test "can set a tag ", ~m(community blog article_tag_attrs article_tag_attrs2 user)a do {:ok, article_tag} = CMS.create_article_tag(community, :blog, article_tag_attrs, user) {:ok, article_tag2} = CMS.create_article_tag(community, :blog, article_tag_attrs2, user) diff --git a/test/groupher_server/cms/articles/blog_test.exs b/test/groupher_server/cms/articles/blog_test.exs index d172016d9..4343c6145 100644 --- a/test/groupher_server/cms/articles/blog_test.exs +++ b/test/groupher_server/cms/articles/blog_test.exs @@ -18,7 +18,6 @@ defmodule GroupherServer.Test.Articles.Blog do end describe "[cms blogs curd]" do - @tag :wip test "can create a blog with valid attrs", ~m(user community blog_attrs)a do {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) diff --git a/test/groupher_server/cms/community/community_test.exs b/test/groupher_server/cms/community/community_test.exs index 083e991ab..dcd2a0c84 100644 --- a/test/groupher_server/cms/community/community_test.exs +++ b/test/groupher_server/cms/community/community_test.exs @@ -59,7 +59,6 @@ defmodule GroupherServer.Test.CMS.Community do end describe "[cms community article_tag]" do - @tag :wip test "articleTagsCount should work", ~m(community article_tag_attrs user)a do {:ok, tag} = CMS.create_article_tag(community, :post, article_tag_attrs, user) {:ok, tag2} = CMS.create_article_tag(community, :job, article_tag_attrs, user) From e065e417a7ec3954e2277b63f5b046a6dcf01d2e Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 14:33:12 +0800 Subject: [PATCH 09/28] feat(blog-thread): fix test --- test/groupher_server/cms/abuse_reports/blog_report_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/groupher_server/cms/abuse_reports/blog_report_test.exs b/test/groupher_server/cms/abuse_reports/blog_report_test.exs index 5d4cbe657..532ab24a1 100644 --- a/test/groupher_server/cms/abuse_reports/blog_report_test.exs +++ b/test/groupher_server/cms/abuse_reports/blog_report_test.exs @@ -28,7 +28,7 @@ defmodule GroupherServer.Test.CMS.AbuseReports.BlogReport do report = all_reports.entries |> List.first() assert report.article.id == blog.id - assert report.article.thread == "JOB" + assert report.article.thread == "BLOG" end test "report a blog should have a abuse report record", ~m(community user blog_attrs)a do From 450508a8474ee7b3df1089d3904311dc75afd526 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 15:18:01 +0800 Subject: [PATCH 10/28] feat(blog-thread): test wip --- lib/groupher_server/cms/helper/macros.ex | 5 + lib/groupher_server/cms/helper/matcher_old.ex | 7 + lib/groupher_server/cms/models/blog.ex | 3 +- lib/groupher_server/cms/models/job.ex | 1 - lib/groupher_server/cms/models/post.ex | 2 - .../schema/Helper/fields.ex | 2 + .../schema/Helper/imports.ex | 4 +- .../schema/cms/cms_types.ex | 5 - .../schema/cms/mutations/blog.ex | 3 +- .../20210607065610_missing_body_to_blog.exs | 7 + .../20210607071205_add_body_to_repo.exs | 8 + .../cms/article_tags/blog_tag_test.exs | 1 - .../cms/articles/blog_emotion_test.exs | 73 +++++++ .../mutation/cms/articles/blog_test.exs | 184 ++++++++++++++++++ test/support/factory.ex | 2 +- 15 files changed, 291 insertions(+), 16 deletions(-) create mode 100644 priv/repo/migrations/20210607065610_missing_body_to_blog.exs create mode 100644 priv/repo/migrations/20210607071205_add_body_to_repo.exs create mode 100644 test/groupher_server_web/mutation/cms/articles/blog_emotion_test.exs create mode 100644 test/groupher_server_web/mutation/cms/articles/blog_test.exs diff --git a/lib/groupher_server/cms/helper/macros.ex b/lib/groupher_server/cms/helper/macros.ex index 7b3f18075..5ee406b72 100644 --- a/lib/groupher_server/cms/helper/macros.ex +++ b/lib/groupher_server/cms/helper/macros.ex @@ -124,6 +124,8 @@ defmodule GroupherServer.CMS.Helper.Macros do """ def general_article_fields(:cast) do [ + :body, + :digest, :original_community_id, :article_comments_count, :article_comments_participators_count, @@ -184,6 +186,9 @@ defmodule GroupherServer.CMS.Helper.Macros do defmacro general_article_fields do quote do field(:title, :string) + field(:body, :string) + field(:digest, :string) + belongs_to(:author, Author) field(:views, :integer, default: 0) diff --git a/lib/groupher_server/cms/helper/matcher_old.ex b/lib/groupher_server/cms/helper/matcher_old.ex index 3d0157875..a4ee2c685 100644 --- a/lib/groupher_server/cms/helper/matcher_old.ex +++ b/lib/groupher_server/cms/helper/matcher_old.ex @@ -10,6 +10,7 @@ defmodule GroupherServer.CMS.Helper.MatcherOld do Post, Repo, Job, + Blog, # viewer # reactions # comments @@ -44,6 +45,12 @@ defmodule GroupherServer.CMS.Helper.MatcherOld do def match_action(:job, :community), do: {:ok, %{target: Job, reactor: Community}} + def match_action(:blog, :self), + do: {:ok, %{target: Blog, reactor: Blog, preload: :author}} + + def match_action(:blog, :community), + do: {:ok, %{target: Blog, reactor: Community}} + ######################################### ## repos ... ######################################### diff --git a/lib/groupher_server/cms/models/blog.ex b/lib/groupher_server/cms/models/blog.ex index 0d2646f4e..442fc5ac2 100644 --- a/lib/groupher_server/cms/models/blog.ex +++ b/lib/groupher_server/cms/models/blog.ex @@ -13,14 +13,13 @@ defmodule GroupherServer.CMS.Model.Blog do @timestamps_opts [type: :utc_datetime_usec] - @required_fields ~w(title digest length)a + @required_fields ~w(title digest)a @article_cast_fields general_article_fields(:cast) @optional_fields ~w(link_addr digest length)a ++ @article_cast_fields @type t :: %Blog{} schema "cms_blogs" do field(:link_addr, :string) - field(:digest, :string) field(:length, :integer) article_tags_field(:blog) diff --git a/lib/groupher_server/cms/models/job.ex b/lib/groupher_server/cms/models/job.ex index 6bbc62b3b..2b6a535d0 100644 --- a/lib/groupher_server/cms/models/job.ex +++ b/lib/groupher_server/cms/models/job.ex @@ -26,7 +26,6 @@ defmodule GroupherServer.CMS.Model.Job do field(:link_addr, :string) field(:copy_right, :string) - field(:digest, :string) field(:length, :integer) article_tags_field(:job) diff --git a/lib/groupher_server/cms/models/post.ex b/lib/groupher_server/cms/models/post.ex index 0b5b15b5d..3bdff758d 100644 --- a/lib/groupher_server/cms/models/post.ex +++ b/lib/groupher_server/cms/models/post.ex @@ -22,8 +22,6 @@ defmodule GroupherServer.CMS.Model.Post do @type t :: %Post{} schema "cms_posts" do - field(:body, :string) - field(:digest, :string) field(:link_addr, :string) field(:copy_right, :string) field(:length, :integer) diff --git a/lib/groupher_server_web/schema/Helper/fields.ex b/lib/groupher_server_web/schema/Helper/fields.ex index 91e87f584..f95f35920 100644 --- a/lib/groupher_server_web/schema/Helper/fields.ex +++ b/lib/groupher_server_web/schema/Helper/fields.ex @@ -20,6 +20,8 @@ defmodule GroupherServerWeb.Schema.Helper.Fields do quote do field(:id, :id) field(:title, :string) + field(:body, :string) + field(:digest, :string) field(:views, :integer) field(:is_pinned, :boolean) field(:mark_delete, :boolean) diff --git a/lib/groupher_server_web/schema/Helper/imports.ex b/lib/groupher_server_web/schema/Helper/imports.ex index e57e436fc..a683e7b9f 100644 --- a/lib/groupher_server_web/schema/Helper/imports.ex +++ b/lib/groupher_server_web/schema/Helper/imports.ex @@ -4,10 +4,10 @@ defmodule GroupherServerWeb.Schema.Helper.Imports do """ import Helper.Utils, only: [get_config: 2] - @article_threads get_config(:article, :threads) - alias GroupherServerWeb.Schema.{CMS} + alias GroupherServerWeb.Schema.CMS + @article_threads get_config(:article, :threads) @doc """ import article fields based on @article_threads e.g: diff --git a/lib/groupher_server_web/schema/cms/cms_types.ex b/lib/groupher_server_web/schema/cms/cms_types.ex index fc1abcad4..5225f1830 100644 --- a/lib/groupher_server_web/schema/cms/cms_types.ex +++ b/lib/groupher_server_web/schema/cms/cms_types.ex @@ -4,8 +4,6 @@ defmodule GroupherServerWeb.Schema.CMS.Types do """ use Helper.GqlSchemaSuite - import Helper.Utils, only: [get_config: 2] - import GroupherServerWeb.Schema.Helper.Fields import GroupherServerWeb.Schema.Helper.Objects @@ -60,7 +58,6 @@ defmodule GroupherServerWeb.Schema.CMS.Types do general_article_fields() article_comments_fields() - field(:digest, :string) field(:length, :integer) field(:link_addr, :string) field(:copy_right, :string) @@ -101,7 +98,6 @@ defmodule GroupherServerWeb.Schema.CMS.Types do field(:desc, :string) field(:company, :string) field(:company_link, :string) - field(:digest, :string) field(:length, :integer) field(:link_addr, :string) field(:copy_right, :string) @@ -116,7 +112,6 @@ defmodule GroupherServerWeb.Schema.CMS.Types do general_article_fields() article_comments_fields() - field(:digest, :string) field(:length, :integer) field(:link_addr, :string) # field(:body, :string) diff --git a/lib/groupher_server_web/schema/cms/mutations/blog.ex b/lib/groupher_server_web/schema/cms/mutations/blog.ex index 2df220478..bbd61c9b2 100644 --- a/lib/groupher_server_web/schema/cms/mutations/blog.ex +++ b/lib/groupher_server_web/schema/cms/mutations/blog.ex @@ -9,6 +9,7 @@ defmodule GroupherServerWeb.Schema.CMS.Mutations.Blog do @desc "create a blog" field :create_blog, :blog do arg(:title, non_null(:string)) + arg(:body, non_null(:string)) arg(:digest, non_null(:string)) arg(:length, non_null(:integer)) arg(:community_id, non_null(:id)) @@ -31,8 +32,6 @@ defmodule GroupherServerWeb.Schema.CMS.Mutations.Blog do arg(:body, :string) arg(:digest, :string) arg(:length, :integer) - arg(:copy_right, :string) - arg(:desc, :string) arg(:link_addr, :string) arg(:company, :string) diff --git a/priv/repo/migrations/20210607065610_missing_body_to_blog.exs b/priv/repo/migrations/20210607065610_missing_body_to_blog.exs new file mode 100644 index 000000000..f3fed9017 --- /dev/null +++ b/priv/repo/migrations/20210607065610_missing_body_to_blog.exs @@ -0,0 +1,7 @@ +defmodule GroupherServer.Repo.Migrations.MissingBodyToBlog do + use Ecto.Migration + + def change do + alter(table(:cms_blogs), do: add(:body, :string)) + end +end diff --git a/priv/repo/migrations/20210607071205_add_body_to_repo.exs b/priv/repo/migrations/20210607071205_add_body_to_repo.exs new file mode 100644 index 000000000..64272683d --- /dev/null +++ b/priv/repo/migrations/20210607071205_add_body_to_repo.exs @@ -0,0 +1,8 @@ +defmodule GroupherServer.Repo.Migrations.AddBodyToRepo do + use Ecto.Migration + + def change do + alter(table(:cms_repos), do: add(:body, :string)) + alter(table(:cms_repos), do: add(:digest, :string)) + end +end diff --git a/test/groupher_server/cms/article_tags/blog_tag_test.exs b/test/groupher_server/cms/article_tags/blog_tag_test.exs index faad05c05..c2da1dba8 100644 --- a/test/groupher_server/cms/article_tags/blog_tag_test.exs +++ b/test/groupher_server/cms/article_tags/blog_tag_test.exs @@ -109,7 +109,6 @@ defmodule GroupherServer.Test.CMS.ArticleTag.BlogTag do end describe "[blog tag set /unset]" do - @tag :wip test "can set a tag ", ~m(community blog article_tag_attrs article_tag_attrs2 user)a do {:ok, article_tag} = CMS.create_article_tag(community, :blog, article_tag_attrs, user) {:ok, article_tag2} = CMS.create_article_tag(community, :blog, article_tag_attrs2, user) diff --git a/test/groupher_server_web/mutation/cms/articles/blog_emotion_test.exs b/test/groupher_server_web/mutation/cms/articles/blog_emotion_test.exs new file mode 100644 index 000000000..f0f43411f --- /dev/null +++ b/test/groupher_server_web/mutation/cms/articles/blog_emotion_test.exs @@ -0,0 +1,73 @@ +defmodule GroupherServer.Test.Mutation.Articles.BlogEmotion do + use GroupherServer.TestTools + + alias GroupherServer.CMS + + setup do + {:ok, user} = db_insert(:user) + {:ok, community} = db_insert(:community) + + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user) + owner_conn = simu_conn(:user, user) + + {:ok, ~m(user_conn user guest_conn owner_conn community blog_attrs)a} + end + + describe "[blog emotion]" do + @emotion_query """ + mutation($id: ID!, $emotion: ArticleEmotion!) { + emotionToBlog(id: $id, emotion: $emotion) { + id + emotions { + beerCount + viewerHasBeered + latestBeerUsers { + login + nickname + } + } + } + } + """ + + test "login user can emotion to a pblog", ~m(community blog_attrs user user_conn)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + variables = %{id: blog.id, emotion: "BEER"} + article = user_conn |> mutation_result(@emotion_query, variables, "emotionToBlog") + + assert article |> get_in(["emotions", "beerCount"]) == 1 + assert get_in(article, ["emotions", "viewerHasBeered"]) + end + + @emotion_query """ + mutation($id: ID!, $emotion: ArticleEmotion!) { + undoEmotionToBlog(id: $id, emotion: $emotion) { + id + emotions { + beerCount + viewerHasBeered + latestBeerUsers { + login + nickname + } + } + } + } + """ + + test "login user can undo emotion to a blog", ~m(community blog_attrs user owner_conn)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, _} = CMS.emotion_to_article(:blog, blog.id, :beer, user) + + variables = %{id: blog.id, emotion: "BEER"} + article = owner_conn |> mutation_result(@emotion_query, variables, "undoEmotionToBlog") + + assert article |> get_in(["emotions", "beerCount"]) == 0 + assert not get_in(article, ["emotions", "viewerHasBeered"]) + end + end +end diff --git a/test/groupher_server_web/mutation/cms/articles/blog_test.exs b/test/groupher_server_web/mutation/cms/articles/blog_test.exs new file mode 100644 index 000000000..bb10a4d6e --- /dev/null +++ b/test/groupher_server_web/mutation/cms/articles/blog_test.exs @@ -0,0 +1,184 @@ +defmodule GroupherServer.Test.Mutation.Articles.Blog do + use GroupherServer.TestTools + + alias Helper.ORM + alias GroupherServer.{CMS, Delivery} + + alias CMS.Model.Blog + + setup do + {:ok, blog} = db_insert(:blog) + {:ok, user} = db_insert(:user) + + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user) + owner_conn = simu_conn(:owner, blog) + + {:ok, ~m(user_conn guest_conn owner_conn user blog)a} + end + + describe "[mutation blog curd]" do + @create_blog_query """ + mutation ( + $title: String!, + $body: String, + $digest: String!, + $length: Int!, + $communityId: ID!, + $articleTags: [Ids] + ) { + createBlog( + title: $title, + body: $body, + digest: $digest, + length: $length, + communityId: $communityId, + articleTags: $articleTags + ) { + id + title + body + originalCommunity { + id + } + communities { + id + title + } + } + } + """ + @tag :wip + test "create blog with valid attrs and make sure author exsit" do + {:ok, user} = db_insert(:user) + user_conn = simu_conn(:user, user) + + {:ok, community} = db_insert(:community) + blog_attr = mock_attrs(:blog) + + variables = blog_attr |> Map.merge(%{communityId: community.id}) |> camelize_map_key + + created = user_conn |> mutation_result(@create_blog_query, variables, "createBlog") + + {:ok, found} = ORM.find(Blog, created["id"]) + + assert created["id"] == to_string(found.id) + assert created["originalCommunity"]["id"] == to_string(community.id) + + assert created["id"] == to_string(found.id) + end + + test "create blog should excape xss attracts" do + {:ok, user} = db_insert(:user) + user_conn = simu_conn(:user, user) + + {:ok, community} = db_insert(:community) + blog_attr = mock_attrs(:blog, %{body: assert_v(:xss_string)}) + + variables = blog_attr |> Map.merge(%{communityId: community.id}) |> camelize_map_key + created = user_conn |> mutation_result(@create_blog_query, variables, "createBlog") + {:ok, blog} = ORM.find(Blog, created["id"]) + + assert blog.body == assert_v(:xss_safe_string) + end + + @query """ + mutation($id: ID!, $title: String, $body: String, $articleTags: [Ids]){ + updateBlog(id: $id, title: $title, body: $body, articleTags: $articleTags) { + id + title + body + articleTags { + id + } + } + } + """ + + test "update a blog without login user fails", ~m(guest_conn blog)a do + unique_num = System.unique_integer([:positive, :monotonic]) + + variables = %{ + id: blog.id, + title: "updated title #{unique_num}", + body: "updated body #{unique_num}" + } + + assert guest_conn |> mutation_get_error?(@query, variables, ecode(:account_login)) + end + + test "blog can be update by owner", ~m(owner_conn blog)a do + unique_num = System.unique_integer([:positive, :monotonic]) + + variables = %{ + id: blog.id, + title: "updated title #{unique_num}", + body: "updated body #{unique_num}" + } + + updated = owner_conn |> mutation_result(@query, variables, "updateBlog") + + assert updated["title"] == variables.title + assert updated["body"] == variables.body + end + + test "login user with auth passport update a blog", ~m(blog)a do + blog_communities_0 = blog.communities |> List.first() |> Map.get(:title) + passport_rules = %{blog_communities_0 => %{"blog.edit" => true}} + rule_conn = simu_conn(:user, cms: passport_rules) + + unique_num = System.unique_integer([:positive, :monotonic]) + + variables = %{ + id: blog.id, + title: "updated title #{unique_num}", + body: "updated body #{unique_num}" + } + + updated = rule_conn |> mutation_result(@query, variables, "updateBlog") + + assert updated["id"] == to_string(blog.id) + end + + test "unauth user update blog fails", ~m(user_conn guest_conn blog)a do + unique_num = System.unique_integer([:positive, :monotonic]) + + variables = %{ + id: blog.id, + title: "updated title #{unique_num}", + body: "updated body #{unique_num}" + } + + rule_conn = simu_conn(:user, cms: %{"what.ever" => true}) + + assert user_conn |> mutation_get_error?(@query, variables, ecode(:passport)) + assert guest_conn |> mutation_get_error?(@query, variables, ecode(:account_login)) + assert rule_conn |> mutation_get_error?(@query, variables, ecode(:passport)) + end + + @query """ + mutation($id: ID!){ + deleteBlog(id: $id) { + id + } + } + """ + + test "can delete a blog by blog's owner", ~m(owner_conn blog)a do + deleted = owner_conn |> mutation_result(@query, %{id: blog.id}, "deleteBlog") + + assert deleted["id"] == to_string(blog.id) + assert {:error, _} = ORM.find(Blog, deleted["id"]) + end + + test "can delete a blog by auth user", ~m(blog)a do + belongs_community_title = blog.communities |> List.first() |> Map.get(:title) + rule_conn = simu_conn(:user, cms: %{belongs_community_title => %{"blog.delete" => true}}) + + deleted = rule_conn |> mutation_result(@query, %{id: blog.id}, "deleteBlog") + + assert deleted["id"] == to_string(blog.id) + assert {:error, _} = ORM.find(Blog, deleted["id"]) + end + end +end diff --git a/test/support/factory.ex b/test/support/factory.ex index c2ad046ba..b2021d94f 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -24,7 +24,6 @@ defmodule GroupherServer.Support.Factory do } alias Delivery.Model.{Mention, SysNotification} - alias CMS.Model.Repo @default_article_meta CMS.Model.Embeds.ArticleMeta.default_meta() @default_emotions CMS.Model.Embeds.ArticleCommentEmotion.default_emotions() @@ -151,6 +150,7 @@ defmodule GroupherServer.Support.Factory do %{ meta: @default_article_meta, title: String.slice(body, 1, 49), + body: String.slice(body, 1, 49), digest: String.slice(body, 1, 150), length: String.length(body), author: mock(:author), From a247e2ba50c123c83e4c371be2080647ffba56cc Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 15:27:37 +0800 Subject: [PATCH 11/28] feat(blog-thread): test wip --- lib/groupher_server/cms/delegates/comment_curd.ex | 14 +++++++------- lib/groupher_server/cms/models/job.ex | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/groupher_server/cms/delegates/comment_curd.ex b/lib/groupher_server/cms/delegates/comment_curd.ex index 7cea8fd8b..9e6eb1cdf 100644 --- a/lib/groupher_server/cms/delegates/comment_curd.ex +++ b/lib/groupher_server/cms/delegates/comment_curd.ex @@ -26,7 +26,7 @@ defmodule GroupherServer.CMS.Delegate.CommentCURD do %{community: community, body: body} = args, %User{id: user_id} ) do - with {:ok, action} <- match_action(thread, :comment), + with {:ok, action} <- match_action(:post, :comment), {:ok, content} <- ORM.find(action.target, content_id), {:ok, user} <- ORM.find(User, user_id) do Multi.new() @@ -48,7 +48,7 @@ defmodule GroupherServer.CMS.Delegate.CommentCURD do %{community: community, body: body} = args, %User{id: user_id} = user ) do - with {:ok, action} <- match_action(thread, :comment), + with {:ok, action} <- match_action(:post, :comment), {:ok, comment} <- ORM.find(action.reactor, comment_id) do next_floor = get_next_floor(thread, action.reactor, comment) @@ -70,7 +70,7 @@ defmodule GroupherServer.CMS.Delegate.CommentCURD do Creates a comment for psot, job ... """ def update_comment(thread, id, %{body: body}, %User{id: user_id}) do - with {:ok, action} <- match_action(thread, :comment), + with {:ok, action} <- match_action(:post, :comment), {:ok, content} <- ORM.find(action.reactor, id), true <- content.author_id == user_id do ORM.update(content, %{body: body}) @@ -81,7 +81,7 @@ defmodule GroupherServer.CMS.Delegate.CommentCURD do Delete the comment and increase all the floor after this comment """ def delete_comment(thread, content_id) do - with {:ok, action} <- match_action(thread, :comment), + with {:ok, action} <- match_action(:post, :comment), {:ok, comment} <- ORM.find(action.reactor, content_id) do Multi.new() |> Multi.run(:delete_comment, fn _, _ -> @@ -99,7 +99,7 @@ defmodule GroupherServer.CMS.Delegate.CommentCURD do list paged comments """ def paged_comments(thread, content_id, %{page: page, size: size} = filters) do - with {:ok, action} <- match_action(thread, :comment) do + with {:ok, action} <- match_action(:post, :comment) do dynamic = dynamic_comment_where(thread, content_id) action.reactor @@ -114,7 +114,7 @@ defmodule GroupherServer.CMS.Delegate.CommentCURD do list paged comments participators """ def paged_comments_participators(thread, content_id, %{page: page, size: size} = filters) do - with {:ok, action} <- match_action(thread, :comment) do + with {:ok, action} <- match_action(:post, :comment) do dynamic = dynamic_comment_where(thread, content_id) action.reactor @@ -133,7 +133,7 @@ defmodule GroupherServer.CMS.Delegate.CommentCURD do end def paged_replies(thread, comment_id, %User{id: user_id}) do - with {:ok, action} <- match_action(thread, :comment) do + with {:ok, action} <- match_action(:post, :comment) do action.reactor |> where([c], c.author_id == ^user_id) |> join(:inner, [c], r in assoc(c, :reply_to)) diff --git a/lib/groupher_server/cms/models/job.ex b/lib/groupher_server/cms/models/job.ex index 2b6a535d0..20ab33218 100644 --- a/lib/groupher_server/cms/models/job.ex +++ b/lib/groupher_server/cms/models/job.ex @@ -22,7 +22,6 @@ defmodule GroupherServer.CMS.Model.Job do field(:company, :string) field(:company_link, :string) field(:desc, :string) - field(:body, :string) field(:link_addr, :string) field(:copy_right, :string) From 68411d7fd8cbf0d298847164a78e3e805eb6874f Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 15:40:36 +0800 Subject: [PATCH 12/28] feat(blog-thread): remove matcher old wip --- lib/groupher_server/cms/delegates/comment_curd.ex | 6 ++++-- lib/groupher_server/cms/helper/matcher_old.ex | 6 ------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/groupher_server/cms/delegates/comment_curd.ex b/lib/groupher_server/cms/delegates/comment_curd.ex index 9e6eb1cdf..7d54d5486 100644 --- a/lib/groupher_server/cms/delegates/comment_curd.ex +++ b/lib/groupher_server/cms/delegates/comment_curd.ex @@ -6,17 +6,19 @@ defmodule GroupherServer.CMS.Delegate.CommentCURD do import Helper.Utils, only: [done: 1] import Helper.ErrorCode - import GroupherServer.CMS.Helper.MatcherOld import ShortMaps alias GroupherServer.{Accounts, CMS, Delivery, Repo} alias Accounts.Model.User - alias CMS.Model.PostCommentReply + alias CMS.Model.{PostComment, PostCommentReply} alias Helper.{ORM, QueryBuilder} alias Ecto.Multi + defp match_action(:post, :comment), + do: {:ok, %{target: Post, reactor: PostComment, preload: :author}} + @doc """ Creates a comment for psot, job ... """ diff --git a/lib/groupher_server/cms/helper/matcher_old.ex b/lib/groupher_server/cms/helper/matcher_old.ex index a4ee2c685..54f6c786e 100644 --- a/lib/groupher_server/cms/helper/matcher_old.ex +++ b/lib/groupher_server/cms/helper/matcher_old.ex @@ -30,12 +30,6 @@ defmodule GroupherServer.CMS.Helper.MatcherOld do def match_action(:post, :community), do: {:ok, %{target: Post, reactor: Community}} - def match_action(:post, :comment), - do: {:ok, %{target: Post, reactor: PostComment, preload: :author}} - - def match_action(:post_comment, :like), - do: {:ok, %{target: PostComment, reactor: PostCommentLike}} - ######################################### ## jobs ... ######################################### From d515f7a4d1af77eb5b56ed1fb9548796fe5160d0 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 18:47:57 +0800 Subject: [PATCH 13/28] feat(blog-thread): remove matcher old wip --- lib/groupher_server/cms/delegates/comment_curd.ex | 2 +- lib/groupher_server_web/middleware/passport_loader.ex | 4 ++++ test/groupher_server_web/mutation/cms/articles/blog_test.exs | 2 +- test/groupher_server_web/query/cms/old_post_comment_test.exs | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/groupher_server/cms/delegates/comment_curd.ex b/lib/groupher_server/cms/delegates/comment_curd.ex index 7d54d5486..e1578ef1c 100644 --- a/lib/groupher_server/cms/delegates/comment_curd.ex +++ b/lib/groupher_server/cms/delegates/comment_curd.ex @@ -11,7 +11,7 @@ defmodule GroupherServer.CMS.Delegate.CommentCURD do alias GroupherServer.{Accounts, CMS, Delivery, Repo} alias Accounts.Model.User - alias CMS.Model.{PostComment, PostCommentReply} + alias CMS.Model.{Post, PostComment, PostCommentReply} alias Helper.{ORM, QueryBuilder} alias Ecto.Multi diff --git a/lib/groupher_server_web/middleware/passport_loader.ex b/lib/groupher_server_web/middleware/passport_loader.ex index 51f131c4b..a1ee8eb94 100644 --- a/lib/groupher_server_web/middleware/passport_loader.ex +++ b/lib/groupher_server_web/middleware/passport_loader.ex @@ -46,6 +46,10 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do # def call(%{context: %{cur_user: cur_user}, arguments: %{id: id}} = resolution, [source: .., base: ..]) do # Loader 应该使用 Map 作为参数,以方便模式匹配 def call(%{context: %{cur_user: _}, arguments: %{id: id}} = resolution, args) do + IO.inspect(thread, label: "thread") + IO.inspect(react, label: "react") + IO.inspect("-------") + with {:ok, thread, react} <- parse_source(args, resolution), {:ok, action} <- match_action(thread, react), {:ok, preload} <- parse_preload(action, args), diff --git a/test/groupher_server_web/mutation/cms/articles/blog_test.exs b/test/groupher_server_web/mutation/cms/articles/blog_test.exs index bb10a4d6e..0c792f587 100644 --- a/test/groupher_server_web/mutation/cms/articles/blog_test.exs +++ b/test/groupher_server_web/mutation/cms/articles/blog_test.exs @@ -2,7 +2,7 @@ defmodule GroupherServer.Test.Mutation.Articles.Blog do use GroupherServer.TestTools alias Helper.ORM - alias GroupherServer.{CMS, Delivery} + alias GroupherServer.CMS alias CMS.Model.Blog diff --git a/test/groupher_server_web/query/cms/old_post_comment_test.exs b/test/groupher_server_web/query/cms/old_post_comment_test.exs index 0d41ef65f..200954503 100644 --- a/test/groupher_server_web/query/cms/old_post_comment_test.exs +++ b/test/groupher_server_web/query/cms/old_post_comment_test.exs @@ -219,6 +219,7 @@ defmodule GroupherServer.Test.Query.OldPostComment do } } """ + @tag :wip test "guest user can get replies info", ~m(guest_conn post user community)a do body = "test comment" From f9e04b7462a7b013ff4f2964e125b15fb9420c2c Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 18:53:53 +0800 Subject: [PATCH 14/28] feat(blog-thread): remove matcher old wip --- lib/groupher_server_web/middleware/passport_loader.ex | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/groupher_server_web/middleware/passport_loader.ex b/lib/groupher_server_web/middleware/passport_loader.ex index a1ee8eb94..d6c8ccd4a 100644 --- a/lib/groupher_server_web/middleware/passport_loader.ex +++ b/lib/groupher_server_web/middleware/passport_loader.ex @@ -46,8 +46,10 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do # def call(%{context: %{cur_user: cur_user}, arguments: %{id: id}} = resolution, [source: .., base: ..]) do # Loader 应该使用 Map 作为参数,以方便模式匹配 def call(%{context: %{cur_user: _}, arguments: %{id: id}} = resolution, args) do + {:ok, thread, react} = parse_source(args, resolution) IO.inspect(thread, label: "thread") IO.inspect(react, label: "react") + IO.inspect(match_action(thread, react), label: "match_action(thread, react)") IO.inspect("-------") with {:ok, thread, react} <- parse_source(args, resolution), From 91b14950e76f3048cc9888a33caf72803aba494b Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 19:15:20 +0800 Subject: [PATCH 15/28] feat(blog-thread): remove matcher old debug --- lib/groupher_server/cms/helper/matcher_old.ex | 3 ++ .../middleware/passport_loader.ex | 44 +++++-------------- .../mutation/cms/articles/blog_test.exs | 1 - .../mutation/cms/old_post_comment_test.exs | 2 +- .../query/cms/old_post_comment_test.exs | 1 - 5 files changed, 16 insertions(+), 35 deletions(-) diff --git a/lib/groupher_server/cms/helper/matcher_old.ex b/lib/groupher_server/cms/helper/matcher_old.ex index 54f6c786e..27a209208 100644 --- a/lib/groupher_server/cms/helper/matcher_old.ex +++ b/lib/groupher_server/cms/helper/matcher_old.ex @@ -30,6 +30,9 @@ defmodule GroupherServer.CMS.Helper.MatcherOld do def match_action(:post, :community), do: {:ok, %{target: Post, reactor: Community}} + def match_action(:post, :comment), + do: {:ok, %{target: Post, reactor: PostComment, preload: :author}} + ######################################### ## jobs ... ######################################### diff --git a/lib/groupher_server_web/middleware/passport_loader.ex b/lib/groupher_server_web/middleware/passport_loader.ex index d6c8ccd4a..d85d8b282 100644 --- a/lib/groupher_server_web/middleware/passport_loader.ex +++ b/lib/groupher_server_web/middleware/passport_loader.ex @@ -67,14 +67,10 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do end end - def call(resolution, _) do - # TODO communiy in args - resolution - end + def call(resolution, _), do: resolution - def load_source(resolution, content) do - arguments = resolution.arguments |> Map.merge(%{passport_source: content}) - %{resolution | arguments: arguments} + def load_source(%{arguments: arguments} = resolution, content) do + %{resolution | arguments: Map.put(arguments, :passport_source, content)} end # 取得 content 里面的 conmunities 字段 @@ -92,34 +88,22 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do {:ok, _, react} = parse_source(args) case react == :comment do - true -> - {:ok, action.preload} - - false -> - {:ok, [action.preload, parse_base(args)]} + true -> {:ok, action.preload} + false -> {:ok, [action.preload, parse_base(args)]} end end def load_owner_info(%{context: %{cur_user: cur_user}} = resolution, react, content) do content_author_id = cond do - react == :article_comment -> - content.author.id - - react == :comment -> - content.author.id - - true -> - content.author.user_id + react == :article_comment -> content.author.id + react == :comment -> content.author.id + true -> content.author.user_id end case content_author_id == cur_user.id do - true -> - arguments = resolution.arguments |> Map.merge(%{passport_is_owner: true}) - %{resolution | arguments: arguments} - - _ -> - resolution + true -> %{resolution | arguments: Map.put(resolution.arguments, :passport_is_owner, true)} + _ -> resolution end end @@ -128,9 +112,7 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do parse_source(source: [thread, react]) end - defp parse_source(args, _resolution) do - parse_source(args) - end + defp parse_source(args, _resolution), do: parse_source(args) defp parse_source(args) do case Keyword.has_key?(args, :source) do @@ -142,7 +124,5 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do defp match_source([thread, react]), do: {:ok, thread, react} defp match_source(thread), do: {:ok, thread, :self} - defp parse_base(args) do - Keyword.get(args, :base) || :communities - end + defp parse_base(args), do: Keyword.get(args, :base) || :communities end diff --git a/test/groupher_server_web/mutation/cms/articles/blog_test.exs b/test/groupher_server_web/mutation/cms/articles/blog_test.exs index 0c792f587..d73bf9b9e 100644 --- a/test/groupher_server_web/mutation/cms/articles/blog_test.exs +++ b/test/groupher_server_web/mutation/cms/articles/blog_test.exs @@ -48,7 +48,6 @@ defmodule GroupherServer.Test.Mutation.Articles.Blog do } } """ - @tag :wip test "create blog with valid attrs and make sure author exsit" do {:ok, user} = db_insert(:user) user_conn = simu_conn(:user, user) diff --git a/test/groupher_server_web/mutation/cms/old_post_comment_test.exs b/test/groupher_server_web/mutation/cms/old_post_comment_test.exs index c8b6dbc0f..5725550c9 100644 --- a/test/groupher_server_web/mutation/cms/old_post_comment_test.exs +++ b/test/groupher_server_web/mutation/cms/old_post_comment_test.exs @@ -107,7 +107,7 @@ defmodule GroupherServer.Test.Mutation.OldPostComment do } } """ - + @tag :wip test "comment owner can delete comment", ~m(user community post)a do variables = %{community: community.raw, id: post.id, body: "this a comment"} diff --git a/test/groupher_server_web/query/cms/old_post_comment_test.exs b/test/groupher_server_web/query/cms/old_post_comment_test.exs index 200954503..0d41ef65f 100644 --- a/test/groupher_server_web/query/cms/old_post_comment_test.exs +++ b/test/groupher_server_web/query/cms/old_post_comment_test.exs @@ -219,7 +219,6 @@ defmodule GroupherServer.Test.Query.OldPostComment do } } """ - @tag :wip test "guest user can get replies info", ~m(guest_conn post user community)a do body = "test comment" From 5893df6f7d468e565de26cc30cd2195b27564382 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 22:15:55 +0800 Subject: [PATCH 16/28] feat(blog-thread): remove old post_comment && re-org PassportLoader --- lib/groupher_server/cms/cms.ex | 9 - .../cms/delegates/comment_curd.ex | 242 ----------------- lib/groupher_server/cms/helper/loader.ex | 99 +------ lib/groupher_server/cms/models/post.ex | 5 +- .../cms/models/post_comment.ex | 61 ----- .../cms/models/post_comment_like.ex | 31 --- .../cms/models/post_comment_reply.ex | 29 -- .../middleware/cut_participators.ex | 32 --- .../middleware/passport_loader.ex | 101 ++----- .../resolvers/cms_resolver.ex | 8 - .../schema/Helper/fields.ex | 33 --- .../schema/cms/cms_queries.ex | 10 - .../schema/cms/cms_types.ex | 23 -- .../schema/cms/mutations/comment.ex | 61 ----- .../mutation/cms/cms_manager_test.exs | 20 +- .../mutation/cms/old_post_comment_test.exs | 255 ------------------ .../query/cms/old_post_comment_test.exs | 252 ----------------- 17 files changed, 28 insertions(+), 1243 deletions(-) delete mode 100644 lib/groupher_server/cms/delegates/comment_curd.ex delete mode 100644 lib/groupher_server/cms/models/post_comment.ex delete mode 100644 lib/groupher_server/cms/models/post_comment_like.ex delete mode 100644 lib/groupher_server/cms/models/post_comment_reply.ex delete mode 100644 lib/groupher_server_web/middleware/cut_participators.ex delete mode 100644 test/groupher_server_web/mutation/cms/old_post_comment_test.exs delete mode 100644 test/groupher_server_web/query/cms/old_post_comment_test.exs diff --git a/lib/groupher_server/cms/cms.ex b/lib/groupher_server/cms/cms.ex index 4467a10ca..aca971337 100644 --- a/lib/groupher_server/cms/cms.ex +++ b/lib/groupher_server/cms/cms.ex @@ -18,7 +18,6 @@ defmodule GroupherServer.CMS do ArticleCommentAction, ArticleCommentEmotion, ArticleTag, - CommentCURD, CommunitySync, CommunityCURD, CommunityOperation, @@ -162,14 +161,6 @@ defmodule GroupherServer.CMS do ################### ################### ################### - 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 paged_replies(thread, comment, user), to: CommentCURD - defdelegate reply_comment(thread, comment, args, user), to: CommentCURD - - defdelegate paged_comments(thread, content_id, filters), to: CommentCURD - defdelegate paged_comments_participators(thread, content_id, filters), to: CommentCURD # TODO: move report to abuse report module defdelegate report_article(thread, article_id, reason, attr, user), to: AbuseReport diff --git a/lib/groupher_server/cms/delegates/comment_curd.ex b/lib/groupher_server/cms/delegates/comment_curd.ex deleted file mode 100644 index e1578ef1c..000000000 --- a/lib/groupher_server/cms/delegates/comment_curd.ex +++ /dev/null @@ -1,242 +0,0 @@ -defmodule GroupherServer.CMS.Delegate.CommentCURD do - @moduledoc """ - CURD for comments - """ - import Ecto.Query, warn: false - import Helper.Utils, only: [done: 1] - import Helper.ErrorCode - - import ShortMaps - - alias GroupherServer.{Accounts, CMS, Delivery, Repo} - - alias Accounts.Model.User - alias CMS.Model.{Post, PostComment, PostCommentReply} - - alias Helper.{ORM, QueryBuilder} - alias Ecto.Multi - - defp match_action(:post, :comment), - do: {:ok, %{target: Post, reactor: PostComment, preload: :author}} - - @doc """ - Creates a comment for psot, job ... - """ - def create_comment( - thread, - content_id, - %{community: community, body: body} = args, - %User{id: user_id} - ) do - with {:ok, action} <- match_action(:post, :comment), - {:ok, content} <- ORM.find(action.target, content_id), - {:ok, user} <- ORM.find(User, user_id) do - Multi.new() - |> Multi.run(:create_comment, fn _, _ -> - do_create_comment(thread, action, content, body, 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() - |> create_comment_result() - end - end - - def reply_comment( - thread, - comment_id, - %{community: community, body: body} = args, - %User{id: user_id} = user - ) do - with {:ok, action} <- match_action(:post, :comment), - {:ok, comment} <- ORM.find(action.reactor, comment_id) do - next_floor = get_next_floor(thread, action.reactor, comment) - - attrs = %{ - author_id: user_id, - body: body, - reply_to: comment, - floor: next_floor, - mention_users: Map.get(args, :mention_users, []) - } - - Delivery.mention_from_comment_reply(community, thread, comment, attrs, user) - attrs = merge_reply_attrs(thread, attrs, comment) - bridge_reply(thread, action.reactor, comment, attrs) - end - end - - @doc """ - Creates a comment for psot, job ... - """ - def update_comment(thread, id, %{body: body}, %User{id: user_id}) do - with {:ok, action} <- match_action(:post, :comment), - {:ok, content} <- ORM.find(action.reactor, id), - true <- content.author_id == user_id do - ORM.update(content, %{body: body}) - end - end - - @doc """ - Delete the comment and increase all the floor after this comment - """ - def delete_comment(thread, content_id) do - with {:ok, action} <- match_action(:post, :comment), - {:ok, comment} <- ORM.find(action.reactor, content_id) do - Multi.new() - |> Multi.run(:delete_comment, fn _, _ -> - ORM.delete(comment) - end) - |> Multi.run(:update_floor, fn _, _ -> - exec_update_floor(action.reactor, comment) - end) - |> Repo.transaction() - |> delete_comment_result() - end - end - - @doc """ - list paged comments - """ - def paged_comments(thread, content_id, %{page: page, size: size} = filters) do - with {:ok, action} <- match_action(:post, :comment) do - dynamic = dynamic_comment_where(thread, content_id) - - action.reactor - |> where(^dynamic) - |> QueryBuilder.filter_pack(filters) - |> ORM.paginater(~m(page size)a) - |> done() - end - end - - @doc """ - list paged comments participators - """ - def paged_comments_participators(thread, content_id, %{page: page, size: size} = filters) do - with {:ok, action} <- match_action(:post, :comment) do - dynamic = dynamic_comment_where(thread, content_id) - - action.reactor - |> where(^dynamic) - |> QueryBuilder.filter_pack(filters) - |> join(:inner, [c], a in assoc(c, :author)) - |> distinct([c, a], a.id) - # new added when upgrade to ecto v3 - |> group_by([c, a], a.id) - |> group_by([c, a], c.inserted_at) - # new added when upgrade to ecto v3 end - |> select([c, a], a) - |> ORM.paginater(~m(page size)a) - |> done() - end - end - - def paged_replies(thread, comment_id, %User{id: user_id}) do - with {:ok, action} <- match_action(:post, :comment) do - action.reactor - |> where([c], c.author_id == ^user_id) - |> join(:inner, [c], r in assoc(c, :reply_to)) - |> where([c, r], r.id == ^comment_id) - |> Repo.all() - |> done() - end - end - - defp do_create_comment(thread, action, content, body, user) do - next_floor = get_next_floor(thread, action.reactor, content.id) - - attrs = %{ - author_id: user.id, - body: body, - floor: next_floor - } - - attrs = merge_comment_attrs(thread, attrs, content.id) - - action.reactor |> ORM.create(attrs) - end - - defp create_comment_result({:ok, %{create_comment: result}}), do: {:ok, result} - - defp create_comment_result({:error, :create_comment, result, _steps}) do - {:error, result} - end - - defp delete_comment_result({:ok, %{delete_comment: result}}), do: {:ok, result} - - defp delete_comment_result({:error, :delete_comment, _result, _steps}) do - {:error, [message: "delete comment fails", code: ecode(:delete_fails)]} - end - - defp delete_comment_result({:error, :update_floor, _result, _steps}) do - {:error, [message: "update follor fails", code: ecode(:delete_fails)]} - end - - defp exec_update_floor(queryable, comment) do - Repo.update_all( - from(p in queryable, where: p.id > ^comment.id), - inc: [floor: -1] - ) - |> done() - |> case do - {:ok, _} -> {:ok, comment} - {:error, _} -> {:error, ""} - end - end - - # simulate a join connection - # TODO: use Multi task to refactor - # TODO: refactor boilerplate code - defp bridge_reply(:post, queryable, comment, attrs) do - with {:ok, reply} <- ORM.create(queryable, attrs) do - ORM.update(reply, %{reply_id: comment.id}) - - {:ok, _} = - PostCommentReply |> ORM.create(%{post_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) - - queryable - |> where(^dynamic) - |> ORM.next_count() - end - - # for reply comment - defp get_next_floor(thread, queryable, comment) do - dynamic = dynamic_reply_where(thread, comment) - - queryable - |> where(^dynamic) - |> ORM.next_count() - end - - # merge_comment_attrs when create comemnt - defp merge_comment_attrs(:post, attrs, id), do: attrs |> Map.merge(%{post_id: id}) - defp merge_comment_attrs(:job, attrs, id), do: attrs |> Map.merge(%{job_id: id}) - defp merge_comment_attrs(:repo, attrs, id), do: attrs |> Map.merge(%{repo_id: id}) - - defp merge_reply_attrs(:post, attrs, comment), - do: attrs |> Map.merge(%{post_id: comment.post_id}) - - defp merge_reply_attrs(:job, attrs, comment), do: attrs |> Map.merge(%{job_id: comment.job_id}) - - defp merge_reply_attrs(:repo, attrs, comment), - do: attrs |> Map.merge(%{repo_id: comment.repo_id}) - - defp dynamic_comment_where(:post, id), do: dynamic([c], c.post_id == ^id) - defp dynamic_comment_where(:job, id), do: dynamic([c], c.job_id == ^id) - defp dynamic_comment_where(:repo, id), do: dynamic([c], c.repo_id == ^id) - - defp dynamic_reply_where(:post, comment), do: dynamic([c], c.post_id == ^comment.post_id) - defp dynamic_reply_where(:job, comment), do: dynamic([c], c.job_id == ^comment.job_id) - defp dynamic_reply_where(:repo, comment), do: dynamic([c], c.repo_id == ^comment.repo_id) -end diff --git a/lib/groupher_server/cms/helper/loader.ex b/lib/groupher_server/cms/helper/loader.ex index 2da0e1a83..153ee82cf 100644 --- a/lib/groupher_server/cms/helper/loader.ex +++ b/lib/groupher_server/cms/helper/loader.ex @@ -6,14 +6,7 @@ defmodule GroupherServer.CMS.Helper.Loader do alias GroupherServer.{CMS, Repo} - alias CMS.Model.{ - Author, - CommunityThread, - PostComment, - PostCommentLike, - PostCommentReply - } - + alias CMS.Model.{Author, CommunityThread} alias Helper.QueryBuilder def data, do: Dataloader.Ecto.new(Repo, query: &query/2) @@ -31,96 +24,6 @@ defmodule GroupherServer.CMS.Helper.Loader do ) end - # ------- post comments ------ - @doc """ - get unique participators join in comments - """ - # NOTE: this is NOT the right solution - # should use WINDOW function - # see https://github.com/coderplanets/coderplanets_server/issues/16 - def query({"posts_comments", PostComment}, %{filter: _filter, unique: true}) do - PostComment - |> join(:inner, [c], a in assoc(c, :author)) - # NOTE: this distinct not working in production env, so the uniq logic is move to - # cut_participators.ex middleware, when the data is large, will cause performace issue - # |> distinct([c, a], a.id) - |> select([c, a], a) - end - - def query({"posts_comments", PostComment}, %{count: _, unique: true}) do - PostComment - |> join(:inner, [c], a in assoc(c, :author)) - |> distinct([c, a], a.id) - |> group_by([c, a], a.id) - |> group_by([c, a], c.post_id) - |> select([c, a], count(c.id)) - end - - def query({"posts_comments", PostComment}, %{count: _}) do - PostComment - |> group_by([c], c.post_id) - |> select([c], count(c.id)) - end - - def query({"posts_comments", PostComment}, %{filter: filter}) do - PostComment - |> QueryBuilder.filter_pack(filter) - end - - def query({"posts_comments_replies", PostCommentReply}, %{count: _}) do - PostCommentReply - |> group_by([c], c.post_comment_id) - |> select([c], count(c.id)) - end - - def query({"posts_comments_replies", PostCommentReply}, %{filter: filter}) do - PostCommentReply - |> load_inner_replies(filter) - end - - @doc """ - load replies of the given comment - TODO: remove - """ - defp load_inner_replies(queryable, filter) do - queryable - |> QueryBuilder.filter_pack(filter) - |> join(:inner, [c], r in assoc(c, :reply)) - |> select([c, r], r) - end - - def query({"posts_comments_replies", PostCommentReply}, %{reply_to: _}) do - PostCommentReply - |> join(:inner, [c], r in assoc(c, :post_comment)) - |> select([c, r], r) - end - - def query({"posts_comments_likes", PostCommentLike}, %{count: _}) do - PostCommentLike - |> group_by([f], f.post_comment_id) - |> select([f], count(f.id)) - end - - def query({"posts_comments_likes", PostCommentLike}, %{viewer_did: _, cur_user: cur_user}) do - PostCommentLike |> where([f], f.user_id == ^cur_user.id) - end - - def query({"posts_comments_likes", PostCommentLike}, %{filter: _filter} = args) do - PostCommentLike |> members_pack(args) - end - - # TODO: remove it - def members_pack(queryable, %{filter: filter}) do - queryable |> QueryBuilder.load_inner_users(filter) - end - - # def query({"articles_comments_upvotes", ArticleCommentUpvote}, %{ - # viewer_did: _, - # cur_user: cur_user - # }) do - # ArticleCommentUpvote |> where([f], f.user_id == ^cur_user.id) - # end - # default loader def query(queryable, _args) do queryable diff --git a/lib/groupher_server/cms/models/post.ex b/lib/groupher_server/cms/models/post.ex index 3bdff758d..d16e5710f 100644 --- a/lib/groupher_server/cms/models/post.ex +++ b/lib/groupher_server/cms/models/post.ex @@ -9,7 +9,7 @@ defmodule GroupherServer.CMS.Model.Post do import GroupherServer.CMS.Helper.Macros alias GroupherServer.CMS - alias CMS.Model.{Embeds, PostComment} + alias CMS.Model.Embeds alias Helper.HTML @@ -30,9 +30,6 @@ defmodule GroupherServer.CMS.Model.Post do field(:is_solved, :boolean, default: false) field(:solution_digest, :string) - # TODO: remove after legacy data migrated - has_many(:comments, {"posts_comments", PostComment}) - article_tags_field(:post) article_communities_field(:post) general_article_fields() diff --git a/lib/groupher_server/cms/models/post_comment.ex b/lib/groupher_server/cms/models/post_comment.ex deleted file mode 100644 index 417af9c41..000000000 --- a/lib/groupher_server/cms/models/post_comment.ex +++ /dev/null @@ -1,61 +0,0 @@ -defmodule GroupherServer.CMS.Model.PostComment do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - alias Accounts.Model.User - alias CMS.Model.{Post, PostCommentLike, PostCommentReply} - - alias Helper.HTML - - @required_fields ~w(body author_id post_id floor)a - @optional_fields ~w(reply_id)a - - @type t :: %PostComment{} - schema "posts_comments" do - field(:body, :string) - field(:floor, :integer) - belongs_to(:author, User, foreign_key: :author_id) - belongs_to(:post, Post, foreign_key: :post_id) - belongs_to(:reply_to, PostComment, foreign_key: :reply_id) - - has_many(:replies, {"posts_comments_replies", PostCommentReply}) - has_many(:likes, {"posts_comments_likes", PostCommentLike}) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%PostComment{} = post_comment, attrs) do - post_comment - |> cast(attrs, @required_fields ++ @optional_fields) - |> validate_required(@required_fields) - |> generl_changeset - end - - @doc false - def update_changeset(%PostComment{} = post_comment, attrs) do - post_comment - |> cast(attrs, @required_fields ++ @optional_fields) - |> generl_changeset - end - - defp generl_changeset(content) do - content - |> foreign_key_constraint(:post_id) - |> foreign_key_constraint(:author_id) - |> validate_length(:body, min: 3, max: 2000) - |> HTML.safe_string(:body) - end - - # @doc false - # def update_changeset(%PostComment{} = post_comment, attrs) do - # post_comment - # |> cast(attrs, @required_fields ++ @optional_fields) - # |> foreign_key_constraint(:post_id) - # |> foreign_key_constraint(:author_id) - # end -end diff --git a/lib/groupher_server/cms/models/post_comment_like.ex b/lib/groupher_server/cms/models/post_comment_like.ex deleted file mode 100644 index 1f649aba7..000000000 --- a/lib/groupher_server/cms/models/post_comment_like.ex +++ /dev/null @@ -1,31 +0,0 @@ -defmodule GroupherServer.CMS.Model.PostCommentLike do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - alias Accounts.Model.User - alias CMS.Model.PostComment - - @required_fields ~w(post_comment_id user_id)a - - @type t :: %PostCommentLike{} - schema "posts_comments_likes" do - belongs_to(:user, User, foreign_key: :user_id) - belongs_to(:post_comment, PostComment, foreign_key: :post_comment_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%PostCommentLike{} = post_comment_like, attrs) do - post_comment_like - |> 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_likes_user_id_post_comment_id_index) - end -end diff --git a/lib/groupher_server/cms/models/post_comment_reply.ex b/lib/groupher_server/cms/models/post_comment_reply.ex deleted file mode 100644 index 72eeb1b68..000000000 --- a/lib/groupher_server/cms/models/post_comment_reply.ex +++ /dev/null @@ -1,29 +0,0 @@ -defmodule GroupherServer.CMS.Model.PostCommentReply do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.CMS - alias CMS.Model.PostComment - - @required_fields ~w(post_comment_id reply_id)a - - @type t :: %PostCommentReply{} - schema "posts_comments_replies" do - belongs_to(:post_comment, PostComment, foreign_key: :post_comment_id) - belongs_to(:reply, PostComment, foreign_key: :reply_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%PostCommentReply{} = post_comment_reply, attrs) do - post_comment_reply - |> cast(attrs, @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:post_comment_id) - |> foreign_key_constraint(:reply_id) - end -end diff --git a/lib/groupher_server_web/middleware/cut_participators.ex b/lib/groupher_server_web/middleware/cut_participators.ex deleted file mode 100644 index 560665942..000000000 --- a/lib/groupher_server_web/middleware/cut_participators.ex +++ /dev/null @@ -1,32 +0,0 @@ -defmodule GroupherServerWeb.Middleware.CutParticipators do - @moduledoc """ - # cut comments participators manually by count - # this tem solution may have performace issue when the content's comments - # has too much participators - # - # NOTE: this is NOT the right solution - # should use WINDOW function - # see https://github.com/coderplanets/coderplanets_server/issues/16 - # - # the Enum.uniq logic is a tmp sulution for distinct comments users, this should be - # in dataloader logic, but the distinct is not working in production env - """ - - @behaviour Absinthe.Middleware - @default_length 5 - - def call(%{errors: errors} = resolution, _) when length(errors) > 0, do: resolution - - def call(%{value: value, arguments: %{filter: %{first: first}}} = resolution, _) do - %{resolution | value: value |> Enum.uniq() |> Enum.reverse() |> Enum.slice(0, first)} - end - - def call(%{value: value} = resolution, _) do - %{ - resolution - | value: value |> Enum.uniq() |> Enum.reverse() |> Enum.slice(0, @default_length) - } - end - - def call(resolution, _), do: resolution -end diff --git a/lib/groupher_server_web/middleware/passport_loader.ex b/lib/groupher_server_web/middleware/passport_loader.ex index d85d8b282..eacfd7b63 100644 --- a/lib/groupher_server_web/middleware/passport_loader.ex +++ b/lib/groupher_server_web/middleware/passport_loader.ex @@ -4,10 +4,9 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do """ @behaviour Absinthe.Middleware - import GroupherServer.CMS.Helper.MatcherOld + import GroupherServer.CMS.Helper.Matcher import Helper.Utils import Helper.ErrorCode - import ShortMaps alias Helper.ORM alias GroupherServer.CMS @@ -16,14 +15,11 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do def call(%{errors: errors} = resolution, _) when length(errors) > 0, do: resolution - def call( - %{context: %{cur_user: _}, arguments: ~m(community_id)a} = resolution, - source: :community - ) do - case ORM.find(Community, community_id) do + @doc "load community" + def call(%{context: %{cur_user: _}, arguments: arguments} = resolution, source: :community) do + case ORM.find(Community, arguments.community_id) do {:ok, community} -> - arguments = resolution.arguments |> Map.merge(%{passport_communities: [community]}) - %{resolution | arguments: arguments} + %{resolution | arguments: Map.put(arguments, :passport_communities, [community])} {:error, err_msg} -> resolution |> handle_absinthe_error(err_msg, ecode(:passport)) @@ -31,12 +27,12 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do end @doc "load article comment" - def call(%{context: %{cur_user: _}, arguments: ~m(id)a} = resolution, source: :article_comment) do + def call(%{context: %{cur_user: _}, arguments: %{id: id}} = resolution, source: :article_comment) do case ORM.find(ArticleComment, id, preload: :author) do {:ok, article_comment} -> resolution - |> load_owner_info(:article_comment, article_comment) - |> load_source(article_comment) + |> assign_owner_info(:article_comment, article_comment) + |> assign_source(article_comment) {:error, err_msg} -> resolution |> handle_absinthe_error(err_msg, ecode(:passport)) @@ -45,84 +41,37 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do # def call(%{context: %{cur_user: cur_user}, arguments: %{id: id}} = resolution, [source: .., base: ..]) do # Loader 应该使用 Map 作为参数,以方便模式匹配 - def call(%{context: %{cur_user: _}, arguments: %{id: id}} = resolution, args) do - {:ok, thread, react} = parse_source(args, resolution) - IO.inspect(thread, label: "thread") - IO.inspect(react, label: "react") - IO.inspect(match_action(thread, react), label: "match_action(thread, react)") - IO.inspect("-------") - - with {:ok, thread, react} <- parse_source(args, resolution), - {:ok, action} <- match_action(thread, react), - {:ok, preload} <- parse_preload(action, args), - {:ok, content} <- ORM.find(action.reactor, id, preload: preload) do + def call(%{context: %{cur_user: _}, arguments: %{id: id}} = resolution, source: thread) do + with {:ok, info} <- match(thread), + {:ok, article} <- ORM.find(info.model, id, preload: :author) do resolution - |> load_owner_info(react, content) - |> load_source(content) - |> load_community_info(content, args) + |> assign_owner_info(:article, article) + |> assign_source(article) + |> assign_article_communities_info(article, args) else - {:error, err_msg} -> - resolution - |> handle_absinthe_error(err_msg, ecode(:passport)) + {:error, err_msg} -> handle_absinthe_error(resolution, err_msg, ecode(:passport)) end end def call(resolution, _), do: resolution - def load_source(%{arguments: arguments} = resolution, content) do - %{resolution | arguments: Map.put(arguments, :passport_source, content)} - end - - # 取得 content 里面的 conmunities 字段 - def load_community_info(resolution, content, args) do - communities = content |> Map.get(parse_base(args)) - - # check if communities is a List - communities = if is_list(communities), do: communities, else: [communities] - - arguments = resolution.arguments |> Map.merge(%{passport_communities: communities}) - %{resolution | arguments: arguments} + def assign_source(%{arguments: arguments} = resolution, article) do + %{resolution | arguments: Map.put(arguments, :passport_source, article)} end - defp parse_preload(action, args) do - {:ok, _, react} = parse_source(args) + defp assign_owner_info(%{context: %{cur_user: cur_user}} = resolution, react, article) do + article_author_id = + if react == :article_comment, do: article.author.id, else: article.author.user_id - case react == :comment do - true -> {:ok, action.preload} - false -> {:ok, [action.preload, parse_base(args)]} - end - end - - def load_owner_info(%{context: %{cur_user: cur_user}} = resolution, react, content) do - content_author_id = - cond do - react == :article_comment -> content.author.id - react == :comment -> content.author.id - true -> content.author.user_id - end - - case content_author_id == cur_user.id do + case article_author_id == cur_user.id do true -> %{resolution | arguments: Map.put(resolution.arguments, :passport_is_owner, true)} _ -> resolution end end - # typical usage is delete_comment, should load conent by thread - defp parse_source([source: [:arg_thread, react]], %{arguments: %{thread: thread}}) do - parse_source(source: [thread, react]) - end - - defp parse_source(args, _resolution), do: parse_source(args) - - defp parse_source(args) do - case Keyword.has_key?(args, :source) do - false -> {:error, "Invalid.option: #{args}"} - true -> args |> Keyword.get(:source) |> match_source - end + # 取得 article 里面的 conmunities 字段 + defp assign_article_communities_info(resolution, article, args) do + arguments = resolution.arguments |> Map.merge(%{passport_communities: article.communities}) + %{resolution | arguments: arguments} end - - defp match_source([thread, react]), do: {:ok, thread, react} - defp match_source(thread), do: {:ok, thread, :self} - - defp parse_base(args), do: Keyword.get(args, :base) || :communities end diff --git a/lib/groupher_server_web/resolvers/cms_resolver.ex b/lib/groupher_server_web/resolvers/cms_resolver.ex index f86701ba1..dcb7df54c 100644 --- a/lib/groupher_server_web/resolvers/cms_resolver.ex +++ b/lib/groupher_server_web/resolvers/cms_resolver.ex @@ -344,14 +344,6 @@ defmodule GroupherServerWeb.Resolvers.CMS do CMS.paged_comments(thread, id, filter) end - def paged_comments_participators(_root, ~m(id thread filter)a, _info) do - CMS.paged_comments_participators(thread, id, filter) - end - - def paged_comments_participators(root, ~m(thread)a, _info) do - CMS.paged_comments_participators(thread, root.id, %{page: 1, size: 20}) - end - def create_comment(_root, ~m(thread id)a = args, %{context: %{cur_user: user}}) do CMS.create_comment(thread, id, args, user) end diff --git a/lib/groupher_server_web/schema/Helper/fields.ex b/lib/groupher_server_web/schema/Helper/fields.ex index f95f35920..1292ca08c 100644 --- a/lib/groupher_server_web/schema/Helper/fields.ex +++ b/lib/groupher_server_web/schema/Helper/fields.ex @@ -259,39 +259,6 @@ defmodule GroupherServerWeb.Schema.Helper.Fields do end end - # TODO: remove - defmacro comments_counter_fields(thread) do - quote do - # @dec "total comments of the post" - field :comments_count, :integer do - arg(:count, :count_type, default_value: :count) - - resolve(dataloader(CMS, :comments)) - middleware(M.ConvertToInt) - end - - # @desc "unique participator list of a the comments" - field :comments_participators, list_of(:user) do - arg(:filter, :members_filter) - - # middleware(M.ForceLoader) - middleware(M.PageSizeProof) - resolve(dataloader(CMS, :comments)) - middleware(M.CutParticipators) - end - - field(:paged_comments_participators, :paged_users) do - arg( - :thread, - unquote(String.to_atom("#{to_string(thread)}_thread")), - default_value: unquote(thread) - ) - - resolve(&R.CMS.paged_comments_participators/3) - end - end - end - @doc """ general collect folder meta info """ diff --git a/lib/groupher_server_web/schema/cms/cms_queries.ex b/lib/groupher_server_web/schema/cms/cms_queries.ex index cc025972e..e57e7a7d0 100644 --- a/lib/groupher_server_web/schema/cms/cms_queries.ex +++ b/lib/groupher_server_web/schema/cms/cms_queries.ex @@ -127,16 +127,6 @@ defmodule GroupherServerWeb.Schema.CMS.Queries do resolve(&R.CMS.paged_comments/3) end - @desc "get paged comments participators" - field :paged_comments_participators, :paged_users do - arg(:id, non_null(:id)) - arg(:thread, :thread, default_value: :post) - arg(:filter, :paged_filter) - - middleware(M.PageSizeProof) - resolve(&R.CMS.paged_comments_participators/3) - end - # comments # TODO: remove field :comments, :paged_comments do diff --git a/lib/groupher_server_web/schema/cms/cms_types.ex b/lib/groupher_server_web/schema/cms/cms_types.ex index 5225f1830..645dc9370 100644 --- a/lib/groupher_server_web/schema/cms/cms_types.ex +++ b/lib/groupher_server_web/schema/cms/cms_types.ex @@ -63,29 +63,6 @@ defmodule GroupherServerWeb.Schema.CMS.Types do field(:copy_right, :string) field(:body, :string) - field :comments, list_of(:comment) do - arg(:filter, :members_filter) - - middleware(M.PageSizeProof) - resolve(dataloader(CMS, :comments)) - end - - comments_counter_fields(:post) - - @desc "totalCount of unique participator list of a the comments" - field :comments_participators_count, :integer do - resolve(fn post, _args, %{context: %{loader: loader}} -> - loader - |> Dataloader.load(CMS, {:one, CMS.Model.PostComment}, cp_count: post.id) - |> on_load(fn loader -> - {:ok, Dataloader.get(loader, CMS, {:one, CMS.Model.PostComment}, cp_count: post.id)} - end) - end) - end - - # upvoted_count ? - # collected_count - timestamp_fields(:article) end diff --git a/lib/groupher_server_web/schema/cms/mutations/comment.ex b/lib/groupher_server_web/schema/cms/mutations/comment.ex index 3a98080c7..d10000f8a 100644 --- a/lib/groupher_server_web/schema/cms/mutations/comment.ex +++ b/lib/groupher_server_web/schema/cms/mutations/comment.ex @@ -88,66 +88,5 @@ defmodule GroupherServerWeb.Schema.CMS.Mutations.Comment do middleware(M.Authorize, :login) resolve(&R.CMS.undo_mark_comment_solution/3) end - - ############################ - ############################ - ############################ - ############################ - - @desc "create a comment" - field :create_comment, :comment do - # TODO use thread and force community pass-in - arg(:community, non_null(:string)) - arg(:thread, :thread, default_value: :post) - arg(:id, non_null(:id)) - arg(:body, non_null(:string)) - arg(:mention_users, list_of(:ids)) - - # TDOO: use a comment resolver - middleware(M.Authorize, :login) - # TODO: 文章作者可以删除评论,文章可以设置禁止评论 - resolve(&R.CMS.create_comment/3) - middleware(M.Statistics.MakeContribute, for: :user) - end - - @desc "update a comment" - field :update_comment, :comment do - arg(:id, non_null(:id)) - arg(:thread, :thread, default_value: :post) - arg(:body, non_null(:string)) - - # TDOO: use a comment resolver - middleware(M.Authorize, :login) - resolve(&R.CMS.update_comment/3) - end - - @desc "delete a comment" - field :delete_comment, :comment do - arg(:thread, :thread, default_value: :post) - arg(:id, non_null(:id)) - - middleware(M.Authorize, :login) - # middleware(M.PassportLoader, source: [:post, :comment]) - middleware(M.PassportLoader, source: [:arg_thread, :comment]) - # TODO: 文章可以设置禁止评论 - # middleware(M.Passport, claim: "owner;cms->c?->post.comment.delete") - middleware(M.Passport, claim: "owner") - # middleware(M.Authorize, :login) - resolve(&R.CMS.delete_comment/3) - end - - @desc "reply a exsiting comment" - field :reply_comment, :comment do - arg(:community, non_null(:string)) - arg(:thread, non_null(:thread), default_value: :post) - arg(:id, non_null(:id)) - arg(:body, non_null(:string)) - arg(:mention_users, list_of(:ids)) - - middleware(M.Authorize, :login) - - resolve(&R.CMS.reply_comment/3) - middleware(M.Statistics.MakeContribute, for: :user) - end end end diff --git a/test/groupher_server_web/mutation/cms/cms_manager_test.exs b/test/groupher_server_web/mutation/cms/cms_manager_test.exs index 6594f6fa5..b80f189c8 100644 --- a/test/groupher_server_web/mutation/cms/cms_manager_test.exs +++ b/test/groupher_server_web/mutation/cms/cms_manager_test.exs @@ -2,7 +2,7 @@ defmodule GroupherServer.Test.Mutation.CMS.Manager do use GroupherServer.TestTools alias GroupherServer.CMS - alias CMS.Model.{Post, PostComment} + alias CMS.Model.Post alias Helper.ORM setup do @@ -60,23 +60,5 @@ defmodule GroupherServer.Test.Mutation.CMS.Manager do assert deleted["id"] == to_string(post.id) assert {:error, _} = ORM.find(Post, deleted["id"]) end - - test "root can delete a post with comment", ~m(post community user)a do - passport_rules = %{"root" => true} - rule_conn = simu_conn(:user, cms: passport_rules) - - body = "this is a test comment" - - {:ok, comment} = - CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - {:ok, _} = ORM.find(PostComment, comment.id) - - deleted = rule_conn |> mutation_result(@query, %{id: post.id}, "deletePost") - - assert deleted["id"] == to_string(post.id) - assert {:error, _} = ORM.find(Post, deleted["id"]) - assert {:error, _error} = ORM.find(PostComment, comment.id) - end end end diff --git a/test/groupher_server_web/mutation/cms/old_post_comment_test.exs b/test/groupher_server_web/mutation/cms/old_post_comment_test.exs deleted file mode 100644 index 5725550c9..000000000 --- a/test/groupher_server_web/mutation/cms/old_post_comment_test.exs +++ /dev/null @@ -1,255 +0,0 @@ -defmodule GroupherServer.Test.Mutation.OldPostComment do - use GroupherServer.TestTools - - alias GroupherServer.{CMS, Delivery} - alias CMS.Model.PostComment - - alias Helper.ORM - - setup do - {:ok, post} = db_insert(:post) - {:ok, user} = db_insert(:user) - {:ok, community} = db_insert(:community) - - guest_conn = simu_conn(:guest) - user_conn = simu_conn(:user, user) - - {:ok, comment} = - CMS.create_comment(:post, post.id, %{community: community.raw, body: "test comment"}, user) - - {:ok, ~m(user_conn guest_conn post user community comment)a} - end - - describe "[post comment CURD]" do - @create_comment_query """ - mutation( - $community: String! - $thread: Thread - $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 post", ~m(user_conn community post)a do - variables = %{community: community.raw, thread: "POST", id: post.id, body: "this a comment"} - created = user_conn |> mutation_result(@create_comment_query, variables, "createComment") - - {:ok, found} = ORM.find(PostComment, created["id"]) - - assert created["id"] == to_string(found.id) - end - - test "xss comment should be escaped", ~m(user_conn community post)a do - variables = %{ - community: community.raw, - thread: "POST", - id: post.id, - body: assert_v(:xss_string) - } - - created = user_conn |> mutation_result(@create_comment_query, variables, "createComment") - - {:ok, found} = ORM.find(PostComment, created["id"]) - - assert created["id"] == to_string(found.id) - assert created["body"] == assert_v(:xss_safe_string) - end - - test "guest user create comment fails", ~m(guest_conn post community)a do - variables = %{community: community.raw, thread: "POST", id: post.id, body: "this a comment"} - - assert guest_conn - |> mutation_get_error?(@create_comment_query, variables, ecode(:account_login)) - end - - test "can mention other user when create comment to post", ~m(user_conn community post)a do - {:ok, user2} = db_insert(:user) - - comment_body = "this is a comment" - - variables = - %{community: community.raw, thread: "POST", id: post.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 == post.title - assert the_mention.source_type == "comment" - assert the_mention.parent_id == to_string(post.id) - assert the_mention.parent_type == "post" - assert the_mention.source_preview == comment_body - end - - @delete_comment_query """ - mutation($thread: Thread, $id: ID!) { - deleteComment(thread: $thread, id: $id) { - id - body - } - } - """ - @tag :wip - test "comment owner can delete comment", ~m(user community post)a do - variables = %{community: community.raw, id: post.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, %{id: created["id"]}, "deleteComment") - - assert deleted["id"] == created["id"] - end - - test "unauth user delete comment fails", ~m(user_conn guest_conn community post)a do - variables = %{community: community.raw, id: post.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: Thread - $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: "POST", - 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 "should mention author when reply to a comment", ~m(community post user)a do - body = "this is a comment" - - {:ok, comment} = - CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - variables = %{ - community: community.raw, - thread: "POST", - 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(post.id) - assert the_mention.parent_type == "post" - end - - test "can mention others in a reply", ~m(community post user user_conn)a do - body = "this is a comment" |> String.duplicate(100) - reply_body = "this is a reply" |> String.duplicate(100) - {:ok, user2} = db_insert(:user) - - {:ok, comment} = - CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - variables = %{ - community: community.raw, - thread: "POST", - id: comment.id, - body: reply_body, - 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 String.contains?(comment.body, the_mention.source_title) - assert the_mention.source_type == "comment_reply" - assert String.contains?(reply_body, the_mention.source_preview) - assert the_mention.parent_id == to_string(post.id) - assert the_mention.parent_type == "post" - end - - test "guest user reply comment fails", ~m(guest_conn comment)a do - variables = %{thread: "POST", id: comment.id, body: "this a reply"} - - assert guest_conn |> mutation_get_error?(@reply_comment_query, variables) - 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 -end diff --git a/test/groupher_server_web/query/cms/old_post_comment_test.exs b/test/groupher_server_web/query/cms/old_post_comment_test.exs deleted file mode 100644 index 0d41ef65f..000000000 --- a/test/groupher_server_web/query/cms/old_post_comment_test.exs +++ /dev/null @@ -1,252 +0,0 @@ -defmodule GroupherServer.Test.Query.OldPostComment do - use GroupherServer.TestTools - - alias GroupherServer.CMS - - setup do - {:ok, post} = db_insert(:post) - {:ok, user} = db_insert(:user) - {:ok, community} = db_insert(:community) - - guest_conn = simu_conn(:guest) - user_conn = simu_conn(:user) - - {:ok, ~m(user_conn guest_conn post user community)a} - end - - describe "[post dataloader comment]" do - @query """ - query($filter: PagedPostsFilter) { - pagedPosts(filter: $filter) { - entries { - id - title - commentsParticipatorsCount - commentsParticipators(filter: { first: 5 }) { - id - nickname - } - pagedCommentsParticipators { - entries { - id - nickname - } - totalCount - } - commentsCount - } - totalCount - } - } - """ - - # test "can get comments participators of a post", ~m(user guest_conn)a do - # {:ok, user2} = db_insert(:user) - - # {:ok, community} = db_insert(:community) - # {:ok, post} = CMS.create_article(community, :post, mock_attrs(:post), user) - - # variables = %{filter: %{community: community.raw}} - # results = guest_conn |> query_result(@query, variables, "pagedPosts") - - # comments_participators_count = - # results["entries"] |> List.first() |> Map.get("commentsParticipatorsCount") - - # assert comments_participators_count == 0 - - # body = "this is a test comment" - - # assert {:ok, _comment} = - # CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - # assert {:ok, _comment} = - # CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - # assert {:ok, _comment} = - # CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user2) - - # variables = %{filter: %{community: community.raw}} - # results = guest_conn |> query_result(@query, variables, "pagedPosts") - - # comments_participators_count = - # results["entries"] |> List.first() |> Map.get("commentsParticipatorsCount") - - # comments_count = results["entries"] |> List.first() |> Map.get("commentsCount") - - # assert comments_participators_count == 2 - # assert comments_count == 3 - - # comments_participators = - # results["entries"] |> List.first() |> Map.get("commentsParticipators") - - # assert comments_participators |> Enum.any?(&(&1["id"] == to_string(user.id))) - # assert comments_participators |> Enum.any?(&(&1["id"] == to_string(user2.id))) - # end - - # test "can get comments participators of a post with multi user", ~m(user guest_conn)a do - # body = "this is a test comment" - # {:ok, community} = db_insert(:community) - # {:ok, post1} = CMS.create_article(community, :post, mock_attrs(:post), user) - # {:ok, post2} = CMS.create_article(community, :post, mock_attrs(:post), user) - - # {:ok, users_list} = db_insert_multi(:user, 10) - # {:ok, users_list2} = db_insert_multi(:user, 10) - - # Enum.each( - # users_list, - # &CMS.create_comment(:post, post1.id, %{community: community.raw, body: body}, &1) - # ) - - # Enum.each( - # users_list2, - # &CMS.create_comment(:post, post2.id, %{community: community.raw, body: body}, &1) - # ) - - # variables = %{filter: %{community: community.raw}} - # results = guest_conn |> query_result(@query, variables, "pagedPosts") - - # assert results["entries"] |> List.first() |> Map.get("commentsParticipators") |> length == 5 - # assert results["entries"] |> List.first() |> Map.get("commentsParticipatorsCount") == 10 - - # assert results["entries"] |> List.last() |> Map.get("commentsParticipators") |> length == 5 - # assert results["entries"] |> List.last() |> Map.get("commentsParticipatorsCount") == 10 - # end - - # test "can get paged commetns participators of a post", ~m(user guest_conn)a do - # body = "this is a test comment" - - # {:ok, community} = db_insert(:community) - # {:ok, post} = CMS.create_article(community, :post, mock_attrs(:post), user) - # {:ok, users_list} = db_insert_multi(:user, 10) - - # Enum.each( - # users_list, - # &CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, &1) - # ) - - # variables = %{filter: %{community: community.raw}} - # results = guest_conn |> query_result(@query, variables, "pagedPosts") - # participators = results["entries"] |> List.first() |> Map.get("pagedCommentsParticipators") - - # assert participators["totalCount"] == 10 - # end - end - - @query """ - query($id: ID!, $thread: Thread, $filter: PagedFilter!) { - pagedCommentsParticipators(id: $id, thread: $thread, filter: $filter) { - entries { - id - nickname - } - totalPages - totalCount - pageSize - pageNumber - } - } - """ - test "can get post's paged commetns participators", ~m(user guest_conn)a do - body = "this is a test comment" - - {:ok, community} = db_insert(:community) - {:ok, post} = CMS.create_article(community, :post, mock_attrs(:post), user) - {:ok, users_list} = db_insert_multi(:user, 10) - - Enum.each( - users_list, - &CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, &1) - ) - - variables = %{id: post.id, thread: "POST", 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 :paged_replies - # TODO: filter comment by time / like / reply - describe "[post comment]" do - @query """ - query($id: ID!, $filter: CommentsFilter!) { - pagedComments(id: $id, filter: $filter) { - entries { - id - likesCount - } - totalPages - totalCount - pageSize - pageNumber - } - } - """ - - test "guest user can get a paged comment", ~m(guest_conn post user community)a do - body = "test comment" - - Enum.reduce(1..30, [], fn _, acc -> - {:ok, value} = - CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - acc ++ [value] - end) - - variables = %{id: post.id, filter: %{page: 1, size: 10}} - results = guest_conn |> query_result(@query, variables, "pagedComments") - - assert results |> is_valid_pagination? - assert results["totalCount"] == 30 - end - - @query """ - query($id: ID!, $filter: CommentsFilter!) { - pagedComments(id: $id, filter: $filter) { - entries { - id - body - replyTo { - id - body - } - repliesCount - replies { - id - body - } - } - } - } - """ - test "guest user can get replies 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, reply} = - CMS.reply_comment( - :post, - comment.id, - %{community: community.raw, body: "reply body"}, - 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() - - 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 From ef6f787f847e6ea907fc0cb9c345e51e5e8e0f62 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 22:19:22 +0800 Subject: [PATCH 17/28] feat(blog-thread): remove old publish comment & macther --- lib/groupher_server/accounts/accounts.ex | 1 - .../accounts/delegates/publish.ex | 17 -- .../cms/delegates/comment_curd.ex | 242 +++++++++++++++++ lib/groupher_server/cms/helper/matcher_old.ex | 79 ------ .../cms/models/post_comment.ex | 61 +++++ .../cms/models/post_comment_like.ex | 31 +++ .../cms/models/post_comment_reply.ex | 29 ++ .../middleware/cut_participators.ex | 32 +++ .../resolvers/accounts_resolver.ex | 9 - .../schema/account/account_queries.ex | 10 - .../accounts/published_comments_test.exs | 54 ---- .../mutation/cms/old_post_comment_test.exs | 255 ++++++++++++++++++ .../query/cms/old_post_comment_test.exs | 252 +++++++++++++++++ 13 files changed, 902 insertions(+), 170 deletions(-) create mode 100644 lib/groupher_server/cms/delegates/comment_curd.ex delete mode 100644 lib/groupher_server/cms/helper/matcher_old.ex create mode 100644 lib/groupher_server/cms/models/post_comment.ex create mode 100644 lib/groupher_server/cms/models/post_comment_like.ex create mode 100644 lib/groupher_server/cms/models/post_comment_reply.ex create mode 100644 lib/groupher_server_web/middleware/cut_participators.ex delete mode 100644 test/groupher_server/accounts/published_comments_test.exs create mode 100644 test/groupher_server_web/mutation/cms/old_post_comment_test.exs create mode 100644 test/groupher_server_web/query/cms/old_post_comment_test.exs diff --git a/lib/groupher_server/accounts/accounts.ex b/lib/groupher_server/accounts/accounts.ex index 5eb3a35e4..f79aec453 100644 --- a/lib/groupher_server/accounts/accounts.ex +++ b/lib/groupher_server/accounts/accounts.ex @@ -47,7 +47,6 @@ defmodule GroupherServer.Accounts do # publish defdelegate paged_published_articles(user, thread, filter), to: Publish - defdelegate published_comments(user, thread, filter), to: Publish defdelegate paged_published_article_comments(user, thread, filter), to: Publish defdelegate paged_published_article_comments(user, thread), to: Publish defdelegate update_published_states(user, thread), to: Publish diff --git a/lib/groupher_server/accounts/delegates/publish.ex b/lib/groupher_server/accounts/delegates/publish.ex index ea6552af0..4182cec9a 100644 --- a/lib/groupher_server/accounts/delegates/publish.ex +++ b/lib/groupher_server/accounts/delegates/publish.ex @@ -8,7 +8,6 @@ defmodule GroupherServer.Accounts.Delegate.Publish do import ShortMaps import GroupherServer.CMS.Helper.Matcher - import GroupherServer.CMS.Helper.MatcherOld alias GroupherServer.Accounts.Model.{Embeds, User} alias GroupherServer.CMS.Model.ArticleComment @@ -89,20 +88,4 @@ defmodule GroupherServer.Accounts.Delegate.Publish do |> done() end end - - @doc """ - get paged published comments of a user - """ - def published_comments(%User{id: user_id}, thread, %{page: page, size: size} = filter) do - with {:ok, user} <- ORM.find(User, user_id), - {:ok, content} <- match_action(thread, :comment) do - content.reactor - |> join(:inner, [comment], author in assoc(comment, :author)) - |> where([comment, author], author.id == ^user.id) - |> select([comment, author], comment) - |> QueryBuilder.filter_pack(filter) - |> ORM.paginater(~m(page size)a) - |> done() - end - end end diff --git a/lib/groupher_server/cms/delegates/comment_curd.ex b/lib/groupher_server/cms/delegates/comment_curd.ex new file mode 100644 index 000000000..e1578ef1c --- /dev/null +++ b/lib/groupher_server/cms/delegates/comment_curd.ex @@ -0,0 +1,242 @@ +defmodule GroupherServer.CMS.Delegate.CommentCURD do + @moduledoc """ + CURD for comments + """ + import Ecto.Query, warn: false + import Helper.Utils, only: [done: 1] + import Helper.ErrorCode + + import ShortMaps + + alias GroupherServer.{Accounts, CMS, Delivery, Repo} + + alias Accounts.Model.User + alias CMS.Model.{Post, PostComment, PostCommentReply} + + alias Helper.{ORM, QueryBuilder} + alias Ecto.Multi + + defp match_action(:post, :comment), + do: {:ok, %{target: Post, reactor: PostComment, preload: :author}} + + @doc """ + Creates a comment for psot, job ... + """ + def create_comment( + thread, + content_id, + %{community: community, body: body} = args, + %User{id: user_id} + ) do + with {:ok, action} <- match_action(:post, :comment), + {:ok, content} <- ORM.find(action.target, content_id), + {:ok, user} <- ORM.find(User, user_id) do + Multi.new() + |> Multi.run(:create_comment, fn _, _ -> + do_create_comment(thread, action, content, body, 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() + |> create_comment_result() + end + end + + def reply_comment( + thread, + comment_id, + %{community: community, body: body} = args, + %User{id: user_id} = user + ) do + with {:ok, action} <- match_action(:post, :comment), + {:ok, comment} <- ORM.find(action.reactor, comment_id) do + next_floor = get_next_floor(thread, action.reactor, comment) + + attrs = %{ + author_id: user_id, + body: body, + reply_to: comment, + floor: next_floor, + mention_users: Map.get(args, :mention_users, []) + } + + Delivery.mention_from_comment_reply(community, thread, comment, attrs, user) + attrs = merge_reply_attrs(thread, attrs, comment) + bridge_reply(thread, action.reactor, comment, attrs) + end + end + + @doc """ + Creates a comment for psot, job ... + """ + def update_comment(thread, id, %{body: body}, %User{id: user_id}) do + with {:ok, action} <- match_action(:post, :comment), + {:ok, content} <- ORM.find(action.reactor, id), + true <- content.author_id == user_id do + ORM.update(content, %{body: body}) + end + end + + @doc """ + Delete the comment and increase all the floor after this comment + """ + def delete_comment(thread, content_id) do + with {:ok, action} <- match_action(:post, :comment), + {:ok, comment} <- ORM.find(action.reactor, content_id) do + Multi.new() + |> Multi.run(:delete_comment, fn _, _ -> + ORM.delete(comment) + end) + |> Multi.run(:update_floor, fn _, _ -> + exec_update_floor(action.reactor, comment) + end) + |> Repo.transaction() + |> delete_comment_result() + end + end + + @doc """ + list paged comments + """ + def paged_comments(thread, content_id, %{page: page, size: size} = filters) do + with {:ok, action} <- match_action(:post, :comment) do + dynamic = dynamic_comment_where(thread, content_id) + + action.reactor + |> where(^dynamic) + |> QueryBuilder.filter_pack(filters) + |> ORM.paginater(~m(page size)a) + |> done() + end + end + + @doc """ + list paged comments participators + """ + def paged_comments_participators(thread, content_id, %{page: page, size: size} = filters) do + with {:ok, action} <- match_action(:post, :comment) do + dynamic = dynamic_comment_where(thread, content_id) + + action.reactor + |> where(^dynamic) + |> QueryBuilder.filter_pack(filters) + |> join(:inner, [c], a in assoc(c, :author)) + |> distinct([c, a], a.id) + # new added when upgrade to ecto v3 + |> group_by([c, a], a.id) + |> group_by([c, a], c.inserted_at) + # new added when upgrade to ecto v3 end + |> select([c, a], a) + |> ORM.paginater(~m(page size)a) + |> done() + end + end + + def paged_replies(thread, comment_id, %User{id: user_id}) do + with {:ok, action} <- match_action(:post, :comment) do + action.reactor + |> where([c], c.author_id == ^user_id) + |> join(:inner, [c], r in assoc(c, :reply_to)) + |> where([c, r], r.id == ^comment_id) + |> Repo.all() + |> done() + end + end + + defp do_create_comment(thread, action, content, body, user) do + next_floor = get_next_floor(thread, action.reactor, content.id) + + attrs = %{ + author_id: user.id, + body: body, + floor: next_floor + } + + attrs = merge_comment_attrs(thread, attrs, content.id) + + action.reactor |> ORM.create(attrs) + end + + defp create_comment_result({:ok, %{create_comment: result}}), do: {:ok, result} + + defp create_comment_result({:error, :create_comment, result, _steps}) do + {:error, result} + end + + defp delete_comment_result({:ok, %{delete_comment: result}}), do: {:ok, result} + + defp delete_comment_result({:error, :delete_comment, _result, _steps}) do + {:error, [message: "delete comment fails", code: ecode(:delete_fails)]} + end + + defp delete_comment_result({:error, :update_floor, _result, _steps}) do + {:error, [message: "update follor fails", code: ecode(:delete_fails)]} + end + + defp exec_update_floor(queryable, comment) do + Repo.update_all( + from(p in queryable, where: p.id > ^comment.id), + inc: [floor: -1] + ) + |> done() + |> case do + {:ok, _} -> {:ok, comment} + {:error, _} -> {:error, ""} + end + end + + # simulate a join connection + # TODO: use Multi task to refactor + # TODO: refactor boilerplate code + defp bridge_reply(:post, queryable, comment, attrs) do + with {:ok, reply} <- ORM.create(queryable, attrs) do + ORM.update(reply, %{reply_id: comment.id}) + + {:ok, _} = + PostCommentReply |> ORM.create(%{post_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) + + queryable + |> where(^dynamic) + |> ORM.next_count() + end + + # for reply comment + defp get_next_floor(thread, queryable, comment) do + dynamic = dynamic_reply_where(thread, comment) + + queryable + |> where(^dynamic) + |> ORM.next_count() + end + + # merge_comment_attrs when create comemnt + defp merge_comment_attrs(:post, attrs, id), do: attrs |> Map.merge(%{post_id: id}) + defp merge_comment_attrs(:job, attrs, id), do: attrs |> Map.merge(%{job_id: id}) + defp merge_comment_attrs(:repo, attrs, id), do: attrs |> Map.merge(%{repo_id: id}) + + defp merge_reply_attrs(:post, attrs, comment), + do: attrs |> Map.merge(%{post_id: comment.post_id}) + + defp merge_reply_attrs(:job, attrs, comment), do: attrs |> Map.merge(%{job_id: comment.job_id}) + + defp merge_reply_attrs(:repo, attrs, comment), + do: attrs |> Map.merge(%{repo_id: comment.repo_id}) + + defp dynamic_comment_where(:post, id), do: dynamic([c], c.post_id == ^id) + defp dynamic_comment_where(:job, id), do: dynamic([c], c.job_id == ^id) + defp dynamic_comment_where(:repo, id), do: dynamic([c], c.repo_id == ^id) + + defp dynamic_reply_where(:post, comment), do: dynamic([c], c.post_id == ^comment.post_id) + defp dynamic_reply_where(:job, comment), do: dynamic([c], c.job_id == ^comment.job_id) + defp dynamic_reply_where(:repo, comment), do: dynamic([c], c.repo_id == ^comment.repo_id) +end diff --git a/lib/groupher_server/cms/helper/matcher_old.ex b/lib/groupher_server/cms/helper/matcher_old.ex deleted file mode 100644 index 27a209208..000000000 --- a/lib/groupher_server/cms/helper/matcher_old.ex +++ /dev/null @@ -1,79 +0,0 @@ -defmodule GroupherServer.CMS.Helper.MatcherOld do - @moduledoc """ - this module defined the matches and handy guard ... - """ - import Ecto.Query, warn: false - - alias GroupherServer.CMS.Model.{ - Community, - # threads - Post, - Repo, - Job, - Blog, - # viewer - # reactions - # comments - PostComment, - # commtnes reaction - PostCommentLike, - # - Community - } - - ######################################### - ## posts ... - ######################################### - def match_action(:post, :self), - do: {:ok, %{target: Post, reactor: Post, preload: :author}} - - def match_action(:post, :community), - do: {:ok, %{target: Post, reactor: Community}} - - def match_action(:post, :comment), - do: {:ok, %{target: Post, reactor: PostComment, preload: :author}} - - ######################################### - ## jobs ... - ######################################### - def match_action(:job, :self), - do: {:ok, %{target: Job, reactor: Job, preload: :author}} - - def match_action(:job, :community), - do: {:ok, %{target: Job, reactor: Community}} - - def match_action(:blog, :self), - do: {:ok, %{target: Blog, reactor: Blog, preload: :author}} - - def match_action(:blog, :community), - do: {:ok, %{target: Blog, reactor: Community}} - - ######################################### - ## repos ... - ######################################### - def match_action(:repo, :self), - do: {:ok, %{target: Repo, reactor: Repo, preload: :author}} - - def match_action(:repo, :community), - do: {:ok, %{target: Repo, reactor: Community}} - - # dynamic where query match - def dynamic_where(thread, id) do - case thread do - :post -> - {:ok, dynamic([p], p.post_id == ^id)} - - :post_comment -> - {:ok, dynamic([p], p.post_comment_id == ^id)} - - :job -> - {:ok, dynamic([p], p.job_id == ^id)} - - :repo -> - {:ok, dynamic([p], p.repo_id == ^id)} - - _ -> - {:error, 'where is not match'} - end - end -end diff --git a/lib/groupher_server/cms/models/post_comment.ex b/lib/groupher_server/cms/models/post_comment.ex new file mode 100644 index 000000000..417af9c41 --- /dev/null +++ b/lib/groupher_server/cms/models/post_comment.ex @@ -0,0 +1,61 @@ +defmodule GroupherServer.CMS.Model.PostComment do + @moduledoc false + alias __MODULE__ + + use Ecto.Schema + import Ecto.Changeset + + alias GroupherServer.{Accounts, CMS} + alias Accounts.Model.User + alias CMS.Model.{Post, PostCommentLike, PostCommentReply} + + alias Helper.HTML + + @required_fields ~w(body author_id post_id floor)a + @optional_fields ~w(reply_id)a + + @type t :: %PostComment{} + schema "posts_comments" do + field(:body, :string) + field(:floor, :integer) + belongs_to(:author, User, foreign_key: :author_id) + belongs_to(:post, Post, foreign_key: :post_id) + belongs_to(:reply_to, PostComment, foreign_key: :reply_id) + + has_many(:replies, {"posts_comments_replies", PostCommentReply}) + has_many(:likes, {"posts_comments_likes", PostCommentLike}) + + timestamps(type: :utc_datetime) + end + + @doc false + def changeset(%PostComment{} = post_comment, attrs) do + post_comment + |> cast(attrs, @required_fields ++ @optional_fields) + |> validate_required(@required_fields) + |> generl_changeset + end + + @doc false + def update_changeset(%PostComment{} = post_comment, attrs) do + post_comment + |> cast(attrs, @required_fields ++ @optional_fields) + |> generl_changeset + end + + defp generl_changeset(content) do + content + |> foreign_key_constraint(:post_id) + |> foreign_key_constraint(:author_id) + |> validate_length(:body, min: 3, max: 2000) + |> HTML.safe_string(:body) + end + + # @doc false + # def update_changeset(%PostComment{} = post_comment, attrs) do + # post_comment + # |> cast(attrs, @required_fields ++ @optional_fields) + # |> foreign_key_constraint(:post_id) + # |> foreign_key_constraint(:author_id) + # end +end diff --git a/lib/groupher_server/cms/models/post_comment_like.ex b/lib/groupher_server/cms/models/post_comment_like.ex new file mode 100644 index 000000000..1f649aba7 --- /dev/null +++ b/lib/groupher_server/cms/models/post_comment_like.ex @@ -0,0 +1,31 @@ +defmodule GroupherServer.CMS.Model.PostCommentLike do + @moduledoc false + alias __MODULE__ + + use Ecto.Schema + import Ecto.Changeset + + alias GroupherServer.{Accounts, CMS} + alias Accounts.Model.User + alias CMS.Model.PostComment + + @required_fields ~w(post_comment_id user_id)a + + @type t :: %PostCommentLike{} + schema "posts_comments_likes" do + belongs_to(:user, User, foreign_key: :user_id) + belongs_to(:post_comment, PostComment, foreign_key: :post_comment_id) + + timestamps(type: :utc_datetime) + end + + @doc false + def changeset(%PostCommentLike{} = post_comment_like, attrs) do + post_comment_like + |> 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_likes_user_id_post_comment_id_index) + end +end diff --git a/lib/groupher_server/cms/models/post_comment_reply.ex b/lib/groupher_server/cms/models/post_comment_reply.ex new file mode 100644 index 000000000..72eeb1b68 --- /dev/null +++ b/lib/groupher_server/cms/models/post_comment_reply.ex @@ -0,0 +1,29 @@ +defmodule GroupherServer.CMS.Model.PostCommentReply do + @moduledoc false + alias __MODULE__ + + use Ecto.Schema + import Ecto.Changeset + + alias GroupherServer.CMS + alias CMS.Model.PostComment + + @required_fields ~w(post_comment_id reply_id)a + + @type t :: %PostCommentReply{} + schema "posts_comments_replies" do + belongs_to(:post_comment, PostComment, foreign_key: :post_comment_id) + belongs_to(:reply, PostComment, foreign_key: :reply_id) + + timestamps(type: :utc_datetime) + end + + @doc false + def changeset(%PostCommentReply{} = post_comment_reply, attrs) do + post_comment_reply + |> cast(attrs, @required_fields) + |> validate_required(@required_fields) + |> foreign_key_constraint(:post_comment_id) + |> foreign_key_constraint(:reply_id) + end +end diff --git a/lib/groupher_server_web/middleware/cut_participators.ex b/lib/groupher_server_web/middleware/cut_participators.ex new file mode 100644 index 000000000..560665942 --- /dev/null +++ b/lib/groupher_server_web/middleware/cut_participators.ex @@ -0,0 +1,32 @@ +defmodule GroupherServerWeb.Middleware.CutParticipators do + @moduledoc """ + # cut comments participators manually by count + # this tem solution may have performace issue when the content's comments + # has too much participators + # + # NOTE: this is NOT the right solution + # should use WINDOW function + # see https://github.com/coderplanets/coderplanets_server/issues/16 + # + # the Enum.uniq logic is a tmp sulution for distinct comments users, this should be + # in dataloader logic, but the distinct is not working in production env + """ + + @behaviour Absinthe.Middleware + @default_length 5 + + def call(%{errors: errors} = resolution, _) when length(errors) > 0, do: resolution + + def call(%{value: value, arguments: %{filter: %{first: first}}} = resolution, _) do + %{resolution | value: value |> Enum.uniq() |> Enum.reverse() |> Enum.slice(0, first)} + end + + def call(%{value: value} = resolution, _) do + %{ + resolution + | value: value |> Enum.uniq() |> Enum.reverse() |> Enum.slice(0, @default_length) + } + end + + def call(resolution, _), do: resolution +end diff --git a/lib/groupher_server_web/resolvers/accounts_resolver.ex b/lib/groupher_server_web/resolvers/accounts_resolver.ex index e7d7a3e7a..888d09b96 100644 --- a/lib/groupher_server_web/resolvers/accounts_resolver.ex +++ b/lib/groupher_server_web/resolvers/accounts_resolver.ex @@ -207,15 +207,6 @@ defmodule GroupherServerWeb.Resolvers.Accounts do end end - # published comments - def published_comments(_root, ~m(user_id filter thread)a, _info) do - Accounts.published_comments(%User{id: user_id}, thread, filter) - end - - def published_comments(_root, ~m(filter thread)a, %{context: %{cur_user: cur_user}}) do - Accounts.published_comments(cur_user, thread, filter) - end - # paged communities which the user it's the editor def editable_communities(_root, ~m(login filter)a, _info) do with {:ok, user_id} <- Accounts.get_userid_and_cache(login) do diff --git a/lib/groupher_server_web/schema/account/account_queries.ex b/lib/groupher_server_web/schema/account/account_queries.ex index 9d31b9d58..d10df1695 100644 --- a/lib/groupher_server_web/schema/account/account_queries.ex +++ b/lib/groupher_server_web/schema/account/account_queries.ex @@ -111,16 +111,6 @@ defmodule GroupherServerWeb.Schema.Account.Queries do resolve(&R.Accounts.search_users/3) end - @desc "get paged published comments on post" - field :published_post_comments, :paged_post_comments do - arg(:user_id, non_null(:id)) - arg(:filter, non_null(:paged_filter)) - arg(:thread, :post_thread, default_value: :post) - - middleware(M.PageSizeProof) - resolve(&R.Accounts.published_comments/3) - end - @desc "get paged published article comments" field :paged_published_article_comments, :paged_article_comments do arg(:login, non_null(:string)) diff --git a/test/groupher_server/accounts/published_comments_test.exs b/test/groupher_server/accounts/published_comments_test.exs deleted file mode 100644 index 3458f07f2..000000000 --- a/test/groupher_server/accounts/published_comments_test.exs +++ /dev/null @@ -1,54 +0,0 @@ -defmodule GroupherServer.Test.Accounts.PublishedComments do - use GroupherServer.TestTools - - alias GroupherServer.{Accounts, CMS} - - @publish_count 10 - - setup do - {:ok, user} = db_insert(:user) - {:ok, user2} = db_insert(:user) - {:ok, community} = db_insert(:community) - - {:ok, ~m(user user2 community)a} - end - - describe "[Accounts Publised post comments]" do - test "fresh user get empty paged published posts", ~m(user)a do - {:ok, results} = Accounts.published_comments(user, :post, %{page: 1, size: 20}) - - assert results |> is_valid_pagination?(:raw) - assert results.total_count == 0 - end - - test "user can get paged published post comments", ~m(user user2 community)a do - body = "this is a test comment" - {:ok, post} = db_insert(:post) - {:ok, post2} = db_insert(:post) - - pub_comments = - Enum.reduce(1..@publish_count, [], fn _, acc -> - body = "this is a test comment" - - {:ok, comment} = - CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - acc ++ [comment] - end) - - {:ok, _comment} = - CMS.create_comment(:post, post2.id, %{community: community.raw, body: body}, user) - - {:ok, _comment} = - CMS.create_comment(:post, post2.id, %{community: community.raw, body: body}, user2) - - {:ok, results} = Accounts.published_comments(user, :post, %{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_web/mutation/cms/old_post_comment_test.exs b/test/groupher_server_web/mutation/cms/old_post_comment_test.exs new file mode 100644 index 000000000..5725550c9 --- /dev/null +++ b/test/groupher_server_web/mutation/cms/old_post_comment_test.exs @@ -0,0 +1,255 @@ +defmodule GroupherServer.Test.Mutation.OldPostComment do + use GroupherServer.TestTools + + alias GroupherServer.{CMS, Delivery} + alias CMS.Model.PostComment + + alias Helper.ORM + + setup do + {:ok, post} = db_insert(:post) + {:ok, user} = db_insert(:user) + {:ok, community} = db_insert(:community) + + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user, user) + + {:ok, comment} = + CMS.create_comment(:post, post.id, %{community: community.raw, body: "test comment"}, user) + + {:ok, ~m(user_conn guest_conn post user community comment)a} + end + + describe "[post comment CURD]" do + @create_comment_query """ + mutation( + $community: String! + $thread: Thread + $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 post", ~m(user_conn community post)a do + variables = %{community: community.raw, thread: "POST", id: post.id, body: "this a comment"} + created = user_conn |> mutation_result(@create_comment_query, variables, "createComment") + + {:ok, found} = ORM.find(PostComment, created["id"]) + + assert created["id"] == to_string(found.id) + end + + test "xss comment should be escaped", ~m(user_conn community post)a do + variables = %{ + community: community.raw, + thread: "POST", + id: post.id, + body: assert_v(:xss_string) + } + + created = user_conn |> mutation_result(@create_comment_query, variables, "createComment") + + {:ok, found} = ORM.find(PostComment, created["id"]) + + assert created["id"] == to_string(found.id) + assert created["body"] == assert_v(:xss_safe_string) + end + + test "guest user create comment fails", ~m(guest_conn post community)a do + variables = %{community: community.raw, thread: "POST", id: post.id, body: "this a comment"} + + assert guest_conn + |> mutation_get_error?(@create_comment_query, variables, ecode(:account_login)) + end + + test "can mention other user when create comment to post", ~m(user_conn community post)a do + {:ok, user2} = db_insert(:user) + + comment_body = "this is a comment" + + variables = + %{community: community.raw, thread: "POST", id: post.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 == post.title + assert the_mention.source_type == "comment" + assert the_mention.parent_id == to_string(post.id) + assert the_mention.parent_type == "post" + assert the_mention.source_preview == comment_body + end + + @delete_comment_query """ + mutation($thread: Thread, $id: ID!) { + deleteComment(thread: $thread, id: $id) { + id + body + } + } + """ + @tag :wip + test "comment owner can delete comment", ~m(user community post)a do + variables = %{community: community.raw, id: post.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, %{id: created["id"]}, "deleteComment") + + assert deleted["id"] == created["id"] + end + + test "unauth user delete comment fails", ~m(user_conn guest_conn community post)a do + variables = %{community: community.raw, id: post.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: Thread + $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: "POST", + 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 "should mention author when reply to a comment", ~m(community post user)a do + body = "this is a comment" + + {:ok, comment} = + CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) + + variables = %{ + community: community.raw, + thread: "POST", + 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(post.id) + assert the_mention.parent_type == "post" + end + + test "can mention others in a reply", ~m(community post user user_conn)a do + body = "this is a comment" |> String.duplicate(100) + reply_body = "this is a reply" |> String.duplicate(100) + {:ok, user2} = db_insert(:user) + + {:ok, comment} = + CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) + + variables = %{ + community: community.raw, + thread: "POST", + id: comment.id, + body: reply_body, + 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 String.contains?(comment.body, the_mention.source_title) + assert the_mention.source_type == "comment_reply" + assert String.contains?(reply_body, the_mention.source_preview) + assert the_mention.parent_id == to_string(post.id) + assert the_mention.parent_type == "post" + end + + test "guest user reply comment fails", ~m(guest_conn comment)a do + variables = %{thread: "POST", id: comment.id, body: "this a reply"} + + assert guest_conn |> mutation_get_error?(@reply_comment_query, variables) + 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 +end diff --git a/test/groupher_server_web/query/cms/old_post_comment_test.exs b/test/groupher_server_web/query/cms/old_post_comment_test.exs new file mode 100644 index 000000000..0d41ef65f --- /dev/null +++ b/test/groupher_server_web/query/cms/old_post_comment_test.exs @@ -0,0 +1,252 @@ +defmodule GroupherServer.Test.Query.OldPostComment do + use GroupherServer.TestTools + + alias GroupherServer.CMS + + setup do + {:ok, post} = db_insert(:post) + {:ok, user} = db_insert(:user) + {:ok, community} = db_insert(:community) + + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user) + + {:ok, ~m(user_conn guest_conn post user community)a} + end + + describe "[post dataloader comment]" do + @query """ + query($filter: PagedPostsFilter) { + pagedPosts(filter: $filter) { + entries { + id + title + commentsParticipatorsCount + commentsParticipators(filter: { first: 5 }) { + id + nickname + } + pagedCommentsParticipators { + entries { + id + nickname + } + totalCount + } + commentsCount + } + totalCount + } + } + """ + + # test "can get comments participators of a post", ~m(user guest_conn)a do + # {:ok, user2} = db_insert(:user) + + # {:ok, community} = db_insert(:community) + # {:ok, post} = CMS.create_article(community, :post, mock_attrs(:post), user) + + # variables = %{filter: %{community: community.raw}} + # results = guest_conn |> query_result(@query, variables, "pagedPosts") + + # comments_participators_count = + # results["entries"] |> List.first() |> Map.get("commentsParticipatorsCount") + + # assert comments_participators_count == 0 + + # body = "this is a test comment" + + # assert {:ok, _comment} = + # CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) + + # assert {:ok, _comment} = + # CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) + + # assert {:ok, _comment} = + # CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user2) + + # variables = %{filter: %{community: community.raw}} + # results = guest_conn |> query_result(@query, variables, "pagedPosts") + + # comments_participators_count = + # results["entries"] |> List.first() |> Map.get("commentsParticipatorsCount") + + # comments_count = results["entries"] |> List.first() |> Map.get("commentsCount") + + # assert comments_participators_count == 2 + # assert comments_count == 3 + + # comments_participators = + # results["entries"] |> List.first() |> Map.get("commentsParticipators") + + # assert comments_participators |> Enum.any?(&(&1["id"] == to_string(user.id))) + # assert comments_participators |> Enum.any?(&(&1["id"] == to_string(user2.id))) + # end + + # test "can get comments participators of a post with multi user", ~m(user guest_conn)a do + # body = "this is a test comment" + # {:ok, community} = db_insert(:community) + # {:ok, post1} = CMS.create_article(community, :post, mock_attrs(:post), user) + # {:ok, post2} = CMS.create_article(community, :post, mock_attrs(:post), user) + + # {:ok, users_list} = db_insert_multi(:user, 10) + # {:ok, users_list2} = db_insert_multi(:user, 10) + + # Enum.each( + # users_list, + # &CMS.create_comment(:post, post1.id, %{community: community.raw, body: body}, &1) + # ) + + # Enum.each( + # users_list2, + # &CMS.create_comment(:post, post2.id, %{community: community.raw, body: body}, &1) + # ) + + # variables = %{filter: %{community: community.raw}} + # results = guest_conn |> query_result(@query, variables, "pagedPosts") + + # assert results["entries"] |> List.first() |> Map.get("commentsParticipators") |> length == 5 + # assert results["entries"] |> List.first() |> Map.get("commentsParticipatorsCount") == 10 + + # assert results["entries"] |> List.last() |> Map.get("commentsParticipators") |> length == 5 + # assert results["entries"] |> List.last() |> Map.get("commentsParticipatorsCount") == 10 + # end + + # test "can get paged commetns participators of a post", ~m(user guest_conn)a do + # body = "this is a test comment" + + # {:ok, community} = db_insert(:community) + # {:ok, post} = CMS.create_article(community, :post, mock_attrs(:post), user) + # {:ok, users_list} = db_insert_multi(:user, 10) + + # Enum.each( + # users_list, + # &CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, &1) + # ) + + # variables = %{filter: %{community: community.raw}} + # results = guest_conn |> query_result(@query, variables, "pagedPosts") + # participators = results["entries"] |> List.first() |> Map.get("pagedCommentsParticipators") + + # assert participators["totalCount"] == 10 + # end + end + + @query """ + query($id: ID!, $thread: Thread, $filter: PagedFilter!) { + pagedCommentsParticipators(id: $id, thread: $thread, filter: $filter) { + entries { + id + nickname + } + totalPages + totalCount + pageSize + pageNumber + } + } + """ + test "can get post's paged commetns participators", ~m(user guest_conn)a do + body = "this is a test comment" + + {:ok, community} = db_insert(:community) + {:ok, post} = CMS.create_article(community, :post, mock_attrs(:post), user) + {:ok, users_list} = db_insert_multi(:user, 10) + + Enum.each( + users_list, + &CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, &1) + ) + + variables = %{id: post.id, thread: "POST", 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 :paged_replies + # TODO: filter comment by time / like / reply + describe "[post comment]" do + @query """ + query($id: ID!, $filter: CommentsFilter!) { + pagedComments(id: $id, filter: $filter) { + entries { + id + likesCount + } + totalPages + totalCount + pageSize + pageNumber + } + } + """ + + test "guest user can get a paged comment", ~m(guest_conn post user community)a do + body = "test comment" + + Enum.reduce(1..30, [], fn _, acc -> + {:ok, value} = + CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) + + acc ++ [value] + end) + + variables = %{id: post.id, filter: %{page: 1, size: 10}} + results = guest_conn |> query_result(@query, variables, "pagedComments") + + assert results |> is_valid_pagination? + assert results["totalCount"] == 30 + end + + @query """ + query($id: ID!, $filter: CommentsFilter!) { + pagedComments(id: $id, filter: $filter) { + entries { + id + body + replyTo { + id + body + } + repliesCount + replies { + id + body + } + } + } + } + """ + test "guest user can get replies 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, reply} = + CMS.reply_comment( + :post, + comment.id, + %{community: community.raw, body: "reply body"}, + 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() + + 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 From 105fc61a929ae89d3bb1760b02ec5d100a32d402 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 22:26:09 +0800 Subject: [PATCH 18/28] feat(blog-thread): wip --- lib/groupher_server_web/middleware/passport_loader.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/groupher_server_web/middleware/passport_loader.ex b/lib/groupher_server_web/middleware/passport_loader.ex index eacfd7b63..abce200bf 100644 --- a/lib/groupher_server_web/middleware/passport_loader.ex +++ b/lib/groupher_server_web/middleware/passport_loader.ex @@ -47,7 +47,7 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do resolution |> assign_owner_info(:article, article) |> assign_source(article) - |> assign_article_communities_info(article, args) + |> assign_article_communities_info(article) else {:error, err_msg} -> handle_absinthe_error(resolution, err_msg, ecode(:passport)) end @@ -70,7 +70,7 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do end # 取得 article 里面的 conmunities 字段 - defp assign_article_communities_info(resolution, article, args) do + defp assign_article_communities_info(resolution, article) do arguments = resolution.arguments |> Map.merge(%{passport_communities: article.communities}) %{resolution | arguments: arguments} end From 1d993ad930235ab1342f754dad30d700a70f650e Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 22:55:40 +0800 Subject: [PATCH 19/28] feat(blog-thread): clean up old post-comment --- .../cms/delegates/article_comment.ex | 2 +- .../cms/delegates/article_comment_action.ex | 2 +- .../cms/delegates/comment_curd.ex | 242 ----------------- lib/groupher_server/cms/helper/utils.ex | 1 - .../cms/models/post_comment.ex | 61 ----- .../cms/models/post_comment_like.ex | 31 --- .../cms/models/post_comment_reply.ex | 29 -- .../resolvers/cms_resolver.ex | 20 -- .../schema/Helper/fields.ex | 45 ---- .../schema/cms/cms_metrics.ex | 9 +- .../schema/cms/cms_queries.ex | 23 +- .../schema/cms/cms_types.ex | 21 +- lib/helper/error_code.ex | 2 +- priv/mock/post_comments_seeds.exs | 18 +- .../mutation/accounts/customization_test.exs | 7 +- .../mutation/cms/old_post_comment_test.exs | 255 ------------------ .../query/cms/old_post_comment_test.exs | 252 ----------------- 17 files changed, 17 insertions(+), 1003 deletions(-) delete mode 100644 lib/groupher_server/cms/delegates/comment_curd.ex delete mode 100644 lib/groupher_server/cms/models/post_comment.ex delete mode 100644 lib/groupher_server/cms/models/post_comment_like.ex delete mode 100644 lib/groupher_server/cms/models/post_comment_reply.ex delete mode 100644 test/groupher_server_web/mutation/cms/old_post_comment_test.exs delete mode 100644 test/groupher_server_web/query/cms/old_post_comment_test.exs diff --git a/lib/groupher_server/cms/delegates/article_comment.ex b/lib/groupher_server/cms/delegates/article_comment.ex index 745ca815b..4f3997eb4 100644 --- a/lib/groupher_server/cms/delegates/article_comment.ex +++ b/lib/groupher_server/cms/delegates/article_comment.ex @@ -405,7 +405,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do defp result({:ok, %{mark_solution: result}}), do: {:ok, result} defp result({:error, :create_article_comment, result, _steps}) do - raise_error(:create_comment, result) + raise_error(:create_article_comment, result) end defp result({:error, _, result, _steps}), do: {:error, result} diff --git a/lib/groupher_server/cms/delegates/article_comment_action.ex b/lib/groupher_server/cms/delegates/article_comment_action.ex index 8db7ecec1..db9ac6550 100644 --- a/lib/groupher_server/cms/delegates/article_comment_action.ex +++ b/lib/groupher_server/cms/delegates/article_comment_action.ex @@ -361,7 +361,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleCommentAction do defp result({:ok, %{delete_article_comment: result}}), do: {:ok, result} defp result({:error, :create_article_comment, result, _steps}) do - raise_error(:create_comment, result) + raise_error(:create_article_comment, result) end defp result({:error, :add_participator, result, _steps}) do diff --git a/lib/groupher_server/cms/delegates/comment_curd.ex b/lib/groupher_server/cms/delegates/comment_curd.ex deleted file mode 100644 index e1578ef1c..000000000 --- a/lib/groupher_server/cms/delegates/comment_curd.ex +++ /dev/null @@ -1,242 +0,0 @@ -defmodule GroupherServer.CMS.Delegate.CommentCURD do - @moduledoc """ - CURD for comments - """ - import Ecto.Query, warn: false - import Helper.Utils, only: [done: 1] - import Helper.ErrorCode - - import ShortMaps - - alias GroupherServer.{Accounts, CMS, Delivery, Repo} - - alias Accounts.Model.User - alias CMS.Model.{Post, PostComment, PostCommentReply} - - alias Helper.{ORM, QueryBuilder} - alias Ecto.Multi - - defp match_action(:post, :comment), - do: {:ok, %{target: Post, reactor: PostComment, preload: :author}} - - @doc """ - Creates a comment for psot, job ... - """ - def create_comment( - thread, - content_id, - %{community: community, body: body} = args, - %User{id: user_id} - ) do - with {:ok, action} <- match_action(:post, :comment), - {:ok, content} <- ORM.find(action.target, content_id), - {:ok, user} <- ORM.find(User, user_id) do - Multi.new() - |> Multi.run(:create_comment, fn _, _ -> - do_create_comment(thread, action, content, body, 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() - |> create_comment_result() - end - end - - def reply_comment( - thread, - comment_id, - %{community: community, body: body} = args, - %User{id: user_id} = user - ) do - with {:ok, action} <- match_action(:post, :comment), - {:ok, comment} <- ORM.find(action.reactor, comment_id) do - next_floor = get_next_floor(thread, action.reactor, comment) - - attrs = %{ - author_id: user_id, - body: body, - reply_to: comment, - floor: next_floor, - mention_users: Map.get(args, :mention_users, []) - } - - Delivery.mention_from_comment_reply(community, thread, comment, attrs, user) - attrs = merge_reply_attrs(thread, attrs, comment) - bridge_reply(thread, action.reactor, comment, attrs) - end - end - - @doc """ - Creates a comment for psot, job ... - """ - def update_comment(thread, id, %{body: body}, %User{id: user_id}) do - with {:ok, action} <- match_action(:post, :comment), - {:ok, content} <- ORM.find(action.reactor, id), - true <- content.author_id == user_id do - ORM.update(content, %{body: body}) - end - end - - @doc """ - Delete the comment and increase all the floor after this comment - """ - def delete_comment(thread, content_id) do - with {:ok, action} <- match_action(:post, :comment), - {:ok, comment} <- ORM.find(action.reactor, content_id) do - Multi.new() - |> Multi.run(:delete_comment, fn _, _ -> - ORM.delete(comment) - end) - |> Multi.run(:update_floor, fn _, _ -> - exec_update_floor(action.reactor, comment) - end) - |> Repo.transaction() - |> delete_comment_result() - end - end - - @doc """ - list paged comments - """ - def paged_comments(thread, content_id, %{page: page, size: size} = filters) do - with {:ok, action} <- match_action(:post, :comment) do - dynamic = dynamic_comment_where(thread, content_id) - - action.reactor - |> where(^dynamic) - |> QueryBuilder.filter_pack(filters) - |> ORM.paginater(~m(page size)a) - |> done() - end - end - - @doc """ - list paged comments participators - """ - def paged_comments_participators(thread, content_id, %{page: page, size: size} = filters) do - with {:ok, action} <- match_action(:post, :comment) do - dynamic = dynamic_comment_where(thread, content_id) - - action.reactor - |> where(^dynamic) - |> QueryBuilder.filter_pack(filters) - |> join(:inner, [c], a in assoc(c, :author)) - |> distinct([c, a], a.id) - # new added when upgrade to ecto v3 - |> group_by([c, a], a.id) - |> group_by([c, a], c.inserted_at) - # new added when upgrade to ecto v3 end - |> select([c, a], a) - |> ORM.paginater(~m(page size)a) - |> done() - end - end - - def paged_replies(thread, comment_id, %User{id: user_id}) do - with {:ok, action} <- match_action(:post, :comment) do - action.reactor - |> where([c], c.author_id == ^user_id) - |> join(:inner, [c], r in assoc(c, :reply_to)) - |> where([c, r], r.id == ^comment_id) - |> Repo.all() - |> done() - end - end - - defp do_create_comment(thread, action, content, body, user) do - next_floor = get_next_floor(thread, action.reactor, content.id) - - attrs = %{ - author_id: user.id, - body: body, - floor: next_floor - } - - attrs = merge_comment_attrs(thread, attrs, content.id) - - action.reactor |> ORM.create(attrs) - end - - defp create_comment_result({:ok, %{create_comment: result}}), do: {:ok, result} - - defp create_comment_result({:error, :create_comment, result, _steps}) do - {:error, result} - end - - defp delete_comment_result({:ok, %{delete_comment: result}}), do: {:ok, result} - - defp delete_comment_result({:error, :delete_comment, _result, _steps}) do - {:error, [message: "delete comment fails", code: ecode(:delete_fails)]} - end - - defp delete_comment_result({:error, :update_floor, _result, _steps}) do - {:error, [message: "update follor fails", code: ecode(:delete_fails)]} - end - - defp exec_update_floor(queryable, comment) do - Repo.update_all( - from(p in queryable, where: p.id > ^comment.id), - inc: [floor: -1] - ) - |> done() - |> case do - {:ok, _} -> {:ok, comment} - {:error, _} -> {:error, ""} - end - end - - # simulate a join connection - # TODO: use Multi task to refactor - # TODO: refactor boilerplate code - defp bridge_reply(:post, queryable, comment, attrs) do - with {:ok, reply} <- ORM.create(queryable, attrs) do - ORM.update(reply, %{reply_id: comment.id}) - - {:ok, _} = - PostCommentReply |> ORM.create(%{post_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) - - queryable - |> where(^dynamic) - |> ORM.next_count() - end - - # for reply comment - defp get_next_floor(thread, queryable, comment) do - dynamic = dynamic_reply_where(thread, comment) - - queryable - |> where(^dynamic) - |> ORM.next_count() - end - - # merge_comment_attrs when create comemnt - defp merge_comment_attrs(:post, attrs, id), do: attrs |> Map.merge(%{post_id: id}) - defp merge_comment_attrs(:job, attrs, id), do: attrs |> Map.merge(%{job_id: id}) - defp merge_comment_attrs(:repo, attrs, id), do: attrs |> Map.merge(%{repo_id: id}) - - defp merge_reply_attrs(:post, attrs, comment), - do: attrs |> Map.merge(%{post_id: comment.post_id}) - - defp merge_reply_attrs(:job, attrs, comment), do: attrs |> Map.merge(%{job_id: comment.job_id}) - - defp merge_reply_attrs(:repo, attrs, comment), - do: attrs |> Map.merge(%{repo_id: comment.repo_id}) - - defp dynamic_comment_where(:post, id), do: dynamic([c], c.post_id == ^id) - defp dynamic_comment_where(:job, id), do: dynamic([c], c.job_id == ^id) - defp dynamic_comment_where(:repo, id), do: dynamic([c], c.repo_id == ^id) - - defp dynamic_reply_where(:post, comment), do: dynamic([c], c.post_id == ^comment.post_id) - defp dynamic_reply_where(:job, comment), do: dynamic([c], c.job_id == ^comment.job_id) - defp dynamic_reply_where(:repo, comment), do: dynamic([c], c.repo_id == ^comment.repo_id) -end diff --git a/lib/groupher_server/cms/helper/utils.ex b/lib/groupher_server/cms/helper/utils.ex index 7a0e7159e..8bc647018 100644 --- a/lib/groupher_server/cms/helper/utils.ex +++ b/lib/groupher_server/cms/helper/utils.ex @@ -6,7 +6,6 @@ defmodule GroupherServer.CMS.Helper.Utils do import Helper.Utils, only: [get_config: 2] alias GroupherServer.CMS - alias CMS.Model.Community @article_threads get_config(:article, :threads) @article_fields @article_threads |> Enum.map(&:"#{&1}_id") diff --git a/lib/groupher_server/cms/models/post_comment.ex b/lib/groupher_server/cms/models/post_comment.ex deleted file mode 100644 index 417af9c41..000000000 --- a/lib/groupher_server/cms/models/post_comment.ex +++ /dev/null @@ -1,61 +0,0 @@ -defmodule GroupherServer.CMS.Model.PostComment do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - alias Accounts.Model.User - alias CMS.Model.{Post, PostCommentLike, PostCommentReply} - - alias Helper.HTML - - @required_fields ~w(body author_id post_id floor)a - @optional_fields ~w(reply_id)a - - @type t :: %PostComment{} - schema "posts_comments" do - field(:body, :string) - field(:floor, :integer) - belongs_to(:author, User, foreign_key: :author_id) - belongs_to(:post, Post, foreign_key: :post_id) - belongs_to(:reply_to, PostComment, foreign_key: :reply_id) - - has_many(:replies, {"posts_comments_replies", PostCommentReply}) - has_many(:likes, {"posts_comments_likes", PostCommentLike}) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%PostComment{} = post_comment, attrs) do - post_comment - |> cast(attrs, @required_fields ++ @optional_fields) - |> validate_required(@required_fields) - |> generl_changeset - end - - @doc false - def update_changeset(%PostComment{} = post_comment, attrs) do - post_comment - |> cast(attrs, @required_fields ++ @optional_fields) - |> generl_changeset - end - - defp generl_changeset(content) do - content - |> foreign_key_constraint(:post_id) - |> foreign_key_constraint(:author_id) - |> validate_length(:body, min: 3, max: 2000) - |> HTML.safe_string(:body) - end - - # @doc false - # def update_changeset(%PostComment{} = post_comment, attrs) do - # post_comment - # |> cast(attrs, @required_fields ++ @optional_fields) - # |> foreign_key_constraint(:post_id) - # |> foreign_key_constraint(:author_id) - # end -end diff --git a/lib/groupher_server/cms/models/post_comment_like.ex b/lib/groupher_server/cms/models/post_comment_like.ex deleted file mode 100644 index 1f649aba7..000000000 --- a/lib/groupher_server/cms/models/post_comment_like.ex +++ /dev/null @@ -1,31 +0,0 @@ -defmodule GroupherServer.CMS.Model.PostCommentLike do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - alias Accounts.Model.User - alias CMS.Model.PostComment - - @required_fields ~w(post_comment_id user_id)a - - @type t :: %PostCommentLike{} - schema "posts_comments_likes" do - belongs_to(:user, User, foreign_key: :user_id) - belongs_to(:post_comment, PostComment, foreign_key: :post_comment_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%PostCommentLike{} = post_comment_like, attrs) do - post_comment_like - |> 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_likes_user_id_post_comment_id_index) - end -end diff --git a/lib/groupher_server/cms/models/post_comment_reply.ex b/lib/groupher_server/cms/models/post_comment_reply.ex deleted file mode 100644 index 72eeb1b68..000000000 --- a/lib/groupher_server/cms/models/post_comment_reply.ex +++ /dev/null @@ -1,29 +0,0 @@ -defmodule GroupherServer.CMS.Model.PostCommentReply do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.CMS - alias CMS.Model.PostComment - - @required_fields ~w(post_comment_id reply_id)a - - @type t :: %PostCommentReply{} - schema "posts_comments_replies" do - belongs_to(:post_comment, PostComment, foreign_key: :post_comment_id) - belongs_to(:reply, PostComment, foreign_key: :reply_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%PostCommentReply{} = post_comment_reply, attrs) do - post_comment_reply - |> cast(attrs, @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:post_comment_id) - |> foreign_key_constraint(:reply_id) - end -end diff --git a/lib/groupher_server_web/resolvers/cms_resolver.ex b/lib/groupher_server_web/resolvers/cms_resolver.ex index dcb7df54c..8a541f8b9 100644 --- a/lib/groupher_server_web/resolvers/cms_resolver.ex +++ b/lib/groupher_server_web/resolvers/cms_resolver.ex @@ -340,26 +340,6 @@ defmodule GroupherServerWeb.Resolvers.CMS do CMS.paged_comment_replies(id, filter) end - def paged_comments(_root, ~m(id thread filter)a, _info) do - CMS.paged_comments(thread, id, filter) - end - - def create_comment(_root, ~m(thread id)a = args, %{context: %{cur_user: user}}) do - CMS.create_comment(thread, id, args, user) - end - - def update_comment(_root, ~m(thread id)a = args, %{context: %{cur_user: user}}) do - CMS.update_comment(thread, id, args, user) - end - - def delete_comment(_root, ~m(thread id)a, _info) do - CMS.delete_comment(thread, id) - end - - def reply_comment(_root, ~m(thread id)a = args, %{context: %{cur_user: user}}) do - CMS.reply_comment(thread, id, args, 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/Helper/fields.ex b/lib/groupher_server_web/schema/Helper/fields.ex index 1292ca08c..90550f2d2 100644 --- a/lib/groupher_server_web/schema/Helper/fields.ex +++ b/lib/groupher_server_web/schema/Helper/fields.ex @@ -206,51 +206,6 @@ defmodule GroupherServerWeb.Schema.Helper.Fields do ) end - # TODO: remove - defmacro comments_fields do - quote do - field(:id, :id) - field(:body, :string) - field(:floor, :integer) - field(:author, :user, resolve: dataloader(CMS, :author)) - - field :reply_to, :comment do - resolve(dataloader(CMS, :reply_to)) - end - - field :likes, list_of(:user) do - arg(:filter, :members_filter) - - middleware(M.PageSizeProof) - resolve(dataloader(CMS, :likes)) - end - - field :likes_count, :integer do - arg(:count, :count_type, default_value: :count) - - resolve(dataloader(CMS, :likes)) - middleware(M.ConvertToInt) - end - - field :replies, list_of(:comment) do - arg(:filter, :members_filter) - - middleware(M.ForceLoader) - middleware(M.PageSizeProof) - resolve(dataloader(CMS, :replies)) - end - - field :replies_count, :integer do - arg(:count, :count_type, default_value: :count) - - resolve(dataloader(CMS, :replies)) - middleware(M.ConvertToInt) - end - - timestamp_fields() - end - end - defmacro article_comments_fields do quote do field(:article_comments_participators, list_of(:user)) diff --git a/lib/groupher_server_web/schema/cms/cms_metrics.ex b/lib/groupher_server_web/schema/cms/cms_metrics.ex index a41d5b049..696617316 100644 --- a/lib/groupher_server_web/schema/cms/cms_metrics.ex +++ b/lib/groupher_server_web/schema/cms/cms_metrics.ex @@ -5,7 +5,7 @@ defmodule GroupherServerWeb.Schema.CMS.Metrics do use Absinthe.Schema.Notation import GroupherServerWeb.Schema.Helper.Fields - import Helper.Utils, only: [module_to_atom: 1, get_config: 2] + import Helper.Utils, only: [module_to_atom: 1] @default_inner_page_size 5 @@ -30,13 +30,6 @@ defmodule GroupherServerWeb.Schema.CMS.Metrics do @desc "emotion options of comment" enum(:article_comment_emotion, do: emotion_values(:comment)) - # TODO: remove - enum(:count_type, do: value(:count)) - # TODO: remove - enum :cms_comment do - value(:post_comment) - end - enum :thread do article_values() value(:user) diff --git a/lib/groupher_server_web/schema/cms/cms_queries.ex b/lib/groupher_server_web/schema/cms/cms_queries.ex index e57e7a7d0..29f7b37d6 100644 --- a/lib/groupher_server_web/schema/cms/cms_queries.ex +++ b/lib/groupher_server_web/schema/cms/cms_queries.ex @@ -109,7 +109,7 @@ defmodule GroupherServerWeb.Schema.CMS.Queries do end @desc "get paged replies of a comment" - field :paged_comment_replies, :paged_article_replies do + field :paged_comment_replies, :paged_comment_replies do arg(:id, non_null(:id)) arg(:filter, :comments_filter) @@ -117,27 +117,6 @@ defmodule GroupherServerWeb.Schema.CMS.Queries do resolve(&R.CMS.paged_comment_replies/3) end - @desc "get paged comments" - field :paged_comments, :paged_comments do - arg(:id, non_null(:id)) - arg(:thread, :thread, default_value: :post) - arg(:filter, :comments_filter) - - middleware(M.PageSizeProof) - resolve(&R.CMS.paged_comments/3) - end - - # comments - # TODO: remove - field :comments, :paged_comments do - arg(:id, non_null(:id)) - arg(:thread, :thread, default_value: :post) - arg(:filter, :comments_filter) - - middleware(M.PageSizeProof) - resolve(&R.CMS.paged_comments/3) - end - @desc "paged reports list" field :paged_abuse_reports, :paged_reports do arg(:filter, non_null(:report_filter)) diff --git a/lib/groupher_server_web/schema/cms/cms_types.ex b/lib/groupher_server_web/schema/cms/cms_types.ex index 645dc9370..3dc65d34e 100644 --- a/lib/groupher_server_web/schema/cms/cms_types.ex +++ b/lib/groupher_server_web/schema/cms/cms_types.ex @@ -327,40 +327,21 @@ defmodule GroupherServerWeb.Schema.CMS.Types do pagination_fields() end - object :comment do - comments_fields() - end - - object :post_comment do - comments_fields() - field(:post, :post, resolve: dataloader(CMS, :post)) - end - object :paged_categories do field(:entries, list_of(:category)) pagination_fields() end - object :paged_comments do - field(:entries, list_of(:comment)) - pagination_fields() - end - object :paged_article_comments do field(:entries, list_of(:article_comment)) pagination_fields() end - object :paged_article_replies do + object :paged_comment_replies do field(:entries, list_of(:article_comment_reply)) pagination_fields() end - object :paged_post_comments do - field(:entries, list_of(:post_comment)) - pagination_fields() - end - object :paged_communities do field(:entries, list_of(:community)) pagination_fields() diff --git a/lib/helper/error_code.ex b/lib/helper/error_code.ex index 64660bae0..825fac99f 100644 --- a/lib/helper/error_code.ex +++ b/lib/helper/error_code.ex @@ -40,7 +40,7 @@ defmodule Helper.ErrorCode do def ecode(:throttle_hour), do: @throttle_base + 2 def ecode(:throttle_day), do: @throttle_base + 3 # comment - def ecode(:create_comment), do: @comment_base + 1 + def ecode(:create_article_comment), do: @comment_base + 1 # article def ecode(:too_much_pinned_article), do: @article_base + 1 def ecode(:already_collected_in_folder), do: @article_base + 2 diff --git a/priv/mock/post_comments_seeds.exs b/priv/mock/post_comments_seeds.exs index 83ee6252f..bcee16c5e 100644 --- a/priv/mock/post_comments_seeds.exs +++ b/priv/mock/post_comments_seeds.exs @@ -9,14 +9,14 @@ alias Accounts.Model.User Enum.reduce(1..15, [], fn _, acc -> unique_num = System.unique_integer([:positive, :monotonic]) - {:ok, value} = - CMS.create_comment( - :post, - :comment, - post.id, - %User{id: user.id}, - "#{Faker.Lorem.Shakespeare.king_richard_iii()} - #{unique_num}" - ) + # {:ok, value} = + # CMS.create_comment( + # :post, + # :comment, + # post.id, + # %User{id: user.id}, + # "#{Faker.Lorem.Shakespeare.king_richard_iii()} - #{unique_num}" + # ) - acc ++ [value] + # acc ++ [value] end) diff --git a/test/groupher_server_web/mutation/accounts/customization_test.exs b/test/groupher_server_web/mutation/accounts/customization_test.exs index 290d90122..97e3321b2 100644 --- a/test/groupher_server_web/mutation/accounts/customization_test.exs +++ b/test/groupher_server_web/mutation/accounts/customization_test.exs @@ -62,17 +62,14 @@ defmodule GroupherServer.Test.Mutation.Account.Customization do query($filter: PagedPostsFilter!) { pagedPosts(filter: $filter) { entries { - commentsCount - commentsParticipators(filter: { first: 5 }) { - id - } + id } pageSize pageNumber } } """ - + @tag :wip test "PageSizeProof middleware should lint c11n displayDensity size", ~m(user)a do user_conn = simu_conn(:user, user) db_insert_multi(:post, 50) diff --git a/test/groupher_server_web/mutation/cms/old_post_comment_test.exs b/test/groupher_server_web/mutation/cms/old_post_comment_test.exs deleted file mode 100644 index 5725550c9..000000000 --- a/test/groupher_server_web/mutation/cms/old_post_comment_test.exs +++ /dev/null @@ -1,255 +0,0 @@ -defmodule GroupherServer.Test.Mutation.OldPostComment do - use GroupherServer.TestTools - - alias GroupherServer.{CMS, Delivery} - alias CMS.Model.PostComment - - alias Helper.ORM - - setup do - {:ok, post} = db_insert(:post) - {:ok, user} = db_insert(:user) - {:ok, community} = db_insert(:community) - - guest_conn = simu_conn(:guest) - user_conn = simu_conn(:user, user) - - {:ok, comment} = - CMS.create_comment(:post, post.id, %{community: community.raw, body: "test comment"}, user) - - {:ok, ~m(user_conn guest_conn post user community comment)a} - end - - describe "[post comment CURD]" do - @create_comment_query """ - mutation( - $community: String! - $thread: Thread - $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 post", ~m(user_conn community post)a do - variables = %{community: community.raw, thread: "POST", id: post.id, body: "this a comment"} - created = user_conn |> mutation_result(@create_comment_query, variables, "createComment") - - {:ok, found} = ORM.find(PostComment, created["id"]) - - assert created["id"] == to_string(found.id) - end - - test "xss comment should be escaped", ~m(user_conn community post)a do - variables = %{ - community: community.raw, - thread: "POST", - id: post.id, - body: assert_v(:xss_string) - } - - created = user_conn |> mutation_result(@create_comment_query, variables, "createComment") - - {:ok, found} = ORM.find(PostComment, created["id"]) - - assert created["id"] == to_string(found.id) - assert created["body"] == assert_v(:xss_safe_string) - end - - test "guest user create comment fails", ~m(guest_conn post community)a do - variables = %{community: community.raw, thread: "POST", id: post.id, body: "this a comment"} - - assert guest_conn - |> mutation_get_error?(@create_comment_query, variables, ecode(:account_login)) - end - - test "can mention other user when create comment to post", ~m(user_conn community post)a do - {:ok, user2} = db_insert(:user) - - comment_body = "this is a comment" - - variables = - %{community: community.raw, thread: "POST", id: post.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 == post.title - assert the_mention.source_type == "comment" - assert the_mention.parent_id == to_string(post.id) - assert the_mention.parent_type == "post" - assert the_mention.source_preview == comment_body - end - - @delete_comment_query """ - mutation($thread: Thread, $id: ID!) { - deleteComment(thread: $thread, id: $id) { - id - body - } - } - """ - @tag :wip - test "comment owner can delete comment", ~m(user community post)a do - variables = %{community: community.raw, id: post.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, %{id: created["id"]}, "deleteComment") - - assert deleted["id"] == created["id"] - end - - test "unauth user delete comment fails", ~m(user_conn guest_conn community post)a do - variables = %{community: community.raw, id: post.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: Thread - $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: "POST", - 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 "should mention author when reply to a comment", ~m(community post user)a do - body = "this is a comment" - - {:ok, comment} = - CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - variables = %{ - community: community.raw, - thread: "POST", - 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(post.id) - assert the_mention.parent_type == "post" - end - - test "can mention others in a reply", ~m(community post user user_conn)a do - body = "this is a comment" |> String.duplicate(100) - reply_body = "this is a reply" |> String.duplicate(100) - {:ok, user2} = db_insert(:user) - - {:ok, comment} = - CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - variables = %{ - community: community.raw, - thread: "POST", - id: comment.id, - body: reply_body, - 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 String.contains?(comment.body, the_mention.source_title) - assert the_mention.source_type == "comment_reply" - assert String.contains?(reply_body, the_mention.source_preview) - assert the_mention.parent_id == to_string(post.id) - assert the_mention.parent_type == "post" - end - - test "guest user reply comment fails", ~m(guest_conn comment)a do - variables = %{thread: "POST", id: comment.id, body: "this a reply"} - - assert guest_conn |> mutation_get_error?(@reply_comment_query, variables) - 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 -end diff --git a/test/groupher_server_web/query/cms/old_post_comment_test.exs b/test/groupher_server_web/query/cms/old_post_comment_test.exs deleted file mode 100644 index 0d41ef65f..000000000 --- a/test/groupher_server_web/query/cms/old_post_comment_test.exs +++ /dev/null @@ -1,252 +0,0 @@ -defmodule GroupherServer.Test.Query.OldPostComment do - use GroupherServer.TestTools - - alias GroupherServer.CMS - - setup do - {:ok, post} = db_insert(:post) - {:ok, user} = db_insert(:user) - {:ok, community} = db_insert(:community) - - guest_conn = simu_conn(:guest) - user_conn = simu_conn(:user) - - {:ok, ~m(user_conn guest_conn post user community)a} - end - - describe "[post dataloader comment]" do - @query """ - query($filter: PagedPostsFilter) { - pagedPosts(filter: $filter) { - entries { - id - title - commentsParticipatorsCount - commentsParticipators(filter: { first: 5 }) { - id - nickname - } - pagedCommentsParticipators { - entries { - id - nickname - } - totalCount - } - commentsCount - } - totalCount - } - } - """ - - # test "can get comments participators of a post", ~m(user guest_conn)a do - # {:ok, user2} = db_insert(:user) - - # {:ok, community} = db_insert(:community) - # {:ok, post} = CMS.create_article(community, :post, mock_attrs(:post), user) - - # variables = %{filter: %{community: community.raw}} - # results = guest_conn |> query_result(@query, variables, "pagedPosts") - - # comments_participators_count = - # results["entries"] |> List.first() |> Map.get("commentsParticipatorsCount") - - # assert comments_participators_count == 0 - - # body = "this is a test comment" - - # assert {:ok, _comment} = - # CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - # assert {:ok, _comment} = - # CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - # assert {:ok, _comment} = - # CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user2) - - # variables = %{filter: %{community: community.raw}} - # results = guest_conn |> query_result(@query, variables, "pagedPosts") - - # comments_participators_count = - # results["entries"] |> List.first() |> Map.get("commentsParticipatorsCount") - - # comments_count = results["entries"] |> List.first() |> Map.get("commentsCount") - - # assert comments_participators_count == 2 - # assert comments_count == 3 - - # comments_participators = - # results["entries"] |> List.first() |> Map.get("commentsParticipators") - - # assert comments_participators |> Enum.any?(&(&1["id"] == to_string(user.id))) - # assert comments_participators |> Enum.any?(&(&1["id"] == to_string(user2.id))) - # end - - # test "can get comments participators of a post with multi user", ~m(user guest_conn)a do - # body = "this is a test comment" - # {:ok, community} = db_insert(:community) - # {:ok, post1} = CMS.create_article(community, :post, mock_attrs(:post), user) - # {:ok, post2} = CMS.create_article(community, :post, mock_attrs(:post), user) - - # {:ok, users_list} = db_insert_multi(:user, 10) - # {:ok, users_list2} = db_insert_multi(:user, 10) - - # Enum.each( - # users_list, - # &CMS.create_comment(:post, post1.id, %{community: community.raw, body: body}, &1) - # ) - - # Enum.each( - # users_list2, - # &CMS.create_comment(:post, post2.id, %{community: community.raw, body: body}, &1) - # ) - - # variables = %{filter: %{community: community.raw}} - # results = guest_conn |> query_result(@query, variables, "pagedPosts") - - # assert results["entries"] |> List.first() |> Map.get("commentsParticipators") |> length == 5 - # assert results["entries"] |> List.first() |> Map.get("commentsParticipatorsCount") == 10 - - # assert results["entries"] |> List.last() |> Map.get("commentsParticipators") |> length == 5 - # assert results["entries"] |> List.last() |> Map.get("commentsParticipatorsCount") == 10 - # end - - # test "can get paged commetns participators of a post", ~m(user guest_conn)a do - # body = "this is a test comment" - - # {:ok, community} = db_insert(:community) - # {:ok, post} = CMS.create_article(community, :post, mock_attrs(:post), user) - # {:ok, users_list} = db_insert_multi(:user, 10) - - # Enum.each( - # users_list, - # &CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, &1) - # ) - - # variables = %{filter: %{community: community.raw}} - # results = guest_conn |> query_result(@query, variables, "pagedPosts") - # participators = results["entries"] |> List.first() |> Map.get("pagedCommentsParticipators") - - # assert participators["totalCount"] == 10 - # end - end - - @query """ - query($id: ID!, $thread: Thread, $filter: PagedFilter!) { - pagedCommentsParticipators(id: $id, thread: $thread, filter: $filter) { - entries { - id - nickname - } - totalPages - totalCount - pageSize - pageNumber - } - } - """ - test "can get post's paged commetns participators", ~m(user guest_conn)a do - body = "this is a test comment" - - {:ok, community} = db_insert(:community) - {:ok, post} = CMS.create_article(community, :post, mock_attrs(:post), user) - {:ok, users_list} = db_insert_multi(:user, 10) - - Enum.each( - users_list, - &CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, &1) - ) - - variables = %{id: post.id, thread: "POST", 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 :paged_replies - # TODO: filter comment by time / like / reply - describe "[post comment]" do - @query """ - query($id: ID!, $filter: CommentsFilter!) { - pagedComments(id: $id, filter: $filter) { - entries { - id - likesCount - } - totalPages - totalCount - pageSize - pageNumber - } - } - """ - - test "guest user can get a paged comment", ~m(guest_conn post user community)a do - body = "test comment" - - Enum.reduce(1..30, [], fn _, acc -> - {:ok, value} = - CMS.create_comment(:post, post.id, %{community: community.raw, body: body}, user) - - acc ++ [value] - end) - - variables = %{id: post.id, filter: %{page: 1, size: 10}} - results = guest_conn |> query_result(@query, variables, "pagedComments") - - assert results |> is_valid_pagination? - assert results["totalCount"] == 30 - end - - @query """ - query($id: ID!, $filter: CommentsFilter!) { - pagedComments(id: $id, filter: $filter) { - entries { - id - body - replyTo { - id - body - } - repliesCount - replies { - id - body - } - } - } - } - """ - test "guest user can get replies 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, reply} = - CMS.reply_comment( - :post, - comment.id, - %{community: community.raw, body: "reply body"}, - 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() - - 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 From 6c698c7e37b5b9506433ddc9efdd0a02607c2864 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 23:03:46 +0800 Subject: [PATCH 20/28] feat(blog-thread): clean up wip --- lib/groupher_server/cms/helper/utils.ex | 2 -- lib/groupher_server_web/schema/Helper/fields.ex | 2 -- lib/groupher_server_web/schema/cms/cms_types.ex | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/groupher_server/cms/helper/utils.ex b/lib/groupher_server/cms/helper/utils.ex index 8bc647018..0a8aeeca2 100644 --- a/lib/groupher_server/cms/helper/utils.ex +++ b/lib/groupher_server/cms/helper/utils.ex @@ -5,8 +5,6 @@ defmodule GroupherServer.CMS.Helper.Utils do import Ecto.Changeset import Helper.Utils, only: [get_config: 2] - alias GroupherServer.CMS - @article_threads get_config(:article, :threads) @article_fields @article_threads |> Enum.map(&:"#{&1}_id") diff --git a/lib/groupher_server_web/schema/Helper/fields.ex b/lib/groupher_server_web/schema/Helper/fields.ex index 90550f2d2..edd51ce39 100644 --- a/lib/groupher_server_web/schema/Helper/fields.ex +++ b/lib/groupher_server_web/schema/Helper/fields.ex @@ -6,8 +6,6 @@ defmodule GroupherServerWeb.Schema.Helper.Fields do import Absinthe.Resolution.Helpers, only: [dataloader: 2] alias GroupherServer.CMS - alias GroupherServerWeb.Middleware, as: M - alias GroupherServerWeb.Resolvers, as: R @page_size get_config(:general, :page_size) diff --git a/lib/groupher_server_web/schema/cms/cms_types.ex b/lib/groupher_server_web/schema/cms/cms_types.ex index 3dc65d34e..31042e8ec 100644 --- a/lib/groupher_server_web/schema/cms/cms_types.ex +++ b/lib/groupher_server_web/schema/cms/cms_types.ex @@ -8,7 +8,7 @@ defmodule GroupherServerWeb.Schema.CMS.Types do import GroupherServerWeb.Schema.Helper.Objects import Ecto.Query, warn: false - import Absinthe.Resolution.Helpers, only: [dataloader: 2, on_load: 2] + import Absinthe.Resolution.Helpers, only: [dataloader: 2] alias GroupherServer.CMS alias GroupherServerWeb.Schema From e1a5018332e1d1f0a98b4eff58ef8f779e0b7cf8 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 23:22:40 +0800 Subject: [PATCH 21/28] feat(blog-thread): clean up wip --- lib/groupher_server/cms/delegates/article_comment.ex | 6 ++---- lib/groupher_server/cms/models/community.ex | 2 -- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/groupher_server/cms/delegates/article_comment.ex b/lib/groupher_server/cms/delegates/article_comment.ex index 4f3997eb4..ba1be04c9 100644 --- a/lib/groupher_server/cms/delegates/article_comment.ex +++ b/lib/groupher_server/cms/delegates/article_comment.ex @@ -3,7 +3,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do CURD and operations for article comments """ import Ecto.Query, warn: false - import Helper.Utils, only: [done: 1, ensure: 2, get_config: 2] + import Helper.Utils, only: [done: 1, ensure: 2] import Helper.ErrorCode import GroupherServer.CMS.Delegate.Helper, only: [mark_viewer_emotion_states: 3] @@ -19,8 +19,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do alias CMS.Model.{ArticleComment, ArticlePinnedComment, Embeds} alias Ecto.Multi - @article_threads get_config(:article, :threads) - @max_participator_count ArticleComment.max_participator_count() @default_emotions Embeds.ArticleCommentEmotion.default_emotions() @delete_hint ArticleComment.delete_hint() @@ -383,7 +381,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleComment do Map.merge(paged_comments, %{entries: entries}) end - defp set_question_flag_ifneed(%{is_question: true} = article, %ArticleComment{} = comment) do + defp set_question_flag_ifneed(%{is_question: true} = _article, %ArticleComment{} = comment) do ORM.update(comment, %{is_for_question: true}) end diff --git a/lib/groupher_server/cms/models/community.ex b/lib/groupher_server/cms/models/community.ex index 9edd3adda..e81fcc56d 100644 --- a/lib/groupher_server/cms/models/community.ex +++ b/lib/groupher_server/cms/models/community.ex @@ -4,10 +4,8 @@ defmodule GroupherServer.CMS.Model.Community do use Ecto.Schema import Ecto.Changeset - import GroupherServer.CMS.Helper.Macros alias GroupherServer.{Accounts, CMS} - alias Accounts.Model.User alias CMS.Model.{ From 78f27bf5b3cefd112b44d07c3e14f0a6cd620c1b Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 7 Jun 2021 23:32:25 +0800 Subject: [PATCH 22/28] fix(passport): article preload loader --- lib/groupher_server_web/middleware/passport_loader.ex | 2 +- .../mutation/accounts/customization_test.exs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/groupher_server_web/middleware/passport_loader.ex b/lib/groupher_server_web/middleware/passport_loader.ex index abce200bf..7a4dd00e6 100644 --- a/lib/groupher_server_web/middleware/passport_loader.ex +++ b/lib/groupher_server_web/middleware/passport_loader.ex @@ -43,7 +43,7 @@ defmodule GroupherServerWeb.Middleware.PassportLoader do # Loader 应该使用 Map 作为参数,以方便模式匹配 def call(%{context: %{cur_user: _}, arguments: %{id: id}} = resolution, source: thread) do with {:ok, info} <- match(thread), - {:ok, article} <- ORM.find(info.model, id, preload: :author) do + {:ok, article} <- ORM.find(info.model, id, preload: [:author, :communities]) do resolution |> assign_owner_info(:article, article) |> assign_source(article) diff --git a/test/groupher_server_web/mutation/accounts/customization_test.exs b/test/groupher_server_web/mutation/accounts/customization_test.exs index 97e3321b2..9b9ad2a79 100644 --- a/test/groupher_server_web/mutation/accounts/customization_test.exs +++ b/test/groupher_server_web/mutation/accounts/customization_test.exs @@ -69,7 +69,6 @@ defmodule GroupherServer.Test.Mutation.Account.Customization do } } """ - @tag :wip test "PageSizeProof middleware should lint c11n displayDensity size", ~m(user)a do user_conn = simu_conn(:user, user) db_insert_multi(:post, 50) From 560c4fdc26fd1986b0a37083a42f845b46328111 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 8 Jun 2021 00:10:39 +0800 Subject: [PATCH 23/28] chore: wip --- .../schema/cms/mutations/blog.ex | 4 +- .../mutation/cms/articles/blog_test.exs | 2 +- .../mutation/statistics/statistics_test.exs | 45 +++++++++++++++---- test/helper/orm_test.exs | 4 +- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/lib/groupher_server_web/schema/cms/mutations/blog.ex b/lib/groupher_server_web/schema/cms/mutations/blog.ex index bbd61c9b2..3a159419e 100644 --- a/lib/groupher_server_web/schema/cms/mutations/blog.ex +++ b/lib/groupher_server_web/schema/cms/mutations/blog.ex @@ -11,11 +11,9 @@ defmodule GroupherServerWeb.Schema.CMS.Mutations.Blog do arg(:title, non_null(:string)) arg(:body, non_null(:string)) arg(:digest, non_null(:string)) - arg(:length, non_null(:integer)) + arg(:length, :integer) arg(:community_id, non_null(:id)) - arg(:link_addr, :string) - arg(:thread, :thread, default_value: :blog) arg(:article_tags, list_of(:ids)) diff --git a/test/groupher_server_web/mutation/cms/articles/blog_test.exs b/test/groupher_server_web/mutation/cms/articles/blog_test.exs index d73bf9b9e..051c3242e 100644 --- a/test/groupher_server_web/mutation/cms/articles/blog_test.exs +++ b/test/groupher_server_web/mutation/cms/articles/blog_test.exs @@ -23,7 +23,7 @@ defmodule GroupherServer.Test.Mutation.Articles.Blog do $title: String!, $body: String, $digest: String!, - $length: Int!, + $length: Int, $communityId: ID!, $articleTags: [Ids] ) { diff --git a/test/groupher_server_web/mutation/statistics/statistics_test.exs b/test/groupher_server_web/mutation/statistics/statistics_test.exs index 50acdddb9..ce5f5aee0 100644 --- a/test/groupher_server_web/mutation/statistics/statistics_test.exs +++ b/test/groupher_server_web/mutation/statistics/statistics_test.exs @@ -100,6 +100,36 @@ defmodule GroupherServer.Test.Mutation.Statistics do assert contributes.count == 1 end + @create_blog_query """ + mutation ( + $title: String!, + $body: String!, + $digest: String!, + $communityId: ID!, + $articleTags: [Ids] + ) { + createBlog( + title: $title, + body: $body, + digest: $digest, + communityId: $communityId, + articleTags: $articleTags + ) { + id + title + body + } + } + """ + test "user should have contribute list after create a blog", ~m(user_conn user community)a do + variables = blog_attr |> Map.merge(%{communityId: community.id}) |> camelize_map_key + + user_conn |> mutation_result(@create_blog_query, variables, "createBlog") + + {:ok, contributes} = ORM.find_by(UserContribute, user_id: user.id) + assert contributes.count == 1 + end + @create_repo_query """ mutation( $title: String!, @@ -157,19 +187,18 @@ defmodule GroupherServer.Test.Mutation.Statistics do assert contributes.count == 1 end - @create_comment_query """ - mutation($community: String!, $thread: Thread, $id: ID!, $body: String!) { - createComment(community: $community, thread: $thread, id: $id, body: $body) { + @write_comment_query """ + mutation($thread: Thread!, $id: ID!, $content: String!) { + createArticleComment(thread: $thread, id: $id, content: $content) { id - body + bodyHtml } } """ - test "user should have contribute list after create a comment", - ~m(user_conn user community)a do + test "user should have contribute list after create a comment", ~m(user_conn user)a do {:ok, post} = db_insert(:post) - variables = %{community: community.raw, thread: "POST", id: post.id, body: "this a comment"} - user_conn |> mutation_result(@create_comment_query, variables, "createComment") + variables = %{thread: "POST", id: post.id, content: "comment"} + user_conn |> mutation_result(@write_comment_query, variables, "createArticleComment") {:ok, contributes} = ORM.find_by(UserContribute, user_id: user.id) assert contributes.count == 1 diff --git a/test/helper/orm_test.exs b/test/helper/orm_test.exs index b916e7826..dec1c21c5 100644 --- a/test/helper/orm_test.exs +++ b/test/helper/orm_test.exs @@ -40,10 +40,10 @@ defmodule GroupherServer.Test.Helper.ORM do end test "find/3 with preload can preload muilt fields", %{post: post} do - {:ok, found} = ORM.find(Post, post.id, preload: [:author, :comments, :communities]) + {:ok, found} = ORM.find(Post, post.id, preload: [:author, :article_tags, :communities]) # IO.inspect found assert %Author{} = found.author - assert %Ecto.Association.NotLoaded{} != found.comments + assert %Ecto.Association.NotLoaded{} != found.article_tags assert %Ecto.Association.NotLoaded{} != found.communities end From dd47914dee45d5bb8ed45289f4a4fea29dc41e8d Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 8 Jun 2021 00:18:19 +0800 Subject: [PATCH 24/28] chore: wip --- test/groupher_server_web/mutation/statistics/statistics_test.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/groupher_server_web/mutation/statistics/statistics_test.exs b/test/groupher_server_web/mutation/statistics/statistics_test.exs index ce5f5aee0..060235f87 100644 --- a/test/groupher_server_web/mutation/statistics/statistics_test.exs +++ b/test/groupher_server_web/mutation/statistics/statistics_test.exs @@ -122,6 +122,7 @@ defmodule GroupherServer.Test.Mutation.Statistics do } """ test "user should have contribute list after create a blog", ~m(user_conn user community)a do + blog_attr = mock_attrs(:blog) variables = blog_attr |> Map.merge(%{communityId: community.id}) |> camelize_map_key user_conn |> mutation_result(@create_blog_query, variables, "createBlog") From 6714066d969d59bbed50b23e17feca65cb85d268 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 8 Jun 2021 00:26:24 +0800 Subject: [PATCH 25/28] chore: wip --- test/groupher_server/cms/comments/blog_comment_test.exs | 2 ++ test/groupher_server/cms/comments/job_comment_test.exs | 2 ++ test/groupher_server/cms/comments/post_comment_test.exs | 2 ++ test/groupher_server/cms/comments/repo_comment_test.exs | 2 ++ 4 files changed, 8 insertions(+) diff --git a/test/groupher_server/cms/comments/blog_comment_test.exs b/test/groupher_server/cms/comments/blog_comment_test.exs index 1a8f095b9..1813d994d 100644 --- a/test/groupher_server/cms/comments/blog_comment_test.exs +++ b/test/groupher_server/cms/comments/blog_comment_test.exs @@ -416,6 +416,8 @@ defmodule GroupherServer.Test.CMS.Comments.BlogComment do acc ++ [comment] end) + Process.sleep(1000) + {:ok, paged_comments} = CMS.paged_article_comments( :blog, diff --git a/test/groupher_server/cms/comments/job_comment_test.exs b/test/groupher_server/cms/comments/job_comment_test.exs index 69cc8dbff..1c67af8bd 100644 --- a/test/groupher_server/cms/comments/job_comment_test.exs +++ b/test/groupher_server/cms/comments/job_comment_test.exs @@ -415,6 +415,8 @@ defmodule GroupherServer.Test.CMS.Comments.JobComment do acc ++ [comment] end) + Process.sleep(1000) + {:ok, paged_comments} = CMS.paged_article_comments( :job, diff --git a/test/groupher_server/cms/comments/post_comment_test.exs b/test/groupher_server/cms/comments/post_comment_test.exs index 791217b5b..321110965 100644 --- a/test/groupher_server/cms/comments/post_comment_test.exs +++ b/test/groupher_server/cms/comments/post_comment_test.exs @@ -416,6 +416,8 @@ defmodule GroupherServer.Test.CMS.Comments.PostComment do acc ++ [comment] end) + Process.sleep(1000) + {:ok, paged_comments} = CMS.paged_article_comments( :post, diff --git a/test/groupher_server/cms/comments/repo_comment_test.exs b/test/groupher_server/cms/comments/repo_comment_test.exs index 847defc45..2729db2e8 100644 --- a/test/groupher_server/cms/comments/repo_comment_test.exs +++ b/test/groupher_server/cms/comments/repo_comment_test.exs @@ -416,6 +416,8 @@ defmodule GroupherServer.Test.CMS.Comments.RepoComment do acc ++ [comment] end) + Process.sleep(1000) + {:ok, paged_comments} = CMS.paged_article_comments( :repo, From 8978ddc0cf666a29a09de9e79f171a15c2560ece Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 8 Jun 2021 00:28:19 +0800 Subject: [PATCH 26/28] chore: wip --- test/groupher_server/cms/comments/blog_comment_test.exs | 4 +--- test/groupher_server/cms/comments/job_comment_test.exs | 4 +--- test/groupher_server/cms/comments/post_comment_test.exs | 4 +--- test/groupher_server/cms/comments/repo_comment_test.exs | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/test/groupher_server/cms/comments/blog_comment_test.exs b/test/groupher_server/cms/comments/blog_comment_test.exs index 1813d994d..6b3241cd4 100644 --- a/test/groupher_server/cms/comments/blog_comment_test.exs +++ b/test/groupher_server/cms/comments/blog_comment_test.exs @@ -407,7 +407,7 @@ defmodule GroupherServer.Test.CMS.Comments.BlogComment do test "paged article comments folded flag should be false", ~m(user blog)a do total_count = 30 page_number = 1 - page_size = 10 + page_size = 35 all_comments = Enum.reduce(1..total_count, [], fn _, acc -> @@ -416,8 +416,6 @@ defmodule GroupherServer.Test.CMS.Comments.BlogComment do acc ++ [comment] end) - Process.sleep(1000) - {:ok, paged_comments} = CMS.paged_article_comments( :blog, diff --git a/test/groupher_server/cms/comments/job_comment_test.exs b/test/groupher_server/cms/comments/job_comment_test.exs index 1c67af8bd..dcc32a586 100644 --- a/test/groupher_server/cms/comments/job_comment_test.exs +++ b/test/groupher_server/cms/comments/job_comment_test.exs @@ -406,7 +406,7 @@ defmodule GroupherServer.Test.CMS.Comments.JobComment do test "paged article comments folded flag should be false", ~m(user job)a do total_count = 30 page_number = 1 - page_size = 10 + page_size = 35 all_comments = Enum.reduce(1..total_count, [], fn _, acc -> @@ -415,8 +415,6 @@ defmodule GroupherServer.Test.CMS.Comments.JobComment do acc ++ [comment] end) - Process.sleep(1000) - {:ok, paged_comments} = CMS.paged_article_comments( :job, diff --git a/test/groupher_server/cms/comments/post_comment_test.exs b/test/groupher_server/cms/comments/post_comment_test.exs index 321110965..9b60f7382 100644 --- a/test/groupher_server/cms/comments/post_comment_test.exs +++ b/test/groupher_server/cms/comments/post_comment_test.exs @@ -407,7 +407,7 @@ defmodule GroupherServer.Test.CMS.Comments.PostComment do test "paged article comments folded flag should be false", ~m(user post)a do total_count = 30 page_number = 1 - page_size = 10 + page_size = 35 all_comments = Enum.reduce(1..total_count, [], fn _, acc -> @@ -416,8 +416,6 @@ defmodule GroupherServer.Test.CMS.Comments.PostComment do acc ++ [comment] end) - Process.sleep(1000) - {:ok, paged_comments} = CMS.paged_article_comments( :post, diff --git a/test/groupher_server/cms/comments/repo_comment_test.exs b/test/groupher_server/cms/comments/repo_comment_test.exs index 2729db2e8..b5a2e003c 100644 --- a/test/groupher_server/cms/comments/repo_comment_test.exs +++ b/test/groupher_server/cms/comments/repo_comment_test.exs @@ -407,7 +407,7 @@ defmodule GroupherServer.Test.CMS.Comments.RepoComment do test "paged article comments folded flag should be false", ~m(user repo)a do total_count = 30 page_number = 1 - page_size = 10 + page_size = 35 all_comments = Enum.reduce(1..total_count, [], fn _, acc -> @@ -416,8 +416,6 @@ defmodule GroupherServer.Test.CMS.Comments.RepoComment do acc ++ [comment] end) - Process.sleep(1000) - {:ok, paged_comments} = CMS.paged_article_comments( :repo, From fb9733ee6ca20e77e5de1221a308e07d9f50eb89 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 8 Jun 2021 09:46:23 +0800 Subject: [PATCH 27/28] refactor(blog-thread): add more test --- .../accounts/models/collect_folder.ex | 1 + .../published/published_blogs_test.exs | 93 ++++++++ .../mutation/accounts/collect_folder_test.exs | 136 +++++++++-- .../cms/abuse_reports/blog_report_test.exs | 62 +++++ .../cms/article_community/blog_test.exs | 148 ++++++++++++ .../cms/article_tags/blog_tag_test.exs | 91 +++++++ .../cms/comments/blog_comment_test.exs | 222 ++++++++++++++++++ .../mutation/cms/flags/blog_flag_test.exs | 181 ++++++++++++++ .../mutation/cms/sink/blog_sink_test.exs | 79 +++++++ .../mutation/cms/upvotes/blog_upvote_test.exs | 64 +++++ 10 files changed, 1056 insertions(+), 21 deletions(-) create mode 100644 test/groupher_server/accounts/published/published_blogs_test.exs create mode 100644 test/groupher_server_web/mutation/cms/abuse_reports/blog_report_test.exs create mode 100644 test/groupher_server_web/mutation/cms/article_community/blog_test.exs create mode 100644 test/groupher_server_web/mutation/cms/article_tags/blog_tag_test.exs create mode 100644 test/groupher_server_web/mutation/cms/comments/blog_comment_test.exs create mode 100644 test/groupher_server_web/mutation/cms/flags/blog_flag_test.exs create mode 100644 test/groupher_server_web/mutation/cms/sink/blog_sink_test.exs create mode 100644 test/groupher_server_web/mutation/cms/upvotes/blog_upvote_test.exs diff --git a/lib/groupher_server/accounts/models/collect_folder.ex b/lib/groupher_server/accounts/models/collect_folder.ex index cf4fc5608..d0f3b0fbb 100644 --- a/lib/groupher_server/accounts/models/collect_folder.ex +++ b/lib/groupher_server/accounts/models/collect_folder.ex @@ -3,6 +3,7 @@ defmodule GroupherServer.Accounts.Model.CollectFolder do alias __MODULE__ use Ecto.Schema + use Accessible import Ecto.Changeset alias GroupherServer.{Accounts, CMS} diff --git a/test/groupher_server/accounts/published/published_blogs_test.exs b/test/groupher_server/accounts/published/published_blogs_test.exs new file mode 100644 index 000000000..2ac2b7aed --- /dev/null +++ b/test/groupher_server/accounts/published/published_blogs_test.exs @@ -0,0 +1,93 @@ +defmodule GroupherServer.Test.Accounts.Published.Blog do + use GroupherServer.TestTools + + alias GroupherServer.{Accounts, CMS} + alias Accounts.Model.User + alias Helper.ORM + + @publish_count 10 + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, blog} = db_insert(:blog) + {:ok, community} = db_insert(:community) + {:ok, community2} = db_insert(:community) + + {:ok, ~m(user user2 blog community community2)a} + end + + describe "[publised blogs]" do + test "create blog should update user published meta", ~m(community user)a do + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + {:ok, _blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, _blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, user} = ORM.find(User, user.id) + assert user.meta.published_blogs_count == 2 + end + + test "fresh user get empty paged published blogs", ~m(user)a do + {:ok, results} = Accounts.paged_published_articles(user, :blog, %{page: 1, size: 20}) + + assert results |> is_valid_pagination?(:raw) + assert results.total_count == 0 + end + + test "user can get paged published blogs", ~m(user user2 community community2)a do + pub_blogs = + Enum.reduce(1..@publish_count, [], fn _, acc -> + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + acc ++ [blog] + end) + + pub_blogs2 = + Enum.reduce(1..@publish_count, [], fn _, acc -> + blog_attrs = mock_attrs(:blog, %{community_id: community2.id}) + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + acc ++ [blog] + end) + + # unrelated other user + Enum.reduce(1..5, [], fn _, acc -> + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user2) + + acc ++ [blog] + end) + + {:ok, results} = Accounts.paged_published_articles(user, :blog, %{page: 1, size: 20}) + + assert results |> is_valid_pagination?(:raw) + assert results.total_count == @publish_count * 2 + + random_blog_id = pub_blogs |> Enum.random() |> Map.get(:id) + random_blog_id2 = pub_blogs2 |> Enum.random() |> Map.get(:id) + assert results.entries |> Enum.any?(&(&1.id == random_blog_id)) + assert results.entries |> Enum.any?(&(&1.id == random_blog_id2)) + end + end + + describe "[publised blog comments]" do + test "can get published article comments", ~m(blog user)a do + total_count = 10 + + Enum.reduce(1..total_count, [], fn _, acc -> + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + acc ++ [comment] + end) + + filter = %{page: 1, size: 20} + {:ok, articles} = Accounts.paged_published_article_comments(user, :blog, filter) + + entries = articles.entries + article = entries |> List.first() + + assert article.article.id == blog.id + assert article.article.title == blog.title + end + end +end diff --git a/test/groupher_server_web/mutation/accounts/collect_folder_test.exs b/test/groupher_server_web/mutation/accounts/collect_folder_test.exs index 130d324c3..998c1f3c0 100644 --- a/test/groupher_server_web/mutation/accounts/collect_folder_test.exs +++ b/test/groupher_server_web/mutation/accounts/collect_folder_test.exs @@ -13,11 +13,12 @@ defmodule GroupherServer.Test.Mutation.Accounts.CollectFolder do {:ok, post} = db_insert(:post) {:ok, job} = db_insert(:job) {:ok, repo} = db_insert(:repo) + {:ok, blog} = db_insert(:blog) user_conn = simu_conn(:user, user) guest_conn = simu_conn(:guest) - {:ok, ~m(user_conn guest_conn user post job repo)a} + {:ok, ~m(user_conn guest_conn user post job repo blog)a} end describe "[Accounts CollectFolder CURD]" do @@ -71,7 +72,6 @@ defmodule GroupherServer.Test.Mutation.Accounts.CollectFolder do } } """ - test "login user can update own collect folder", ~m(user_conn user)a do args = %{title: "folder_title", private: false} {:ok, folder} = Accounts.create_collect_folder(args, user) @@ -92,7 +92,6 @@ defmodule GroupherServer.Test.Mutation.Accounts.CollectFolder do } } """ - test "login user can delete own collect folder", ~m(user_conn user)a do args = %{title: "folder_title", private: false} {:ok, folder} = Accounts.create_collect_folder(args, user) @@ -116,14 +115,25 @@ defmodule GroupherServer.Test.Mutation.Accounts.CollectFolder do hasPost hasJob hasRepo + hasBlog postCount jobCount repoCount + blogCount } } } """ - + @meta %{ + "hasJob" => false, + "hasPost" => false, + "hasRepo" => false, + "hasBlog" => false, + "jobCount" => 0, + "postCount" => 0, + "repoCount" => 0, + "blogCount" => 0 + } test "user can add a post to collect folder", ~m(user user_conn post)a do args = %{title: "folder_title", private: false} {:ok, folder} = Accounts.create_collect_folder(args, user) @@ -134,14 +144,7 @@ defmodule GroupherServer.Test.Mutation.Accounts.CollectFolder do assert folder["totalCount"] == 1 assert folder["lastUpdated"] != nil - assert folder["meta"] == %{ - "hasJob" => false, - "hasPost" => true, - "hasRepo" => false, - "jobCount" => 0, - "postCount" => 1, - "repoCount" => 0 - } + assert folder["meta"] == @meta |> Map.merge(%{"hasPost" => true, "postCount" => 1}) {:ok, article_collect} = ArticleCollect |> ORM.find_by(%{post_id: post.id, user_id: user.id}) @@ -152,6 +155,68 @@ defmodule GroupherServer.Test.Mutation.Accounts.CollectFolder do assert folder_in_article_collect.meta.post_count == 1 end + test "user can add a job to collect folder", ~m(user user_conn job)a do + args = %{title: "folder_title", private: false} + {:ok, folder} = Accounts.create_collect_folder(args, user) + + variables = %{articleId: job.id, folderId: folder.id, thread: "JOB"} + folder = user_conn |> mutation_result(@query, variables, "addToCollect") + + assert folder["totalCount"] == 1 + assert folder["lastUpdated"] != nil + + assert folder["meta"] == @meta |> Map.merge(%{"hasJob" => true, "jobCount" => 1}) + + {:ok, article_collect} = ArticleCollect |> ORM.find_by(%{job_id: job.id, user_id: user.id}) + + folder_in_article_collect = article_collect.collect_folders |> List.first() + + assert folder_in_article_collect.meta.has_job + assert folder_in_article_collect.meta.job_count == 1 + end + + test "user can add a repo to collect folder", ~m(user user_conn repo)a do + args = %{title: "folder_title", private: false} + {:ok, folder} = Accounts.create_collect_folder(args, user) + + variables = %{articleId: repo.id, folderId: folder.id, thread: "REPO"} + folder = user_conn |> mutation_result(@query, variables, "addToCollect") + + assert folder["totalCount"] == 1 + assert folder["lastUpdated"] != nil + + assert folder["meta"] == @meta |> Map.merge(%{"hasRepo" => true, "repoCount" => 1}) + + {:ok, article_collect} = + ArticleCollect |> ORM.find_by(%{repo_id: repo.id, user_id: user.id}) + + folder_in_article_collect = article_collect.collect_folders |> List.first() + + assert folder_in_article_collect.meta.has_repo + assert folder_in_article_collect.meta.repo_count == 1 + end + + test "user can add a blog to collect folder", ~m(user user_conn blog)a do + args = %{title: "folder_title", private: false} + {:ok, folder} = Accounts.create_collect_folder(args, user) + + variables = %{articleId: blog.id, folderId: folder.id, thread: "BLOG"} + folder = user_conn |> mutation_result(@query, variables, "addToCollect") + + assert folder["totalCount"] == 1 + assert folder["lastUpdated"] != nil + + assert folder["meta"] == @meta |> Map.merge(%{"hasBlog" => true, "blogCount" => 1}) + + {:ok, article_collect} = + ArticleCollect |> ORM.find_by(%{blog_id: blog.id, user_id: user.id}) + + folder_in_article_collect = article_collect.collect_folders |> List.first() + + assert folder_in_article_collect.meta.has_blog + assert folder_in_article_collect.meta.blog_count == 1 + end + @query """ mutation($articleId: ID!, $folderId: ID!, $thread: Thread) { removeFromCollect(articleId: $articleId, folderId: $folderId, thread: $thread) { @@ -164,14 +229,15 @@ defmodule GroupherServer.Test.Mutation.Accounts.CollectFolder do hasPost hasJob hasRepo + hasBlog postCount jobCount repoCount + blogCount } } } """ - test "user can remove a post from collect folder", ~m(user user_conn post)a do args = %{title: "folder_title", private: false} {:ok, folder} = Accounts.create_collect_folder(args, user) @@ -180,15 +246,43 @@ defmodule GroupherServer.Test.Mutation.Accounts.CollectFolder do variables = %{articleId: post.id, folderId: folder.id, thread: "POST"} result = user_conn |> mutation_result(@query, variables, "removeFromCollect") - assert result["meta"] == %{ - "hasJob" => false, - "hasPost" => false, - "hasRepo" => false, - "jobCount" => 0, - "postCount" => 0, - "repoCount" => 0 - } + assert result["meta"] == @meta + assert result["totalCount"] == 0 + end + + test "user can remove a job from collect folder", ~m(user user_conn job)a do + args = %{title: "folder_title", private: false} + {:ok, folder} = Accounts.create_collect_folder(args, user) + {:ok, _folder} = Accounts.add_to_collect(:job, job.id, folder.id, user) + + variables = %{articleId: job.id, folderId: folder.id, thread: "JOB"} + result = user_conn |> mutation_result(@query, variables, "removeFromCollect") + + assert result["meta"] == @meta + assert result["totalCount"] == 0 + end + + test "user can remove a repo from collect folder", ~m(user user_conn repo)a do + args = %{title: "folder_title", private: false} + {:ok, folder} = Accounts.create_collect_folder(args, user) + {:ok, _folder} = Accounts.add_to_collect(:repo, repo.id, folder.id, user) + + variables = %{articleId: repo.id, folderId: folder.id, thread: "REPO"} + result = user_conn |> mutation_result(@query, variables, "removeFromCollect") + + assert result["meta"] == @meta + assert result["totalCount"] == 0 + end + + test "user can remove a blog from collect folder", ~m(user user_conn blog)a do + args = %{title: "folder_title", private: false} + {:ok, folder} = Accounts.create_collect_folder(args, user) + {:ok, _folder} = Accounts.add_to_collect(:blog, blog.id, folder.id, user) + + variables = %{articleId: blog.id, folderId: folder.id, thread: "BLOG"} + result = user_conn |> mutation_result(@query, variables, "removeFromCollect") + assert result["meta"] == @meta assert result["totalCount"] == 0 end end diff --git a/test/groupher_server_web/mutation/cms/abuse_reports/blog_report_test.exs b/test/groupher_server_web/mutation/cms/abuse_reports/blog_report_test.exs new file mode 100644 index 000000000..f6a602fb8 --- /dev/null +++ b/test/groupher_server_web/mutation/cms/abuse_reports/blog_report_test.exs @@ -0,0 +1,62 @@ +defmodule GroupherServer.Test.Mutation.AbuseReports.BlogReport do + use GroupherServer.TestTools + + alias GroupherServer.CMS + + setup do + {:ok, user} = db_insert(:user) + {:ok, community} = db_insert(:community) + + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user) + owner_conn = simu_conn(:user, user) + + {:ok, ~m(user_conn user guest_conn owner_conn community blog_attrs)a} + end + + describe "[blog report/undo_report]" do + @report_query """ + mutation($id: ID!, $reason: String!, $attr: String) { + reportBlog(id: $id, reason: $reason, attr: $attr) { + id + title + } + } + """ + + test "login user can report a blog", ~m(community blog_attrs user user_conn)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + variables = %{id: blog.id, reason: "reason"} + article = user_conn |> mutation_result(@report_query, variables, "reportBlog") + + assert article["id"] == to_string(blog.id) + end + + @undo_report_query """ + mutation($id: ID!) { + undoReportBlog(id: $id) { + id + title + } + } + """ + + test "login user can undo report a blog", ~m(community blog_attrs user user_conn)a do + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + variables = %{id: blog.id, reason: "reason"} + article = user_conn |> mutation_result(@report_query, variables, "reportBlog") + + assert article["id"] == to_string(blog.id) + + variables = %{id: blog.id} + + article = user_conn |> mutation_result(@undo_report_query, variables, "undoReportBlog") + + assert article["id"] == to_string(blog.id) + end + end +end diff --git a/test/groupher_server_web/mutation/cms/article_community/blog_test.exs b/test/groupher_server_web/mutation/cms/article_community/blog_test.exs new file mode 100644 index 000000000..57b0c0670 --- /dev/null +++ b/test/groupher_server_web/mutation/cms/article_community/blog_test.exs @@ -0,0 +1,148 @@ +defmodule GroupherServer.Test.Mutation.ArticleCommunity.Blog do + use GroupherServer.TestTools + + alias Helper.ORM + alias GroupherServer.CMS + alias CMS.Model.Blog + + setup do + {:ok, blog} = db_insert(:blog) + {:ok, community} = db_insert(:community) + + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user) + owner_conn = simu_conn(:owner, blog) + + {:ok, ~m(user_conn guest_conn owner_conn community blog)a} + end + + describe "[mirror/unmirror/move blog to/from community]" do + @mirror_article_query """ + mutation($id: ID!, $thread: Thread, $communityId: ID!) { + mirrorArticle(id: $id, thread: $thread, communityId: $communityId) { + id + } + } + """ + test "auth user can mirror a blog to other community", ~m(blog)a do + passport_rules = %{"blog.community.mirror" => true} + rule_conn = simu_conn(:user, cms: passport_rules) + + {:ok, community} = db_insert(:community) + variables = %{id: blog.id, thread: "BLOG", communityId: community.id} + rule_conn |> mutation_result(@mirror_article_query, variables, "mirrorArticle") + {:ok, found} = ORM.find(Blog, blog.id, preload: :communities) + + assoc_communities = found.communities |> Enum.map(& &1.id) + assert community.id in assoc_communities + end + + test "unauth user cannot mirror a blog to a community", ~m(user_conn guest_conn blog)a do + {:ok, community} = db_insert(:community) + variables = %{id: blog.id, thread: "BLOG", communityId: community.id} + rule_conn = simu_conn(:user, cms: %{"what.ever" => true}) + + assert user_conn + |> mutation_get_error?(@mirror_article_query, variables, ecode(:passport)) + + assert guest_conn + |> mutation_get_error?(@mirror_article_query, variables, ecode(:account_login)) + + assert rule_conn + |> mutation_get_error?(@mirror_article_query, variables, ecode(:passport)) + end + + test "auth user can mirror multi blog to other communities", ~m(blog)a do + passport_rules = %{"blog.community.mirror" => true} + rule_conn = simu_conn(:user, cms: passport_rules) + + {:ok, community} = db_insert(:community) + {:ok, community2} = db_insert(:community) + + variables = %{id: blog.id, thread: "BLOG", communityId: community.id} + rule_conn |> mutation_result(@mirror_article_query, variables, "mirrorArticle") + + variables = %{id: blog.id, thread: "BLOG", communityId: community2.id} + rule_conn |> mutation_result(@mirror_article_query, variables, "mirrorArticle") + + {:ok, found} = ORM.find(Blog, blog.id, preload: :communities) + + assoc_communities = found.communities |> Enum.map(& &1.id) + assert community.id in assoc_communities + assert community2.id in assoc_communities + end + + @unmirror_article_query """ + mutation($id: ID!, $thread: Thread, $communityId: ID!) { + unmirrorArticle(id: $id, thread: $thread, communityId: $communityId) { + id + } + } + """ + + test "auth user can unmirror blog to a community", ~m(blog)a do + passport_rules = %{"blog.community.mirror" => true} + rule_conn = simu_conn(:user, cms: passport_rules) + + {:ok, community} = db_insert(:community) + {:ok, community2} = db_insert(:community) + + variables = %{id: blog.id, thread: "BLOG", communityId: community.id} + rule_conn |> mutation_result(@mirror_article_query, variables, "mirrorArticle") + + variables2 = %{id: blog.id, thread: "BLOG", communityId: community2.id} + rule_conn |> mutation_result(@mirror_article_query, variables2, "mirrorArticle") + + {:ok, found} = ORM.find(Blog, blog.id, preload: :communities) + + assoc_communities = found.communities |> Enum.map(& &1.id) + assert community.id in assoc_communities + assert community2.id in assoc_communities + + passport_rules = %{"blog.community.unmirror" => true} + rule_conn = simu_conn(:user, cms: passport_rules) + + rule_conn |> mutation_result(@unmirror_article_query, variables, "unmirrorArticle") + {:ok, found} = ORM.find(Blog, blog.id, preload: :communities) + assoc_communities = found.communities |> Enum.map(& &1.id) + assert community.id not in assoc_communities + assert community2.id in assoc_communities + end + + @move_article_query """ + mutation($id: ID!, $thread: Thread, $communityId: ID!) { + moveArticle(id: $id, thread: $thread, communityId: $communityId) { + id + } + } + """ + test "auth user can move blog to other community", ~m(blog)a do + passport_rules = %{"blog.community.mirror" => true} + rule_conn = simu_conn(:user, cms: passport_rules) + + {:ok, community} = db_insert(:community) + {:ok, community2} = db_insert(:community) + + variables = %{id: blog.id, thread: "BLOG", communityId: community.id} + rule_conn |> mutation_result(@mirror_article_query, variables, "mirrorArticle") + {:ok, found} = ORM.find(Blog, blog.id, preload: [:original_community, :communities]) + assoc_communities = found.communities |> Enum.map(& &1.id) + assert community.id in assoc_communities + + passport_rules = %{"blog.community.move" => true} + rule_conn = simu_conn(:user, cms: passport_rules) + + pre_original_community_id = found.original_community.id + + variables = %{id: blog.id, thread: "BLOG", communityId: community2.id} + rule_conn |> mutation_result(@move_article_query, variables, "moveArticle") + {:ok, found} = ORM.find(Blog, blog.id, preload: [:original_community, :communities]) + assoc_communities = found.communities |> Enum.map(& &1.id) + assert pre_original_community_id not in assoc_communities + assert community2.id in assoc_communities + assert community2.id == found.original_community_id + + assert found.original_community.id == community2.id + end + end +end diff --git a/test/groupher_server_web/mutation/cms/article_tags/blog_tag_test.exs b/test/groupher_server_web/mutation/cms/article_tags/blog_tag_test.exs new file mode 100644 index 000000000..5cb3004eb --- /dev/null +++ b/test/groupher_server_web/mutation/cms/article_tags/blog_tag_test.exs @@ -0,0 +1,91 @@ +defmodule GroupherServer.Test.Mutation.ArticleTags.BlogTag do + @moduledoc false + + use GroupherServer.TestTools + + alias Helper.ORM + alias GroupherServer.CMS + alias CMS.Model.Blog + + setup do + {:ok, blog} = db_insert(:blog) + {:ok, user} = db_insert(:user) + {:ok, community} = db_insert(:community) + + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user) + owner_conn = simu_conn(:owner, blog) + + article_tag_attrs = mock_attrs(:article_tag) + article_tag_attrs2 = mock_attrs(:article_tag) + + {:ok, + ~m(user_conn guest_conn owner_conn community blog article_tag_attrs article_tag_attrs2 user)a} + end + + describe "[mutation blog tag]" do + @set_tag_query """ + mutation($id: ID!, $thread: Thread, $articleTagId: ID!, $communityId: ID!) { + setArticleTag(id: $id, thread: $thread, articleTagId: $articleTagId, communityId: $communityId) { + id + } + } + """ + + test "auth user can set a valid tag to blog", ~m(community blog article_tag_attrs user)a do + {:ok, article_tag} = CMS.create_article_tag(community, :blog, article_tag_attrs, user) + + passport_rules = %{community.title => %{"blog.article_tag.set" => true}} + rule_conn = simu_conn(:user, cms: passport_rules) + + variables = %{ + id: blog.id, + thread: "BLOG", + articleTagId: article_tag.id, + communityId: community.id + } + + rule_conn |> mutation_result(@set_tag_query, variables, "setArticleTag") + {:ok, found} = ORM.find(Blog, blog.id, preload: :article_tags) + + assoc_tags = found.article_tags |> Enum.map(& &1.id) + assert article_tag.id in assoc_tags + end + + @unset_tag_query """ + mutation($id: ID!, $thread: Thread, $articleTagId: ID!, $communityId: ID!) { + unsetArticleTag(id: $id, thread: $thread, articleTagId: $articleTagId, communityId: $communityId) { + id + title + } + } + """ + + test "can unset tag to a blog", + ~m(community blog article_tag_attrs article_tag_attrs2 user)a do + {:ok, article_tag} = CMS.create_article_tag(community, :blog, article_tag_attrs, user) + {:ok, article_tag2} = CMS.create_article_tag(community, :blog, article_tag_attrs2, user) + + {:ok, _} = CMS.set_article_tag(:blog, blog.id, article_tag.id) + {:ok, _} = CMS.set_article_tag(:blog, blog.id, article_tag2.id) + + passport_rules = %{community.title => %{"blog.article_tag.unset" => true}} + rule_conn = simu_conn(:user, cms: passport_rules) + + variables = %{ + id: blog.id, + thread: "BLOG", + articleTagId: article_tag.id, + communityId: community.id + } + + rule_conn |> mutation_result(@unset_tag_query, variables, "unsetArticleTag") + + {:ok, blog} = ORM.find(Blog, blog.id, preload: :article_tags) + assoc_tags = blog.article_tags |> Enum.map(& &1.id) + + assert article_tag.id not in assoc_tags + assert article_tag2.id in assoc_tags + end + end +end diff --git a/test/groupher_server_web/mutation/cms/comments/blog_comment_test.exs b/test/groupher_server_web/mutation/cms/comments/blog_comment_test.exs new file mode 100644 index 000000000..c0593805d --- /dev/null +++ b/test/groupher_server_web/mutation/cms/comments/blog_comment_test.exs @@ -0,0 +1,222 @@ +defmodule GroupherServer.Test.Mutation.Comments.BlogComment do + use GroupherServer.TestTools + + alias GroupherServer.CMS + alias CMS.Model.Blog + + alias Helper.ORM + + setup do + {:ok, user} = db_insert(:user) + {:ok, community} = db_insert(:community) + {:ok, blog} = CMS.create_article(community, :blog, mock_attrs(:blog), user) + + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user) + owner_conn = simu_conn(:user, user) + + {:ok, ~m(user_conn user guest_conn owner_conn community blog)a} + end + + describe "[article comment CURD]" do + @write_comment_query """ + mutation($thread: Thread!, $id: ID!, $content: String!) { + createArticleComment(thread: $thread,id: $id, content: $content) { + id + bodyHtml + } + } + """ + test "write article comment to a exsit blog", ~m(blog user_conn)a do + comment = "a test comment" + variables = %{thread: "BLOG", id: blog.id, content: comment} + + result = + user_conn |> mutation_result(@write_comment_query, variables, "createArticleComment") + + assert result["bodyHtml"] == comment + end + + @reply_comment_query """ + mutation($id: ID!, $content: String!) { + replyArticleComment(id: $id, content: $content) { + id + bodyHtml + } + } + """ + test "login user can reply to a comment", ~m(blog user user_conn)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "commment", user) + variables = %{id: comment.id, content: "reply content"} + + result = + user_conn + |> mutation_result(@reply_comment_query, variables, "replyArticleComment") + + assert result["bodyHtml"] == "reply content" + end + + @update_comment_query """ + mutation($id: ID!, $content: String!) { + updateArticleComment(id: $id, content: $content) { + id + bodyHtml + } + } + """ + test "only owner can update a exsit comment", + ~m(blog user guest_conn user_conn owner_conn)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "blog comment", user) + variables = %{id: comment.id, content: "updated comment"} + + assert user_conn |> mutation_get_error?(@update_comment_query, variables, ecode(:passport)) + + assert guest_conn + |> mutation_get_error?(@update_comment_query, variables, ecode(:account_login)) + + updated = + owner_conn |> mutation_result(@update_comment_query, variables, "updateArticleComment") + + assert updated["bodyHtml"] == "updated comment" + end + + @delete_comment_query """ + mutation($id: ID!) { + deleteArticleComment(id: $id) { + id + isDeleted + } + } + """ + test "only owner can delete a exsit comment", + ~m(blog user guest_conn user_conn owner_conn)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "blog comment", user) + variables = %{id: comment.id} + + assert user_conn |> mutation_get_error?(@delete_comment_query, variables, ecode(:passport)) + + assert guest_conn + |> mutation_get_error?(@delete_comment_query, variables, ecode(:account_login)) + + deleted = + owner_conn |> mutation_result(@delete_comment_query, variables, "deleteArticleComment") + + assert deleted["id"] == to_string(comment.id) + assert deleted["isDeleted"] + end + end + + describe "[article comment emotion]" do + @emotion_comment_query """ + mutation($id: ID!, $emotion: ArticleCommentEmotion!) { + emotionToComment(id: $id, emotion: $emotion) { + id + emotions { + beerCount + viewerHasBeered + latestBeerUsers { + login + nickname + } + } + } + } + """ + test "login user can emotion to a comment", ~m(blog user user_conn)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "blog comment", user) + variables = %{id: comment.id, emotion: "BEER"} + + comment = + user_conn |> mutation_result(@emotion_comment_query, variables, "emotionToComment") + + assert comment |> get_in(["emotions", "beerCount"]) == 1 + assert get_in(comment, ["emotions", "viewerHasBeered"]) + end + + @emotion_comment_query """ + mutation($id: ID!, $emotion: ArticleCommentEmotion!) { + undoEmotionToComment(id: $id, emotion: $emotion) { + id + emotions { + beerCount + viewerHasBeered + latestBeerUsers { + login + nickname + } + } + } + } + """ + test "login user can undo emotion to a comment", ~m(blog user owner_conn)a do + {:ok, comment} = CMS.create_article_comment(:blog, blog.id, "blog comment", user) + {:ok, _} = CMS.emotion_to_comment(comment.id, :beer, user) + + variables = %{id: comment.id, emotion: "BEER"} + + comment = + owner_conn |> mutation_result(@emotion_comment_query, variables, "undoEmotionToComment") + + assert comment |> get_in(["emotions", "beerCount"]) == 0 + assert not get_in(comment, ["emotions", "viewerHasBeered"]) + end + end + + describe "[article comment lock/unlock]" do + @query """ + mutation($id: ID!, $communityId: ID!){ + lockBlogComment(id: $id, communityId: $communityId) { + id + } + } + """ + + test "can lock a blog's comment", ~m(community blog)a do + variables = %{id: blog.id, communityId: community.id} + passport_rules = %{community.raw => %{"blog.lock_comment" => true}} + rule_conn = simu_conn(:user, cms: passport_rules) + + result = rule_conn |> mutation_result(@query, variables, "lockBlogComment") + assert result["id"] == to_string(blog.id) + + {:ok, blog} = ORM.find(Blog, blog.id) + assert blog.meta.is_comment_locked + end + + test "unauth user fails", ~m(guest_conn community blog)a do + variables = %{id: blog.id, communityId: community.id} + + assert guest_conn |> mutation_get_error?(@query, variables, ecode(:account_login)) + end + + @query """ + mutation($id: ID!, $communityId: ID!){ + undoLockBlogComment(id: $id, communityId: $communityId) { + id + } + } + """ + + test "can undo lock a blog's comment", ~m(community blog)a do + {:ok, _} = CMS.lock_article_comment(:blog, blog.id) + {:ok, blog} = ORM.find(Blog, blog.id) + assert blog.meta.is_comment_locked + + variables = %{id: blog.id, communityId: community.id} + passport_rules = %{community.raw => %{"blog.undo_lock_comment" => true}} + rule_conn = simu_conn(:user, cms: passport_rules) + + result = rule_conn |> mutation_result(@query, variables, "undoLockBlogComment") + assert result["id"] == to_string(blog.id) + + {:ok, blog} = ORM.find(Blog, blog.id) + assert not blog.meta.is_comment_locked + end + + test "unauth user undo fails", ~m(guest_conn community blog)a do + variables = %{id: blog.id, communityId: community.id} + + assert guest_conn |> mutation_get_error?(@query, variables, ecode(:account_login)) + end + end +end diff --git a/test/groupher_server_web/mutation/cms/flags/blog_flag_test.exs b/test/groupher_server_web/mutation/cms/flags/blog_flag_test.exs new file mode 100644 index 000000000..1e251cdb2 --- /dev/null +++ b/test/groupher_server_web/mutation/cms/flags/blog_flag_test.exs @@ -0,0 +1,181 @@ +defmodule GroupherServer.Test.Mutation.Flags.BlogFlag do + use GroupherServer.TestTools + + alias GroupherServer.CMS + alias CMS.Model.Community + + alias Helper.ORM + + setup do + {:ok, user} = db_insert(:user) + {:ok, community} = db_insert(:community) + + {:ok, blog} = CMS.create_article(community, :blog, mock_attrs(:blog), user) + + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user) + owner_conn = simu_conn(:user, user) + + {:ok, ~m(user_conn guest_conn owner_conn community user blog)a} + end + + describe "[mutation blog flag curd]" do + @query """ + mutation($id: ID!){ + markDeleteBlog(id: $id) { + id + markDelete + } + } + """ + @tag :wip + test "auth user can markDelete blog", ~m(blog)a do + variables = %{id: blog.id} + + passport_rules = %{"blog.mark_delete" => true} + rule_conn = simu_conn(:user, cms: passport_rules) + + updated = rule_conn |> mutation_result(@query, variables, "markDeleteBlog") + + assert updated["id"] == to_string(blog.id) + assert updated["markDelete"] == true + end + + @tag :wip + test "mark delete blog should update blog's communities meta count", ~m(user)a do + community_attrs = mock_attrs(:community) |> Map.merge(%{user_id: user.id}) + {:ok, community} = CMS.create_community(community_attrs) + {:ok, blog} = CMS.create_article(community, :blog, mock_attrs(:blog), user) + + {:ok, community} = ORM.find(Community, community.id) + assert community.meta.blogs_count == 1 + + variables = %{id: blog.id} + passport_rules = %{"blog.mark_delete" => true} + rule_conn = simu_conn(:user, cms: passport_rules) + + rule_conn |> mutation_result(@query, variables, "markDeleteBlog") + + {:ok, community} = ORM.find(Community, community.id) + assert community.meta.blogs_count == 0 + end + + @tag :wip + test "unauth user markDelete blog fails", ~m(user_conn guest_conn blog)a do + variables = %{id: blog.id} + rule_conn = simu_conn(:user, cms: %{"what.ever" => true}) + + assert user_conn |> mutation_get_error?(@query, variables, ecode(:passport)) + assert guest_conn |> mutation_get_error?(@query, variables, ecode(:account_login)) + assert rule_conn |> mutation_get_error?(@query, variables, ecode(:passport)) + end + + @query """ + mutation($id: ID!){ + undoMarkDeleteBlog(id: $id) { + id + markDelete + } + } + """ + test "auth user can undo markDelete blog", ~m(blog)a do + variables = %{id: blog.id} + + {:ok, _} = CMS.mark_delete_article(:blog, blog.id) + + passport_rules = %{"blog.undo_mark_delete" => true} + rule_conn = simu_conn(:user, cms: passport_rules) + + updated = rule_conn |> mutation_result(@query, variables, "undoMarkDeleteBlog") + + assert updated["id"] == to_string(blog.id) + assert updated["markDelete"] == false + end + + test "undo mark delete blog should update blog's communities meta count", ~m(user)a do + community_attrs = mock_attrs(:community) |> Map.merge(%{user_id: user.id}) + {:ok, community} = CMS.create_community(community_attrs) + {:ok, blog} = CMS.create_article(community, :blog, mock_attrs(:blog), user) + + {:ok, _} = CMS.mark_delete_article(:blog, blog.id) + + {:ok, community} = ORM.find(Community, community.id) + assert community.meta.blogs_count == 0 + + variables = %{id: blog.id} + passport_rules = %{"blog.undo_mark_delete" => true} + rule_conn = simu_conn(:user, cms: passport_rules) + rule_conn |> mutation_result(@query, variables, "undoMarkDeleteBlog") + + {:ok, community} = ORM.find(Community, community.id) + assert community.meta.blogs_count == 1 + end + + test "unauth user undo markDelete blog fails", ~m(user_conn guest_conn blog)a do + variables = %{id: blog.id} + rule_conn = simu_conn(:user, cms: %{"what.ever" => true}) + + assert user_conn |> mutation_get_error?(@query, variables, ecode(:passport)) + assert guest_conn |> mutation_get_error?(@query, variables, ecode(:account_login)) + assert rule_conn |> mutation_get_error?(@query, variables, ecode(:passport)) + end + + @query """ + mutation($id: ID!, $communityId: ID!){ + pinBlog(id: $id, communityId: $communityId) { + id + } + } + """ + + test "auth user can pin blog", ~m(community blog)a do + variables = %{id: blog.id, communityId: community.id} + + passport_rules = %{community.raw => %{"blog.pin" => true}} + rule_conn = simu_conn(:user, cms: passport_rules) + + updated = rule_conn |> mutation_result(@query, variables, "pinBlog") + + assert updated["id"] == to_string(blog.id) + end + + test "unauth user pin blog fails", ~m(user_conn guest_conn community blog)a do + variables = %{id: blog.id, communityId: community.id} + rule_conn = simu_conn(:user, cms: %{"what.ever" => true}) + + assert user_conn |> mutation_get_error?(@query, variables, ecode(:passport)) + assert guest_conn |> mutation_get_error?(@query, variables, ecode(:account_login)) + assert rule_conn |> mutation_get_error?(@query, variables, ecode(:passport)) + end + + @query """ + mutation($id: ID!, $communityId: ID!){ + undoPinBlog(id: $id, communityId: $communityId) { + id + isPinned + } + } + """ + + test "auth user can undo pin blog", ~m(community blog)a do + variables = %{id: blog.id, communityId: community.id} + + passport_rules = %{community.raw => %{"blog.undo_pin" => true}} + rule_conn = simu_conn(:user, cms: passport_rules) + + CMS.pin_article(:blog, blog.id, community.id) + updated = rule_conn |> mutation_result(@query, variables, "undoPinBlog") + + assert updated["id"] == to_string(blog.id) + end + + test "unauth user undo pin blog fails", ~m(user_conn guest_conn community blog)a do + variables = %{id: blog.id, communityId: community.id} + rule_conn = simu_conn(:user, cms: %{"what.ever" => true}) + + assert user_conn |> mutation_get_error?(@query, variables, ecode(:passport)) + assert guest_conn |> mutation_get_error?(@query, variables, ecode(:account_login)) + assert rule_conn |> mutation_get_error?(@query, variables, ecode(:passport)) + end + end +end diff --git a/test/groupher_server_web/mutation/cms/sink/blog_sink_test.exs b/test/groupher_server_web/mutation/cms/sink/blog_sink_test.exs new file mode 100644 index 000000000..9713f58cc --- /dev/null +++ b/test/groupher_server_web/mutation/cms/sink/blog_sink_test.exs @@ -0,0 +1,79 @@ +defmodule GroupherServer.Test.Mutation.Sink.BlogSink do + @moduledoc false + use GroupherServer.TestTools + + alias GroupherServer.CMS + alias CMS.Model.Blog + + alias Helper.ORM + + setup do + {:ok, user} = db_insert(:user) + {:ok, community} = db_insert(:community) + {:ok, blog} = CMS.create_article(community, :blog, mock_attrs(:blog), user) + + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user, user) + + {:ok, ~m(user_conn guest_conn community blog user)a} + end + + describe "[blog sink]" do + @query """ + mutation($id: ID!, $communityId: ID!){ + sinkBlog(id: $id, communityId: $communityId) { + id + } + } + """ + + test "login user can sink a blog", ~m(community blog)a do + variables = %{id: blog.id, communityId: community.id} + passport_rules = %{community.raw => %{"blog.sink" => true}} + rule_conn = simu_conn(:user, cms: passport_rules) + + result = rule_conn |> mutation_result(@query, variables, "sinkBlog") + assert result["id"] == to_string(blog.id) + + {:ok, blog} = ORM.find(Blog, blog.id) + assert blog.meta.is_sinked + assert blog.active_at == blog.inserted_at + end + + test "unauth user sink a blog fails", ~m(guest_conn community blog)a do + variables = %{id: blog.id, communityId: community.id} + + assert guest_conn |> mutation_get_error?(@query, variables, ecode(:account_login)) + end + + @query """ + mutation($id: ID!, $communityId: ID!){ + undoSinkBlog(id: $id, communityId: $communityId) { + id + } + } + """ + + test "login user can undo sink to a blog", ~m(community blog)a do + variables = %{id: blog.id, communityId: community.id} + + passport_rules = %{community.raw => %{"blog.undo_sink" => true}} + rule_conn = simu_conn(:user, cms: passport_rules) + + {:ok, _} = CMS.sink_article(:blog, blog.id) + updated = rule_conn |> mutation_result(@query, variables, "undoSinkBlog") + assert updated["id"] == to_string(blog.id) + + {:ok, blog} = ORM.find(Blog, blog.id) + assert not blog.meta.is_sinked + end + + :wip2 + + test "unauth user undo sink a blog fails", ~m(guest_conn community blog)a do + variables = %{id: blog.id, communityId: community.id} + + assert guest_conn |> mutation_get_error?(@query, variables, ecode(:account_login)) + end + end +end diff --git a/test/groupher_server_web/mutation/cms/upvotes/blog_upvote_test.exs b/test/groupher_server_web/mutation/cms/upvotes/blog_upvote_test.exs new file mode 100644 index 000000000..80030d006 --- /dev/null +++ b/test/groupher_server_web/mutation/cms/upvotes/blog_upvote_test.exs @@ -0,0 +1,64 @@ +defmodule GroupherServer.Test.Mutation.Upvotes.BlogUpvote do + @moduledoc false + use GroupherServer.TestTools + + alias GroupherServer.CMS + + setup do + {:ok, blog} = db_insert(:blog) + {:ok, user} = db_insert(:user) + + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user, user) + + {:ok, ~m(user_conn guest_conn blog user)a} + end + + describe "[blog upvote]" do + @query """ + mutation($id: ID!) { + upvoteBlog(id: $id) { + id + } + } + """ + + test "login user can upvote a blog", ~m(user_conn blog)a do + variables = %{id: blog.id} + created = user_conn |> mutation_result(@query, variables, "upvoteBlog") + + assert created["id"] == to_string(blog.id) + end + + test "unauth user upvote a blog fails", ~m(guest_conn blog)a do + variables = %{id: blog.id} + + assert guest_conn + |> mutation_get_error?(@query, variables, ecode(:account_login)) + end + + @query """ + mutation($id: ID!) { + undoUpvoteBlog(id: $id) { + id + } + } + """ + + test "login user can undo upvote to a blog", ~m(user_conn blog user)a do + {:ok, _} = CMS.upvote_article(:blog, blog.id, user) + + variables = %{id: blog.id} + updated = user_conn |> mutation_result(@query, variables, "undoUpvoteBlog") + + assert updated["id"] == to_string(blog.id) + end + + test "unauth user undo upvote a blog fails", ~m(guest_conn blog)a do + variables = %{id: blog.id} + + assert guest_conn + |> mutation_get_error?(@query, variables, ecode(:account_login)) + end + end +end From 57c0b242e2d2e553319a508fea17cb9de8b77c7e Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 8 Jun 2021 10:01:30 +0800 Subject: [PATCH 28/28] refactor(blog-thread): improve comment fold test --- test/groupher_server/cms/comments/blog_comment_test.exs | 2 +- test/groupher_server/cms/comments/job_comment_test.exs | 2 +- test/groupher_server/cms/comments/post_comment_test.exs | 2 +- test/groupher_server/cms/comments/repo_comment_test.exs | 3 ++- test/groupher_server_web/mutation/cms/flags/blog_flag_test.exs | 3 --- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/test/groupher_server/cms/comments/blog_comment_test.exs b/test/groupher_server/cms/comments/blog_comment_test.exs index 6b3241cd4..8ec588d73 100644 --- a/test/groupher_server/cms/comments/blog_comment_test.exs +++ b/test/groupher_server/cms/comments/blog_comment_test.exs @@ -424,7 +424,7 @@ defmodule GroupherServer.Test.CMS.Comments.BlogComment do :replies ) - random_comment = all_comments |> Enum.at(Enum.random(0..total_count)) + random_comment = all_comments |> Enum.at(Enum.random(0..(total_count - 1))) assert not random_comment.is_folded diff --git a/test/groupher_server/cms/comments/job_comment_test.exs b/test/groupher_server/cms/comments/job_comment_test.exs index dcc32a586..0be65e808 100644 --- a/test/groupher_server/cms/comments/job_comment_test.exs +++ b/test/groupher_server/cms/comments/job_comment_test.exs @@ -423,7 +423,7 @@ defmodule GroupherServer.Test.CMS.Comments.JobComment do :replies ) - random_comment = all_comments |> Enum.at(Enum.random(0..total_count)) + random_comment = all_comments |> Enum.at(Enum.random(0..(total_count - 1))) assert not random_comment.is_folded diff --git a/test/groupher_server/cms/comments/post_comment_test.exs b/test/groupher_server/cms/comments/post_comment_test.exs index 9b60f7382..3f68d7931 100644 --- a/test/groupher_server/cms/comments/post_comment_test.exs +++ b/test/groupher_server/cms/comments/post_comment_test.exs @@ -424,7 +424,7 @@ defmodule GroupherServer.Test.CMS.Comments.PostComment do :replies ) - random_comment = all_comments |> Enum.at(Enum.random(0..total_count)) + random_comment = all_comments |> Enum.at(Enum.random(0..(total_count - 1))) assert not random_comment.is_folded diff --git a/test/groupher_server/cms/comments/repo_comment_test.exs b/test/groupher_server/cms/comments/repo_comment_test.exs index b5a2e003c..2de0fa6e0 100644 --- a/test/groupher_server/cms/comments/repo_comment_test.exs +++ b/test/groupher_server/cms/comments/repo_comment_test.exs @@ -404,6 +404,7 @@ defmodule GroupherServer.Test.CMS.Comments.RepoComment do assert results.total_count == total_count + 1 end + @tag :wip test "paged article comments folded flag should be false", ~m(user repo)a do total_count = 30 page_number = 1 @@ -424,7 +425,7 @@ defmodule GroupherServer.Test.CMS.Comments.RepoComment do :replies ) - random_comment = all_comments |> Enum.at(Enum.random(0..total_count)) + random_comment = all_comments |> Enum.at(Enum.random(0..(total_count - 1))) assert not random_comment.is_folded diff --git a/test/groupher_server_web/mutation/cms/flags/blog_flag_test.exs b/test/groupher_server_web/mutation/cms/flags/blog_flag_test.exs index 1e251cdb2..6d4526d82 100644 --- a/test/groupher_server_web/mutation/cms/flags/blog_flag_test.exs +++ b/test/groupher_server_web/mutation/cms/flags/blog_flag_test.exs @@ -28,7 +28,6 @@ defmodule GroupherServer.Test.Mutation.Flags.BlogFlag do } } """ - @tag :wip test "auth user can markDelete blog", ~m(blog)a do variables = %{id: blog.id} @@ -41,7 +40,6 @@ defmodule GroupherServer.Test.Mutation.Flags.BlogFlag do assert updated["markDelete"] == true end - @tag :wip test "mark delete blog should update blog's communities meta count", ~m(user)a do community_attrs = mock_attrs(:community) |> Map.merge(%{user_id: user.id}) {:ok, community} = CMS.create_community(community_attrs) @@ -60,7 +58,6 @@ defmodule GroupherServer.Test.Mutation.Flags.BlogFlag do assert community.meta.blogs_count == 0 end - @tag :wip test "unauth user markDelete blog fails", ~m(user_conn guest_conn blog)a do variables = %{id: blog.id} rule_conn = simu_conn(:user, cms: %{"what.ever" => true})