diff --git a/lib/groupher_server/cms/cms.ex b/lib/groupher_server/cms/cms.ex index a063bac7c..a7b22e92d 100644 --- a/lib/groupher_server/cms/cms.ex +++ b/lib/groupher_server/cms/cms.ex @@ -70,17 +70,16 @@ defmodule GroupherServer.CMS do defdelegate subscribe_default_community_ifnot(user), to: CommunityOperation # ArticleCURD - defdelegate read_content(thread, id, user), to: ArticleCURD - defdelegate paged_contents(queryable, filter, user), to: ArticleCURD - defdelegate paged_contents(queryable, filter), to: ArticleCURD + defdelegate read_article(thread, id), to: ArticleCURD + defdelegate read_article(thread, id, user), to: ArticleCURD + + defdelegate paged_articles(queryable, filter), to: ArticleCURD + defdelegate paged_articles(queryable, filter, user), to: ArticleCURD + defdelegate create_content(community, thread, attrs, user), to: ArticleCURD defdelegate update_content(content, attrs), to: ArticleCURD - defdelegate reaction_users(thread, react, id, filters), to: ArticleCURD # ArticleReaction - defdelegate reaction(thread, react, content_id, user), to: ArticleReaction - defdelegate undo_reaction(thread, react, content_id, user), to: ArticleReaction - defdelegate upvote_article(thread, article_id, user), to: ArticleReaction defdelegate undo_upvote_article(thread, article_id, user), to: ArticleReaction diff --git a/lib/groupher_server/cms/delegates/article_curd.ex b/lib/groupher_server/cms/delegates/article_curd.ex index f36ad79f5..66a618e09 100644 --- a/lib/groupher_server/cms/delegates/article_curd.ex +++ b/lib/groupher_server/cms/delegates/article_curd.ex @@ -5,55 +5,97 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do import Ecto.Query, warn: false import GroupherServer.CMS.Utils.Matcher2 + import GroupherServer.CMS.Utils.Matcher, only: [match_action: 2] - import GroupherServer.CMS.Utils.Matcher, only: [match_action: 2, dynamic_where: 2] import Helper.Utils, only: [done: 1, pick_by: 2, integerfy: 1] import Helper.ErrorCode - import ShortMaps + alias Helper.{Later, ORM} alias GroupherServer.{Accounts, CMS, Delivery, Email, Repo, Statistics} alias Accounts.User alias CMS.{Author, Community, PinnedArticle, Embeds, Delegate, Tag} alias Delegate.ArticleOperation - alias Helper.{Later, ORM, QueryBuilder} alias Ecto.Multi @default_article_meta Embeds.ArticleMeta.default_meta() @doc """ - login user read cms content by add views count and viewer record + read articles for un-logined user """ - def read_content(thread, id, %User{id: user_id}) do - condition = %{user_id: user_id} |> Map.merge(content_id(thread, id)) - - with {:ok, action} <- match_action(thread, :self), - {:ok, _viewer} <- action.viewer |> ORM.findby_or_insert(condition, condition) do - action.target |> ORM.read(id, inc: :views) + def read_article(thread, id) do + with {:ok, info} <- match(thread) do + ORM.read(info.model, id, inc: :views) end end @doc """ - get paged post / job ... + read articles for logined user """ - def paged_contents(queryable, filter, user) do - queryable - |> domain_filter_query(filter) - |> community_with_flag_query(filter) - |> read_state_query(filter, user) - |> ORM.find_all(filter) - |> add_pin_contents_ifneed(queryable, filter) + def read_article(thread, id, %User{id: user_id}) do + with {:ok, info} <- match(thread) do + Multi.new() + |> Multi.run(:inc_views, fn _, _ -> + ORM.read(info.model, id, inc: :views) + end) + |> Multi.run(:add_viewed_user, fn _, %{inc_views: article} -> + update_viewed_user_list(article, user_id) + end) + |> Repo.transaction() + |> read_result() + end end - def paged_contents(queryable, filter) do - queryable - |> domain_filter_query(filter) - |> community_with_flag_query(filter) - |> ORM.find_all(filter) - # TODO: if filter has when/sort/length/job... then don't - |> add_pin_contents_ifneed(queryable, filter) + def paged_articles(thread, filter) do + with {:ok, info} <- match(thread) do + info.model + |> domain_filter_query(filter) + |> community_with_flag_query(filter) + |> ORM.find_all(filter) + |> add_pin_contents_ifneed(info.model, filter) + end + end + + def paged_articles(thread, filter, %User{} = user) do + with {:ok, info} <- match(thread) do + info.model + |> domain_filter_query(filter) + |> community_with_flag_query(filter) + |> ORM.find_all(filter) + |> add_pin_contents_ifneed(info.model, filter) + |> mark_viewer_has_states(user) + end + end + + defp mark_viewer_has_states({:ok, %{entries: []} = contents}, _), do: {:ok, contents} + + defp mark_viewer_has_states({:ok, %{entries: entries} = contents}, user) do + entries = Enum.map(entries, &Map.merge(&1, do_mark_viewer_has_states(&1.meta, user))) + {:ok, Map.merge(contents, %{entries: entries})} + end + + defp mark_viewer_has_states({:error, reason}, _), do: {:error, reason} + + defp do_mark_viewer_has_states(nil, _) do + %{ + viewer_has_collected: false, + viewer_has_upvoted: false, + viewer_has_viewed: false, + viewer_has_reported: false + } + end + + defp do_mark_viewer_has_states(meta, %User{id: user_id}) do + # TODO: 根据是否付费进一步判断 + # user_is_member = true + %{ + viewer_has_collected: Enum.member?(meta.collected_user_ids, user_id), + viewer_has_upvoted: Enum.member?(meta.upvoted_user_ids, user_id), + viewer_has_viewed: Enum.member?(meta.viewed_user_ids, user_id), + viewer_has_reported: Enum.member?(meta.reported_user_ids, user_id) + } end @doc """ @@ -246,19 +288,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do defp domain_filter_query(queryable, _filter), do: queryable - # query if user has viewed before - defp read_state_query(queryable, %{read: true} = _filter, user) do - queryable - |> join(:inner, [content, f, c], viewers in assoc(content, :viewers)) - |> where([content, f, c, viewers], viewers.user_id == ^user.id) - end - - defp read_state_query(queryable, %{read: false} = _filter, _user) do - queryable - end - - defp read_state_query(queryable, _, _), do: queryable - defp add_pin_contents_ifneed(contents, querable, %{community: _community} = filter) do with {:ok, _} <- should_add_pin?(filter), {:ok, info} <- match(querable), @@ -285,10 +314,10 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do defp add_pin_contents_ifneed(contents, _querable, _filter), do: contents # if filter contains like: tags, sort.., then don't add pin content - defp should_add_pin?(%{page: 1, tag: :all, sort: :desc_inserted, read: :all} = filter) do + defp should_add_pin?(%{page: 1, tag: :all, sort: :desc_inserted} = filter) do filter |> Map.keys() - |> Enum.reject(fn x -> x in [:community, :tag, :sort, :read, :page, :size] end) + |> Enum.reject(fn x -> x in [:community, :tag, :sort, :page, :size] end) |> case do [] -> {:ok, :pass} _ -> {:error, :pass} @@ -355,10 +384,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do defp update_content_result({:error, :update_content, result, _steps}), do: {:error, result} defp update_content_result({:error, :update_tag, result, _steps}), do: {:error, result} - defp content_id(:post, id), do: %{post_id: id} - defp content_id(:job, id), do: %{job_id: id} - defp content_id(:repo, id), do: %{repo_id: id} - # for create content step in Multi.new defp do_create_content(target, attrs, %Author{id: aid}, %Community{id: cid}) do target @@ -417,4 +442,32 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do end defp exec_update_tags(_content, _), do: {:ok, :pass} + + defp update_viewed_user_list(%{meta: nil} = article, user_id) do + new_ids = Enum.uniq([user_id] ++ @default_article_meta.viewed_user_ids) + updated_meta = @default_article_meta |> Map.merge(%{viewed_user_ids: new_ids}) + + article + |> Ecto.Changeset.change() + |> Ecto.Changeset.put_embed(:meta, updated_meta) + |> Repo.update() + end + + defp update_viewed_user_list(%{meta: meta} = article, user_id) do + new_ids = Enum.uniq([user_id] ++ meta.viewed_user_ids) + + updated_meta = + meta |> Map.merge(%{viewed_user_ids: new_ids}) |> Map.from_struct() |> Map.delete(:id) + + article + |> Ecto.Changeset.change() + |> Ecto.Changeset.put_embed(:meta, updated_meta) + |> Repo.update() + end + + defp read_result({:ok, %{inc_views: result}}), do: result |> done() + + defp read_result({:error, _, result, _steps}) do + {:error, result} + end end diff --git a/lib/groupher_server/cms/delegates/article_reaction.ex b/lib/groupher_server/cms/delegates/article_reaction.ex index 190dc1234..4edf0c7e2 100644 --- a/lib/groupher_server/cms/delegates/article_reaction.ex +++ b/lib/groupher_server/cms/delegates/article_reaction.ex @@ -2,22 +2,23 @@ defmodule GroupherServer.CMS.Delegate.ArticleReaction do @moduledoc """ reaction[upvote, collect, watch ...] on article [post, job...] """ - import Helper.Utils, only: [done: 1, done: 2] + import Helper.Utils, only: [done: 1] import GroupherServer.CMS.Utils.Matcher2 - import GroupherServer.CMS.Utils.Matcher, only: [match_action: 2] import Ecto.Query, warn: false - import Helper.ErrorCode + # import Helper.ErrorCode import ShortMaps alias Helper.{ORM, QueryBuilder} alias GroupherServer.{Accounts, CMS, Repo} alias Accounts.User - alias CMS.{ArticleUpvote, ArticleCollect} + alias CMS.{ArticleUpvote, ArticleCollect, Embeds} alias Ecto.Multi + @default_article_meta Embeds.ArticleMeta.default_meta() + def upvoted_users(thread, article_id, filter) do load_reaction_users(ArticleUpvote, thread, article_id, filter) end @@ -46,6 +47,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleReaction do |> Multi.run(:inc_article_collects_count, fn _, _ -> update_article_upvotes_count(info, article, :collects_count, :inc) end) + |> Multi.run(:update_article_reaction_user_list, fn _, _ -> + update_article_reaction_user_list(:collect, article, user_id, :add) + end) |> Multi.run(:create_collect, fn _, _ -> thread_upcase = thread |> to_string |> String.upcase() args = Map.put(%{user_id: user_id, thread: thread_upcase}, info.foreign_key, article.id) @@ -82,6 +86,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleReaction do |> Multi.run(:inc_article_collects_count, fn _, _ -> update_article_upvotes_count(info, article, :collects_count, :dec) end) + |> Multi.run(:update_article_reaction_user_list, fn _, _ -> + update_article_reaction_user_list(:collect, article, user_id, :remove) + end) |> Multi.run(:undo_collect, fn _, _ -> args = Map.put(%{user_id: user_id}, info.foreign_key, article.id) @@ -142,6 +149,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleReaction do |> Multi.run(:inc_article_upvotes_count, fn _, _ -> update_article_upvotes_count(info, article, :upvotes_count, :inc) end) + |> Multi.run(:update_article_reaction_user_list, fn _, _ -> + update_article_reaction_user_list(:upvot, article, user_id, :add) + end) |> Multi.run(:add_achievement, fn _, _ -> achiever_id = article.author.user_id Accounts.achieve(%User{id: achiever_id}, :inc, :upvote) @@ -167,6 +177,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleReaction do |> Multi.run(:inc_article_upvotes_count, fn _, _ -> update_article_upvotes_count(info, article, :upvotes_count, :dec) end) + |> Multi.run(:update_article_reaction_user_list, fn _, _ -> + update_article_reaction_user_list(:upvot, article, user_id, :remove) + end) |> Multi.run(:undo_upvote, fn _, _ -> args = Map.put(%{user_id: user_id}, info.foreign_key, article.id) @@ -199,6 +212,56 @@ defmodule GroupherServer.CMS.Delegate.ArticleReaction do end end + @doc """ + add or remove artilce's reaction users is list history + e.g: + add/remove user_id to upvoted_user_ids in article meta + """ + @spec update_article_reaction_user_list( + :upvot | :collect, + T.article_common(), + String.t(), + :add | :remove + ) :: T.article_common() + defp update_article_reaction_user_list(action, %{meta: nil} = article, user_id, opt) do + cur_user_ids = [] + + updated_user_ids = + case opt do + :add -> [user_id] ++ cur_user_ids + :remove -> cur_user_ids -- [user_id] + end + + updated_meta = @default_article_meta |> Map.merge(%{"#{action}ed_user_ids": updated_user_ids}) + + do_update_article_meta(article, updated_meta) + end + + defp update_article_reaction_user_list(action, article, user_id, opt) do + cur_user_ids = get_in(article, [:meta, :"#{action}ed_user_ids"]) + + updated_user_ids = + case opt do + :add -> [user_id] ++ cur_user_ids + :remove -> cur_user_ids -- [user_id] + end + + meta = + article.meta + |> Map.merge(%{"#{action}ed_user_ids": updated_user_ids}) + |> Map.from_struct() + |> Map.delete(:id) + + do_update_article_meta(article, meta) + end + + defp do_update_article_meta(article, meta) do + article + |> Ecto.Changeset.change() + |> Ecto.Changeset.put_embed(:meta, meta) + |> Repo.update() + end + defp reaction_result({:ok, %{create_upvote: result}}), do: result |> done() defp reaction_result({:ok, %{undo_upvote: result}}), do: result |> done() diff --git a/lib/groupher_server/cms/embeds/article_meta.ex b/lib/groupher_server/cms/embeds/article_meta.ex index 386af158e..ef8c153ac 100644 --- a/lib/groupher_server/cms/embeds/article_meta.ex +++ b/lib/groupher_server/cms/embeds/article_meta.ex @@ -3,14 +3,19 @@ defmodule GroupherServer.CMS.Embeds.ArticleMeta do general article meta info for article-like content, like post, job, works ... """ use Ecto.Schema + use Accessible import Ecto.Changeset - @optional_fields ~w(is_edited is_comment_locked is_reported)a + @optional_fields ~w(is_edited is_comment_locked is_reported upvoted_user_ids collected_user_ids viewed_user_ids reported_user_ids)a @default_meta %{ is_edited: false, is_comment_locked: false, - is_reported: false + is_reported: false, + upvoted_user_ids: [], + collected_user_ids: [], + viewed_user_ids: [], + reported_user_ids: [] } @doc "for test usage" @@ -20,6 +25,11 @@ defmodule GroupherServer.CMS.Embeds.ArticleMeta do field(:is_edited, :boolean, default: false) field(:is_comment_locked, :boolean, default: false) field(:is_reported, :boolean, default: false) + # reaction history + field(:upvoted_user_ids, {:array, :integer}, default: []) + field(:collected_user_ids, {:array, :integer}, default: []) + field(:viewed_user_ids, {:array, :integer}, default: []) + field(:reported_user_ids, {:array, :integer}, default: []) end def changeset(struct, params) do diff --git a/lib/groupher_server/cms/job.ex b/lib/groupher_server/cms/job.ex index fd5df1042..1aecc75db 100644 --- a/lib/groupher_server/cms/job.ex +++ b/lib/groupher_server/cms/job.ex @@ -14,7 +14,6 @@ defmodule GroupherServer.CMS.Job do Embeds, ArticleComment, Community, - JobViewer, JobCommunityFlag, Tag, ArticleUpvote, @@ -69,8 +68,6 @@ defmodule GroupherServer.CMS.Job do field(:article_comments_count, :integer, default: 0) field(:article_comments_participators_count, :integer, default: 0) - has_many(:viewers, {"jobs_viewers", JobViewer}) - many_to_many( :tags, Tag, diff --git a/lib/groupher_server/cms/job_viewer.ex b/lib/groupher_server/cms/job_viewer.ex deleted file mode 100644 index dbac5ee3d..000000000 --- a/lib/groupher_server/cms/job_viewer.ex +++ /dev/null @@ -1,28 +0,0 @@ -defmodule GroupherServer.CMS.JobViewer do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - alias CMS.Job - - @required_fields ~w(job_id user_id)a - - @type t :: %JobViewer{} - schema "jobs_viewers" do - belongs_to(:job, Job, foreign_key: :job_id) - belongs_to(:user, Accounts.User, foreign_key: :user_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%JobViewer{} = job_viewer, attrs) do - job_viewer - |> cast(attrs, @required_fields) - |> validate_required(@required_fields) - |> unique_constraint(:user_id, name: :jobs_viewers_job_id_user_id_index) - end -end diff --git a/lib/groupher_server/cms/post.ex b/lib/groupher_server/cms/post.ex index ec61645a7..fcd20c3d3 100644 --- a/lib/groupher_server/cms/post.ex +++ b/lib/groupher_server/cms/post.ex @@ -17,7 +17,6 @@ defmodule GroupherServer.CMS.Post do Community, PostComment, PostCommunityFlag, - PostViewer, Tag, ArticleUpvote, ArticleCollect @@ -40,6 +39,7 @@ defmodule GroupherServer.CMS.Post do field(:length, :integer) field(:views, :integer, default: 0) + belongs_to(:author, Author) embeds_one(:meta, Embeds.ArticleMeta, on_replace: :update) has_many(:community_flags, {"posts_communities_flags", PostCommunityFlag}) @@ -49,7 +49,16 @@ defmodule GroupherServer.CMS.Post do field(:is_pinned, :boolean, default: false, virtual: true) field(:trash, :boolean, default_value: false, virtual: true) - belongs_to(:author, Author) + field(:viewer_has_viewed, :boolean, default: false, virtual: true) + field(:viewer_has_upvoted, :boolean, default: false, virtual: true) + field(:viewer_has_collected, :boolean, default: false, virtual: true) + field(:viewer_has_reported, :boolean, default: false, virtual: true) + + has_many(:upvotes, {"article_upvotes", ArticleUpvote}) + field(:upvotes_count, :integer, default: 0) + + has_many(:collects, {"article_collects", ArticleCollect}) + field(:collects_count, :integer, default: 0) # TODO # 相关文章 @@ -63,13 +72,6 @@ defmodule GroupherServer.CMS.Post do # 评论参与者,只保留最近 5 个 embeds_many(:article_comments_participators, Accounts.User, on_replace: :delete) - has_many(:upvotes, {"article_upvotes", ArticleUpvote}) - field(:upvotes_count, :integer, default: 0) - - has_many(:collects, {"article_collects", ArticleCollect}) - field(:collects_count, :integer, default: 0) - - has_many(:viewers, {"posts_viewers", PostViewer}) # The keys are inflected from the schema names! # see https://hexdocs.pm/ecto/Ecto.Schema.html many_to_many( diff --git a/lib/groupher_server/cms/post_viewer.ex b/lib/groupher_server/cms/post_viewer.ex deleted file mode 100644 index 7b5a49462..000000000 --- a/lib/groupher_server/cms/post_viewer.ex +++ /dev/null @@ -1,28 +0,0 @@ -defmodule GroupherServer.CMS.PostViewer do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - alias CMS.Post - - @required_fields ~w(post_id user_id)a - - @type t :: %PostViewer{} - schema "posts_viewers" do - belongs_to(:post, Post, foreign_key: :post_id) - belongs_to(:user, Accounts.User, foreign_key: :user_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%PostViewer{} = post_viewer, attrs) do - post_viewer - |> cast(attrs, @required_fields) - |> validate_required(@required_fields) - |> unique_constraint(:user_id, name: :posts_viewers_post_id_user_id_index) - end -end diff --git a/lib/groupher_server/cms/repo.ex b/lib/groupher_server/cms/repo.ex index fd34f9b37..6ccd4408c 100644 --- a/lib/groupher_server/cms/repo.ex +++ b/lib/groupher_server/cms/repo.ex @@ -3,6 +3,8 @@ defmodule GroupherServer.CMS.Repo do alias __MODULE__ use Ecto.Schema + use Accessible + import Ecto.Changeset alias GroupherServer.CMS @@ -12,7 +14,6 @@ defmodule GroupherServer.CMS.Repo do Embeds, Community, RepoContributor, - RepoViewer, RepoLang, RepoCommunityFlag, Tag, @@ -68,8 +69,6 @@ defmodule GroupherServer.CMS.Repo do field(:last_sync, :utc_datetime) - has_many(:viewers, {"repos_viewers", RepoViewer}) - many_to_many( :tags, Tag, diff --git a/lib/groupher_server/cms/repo_viewer.ex b/lib/groupher_server/cms/repo_viewer.ex deleted file mode 100644 index 4b8fad2c9..000000000 --- a/lib/groupher_server/cms/repo_viewer.ex +++ /dev/null @@ -1,28 +0,0 @@ -defmodule GroupherServer.CMS.RepoViewer do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.{Accounts, CMS} - alias CMS.Repo - - @required_fields ~w(repo_id user_id)a - - @type t :: %RepoViewer{} - schema "repos_viewers" do - belongs_to(:repo, Repo, foreign_key: :repo_id) - belongs_to(:user, Accounts.User, foreign_key: :user_id) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%RepoViewer{} = repo_viewer, attrs) do - repo_viewer - |> cast(attrs, @required_fields) - |> validate_required(@required_fields) - |> unique_constraint(:user_id, name: :repos_viewers_repo_id_user_id_index) - end -end diff --git a/lib/groupher_server/cms/utils/loader.ex b/lib/groupher_server/cms/utils/loader.ex index a4946c30b..659e23cb0 100644 --- a/lib/groupher_server/cms/utils/loader.ex +++ b/lib/groupher_server/cms/utils/loader.ex @@ -15,16 +15,13 @@ defmodule GroupherServer.CMS.Utils.Loader do CommunityThread, # POST Post, - PostViewer, PostComment, PostCommentLike, PostCommentReply, # JOB - Job, - JobViewer, + Job # JobStar, # Repo, - RepoViewer } alias Helper.QueryBuilder @@ -92,18 +89,6 @@ defmodule GroupherServer.CMS.Utils.Loader do ) end - def query({"posts_viewers", PostViewer}, %{cur_user: cur_user}) do - PostViewer |> where([pv], pv.user_id == ^cur_user.id) - end - - def query({"jobs_viewers", JobViewer}, %{cur_user: cur_user}) do - JobViewer |> where([pv], pv.user_id == ^cur_user.id) - end - - def query({"repos_viewers", RepoViewer}, %{cur_user: cur_user}) do - RepoViewer |> where([pv], pv.user_id == ^cur_user.id) - end - def query({"communities_subscribers", CommunitySubscriber}, args) do CommunitySubscriber |> QueryBuilder.members_pack(args) end diff --git a/lib/groupher_server/cms/utils/matcher.ex b/lib/groupher_server/cms/utils/matcher.ex index 02c52f14e..732b2ebbd 100644 --- a/lib/groupher_server/cms/utils/matcher.ex +++ b/lib/groupher_server/cms/utils/matcher.ex @@ -11,9 +11,6 @@ defmodule GroupherServer.CMS.Utils.Matcher do Repo, Job, # viewer - PostViewer, - JobViewer, - RepoViewer, # reactions # comments PostComment, @@ -32,7 +29,7 @@ defmodule GroupherServer.CMS.Utils.Matcher do ## posts ... ######################################### def match_action(:post, :self), - do: {:ok, %{target: Post, reactor: Post, preload: :author, viewer: PostViewer}} + do: {:ok, %{target: Post, reactor: Post, preload: :author}} def match_action(:post, :tag), do: {:ok, %{target: Post, reactor: Tag}} # NOTE: the tech, radar, share, city thread also use common tag @@ -54,7 +51,7 @@ defmodule GroupherServer.CMS.Utils.Matcher do ## jobs ... ######################################### def match_action(:job, :self), - do: {:ok, %{target: Job, reactor: Job, preload: :author, viewer: JobViewer}} + do: {:ok, %{target: Job, reactor: Job, preload: :author}} def match_action(:job, :community), do: {:ok, %{target: Job, reactor: Community, flag: JobCommunityFlag}} @@ -65,7 +62,7 @@ defmodule GroupherServer.CMS.Utils.Matcher do ## repos ... ######################################### def match_action(:repo, :self), - do: {:ok, %{target: Repo, reactor: Repo, preload: :author, viewer: RepoViewer}} + do: {:ok, %{target: Repo, reactor: Repo, preload: :author}} def match_action(:repo, :community), do: {:ok, %{target: Repo, reactor: Community, flag: RepoCommunityFlag}} diff --git a/lib/groupher_server_web/middleware/pagesize_proof.ex b/lib/groupher_server_web/middleware/pagesize_proof.ex index 4967f01d0..ad9431eb5 100644 --- a/lib/groupher_server_web/middleware/pagesize_proof.ex +++ b/lib/groupher_server_web/middleware/pagesize_proof.ex @@ -29,7 +29,6 @@ defmodule GroupherServerWeb.Middleware.PageSizeProof do # NOTE: c11n display_density should also linted by page limit, # otherwise dataloader will crash for empty extra items size = customization.display_density |> String.to_integer() |> min(@max_page_size) - # size = 28 case Map.has_key?(arguments, :filter) do true -> diff --git a/lib/groupher_server_web/resolvers/cms_resolver.ex b/lib/groupher_server_web/resolvers/cms_resolver.ex index e2de5723c..81ae3b04c 100644 --- a/lib/groupher_server_web/resolvers/cms_resolver.ex +++ b/lib/groupher_server_web/resolvers/cms_resolver.ex @@ -8,7 +8,7 @@ defmodule GroupherServerWeb.Resolvers.CMS do alias GroupherServer.{Accounts, CMS} alias Accounts.User - alias CMS.{Post, Repo, Job, Community, Category, Tag, Thread} + alias CMS.{Community, Category, Tag, Thread} alias Helper.ORM @@ -46,46 +46,25 @@ defmodule GroupherServerWeb.Resolvers.CMS do # ####################### # community thread (post, job), login user should be logged # ####################### - def post(_root, %{id: id}, %{context: %{cur_user: user}}) do - CMS.read_content(:post, id, user) + def read_article(_root, %{thread: thread, id: id}, %{context: %{cur_user: user}}) do + CMS.read_article(thread, id, user) end - def post(_root, %{id: id}, _info), - do: Post |> ORM.read(id, inc: :views) - - def job(_root, %{id: id}, %{context: %{cur_user: user}}) do - CMS.read_content(:job, id, user) + def read_article(_root, %{thread: thread, id: id}, _info) do + CMS.read_article(thread, id) end - def job(_root, %{id: id}, _info), do: Job |> ORM.read(id, inc: :views) - - def repo(_root, %{id: id}, %{context: %{cur_user: user}}) do - CMS.read_content(:repo, id, user) + def paged_articles(_root, ~m(thread filter)a, %{context: %{cur_user: user}}) do + CMS.paged_articles(thread, filter, user) end - def repo(_root, %{id: id}, _info), do: Repo |> ORM.read(id, inc: :views) + def paged_articles(_root, ~m(thread filter)a, _info) do + CMS.paged_articles(thread, filter) + end def wiki(_root, ~m(community)a, _info), do: CMS.get_wiki(%Community{raw: community}) def cheatsheet(_root, ~m(community)a, _info), do: CMS.get_cheatsheet(%Community{raw: community}) - def paged_posts(_root, ~m(filter)a, %{context: %{cur_user: user}}) do - Post |> CMS.paged_contents(filter, user) - end - - def paged_posts(_root, ~m(filter)a, _info), do: Post |> CMS.paged_contents(filter) - - def paged_repos(_root, ~m(filter)a, %{context: %{cur_user: user}}) do - Repo |> CMS.paged_contents(filter, user) - end - - def paged_repos(_root, ~m(filter)a, _info), do: Repo |> CMS.paged_contents(filter) - - def paged_jobs(_root, ~m(filter)a, %{context: %{cur_user: user}}) do - Job |> CMS.paged_contents(filter, user) - end - - def paged_jobs(_root, ~m(filter)a, _info), do: Job |> CMS.paged_contents(filter) - def create_content(_root, ~m(community_id thread)a = args, %{context: %{cur_user: user}}) do CMS.create_content(%Community{id: community_id}, thread, args, user) end diff --git a/lib/groupher_server_web/schema/cms/cms_misc.ex b/lib/groupher_server_web/schema/cms/cms_misc.ex index dfee96be6..c8a8c9d4e 100644 --- a/lib/groupher_server_web/schema/cms/cms_misc.ex +++ b/lib/groupher_server_web/schema/cms/cms_misc.ex @@ -138,12 +138,6 @@ defmodule GroupherServerWeb.Schema.CMS.Misc do value(:least_words) end - enum :read_enum do - value(:all) - # value(false) - value(true) - end - enum :rainbow_color_enum do value(:red) value(:orange) @@ -203,7 +197,6 @@ defmodule GroupherServerWeb.Schema.CMS.Misc do field(:when, :when_enum) field(:sort, :sort_enum) field(:length, :length_enum) - field(:read, :read_enum, default_value: :all) # @desc "Matching a tag" # @desc "Added to the menu after this date" # field(:added_after, :datetime) diff --git a/lib/groupher_server_web/schema/cms/cms_queries.ex b/lib/groupher_server_web/schema/cms/cms_queries.ex index c89ac01b1..2ae1c61e0 100644 --- a/lib/groupher_server_web/schema/cms/cms_queries.ex +++ b/lib/groupher_server_web/schema/cms/cms_queries.ex @@ -2,6 +2,8 @@ defmodule GroupherServerWeb.Schema.CMS.Queries do @moduledoc """ CMS queries """ + import GroupherServerWeb.Schema.Utils.Helper + use Helper.GqlSchemaSuite object :cms_queries do @@ -65,34 +67,6 @@ defmodule GroupherServerWeb.Schema.CMS.Queries do resolve(&R.CMS.paged_threads/3) end - @desc "get post by id" - field :post, non_null(:post) do - arg(:id, non_null(:id)) - resolve(&R.CMS.post/3) - end - - @desc "get paged posts" - field :paged_posts, :paged_posts do - arg(:filter, non_null(:paged_posts_filter)) - - middleware(M.PageSizeProof) - resolve(&R.CMS.paged_posts/3) - end - - @desc "get repo by id" - field :repo, non_null(:repo) do - arg(:id, non_null(:id)) - resolve(&R.CMS.repo/3) - end - - @desc "get paged repos" - field :paged_repos, :paged_repos do - arg(:filter, non_null(:paged_repos_filter)) - - middleware(M.PageSizeProof) - resolve(&R.CMS.paged_repos/3) - end - @desc "get wiki by community raw name" field :wiki, non_null(:wiki) do arg(:community, :string) @@ -105,50 +79,12 @@ defmodule GroupherServerWeb.Schema.CMS.Queries do resolve(&R.CMS.cheatsheet/3) end - @desc "get job by id" - field :job, non_null(:job) do - arg(:id, non_null(:id)) - resolve(&R.CMS.job/3) - end - - @desc "get paged jobs" - field :paged_jobs, :paged_jobs do - arg(:filter, non_null(:paged_jobs_filter)) - - middleware(M.PageSizeProof) - resolve(&R.CMS.paged_jobs/3) - end - - @desc "get paged upvoted users of an article" - field :upvoted_users, :paged_users do - arg(:id, non_null(:id)) - arg(:thread, :cms_thread, default_value: :post) - arg(:filter, non_null(:paged_filter)) - - middleware(M.PageSizeProof) - resolve(&R.CMS.upvoted_users/3) - end - - @desc "get paged upvoted users of an article" - field :collected_users, :paged_users do - arg(:id, non_null(:id)) - arg(:thread, :cms_thread, default_value: :post) - arg(:filter, non_null(:paged_filter)) - - middleware(M.PageSizeProof) - resolve(&R.CMS.collected_users/3) - end - - @desc "get paged users of a reaction related to cms content" - field :reaction_users, :paged_users do - arg(:id, non_null(:id)) - arg(:thread, :react_thread, default_value: :post) - arg(:action, non_null(:react_action)) - arg(:filter, non_null(:paged_filter)) + article_queries(:post) + article_queries(:job) + article_queries(:repo) - middleware(M.PageSizeProof) - resolve(&R.CMS.reaction_users/3) - end + article_reacted_users_query(:upvot, &R.CMS.upvoted_users/3) + article_reacted_users_query(:collect, &R.CMS.collected_users/3) # get all tags @desc "get paged tags" diff --git a/lib/groupher_server_web/schema/cms/cms_types.ex b/lib/groupher_server_web/schema/cms/cms_types.ex index fc69b6c43..5e42563e9 100644 --- a/lib/groupher_server_web/schema/cms/cms_types.ex +++ b/lib/groupher_server_web/schema/cms/cms_types.ex @@ -69,9 +69,7 @@ defmodule GroupherServerWeb.Schema.CMS.Types do end) end - has_viewed_field() - # viewer_has_upvoted - # viewer_has_collected + viewer_has_state_fields() # upvoted_count # collected_count @@ -112,7 +110,7 @@ defmodule GroupherServerWeb.Schema.CMS.Types do # comments_participators comments_counter_fields(:job) - has_viewed_field() + viewer_has_state_fields() timestamp_fields() end @@ -153,7 +151,7 @@ defmodule GroupherServerWeb.Schema.CMS.Types do field(:origial_community, :community, resolve: dataloader(CMS, :origial_community)) field(:communities, list_of(:community), resolve: dataloader(CMS, :communities)) - has_viewed_field() + viewer_has_state_fields() # comments_count # comments_participators comments_counter_fields(:repo) diff --git a/lib/groupher_server_web/schema/utils/helper.ex b/lib/groupher_server_web/schema/utils/helper.ex index d11ff9b9a..01460849e 100644 --- a/lib/groupher_server_web/schema/utils/helper.ex +++ b/lib/groupher_server_web/schema/utils/helper.ex @@ -39,7 +39,6 @@ defmodule GroupherServerWeb.Schema.Utils.Helper do quote do field(:when, :when_enum) field(:length, :length_enum) - field(:read, :read_enum, default_value: :all) field(:tag, :string, default_value: :all) field(:community, :string) end @@ -89,15 +88,51 @@ defmodule GroupherServerWeb.Schema.Utils.Helper do end end - defmacro has_viewed_field do + defmacro viewer_has_state_fields do quote do - # @desc "if user has viewed this content" - field :viewer_has_viewed, :boolean do - middleware(M.Authorize, :login) - middleware(M.PutCurrentUser) + field(:viewer_has_collected, :boolean) + field(:viewer_has_upvoted, :boolean) + field(:viewer_has_viewed, :boolean) + field(:viewer_has_reported, :boolean) + end + end - resolve(dataloader(CMS, :viewers)) - middleware(M.ViewerDidConvert) + @doc """ + query generator for threads, like: + + post, page_posts ... + """ + defmacro article_queries(thread) do + quote do + @desc unquote("get #{thread} by id") + field unquote(thread), non_null(unquote(thread)) do + arg(:id, non_null(:id)) + arg(:thread, unquote(:"#{thread}_thread"), default_value: unquote(thread)) + + resolve(&R.CMS.read_article/3) + end + + @desc unquote("get paged #{thread}s") + field unquote(:"paged_#{thread}s"), unquote(:"paged_#{thread}s") do + arg(:thread, unquote(:"#{thread}_thread"), default_value: unquote(thread)) + arg(:filter, non_null(unquote(:"paged_#{thread}s_filter"))) + + middleware(M.PageSizeProof) + resolve(&R.CMS.paged_articles/3) + end + end + end + + defmacro article_reacted_users_query(action, resolver) do + quote do + @desc unquote("get paged #{action}ed users of an article") + field unquote(:"#{action}ed_users"), :paged_users do + arg(:id, non_null(:id)) + arg(:thread, :cms_thread, default_value: :post) + arg(:filter, non_null(:paged_filter)) + + middleware(M.PageSizeProof) + resolve(unquote(resolver)) end end end diff --git a/lib/helper/types.ex b/lib/helper/types.ex index e9b06c407..1aae84773 100644 --- a/lib/helper/types.ex +++ b/lib/helper/types.ex @@ -62,7 +62,13 @@ defmodule Helper.Types do id: Integer.t(), thread: Atom.t(), title: String.t(), - upvotes_count: Integer.t() + upvotes_count: Integer.t(), + meta: %{ + upvoted_user_ids: [Integer.t()], + collected_user_ids: [Integer.t()], + viewed_user_ids: [Integer.t()], + reported_user_ids: [Integer.t()] + } } @type paged_article_common :: %{ diff --git a/priv/repo/migrations/20210507051338_remove_viewer_tables.exs b/priv/repo/migrations/20210507051338_remove_viewer_tables.exs new file mode 100644 index 000000000..0e68c8be1 --- /dev/null +++ b/priv/repo/migrations/20210507051338_remove_viewer_tables.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.RemoveViewerTables do + use Ecto.Migration + + def change do + drop(table(:posts_viewers)) + drop(table(:jobs_viewers)) + drop(table(:repos_viewers)) + end +end diff --git a/test/groupher_server/cms/article_collect_test.exs b/test/groupher_server/cms/article_collect_test.exs index 0a5810e27..338d4e779 100644 --- a/test/groupher_server/cms/article_collect_test.exs +++ b/test/groupher_server/cms/article_collect_test.exs @@ -1,4 +1,5 @@ defmodule GroupherServer.Test.ArticleCollect do + @moduledoc false use GroupherServer.TestTools alias Helper.ORM @@ -62,6 +63,40 @@ defmodule GroupherServer.Test.ArticleCollect do assert user_exist_in?(user, users.entries) assert user_exist_in?(user2, users.entries) end + + test "post meta history should be updated", ~m(user user2 community post_attrs)a do + {:ok, post} = CMS.create_content(community, :post, post_attrs, user) + {:ok, _} = CMS.collect_article(:post, post.id, user) + + {:ok, article} = ORM.find(Post, post.id) + assert user.id in article.meta.collected_user_ids + + {:ok, _} = CMS.collect_article(:post, post.id, user2) + {:ok, article} = ORM.find(Post, post.id) + + assert user.id in article.meta.collected_user_ids + assert user2.id in article.meta.collected_user_ids + end + + test "post meta history should be updated after undo collect", + ~m(user user2 community post_attrs)a do + {:ok, post} = CMS.create_content(community, :post, post_attrs, user) + {:ok, _} = CMS.collect_article(:post, post.id, user) + {:ok, _} = CMS.collect_article(:post, post.id, user2) + + {:ok, article} = ORM.find(Post, post.id) + assert user.id in article.meta.collected_user_ids + assert user2.id in article.meta.collected_user_ids + + {:ok, _} = CMS.undo_collect_article(:post, post.id, user2) + {:ok, article} = ORM.find(Post, post.id) + assert user2.id not in article.meta.collected_user_ids + + {:ok, _} = CMS.undo_collect_article(:post, post.id, user) + {:ok, article} = ORM.find(Post, post.id) + assert user.id not in article.meta.collected_user_ids + assert user2.id not in article.meta.collected_user_ids + end end describe "[cms job collect]" do @@ -110,5 +145,38 @@ defmodule GroupherServer.Test.ArticleCollect do assert user_exist_in?(user, users.entries) assert user_exist_in?(user2, users.entries) end + + test "job meta history should be updated", ~m(user user2 community job_attrs)a do + {:ok, job} = CMS.create_content(community, :job, job_attrs, user) + {:ok, _} = CMS.collect_article(:job, job.id, user) + + {:ok, article} = ORM.find(Job, job.id) + assert user.id in article.meta.collected_user_ids + + {:ok, _} = CMS.collect_article(:job, job.id, user2) + {:ok, article} = ORM.find(Job, job.id) + assert user.id in article.meta.collected_user_ids + assert user2.id in article.meta.collected_user_ids + end + + test "job meta history should be updated after undo collect", + ~m(user user2 community job_attrs)a do + {:ok, job} = CMS.create_content(community, :job, job_attrs, user) + {:ok, _} = CMS.collect_article(:job, job.id, user) + {:ok, _} = CMS.collect_article(:job, job.id, user2) + + {:ok, article} = ORM.find(Job, job.id) + assert user.id in article.meta.collected_user_ids + assert user2.id in article.meta.collected_user_ids + + {:ok, _} = CMS.undo_collect_article(:job, job.id, user2) + {:ok, article} = ORM.find(Job, job.id) + assert user2.id not in article.meta.collected_user_ids + + {:ok, _} = CMS.undo_collect_article(:job, job.id, user) + {:ok, article} = ORM.find(Job, job.id) + assert user.id not in article.meta.collected_user_ids + assert user2.id not in article.meta.collected_user_ids + end end end diff --git a/test/groupher_server/cms/article_comment_test.exs b/test/groupher_server/cms/article_comment_test.exs index 91ebbc2d8..1ac5c2eae 100644 --- a/test/groupher_server/cms/article_comment_test.exs +++ b/test/groupher_server/cms/article_comment_test.exs @@ -555,7 +555,7 @@ defmodule GroupherServer.Test.CMS.ArticleComment do assert deleted_comment.body_html == @delete_hint end - @tag :wip2 + @tag :wip test "delete comment still update article's comments_count field", ~m(user post)a do {:ok, _comment} = CMS.create_article_comment(:post, post.id, "commment", user) {:ok, _comment} = CMS.create_article_comment(:post, post.id, "commment", user) diff --git a/test/groupher_server/cms/article_upvote_test.exs b/test/groupher_server/cms/article_upvote_test.exs index cbd90b863..87afa8370 100644 --- a/test/groupher_server/cms/article_upvote_test.exs +++ b/test/groupher_server/cms/article_upvote_test.exs @@ -55,6 +55,34 @@ defmodule GroupherServer.Test.ArticleUpvote do assert user_exist_in?(user, users.entries) assert user_exist_in?(user2, users.entries) end + + test "post meta history should be updated after upvote", + ~m(user user2 community post_attrs)a do + {:ok, post} = CMS.create_content(community, :post, post_attrs, user) + {:ok, article} = CMS.upvote_article(:post, post.id, user) + assert user.id in article.meta.upvoted_user_ids + + {:ok, article} = CMS.upvote_article(:post, post.id, user2) + assert user.id in article.meta.upvoted_user_ids + assert user2.id in article.meta.upvoted_user_ids + end + + test "post meta history should be updated after undo upvote", + ~m(user user2 community post_attrs)a do + {:ok, post} = CMS.create_content(community, :post, post_attrs, user) + + {:ok, _article} = CMS.upvote_article(:post, post.id, user) + {:ok, article} = CMS.upvote_article(:post, post.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(:post, post.id, user2) + assert user2.id not in article.meta.upvoted_user_ids + + {:ok, article} = CMS.undo_upvote_article(:post, post.id, user) + assert user.id not in article.meta.upvoted_user_ids + end end describe "[cms job upvote]" do @@ -97,5 +125,32 @@ defmodule GroupherServer.Test.ArticleUpvote do assert user_exist_in?(user, users.entries) assert user_exist_in?(user2, users.entries) end + + test "job meta history should be updated", ~m(user user2 community job_attrs)a do + {:ok, job} = CMS.create_content(community, :job, job_attrs, user) + {:ok, article} = CMS.upvote_article(:job, job.id, user) + assert user.id in article.meta.upvoted_user_ids + + {:ok, article} = CMS.upvote_article(:job, job.id, user2) + assert user.id in article.meta.upvoted_user_ids + assert user2.id in article.meta.upvoted_user_ids + end + + test "job meta history should be updated after undo upvote", + ~m(user user2 community job_attrs)a do + {:ok, job} = CMS.create_content(community, :job, job_attrs, user) + + {:ok, _article} = CMS.upvote_article(:job, job.id, user) + {:ok, article} = CMS.upvote_article(:job, job.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(:job, job.id, user2) + assert user2.id not in article.meta.upvoted_user_ids + + {:ok, article} = CMS.undo_upvote_article(:job, job.id, user) + assert user.id not in article.meta.upvoted_user_ids + end end end diff --git a/test/groupher_server/cms/post_test.exs b/test/groupher_server/cms/post_test.exs index 71556f163..4f4743e80 100644 --- a/test/groupher_server/cms/post_test.exs +++ b/test/groupher_server/cms/post_test.exs @@ -6,12 +6,13 @@ defmodule GroupherServer.Test.CMS.Post do setup do {:ok, user} = db_insert(:user) - # {:ok, post} = db_insert(:post) + {:ok, user2} = db_insert(:user) + {:ok, post} = db_insert(:post) {:ok, community} = db_insert(:community) post_attrs = mock_attrs(:post, %{community_id: community.id}) - {:ok, ~m(user community post_attrs)a} + {:ok, ~m(user user2 community post post_attrs)a} end describe "[cms post curd]" do @@ -25,6 +26,28 @@ defmodule GroupherServer.Test.CMS.Post do assert post.title == post_attrs.title end + @tag :wip3 + test "read post should update views and meta viewed_user_list", + ~m(post_attrs community user user2)a do + {:ok, post} = CMS.create_content(community, :post, post_attrs, user) + {:ok, _} = CMS.read_article(:post, post.id, user) + {:ok, _created} = ORM.find(CMS.Post, post.id) + + # same user duplicate case + {:ok, _} = CMS.read_article(:post, post.id, user) + {:ok, created} = ORM.find(CMS.Post, post.id) + + assert created.meta.viewed_user_ids |> length == 1 + assert user.id in created.meta.viewed_user_ids + + {:ok, _} = CMS.read_article(:post, post.id, user2) + {:ok, created} = ORM.find(CMS.Post, post.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 "created post has origial community info", ~m(user community post_attrs)a do {:ok, post} = CMS.create_content(community, :post, post_attrs, user) {:ok, found} = ORM.find(CMS.Post, post.id, preload: :origial_community) diff --git a/test/groupher_server_web/mutation/accounts/customization_test.exs b/test/groupher_server_web/mutation/accounts/customization_test.exs index 04353cc33..de3de03cd 100644 --- a/test/groupher_server_web/mutation/accounts/customization_test.exs +++ b/test/groupher_server_web/mutation/accounts/customization_test.exs @@ -72,6 +72,7 @@ defmodule GroupherServer.Test.Mutation.Account.Customization do } } """ + @tag :wip2 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/query/cms/article_reaction_users_test.exs b/test/groupher_server_web/query/cms/article_reaction_users_test.exs index 93b26c3cf..2f5edbefb 100644 --- a/test/groupher_server_web/query/cms/article_reaction_users_test.exs +++ b/test/groupher_server_web/query/cms/article_reaction_users_test.exs @@ -36,8 +36,8 @@ defmodule GroupherServer.Test.Query.ArticleReactionUsers do } } """ - @tag :wip - test "guest can get favroted user list after upvote to a post", + @tag :wip3 + test "guest can get upvoted users list after upvote to a post", ~m(guest_conn post user user2)a do {:ok, _} = CMS.upvote_article(:post, post.id, user) {:ok, _} = CMS.upvote_article(:post, post.id, user2) @@ -52,8 +52,8 @@ defmodule GroupherServer.Test.Query.ArticleReactionUsers do assert user_exist_in?(user2, results["entries"], :string_key) end - @tag :wip - test "guest can get favroted user list after upvote to a job", + @tag :wip3 + test "guest can get upvoted users list after upvote to a job", ~m(guest_conn job user user2)a do {:ok, _} = CMS.upvote_article(:job, job.id, user) {:ok, _} = CMS.upvote_article(:job, job.id, user2) @@ -89,8 +89,9 @@ defmodule GroupherServer.Test.Query.ArticleReactionUsers do } } """ - @tag :wip - test "guest can get stared user list after collect a post", ~m(guest_conn post user user2)a do + @tag :wip3 + test "guest can get collected users list after collect a post", + ~m(guest_conn post user user2)a do {:ok, _} = CMS.collect_article(:post, post.id, user) {:ok, _} = CMS.collect_article(:post, post.id, user2) @@ -104,8 +105,9 @@ defmodule GroupherServer.Test.Query.ArticleReactionUsers do assert user_exist_in?(user2, results["entries"], :string_key) end - @tag :wip - test "guest can get stared user list after collect a job", ~m(guest_conn job user user2)a do + @tag :wip3 + test "guest can get collected users list after collect a job", + ~m(guest_conn job user user2)a do {:ok, _} = CMS.collect_article(:job, job.id, user) {:ok, _} = CMS.collect_article(:job, job.id, user2) diff --git a/test/groupher_server_web/query/cms/job_test.exs b/test/groupher_server_web/query/cms/job_test.exs index 02ed33028..417d8e867 100644 --- a/test/groupher_server_web/query/cms/job_test.exs +++ b/test/groupher_server_web/query/cms/job_test.exs @@ -19,6 +19,7 @@ defmodule GroupherServer.Test.Query.Job do } } """ + @tag :wip3 test "basic graphql query on job with logined user", ~m(user_conn job)a do variables = %{id: job.id} results = user_conn |> query_result(@query, variables, "job") @@ -29,6 +30,7 @@ defmodule GroupherServer.Test.Query.Job do assert length(Map.keys(results)) == 3 end + @tag :wip3 test "basic graphql query on job with stranger(unloged user)", ~m(guest_conn job)a do variables = %{id: job.id} results = guest_conn |> query_result(@query, variables, "job") diff --git a/test/groupher_server_web/query/cms/job_viewer_test.exs b/test/groupher_server_web/query/cms/job_viewer_test.exs deleted file mode 100644 index a04d4b373..000000000 --- a/test/groupher_server_web/query/cms/job_viewer_test.exs +++ /dev/null @@ -1,109 +0,0 @@ -defmodule GroupherServer.Test.Query.JobViewer do - use GroupherServer.TestTools - - alias Helper.ORM - alias GroupherServer.CMS - - setup do - {:ok, community} = db_insert(:community) - {:ok, user} = db_insert(:user) - {:ok, job} = CMS.create_content(community, :job, mock_attrs(:job), user) - # noise - {:ok, job2} = CMS.create_content(community, :job, mock_attrs(:job), user) - - guest_conn = simu_conn(:guest) - user_conn = simu_conn(:user) - - {:ok, ~m(user_conn guest_conn community job job2)a} - end - - @query """ - query($id: ID!) { - job(id: $id) { - views - } - } - """ - test "guest user views should +1 after query the job", ~m(guest_conn job)a do - variables = %{id: job.id} - views_1 = guest_conn |> query_result(@query, variables, "job") |> Map.get("views") - - variables = %{id: job.id} - views_2 = guest_conn |> query_result(@query, variables, "job") |> Map.get("views") - assert views_2 == views_1 + 1 - end - - test "login views should +1 after query the job", ~m(user_conn job)a do - variables = %{id: job.id} - views_1 = user_conn |> query_result(@query, variables, "job") |> Map.get("views") - - variables = %{id: job.id} - views_2 = user_conn |> query_result(@query, variables, "job") |> Map.get("views") - assert views_2 == views_1 + 1 - end - - test "login views be record only once in job viewers", ~m(job)a do - {:ok, user} = db_insert(:user) - user_conn = simu_conn(:user, user) - - assert {:error, _} = ORM.find_by(CMS.JobViewer, %{job_id: job.id, user_id: user.id}) - - variables = %{id: job.id} - user_conn |> query_result(@query, variables, "job") |> Map.get("views") - assert {:ok, viewer} = ORM.find_by(CMS.JobViewer, %{job_id: job.id, user_id: user.id}) - assert viewer.job_id == job.id - assert viewer.user_id == user.id - - variables = %{id: job.id} - user_conn |> query_result(@query, variables, "job") |> Map.get("views") - assert {:ok, _} = ORM.find_by(CMS.JobViewer, %{job_id: job.id, user_id: user.id}) - assert viewer.job_id == job.id - assert viewer.user_id == user.id - end - - @paged_query """ - query($filter: PagedJobsFilter!) { - pagedJobs(filter: $filter) { - entries { - id - views - viewerHasViewed - } - } - } - """ - - @query """ - query($id: ID!) { - job(id: $id) { - id - views - viewerHasViewed - } - } - """ - test "user get has viewed flag after query/read the job", ~m(user_conn community job)a do - variables = %{filter: %{community: community.raw}} - results = user_conn |> query_result(@paged_query, variables, "pagedJobs") - found = Enum.find(results["entries"], &(&1["id"] == to_string(job.id))) - assert found["viewerHasViewed"] == false - - variables = %{id: job.id} - result = user_conn |> query_result(@query, variables, "job") - assert result["viewerHasViewed"] == true - - # noise: test viewer dataloader - {:ok, user2} = db_insert(:user) - user_conn2 = simu_conn(:user, user2) - variables = %{filter: %{community: community.raw}} - results = user_conn2 |> query_result(@paged_query, variables, "pagedJobs") - found = Enum.find(results["entries"], &(&1["id"] == to_string(job.id))) - assert found["viewerHasViewed"] == false - - variables = %{filter: %{community: community.raw}} - results = user_conn |> query_result(@paged_query, variables, "pagedJobs") - - found = Enum.find(results["entries"], &(&1["id"] == to_string(job.id))) - assert found["viewerHasViewed"] == true - end -end diff --git a/test/groupher_server_web/query/cms/paged_jobs_test.exs b/test/groupher_server_web/query/cms/paged_jobs_test.exs index c7e3f9301..b1254dde5 100644 --- a/test/groupher_server_web/query/cms/paged_jobs_test.exs +++ b/test/groupher_server_web/query/cms/paged_jobs_test.exs @@ -1,4 +1,5 @@ defmodule GroupherServer.Test.Query.PagedJobs do + @moduledoc false use GroupherServer.TestTools import Helper.Utils, only: [get_config: 2] @@ -82,6 +83,50 @@ defmodule GroupherServer.Test.Query.PagedJobs do end end + describe "[query paged_jobs filter has_xxx]" do + @query """ + query($filter: PagedJobsFilter!) { + pagedJobs(filter: $filter) { + entries { + id + viewerHasCollected + viewerHasUpvoted + viewerHasViewed + } + totalCount + } + } + """ + @tag :wip3 + test "has_xxx state should work", ~m(user)a do + user_conn = simu_conn(:user, user) + {:ok, community} = db_insert(:community) + + {:ok, job} = CMS.create_content(community, :job, mock_attrs(:job), user) + {:ok, _job} = CMS.create_content(community, :job, mock_attrs(:job), user) + {:ok, _job3} = CMS.create_content(community, :job, mock_attrs(:job), user) + + variables = %{filter: %{community: community.raw}} + results = user_conn |> query_result(@query, variables, "pagedJobs") + assert results["totalCount"] == 3 + + the_job = Enum.find(results["entries"], &(&1["id"] == to_string(job.id))) + assert not the_job["viewerHasViewed"] + assert not the_job["viewerHasUpvoted"] + assert not the_job["viewerHasCollected"] + + {:ok, _} = CMS.read_article(:job, job.id, user) + {:ok, _} = CMS.upvote_article(:job, job.id, user) + {:ok, _} = CMS.collect_article(:job, job.id, user) + + results = user_conn |> query_result(@query, variables, "pagedJobs") + the_job = Enum.find(results["entries"], &(&1["id"] == to_string(job.id))) + assert the_job["viewerHasViewed"] + assert the_job["viewerHasUpvoted"] + assert the_job["viewerHasCollected"] + end + end + describe "[query paged_jobss filter sort]" do @query """ query($filter: PagedJobsFilter!) { diff --git a/test/groupher_server_web/query/cms/paged_posts_test.exs b/test/groupher_server_web/query/cms/paged_posts_test.exs index 448489bbb..bde4c3b74 100644 --- a/test/groupher_server_web/query/cms/paged_posts_test.exs +++ b/test/groupher_server_web/query/cms/paged_posts_test.exs @@ -1,4 +1,6 @@ defmodule GroupherServer.Test.Query.PagedPosts do + @moduledoc false + use GroupherServer.TestTools import Helper.Utils, only: [get_config: 2] @@ -154,19 +156,22 @@ defmodule GroupherServer.Test.Query.PagedPosts do end end - describe "[query paged_posts filter read]" do + describe "[query paged_posts filter has_xxx]" do @query """ query($filter: PagedPostsFilter!) { pagedPosts(filter: $filter) { entries { id + viewerHasCollected + viewerHasUpvoted viewerHasViewed } totalCount } } """ - test "read state true filter should work", ~m(user)a do + @tag :wip3 + test "has_xxx state should work", ~m(user)a do user_conn = simu_conn(:user, user) {:ok, community} = db_insert(:community) @@ -178,33 +183,20 @@ defmodule GroupherServer.Test.Query.PagedPosts do results = user_conn |> query_result(@query, variables, "pagedPosts") assert results["totalCount"] == 3 - {:ok, _} = CMS.read_content(:post, post.id, user) - - variables = %{filter: %{community: community.raw, read: "TRUE"}} - results = user_conn |> query_result(@query, variables, "pagedPosts") - - assert results["totalCount"] == 1 - end - - @tag :wip - test "read state all filter should work", ~m(user)a do - user_conn = simu_conn(:user, user) - {:ok, community} = db_insert(:community) - - {:ok, post} = CMS.create_content(community, :post, mock_attrs(:post), user) - {:ok, _post2} = CMS.create_content(community, :post, mock_attrs(:post), user) - {:ok, _post3} = CMS.create_content(community, :post, mock_attrs(:post), user) + the_post = Enum.find(results["entries"], &(&1["id"] == to_string(post.id))) + assert not the_post["viewerHasViewed"] + assert not the_post["viewerHasUpvoted"] + assert not the_post["viewerHasCollected"] - variables = %{filter: %{community: community.raw}} - results = user_conn |> query_result(@query, variables, "pagedPosts") - assert results["totalCount"] == 3 - - {:ok, _} = CMS.read_content(:post, post.id, user) + {:ok, _} = CMS.read_article(:post, post.id, user) + {:ok, _} = CMS.upvote_article(:post, post.id, user) + {:ok, _} = CMS.collect_article(:post, post.id, user) - variables = %{filter: %{community: community.raw, read: "ALL"}} results = user_conn |> query_result(@query, variables, "pagedPosts") - - assert results["totalCount"] == 3 + the_post = Enum.find(results["entries"], &(&1["id"] == to_string(post.id))) + assert the_post["viewerHasViewed"] + assert the_post["viewerHasUpvoted"] + assert the_post["viewerHasCollected"] end end diff --git a/test/groupher_server_web/query/cms/paged_repos_test.exs b/test/groupher_server_web/query/cms/paged_repos_test.exs index 075295a07..e725b7a0f 100644 --- a/test/groupher_server_web/query/cms/paged_repos_test.exs +++ b/test/groupher_server_web/query/cms/paged_repos_test.exs @@ -79,6 +79,50 @@ defmodule GroupherServer.Test.Query.PagedRepos do end end + describe "[query paged_repos filter has_xxx]" do + @query """ + query($filter: PagedReposFilter!) { + pagedRepos(filter: $filter) { + entries { + id + viewerHasCollected + viewerHasUpvoted + viewerHasViewed + } + totalCount + } + } + """ + @tag :wip3 + test "has_xxx state should work", ~m(user)a do + user_conn = simu_conn(:user, user) + {:ok, community} = db_insert(:community) + + {:ok, repo} = CMS.create_content(community, :repo, mock_attrs(:repo), user) + {:ok, _repo} = CMS.create_content(community, :repo, mock_attrs(:repo), user) + {:ok, _repo3} = CMS.create_content(community, :repo, mock_attrs(:repo), user) + + variables = %{filter: %{community: community.raw}} + results = user_conn |> query_result(@query, variables, "pagedRepos") + assert results["totalCount"] == 3 + + the_repo = Enum.find(results["entries"], &(&1["id"] == to_string(repo.id))) + assert not the_repo["viewerHasViewed"] + assert not the_repo["viewerHasUpvoted"] + assert not the_repo["viewerHasCollected"] + + {:ok, _} = CMS.read_article(:repo, repo.id, user) + {:ok, _} = CMS.upvote_article(:repo, repo.id, user) + {:ok, _} = CMS.collect_article(:repo, repo.id, user) + + results = user_conn |> query_result(@query, variables, "pagedRepos") + the_repo = Enum.find(results["entries"], &(&1["id"] == to_string(repo.id))) + assert the_repo["viewerHasViewed"] + assert the_repo["viewerHasUpvoted"] + assert the_repo["viewerHasCollected"] + end + end + describe "[query paged_repos filter sort]" do @query """ query($filter: PagedReposFilter!) { diff --git a/test/groupher_server_web/query/cms/post_test.exs b/test/groupher_server_web/query/cms/post_test.exs index 484f935f5..3c53e9c6e 100644 --- a/test/groupher_server_web/query/cms/post_test.exs +++ b/test/groupher_server_web/query/cms/post_test.exs @@ -28,6 +28,7 @@ defmodule GroupherServer.Test.Query.Post do } } """ + @tag :wip3 test "basic graphql query on post with logined user", ~m(user_conn community user post_attrs)a do {:ok, post} = CMS.create_content(community, :post, post_attrs, user) @@ -42,6 +43,7 @@ defmodule GroupherServer.Test.Query.Post do assert length(Map.keys(results)) == 4 end + @tag :wip3 test "basic graphql query on post with stranger(unloged user)", ~m(guest_conn post)a do variables = %{id: post.id} results = guest_conn |> query_result(@query, variables, "post") diff --git a/test/groupher_server_web/query/cms/post_viewer_test.exs b/test/groupher_server_web/query/cms/post_viewer_test.exs deleted file mode 100644 index 78bc8bf6a..000000000 --- a/test/groupher_server_web/query/cms/post_viewer_test.exs +++ /dev/null @@ -1,109 +0,0 @@ -defmodule GroupherServer.Test.Query.PostViewer do - use GroupherServer.TestTools - - alias Helper.ORM - alias GroupherServer.CMS - - setup do - {:ok, community} = db_insert(:community) - {:ok, user} = db_insert(:user) - {:ok, post} = CMS.create_content(community, :post, mock_attrs(:post), user) - # noise - {:ok, post2} = CMS.create_content(community, :post, mock_attrs(:post), user) - - guest_conn = simu_conn(:guest) - user_conn = simu_conn(:user) - - {:ok, ~m(user_conn guest_conn community post post2)a} - end - - @query """ - query($id: ID!) { - post(id: $id) { - views - } - } - """ - test "guest user views should +1 after query the post", ~m(guest_conn post)a do - variables = %{id: post.id} - views_1 = guest_conn |> query_result(@query, variables, "post") |> Map.get("views") - - variables = %{id: post.id} - views_2 = guest_conn |> query_result(@query, variables, "post") |> Map.get("views") - assert views_2 == views_1 + 1 - end - - test "login views should +1 after query the post", ~m(user_conn post)a do - variables = %{id: post.id} - views_1 = user_conn |> query_result(@query, variables, "post") |> Map.get("views") - - variables = %{id: post.id} - views_2 = user_conn |> query_result(@query, variables, "post") |> Map.get("views") - assert views_2 == views_1 + 1 - end - - test "login views be record only once in post viewers", ~m(post)a do - {:ok, user} = db_insert(:user) - user_conn = simu_conn(:user, user) - - assert {:error, _} = ORM.find_by(CMS.PostViewer, %{post_id: post.id, user_id: user.id}) - - variables = %{id: post.id} - user_conn |> query_result(@query, variables, "post") |> Map.get("views") - assert {:ok, viewer} = ORM.find_by(CMS.PostViewer, %{post_id: post.id, user_id: user.id}) - assert viewer.post_id == post.id - assert viewer.user_id == user.id - - variables = %{id: post.id} - user_conn |> query_result(@query, variables, "post") |> Map.get("views") - assert {:ok, _} = ORM.find_by(CMS.PostViewer, %{post_id: post.id, user_id: user.id}) - assert viewer.post_id == post.id - assert viewer.user_id == user.id - end - - @paged_query """ - query($filter: PagedPostsFilter!) { - pagedPosts(filter: $filter) { - entries { - id - views - viewerHasViewed - } - } - } - """ - - @query """ - query($id: ID!) { - post(id: $id) { - id - views - viewerHasViewed - } - } - """ - test "user get has viewed flag after query/read the post", ~m(user_conn community post)a do - variables = %{filter: %{community: community.raw}} - results = user_conn |> query_result(@paged_query, variables, "pagedPosts") - found = Enum.find(results["entries"], &(&1["id"] == to_string(post.id))) - assert found["viewerHasViewed"] == false - - variables = %{id: post.id} - result = user_conn |> query_result(@query, variables, "post") - assert result["viewerHasViewed"] == true - - # noise: test viewer dataloader - {:ok, user2} = db_insert(:user) - user_conn2 = simu_conn(:user, user2) - variables = %{filter: %{community: community.raw}} - results = user_conn2 |> query_result(@paged_query, variables, "pagedPosts") - found = Enum.find(results["entries"], &(&1["id"] == to_string(post.id))) - assert found["viewerHasViewed"] == false - - variables = %{filter: %{community: community.raw}} - results = user_conn |> query_result(@paged_query, variables, "pagedPosts") - - found = Enum.find(results["entries"], &(&1["id"] == to_string(post.id))) - assert found["viewerHasViewed"] == true - end -end diff --git a/test/groupher_server_web/query/cms/posts_flags_test.exs b/test/groupher_server_web/query/cms/posts_flags_test.exs index 15ed9be50..a63fa5d41 100644 --- a/test/groupher_server_web/query/cms/posts_flags_test.exs +++ b/test/groupher_server_web/query/cms/posts_flags_test.exs @@ -51,7 +51,7 @@ defmodule GroupherServer.Test.Query.PostsFlags do } } """ - @tag :wip + @tag :wip3 test "if have pined posts, the pined posts should at the top of entries", ~m(guest_conn community post_m)a do variables = %{filter: %{community: community.raw}} diff --git a/test/groupher_server_web/query/cms/repo_test.exs b/test/groupher_server_web/query/cms/repo_test.exs index af596f902..a4c82f63a 100644 --- a/test/groupher_server_web/query/cms/repo_test.exs +++ b/test/groupher_server_web/query/cms/repo_test.exs @@ -19,6 +19,7 @@ defmodule GroupherServer.Test.Query.Repo do } } """ + @tag :wip3 test "basic graphql query on repo with logined user", ~m(user_conn repo)a do variables = %{id: repo.id} results = user_conn |> query_result(@query, variables, "repo") @@ -29,6 +30,7 @@ defmodule GroupherServer.Test.Query.Repo do assert length(Map.keys(results)) == 3 end + @tag :wip3 test "basic graphql query on repo with stranger(unloged user)", ~m(guest_conn repo)a do variables = %{id: repo.id} results = guest_conn |> query_result(@query, variables, "repo") diff --git a/test/groupher_server_web/query/cms/repo_viewer_test.exs b/test/groupher_server_web/query/cms/repo_viewer_test.exs deleted file mode 100644 index 1718de124..000000000 --- a/test/groupher_server_web/query/cms/repo_viewer_test.exs +++ /dev/null @@ -1,109 +0,0 @@ -defmodule GroupherServer.Test.Query.RepoViewer do - use GroupherServer.TestTools - - alias Helper.ORM - alias GroupherServer.CMS - - setup do - {:ok, community} = db_insert(:community) - {:ok, user} = db_insert(:user) - {:ok, repo} = CMS.create_content(community, :repo, mock_attrs(:repo), user) - # noise - {:ok, repo2} = CMS.create_content(community, :repo, mock_attrs(:repo), user) - - guest_conn = simu_conn(:guest) - user_conn = simu_conn(:user) - - {:ok, ~m(user_conn guest_conn community repo repo2)a} - end - - @query """ - query($id: ID!) { - repo(id: $id) { - views - } - } - """ - test "guest user views should +1 after query the repo", ~m(guest_conn repo)a do - variables = %{id: repo.id} - views_1 = guest_conn |> query_result(@query, variables, "repo") |> Map.get("views") - - variables = %{id: repo.id} - views_2 = guest_conn |> query_result(@query, variables, "repo") |> Map.get("views") - assert views_2 == views_1 + 1 - end - - test "login views should +1 after query the repo", ~m(user_conn repo)a do - variables = %{id: repo.id} - views_1 = user_conn |> query_result(@query, variables, "repo") |> Map.get("views") - - variables = %{id: repo.id} - views_2 = user_conn |> query_result(@query, variables, "repo") |> Map.get("views") - assert views_2 == views_1 + 1 - end - - test "login views be record only once in repo viewers", ~m(repo)a do - {:ok, user} = db_insert(:user) - user_conn = simu_conn(:user, user) - - assert {:error, _} = ORM.find_by(CMS.RepoViewer, %{repo_id: repo.id, user_id: user.id}) - - variables = %{id: repo.id} - user_conn |> query_result(@query, variables, "repo") |> Map.get("views") - assert {:ok, viewer} = ORM.find_by(CMS.RepoViewer, %{repo_id: repo.id, user_id: user.id}) - assert viewer.repo_id == repo.id - assert viewer.user_id == user.id - - variables = %{id: repo.id} - user_conn |> query_result(@query, variables, "repo") |> Map.get("views") - assert {:ok, _} = ORM.find_by(CMS.RepoViewer, %{repo_id: repo.id, user_id: user.id}) - assert viewer.repo_id == repo.id - assert viewer.user_id == user.id - end - - @paged_query """ - query($filter: PagedReposFilter!) { - pagedRepos(filter: $filter) { - entries { - id - views - viewerHasViewed - } - } - } - """ - - @query """ - query($id: ID!) { - repo(id: $id) { - id - views - viewerHasViewed - } - } - """ - test "user get has viewed flag after query/read the repo", ~m(user_conn community repo)a do - variables = %{filter: %{community: community.raw}} - results = user_conn |> query_result(@paged_query, variables, "pagedRepos") - found = Enum.find(results["entries"], &(&1["id"] == to_string(repo.id))) - assert found["viewerHasViewed"] == false - - variables = %{id: repo.id} - result = user_conn |> query_result(@query, variables, "repo") - assert result["viewerHasViewed"] == true - - # noise: test viewer dataloader - {:ok, user2} = db_insert(:user) - user_conn2 = simu_conn(:user, user2) - variables = %{filter: %{community: community.raw}} - results = user_conn2 |> query_result(@paged_query, variables, "pagedRepos") - found = Enum.find(results["entries"], &(&1["id"] == to_string(repo.id))) - assert found["viewerHasViewed"] == false - - variables = %{filter: %{community: community.raw}} - results = user_conn |> query_result(@paged_query, variables, "pagedRepos") - - found = Enum.find(results["entries"], &(&1["id"] == to_string(repo.id))) - assert found["viewerHasViewed"] == true - end -end