From 6f181bbd64fee387e406ccef14ccb16e0243d651 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Wed, 16 Jun 2021 19:36:30 +0800 Subject: [PATCH 01/54] refactor(delivery): back up mentions and notification --- .../delivery/delegates/mentions.ex | 17 +++++++++++--- .../delivery/delegates/notifications.ex | 6 ++--- .../delivery/delegates/utils.ex | 22 +++++++++---------- .../models/{mention.ex => old_mention.ex} | 8 +++---- .../{notification.ex => old_notification.ex} | 8 +++---- ...06_rename_community_threads_to_threads.exs | 3 ++- ...945_back_old_mention_and_notifications.exs | 7 ++++++ .../groupher_server/delivery/mention_test.exs | 6 ++--- .../delivery/notification_test.exs | 6 ++--- .../query/accounts/mention_test.exs | 2 +- test/support/factory.ex | 4 ++-- 11 files changed, 54 insertions(+), 35 deletions(-) rename lib/groupher_server/delivery/models/{mention.ex => old_mention.ex} (85%) rename lib/groupher_server/delivery/models/{notification.ex => old_notification.ex} (82%) create mode 100644 priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs diff --git a/lib/groupher_server/delivery/delegates/mentions.ex b/lib/groupher_server/delivery/delegates/mentions.ex index d440ffcfd..43d8226ed 100644 --- a/lib/groupher_server/delivery/delegates/mentions.ex +++ b/lib/groupher_server/delivery/delegates/mentions.ex @@ -7,7 +7,7 @@ defmodule GroupherServer.Delivery.Delegate.Mentions do alias GroupherServer.{Accounts, Delivery, Repo} alias Accounts.Model.User - alias Delivery.Model.Mention + alias Delivery.Model.OldMention alias Delivery.Delegate.Utils # TODO: move mention logic to create contents @@ -51,12 +51,23 @@ defmodule GroupherServer.Delivery.Delegate.Mentions do acc ++ [attrs] end) - Repo.insert_all(Mention, records) + Repo.insert_all(OldMention, records) {:ok, %{done: true}} # |> done(:status) end + """ + title: + thread: + id + block_linker + comment_id + """ + + # def mention_from_article() + # deff mention_from_comment() + def mention_from_content(community, :post, content, args, %User{} = from_user) do to_user_ids = Map.get(args, :mention_users) topic = Map.get(args, :topic, "posts") @@ -133,6 +144,6 @@ defmodule GroupherServer.Delivery.Delegate.Mentions do fetch mentions from Delivery stop """ def fetch_mentions(%User{} = user, %{page: _, size: _, read: _} = filter) do - Utils.fetch_messages(user, Mention, filter) + Utils.fetch_messages(user, OldMention, filter) end end diff --git a/lib/groupher_server/delivery/delegates/notifications.ex b/lib/groupher_server/delivery/delegates/notifications.ex index a41cce7fb..20bb9aac3 100644 --- a/lib/groupher_server/delivery/delegates/notifications.ex +++ b/lib/groupher_server/delivery/delegates/notifications.ex @@ -7,7 +7,7 @@ defmodule GroupherServer.Delivery.Delegate.Notifications do alias GroupherServer.{Accounts, Delivery} alias Accounts.Model.User - alias Delivery.Model.{Notification, SysNotification} + alias Delivery.Model.{OldNotification, SysNotification} alias Delivery.Delegate.Utils alias Helper.ORM @@ -34,14 +34,14 @@ defmodule GroupherServer.Delivery.Delegate.Notifications do source_preview: info.source_preview } - Notification |> ORM.create(attrs) + OldNotification |> ORM.create(attrs) end @doc """ fetch notifications from Delivery """ def fetch_notifications(%User{} = user, %{page: _, size: _, read: _} = filter) do - Utils.fetch_messages(user, Notification, filter) + Utils.fetch_messages(user, OldNotification, filter) end def fetch_sys_notifications(%User{} = user, %{page: _, size: _} = filter) do diff --git a/lib/groupher_server/delivery/delegates/utils.ex b/lib/groupher_server/delivery/delegates/utils.ex index cf8982f5a..cd9d38575 100644 --- a/lib/groupher_server/delivery/delegates/utils.ex +++ b/lib/groupher_server/delivery/delegates/utils.ex @@ -10,14 +10,14 @@ defmodule GroupherServer.Delivery.Delegate.Utils do alias GroupherServer.{Accounts, Delivery, Repo} alias Accounts.Model.User - alias Delivery.Model.{Notification, SysNotification, Mention, Record} + alias Delivery.Model.{OldNotification, SysNotification, OldMention, Record} alias Helper.ORM def mailbox_status(%User{} = user) do filter = %{page: 1, size: 1, read: false} - {:ok, mention_mail} = fetch_mails(user, Mention, filter) - {:ok, notification_mail} = fetch_mails(user, Notification, filter) + {:ok, mention_mail} = fetch_mails(user, OldMention, filter) + {:ok, notification_mail} = fetch_mails(user, OldNotification, filter) mention_count = mention_mail.total_count notification_count = notification_mail.total_count @@ -31,8 +31,8 @@ defmodule GroupherServer.Delivery.Delegate.Utils do def fetch_record(%User{id: user_id}), do: Record |> ORM.find_by(user_id: user_id) - def mark_read_all(%User{} = user, :mention), do: Mention |> do_mark_read_all(user) - def mark_read_all(%User{} = user, :notification), do: Notification |> do_mark_read_all(user) + def mark_read_all(%User{} = user, :mention), do: OldMention |> do_mark_read_all(user) + def mark_read_all(%User{} = user, :notification), do: OldNotification |> do_mark_read_all(user) @doc """ fetch mentions / notifications @@ -89,15 +89,15 @@ defmodule GroupherServer.Delivery.Delegate.Utils do mails end - defp record_operation(Mention, _read, {:ok, %{entries: []}}), do: {:ok, ""} - defp record_operation(Notification, _read, {:ok, %{entries: []}}), do: {:ok, ""} + defp record_operation(OldMention, _read, {:ok, %{entries: []}}), do: {:ok, ""} + defp record_operation(OldNotification, _read, {:ok, %{entries: []}}), do: {:ok, ""} defp record_operation(_, SysNotification, {:ok, %{entries: []}}), do: {:ok, ""} - defp record_operation(Mention, read, {:ok, %{entries: entries}}) do + defp record_operation(OldMention, read, {:ok, %{entries: entries}}) do do_record_operation(:mentions_record, read, {:ok, %{entries: entries}}) end - defp record_operation(Notification, read, {:ok, %{entries: entries}}) do + defp record_operation(OldNotification, read, {:ok, %{entries: entries}}) do do_record_operation(:notifications_record, read, {:ok, %{entries: entries}}) end @@ -145,12 +145,12 @@ defmodule GroupherServer.Delivery.Delegate.Utils do Record |> ORM.upsert_by([user_id: user_id], attrs) end - defp get_last_fetch_time(Mention, read, user) do + defp get_last_fetch_time(OldMention, read, user) do timekey = get_record_lasttime_key(read) do_get_last_fetch_time(:mentions_record, user, timekey) end - defp get_last_fetch_time(Notification, read, user) do + defp get_last_fetch_time(OldNotification, read, user) do timekey = get_record_lasttime_key(read) do_get_last_fetch_time(:notifications_record, user, timekey) end diff --git a/lib/groupher_server/delivery/models/mention.ex b/lib/groupher_server/delivery/models/old_mention.ex similarity index 85% rename from lib/groupher_server/delivery/models/mention.ex rename to lib/groupher_server/delivery/models/old_mention.ex index 076c1f7ca..c3716fd2e 100644 --- a/lib/groupher_server/delivery/models/mention.ex +++ b/lib/groupher_server/delivery/models/old_mention.ex @@ -1,4 +1,4 @@ -defmodule GroupherServer.Delivery.Model.Mention do +defmodule GroupherServer.Delivery.Model.OldMention do @moduledoc false alias __MODULE__ @@ -10,8 +10,8 @@ defmodule GroupherServer.Delivery.Model.Mention do @required_fields ~w(from_user_id to_user_id source_title source_id source_type source_preview)a @optional_fields ~w(parent_id parent_type read floor community)a - @type t :: %Mention{} - schema "mentions" do + @type t :: %OldMention{} + schema "old_mentions" do belongs_to(:from_user, User) belongs_to(:to_user, User) field(:source_id, :string) @@ -28,7 +28,7 @@ defmodule GroupherServer.Delivery.Model.Mention do end @doc false - def changeset(%Mention{} = mention, attrs) do + def changeset(%OldMention{} = mention, attrs) do mention |> cast(attrs, @optional_fields ++ @required_fields) |> validate_required(@required_fields) diff --git a/lib/groupher_server/delivery/models/notification.ex b/lib/groupher_server/delivery/models/old_notification.ex similarity index 82% rename from lib/groupher_server/delivery/models/notification.ex rename to lib/groupher_server/delivery/models/old_notification.ex index 146c0ce92..a01f8467d 100644 --- a/lib/groupher_server/delivery/models/notification.ex +++ b/lib/groupher_server/delivery/models/old_notification.ex @@ -1,4 +1,4 @@ -defmodule GroupherServer.Delivery.Model.Notification do +defmodule GroupherServer.Delivery.Model.OldNotification do @moduledoc false alias __MODULE__ @@ -10,8 +10,8 @@ defmodule GroupherServer.Delivery.Model.Notification do @required_fields ~w(from_user_id to_user_id action source_title source_id source_preview source_type)a @optional_fields ~w(parent_id parent_type read)a - @type t :: %Notification{} - schema "notifications" do + @type t :: %OldNotification{} + schema "old_notifications" do belongs_to(:from_user, User) belongs_to(:to_user, User) field(:action, :string) @@ -28,7 +28,7 @@ defmodule GroupherServer.Delivery.Model.Notification do end @doc false - def changeset(%Notification{} = notification, attrs) do + def changeset(%OldNotification{} = notification, attrs) do notification |> cast(attrs, @optional_fields ++ @required_fields) |> validate_required(@required_fields) diff --git a/priv/repo/migrations/20180417085106_rename_community_threads_to_threads.exs b/priv/repo/migrations/20180417085106_rename_community_threads_to_threads.exs index d076c7e13..aaf962b8b 100644 --- a/priv/repo/migrations/20180417085106_rename_community_threads_to_threads.exs +++ b/priv/repo/migrations/20180417085106_rename_community_threads_to_threads.exs @@ -2,6 +2,7 @@ defmodule GroupherServer.Repo.Migrations.RenameCommunityThreadsToThreads do use Ecto.Migration def change do - rename(table("community_threads"), to: table("threads")) + rename(table("mentions"), to: table("old_mentions_old")) + rename(table("notifications"), to: table("old_notifications")) end end diff --git a/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs b/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs new file mode 100644 index 000000000..77c37f2af --- /dev/null +++ b/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs @@ -0,0 +1,7 @@ +defmodule GroupherServer.Repo.Migrations.BackOldMentionAndNotifications do + use Ecto.Migration + + def change do + + end +end diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index f45ca0544..419c940c7 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.Delivery.Mention do +defmodule GroupherServer.Test.Delivery.OldMention do use GroupherServer.TestTools import Ecto.Query, warn: false @@ -8,7 +8,7 @@ defmodule GroupherServer.Test.Delivery.Mention do alias GroupherServer.{Accounts, Delivery} alias Accounts.Model.MentionMail - alias Delivery.Model.Mention + alias Delivery.Model.OldMention describe "mentions" do test "user can mention other user" do @@ -65,7 +65,7 @@ defmodule GroupherServer.Test.Delivery.Mention do {:ok, _mentions} = Accounts.fetch_mentions(user, filter) {:ok, mentions} = - Mention + OldMention |> where([m], m.to_user_id == ^user.id) |> ORM.paginater(page: 1, size: 10) |> done() diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index 9b3b7d633..eae70bf7d 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.Delivery.Notification do +defmodule GroupherServer.Test.Delivery.OldNotification do use GroupherServer.TestTools import Ecto.Query, warn: false @@ -8,7 +8,7 @@ defmodule GroupherServer.Test.Delivery.Notification do alias GroupherServer.{Accounts, Delivery} alias Accounts.Model.NotificationMail - alias Delivery.Model.Notification + alias Delivery.Model.OldNotification describe "[delivery notification]" do test "user can notify other user" do @@ -64,7 +64,7 @@ defmodule GroupherServer.Test.Delivery.Notification do {:ok, _mentions} = Accounts.fetch_notifications(user, filter) {:ok, notifications} = - Notification + OldNotification |> where([m], m.to_user_id == ^user.id) |> ORM.paginater(page: 1, size: 10) |> done() diff --git a/test/groupher_server_web/query/accounts/mention_test.exs b/test/groupher_server_web/query/accounts/mention_test.exs index ae15cf14a..a05538020 100644 --- a/test/groupher_server_web/query/accounts/mention_test.exs +++ b/test/groupher_server_web/query/accounts/mention_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.Query.Accounts.Mention do +defmodule GroupherServer.Test.Query.Accounts.OldMention do use GroupherServer.TestTools # alias GroupherServer.Accounts diff --git a/test/support/factory.ex b/test/support/factory.ex index 15f8e04e5..93bac7d70 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -23,7 +23,7 @@ defmodule GroupherServer.Support.Factory do Comment } - alias Delivery.Model.{Mention, SysNotification} + alias Delivery.Model.{OldMention, SysNotification} @default_article_meta CMS.Model.Embeds.ArticleMeta.default_meta() @default_emotions CMS.Model.Embeds.CommentEmotion.default_emotions() @@ -383,7 +383,7 @@ defmodule GroupherServer.Support.Factory do 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)) - defp mock(:mention), do: Mention |> struct(mock_meta(:mention)) + defp mock(:mention), do: OldMention |> struct(mock_meta(:mention)) defp mock(:author), do: Author |> struct(mock_meta(:author)) defp mock(:category), do: Category |> struct(mock_meta(:category)) defp mock(:article_tag), do: ArticleTag |> struct(mock_meta(:article_tag)) From 52166a76c29a385fd94bef4841026abda0d5ce53 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Wed, 16 Jun 2021 19:38:56 +0800 Subject: [PATCH 02/54] refactor(delivery): back up mentions and notification --- .../20180417085106_rename_community_threads_to_threads.exs | 3 +-- .../20210616112945_back_old_mention_and_notifications.exs | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/priv/repo/migrations/20180417085106_rename_community_threads_to_threads.exs b/priv/repo/migrations/20180417085106_rename_community_threads_to_threads.exs index aaf962b8b..d076c7e13 100644 --- a/priv/repo/migrations/20180417085106_rename_community_threads_to_threads.exs +++ b/priv/repo/migrations/20180417085106_rename_community_threads_to_threads.exs @@ -2,7 +2,6 @@ defmodule GroupherServer.Repo.Migrations.RenameCommunityThreadsToThreads do use Ecto.Migration def change do - rename(table("mentions"), to: table("old_mentions_old")) - rename(table("notifications"), to: table("old_notifications")) + rename(table("community_threads"), to: table("threads")) end end diff --git a/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs b/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs index 77c37f2af..62d71c101 100644 --- a/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs +++ b/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs @@ -2,6 +2,7 @@ defmodule GroupherServer.Repo.Migrations.BackOldMentionAndNotifications do use Ecto.Migration def change do - + rename(table("mentions"), to: table("old_mentions_old")) + rename(table("notifications"), to: table("old_notifications")) end end From 49ab9da648f4882468ab610cc3bd93a205186201 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Wed, 16 Jun 2021 19:59:22 +0800 Subject: [PATCH 03/54] refactor(delivery): back up mentions and notification wip --- .../20210616112945_back_old_mention_and_notifications.exs | 2 +- test/groupher_server/cms/cite_contents/cite_post_test.exs | 1 - test/groupher_server_web/mutation/cms/articles/post_test.exs | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs b/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs index 62d71c101..016df13cf 100644 --- a/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs +++ b/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs @@ -2,7 +2,7 @@ defmodule GroupherServer.Repo.Migrations.BackOldMentionAndNotifications do use Ecto.Migration def change do - rename(table("mentions"), to: table("old_mentions_old")) + rename(table("mentions"), to: table("old_mentions")) rename(table("notifications"), to: table("old_notifications")) end end diff --git a/test/groupher_server/cms/cite_contents/cite_post_test.exs b/test/groupher_server/cms/cite_contents/cite_post_test.exs index fcecab7b1..d040be32f 100644 --- a/test/groupher_server/cms/cite_contents/cite_post_test.exs +++ b/test/groupher_server/cms/cite_contents/cite_post_test.exs @@ -220,7 +220,6 @@ defmodule GroupherServer.Test.CMS.CiteContent.Post do end describe "[cross cite]" do - @tag :wip test "can citing multi type thread and comment in one time", ~m(user community post2)a do post_attrs = mock_attrs(:post, %{community_id: community.id}) job_attrs = mock_attrs(:job, %{community_id: community.id}) diff --git a/test/groupher_server_web/mutation/cms/articles/post_test.exs b/test/groupher_server_web/mutation/cms/articles/post_test.exs index b2a35349b..22d7362a9 100644 --- a/test/groupher_server_web/mutation/cms/articles/post_test.exs +++ b/test/groupher_server_web/mutation/cms/articles/post_test.exs @@ -104,6 +104,7 @@ defmodule GroupherServer.Test.Mutation.Articles.Post do assert user_conn |> mutation_get_error?(@create_post_query, variables) end + @tag :wip test "can create post with mentionUsers" do {:ok, user} = db_insert(:user) {:ok, user2} = db_insert(:user) From 149f07d6edcfe4d171c508601067ad620de5428c Mon Sep 17 00:00:00 2001 From: mydearxym Date: Thu, 17 Jun 2021 14:31:50 +0800 Subject: [PATCH 04/54] refactor(delivery): wip --- .../cms/delegates/cite_tasks.ex | 7 +- .../delivery/delegates/mention.ex | 111 ++++++++++++ .../delivery/delegates/utils.ex | 15 +- lib/groupher_server/delivery/delivery.ex | 5 +- .../delivery/models/mention.ex | 37 ++++ ...945_back_old_mention_and_notifications.exs | 3 + .../20210617014552_create_new_mention.exs | 25 +++ .../cms/cite_contents/cite_post_test.exs | 2 +- .../groupher_server/delivery/mention_test.exs | 162 +++++------------- .../delivery/old_mention_test.exs | 133 ++++++++++++++ .../mutation/cms/articles/post_test.exs | 1 - 11 files changed, 369 insertions(+), 132 deletions(-) create mode 100644 lib/groupher_server/delivery/delegates/mention.ex create mode 100644 lib/groupher_server/delivery/models/mention.ex create mode 100644 priv/repo/migrations/20210617014552_create_new_mention.exs create mode 100644 test/groupher_server/delivery/old_mention_test.exs diff --git a/lib/groupher_server/cms/delegates/cite_tasks.ex b/lib/groupher_server/cms/delegates/cite_tasks.ex index f4dc99eb1..77ec7da44 100644 --- a/lib/groupher_server/cms/delegates/cite_tasks.ex +++ b/lib/groupher_server/cms/delegates/cite_tasks.ex @@ -70,7 +70,12 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do defp delete_all_cited_contents(article) do with {:ok, thread} <- thread_of_article(article), {:ok, info} <- match(thread) do - query = from(c in CitedContent, where: field(c, ^info.foreign_key) == ^article.id) + thread = thread |> to_string |> String.upcase() + + query = + from(c in CitedContent, + where: field(c, ^info.foreign_key) == ^article.id and c.cited_by_type == ^thread + ) ORM.delete_all(query, :if_exist) end diff --git a/lib/groupher_server/delivery/delegates/mention.ex b/lib/groupher_server/delivery/delegates/mention.ex new file mode 100644 index 000000000..5aa90811d --- /dev/null +++ b/lib/groupher_server/delivery/delegates/mention.ex @@ -0,0 +1,111 @@ +defmodule GroupherServer.Delivery.Delegate.Mention do + @moduledoc """ + The Delivery context. + """ + import Ecto.Query, warn: false + import Helper.Utils, only: [done: 1, thread_of_article: 1] + import GroupherServer.CMS.Helper.Matcher + import ShortMaps + + alias GroupherServer.{Accounts, CMS, Delivery, Repo} + + alias Accounts.Model.User + alias CMS.Model.Comment + alias Delivery.Model.{OldMention, Mention} + + alias Delivery.Delegate.Utils + alias Helper.ORM + + alias Ecto.Multi + + """ + %{ + type: "POST", # "COMMENT", + title: "article title", + id: 23, + block_linker: ["die"], + comment_id: 22, + read: false + } + """ + + def batch_mention(%Comment{} = comment, contents, %User{} = user, %User{} = to_user) do + Multi.new() + |> Multi.run(:batch_delete_related_mentions, fn _, _ -> + delete_related_mentions(comment, user) + end) + |> Multi.run(:batch_insert_related_mentions, fn _, _ -> + case {0, nil} !== Repo.insert_all(Mention, contents) do + true -> {:ok, :pass} + false -> {:error, "insert mentions error"} + end + end) + |> Repo.transaction() + |> result() + + # 1. + # delete_all Mention |> where from_user_id == user.id and comment_id == comment.id + # 2. + # insert_all shaped contents + end + + def batch_send(article, contents, %User{} = user, %User{} = to_user) do + Multi.new() + |> Multi.run(:batch_delete_related_mentions, fn _, _ -> + delete_related_mentions(article, user) + end) + |> Multi.run(:batch_insert_related_mentions, fn _, _ -> + case {0, nil} !== Repo.insert_all(Mention, contents) do + true -> {:ok, :pass} + false -> {:error, "insert mentions error"} + end + end) + |> Repo.transaction() + |> result() + end + + defp result({:ok, %{batch_insert_related_mentions: result}}), do: {:ok, result} + + defp result({:error, _, result, _steps}) do + {:error, result} + end + + defp delete_related_mentions(%Comment{} = comment, %User{} = user) do + from(m in Mention, + where: m.comment_id == ^comment.id, + where: m.from_user_id == ^user.id + ) + |> ORM.delete_all(:if_exist) + end + + defp delete_related_mentions(article, %User{} = user) do + with {:ok, thread} <- thread_of_article(article), + {:ok, info} <- match(thread) do + thread = thread |> to_string |> String.upcase() + + from(m in Mention, + where: m.article_id == ^article.id, + where: m.type == ^thread, + where: m.from_user_id == ^user.id + ) + |> ORM.delete_all(:if_exist) + end + end + + def paged_mentions(%User{} = user, %{page: page, size: size} = filter) do + read = Map.get(filter, :read, false) + + Mention + |> where([m], m.to_user_id == ^user.id) + |> where([m], m.read == ^read) + |> ORM.paginater(~m(page size)a) + |> done() + end + + @doc """ + fetch mentions from Delivery stop + """ + def fetch_mentions(%User{} = user, %{page: _, size: _, read: _} = filter) do + Utils.fetch_messages(user, OldMention, filter) + end +end diff --git a/lib/groupher_server/delivery/delegates/utils.ex b/lib/groupher_server/delivery/delegates/utils.ex index cd9d38575..c3eeb2d11 100644 --- a/lib/groupher_server/delivery/delegates/utils.ex +++ b/lib/groupher_server/delivery/delegates/utils.ex @@ -78,11 +78,7 @@ defmodule GroupherServer.Delivery.Delegate.Utils do |> where([m], m.inserted_at > ^last_fetch_time) |> where([m], m.read == ^read) - mails = - query - |> order_by(desc: :inserted_at) - |> ORM.paginater(~m(page size)a) - |> done() + mails = query |> order_by(desc: :inserted_at) |> ORM.paginater(~m(page size)a) |> done() delete_items(query, mails) @@ -211,15 +207,10 @@ defmodule GroupherServer.Delivery.Delegate.Utils do end defp do_mark_read_all(queryable, %User{} = user) do - query = - queryable - |> where([m], m.to_user_id == ^user.id) + query = queryable |> where([m], m.to_user_id == ^user.id) try do - Repo.update_all( - query, - set: [read: true] - ) + Repo.update_all(query, set: [read: true]) {:ok, %{status: true}} rescue diff --git a/lib/groupher_server/delivery/delivery.ex b/lib/groupher_server/delivery/delivery.ex index d7debea5a..5abbd2ab9 100644 --- a/lib/groupher_server/delivery/delivery.ex +++ b/lib/groupher_server/delivery/delivery.ex @@ -4,10 +4,13 @@ defmodule GroupherServer.Delivery do """ alias GroupherServer.Delivery - alias Delivery.Delegate.{Mentions, Notifications, Utils} + alias Delivery.Delegate.{Mention, Mentions, Notifications, Utils} defdelegate mailbox_status(user), to: Utils + defdelegate batch_mention(content, contents, from_user, to_user), to: Mention + defdelegate paged_mentions(user, filter), to: Mention + # system_notifications defdelegate publish_system_notification(info), to: Notifications defdelegate fetch_sys_notifications(user, filter), to: Notifications diff --git a/lib/groupher_server/delivery/models/mention.ex b/lib/groupher_server/delivery/models/mention.ex new file mode 100644 index 000000000..22e98b33a --- /dev/null +++ b/lib/groupher_server/delivery/models/mention.ex @@ -0,0 +1,37 @@ +defmodule GroupherServer.Delivery.Model.Mention do + @moduledoc false + alias __MODULE__ + + use Ecto.Schema + import Ecto.Changeset + + alias GroupherServer.Accounts.Model.User + + @required_fields ~w(from_user_id to_user_id title article_id type)a + @optional_fields ~w(comment_id read)a + + @type t :: %Mention{} + schema "mentions" do + field(:type, :string) + field(:article_id, :id) + field(:title, :string) + field(:comment_id, :id) + field(:read, :boolean) + + field(:block_linker, {:array, :string}) + + belongs_to(:from_user, User) + belongs_to(:to_user, User) + + timestamps(type: :utc_datetime) + end + + @doc false + def changeset(%Mention{} = mention, attrs) do + mention + |> cast(attrs, @optional_fields ++ @required_fields) + |> validate_required(@required_fields) + |> foreign_key_constraint(:from_user_id) + |> foreign_key_constraint(:to_user_id) + end +end diff --git a/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs b/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs index 016df13cf..e3b3d2b4b 100644 --- a/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs +++ b/priv/repo/migrations/20210616112945_back_old_mention_and_notifications.exs @@ -2,6 +2,9 @@ defmodule GroupherServer.Repo.Migrations.BackOldMentionAndNotifications do use Ecto.Migration def change do + drop(index(:mentions, [:from_user_id])) + drop(index(:mentions, [:to_user_id])) + rename(table("mentions"), to: table("old_mentions")) rename(table("notifications"), to: table("old_notifications")) end diff --git a/priv/repo/migrations/20210617014552_create_new_mention.exs b/priv/repo/migrations/20210617014552_create_new_mention.exs new file mode 100644 index 000000000..7b0d86e74 --- /dev/null +++ b/priv/repo/migrations/20210617014552_create_new_mention.exs @@ -0,0 +1,25 @@ +defmodule GroupherServer.Repo.Migrations.CreateNewMention do + use Ecto.Migration + + def change do + create table(:mentions) do + # article or comment + add(:type, :string) + add(:article_id, :id) + add(:title, :string) + # optional comment id + add(:comment_id, :id) + add(:from_user_id, references(:users, on_delete: :nothing), null: false) + add(:to_user_id, references(:users, on_delete: :nothing), null: false) + + add(:block_linker, {:array, :string}) + + add(:read, :boolean, default: false) + + timestamps() + end + + create(index(:mentions, [:from_user_id])) + create(index(:mentions, [:to_user_id])) + end +end diff --git a/test/groupher_server/cms/cite_contents/cite_post_test.exs b/test/groupher_server/cms/cite_contents/cite_post_test.exs index d040be32f..af0b2fe2b 100644 --- a/test/groupher_server/cms/cite_contents/cite_post_test.exs +++ b/test/groupher_server/cms/cite_contents/cite_post_test.exs @@ -254,7 +254,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Post do {:ok, result} = CMS.paged_citing_contents("POST", post2.id, %{page: 1, size: 10}) # IO.inspect(result, label: "the result") - result.total_count == 4 + assert result.total_count == 4 result_post = result.entries |> List.first() result_job = result.entries |> Enum.at(1) diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index 419c940c7..69a09baa5 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.Delivery.OldMention do +defmodule GroupherServer.Test.Delivery.Mention do use GroupherServer.TestTools import Ecto.Query, warn: false @@ -8,126 +8,56 @@ defmodule GroupherServer.Test.Delivery.OldMention do alias GroupherServer.{Accounts, Delivery} alias Accounts.Model.MentionMail - alias Delivery.Model.OldMention + alias Delivery.Model.Mention - describe "mentions" do - test "user can mention other user" do - {:ok, [user, user2]} = db_insert_multi(:user, 2) - - mock_mentions_for(user, 1) - mock_mentions_for(user2, 1) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Delivery.fetch_mentions(user, filter) - - assert mentions |> is_valid_pagination?(:raw) - assert mentions |> Map.get(:total_count) == 1 - assert mentions.entries |> List.first() |> Map.get(:to_user_id) == user.id - assert mentions.entries |> List.first() |> Map.get(:community) == "elixir" - end - - test "user can fetch mentions and store in own mention mail-box" do - {:ok, user} = db_insert(:user) - - mock_mentions_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) - - {:ok, mention_mails} = - MentionMail - |> where([m], m.to_user_id == ^user.id) - |> where([m], m.read == false) - |> ORM.paginater(page: 1, size: 10) - |> done() - - mention_ids = - mentions.entries - |> Enum.reduce([], fn m, acc -> - acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) - end) - - mention_mail_ids = - mention_mails.entries - |> Enum.reduce([], fn m, acc -> - acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) - end) - - assert Enum.sort(mention_ids) == Enum.sort(mention_mail_ids) - end - - test "delete related delivery mentions after user fetch" do - {:ok, user} = db_insert(:user) - - mock_mentions_for(user, 1) - - filter = %{page: 1, size: 20, read: false} - {:ok, _mentions} = Accounts.fetch_mentions(user, filter) - - {:ok, mentions} = - OldMention - |> where([m], m.to_user_id == ^user.id) - |> ORM.paginater(page: 1, size: 10) - |> done() - - assert Enum.empty?(mentions.entries) - end + setup do + {:ok, post} = db_insert(:post) + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, community} = db_insert(:community) - test "store user fetch info in delivery records, with last_fetch_unread_time info" do - {:ok, user} = db_insert(:user) + guest_conn = simu_conn(:guest) + user_conn = simu_conn(:user) + owner_conn = simu_conn(:owner, post) - mock_mentions_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) - {:ok, record} = Delivery.fetch_record(user) - - latest_insert_time = mentions.entries |> List.first() |> Map.get(:inserted_at) |> to_string - - record_last_fetch_unresd_time = - record |> Map.get(:mentions_record) |> Map.get("last_fetch_unread_time") - - assert latest_insert_time == record_last_fetch_unresd_time - end - - test "user can mark one mention as read" do - {:ok, user} = db_insert(:user) - - mock_mentions_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) - first_mention = mentions.entries |> List.first() - assert mentions.total_count == 3 - Accounts.mark_mail_read(first_mention, user) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) - assert mentions.total_count == 2 - - filter = %{page: 1, size: 20, read: true} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) - assert mentions.total_count == 1 - end - - test "user can mark all unread mentions as read" do - {:ok, user} = db_insert(:user) - - mock_mentions_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, _mentions} = Accounts.fetch_mentions(user, filter) - Accounts.mark_mail_read_all(user, :mention) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) - - assert Enum.empty?(mentions.entries) + {:ok, ~m(community post user user2)a} + end - filter = %{page: 1, size: 20, read: true} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) + # attrs = %{ + # # should also be article's thread + # type: "COMMENT", + # title: content.title, + # article_id: content.article_id, + # comment_id: content.comment_id, + # read: false, + # block_linker: content.block_linker, + # from_user_id: user.id, + # to_user_id: to_user.id + # } - assert mentions.total_count == 3 + describe "mentions" do + @tag :wip + test "can batch send mentions", ~m(post user user2)a do + contents = [ + %{ + type: "POST", + title: post.title, + article_id: post.id, + comment_id: nil, + read: false, + block_linker: ["tmp"], + from_user_id: user.id, + to_user_id: user2.id, + inserted_at: post.updated_at |> DateTime.truncate(:second), + updated_at: post.updated_at |> DateTime.truncate(:second) + } + ] + + {:ok, :pass} = Delivery.batch_mention(post, contents, user, user2) + + hello = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + + IO.inspect(hello, label: "hello --> ") end end end diff --git a/test/groupher_server/delivery/old_mention_test.exs b/test/groupher_server/delivery/old_mention_test.exs new file mode 100644 index 000000000..419c940c7 --- /dev/null +++ b/test/groupher_server/delivery/old_mention_test.exs @@ -0,0 +1,133 @@ +defmodule GroupherServer.Test.Delivery.OldMention do + use GroupherServer.TestTools + + import Ecto.Query, warn: false + import Helper.Utils + + alias Helper.ORM + alias GroupherServer.{Accounts, Delivery} + + alias Accounts.Model.MentionMail + alias Delivery.Model.OldMention + + describe "mentions" do + test "user can mention other user" do + {:ok, [user, user2]} = db_insert_multi(:user, 2) + + mock_mentions_for(user, 1) + mock_mentions_for(user2, 1) + + filter = %{page: 1, size: 20, read: false} + {:ok, mentions} = Delivery.fetch_mentions(user, filter) + + assert mentions |> is_valid_pagination?(:raw) + assert mentions |> Map.get(:total_count) == 1 + assert mentions.entries |> List.first() |> Map.get(:to_user_id) == user.id + assert mentions.entries |> List.first() |> Map.get(:community) == "elixir" + end + + test "user can fetch mentions and store in own mention mail-box" do + {:ok, user} = db_insert(:user) + + mock_mentions_for(user, 3) + + filter = %{page: 1, size: 20, read: false} + {:ok, mentions} = Accounts.fetch_mentions(user, filter) + + {:ok, mention_mails} = + MentionMail + |> where([m], m.to_user_id == ^user.id) + |> where([m], m.read == false) + |> ORM.paginater(page: 1, size: 10) + |> done() + + mention_ids = + mentions.entries + |> Enum.reduce([], fn m, acc -> + acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) + end) + + mention_mail_ids = + mention_mails.entries + |> Enum.reduce([], fn m, acc -> + acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) + end) + + assert Enum.sort(mention_ids) == Enum.sort(mention_mail_ids) + end + + test "delete related delivery mentions after user fetch" do + {:ok, user} = db_insert(:user) + + mock_mentions_for(user, 1) + + filter = %{page: 1, size: 20, read: false} + {:ok, _mentions} = Accounts.fetch_mentions(user, filter) + + {:ok, mentions} = + OldMention + |> where([m], m.to_user_id == ^user.id) + |> ORM.paginater(page: 1, size: 10) + |> done() + + assert Enum.empty?(mentions.entries) + end + + test "store user fetch info in delivery records, with last_fetch_unread_time info" do + {:ok, user} = db_insert(:user) + + mock_mentions_for(user, 3) + + filter = %{page: 1, size: 20, read: false} + {:ok, mentions} = Accounts.fetch_mentions(user, filter) + {:ok, record} = Delivery.fetch_record(user) + + latest_insert_time = mentions.entries |> List.first() |> Map.get(:inserted_at) |> to_string + + record_last_fetch_unresd_time = + record |> Map.get(:mentions_record) |> Map.get("last_fetch_unread_time") + + assert latest_insert_time == record_last_fetch_unresd_time + end + + test "user can mark one mention as read" do + {:ok, user} = db_insert(:user) + + mock_mentions_for(user, 3) + + filter = %{page: 1, size: 20, read: false} + {:ok, mentions} = Accounts.fetch_mentions(user, filter) + first_mention = mentions.entries |> List.first() + assert mentions.total_count == 3 + Accounts.mark_mail_read(first_mention, user) + + filter = %{page: 1, size: 20, read: false} + {:ok, mentions} = Accounts.fetch_mentions(user, filter) + assert mentions.total_count == 2 + + filter = %{page: 1, size: 20, read: true} + {:ok, mentions} = Accounts.fetch_mentions(user, filter) + assert mentions.total_count == 1 + end + + test "user can mark all unread mentions as read" do + {:ok, user} = db_insert(:user) + + mock_mentions_for(user, 3) + + filter = %{page: 1, size: 20, read: false} + {:ok, _mentions} = Accounts.fetch_mentions(user, filter) + Accounts.mark_mail_read_all(user, :mention) + + filter = %{page: 1, size: 20, read: false} + {:ok, mentions} = Accounts.fetch_mentions(user, filter) + + assert Enum.empty?(mentions.entries) + + filter = %{page: 1, size: 20, read: true} + {:ok, mentions} = Accounts.fetch_mentions(user, filter) + + assert mentions.total_count == 3 + end + end +end diff --git a/test/groupher_server_web/mutation/cms/articles/post_test.exs b/test/groupher_server_web/mutation/cms/articles/post_test.exs index 22d7362a9..b2a35349b 100644 --- a/test/groupher_server_web/mutation/cms/articles/post_test.exs +++ b/test/groupher_server_web/mutation/cms/articles/post_test.exs @@ -104,7 +104,6 @@ defmodule GroupherServer.Test.Mutation.Articles.Post do assert user_conn |> mutation_get_error?(@create_post_query, variables) end - @tag :wip test "can create post with mentionUsers" do {:ok, user} = db_insert(:user) {:ok, user2} = db_insert(:user) From f94774e2f1f90b8b6d2fbfda1ca749aa8b5c32a9 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Thu, 17 Jun 2021 14:34:13 +0800 Subject: [PATCH 05/54] refactor(delivery): wip --- lib/groupher_server/delivery/delegates/mention.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/groupher_server/delivery/delegates/mention.ex b/lib/groupher_server/delivery/delegates/mention.ex index 5aa90811d..9db6f86a9 100644 --- a/lib/groupher_server/delivery/delegates/mention.ex +++ b/lib/groupher_server/delivery/delegates/mention.ex @@ -49,7 +49,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do # insert_all shaped contents end - def batch_send(article, contents, %User{} = user, %User{} = to_user) do + def batch_mention(article, contents, %User{} = user, %User{} = to_user) do Multi.new() |> Multi.run(:batch_delete_related_mentions, fn _, _ -> delete_related_mentions(article, user) From e16d5d07ab9e27f834a5caeb0008084e883ee38b Mon Sep 17 00:00:00 2001 From: mydearxym Date: Thu, 17 Jun 2021 15:02:17 +0800 Subject: [PATCH 06/54] refactor(delivery): wip --- .../cms/delegates/cite_tasks.ex | 16 +++---- .../cms/delegates/cited_content.ex | 10 ++--- .../delivery/delegates/mention.ex | 45 ++++++++++++------- .../groupher_server/delivery/mention_test.exs | 10 ++++- 4 files changed, 50 insertions(+), 31 deletions(-) diff --git a/lib/groupher_server/cms/delegates/cite_tasks.ex b/lib/groupher_server/cms/delegates/cite_tasks.ex index 77ec7da44..2cb2112db 100644 --- a/lib/groupher_server/cms/delegates/cite_tasks.ex +++ b/lib/groupher_server/cms/delegates/cite_tasks.ex @@ -40,7 +40,7 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do def handle(%{body: body} = content) do with {:ok, %{"blocks" => blocks}} <- Jason.decode(body), - content <- preload_content_author(content) do + content <- preload_author(content) do Multi.new() |> Multi.run(:delete_all_cited_contents, fn _, _ -> delete_all_cited_contents(content) @@ -56,8 +56,8 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do end end - def preload_content_author(%Comment{} = comment), do: comment - def preload_content_author(article), do: Repo.preload(article, author: :user) + def preload_author(%Comment{} = comment), do: comment + def preload_author(article), do: Repo.preload(article, author: :user) # delete all records before insert_all, this will dynamiclly update # those cited info when update article @@ -176,7 +176,7 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do defp do_parse_cited_info_per_block(content, block_id, links) do Enum.reduce(links, [], fn link, acc -> case parse_valid_cited(content.id, link) do - {:ok, cited} -> List.insert_at(acc, 0, shape_cited(content, cited, block_id)) + {:ok, cited} -> List.insert_at(acc, 0, shape(content, cited, block_id)) _ -> acc end end) @@ -265,7 +265,7 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do # cite article in comment # 在评论中引用文章 - defp shape_cited(%Comment{} = comment, %{type: :article, content: cited}, block_id) do + defp shape(%Comment{} = comment, %{type: :article, content: cited}, block_id) do %{ cited_by_id: cited.id, cited_by_type: cited.meta.thread, @@ -282,7 +282,7 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do # cite comment in comment # 评论中引用评论 - defp shape_cited(%Comment{} = comment, %{type: :comment, content: cited}, block_id) do + defp shape(%Comment{} = comment, %{type: :comment, content: cited}, block_id) do %{ cited_by_id: cited.id, cited_by_type: "COMMENT", @@ -299,7 +299,7 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do # cite article in article # 文章之间相互引用 - defp shape_cited(article, %{type: :article, content: cited}, block_id) do + defp shape(article, %{type: :article, content: cited}, block_id) do {:ok, thread} = thread_of_article(article) {:ok, info} = match(thread) @@ -319,7 +319,7 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do # cite comment in article # 文章中引用评论 - defp shape_cited(article, %{type: :comment, content: cited}, block_id) do + defp shape(article, %{type: :comment, content: cited}, block_id) do {:ok, thread} = thread_of_article(article) {:ok, info} = match(thread) diff --git a/lib/groupher_server/cms/delegates/cited_content.ex b/lib/groupher_server/cms/delegates/cited_content.ex index d669a718f..ccf81959a 100644 --- a/lib/groupher_server/cms/delegates/cited_content.ex +++ b/lib/groupher_server/cms/delegates/cited_content.ex @@ -33,14 +33,14 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do end def extract_contents(%{entries: entries} = paged_contents) do - entries = entries |> Repo.preload(@cited_preloads) |> Enum.map(&shape_article(&1)) + entries = entries |> Repo.preload(@cited_preloads) |> Enum.map(&shape(&1)) Map.put(paged_contents, :entries, entries) end # shape comment cite - @spec shape_article(CitedContent.t()) :: T.cite_info() - defp shape_article(%CitedContent{comment_id: comment_id} = cited) when not is_nil(comment_id) do + @spec shape(CitedContent.t()) :: T.cite_info() + defp shape(%CitedContent{comment_id: comment_id} = cited) when not is_nil(comment_id) do %{block_linker: block_linker, comment: comment, inserted_at: inserted_at} = cited comment_thread = comment.thread |> String.downcase() |> String.to_atom() @@ -60,7 +60,7 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do end # shape general article cite - defp shape_article(%CitedContent{} = cited) do + defp shape(%CitedContent{} = cited) do %{block_linker: block_linker, inserted_at: inserted_at} = cited thread = citing_thread(cited) @@ -79,7 +79,7 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do end # find thread_id that not empty - # only used for shape_article + # only used for shape defp citing_thread(cited) do @article_threads |> Enum.find(fn thread -> not is_nil(Map.get(cited, :"#{thread}_id")) end) end diff --git a/lib/groupher_server/delivery/delegates/mention.ex b/lib/groupher_server/delivery/delegates/mention.ex index 9db6f86a9..cdaaf9e4a 100644 --- a/lib/groupher_server/delivery/delegates/mention.ex +++ b/lib/groupher_server/delivery/delegates/mention.ex @@ -42,11 +42,6 @@ defmodule GroupherServer.Delivery.Delegate.Mention do end) |> Repo.transaction() |> result() - - # 1. - # delete_all Mention |> where from_user_id == user.id and comment_id == comment.id - # 2. - # insert_all shaped contents end def batch_mention(article, contents, %User{} = user, %User{} = to_user) do @@ -64,12 +59,6 @@ defmodule GroupherServer.Delivery.Delegate.Mention do |> result() end - defp result({:ok, %{batch_insert_related_mentions: result}}), do: {:ok, result} - - defp result({:error, _, result, _steps}) do - {:error, result} - end - defp delete_related_mentions(%Comment{} = comment, %User{} = user) do from(m in Mention, where: m.comment_id == ^comment.id, @@ -99,13 +88,37 @@ defmodule GroupherServer.Delivery.Delegate.Mention do |> where([m], m.to_user_id == ^user.id) |> where([m], m.read == ^read) |> ORM.paginater(~m(page size)a) + |> extract_contents |> done() end - @doc """ - fetch mentions from Delivery stop - """ - def fetch_mentions(%User{} = user, %{page: _, size: _, read: _} = filter) do - Utils.fetch_messages(user, OldMention, filter) + def extract_contents(%{entries: entries} = paged_contents) do + entries = entries |> Repo.preload(:from_user) |> Enum.map(&shape(&1)) + + Map.put(paged_contents, :entries, entries) + end + + # who in what part, mentioned me? + defp shape(%Mention{} = mention) do + user = Map.take(mention.from_user, [:login, :nickname, :avatar]) + + mention + |> Map.take([ + :type, + :article_id, + :comment_id, + :title, + :block_linker, + :inserted_at, + :updated_at, + :read + ]) + |> Map.put(:user, user) + end + + defp result({:ok, %{batch_insert_related_mentions: result}}), do: {:ok, result} + + defp result({:error, _, result, _steps}) do + {:error, result} end end diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index 69a09baa5..418ec8f17 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -55,9 +55,15 @@ defmodule GroupherServer.Test.Delivery.Mention do {:ok, :pass} = Delivery.batch_mention(post, contents, user, user2) - hello = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) - IO.inspect(hello, label: "hello --> ") + mention = result.entries |> List.first() + + assert mention.title == post.title + assert mention.article_id == post.id + assert mention.user.login == user.login + + IO.inspect(result, label: "hello --> ") end end end From 6db40a3661319223e11b41628592207562212243 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Thu, 17 Jun 2021 15:27:17 +0800 Subject: [PATCH 07/54] refactor(delivery): wip --- .../groupher_server/delivery/mention_test.exs | 94 ++++++++++++------- 1 file changed, 60 insertions(+), 34 deletions(-) diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index 418ec8f17..4ccf79ab2 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -2,43 +2,74 @@ defmodule GroupherServer.Test.Delivery.Mention do use GroupherServer.TestTools import Ecto.Query, warn: false - import Helper.Utils + # import Helper.Utils - alias Helper.ORM - alias GroupherServer.{Accounts, Delivery} - - alias Accounts.Model.MentionMail - alias Delivery.Model.Mention + alias GroupherServer.Delivery setup do {:ok, post} = db_insert(:post) {:ok, user} = db_insert(:user) {:ok, user2} = db_insert(:user) + {:ok, user3} = db_insert(:user) {:ok, community} = db_insert(:community) - guest_conn = simu_conn(:guest) - user_conn = simu_conn(:user) - owner_conn = simu_conn(:owner, post) + mention_contents = [ + %{ + type: "POST", + title: post.title, + article_id: post.id, + comment_id: nil, + read: false, + block_linker: ["tmp"], + from_user_id: user.id, + to_user_id: user2.id, + inserted_at: post.updated_at |> DateTime.truncate(:second), + updated_at: post.updated_at |> DateTime.truncate(:second) + } + ] - {:ok, ~m(community post user user2)a} + {:ok, ~m(community post user user2 user3 mention_contents)a} end - # attrs = %{ - # # should also be article's thread - # type: "COMMENT", - # title: content.title, - # article_id: content.article_id, - # comment_id: content.comment_id, - # read: false, - # block_linker: content.block_linker, - # from_user_id: user.id, - # to_user_id: to_user.id - # } - describe "mentions" do @tag :wip - test "can batch send mentions", ~m(post user user2)a do - contents = [ + test "can batch send mentions", ~m(post user user2 mention_contents)a do + {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user, user2) + {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + + mention = result.entries |> List.first() + + assert mention.title == post.title + assert mention.article_id == post.id + assert mention.user.login == user.login + end + + @tag :wip + test "mention multiable times on same article, will only have one record", + ~m(post user user2 mention_contents)a do + {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user, user2) + {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + + assert result.total_count == 1 + + {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user, user2) + {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + + assert result.total_count == 1 + end + + @tag :wip + test "if mention before, update with no mention content will not do mention in final", + ~m(post user user2 user3 mention_contents)a do + {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user, user2) + {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + + assert result.total_count == 1 + + {:ok, result} = Delivery.paged_mentions(user3, %{page: 1, size: 10}) + assert result.total_count == 0 + + mention_contents = [ %{ type: "POST", title: post.title, @@ -47,23 +78,18 @@ defmodule GroupherServer.Test.Delivery.Mention do read: false, block_linker: ["tmp"], from_user_id: user.id, - to_user_id: user2.id, + to_user_id: user3.id, inserted_at: post.updated_at |> DateTime.truncate(:second), updated_at: post.updated_at |> DateTime.truncate(:second) } ] - {:ok, :pass} = Delivery.batch_mention(post, contents, user, user2) - + {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user, user2) {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + assert result.total_count == 0 - mention = result.entries |> List.first() - - assert mention.title == post.title - assert mention.article_id == post.id - assert mention.user.login == user.login - - IO.inspect(result, label: "hello --> ") + {:ok, result} = Delivery.paged_mentions(user3, %{page: 1, size: 10}) + assert result.total_count == 1 end end end From 9b6d0d679c88ff9fddabcbe18a3fc9d85cc253b8 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Thu, 17 Jun 2021 21:56:42 +0800 Subject: [PATCH 08/54] refactor(delivery): wip --- .../cms/delegates/article_curd.ex | 16 ++- .../delegates/{cite_tasks.ex => cite_task.ex} | 6 +- .../cms/delegates/comment_curd.ex | 2 +- .../cms/delegates/mention_task.ex | 118 ++++++++++++++++++ .../delivery/delegates/mention.ex | 18 +-- lib/groupher_server/delivery/delivery.ex | 2 +- .../cite_blog_test.exs | 26 ++-- .../cite_job_test.exs | 26 ++-- .../cite_post_test.exs | 34 ++--- .../cms/mention_tasks/post_mention_test.exs | 48 +++++++ .../groupher_server/delivery/mention_test.exs | 10 +- .../query/cms/citings/blog_citing_test.exs | 8 +- .../query/cms/citings/job_citing_test.exs | 8 +- .../query/cms/citings/post_citing_test.exs | 8 +- 14 files changed, 254 insertions(+), 76 deletions(-) rename lib/groupher_server/cms/delegates/{cite_tasks.ex => cite_task.ex} (98%) create mode 100644 lib/groupher_server/cms/delegates/mention_task.ex rename test/groupher_server/cms/{cite_contents => cite_tasks}/cite_blog_test.exs (94%) rename test/groupher_server/cms/{cite_contents => cite_tasks}/cite_job_test.exs (94%) rename test/groupher_server/cms/{cite_contents => cite_tasks}/cite_post_test.exs (94%) create mode 100644 test/groupher_server/cms/mention_tasks/post_mention_test.exs diff --git a/lib/groupher_server/cms/delegates/article_curd.ex b/lib/groupher_server/cms/delegates/article_curd.ex index 4c4da0ee3..1c8613314 100644 --- a/lib/groupher_server/cms/delegates/article_curd.ex +++ b/lib/groupher_server/cms/delegates/article_curd.ex @@ -18,7 +18,15 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do alias Accounts.Model.User alias CMS.Model.{Author, Community, PinnedArticle, Embeds} - alias CMS.Delegate.{ArticleCommunity, CommentCurd, ArticleTag, CommunityCURD, CiteTasks} + + alias CMS.Delegate.{ + ArticleCommunity, + CommentCurd, + ArticleTag, + CommunityCURD, + CiteTask, + MentionTask + } alias Ecto.Multi @@ -165,7 +173,8 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do Accounts.update_published_states(uid, thread) end) |> Multi.run(:after_tasks, fn _, %{create_article: article} -> - Later.run({CiteTasks, :handle, [article]}) + Later.run({CiteTask, :handle, [article]}) + Later.run({MentionTask, :handle, [article]}) Later.run({__MODULE__, :notify_admin_new_article, [article]}) end) |> Multi.run(:mention_users, fn _, %{create_article: article} -> @@ -224,7 +233,8 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do ArticleCommunity.update_edit_status(update_article) end) |> Multi.run(:after_tasks, fn _, %{update_article: update_article} -> - Later.run({CiteTasks, :handle, [update_article]}) + Later.run({CiteTask, :handle, [update_article]}) + Later.run({MentionTask, :handle, [update_article]}) end) |> Repo.transaction() |> result() diff --git a/lib/groupher_server/cms/delegates/cite_tasks.ex b/lib/groupher_server/cms/delegates/cite_task.ex similarity index 98% rename from lib/groupher_server/cms/delegates/cite_tasks.ex rename to lib/groupher_server/cms/delegates/cite_task.ex index 2cb2112db..d9de2a1d9 100644 --- a/lib/groupher_server/cms/delegates/cite_tasks.ex +++ b/lib/groupher_server/cms/delegates/cite_task.ex @@ -1,4 +1,4 @@ -defmodule GroupherServer.CMS.Delegate.CiteTasks do +defmodule GroupherServer.CMS.Delegate.CiteTask do @moduledoc """ run tasks in every article blocks if need @@ -48,7 +48,7 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do |> Multi.run(:update_cited_info, fn _, _ -> blocks |> Enum.reduce([], &(&2 ++ parse_cited_info_per_block(content, &1))) - |> merge_same_cited_article_block + |> merge_same_block_linker |> update_cited_info end) |> Repo.transaction() @@ -132,7 +132,7 @@ defmodule GroupherServer.CMS.Delegate.CiteTasks do }, ] """ - defp merge_same_cited_article_block(cited_contents) do + defp merge_same_block_linker(cited_contents) do cited_contents |> Enum.reduce([], fn content, acc -> case Enum.find_index(acc, &(&1.cited_by_id == content.cited_by_id)) do diff --git a/lib/groupher_server/cms/delegates/comment_curd.ex b/lib/groupher_server/cms/delegates/comment_curd.ex index 80b0fb18e..a3ab85b90 100644 --- a/lib/groupher_server/cms/delegates/comment_curd.ex +++ b/lib/groupher_server/cms/delegates/comment_curd.ex @@ -114,7 +114,7 @@ defmodule GroupherServer.CMS.Delegate.CommentCurd do end end) |> Multi.run(:block_tasks, fn _, %{create_comment: create_comment} -> - Later.run({CiteTasks, :handle, [create_comment]}) + Later.run({CiteTask, :handle, [create_comment]}) end) |> Repo.transaction() |> result() diff --git a/lib/groupher_server/cms/delegates/mention_task.ex b/lib/groupher_server/cms/delegates/mention_task.ex new file mode 100644 index 000000000..37eeb76eb --- /dev/null +++ b/lib/groupher_server/cms/delegates/mention_task.ex @@ -0,0 +1,118 @@ +defmodule GroupherServer.CMS.Delegate.MentionTask do + @moduledoc """ + run tasks in every article blocks if need + + current task: "cite link" and "mention" + + ## cite link + + 我被站内哪些文章或评论引用了,是值得关注的事 + 我引用了谁不重要,帖子里链接已经表明了, 这和 github issue 的双向链接不一样,因为一般不需要关注这个 + 帖子是否解决,是否被 merge 等状态。 + + 基本结构: + + cited_thread, cited_article_id, [xxx_article]_id, [block_id, block2_id], + + POST post_333 -> cited_article_333, [block_id, block2_id]] + + cited_type, cited_content_id, [contents]_id, [block_id, cited_block_id], + + cited_type: thread or comment + content: article or comment + # cited_article_comment_id, [xxx_article]_id, [block_id, block2_id, ...], + """ + + import Ecto.Query, warn: false + import Helper.Utils, only: [get_config: 2, thread_of_article: 1, done: 1] + import GroupherServer.CMS.Helper.Matcher + import Helper.ErrorCode + + alias GroupherServer.{Accounts, CMS, Repo} + alias CMS.Model.{CitedContent, Comment} + alias Helper.ORM + + alias Ecto.Multi + + @site_host get_config(:general, :site_host) + @article_threads get_config(:article, :threads) + + @article_mention_class "cdx-mention" + + def handle(%{body: body} = content) do + with {:ok, %{"blocks" => blocks}} <- Jason.decode(body), + content <- preload_author(content) do + blocks + |> Enum.reduce([], &(&2 ++ parse_cited_info_per_block(content, &1))) + |> merge_same_block_linker(:to_user_id) + |> IO.inspect(label: "blocks") + end + end + + def preload_author(%Comment{} = comment), do: comment + def preload_author(article), do: Repo.preload(article, author: :user) + + defp parse_cited_info_per_block(content, %{"id" => block_id, "data" => %{"text" => text}}) do + mentions = Floki.find(text, ".#{@article_mention_class}") + + do_parse_cited_info_per_block(content, block_id, mentions) + end + + # links Floki parsed fmt + # content means both article and comment + # e.g: + # [{"a", [{"href", "https://coderplanets.com/post/195675"}], []},] + defp do_parse_cited_info_per_block(content, block_id, mentions) do + Enum.reduce(mentions, [], fn mention, acc -> + case parse_mention_user_id(mention) do + {:ok, user_id} -> List.insert_at(acc, 0, shape(content, user_id, block_id)) + {:error, _} -> acc + end + end) + |> Enum.uniq() + end + + # 确保 mention 的用户是存在的 + defp parse_mention_user_id({_, _, [user_login]}) do + Accounts.get_userid_and_cache(user_login) + end + + defp shape(%Comment{} = comment, mention_user_id, block_id) do + # @article_threads |> Enum.find(fn thread -> not is_nil(Map.get(comment, :"#{thread}_id")) end) + %{ + block_linker: [block_id], + read: false, + from_user_id: comment.author_id, + to_user_id: mention_user_id + } + end + + defp shape(article, to_user_id, block_id) do + %{ + type: article.meta.thread, + title: article.title, + article_id: article.id, + block_linker: [block_id], + read: false, + from_user_id: article.author.user_id, + to_user_id: to_user_id + } + end + + defp merge_same_block_linker(contents, group_key) do + contents + |> Enum.reduce([], fn content, acc -> + case Enum.find_index(acc, &(Map.get(&1, group_key) == Map.get(content, group_key))) do + nil -> + acc ++ [content] + + index -> + List.update_at( + acc, + index, + &Map.put(&1, :block_linker, &1.block_linker ++ content.block_linker) + ) + end + end) + end +end diff --git a/lib/groupher_server/delivery/delegates/mention.ex b/lib/groupher_server/delivery/delegates/mention.ex index cdaaf9e4a..304517d56 100644 --- a/lib/groupher_server/delivery/delegates/mention.ex +++ b/lib/groupher_server/delivery/delegates/mention.ex @@ -26,13 +26,15 @@ defmodule GroupherServer.Delivery.Delegate.Mention do block_linker: ["die"], comment_id: 22, read: false + from_user_id: ... + to_user_id: ... } """ - def batch_mention(%Comment{} = comment, contents, %User{} = user, %User{} = to_user) do + def batch_mention(%Comment{} = comment, contents, %User{} = from_user) do Multi.new() |> Multi.run(:batch_delete_related_mentions, fn _, _ -> - delete_related_mentions(comment, user) + delete_related_mentions(comment, from_user) end) |> Multi.run(:batch_insert_related_mentions, fn _, _ -> case {0, nil} !== Repo.insert_all(Mention, contents) do @@ -44,10 +46,10 @@ defmodule GroupherServer.Delivery.Delegate.Mention do |> result() end - def batch_mention(article, contents, %User{} = user, %User{} = to_user) do + def batch_mention(article, contents, %User{} = from_user) do Multi.new() |> Multi.run(:batch_delete_related_mentions, fn _, _ -> - delete_related_mentions(article, user) + delete_related_mentions(article, from_user) end) |> Multi.run(:batch_insert_related_mentions, fn _, _ -> case {0, nil} !== Repo.insert_all(Mention, contents) do @@ -59,15 +61,15 @@ defmodule GroupherServer.Delivery.Delegate.Mention do |> result() end - defp delete_related_mentions(%Comment{} = comment, %User{} = user) do + defp delete_related_mentions(%Comment{} = comment, %User{} = from_user) do from(m in Mention, where: m.comment_id == ^comment.id, - where: m.from_user_id == ^user.id + where: m.from_user_id == ^from_user.id ) |> ORM.delete_all(:if_exist) end - defp delete_related_mentions(article, %User{} = user) do + defp delete_related_mentions(article, %User{} = from_user) do with {:ok, thread} <- thread_of_article(article), {:ok, info} <- match(thread) do thread = thread |> to_string |> String.upcase() @@ -75,7 +77,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do from(m in Mention, where: m.article_id == ^article.id, where: m.type == ^thread, - where: m.from_user_id == ^user.id + where: m.from_user_id == ^from_user.id ) |> ORM.delete_all(:if_exist) end diff --git a/lib/groupher_server/delivery/delivery.ex b/lib/groupher_server/delivery/delivery.ex index 5abbd2ab9..d3cd32a92 100644 --- a/lib/groupher_server/delivery/delivery.ex +++ b/lib/groupher_server/delivery/delivery.ex @@ -8,7 +8,7 @@ defmodule GroupherServer.Delivery do defdelegate mailbox_status(user), to: Utils - defdelegate batch_mention(content, contents, from_user, to_user), to: Mention + defdelegate batch_mention(content, contents, from_user), to: Mention defdelegate paged_mentions(user, filter), to: Mention # system_notifications diff --git a/test/groupher_server/cms/cite_contents/cite_blog_test.exs b/test/groupher_server/cms/cite_tasks/cite_blog_test.exs similarity index 94% rename from test/groupher_server/cms/cite_contents/cite_blog_test.exs rename to test/groupher_server/cms/cite_tasks/cite_blog_test.exs index 27ae3da51..6d34f18b6 100644 --- a/test/groupher_server/cms/cite_contents/cite_blog_test.exs +++ b/test/groupher_server/cms/cite_tasks/cite_blog_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.CMS.CiteContent.Blog do +defmodule GroupherServer.Test.CMS.CiteTask.Blog do use GroupherServer.TestTools import Helper.Utils, only: [get_config: 2] @@ -7,7 +7,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Blog do alias GroupherServer.CMS alias CMS.Model.{Blog, Comment, CitedContent} - alias CMS.Delegate.CiteTasks + alias CMS.Delegate.CiteTask @site_host get_config(:general, :site_host) @@ -47,8 +47,8 @@ defmodule GroupherServer.Test.CMS.CiteContent.Blog do blog_attrs = blog_attrs |> Map.merge(%{body: body}) {:ok, blog_n} = CMS.create_article(community, :blog, blog_attrs, user) - CiteTasks.handle(blog) - CiteTasks.handle(blog_n) + CiteTask.handle(blog) + CiteTask.handle(blog_n) {:ok, blog2} = ORM.find(Blog, blog2.id) {:ok, blog3} = ORM.find(Blog, blog3.id) @@ -67,7 +67,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Blog do body = mock_rich_text(~s(the )) {:ok, blog} = CMS.update_article(blog, %{body: body}) - CiteTasks.handle(blog) + CiteTask.handle(blog) {:ok, blog} = ORM.find(Blog, blog.id) assert blog.meta.citing_count == 0 @@ -84,7 +84,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Blog do ) ) - CiteTasks.handle(comment) + CiteTask.handle(comment) {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 0 @@ -99,7 +99,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Blog do blog_attrs = blog_attrs |> Map.merge(%{body: body}) {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) - CiteTasks.handle(blog) + CiteTask.handle(blog) {:ok, comment} = ORM.find(Comment, comment.id) assert comment.meta.citing_count == 1 @@ -119,7 +119,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Blog do {:ok, comment} = CMS.create_comment(:blog, blog.id, comment_body, user) - CiteTasks.handle(comment) + CiteTask.handle(comment) {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 1 @@ -143,12 +143,12 @@ defmodule GroupherServer.Test.CMS.CiteContent.Blog do ) {:ok, comment} = CMS.create_comment(:blog, blog.id, comment_body, user) - CiteTasks.handle(comment) + CiteTask.handle(comment) comment_body = mock_rich_text(~s(the )) {:ok, comment} = CMS.create_comment(:blog, blog.id, comment_body, user) - CiteTasks.handle(comment) + CiteTask.handle(comment) {:ok, blog2} = ORM.find(Blog, blog2.id) {:ok, blog3} = ORM.find(Blog, blog3.id) @@ -188,9 +188,9 @@ defmodule GroupherServer.Test.CMS.CiteContent.Blog do blog_attrs = blog_attrs |> Map.merge(%{body: body}) {:ok, blog_y} = CMS.create_article(community, :blog, blog_attrs, user) - CiteTasks.handle(blog_x) - CiteTasks.handle(comment) - CiteTasks.handle(blog_y) + CiteTask.handle(blog_x) + CiteTask.handle(comment) + CiteTask.handle(blog_y) {:ok, result} = CMS.paged_citing_contents("BLOG", blog2.id, %{page: 1, size: 10}) diff --git a/test/groupher_server/cms/cite_contents/cite_job_test.exs b/test/groupher_server/cms/cite_tasks/cite_job_test.exs similarity index 94% rename from test/groupher_server/cms/cite_contents/cite_job_test.exs rename to test/groupher_server/cms/cite_tasks/cite_job_test.exs index 6710f2ba8..8d509389f 100644 --- a/test/groupher_server/cms/cite_contents/cite_job_test.exs +++ b/test/groupher_server/cms/cite_tasks/cite_job_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.CMS.CiteContent.Job do +defmodule GroupherServer.Test.CMS.CiteTask.Job do use GroupherServer.TestTools import Helper.Utils, only: [get_config: 2] @@ -7,7 +7,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Job do alias GroupherServer.CMS alias CMS.Model.{Job, Comment, CitedContent} - alias CMS.Delegate.CiteTasks + alias CMS.Delegate.CiteTask @site_host get_config(:general, :site_host) @@ -47,8 +47,8 @@ defmodule GroupherServer.Test.CMS.CiteContent.Job do job_attrs = job_attrs |> Map.merge(%{body: body}) {:ok, job_n} = CMS.create_article(community, :job, job_attrs, user) - CiteTasks.handle(job) - CiteTasks.handle(job_n) + CiteTask.handle(job) + CiteTask.handle(job_n) {:ok, job2} = ORM.find(Job, job2.id) {:ok, job3} = ORM.find(Job, job3.id) @@ -67,7 +67,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Job do body = mock_rich_text(~s(the )) {:ok, job} = CMS.update_article(job, %{body: body}) - CiteTasks.handle(job) + CiteTask.handle(job) {:ok, job} = ORM.find(Job, job.id) assert job.meta.citing_count == 0 @@ -84,7 +84,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Job do ) ) - CiteTasks.handle(comment) + CiteTask.handle(comment) {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 0 @@ -99,7 +99,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Job do job_attrs = job_attrs |> Map.merge(%{body: body}) {:ok, job} = CMS.create_article(community, :job, job_attrs, user) - CiteTasks.handle(job) + CiteTask.handle(job) {:ok, comment} = ORM.find(Comment, comment.id) assert comment.meta.citing_count == 1 @@ -119,7 +119,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Job do {:ok, comment} = CMS.create_comment(:job, job.id, comment_body, user) - CiteTasks.handle(comment) + CiteTask.handle(comment) {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 1 @@ -143,12 +143,12 @@ defmodule GroupherServer.Test.CMS.CiteContent.Job do ) {:ok, comment} = CMS.create_comment(:job, job.id, comment_body, user) - CiteTasks.handle(comment) + CiteTask.handle(comment) comment_body = mock_rich_text(~s(the )) {:ok, comment} = CMS.create_comment(:job, job.id, comment_body, user) - CiteTasks.handle(comment) + CiteTask.handle(comment) {:ok, job2} = ORM.find(Job, job2.id) {:ok, job3} = ORM.find(Job, job3.id) @@ -187,9 +187,9 @@ defmodule GroupherServer.Test.CMS.CiteContent.Job do job_attrs = job_attrs |> Map.merge(%{body: body}) {:ok, job_y} = CMS.create_article(community, :job, job_attrs, user) - CiteTasks.handle(job_x) - CiteTasks.handle(comment) - CiteTasks.handle(job_y) + CiteTask.handle(job_x) + CiteTask.handle(comment) + CiteTask.handle(job_y) {:ok, result} = CMS.paged_citing_contents("JOB", job2.id, %{page: 1, size: 10}) diff --git a/test/groupher_server/cms/cite_contents/cite_post_test.exs b/test/groupher_server/cms/cite_tasks/cite_post_test.exs similarity index 94% rename from test/groupher_server/cms/cite_contents/cite_post_test.exs rename to test/groupher_server/cms/cite_tasks/cite_post_test.exs index af0b2fe2b..5d45159b4 100644 --- a/test/groupher_server/cms/cite_contents/cite_post_test.exs +++ b/test/groupher_server/cms/cite_tasks/cite_post_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.CMS.CiteContent.Post do +defmodule GroupherServer.Test.CMS.CiteTask.Post do use GroupherServer.TestTools import Helper.Utils, only: [get_config: 2] @@ -7,7 +7,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Post do alias GroupherServer.CMS alias CMS.Model.{Post, Comment, CitedContent} - alias CMS.Delegate.CiteTasks + alias CMS.Delegate.CiteTask @site_host get_config(:general, :site_host) @@ -47,8 +47,8 @@ defmodule GroupherServer.Test.CMS.CiteContent.Post do post_attrs = post_attrs |> Map.merge(%{body: body}) {:ok, post_n} = CMS.create_article(community, :post, post_attrs, user) - CiteTasks.handle(post) - CiteTasks.handle(post_n) + CiteTask.handle(post) + CiteTask.handle(post_n) {:ok, post2} = ORM.find(Post, post2.id) {:ok, post3} = ORM.find(Post, post3.id) @@ -67,7 +67,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Post do body = mock_rich_text(~s(the )) {:ok, post} = CMS.update_article(post, %{body: body}) - CiteTasks.handle(post) + CiteTask.handle(post) {:ok, post} = ORM.find(Post, post.id) assert post.meta.citing_count == 0 @@ -84,7 +84,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Post do ) ) - CiteTasks.handle(comment) + CiteTask.handle(comment) {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 0 @@ -99,7 +99,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Post do post_attrs = post_attrs |> Map.merge(%{body: body}) {:ok, post} = CMS.create_article(community, :post, post_attrs, user) - CiteTasks.handle(post) + CiteTask.handle(post) {:ok, comment} = ORM.find(Comment, comment.id) assert comment.meta.citing_count == 1 @@ -119,7 +119,7 @@ defmodule GroupherServer.Test.CMS.CiteContent.Post do {:ok, comment} = CMS.create_comment(:post, post.id, comment_body, user) - CiteTasks.handle(comment) + CiteTask.handle(comment) {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 1 @@ -143,12 +143,12 @@ defmodule GroupherServer.Test.CMS.CiteContent.Post do ) {:ok, comment} = CMS.create_comment(:post, post.id, comment_body, user) - CiteTasks.handle(comment) + CiteTask.handle(comment) comment_body = mock_rich_text(~s(the )) {:ok, comment} = CMS.create_comment(:post, post.id, comment_body, user) - CiteTasks.handle(comment) + CiteTask.handle(comment) {:ok, post2} = ORM.find(Post, post2.id) {:ok, post3} = ORM.find(Post, post3.id) @@ -188,9 +188,9 @@ defmodule GroupherServer.Test.CMS.CiteContent.Post do post_attrs = post_attrs |> Map.merge(%{body: body}) {:ok, post_y} = CMS.create_article(community, :post, post_attrs, user) - CiteTasks.handle(post_x) - CiteTasks.handle(comment) - CiteTasks.handle(post_y) + CiteTask.handle(post_x) + CiteTask.handle(comment) + CiteTask.handle(post_y) {:ok, result} = CMS.paged_citing_contents("POST", post2.id, %{page: 1, size: 10}) @@ -230,26 +230,26 @@ defmodule GroupherServer.Test.CMS.CiteContent.Post do {:ok, post} = CMS.create_article(community, :post, Map.merge(post_attrs, %{body: body}), user) - CiteTasks.handle(post) + CiteTask.handle(post) Process.sleep(1000) {:ok, job} = CMS.create_article(community, :job, Map.merge(job_attrs, %{body: body}), user) - CiteTasks.handle(job) + CiteTask.handle(job) Process.sleep(1000) comment_body = mock_comment(~s(the )) {:ok, comment} = CMS.create_comment(:job, job.id, comment_body, user) - CiteTasks.handle(comment) + CiteTask.handle(comment) Process.sleep(1000) {:ok, blog} = CMS.create_article(community, :blog, Map.merge(blog_attrs, %{body: body}), user) - CiteTasks.handle(blog) + CiteTask.handle(blog) {:ok, result} = CMS.paged_citing_contents("POST", post2.id, %{page: 1, size: 10}) # IO.inspect(result, label: "the result") diff --git a/test/groupher_server/cms/mention_tasks/post_mention_test.exs b/test/groupher_server/cms/mention_tasks/post_mention_test.exs new file mode 100644 index 000000000..5b37f91b4 --- /dev/null +++ b/test/groupher_server/cms/mention_tasks/post_mention_test.exs @@ -0,0 +1,48 @@ +defmodule GroupherServer.Test.CMS.MentionTask.Post do + use GroupherServer.TestTools + + import Helper.Utils, only: [get_config: 2] + + alias Helper.ORM + alias GroupherServer.CMS + + alias CMS.Model.{Post, Comment, CitedContent} + alias CMS.Delegate.MentionTask + + @site_host get_config(:general, :site_host) + + @article_mention_class "cdx-mention" + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, post} = db_insert(:post) + {:ok, post2} = db_insert(:post) + {:ok, post3} = db_insert(:post) + {:ok, post4} = db_insert(:post) + {:ok, post5} = db_insert(:post) + + {:ok, community} = db_insert(:community) + + post_attrs = mock_attrs(:post, %{community_id: community.id}) + + {:ok, ~m(user user2 community post post2 post3 post4 post5 post_attrs)a} + end + + describe "[cite basic]" do + @tag :wip + test "cited multi post should work", + ~m(user user2 community post2 post3 post4 post5 post_attrs)a do + body = + mock_rich_text( + ~s(hi
#{user2.login}
), + ~s(hi
#{user2.login}
) + ) + + post_attrs = post_attrs |> Map.merge(%{body: body}) + {:ok, post} = CMS.create_article(community, :post, post_attrs, user) + + MentionTask.handle(post) + end + end +end diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index 4ccf79ab2..3aacfd764 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -34,7 +34,7 @@ defmodule GroupherServer.Test.Delivery.Mention do describe "mentions" do @tag :wip test "can batch send mentions", ~m(post user user2 mention_contents)a do - {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user, user2) + {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user) {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) mention = result.entries |> List.first() @@ -47,12 +47,12 @@ defmodule GroupherServer.Test.Delivery.Mention do @tag :wip test "mention multiable times on same article, will only have one record", ~m(post user user2 mention_contents)a do - {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user, user2) + {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user) {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) assert result.total_count == 1 - {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user, user2) + {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user) {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) assert result.total_count == 1 @@ -61,7 +61,7 @@ defmodule GroupherServer.Test.Delivery.Mention do @tag :wip test "if mention before, update with no mention content will not do mention in final", ~m(post user user2 user3 mention_contents)a do - {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user, user2) + {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user) {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) assert result.total_count == 1 @@ -84,7 +84,7 @@ defmodule GroupherServer.Test.Delivery.Mention do } ] - {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user, user2) + {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user) {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) assert result.total_count == 0 diff --git a/test/groupher_server_web/query/cms/citings/blog_citing_test.exs b/test/groupher_server_web/query/cms/citings/blog_citing_test.exs index 8fcc8140b..8fb2a385f 100644 --- a/test/groupher_server_web/query/cms/citings/blog_citing_test.exs +++ b/test/groupher_server_web/query/cms/citings/blog_citing_test.exs @@ -6,7 +6,7 @@ defmodule GroupherServer.Test.Query.AbuseReports.BlogCiting do alias GroupherServer.CMS - alias CMS.Delegate.CiteTasks + alias CMS.Delegate.CiteTask @site_host get_config(:general, :site_host) @@ -69,9 +69,9 @@ defmodule GroupherServer.Test.Query.AbuseReports.BlogCiting do blog_attrs = blog_attrs |> Map.merge(%{body: body}) {:ok, blog_y} = CMS.create_article(community, :blog, blog_attrs, user) - CiteTasks.handle(blog_x) - CiteTasks.handle(comment) - CiteTasks.handle(blog_y) + CiteTask.handle(blog_x) + CiteTask.handle(comment) + CiteTask.handle(blog_y) variables = %{content: "BLOG", id: blog2.id, filter: %{page: 1, size: 10}} results = guest_conn |> query_result(@query, variables, "pagedCitingContents") diff --git a/test/groupher_server_web/query/cms/citings/job_citing_test.exs b/test/groupher_server_web/query/cms/citings/job_citing_test.exs index 67e3b55e7..9e00f9eee 100644 --- a/test/groupher_server_web/query/cms/citings/job_citing_test.exs +++ b/test/groupher_server_web/query/cms/citings/job_citing_test.exs @@ -6,7 +6,7 @@ defmodule GroupherServer.Test.Query.AbuseReports.JobCiting do alias GroupherServer.CMS - alias CMS.Delegate.CiteTasks + alias CMS.Delegate.CiteTask @site_host get_config(:general, :site_host) @@ -69,9 +69,9 @@ defmodule GroupherServer.Test.Query.AbuseReports.JobCiting do job_attrs = job_attrs |> Map.merge(%{body: body}) {:ok, job_y} = CMS.create_article(community, :job, job_attrs, user) - CiteTasks.handle(job_x) - CiteTasks.handle(comment) - CiteTasks.handle(job_y) + CiteTask.handle(job_x) + CiteTask.handle(comment) + CiteTask.handle(job_y) variables = %{content: "JOB", id: job2.id, filter: %{page: 1, size: 10}} results = guest_conn |> query_result(@query, variables, "pagedCitingContents") diff --git a/test/groupher_server_web/query/cms/citings/post_citing_test.exs b/test/groupher_server_web/query/cms/citings/post_citing_test.exs index 354a7bd5e..070bb0455 100644 --- a/test/groupher_server_web/query/cms/citings/post_citing_test.exs +++ b/test/groupher_server_web/query/cms/citings/post_citing_test.exs @@ -6,7 +6,7 @@ defmodule GroupherServer.Test.Query.AbuseReports.PostCiting do alias GroupherServer.CMS - alias CMS.Delegate.CiteTasks + alias CMS.Delegate.CiteTask @site_host get_config(:general, :site_host) @@ -69,9 +69,9 @@ defmodule GroupherServer.Test.Query.AbuseReports.PostCiting do post_attrs = post_attrs |> Map.merge(%{body: body}) {:ok, post_y} = CMS.create_article(community, :post, post_attrs, user) - CiteTasks.handle(post_x) - CiteTasks.handle(comment) - CiteTasks.handle(post_y) + CiteTask.handle(post_x) + CiteTask.handle(comment) + CiteTask.handle(post_y) variables = %{content: "POST", id: post2.id, filter: %{page: 1, size: 10}} results = guest_conn |> query_result(@query, variables, "pagedCitingContents") From 88a4215be67f13799aa43d49e11569e3e4d61dbf Mon Sep 17 00:00:00 2001 From: mydearxym Date: Thu, 17 Jun 2021 22:54:40 +0800 Subject: [PATCH 09/54] refactor(delivery): re-org mention & dir, naming --- .../cms/delegates/article_curd.ex | 15 ++++--- .../cms/delegates/comment_curd.ex | 5 ++- .../delegates/{cite_task.ex => hooks/cite.ex} | 42 ++----------------- .../cms/delegates/hooks/helper.ex | 38 +++++++++++++++++ .../{mention_task.ex => hooks/mention.ex} | 32 +++----------- .../{cite_tasks => hooks}/cite_blog_test.exs | 26 ++++++------ .../{cite_tasks => hooks}/cite_job_test.exs | 26 ++++++------ .../{cite_tasks => hooks}/cite_post_test.exs | 34 +++++++-------- .../mention_in_post_test.exs} | 26 ++++++------ .../cite_blog_test.exs} | 10 ++--- .../cite_job_test.exs} | 10 ++--- .../cite_post_test.exs} | 10 ++--- 12 files changed, 127 insertions(+), 147 deletions(-) rename lib/groupher_server/cms/delegates/{cite_task.ex => hooks/cite.ex} (91%) create mode 100644 lib/groupher_server/cms/delegates/hooks/helper.ex rename lib/groupher_server/cms/delegates/{mention_task.ex => hooks/mention.ex} (78%) rename test/groupher_server/cms/{cite_tasks => hooks}/cite_blog_test.exs (94%) rename test/groupher_server/cms/{cite_tasks => hooks}/cite_job_test.exs (94%) rename test/groupher_server/cms/{cite_tasks => hooks}/cite_post_test.exs (94%) rename test/groupher_server/cms/{mention_tasks/post_mention_test.exs => hooks/mention_in_post_test.exs} (59%) rename test/groupher_server_web/query/cms/{citings/blog_citing_test.exs => hooks/cite_blog_test.exs} (91%) rename test/groupher_server_web/query/cms/{citings/job_citing_test.exs => hooks/cite_job_test.exs} (91%) rename test/groupher_server_web/query/cms/{citings/post_citing_test.exs => hooks/cite_post_test.exs} (91%) diff --git a/lib/groupher_server/cms/delegates/article_curd.ex b/lib/groupher_server/cms/delegates/article_curd.ex index 1c8613314..a0100d637 100644 --- a/lib/groupher_server/cms/delegates/article_curd.ex +++ b/lib/groupher_server/cms/delegates/article_curd.ex @@ -24,8 +24,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do CommentCurd, ArticleTag, CommunityCURD, - CiteTask, - MentionTask + Hooks } alias Ecto.Multi @@ -172,9 +171,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do |> Multi.run(:update_user_published_meta, fn _, _ -> Accounts.update_published_states(uid, thread) end) - |> Multi.run(:after_tasks, fn _, %{create_article: article} -> - Later.run({CiteTask, :handle, [article]}) - Later.run({MentionTask, :handle, [article]}) + |> Multi.run(:after_hooks, fn _, %{create_article: article} -> + Later.run({Hooks.Cite, :handle, [article]}) + Later.run({Hooks.Mention, :handle, [article]}) Later.run({__MODULE__, :notify_admin_new_article, [article]}) end) |> Multi.run(:mention_users, fn _, %{create_article: article} -> @@ -232,9 +231,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do |> Multi.run(:update_edit_status, fn _, %{update_article: update_article} -> ArticleCommunity.update_edit_status(update_article) end) - |> Multi.run(:after_tasks, fn _, %{update_article: update_article} -> - Later.run({CiteTask, :handle, [update_article]}) - Later.run({MentionTask, :handle, [update_article]}) + |> Multi.run(:after_hooks, fn _, %{update_article: update_article} -> + Later.run({Hooks.Cite, :handle, [update_article]}) + Later.run({Hooks.Mention, :handle, [update_article]}) end) |> Repo.transaction() |> result() diff --git a/lib/groupher_server/cms/delegates/comment_curd.ex b/lib/groupher_server/cms/delegates/comment_curd.ex index a3ab85b90..0ddadff8c 100644 --- a/lib/groupher_server/cms/delegates/comment_curd.ex +++ b/lib/groupher_server/cms/delegates/comment_curd.ex @@ -14,6 +14,7 @@ defmodule GroupherServer.CMS.Delegate.CommentCurd do alias Helper.{Later, ORM, QueryBuilder, Converter} alias GroupherServer.{Accounts, CMS, Repo} alias CMS.Model.Post + alias CMS.Delegate.Hooks alias Accounts.Model.User alias CMS.Model.{Comment, PinnedComment, Embeds} @@ -113,8 +114,8 @@ defmodule GroupherServer.CMS.Delegate.CommentCurd do false -> CMS.update_active_timestamp(thread, article) end end) - |> Multi.run(:block_tasks, fn _, %{create_comment: create_comment} -> - Later.run({CiteTask, :handle, [create_comment]}) + |> Multi.run(:after_hooks, fn _, %{create_comment: create_comment} -> + Later.run({Hooks.Cite, :handle, [create_comment]}) end) |> Repo.transaction() |> result() diff --git a/lib/groupher_server/cms/delegates/cite_task.ex b/lib/groupher_server/cms/delegates/hooks/cite.ex similarity index 91% rename from lib/groupher_server/cms/delegates/cite_task.ex rename to lib/groupher_server/cms/delegates/hooks/cite.ex index d9de2a1d9..75244205e 100644 --- a/lib/groupher_server/cms/delegates/cite_task.ex +++ b/lib/groupher_server/cms/delegates/hooks/cite.ex @@ -1,4 +1,4 @@ -defmodule GroupherServer.CMS.Delegate.CiteTask do +defmodule GroupherServer.CMS.Delegate.Hooks.Cite do @moduledoc """ run tasks in every article blocks if need @@ -25,6 +25,7 @@ defmodule GroupherServer.CMS.Delegate.CiteTask do import Ecto.Query, warn: false import Helper.Utils, only: [get_config: 2, thread_of_article: 1, done: 1] + import GroupherServer.CMS.Delegate.Hooks.Helper, only: [merge_same_block_linker: 2] import GroupherServer.CMS.Helper.Matcher import Helper.ErrorCode @@ -48,7 +49,7 @@ defmodule GroupherServer.CMS.Delegate.CiteTask do |> Multi.run(:update_cited_info, fn _, _ -> blocks |> Enum.reduce([], &(&2 ++ parse_cited_info_per_block(content, &1))) - |> merge_same_block_linker + |> merge_same_block_linker(:cited_by_id) |> update_cited_info end) |> Repo.transaction() @@ -112,43 +113,6 @@ defmodule GroupherServer.CMS.Delegate.CiteTask do |> done end - @doc """ - merge same cited article in different blocks - e.g: - [ - %{ - block_linker: ["block-zByQI"], - cited_by_id: 190058, - cited_by_type: "POST", - post_id: 190059, - user_id: 1413053 - }, - %{ - block_linker: ["block-zByQI", "block-ZgKJs"], - cited_by_id: 190057, - cited_by_type: "POST", - post_id: 190059, - user_id: 1413053 - }, - ] - """ - defp merge_same_block_linker(cited_contents) do - cited_contents - |> Enum.reduce([], fn content, acc -> - case Enum.find_index(acc, &(&1.cited_by_id == content.cited_by_id)) do - nil -> - acc ++ [content] - - index -> - List.update_at( - acc, - index, - &Map.merge(&1, %{block_linker: &1.block_linker ++ content.block_linker}) - ) - end - end) - end - @doc """ return fmt like: [ diff --git a/lib/groupher_server/cms/delegates/hooks/helper.ex b/lib/groupher_server/cms/delegates/hooks/helper.ex new file mode 100644 index 000000000..8e8e43fb6 --- /dev/null +++ b/lib/groupher_server/cms/delegates/hooks/helper.ex @@ -0,0 +1,38 @@ +defmodule GroupherServer.CMS.Delegate.Hooks.Helper do + @moduledoc """ + helper functions for hooks + """ + + @doc """ + merge same cited article in different blocks + e.g: + [ + %{ + block_linker: ["block-zByQI"], + [group_key]: 190057, + .. + }, + %{ + block_linker: ["block-zByQI", "block-ZgKJs"], + [group_key]: 190057, + .. + }, + ] + """ + def merge_same_block_linker(contents, group_key) do + contents + |> Enum.reduce([], fn content, acc -> + case Enum.find_index(acc, &(Map.get(&1, group_key) == Map.get(content, group_key))) do + nil -> + acc ++ [content] + + index -> + List.update_at( + acc, + index, + &Map.put(&1, :block_linker, &1.block_linker ++ content.block_linker) + ) + end + end) + end +end diff --git a/lib/groupher_server/cms/delegates/mention_task.ex b/lib/groupher_server/cms/delegates/hooks/mention.ex similarity index 78% rename from lib/groupher_server/cms/delegates/mention_task.ex rename to lib/groupher_server/cms/delegates/hooks/mention.ex index 37eeb76eb..86678d033 100644 --- a/lib/groupher_server/cms/delegates/mention_task.ex +++ b/lib/groupher_server/cms/delegates/hooks/mention.ex @@ -1,4 +1,4 @@ -defmodule GroupherServer.CMS.Delegate.MentionTask do +defmodule GroupherServer.CMS.Delegate.Hooks.Mention do @moduledoc """ run tasks in every article blocks if need @@ -25,16 +25,11 @@ defmodule GroupherServer.CMS.Delegate.MentionTask do import Ecto.Query, warn: false import Helper.Utils, only: [get_config: 2, thread_of_article: 1, done: 1] - import GroupherServer.CMS.Helper.Matcher - import Helper.ErrorCode + import GroupherServer.CMS.Delegate.Hooks.Helper, only: [merge_same_block_linker: 2] alias GroupherServer.{Accounts, CMS, Repo} - alias CMS.Model.{CitedContent, Comment} - alias Helper.ORM + alias CMS.Model.Comment - alias Ecto.Multi - - @site_host get_config(:general, :site_host) @article_threads get_config(:article, :threads) @article_mention_class "cdx-mention" @@ -45,7 +40,7 @@ defmodule GroupherServer.CMS.Delegate.MentionTask do blocks |> Enum.reduce([], &(&2 ++ parse_cited_info_per_block(content, &1))) |> merge_same_block_linker(:to_user_id) - |> IO.inspect(label: "blocks") + |> done end end @@ -89,7 +84,7 @@ defmodule GroupherServer.CMS.Delegate.MentionTask do defp shape(article, to_user_id, block_id) do %{ - type: article.meta.thread, + type: thread_of_article(article), title: article.title, article_id: article.id, block_linker: [block_id], @@ -98,21 +93,4 @@ defmodule GroupherServer.CMS.Delegate.MentionTask do to_user_id: to_user_id } end - - defp merge_same_block_linker(contents, group_key) do - contents - |> Enum.reduce([], fn content, acc -> - case Enum.find_index(acc, &(Map.get(&1, group_key) == Map.get(content, group_key))) do - nil -> - acc ++ [content] - - index -> - List.update_at( - acc, - index, - &Map.put(&1, :block_linker, &1.block_linker ++ content.block_linker) - ) - end - end) - end end diff --git a/test/groupher_server/cms/cite_tasks/cite_blog_test.exs b/test/groupher_server/cms/hooks/cite_blog_test.exs similarity index 94% rename from test/groupher_server/cms/cite_tasks/cite_blog_test.exs rename to test/groupher_server/cms/hooks/cite_blog_test.exs index 6d34f18b6..d336a1e53 100644 --- a/test/groupher_server/cms/cite_tasks/cite_blog_test.exs +++ b/test/groupher_server/cms/hooks/cite_blog_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.CMS.CiteTask.Blog do +defmodule GroupherServer.Test.CMS.Hooks.CiteBlog do use GroupherServer.TestTools import Helper.Utils, only: [get_config: 2] @@ -7,7 +7,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Blog do alias GroupherServer.CMS alias CMS.Model.{Blog, Comment, CitedContent} - alias CMS.Delegate.CiteTask + alias CMS.Delegate.Hooks @site_host get_config(:general, :site_host) @@ -47,8 +47,8 @@ defmodule GroupherServer.Test.CMS.CiteTask.Blog do blog_attrs = blog_attrs |> Map.merge(%{body: body}) {:ok, blog_n} = CMS.create_article(community, :blog, blog_attrs, user) - CiteTask.handle(blog) - CiteTask.handle(blog_n) + Hooks.Cite.handle(blog) + Hooks.Cite.handle(blog_n) {:ok, blog2} = ORM.find(Blog, blog2.id) {:ok, blog3} = ORM.find(Blog, blog3.id) @@ -67,7 +67,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Blog do body = mock_rich_text(~s(the
)) {:ok, blog} = CMS.update_article(blog, %{body: body}) - CiteTask.handle(blog) + Hooks.Cite.handle(blog) {:ok, blog} = ORM.find(Blog, blog.id) assert blog.meta.citing_count == 0 @@ -84,7 +84,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Blog do ) ) - CiteTask.handle(comment) + Hooks.Cite.handle(comment) {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 0 @@ -99,7 +99,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Blog do blog_attrs = blog_attrs |> Map.merge(%{body: body}) {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) - CiteTask.handle(blog) + Hooks.Cite.handle(blog) {:ok, comment} = ORM.find(Comment, comment.id) assert comment.meta.citing_count == 1 @@ -119,7 +119,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Blog do {:ok, comment} = CMS.create_comment(:blog, blog.id, comment_body, user) - CiteTask.handle(comment) + Hooks.Cite.handle(comment) {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 1 @@ -143,12 +143,12 @@ defmodule GroupherServer.Test.CMS.CiteTask.Blog do ) {:ok, comment} = CMS.create_comment(:blog, blog.id, comment_body, user) - CiteTask.handle(comment) + Hooks.Cite.handle(comment) comment_body = mock_rich_text(~s(the )) {:ok, comment} = CMS.create_comment(:blog, blog.id, comment_body, user) - CiteTask.handle(comment) + Hooks.Cite.handle(comment) {:ok, blog2} = ORM.find(Blog, blog2.id) {:ok, blog3} = ORM.find(Blog, blog3.id) @@ -188,9 +188,9 @@ defmodule GroupherServer.Test.CMS.CiteTask.Blog do blog_attrs = blog_attrs |> Map.merge(%{body: body}) {:ok, blog_y} = CMS.create_article(community, :blog, blog_attrs, user) - CiteTask.handle(blog_x) - CiteTask.handle(comment) - CiteTask.handle(blog_y) + Hooks.Cite.handle(blog_x) + Hooks.Cite.handle(comment) + Hooks.Cite.handle(blog_y) {:ok, result} = CMS.paged_citing_contents("BLOG", blog2.id, %{page: 1, size: 10}) diff --git a/test/groupher_server/cms/cite_tasks/cite_job_test.exs b/test/groupher_server/cms/hooks/cite_job_test.exs similarity index 94% rename from test/groupher_server/cms/cite_tasks/cite_job_test.exs rename to test/groupher_server/cms/hooks/cite_job_test.exs index 8d509389f..7241ef603 100644 --- a/test/groupher_server/cms/cite_tasks/cite_job_test.exs +++ b/test/groupher_server/cms/hooks/cite_job_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.CMS.CiteTask.Job do +defmodule GroupherServer.Test.CMS.Hooks.CiteJob do use GroupherServer.TestTools import Helper.Utils, only: [get_config: 2] @@ -7,7 +7,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Job do alias GroupherServer.CMS alias CMS.Model.{Job, Comment, CitedContent} - alias CMS.Delegate.CiteTask + alias CMS.Delegate.Hooks @site_host get_config(:general, :site_host) @@ -47,8 +47,8 @@ defmodule GroupherServer.Test.CMS.CiteTask.Job do job_attrs = job_attrs |> Map.merge(%{body: body}) {:ok, job_n} = CMS.create_article(community, :job, job_attrs, user) - CiteTask.handle(job) - CiteTask.handle(job_n) + Hooks.Cite.handle(job) + Hooks.Cite.handle(job_n) {:ok, job2} = ORM.find(Job, job2.id) {:ok, job3} = ORM.find(Job, job3.id) @@ -67,7 +67,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Job do body = mock_rich_text(~s(the )) {:ok, job} = CMS.update_article(job, %{body: body}) - CiteTask.handle(job) + Hooks.Cite.handle(job) {:ok, job} = ORM.find(Job, job.id) assert job.meta.citing_count == 0 @@ -84,7 +84,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Job do ) ) - CiteTask.handle(comment) + Hooks.Cite.handle(comment) {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 0 @@ -99,7 +99,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Job do job_attrs = job_attrs |> Map.merge(%{body: body}) {:ok, job} = CMS.create_article(community, :job, job_attrs, user) - CiteTask.handle(job) + Hooks.Cite.handle(job) {:ok, comment} = ORM.find(Comment, comment.id) assert comment.meta.citing_count == 1 @@ -119,7 +119,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Job do {:ok, comment} = CMS.create_comment(:job, job.id, comment_body, user) - CiteTask.handle(comment) + Hooks.Cite.handle(comment) {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 1 @@ -143,12 +143,12 @@ defmodule GroupherServer.Test.CMS.CiteTask.Job do ) {:ok, comment} = CMS.create_comment(:job, job.id, comment_body, user) - CiteTask.handle(comment) + Hooks.Cite.handle(comment) comment_body = mock_rich_text(~s(the )) {:ok, comment} = CMS.create_comment(:job, job.id, comment_body, user) - CiteTask.handle(comment) + Hooks.Cite.handle(comment) {:ok, job2} = ORM.find(Job, job2.id) {:ok, job3} = ORM.find(Job, job3.id) @@ -187,9 +187,9 @@ defmodule GroupherServer.Test.CMS.CiteTask.Job do job_attrs = job_attrs |> Map.merge(%{body: body}) {:ok, job_y} = CMS.create_article(community, :job, job_attrs, user) - CiteTask.handle(job_x) - CiteTask.handle(comment) - CiteTask.handle(job_y) + Hooks.Cite.handle(job_x) + Hooks.Cite.handle(comment) + Hooks.Cite.handle(job_y) {:ok, result} = CMS.paged_citing_contents("JOB", job2.id, %{page: 1, size: 10}) diff --git a/test/groupher_server/cms/cite_tasks/cite_post_test.exs b/test/groupher_server/cms/hooks/cite_post_test.exs similarity index 94% rename from test/groupher_server/cms/cite_tasks/cite_post_test.exs rename to test/groupher_server/cms/hooks/cite_post_test.exs index 5d45159b4..2fb5802e3 100644 --- a/test/groupher_server/cms/cite_tasks/cite_post_test.exs +++ b/test/groupher_server/cms/hooks/cite_post_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.CMS.CiteTask.Post do +defmodule GroupherServer.Test.CMS.Hooks.CitePost do use GroupherServer.TestTools import Helper.Utils, only: [get_config: 2] @@ -7,7 +7,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Post do alias GroupherServer.CMS alias CMS.Model.{Post, Comment, CitedContent} - alias CMS.Delegate.CiteTask + alias CMS.Delegate.Hooks @site_host get_config(:general, :site_host) @@ -47,8 +47,8 @@ defmodule GroupherServer.Test.CMS.CiteTask.Post do post_attrs = post_attrs |> Map.merge(%{body: body}) {:ok, post_n} = CMS.create_article(community, :post, post_attrs, user) - CiteTask.handle(post) - CiteTask.handle(post_n) + Hooks.Cite.handle(post) + Hooks.Cite.handle(post_n) {:ok, post2} = ORM.find(Post, post2.id) {:ok, post3} = ORM.find(Post, post3.id) @@ -67,7 +67,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Post do body = mock_rich_text(~s(the )) {:ok, post} = CMS.update_article(post, %{body: body}) - CiteTask.handle(post) + Hooks.Cite.handle(post) {:ok, post} = ORM.find(Post, post.id) assert post.meta.citing_count == 0 @@ -84,7 +84,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Post do ) ) - CiteTask.handle(comment) + Hooks.Cite.handle(comment) {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 0 @@ -99,7 +99,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Post do post_attrs = post_attrs |> Map.merge(%{body: body}) {:ok, post} = CMS.create_article(community, :post, post_attrs, user) - CiteTask.handle(post) + Hooks.Cite.handle(post) {:ok, comment} = ORM.find(Comment, comment.id) assert comment.meta.citing_count == 1 @@ -119,7 +119,7 @@ defmodule GroupherServer.Test.CMS.CiteTask.Post do {:ok, comment} = CMS.create_comment(:post, post.id, comment_body, user) - CiteTask.handle(comment) + Hooks.Cite.handle(comment) {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 1 @@ -143,12 +143,12 @@ defmodule GroupherServer.Test.CMS.CiteTask.Post do ) {:ok, comment} = CMS.create_comment(:post, post.id, comment_body, user) - CiteTask.handle(comment) + Hooks.Cite.handle(comment) comment_body = mock_rich_text(~s(the )) {:ok, comment} = CMS.create_comment(:post, post.id, comment_body, user) - CiteTask.handle(comment) + Hooks.Cite.handle(comment) {:ok, post2} = ORM.find(Post, post2.id) {:ok, post3} = ORM.find(Post, post3.id) @@ -188,9 +188,9 @@ defmodule GroupherServer.Test.CMS.CiteTask.Post do post_attrs = post_attrs |> Map.merge(%{body: body}) {:ok, post_y} = CMS.create_article(community, :post, post_attrs, user) - CiteTask.handle(post_x) - CiteTask.handle(comment) - CiteTask.handle(post_y) + Hooks.Cite.handle(post_x) + Hooks.Cite.handle(comment) + Hooks.Cite.handle(post_y) {:ok, result} = CMS.paged_citing_contents("POST", post2.id, %{page: 1, size: 10}) @@ -230,26 +230,26 @@ defmodule GroupherServer.Test.CMS.CiteTask.Post do {:ok, post} = CMS.create_article(community, :post, Map.merge(post_attrs, %{body: body}), user) - CiteTask.handle(post) + Hooks.Cite.handle(post) Process.sleep(1000) {:ok, job} = CMS.create_article(community, :job, Map.merge(job_attrs, %{body: body}), user) - CiteTask.handle(job) + Hooks.Cite.handle(job) Process.sleep(1000) comment_body = mock_comment(~s(the )) {:ok, comment} = CMS.create_comment(:job, job.id, comment_body, user) - CiteTask.handle(comment) + Hooks.Cite.handle(comment) Process.sleep(1000) {:ok, blog} = CMS.create_article(community, :blog, Map.merge(blog_attrs, %{body: body}), user) - CiteTask.handle(blog) + Hooks.Cite.handle(blog) {:ok, result} = CMS.paged_citing_contents("POST", post2.id, %{page: 1, size: 10}) # IO.inspect(result, label: "the result") diff --git a/test/groupher_server/cms/mention_tasks/post_mention_test.exs b/test/groupher_server/cms/hooks/mention_in_post_test.exs similarity index 59% rename from test/groupher_server/cms/mention_tasks/post_mention_test.exs rename to test/groupher_server/cms/hooks/mention_in_post_test.exs index 5b37f91b4..f61022531 100644 --- a/test/groupher_server/cms/mention_tasks/post_mention_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_post_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.CMS.MentionTask.Post do +defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do use GroupherServer.TestTools import Helper.Utils, only: [get_config: 2] @@ -6,8 +6,8 @@ defmodule GroupherServer.Test.CMS.MentionTask.Post do alias Helper.ORM alias GroupherServer.CMS - alias CMS.Model.{Post, Comment, CitedContent} - alias CMS.Delegate.MentionTask + alias CMS.Model.{Comment} + alias CMS.Delegate.Hooks @site_host get_config(:general, :site_host) @@ -16,33 +16,33 @@ defmodule GroupherServer.Test.CMS.MentionTask.Post do setup do {:ok, user} = db_insert(:user) {:ok, user2} = db_insert(:user) + {:ok, user3} = db_insert(:user) {:ok, post} = db_insert(:post) - {:ok, post2} = db_insert(:post) - {:ok, post3} = db_insert(:post) - {:ok, post4} = db_insert(:post) - {:ok, post5} = db_insert(:post) {:ok, community} = db_insert(:community) post_attrs = mock_attrs(:post, %{community_id: community.id}) - {:ok, ~m(user user2 community post post2 post3 post4 post5 post_attrs)a} + {:ok, ~m(user user2 user3 community post post_attrs)a} end - describe "[cite basic]" do + describe "[mention in post basic]" do @tag :wip - test "cited multi post should work", - ~m(user user2 community post2 post3 post4 post5 post_attrs)a do + test "mention multi user in post should work", ~m(user user2 user3 community post_attrs)a do body = mock_rich_text( - ~s(hi
#{user2.login}
), + ~s(hi
#{user2.login}
, and
#{user3.login}
), ~s(hi
#{user2.login}
) ) post_attrs = post_attrs |> Map.merge(%{body: body}) {:ok, post} = CMS.create_article(community, :post, post_attrs, user) - MentionTask.handle(post) + {:ok, result} = Hooks.Mention.handle(post) + + assert length(result) == 2 end end end diff --git a/test/groupher_server_web/query/cms/citings/blog_citing_test.exs b/test/groupher_server_web/query/cms/hooks/cite_blog_test.exs similarity index 91% rename from test/groupher_server_web/query/cms/citings/blog_citing_test.exs rename to test/groupher_server_web/query/cms/hooks/cite_blog_test.exs index 8fb2a385f..d7e4ae2ea 100644 --- a/test/groupher_server_web/query/cms/citings/blog_citing_test.exs +++ b/test/groupher_server_web/query/cms/hooks/cite_blog_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.Query.AbuseReports.BlogCiting do +defmodule GroupherServer.Test.Query.Hooks.CiteBlog do @moduledoc false use GroupherServer.TestTools @@ -6,7 +6,7 @@ defmodule GroupherServer.Test.Query.AbuseReports.BlogCiting do alias GroupherServer.CMS - alias CMS.Delegate.CiteTask + alias CMS.Delegate.Hooks @site_host get_config(:general, :site_host) @@ -69,9 +69,9 @@ defmodule GroupherServer.Test.Query.AbuseReports.BlogCiting do blog_attrs = blog_attrs |> Map.merge(%{body: body}) {:ok, blog_y} = CMS.create_article(community, :blog, blog_attrs, user) - CiteTask.handle(blog_x) - CiteTask.handle(comment) - CiteTask.handle(blog_y) + Hooks.Cite.handle(blog_x) + Hooks.Cite.handle(comment) + Hooks.Cite.handle(blog_y) variables = %{content: "BLOG", id: blog2.id, filter: %{page: 1, size: 10}} results = guest_conn |> query_result(@query, variables, "pagedCitingContents") diff --git a/test/groupher_server_web/query/cms/citings/job_citing_test.exs b/test/groupher_server_web/query/cms/hooks/cite_job_test.exs similarity index 91% rename from test/groupher_server_web/query/cms/citings/job_citing_test.exs rename to test/groupher_server_web/query/cms/hooks/cite_job_test.exs index 9e00f9eee..e92903478 100644 --- a/test/groupher_server_web/query/cms/citings/job_citing_test.exs +++ b/test/groupher_server_web/query/cms/hooks/cite_job_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.Query.AbuseReports.JobCiting do +defmodule GroupherServer.Test.Query.Hooks.CiteJob do @moduledoc false use GroupherServer.TestTools @@ -6,7 +6,7 @@ defmodule GroupherServer.Test.Query.AbuseReports.JobCiting do alias GroupherServer.CMS - alias CMS.Delegate.CiteTask + alias CMS.Delegate.Hooks @site_host get_config(:general, :site_host) @@ -69,9 +69,9 @@ defmodule GroupherServer.Test.Query.AbuseReports.JobCiting do job_attrs = job_attrs |> Map.merge(%{body: body}) {:ok, job_y} = CMS.create_article(community, :job, job_attrs, user) - CiteTask.handle(job_x) - CiteTask.handle(comment) - CiteTask.handle(job_y) + Hooks.Cite.handle(job_x) + Hooks.Cite.handle(comment) + Hooks.Cite.handle(job_y) variables = %{content: "JOB", id: job2.id, filter: %{page: 1, size: 10}} results = guest_conn |> query_result(@query, variables, "pagedCitingContents") diff --git a/test/groupher_server_web/query/cms/citings/post_citing_test.exs b/test/groupher_server_web/query/cms/hooks/cite_post_test.exs similarity index 91% rename from test/groupher_server_web/query/cms/citings/post_citing_test.exs rename to test/groupher_server_web/query/cms/hooks/cite_post_test.exs index 070bb0455..a33ab94aa 100644 --- a/test/groupher_server_web/query/cms/citings/post_citing_test.exs +++ b/test/groupher_server_web/query/cms/hooks/cite_post_test.exs @@ -1,4 +1,4 @@ -defmodule GroupherServer.Test.Query.AbuseReports.PostCiting do +defmodule GroupherServer.Test.Query.Hooks.PostCiting do @moduledoc false use GroupherServer.TestTools @@ -6,7 +6,7 @@ defmodule GroupherServer.Test.Query.AbuseReports.PostCiting do alias GroupherServer.CMS - alias CMS.Delegate.CiteTask + alias CMS.Delegate.Hooks @site_host get_config(:general, :site_host) @@ -69,9 +69,9 @@ defmodule GroupherServer.Test.Query.AbuseReports.PostCiting do post_attrs = post_attrs |> Map.merge(%{body: body}) {:ok, post_y} = CMS.create_article(community, :post, post_attrs, user) - CiteTask.handle(post_x) - CiteTask.handle(comment) - CiteTask.handle(post_y) + Hooks.Cite.handle(post_x) + Hooks.Cite.handle(comment) + Hooks.Cite.handle(post_y) variables = %{content: "POST", id: post2.id, filter: %{page: 1, size: 10}} results = guest_conn |> query_result(@query, variables, "pagedCitingContents") From e7e18c32ddfe297521552d275c523d4392d1cc79 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Fri, 18 Jun 2021 11:20:46 +0800 Subject: [PATCH 10/54] refactor(delivery): move cite ORM opt to delegate & fmt, naming --- .../cms/delegates/cited_content.ex | 68 +++++++++- lib/groupher_server/cms/delegates/helper.ex | 5 +- .../cms/delegates/hooks/cite.ex | 120 +++++------------- .../delivery/delegates/mention.ex | 20 +-- 4 files changed, 113 insertions(+), 100 deletions(-) diff --git a/lib/groupher_server/cms/delegates/cited_content.ex b/lib/groupher_server/cms/delegates/cited_content.ex index ccf81959a..e99a0b424 100644 --- a/lib/groupher_server/cms/delegates/cited_content.ex +++ b/lib/groupher_server/cms/delegates/cited_content.ex @@ -4,14 +4,16 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do """ import Ecto.Query, warn: false - import Helper.Utils, only: [done: 1, get_config: 2] + import Helper.Utils, only: [done: 1, get_config: 2, thread_of_article: 1] + import GroupherServer.CMS.Helper.Matcher import ShortMaps alias Helper.Types, as: T alias GroupherServer.{CMS, Repo} + alias Helper.{ORM, QueryBuilder} - alias CMS.Model.CitedContent + alias CMS.Model.{CitedContent, Comment} @article_threads get_config(:article, :threads) @@ -32,7 +34,67 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do |> done end - def extract_contents(%{entries: entries} = paged_contents) do + @doc "delete all records before insert_all, this will dynamiclly update" + # those cited info when update article + # 插入引用记录之前先全部清除,这样可以在更新文章的时候自动计算引用信息 + def batch_delete_cited_contents(%Comment{} = comment) do + from(c in CitedContent, where: c.comment_id == ^comment.id) + |> ORM.delete_all(:if_exist) + end + + def batch_delete_cited_contents(article) do + with {:ok, thread} <- thread_of_article(article), + {:ok, info} <- match(thread) do + thread = thread |> to_string |> String.upcase() + + from(c in CitedContent, + where: field(c, ^info.foreign_key) == ^article.id and c.cited_by_type == ^thread + ) + |> ORM.delete_all(:if_exist) + end + end + + @doc "batch insert CitedContent record and update citing count" + def batch_insert_cited_contents(cited_contents) do + # 注意这里多了 cited_content 和 citting_time + # cited_content 是为了下一步更新 citting_count 预先加载的,避免单独 preload 消耗性能 + # citing_time 是因为 insert_all 必须要自己更新时间 + # see: https://github.com/elixir-ecto/ecto/issues/1932#issuecomment-314083252 + clean_cited_contents = + cited_contents + |> Enum.map(&(&1 |> Map.merge(%{inserted_at: &1.citing_time, updated_at: &1.citing_time}))) + |> Enum.map(&Map.delete(&1, :cited_content)) + |> Enum.map(&Map.delete(&1, :citing_time)) + + case {0, nil} !== Repo.insert_all(CitedContent, clean_cited_contents) do + true -> update_content_citing_count(cited_contents) + false -> {:error, "insert cited content error"} + end + + case {0, nil} !== Repo.insert_all(CitedContent, clean_cited_contents) do + true -> update_content_citing_count(cited_contents) + false -> {:error, "insert cited content error"} + end + end + + # update article/comment 's citting_count in meta + defp update_content_citing_count(cited_contents) do + Enum.all?(cited_contents, fn content -> + count_query = from(c in CitedContent, where: c.cited_by_id == ^content.cited_by_id) + count = Repo.aggregate(count_query, :count) + + cited_content = content.cited_content + meta = Map.merge(cited_content.meta, %{citing_count: count}) + + case cited_content |> ORM.update_meta(meta) do + {:ok, _} -> true + {:error, _} -> false + end + end) + |> done + end + + defp extract_contents(%{entries: entries} = paged_contents) do entries = entries |> Repo.preload(@cited_preloads) |> Enum.map(&shape(&1)) Map.put(paged_contents, :entries, entries) diff --git a/lib/groupher_server/cms/delegates/helper.ex b/lib/groupher_server/cms/delegates/helper.ex index 9ac198f1d..52f723643 100644 --- a/lib/groupher_server/cms/delegates/helper.ex +++ b/lib/groupher_server/cms/delegates/helper.ex @@ -10,7 +10,7 @@ defmodule GroupherServer.CMS.Delegate.Helper do alias Helper.{ORM, QueryBuilder} alias GroupherServer.{Accounts, Repo, CMS} - alias CMS.Model.{ArticleUpvote, ArticleCollect} + alias CMS.Model.{ArticleUpvote, ArticleCollect, Comment} alias Accounts.Model.User @default_article_meta CMS.Model.Embeds.ArticleMeta.default_meta() @@ -21,6 +21,9 @@ defmodule GroupherServer.CMS.Delegate.Helper do @supported_emotions get_config(:article, :emotions) @supported_comment_emotions get_config(:article, :comment_emotions) + def preload_author(%Comment{} = comment), do: comment + def preload_author(article), do: Repo.preload(article, author: :user) + ####### # emotion related ####### diff --git a/lib/groupher_server/cms/delegates/hooks/cite.ex b/lib/groupher_server/cms/delegates/hooks/cite.ex index 75244205e..fd6aaae95 100644 --- a/lib/groupher_server/cms/delegates/hooks/cite.ex +++ b/lib/groupher_server/cms/delegates/hooks/cite.ex @@ -24,15 +24,20 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do """ import Ecto.Query, warn: false - import Helper.Utils, only: [get_config: 2, thread_of_article: 1, done: 1] - import GroupherServer.CMS.Delegate.Hooks.Helper, only: [merge_same_block_linker: 2] + import Helper.Utils, only: [get_config: 2, thread_of_article: 1] import GroupherServer.CMS.Helper.Matcher + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] + import GroupherServer.CMS.Delegate.Hooks.Helper, only: [merge_same_block_linker: 2] + + import GroupherServer.CMS.Delegate.CitedContent, + only: [batch_delete_cited_contents: 1, batch_insert_cited_contents: 1] + import Helper.ErrorCode alias GroupherServer.{CMS, Repo} - alias CMS.Model.{CitedContent, Comment} - alias Helper.ORM + alias CMS.Model.Comment + alias Helper.ORM alias Ecto.Multi @site_host get_config(:general, :site_host) @@ -44,75 +49,19 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do content <- preload_author(content) do Multi.new() |> Multi.run(:delete_all_cited_contents, fn _, _ -> - delete_all_cited_contents(content) + batch_delete_cited_contents(content) end) |> Multi.run(:update_cited_info, fn _, _ -> blocks - |> Enum.reduce([], &(&2 ++ parse_cited_info_per_block(content, &1))) + |> Enum.reduce([], &(&2 ++ parse_cited_per_block(content, &1))) |> merge_same_block_linker(:cited_by_id) - |> update_cited_info + |> batch_insert_cited_contents end) |> Repo.transaction() |> result() end end - def preload_author(%Comment{} = comment), do: comment - def preload_author(article), do: Repo.preload(article, author: :user) - - # delete all records before insert_all, this will dynamiclly update - # those cited info when update article - # 插入引用记录之前先全部清除,这样可以在更新文章的时候自动计算引用信息 - defp delete_all_cited_contents(%Comment{} = comment) do - query = from(c in CitedContent, where: c.comment_id == ^comment.id) - ORM.delete_all(query, :if_exist) - end - - defp delete_all_cited_contents(article) do - with {:ok, thread} <- thread_of_article(article), - {:ok, info} <- match(thread) do - thread = thread |> to_string |> String.upcase() - - query = - from(c in CitedContent, - where: field(c, ^info.foreign_key) == ^article.id and c.cited_by_type == ^thread - ) - - ORM.delete_all(query, :if_exist) - end - end - - # batch insert CitedContent record and update citing count - defp update_cited_info(cited_contents) do - # see: https://github.com/elixir-ecto/ecto/issues/1932#issuecomment-314083252 - clean_cited_contents = - cited_contents - |> Enum.map(&(&1 |> Map.merge(%{inserted_at: &1.citing_time, updated_at: &1.citing_time}))) - |> Enum.map(&Map.delete(&1, :cited_content)) - |> Enum.map(&Map.delete(&1, :citing_time)) - - case {0, nil} !== Repo.insert_all(CitedContent, clean_cited_contents) do - true -> update_citing_count(cited_contents) - false -> {:error, "insert cited content error"} - end - end - - defp update_citing_count(cited_contents) do - Enum.all?(cited_contents, fn content -> - count_query = from(c in CitedContent, where: c.cited_by_id == ^content.cited_by_id) - count = Repo.aggregate(count_query, :count) - - cited_content = content.cited_content - meta = Map.merge(cited_content.meta, %{citing_count: count}) - - case cited_content |> ORM.update_meta(meta) do - {:ok, _} -> true - {:error, _} -> false - end - end) - |> done - end - @doc """ return fmt like: [ @@ -127,17 +76,17 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do ... ] """ - defp parse_cited_info_per_block(content, %{"id" => block_id, "data" => %{"text" => text}}) do + defp parse_cited_per_block(content, %{"id" => block_id, "data" => %{"text" => text}}) do links = Floki.find(text, "a[href]") - do_parse_cited_info_per_block(content, block_id, links) + parse_links_in_block(content, block_id, links) end # links Floki parsed fmt # content means both article and comment # e.g: # [{"a", [{"href", "https://coderplanets.com/post/195675"}], []},] - defp do_parse_cited_info_per_block(content, block_id, links) do + defp parse_links_in_block(content, block_id, links) do Enum.reduce(links, [], fn link, acc -> case parse_valid_cited(content.id, link) do {:ok, cited} -> List.insert_at(acc, 0, shape(content, cited, block_id)) @@ -149,24 +98,20 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do # parse cited with check if citing link is point to itself defp parse_valid_cited(content_id, link) do - with {:ok, cited} <- parse_cited(link), - %{content: content} <- cited do - case content.id !== content_id do + with {:ok, cited} <- parse_cited_in_link(link) do + case not is_citing_itself?(content_id, cited) do true -> {:ok, cited} - false -> {:error, "citing itself"} + false -> {:error, "citing itself, ignored"} end end end # return fmt: %{type: :comment | :article, content: %Comment{} | Article} # 要考虑是否有 comment_id 的情况,如果有,那么 就应该 load comment 而不是 article - defp parse_cited({"a", attrs, _}) do + defp parse_cited_in_link({"a", attrs, _}) do with {:ok, link} <- parse_link(attrs), true <- is_site_article_link?(link) do - # IO.inspect(link, label: "parse link") - # IO.inspect(is_comment_link?(link), label: "is_comment_link") - - case is_comment_link?(link) do + case is_link_for_comment?(link) do true -> load_cited_comment_from_url(link) false -> load_cited_article_from_url(link) end @@ -188,17 +133,6 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do end end - # 检测是否是站内文章的链接 - defp is_site_article_link?(url) do - Enum.any?(@valid_article_prefix, &String.starts_with?(url, &1)) - end - - defp is_comment_link?(url) do - with %{query: query} <- URI.parse(url) do - not is_nil(query) and String.starts_with?(query, "comment_id=") - end - end - defp load_cited_comment_from_url(url) do %{query: query} = URI.parse(url) @@ -227,6 +161,20 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do end end + # check if article/comment id is point to itself + defp is_citing_itself?(content_id, %{content: %{id: id}}), do: content_id == id + + # 检测是否是站内文章的链接 + defp is_site_article_link?(url) do + Enum.any?(@valid_article_prefix, &String.starts_with?(url, &1)) + end + + defp is_link_for_comment?(url) do + with %{query: query} <- URI.parse(url) do + not is_nil(query) and String.starts_with?(query, "comment_id=") + end + end + # cite article in comment # 在评论中引用文章 defp shape(%Comment{} = comment, %{type: :article, content: cited}, block_id) do diff --git a/lib/groupher_server/delivery/delegates/mention.ex b/lib/groupher_server/delivery/delegates/mention.ex index 304517d56..ced03c99a 100644 --- a/lib/groupher_server/delivery/delegates/mention.ex +++ b/lib/groupher_server/delivery/delegates/mention.ex @@ -33,10 +33,10 @@ defmodule GroupherServer.Delivery.Delegate.Mention do def batch_mention(%Comment{} = comment, contents, %User{} = from_user) do Multi.new() - |> Multi.run(:batch_delete_related_mentions, fn _, _ -> - delete_related_mentions(comment, from_user) + |> Multi.run(:batch_delete_mentions, fn _, _ -> + batch_delete_mentions(comment, from_user) end) - |> Multi.run(:batch_insert_related_mentions, fn _, _ -> + |> Multi.run(:batch_insert_mentions, fn _, _ -> case {0, nil} !== Repo.insert_all(Mention, contents) do true -> {:ok, :pass} false -> {:error, "insert mentions error"} @@ -48,10 +48,10 @@ defmodule GroupherServer.Delivery.Delegate.Mention do def batch_mention(article, contents, %User{} = from_user) do Multi.new() - |> Multi.run(:batch_delete_related_mentions, fn _, _ -> - delete_related_mentions(article, from_user) + |> Multi.run(:batch_delete_mentions, fn _, _ -> + batch_delete_mentions(article, from_user) end) - |> Multi.run(:batch_insert_related_mentions, fn _, _ -> + |> Multi.run(:batch_insert_mentions, fn _, _ -> case {0, nil} !== Repo.insert_all(Mention, contents) do true -> {:ok, :pass} false -> {:error, "insert mentions error"} @@ -61,7 +61,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do |> result() end - defp delete_related_mentions(%Comment{} = comment, %User{} = from_user) do + defp batch_delete_mentions(%Comment{} = comment, %User{} = from_user) do from(m in Mention, where: m.comment_id == ^comment.id, where: m.from_user_id == ^from_user.id @@ -69,7 +69,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do |> ORM.delete_all(:if_exist) end - defp delete_related_mentions(article, %User{} = from_user) do + defp batch_delete_mentions(article, %User{} = from_user) do with {:ok, thread} <- thread_of_article(article), {:ok, info} <- match(thread) do thread = thread |> to_string |> String.upcase() @@ -94,7 +94,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do |> done() end - def extract_contents(%{entries: entries} = paged_contents) do + defp extract_contents(%{entries: entries} = paged_contents) do entries = entries |> Repo.preload(:from_user) |> Enum.map(&shape(&1)) Map.put(paged_contents, :entries, entries) @@ -118,7 +118,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do |> Map.put(:user, user) end - defp result({:ok, %{batch_insert_related_mentions: result}}), do: {:ok, result} + defp result({:ok, %{batch_insert_mentions: result}}), do: {:ok, result} defp result({:error, _, result, _steps}) do {:error, result} From db08ad8b2d4ff5ac263ce3a34d4683be02715db9 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Fri, 18 Jun 2021 11:38:48 +0800 Subject: [PATCH 11/54] refactor(delivery): fix dup case --- lib/groupher_server/cms/delegates/cited_content.ex | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/groupher_server/cms/delegates/cited_content.ex b/lib/groupher_server/cms/delegates/cited_content.ex index e99a0b424..07f7e0a22 100644 --- a/lib/groupher_server/cms/delegates/cited_content.ex +++ b/lib/groupher_server/cms/delegates/cited_content.ex @@ -70,11 +70,6 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do true -> update_content_citing_count(cited_contents) false -> {:error, "insert cited content error"} end - - case {0, nil} !== Repo.insert_all(CitedContent, clean_cited_contents) do - true -> update_content_citing_count(cited_contents) - false -> {:error, "insert cited content error"} - end end # update article/comment 's citting_count in meta From c0883b6b3664697bfa4fbe81f1386f2d5e076e7f Mon Sep 17 00:00:00 2001 From: mydearxym Date: Fri, 18 Jun 2021 12:39:13 +0800 Subject: [PATCH 12/54] refactor(delivery): wip --- lib/groupher_server/cms/delegates/helper.ex | 4 +-- .../cms/delegates/hooks/cite.ex | 10 +++++-- .../cms/delegates/hooks/mention.ex | 30 ++++++++++++++----- lib/helper/utils/utils.ex | 4 +++ .../cms/hooks/mention_in_post_test.exs | 15 ++++++++-- .../groupher_server/delivery/mention_test.exs | 3 -- 6 files changed, 47 insertions(+), 19 deletions(-) diff --git a/lib/groupher_server/cms/delegates/helper.ex b/lib/groupher_server/cms/delegates/helper.ex index 52f723643..d9a682838 100644 --- a/lib/groupher_server/cms/delegates/helper.ex +++ b/lib/groupher_server/cms/delegates/helper.ex @@ -21,8 +21,8 @@ defmodule GroupherServer.CMS.Delegate.Helper do @supported_emotions get_config(:article, :emotions) @supported_comment_emotions get_config(:article, :comment_emotions) - def preload_author(%Comment{} = comment), do: comment - def preload_author(article), do: Repo.preload(article, author: :user) + def preload_author(%Comment{} = comment), do: comment |> done + def preload_author(article), do: Repo.preload(article, author: :user) |> done ####### # emotion related diff --git a/lib/groupher_server/cms/delegates/hooks/cite.ex b/lib/groupher_server/cms/delegates/hooks/cite.ex index fd6aaae95..5574b3470 100644 --- a/lib/groupher_server/cms/delegates/hooks/cite.ex +++ b/lib/groupher_server/cms/delegates/hooks/cite.ex @@ -46,7 +46,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do def handle(%{body: body} = content) do with {:ok, %{"blocks" => blocks}} <- Jason.decode(body), - content <- preload_author(content) do + {:ok, content} <- preload_author(content) do Multi.new() |> Multi.run(:delete_all_cited_contents, fn _, _ -> batch_delete_cited_contents(content) @@ -178,9 +178,11 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do # cite article in comment # 在评论中引用文章 defp shape(%Comment{} = comment, %{type: :article, content: cited}, block_id) do + cited_by_type = cited.meta.thread |> to_string |> String.upcase() + %{ cited_by_id: cited.id, - cited_by_type: cited.meta.thread, + cited_by_type: cited_by_type, comment_id: comment.id, block_linker: [block_id], user_id: comment.author_id, @@ -215,9 +217,11 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do {:ok, thread} = thread_of_article(article) {:ok, info} = match(thread) + cited_by_type = cited.meta.thread |> to_string |> String.upcase() + %{ cited_by_id: cited.id, - cited_by_type: cited.meta.thread, + cited_by_type: cited_by_type, block_linker: [block_id], user_id: article.author.user.id, # extra fields for next-step usage diff --git a/lib/groupher_server/cms/delegates/hooks/mention.ex b/lib/groupher_server/cms/delegates/hooks/mention.ex index 86678d033..eecb395d2 100644 --- a/lib/groupher_server/cms/delegates/hooks/mention.ex +++ b/lib/groupher_server/cms/delegates/hooks/mention.ex @@ -24,10 +24,12 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do """ import Ecto.Query, warn: false - import Helper.Utils, only: [get_config: 2, thread_of_article: 1, done: 1] + import Helper.Utils, only: [get_config: 2, thread_of_article: 2, done: 1] + + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] import GroupherServer.CMS.Delegate.Hooks.Helper, only: [merge_same_block_linker: 2] - alias GroupherServer.{Accounts, CMS, Repo} + alias GroupherServer.{Accounts, CMS, Delivery, Repo} alias CMS.Model.Comment @article_threads get_config(:article, :threads) @@ -36,16 +38,23 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do def handle(%{body: body} = content) do with {:ok, %{"blocks" => blocks}} <- Jason.decode(body), - content <- preload_author(content) do + {:ok, content} <- preload_author(content) do blocks |> Enum.reduce([], &(&2 ++ parse_cited_info_per_block(content, &1))) |> merge_same_block_linker(:to_user_id) - |> done + |> batch_mention(content) end end - def preload_author(%Comment{} = comment), do: comment - def preload_author(article), do: Repo.preload(article, author: :user) + # contents list of mention fmt args + defp batch_mention(_contents, %Comment{} = _comment) do + {:ok, :pass} + end + + defp batch_mention(contents, article) do + from_user = article.author.user + Delivery.batch_mention(article, contents, from_user) + end defp parse_cited_info_per_block(content, %{"id" => block_id, "data" => %{"text" => text}}) do mentions = Floki.find(text, ".#{@article_mention_class}") @@ -75,6 +84,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do defp shape(%Comment{} = comment, mention_user_id, block_id) do # @article_threads |> Enum.find(fn thread -> not is_nil(Map.get(comment, :"#{thread}_id")) end) %{ + type: "COMMENT", block_linker: [block_id], read: false, from_user_id: comment.author_id, @@ -83,14 +93,18 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do end defp shape(article, to_user_id, block_id) do + {:ok, thread} = thread_of_article(article, :upcase) + %{ - type: thread_of_article(article), + type: thread, title: article.title, article_id: article.id, block_linker: [block_id], read: false, from_user_id: article.author.user_id, - to_user_id: to_user_id + to_user_id: to_user_id, + inserted_at: article.updated_at |> DateTime.truncate(:second), + updated_at: article.updated_at |> DateTime.truncate(:second) } end end diff --git a/lib/helper/utils/utils.ex b/lib/helper/utils/utils.ex index 34cacb414..ff2916061 100644 --- a/lib/helper/utils/utils.ex +++ b/lib/helper/utils/utils.ex @@ -217,6 +217,10 @@ defmodule Helper.Utils do def thread_of_article(_), do: {:error, "invalid article"} + def thread_of_article(%{meta: %{thread: thread}}, :upcase) do + thread |> to_string |> String.upcase() |> done + end + def uid(str_len \\ 5) do Nanoid.generate(str_len, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") end diff --git a/test/groupher_server/cms/hooks/mention_in_post_test.exs b/test/groupher_server/cms/hooks/mention_in_post_test.exs index f61022531..f868f2f17 100644 --- a/test/groupher_server/cms/hooks/mention_in_post_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_post_test.exs @@ -2,9 +2,10 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do use GroupherServer.TestTools import Helper.Utils, only: [get_config: 2] + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] alias Helper.ORM - alias GroupherServer.CMS + alias GroupherServer.{CMS, Delivery} alias CMS.Model.{Comment} alias CMS.Delegate.Hooks @@ -39,10 +40,18 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do post_attrs = post_attrs |> Map.merge(%{body: body}) {:ok, post} = CMS.create_article(community, :post, post_attrs, user) + {:ok, post} = preload_author(post) - {:ok, result} = Hooks.Mention.handle(post) + {:ok, _result} = Hooks.Mention.handle(post) - assert length(result) == 2 + {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + + mention = result.entries |> List.first() + assert mention.article_id == post.id + assert mention.title == post.title + assert mention.user.login == post.author.user.login + + IO.inspect(result, label: "the result") end end end diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index 3aacfd764..95f6869d8 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -32,7 +32,6 @@ defmodule GroupherServer.Test.Delivery.Mention do end describe "mentions" do - @tag :wip test "can batch send mentions", ~m(post user user2 mention_contents)a do {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user) {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) @@ -44,7 +43,6 @@ defmodule GroupherServer.Test.Delivery.Mention do assert mention.user.login == user.login end - @tag :wip test "mention multiable times on same article, will only have one record", ~m(post user user2 mention_contents)a do {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user) @@ -58,7 +56,6 @@ defmodule GroupherServer.Test.Delivery.Mention do assert result.total_count == 1 end - @tag :wip test "if mention before, update with no mention content will not do mention in final", ~m(post user user2 user3 mention_contents)a do {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user) From 05f5e6f1f42317809dc55474d17e2f218a2298d1 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Fri, 18 Jun 2021 15:13:08 +0800 Subject: [PATCH 13/54] refactor(delivery): mention wip --- .../cms/delegates/cited_content.ex | 2 + lib/groupher_server/cms/delegates/helper.ex | 19 ++++++- .../cms/delegates/hooks/mention.ex | 48 +++++++++++------ .../delivery/delegates/mention.ex | 2 + .../cms/hooks/mention_in_post_test.exs | 54 +++++++++++++++++-- 5 files changed, 104 insertions(+), 21 deletions(-) diff --git a/lib/groupher_server/cms/delegates/cited_content.ex b/lib/groupher_server/cms/delegates/cited_content.ex index 07f7e0a22..bbff77b55 100644 --- a/lib/groupher_server/cms/delegates/cited_content.ex +++ b/lib/groupher_server/cms/delegates/cited_content.ex @@ -55,6 +55,8 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do end @doc "batch insert CitedContent record and update citing count" + def batch_insert_cited_contents([]), do: [] + def batch_insert_cited_contents(cited_contents) do # 注意这里多了 cited_content 和 citting_time # cited_content 是为了下一步更新 citting_count 预先加载的,避免单独 preload 消耗性能 diff --git a/lib/groupher_server/cms/delegates/helper.ex b/lib/groupher_server/cms/delegates/helper.ex index d9a682838..d6dedb47a 100644 --- a/lib/groupher_server/cms/delegates/helper.ex +++ b/lib/groupher_server/cms/delegates/helper.ex @@ -21,9 +21,26 @@ defmodule GroupherServer.CMS.Delegate.Helper do @supported_emotions get_config(:article, :emotions) @supported_comment_emotions get_config(:article, :comment_emotions) - def preload_author(%Comment{} = comment), do: comment |> done + def preload_author(%Comment{} = comment), do: Repo.preload(comment, :author) |> done def preload_author(article), do: Repo.preload(article, author: :user) |> done + @doc "get author of article or comment" + def author_of(%Comment{} = comment) do + case Ecto.assoc_loaded?(comment.author) do + true -> comment.author + false -> Repo.preload(comment, :author) |> Map.get(:author) + end + |> done + end + + def author_of(article) do + case Ecto.assoc_loaded?(article.author) do + true -> article.author.user + false -> Repo.preload(article, author: :user) |> get_in([:author, :user]) + end + |> done + end + ####### # emotion related ####### diff --git a/lib/groupher_server/cms/delegates/hooks/mention.ex b/lib/groupher_server/cms/delegates/hooks/mention.ex index eecb395d2..25368e4d9 100644 --- a/lib/groupher_server/cms/delegates/hooks/mention.ex +++ b/lib/groupher_server/cms/delegates/hooks/mention.ex @@ -24,9 +24,9 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do """ import Ecto.Query, warn: false - import Helper.Utils, only: [get_config: 2, thread_of_article: 2, done: 1] + import Helper.Utils, only: [get_config: 2, thread_of_article: 2] - import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1, author_of: 1] import GroupherServer.CMS.Delegate.Hooks.Helper, only: [merge_same_block_linker: 2] alias GroupherServer.{Accounts, CMS, Delivery, Repo} @@ -40,15 +40,16 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do with {:ok, %{"blocks" => blocks}} <- Jason.decode(body), {:ok, content} <- preload_author(content) do blocks - |> Enum.reduce([], &(&2 ++ parse_cited_info_per_block(content, &1))) + |> Enum.reduce([], &(&2 ++ parse_mention_info_per_block(content, &1))) |> merge_same_block_linker(:to_user_id) |> batch_mention(content) end end # contents list of mention fmt args - defp batch_mention(_contents, %Comment{} = _comment) do - {:ok, :pass} + defp batch_mention(contents, %Comment{} = comment) do + from_user = comment.author + Delivery.batch_mention(comment, contents, from_user) end defp batch_mention(contents, article) do @@ -56,19 +57,19 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do Delivery.batch_mention(article, contents, from_user) end - defp parse_cited_info_per_block(content, %{"id" => block_id, "data" => %{"text" => text}}) do + defp parse_mention_info_per_block(content, %{"id" => block_id, "data" => %{"text" => text}}) do mentions = Floki.find(text, ".#{@article_mention_class}") - do_parse_cited_info_per_block(content, block_id, mentions) + parse_mention_in_block(content, block_id, mentions) end - # links Floki parsed fmt + # mentions Floki parsed fmt # content means both article and comment # e.g: - # [{"a", [{"href", "https://coderplanets.com/post/195675"}], []},] - defp do_parse_cited_info_per_block(content, block_id, mentions) do + # [{"div", [{"class", "cdx-mention"}], ["penelope438"]}] + defp parse_mention_in_block(content, block_id, mentions) do Enum.reduce(mentions, [], fn mention, acc -> - case parse_mention_user_id(mention) do + case parse_mention_user_id(content, mention) do {:ok, user_id} -> List.insert_at(acc, 0, shape(content, user_id, block_id)) {:error, _} -> acc end @@ -76,19 +77,34 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do |> Enum.uniq() end - # 确保 mention 的用户是存在的 - defp parse_mention_user_id({_, _, [user_login]}) do - Accounts.get_userid_and_cache(user_login) + # make sure mention user is exsit and not author self + # 确保 mention 的用户是存在的, 并且不是在提及自己 + defp parse_mention_user_id(content, {_, _, [user_login]}) do + with {:ok, author} <- author_of(content), + {:ok, user_id} <- Accounts.get_userid_and_cache(user_login) do + case author.id !== user_id do + true -> {:ok, user_id} + false -> {:error, "mention yourself, ignored"} + end + end end defp shape(%Comment{} = comment, mention_user_id, block_id) do - # @article_threads |> Enum.find(fn thread -> not is_nil(Map.get(comment, :"#{thread}_id")) end) + article_thread = @article_threads |> Enum.find(&(not is_nil(Map.get(comment, :"#{&1}_id")))) + comment = Repo.preload(comment, article_thread) + parent_article = comment |> Map.get(article_thread) + %{ type: "COMMENT", + title: parent_article.title, + article_id: parent_article.id, + comment_id: comment.id, block_linker: [block_id], read: false, from_user_id: comment.author_id, - to_user_id: mention_user_id + to_user_id: mention_user_id, + inserted_at: comment.updated_at |> DateTime.truncate(:second), + updated_at: comment.updated_at |> DateTime.truncate(:second) } end diff --git a/lib/groupher_server/delivery/delegates/mention.ex b/lib/groupher_server/delivery/delegates/mention.ex index ced03c99a..21bf56d93 100644 --- a/lib/groupher_server/delivery/delegates/mention.ex +++ b/lib/groupher_server/delivery/delegates/mention.ex @@ -31,6 +31,8 @@ defmodule GroupherServer.Delivery.Delegate.Mention do } """ + def batch_mention(_, [], _), do: {:ok, :pass} + def batch_mention(%Comment{} = comment, contents, %User{} = from_user) do Multi.new() |> Multi.run(:batch_delete_mentions, fn _, _ -> diff --git a/test/groupher_server/cms/hooks/mention_in_post_test.exs b/test/groupher_server/cms/hooks/mention_in_post_test.exs index f868f2f17..d40781730 100644 --- a/test/groupher_server/cms/hooks/mention_in_post_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_post_test.exs @@ -4,10 +4,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do import Helper.Utils, only: [get_config: 2] import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] - alias Helper.ORM alias GroupherServer.{CMS, Delivery} - - alias CMS.Model.{Comment} alias CMS.Delegate.Hooks @site_host get_config(:general, :site_host) @@ -47,11 +44,60 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) mention = result.entries |> List.first() + assert mention.type == "POST" + assert mention.block_linker |> length == 2 + assert mention.article_id == post.id + assert mention.title == post.title + assert mention.user.login == post.author.user.login + + {:ok, result} = Delivery.paged_mentions(user3, %{page: 1, size: 10}) + + mention = result.entries |> List.first() + assert mention.type == "POST" + assert mention.block_linker |> length == 1 assert mention.article_id == post.id assert mention.title == post.title assert mention.user.login == post.author.user.login + end + + @tag :wip + test "mention in post's comment should work", ~m(user user2 post)a do + comment_body = + mock_rich_text(~s(hi
#{user2.login}
)) + + {:ok, comment} = CMS.create_comment(:post, post.id, comment_body, user) + {:ok, comment} = preload_author(comment) + + {:ok, _result} = Hooks.Mention.handle(comment) + {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + + mention = result.entries |> List.first() + assert mention.type == "COMMENT" + assert mention.comment_id == comment.id + assert mention.block_linker |> length == 1 + assert mention.article_id == post.id + assert mention.title == post.title + assert mention.user.login == comment.author.login + end + + @tag :wip + test "can not mention author self in post or comment", ~m(community user post_attrs)a do + body = mock_rich_text(~s(hi
#{user.login}
)) + post_attrs = post_attrs |> Map.merge(%{body: body}) + {:ok, post} = CMS.create_article(community, :post, post_attrs, user) + + {:ok, result} = Delivery.paged_mentions(user, %{page: 1, size: 10}) + assert result.total_count == 0 + + comment_body = + mock_rich_text(~s(hi
#{user.login}
)) + + {:ok, comment} = CMS.create_comment(:post, post.id, comment_body, user) + + {:ok, _result} = Hooks.Mention.handle(comment) + {:ok, result} = Delivery.paged_mentions(user, %{page: 1, size: 10}) - IO.inspect(result, label: "the result") + assert result.total_count == 0 end end end From 509c7178d759811b53d0cae36efdca61f770d6a5 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Fri, 18 Jun 2021 15:24:08 +0800 Subject: [PATCH 14/54] refactor(delivery): cite fix --- lib/groupher_server/cms/delegates/cited_content.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/groupher_server/cms/delegates/cited_content.ex b/lib/groupher_server/cms/delegates/cited_content.ex index bbff77b55..ce67f6280 100644 --- a/lib/groupher_server/cms/delegates/cited_content.ex +++ b/lib/groupher_server/cms/delegates/cited_content.ex @@ -55,7 +55,7 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do end @doc "batch insert CitedContent record and update citing count" - def batch_insert_cited_contents([]), do: [] + def batch_insert_cited_contents([]), do: {:ok, :pass} def batch_insert_cited_contents(cited_contents) do # 注意这里多了 cited_content 和 citting_time From 4dd027d043687ec81bffb204b0c9a37c7b8ebc15 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Fri, 18 Jun 2021 15:29:49 +0800 Subject: [PATCH 15/54] refactor(delivery): more test on mention --- .../cms/hooks/mention_in_blog_test.exs | 103 ++++++++++++++++++ .../cms/hooks/mention_in_job_test.exs | 103 ++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 test/groupher_server/cms/hooks/mention_in_blog_test.exs create mode 100644 test/groupher_server/cms/hooks/mention_in_job_test.exs diff --git a/test/groupher_server/cms/hooks/mention_in_blog_test.exs b/test/groupher_server/cms/hooks/mention_in_blog_test.exs new file mode 100644 index 000000000..190854d13 --- /dev/null +++ b/test/groupher_server/cms/hooks/mention_in_blog_test.exs @@ -0,0 +1,103 @@ +defmodule GroupherServer.Test.CMS.Hooks.MentionInBlog do + use GroupherServer.TestTools + + import Helper.Utils, only: [get_config: 2] + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] + + alias GroupherServer.{CMS, Delivery} + alias CMS.Delegate.Hooks + + @site_host get_config(:general, :site_host) + + @article_mention_class "cdx-mention" + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, user3} = db_insert(:user) + {:ok, blog} = db_insert(:blog) + + {:ok, community} = db_insert(:community) + + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + + {:ok, ~m(user user2 user3 community blog blog_attrs)a} + end + + describe "[mention in blog basic]" do + @tag :wip + test "mention multi user in blog should work", ~m(user user2 user3 community blog_attrs)a do + body = + mock_rich_text( + ~s(hi
#{user2.login}
, and
#{user3.login}
), + ~s(hi
#{user2.login}
) + ) + + blog_attrs = blog_attrs |> Map.merge(%{body: body}) + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, blog} = preload_author(blog) + + {:ok, _result} = Hooks.Mention.handle(blog) + + {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + + mention = result.entries |> List.first() + assert mention.type == "BLOG" + assert mention.block_linker |> length == 2 + assert mention.article_id == blog.id + assert mention.title == blog.title + assert mention.user.login == blog.author.user.login + + {:ok, result} = Delivery.paged_mentions(user3, %{page: 1, size: 10}) + + mention = result.entries |> List.first() + assert mention.type == "BLOG" + assert mention.block_linker |> length == 1 + assert mention.article_id == blog.id + assert mention.title == blog.title + assert mention.user.login == blog.author.user.login + end + + @tag :wip + test "mention in blog's comment should work", ~m(user user2 blog)a do + comment_body = + mock_rich_text(~s(hi
#{user2.login}
)) + + {:ok, comment} = CMS.create_comment(:blog, blog.id, comment_body, user) + {:ok, comment} = preload_author(comment) + + {:ok, _result} = Hooks.Mention.handle(comment) + {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + + mention = result.entries |> List.first() + assert mention.type == "COMMENT" + assert mention.comment_id == comment.id + assert mention.block_linker |> length == 1 + assert mention.article_id == blog.id + assert mention.title == blog.title + assert mention.user.login == comment.author.login + end + + @tag :wip + test "can not mention author self in blog or comment", ~m(community user blog_attrs)a do + body = mock_rich_text(~s(hi
#{user.login}
)) + blog_attrs = blog_attrs |> Map.merge(%{body: body}) + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + + {:ok, result} = Delivery.paged_mentions(user, %{page: 1, size: 10}) + assert result.total_count == 0 + + comment_body = + mock_rich_text(~s(hi
#{user.login}
)) + + {:ok, comment} = CMS.create_comment(:blog, blog.id, comment_body, user) + + {:ok, _result} = Hooks.Mention.handle(comment) + {:ok, result} = Delivery.paged_mentions(user, %{page: 1, size: 10}) + + assert result.total_count == 0 + end + end +end diff --git a/test/groupher_server/cms/hooks/mention_in_job_test.exs b/test/groupher_server/cms/hooks/mention_in_job_test.exs new file mode 100644 index 000000000..945f877a6 --- /dev/null +++ b/test/groupher_server/cms/hooks/mention_in_job_test.exs @@ -0,0 +1,103 @@ +defmodule GroupherServer.Test.CMS.Hooks.MentionInJob do + use GroupherServer.TestTools + + import Helper.Utils, only: [get_config: 2] + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] + + alias GroupherServer.{CMS, Delivery} + alias CMS.Delegate.Hooks + + @site_host get_config(:general, :site_host) + + @article_mention_class "cdx-mention" + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, user3} = db_insert(:user) + {:ok, job} = db_insert(:job) + + {:ok, community} = db_insert(:community) + + job_attrs = mock_attrs(:job, %{community_id: community.id}) + + {:ok, ~m(user user2 user3 community job job_attrs)a} + end + + describe "[mention in job basic]" do + @tag :wip + test "mention multi user in job should work", ~m(user user2 user3 community job_attrs)a do + body = + mock_rich_text( + ~s(hi
#{user2.login}
, and
#{user3.login}
), + ~s(hi
#{user2.login}
) + ) + + job_attrs = job_attrs |> Map.merge(%{body: body}) + {:ok, job} = CMS.create_article(community, :job, job_attrs, user) + {:ok, job} = preload_author(job) + + {:ok, _result} = Hooks.Mention.handle(job) + + {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + + mention = result.entries |> List.first() + assert mention.type == "JOB" + assert mention.block_linker |> length == 2 + assert mention.article_id == job.id + assert mention.title == job.title + assert mention.user.login == job.author.user.login + + {:ok, result} = Delivery.paged_mentions(user3, %{page: 1, size: 10}) + + mention = result.entries |> List.first() + assert mention.type == "JOB" + assert mention.block_linker |> length == 1 + assert mention.article_id == job.id + assert mention.title == job.title + assert mention.user.login == job.author.user.login + end + + @tag :wip + test "mention in job's comment should work", ~m(user user2 job)a do + comment_body = + mock_rich_text(~s(hi
#{user2.login}
)) + + {:ok, comment} = CMS.create_comment(:job, job.id, comment_body, user) + {:ok, comment} = preload_author(comment) + + {:ok, _result} = Hooks.Mention.handle(comment) + {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + + mention = result.entries |> List.first() + assert mention.type == "COMMENT" + assert mention.comment_id == comment.id + assert mention.block_linker |> length == 1 + assert mention.article_id == job.id + assert mention.title == job.title + assert mention.user.login == comment.author.login + end + + @tag :wip + test "can not mention author self in job or comment", ~m(community user job_attrs)a do + body = mock_rich_text(~s(hi
#{user.login}
)) + job_attrs = job_attrs |> Map.merge(%{body: body}) + {:ok, job} = CMS.create_article(community, :job, job_attrs, user) + + {:ok, result} = Delivery.paged_mentions(user, %{page: 1, size: 10}) + assert result.total_count == 0 + + comment_body = + mock_rich_text(~s(hi
#{user.login}
)) + + {:ok, comment} = CMS.create_comment(:job, job.id, comment_body, user) + + {:ok, _result} = Hooks.Mention.handle(comment) + {:ok, result} = Delivery.paged_mentions(user, %{page: 1, size: 10}) + + assert result.total_count == 0 + end + end +end From 3858123055c1c136f25d7bb25bc82bf938e18329 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sat, 19 Jun 2021 00:13:46 +0800 Subject: [PATCH 16/54] refactor(delivery): better naming --- lib/groupher_server/cms/cms.ex | 4 +- .../cms/delegates/cited_content.ex | 8 +-- .../cms/delegates/hooks/cite.ex | 58 +++++++++--------- .../cms/delegates/hooks/mention.ex | 60 ++++++------------- .../{cited_content.ex => cited_artiment.ex} | 14 ++--- lib/groupher_server/cms/models/post.ex | 2 +- .../delivery/delegates/mention.ex | 42 +++++-------- .../delivery/delegates/postman.ex | 11 ++++ lib/groupher_server/delivery/delivery.ex | 4 +- ...name_cited_contents_to_cited_artiments.exs | 9 +++ .../cms/hooks/cite_blog_test.exs | 6 +- .../cms/hooks/cite_job_test.exs | 6 +- .../cms/hooks/cite_post_test.exs | 6 +- .../groupher_server/delivery/mention_test.exs | 10 ++-- 14 files changed, 113 insertions(+), 127 deletions(-) rename lib/groupher_server/cms/models/{cited_content.ex => cited_artiment.ex} (78%) create mode 100644 lib/groupher_server/delivery/delegates/postman.ex create mode 100644 priv/repo/migrations/20210618160827_rename_cited_contents_to_cited_artiments.exs diff --git a/lib/groupher_server/cms/cms.ex b/lib/groupher_server/cms/cms.ex index d883a9935..f4a7a98b5 100644 --- a/lib/groupher_server/cms/cms.ex +++ b/lib/groupher_server/cms/cms.ex @@ -12,7 +12,7 @@ defmodule GroupherServer.CMS do ArticleCURD, ArticleCommunity, ArticleEmotion, - CitedContent, + CitedArtiment, CommentCurd, ArticleCollect, ArticleUpvote, @@ -97,7 +97,7 @@ defmodule GroupherServer.CMS do defdelegate sink_article(thread, id), to: ArticleCURD defdelegate undo_sink_article(thread, id), to: ArticleCURD - defdelegate paged_citing_contents(type, id, filter), to: CitedContent + defdelegate paged_citing_contents(type, id, filter), to: CitedArtiment defdelegate upvote_article(thread, article_id, user), to: ArticleUpvote defdelegate undo_upvote_article(thread, article_id, user), to: ArticleUpvote diff --git a/lib/groupher_server/cms/delegates/cited_content.ex b/lib/groupher_server/cms/delegates/cited_content.ex index ce67f6280..59114b389 100644 --- a/lib/groupher_server/cms/delegates/cited_content.ex +++ b/lib/groupher_server/cms/delegates/cited_content.ex @@ -37,12 +37,12 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do @doc "delete all records before insert_all, this will dynamiclly update" # those cited info when update article # 插入引用记录之前先全部清除,这样可以在更新文章的时候自动计算引用信息 - def batch_delete_cited_contents(%Comment{} = comment) do + def batch_delete_cited_artiments(%Comment{} = comment) do from(c in CitedContent, where: c.comment_id == ^comment.id) |> ORM.delete_all(:if_exist) end - def batch_delete_cited_contents(article) do + def batch_delete_cited_artiments(article) do with {:ok, thread} <- thread_of_article(article), {:ok, info} <- match(thread) do thread = thread |> to_string |> String.upcase() @@ -55,9 +55,9 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do end @doc "batch insert CitedContent record and update citing count" - def batch_insert_cited_contents([]), do: {:ok, :pass} + def batch_insert_cited_artiments([]), do: {:ok, :pass} - def batch_insert_cited_contents(cited_contents) do + def batch_insert_cited_artiments(cited_contents) do # 注意这里多了 cited_content 和 citting_time # cited_content 是为了下一步更新 citting_count 预先加载的,避免单独 preload 消耗性能 # citing_time 是因为 insert_all 必须要自己更新时间 diff --git a/lib/groupher_server/cms/delegates/hooks/cite.ex b/lib/groupher_server/cms/delegates/hooks/cite.ex index 5574b3470..047b9fded 100644 --- a/lib/groupher_server/cms/delegates/hooks/cite.ex +++ b/lib/groupher_server/cms/delegates/hooks/cite.ex @@ -16,10 +16,10 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do POST post_333 -> cited_article_333, [block_id, block2_id]] - cited_type, cited_content_id, [contents]_id, [block_id, cited_block_id], + cited_type, cited_artiment_id, [contents]_id, [block_id, cited_block_id], cited_type: thread or comment - content: article or comment + artiment: article or comment # cited_article_comment_id, [xxx_article]_id, [block_id, block2_id, ...], """ @@ -29,8 +29,8 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] import GroupherServer.CMS.Delegate.Hooks.Helper, only: [merge_same_block_linker: 2] - import GroupherServer.CMS.Delegate.CitedContent, - only: [batch_delete_cited_contents: 1, batch_insert_cited_contents: 1] + import GroupherServer.CMS.Delegate.CitedArtiment, + only: [batch_delete_cited_artiments: 1, batch_insert_cited_artiments: 1] import Helper.ErrorCode @@ -44,18 +44,18 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do @article_threads get_config(:article, :threads) @valid_article_prefix Enum.map(@article_threads, &"#{@site_host}/#{&1}/") - def handle(%{body: body} = content) do + def handle(%{body: body} = artiment) do with {:ok, %{"blocks" => blocks}} <- Jason.decode(body), - {:ok, content} <- preload_author(content) do + {:ok, artiment} <- preload_author(artiment) do Multi.new() - |> Multi.run(:delete_all_cited_contents, fn _, _ -> - batch_delete_cited_contents(content) + |> Multi.run(:delete_all_cited_artiments, fn _, _ -> + batch_delete_cited_artiments(artiment) end) |> Multi.run(:update_cited_info, fn _, _ -> blocks - |> Enum.reduce([], &(&2 ++ parse_cited_per_block(content, &1))) + |> Enum.reduce([], &(&2 ++ parse_cited_per_block(artiment, &1))) |> merge_same_block_linker(:cited_by_id) - |> batch_insert_cited_contents + |> batch_insert_cited_artiments end) |> Repo.transaction() |> result() @@ -69,27 +69,27 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do block_linker: ["block-ZgKJs"], cited_by_id: 190057, cited_by_type: "POST", - cited_content: #loaded, + cited_artiment: #loaded, post_id: 190059, user_id: 1413053 } ... ] """ - defp parse_cited_per_block(content, %{"id" => block_id, "data" => %{"text" => text}}) do + defp parse_cited_per_block(artiment, %{"id" => block_id, "data" => %{"text" => text}}) do links = Floki.find(text, "a[href]") - parse_links_in_block(content, block_id, links) + parse_links_in_block(artiment, block_id, links) end # links Floki parsed fmt - # content means both article and comment + # artiment means both article and comment # e.g: # [{"a", [{"href", "https://coderplanets.com/post/195675"}], []},] - defp parse_links_in_block(content, block_id, links) do + defp parse_links_in_block(artiment, block_id, links) do Enum.reduce(links, [], fn link, acc -> - case parse_valid_cited(content.id, link) do - {:ok, cited} -> List.insert_at(acc, 0, shape(content, cited, block_id)) + case parse_valid_cited(artiment.id, link) do + {:ok, cited} -> List.insert_at(acc, 0, shape(artiment, cited, block_id)) _ -> acc end end) @@ -106,7 +106,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do end end - # return fmt: %{type: :comment | :article, content: %Comment{} | Article} + # return fmt: %{type: :comment | :article, artiment: %Comment{} | Article} # 要考虑是否有 comment_id 的情况,如果有,那么 就应该 load comment 而不是 article defp parse_cited_in_link({"a", attrs, _}) do with {:ok, link} <- parse_link(attrs), @@ -140,7 +140,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do comment_id = URI.decode_query(query) |> Map.get("comment_id") with {:ok, comment} <- ORM.find(Comment, comment_id) do - {:ok, %{type: :comment, content: comment}} + {:ok, %{type: :comment, artiment: comment}} end rescue _ -> {:error, "load comment error"} @@ -157,12 +157,12 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do with {:ok, info} <- match(thread), {:ok, article} <- ORM.find(info.model, article_id) do - {:ok, %{type: :article, content: article}} + {:ok, %{type: :article, artiment: article}} end end # check if article/comment id is point to itself - defp is_citing_itself?(content_id, %{content: %{id: id}}), do: content_id == id + defp is_citing_itself?(content_id, %{artiment: %{id: id}}), do: content_id == id # 检测是否是站内文章的链接 defp is_site_article_link?(url) do @@ -177,7 +177,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do # cite article in comment # 在评论中引用文章 - defp shape(%Comment{} = comment, %{type: :article, content: cited}, block_id) do + defp shape(%Comment{} = comment, %{type: :article, artiment: cited}, block_id) do cited_by_type = cited.meta.thread |> to_string |> String.upcase() %{ @@ -188,7 +188,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do user_id: comment.author_id, # extra fields for next-step usage # used for updating citing_count, avoid load again - cited_content: cited, + cited_artiment: cited, # for later insert all citing_time: comment.updated_at |> DateTime.truncate(:second) } @@ -196,7 +196,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do # cite comment in comment # 评论中引用评论 - defp shape(%Comment{} = comment, %{type: :comment, content: cited}, block_id) do + defp shape(%Comment{} = comment, %{type: :comment, artiment: cited}, block_id) do %{ cited_by_id: cited.id, cited_by_type: "COMMENT", @@ -205,7 +205,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do user_id: comment.author_id, # extra fields for next-step usage # used for updating citing_count, avoid load again - cited_content: cited, + cited_artiment: cited, # for later insert all citing_time: comment.updated_at |> DateTime.truncate(:second) } @@ -213,7 +213,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do # cite article in article # 文章之间相互引用 - defp shape(article, %{type: :article, content: cited}, block_id) do + defp shape(article, %{type: :article, artiment: cited}, block_id) do {:ok, thread} = thread_of_article(article) {:ok, info} = match(thread) @@ -226,7 +226,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do user_id: article.author.user.id, # extra fields for next-step usage # used for updating citing_count, avoid load again - cited_content: cited, + cited_artiment: cited, # for later insert all citing_time: article.updated_at |> DateTime.truncate(:second) } @@ -235,7 +235,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do # cite comment in article # 文章中引用评论 - defp shape(article, %{type: :comment, content: cited}, block_id) do + defp shape(article, %{type: :comment, artiment: cited}, block_id) do {:ok, thread} = thread_of_article(article) {:ok, info} = match(thread) @@ -246,7 +246,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do user_id: article.author.user.id, # extra fields for next-step usage # used for updating citing_count, avoid load again - cited_content: cited, + cited_artiment: cited, # for later insert all citing_time: article.updated_at |> DateTime.truncate(:second) } diff --git a/lib/groupher_server/cms/delegates/hooks/mention.ex b/lib/groupher_server/cms/delegates/hooks/mention.ex index 25368e4d9..50c2c9547 100644 --- a/lib/groupher_server/cms/delegates/hooks/mention.ex +++ b/lib/groupher_server/cms/delegates/hooks/mention.ex @@ -1,28 +1,9 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do @moduledoc """ - run tasks in every article blocks if need + hooks for mention task - current task: "cite link" and "mention" - - ## cite link - - 我被站内哪些文章或评论引用了,是值得关注的事 - 我引用了谁不重要,帖子里链接已经表明了, 这和 github issue 的双向链接不一样,因为一般不需要关注这个 - 帖子是否解决,是否被 merge 等状态。 - - 基本结构: - - cited_thread, cited_article_id, [xxx_article]_id, [block_id, block2_id], - - POST post_333 -> cited_article_333, [block_id, block2_id]] - - cited_type, cited_content_id, [contents]_id, [block_id, cited_block_id], - - cited_type: thread or comment - content: article or comment - # cited_article_comment_id, [xxx_article]_id, [block_id, block2_id, ...], + parse and fmt(see shape function) mentions to Delivery module """ - import Ecto.Query, warn: false import Helper.Utils, only: [get_config: 2, thread_of_article: 2] @@ -36,41 +17,36 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do @article_mention_class "cdx-mention" - def handle(%{body: body} = content) do + def handle(%{body: body} = artiment) do with {:ok, %{"blocks" => blocks}} <- Jason.decode(body), - {:ok, content} <- preload_author(content) do + {:ok, artiment} <- preload_author(artiment) do blocks - |> Enum.reduce([], &(&2 ++ parse_mention_info_per_block(content, &1))) + |> Enum.reduce([], &(&2 ++ parse_mention_info_per_block(artiment, &1))) |> merge_same_block_linker(:to_user_id) - |> batch_mention(content) + |> handle_mentions(artiment) end end - # contents list of mention fmt args - defp batch_mention(contents, %Comment{} = comment) do - from_user = comment.author - Delivery.batch_mention(comment, contents, from_user) - end - - defp batch_mention(contents, article) do - from_user = article.author.user - Delivery.batch_mention(article, contents, from_user) + defp handle_mentions(mentions, artiment) do + with {:ok, author} <- author_of(artiment) do + Delivery.send(:mention, artiment, mentions, author) + end end - defp parse_mention_info_per_block(content, %{"id" => block_id, "data" => %{"text" => text}}) do + defp parse_mention_info_per_block(artiment, %{"id" => block_id, "data" => %{"text" => text}}) do mentions = Floki.find(text, ".#{@article_mention_class}") - parse_mention_in_block(content, block_id, mentions) + parse_mention_in_block(artiment, block_id, mentions) end # mentions Floki parsed fmt - # content means both article and comment + # artiment means both article and comment # e.g: # [{"div", [{"class", "cdx-mention"}], ["penelope438"]}] - defp parse_mention_in_block(content, block_id, mentions) do + defp parse_mention_in_block(artiment, block_id, mentions) do Enum.reduce(mentions, [], fn mention, acc -> - case parse_mention_user_id(content, mention) do - {:ok, user_id} -> List.insert_at(acc, 0, shape(content, user_id, block_id)) + case parse_mention_user_id(artiment, mention) do + {:ok, user_id} -> List.insert_at(acc, 0, shape(artiment, user_id, block_id)) {:error, _} -> acc end end) @@ -79,8 +55,8 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do # make sure mention user is exsit and not author self # 确保 mention 的用户是存在的, 并且不是在提及自己 - defp parse_mention_user_id(content, {_, _, [user_login]}) do - with {:ok, author} <- author_of(content), + defp parse_mention_user_id(artiment, {_, _, [user_login]}) do + with {:ok, author} <- author_of(artiment), {:ok, user_id} <- Accounts.get_userid_and_cache(user_login) do case author.id !== user_id do true -> {:ok, user_id} diff --git a/lib/groupher_server/cms/models/cited_content.ex b/lib/groupher_server/cms/models/cited_artiment.ex similarity index 78% rename from lib/groupher_server/cms/models/cited_content.ex rename to lib/groupher_server/cms/models/cited_artiment.ex index 545a8e58c..9d11232bb 100644 --- a/lib/groupher_server/cms/models/cited_content.ex +++ b/lib/groupher_server/cms/models/cited_artiment.ex @@ -1,4 +1,4 @@ -defmodule GroupherServer.CMS.Model.CitedContent do +defmodule GroupherServer.CMS.Model.CitedArtiment do @moduledoc false alias __MODULE__ @@ -19,8 +19,8 @@ defmodule GroupherServer.CMS.Model.CitedContent do @article_cast_fields general_article_fields(:cast) @optional_fields ~w(comment_id block_linker)a ++ @article_cast_fields - @type t :: %CitedContent{} - schema "cited_contents" do + @type t :: %CitedArtiment{} + schema "cited_artiments" do field(:cited_by_type, :string) field(:cited_by_id, :id) @@ -35,15 +35,15 @@ defmodule GroupherServer.CMS.Model.CitedContent do end @doc false - def changeset(%CitedContent{} = cited_content, attrs) do - cited_content + def changeset(%CitedArtiment{} = cited_artiment, attrs) do + cited_artiment |> cast(attrs, @optional_fields ++ @required_fields) |> validate_required(@required_fields) end @doc false - def update_changeset(%CitedContent{} = cited_content, attrs) do - cited_content + def update_changeset(%CitedArtiment{} = cited_artiment, attrs) do + cited_artiment |> cast(attrs, @optional_fields ++ @required_fields) end end diff --git a/lib/groupher_server/cms/models/post.ex b/lib/groupher_server/cms/models/post.ex index 5f2059e64..ff92b9c96 100644 --- a/lib/groupher_server/cms/models/post.ex +++ b/lib/groupher_server/cms/models/post.ex @@ -32,7 +32,7 @@ defmodule GroupherServer.CMS.Model.Post do # TODO: move to general_article_fields # embeds_one(:block_task_runner, Embeds.BlockTaskRunner, on_replace: :update) - # embeds_many(:citing_contents, CMS.CitedContent, on_replace: :delete) + # embeds_many(:citing_contents, CMS.CitedArtiment, on_replace: :delete) article_tags_field(:post) article_communities_field(:post) diff --git a/lib/groupher_server/delivery/delegates/mention.ex b/lib/groupher_server/delivery/delegates/mention.ex index 21bf56d93..7cf843b97 100644 --- a/lib/groupher_server/delivery/delegates/mention.ex +++ b/lib/groupher_server/delivery/delegates/mention.ex @@ -4,42 +4,33 @@ defmodule GroupherServer.Delivery.Delegate.Mention do """ import Ecto.Query, warn: false import Helper.Utils, only: [done: 1, thread_of_article: 1] - import GroupherServer.CMS.Helper.Matcher import ShortMaps alias GroupherServer.{Accounts, CMS, Delivery, Repo} alias Accounts.Model.User alias CMS.Model.Comment - alias Delivery.Model.{OldMention, Mention} + alias Delivery.Model.Mention - alias Delivery.Delegate.Utils alias Helper.ORM - alias Ecto.Multi - """ - %{ - type: "POST", # "COMMENT", - title: "article title", - id: 23, - block_linker: ["die"], - comment_id: 22, - read: false - from_user_id: ... - to_user_id: ... - } - """ + # 发送 + # Delivery.send(:mention, content, mentions, user) + # Delivery.send(:notify, content, mentions, user) + + # 用户侧取 + # Delivery.fetch(:mention) - def batch_mention(_, [], _), do: {:ok, :pass} + def handle(_, [], _), do: {:ok, :pass} - def batch_mention(%Comment{} = comment, contents, %User{} = from_user) do + def handle(%Comment{} = comment, mentions, %User{} = from_user) do Multi.new() |> Multi.run(:batch_delete_mentions, fn _, _ -> batch_delete_mentions(comment, from_user) end) |> Multi.run(:batch_insert_mentions, fn _, _ -> - case {0, nil} !== Repo.insert_all(Mention, contents) do + case {0, nil} !== Repo.insert_all(Mention, mentions) do true -> {:ok, :pass} false -> {:error, "insert mentions error"} end @@ -48,13 +39,13 @@ defmodule GroupherServer.Delivery.Delegate.Mention do |> result() end - def batch_mention(article, contents, %User{} = from_user) do + def handle(article, mentions, %User{} = from_user) do Multi.new() |> Multi.run(:batch_delete_mentions, fn _, _ -> batch_delete_mentions(article, from_user) end) |> Multi.run(:batch_insert_mentions, fn _, _ -> - case {0, nil} !== Repo.insert_all(Mention, contents) do + case {0, nil} !== Repo.insert_all(Mention, mentions) do true -> {:ok, :pass} false -> {:error, "insert mentions error"} end @@ -72,8 +63,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do end defp batch_delete_mentions(article, %User{} = from_user) do - with {:ok, thread} <- thread_of_article(article), - {:ok, info} <- match(thread) do + with {:ok, thread} <- thread_of_article(article) do thread = thread |> to_string |> String.upcase() from(m in Mention, @@ -92,14 +82,14 @@ defmodule GroupherServer.Delivery.Delegate.Mention do |> where([m], m.to_user_id == ^user.id) |> where([m], m.read == ^read) |> ORM.paginater(~m(page size)a) - |> extract_contents + |> extract_mentions |> done() end - defp extract_contents(%{entries: entries} = paged_contents) do + defp extract_mentions(%{entries: entries} = paged_mentions) do entries = entries |> Repo.preload(:from_user) |> Enum.map(&shape(&1)) - Map.put(paged_contents, :entries, entries) + Map.put(paged_mentions, :entries, entries) end # who in what part, mentioned me? diff --git a/lib/groupher_server/delivery/delegates/postman.ex b/lib/groupher_server/delivery/delegates/postman.ex new file mode 100644 index 000000000..80e9b31e7 --- /dev/null +++ b/lib/groupher_server/delivery/delegates/postman.ex @@ -0,0 +1,11 @@ +defmodule GroupherServer.Delivery.Delegate.Postman do + @moduledoc """ + The Delivery context. + """ + + alias GroupherServer.Delivery.Delegate.Mention + + def send(:mention, artiment, mentions, from_user) do + Mention.handle(artiment, mentions, from_user) + end +end diff --git a/lib/groupher_server/delivery/delivery.ex b/lib/groupher_server/delivery/delivery.ex index d3cd32a92..2d74138cd 100644 --- a/lib/groupher_server/delivery/delivery.ex +++ b/lib/groupher_server/delivery/delivery.ex @@ -4,11 +4,11 @@ defmodule GroupherServer.Delivery do """ alias GroupherServer.Delivery - alias Delivery.Delegate.{Mention, Mentions, Notifications, Utils} + alias Delivery.Delegate.{Postman, Mention, Mentions, Notifications, Utils} defdelegate mailbox_status(user), to: Utils - defdelegate batch_mention(content, contents, from_user), to: Mention + defdelegate send(service, artiment, mentions, from_user), to: Postman defdelegate paged_mentions(user, filter), to: Mention # system_notifications diff --git a/priv/repo/migrations/20210618160827_rename_cited_contents_to_cited_artiments.exs b/priv/repo/migrations/20210618160827_rename_cited_contents_to_cited_artiments.exs new file mode 100644 index 000000000..1193e83d7 --- /dev/null +++ b/priv/repo/migrations/20210618160827_rename_cited_contents_to_cited_artiments.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.RenameCitedContentsToCitedArtiments do + use Ecto.Migration + + def change do + drop(index(:cited_contents, [:cited_by_type, :cited_by_id])) + rename(table(:cited_contents), to: table(:cited_artiments)) + create(index(:cited_artiments, [:cited_by_type, :cited_by_id])) + end +end diff --git a/test/groupher_server/cms/hooks/cite_blog_test.exs b/test/groupher_server/cms/hooks/cite_blog_test.exs index d336a1e53..0e3a568c8 100644 --- a/test/groupher_server/cms/hooks/cite_blog_test.exs +++ b/test/groupher_server/cms/hooks/cite_blog_test.exs @@ -6,7 +6,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteBlog do alias Helper.ORM alias GroupherServer.CMS - alias CMS.Model.{Blog, Comment, CitedContent} + alias CMS.Model.{Blog, Comment, CitedArtiment} alias CMS.Delegate.Hooks @site_host get_config(:general, :site_host) @@ -104,7 +104,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteBlog do {:ok, comment} = ORM.find(Comment, comment.id) assert comment.meta.citing_count == 1 - {:ok, cite_content} = ORM.find_by(CitedContent, %{cited_by_id: comment.id}) + {:ok, cite_content} = ORM.find_by(CitedArtiment, %{cited_by_id: comment.id}) assert blog.id == cite_content.blog_id assert cite_content.cited_by_type == "COMMENT" end @@ -124,7 +124,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteBlog do {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 1 - {:ok, cite_content} = ORM.find_by(CitedContent, %{cited_by_id: cited_comment.id}) + {:ok, cite_content} = ORM.find_by(CitedArtiment, %{cited_by_id: cited_comment.id}) assert comment.id == cite_content.comment_id assert cited_comment.id == cite_content.cited_by_id assert cite_content.cited_by_type == "COMMENT" diff --git a/test/groupher_server/cms/hooks/cite_job_test.exs b/test/groupher_server/cms/hooks/cite_job_test.exs index 7241ef603..373b07911 100644 --- a/test/groupher_server/cms/hooks/cite_job_test.exs +++ b/test/groupher_server/cms/hooks/cite_job_test.exs @@ -6,7 +6,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteJob do alias Helper.ORM alias GroupherServer.CMS - alias CMS.Model.{Job, Comment, CitedContent} + alias CMS.Model.{Job, Comment, CitedArtiment} alias CMS.Delegate.Hooks @site_host get_config(:general, :site_host) @@ -104,7 +104,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteJob do {:ok, comment} = ORM.find(Comment, comment.id) assert comment.meta.citing_count == 1 - {:ok, cite_content} = ORM.find_by(CitedContent, %{cited_by_id: comment.id}) + {:ok, cite_content} = ORM.find_by(CitedArtiment, %{cited_by_id: comment.id}) assert job.id == cite_content.job_id assert cite_content.cited_by_type == "COMMENT" end @@ -124,7 +124,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteJob do {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 1 - {:ok, cite_content} = ORM.find_by(CitedContent, %{cited_by_id: cited_comment.id}) + {:ok, cite_content} = ORM.find_by(CitedArtiment, %{cited_by_id: cited_comment.id}) assert comment.id == cite_content.comment_id assert cited_comment.id == cite_content.cited_by_id assert cite_content.cited_by_type == "COMMENT" diff --git a/test/groupher_server/cms/hooks/cite_post_test.exs b/test/groupher_server/cms/hooks/cite_post_test.exs index 2fb5802e3..21d67bc35 100644 --- a/test/groupher_server/cms/hooks/cite_post_test.exs +++ b/test/groupher_server/cms/hooks/cite_post_test.exs @@ -6,7 +6,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CitePost do alias Helper.ORM alias GroupherServer.CMS - alias CMS.Model.{Post, Comment, CitedContent} + alias CMS.Model.{Post, Comment, CitedArtiment} alias CMS.Delegate.Hooks @site_host get_config(:general, :site_host) @@ -104,7 +104,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CitePost do {:ok, comment} = ORM.find(Comment, comment.id) assert comment.meta.citing_count == 1 - {:ok, cite_content} = ORM.find_by(CitedContent, %{cited_by_id: comment.id}) + {:ok, cite_content} = ORM.find_by(CitedArtiment, %{cited_by_id: comment.id}) assert post.id == cite_content.post_id assert cite_content.cited_by_type == "COMMENT" end @@ -124,7 +124,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CitePost do {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 1 - {:ok, cite_content} = ORM.find_by(CitedContent, %{cited_by_id: cited_comment.id}) + {:ok, cite_content} = ORM.find_by(CitedArtiment, %{cited_by_id: cited_comment.id}) assert comment.id == cite_content.comment_id assert cited_comment.id == cite_content.cited_by_id assert cite_content.cited_by_type == "COMMENT" diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index 95f6869d8..61c87daf9 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -33,7 +33,7 @@ defmodule GroupherServer.Test.Delivery.Mention do describe "mentions" do test "can batch send mentions", ~m(post user user2 mention_contents)a do - {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user) + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) mention = result.entries |> List.first() @@ -45,12 +45,12 @@ defmodule GroupherServer.Test.Delivery.Mention do test "mention multiable times on same article, will only have one record", ~m(post user user2 mention_contents)a do - {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user) + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) assert result.total_count == 1 - {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user) + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) assert result.total_count == 1 @@ -58,7 +58,7 @@ defmodule GroupherServer.Test.Delivery.Mention do test "if mention before, update with no mention content will not do mention in final", ~m(post user user2 user3 mention_contents)a do - {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user) + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) assert result.total_count == 1 @@ -81,7 +81,7 @@ defmodule GroupherServer.Test.Delivery.Mention do } ] - {:ok, :pass} = Delivery.batch_mention(post, mention_contents, user) + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) assert result.total_count == 0 From e4a2fcbaa1a53c9cbcccad1079a7fe82637b2f05 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sat, 19 Jun 2021 00:30:20 +0800 Subject: [PATCH 17/54] refactor(delivery): better naming --- .../{cited_content.ex => cited_artiment.ex} | 54 +++++++++---------- .../cms/delegates/hooks/cite.ex | 18 +++---- 2 files changed, 35 insertions(+), 37 deletions(-) rename lib/groupher_server/cms/delegates/{cited_content.ex => cited_artiment.ex} (71%) diff --git a/lib/groupher_server/cms/delegates/cited_content.ex b/lib/groupher_server/cms/delegates/cited_artiment.ex similarity index 71% rename from lib/groupher_server/cms/delegates/cited_content.ex rename to lib/groupher_server/cms/delegates/cited_artiment.ex index 59114b389..f5bcbaa96 100644 --- a/lib/groupher_server/cms/delegates/cited_content.ex +++ b/lib/groupher_server/cms/delegates/cited_artiment.ex @@ -1,4 +1,4 @@ -defmodule GroupherServer.CMS.Delegate.CitedContent do +defmodule GroupherServer.CMS.Delegate.CitedArtiment do @moduledoc """ CURD operation on post/job ... """ @@ -13,7 +13,7 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do alias Helper.{ORM, QueryBuilder} - alias CMS.Model.{CitedContent, Comment} + alias CMS.Model.{CitedArtiment, Comment} @article_threads get_config(:article, :threads) @@ -26,7 +26,7 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do def paged_citing_contents(cited_by_type, cited_by_id, %{page: page, size: size} = filter) do cited_by_type = cited_by_type |> to_string |> String.upcase() - CitedContent + CitedArtiment |> where([c], c.cited_by_id == ^cited_by_id and c.cited_by_type == ^cited_by_type) |> QueryBuilder.filter_pack(Map.merge(filter, %{sort: :asc_inserted})) |> ORM.paginater(~m(page size)a) @@ -37,53 +37,53 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do @doc "delete all records before insert_all, this will dynamiclly update" # those cited info when update article # 插入引用记录之前先全部清除,这样可以在更新文章的时候自动计算引用信息 - def batch_delete_cited_artiments(%Comment{} = comment) do - from(c in CitedContent, where: c.comment_id == ^comment.id) + def batch_delete_by(%Comment{} = comment) do + from(c in CitedArtiment, where: c.comment_id == ^comment.id) |> ORM.delete_all(:if_exist) end - def batch_delete_cited_artiments(article) do + def batch_delete_by(article) do with {:ok, thread} <- thread_of_article(article), {:ok, info} <- match(thread) do thread = thread |> to_string |> String.upcase() - from(c in CitedContent, + from(c in CitedArtiment, where: field(c, ^info.foreign_key) == ^article.id and c.cited_by_type == ^thread ) |> ORM.delete_all(:if_exist) end end - @doc "batch insert CitedContent record and update citing count" - def batch_insert_cited_artiments([]), do: {:ok, :pass} + @doc "batch insert CitedArtiment record and update citing count" + def batch_insert([]), do: {:ok, :pass} - def batch_insert_cited_artiments(cited_contents) do - # 注意这里多了 cited_content 和 citting_time - # cited_content 是为了下一步更新 citting_count 预先加载的,避免单独 preload 消耗性能 + def batch_insert(cited_artiments) do + # 注意这里多了 artiment 和 citting_time + # artiment 是为了下一步更新 citting_count 预先加载的,避免单独 preload 消耗性能 # citing_time 是因为 insert_all 必须要自己更新时间 # see: https://github.com/elixir-ecto/ecto/issues/1932#issuecomment-314083252 - clean_cited_contents = - cited_contents + clean_cited_artiments = + cited_artiments |> Enum.map(&(&1 |> Map.merge(%{inserted_at: &1.citing_time, updated_at: &1.citing_time}))) - |> Enum.map(&Map.delete(&1, :cited_content)) + |> Enum.map(&Map.delete(&1, :artiment)) |> Enum.map(&Map.delete(&1, :citing_time)) - case {0, nil} !== Repo.insert_all(CitedContent, clean_cited_contents) do - true -> update_content_citing_count(cited_contents) - false -> {:error, "insert cited content error"} + case {0, nil} !== Repo.insert_all(CitedArtiment, clean_cited_artiments) do + true -> update_artiment_citing_count(cited_artiments) + false -> {:error, "insert cited artiment error"} end end # update article/comment 's citting_count in meta - defp update_content_citing_count(cited_contents) do - Enum.all?(cited_contents, fn content -> - count_query = from(c in CitedContent, where: c.cited_by_id == ^content.cited_by_id) + defp update_artiment_citing_count(cited_artiments) do + Enum.all?(cited_artiments, fn cited -> + count_query = from(c in CitedArtiment, where: c.cited_by_id == ^cited.cited_by_id) count = Repo.aggregate(count_query, :count) - cited_content = content.cited_content - meta = Map.merge(cited_content.meta, %{citing_count: count}) + artiment = cited.artiment + meta = Map.merge(artiment.meta, %{citing_count: count}) - case cited_content |> ORM.update_meta(meta) do + case artiment |> ORM.update_meta(meta) do {:ok, _} -> true {:error, _} -> false end @@ -98,8 +98,8 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do end # shape comment cite - @spec shape(CitedContent.t()) :: T.cite_info() - defp shape(%CitedContent{comment_id: comment_id} = cited) when not is_nil(comment_id) do + @spec shape(CitedArtiment.t()) :: T.cite_info() + defp shape(%CitedArtiment{comment_id: comment_id} = cited) when not is_nil(comment_id) do %{block_linker: block_linker, comment: comment, inserted_at: inserted_at} = cited comment_thread = comment.thread |> String.downcase() |> String.to_atom() @@ -119,7 +119,7 @@ defmodule GroupherServer.CMS.Delegate.CitedContent do end # shape general article cite - defp shape(%CitedContent{} = cited) do + defp shape(%CitedArtiment{} = cited) do %{block_linker: block_linker, inserted_at: inserted_at} = cited thread = citing_thread(cited) diff --git a/lib/groupher_server/cms/delegates/hooks/cite.ex b/lib/groupher_server/cms/delegates/hooks/cite.ex index 047b9fded..22982a4b2 100644 --- a/lib/groupher_server/cms/delegates/hooks/cite.ex +++ b/lib/groupher_server/cms/delegates/hooks/cite.ex @@ -29,12 +29,10 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] import GroupherServer.CMS.Delegate.Hooks.Helper, only: [merge_same_block_linker: 2] - import GroupherServer.CMS.Delegate.CitedArtiment, - only: [batch_delete_cited_artiments: 1, batch_insert_cited_artiments: 1] - import Helper.ErrorCode alias GroupherServer.{CMS, Repo} + alias CMS.Delegate.CitedArtiment alias CMS.Model.Comment alias Helper.ORM @@ -49,13 +47,13 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do {:ok, artiment} <- preload_author(artiment) do Multi.new() |> Multi.run(:delete_all_cited_artiments, fn _, _ -> - batch_delete_cited_artiments(artiment) + CitedArtiment.batch_delete_by(artiment) end) |> Multi.run(:update_cited_info, fn _, _ -> blocks |> Enum.reduce([], &(&2 ++ parse_cited_per_block(artiment, &1))) |> merge_same_block_linker(:cited_by_id) - |> batch_insert_cited_artiments + |> CitedArtiment.batch_insert() end) |> Repo.transaction() |> result() @@ -69,7 +67,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do block_linker: ["block-ZgKJs"], cited_by_id: 190057, cited_by_type: "POST", - cited_artiment: #loaded, + artiment: #loaded, post_id: 190059, user_id: 1413053 } @@ -188,7 +186,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do user_id: comment.author_id, # extra fields for next-step usage # used for updating citing_count, avoid load again - cited_artiment: cited, + artiment: cited, # for later insert all citing_time: comment.updated_at |> DateTime.truncate(:second) } @@ -205,7 +203,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do user_id: comment.author_id, # extra fields for next-step usage # used for updating citing_count, avoid load again - cited_artiment: cited, + artiment: cited, # for later insert all citing_time: comment.updated_at |> DateTime.truncate(:second) } @@ -226,7 +224,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do user_id: article.author.user.id, # extra fields for next-step usage # used for updating citing_count, avoid load again - cited_artiment: cited, + artiment: cited, # for later insert all citing_time: article.updated_at |> DateTime.truncate(:second) } @@ -246,7 +244,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do user_id: article.author.user.id, # extra fields for next-step usage # used for updating citing_count, avoid load again - cited_artiment: cited, + artiment: cited, # for later insert all citing_time: article.updated_at |> DateTime.truncate(:second) } From ae217bf20ed46c976e55a3d88d5c538f01579f1b Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sat, 19 Jun 2021 00:47:07 +0800 Subject: [PATCH 18/54] refactor(delivery): mini improve --- lib/groupher_server/cms/delegates/cited_artiment.ex | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/groupher_server/cms/delegates/cited_artiment.ex b/lib/groupher_server/cms/delegates/cited_artiment.ex index f5bcbaa96..f6dcbef8a 100644 --- a/lib/groupher_server/cms/delegates/cited_artiment.ex +++ b/lib/groupher_server/cms/delegates/cited_artiment.ex @@ -64,9 +64,8 @@ defmodule GroupherServer.CMS.Delegate.CitedArtiment do # see: https://github.com/elixir-ecto/ecto/issues/1932#issuecomment-314083252 clean_cited_artiments = cited_artiments - |> Enum.map(&(&1 |> Map.merge(%{inserted_at: &1.citing_time, updated_at: &1.citing_time}))) - |> Enum.map(&Map.delete(&1, :artiment)) - |> Enum.map(&Map.delete(&1, :citing_time)) + |> Enum.map(&Map.merge(&1, %{inserted_at: &1.citing_time, updated_at: &1.citing_time})) + |> Enum.map(&Map.drop(&1, [:artiment, :citing_time])) case {0, nil} !== Repo.insert_all(CitedArtiment, clean_cited_artiments) do true -> update_artiment_citing_count(cited_artiments) From 54272baff69c73cbcdfdf4a52a98f81c3e63d442 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sat, 19 Jun 2021 09:52:39 +0800 Subject: [PATCH 19/54] refactor(delivery): rename fetch instead of paged_mention --- lib/groupher_server/delivery/delegates/postman.ex | 4 ++++ lib/groupher_server/delivery/delivery.ex | 4 ++-- .../cms/hooks/mention_in_blog_test.exs | 10 +++++----- .../cms/hooks/mention_in_job_test.exs | 10 +++++----- .../cms/hooks/mention_in_post_test.exs | 10 +++++----- test/groupher_server/delivery/mention_test.exs | 14 +++++++------- 6 files changed, 28 insertions(+), 24 deletions(-) diff --git a/lib/groupher_server/delivery/delegates/postman.ex b/lib/groupher_server/delivery/delegates/postman.ex index 80e9b31e7..13a5dbd5f 100644 --- a/lib/groupher_server/delivery/delegates/postman.ex +++ b/lib/groupher_server/delivery/delegates/postman.ex @@ -8,4 +8,8 @@ defmodule GroupherServer.Delivery.Delegate.Postman do def send(:mention, artiment, mentions, from_user) do Mention.handle(artiment, mentions, from_user) end + + def fetch(:mention, user, filter) do + Mention.paged_mentions(user, filter) + end end diff --git a/lib/groupher_server/delivery/delivery.ex b/lib/groupher_server/delivery/delivery.ex index 2d74138cd..b0716fcc4 100644 --- a/lib/groupher_server/delivery/delivery.ex +++ b/lib/groupher_server/delivery/delivery.ex @@ -4,12 +4,12 @@ defmodule GroupherServer.Delivery do """ alias GroupherServer.Delivery - alias Delivery.Delegate.{Postman, Mention, Mentions, Notifications, Utils} + alias Delivery.Delegate.{Postman, Mentions, Notifications, Utils} defdelegate mailbox_status(user), to: Utils defdelegate send(service, artiment, mentions, from_user), to: Postman - defdelegate paged_mentions(user, filter), to: Mention + defdelegate fetch(service, user, filter), to: Postman # system_notifications defdelegate publish_system_notification(info), to: Notifications diff --git a/test/groupher_server/cms/hooks/mention_in_blog_test.exs b/test/groupher_server/cms/hooks/mention_in_blog_test.exs index 190854d13..c76f2f6ba 100644 --- a/test/groupher_server/cms/hooks/mention_in_blog_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_blog_test.exs @@ -41,7 +41,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInBlog do {:ok, _result} = Hooks.Mention.handle(blog) - {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) mention = result.entries |> List.first() assert mention.type == "BLOG" @@ -50,7 +50,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInBlog do assert mention.title == blog.title assert mention.user.login == blog.author.user.login - {:ok, result} = Delivery.paged_mentions(user3, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user3, %{page: 1, size: 10}) mention = result.entries |> List.first() assert mention.type == "BLOG" @@ -69,7 +69,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInBlog do {:ok, comment} = preload_author(comment) {:ok, _result} = Hooks.Mention.handle(comment) - {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) mention = result.entries |> List.first() assert mention.type == "COMMENT" @@ -86,7 +86,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInBlog do blog_attrs = blog_attrs |> Map.merge(%{body: body}) {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) - {:ok, result} = Delivery.paged_mentions(user, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10}) assert result.total_count == 0 comment_body = @@ -95,7 +95,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInBlog do {:ok, comment} = CMS.create_comment(:blog, blog.id, comment_body, user) {:ok, _result} = Hooks.Mention.handle(comment) - {:ok, result} = Delivery.paged_mentions(user, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10}) assert result.total_count == 0 end diff --git a/test/groupher_server/cms/hooks/mention_in_job_test.exs b/test/groupher_server/cms/hooks/mention_in_job_test.exs index 945f877a6..a389210ed 100644 --- a/test/groupher_server/cms/hooks/mention_in_job_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_job_test.exs @@ -41,7 +41,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInJob do {:ok, _result} = Hooks.Mention.handle(job) - {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) mention = result.entries |> List.first() assert mention.type == "JOB" @@ -50,7 +50,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInJob do assert mention.title == job.title assert mention.user.login == job.author.user.login - {:ok, result} = Delivery.paged_mentions(user3, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user3, %{page: 1, size: 10}) mention = result.entries |> List.first() assert mention.type == "JOB" @@ -69,7 +69,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInJob do {:ok, comment} = preload_author(comment) {:ok, _result} = Hooks.Mention.handle(comment) - {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) mention = result.entries |> List.first() assert mention.type == "COMMENT" @@ -86,7 +86,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInJob do job_attrs = job_attrs |> Map.merge(%{body: body}) {:ok, job} = CMS.create_article(community, :job, job_attrs, user) - {:ok, result} = Delivery.paged_mentions(user, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10}) assert result.total_count == 0 comment_body = @@ -95,7 +95,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInJob do {:ok, comment} = CMS.create_comment(:job, job.id, comment_body, user) {:ok, _result} = Hooks.Mention.handle(comment) - {:ok, result} = Delivery.paged_mentions(user, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10}) assert result.total_count == 0 end diff --git a/test/groupher_server/cms/hooks/mention_in_post_test.exs b/test/groupher_server/cms/hooks/mention_in_post_test.exs index d40781730..10c99741d 100644 --- a/test/groupher_server/cms/hooks/mention_in_post_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_post_test.exs @@ -41,7 +41,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do {:ok, _result} = Hooks.Mention.handle(post) - {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) mention = result.entries |> List.first() assert mention.type == "POST" @@ -50,7 +50,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do assert mention.title == post.title assert mention.user.login == post.author.user.login - {:ok, result} = Delivery.paged_mentions(user3, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user3, %{page: 1, size: 10}) mention = result.entries |> List.first() assert mention.type == "POST" @@ -69,7 +69,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do {:ok, comment} = preload_author(comment) {:ok, _result} = Hooks.Mention.handle(comment) - {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) mention = result.entries |> List.first() assert mention.type == "COMMENT" @@ -86,7 +86,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do post_attrs = post_attrs |> Map.merge(%{body: body}) {:ok, post} = CMS.create_article(community, :post, post_attrs, user) - {:ok, result} = Delivery.paged_mentions(user, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10}) assert result.total_count == 0 comment_body = @@ -95,7 +95,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do {:ok, comment} = CMS.create_comment(:post, post.id, comment_body, user) {:ok, _result} = Hooks.Mention.handle(comment) - {:ok, result} = Delivery.paged_mentions(user, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10}) assert result.total_count == 0 end diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index 61c87daf9..ff25667f6 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -34,7 +34,7 @@ defmodule GroupherServer.Test.Delivery.Mention do describe "mentions" do test "can batch send mentions", ~m(post user user2 mention_contents)a do {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) - {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) mention = result.entries |> List.first() @@ -46,12 +46,12 @@ defmodule GroupherServer.Test.Delivery.Mention do test "mention multiable times on same article, will only have one record", ~m(post user user2 mention_contents)a do {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) - {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) assert result.total_count == 1 {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) - {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) assert result.total_count == 1 end @@ -59,11 +59,11 @@ defmodule GroupherServer.Test.Delivery.Mention do test "if mention before, update with no mention content will not do mention in final", ~m(post user user2 user3 mention_contents)a do {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) - {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) assert result.total_count == 1 - {:ok, result} = Delivery.paged_mentions(user3, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user3, %{page: 1, size: 10}) assert result.total_count == 0 mention_contents = [ @@ -82,10 +82,10 @@ defmodule GroupherServer.Test.Delivery.Mention do ] {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) - {:ok, result} = Delivery.paged_mentions(user2, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) assert result.total_count == 0 - {:ok, result} = Delivery.paged_mentions(user3, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:mention, user3, %{page: 1, size: 10}) assert result.total_count == 1 end end From 5e41de0d00eb4c9f5f2fbdd2172c6e0a31bb04bf Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sat, 19 Jun 2021 14:27:04 +0800 Subject: [PATCH 20/54] refactor(delivery): notification wip --- .../delivery/delegates/mention.ex | 22 +-- .../delivery/delegates/notification.ex | 85 ++++++++++ .../delivery/delegates/postman.ex | 13 +- lib/groupher_server/delivery/delivery.ex | 1 + .../delivery/models/notification.ex | 41 +++++ ...0210619021543_create_new_notifications.exs | 24 +++ .../cms/hooks/mention_in_blog_test.exs | 3 - .../cms/hooks/mention_in_job_test.exs | 3 - .../cms/hooks/mention_in_post_test.exs | 3 - .../delivery/notification_test.exs | 152 ++++-------------- .../delivery/old_notification_test.exs | 130 +++++++++++++++ 11 files changed, 335 insertions(+), 142 deletions(-) create mode 100644 lib/groupher_server/delivery/delegates/notification.ex create mode 100644 lib/groupher_server/delivery/models/notification.ex create mode 100644 priv/repo/migrations/20210619021543_create_new_notifications.exs create mode 100644 test/groupher_server/delivery/old_notification_test.exs diff --git a/lib/groupher_server/delivery/delegates/mention.ex b/lib/groupher_server/delivery/delegates/mention.ex index 7cf843b97..89057ebfd 100644 --- a/lib/groupher_server/delivery/delegates/mention.ex +++ b/lib/groupher_server/delivery/delegates/mention.ex @@ -54,6 +54,17 @@ defmodule GroupherServer.Delivery.Delegate.Mention do |> result() end + def paged_mentions(%User{} = user, %{page: page, size: size} = filter) do + read = Map.get(filter, :read, false) + + Mention + |> where([m], m.to_user_id == ^user.id) + |> where([m], m.read == ^read) + |> ORM.paginater(~m(page size)a) + |> extract_mentions + |> done() + end + defp batch_delete_mentions(%Comment{} = comment, %User{} = from_user) do from(m in Mention, where: m.comment_id == ^comment.id, @@ -75,17 +86,6 @@ defmodule GroupherServer.Delivery.Delegate.Mention do end end - def paged_mentions(%User{} = user, %{page: page, size: size} = filter) do - read = Map.get(filter, :read, false) - - Mention - |> where([m], m.to_user_id == ^user.id) - |> where([m], m.read == ^read) - |> ORM.paginater(~m(page size)a) - |> extract_mentions - |> done() - end - defp extract_mentions(%{entries: entries} = paged_mentions) do entries = entries |> Repo.preload(:from_user) |> Enum.map(&shape(&1)) diff --git a/lib/groupher_server/delivery/delegates/notification.ex b/lib/groupher_server/delivery/delegates/notification.ex new file mode 100644 index 000000000..e7acb25b9 --- /dev/null +++ b/lib/groupher_server/delivery/delegates/notification.ex @@ -0,0 +1,85 @@ +defmodule GroupherServer.Delivery.Delegate.Notification do + @moduledoc """ + notification for upvote, comment, publish, collect, watch, follow an article or user + """ + import Ecto.Query, warn: false + import Helper.Utils, only: [done: 1, strip_struct: 1] + import ShortMaps + + alias GroupherServer.{Accounts, Delivery, Repo} + alias Delivery.Model.Notification + alias Accounts.Model.User + alias Helper.ORM + + @notify_group_interval_hour 1 + + def handle(attrs, %User{} = from_user) do + from_user = from_user |> Map.take([:login, :nickname]) |> Map.put(:user_id, from_user.id) + + case similar_action_in_latest_notify(attrs) do + {:ok, notify} -> merge_notification(notify, from_user) + {:error, _} -> create_notification(attrs, from_user) + end + end + + defp merge_notification(notify, from_user) do + cur_from_users = notify.from_users |> Enum.map(&strip_struct(&1)) + from_users = (cur_from_users ++ [from_user]) |> Enum.uniq() + + notify + |> Ecto.Changeset.change() + |> Ecto.Changeset.put_embed(:from_users, from_users) + |> Repo.update() + end + + defp create_notification(attrs, from_user) do + %Notification{} + |> Ecto.Changeset.change(attrs) + |> Ecto.Changeset.put_embed(:from_users, [from_user]) + |> Repo.insert() + end + + defp similar_action_in_latest_notify(%{comment_id: comment_id} = attrs) + when not is_nil(comment_id) do + ~m(user_id type article_id action comment_id)a = attrs + n_hour_ago = Timex.shift(Timex.now(), hours: -@notify_group_interval_hour) + + from(n in Notification, + where: n.inserted_at >= ^n_hour_ago, + where: n.user_id == ^user_id, + where: n.type == ^type, + where: n.article_id == ^article_id, + where: n.comment_id == ^comment_id, + where: n.action == ^action, + where: n.read == false + ) + |> Repo.one() + |> done + end + + defp similar_action_in_latest_notify(attrs) do + ~m(user_id type article_id action)a = attrs + n_hour_ago = Timex.shift(Timex.now(), hours: -@notify_group_interval_hour) + + from(n in Notification, + where: n.inserted_at >= ^n_hour_ago, + where: n.user_id == ^user_id, + where: n.type == ^type, + where: n.article_id == ^article_id, + where: n.action == ^action, + where: n.read == false + ) + |> Repo.one() + |> done + end + + def paged_notifications(user_id, %{page: page, size: size} = filter) do + read = Map.get(filter, :read, false) + + Notification + |> where([n], n.user_id == ^user_id) + |> where([n], n.read == ^read) + |> ORM.paginater(~m(page size)a) + |> done() + end +end diff --git a/lib/groupher_server/delivery/delegates/postman.ex b/lib/groupher_server/delivery/delegates/postman.ex index 13a5dbd5f..fafca5234 100644 --- a/lib/groupher_server/delivery/delegates/postman.ex +++ b/lib/groupher_server/delivery/delegates/postman.ex @@ -3,13 +3,24 @@ defmodule GroupherServer.Delivery.Delegate.Postman do The Delivery context. """ - alias GroupherServer.Delivery.Delegate.Mention + alias GroupherServer.Delivery.Delegate.{Mention, Notification} def send(:mention, artiment, mentions, from_user) do Mention.handle(artiment, mentions, from_user) end + def send(:notify, attrs, from_user) do + Notification.handle(attrs, from_user) + end + def fetch(:mention, user, filter) do Mention.paged_mentions(user, filter) end + + def fetch(:notification, user, filter) do + Notification.paged_notifications(user, filter) + end + + # def send(_, _, _), do: {:error, "delivery, not such service"} + # def send(_, _, _, _), do: {:error, "delivery, not such service"} end diff --git a/lib/groupher_server/delivery/delivery.ex b/lib/groupher_server/delivery/delivery.ex index b0716fcc4..0f09075cd 100644 --- a/lib/groupher_server/delivery/delivery.ex +++ b/lib/groupher_server/delivery/delivery.ex @@ -9,6 +9,7 @@ defmodule GroupherServer.Delivery do defdelegate mailbox_status(user), to: Utils defdelegate send(service, artiment, mentions, from_user), to: Postman + defdelegate send(service, attrs, from_user), to: Postman defdelegate fetch(service, user, filter), to: Postman # system_notifications diff --git a/lib/groupher_server/delivery/models/notification.ex b/lib/groupher_server/delivery/models/notification.ex new file mode 100644 index 000000000..09c023ab8 --- /dev/null +++ b/lib/groupher_server/delivery/models/notification.ex @@ -0,0 +1,41 @@ +defmodule GroupherServer.Delivery.Model.Notification do + @moduledoc false + alias __MODULE__ + + use Ecto.Schema + import Ecto.Changeset + + alias GroupherServer.{Accounts, CMS} + alias Accounts.Model.User + alias CMS.Model.Embeds + + @required_fields ~w(user_id action)a + @optional_fields ~w(type article_id comment_id title read)a + + @type t :: %Notification{} + schema "notifications" do + belongs_to(:user, User) + # article or comment + field(:type, :string) + field(:article_id, :id) + field(:title, :string) + # optional comment id + field(:comment_id, :id) + # + field(:action, :string) + embeds_many(:from_users, Embeds.User, on_replace: :delete) + + field(:read, :boolean, default: false) + + timestamps(type: :utc_datetime) + end + + @doc false + def changeset(%Notification{} = mention, attrs) do + mention + |> cast(attrs, @optional_fields ++ @required_fields) + |> validate_required(@required_fields) + |> cast_embed(:from_users, required: true, with: &Embeds.User.changeset/2) + |> foreign_key_constraint(:user_id) + end +end diff --git a/priv/repo/migrations/20210619021543_create_new_notifications.exs b/priv/repo/migrations/20210619021543_create_new_notifications.exs new file mode 100644 index 000000000..a351bf350 --- /dev/null +++ b/priv/repo/migrations/20210619021543_create_new_notifications.exs @@ -0,0 +1,24 @@ +defmodule GroupherServer.Repo.Migrations.CreateNewNotifications do + use Ecto.Migration + + def change do + create table(:notifications) do + add(:user_id, references(:users, on_delete: :nothing), null: false) + # article or comment + add(:type, :string) + add(:article_id, :id) + add(:title, :string) + # optional comment id + add(:comment_id, :id) + # + add(:action, :string) + add(:from_users, :map) + + add(:read, :boolean, default: false) + + timestamps() + end + + create(index(:notifications, [:user_id])) + end +end diff --git a/test/groupher_server/cms/hooks/mention_in_blog_test.exs b/test/groupher_server/cms/hooks/mention_in_blog_test.exs index c76f2f6ba..638c49211 100644 --- a/test/groupher_server/cms/hooks/mention_in_blog_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_blog_test.exs @@ -25,7 +25,6 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInBlog do end describe "[mention in blog basic]" do - @tag :wip test "mention multi user in blog should work", ~m(user user2 user3 community blog_attrs)a do body = mock_rich_text( @@ -60,7 +59,6 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInBlog do assert mention.user.login == blog.author.user.login end - @tag :wip test "mention in blog's comment should work", ~m(user user2 blog)a do comment_body = mock_rich_text(~s(hi
#{user2.login}
)) @@ -80,7 +78,6 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInBlog do assert mention.user.login == comment.author.login end - @tag :wip test "can not mention author self in blog or comment", ~m(community user blog_attrs)a do body = mock_rich_text(~s(hi
#{user.login}
)) blog_attrs = blog_attrs |> Map.merge(%{body: body}) diff --git a/test/groupher_server/cms/hooks/mention_in_job_test.exs b/test/groupher_server/cms/hooks/mention_in_job_test.exs index a389210ed..84481f2b1 100644 --- a/test/groupher_server/cms/hooks/mention_in_job_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_job_test.exs @@ -25,7 +25,6 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInJob do end describe "[mention in job basic]" do - @tag :wip test "mention multi user in job should work", ~m(user user2 user3 community job_attrs)a do body = mock_rich_text( @@ -60,7 +59,6 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInJob do assert mention.user.login == job.author.user.login end - @tag :wip test "mention in job's comment should work", ~m(user user2 job)a do comment_body = mock_rich_text(~s(hi
#{user2.login}
)) @@ -80,7 +78,6 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInJob do assert mention.user.login == comment.author.login end - @tag :wip test "can not mention author self in job or comment", ~m(community user job_attrs)a do body = mock_rich_text(~s(hi
#{user.login}
)) job_attrs = job_attrs |> Map.merge(%{body: body}) diff --git a/test/groupher_server/cms/hooks/mention_in_post_test.exs b/test/groupher_server/cms/hooks/mention_in_post_test.exs index 10c99741d..6566c78ff 100644 --- a/test/groupher_server/cms/hooks/mention_in_post_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_post_test.exs @@ -25,7 +25,6 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do end describe "[mention in post basic]" do - @tag :wip test "mention multi user in post should work", ~m(user user2 user3 community post_attrs)a do body = mock_rich_text( @@ -60,7 +59,6 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do assert mention.user.login == post.author.user.login end - @tag :wip test "mention in post's comment should work", ~m(user user2 post)a do comment_body = mock_rich_text(~s(hi
#{user2.login}
)) @@ -80,7 +78,6 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do assert mention.user.login == comment.author.login end - @tag :wip test "can not mention author self in post or comment", ~m(community user post_attrs)a do body = mock_rich_text(~s(hi
#{user.login}
)) post_attrs = post_attrs |> Map.merge(%{body: body}) diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index eae70bf7d..24890d4ae 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -1,130 +1,40 @@ -defmodule GroupherServer.Test.Delivery.OldNotification do +defmodule GroupherServer.Test.Delivery.Notification do use GroupherServer.TestTools import Ecto.Query, warn: false - import Helper.Utils - - alias Helper.ORM - alias GroupherServer.{Accounts, Delivery} - - alias Accounts.Model.NotificationMail - alias Delivery.Model.OldNotification - - describe "[delivery notification]" do - test "user can notify other user" do - {:ok, [user, user2]} = db_insert_multi(:user, 2) - - mock_notifications_for(user, 1) - mock_notifications_for(user2, 1) - - filter = %{page: 1, size: 20, read: false} - {:ok, notifications} = Delivery.fetch_notifications(user, filter) - - assert notifications |> is_valid_pagination?(:raw) - assert notifications |> Map.get(:total_count) == 1 - assert user.id == notifications.entries |> List.first() |> Map.get(:to_user_id) - end - - test "user can fetch notifications and store in own mention mail-box" do - {:ok, user} = db_insert(:user) - - mock_notifications_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) - - {:ok, notification_mails} = - NotificationMail - |> where([m], m.to_user_id == ^user.id) - |> where([m], m.read == false) - |> ORM.paginater(page: 1, size: 10) - |> done() - - notification_ids = - notifications.entries - |> Enum.reduce([], fn m, acc -> - acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) - end) - - notification_mail_ids = - notification_mails.entries - |> Enum.reduce([], fn m, acc -> - acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) - end) - - assert Enum.sort(notification_ids) == Enum.sort(notification_mail_ids) - end - - test "delete related delivery notifications after user fetch" do - {:ok, user} = db_insert(:user) - - mock_notifications_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, _mentions} = Accounts.fetch_notifications(user, filter) - - {:ok, notifications} = - OldNotification - |> where([m], m.to_user_id == ^user.id) - |> ORM.paginater(page: 1, size: 10) - |> done() - - assert Enum.empty?(notifications.entries) - end - - test "store user fetch info in delivery records, with last_fetch_unread_time info" do - {:ok, user} = db_insert(:user) - - mock_notifications_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) - {:ok, record} = Delivery.fetch_record(user) - - latest_insert_time = - notifications.entries |> List.first() |> Map.get(:inserted_at) |> to_string - - record_last_fetch_unresd_time = - record |> Map.get(:notifications_record) |> Map.get("last_fetch_unread_time") - - assert latest_insert_time == record_last_fetch_unresd_time - end - - test "user can mark one notifications as read" do - {:ok, user} = db_insert(:user) - - mock_notifications_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) - first_notification = notifications.entries |> List.first() - assert notifications.total_count == 3 - Accounts.mark_mail_read(first_notification, user) - - filter = %{page: 1, size: 20, read: false} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) - assert notifications.total_count == 2 - - filter = %{page: 1, size: 20, read: true} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) - assert notifications.total_count == 1 - end - - test "user can mark all unread notifications as read" do - {:ok, user} = db_insert(:user) - - mock_notifications_for(user, 3) - - Accounts.mark_mail_read_all(user, :notification) + # import Helper.Utils + + alias GroupherServer.Delivery + + setup do + {:ok, post} = db_insert(:post) + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, user3} = db_insert(:user) + {:ok, community} = db_insert(:community) + + notify = %{ + type: "POST", + article_id: post.id, + title: post.title, + action: "UPVOTE", + user_id: user.id, + read: false + # inserted_at: post.updated_at |> DateTime.truncate(:second), + } + + {:ok, ~m(community post user user2 user3 notify)a} + end - filter = %{page: 1, size: 20, read: false} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) + describe "notification curd" do + @tag :wip + test "can insert notification.", ~m(post user user2 user3 notify)a do + {:ok, _} = Delivery.send(:notify, notify, user2) + {:ok, _} = Delivery.send(:notify, notify, user3) - assert Enum.empty?(notifications.entries) + {:ok, hello} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) - filter = %{page: 1, size: 20, read: true} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) - assert notifications.total_count == 3 + IO.inspect(hello, label: "hello") end end end diff --git a/test/groupher_server/delivery/old_notification_test.exs b/test/groupher_server/delivery/old_notification_test.exs new file mode 100644 index 000000000..eae70bf7d --- /dev/null +++ b/test/groupher_server/delivery/old_notification_test.exs @@ -0,0 +1,130 @@ +defmodule GroupherServer.Test.Delivery.OldNotification do + use GroupherServer.TestTools + + import Ecto.Query, warn: false + import Helper.Utils + + alias Helper.ORM + alias GroupherServer.{Accounts, Delivery} + + alias Accounts.Model.NotificationMail + alias Delivery.Model.OldNotification + + describe "[delivery notification]" do + test "user can notify other user" do + {:ok, [user, user2]} = db_insert_multi(:user, 2) + + mock_notifications_for(user, 1) + mock_notifications_for(user2, 1) + + filter = %{page: 1, size: 20, read: false} + {:ok, notifications} = Delivery.fetch_notifications(user, filter) + + assert notifications |> is_valid_pagination?(:raw) + assert notifications |> Map.get(:total_count) == 1 + assert user.id == notifications.entries |> List.first() |> Map.get(:to_user_id) + end + + test "user can fetch notifications and store in own mention mail-box" do + {:ok, user} = db_insert(:user) + + mock_notifications_for(user, 3) + + filter = %{page: 1, size: 20, read: false} + {:ok, notifications} = Accounts.fetch_notifications(user, filter) + + {:ok, notification_mails} = + NotificationMail + |> where([m], m.to_user_id == ^user.id) + |> where([m], m.read == false) + |> ORM.paginater(page: 1, size: 10) + |> done() + + notification_ids = + notifications.entries + |> Enum.reduce([], fn m, acc -> + acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) + end) + + notification_mail_ids = + notification_mails.entries + |> Enum.reduce([], fn m, acc -> + acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) + end) + + assert Enum.sort(notification_ids) == Enum.sort(notification_mail_ids) + end + + test "delete related delivery notifications after user fetch" do + {:ok, user} = db_insert(:user) + + mock_notifications_for(user, 3) + + filter = %{page: 1, size: 20, read: false} + {:ok, _mentions} = Accounts.fetch_notifications(user, filter) + + {:ok, notifications} = + OldNotification + |> where([m], m.to_user_id == ^user.id) + |> ORM.paginater(page: 1, size: 10) + |> done() + + assert Enum.empty?(notifications.entries) + end + + test "store user fetch info in delivery records, with last_fetch_unread_time info" do + {:ok, user} = db_insert(:user) + + mock_notifications_for(user, 3) + + filter = %{page: 1, size: 20, read: false} + {:ok, notifications} = Accounts.fetch_notifications(user, filter) + {:ok, record} = Delivery.fetch_record(user) + + latest_insert_time = + notifications.entries |> List.first() |> Map.get(:inserted_at) |> to_string + + record_last_fetch_unresd_time = + record |> Map.get(:notifications_record) |> Map.get("last_fetch_unread_time") + + assert latest_insert_time == record_last_fetch_unresd_time + end + + test "user can mark one notifications as read" do + {:ok, user} = db_insert(:user) + + mock_notifications_for(user, 3) + + filter = %{page: 1, size: 20, read: false} + {:ok, notifications} = Accounts.fetch_notifications(user, filter) + first_notification = notifications.entries |> List.first() + assert notifications.total_count == 3 + Accounts.mark_mail_read(first_notification, user) + + filter = %{page: 1, size: 20, read: false} + {:ok, notifications} = Accounts.fetch_notifications(user, filter) + assert notifications.total_count == 2 + + filter = %{page: 1, size: 20, read: true} + {:ok, notifications} = Accounts.fetch_notifications(user, filter) + assert notifications.total_count == 1 + end + + test "user can mark all unread notifications as read" do + {:ok, user} = db_insert(:user) + + mock_notifications_for(user, 3) + + Accounts.mark_mail_read_all(user, :notification) + + filter = %{page: 1, size: 20, read: false} + {:ok, notifications} = Accounts.fetch_notifications(user, filter) + + assert Enum.empty?(notifications.entries) + + filter = %{page: 1, size: 20, read: true} + {:ok, notifications} = Accounts.fetch_notifications(user, filter) + assert notifications.total_count == 3 + end + end +end From 79f10f073af8b1b66346757015d04afa131a3ea7 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sat, 19 Jun 2021 19:40:58 +0800 Subject: [PATCH 21/54] refactor(delivery): notification wip --- config/config.exs | 6 +- .../cms/delegates/article_tag.ex | 6 +- .../delivery/delegates/notification.ex | 135 ++++++++++++------ .../delivery/delegates/postman.ex | 5 + lib/helper/utils/map.ex | 6 +- lib/helper/utils/utils.ex | 2 +- .../cms/hooks/mention_in_blog_test.exs | 3 - .../cms/hooks/mention_in_job_test.exs | 3 - .../cms/hooks/mention_in_post_test.exs | 3 - .../delivery/notification_test.exs | 134 +++++++++++++++-- test/helper/utils_test.exs | 2 +- test/support/assert_helper.ex | 1 - 12 files changed, 228 insertions(+), 78 deletions(-) diff --git a/config/config.exs b/config/config.exs index 0f38df2fb..eb3a55861 100644 --- a/config/config.exs +++ b/config/config.exs @@ -47,7 +47,11 @@ config :groupher_server, :general, user_achieve_upvote_weight: 1, user_achieve_watch_weight: 1, user_achieve_collect_weight: 2, - user_achieve_follow_weight: 3 + user_achieve_follow_weight: 3, + # others + # 在这个时间段内,多条提醒消息将被合并为一条 + notify_group_interval_hour: 1, + nofity_types: [:upvote, :comment, :reply, :collect, :follow] config :groupher_server, :customization, theme: "cyan", diff --git a/lib/groupher_server/cms/delegates/article_tag.ex b/lib/groupher_server/cms/delegates/article_tag.ex index 8fc0a6013..947d11d6c 100644 --- a/lib/groupher_server/cms/delegates/article_tag.ex +++ b/lib/groupher_server/cms/delegates/article_tag.ex @@ -5,7 +5,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleTag do import Ecto.Query, warn: false import GroupherServer.CMS.Helper.Matcher import Helper.Validator.Guards, only: [g_is_id: 1] - import Helper.Utils, only: [done: 1, map_atom_values_to_upcase_str: 1] + import Helper.Utils, only: [done: 1, atom_values_to_upcase: 1] import GroupherServer.CMS.Delegate.ArticleCURD, only: [ensure_author_exists: 1] import ShortMaps import Helper.ErrorCode @@ -31,7 +31,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleTag do Multi.new() |> Multi.run(:create_article_tag, fn _, _ -> update_attrs = %{author_id: author.id, community_id: community.id, thread: thread} - attrs = attrs |> Map.merge(update_attrs) |> map_atom_values_to_upcase_str + attrs = attrs |> Map.merge(update_attrs) |> atom_values_to_upcase ORM.create(ArticleTag, attrs) end) @@ -48,7 +48,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleTag do """ def update_article_tag(id, attrs) do with {:ok, article_tag} <- ORM.find(ArticleTag, id) do - attrs = attrs |> map_atom_values_to_upcase_str + attrs = attrs |> atom_values_to_upcase ORM.update(article_tag, attrs) end end diff --git a/lib/groupher_server/delivery/delegates/notification.ex b/lib/groupher_server/delivery/delegates/notification.ex index e7acb25b9..9cb511ad3 100644 --- a/lib/groupher_server/delivery/delegates/notification.ex +++ b/lib/groupher_server/delivery/delegates/notification.ex @@ -3,7 +3,10 @@ defmodule GroupherServer.Delivery.Delegate.Notification do notification for upvote, comment, publish, collect, watch, follow an article or user """ import Ecto.Query, warn: false - import Helper.Utils, only: [done: 1, strip_struct: 1] + + import Helper.Utils, + only: [get_config: 2, done: 1, strip_struct: 1, atom_values_to_upcase: 1] + import ShortMaps alias GroupherServer.{Accounts, Delivery, Repo} @@ -11,75 +14,113 @@ defmodule GroupherServer.Delivery.Delegate.Notification do alias Accounts.Model.User alias Helper.ORM - @notify_group_interval_hour 1 + @supported_notify_type get_config(:general, :nofity_types) + @notify_group_interval_hour get_config(:general, :notify_group_interval_hour) - def handle(attrs, %User{} = from_user) do - from_user = from_user |> Map.take([:login, :nickname]) |> Map.put(:user_id, from_user.id) + def handle(%{action: action} = attrs, %User{} = from_user) do + with true <- action in @supported_notify_type, + true <- is_valid?(attrs) do + from_user = from_user |> Map.take([:login, :nickname]) |> Map.put(:user_id, from_user.id) - case similar_action_in_latest_notify(attrs) do - {:ok, notify} -> merge_notification(notify, from_user) - {:error, _} -> create_notification(attrs, from_user) + case similar_notify_latest_peroid(attrs) do + {:ok, notify} -> merge_notification(notify, from_user) + {:error, _} -> create_notification(attrs, from_user) + end + else + false -> {:error, "invalid args for notification"} + error -> error end end + def paged_notifications(user_id, %{page: page, size: size} = filter) do + read = Map.get(filter, :read, false) + + Notification + |> where([n], n.user_id == ^user_id) + |> where([n], n.read == ^read) + |> ORM.paginater(~m(page size)a) + |> done() + end + + # 如果在临近时间段内有类似操作,直接将这次的操作人添加到 from_users 中即可 + # 避免对统一操作的大量重复消息提醒,体验不好 defp merge_notification(notify, from_user) do cur_from_users = notify.from_users |> Enum.map(&strip_struct(&1)) - from_users = (cur_from_users ++ [from_user]) |> Enum.uniq() + from_users = ([from_user] ++ cur_from_users) |> Enum.uniq() - notify - |> Ecto.Changeset.change() - |> Ecto.Changeset.put_embed(:from_users, from_users) - |> Repo.update() + notify |> ORM.update_embed(:from_users, from_users) end defp create_notification(attrs, from_user) do %Notification{} - |> Ecto.Changeset.change(attrs) + |> Ecto.Changeset.change(atom_values_to_upcase(attrs)) |> Ecto.Changeset.put_embed(:from_users, [from_user]) |> Repo.insert() end - defp similar_action_in_latest_notify(%{comment_id: comment_id} = attrs) + defp similar_notify_latest_peroid(%{action: :follow} = attrs) do + do_find_similar(Notification, attrs) + end + + defp similar_notify_latest_peroid(%{comment_id: comment_id} = attrs) when not is_nil(comment_id) do - ~m(user_id type article_id action comment_id)a = attrs - n_hour_ago = Timex.shift(Timex.now(), hours: -@notify_group_interval_hour) - - from(n in Notification, - where: n.inserted_at >= ^n_hour_ago, - where: n.user_id == ^user_id, - where: n.type == ^type, - where: n.article_id == ^article_id, - where: n.comment_id == ^comment_id, - where: n.action == ^action, - where: n.read == false - ) - |> Repo.one() - |> done + ~m(type article_id comment_id)a = atom_values_to_upcase(attrs) + + Notification + |> where([n], n.type == ^type and n.article_id == ^article_id and n.comment_id == ^comment_id) + |> do_find_similar(attrs) + end + + defp similar_notify_latest_peroid(attrs) do + ~m(type article_id)a = atom_values_to_upcase(attrs) + + Notification + |> where([n], n.type == ^type and n.article_id == ^article_id) + |> do_find_similar(attrs) end - defp similar_action_in_latest_notify(attrs) do - ~m(user_id type article_id action)a = attrs - n_hour_ago = Timex.shift(Timex.now(), hours: -@notify_group_interval_hour) - - from(n in Notification, - where: n.inserted_at >= ^n_hour_ago, - where: n.user_id == ^user_id, - where: n.type == ^type, - where: n.article_id == ^article_id, - where: n.action == ^action, - where: n.read == false - ) + defp do_find_similar(queryable, attrs) do + ~m(user_id action)a = atom_values_to_upcase(attrs) + + queryable + |> where([n], n.inserted_at >= ^interval_threshold_time() and n.user_id == ^user_id) + |> where([n], n.action == ^action and n.read == false) |> Repo.one() |> done end - def paged_notifications(user_id, %{page: page, size: size} = filter) do - read = Map.get(filter, :read, false) + # [:upvote, :comment, :reply, :collect, :follow] + defp is_valid?(%{action: :upvote, type: :comment} = attrs) do + attrs |> all_exist?([:article_id, :type, :title, :comment_id, :user_id]) + end - Notification - |> where([n], n.user_id == ^user_id) - |> where([n], n.read == ^read) - |> ORM.paginater(~m(page size)a) - |> done() + defp is_valid?(%{action: :upvote} = attrs) do + attrs |> all_exist?([:article_id, :type, :title, :user_id]) + end + + defp is_valid?(%{action: :comment} = attrs) do + attrs |> all_exist?([:article_id, :type, :title, :user_id]) + end + + defp is_valid?(%{action: :reply} = attrs) do + attrs |> all_exist?([:article_id, :type, :title, :comment_id, :user_id]) + end + + defp is_valid?(%{action: :collect} = attrs) do + attrs |> all_exist?([:article_id, :type, :title, :user_id]) + end + + defp is_valid?(%{action: :follow} = attrs), do: attrs |> all_exist?([:user_id]) + + # 确保 key 存在,并且不为 nil + defp all_exist?(attrs, keys) when is_map(attrs) and is_list(keys) do + Enum.all?(keys, fn key -> + Map.has_key?(attrs, key) and not is_nil(attrs[key]) + end) + end + + # 此时间段内的相似通知会被 merge + defp interval_threshold_time() do + Timex.shift(Timex.now(), hours: -@notify_group_interval_hour) end end diff --git a/lib/groupher_server/delivery/delegates/postman.ex b/lib/groupher_server/delivery/delegates/postman.ex index fafca5234..a1702bcab 100644 --- a/lib/groupher_server/delivery/delegates/postman.ex +++ b/lib/groupher_server/delivery/delegates/postman.ex @@ -13,6 +13,11 @@ defmodule GroupherServer.Delivery.Delegate.Postman do Notification.handle(attrs, from_user) end + # TODO: + # def revoke(:notify, attrs, from_user) do + # Notification.handle(attrs, from_user) + # end + def fetch(:mention, user, filter) do Mention.paged_mentions(user, filter) end diff --git a/lib/helper/utils/map.ex b/lib/helper/utils/map.ex index 4bb43f6cc..02bba9e70 100644 --- a/lib/helper/utils/map.ex +++ b/lib/helper/utils/map.ex @@ -8,17 +8,17 @@ defmodule Helper.Utils.Map do e.g: %{hello: :world} # -> %{hello: "WORLD"} """ - def map_atom_values_to_upcase_str(map) when is_map(map) do + def atom_values_to_upcase(map) when is_map(map) do map |> Enum.reduce(%{}, fn {key, val}, acc -> - case is_atom(val) do + case val !== true and val !== false and is_atom(val) do true -> Map.put(acc, key, val |> to_string |> String.upcase()) false -> Map.put(acc, key, val) end end) end - def map_atom_values_to_upcase_str(value), do: value + def atom_values_to_upcase(value), do: value def map_key_stringify(%{__struct__: _} = map) when is_map(map) do map = Map.from_struct(map) diff --git a/lib/helper/utils/utils.ex b/lib/helper/utils/utils.ex index ff2916061..18a8a35f3 100644 --- a/lib/helper/utils/utils.ex +++ b/lib/helper/utils/utils.ex @@ -11,7 +11,7 @@ defmodule Helper.Utils do alias Helper.{Cache, Utils} # Map utils - defdelegate map_atom_values_to_upcase_str(map), to: Utils.Map + defdelegate atom_values_to_upcase(map), to: Utils.Map defdelegate map_key_stringify(map), to: Utils.Map defdelegate keys_to_atoms(map), to: Utils.Map defdelegate keys_to_strings(map), to: Utils.Map diff --git a/test/groupher_server/cms/hooks/mention_in_blog_test.exs b/test/groupher_server/cms/hooks/mention_in_blog_test.exs index 638c49211..e1b5eefed 100644 --- a/test/groupher_server/cms/hooks/mention_in_blog_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_blog_test.exs @@ -1,14 +1,11 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInBlog do use GroupherServer.TestTools - import Helper.Utils, only: [get_config: 2] import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] alias GroupherServer.{CMS, Delivery} alias CMS.Delegate.Hooks - @site_host get_config(:general, :site_host) - @article_mention_class "cdx-mention" setup do diff --git a/test/groupher_server/cms/hooks/mention_in_job_test.exs b/test/groupher_server/cms/hooks/mention_in_job_test.exs index 84481f2b1..55c4b96bf 100644 --- a/test/groupher_server/cms/hooks/mention_in_job_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_job_test.exs @@ -1,14 +1,11 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInJob do use GroupherServer.TestTools - import Helper.Utils, only: [get_config: 2] import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] alias GroupherServer.{CMS, Delivery} alias CMS.Delegate.Hooks - @site_host get_config(:general, :site_host) - @article_mention_class "cdx-mention" setup do diff --git a/test/groupher_server/cms/hooks/mention_in_post_test.exs b/test/groupher_server/cms/hooks/mention_in_post_test.exs index 6566c78ff..f86849921 100644 --- a/test/groupher_server/cms/hooks/mention_in_post_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_post_test.exs @@ -1,14 +1,11 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do use GroupherServer.TestTools - import Helper.Utils, only: [get_config: 2] import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] alias GroupherServer.{CMS, Delivery} alias CMS.Delegate.Hooks - @site_host get_config(:general, :site_host) - @article_mention_class "cdx-mention" setup do diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index 24890d4ae..50b5ae6e7 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -2,9 +2,11 @@ defmodule GroupherServer.Test.Delivery.Notification do use GroupherServer.TestTools import Ecto.Query, warn: false - # import Helper.Utils + import Helper.Utils, only: [get_config: 2] - alias GroupherServer.Delivery + alias GroupherServer.{Delivery, Repo} + + @notify_group_interval_hour get_config(:general, :notify_group_interval_hour) setup do {:ok, post} = db_insert(:post) @@ -13,28 +15,136 @@ defmodule GroupherServer.Test.Delivery.Notification do {:ok, user3} = db_insert(:user) {:ok, community} = db_insert(:community) - notify = %{ - type: "POST", + notify_attrs = %{ + type: :post, article_id: post.id, title: post.title, - action: "UPVOTE", + action: :upvote, user_id: user.id, read: false - # inserted_at: post.updated_at |> DateTime.truncate(:second), } - {:ok, ~m(community post user user2 user3 notify)a} + {:ok, ~m(community post user user2 user3 notify_attrs)a} end describe "notification curd" do @tag :wip - test "can insert notification.", ~m(post user user2 user3 notify)a do - {:ok, _} = Delivery.send(:notify, notify, user2) - {:ok, _} = Delivery.send(:notify, notify, user3) + test "similar notify should be merged", ~m(user user2 user3 notify_attrs)a do + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + {:ok, _} = Delivery.send(:notify, notify_attrs, user3) + + {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + + notify = paged_notifies.entries |> List.first() + + assert paged_notifies.total_count == 1 + + assert notify.from_users |> length == 2 + assert user2 |> user_exist_in?(notify.from_users) + assert user3 |> user_exist_in?(notify.from_users) + end + + @tag :wip + test "different notify should not be merged", ~m(user user2 user3 notify_attrs)a do + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + notify_attrs = notify_attrs |> Map.put(:action, :collect) + {:ok, _} = Delivery.send(:notify, notify_attrs, user3) + + {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + + assert paged_notifies.total_count == 2 + + notify1 = paged_notifies.entries |> List.first() + notify2 = paged_notifies.entries |> List.last() + + assert user3 |> user_exist_in?(notify1.from_users) + assert user2 |> user_exist_in?(notify2.from_users) + end + + @tag :wip + test "notify not in @notify_group_interval_hour should not be merged", + ~m(user user2 user3 notify_attrs)a do + {:ok, notify} = Delivery.send(:notify, notify_attrs, user2) + + before_inserted_at = + Timex.shift(Timex.now(), hours: -@notify_group_interval_hour, minutes: -1) + |> DateTime.truncate(:second) + + notify + |> Ecto.Changeset.change(%{inserted_at: before_inserted_at}) + |> Repo.update() + + {:ok, _} = Delivery.send(:notify, notify_attrs, user3) + + {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + + assert paged_notifies.total_count == 2 + + notify1 = paged_notifies.entries |> List.first() + notify2 = paged_notifies.entries |> List.last() + + assert user3 |> user_exist_in?(notify1.from_users) + assert user2 |> user_exist_in?(notify2.from_users) + end + + # @tag :wip + # test "notify myself got ignored" do + # end + end + + describe "basic type support" do + @tag :wip + test "support upvote", ~m(post user user2 notify_attrs)a do + notify_attrs + |> Map.merge(%{ + type: :post, + article_id: post.id, + title: post.title, + action: :upvote, + user_id: user.id + }) + + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + + notify_attrs + |> Map.merge(%{ + type: :comment, + article_id: post.id, + comment_id: 11, + title: post.title, + action: :upvote, + user_id: user.id + }) + + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + + invalid_notify_attrs = + notify_attrs + |> Map.merge(%{ + type: :comment, + article_id: post.id, + title: post.title, + action: :upvote, + user_id: user.id + }) + + {:error, _} = Delivery.send(:notify, invalid_notify_attrs, user2) + end + + @tag :wip + test "support follow", ~m(user user2)a do + notify_attrs = %{ + action: :follow, + user_id: user.id + } + + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) - {:ok, hello} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + invalid_notify_attrs = %{ + action: :follow + } - IO.inspect(hello, label: "hello") + {:error, _} = Delivery.send(:notify, invalid_notify_attrs, user2) end end end diff --git a/test/helper/utils_test.exs b/test/helper/utils_test.exs index b33e73117..24dcb107e 100644 --- a/test/helper/utils_test.exs +++ b/test/helper/utils_test.exs @@ -12,7 +12,7 @@ defmodule GroupherServer.Test.Helper.UtilsTest do other: "hello" } - result = Utils.map_atom_values_to_upcase_str(map) + result = Utils.atom_values_to_upcase(map) assert result.color == "GREEN" assert result.thread == "POST" diff --git a/test/support/assert_helper.ex b/test/support/assert_helper.ex index 1b358f421..47cd0fd3b 100644 --- a/test/support/assert_helper.ex +++ b/test/support/assert_helper.ex @@ -12,7 +12,6 @@ defmodule GroupherServer.Test.AssertHelper do @endpoint GroupherServerWeb.Endpoint - @page_size get_config(:general, :page_size) @inner_page_size get_config(:general, :inner_page_size) @doc """ From a0339683254f864977a147c1b56e120307979e6e Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sat, 19 Jun 2021 20:06:53 +0800 Subject: [PATCH 22/54] refactor(delivery): notification wip --- .../delivery/delegates/notification.ex | 9 +- .../delivery/notification_test.exs | 89 +++++++++++++++++-- 2 files changed, 86 insertions(+), 12 deletions(-) diff --git a/lib/groupher_server/delivery/delegates/notification.ex b/lib/groupher_server/delivery/delegates/notification.ex index 9cb511ad3..756e71bb5 100644 --- a/lib/groupher_server/delivery/delegates/notification.ex +++ b/lib/groupher_server/delivery/delegates/notification.ex @@ -17,9 +17,10 @@ defmodule GroupherServer.Delivery.Delegate.Notification do @supported_notify_type get_config(:general, :nofity_types) @notify_group_interval_hour get_config(:general, :notify_group_interval_hour) - def handle(%{action: action} = attrs, %User{} = from_user) do + def handle(%{action: action, user_id: user_id} = attrs, %User{} = from_user) do with true <- action in @supported_notify_type, - true <- is_valid?(attrs) do + true <- is_valid?(attrs), + true <- user_id !== from_user.id do from_user = from_user |> Map.take([:login, :nickname]) |> Map.put(:user_id, from_user.id) case similar_notify_latest_peroid(attrs) do @@ -99,7 +100,7 @@ defmodule GroupherServer.Delivery.Delegate.Notification do end defp is_valid?(%{action: :comment} = attrs) do - attrs |> all_exist?([:article_id, :type, :title, :user_id]) + attrs |> all_exist?([:article_id, :type, :title, :comment_id, :user_id]) end defp is_valid?(%{action: :reply} = attrs) do @@ -112,6 +113,8 @@ defmodule GroupherServer.Delivery.Delegate.Notification do defp is_valid?(%{action: :follow} = attrs), do: attrs |> all_exist?([:user_id]) + defp is_valid?(_), do: false + # 确保 key 存在,并且不为 nil defp all_exist?(attrs, keys) when is_map(attrs) and is_list(keys) do Enum.all?(keys, fn key -> diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index 50b5ae6e7..cbe4a4afa 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -87,9 +87,10 @@ defmodule GroupherServer.Test.Delivery.Notification do assert user2 |> user_exist_in?(notify2.from_users) end - # @tag :wip - # test "notify myself got ignored" do - # end + @tag :wip + test "notify myself got ignored", ~m(user notify_attrs)a do + {:error, _} = Delivery.send(:notify, notify_attrs, user) + end end describe "basic type support" do @@ -131,6 +132,82 @@ defmodule GroupherServer.Test.Delivery.Notification do {:error, _} = Delivery.send(:notify, invalid_notify_attrs, user2) end + @tag :wip + test "support collect", ~m(post user user2 notify_attrs)a do + notify_attrs + |> Map.merge(%{ + type: :post, + article_id: post.id, + title: post.title, + action: :collect, + user_id: user.id + }) + + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + + invalid_notify_attrs = + notify_attrs + |> Map.merge(%{ + article_id: nil, + title: post.title, + action: :collect, + user_id: user.id + }) + + {:error, _} = Delivery.send(:notify, invalid_notify_attrs, user2) + end + + @tag :wip + test "support comment and reply", ~m(post user user2 notify_attrs)a do + notify_attrs + |> Map.merge(%{ + type: :post, + article_id: post.id, + title: post.title, + comment_id: 11, + action: :comment, + user_id: user.id + }) + + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + + notify_attrs + |> Map.merge(%{ + type: :post, + article_id: post.id, + comment_id: 11, + title: post.title, + action: :reply, + user_id: user.id + }) + + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + + invalid_notify_attrs = + notify_attrs + |> Map.merge(%{ + type: :post, + article_id: post.id, + title: post.title, + action: :comment, + user_id: user.id + }) + + {:error, _} = Delivery.send(:notify, invalid_notify_attrs, user2) + + invalid_notify_attrs = + notify_attrs + |> Map.merge(%{ + type: :post, + article_id: post.id, + title: post.title, + action: :reply, + user_id: user.id + }) + + {:error, _} = Delivery.send(:notify, invalid_notify_attrs, user2) + end + @tag :wip test "support follow", ~m(user user2)a do notify_attrs = %{ @@ -139,12 +216,6 @@ defmodule GroupherServer.Test.Delivery.Notification do } {:ok, _} = Delivery.send(:notify, notify_attrs, user2) - - invalid_notify_attrs = %{ - action: :follow - } - - {:error, _} = Delivery.send(:notify, invalid_notify_attrs, user2) end end end From 59adb5e724fc2d7bea205482711d3ae3d9a855db Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 01:04:28 +0800 Subject: [PATCH 23/54] refactor(delivery): notification wip, cool --- .../delivery/delegates/notification.ex | 56 ++++++++-- .../delivery/delegates/postman.ex | 20 +--- lib/groupher_server/delivery/delivery.ex | 1 + .../delivery/notification_test.exs | 101 ++++++++++++++++-- 4 files changed, 146 insertions(+), 32 deletions(-) diff --git a/lib/groupher_server/delivery/delegates/notification.ex b/lib/groupher_server/delivery/delegates/notification.ex index 756e71bb5..4c90e20cf 100644 --- a/lib/groupher_server/delivery/delegates/notification.ex +++ b/lib/groupher_server/delivery/delegates/notification.ex @@ -23,7 +23,7 @@ defmodule GroupherServer.Delivery.Delegate.Notification do true <- user_id !== from_user.id do from_user = from_user |> Map.take([:login, :nickname]) |> Map.put(:user_id, from_user.id) - case similar_notify_latest_peroid(attrs) do + case find_exist_notify(attrs, :latest_peroid) do {:ok, notify} -> merge_notification(notify, from_user) {:error, _} -> create_notification(attrs, from_user) end @@ -33,6 +33,30 @@ defmodule GroupherServer.Delivery.Delegate.Notification do end end + @doc "revoke action in notification in all history" + def revoke(attrs, %User{} = from_user) do + attrs = attrs |> Map.put(:from_user, from_user) + + with {:ok, notifications} <- find_exist_notify(attrs, :all) do + Enum.each(notifications, fn notify -> + case length(notify.from_users) == 1 do + # 只有一就删除记录 + true -> + ORM.delete(notify) + + # 如果是多人集合就在 from_users 中删除该用户 + false -> + from_users = Enum.reject(notify.from_users, &(&1.login == from_user.login)) + notify |> ORM.update_embed(:from_users, from_users) + end + end) + |> done + else + false -> {:ok, :pass} + {:error, _} -> {:ok, :pass} + end + end + def paged_notifications(user_id, %{page: page, size: size} = filter) do read = Map.get(filter, :read, false) @@ -59,28 +83,28 @@ defmodule GroupherServer.Delivery.Delegate.Notification do |> Repo.insert() end - defp similar_notify_latest_peroid(%{action: :follow} = attrs) do - do_find_similar(Notification, attrs) + defp find_exist_notify(%{action: :follow} = attrs, opt) do + do_find_exist_notify(Notification, attrs, opt) end - defp similar_notify_latest_peroid(%{comment_id: comment_id} = attrs) + defp find_exist_notify(%{comment_id: comment_id} = attrs, opt) when not is_nil(comment_id) do ~m(type article_id comment_id)a = atom_values_to_upcase(attrs) Notification |> where([n], n.type == ^type and n.article_id == ^article_id and n.comment_id == ^comment_id) - |> do_find_similar(attrs) + |> do_find_exist_notify(attrs, opt) end - defp similar_notify_latest_peroid(attrs) do + defp find_exist_notify(attrs, opt) do ~m(type article_id)a = atom_values_to_upcase(attrs) Notification |> where([n], n.type == ^type and n.article_id == ^article_id) - |> do_find_similar(attrs) + |> do_find_exist_notify(attrs, opt) end - defp do_find_similar(queryable, attrs) do + defp do_find_exist_notify(queryable, attrs, :latest_peroid) do ~m(user_id action)a = atom_values_to_upcase(attrs) queryable @@ -90,6 +114,22 @@ defmodule GroupherServer.Delivery.Delegate.Notification do |> done end + defp do_find_exist_notify(queryable, attrs, _opt) do + ~m(user_id action from_user)a = atom_values_to_upcase(attrs) + + queryable = queryable |> where([n], n.user_id == ^user_id and n.action == ^action) + + # select login in from_users + # see https://stackoverflow.com/questions/51267155/in-postgresql-how-can-i-select-rows-where-a-jsonb-array-contains-objects + # see https://elixirforum.com/t/writing-queries-with-multiple-from-clauses/28646/2?u=mydearxym + from(n in queryable, + cross_join: fu in fragment("jsonb_array_elements(?)", n.from_users), + where: fragment("?->>'login' = ?", fu, ^from_user.login) + ) + |> Repo.all() + |> done + end + # [:upvote, :comment, :reply, :collect, :follow] defp is_valid?(%{action: :upvote, type: :comment} = attrs) do attrs |> all_exist?([:article_id, :type, :title, :comment_id, :user_id]) diff --git a/lib/groupher_server/delivery/delegates/postman.ex b/lib/groupher_server/delivery/delegates/postman.ex index a1702bcab..5aca37b14 100644 --- a/lib/groupher_server/delivery/delegates/postman.ex +++ b/lib/groupher_server/delivery/delegates/postman.ex @@ -9,22 +9,10 @@ defmodule GroupherServer.Delivery.Delegate.Postman do Mention.handle(artiment, mentions, from_user) end - def send(:notify, attrs, from_user) do - Notification.handle(attrs, from_user) - end - - # TODO: - # def revoke(:notify, attrs, from_user) do - # Notification.handle(attrs, from_user) - # end - - def fetch(:mention, user, filter) do - Mention.paged_mentions(user, filter) - end - - def fetch(:notification, user, filter) do - Notification.paged_notifications(user, filter) - end + def send(:notify, attrs, from_user), do: Notification.handle(attrs, from_user) + def revoke(:notify, attrs, from_user), do: Notification.revoke(attrs, from_user) + def fetch(:mention, user, filter), do: Mention.paged_mentions(user, filter) + def fetch(:notification, user, filter), do: Notification.paged_notifications(user, filter) # def send(_, _, _), do: {:error, "delivery, not such service"} # def send(_, _, _, _), do: {:error, "delivery, not such service"} diff --git a/lib/groupher_server/delivery/delivery.ex b/lib/groupher_server/delivery/delivery.ex index 0f09075cd..d4ee3d670 100644 --- a/lib/groupher_server/delivery/delivery.ex +++ b/lib/groupher_server/delivery/delivery.ex @@ -10,6 +10,7 @@ defmodule GroupherServer.Delivery do defdelegate send(service, artiment, mentions, from_user), to: Postman defdelegate send(service, attrs, from_user), to: Postman + defdelegate revoke(service, attrs, from_user), to: Postman defdelegate fetch(service, user, filter), to: Postman # system_notifications diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index cbe4a4afa..dac6fa000 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -13,6 +13,7 @@ defmodule GroupherServer.Test.Delivery.Notification do {:ok, user} = db_insert(:user) {:ok, user2} = db_insert(:user) {:ok, user3} = db_insert(:user) + {:ok, user4} = db_insert(:user) {:ok, community} = db_insert(:community) notify_attrs = %{ @@ -24,7 +25,18 @@ defmodule GroupherServer.Test.Delivery.Notification do read: false } - {:ok, ~m(community post user user2 user3 notify_attrs)a} + {:ok, ~m(community post user user2 user3 user4 notify_attrs)a} + end + + # 将插入时间模拟到 @notify_group_interval_hour 之前, 防止折叠 + defp move_insert_at_long_ago(notify) do + before_inserted_at = + Timex.shift(Timex.now(), hours: -@notify_group_interval_hour, minutes: -1) + |> DateTime.truncate(:second) + + notify + |> Ecto.Changeset.change(%{inserted_at: before_inserted_at}) + |> Repo.update() end describe "notification curd" do @@ -66,13 +78,7 @@ defmodule GroupherServer.Test.Delivery.Notification do ~m(user user2 user3 notify_attrs)a do {:ok, notify} = Delivery.send(:notify, notify_attrs, user2) - before_inserted_at = - Timex.shift(Timex.now(), hours: -@notify_group_interval_hour, minutes: -1) - |> DateTime.truncate(:second) - - notify - |> Ecto.Changeset.change(%{inserted_at: before_inserted_at}) - |> Repo.update() + move_insert_at_long_ago(notify) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) @@ -93,6 +99,85 @@ defmodule GroupherServer.Test.Delivery.Notification do end end + describe "revoke case" do + # @tag :wip + test "can revoke a notification", ~m(user user2 notify_attrs)a do + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + + {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + assert paged_notifies.total_count == 1 + + Delivery.revoke(:notify, notify_attrs, user2) + + {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + assert paged_notifies.total_count == 0 + end + + # @tag :wip + test "can revoke a multi-user joined notification", ~m(user user2 user3 notify_attrs)a do + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + {:ok, _} = Delivery.send(:notify, notify_attrs, user3) + + {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + assert paged_notifies.total_count == 1 + notify = paged_notifies.entries |> List.first() + assert user_exist_in?(user2, notify.from_users) + assert user_exist_in?(user3, notify.from_users) + + Delivery.revoke(:notify, notify_attrs, user2) + + {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + assert paged_notifies.total_count == 1 + + notify = paged_notifies.entries |> List.first() + assert not user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "can revoke a multi-user joined notification, long peroid", + ~m(user user2 user3 notify_attrs)a do + {:ok, notify} = Delivery.send(:notify, notify_attrs, user2) + + move_insert_at_long_ago(notify) + + {:ok, _} = Delivery.send(:notify, notify_attrs, user3) + + {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + assert paged_notifies.total_count == 2 + + Delivery.revoke(:notify, notify_attrs, user2) + + {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + assert paged_notifies.total_count == 1 + notify = paged_notifies.entries |> List.first() + assert not user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "can revoke a multi-user joined notification, long peroid, edge case", + ~m(user user2 user3 user4 notify_attrs)a do + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + {:ok, notify} = Delivery.send(:notify, notify_attrs, user3) + + move_insert_at_long_ago(notify) + + {:ok, _} = Delivery.send(:notify, notify_attrs, user4) + + {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + assert paged_notifies.total_count == 2 + + Delivery.revoke(:notify, notify_attrs, user2) + + {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + assert paged_notifies.total_count == 2 + notify1 = paged_notifies.entries |> List.first() + notify2 = paged_notifies.entries |> List.last() + + assert not user_exist_in?(user2, notify1.from_users) + assert not user_exist_in?(user2, notify2.from_users) + end + end + describe "basic type support" do @tag :wip test "support upvote", ~m(post user user2 notify_attrs)a do From 2fb8209648120fd9d1abf4b19c7b75894d81a96a Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 10:08:47 +0800 Subject: [PATCH 24/54] refactor(delivery): use common atom key --- .../cms/delegates/cited_artiment.ex | 9 ++++++--- lib/groupher_server/cms/delegates/hooks/cite.ex | 14 +++++--------- .../delivery/delegates/notification.ex | 9 +++++++++ lib/helper/utils/utils.ex | 4 ++++ 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/lib/groupher_server/cms/delegates/cited_artiment.ex b/lib/groupher_server/cms/delegates/cited_artiment.ex index f6dcbef8a..3399fb32d 100644 --- a/lib/groupher_server/cms/delegates/cited_artiment.ex +++ b/lib/groupher_server/cms/delegates/cited_artiment.ex @@ -4,7 +4,9 @@ defmodule GroupherServer.CMS.Delegate.CitedArtiment do """ import Ecto.Query, warn: false - import Helper.Utils, only: [done: 1, get_config: 2, thread_of_article: 1] + import Helper.Utils, + only: [done: 1, get_config: 2, thread_of_article: 1, atom_values_to_upcase: 1, to_upcase: 1] + import GroupherServer.CMS.Helper.Matcher import ShortMaps @@ -24,7 +26,7 @@ defmodule GroupherServer.CMS.Delegate.CitedArtiment do @doc "get paged citing contents" def paged_citing_contents(cited_by_type, cited_by_id, %{page: page, size: size} = filter) do - cited_by_type = cited_by_type |> to_string |> String.upcase() + cited_by_type = to_upcase(cited_by_type) CitedArtiment |> where([c], c.cited_by_id == ^cited_by_id and c.cited_by_type == ^cited_by_type) @@ -45,7 +47,7 @@ defmodule GroupherServer.CMS.Delegate.CitedArtiment do def batch_delete_by(article) do with {:ok, thread} <- thread_of_article(article), {:ok, info} <- match(thread) do - thread = thread |> to_string |> String.upcase() + thread = to_upcase(thread) from(c in CitedArtiment, where: field(c, ^info.foreign_key) == ^article.id and c.cited_by_type == ^thread @@ -66,6 +68,7 @@ defmodule GroupherServer.CMS.Delegate.CitedArtiment do cited_artiments |> Enum.map(&Map.merge(&1, %{inserted_at: &1.citing_time, updated_at: &1.citing_time})) |> Enum.map(&Map.drop(&1, [:artiment, :citing_time])) + |> Enum.map(&atom_values_to_upcase(&1)) case {0, nil} !== Repo.insert_all(CitedArtiment, clean_cited_artiments) do true -> update_artiment_citing_count(cited_artiments) diff --git a/lib/groupher_server/cms/delegates/hooks/cite.ex b/lib/groupher_server/cms/delegates/hooks/cite.ex index 22982a4b2..dc6e30e1b 100644 --- a/lib/groupher_server/cms/delegates/hooks/cite.ex +++ b/lib/groupher_server/cms/delegates/hooks/cite.ex @@ -66,7 +66,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do %{ block_linker: ["block-ZgKJs"], cited_by_id: 190057, - cited_by_type: "POST", + cited_by_type: :post, artiment: #loaded, post_id: 190059, user_id: 1413053 @@ -176,11 +176,9 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do # cite article in comment # 在评论中引用文章 defp shape(%Comment{} = comment, %{type: :article, artiment: cited}, block_id) do - cited_by_type = cited.meta.thread |> to_string |> String.upcase() - %{ cited_by_id: cited.id, - cited_by_type: cited_by_type, + cited_by_type: cited.meta.thread, comment_id: comment.id, block_linker: [block_id], user_id: comment.author_id, @@ -197,7 +195,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do defp shape(%Comment{} = comment, %{type: :comment, artiment: cited}, block_id) do %{ cited_by_id: cited.id, - cited_by_type: "COMMENT", + cited_by_type: :comment, comment_id: comment.id, block_linker: [block_id], user_id: comment.author_id, @@ -215,11 +213,9 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do {:ok, thread} = thread_of_article(article) {:ok, info} = match(thread) - cited_by_type = cited.meta.thread |> to_string |> String.upcase() - %{ cited_by_id: cited.id, - cited_by_type: cited_by_type, + cited_by_type: cited.meta.thread, block_linker: [block_id], user_id: article.author.user.id, # extra fields for next-step usage @@ -239,7 +235,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do %{ cited_by_id: cited.id, - cited_by_type: "COMMENT", + cited_by_type: :comment, block_linker: [block_id], user_id: article.author.user.id, # extra fields for next-step usage diff --git a/lib/groupher_server/delivery/delegates/notification.ex b/lib/groupher_server/delivery/delegates/notification.ex index 4c90e20cf..9ff8d3bc0 100644 --- a/lib/groupher_server/delivery/delegates/notification.ex +++ b/lib/groupher_server/delivery/delegates/notification.ex @@ -76,6 +76,7 @@ defmodule GroupherServer.Delivery.Delegate.Notification do notify |> ORM.update_embed(:from_users, from_users) end + # 创建通知 defp create_notification(attrs, from_user) do %Notification{} |> Ecto.Changeset.change(atom_values_to_upcase(attrs)) @@ -104,6 +105,10 @@ defmodule GroupherServer.Delivery.Delegate.Notification do |> do_find_exist_notify(attrs, opt) end + # find exist notification, in latest peroid + # 在最近的时期内,找到一个存在的通知 + @spec do_find_exist_notify(Ecto.Queryable.t(), Map.t(), Atom.t()) :: + {Atom.t(), Notification.t()} defp do_find_exist_notify(queryable, attrs, :latest_peroid) do ~m(user_id action)a = atom_values_to_upcase(attrs) @@ -114,6 +119,10 @@ defmodule GroupherServer.Delivery.Delegate.Notification do |> done end + # find exist notifications, in all history + # 在所有通知中,找到多个存在的通知 + @spec do_find_exist_notify(Ecto.Queryable.t(), Map.t(), Atom.t()) :: + {Atom.t(), [Notification.t()]} defp do_find_exist_notify(queryable, attrs, _opt) do ~m(user_id action from_user)a = atom_values_to_upcase(attrs) diff --git a/lib/helper/utils/utils.ex b/lib/helper/utils/utils.ex index 18a8a35f3..4d321b318 100644 --- a/lib/helper/utils/utils.ex +++ b/lib/helper/utils/utils.ex @@ -221,6 +221,10 @@ defmodule Helper.Utils do thread |> to_string |> String.upcase() |> done end + def to_upcase(v) when is_atom(v), do: v |> to_string |> String.upcase() + def to_upcase(v) when is_binary(v), do: v |> String.upcase() + def to_upcase(_), do: nil + def uid(str_len \\ 5) do Nanoid.generate(str_len, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") end From f253a880f20ab2e18081c73261a349e3a233e76b Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 12:51:04 +0800 Subject: [PATCH 25/54] refactor(delivery): upvote hooks --- .../cms/delegates/article_upvote.ex | 13 +++- .../cms/delegates/hooks/notify.ex | 45 ++++++++++++++ .../cms/hooks/notify_post_test.exs | 62 +++++++++++++++++++ .../delivery/notification_test.exs | 12 ---- 4 files changed, 117 insertions(+), 15 deletions(-) create mode 100644 lib/groupher_server/cms/delegates/hooks/notify.ex create mode 100644 test/groupher_server/cms/hooks/notify_post_test.exs diff --git a/lib/groupher_server/cms/delegates/article_upvote.ex b/lib/groupher_server/cms/delegates/article_upvote.ex index 9f0cec4c7..6bff40a14 100644 --- a/lib/groupher_server/cms/delegates/article_upvote.ex +++ b/lib/groupher_server/cms/delegates/article_upvote.ex @@ -15,11 +15,12 @@ defmodule GroupherServer.CMS.Delegate.ArticleUpvote do # import Helper.ErrorCode - alias Helper.ORM + alias Helper.{ORM, Later} alias GroupherServer.{Accounts, CMS, Repo} alias Accounts.Model.User alias CMS.Model.ArticleUpvote + alias CMS.Delegate.Hooks alias Ecto.Multi @@ -28,7 +29,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleUpvote do end @doc "upvote to a article-like content" - def upvote_article(thread, article_id, %User{id: user_id}) do + def upvote_article(thread, article_id, %User{id: user_id} = from_user) do with {:ok, info} <- match(thread), {:ok, article} <- ORM.find(info.model, article_id, preload: [author: :user]) do Multi.new() @@ -50,13 +51,16 @@ defmodule GroupherServer.CMS.Delegate.ArticleUpvote do ORM.find(info.model, article.id) end end) + |> Multi.run(:after_hooks, fn _, _ -> + Later.run({Hooks.Notify, :handle, [:upvote, article, from_user]}) + end) |> Repo.transaction() |> result() end end @doc "upvote to a article-like content" - def undo_upvote_article(thread, article_id, %User{id: user_id}) do + def undo_upvote_article(thread, article_id, %User{id: user_id} = from_user) do with {:ok, info} <- match(thread), {:ok, article} <- ORM.find(info.model, article_id) do Multi.new() @@ -72,6 +76,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleUpvote do ORM.findby_delete(ArticleUpvote, args) ORM.find(info.model, article.id) end) + |> Multi.run(:after_hooks, fn _, _ -> + Later.run({Hooks.Notify, :handle, [:undo, :upvote, article, from_user]}) + end) |> Repo.transaction() |> result() end diff --git a/lib/groupher_server/cms/delegates/hooks/notify.ex b/lib/groupher_server/cms/delegates/hooks/notify.ex new file mode 100644 index 000000000..8d5998a7d --- /dev/null +++ b/lib/groupher_server/cms/delegates/hooks/notify.ex @@ -0,0 +1,45 @@ +defmodule GroupherServer.CMS.Delegate.Hooks.Notify do + @moduledoc """ + notify hooks, for upvote, collect, comment, reply + """ + import Helper.Utils, only: [get_config: 2, thread_of_article: 1] + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] + + alias GroupherServer.{Accounts, CMS, Delivery, Repo} + + alias Accounts.Model.User + alias CMS.Model.Comment + + # def handle(action, %Comment{id: comment_id} = comment, %User{} = from_user) do + # end + + def handle(:undo, action, article, %User{} = from_user) do + {:ok, article} = preload_author(article) + {:ok, thread} = thread_of_article(article) + + notify_attrs = %{ + type: thread, + article_id: article.id, + action: action, + user_id: article.author.user.id + } + + Delivery.revoke(:notify, notify_attrs, from_user) + end + + def handle(action, article, %User{} = from_user) do + {:ok, article} = preload_author(article) + + {:ok, thread} = thread_of_article(article) + + notify_attrs = %{ + type: thread, + article_id: article.id, + title: article.title, + action: action, + user_id: article.author.user.id + } + + Delivery.send(:notify, notify_attrs, from_user) + end +end diff --git a/test/groupher_server/cms/hooks/notify_post_test.exs b/test/groupher_server/cms/hooks/notify_post_test.exs new file mode 100644 index 000000000..cd3e08cf3 --- /dev/null +++ b/test/groupher_server/cms/hooks/notify_post_test.exs @@ -0,0 +1,62 @@ +defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do + use GroupherServer.TestTools + + import Helper.Utils, only: [get_config: 2] + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] + + alias GroupherServer.{CMS, Delivery} + + # alias CMS.Model.{Comment} + alias CMS.Delegate.Hooks + + @site_host get_config(:general, :site_host) + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + + {:ok, community} = db_insert(:community) + + post_attrs = mock_attrs(:post, %{community_id: community.id}) + {:ok, post} = CMS.create_article(community, :post, post_attrs, user) + + {:ok, ~m(user2 post)a} + end + + describe "[upvote notify]" do + @tag :wip + test "upvote hook should work", ~m(user2 post)a do + {:ok, post} = preload_author(post) + + {:ok, article} = CMS.upvote_article(:post, post.id, user2) + Hooks.Notify.handle(:upvote, article, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, post.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.article_id == post.id + assert notify.type == "POST" + assert notify.user_id == post.author.user.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "undo upvote hook should work", ~m(user2 post)a do + {:ok, post} = preload_author(post) + + {:ok, article} = CMS.upvote_article(:post, post.id, user2) + Hooks.Notify.handle(:upvote, article, user2) + + {:ok, article} = CMS.undo_upvote_article(:post, post.id, user2) + Hooks.Notify.handle(:undo, :upvote, article, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, post.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + end +end diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index dac6fa000..7f5fad0e2 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -40,7 +40,6 @@ defmodule GroupherServer.Test.Delivery.Notification do end describe "notification curd" do - @tag :wip test "similar notify should be merged", ~m(user user2 user3 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) @@ -56,7 +55,6 @@ defmodule GroupherServer.Test.Delivery.Notification do assert user3 |> user_exist_in?(notify.from_users) end - @tag :wip test "different notify should not be merged", ~m(user user2 user3 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) notify_attrs = notify_attrs |> Map.put(:action, :collect) @@ -73,7 +71,6 @@ defmodule GroupherServer.Test.Delivery.Notification do assert user2 |> user_exist_in?(notify2.from_users) end - @tag :wip test "notify not in @notify_group_interval_hour should not be merged", ~m(user user2 user3 notify_attrs)a do {:ok, notify} = Delivery.send(:notify, notify_attrs, user2) @@ -93,14 +90,12 @@ defmodule GroupherServer.Test.Delivery.Notification do assert user2 |> user_exist_in?(notify2.from_users) end - @tag :wip test "notify myself got ignored", ~m(user notify_attrs)a do {:error, _} = Delivery.send(:notify, notify_attrs, user) end end describe "revoke case" do - # @tag :wip test "can revoke a notification", ~m(user user2 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) @@ -113,7 +108,6 @@ defmodule GroupherServer.Test.Delivery.Notification do assert paged_notifies.total_count == 0 end - # @tag :wip test "can revoke a multi-user joined notification", ~m(user user2 user3 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) @@ -133,7 +127,6 @@ defmodule GroupherServer.Test.Delivery.Notification do assert not user_exist_in?(user2, notify.from_users) end - @tag :wip test "can revoke a multi-user joined notification, long peroid", ~m(user user2 user3 notify_attrs)a do {:ok, notify} = Delivery.send(:notify, notify_attrs, user2) @@ -153,7 +146,6 @@ defmodule GroupherServer.Test.Delivery.Notification do assert not user_exist_in?(user2, notify.from_users) end - @tag :wip test "can revoke a multi-user joined notification, long peroid, edge case", ~m(user user2 user3 user4 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) @@ -179,7 +171,6 @@ defmodule GroupherServer.Test.Delivery.Notification do end describe "basic type support" do - @tag :wip test "support upvote", ~m(post user user2 notify_attrs)a do notify_attrs |> Map.merge(%{ @@ -217,7 +208,6 @@ defmodule GroupherServer.Test.Delivery.Notification do {:error, _} = Delivery.send(:notify, invalid_notify_attrs, user2) end - @tag :wip test "support collect", ~m(post user user2 notify_attrs)a do notify_attrs |> Map.merge(%{ @@ -242,7 +232,6 @@ defmodule GroupherServer.Test.Delivery.Notification do {:error, _} = Delivery.send(:notify, invalid_notify_attrs, user2) end - @tag :wip test "support comment and reply", ~m(post user user2 notify_attrs)a do notify_attrs |> Map.merge(%{ @@ -293,7 +282,6 @@ defmodule GroupherServer.Test.Delivery.Notification do {:error, _} = Delivery.send(:notify, invalid_notify_attrs, user2) end - @tag :wip test "support follow", ~m(user user2)a do notify_attrs = %{ action: :follow, From 28c0ee25f33b5d745cdef1ce95520e6788c99dbc Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 14:55:44 +0800 Subject: [PATCH 26/54] refactor(delivery): upvote hooks for job & blog tests --- .../cms/delegates/comment_action.ex | 13 ++- .../cms/delegates/hooks/notify.ex | 40 +++++-- .../cms/hooks/notify_blog_test.exs | 102 ++++++++++++++++++ .../cms/hooks/notify_job_test.exs | 102 ++++++++++++++++++ .../cms/hooks/notify_post_test.exs | 46 +++++++- 5 files changed, 291 insertions(+), 12 deletions(-) create mode 100644 test/groupher_server/cms/hooks/notify_blog_test.exs create mode 100644 test/groupher_server/cms/hooks/notify_job_test.exs diff --git a/lib/groupher_server/cms/delegates/comment_action.ex b/lib/groupher_server/cms/delegates/comment_action.ex index 8972e207f..5f4e8ebb8 100644 --- a/lib/groupher_server/cms/delegates/comment_action.ex +++ b/lib/groupher_server/cms/delegates/comment_action.ex @@ -17,11 +17,12 @@ defmodule GroupherServer.CMS.Delegate.CommentAction do import GroupherServer.CMS.Helper.Matcher alias Helper.Types, as: T - alias Helper.ORM + alias Helper.{ORM, Later} alias GroupherServer.{Accounts, CMS, Repo} alias Accounts.Model.User alias CMS.Model.{Comment, PinnedComment, CommentUpvote, CommentReply, Embeds} + alias CMS.Delegate.Hooks alias Ecto.Multi @@ -147,7 +148,7 @@ defmodule GroupherServer.CMS.Delegate.CommentAction do end @doc "upvote a comment" - def upvote_comment(comment_id, %User{id: user_id}) do + def upvote_comment(comment_id, %User{id: user_id} = from_user) do with {:ok, comment} <- ORM.find(Comment, comment_id), false <- comment.is_deleted do Multi.new() @@ -174,13 +175,16 @@ defmodule GroupherServer.CMS.Delegate.CommentAction do |> Map.merge(%{viewer_has_reported: viewer_has_reported}) |> done end) + |> Multi.run(:after_hooks, fn _, _ -> + Later.run({Hooks.Notify, :handle, [:upvote, comment, from_user]}) + end) |> Repo.transaction() |> result() end end @doc "upvote a comment" - def undo_upvote_comment(comment_id, %User{id: user_id}) do + def undo_upvote_comment(comment_id, %User{id: user_id} = from_user) do with {:ok, comment} <- ORM.find(Comment, comment_id), false <- comment.is_deleted do Multi.new() @@ -211,6 +215,9 @@ defmodule GroupherServer.CMS.Delegate.CommentAction do |> Map.merge(%{viewer_has_reported: viewer_has_reported}) |> done end) + |> Multi.run(:after_hooks, fn _, _ -> + Later.run({Hooks.Notify, :handle, [:undo, :upvote, comment, from_user]}) + end) |> Repo.transaction() |> result() end diff --git a/lib/groupher_server/cms/delegates/hooks/notify.ex b/lib/groupher_server/cms/delegates/hooks/notify.ex index 8d5998a7d..033f2f496 100644 --- a/lib/groupher_server/cms/delegates/hooks/notify.ex +++ b/lib/groupher_server/cms/delegates/hooks/notify.ex @@ -2,7 +2,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Notify do @moduledoc """ notify hooks, for upvote, collect, comment, reply """ - import Helper.Utils, only: [get_config: 2, thread_of_article: 1] + import Helper.Utils, only: [thread_of_article: 1] import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] alias GroupherServer.{Accounts, CMS, Delivery, Repo} @@ -10,33 +10,61 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Notify do alias Accounts.Model.User alias CMS.Model.Comment - # def handle(action, %Comment{id: comment_id} = comment, %User{} = from_user) do - # end + def handle(:undo, action, %Comment{} = comment, %User{} = from_user) do + article_thread = comment.thread |> String.downcase() |> String.to_atom() + article = comment |> Repo.preload(article_thread) |> Map.get(article_thread) + + notify_attrs = %{ + action: action, + type: :comment, + article_id: article.id, + title: article.title, + comment_id: comment.id, + user_id: comment.author_id + } + + Delivery.revoke(:notify, notify_attrs, from_user) + end def handle(:undo, action, article, %User{} = from_user) do {:ok, article} = preload_author(article) {:ok, thread} = thread_of_article(article) notify_attrs = %{ + action: action, type: thread, article_id: article.id, - action: action, user_id: article.author.user.id } Delivery.revoke(:notify, notify_attrs, from_user) end + def handle(action, %Comment{} = comment, %User{} = from_user) do + article_thread = comment.thread |> String.downcase() |> String.to_atom() + article = comment |> Repo.preload(article_thread) |> Map.get(article_thread) + + notify_attrs = %{ + action: action, + type: :comment, + article_id: article.id, + title: article.title, + comment_id: comment.id, + user_id: comment.author_id + } + + Delivery.send(:notify, notify_attrs, from_user) + end + def handle(action, article, %User{} = from_user) do {:ok, article} = preload_author(article) - {:ok, thread} = thread_of_article(article) notify_attrs = %{ + action: action, type: thread, article_id: article.id, title: article.title, - action: action, user_id: article.author.user.id } diff --git a/test/groupher_server/cms/hooks/notify_blog_test.exs b/test/groupher_server/cms/hooks/notify_blog_test.exs new file mode 100644 index 000000000..a3742800e --- /dev/null +++ b/test/groupher_server/cms/hooks/notify_blog_test.exs @@ -0,0 +1,102 @@ +defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do + use GroupherServer.TestTools + + import Helper.Utils, only: [get_config: 2] + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] + + alias GroupherServer.{CMS, Delivery} + + # alias CMS.Model.{Comment} + alias CMS.Delegate.Hooks + + @site_host get_config(:general, :site_host) + + 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, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, comment} = CMS.create_comment(:blog, blog.id, mock_comment(), user) + + {:ok, ~m(user2 blog comment)a} + end + + describe "[upvote notify]" do + @tag :wip + test "upvote hook should work on blog", ~m(user2 blog)a do + {:ok, blog} = preload_author(blog) + + {:ok, article} = CMS.upvote_article(:blog, blog.id, user2) + Hooks.Notify.handle(:upvote, article, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "UPVOTE" + assert notify.article_id == blog.id + assert notify.type == "BLOG" + assert notify.user_id == blog.author.user.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "upvote hook should work on blog comment", ~m(user2 blog comment)a do + {:ok, comment} = CMS.upvote_comment(comment.id, user2) + {:ok, comment} = preload_author(comment) + + Hooks.Notify.handle(:upvote, comment, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "UPVOTE" + assert notify.article_id == blog.id + assert notify.type == "COMMENT" + assert notify.user_id == comment.author.id + assert notify.comment_id == comment.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "undo upvote hook should work on blog", ~m(user2 blog)a do + {:ok, blog} = preload_author(blog) + + {:ok, article} = CMS.upvote_article(:blog, blog.id, user2) + Hooks.Notify.handle(:upvote, article, user2) + + {:ok, article} = CMS.undo_upvote_article(:blog, blog.id, user2) + Hooks.Notify.handle(:undo, :upvote, article, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + + @tag :wip + test "undo upvote hook should work on blog comment", ~m(user2 comment)a do + {:ok, comment} = CMS.upvote_comment(comment.id, user2) + + Hooks.Notify.handle(:upvote, comment, user2) + + {:ok, comment} = CMS.undo_upvote_comment(comment.id, user2) + Hooks.Notify.handle(:undo, :upvote, comment, user2) + + {:ok, comment} = preload_author(comment) + + {:ok, notifications} = + Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + end +end diff --git a/test/groupher_server/cms/hooks/notify_job_test.exs b/test/groupher_server/cms/hooks/notify_job_test.exs new file mode 100644 index 000000000..3a50f89f6 --- /dev/null +++ b/test/groupher_server/cms/hooks/notify_job_test.exs @@ -0,0 +1,102 @@ +defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do + use GroupherServer.TestTools + + import Helper.Utils, only: [get_config: 2] + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] + + alias GroupherServer.{CMS, Delivery} + + # alias CMS.Model.{Comment} + alias CMS.Delegate.Hooks + + @site_host get_config(:general, :site_host) + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + + {:ok, community} = db_insert(:community) + + job_attrs = mock_attrs(:job, %{community_id: community.id}) + {:ok, job} = CMS.create_article(community, :job, job_attrs, user) + {:ok, comment} = CMS.create_comment(:job, job.id, mock_comment(), user) + + {:ok, ~m(user2 job comment)a} + end + + describe "[upvote notify]" do + @tag :wip + test "upvote hook should work on job", ~m(user2 job)a do + {:ok, job} = preload_author(job) + + {:ok, article} = CMS.upvote_article(:job, job.id, user2) + Hooks.Notify.handle(:upvote, article, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "UPVOTE" + assert notify.article_id == job.id + assert notify.type == "JOB" + assert notify.user_id == job.author.user.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "upvote hook should work on job comment", ~m(user2 job comment)a do + {:ok, comment} = CMS.upvote_comment(comment.id, user2) + {:ok, comment} = preload_author(comment) + + Hooks.Notify.handle(:upvote, comment, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "UPVOTE" + assert notify.article_id == job.id + assert notify.type == "COMMENT" + assert notify.user_id == comment.author.id + assert notify.comment_id == comment.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "undo upvote hook should work on job", ~m(user2 job)a do + {:ok, job} = preload_author(job) + + {:ok, article} = CMS.upvote_article(:job, job.id, user2) + Hooks.Notify.handle(:upvote, article, user2) + + {:ok, article} = CMS.undo_upvote_article(:job, job.id, user2) + Hooks.Notify.handle(:undo, :upvote, article, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + + @tag :wip + test "undo upvote hook should work on job comment", ~m(user2 comment)a do + {:ok, comment} = CMS.upvote_comment(comment.id, user2) + + Hooks.Notify.handle(:upvote, comment, user2) + + {:ok, comment} = CMS.undo_upvote_comment(comment.id, user2) + Hooks.Notify.handle(:undo, :upvote, comment, user2) + + {:ok, comment} = preload_author(comment) + + {:ok, notifications} = + Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + end +end diff --git a/test/groupher_server/cms/hooks/notify_post_test.exs b/test/groupher_server/cms/hooks/notify_post_test.exs index cd3e08cf3..fbb933d41 100644 --- a/test/groupher_server/cms/hooks/notify_post_test.exs +++ b/test/groupher_server/cms/hooks/notify_post_test.exs @@ -19,13 +19,14 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do post_attrs = mock_attrs(:post, %{community_id: community.id}) {:ok, post} = CMS.create_article(community, :post, post_attrs, user) + {:ok, comment} = CMS.create_comment(:post, post.id, mock_comment(), user) - {:ok, ~m(user2 post)a} + {:ok, ~m(user2 post comment)a} end describe "[upvote notify]" do @tag :wip - test "upvote hook should work", ~m(user2 post)a do + test "upvote hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) {:ok, article} = CMS.upvote_article(:post, post.id, user2) @@ -37,6 +38,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert notifications.total_count == 1 notify = notifications.entries |> List.first() + assert notify.action == "UPVOTE" assert notify.article_id == post.id assert notify.type == "POST" assert notify.user_id == post.author.user.id @@ -44,7 +46,28 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do end @tag :wip - test "undo upvote hook should work", ~m(user2 post)a do + test "upvote hook should work on post comment", ~m(user2 post comment)a do + {:ok, comment} = CMS.upvote_comment(comment.id, user2) + {:ok, comment} = preload_author(comment) + + Hooks.Notify.handle(:upvote, comment, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "UPVOTE" + assert notify.article_id == post.id + assert notify.type == "COMMENT" + assert notify.user_id == comment.author.id + assert notify.comment_id == comment.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "undo upvote hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) {:ok, article} = CMS.upvote_article(:post, post.id, user2) @@ -58,5 +81,22 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert notifications.total_count == 0 end + + @tag :wip + test "undo upvote hook should work on post comment", ~m(user2 comment)a do + {:ok, comment} = CMS.upvote_comment(comment.id, user2) + + Hooks.Notify.handle(:upvote, comment, user2) + + {:ok, comment} = CMS.undo_upvote_comment(comment.id, user2) + Hooks.Notify.handle(:undo, :upvote, comment, user2) + + {:ok, comment} = preload_author(comment) + + {:ok, notifications} = + Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end end end From b6571807482c409fe2456cb35af1cb096fbc2a04 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 16:32:01 +0800 Subject: [PATCH 27/54] refactor(delivery): collect hooks & tests --- .../cms/delegates/article_collect.ex | 13 +++-- .../cms/hooks/notify_blog_test.exs | 51 +++++++++++++++---- .../cms/hooks/notify_job_test.exs | 51 +++++++++++++++---- .../cms/hooks/notify_post_test.exs | 51 +++++++++++++++---- 4 files changed, 136 insertions(+), 30 deletions(-) diff --git a/lib/groupher_server/cms/delegates/article_collect.ex b/lib/groupher_server/cms/delegates/article_collect.ex index 19126bb99..1eac93dba 100644 --- a/lib/groupher_server/cms/delegates/article_collect.ex +++ b/lib/groupher_server/cms/delegates/article_collect.ex @@ -14,11 +14,12 @@ defmodule GroupherServer.CMS.Delegate.ArticleCollect do ] # import Helper.ErrorCode - alias Helper.{ORM} + alias Helper.{ORM, Later} alias GroupherServer.{Accounts, CMS, Repo} alias Accounts.Model.User alias CMS.Model.ArticleCollect + alias CMS.Delegate.Hooks alias Ecto.Multi @@ -32,7 +33,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleCollect do @doc """ collect an article """ - def collect_article(thread, article_id, %User{id: user_id}) do + def collect_article(thread, article_id, %User{id: user_id} = from_user) do with {:ok, info} <- match(thread), {:ok, article} <- ORM.find(info.model, article_id, preload: [author: :user]) do Multi.new() @@ -51,6 +52,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleCollect do ORM.create(ArticleCollect, args) end) + |> Multi.run(:after_hooks, fn _, _ -> + Later.run({Hooks.Notify, :handle, [:collect, article, from_user]}) + end) |> Repo.transaction() |> result() end @@ -71,7 +75,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleCollect do end end - def undo_collect_article(thread, article_id, %User{id: user_id}) do + def undo_collect_article(thread, article_id, %User{id: user_id} = from_user) do with {:ok, info} <- match(thread), {:ok, article} <- ORM.find(info.model, article_id, preload: [author: :user]) do Multi.new() @@ -89,6 +93,9 @@ defmodule GroupherServer.CMS.Delegate.ArticleCollect do ORM.findby_delete(ArticleCollect, args) end) + |> Multi.run(:after_hooks, fn _, _ -> + Later.run({Hooks.Notify, :handle, [:undo, :collect, article, from_user]}) + end) |> Repo.transaction() |> result() end diff --git a/test/groupher_server/cms/hooks/notify_blog_test.exs b/test/groupher_server/cms/hooks/notify_blog_test.exs index a3742800e..efea903b0 100644 --- a/test/groupher_server/cms/hooks/notify_blog_test.exs +++ b/test/groupher_server/cms/hooks/notify_blog_test.exs @@ -1,16 +1,11 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do use GroupherServer.TestTools - import Helper.Utils, only: [get_config: 2] import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] alias GroupherServer.{CMS, Delivery} - - # alias CMS.Model.{Comment} alias CMS.Delegate.Hooks - @site_host get_config(:general, :site_host) - setup do {:ok, user} = db_insert(:user) {:ok, user2} = db_insert(:user) @@ -25,7 +20,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do end describe "[upvote notify]" do - @tag :wip + @tag :wip2 test "upvote hook should work on blog", ~m(user2 blog)a do {:ok, blog} = preload_author(blog) @@ -45,7 +40,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert user_exist_in?(user2, notify.from_users) end - @tag :wip + @tag :wip2 test "upvote hook should work on blog comment", ~m(user2 blog comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) {:ok, comment} = preload_author(comment) @@ -66,7 +61,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert user_exist_in?(user2, notify.from_users) end - @tag :wip + @tag :wip2 test "undo upvote hook should work on blog", ~m(user2 blog)a do {:ok, blog} = preload_author(blog) @@ -82,7 +77,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert notifications.total_count == 0 end - @tag :wip + @tag :wip2 test "undo upvote hook should work on blog comment", ~m(user2 comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) @@ -99,4 +94,42 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert notifications.total_count == 0 end end + + describe "[collect notify]" do + @tag :wip + test "collect hook should work on blog", ~m(user2 blog)a do + {:ok, blog} = preload_author(blog) + + {:ok, _} = CMS.collect_article(:blog, blog.id, user2) + Hooks.Notify.handle(:collect, blog, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "COLLECT" + assert notify.article_id == blog.id + assert notify.type == "BLOG" + assert notify.user_id == blog.author.user.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "undo collect hook should work on blog", ~m(user2 blog)a do + {:ok, blog} = preload_author(blog) + + {:ok, _} = CMS.upvote_article(:blog, blog.id, user2) + Hooks.Notify.handle(:collect, blog, user2) + + {:ok, _} = CMS.undo_upvote_article(:blog, blog.id, user2) + Hooks.Notify.handle(:undo, :collect, blog, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + end end diff --git a/test/groupher_server/cms/hooks/notify_job_test.exs b/test/groupher_server/cms/hooks/notify_job_test.exs index 3a50f89f6..114985c8f 100644 --- a/test/groupher_server/cms/hooks/notify_job_test.exs +++ b/test/groupher_server/cms/hooks/notify_job_test.exs @@ -1,16 +1,11 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do use GroupherServer.TestTools - import Helper.Utils, only: [get_config: 2] import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] alias GroupherServer.{CMS, Delivery} - - # alias CMS.Model.{Comment} alias CMS.Delegate.Hooks - @site_host get_config(:general, :site_host) - setup do {:ok, user} = db_insert(:user) {:ok, user2} = db_insert(:user) @@ -25,7 +20,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do end describe "[upvote notify]" do - @tag :wip + @tag :wip2 test "upvote hook should work on job", ~m(user2 job)a do {:ok, job} = preload_author(job) @@ -45,7 +40,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert user_exist_in?(user2, notify.from_users) end - @tag :wip + @tag :wip2 test "upvote hook should work on job comment", ~m(user2 job comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) {:ok, comment} = preload_author(comment) @@ -66,7 +61,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert user_exist_in?(user2, notify.from_users) end - @tag :wip + @tag :wip2 test "undo upvote hook should work on job", ~m(user2 job)a do {:ok, job} = preload_author(job) @@ -82,7 +77,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert notifications.total_count == 0 end - @tag :wip + @tag :wip2 test "undo upvote hook should work on job comment", ~m(user2 comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) @@ -99,4 +94,42 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert notifications.total_count == 0 end end + + describe "[collect notify]" do + @tag :wip + test "collect hook should work on job", ~m(user2 job)a do + {:ok, job} = preload_author(job) + + {:ok, _} = CMS.collect_article(:job, job.id, user2) + Hooks.Notify.handle(:collect, job, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "COLLECT" + assert notify.article_id == job.id + assert notify.type == "JOB" + assert notify.user_id == job.author.user.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "undo collect hook should work on job", ~m(user2 job)a do + {:ok, job} = preload_author(job) + + {:ok, _} = CMS.upvote_article(:job, job.id, user2) + Hooks.Notify.handle(:collect, job, user2) + + {:ok, _} = CMS.undo_upvote_article(:job, job.id, user2) + Hooks.Notify.handle(:undo, :collect, job, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + end end diff --git a/test/groupher_server/cms/hooks/notify_post_test.exs b/test/groupher_server/cms/hooks/notify_post_test.exs index fbb933d41..2a77847cb 100644 --- a/test/groupher_server/cms/hooks/notify_post_test.exs +++ b/test/groupher_server/cms/hooks/notify_post_test.exs @@ -1,16 +1,11 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do use GroupherServer.TestTools - import Helper.Utils, only: [get_config: 2] import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] alias GroupherServer.{CMS, Delivery} - - # alias CMS.Model.{Comment} alias CMS.Delegate.Hooks - @site_host get_config(:general, :site_host) - setup do {:ok, user} = db_insert(:user) {:ok, user2} = db_insert(:user) @@ -25,7 +20,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do end describe "[upvote notify]" do - @tag :wip + @tag :wip2 test "upvote hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -45,7 +40,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert user_exist_in?(user2, notify.from_users) end - @tag :wip + @tag :wip2 test "upvote hook should work on post comment", ~m(user2 post comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) {:ok, comment} = preload_author(comment) @@ -66,7 +61,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert user_exist_in?(user2, notify.from_users) end - @tag :wip + @tag :wip2 test "undo upvote hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -82,7 +77,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert notifications.total_count == 0 end - @tag :wip + @tag :wip2 test "undo upvote hook should work on post comment", ~m(user2 comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) @@ -99,4 +94,42 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert notifications.total_count == 0 end end + + describe "[collect notify]" do + @tag :wip + test "collect hook should work on post", ~m(user2 post)a do + {:ok, post} = preload_author(post) + + {:ok, _} = CMS.collect_article(:post, post.id, user2) + Hooks.Notify.handle(:collect, post, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, post.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "COLLECT" + assert notify.article_id == post.id + assert notify.type == "POST" + assert notify.user_id == post.author.user.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "undo collect hook should work on post", ~m(user2 post)a do + {:ok, post} = preload_author(post) + + {:ok, _} = CMS.upvote_article(:post, post.id, user2) + Hooks.Notify.handle(:collect, post, user2) + + {:ok, _} = CMS.undo_upvote_article(:post, post.id, user2) + Hooks.Notify.handle(:undo, :collect, post, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, post.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + end end From 60bef5a0ac87361ac6c87cf6d12ce60147d4934b Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 19:48:37 +0800 Subject: [PATCH 28/54] refactor(delivery): rename type -> thread in notification --- config/config.exs | 2 +- .../cms/delegates/comment_curd.ex | 5 +- lib/groupher_server/cms/delegates/helper.ex | 9 ++ .../cms/delegates/hooks/notify.ex | 61 +++++--- .../delivery/delegates/notification.ex | 36 +++-- .../delivery/models/notification.ex | 4 +- ...12_rename_notifications_type_to_thread.exs | 7 + .../cms/hooks/notify_blog_test.exs | 135 ------------------ .../cms/hooks/notify_job_test.exs | 135 ------------------ .../cms/hooks/notify_post_test.exs | 32 ++++- .../delivery/notification_test.exs | 19 ++- 11 files changed, 116 insertions(+), 329 deletions(-) create mode 100644 priv/repo/migrations/20210620091612_rename_notifications_type_to_thread.exs delete mode 100644 test/groupher_server/cms/hooks/notify_blog_test.exs delete mode 100644 test/groupher_server/cms/hooks/notify_job_test.exs diff --git a/config/config.exs b/config/config.exs index eb3a55861..80feaece3 100644 --- a/config/config.exs +++ b/config/config.exs @@ -51,7 +51,7 @@ config :groupher_server, :general, # others # 在这个时间段内,多条提醒消息将被合并为一条 notify_group_interval_hour: 1, - nofity_types: [:upvote, :comment, :reply, :collect, :follow] + nofity_actions: [:upvote, :comment, :reply, :collect, :follow] config :groupher_server, :customization, theme: "cyan", diff --git a/lib/groupher_server/cms/delegates/comment_curd.ex b/lib/groupher_server/cms/delegates/comment_curd.ex index 0ddadff8c..05ad8575d 100644 --- a/lib/groupher_server/cms/delegates/comment_curd.ex +++ b/lib/groupher_server/cms/delegates/comment_curd.ex @@ -114,8 +114,9 @@ defmodule GroupherServer.CMS.Delegate.CommentCurd do false -> CMS.update_active_timestamp(thread, article) end end) - |> Multi.run(:after_hooks, fn _, %{create_comment: create_comment} -> - Later.run({Hooks.Cite, :handle, [create_comment]}) + |> Multi.run(:after_hooks, fn _, %{create_comment: comment} -> + Later.run({Hooks.Cite, :handle, [comment]}) + Later.run({Hooks.Notify, :handle, [:comment, comment, user]}) end) |> Repo.transaction() |> result() diff --git a/lib/groupher_server/cms/delegates/helper.ex b/lib/groupher_server/cms/delegates/helper.ex index d6dedb47a..442480436 100644 --- a/lib/groupher_server/cms/delegates/helper.ex +++ b/lib/groupher_server/cms/delegates/helper.ex @@ -41,6 +41,15 @@ defmodule GroupherServer.CMS.Delegate.Helper do |> done end + @doc "get parent article of a comment" + def parent_article_of(%Comment{} = comment) do + article_thread = comment.thread |> String.downcase() |> String.to_atom() + + comment |> Repo.preload(article_thread) |> Map.get(article_thread) |> done + end + + def parent_article_of(_), do: {:error, "only support comment"} + ####### # emotion related ####### diff --git a/lib/groupher_server/cms/delegates/hooks/notify.ex b/lib/groupher_server/cms/delegates/hooks/notify.ex index 033f2f496..a1b2c3db7 100644 --- a/lib/groupher_server/cms/delegates/hooks/notify.ex +++ b/lib/groupher_server/cms/delegates/hooks/notify.ex @@ -3,71 +3,90 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Notify do notify hooks, for upvote, collect, comment, reply """ import Helper.Utils, only: [thread_of_article: 1] - import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1, parent_article_of: 1] - alias GroupherServer.{Accounts, CMS, Delivery, Repo} + alias GroupherServer.{Accounts, CMS, Delivery} alias Accounts.Model.User alias CMS.Model.Comment - def handle(:undo, action, %Comment{} = comment, %User{} = from_user) do - article_thread = comment.thread |> String.downcase() |> String.to_atom() - article = comment |> Repo.preload(article_thread) |> Map.get(article_thread) + # 发布评论是特殊情况,单独处理 + def handle(:comment, %Comment{} = comment, %User{} = from_user) do + {:ok, article} = parent_article_of(comment) + {:ok, article} = preload_author(article) + {:ok, thread} = thread_of_article(article) notify_attrs = %{ - action: action, - type: :comment, + action: :comment, + thread: thread, article_id: article.id, title: article.title, comment_id: comment.id, - user_id: comment.author_id + # NOTE: 这里是提醒该评论文章的作者,不是评论本身的作者 + user_id: article.author.user.id } - Delivery.revoke(:notify, notify_attrs, from_user) + Delivery.send(:notify, notify_attrs, from_user) end - def handle(:undo, action, article, %User{} = from_user) do + def handle(action, %Comment{} = comment, %User{} = from_user) do + {:ok, article} = parent_article_of(comment) + {:ok, thread} = thread_of_article(article) + + notify_attrs = %{ + action: action, + thread: thread, + article_id: article.id, + title: article.title, + user_id: comment.author_id, + comment_id: comment.id + } + + Delivery.send(:notify, notify_attrs, from_user) + end + + def handle(action, article, %User{} = from_user) do {:ok, article} = preload_author(article) {:ok, thread} = thread_of_article(article) notify_attrs = %{ action: action, - type: thread, + thread: thread, article_id: article.id, + title: article.title, user_id: article.author.user.id } - Delivery.revoke(:notify, notify_attrs, from_user) + Delivery.send(:notify, notify_attrs, from_user) end - def handle(action, %Comment{} = comment, %User{} = from_user) do - article_thread = comment.thread |> String.downcase() |> String.to_atom() - article = comment |> Repo.preload(article_thread) |> Map.get(article_thread) + def handle(:undo, action, %Comment{} = comment, %User{} = from_user) do + {:ok, article} = parent_article_of(comment) + {:ok, thread} = thread_of_article(article) notify_attrs = %{ action: action, - type: :comment, + thread: thread, article_id: article.id, title: article.title, comment_id: comment.id, user_id: comment.author_id } - Delivery.send(:notify, notify_attrs, from_user) + Delivery.revoke(:notify, notify_attrs, from_user) end - def handle(action, article, %User{} = from_user) do + def handle(:undo, action, article, %User{} = from_user) do {:ok, article} = preload_author(article) {:ok, thread} = thread_of_article(article) notify_attrs = %{ action: action, - type: thread, + thread: thread, article_id: article.id, - title: article.title, user_id: article.author.user.id } - Delivery.send(:notify, notify_attrs, from_user) + Delivery.revoke(:notify, notify_attrs, from_user) end end diff --git a/lib/groupher_server/delivery/delegates/notification.ex b/lib/groupher_server/delivery/delegates/notification.ex index 9ff8d3bc0..f5016890e 100644 --- a/lib/groupher_server/delivery/delegates/notification.ex +++ b/lib/groupher_server/delivery/delegates/notification.ex @@ -14,11 +14,11 @@ defmodule GroupherServer.Delivery.Delegate.Notification do alias Accounts.Model.User alias Helper.ORM - @supported_notify_type get_config(:general, :nofity_types) + @notify_actions get_config(:general, :nofity_actions) @notify_group_interval_hour get_config(:general, :notify_group_interval_hour) def handle(%{action: action, user_id: user_id} = attrs, %User{} = from_user) do - with true <- action in @supported_notify_type, + with true <- action in @notify_actions, true <- is_valid?(attrs), true <- user_id !== from_user.id do from_user = from_user |> Map.take([:login, :nickname]) |> Map.put(:user_id, from_user.id) @@ -90,18 +90,21 @@ defmodule GroupherServer.Delivery.Delegate.Notification do defp find_exist_notify(%{comment_id: comment_id} = attrs, opt) when not is_nil(comment_id) do - ~m(type article_id comment_id)a = atom_values_to_upcase(attrs) + ~m(thread article_id comment_id)a = atom_values_to_upcase(attrs) Notification - |> where([n], n.type == ^type and n.article_id == ^article_id and n.comment_id == ^comment_id) + |> where( + [n], + n.thread == ^thread and n.article_id == ^article_id and n.comment_id == ^comment_id + ) |> do_find_exist_notify(attrs, opt) end defp find_exist_notify(attrs, opt) do - ~m(type article_id)a = atom_values_to_upcase(attrs) + ~m(thread article_id)a = atom_values_to_upcase(attrs) Notification - |> where([n], n.type == ^type and n.article_id == ^article_id) + |> where([n], n.thread == ^thread and n.article_id == ^article_id) |> do_find_exist_notify(attrs, opt) end @@ -139,29 +142,24 @@ defmodule GroupherServer.Delivery.Delegate.Notification do |> done end - # [:upvote, :comment, :reply, :collect, :follow] - defp is_valid?(%{action: :upvote, type: :comment} = attrs) do - attrs |> all_exist?([:article_id, :type, :title, :comment_id, :user_id]) - end + defp is_valid?(%{action: :follow} = attrs), do: attrs |> all_exist?([:user_id]) defp is_valid?(%{action: :upvote} = attrs) do - attrs |> all_exist?([:article_id, :type, :title, :user_id]) + attrs |> all_exist?([:article_id, :thread, :title, :user_id]) end - defp is_valid?(%{action: :comment} = attrs) do - attrs |> all_exist?([:article_id, :type, :title, :comment_id, :user_id]) + defp is_valid?(%{action: :collect} = attrs) do + attrs |> all_exist?([:article_id, :thread, :title, :user_id]) end - defp is_valid?(%{action: :reply} = attrs) do - attrs |> all_exist?([:article_id, :type, :title, :comment_id, :user_id]) + defp is_valid?(%{action: :comment} = attrs) do + attrs |> all_exist?([:article_id, :thread, :title, :comment_id, :user_id]) end - defp is_valid?(%{action: :collect} = attrs) do - attrs |> all_exist?([:article_id, :type, :title, :user_id]) + defp is_valid?(%{action: :reply} = attrs) do + attrs |> all_exist?([:article_id, :thread, :title, :comment_id, :user_id]) end - defp is_valid?(%{action: :follow} = attrs), do: attrs |> all_exist?([:user_id]) - defp is_valid?(_), do: false # 确保 key 存在,并且不为 nil diff --git a/lib/groupher_server/delivery/models/notification.ex b/lib/groupher_server/delivery/models/notification.ex index 09c023ab8..cd7386c96 100644 --- a/lib/groupher_server/delivery/models/notification.ex +++ b/lib/groupher_server/delivery/models/notification.ex @@ -10,13 +10,13 @@ defmodule GroupherServer.Delivery.Model.Notification do alias CMS.Model.Embeds @required_fields ~w(user_id action)a - @optional_fields ~w(type article_id comment_id title read)a + @optional_fields ~w(thread article_id comment_id title read)a @type t :: %Notification{} schema "notifications" do belongs_to(:user, User) # article or comment - field(:type, :string) + field(:thread, :string) field(:article_id, :id) field(:title, :string) # optional comment id diff --git a/priv/repo/migrations/20210620091612_rename_notifications_type_to_thread.exs b/priv/repo/migrations/20210620091612_rename_notifications_type_to_thread.exs new file mode 100644 index 000000000..dfa9bef82 --- /dev/null +++ b/priv/repo/migrations/20210620091612_rename_notifications_type_to_thread.exs @@ -0,0 +1,7 @@ +defmodule GroupherServer.Repo.Migrations.RenameNotificationsTypeToThread do + use Ecto.Migration + + def change do + rename(table(:notifications), :type, to: :thread) + end +end diff --git a/test/groupher_server/cms/hooks/notify_blog_test.exs b/test/groupher_server/cms/hooks/notify_blog_test.exs deleted file mode 100644 index efea903b0..000000000 --- a/test/groupher_server/cms/hooks/notify_blog_test.exs +++ /dev/null @@ -1,135 +0,0 @@ -defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do - use GroupherServer.TestTools - - import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] - - alias GroupherServer.{CMS, Delivery} - alias CMS.Delegate.Hooks - - 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, blog} = CMS.create_article(community, :blog, blog_attrs, user) - {:ok, comment} = CMS.create_comment(:blog, blog.id, mock_comment(), user) - - {:ok, ~m(user2 blog comment)a} - end - - describe "[upvote notify]" do - @tag :wip2 - test "upvote hook should work on blog", ~m(user2 blog)a do - {:ok, blog} = preload_author(blog) - - {:ok, article} = CMS.upvote_article(:blog, blog.id, user2) - Hooks.Notify.handle(:upvote, article, user2) - - {:ok, notifications} = - Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) - - assert notifications.total_count == 1 - - notify = notifications.entries |> List.first() - assert notify.action == "UPVOTE" - assert notify.article_id == blog.id - assert notify.type == "BLOG" - assert notify.user_id == blog.author.user.id - assert user_exist_in?(user2, notify.from_users) - end - - @tag :wip2 - test "upvote hook should work on blog comment", ~m(user2 blog comment)a do - {:ok, comment} = CMS.upvote_comment(comment.id, user2) - {:ok, comment} = preload_author(comment) - - Hooks.Notify.handle(:upvote, comment, user2) - - {:ok, notifications} = - Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) - - assert notifications.total_count == 1 - - notify = notifications.entries |> List.first() - assert notify.action == "UPVOTE" - assert notify.article_id == blog.id - assert notify.type == "COMMENT" - assert notify.user_id == comment.author.id - assert notify.comment_id == comment.id - assert user_exist_in?(user2, notify.from_users) - end - - @tag :wip2 - test "undo upvote hook should work on blog", ~m(user2 blog)a do - {:ok, blog} = preload_author(blog) - - {:ok, article} = CMS.upvote_article(:blog, blog.id, user2) - Hooks.Notify.handle(:upvote, article, user2) - - {:ok, article} = CMS.undo_upvote_article(:blog, blog.id, user2) - Hooks.Notify.handle(:undo, :upvote, article, user2) - - {:ok, notifications} = - Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) - - assert notifications.total_count == 0 - end - - @tag :wip2 - test "undo upvote hook should work on blog comment", ~m(user2 comment)a do - {:ok, comment} = CMS.upvote_comment(comment.id, user2) - - Hooks.Notify.handle(:upvote, comment, user2) - - {:ok, comment} = CMS.undo_upvote_comment(comment.id, user2) - Hooks.Notify.handle(:undo, :upvote, comment, user2) - - {:ok, comment} = preload_author(comment) - - {:ok, notifications} = - Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) - - assert notifications.total_count == 0 - end - end - - describe "[collect notify]" do - @tag :wip - test "collect hook should work on blog", ~m(user2 blog)a do - {:ok, blog} = preload_author(blog) - - {:ok, _} = CMS.collect_article(:blog, blog.id, user2) - Hooks.Notify.handle(:collect, blog, user2) - - {:ok, notifications} = - Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) - - assert notifications.total_count == 1 - - notify = notifications.entries |> List.first() - assert notify.action == "COLLECT" - assert notify.article_id == blog.id - assert notify.type == "BLOG" - assert notify.user_id == blog.author.user.id - assert user_exist_in?(user2, notify.from_users) - end - - @tag :wip - test "undo collect hook should work on blog", ~m(user2 blog)a do - {:ok, blog} = preload_author(blog) - - {:ok, _} = CMS.upvote_article(:blog, blog.id, user2) - Hooks.Notify.handle(:collect, blog, user2) - - {:ok, _} = CMS.undo_upvote_article(:blog, blog.id, user2) - Hooks.Notify.handle(:undo, :collect, blog, user2) - - {:ok, notifications} = - Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) - - assert notifications.total_count == 0 - end - end -end diff --git a/test/groupher_server/cms/hooks/notify_job_test.exs b/test/groupher_server/cms/hooks/notify_job_test.exs deleted file mode 100644 index 114985c8f..000000000 --- a/test/groupher_server/cms/hooks/notify_job_test.exs +++ /dev/null @@ -1,135 +0,0 @@ -defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do - use GroupherServer.TestTools - - import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] - - alias GroupherServer.{CMS, Delivery} - alias CMS.Delegate.Hooks - - setup do - {:ok, user} = db_insert(:user) - {:ok, user2} = db_insert(:user) - - {:ok, community} = db_insert(:community) - - job_attrs = mock_attrs(:job, %{community_id: community.id}) - {:ok, job} = CMS.create_article(community, :job, job_attrs, user) - {:ok, comment} = CMS.create_comment(:job, job.id, mock_comment(), user) - - {:ok, ~m(user2 job comment)a} - end - - describe "[upvote notify]" do - @tag :wip2 - test "upvote hook should work on job", ~m(user2 job)a do - {:ok, job} = preload_author(job) - - {:ok, article} = CMS.upvote_article(:job, job.id, user2) - Hooks.Notify.handle(:upvote, article, user2) - - {:ok, notifications} = - Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) - - assert notifications.total_count == 1 - - notify = notifications.entries |> List.first() - assert notify.action == "UPVOTE" - assert notify.article_id == job.id - assert notify.type == "JOB" - assert notify.user_id == job.author.user.id - assert user_exist_in?(user2, notify.from_users) - end - - @tag :wip2 - test "upvote hook should work on job comment", ~m(user2 job comment)a do - {:ok, comment} = CMS.upvote_comment(comment.id, user2) - {:ok, comment} = preload_author(comment) - - Hooks.Notify.handle(:upvote, comment, user2) - - {:ok, notifications} = - Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) - - assert notifications.total_count == 1 - - notify = notifications.entries |> List.first() - assert notify.action == "UPVOTE" - assert notify.article_id == job.id - assert notify.type == "COMMENT" - assert notify.user_id == comment.author.id - assert notify.comment_id == comment.id - assert user_exist_in?(user2, notify.from_users) - end - - @tag :wip2 - test "undo upvote hook should work on job", ~m(user2 job)a do - {:ok, job} = preload_author(job) - - {:ok, article} = CMS.upvote_article(:job, job.id, user2) - Hooks.Notify.handle(:upvote, article, user2) - - {:ok, article} = CMS.undo_upvote_article(:job, job.id, user2) - Hooks.Notify.handle(:undo, :upvote, article, user2) - - {:ok, notifications} = - Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) - - assert notifications.total_count == 0 - end - - @tag :wip2 - test "undo upvote hook should work on job comment", ~m(user2 comment)a do - {:ok, comment} = CMS.upvote_comment(comment.id, user2) - - Hooks.Notify.handle(:upvote, comment, user2) - - {:ok, comment} = CMS.undo_upvote_comment(comment.id, user2) - Hooks.Notify.handle(:undo, :upvote, comment, user2) - - {:ok, comment} = preload_author(comment) - - {:ok, notifications} = - Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) - - assert notifications.total_count == 0 - end - end - - describe "[collect notify]" do - @tag :wip - test "collect hook should work on job", ~m(user2 job)a do - {:ok, job} = preload_author(job) - - {:ok, _} = CMS.collect_article(:job, job.id, user2) - Hooks.Notify.handle(:collect, job, user2) - - {:ok, notifications} = - Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) - - assert notifications.total_count == 1 - - notify = notifications.entries |> List.first() - assert notify.action == "COLLECT" - assert notify.article_id == job.id - assert notify.type == "JOB" - assert notify.user_id == job.author.user.id - assert user_exist_in?(user2, notify.from_users) - end - - @tag :wip - test "undo collect hook should work on job", ~m(user2 job)a do - {:ok, job} = preload_author(job) - - {:ok, _} = CMS.upvote_article(:job, job.id, user2) - Hooks.Notify.handle(:collect, job, user2) - - {:ok, _} = CMS.undo_upvote_article(:job, job.id, user2) - Hooks.Notify.handle(:undo, :collect, job, user2) - - {:ok, notifications} = - Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) - - assert notifications.total_count == 0 - end - end -end diff --git a/test/groupher_server/cms/hooks/notify_post_test.exs b/test/groupher_server/cms/hooks/notify_post_test.exs index 2a77847cb..dbd9533ad 100644 --- a/test/groupher_server/cms/hooks/notify_post_test.exs +++ b/test/groupher_server/cms/hooks/notify_post_test.exs @@ -40,7 +40,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert user_exist_in?(user2, notify.from_users) end - @tag :wip2 + @tag :wip test "upvote hook should work on post comment", ~m(user2 post comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) {:ok, comment} = preload_author(comment) @@ -55,7 +55,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do notify = notifications.entries |> List.first() assert notify.action == "UPVOTE" assert notify.article_id == post.id - assert notify.type == "COMMENT" + assert notify.type == "POST" assert notify.user_id == comment.author.id assert notify.comment_id == comment.id assert user_exist_in?(user2, notify.from_users) @@ -96,7 +96,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do end describe "[collect notify]" do - @tag :wip + @tag :wip2 test "collect hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -116,7 +116,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert user_exist_in?(user2, notify.from_users) end - @tag :wip + @tag :wip2 test "undo collect hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -132,4 +132,28 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert notifications.total_count == 0 end end + + describe "[comment notify]" do + @tag :wip + test "post author should get notify after some one comment on it", ~m(user2 post)a do + {:ok, post} = preload_author(post) + + {:ok, comment} = CMS.create_comment(:post, post.id, mock_comment(), user2) + Hooks.Notify.handle(:comment, comment, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, post.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "COMMENT" + assert notify.type == "POST" + assert notify.article_id == post.id + assert notify.user_id == post.author.user.id + assert user_exist_in?(user2, notify.from_users) + + IO.inspect(notifications, label: "notifications") + end + end end diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index 7f5fad0e2..b14e36592 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -170,11 +170,11 @@ defmodule GroupherServer.Test.Delivery.Notification do end end - describe "basic type support" do + describe "basic thread support" do test "support upvote", ~m(post user user2 notify_attrs)a do notify_attrs |> Map.merge(%{ - type: :post, + thread: :post, article_id: post.id, title: post.title, action: :upvote, @@ -185,7 +185,7 @@ defmodule GroupherServer.Test.Delivery.Notification do notify_attrs |> Map.merge(%{ - type: :comment, + thread: :post, article_id: post.id, comment_id: 11, title: post.title, @@ -198,8 +198,7 @@ defmodule GroupherServer.Test.Delivery.Notification do invalid_notify_attrs = notify_attrs |> Map.merge(%{ - type: :comment, - article_id: post.id, + type: :post, title: post.title, action: :upvote, user_id: user.id @@ -211,7 +210,7 @@ defmodule GroupherServer.Test.Delivery.Notification do test "support collect", ~m(post user user2 notify_attrs)a do notify_attrs |> Map.merge(%{ - type: :post, + thread: :post, article_id: post.id, title: post.title, action: :collect, @@ -235,7 +234,7 @@ defmodule GroupherServer.Test.Delivery.Notification do test "support comment and reply", ~m(post user user2 notify_attrs)a do notify_attrs |> Map.merge(%{ - type: :post, + thread: :post, article_id: post.id, title: post.title, comment_id: 11, @@ -247,7 +246,7 @@ defmodule GroupherServer.Test.Delivery.Notification do notify_attrs |> Map.merge(%{ - type: :post, + thread: :post, article_id: post.id, comment_id: 11, title: post.title, @@ -260,7 +259,7 @@ defmodule GroupherServer.Test.Delivery.Notification do invalid_notify_attrs = notify_attrs |> Map.merge(%{ - type: :post, + thread: :post, article_id: post.id, title: post.title, action: :comment, @@ -272,7 +271,7 @@ defmodule GroupherServer.Test.Delivery.Notification do invalid_notify_attrs = notify_attrs |> Map.merge(%{ - type: :post, + thread: :post, article_id: post.id, title: post.title, action: :reply, From 52e13bcd20a95c906fcae130c4a6a4c1b8a1ffc2 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 20:06:01 +0800 Subject: [PATCH 29/54] refactor(delivery): fix test --- test/groupher_server/cms/hooks/notify_post_test.exs | 12 +++++------- test/groupher_server/delivery/notification_test.exs | 3 ++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/test/groupher_server/cms/hooks/notify_post_test.exs b/test/groupher_server/cms/hooks/notify_post_test.exs index dbd9533ad..e85a51a76 100644 --- a/test/groupher_server/cms/hooks/notify_post_test.exs +++ b/test/groupher_server/cms/hooks/notify_post_test.exs @@ -35,12 +35,12 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do notify = notifications.entries |> List.first() assert notify.action == "UPVOTE" assert notify.article_id == post.id - assert notify.type == "POST" + assert notify.thread == "POST" assert notify.user_id == post.author.user.id assert user_exist_in?(user2, notify.from_users) end - @tag :wip + @tag :wip2 test "upvote hook should work on post comment", ~m(user2 post comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) {:ok, comment} = preload_author(comment) @@ -55,7 +55,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do notify = notifications.entries |> List.first() assert notify.action == "UPVOTE" assert notify.article_id == post.id - assert notify.type == "POST" + assert notify.thread == "POST" assert notify.user_id == comment.author.id assert notify.comment_id == comment.id assert user_exist_in?(user2, notify.from_users) @@ -111,7 +111,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do notify = notifications.entries |> List.first() assert notify.action == "COLLECT" assert notify.article_id == post.id - assert notify.type == "POST" + assert notify.thread == "POST" assert notify.user_id == post.author.user.id assert user_exist_in?(user2, notify.from_users) end @@ -148,12 +148,10 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do notify = notifications.entries |> List.first() assert notify.action == "COMMENT" - assert notify.type == "POST" + assert notify.thread == "POST" assert notify.article_id == post.id assert notify.user_id == post.author.user.id assert user_exist_in?(user2, notify.from_users) - - IO.inspect(notifications, label: "notifications") end end end diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index b14e36592..ec757c567 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -17,7 +17,7 @@ defmodule GroupherServer.Test.Delivery.Notification do {:ok, community} = db_insert(:community) notify_attrs = %{ - type: :post, + thread: :post, article_id: post.id, title: post.title, action: :upvote, @@ -55,6 +55,7 @@ defmodule GroupherServer.Test.Delivery.Notification do assert user3 |> user_exist_in?(notify.from_users) end + @tag :wip test "different notify should not be merged", ~m(user user2 user3 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) notify_attrs = notify_attrs |> Map.put(:action, :collect) From 7f1332b5db7c8738c4115332c8d56c8eccd4d705 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 20:16:20 +0800 Subject: [PATCH 30/54] refactor(delivery): fix test --- test/groupher_server/cms/hooks/notify_post_test.exs | 2 +- test/groupher_server/delivery/notification_test.exs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/groupher_server/cms/hooks/notify_post_test.exs b/test/groupher_server/cms/hooks/notify_post_test.exs index e85a51a76..96cbfdd0e 100644 --- a/test/groupher_server/cms/hooks/notify_post_test.exs +++ b/test/groupher_server/cms/hooks/notify_post_test.exs @@ -134,7 +134,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do end describe "[comment notify]" do - @tag :wip + @tag :wip2 test "post author should get notify after some one comment on it", ~m(user2 post)a do {:ok, post} = preload_author(post) diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index ec757c567..e623caf39 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -55,7 +55,7 @@ defmodule GroupherServer.Test.Delivery.Notification do assert user3 |> user_exist_in?(notify.from_users) end - @tag :wip + @tag :wip2 test "different notify should not be merged", ~m(user user2 user3 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) notify_attrs = notify_attrs |> Map.put(:action, :collect) @@ -172,6 +172,7 @@ defmodule GroupherServer.Test.Delivery.Notification do end describe "basic thread support" do + @tag :wip test "support upvote", ~m(post user user2 notify_attrs)a do notify_attrs |> Map.merge(%{ @@ -200,6 +201,7 @@ defmodule GroupherServer.Test.Delivery.Notification do notify_attrs |> Map.merge(%{ type: :post, + article_id: nil, title: post.title, action: :upvote, user_id: user.id From 0733508121409c3d9f97b0d53311d9845a604e39 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 20:42:53 +0800 Subject: [PATCH 31/54] refactor(delivery): enhence test --- .../cms/delegates/comment_action.ex | 3 + .../cms/delegates/hooks/notify.ex | 19 ++ .../cms/hooks/notify_blog_test.exs | 183 ++++++++++++++++++ .../cms/hooks/notify_job_test.exs | 183 ++++++++++++++++++ .../cms/hooks/notify_post_test.exs | 30 ++- 5 files changed, 416 insertions(+), 2 deletions(-) create mode 100644 test/groupher_server/cms/hooks/notify_blog_test.exs create mode 100644 test/groupher_server/cms/hooks/notify_job_test.exs diff --git a/lib/groupher_server/cms/delegates/comment_action.ex b/lib/groupher_server/cms/delegates/comment_action.ex index 5f4e8ebb8..b0a805225 100644 --- a/lib/groupher_server/cms/delegates/comment_action.ex +++ b/lib/groupher_server/cms/delegates/comment_action.ex @@ -139,6 +139,9 @@ defmodule GroupherServer.CMS.Delegate.CommentAction do |> Ecto.Changeset.put_assoc(:reply_to, replying_comment) |> Repo.update() end) + |> Multi.run(:after_hooks, fn _, %{create_reply_comment: replyed_comment} -> + Later.run({Hooks.Notify, :handle, [:reply, replyed_comment, user]}) + end) |> Repo.transaction() |> result() else diff --git a/lib/groupher_server/cms/delegates/hooks/notify.ex b/lib/groupher_server/cms/delegates/hooks/notify.ex index a1b2c3db7..69120047b 100644 --- a/lib/groupher_server/cms/delegates/hooks/notify.ex +++ b/lib/groupher_server/cms/delegates/hooks/notify.ex @@ -29,6 +29,25 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Notify do Delivery.send(:notify, notify_attrs, from_user) end + # 回复评论是特殊情况,单独处理 + def handle(:reply, %Comment{} = reply_comment, %User{} = from_user) do + {:ok, article} = parent_article_of(reply_comment) + {:ok, article} = preload_author(article) + {:ok, thread} = thread_of_article(article) + + notify_attrs = %{ + action: :reply, + thread: thread, + article_id: article.id, + title: article.title, + comment_id: reply_comment.id, + # NOTE: 这里是提醒该评论的作者,不提醒文章作者了 + user_id: reply_comment.reply_to.author_id + } + + Delivery.send(:notify, notify_attrs, from_user) + end + def handle(action, %Comment{} = comment, %User{} = from_user) do {:ok, article} = parent_article_of(comment) {:ok, thread} = thread_of_article(article) diff --git a/test/groupher_server/cms/hooks/notify_blog_test.exs b/test/groupher_server/cms/hooks/notify_blog_test.exs new file mode 100644 index 000000000..d3d4b36c5 --- /dev/null +++ b/test/groupher_server/cms/hooks/notify_blog_test.exs @@ -0,0 +1,183 @@ +defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do + use GroupherServer.TestTools + + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] + + alias GroupherServer.{CMS, Delivery} + alias CMS.Delegate.Hooks + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, user3} = db_insert(:user) + + {:ok, community} = db_insert(:community) + + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + {:ok, blog} = CMS.create_article(community, :blog, blog_attrs, user) + {:ok, comment} = CMS.create_comment(:blog, blog.id, mock_comment(), user) + + {:ok, ~m(user2 user3 blog comment)a} + end + + describe "[upvote notify]" do + @tag :wip2 + test "upvote hook should work on blog", ~m(user2 blog)a do + {:ok, blog} = preload_author(blog) + + {:ok, article} = CMS.upvote_article(:blog, blog.id, user2) + Hooks.Notify.handle(:upvote, article, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "UPVOTE" + assert notify.article_id == blog.id + assert notify.thread == "BLOG" + assert notify.user_id == blog.author.user.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip2 + test "upvote hook should work on blog comment", ~m(user2 blog comment)a do + {:ok, comment} = CMS.upvote_comment(comment.id, user2) + {:ok, comment} = preload_author(comment) + + Hooks.Notify.handle(:upvote, comment, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "UPVOTE" + assert notify.article_id == blog.id + assert notify.thread == "BLOG" + assert notify.user_id == comment.author.id + assert notify.comment_id == comment.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip2 + test "undo upvote hook should work on blog", ~m(user2 blog)a do + {:ok, blog} = preload_author(blog) + + {:ok, article} = CMS.upvote_article(:blog, blog.id, user2) + Hooks.Notify.handle(:upvote, article, user2) + + {:ok, article} = CMS.undo_upvote_article(:blog, blog.id, user2) + Hooks.Notify.handle(:undo, :upvote, article, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + + @tag :wip2 + test "undo upvote hook should work on blog comment", ~m(user2 comment)a do + {:ok, comment} = CMS.upvote_comment(comment.id, user2) + + Hooks.Notify.handle(:upvote, comment, user2) + + {:ok, comment} = CMS.undo_upvote_comment(comment.id, user2) + Hooks.Notify.handle(:undo, :upvote, comment, user2) + + {:ok, comment} = preload_author(comment) + + {:ok, notifications} = + Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + end + + describe "[collect notify]" do + @tag :wip2 + test "collect hook should work on blog", ~m(user2 blog)a do + {:ok, blog} = preload_author(blog) + + {:ok, _} = CMS.collect_article(:blog, blog.id, user2) + Hooks.Notify.handle(:collect, blog, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "COLLECT" + assert notify.article_id == blog.id + assert notify.thread == "BLOG" + assert notify.user_id == blog.author.user.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip2 + test "undo collect hook should work on blog", ~m(user2 blog)a do + {:ok, blog} = preload_author(blog) + + {:ok, _} = CMS.upvote_article(:blog, blog.id, user2) + Hooks.Notify.handle(:collect, blog, user2) + + {:ok, _} = CMS.undo_upvote_article(:blog, blog.id, user2) + Hooks.Notify.handle(:undo, :collect, blog, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + end + + describe "[comment notify]" do + @tag :wip + test "blog author should get notify after some one comment on it", ~m(user2 blog)a do + {:ok, blog} = preload_author(blog) + + {:ok, comment} = CMS.create_comment(:blog, blog.id, mock_comment(), user2) + Hooks.Notify.handle(:comment, comment, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "COMMENT" + assert notify.thread == "BLOG" + assert notify.article_id == blog.id + assert notify.user_id == blog.author.user.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "blog comment author should get notify after some one reply it", ~m(user2 user3 blog)a do + {:ok, blog} = preload_author(blog) + + {:ok, comment} = CMS.create_comment(:blog, blog.id, mock_comment(), user2) + {:ok, replyed_comment} = CMS.reply_comment(comment.id, mock_comment(), user3) + + Hooks.Notify.handle(:reply, replyed_comment, user3) + + {:ok, notifications} = + Delivery.fetch(:notification, comment.author_id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + + assert notify.action == "REPLY" + assert notify.thread == "BLOG" + assert notify.article_id == blog.id + assert notify.comment_id == replyed_comment.id + + assert notify.user_id == comment.author_id + assert user_exist_in?(user3, notify.from_users) + end + end +end diff --git a/test/groupher_server/cms/hooks/notify_job_test.exs b/test/groupher_server/cms/hooks/notify_job_test.exs new file mode 100644 index 000000000..832aa5c2e --- /dev/null +++ b/test/groupher_server/cms/hooks/notify_job_test.exs @@ -0,0 +1,183 @@ +defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do + use GroupherServer.TestTools + + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] + + alias GroupherServer.{CMS, Delivery} + alias CMS.Delegate.Hooks + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, user3} = db_insert(:user) + + {:ok, community} = db_insert(:community) + + job_attrs = mock_attrs(:job, %{community_id: community.id}) + {:ok, job} = CMS.create_article(community, :job, job_attrs, user) + {:ok, comment} = CMS.create_comment(:job, job.id, mock_comment(), user) + + {:ok, ~m(user2 user3 job comment)a} + end + + describe "[upvote notify]" do + @tag :wip2 + test "upvote hook should work on job", ~m(user2 job)a do + {:ok, job} = preload_author(job) + + {:ok, article} = CMS.upvote_article(:job, job.id, user2) + Hooks.Notify.handle(:upvote, article, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "UPVOTE" + assert notify.article_id == job.id + assert notify.thread == "JOB" + assert notify.user_id == job.author.user.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip2 + test "upvote hook should work on job comment", ~m(user2 job comment)a do + {:ok, comment} = CMS.upvote_comment(comment.id, user2) + {:ok, comment} = preload_author(comment) + + Hooks.Notify.handle(:upvote, comment, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "UPVOTE" + assert notify.article_id == job.id + assert notify.thread == "JOB" + assert notify.user_id == comment.author.id + assert notify.comment_id == comment.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip2 + test "undo upvote hook should work on job", ~m(user2 job)a do + {:ok, job} = preload_author(job) + + {:ok, article} = CMS.upvote_article(:job, job.id, user2) + Hooks.Notify.handle(:upvote, article, user2) + + {:ok, article} = CMS.undo_upvote_article(:job, job.id, user2) + Hooks.Notify.handle(:undo, :upvote, article, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + + @tag :wip2 + test "undo upvote hook should work on job comment", ~m(user2 comment)a do + {:ok, comment} = CMS.upvote_comment(comment.id, user2) + + Hooks.Notify.handle(:upvote, comment, user2) + + {:ok, comment} = CMS.undo_upvote_comment(comment.id, user2) + Hooks.Notify.handle(:undo, :upvote, comment, user2) + + {:ok, comment} = preload_author(comment) + + {:ok, notifications} = + Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + end + + describe "[collect notify]" do + @tag :wip2 + test "collect hook should work on job", ~m(user2 job)a do + {:ok, job} = preload_author(job) + + {:ok, _} = CMS.collect_article(:job, job.id, user2) + Hooks.Notify.handle(:collect, job, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "COLLECT" + assert notify.article_id == job.id + assert notify.thread == "JOB" + assert notify.user_id == job.author.user.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip2 + test "undo collect hook should work on job", ~m(user2 job)a do + {:ok, job} = preload_author(job) + + {:ok, _} = CMS.upvote_article(:job, job.id, user2) + Hooks.Notify.handle(:collect, job, user2) + + {:ok, _} = CMS.undo_upvote_article(:job, job.id, user2) + Hooks.Notify.handle(:undo, :collect, job, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 0 + end + end + + describe "[comment notify]" do + @tag :wip + test "job author should get notify after some one comment on it", ~m(user2 job)a do + {:ok, job} = preload_author(job) + + {:ok, comment} = CMS.create_comment(:job, job.id, mock_comment(), user2) + Hooks.Notify.handle(:comment, comment, user2) + + {:ok, notifications} = + Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "COMMENT" + assert notify.thread == "JOB" + assert notify.article_id == job.id + assert notify.user_id == job.author.user.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "job comment author should get notify after some one reply it", ~m(user2 user3 job)a do + {:ok, job} = preload_author(job) + + {:ok, comment} = CMS.create_comment(:job, job.id, mock_comment(), user2) + {:ok, replyed_comment} = CMS.reply_comment(comment.id, mock_comment(), user3) + + Hooks.Notify.handle(:reply, replyed_comment, user3) + + {:ok, notifications} = + Delivery.fetch(:notification, comment.author_id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + + assert notify.action == "REPLY" + assert notify.thread == "JOB" + assert notify.article_id == job.id + assert notify.comment_id == replyed_comment.id + + assert notify.user_id == comment.author_id + assert user_exist_in?(user3, notify.from_users) + end + end +end diff --git a/test/groupher_server/cms/hooks/notify_post_test.exs b/test/groupher_server/cms/hooks/notify_post_test.exs index 96cbfdd0e..f6c88194c 100644 --- a/test/groupher_server/cms/hooks/notify_post_test.exs +++ b/test/groupher_server/cms/hooks/notify_post_test.exs @@ -9,6 +9,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do setup do {:ok, user} = db_insert(:user) {:ok, user2} = db_insert(:user) + {:ok, user3} = db_insert(:user) {:ok, community} = db_insert(:community) @@ -16,7 +17,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do {:ok, post} = CMS.create_article(community, :post, post_attrs, user) {:ok, comment} = CMS.create_comment(:post, post.id, mock_comment(), user) - {:ok, ~m(user2 post comment)a} + {:ok, ~m(user2 user3 post comment)a} end describe "[upvote notify]" do @@ -134,7 +135,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do end describe "[comment notify]" do - @tag :wip2 + @tag :wip test "post author should get notify after some one comment on it", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -153,5 +154,30 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert notify.user_id == post.author.user.id assert user_exist_in?(user2, notify.from_users) end + + @tag :wip + test "post comment author should get notify after some one reply it", ~m(user2 user3 post)a do + {:ok, post} = preload_author(post) + + {:ok, comment} = CMS.create_comment(:post, post.id, mock_comment(), user2) + {:ok, replyed_comment} = CMS.reply_comment(comment.id, mock_comment(), user3) + + Hooks.Notify.handle(:reply, replyed_comment, user3) + + {:ok, notifications} = + Delivery.fetch(:notification, comment.author_id, %{page: 1, size: 20}) + + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + + assert notify.action == "REPLY" + assert notify.thread == "POST" + assert notify.article_id == post.id + assert notify.comment_id == replyed_comment.id + + assert notify.user_id == comment.author_id + assert user_exist_in?(user3, notify.from_users) + end end end From 69f37b6933acddb51c8c26fa356a60b5c0487a05 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 21:01:54 +0800 Subject: [PATCH 32/54] refactor(cite): naming adjust --- .../cms/delegates/hooks/cite.ex | 5 ++ .../cms/hooks/cite_blog_test.exs | 85 ++++++++++++++++--- .../cms/hooks/cite_job_test.exs | 74 ++++++++++++++-- .../cms/hooks/cite_post_test.exs | 17 ++-- .../cms/hooks/notify_blog_test.exs | 4 +- .../cms/hooks/notify_job_test.exs | 4 +- .../cms/hooks/notify_post_test.exs | 4 +- .../delivery/notification_test.exs | 2 +- 8 files changed, 161 insertions(+), 34 deletions(-) diff --git a/lib/groupher_server/cms/delegates/hooks/cite.ex b/lib/groupher_server/cms/delegates/hooks/cite.ex index dc6e30e1b..7f97b8375 100644 --- a/lib/groupher_server/cms/delegates/hooks/cite.ex +++ b/lib/groupher_server/cms/delegates/hooks/cite.ex @@ -21,6 +21,11 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Cite do cited_type: thread or comment artiment: article or comment # cited_article_comment_id, [xxx_article]_id, [block_id, block2_id, ...], + + 注意 cited_by_type 不能命名为 cited_by_thread + + 因为 cited_by_thread 无法表示这样的语义: + # 某评论被 post 以 comment link 的方式引用了 """ import Ecto.Query, warn: false diff --git a/test/groupher_server/cms/hooks/cite_blog_test.exs b/test/groupher_server/cms/hooks/cite_blog_test.exs index 0e3a568c8..4b71ddff7 100644 --- a/test/groupher_server/cms/hooks/cite_blog_test.exs +++ b/test/groupher_server/cms/hooks/cite_blog_test.exs @@ -31,9 +31,9 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteBlog do test "cited multi blog should work", ~m(user community blog2 blog3 blog4 blog5 blog_attrs)a do body = mock_rich_text( - ~s(the
and same la is awesome, the is awesome too.), + ~s(the and same la is awesome, the is awesome too.), # second paragraph ~s(the paragraph 2 again, the paragraph 2 and same la is awesome, the is awesome too.), + ~s(the and same la is awesome, the is awesome too.), # second paragraph ~s(the paragraph 2 again, the paragraph 2 )) + + {:ok, blog} = CMS.create_article(community, :blog, Map.merge(blog_attrs, %{body: body}), user) + + Hooks.Cite.handle(blog) + + Process.sleep(1000) + + {:ok, blog} = CMS.create_article(community, :blog, Map.merge(blog_attrs, %{body: body}), user) + Hooks.Cite.handle(blog) + + Process.sleep(1000) + + comment_body = mock_comment(~s(the )) + {:ok, comment} = CMS.create_comment(:blog, blog.id, comment_body, user) + + Hooks.Cite.handle(comment) + + Process.sleep(1000) + + {:ok, blog} = + CMS.create_article(community, :blog, Map.merge(blog_attrs, %{body: body}), user) + + Hooks.Cite.handle(blog) + + {:ok, result} = CMS.paged_citing_contents("BLOG", blog2.id, %{page: 1, size: 10}) + # IO.inspect(result, label: "the result") + + assert result.total_count == 4 + + result_blog = result.entries |> List.first() + result_blog = result.entries |> Enum.at(1) + result_comment = result.entries |> Enum.at(2) + result_blog = result.entries |> List.last() + + assert result_blog.id == blog.id + assert result_blog.thread == :blog + + assert result_blog.id == blog.id + assert result_blog.thread == :blog + + assert result_comment.id == blog.id + assert result_comment.thread == :blog + assert result_comment.comment_id == comment.id + + assert result_blog.id == blog.id + assert result_blog.thread == :blog + end + end end diff --git a/test/groupher_server/cms/hooks/cite_job_test.exs b/test/groupher_server/cms/hooks/cite_job_test.exs index 373b07911..ae4d4bd6e 100644 --- a/test/groupher_server/cms/hooks/cite_job_test.exs +++ b/test/groupher_server/cms/hooks/cite_job_test.exs @@ -90,6 +90,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteJob do assert cited_comment.meta.citing_count == 0 end + @tag :wip test "can cite job's comment in job", ~m(community user job job2 job_attrs)a do {:ok, comment} = CMS.create_comment(:job, job.id, mock_rich_text("hello"), user) @@ -104,9 +105,11 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteJob do {:ok, comment} = ORM.find(Comment, comment.id) assert comment.meta.citing_count == 1 - {:ok, cite_content} = ORM.find_by(CitedArtiment, %{cited_by_id: comment.id}) - assert job.id == cite_content.job_id - assert cite_content.cited_by_type == "COMMENT" + {:ok, cited_content} = ORM.find_by(CitedArtiment, %{cited_by_id: comment.id}) + + # 被 job 以 comment link 的方式引用了 + assert cited_content.job_id == job.id + assert cited_content.cited_by_type == "COMMENT" end test "can cite a comment in a comment", ~m(user job)a do @@ -124,10 +127,10 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteJob do {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 1 - {:ok, cite_content} = ORM.find_by(CitedArtiment, %{cited_by_id: cited_comment.id}) - assert comment.id == cite_content.comment_id - assert cited_comment.id == cite_content.cited_by_id - assert cite_content.cited_by_type == "COMMENT" + {:ok, cited_content} = ORM.find_by(CitedArtiment, %{cited_by_id: cited_comment.id}) + assert comment.id == cited_content.comment_id + assert cited_comment.id == cited_content.cited_by_id + assert cited_content.cited_by_type == "COMMENT" end test "can cited job inside a comment", ~m(user job job2 job3 job4 job5)a do @@ -182,6 +185,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteJob do job_attrs = job_attrs |> Map.merge(%{body: body}) {:ok, job_x} = CMS.create_article(community, :job, job_attrs, user) + Process.sleep(1000) body = mock_rich_text(~s(the )) job_attrs = job_attrs |> Map.merge(%{body: body}) @@ -217,4 +221,60 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteJob do assert result.total_count == 3 end end + + describe "[cross cite]" do + test "can citing multi type thread and comment in one time", ~m(user community job2)a do + job_attrs = mock_attrs(:job, %{community_id: community.id}) + job_attrs = mock_attrs(:job, %{community_id: community.id}) + blog_attrs = mock_attrs(:blog, %{community_id: community.id}) + + body = mock_rich_text(~s(the )) + + {:ok, job} = CMS.create_article(community, :job, Map.merge(job_attrs, %{body: body}), user) + + Hooks.Cite.handle(job) + + Process.sleep(1000) + + {:ok, job} = CMS.create_article(community, :job, Map.merge(job_attrs, %{body: body}), user) + Hooks.Cite.handle(job) + + Process.sleep(1000) + + comment_body = mock_comment(~s(the )) + {:ok, comment} = CMS.create_comment(:job, job.id, comment_body, user) + + Hooks.Cite.handle(comment) + + Process.sleep(1000) + + {:ok, blog} = + CMS.create_article(community, :blog, Map.merge(blog_attrs, %{body: body}), user) + + Hooks.Cite.handle(blog) + + {:ok, result} = CMS.paged_citing_contents("JOB", job2.id, %{page: 1, size: 10}) + # IO.inspect(result, label: "the result") + + assert result.total_count == 4 + + result_job = result.entries |> List.first() + result_job = result.entries |> Enum.at(1) + result_comment = result.entries |> Enum.at(2) + result_blog = result.entries |> List.last() + + assert result_job.id == job.id + assert result_job.thread == :job + + assert result_job.id == job.id + assert result_job.thread == :job + + assert result_comment.id == job.id + assert result_comment.thread == :job + assert result_comment.comment_id == comment.id + + assert result_blog.id == blog.id + assert result_blog.thread == :blog + end + end end diff --git a/test/groupher_server/cms/hooks/cite_post_test.exs b/test/groupher_server/cms/hooks/cite_post_test.exs index 21d67bc35..d24d1043a 100644 --- a/test/groupher_server/cms/hooks/cite_post_test.exs +++ b/test/groupher_server/cms/hooks/cite_post_test.exs @@ -90,6 +90,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CitePost do assert cited_comment.meta.citing_count == 0 end + @tag :wip test "can cite post's comment in post", ~m(community user post post2 post_attrs)a do {:ok, comment} = CMS.create_comment(:post, post.id, mock_rich_text("hello"), user) @@ -104,9 +105,11 @@ defmodule GroupherServer.Test.CMS.Hooks.CitePost do {:ok, comment} = ORM.find(Comment, comment.id) assert comment.meta.citing_count == 1 - {:ok, cite_content} = ORM.find_by(CitedArtiment, %{cited_by_id: comment.id}) - assert post.id == cite_content.post_id - assert cite_content.cited_by_type == "COMMENT" + {:ok, cited_content} = ORM.find_by(CitedArtiment, %{cited_by_id: comment.id}) + + # 被 post 以 comment link 的方式引用了 + assert cited_content.post_id == post.id + assert cited_content.cited_by_type == "COMMENT" end test "can cite a comment in a comment", ~m(user post)a do @@ -124,10 +127,10 @@ defmodule GroupherServer.Test.CMS.Hooks.CitePost do {:ok, cited_comment} = ORM.find(Comment, cited_comment.id) assert cited_comment.meta.citing_count == 1 - {:ok, cite_content} = ORM.find_by(CitedArtiment, %{cited_by_id: cited_comment.id}) - assert comment.id == cite_content.comment_id - assert cited_comment.id == cite_content.cited_by_id - assert cite_content.cited_by_type == "COMMENT" + {:ok, cited_content} = ORM.find_by(CitedArtiment, %{cited_by_id: cited_comment.id}) + assert comment.id == cited_content.comment_id + assert cited_comment.id == cited_content.cited_by_id + assert cited_content.cited_by_type == "COMMENT" end test "can cited post inside a comment", ~m(user post post2 post3 post4 post5)a do diff --git a/test/groupher_server/cms/hooks/notify_blog_test.exs b/test/groupher_server/cms/hooks/notify_blog_test.exs index d3d4b36c5..2ccdd35f7 100644 --- a/test/groupher_server/cms/hooks/notify_blog_test.exs +++ b/test/groupher_server/cms/hooks/notify_blog_test.exs @@ -135,7 +135,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do end describe "[comment notify]" do - @tag :wip + @tag :wip2 test "blog author should get notify after some one comment on it", ~m(user2 blog)a do {:ok, blog} = preload_author(blog) @@ -155,7 +155,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert user_exist_in?(user2, notify.from_users) end - @tag :wip + @tag :wip2 test "blog comment author should get notify after some one reply it", ~m(user2 user3 blog)a do {:ok, blog} = preload_author(blog) diff --git a/test/groupher_server/cms/hooks/notify_job_test.exs b/test/groupher_server/cms/hooks/notify_job_test.exs index 832aa5c2e..ba6743959 100644 --- a/test/groupher_server/cms/hooks/notify_job_test.exs +++ b/test/groupher_server/cms/hooks/notify_job_test.exs @@ -135,7 +135,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do end describe "[comment notify]" do - @tag :wip + @tag :wip2 test "job author should get notify after some one comment on it", ~m(user2 job)a do {:ok, job} = preload_author(job) @@ -155,7 +155,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert user_exist_in?(user2, notify.from_users) end - @tag :wip + @tag :wip2 test "job comment author should get notify after some one reply it", ~m(user2 user3 job)a do {:ok, job} = preload_author(job) diff --git a/test/groupher_server/cms/hooks/notify_post_test.exs b/test/groupher_server/cms/hooks/notify_post_test.exs index f6c88194c..0a01b3538 100644 --- a/test/groupher_server/cms/hooks/notify_post_test.exs +++ b/test/groupher_server/cms/hooks/notify_post_test.exs @@ -135,7 +135,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do end describe "[comment notify]" do - @tag :wip + @tag :wip2 test "post author should get notify after some one comment on it", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -155,7 +155,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert user_exist_in?(user2, notify.from_users) end - @tag :wip + @tag :wip2 test "post comment author should get notify after some one reply it", ~m(user2 user3 post)a do {:ok, post} = preload_author(post) diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index e623caf39..e1265d9ce 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -172,7 +172,7 @@ defmodule GroupherServer.Test.Delivery.Notification do end describe "basic thread support" do - @tag :wip + @tag :wip2 test "support upvote", ~m(post user user2 notify_attrs)a do notify_attrs |> Map.merge(%{ From ac43691f40c53a3ffa0afecc66beb0af7c380203 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 21:20:41 +0800 Subject: [PATCH 33/54] refactor(mention): rename type -> thread --- .../cms/delegates/comment_action.ex | 1 + lib/groupher_server/cms/delegates/comment_curd.ex | 1 + lib/groupher_server/cms/delegates/hooks/mention.ex | 8 ++++---- lib/groupher_server/delivery/delegates/mention.ex | 14 ++++++-------- lib/groupher_server/delivery/models/mention.ex | 4 ++-- ...210620131328_rename_mentions_type_to_thread.exs | 7 +++++++ 6 files changed, 21 insertions(+), 14 deletions(-) create mode 100644 priv/repo/migrations/20210620131328_rename_mentions_type_to_thread.exs diff --git a/lib/groupher_server/cms/delegates/comment_action.ex b/lib/groupher_server/cms/delegates/comment_action.ex index b0a805225..71c3583b4 100644 --- a/lib/groupher_server/cms/delegates/comment_action.ex +++ b/lib/groupher_server/cms/delegates/comment_action.ex @@ -141,6 +141,7 @@ defmodule GroupherServer.CMS.Delegate.CommentAction do end) |> Multi.run(:after_hooks, fn _, %{create_reply_comment: replyed_comment} -> Later.run({Hooks.Notify, :handle, [:reply, replyed_comment, user]}) + Later.run({Hooks.Mention, :handle, [replyed_comment]}) end) |> Repo.transaction() |> result() diff --git a/lib/groupher_server/cms/delegates/comment_curd.ex b/lib/groupher_server/cms/delegates/comment_curd.ex index 05ad8575d..a28f24f3c 100644 --- a/lib/groupher_server/cms/delegates/comment_curd.ex +++ b/lib/groupher_server/cms/delegates/comment_curd.ex @@ -117,6 +117,7 @@ defmodule GroupherServer.CMS.Delegate.CommentCurd do |> Multi.run(:after_hooks, fn _, %{create_comment: comment} -> Later.run({Hooks.Cite, :handle, [comment]}) Later.run({Hooks.Notify, :handle, [:comment, comment, user]}) + Later.run({Hooks.Mention, :handle, [comment]}) end) |> Repo.transaction() |> result() diff --git a/lib/groupher_server/cms/delegates/hooks/mention.ex b/lib/groupher_server/cms/delegates/hooks/mention.ex index 50c2c9547..f48d66fa5 100644 --- a/lib/groupher_server/cms/delegates/hooks/mention.ex +++ b/lib/groupher_server/cms/delegates/hooks/mention.ex @@ -5,7 +5,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do parse and fmt(see shape function) mentions to Delivery module """ import Ecto.Query, warn: false - import Helper.Utils, only: [get_config: 2, thread_of_article: 2] + import Helper.Utils, only: [get_config: 2, thread_of_article: 1] import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1, author_of: 1] import GroupherServer.CMS.Delegate.Hooks.Helper, only: [merge_same_block_linker: 2] @@ -71,7 +71,7 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do parent_article = comment |> Map.get(article_thread) %{ - type: "COMMENT", + thread: article_thread, title: parent_article.title, article_id: parent_article.id, comment_id: comment.id, @@ -85,10 +85,10 @@ defmodule GroupherServer.CMS.Delegate.Hooks.Mention do end defp shape(article, to_user_id, block_id) do - {:ok, thread} = thread_of_article(article, :upcase) + {:ok, thread} = thread_of_article(article) %{ - type: thread, + thread: thread, title: article.title, article_id: article.id, block_linker: [block_id], diff --git a/lib/groupher_server/delivery/delegates/mention.ex b/lib/groupher_server/delivery/delegates/mention.ex index 89057ebfd..e9ddc8102 100644 --- a/lib/groupher_server/delivery/delegates/mention.ex +++ b/lib/groupher_server/delivery/delegates/mention.ex @@ -3,7 +3,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do The Delivery context. """ import Ecto.Query, warn: false - import Helper.Utils, only: [done: 1, thread_of_article: 1] + import Helper.Utils, only: [done: 1, thread_of_article: 2, atom_values_to_upcase: 1] import ShortMaps alias GroupherServer.{Accounts, CMS, Delivery, Repo} @@ -30,7 +30,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do batch_delete_mentions(comment, from_user) end) |> Multi.run(:batch_insert_mentions, fn _, _ -> - case {0, nil} !== Repo.insert_all(Mention, mentions) do + case {0, nil} !== Repo.insert_all(Mention, atom_values_to_upcase(mentions)) do true -> {:ok, :pass} false -> {:error, "insert mentions error"} end @@ -45,7 +45,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do batch_delete_mentions(article, from_user) end) |> Multi.run(:batch_insert_mentions, fn _, _ -> - case {0, nil} !== Repo.insert_all(Mention, mentions) do + case {0, nil} !== Repo.insert_all(Mention, atom_values_to_upcase(mentions)) do true -> {:ok, :pass} false -> {:error, "insert mentions error"} end @@ -74,12 +74,10 @@ defmodule GroupherServer.Delivery.Delegate.Mention do end defp batch_delete_mentions(article, %User{} = from_user) do - with {:ok, thread} <- thread_of_article(article) do - thread = thread |> to_string |> String.upcase() - + with {:ok, thread} <- thread_of_article(article, :upcase) do from(m in Mention, where: m.article_id == ^article.id, - where: m.type == ^thread, + where: m.thread == ^thread, where: m.from_user_id == ^from_user.id ) |> ORM.delete_all(:if_exist) @@ -98,7 +96,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do mention |> Map.take([ - :type, + :thread, :article_id, :comment_id, :title, diff --git a/lib/groupher_server/delivery/models/mention.ex b/lib/groupher_server/delivery/models/mention.ex index 22e98b33a..2b8bf7188 100644 --- a/lib/groupher_server/delivery/models/mention.ex +++ b/lib/groupher_server/delivery/models/mention.ex @@ -7,12 +7,12 @@ defmodule GroupherServer.Delivery.Model.Mention do alias GroupherServer.Accounts.Model.User - @required_fields ~w(from_user_id to_user_id title article_id type)a + @required_fields ~w(from_user_id to_user_id title article_id thread)a @optional_fields ~w(comment_id read)a @type t :: %Mention{} schema "mentions" do - field(:type, :string) + field(:thread, :string) field(:article_id, :id) field(:title, :string) field(:comment_id, :id) diff --git a/priv/repo/migrations/20210620131328_rename_mentions_type_to_thread.exs b/priv/repo/migrations/20210620131328_rename_mentions_type_to_thread.exs new file mode 100644 index 000000000..7e89483f4 --- /dev/null +++ b/priv/repo/migrations/20210620131328_rename_mentions_type_to_thread.exs @@ -0,0 +1,7 @@ +defmodule GroupherServer.Repo.Migrations.RenameMentionsTypeToThread do + use Ecto.Migration + + def change do + rename(table(:mentions), :type, to: :thread) + end +end From 076ad218d7ad98522532a65cdc32d9b73515179e Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 21:29:14 +0800 Subject: [PATCH 34/54] refactor(mention): clean up --- .../cms/hooks/cite_blog_test.exs | 70 ++----------------- .../cms/hooks/cite_job_test.exs | 58 +-------------- .../cms/hooks/cite_post_test.exs | 2 +- .../cms/hooks/notify_blog_test.exs | 16 ++--- .../cms/hooks/notify_job_test.exs | 16 ++--- .../cms/hooks/notify_post_test.exs | 16 ++--- .../delivery/notification_test.exs | 4 +- 7 files changed, 35 insertions(+), 147 deletions(-) diff --git a/test/groupher_server/cms/hooks/cite_blog_test.exs b/test/groupher_server/cms/hooks/cite_blog_test.exs index 4b71ddff7..12d8b65c7 100644 --- a/test/groupher_server/cms/hooks/cite_blog_test.exs +++ b/test/groupher_server/cms/hooks/cite_blog_test.exs @@ -31,9 +31,9 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteBlog do test "cited multi blog should work", ~m(user community blog2 blog3 blog4 blog5 blog_attrs)a do body = mock_rich_text( - ~s(the and same la is awesome, the is awesome too.), + ~s(the and same la is awesome, the is awesome too.), # second paragraph ~s(the paragraph 2 again, the paragraph 2 and same la is awesome, the is awesome too.), + ~s(the and same la is awesome, the is awesome too.), # second paragraph ~s(the paragraph 2 again, the paragraph 2 )) - - {:ok, blog} = CMS.create_article(community, :blog, Map.merge(blog_attrs, %{body: body}), user) - - Hooks.Cite.handle(blog) - - Process.sleep(1000) - - {:ok, blog} = CMS.create_article(community, :blog, Map.merge(blog_attrs, %{body: body}), user) - Hooks.Cite.handle(blog) - - Process.sleep(1000) - - comment_body = mock_comment(~s(the )) - {:ok, comment} = CMS.create_comment(:blog, blog.id, comment_body, user) - - Hooks.Cite.handle(comment) - - Process.sleep(1000) - - {:ok, blog} = - CMS.create_article(community, :blog, Map.merge(blog_attrs, %{body: body}), user) - - Hooks.Cite.handle(blog) - - {:ok, result} = CMS.paged_citing_contents("BLOG", blog2.id, %{page: 1, size: 10}) - # IO.inspect(result, label: "the result") - - assert result.total_count == 4 - - result_blog = result.entries |> List.first() - result_blog = result.entries |> Enum.at(1) - result_comment = result.entries |> Enum.at(2) - result_blog = result.entries |> List.last() - - assert result_blog.id == blog.id - assert result_blog.thread == :blog - - assert result_blog.id == blog.id - assert result_blog.thread == :blog - - assert result_comment.id == blog.id - assert result_comment.thread == :blog - assert result_comment.comment_id == comment.id - - assert result_blog.id == blog.id - assert result_blog.thread == :blog - end - end end diff --git a/test/groupher_server/cms/hooks/cite_job_test.exs b/test/groupher_server/cms/hooks/cite_job_test.exs index ae4d4bd6e..d0e598217 100644 --- a/test/groupher_server/cms/hooks/cite_job_test.exs +++ b/test/groupher_server/cms/hooks/cite_job_test.exs @@ -90,7 +90,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteJob do assert cited_comment.meta.citing_count == 0 end - @tag :wip + @tag :wip2 test "can cite job's comment in job", ~m(community user job job2 job_attrs)a do {:ok, comment} = CMS.create_comment(:job, job.id, mock_rich_text("hello"), user) @@ -221,60 +221,4 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteJob do assert result.total_count == 3 end end - - describe "[cross cite]" do - test "can citing multi type thread and comment in one time", ~m(user community job2)a do - job_attrs = mock_attrs(:job, %{community_id: community.id}) - job_attrs = mock_attrs(:job, %{community_id: community.id}) - blog_attrs = mock_attrs(:blog, %{community_id: community.id}) - - body = mock_rich_text(~s(the )) - - {:ok, job} = CMS.create_article(community, :job, Map.merge(job_attrs, %{body: body}), user) - - Hooks.Cite.handle(job) - - Process.sleep(1000) - - {:ok, job} = CMS.create_article(community, :job, Map.merge(job_attrs, %{body: body}), user) - Hooks.Cite.handle(job) - - Process.sleep(1000) - - comment_body = mock_comment(~s(the )) - {:ok, comment} = CMS.create_comment(:job, job.id, comment_body, user) - - Hooks.Cite.handle(comment) - - Process.sleep(1000) - - {:ok, blog} = - CMS.create_article(community, :blog, Map.merge(blog_attrs, %{body: body}), user) - - Hooks.Cite.handle(blog) - - {:ok, result} = CMS.paged_citing_contents("JOB", job2.id, %{page: 1, size: 10}) - # IO.inspect(result, label: "the result") - - assert result.total_count == 4 - - result_job = result.entries |> List.first() - result_job = result.entries |> Enum.at(1) - result_comment = result.entries |> Enum.at(2) - result_blog = result.entries |> List.last() - - assert result_job.id == job.id - assert result_job.thread == :job - - assert result_job.id == job.id - assert result_job.thread == :job - - assert result_comment.id == job.id - assert result_comment.thread == :job - assert result_comment.comment_id == comment.id - - assert result_blog.id == blog.id - assert result_blog.thread == :blog - end - end end diff --git a/test/groupher_server/cms/hooks/cite_post_test.exs b/test/groupher_server/cms/hooks/cite_post_test.exs index d24d1043a..042ef606c 100644 --- a/test/groupher_server/cms/hooks/cite_post_test.exs +++ b/test/groupher_server/cms/hooks/cite_post_test.exs @@ -90,7 +90,7 @@ defmodule GroupherServer.Test.CMS.Hooks.CitePost do assert cited_comment.meta.citing_count == 0 end - @tag :wip + @tag :wip2 test "can cite post's comment in post", ~m(community user post post2 post_attrs)a do {:ok, comment} = CMS.create_comment(:post, post.id, mock_rich_text("hello"), user) diff --git a/test/groupher_server/cms/hooks/notify_blog_test.exs b/test/groupher_server/cms/hooks/notify_blog_test.exs index 2ccdd35f7..59dbee407 100644 --- a/test/groupher_server/cms/hooks/notify_blog_test.exs +++ b/test/groupher_server/cms/hooks/notify_blog_test.exs @@ -21,7 +21,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do end describe "[upvote notify]" do - @tag :wip2 + @tag :wip22 test "upvote hook should work on blog", ~m(user2 blog)a do {:ok, blog} = preload_author(blog) @@ -41,7 +41,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert user_exist_in?(user2, notify.from_users) end - @tag :wip2 + @tag :wip22 test "upvote hook should work on blog comment", ~m(user2 blog comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) {:ok, comment} = preload_author(comment) @@ -62,7 +62,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert user_exist_in?(user2, notify.from_users) end - @tag :wip2 + @tag :wip22 test "undo upvote hook should work on blog", ~m(user2 blog)a do {:ok, blog} = preload_author(blog) @@ -78,7 +78,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert notifications.total_count == 0 end - @tag :wip2 + @tag :wip22 test "undo upvote hook should work on blog comment", ~m(user2 comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) @@ -97,7 +97,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do end describe "[collect notify]" do - @tag :wip2 + @tag :wip22 test "collect hook should work on blog", ~m(user2 blog)a do {:ok, blog} = preload_author(blog) @@ -117,7 +117,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert user_exist_in?(user2, notify.from_users) end - @tag :wip2 + @tag :wip22 test "undo collect hook should work on blog", ~m(user2 blog)a do {:ok, blog} = preload_author(blog) @@ -135,7 +135,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do end describe "[comment notify]" do - @tag :wip2 + @tag :wip22 test "blog author should get notify after some one comment on it", ~m(user2 blog)a do {:ok, blog} = preload_author(blog) @@ -155,7 +155,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert user_exist_in?(user2, notify.from_users) end - @tag :wip2 + @tag :wip22 test "blog comment author should get notify after some one reply it", ~m(user2 user3 blog)a do {:ok, blog} = preload_author(blog) diff --git a/test/groupher_server/cms/hooks/notify_job_test.exs b/test/groupher_server/cms/hooks/notify_job_test.exs index ba6743959..24d2a3d18 100644 --- a/test/groupher_server/cms/hooks/notify_job_test.exs +++ b/test/groupher_server/cms/hooks/notify_job_test.exs @@ -21,7 +21,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do end describe "[upvote notify]" do - @tag :wip2 + @tag :wip22 test "upvote hook should work on job", ~m(user2 job)a do {:ok, job} = preload_author(job) @@ -41,7 +41,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert user_exist_in?(user2, notify.from_users) end - @tag :wip2 + @tag :wip22 test "upvote hook should work on job comment", ~m(user2 job comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) {:ok, comment} = preload_author(comment) @@ -62,7 +62,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert user_exist_in?(user2, notify.from_users) end - @tag :wip2 + @tag :wip22 test "undo upvote hook should work on job", ~m(user2 job)a do {:ok, job} = preload_author(job) @@ -78,7 +78,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert notifications.total_count == 0 end - @tag :wip2 + @tag :wip22 test "undo upvote hook should work on job comment", ~m(user2 comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) @@ -97,7 +97,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do end describe "[collect notify]" do - @tag :wip2 + @tag :wip22 test "collect hook should work on job", ~m(user2 job)a do {:ok, job} = preload_author(job) @@ -117,7 +117,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert user_exist_in?(user2, notify.from_users) end - @tag :wip2 + @tag :wip22 test "undo collect hook should work on job", ~m(user2 job)a do {:ok, job} = preload_author(job) @@ -135,7 +135,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do end describe "[comment notify]" do - @tag :wip2 + @tag :wip22 test "job author should get notify after some one comment on it", ~m(user2 job)a do {:ok, job} = preload_author(job) @@ -155,7 +155,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert user_exist_in?(user2, notify.from_users) end - @tag :wip2 + @tag :wip22 test "job comment author should get notify after some one reply it", ~m(user2 user3 job)a do {:ok, job} = preload_author(job) diff --git a/test/groupher_server/cms/hooks/notify_post_test.exs b/test/groupher_server/cms/hooks/notify_post_test.exs index 0a01b3538..64759fdf8 100644 --- a/test/groupher_server/cms/hooks/notify_post_test.exs +++ b/test/groupher_server/cms/hooks/notify_post_test.exs @@ -21,7 +21,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do end describe "[upvote notify]" do - @tag :wip2 + @tag :wip22 test "upvote hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -41,7 +41,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert user_exist_in?(user2, notify.from_users) end - @tag :wip2 + @tag :wip22 test "upvote hook should work on post comment", ~m(user2 post comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) {:ok, comment} = preload_author(comment) @@ -62,7 +62,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert user_exist_in?(user2, notify.from_users) end - @tag :wip2 + @tag :wip22 test "undo upvote hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -78,7 +78,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert notifications.total_count == 0 end - @tag :wip2 + @tag :wip22 test "undo upvote hook should work on post comment", ~m(user2 comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) @@ -97,7 +97,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do end describe "[collect notify]" do - @tag :wip2 + @tag :wip22 test "collect hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -117,7 +117,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert user_exist_in?(user2, notify.from_users) end - @tag :wip2 + @tag :wip22 test "undo collect hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -135,7 +135,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do end describe "[comment notify]" do - @tag :wip2 + @tag :wip22 test "post author should get notify after some one comment on it", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -155,7 +155,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert user_exist_in?(user2, notify.from_users) end - @tag :wip2 + @tag :wip22 test "post comment author should get notify after some one reply it", ~m(user2 user3 post)a do {:ok, post} = preload_author(post) diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index e1265d9ce..4f46b878c 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -55,7 +55,7 @@ defmodule GroupherServer.Test.Delivery.Notification do assert user3 |> user_exist_in?(notify.from_users) end - @tag :wip2 + @tag :wip22 test "different notify should not be merged", ~m(user user2 user3 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) notify_attrs = notify_attrs |> Map.put(:action, :collect) @@ -172,7 +172,7 @@ defmodule GroupherServer.Test.Delivery.Notification do end describe "basic thread support" do - @tag :wip2 + @tag :wip22 test "support upvote", ~m(post user user2 notify_attrs)a do notify_attrs |> Map.merge(%{ From 6d20bc5da8ee49e7f5e46a20569ec7d507a8bc83 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 21:43:50 +0800 Subject: [PATCH 35/54] refactor(mention): mention thread clean up --- lib/groupher_server/delivery/delegates/mention.ex | 8 ++++++-- test/groupher_server/cms/hooks/cite_blog_test.exs | 1 - test/groupher_server/cms/hooks/cite_job_test.exs | 1 - test/groupher_server/cms/hooks/cite_post_test.exs | 1 - test/groupher_server/cms/hooks/mention_in_blog_test.exs | 6 +++--- test/groupher_server/cms/hooks/mention_in_job_test.exs | 6 +++--- test/groupher_server/cms/hooks/mention_in_post_test.exs | 7 ++++--- test/groupher_server/cms/hooks/notify_blog_test.exs | 8 -------- test/groupher_server/cms/hooks/notify_job_test.exs | 8 -------- test/groupher_server/cms/hooks/notify_post_test.exs | 8 -------- test/groupher_server/delivery/notification_test.exs | 2 -- 11 files changed, 16 insertions(+), 40 deletions(-) diff --git a/lib/groupher_server/delivery/delegates/mention.ex b/lib/groupher_server/delivery/delegates/mention.ex index e9ddc8102..5c1e7c196 100644 --- a/lib/groupher_server/delivery/delegates/mention.ex +++ b/lib/groupher_server/delivery/delegates/mention.ex @@ -30,7 +30,9 @@ defmodule GroupherServer.Delivery.Delegate.Mention do batch_delete_mentions(comment, from_user) end) |> Multi.run(:batch_insert_mentions, fn _, _ -> - case {0, nil} !== Repo.insert_all(Mention, atom_values_to_upcase(mentions)) do + mentions = Enum.map(mentions, &atom_values_to_upcase(&1)) + + case {0, nil} !== Repo.insert_all(Mention, mentions) do true -> {:ok, :pass} false -> {:error, "insert mentions error"} end @@ -45,7 +47,9 @@ defmodule GroupherServer.Delivery.Delegate.Mention do batch_delete_mentions(article, from_user) end) |> Multi.run(:batch_insert_mentions, fn _, _ -> - case {0, nil} !== Repo.insert_all(Mention, atom_values_to_upcase(mentions)) do + mentions = Enum.map(mentions, &atom_values_to_upcase(&1)) + + case {0, nil} !== Repo.insert_all(Mention, mentions) do true -> {:ok, :pass} false -> {:error, "insert mentions error"} end diff --git a/test/groupher_server/cms/hooks/cite_blog_test.exs b/test/groupher_server/cms/hooks/cite_blog_test.exs index 12d8b65c7..e79bea215 100644 --- a/test/groupher_server/cms/hooks/cite_blog_test.exs +++ b/test/groupher_server/cms/hooks/cite_blog_test.exs @@ -90,7 +90,6 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteBlog do assert cited_comment.meta.citing_count == 0 end - @tag :wip2 test "can cite blog's comment in blog", ~m(community user blog blog2 blog_attrs)a do {:ok, comment} = CMS.create_comment(:blog, blog.id, mock_rich_text("hello"), user) diff --git a/test/groupher_server/cms/hooks/cite_job_test.exs b/test/groupher_server/cms/hooks/cite_job_test.exs index d0e598217..6187fd5d3 100644 --- a/test/groupher_server/cms/hooks/cite_job_test.exs +++ b/test/groupher_server/cms/hooks/cite_job_test.exs @@ -90,7 +90,6 @@ defmodule GroupherServer.Test.CMS.Hooks.CiteJob do assert cited_comment.meta.citing_count == 0 end - @tag :wip2 test "can cite job's comment in job", ~m(community user job job2 job_attrs)a do {:ok, comment} = CMS.create_comment(:job, job.id, mock_rich_text("hello"), user) diff --git a/test/groupher_server/cms/hooks/cite_post_test.exs b/test/groupher_server/cms/hooks/cite_post_test.exs index 042ef606c..beb4b2358 100644 --- a/test/groupher_server/cms/hooks/cite_post_test.exs +++ b/test/groupher_server/cms/hooks/cite_post_test.exs @@ -90,7 +90,6 @@ defmodule GroupherServer.Test.CMS.Hooks.CitePost do assert cited_comment.meta.citing_count == 0 end - @tag :wip2 test "can cite post's comment in post", ~m(community user post post2 post_attrs)a do {:ok, comment} = CMS.create_comment(:post, post.id, mock_rich_text("hello"), user) diff --git a/test/groupher_server/cms/hooks/mention_in_blog_test.exs b/test/groupher_server/cms/hooks/mention_in_blog_test.exs index e1b5eefed..bc5e5dbd6 100644 --- a/test/groupher_server/cms/hooks/mention_in_blog_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_blog_test.exs @@ -40,7 +40,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInBlog do {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) mention = result.entries |> List.first() - assert mention.type == "BLOG" + assert mention.thread == "BLOG" assert mention.block_linker |> length == 2 assert mention.article_id == blog.id assert mention.title == blog.title @@ -49,7 +49,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInBlog do {:ok, result} = Delivery.fetch(:mention, user3, %{page: 1, size: 10}) mention = result.entries |> List.first() - assert mention.type == "BLOG" + assert mention.thread == "BLOG" assert mention.block_linker |> length == 1 assert mention.article_id == blog.id assert mention.title == blog.title @@ -67,7 +67,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInBlog do {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) mention = result.entries |> List.first() - assert mention.type == "COMMENT" + assert mention.thread == "BLOG" assert mention.comment_id == comment.id assert mention.block_linker |> length == 1 assert mention.article_id == blog.id diff --git a/test/groupher_server/cms/hooks/mention_in_job_test.exs b/test/groupher_server/cms/hooks/mention_in_job_test.exs index 55c4b96bf..4b216ae87 100644 --- a/test/groupher_server/cms/hooks/mention_in_job_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_job_test.exs @@ -40,7 +40,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInJob do {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) mention = result.entries |> List.first() - assert mention.type == "JOB" + assert mention.thread == "JOB" assert mention.block_linker |> length == 2 assert mention.article_id == job.id assert mention.title == job.title @@ -49,7 +49,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInJob do {:ok, result} = Delivery.fetch(:mention, user3, %{page: 1, size: 10}) mention = result.entries |> List.first() - assert mention.type == "JOB" + assert mention.thread == "JOB" assert mention.block_linker |> length == 1 assert mention.article_id == job.id assert mention.title == job.title @@ -67,7 +67,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInJob do {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) mention = result.entries |> List.first() - assert mention.type == "COMMENT" + assert mention.thread == "JOB" assert mention.comment_id == comment.id assert mention.block_linker |> length == 1 assert mention.article_id == job.id diff --git a/test/groupher_server/cms/hooks/mention_in_post_test.exs b/test/groupher_server/cms/hooks/mention_in_post_test.exs index f86849921..28027a3d0 100644 --- a/test/groupher_server/cms/hooks/mention_in_post_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_post_test.exs @@ -22,6 +22,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do end describe "[mention in post basic]" do + @tag :wip test "mention multi user in post should work", ~m(user user2 user3 community post_attrs)a do body = mock_rich_text( @@ -40,7 +41,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) mention = result.entries |> List.first() - assert mention.type == "POST" + assert mention.thread == "POST" assert mention.block_linker |> length == 2 assert mention.article_id == post.id assert mention.title == post.title @@ -49,7 +50,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do {:ok, result} = Delivery.fetch(:mention, user3, %{page: 1, size: 10}) mention = result.entries |> List.first() - assert mention.type == "POST" + assert mention.thread == "POST" assert mention.block_linker |> length == 1 assert mention.article_id == post.id assert mention.title == post.title @@ -67,7 +68,7 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) mention = result.entries |> List.first() - assert mention.type == "COMMENT" + assert mention.thread == "POST" assert mention.comment_id == comment.id assert mention.block_linker |> length == 1 assert mention.article_id == post.id diff --git a/test/groupher_server/cms/hooks/notify_blog_test.exs b/test/groupher_server/cms/hooks/notify_blog_test.exs index 59dbee407..89001ee54 100644 --- a/test/groupher_server/cms/hooks/notify_blog_test.exs +++ b/test/groupher_server/cms/hooks/notify_blog_test.exs @@ -21,7 +21,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do end describe "[upvote notify]" do - @tag :wip22 test "upvote hook should work on blog", ~m(user2 blog)a do {:ok, blog} = preload_author(blog) @@ -41,7 +40,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert user_exist_in?(user2, notify.from_users) end - @tag :wip22 test "upvote hook should work on blog comment", ~m(user2 blog comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) {:ok, comment} = preload_author(comment) @@ -62,7 +60,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert user_exist_in?(user2, notify.from_users) end - @tag :wip22 test "undo upvote hook should work on blog", ~m(user2 blog)a do {:ok, blog} = preload_author(blog) @@ -78,7 +75,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert notifications.total_count == 0 end - @tag :wip22 test "undo upvote hook should work on blog comment", ~m(user2 comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) @@ -97,7 +93,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do end describe "[collect notify]" do - @tag :wip22 test "collect hook should work on blog", ~m(user2 blog)a do {:ok, blog} = preload_author(blog) @@ -117,7 +112,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert user_exist_in?(user2, notify.from_users) end - @tag :wip22 test "undo collect hook should work on blog", ~m(user2 blog)a do {:ok, blog} = preload_author(blog) @@ -135,7 +129,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do end describe "[comment notify]" do - @tag :wip22 test "blog author should get notify after some one comment on it", ~m(user2 blog)a do {:ok, blog} = preload_author(blog) @@ -155,7 +148,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do assert user_exist_in?(user2, notify.from_users) end - @tag :wip22 test "blog comment author should get notify after some one reply it", ~m(user2 user3 blog)a do {:ok, blog} = preload_author(blog) diff --git a/test/groupher_server/cms/hooks/notify_job_test.exs b/test/groupher_server/cms/hooks/notify_job_test.exs index 24d2a3d18..eb9686f3b 100644 --- a/test/groupher_server/cms/hooks/notify_job_test.exs +++ b/test/groupher_server/cms/hooks/notify_job_test.exs @@ -21,7 +21,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do end describe "[upvote notify]" do - @tag :wip22 test "upvote hook should work on job", ~m(user2 job)a do {:ok, job} = preload_author(job) @@ -41,7 +40,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert user_exist_in?(user2, notify.from_users) end - @tag :wip22 test "upvote hook should work on job comment", ~m(user2 job comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) {:ok, comment} = preload_author(comment) @@ -62,7 +60,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert user_exist_in?(user2, notify.from_users) end - @tag :wip22 test "undo upvote hook should work on job", ~m(user2 job)a do {:ok, job} = preload_author(job) @@ -78,7 +75,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert notifications.total_count == 0 end - @tag :wip22 test "undo upvote hook should work on job comment", ~m(user2 comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) @@ -97,7 +93,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do end describe "[collect notify]" do - @tag :wip22 test "collect hook should work on job", ~m(user2 job)a do {:ok, job} = preload_author(job) @@ -117,7 +112,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert user_exist_in?(user2, notify.from_users) end - @tag :wip22 test "undo collect hook should work on job", ~m(user2 job)a do {:ok, job} = preload_author(job) @@ -135,7 +129,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do end describe "[comment notify]" do - @tag :wip22 test "job author should get notify after some one comment on it", ~m(user2 job)a do {:ok, job} = preload_author(job) @@ -155,7 +148,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do assert user_exist_in?(user2, notify.from_users) end - @tag :wip22 test "job comment author should get notify after some one reply it", ~m(user2 user3 job)a do {:ok, job} = preload_author(job) diff --git a/test/groupher_server/cms/hooks/notify_post_test.exs b/test/groupher_server/cms/hooks/notify_post_test.exs index 64759fdf8..fe23b3210 100644 --- a/test/groupher_server/cms/hooks/notify_post_test.exs +++ b/test/groupher_server/cms/hooks/notify_post_test.exs @@ -21,7 +21,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do end describe "[upvote notify]" do - @tag :wip22 test "upvote hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -41,7 +40,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert user_exist_in?(user2, notify.from_users) end - @tag :wip22 test "upvote hook should work on post comment", ~m(user2 post comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) {:ok, comment} = preload_author(comment) @@ -62,7 +60,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert user_exist_in?(user2, notify.from_users) end - @tag :wip22 test "undo upvote hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -78,7 +75,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert notifications.total_count == 0 end - @tag :wip22 test "undo upvote hook should work on post comment", ~m(user2 comment)a do {:ok, comment} = CMS.upvote_comment(comment.id, user2) @@ -97,7 +93,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do end describe "[collect notify]" do - @tag :wip22 test "collect hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -117,7 +112,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert user_exist_in?(user2, notify.from_users) end - @tag :wip22 test "undo collect hook should work on post", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -135,7 +129,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do end describe "[comment notify]" do - @tag :wip22 test "post author should get notify after some one comment on it", ~m(user2 post)a do {:ok, post} = preload_author(post) @@ -155,7 +148,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do assert user_exist_in?(user2, notify.from_users) end - @tag :wip22 test "post comment author should get notify after some one reply it", ~m(user2 user3 post)a do {:ok, post} = preload_author(post) diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index 4f46b878c..8396f5b7e 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -55,7 +55,6 @@ defmodule GroupherServer.Test.Delivery.Notification do assert user3 |> user_exist_in?(notify.from_users) end - @tag :wip22 test "different notify should not be merged", ~m(user user2 user3 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) notify_attrs = notify_attrs |> Map.put(:action, :collect) @@ -172,7 +171,6 @@ defmodule GroupherServer.Test.Delivery.Notification do end describe "basic thread support" do - @tag :wip22 test "support upvote", ~m(post user user2 notify_attrs)a do notify_attrs |> Map.merge(%{ From fd59e167a33650a3e648be83ae812a3d028392cb Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 22:14:46 +0800 Subject: [PATCH 36/54] refactor(mention): fix test --- lib/helper/utils/map.ex | 2 +- test/groupher_server/cms/hooks/mention_in_post_test.exs | 1 - test/groupher_server/delivery/mention_test.exs | 3 ++- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/helper/utils/map.ex b/lib/helper/utils/map.ex index 02bba9e70..80434e085 100644 --- a/lib/helper/utils/map.ex +++ b/lib/helper/utils/map.ex @@ -11,7 +11,7 @@ defmodule Helper.Utils.Map do def atom_values_to_upcase(map) when is_map(map) do map |> Enum.reduce(%{}, fn {key, val}, acc -> - case val !== true and val !== false and is_atom(val) do + case val !== true and val !== false and not is_nil(val) and is_atom(val) do true -> Map.put(acc, key, val |> to_string |> String.upcase()) false -> Map.put(acc, key, val) end diff --git a/test/groupher_server/cms/hooks/mention_in_post_test.exs b/test/groupher_server/cms/hooks/mention_in_post_test.exs index 28027a3d0..1ef5c2edf 100644 --- a/test/groupher_server/cms/hooks/mention_in_post_test.exs +++ b/test/groupher_server/cms/hooks/mention_in_post_test.exs @@ -22,7 +22,6 @@ defmodule GroupherServer.Test.CMS.Hooks.MentionInPost do end describe "[mention in post basic]" do - @tag :wip test "mention multi user in post should work", ~m(user user2 user3 community post_attrs)a do body = mock_rich_text( diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index ff25667f6..0f8329e88 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -15,7 +15,7 @@ defmodule GroupherServer.Test.Delivery.Mention do mention_contents = [ %{ - type: "POST", + thread: "POST", title: post.title, article_id: post.id, comment_id: nil, @@ -43,6 +43,7 @@ defmodule GroupherServer.Test.Delivery.Mention do assert mention.user.login == user.login end + @tag :wip test "mention multiable times on same article, will only have one record", ~m(post user user2 mention_contents)a do {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) From 25cb48228e7088e0b514bbc9c8ffeb88fc967838 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 22:21:11 +0800 Subject: [PATCH 37/54] refactor(mention): fix test --- test/groupher_server/delivery/mention_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index 0f8329e88..b20f526aa 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -69,7 +69,7 @@ defmodule GroupherServer.Test.Delivery.Mention do mention_contents = [ %{ - type: "POST", + thread: "POST", title: post.title, article_id: post.id, comment_id: nil, From 4c874e1578460d3cba8dbc6ef543f2112d3e375b Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 23:21:47 +0800 Subject: [PATCH 38/54] refactor(notify): test for follow --- .../groupher_server/delivery/mention_test.exs | 1 - .../delivery/notification_test.exs | 44 ++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index b20f526aa..74a3420ff 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -43,7 +43,6 @@ defmodule GroupherServer.Test.Delivery.Mention do assert mention.user.login == user.login end - @tag :wip test "mention multiable times on same article, will only have one record", ~m(post user user2 mention_contents)a do {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index 8396f5b7e..d2b8b3a2c 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -39,7 +39,49 @@ defmodule GroupherServer.Test.Delivery.Notification do |> Repo.update() end - describe "notification curd" do + describe "account follow" do + @tag :wip + test "support follow action", ~m(user user2)a do + notify_attrs = %{ + action: :follow, + user_id: user.id + } + + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + + {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + + assert paged_notifies.total_count == 1 + notify = paged_notifies.entries |> List.first() + + assert notify.action == "FOLLOW" + assert notify.user_id == user.id + assert user2 |> user_exist_in?(notify.from_users) + end + + @tag :wip + test "similar follow notify should be merged", ~m(user user2 user3)a do + notify_attrs = %{ + action: :follow, + user_id: user.id + } + + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + {:ok, _} = Delivery.send(:notify, notify_attrs, user3) + + {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + + notify = paged_notifies.entries |> List.first() + + assert paged_notifies.total_count == 1 + + assert notify.from_users |> length == 2 + assert user2 |> user_exist_in?(notify.from_users) + assert user3 |> user_exist_in?(notify.from_users) + end + end + + describe "notification" do test "similar notify should be merged", ~m(user user2 user3 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) From 7e99c6c591898dc6ad9520309b5298271353c948 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Sun, 20 Jun 2021 23:53:21 +0800 Subject: [PATCH 39/54] refactor(notify): hooks for follow & test --- .../accounts/delegates/fans.ex | 35 +++++++++------- .../accounts/delegates/hooks/notify.ex | 26 ++++++++++++ .../accounts/hooks/notify_test.exs | 41 +++++++++++++++++++ .../delivery/notification_test.exs | 2 - 4 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 lib/groupher_server/accounts/delegates/hooks/notify.ex create mode 100644 test/groupher_server/accounts/hooks/notify_test.exs diff --git a/lib/groupher_server/accounts/delegates/fans.ex b/lib/groupher_server/accounts/delegates/fans.ex index 0c3e52f19..bc0ed7e09 100644 --- a/lib/groupher_server/accounts/delegates/fans.ex +++ b/lib/groupher_server/accounts/delegates/fans.ex @@ -7,10 +7,11 @@ defmodule GroupherServer.Accounts.Delegate.Fans do import Helper.ErrorCode import ShortMaps - alias Helper.{ORM, QueryBuilder, SpecType} + alias Helper.{ORM, QueryBuilder, Later, SpecType} alias GroupherServer.{Accounts, Repo} - alias GroupherServer.Accounts.Model.{User, Embeds, UserFollower, UserFollowing} + alias Accounts.Model.{User, Embeds, UserFollower, UserFollowing} + alias Accounts.Delegate.Hooks alias Ecto.Multi @@ -20,27 +21,30 @@ defmodule GroupherServer.Accounts.Delegate.Fans do follow a user """ @spec follow(User.t(), User.t()) :: {:ok, User.t()} | SpecType.gq_error() - def follow(%User{id: user_id}, %User{id: follower_id}) do - with true <- to_string(user_id) !== to_string(follower_id), - {:ok, target_user} <- ORM.find(User, follower_id) do + def follow(%User{} = user, %User{} = follower) do + with true <- to_string(user.id) !== to_string(follower.id), + {:ok, target_user} <- ORM.find(User, follower.id) do Multi.new() |> Multi.insert( :create_follower, - UserFollower.changeset(%UserFollower{}, %{user_id: target_user.id, follower_id: user_id}) + UserFollower.changeset(%UserFollower{}, %{user_id: target_user.id, follower_id: user.id}) ) |> Multi.insert( :create_following, UserFollowing.changeset(%UserFollowing{}, %{ - user_id: user_id, + user_id: user.id, following_id: target_user.id }) ) |> Multi.run(:update_user_follow_info, fn _, _ -> - update_user_follow_info(target_user, user_id, :add) + update_user_follow_info(target_user, user.id, :add) end) |> Multi.run(:add_achievement, fn _, _ -> Accounts.achieve(%User{id: target_user.id}, :inc, :follow) end) + |> Multi.run(:after_hooks, fn _, _ -> + Later.run({Hooks.Notify, :handle, [:follow, user, follower]}) + end) |> Repo.transaction() |> result() else @@ -53,22 +57,25 @@ defmodule GroupherServer.Accounts.Delegate.Fans do undo a follow action to a user """ @spec undo_follow(User.t(), User.t()) :: {:ok, User.t()} | SpecType.gq_error() - def undo_follow(%User{id: user_id}, %User{id: follower_id}) do - with true <- to_string(user_id) !== to_string(follower_id), - {:ok, target_user} <- ORM.find(User, follower_id) do + def undo_follow(%User{} = user, %User{} = follower) do + with true <- to_string(user.id) !== to_string(follower.id), + {:ok, target_user} <- ORM.find(User, follower.id) do Multi.new() |> Multi.run(:delete_follower, fn _, _ -> - ORM.findby_delete!(UserFollower, %{user_id: target_user.id, follower_id: user_id}) + ORM.findby_delete!(UserFollower, %{user_id: target_user.id, follower_id: user.id}) end) |> Multi.run(:delete_following, fn _, _ -> - ORM.findby_delete!(UserFollowing, %{user_id: user_id, following_id: target_user.id}) + ORM.findby_delete!(UserFollowing, %{user_id: user.id, following_id: target_user.id}) end) |> Multi.run(:update_user_follow_info, fn _, _ -> - update_user_follow_info(target_user, user_id, :remove) + update_user_follow_info(target_user, user.id, :remove) end) |> Multi.run(:minus_achievement, fn _, _ -> Accounts.achieve(%User{id: target_user.id}, :dec, :follow) end) + |> Multi.run(:after_hooks, fn _, _ -> + Later.run({Hooks.Notify, :handle, [:undo, :follow, user, follower]}) + end) |> Repo.transaction() |> result() else diff --git a/lib/groupher_server/accounts/delegates/hooks/notify.ex b/lib/groupher_server/accounts/delegates/hooks/notify.ex new file mode 100644 index 000000000..c87b5ec8e --- /dev/null +++ b/lib/groupher_server/accounts/delegates/hooks/notify.ex @@ -0,0 +1,26 @@ +defmodule GroupherServer.Accounts.Delegate.Hooks.Notify do + @moduledoc """ + notify hooks, for upvote, collect, comment, reply + """ + alias GroupherServer.{Accounts, Delivery} + alias Accounts.Model.User + + # 发布评论是特殊情况,单独处理 + def handle(:follow, %User{} = user, %User{} = from_user) do + notify_attrs = %{ + action: :follow, + user_id: user.id + } + + Delivery.send(:notify, notify_attrs, from_user) + end + + def handle(:undo, :follow, %User{} = user, %User{} = from_user) do + notify_attrs = %{ + action: :follow, + user_id: user.id + } + + Delivery.revoke(:notify, notify_attrs, from_user) + end +end diff --git a/test/groupher_server/accounts/hooks/notify_test.exs b/test/groupher_server/accounts/hooks/notify_test.exs new file mode 100644 index 000000000..03ae59382 --- /dev/null +++ b/test/groupher_server/accounts/hooks/notify_test.exs @@ -0,0 +1,41 @@ +defmodule GroupherServer.Test.Accounts.Hooks.Notify do + use GroupherServer.TestTools + + import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] + + alias GroupherServer.{Accounts, Delivery} + alias Accounts.Delegate.Hooks + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + + {:ok, ~m(user user2 )a} + end + + describe "[follow notify]" do + @tag :wip + test "follow notify hook should work", ~m(user user2)a do + {:ok, _} = Accounts.follow(user, user2) + Hooks.Notify.handle(:follow, user, user2) + + {:ok, notifications} = Delivery.fetch(:notification, user.id, %{page: 1, size: 20}) + assert notifications.total_count == 1 + + notify = notifications.entries |> List.first() + assert notify.action == "FOLLOW" + assert notify.user_id == user.id + assert user_exist_in?(user2, notify.from_users) + end + + @tag :wip + test "undo follow notify hook should work", ~m(user user2)a do + {:ok, _} = Accounts.follow(user, user2) + Hooks.Notify.handle(:follow, user, user2) + Hooks.Notify.handle(:undo, :follow, user, user2) + + {:ok, notifications} = Delivery.fetch(:notification, user.id, %{page: 1, size: 20}) + assert notifications.total_count == 0 + end + end +end diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index d2b8b3a2c..d31b7f6d5 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -40,7 +40,6 @@ defmodule GroupherServer.Test.Delivery.Notification do end describe "account follow" do - @tag :wip test "support follow action", ~m(user user2)a do notify_attrs = %{ action: :follow, @@ -59,7 +58,6 @@ defmodule GroupherServer.Test.Delivery.Notification do assert user2 |> user_exist_in?(notify.from_users) end - @tag :wip test "similar follow notify should be merged", ~m(user user2 user3)a do notify_attrs = %{ action: :follow, From dfba75ec354c43102a1f51517961f9714563f775 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 21 Jun 2021 14:34:24 +0800 Subject: [PATCH 40/54] refactor(notify): wip --- lib/groupher_server/accounts/accounts.ex | 3 + .../accounts/delegates/mailbox.ex | 25 ++++ .../accounts/models/embeds/user_mailbox.ex | 22 +++ lib/groupher_server/accounts/models/user.ex | 2 + .../delivery/delegates/mention.ex | 29 +++- .../delivery/delegates/notification.ex | 10 +- .../delivery/delegates/postman.ex | 7 + lib/groupher_server/delivery/delivery.ex | 2 + .../delivery/models/mention.ex | 4 + .../20210621041646_add_mailbox_to_user.exs | 9 ++ .../accounts/accounts_test.exs | 4 +- .../accounts/hooks/notify_test.exs | 2 - test/groupher_server/accounts/mailbx_test.exs | 68 ++++++++++ .../groupher_server/delivery/mention_test.exs | 128 +++++++++++++----- .../delivery/notification_test.exs | 10 ++ ...elivery_test.exs => old_delivery_test.exs} | 0 16 files changed, 287 insertions(+), 38 deletions(-) create mode 100644 lib/groupher_server/accounts/delegates/mailbox.ex create mode 100644 lib/groupher_server/accounts/models/embeds/user_mailbox.ex create mode 100644 priv/repo/migrations/20210621041646_add_mailbox_to_user.exs create mode 100644 test/groupher_server/accounts/mailbx_test.exs rename test/groupher_server/delivery/{delivery_test.exs => old_delivery_test.exs} (100%) diff --git a/lib/groupher_server/accounts/accounts.ex b/lib/groupher_server/accounts/accounts.ex index f79aec453..28d76b6cb 100644 --- a/lib/groupher_server/accounts/accounts.ex +++ b/lib/groupher_server/accounts/accounts.ex @@ -8,6 +8,7 @@ defmodule GroupherServer.Accounts do CollectFolder, Publish, Mails, + Mailbox, Profile, UpvotedArticles, Search, @@ -74,6 +75,8 @@ defmodule GroupherServer.Accounts do defdelegate mark_mail_read_all(user, opt), to: Mails defdelegate mark_mail_read(mail, user), to: Mails + defdelegate update_mailbox_status(user_id), to: Mailbox + # customization defdelegate get_customization(user), to: Customization defdelegate set_customization(user, key, value), to: Customization diff --git a/lib/groupher_server/accounts/delegates/mailbox.ex b/lib/groupher_server/accounts/delegates/mailbox.ex new file mode 100644 index 000000000..8b9ff412e --- /dev/null +++ b/lib/groupher_server/accounts/delegates/mailbox.ex @@ -0,0 +1,25 @@ +defmodule GroupherServer.Accounts.Delegate.Mailbox do + import Ecto.Query, warn: false + + alias GroupherServer.{Accounts, Delivery} + alias Accounts.Model.User + alias Helper.ORM + + def update_mailbox_status(user_id) do + with {:ok, user} <- ORM.find(User, user_id), + {:ok, unread_mentions_count} <- Delivery.unread_count(:mention, user_id), + {:ok, unread_notifications_count} <- Delivery.unread_count(:notification, user_id) do + unread_total_count = unread_mentions_count + unread_notifications_count + is_empty = unread_total_count < 1 + + mailbox = %{ + unread_mentions_count: unread_mentions_count, + unread_notifications_count: unread_notifications_count, + unread_total_count: unread_total_count, + is_empty: is_empty + } + + user |> ORM.update_embed(:mailbox, mailbox) + end + end +end diff --git a/lib/groupher_server/accounts/models/embeds/user_mailbox.ex b/lib/groupher_server/accounts/models/embeds/user_mailbox.ex new file mode 100644 index 000000000..a5da1655a --- /dev/null +++ b/lib/groupher_server/accounts/models/embeds/user_mailbox.ex @@ -0,0 +1,22 @@ +defmodule GroupherServer.Accounts.Model.Embeds.UserMailbox do + @moduledoc """ + general article meta info for articles + """ + use Ecto.Schema + use Accessible + + import Ecto.Changeset + + @optional_fields ~w(reported_count)a + + embedded_schema do + field(:is_empty, :boolean, default: false) + field(:unread_total_count, :integer, default: 0) + field(:unread_mentions_count, :integer, default: 0) + field(:unread_notifications_count, :integer, default: 0) + end + + def changeset(struct, params) do + struct |> cast(params, @optional_fields) + end +end diff --git a/lib/groupher_server/accounts/models/user.ex b/lib/groupher_server/accounts/models/user.ex index 7afdab060..8f7b53769 100644 --- a/lib/groupher_server/accounts/models/user.ex +++ b/lib/groupher_server/accounts/models/user.ex @@ -74,6 +74,7 @@ defmodule GroupherServer.Accounts.Model.User do embeds_one(:meta, Embeds.UserMeta, on_replace: :update) embeds_one(:contributes, Embeds.UserContribute, on_replace: :update) + embeds_one(:mailbox, Embeds.UserMailbox, on_replace: :update) has_one(:customization, Customization) has_one(:purchase, Purchase) @@ -97,6 +98,7 @@ defmodule GroupherServer.Accounts.Model.User do |> cast_embed(:education_backgrounds, with: &EducationBackground.changeset/2) |> cast_embed(:work_backgrounds, with: &WorkBackground.changeset/2) |> cast_embed(:meta, required: false, with: &Embeds.UserMeta.changeset/2) + |> cast_embed(:mailbox, required: false, with: &Embeds.UserMailbox.changeset/2) |> validate_length(:nickname, min: 3, max: 30) |> validate_length(:bio, min: 3, max: 100) |> validate_inclusion(:sex, ["dude", "girl"]) diff --git a/lib/groupher_server/delivery/delegates/mention.ex b/lib/groupher_server/delivery/delegates/mention.ex index 5c1e7c196..3348f92ed 100644 --- a/lib/groupher_server/delivery/delegates/mention.ex +++ b/lib/groupher_server/delivery/delegates/mention.ex @@ -47,9 +47,13 @@ defmodule GroupherServer.Delivery.Delegate.Mention do batch_delete_mentions(article, from_user) end) |> Multi.run(:batch_insert_mentions, fn _, _ -> - mentions = Enum.map(mentions, &atom_values_to_upcase(&1)) + mentions = + mentions + |> Enum.map(&atom_values_to_upcase(&1)) + # ignore mention myself + |> Enum.reject(&(&1.to_user_id == from_user.id)) - case {0, nil} !== Repo.insert_all(Mention, mentions) do + case Enum.empty?(mentions) or {0, nil} !== Repo.insert_all(Mention, mentions) do true -> {:ok, :pass} false -> {:error, "insert mentions error"} end @@ -58,6 +62,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do |> result() end + @doc "paged mentions" def paged_mentions(%User{} = user, %{page: page, size: size} = filter) do read = Map.get(filter, :read, false) @@ -69,6 +74,25 @@ defmodule GroupherServer.Delivery.Delegate.Mention do |> done() end + @doc "get unread mentions count" + def unread_count(user_id) do + Mention + |> where([m], m.to_user_id == ^user_id and m.read == false) + |> Repo.aggregate(:count) + |> done + end + + def mark_read(ids, %User{} = user) when is_list(ids) do + query = Mention |> where([m], m.id in ^ids and m.to_user_id == ^user.id and m.read == false) + + result = Repo.update_all(query, set: [read: true]) + + case result do + {0, nil} -> {:error, "no such mentions found"} + _ -> {:ok, :done} + end + end + defp batch_delete_mentions(%Comment{} = comment, %User{} = from_user) do from(m in Mention, where: m.comment_id == ^comment.id, @@ -100,6 +124,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do mention |> Map.take([ + :id, :thread, :article_id, :comment_id, diff --git a/lib/groupher_server/delivery/delegates/notification.ex b/lib/groupher_server/delivery/delegates/notification.ex index f5016890e..47d2ac8bd 100644 --- a/lib/groupher_server/delivery/delegates/notification.ex +++ b/lib/groupher_server/delivery/delegates/notification.ex @@ -64,7 +64,15 @@ defmodule GroupherServer.Delivery.Delegate.Notification do |> where([n], n.user_id == ^user_id) |> where([n], n.read == ^read) |> ORM.paginater(~m(page size)a) - |> done() + |> done + end + + # 注意这里并不是准确的 count, 因为可能有短时间内 merge 到一起的通知 + def unread_count(user_id) do + Notification + |> where([n], n.user_id == ^user_id and n.read == false) + |> Repo.aggregate(:count) + |> done end # 如果在临近时间段内有类似操作,直接将这次的操作人添加到 from_users 中即可 diff --git a/lib/groupher_server/delivery/delegates/postman.ex b/lib/groupher_server/delivery/delegates/postman.ex index 5aca37b14..79e3f5089 100644 --- a/lib/groupher_server/delivery/delegates/postman.ex +++ b/lib/groupher_server/delivery/delegates/postman.ex @@ -14,6 +14,13 @@ defmodule GroupherServer.Delivery.Delegate.Postman do def fetch(:mention, user, filter), do: Mention.paged_mentions(user, filter) def fetch(:notification, user, filter), do: Notification.paged_notifications(user, filter) + def unread_count(:mention, user_id), do: Mention.unread_count(user_id) + def unread_count(:notification, user_id), do: Notification.unread_count(user_id) + + def mark_read(:mention, ids, user), do: Mention.mark_read(ids, user) + # def mark_read(:mention, ids, user), do: false + # def mark_read_all(:mention, id, user), do: false + # def send(_, _, _), do: {:error, "delivery, not such service"} # def send(_, _, _, _), do: {:error, "delivery, not such service"} end diff --git a/lib/groupher_server/delivery/delivery.ex b/lib/groupher_server/delivery/delivery.ex index d4ee3d670..3e03487bd 100644 --- a/lib/groupher_server/delivery/delivery.ex +++ b/lib/groupher_server/delivery/delivery.ex @@ -12,7 +12,9 @@ defmodule GroupherServer.Delivery do defdelegate send(service, attrs, from_user), to: Postman defdelegate revoke(service, attrs, from_user), to: Postman defdelegate fetch(service, user, filter), to: Postman + defdelegate unread_count(service, user), to: Postman + defdelegate mark_read(service, ids, user), to: Postman # system_notifications defdelegate publish_system_notification(info), to: Notifications defdelegate fetch_sys_notifications(user, filter), to: Notifications diff --git a/lib/groupher_server/delivery/models/mention.ex b/lib/groupher_server/delivery/models/mention.ex index 2b8bf7188..10a184905 100644 --- a/lib/groupher_server/delivery/models/mention.ex +++ b/lib/groupher_server/delivery/models/mention.ex @@ -34,4 +34,8 @@ defmodule GroupherServer.Delivery.Model.Mention do |> foreign_key_constraint(:from_user_id) |> foreign_key_constraint(:to_user_id) end + + def update_changeset(%Mention{} = mention, attrs) do + mention |> cast(attrs, @optional_fields ++ @required_fields) + end end diff --git a/priv/repo/migrations/20210621041646_add_mailbox_to_user.exs b/priv/repo/migrations/20210621041646_add_mailbox_to_user.exs new file mode 100644 index 000000000..46692752b --- /dev/null +++ b/priv/repo/migrations/20210621041646_add_mailbox_to_user.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.AddMailboxToUser do + use Ecto.Migration + + def change do + alter table(:users) do + add(:mailbox, :map) + end + end +end diff --git a/test/groupher_server/accounts/accounts_test.exs b/test/groupher_server/accounts/accounts_test.exs index db0380369..531f85fd6 100644 --- a/test/groupher_server/accounts/accounts_test.exs +++ b/test/groupher_server/accounts/accounts_test.exs @@ -6,12 +6,12 @@ defmodule GroupherServer.Test.Accounts do alias Helper.{Guardian, ORM} alias GroupherServer.Accounts + alias Accounts.Model.User + # @valid_user mock_attrs(:user) @valid_github_profile mock_attrs(:github_profile) |> map_key_stringify describe "[update user]" do - alias Accounts.Model.User - test "update user with valid attrs" do {:ok, user} = db_insert(:user) diff --git a/test/groupher_server/accounts/hooks/notify_test.exs b/test/groupher_server/accounts/hooks/notify_test.exs index 03ae59382..d1d81b2bf 100644 --- a/test/groupher_server/accounts/hooks/notify_test.exs +++ b/test/groupher_server/accounts/hooks/notify_test.exs @@ -14,7 +14,6 @@ defmodule GroupherServer.Test.Accounts.Hooks.Notify do end describe "[follow notify]" do - @tag :wip test "follow notify hook should work", ~m(user user2)a do {:ok, _} = Accounts.follow(user, user2) Hooks.Notify.handle(:follow, user, user2) @@ -28,7 +27,6 @@ defmodule GroupherServer.Test.Accounts.Hooks.Notify do assert user_exist_in?(user2, notify.from_users) end - @tag :wip test "undo follow notify hook should work", ~m(user user2)a do {:ok, _} = Accounts.follow(user, user2) Hooks.Notify.handle(:follow, user, user2) diff --git a/test/groupher_server/accounts/mailbx_test.exs b/test/groupher_server/accounts/mailbx_test.exs new file mode 100644 index 000000000..951d9b054 --- /dev/null +++ b/test/groupher_server/accounts/mailbx_test.exs @@ -0,0 +1,68 @@ +defmodule GroupherServer.Test.Accounts.Mailbox do + use GroupherServer.TestTools + # TODO import Service.Utils move both helper and github + import Helper.Utils + + alias GroupherServer.{Accounts, Delivery} + + setup do + {:ok, post} = db_insert(:post) + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + {:ok, user3} = db_insert(:user) + + notify_attrs = %{ + thread: :post, + article_id: post.id, + title: post.title, + action: :upvote, + user_id: user.id, + read: false + } + + {:ok, ~m(post user user2 user3 notify_attrs)a} + end + + describe "mailbox status" do + @tag :wip2 + test "can get mailbox status", ~m(post user user2 notify_attrs)a do + notify_attrs = %{ + thread: :post, + article_id: post.id, + title: post.title, + action: :upvote, + user_id: user.id + } + + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + {:ok, user} = Accounts.update_mailbox_status(user.id) + + assert user.mailbox.is_empty == false + assert user.mailbox.unread_notifications_count == 1 + assert user.mailbox.unread_total_count == 1 + + mention_contents = [ + %{ + thread: "POST", + title: post.title, + article_id: post.id, + comment_id: nil, + read: false, + block_linker: ["tmp"], + from_user_id: user2.id, + to_user_id: user.id, + inserted_at: post.updated_at |> DateTime.truncate(:second), + updated_at: post.updated_at |> DateTime.truncate(:second) + } + ] + + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user2) + {:ok, user} = Accounts.update_mailbox_status(user.id) + + assert user.mailbox.is_empty == false + assert user.mailbox.unread_notifications_count == 1 + assert user.mailbox.unread_mentions_count == 1 + assert user.mailbox.unread_total_count == 2 + end + end +end diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index 74a3420ff..b15528973 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -13,26 +13,93 @@ defmodule GroupherServer.Test.Delivery.Mention do {:ok, user3} = db_insert(:user) {:ok, community} = db_insert(:community) - mention_contents = [ - %{ - thread: "POST", - title: post.title, - article_id: post.id, - comment_id: nil, - read: false, - block_linker: ["tmp"], - from_user_id: user.id, - to_user_id: user2.id, - inserted_at: post.updated_at |> DateTime.truncate(:second), - updated_at: post.updated_at |> DateTime.truncate(:second) - } - ] - - {:ok, ~m(community post user user2 user3 mention_contents)a} + mention_attr = %{ + thread: "POST", + title: post.title, + article_id: post.id, + comment_id: nil, + block_linker: ["tmp"], + inserted_at: post.updated_at |> DateTime.truncate(:second), + updated_at: post.updated_at |> DateTime.truncate(:second) + } + + {:ok, ~m(community post user user2 user3 mention_attr)a} + end + + describe "mark read" do + @tag :wip + test "can mark read a mention", ~m(post user user2 mention_attr)a do + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: user.id, to_user_id: user2.id}) + ] + + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) + + mention = result.entries |> List.first() + {:ok, _} = Delivery.mark_read(:mention, [mention.id], user2) + + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10, read: true}) + mention = result.entries |> List.first() + + assert mention.read + end + + @tag :wip + test "can mark multi mention as read", ~m(post user user2 user3 mention_attr)a do + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: user2.id, to_user_id: user.id}) + ] + + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user2) + + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: user3.id, to_user_id: user.id}) + ] + + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user3) + {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10}) + + mention1 = result.entries |> List.first() + mention2 = result.entries |> List.last() + + Delivery.mark_read(:mention, [mention1.id, mention2.id], user) + + {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10, read: true}) + + mention1 = result.entries |> List.first() + mention2 = result.entries |> List.last() + + assert mention1.read + assert mention2.read + end end describe "mentions" do - test "can batch send mentions", ~m(post user user2 mention_contents)a do + @tag :wip2 + test "can get unread mention count of a user", ~m(post user user2 user3 mention_attr)a do + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: user.id, to_user_id: user3.id}) + ] + + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) + + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: user2.id, to_user_id: user3.id}) + ] + + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user2) + {:ok, count} = Delivery.unread_count(:mention, user3.id) + + assert count == 2 + end + + @tag :wip2 + test "can batch send mentions", ~m(post user user2 mention_attr)a do + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: user.id, to_user_id: user2.id}) + ] + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) @@ -43,8 +110,13 @@ defmodule GroupherServer.Test.Delivery.Mention do assert mention.user.login == user.login end + @tag :wip2 test "mention multiable times on same article, will only have one record", - ~m(post user user2 mention_contents)a do + ~m(post user user2 mention_attr)a do + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: user.id, to_user_id: user2.id}) + ] + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) @@ -56,8 +128,13 @@ defmodule GroupherServer.Test.Delivery.Mention do assert result.total_count == 1 end + @tag :wip2 test "if mention before, update with no mention content will not do mention in final", - ~m(post user user2 user3 mention_contents)a do + ~m(post user user2 user3 mention_attr)a do + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: user.id, to_user_id: user2.id}) + ] + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) @@ -67,18 +144,7 @@ defmodule GroupherServer.Test.Delivery.Mention do assert result.total_count == 0 mention_contents = [ - %{ - thread: "POST", - title: post.title, - article_id: post.id, - comment_id: nil, - read: false, - block_linker: ["tmp"], - from_user_id: user.id, - to_user_id: user3.id, - inserted_at: post.updated_at |> DateTime.truncate(:second), - updated_at: post.updated_at |> DateTime.truncate(:second) - } + Map.merge(mention_attr, %{from_user_id: user.id, to_user_id: user3.id}) ] {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index d31b7f6d5..770e355cd 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -80,6 +80,16 @@ defmodule GroupherServer.Test.Delivery.Notification do end describe "notification" do + @tag :wip2 + test "can get unread notification count of a user", ~m(post user user2 user3 notify_attrs)a do + {:ok, _} = Delivery.send(:notify, notify_attrs, user2) + {:ok, _} = Delivery.send(:notify, notify_attrs, user3) + + {:ok, count} = Delivery.unread_count(:notification, user.id) + + assert count == 1 + end + test "similar notify should be merged", ~m(user user2 user3 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) diff --git a/test/groupher_server/delivery/delivery_test.exs b/test/groupher_server/delivery/old_delivery_test.exs similarity index 100% rename from test/groupher_server/delivery/delivery_test.exs rename to test/groupher_server/delivery/old_delivery_test.exs From 46c27fc59d5cdcc59e8dd5f1fc0522a0b121789b Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 21 Jun 2021 17:50:40 +0800 Subject: [PATCH 41/54] refactor(notify): mark read & re-org ORM functions --- .../accounts/delegates/profile.ex | 3 +- .../cms/delegates/cited_artiment.ex | 4 +- .../cms/delegates/comment_action.ex | 14 +- .../cms/delegates/comment_curd.ex | 12 +- .../cms/delegates/community_curd.ex | 30 ++--- lib/groupher_server/cms/delegates/helper.ex | 4 +- .../delivery/delegates/mention.ex | 28 ++-- .../delivery/delegates/notification.ex | 24 +++- .../delivery/delegates/postman.ex | 7 +- lib/groupher_server/delivery/delivery.ex | 1 + lib/helper/orm.ex | 25 ++-- .../accounts/accounts_test.exs | 6 +- .../groupher_server/delivery/mention_test.exs | 124 +++++++++++------- .../delivery/notification_test.exs | 46 ++++++- test/helper/orm_test.exs | 2 +- 15 files changed, 203 insertions(+), 127 deletions(-) diff --git a/lib/groupher_server/accounts/delegates/profile.ex b/lib/groupher_server/accounts/delegates/profile.ex index 9afbef3af..9309cb5ba 100644 --- a/lib/groupher_server/accounts/delegates/profile.ex +++ b/lib/groupher_server/accounts/delegates/profile.ex @@ -72,8 +72,7 @@ defmodule GroupherServer.Accounts.Delegate.Profile do """ def update_subscribe_count(user_id) do with {:ok, user} <- ORM.find(User, user_id) do - count_query = from(s in CommunitySubscriber, where: s.user_id == ^user.id) - count = Repo.aggregate(count_query, :count) + {:ok, count} = from(s in CommunitySubscriber, where: s.user_id == ^user.id) |> ORM.count() user |> ORM.update(%{subscribed_communities_count: count}) end diff --git a/lib/groupher_server/cms/delegates/cited_artiment.ex b/lib/groupher_server/cms/delegates/cited_artiment.ex index 3399fb32d..c15034e56 100644 --- a/lib/groupher_server/cms/delegates/cited_artiment.ex +++ b/lib/groupher_server/cms/delegates/cited_artiment.ex @@ -79,8 +79,8 @@ defmodule GroupherServer.CMS.Delegate.CitedArtiment do # update article/comment 's citting_count in meta defp update_artiment_citing_count(cited_artiments) do Enum.all?(cited_artiments, fn cited -> - count_query = from(c in CitedArtiment, where: c.cited_by_id == ^cited.cited_by_id) - count = Repo.aggregate(count_query, :count) + {:ok, count} = + from(c in CitedArtiment, where: c.cited_by_id == ^cited.cited_by_id) |> ORM.count() artiment = cited.artiment meta = Map.merge(artiment.meta, %{citing_count: count}) diff --git a/lib/groupher_server/cms/delegates/comment_action.ex b/lib/groupher_server/cms/delegates/comment_action.ex index 71c3583b4..9f29864b7 100644 --- a/lib/groupher_server/cms/delegates/comment_action.ex +++ b/lib/groupher_server/cms/delegates/comment_action.ex @@ -40,12 +40,11 @@ defmodule GroupherServer.CMS.Delegate.CommentAction do {:ok, info} <- match(full_comment.thread) do Multi.new() |> Multi.run(:checked_pined_comments_count, fn _, _ -> - count_query = + {:ok, pined_comments_count} = from(p in PinnedComment, where: field(p, ^info.foreign_key) == ^full_comment.article.id ) - - pined_comments_count = Repo.aggregate(count_query, :count) + |> ORM.count() case pined_comments_count >= @pinned_comment_limit do true -> {:error, "max #{@pinned_comment_limit} pinned comment for each article"} @@ -163,8 +162,9 @@ defmodule GroupherServer.CMS.Delegate.CommentAction do update_upvoted_user_list(comment, user_id, :add) end) |> Multi.run(:inc_upvotes_count, fn _, %{add_upvoted_user: comment} -> - count_query = from(c in CommentUpvote, where: c.comment_id == ^comment.id) - upvotes_count = Repo.aggregate(count_query, :count) + {:ok, upvotes_count} = + from(c in CommentUpvote, where: c.comment_id == ^comment.id) |> ORM.count() + ORM.update(comment, %{upvotes_count: upvotes_count}) end) |> Multi.run(:check_article_author_upvoted, fn _, %{inc_upvotes_count: comment} -> @@ -202,8 +202,8 @@ defmodule GroupherServer.CMS.Delegate.CommentAction do update_upvoted_user_list(comment, user_id, :remove) end) |> Multi.run(:desc_upvotes_count, fn _, %{remove_upvoted_user: comment} -> - count_query = from(c in CommentUpvote, where: c.comment_id == ^comment_id) - upvotes_count = Repo.aggregate(count_query, :count) + {:ok, upvotes_count} = + from(c in CommentUpvote, where: c.comment_id == ^comment_id) |> ORM.count() ORM.update(comment, %{upvotes_count: Enum.max([upvotes_count - 1, 0])}) end) diff --git a/lib/groupher_server/cms/delegates/comment_curd.ex b/lib/groupher_server/cms/delegates/comment_curd.ex index a28f24f3c..9e630dfea 100644 --- a/lib/groupher_server/cms/delegates/comment_curd.ex +++ b/lib/groupher_server/cms/delegates/comment_curd.ex @@ -251,10 +251,9 @@ defmodule GroupherServer.CMS.Delegate.CommentCurd do def update_comments_count(%Comment{} = comment, opt) do with {:ok, article_info} <- match(:comment_article, comment), {:ok, article} <- ORM.find(article_info.model, article_info.id) do - count_query = + {:ok, cur_count} = from(c in Comment, where: field(c, ^article_info.foreign_key) == ^article_info.id) - - cur_count = Repo.aggregate(count_query, :count) + |> ORM.count() # dec 是 comment 还没有删除的时候的操作,和 inc 不同 # 因为 dec 操作如果放在 delete 后面,那么 update 会失败 @@ -405,8 +404,11 @@ defmodule GroupherServer.CMS.Delegate.CommentCurd do # get next floor under an article's comments list defp next_floor(article, foreign_key) do - count_query = from(c in Comment, where: field(c, ^foreign_key) == ^article.id) - Repo.aggregate(count_query, :count) + 1 + {:ok, cur_count} = + from(c in Comment, where: field(c, ^foreign_key) == ^article.id) + |> ORM.count() + + cur_count + 1 end defp result({:ok, %{set_question_flag_ifneed: result}}), do: {:ok, result} diff --git a/lib/groupher_server/cms/delegates/community_curd.ex b/lib/groupher_server/cms/delegates/community_curd.ex index d67de8d77..fd41378b5 100644 --- a/lib/groupher_server/cms/delegates/community_curd.ex +++ b/lib/groupher_server/cms/delegates/community_curd.ex @@ -58,8 +58,10 @@ defmodule GroupherServer.CMS.Delegate.CommunityCURD do update editors_count of a community """ def update_community_count_field(%Community{} = community, user_id, :editors_count, opt) do - count_query = from(s in CommunityEditor, where: s.community_id == ^community.id) - editors_count = Repo.aggregate(count_query, :count) + {:ok, editors_count} = + from(s in CommunityEditor, where: s.community_id == ^community.id) + |> ORM.count() + community_meta = if is_nil(community.meta), do: @default_meta, else: community.meta editors_ids = @@ -80,8 +82,9 @@ defmodule GroupherServer.CMS.Delegate.CommunityCURD do update article_tags_count of a community """ def update_community_count_field(%Community{} = community, :article_tags_count) do - count_query = from(t in ArticleTag, where: t.community_id == ^community.id) - article_tags_count = Repo.aggregate(count_query, :count) + {:ok, article_tags_count} = + from(t in ArticleTag, where: t.community_id == ^community.id) + |> ORM.count() community |> Ecto.Changeset.change(%{article_tags_count: article_tags_count}) @@ -92,8 +95,9 @@ defmodule GroupherServer.CMS.Delegate.CommunityCURD do update subscribers_count of a community """ def update_community_count_field(%Community{} = community, user_id, :subscribers_count, opt) do - count_query = from(s in CommunitySubscriber, where: s.community_id == ^community.id) - subscribers_count = Repo.aggregate(count_query, :count) + {:ok, subscribers_count} = + from(s in CommunitySubscriber, where: s.community_id == ^community.id) |> ORM.count() + community_meta = if is_nil(community.meta), do: @default_meta, else: community.meta subscribed_user_ids = @@ -122,22 +126,18 @@ defmodule GroupherServer.CMS.Delegate.CommunityCURD do """ def update_community_count_field(%Community{} = community, thread) do with {:ok, info} <- match(thread) do - count_query = + {:ok, thread_article_count} = from(a in info.model, join: c in assoc(a, :communities), - where: a.mark_delete == false, - where: c.id == ^community.id + where: a.mark_delete == false and c.id == ^community.id ) + |> ORM.count() - thread_article_count = Repo.aggregate(count_query, :count) community_meta = if is_nil(community.meta), do: @default_meta, else: community.meta - - meta = community_meta |> Map.put(:"#{thread}s_count", thread_article_count) |> strip_struct + meta = Map.put(community_meta, :"#{thread}s_count", thread_article_count) community - |> Ecto.Changeset.change(%{articles_count: recount_articles_count(meta)}) - |> Ecto.Changeset.put_embed(:meta, meta) - |> Repo.update() + |> ORM.update_meta(meta, changes: %{articles_count: recount_articles_count(meta)}) end end diff --git a/lib/groupher_server/cms/delegates/helper.ex b/lib/groupher_server/cms/delegates/helper.ex index 442480436..08bc37d1e 100644 --- a/lib/groupher_server/cms/delegates/helper.ex +++ b/lib/groupher_server/cms/delegates/helper.ex @@ -157,8 +157,8 @@ defmodule GroupherServer.CMS.Delegate.Helper do :collects_count -> ArticleCollect end - count_query = from(u in schema, where: field(u, ^info.foreign_key) == ^article.id) - cur_count = Repo.aggregate(count_query, :count) + {:ok, cur_count} = + from(u in schema, where: field(u, ^info.foreign_key) == ^article.id) |> ORM.count() case opt do :inc -> diff --git a/lib/groupher_server/delivery/delegates/mention.ex b/lib/groupher_server/delivery/delegates/mention.ex index 3348f92ed..8b3cc6382 100644 --- a/lib/groupher_server/delivery/delegates/mention.ex +++ b/lib/groupher_server/delivery/delegates/mention.ex @@ -67,8 +67,7 @@ defmodule GroupherServer.Delivery.Delegate.Mention do read = Map.get(filter, :read, false) Mention - |> where([m], m.to_user_id == ^user.id) - |> where([m], m.read == ^read) + |> where([m], m.to_user_id == ^user.id and m.read == ^read) |> ORM.paginater(~m(page size)a) |> extract_mentions |> done() @@ -78,19 +77,21 @@ defmodule GroupherServer.Delivery.Delegate.Mention do def unread_count(user_id) do Mention |> where([m], m.to_user_id == ^user_id and m.read == false) - |> Repo.aggregate(:count) - |> done + |> ORM.count() end + @doc "mark mention in ids as readed" def mark_read(ids, %User{} = user) when is_list(ids) do - query = Mention |> where([m], m.id in ^ids and m.to_user_id == ^user.id and m.read == false) - - result = Repo.update_all(query, set: [read: true]) + Mention + |> where([m], m.id in ^ids and m.to_user_id == ^user.id and m.read == false) + |> ORM.mark_read_all() + end - case result do - {0, nil} -> {:error, "no such mentions found"} - _ -> {:ok, :done} - end + @doc "mark all related mentions as readed" + def mark_read_all(%User{} = user) do + Mention + |> where([m], m.to_user_id == ^user.id and m.read == false) + |> ORM.mark_read_all() end defp batch_delete_mentions(%Comment{} = comment, %User{} = from_user) do @@ -138,8 +139,5 @@ defmodule GroupherServer.Delivery.Delegate.Mention do end defp result({:ok, %{batch_insert_mentions: result}}), do: {:ok, result} - - defp result({:error, _, result, _steps}) do - {:error, result} - end + defp result({:error, _, result, _steps}), do: {:error, result} end diff --git a/lib/groupher_server/delivery/delegates/notification.ex b/lib/groupher_server/delivery/delegates/notification.ex index 47d2ac8bd..297add94e 100644 --- a/lib/groupher_server/delivery/delegates/notification.ex +++ b/lib/groupher_server/delivery/delegates/notification.ex @@ -61,8 +61,7 @@ defmodule GroupherServer.Delivery.Delegate.Notification do read = Map.get(filter, :read, false) Notification - |> where([n], n.user_id == ^user_id) - |> where([n], n.read == ^read) + |> where([n], n.user_id == ^user_id and n.read == ^read) |> ORM.paginater(~m(page size)a) |> done end @@ -71,8 +70,21 @@ defmodule GroupherServer.Delivery.Delegate.Notification do def unread_count(user_id) do Notification |> where([n], n.user_id == ^user_id and n.read == false) - |> Repo.aggregate(:count) - |> done + |> ORM.count() + end + + @doc "mark notification in ids as readed" + def mark_read(ids, %User{} = user) when is_list(ids) do + Notification + |> where([m], m.id in ^ids and m.user_id == ^user.id and m.read == false) + |> ORM.mark_read_all() + end + + @doc "mark all related notifications as readed" + def mark_read_all(%User{} = user) do + Notification + |> where([m], m.user_id == ^user.id and m.read == false) + |> ORM.mark_read_all() end # 如果在临近时间段内有类似操作,直接将这次的操作人添加到 from_users 中即可 @@ -172,9 +184,7 @@ defmodule GroupherServer.Delivery.Delegate.Notification do # 确保 key 存在,并且不为 nil defp all_exist?(attrs, keys) when is_map(attrs) and is_list(keys) do - Enum.all?(keys, fn key -> - Map.has_key?(attrs, key) and not is_nil(attrs[key]) - end) + Enum.all?(keys, &(Map.has_key?(attrs, &1) and not is_nil(attrs[&1]))) end # 此时间段内的相似通知会被 merge diff --git a/lib/groupher_server/delivery/delegates/postman.ex b/lib/groupher_server/delivery/delegates/postman.ex index 79e3f5089..73ff2bcde 100644 --- a/lib/groupher_server/delivery/delegates/postman.ex +++ b/lib/groupher_server/delivery/delegates/postman.ex @@ -11,6 +11,7 @@ defmodule GroupherServer.Delivery.Delegate.Postman do def send(:notify, attrs, from_user), do: Notification.handle(attrs, from_user) def revoke(:notify, attrs, from_user), do: Notification.revoke(attrs, from_user) + def fetch(:mention, user, filter), do: Mention.paged_mentions(user, filter) def fetch(:notification, user, filter), do: Notification.paged_notifications(user, filter) @@ -18,8 +19,10 @@ defmodule GroupherServer.Delivery.Delegate.Postman do def unread_count(:notification, user_id), do: Notification.unread_count(user_id) def mark_read(:mention, ids, user), do: Mention.mark_read(ids, user) - # def mark_read(:mention, ids, user), do: false - # def mark_read_all(:mention, id, user), do: false + def mark_read(:notification, ids, user), do: Notification.mark_read(ids, user) + + def mark_read_all(:mention, user), do: Mention.mark_read_all(user) + def mark_read_all(:notification, user), do: Notification.mark_read_all(user) # def send(_, _, _), do: {:error, "delivery, not such service"} # def send(_, _, _, _), do: {:error, "delivery, not such service"} diff --git a/lib/groupher_server/delivery/delivery.ex b/lib/groupher_server/delivery/delivery.ex index 3e03487bd..3aa3a7df3 100644 --- a/lib/groupher_server/delivery/delivery.ex +++ b/lib/groupher_server/delivery/delivery.ex @@ -15,6 +15,7 @@ defmodule GroupherServer.Delivery do defdelegate unread_count(service, user), to: Postman defdelegate mark_read(service, ids, user), to: Postman + defdelegate mark_read_all(service, user), to: Postman # system_notifications defdelegate publish_system_notification(info), to: Notifications defdelegate fetch_sys_notifications(user, filter), to: Notifications diff --git a/lib/helper/orm.ex b/lib/helper/orm.ex index 6e473dceb..9d69d7f34 100644 --- a/lib/helper/orm.ex +++ b/lib/helper/orm.ex @@ -3,7 +3,7 @@ defmodule Helper.ORM do General CORD functions """ import Ecto.Query, warn: false - import Helper.Utils, only: [done: 1, done: 3, add: 1, strip_struct: 1, get_config: 2] + import Helper.Utils, only: [done: 1, done: 3, strip_struct: 1, get_config: 2] import ShortMaps import Helper.ErrorHandler @@ -148,6 +148,13 @@ defmodule Helper.ORM do put_in(content[field], Enum.max([0, updated_count])) |> done end + @doc "mark read as true for all" + def mark_read_all(queryable) do + queryable + |> Repo.update_all(set: [read: true]) + |> done + end + @doc """ NOTICE: this should be use together with Authorize/OwnerCheck etc Middleware DO NOT use it directly @@ -259,19 +266,9 @@ defmodule Helper.ORM do |> Repo.insert() end - @doc """ - return the total count of a Modal based on id column - also support filters - """ - def count(queryable, filter \\ %{}) do - queryable - |> QueryBuilder.filter_pack(filter) - |> select([f], count(f.id)) - |> Repo.one() - end - - def next_count(queryable) do - queryable |> count() |> add() + @doc "count current queryable" + def count(queryable) do + queryable |> Repo.aggregate(:count) |> done end @doc """ diff --git a/test/groupher_server/accounts/accounts_test.exs b/test/groupher_server/accounts/accounts_test.exs index 531f85fd6..231749d9a 100644 --- a/test/groupher_server/accounts/accounts_test.exs +++ b/test/groupher_server/accounts/accounts_test.exs @@ -150,11 +150,11 @@ defmodule GroupherServer.Test.Accounts do end test "exsit github user created twice fails" do - assert ORM.count(GithubUser) == 0 + assert {:ok, 0} == ORM.count(GithubUser) {:ok, _} = Accounts.github_signin(@valid_github_profile) - assert ORM.count(GithubUser) == 1 + assert {:ok, 1} == ORM.count(GithubUser) {:ok, _} = Accounts.github_signin(@valid_github_profile) - assert ORM.count(GithubUser) == 1 + assert {:ok, 1} == ORM.count(GithubUser) end test "github signin user should not locate geo city info" do diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index b15528973..80982a1e5 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -26,55 +26,6 @@ defmodule GroupherServer.Test.Delivery.Mention do {:ok, ~m(community post user user2 user3 mention_attr)a} end - describe "mark read" do - @tag :wip - test "can mark read a mention", ~m(post user user2 mention_attr)a do - mention_contents = [ - Map.merge(mention_attr, %{from_user_id: user.id, to_user_id: user2.id}) - ] - - {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) - {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) - - mention = result.entries |> List.first() - {:ok, _} = Delivery.mark_read(:mention, [mention.id], user2) - - {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10, read: true}) - mention = result.entries |> List.first() - - assert mention.read - end - - @tag :wip - test "can mark multi mention as read", ~m(post user user2 user3 mention_attr)a do - mention_contents = [ - Map.merge(mention_attr, %{from_user_id: user2.id, to_user_id: user.id}) - ] - - {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user2) - - mention_contents = [ - Map.merge(mention_attr, %{from_user_id: user3.id, to_user_id: user.id}) - ] - - {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user3) - {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10}) - - mention1 = result.entries |> List.first() - mention2 = result.entries |> List.last() - - Delivery.mark_read(:mention, [mention1.id, mention2.id], user) - - {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10, read: true}) - - mention1 = result.entries |> List.first() - mention2 = result.entries |> List.last() - - assert mention1.read - assert mention2.read - end - end - describe "mentions" do @tag :wip2 test "can get unread mention count of a user", ~m(post user user2 user3 mention_attr)a do @@ -155,4 +106,79 @@ defmodule GroupherServer.Test.Delivery.Mention do assert result.total_count == 1 end end + + describe "mark read" do + @tag :wip + test "can mark read a mention", ~m(post user user2 mention_attr)a do + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: user.id, to_user_id: user2.id}) + ] + + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user) + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10}) + + mention = result.entries |> List.first() + {:ok, _} = Delivery.mark_read(:mention, [mention.id], user2) + + {:ok, result} = Delivery.fetch(:mention, user2, %{page: 1, size: 10, read: true}) + mention = result.entries |> List.first() + + assert mention.read + end + + @tag :wip + test "can mark multi mention as read", ~m(post user user2 user3 mention_attr)a do + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: user2.id, to_user_id: user.id}) + ] + + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user2) + + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: user3.id, to_user_id: user.id}) + ] + + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user3) + {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10}) + + mention1 = result.entries |> List.first() + mention2 = result.entries |> List.last() + + {:ok, _} = Delivery.mark_read(:mention, [mention1.id, mention2.id], user) + + {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10, read: true}) + + mention1 = result.entries |> List.first() + mention2 = result.entries |> List.last() + + assert mention1.read + assert mention2.read + end + + @tag :wip + test "can mark read all", ~m(post user user2 user3 mention_attr)a do + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: user2.id, to_user_id: user.id}) + ] + + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user2) + + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: user3.id, to_user_id: user.id}) + ] + + {:ok, :pass} = Delivery.send(:mention, post, mention_contents, user3) + + {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10}) + assert result.total_count == 2 + + {:ok, _} = Delivery.mark_read_all(:mention, user) + + {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10}) + assert result.total_count == 0 + + {:ok, result} = Delivery.fetch(:mention, user, %{page: 1, size: 10, read: true}) + assert result.total_count == 2 + end + end end diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index 770e355cd..33918fa88 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -81,7 +81,7 @@ defmodule GroupherServer.Test.Delivery.Notification do describe "notification" do @tag :wip2 - test "can get unread notification count of a user", ~m(post user user2 user3 notify_attrs)a do + test "can get unread notification count of a user", ~m(user user2 user3 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) @@ -124,9 +124,7 @@ defmodule GroupherServer.Test.Delivery.Notification do test "notify not in @notify_group_interval_hour should not be merged", ~m(user user2 user3 notify_attrs)a do {:ok, notify} = Delivery.send(:notify, notify_attrs, user2) - move_insert_at_long_ago(notify) - {:ok, _} = Delivery.send(:notify, notify_attrs, user3) {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) @@ -341,4 +339,46 @@ defmodule GroupherServer.Test.Delivery.Notification do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) end end + + describe "mark read" do + @tag :wip + test "can mark multi notification as read", ~m(user user2 user3 notify_attrs)a do + {:ok, notify} = Delivery.send(:notify, notify_attrs, user2) + move_insert_at_long_ago(notify) + {:ok, _} = Delivery.send(:notify, notify_attrs, user3) + + {:ok, result} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + notify1 = result.entries |> List.first() + notify2 = result.entries |> List.last() + + assert result.total_count == 2 + + {:ok, _} = Delivery.mark_read(:notification, [notify1.id, notify2.id], user) + + {:ok, result} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + assert result.total_count == 0 + + {:ok, result} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10, read: true}) + assert result.total_count == 2 + end + + @tag :wip + test "can mark all notification as read", ~m(user user2 user3 notify_attrs)a do + {:ok, notify} = Delivery.send(:notify, notify_attrs, user2) + move_insert_at_long_ago(notify) + {:ok, _} = Delivery.send(:notify, notify_attrs, user3) + + {:ok, result} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + + assert result.total_count == 2 + + {:ok, _} = Delivery.mark_read_all(:notification, user) + + {:ok, result} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + assert result.total_count == 0 + + {:ok, result} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10, read: true}) + assert result.total_count == 2 + end + end end diff --git a/test/helper/orm_test.exs b/test/helper/orm_test.exs index dec1c21c5..6be1c8a53 100644 --- a/test/helper/orm_test.exs +++ b/test/helper/orm_test.exs @@ -62,7 +62,7 @@ defmodule GroupherServer.Test.Helper.ORM do end test "count should work" do - assert @posts_count + 1 == ORM.count(Post) + assert {:ok, @posts_count + 1} == ORM.count(Post) end describe "[embeds paginator]" do From 7165d640ddab8c19bf916ea31e4b5ffd7c364558 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 21 Jun 2021 17:56:02 +0800 Subject: [PATCH 42/54] refactor(notify): clean up --- test/groupher_server/accounts/mailbx_test.exs | 14 ++------------ test/groupher_server/delivery/mention_test.exs | 7 ------- .../groupher_server/delivery/notification_test.exs | 3 --- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/test/groupher_server/accounts/mailbx_test.exs b/test/groupher_server/accounts/mailbx_test.exs index 951d9b054..ee37990c8 100644 --- a/test/groupher_server/accounts/mailbx_test.exs +++ b/test/groupher_server/accounts/mailbx_test.exs @@ -11,21 +11,11 @@ defmodule GroupherServer.Test.Accounts.Mailbox do {:ok, user2} = db_insert(:user) {:ok, user3} = db_insert(:user) - notify_attrs = %{ - thread: :post, - article_id: post.id, - title: post.title, - action: :upvote, - user_id: user.id, - read: false - } - - {:ok, ~m(post user user2 user3 notify_attrs)a} + {:ok, ~m(post user user2 user3)a} end describe "mailbox status" do - @tag :wip2 - test "can get mailbox status", ~m(post user user2 notify_attrs)a do + test "can get mailbox status", ~m(post user user2)a do notify_attrs = %{ thread: :post, article_id: post.id, diff --git a/test/groupher_server/delivery/mention_test.exs b/test/groupher_server/delivery/mention_test.exs index 80982a1e5..414dcb736 100644 --- a/test/groupher_server/delivery/mention_test.exs +++ b/test/groupher_server/delivery/mention_test.exs @@ -27,7 +27,6 @@ defmodule GroupherServer.Test.Delivery.Mention do end describe "mentions" do - @tag :wip2 test "can get unread mention count of a user", ~m(post user user2 user3 mention_attr)a do mention_contents = [ Map.merge(mention_attr, %{from_user_id: user.id, to_user_id: user3.id}) @@ -45,7 +44,6 @@ defmodule GroupherServer.Test.Delivery.Mention do assert count == 2 end - @tag :wip2 test "can batch send mentions", ~m(post user user2 mention_attr)a do mention_contents = [ Map.merge(mention_attr, %{from_user_id: user.id, to_user_id: user2.id}) @@ -61,7 +59,6 @@ defmodule GroupherServer.Test.Delivery.Mention do assert mention.user.login == user.login end - @tag :wip2 test "mention multiable times on same article, will only have one record", ~m(post user user2 mention_attr)a do mention_contents = [ @@ -79,7 +76,6 @@ defmodule GroupherServer.Test.Delivery.Mention do assert result.total_count == 1 end - @tag :wip2 test "if mention before, update with no mention content will not do mention in final", ~m(post user user2 user3 mention_attr)a do mention_contents = [ @@ -108,7 +104,6 @@ defmodule GroupherServer.Test.Delivery.Mention do end describe "mark read" do - @tag :wip test "can mark read a mention", ~m(post user user2 mention_attr)a do mention_contents = [ Map.merge(mention_attr, %{from_user_id: user.id, to_user_id: user2.id}) @@ -126,7 +121,6 @@ defmodule GroupherServer.Test.Delivery.Mention do assert mention.read end - @tag :wip test "can mark multi mention as read", ~m(post user user2 user3 mention_attr)a do mention_contents = [ Map.merge(mention_attr, %{from_user_id: user2.id, to_user_id: user.id}) @@ -155,7 +149,6 @@ defmodule GroupherServer.Test.Delivery.Mention do assert mention2.read end - @tag :wip test "can mark read all", ~m(post user user2 user3 mention_attr)a do mention_contents = [ Map.merge(mention_attr, %{from_user_id: user2.id, to_user_id: user.id}) diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index 33918fa88..7006f889a 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -80,7 +80,6 @@ defmodule GroupherServer.Test.Delivery.Notification do end describe "notification" do - @tag :wip2 test "can get unread notification count of a user", ~m(user user2 user3 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) @@ -341,7 +340,6 @@ defmodule GroupherServer.Test.Delivery.Notification do end describe "mark read" do - @tag :wip test "can mark multi notification as read", ~m(user user2 user3 notify_attrs)a do {:ok, notify} = Delivery.send(:notify, notify_attrs, user2) move_insert_at_long_ago(notify) @@ -362,7 +360,6 @@ defmodule GroupherServer.Test.Delivery.Notification do assert result.total_count == 2 end - @tag :wip test "can mark all notification as read", ~m(user user2 user3 notify_attrs)a do {:ok, notify} = Delivery.send(:notify, notify_attrs, user2) move_insert_at_long_ago(notify) From 6fd11187ac7a45e82369015c33b65abc8e5291f1 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 21 Jun 2021 18:13:21 +0800 Subject: [PATCH 43/54] refactor(notify): remove old delivery system --- lib/groupher_server/accounts/accounts.ex | 13 - .../accounts/delegates/mails.ex | 130 ---------- .../delivery/delegates/mentions.ex | 149 ------------ .../delivery/delegates/notifications.ex | 50 ---- .../delivery/delegates/utils.ex | 224 ------------------ lib/groupher_server/delivery/delivery.ex | 21 +- .../delivery/models/old_mention.ex | 38 --- .../delivery/models/old_notification.ex | 38 --- lib/groupher_server/delivery/models/record.ex | 29 --- .../delivery/models/sys_notification.ex | 29 --- ...10621100858_remove_old_delivery_tables.exs | 9 + ...0621101125_remove_old_delivery_records.exs | 7 + .../delivery/old_delivery_test.exs | 23 -- .../delivery/old_mention_test.exs | 133 ----------- .../delivery/old_notification_test.exs | 130 ---------- .../delivery/sys_notification_test.exs | 103 -------- 16 files changed, 17 insertions(+), 1109 deletions(-) delete mode 100644 lib/groupher_server/accounts/delegates/mails.ex delete mode 100644 lib/groupher_server/delivery/delegates/mentions.ex delete mode 100644 lib/groupher_server/delivery/delegates/notifications.ex delete mode 100644 lib/groupher_server/delivery/delegates/utils.ex delete mode 100644 lib/groupher_server/delivery/models/old_mention.ex delete mode 100644 lib/groupher_server/delivery/models/old_notification.ex delete mode 100644 lib/groupher_server/delivery/models/record.ex delete mode 100644 lib/groupher_server/delivery/models/sys_notification.ex create mode 100644 priv/repo/migrations/20210621100858_remove_old_delivery_tables.exs create mode 100644 priv/repo/migrations/20210621101125_remove_old_delivery_records.exs delete mode 100644 test/groupher_server/delivery/old_delivery_test.exs delete mode 100644 test/groupher_server/delivery/old_mention_test.exs delete mode 100644 test/groupher_server/delivery/old_notification_test.exs delete mode 100644 test/groupher_server/delivery/sys_notification_test.exs diff --git a/lib/groupher_server/accounts/accounts.ex b/lib/groupher_server/accounts/accounts.ex index 28d76b6cb..47296d7b3 100644 --- a/lib/groupher_server/accounts/accounts.ex +++ b/lib/groupher_server/accounts/accounts.ex @@ -7,7 +7,6 @@ defmodule GroupherServer.Accounts do Fans, CollectFolder, Publish, - Mails, Mailbox, Profile, UpvotedArticles, @@ -63,18 +62,6 @@ defmodule GroupherServer.Accounts do # upvoted articles defdelegate paged_upvoted_articles(user_id, filter), to: UpvotedArticles - # mentions - defdelegate fetch_mentions(user, filter), to: Mails - - # notifications - defdelegate fetch_notifications(user, filter), to: Mails - defdelegate fetch_sys_notifications(user, filter), to: Mails - - # common message - defdelegate mailbox_status(user), to: Mails - defdelegate mark_mail_read_all(user, opt), to: Mails - defdelegate mark_mail_read(mail, user), to: Mails - defdelegate update_mailbox_status(user_id), to: Mailbox # customization diff --git a/lib/groupher_server/accounts/delegates/mails.ex b/lib/groupher_server/accounts/delegates/mails.ex deleted file mode 100644 index 80fb67323..000000000 --- a/lib/groupher_server/accounts/delegates/mails.ex +++ /dev/null @@ -1,130 +0,0 @@ -defmodule GroupherServer.Accounts.Delegate.Mails do - import Ecto.Query, warn: false - import Helper.Utils, only: [done: 1, done: 2] - import ShortMaps - - alias GroupherServer.Repo - alias GroupherServer.Accounts.Model.{User, MentionMail, NotificationMail, SysNotificationMail} - alias GroupherServer.Delivery - alias Helper.ORM - - def mailbox_status(%User{} = user), do: Delivery.mailbox_status(user) - - def fetch_mentions(%User{} = user, filter) do - with {:ok, mentions} <- Delivery.fetch_mentions(user, filter), - {:ok, washed_mentions} <- wash_data(MentionMail, mentions.entries) do - MentionMail |> Repo.insert_all(washed_mentions) - MentionMail |> messages_fetcher(washed_mentions, user, filter) - end - end - - def fetch_notifications(%User{} = user, filter) do - with {:ok, notifications} <- Delivery.fetch_notifications(user, filter), - {:ok, washed_notifications} <- wash_data(NotificationMail, notifications.entries) do - NotificationMail |> Repo.insert_all(washed_notifications) - NotificationMail |> messages_fetcher(washed_notifications, user, filter) - end - end - - def fetch_sys_notifications(%User{} = user, %{page: page, size: size, read: read}) do - with {:ok, sys_notifications} <- - Delivery.fetch_sys_notifications(user, %{page: page, size: size}), - {:ok, washed_notifications} <- - wash_data(SysNotificationMail, user, sys_notifications.entries) do - SysNotificationMail - |> Repo.insert_all(washed_notifications) - - SysNotificationMail - |> order_by(desc: :inserted_at) - |> where([m], m.user_id == ^user.id) - |> where([m], m.read == ^read) - |> ORM.paginater(~m(page size)a) - |> done() - end - end - - defp messages_fetcher(queryable, _washed_data, %User{id: user_id}, %{ - page: page, - size: size, - read: read - }) do - queryable - |> order_by(desc: :inserted_at) - |> where([m], m.to_user_id == ^user_id) - |> where([m], m.read == ^read) - |> preload(:from_user) - |> preload(:to_user) - |> ORM.paginater(~m(page size)a) - |> done() - end - - def mark_mail_read(%MentionMail{id: id}, %User{} = user) do - do_mark_mail_read(MentionMail, id, user) - end - - def mark_mail_read(%NotificationMail{id: id}, %User{} = user) do - do_mark_mail_read(NotificationMail, id, user) - end - - def mark_mail_read(%SysNotificationMail{id: id}, %User{} = user) do - with {:ok, mail} <- SysNotificationMail |> ORM.find_by(id: id, user_id: user.id) do - mail |> ORM.update(%{read: true}) |> done(:status) - end - end - - def mark_mail_read_all(%User{} = user, :mention) do - user |> do_mark_mail_read_all(MentionMail, :mention) - end - - def mark_mail_read_all(%User{} = user, :notification) do - user |> do_mark_mail_read_all(NotificationMail, :notification) - end - - defp do_mark_mail_read(queryable, id, %User{} = user) do - with {:ok, mail} <- queryable |> ORM.find_by(id: id, to_user_id: user.id) do - mail |> ORM.update(%{read: true}) |> done(:status) - end - end - - defp do_mark_mail_read_all(%User{} = user, mail, atom) do - query = - mail - |> where([m], m.to_user_id == ^user.id) - - Repo.update_all(query, set: [read: true]) - - Delivery.mark_read_all(user, atom) - end - - defp wash_data(MentionMail, []), do: {:ok, []} - defp wash_data(NotificationMail, []), do: {:ok, []} - - defp wash_data(MentionMail, list), do: do_wash_data(list) - defp wash_data(NotificationMail, list), do: do_wash_data(list) - - defp wash_data(SysNotificationMail, user, list) do - convert = - list - |> Enum.map( - &(Map.from_struct(&1) - |> Map.delete(:__meta__) - |> Map.put(:user_id, user.id)) - ) - - {:ok, convert} - end - - defp do_wash_data(list) do - convert = - list - |> Enum.map( - &(Map.from_struct(&1) - |> Map.delete(:__meta__) - |> Map.delete(:id) - |> Map.delete(:from_user) - |> Map.delete(:to_user)) - ) - - {:ok, convert} - end -end diff --git a/lib/groupher_server/delivery/delegates/mentions.ex b/lib/groupher_server/delivery/delegates/mentions.ex deleted file mode 100644 index 43d8226ed..000000000 --- a/lib/groupher_server/delivery/delegates/mentions.ex +++ /dev/null @@ -1,149 +0,0 @@ -defmodule GroupherServer.Delivery.Delegate.Mentions do - @moduledoc """ - The Delivery context. - """ - import Helper.Utils, only: [stringfy: 1, integerfy: 1] - - alias GroupherServer.{Accounts, Delivery, Repo} - - alias Accounts.Model.User - alias Delivery.Model.OldMention - alias Delivery.Delegate.Utils - - # TODO: move mention logic to create contents - # TODO: 同一篇文章不能 mention 同一个 user 多次? - def mention_others(%User{id: _from_user_id}, [], _info), do: {:error, %{done: false}} - def mention_others(%User{id: _from_user_id}, nil, _info), do: {:error, %{done: false}} - def mention_others(%User{id: _from_user_id}, [nil], _info), do: {:error, %{done: false}} - - def mention_others(%User{id: from_user_id}, to_uses, info) do - other_users = Enum.uniq(to_uses) - - records = - Enum.reduce(other_users, [], fn to_user, acc -> - attrs = %{ - from_user_id: from_user_id, - to_user_id: integerfy(to_user.id), - source_id: stringfy(info.source_id), - # source_title has 256 limit under table - # chinese takes 2 chars - source_title: String.slice(info.source_title, 0, 50), - source_type: info.source_type, - # source_preview has 256 limit under table - # chinese takes 2 chars - source_preview: String.slice(info.source_preview, 0, 50), - parent_id: stringfy(Map.get(info, :parent_id)), - parent_type: stringfy(Map.get(info, :parent_type)), - community: Map.get(info, :community), - # timestamp are not auto-gen, see: - # https://stackoverflow.com/questions/37537094/insert-all-does-not-create-auto-generated-inserted-at-with-ecto-2-0/46844417 - # Ecto.DateTime.utc(), - inserted_at: DateTime.truncate(Timex.now(), :second), - # Ecto.DateTime.utc() - updated_at: DateTime.truncate(Timex.now(), :second) - } - - attrs = - if Map.has_key?(info, :floor), - do: Map.merge(attrs, %{floor: integerfy(info.floor)}), - else: attrs - - acc ++ [attrs] - end) - - Repo.insert_all(OldMention, records) - - {:ok, %{done: true}} - # |> done(:status) - end - - """ - title: - thread: - id - block_linker - comment_id - """ - - # def mention_from_article() - # deff mention_from_comment() - - def mention_from_content(community, :post, content, args, %User{} = from_user) do - to_user_ids = Map.get(args, :mention_users) - topic = Map.get(args, :topic, "posts") - - info = %{ - source_title: String.slice(content.title, 0, 50), - source_type: topic, - source_id: content.id, - source_preview: String.slice(content.digest, 0, 50), - community: community - } - - mention_others(from_user, to_user_ids, info) - end - - def mention_from_content(community, :job, content, args, %User{} = from_user) do - to_user_ids = Map.get(args, :mention_users) - - info = %{ - source_title: String.slice(content.title, 0, 50), - source_type: "job", - source_id: content.id, - source_preview: String.slice(content.digest, 0, 50), - community: community - } - - mention_others(from_user, to_user_ids, info) - end - - def mention_from_content(_community, _thread, _, _, _user), do: {:ok, :pass} - - def mention_from_comment(community, thread, content, comment, args, %User{} = from_user) do - to_user_ids = Map.get(args, :mention_users) - - info = %{ - source_title: String.slice(content.title, 0, 50), - source_type: "comment", - source_id: comment.id, - source_preview: String.slice(comment.body, 0, 50), - floor: comment.floor, - parent_id: content.id, - parent_type: thread, - community: community - } - - mention_others(from_user, to_user_ids, info) - end - - defp get_reply_content_id(:post, comment), do: comment.post_id - defp get_reply_content_id(:job, comment), do: comment.job_id - defp get_reply_content_id(:repo, comment), do: comment.repo_id - - def mention_from_comment_reply(community, thread, comment, args, %User{} = from_user) do - # IO.inspect comment, label: "reply this comment" - content_id = get_reply_content_id(thread, comment) - to_user_ids = Map.get(args, :mention_users) - - info = %{ - source_title: String.slice(comment.body, 0, 50), - source_type: "comment_reply", - source_id: content_id, - source_preview: String.slice(args.body, 0, 50), - floor: args.floor, - parent_id: content_id, - parent_type: thread, - community: community - } - - mention_others(from_user, to_user_ids, info) - mention_others(from_user, [%{id: comment.author_id}], info) - end - - @doc """ - fetch mentions from Delivery stop - """ - def fetch_mentions(%User{} = user, %{page: _, size: _, read: _} = filter) do - Utils.fetch_messages(user, OldMention, filter) - end -end diff --git a/lib/groupher_server/delivery/delegates/notifications.ex b/lib/groupher_server/delivery/delegates/notifications.ex deleted file mode 100644 index 20bb9aac3..000000000 --- a/lib/groupher_server/delivery/delegates/notifications.ex +++ /dev/null @@ -1,50 +0,0 @@ -defmodule GroupherServer.Delivery.Delegate.Notifications do - @moduledoc """ - The Delivery context. - """ - import Helper.Utils, only: [done: 2] - - alias GroupherServer.{Accounts, Delivery} - - alias Accounts.Model.User - alias Delivery.Model.{OldNotification, SysNotification} - alias Delivery.Delegate.Utils - alias Helper.ORM - - # TODO: audience - def publish_system_notification(info) do - attrs = %{ - source_id: info.source_id, - source_title: info.source_title, - source_type: info |> Map.get(:source_type, ""), - source_preview: info |> Map.get(:source_preview, "") - } - - SysNotification |> ORM.create(attrs) |> done(:status) - end - - def notify_someone(%User{id: from_user_id}, %User{id: to_user_id}, info) do - attrs = %{ - from_user_id: from_user_id, - to_user_id: to_user_id, - action: info.action, - source_id: info.source_id, - source_title: info.source_title, - source_type: info.source_type, - source_preview: info.source_preview - } - - OldNotification |> ORM.create(attrs) - end - - @doc """ - fetch notifications from Delivery - """ - def fetch_notifications(%User{} = user, %{page: _, size: _, read: _} = filter) do - Utils.fetch_messages(user, OldNotification, filter) - end - - def fetch_sys_notifications(%User{} = user, %{page: _, size: _} = filter) do - Utils.fetch_messages(:sys_notification, user, filter) - end -end diff --git a/lib/groupher_server/delivery/delegates/utils.ex b/lib/groupher_server/delivery/delegates/utils.ex deleted file mode 100644 index c3eeb2d11..000000000 --- a/lib/groupher_server/delivery/delegates/utils.ex +++ /dev/null @@ -1,224 +0,0 @@ -defmodule GroupherServer.Delivery.Delegate.Utils do - @moduledoc """ - The Delivery context. - """ - # commons - import Ecto.Query, warn: false - import Helper.Utils - import ShortMaps - - alias GroupherServer.{Accounts, Delivery, Repo} - - alias Accounts.Model.User - alias Delivery.Model.{OldNotification, SysNotification, OldMention, Record} - - alias Helper.ORM - - def mailbox_status(%User{} = user) do - filter = %{page: 1, size: 1, read: false} - {:ok, mention_mail} = fetch_mails(user, OldMention, filter) - {:ok, notification_mail} = fetch_mails(user, OldNotification, filter) - - mention_count = mention_mail.total_count - notification_count = notification_mail.total_count - total_count = mention_count + notification_count - - has_mail = total_count > 0 - - result = ~m(has_mail total_count mention_count notification_count)a - {:ok, result} - end - - def fetch_record(%User{id: user_id}), do: Record |> ORM.find_by(user_id: user_id) - - def mark_read_all(%User{} = user, :mention), do: OldMention |> do_mark_read_all(user) - def mark_read_all(%User{} = user, :notification), do: OldNotification |> do_mark_read_all(user) - - @doc """ - fetch mentions / notifications - """ - def fetch_messages(:sys_notification, %User{} = user, %{page: page, size: size}) do - {:ok, last_fetch_time} = get_last_fetch_time(SysNotification, user) - - mails = - SysNotification - |> order_by(desc: :inserted_at) - |> where([m], m.inserted_at > ^last_fetch_time) - |> ORM.paginater(~m(page size)a) - |> done() - - record_operation(user, SysNotification, mails) - mails - end - - def fetch_messages(%User{} = user, queryable, %{page: _page, size: _size, read: read} = filter) do - mails = fetch_mails_and_delete(user, queryable, filter) - record_operation(queryable, read, mails) - - mails - end - - defp fetch_mails(user, queryable, %{page: page, size: size, read: read}) do - {:ok, last_fetch_time} = get_last_fetch_time(queryable, read, user) - - queryable - |> where([m], m.to_user_id == ^user.id) - |> where([m], m.inserted_at > ^last_fetch_time) - |> where([m], m.read == ^read) - |> ORM.paginater(~m(page size)a) - |> done() - end - - defp fetch_mails_and_delete(user, queryable, %{page: page, size: size, read: read}) do - {:ok, last_fetch_time} = get_last_fetch_time(queryable, read, user) - - query = - queryable - |> where([m], m.to_user_id == ^user.id) - |> where([m], m.inserted_at > ^last_fetch_time) - |> where([m], m.read == ^read) - - mails = query |> order_by(desc: :inserted_at) |> ORM.paginater(~m(page size)a) |> done() - - delete_items(query, mails) - - mails - end - - defp record_operation(OldMention, _read, {:ok, %{entries: []}}), do: {:ok, ""} - defp record_operation(OldNotification, _read, {:ok, %{entries: []}}), do: {:ok, ""} - defp record_operation(_, SysNotification, {:ok, %{entries: []}}), do: {:ok, ""} - - defp record_operation(OldMention, read, {:ok, %{entries: entries}}) do - do_record_operation(:mentions_record, read, {:ok, %{entries: entries}}) - end - - defp record_operation(OldNotification, read, {:ok, %{entries: entries}}) do - do_record_operation(:notifications_record, read, {:ok, %{entries: entries}}) - end - - defp record_operation(%User{} = user, SysNotification, {:ok, %{entries: entries}}) do - do_record_operation(user, :sys_notifications_record, {:ok, %{entries: entries}}) - end - - defp get_record_lasttime(entries) do - first_insert = entries |> List.first() |> Map.get(:inserted_at) - last_insert = entries |> List.last() |> Map.get(:inserted_at) - newest_insert = Enum.max([first_insert, last_insert]) - - newest_insert |> Timex.to_datetime() |> to_string - end - - # sys_notification - defp do_record_operation(%User{id: user_id}, record_name, {:ok, %{entries: entries}}) do - record_last_fetch_time = get_record_lasttime(entries) - - attrs = - %{user_id: user_id} |> Map.put(record_name, %{last_fetch_time: record_last_fetch_time}) - - Record |> ORM.upsert_by([user_id: user_id], attrs) - end - - # last_fetch_read_time - # > the last fetch time of mails that is read - # last_fetch_unread_time - # > the last fetch time of mails that is read - defp do_record_operation(record_name, read, {:ok, %{entries: entries}}) do - record_last_fetch_time = get_record_lasttime(entries) - user_id = entries |> List.first() |> Map.get(:to_user_id) - - attrs = - case read do - true -> - %{user_id: user_id} - |> Map.put(record_name, %{last_fetch_read_time: record_last_fetch_time}) - - false -> - %{user_id: user_id} - |> Map.put(record_name, %{last_fetch_unread_time: record_last_fetch_time}) - end - - Record |> ORM.upsert_by([user_id: user_id], attrs) - end - - defp get_last_fetch_time(OldMention, read, user) do - timekey = get_record_lasttime_key(read) - do_get_last_fetch_time(:mentions_record, user, timekey) - end - - defp get_last_fetch_time(OldNotification, read, user) do - timekey = get_record_lasttime_key(read) - do_get_last_fetch_time(:notifications_record, user, timekey) - end - - defp get_last_fetch_time(SysNotification, user) do - timekey = get_record_lasttime_key(:sys_notifications_record) - do_get_last_fetch_time(:sys_notifications_record, user, timekey) - end - - defp get_record_lasttime_key(:sys_notifications_record) do - "last_fetch_time" - end - - defp get_record_lasttime_key(read) do - case read do - true -> "last_fetch_read_time" - false -> "last_fetch_unread_time" - end - end - - defp do_get_last_fetch_time(record_key, %User{id: user_id}, timekey) do - long_long_ago = Timex.shift(Timex.now(), years: -10) - - with {:ok, record} <- Record |> ORM.find_by(user_id: user_id) do - record - |> has_valid_value(record_key) - |> case do - false -> - {:ok, long_long_ago} - - true -> - record - |> Map.get(record_key) - |> Map.get(timekey, to_string(long_long_ago)) - |> NaiveDateTime.from_iso8601() - end - else - {:error, _} -> - {:ok, long_long_ago} - end - end - - defp delete_items(_queryable, {:ok, %{entries: []}}), do: {:ok, ""} - - defp delete_items(queryable, {:ok, %{entries: entries}}) do - # delete_all only support queryable and where syntax - # TODO: move logic to queue job - - first_id = entries |> List.first() |> Map.get(:id) - last_id = entries |> List.last() |> Map.get(:id) - - min_id = Enum.min([first_id, last_id]) - max_id = Enum.max([first_id, last_id]) - - queryable - |> where([m], m.id >= ^min_id and m.id <= ^max_id) - |> Repo.delete_all() - end - - defp do_mark_read_all(queryable, %User{} = user) do - query = queryable |> where([m], m.to_user_id == ^user.id) - - try do - Repo.update_all(query, set: [read: true]) - - {:ok, %{status: true}} - rescue - _ -> {:error, %{status: false}} - end - end - - defp has_valid_value(map, key) when is_map(map) do - Map.has_key?(map, key) and not is_nil(Map.get(map, key)) - end -end diff --git a/lib/groupher_server/delivery/delivery.ex b/lib/groupher_server/delivery/delivery.ex index 3aa3a7df3..dcd536c5f 100644 --- a/lib/groupher_server/delivery/delivery.ex +++ b/lib/groupher_server/delivery/delivery.ex @@ -4,9 +4,7 @@ defmodule GroupherServer.Delivery do """ alias GroupherServer.Delivery - alias Delivery.Delegate.{Postman, Mentions, Notifications, Utils} - - defdelegate mailbox_status(user), to: Utils + alias Delivery.Delegate.Postman defdelegate send(service, artiment, mentions, from_user), to: Postman defdelegate send(service, attrs, from_user), to: Postman @@ -16,21 +14,4 @@ defmodule GroupherServer.Delivery do defdelegate mark_read(service, ids, user), to: Postman defdelegate mark_read_all(service, user), to: Postman - # system_notifications - defdelegate publish_system_notification(info), to: Notifications - defdelegate fetch_sys_notifications(user, filter), to: Notifications - - # mentions - defdelegate mention_others(from_user, to_user_ids, info), to: Mentions - defdelegate mention_from_content(community, thread, content, args, user), to: Mentions - defdelegate mention_from_comment(community, thread, content, comment, args, user), to: Mentions - defdelegate mention_from_comment_reply(community, thread, comment, args, user), to: Mentions - defdelegate fetch_mentions(user, filter), to: Mentions - - # notifications - defdelegate notify_someone(from_user, to_user, info), to: Notifications - defdelegate fetch_notifications(user, filter), to: Notifications - - defdelegate fetch_record(user), to: Utils - defdelegate mark_read_all(user, opt), to: Utils end diff --git a/lib/groupher_server/delivery/models/old_mention.ex b/lib/groupher_server/delivery/models/old_mention.ex deleted file mode 100644 index c3716fd2e..000000000 --- a/lib/groupher_server/delivery/models/old_mention.ex +++ /dev/null @@ -1,38 +0,0 @@ -defmodule GroupherServer.Delivery.Model.OldMention do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.Accounts.Model.User - - @required_fields ~w(from_user_id to_user_id source_title source_id source_type source_preview)a - @optional_fields ~w(parent_id parent_type read floor community)a - - @type t :: %OldMention{} - schema "old_mentions" do - belongs_to(:from_user, User) - belongs_to(:to_user, User) - field(:source_id, :string) - field(:source_preview, :string) - field(:source_title, :string) - field(:source_type, :string) - field(:parent_id, :string) - field(:parent_type, :string) - field(:community, :string) - field(:floor, :integer) - field(:read, :boolean) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%OldMention{} = mention, attrs) do - mention - |> cast(attrs, @optional_fields ++ @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:from_user_id) - |> foreign_key_constraint(:to_user_id) - end -end diff --git a/lib/groupher_server/delivery/models/old_notification.ex b/lib/groupher_server/delivery/models/old_notification.ex deleted file mode 100644 index a01f8467d..000000000 --- a/lib/groupher_server/delivery/models/old_notification.ex +++ /dev/null @@ -1,38 +0,0 @@ -defmodule GroupherServer.Delivery.Model.OldNotification do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - alias GroupherServer.Accounts.Model.User - - @required_fields ~w(from_user_id to_user_id action source_title source_id source_preview source_type)a - @optional_fields ~w(parent_id parent_type read)a - - @type t :: %OldNotification{} - schema "old_notifications" do - belongs_to(:from_user, User) - belongs_to(:to_user, User) - field(:action, :string) - - field(:source_id, :string) - field(:source_preview, :string) - field(:source_title, :string) - field(:source_type, :string) - field(:parent_id, :string) - field(:parent_type, :string) - field(:read, :boolean) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%OldNotification{} = notification, attrs) do - notification - |> cast(attrs, @optional_fields ++ @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:from_user_id) - |> foreign_key_constraint(:to_user_id) - end -end diff --git a/lib/groupher_server/delivery/models/record.ex b/lib/groupher_server/delivery/models/record.ex deleted file mode 100644 index 66a449728..000000000 --- a/lib/groupher_server/delivery/models/record.ex +++ /dev/null @@ -1,29 +0,0 @@ -defmodule GroupherServer.Delivery.Model.Record do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - alias GroupherServer.Accounts.Model.User - - @required_fields ~w(user_id)a - @optional_fields ~w(mentions_record notifications_record sys_notifications_record)a - - @type t :: %Record{} - schema "delivery_records" do - field(:mentions_record, :map) - field(:notifications_record, :map) - field(:sys_notifications_record, :map) - belongs_to(:user, User) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%Record{} = record, attrs) do - record - |> cast(attrs, @optional_fields ++ @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:user_id) - end -end diff --git a/lib/groupher_server/delivery/models/sys_notification.ex b/lib/groupher_server/delivery/models/sys_notification.ex deleted file mode 100644 index 8c2616575..000000000 --- a/lib/groupher_server/delivery/models/sys_notification.ex +++ /dev/null @@ -1,29 +0,0 @@ -defmodule GroupherServer.Delivery.Model.SysNotification do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - - @required_fields ~w(source_title source_id source_type)a - @optional_fields ~w(source_preview)a - - @type t :: %SysNotification{} - schema "sys_notifications" do - field(:source_id, :string) - field(:source_title, :string) - field(:source_type, :string) - field(:source_preview, :string) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%SysNotification{} = sys_notification, attrs) do - sys_notification - |> cast(attrs, @optional_fields ++ @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:from_user_id) - |> foreign_key_constraint(:to_user_id) - end -end diff --git a/priv/repo/migrations/20210621100858_remove_old_delivery_tables.exs b/priv/repo/migrations/20210621100858_remove_old_delivery_tables.exs new file mode 100644 index 000000000..b658dd4bf --- /dev/null +++ b/priv/repo/migrations/20210621100858_remove_old_delivery_tables.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.RemoveOldDeliveryTables do + use Ecto.Migration + + def change do + drop(table(:old_mentions)) + drop(table(:old_notifications)) + drop(table(:sys_notifications)) + end +end diff --git a/priv/repo/migrations/20210621101125_remove_old_delivery_records.exs b/priv/repo/migrations/20210621101125_remove_old_delivery_records.exs new file mode 100644 index 000000000..a238751fc --- /dev/null +++ b/priv/repo/migrations/20210621101125_remove_old_delivery_records.exs @@ -0,0 +1,7 @@ +defmodule GroupherServer.Repo.Migrations.RemoveOldDeliveryRecords do + use Ecto.Migration + + def change do + drop(table(:delivery_records)) + end +end diff --git a/test/groupher_server/delivery/old_delivery_test.exs b/test/groupher_server/delivery/old_delivery_test.exs deleted file mode 100644 index b77953992..000000000 --- a/test/groupher_server/delivery/old_delivery_test.exs +++ /dev/null @@ -1,23 +0,0 @@ -defmodule GroupherServer.Test.Delivery.Basic do - use GroupherServer.TestTools - - import Ecto.Query, warn: false - alias GroupherServer.Delivery - - test "user can check mailbox status" do - {:ok, user} = db_insert(:user) - {:ok, mail_box} = Delivery.mailbox_status(user) - assert mail_box.has_mail == false - assert mail_box.total_count == 0 - assert mail_box.mention_count == 0 - assert mail_box.notification_count == 0 - - mock_mentions_for(user, 2) - mock_notifications_for(user, 18) - {:ok, mail_box} = Delivery.mailbox_status(user) - assert mail_box.has_mail == true - assert mail_box.total_count == 20 - assert mail_box.mention_count == 2 - assert mail_box.notification_count == 18 - end -end diff --git a/test/groupher_server/delivery/old_mention_test.exs b/test/groupher_server/delivery/old_mention_test.exs deleted file mode 100644 index 419c940c7..000000000 --- a/test/groupher_server/delivery/old_mention_test.exs +++ /dev/null @@ -1,133 +0,0 @@ -defmodule GroupherServer.Test.Delivery.OldMention do - use GroupherServer.TestTools - - import Ecto.Query, warn: false - import Helper.Utils - - alias Helper.ORM - alias GroupherServer.{Accounts, Delivery} - - alias Accounts.Model.MentionMail - alias Delivery.Model.OldMention - - describe "mentions" do - test "user can mention other user" do - {:ok, [user, user2]} = db_insert_multi(:user, 2) - - mock_mentions_for(user, 1) - mock_mentions_for(user2, 1) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Delivery.fetch_mentions(user, filter) - - assert mentions |> is_valid_pagination?(:raw) - assert mentions |> Map.get(:total_count) == 1 - assert mentions.entries |> List.first() |> Map.get(:to_user_id) == user.id - assert mentions.entries |> List.first() |> Map.get(:community) == "elixir" - end - - test "user can fetch mentions and store in own mention mail-box" do - {:ok, user} = db_insert(:user) - - mock_mentions_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) - - {:ok, mention_mails} = - MentionMail - |> where([m], m.to_user_id == ^user.id) - |> where([m], m.read == false) - |> ORM.paginater(page: 1, size: 10) - |> done() - - mention_ids = - mentions.entries - |> Enum.reduce([], fn m, acc -> - acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) - end) - - mention_mail_ids = - mention_mails.entries - |> Enum.reduce([], fn m, acc -> - acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) - end) - - assert Enum.sort(mention_ids) == Enum.sort(mention_mail_ids) - end - - test "delete related delivery mentions after user fetch" do - {:ok, user} = db_insert(:user) - - mock_mentions_for(user, 1) - - filter = %{page: 1, size: 20, read: false} - {:ok, _mentions} = Accounts.fetch_mentions(user, filter) - - {:ok, mentions} = - OldMention - |> where([m], m.to_user_id == ^user.id) - |> ORM.paginater(page: 1, size: 10) - |> done() - - assert Enum.empty?(mentions.entries) - end - - test "store user fetch info in delivery records, with last_fetch_unread_time info" do - {:ok, user} = db_insert(:user) - - mock_mentions_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) - {:ok, record} = Delivery.fetch_record(user) - - latest_insert_time = mentions.entries |> List.first() |> Map.get(:inserted_at) |> to_string - - record_last_fetch_unresd_time = - record |> Map.get(:mentions_record) |> Map.get("last_fetch_unread_time") - - assert latest_insert_time == record_last_fetch_unresd_time - end - - test "user can mark one mention as read" do - {:ok, user} = db_insert(:user) - - mock_mentions_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) - first_mention = mentions.entries |> List.first() - assert mentions.total_count == 3 - Accounts.mark_mail_read(first_mention, user) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) - assert mentions.total_count == 2 - - filter = %{page: 1, size: 20, read: true} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) - assert mentions.total_count == 1 - end - - test "user can mark all unread mentions as read" do - {:ok, user} = db_insert(:user) - - mock_mentions_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, _mentions} = Accounts.fetch_mentions(user, filter) - Accounts.mark_mail_read_all(user, :mention) - - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) - - assert Enum.empty?(mentions.entries) - - filter = %{page: 1, size: 20, read: true} - {:ok, mentions} = Accounts.fetch_mentions(user, filter) - - assert mentions.total_count == 3 - end - end -end diff --git a/test/groupher_server/delivery/old_notification_test.exs b/test/groupher_server/delivery/old_notification_test.exs deleted file mode 100644 index eae70bf7d..000000000 --- a/test/groupher_server/delivery/old_notification_test.exs +++ /dev/null @@ -1,130 +0,0 @@ -defmodule GroupherServer.Test.Delivery.OldNotification do - use GroupherServer.TestTools - - import Ecto.Query, warn: false - import Helper.Utils - - alias Helper.ORM - alias GroupherServer.{Accounts, Delivery} - - alias Accounts.Model.NotificationMail - alias Delivery.Model.OldNotification - - describe "[delivery notification]" do - test "user can notify other user" do - {:ok, [user, user2]} = db_insert_multi(:user, 2) - - mock_notifications_for(user, 1) - mock_notifications_for(user2, 1) - - filter = %{page: 1, size: 20, read: false} - {:ok, notifications} = Delivery.fetch_notifications(user, filter) - - assert notifications |> is_valid_pagination?(:raw) - assert notifications |> Map.get(:total_count) == 1 - assert user.id == notifications.entries |> List.first() |> Map.get(:to_user_id) - end - - test "user can fetch notifications and store in own mention mail-box" do - {:ok, user} = db_insert(:user) - - mock_notifications_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) - - {:ok, notification_mails} = - NotificationMail - |> where([m], m.to_user_id == ^user.id) - |> where([m], m.read == false) - |> ORM.paginater(page: 1, size: 10) - |> done() - - notification_ids = - notifications.entries - |> Enum.reduce([], fn m, acc -> - acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) - end) - - notification_mail_ids = - notification_mails.entries - |> Enum.reduce([], fn m, acc -> - acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) - end) - - assert Enum.sort(notification_ids) == Enum.sort(notification_mail_ids) - end - - test "delete related delivery notifications after user fetch" do - {:ok, user} = db_insert(:user) - - mock_notifications_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, _mentions} = Accounts.fetch_notifications(user, filter) - - {:ok, notifications} = - OldNotification - |> where([m], m.to_user_id == ^user.id) - |> ORM.paginater(page: 1, size: 10) - |> done() - - assert Enum.empty?(notifications.entries) - end - - test "store user fetch info in delivery records, with last_fetch_unread_time info" do - {:ok, user} = db_insert(:user) - - mock_notifications_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) - {:ok, record} = Delivery.fetch_record(user) - - latest_insert_time = - notifications.entries |> List.first() |> Map.get(:inserted_at) |> to_string - - record_last_fetch_unresd_time = - record |> Map.get(:notifications_record) |> Map.get("last_fetch_unread_time") - - assert latest_insert_time == record_last_fetch_unresd_time - end - - test "user can mark one notifications as read" do - {:ok, user} = db_insert(:user) - - mock_notifications_for(user, 3) - - filter = %{page: 1, size: 20, read: false} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) - first_notification = notifications.entries |> List.first() - assert notifications.total_count == 3 - Accounts.mark_mail_read(first_notification, user) - - filter = %{page: 1, size: 20, read: false} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) - assert notifications.total_count == 2 - - filter = %{page: 1, size: 20, read: true} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) - assert notifications.total_count == 1 - end - - test "user can mark all unread notifications as read" do - {:ok, user} = db_insert(:user) - - mock_notifications_for(user, 3) - - Accounts.mark_mail_read_all(user, :notification) - - filter = %{page: 1, size: 20, read: false} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) - - assert Enum.empty?(notifications.entries) - - filter = %{page: 1, size: 20, read: true} - {:ok, notifications} = Accounts.fetch_notifications(user, filter) - assert notifications.total_count == 3 - end - end -end diff --git a/test/groupher_server/delivery/sys_notification_test.exs b/test/groupher_server/delivery/sys_notification_test.exs deleted file mode 100644 index dcd450db5..000000000 --- a/test/groupher_server/delivery/sys_notification_test.exs +++ /dev/null @@ -1,103 +0,0 @@ -defmodule GroupherServer.Test.Delivery.SysNotification do - use GroupherServer.TestTools - - import Ecto.Query, warn: false - import Helper.Utils - - alias Helper.ORM - alias GroupherServer.{Accounts, Delivery} - - alias Accounts.Model.SysNotificationMail - alias Delivery.Model.SysNotification - - describe "[delivery sys notification]" do - test "user can publish system notification" do - attrs = mock_attrs(:sys_notification) - - {:ok, sys_notification} = Delivery.publish_system_notification(attrs) - {:ok, found} = SysNotification |> ORM.find(sys_notification.id) - - assert found.id == sys_notification.id - end - - test "user can get paged system notifications" do - {:ok, user} = db_insert(:user) - mock_sys_notification(10) - - filter = %{page: 1, size: 20} - {:ok, sys_notification} = Delivery.fetch_sys_notifications(user, filter) - - assert sys_notification |> is_valid_pagination?(:raw) - assert sys_notification |> Map.get(:total_count) == 10 - end - - test "user can fetch sys notifications and store in own mail-box" do - {:ok, user} = db_insert(:user) - - mock_sys_notification(3) - - filter = %{page: 1, size: 20, read: false} - {:ok, sys_notifications} = Accounts.fetch_sys_notifications(user, filter) - - {:ok, sys_notification_mails} = - SysNotificationMail - |> where([m], m.user_id == ^user.id) - |> where([m], m.read == false) - |> ORM.paginater(page: 1, size: 10) - |> done() - - sys_notification_ids = - sys_notifications.entries - |> Enum.reduce([], fn m, acc -> - acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) - end) - - sys_notification_mail_ids = - sys_notification_mails.entries - |> Enum.reduce([], fn m, acc -> - acc |> Enum.concat([m |> Map.from_struct() |> Map.get(:id)]) - end) - - assert Enum.sort(sys_notification_ids) == Enum.sort(sys_notification_mail_ids) - end - - test "store user fetch info in delivery records, with last_fetch_time info" do - {:ok, user} = db_insert(:user) - - mock_sys_notification(2) - - filter = %{page: 1, size: 20, read: false} - {:ok, sys_notifications} = Accounts.fetch_sys_notifications(user, filter) - {:ok, record} = Delivery.fetch_record(user) - - latest_insert_time = - sys_notifications.entries |> List.first() |> Map.get(:inserted_at) |> to_string - - record_last_fetch_time = - record |> Map.get(:sys_notifications_record) |> Map.get("last_fetch_time") - - assert latest_insert_time == record_last_fetch_time - end - - test "user can mark one sys notifications as read" do - {:ok, user} = db_insert(:user) - - mock_sys_notification(3) - - filter = %{page: 1, size: 20, read: false} - {:ok, sys_notifications} = Accounts.fetch_sys_notifications(user, filter) - assert sys_notifications.total_count == 3 - - first_sys_notification = sys_notifications.entries |> List.first() - Accounts.mark_mail_read(first_sys_notification, user) - - filter = %{page: 1, size: 20, read: false} - {:ok, sys_notifications} = Accounts.fetch_sys_notifications(user, filter) - assert sys_notifications.total_count == 2 - - filter = %{page: 1, size: 20, read: true} - {:ok, sys_notifications} = Accounts.fetch_sys_notifications(user, filter) - assert sys_notifications.total_count == 1 - end - end -end From 43d33157eeeb4bc9547656c0c1cf32a188be5d8e Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 21 Jun 2021 18:24:28 +0800 Subject: [PATCH 44/54] refactor(notify): remove mention parse when create article --- lib/groupher_server/cms/delegates/article_curd.ex | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/groupher_server/cms/delegates/article_curd.ex b/lib/groupher_server/cms/delegates/article_curd.ex index a0100d637..5338af41a 100644 --- a/lib/groupher_server/cms/delegates/article_curd.ex +++ b/lib/groupher_server/cms/delegates/article_curd.ex @@ -14,7 +14,7 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do import ShortMaps alias Helper.{Later, ORM, QueryBuilder, Converter} - alias GroupherServer.{Accounts, CMS, Delivery, Email, Repo, Statistics} + alias GroupherServer.{Accounts, CMS, Email, Repo, Statistics} alias Accounts.Model.User alias CMS.Model.{Author, Community, PinnedArticle, Embeds} @@ -176,11 +176,6 @@ defmodule GroupherServer.CMS.Delegate.ArticleCURD do Later.run({Hooks.Mention, :handle, [article]}) Later.run({__MODULE__, :notify_admin_new_article, [article]}) end) - |> Multi.run(:mention_users, fn _, %{create_article: article} -> - # article.body |> Jason.decode!() |> 各种小 task - Delivery.mention_from_content(community.raw, thread, article, attrs, %User{id: uid}) - {:ok, :pass} - end) |> Multi.run(:log_action, fn _, _ -> Statistics.log_publish_action(%User{id: uid}) end) From aa80d1a7102bd2dbdde92d3286f6039cf12de4fc Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 21 Jun 2021 22:18:26 +0800 Subject: [PATCH 45/54] refactor(notify): refactor account mailbox tests --- lib/groupher_server/accounts/accounts.ex | 1 + .../accounts/delegates/mailbox.ex | 11 +- .../accounts/models/embeds/user_mailbox.ex | 13 +- .../delivery/delegates/mention.ex | 6 + .../delivery/delegates/notification.ex | 61 +++- .../resolvers/accounts_resolver.ex | 7 +- .../resolvers/delivery_resolver.ex | 18 - lib/groupher_server_web/schema.ex | 10 +- .../schema/account/account_queries.ex | 16 +- .../schema/account/account_types.ex | 35 +- .../schema/cms/mutations/comment.ex | 2 - .../schema/cms/mutations/job.ex | 1 - .../schema/cms/mutations/post.ex | 1 - .../schema/delivery/delivery_mutations.ex | 36 -- .../schema/delivery/delivery_queries.ex | 15 - .../schema/delivery/delivery_types.ex | 92 ----- test/groupher_server/accounts/mailbx_test.exs | 8 + .../mutation/cms/articles/job_test.exs | 32 +- .../mutation/cms/articles/post_test.exs | 29 +- .../mutation/delivery/delivery_test.exs | 327 ------------------ .../query/accounts/mailbox_test.exs | 158 +++++++++ .../query/accounts/mention_test.exs | 97 ------ .../query/accounts/messages_test.exs | 146 -------- test/support/factory.ex | 49 +-- 24 files changed, 259 insertions(+), 912 deletions(-) delete mode 100644 lib/groupher_server_web/resolvers/delivery_resolver.ex delete mode 100644 lib/groupher_server_web/schema/delivery/delivery_mutations.ex delete mode 100644 lib/groupher_server_web/schema/delivery/delivery_queries.ex delete mode 100644 lib/groupher_server_web/schema/delivery/delivery_types.ex delete mode 100644 test/groupher_server_web/mutation/delivery/delivery_test.exs create mode 100644 test/groupher_server_web/query/accounts/mailbox_test.exs delete mode 100644 test/groupher_server_web/query/accounts/mention_test.exs delete mode 100644 test/groupher_server_web/query/accounts/messages_test.exs diff --git a/lib/groupher_server/accounts/accounts.ex b/lib/groupher_server/accounts/accounts.ex index 47296d7b3..da43d0f61 100644 --- a/lib/groupher_server/accounts/accounts.ex +++ b/lib/groupher_server/accounts/accounts.ex @@ -62,6 +62,7 @@ defmodule GroupherServer.Accounts do # upvoted articles defdelegate paged_upvoted_articles(user_id, filter), to: UpvotedArticles + defdelegate mailbox_status(user), to: Mailbox defdelegate update_mailbox_status(user_id), to: Mailbox # customization diff --git a/lib/groupher_server/accounts/delegates/mailbox.ex b/lib/groupher_server/accounts/delegates/mailbox.ex index 8b9ff412e..3567dd181 100644 --- a/lib/groupher_server/accounts/delegates/mailbox.ex +++ b/lib/groupher_server/accounts/delegates/mailbox.ex @@ -1,10 +1,19 @@ defmodule GroupherServer.Accounts.Delegate.Mailbox do import Ecto.Query, warn: false + import Helper.Utils, only: [done: 1] + alias GroupherServer.{Accounts, Delivery} - alias Accounts.Model.User + + alias Accounts.Model.{Embeds, User} alias Helper.ORM + @default_mailbox_status Embeds.UserMailbox.default_status() + + def mailbox_status(%User{mailbox: nil}), do: @default_mailbox_status |> done + def mailbox_status(%User{mailbox: mailbox}), do: mailbox |> done + + @doc "update messages count in mailbox" def update_mailbox_status(user_id) do with {:ok, user} <- ORM.find(User, user_id), {:ok, unread_mentions_count} <- Delivery.unread_count(:mention, user_id), diff --git a/lib/groupher_server/accounts/models/embeds/user_mailbox.ex b/lib/groupher_server/accounts/models/embeds/user_mailbox.ex index a5da1655a..3e3527464 100644 --- a/lib/groupher_server/accounts/models/embeds/user_mailbox.ex +++ b/lib/groupher_server/accounts/models/embeds/user_mailbox.ex @@ -7,10 +7,19 @@ defmodule GroupherServer.Accounts.Model.Embeds.UserMailbox do import Ecto.Changeset - @optional_fields ~w(reported_count)a + @optional_fields ~w(is_empty unread_total_count unread_mentions_count unread_notifications_count)a + + def default_status() do + %{ + is_empty: true, + unread_total_count: 0, + unread_mentions_count: 0, + unread_notifications_count: 0 + } + end embedded_schema do - field(:is_empty, :boolean, default: false) + field(:is_empty, :boolean, default: true) field(:unread_total_count, :integer, default: 0) field(:unread_mentions_count, :integer, default: 0) field(:unread_notifications_count, :integer, default: 0) diff --git a/lib/groupher_server/delivery/delegates/mention.ex b/lib/groupher_server/delivery/delegates/mention.ex index 8b3cc6382..de63b5a8d 100644 --- a/lib/groupher_server/delivery/delegates/mention.ex +++ b/lib/groupher_server/delivery/delegates/mention.ex @@ -37,6 +37,9 @@ defmodule GroupherServer.Delivery.Delegate.Mention do false -> {:error, "insert mentions error"} end end) + |> Multi.run(:update_user_mailbox_status, fn _, _ -> + Enum.each(mentions, &Accounts.update_mailbox_status(&1.to_user_id)) |> done + end) |> Repo.transaction() |> result() end @@ -58,6 +61,9 @@ defmodule GroupherServer.Delivery.Delegate.Mention do false -> {:error, "insert mentions error"} end end) + |> Multi.run(:update_user_mailbox_status, fn _, _ -> + Enum.each(mentions, &Accounts.update_mailbox_status(&1.to_user_id)) |> done + end) |> Repo.transaction() |> result() end diff --git a/lib/groupher_server/delivery/delegates/notification.ex b/lib/groupher_server/delivery/delegates/notification.ex index 297add94e..4ba1dc05f 100644 --- a/lib/groupher_server/delivery/delegates/notification.ex +++ b/lib/groupher_server/delivery/delegates/notification.ex @@ -12,7 +12,9 @@ defmodule GroupherServer.Delivery.Delegate.Notification do alias GroupherServer.{Accounts, Delivery, Repo} alias Delivery.Model.Notification alias Accounts.Model.User + alias Helper.ORM + alias Ecto.Multi @notify_actions get_config(:general, :nofity_actions) @notify_group_interval_hour get_config(:general, :notify_group_interval_hour) @@ -21,12 +23,23 @@ defmodule GroupherServer.Delivery.Delegate.Notification do with true <- action in @notify_actions, true <- is_valid?(attrs), true <- user_id !== from_user.id do - from_user = from_user |> Map.take([:login, :nickname]) |> Map.put(:user_id, from_user.id) - - case find_exist_notify(attrs, :latest_peroid) do - {:ok, notify} -> merge_notification(notify, from_user) - {:error, _} -> create_notification(attrs, from_user) - end + Multi.new() + |> Multi.run(:upsert_notifications, fn _, _ -> + from_user = + from_user + |> Map.take([:login, :nickname]) + |> Map.put(:user_id, from_user.id) + + case find_exist_notify(attrs, :latest_peroid) do + {:ok, notify} -> merge_notification(notify, from_user) + {:error, _} -> create_notification(attrs, from_user) + end + end) + |> Multi.run(:update_user_mailbox_status, fn _, %{upsert_notifications: nofity} -> + Accounts.update_mailbox_status(nofity.user_id) + end) + |> Repo.transaction() + |> result() else false -> {:error, "invalid args for notification"} error -> error @@ -38,19 +51,27 @@ defmodule GroupherServer.Delivery.Delegate.Notification do attrs = attrs |> Map.put(:from_user, from_user) with {:ok, notifications} <- find_exist_notify(attrs, :all) do - Enum.each(notifications, fn notify -> - case length(notify.from_users) == 1 do - # 只有一就删除记录 - true -> - ORM.delete(notify) - - # 如果是多人集合就在 from_users 中删除该用户 - false -> - from_users = Enum.reject(notify.from_users, &(&1.login == from_user.login)) - notify |> ORM.update_embed(:from_users, from_users) - end + Multi.new() + |> Multi.run(:revoke_notifications, fn _, _ -> + Enum.each(notifications, fn notify -> + case length(notify.from_users) == 1 do + # 只有一就删除记录 + true -> + ORM.delete(notify) + + # 如果是多人集合就在 from_users 中删除该用户 + false -> + from_users = Enum.reject(notify.from_users, &(&1.login == from_user.login)) + notify |> ORM.update_embed(:from_users, from_users) + end + end) + |> done end) - |> done + |> Multi.run(:update_user_mailbox_status, fn _, _ -> + Enum.each(notifications, &Accounts.update_mailbox_status(&1.to_user_id)) |> done + end) + |> Repo.transaction() + |> result() else false -> {:ok, :pass} {:error, _} -> {:ok, :pass} @@ -191,4 +212,8 @@ defmodule GroupherServer.Delivery.Delegate.Notification do defp interval_threshold_time() do Timex.shift(Timex.now(), hours: -@notify_group_interval_hour) end + + defp result({:ok, %{upsert_notifications: result}}), do: {:ok, result} + defp result({:ok, %{revoke_notifications: result}}), do: {:ok, result} + defp result({:error, _, result, _steps}), do: {:error, result} end diff --git a/lib/groupher_server_web/resolvers/accounts_resolver.ex b/lib/groupher_server_web/resolvers/accounts_resolver.ex index 888d09b96..b0cf0dd0f 100644 --- a/lib/groupher_server_web/resolvers/accounts_resolver.ex +++ b/lib/groupher_server_web/resolvers/accounts_resolver.ex @@ -220,8 +220,7 @@ defmodule GroupherServerWeb.Resolvers.Accounts do Accounts.paged_editable_communities(cur_user, filter) end - # TODO: refactor - def get_mail_box_status(_root, _args, %{context: %{cur_user: cur_user}}) do + def mailbox_status(_root, _args, %{context: %{cur_user: cur_user}}) do Accounts.mailbox_status(cur_user) end @@ -243,10 +242,6 @@ defmodule GroupherServerWeb.Resolvers.Accounts do Accounts.fetch_notifications(cur_user, filter) end - def fetch_sys_notifications(_root, %{filter: filter}, %{context: %{cur_user: cur_user}}) do - Accounts.fetch_sys_notifications(cur_user, filter) - end - def mark_notification_read(_root, %{id: id}, %{context: %{cur_user: cur_user}}) do Accounts.mark_mail_read(%NotificationMail{id: id}, cur_user) end diff --git a/lib/groupher_server_web/resolvers/delivery_resolver.ex b/lib/groupher_server_web/resolvers/delivery_resolver.ex deleted file mode 100644 index c38f9570d..000000000 --- a/lib/groupher_server_web/resolvers/delivery_resolver.ex +++ /dev/null @@ -1,18 +0,0 @@ -defmodule GroupherServerWeb.Resolvers.Delivery do - @moduledoc false - - alias GroupherServer.{Accounts, Delivery} - - alias Accounts.Model.User - - def mention_others(_root, args, %{context: %{cur_user: cur_user}}) do - from_user_id = cur_user.id - user_ids = args.user_ids - - Delivery.mention_others(%User{id: from_user_id}, user_ids, args) - end - - def publish_system_notification(_root, args, %{context: %{cur_user: _}}) do - Delivery.publish_system_notification(args) - end -end diff --git a/lib/groupher_server_web/schema.ex b/lib/groupher_server_web/schema.ex index 7826f24eb..04a704945 100644 --- a/lib/groupher_server_web/schema.ex +++ b/lib/groupher_server_web/schema.ex @@ -7,7 +7,7 @@ defmodule GroupherServerWeb.Schema do import GroupherServerWeb.Schema.Helper.Imports alias GroupherServerWeb.Middleware, as: M - alias GroupherServerWeb.Schema.{Account, Billing, CMS, Delivery, Statistics, Helper} + alias GroupherServerWeb.Schema.{Account, Billing, CMS, Statistics, Helper} import_types(Absinthe.Type.Custom) @@ -29,11 +29,6 @@ defmodule GroupherServerWeb.Schema do import_types(Statistics.Queries) import_types(Statistics.Mutations) - # delivery - import_types(Delivery.Types) - import_types(Delivery.Queries) - import_types(Delivery.Mutations) - # cms import_types(CMS.Types) import_types(CMS.Queries) @@ -48,7 +43,6 @@ defmodule GroupherServerWeb.Schema do import_fields(:account_queries) import_fields(:billing_queries) import_fields(:statistics_queries) - import_fields(:delivery_queries) import_fields(:cms_queries) end @@ -59,8 +53,6 @@ defmodule GroupherServerWeb.Schema do import_fields(:billing_mutations) # statistics import_fields(:statistics_mutations) - # delivery - import_fields(:delivery_mutations) # cms import_fields(:cms_mutation_community) import_fields(:cms_opertion_mutations) diff --git a/lib/groupher_server_web/schema/account/account_queries.ex b/lib/groupher_server_web/schema/account/account_queries.ex index fcfa4541c..34e231d6a 100644 --- a/lib/groupher_server_web/schema/account/account_queries.ex +++ b/lib/groupher_server_web/schema/account/account_queries.ex @@ -35,14 +35,14 @@ defmodule GroupherServerWeb.Schema.Account.Queries do resolve(&R.Accounts.subscribed_communities/3) end - @desc "get user's mentions" - field :mentions, :paged_mentions do - arg(:filter, :messages_filter) - - middleware(M.Authorize, :login) - middleware(M.PageSizeProof) - resolve(&R.Accounts.fetch_mentions/3) - end + # @desc "get user's mentions" + # field :mentions, :paged_mentions do + # arg(:filter, :messages_filter) + + # middleware(M.Authorize, :login) + # middleware(M.PageSizeProof) + # resolve(&R.Accounts.fetch_mentions/3) + # end @desc "get user's follower" field :paged_followers, :paged_users do diff --git a/lib/groupher_server_web/schema/account/account_types.ex b/lib/groupher_server_web/schema/account/account_types.ex index b79f417ba..1d8dbd4f5 100644 --- a/lib/groupher_server_web/schema/account/account_types.ex +++ b/lib/groupher_server_web/schema/account/account_types.ex @@ -82,38 +82,21 @@ defmodule GroupherServerWeb.Schema.Account.Types do # 3. has_notifications ? # 4. has_watches ? - field :mail_box, :mail_box_status do + field :mailbox, :mailbox_status do middleware(M.Authorize, :login) - resolve(&R.Accounts.get_mail_box_status/3) - end - - field :mentions, :paged_mentions do - arg(:filter, :messages_filter) - - middleware(M.Authorize, :login) - middleware(M.PageSizeProof) - resolve(&R.Accounts.fetch_mentions/3) - end - - field :notifications, :paged_notifications do - arg(:filter, :messages_filter) - - middleware(M.Authorize, :login) - middleware(M.PageSizeProof) - resolve(&R.Accounts.fetch_notifications/3) - end - - field :sys_notifications, :paged_sys_notifications do - arg(:filter, :messages_filter) - - middleware(M.Authorize, :login) - middleware(M.PageSizeProof) - resolve(&R.Accounts.fetch_sys_notifications/3) + resolve(&R.Accounts.mailbox_status/3) end timestamp_fields() end + object :mailbox_status do + field(:is_empty, :boolean) + field(:unread_total_count, :integer) + field(:unread_mentions_count, :integer) + field(:unread_notifications_count, :integer) + end + # field(:sidebar_layout, :map) object :customization do field(:theme, :string) diff --git a/lib/groupher_server_web/schema/cms/mutations/comment.ex b/lib/groupher_server_web/schema/cms/mutations/comment.ex index f35ba6b7f..1005f26e4 100644 --- a/lib/groupher_server_web/schema/cms/mutations/comment.ex +++ b/lib/groupher_server_web/schema/cms/mutations/comment.ex @@ -11,7 +11,6 @@ defmodule GroupherServerWeb.Schema.CMS.Mutations.Comment do 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) @@ -24,7 +23,6 @@ defmodule GroupherServerWeb.Schema.CMS.Mutations.Comment do field :update_comment, :comment do arg(:id, non_null(:id)) arg(:body, non_null(:string)) - # arg(:mention_users, list_of(:ids)) middleware(M.Authorize, :login) middleware(M.PassportLoader, source: :comment) diff --git a/lib/groupher_server_web/schema/cms/mutations/job.ex b/lib/groupher_server_web/schema/cms/mutations/job.ex index 08c98e429..40031999d 100644 --- a/lib/groupher_server_web/schema/cms/mutations/job.ex +++ b/lib/groupher_server_web/schema/cms/mutations/job.ex @@ -22,7 +22,6 @@ defmodule GroupherServerWeb.Schema.CMS.Mutations.Job do arg(:thread, :thread, default_value: :job) arg(:article_tags, list_of(:ids)) - arg(:mention_users, list_of(:ids)) middleware(M.Authorize, :login) middleware(M.PublishThrottle) diff --git a/lib/groupher_server_web/schema/cms/mutations/post.ex b/lib/groupher_server_web/schema/cms/mutations/post.ex index 059f238d3..fab287082 100644 --- a/lib/groupher_server_web/schema/cms/mutations/post.ex +++ b/lib/groupher_server_web/schema/cms/mutations/post.ex @@ -18,7 +18,6 @@ defmodule GroupherServerWeb.Schema.CMS.Mutations.Post do arg(:community_id, non_null(:id)) arg(:thread, :thread, default_value: :post) arg(:article_tags, list_of(:ids)) - arg(:mention_users, list_of(:ids)) middleware(M.Authorize, :login) # middleware(M.PublishThrottle) diff --git a/lib/groupher_server_web/schema/delivery/delivery_mutations.ex b/lib/groupher_server_web/schema/delivery/delivery_mutations.ex deleted file mode 100644 index 555c14675..000000000 --- a/lib/groupher_server_web/schema/delivery/delivery_mutations.ex +++ /dev/null @@ -1,36 +0,0 @@ -defmodule GroupherServerWeb.Schema.Delivery.Mutations do - @moduledoc """ - Delivery.Mutations - """ - use Helper.GqlSchemaSuite - - object :delivery_mutations do - field :mention_others, :status do - arg(:user_ids, non_null(list_of(:ids))) - - arg(:source_id, non_null(:id)) - arg(:source_title, non_null(:string)) - arg(:source_type, non_null(:string)) - arg(:source_preview, non_null(:string)) - arg(:community, non_null(:string)) - arg(:parent_id, :id) - arg(:parent_type, :string) - - middleware(M.Authorize, :login) - resolve(&R.Delivery.mention_others/3) - end - - field :publish_system_notification, :status do - arg(:source_id, non_null(:id)) - arg(:source_title, non_null(:string)) - arg(:source_type, non_null(:string)) - arg(:source_preview, :string) - - middleware(M.Authorize, :login) - # TODO: use delivery passport system instead of cms's - middleware(M.Passport, claim: "cms->system_notification.publish") - - resolve(&R.Delivery.publish_system_notification/3) - end - end -end diff --git a/lib/groupher_server_web/schema/delivery/delivery_queries.ex b/lib/groupher_server_web/schema/delivery/delivery_queries.ex deleted file mode 100644 index c78649dd9..000000000 --- a/lib/groupher_server_web/schema/delivery/delivery_queries.ex +++ /dev/null @@ -1,15 +0,0 @@ -defmodule GroupherServerWeb.Schema.Delivery.Queries do - @moduledoc """ - Delivery.Queries - """ - use Helper.GqlSchemaSuite - - object :delivery_queries do - @desc "get mention list?" - field :xxxx_todo, :boolean do - arg(:id, non_null(:id)) - - resolve(&R.Delivery.mention_others/3) - end - end -end diff --git a/lib/groupher_server_web/schema/delivery/delivery_types.ex b/lib/groupher_server_web/schema/delivery/delivery_types.ex deleted file mode 100644 index 138e55dec..000000000 --- a/lib/groupher_server_web/schema/delivery/delivery_types.ex +++ /dev/null @@ -1,92 +0,0 @@ -defmodule GroupherServerWeb.Schema.Delivery.Types do - use Absinthe.Schema.Notation - - import GroupherServerWeb.Schema.Helper.Fields - import Helper.Utils, only: [get_config: 2] - - @page_size get_config(:general, :page_size) - - object :mail_box_status do - field(:has_mail, :boolean) - field(:total_count, :integer) - field(:mention_count, :integer) - field(:notification_count, :integer) - end - - object :mention do - field(:id, :id) - field(:from_user_id, :id) - field(:to_user_id, :id) - field(:from_user, :user) - field(:to_user, :user) - - field(:source_title, :string) - field(:source_id, :string) - field(:source_preview, :string) - field(:source_type, :string) - - field(:parent_id, :string) - field(:parent_type, :string) - field(:floor, :integer) - - field(:community, :string) - field(:read, :boolean) - end - - # object :sys_notification do - # field(:id, :id) - - # field(:source_id, :string) - # field(:source_title, :string) - # field(:source_preview, :string) - # field(:source_type, :string) - - # field(:read, :boolean) - # end - - object :notification do - field(:id, :id) - field(:from_user_id, :id) - field(:to_user_id, :id) - field(:action, :string) - - field(:source_id, :string) - field(:source_title, :string) - field(:source_preview, :string) - field(:source_type, :string) - field(:read, :boolean) - end - - object :sys_notification do - field(:id, :id) - field(:user_id, :id) - - field(:source_id, :string) - field(:source_title, :string) - field(:source_preview, :string) - field(:source_type, :string) - field(:read, :boolean) - end - - object :paged_mentions do - field(:entries, list_of(:mention)) - pagination_fields() - end - - object :paged_notifications do - field(:entries, list_of(:notification)) - pagination_fields() - end - - object :paged_sys_notifications do - field(:entries, list_of(:sys_notification)) - pagination_fields() - end - - input_object :messages_filter do - field(:read, :boolean, default_value: false) - - field(:page, :integer, default_value: 1) - field(:size, :integer, default_value: @page_size) - end -end diff --git a/test/groupher_server/accounts/mailbx_test.exs b/test/groupher_server/accounts/mailbx_test.exs index ee37990c8..57ecaa4ce 100644 --- a/test/groupher_server/accounts/mailbx_test.exs +++ b/test/groupher_server/accounts/mailbx_test.exs @@ -5,6 +5,8 @@ defmodule GroupherServer.Test.Accounts.Mailbox do alias GroupherServer.{Accounts, Delivery} + @default_mailbox_status Accounts.Model.Embeds.UserMailbox.default_status() + setup do {:ok, post} = db_insert(:post) {:ok, user} = db_insert(:user) @@ -15,6 +17,12 @@ defmodule GroupherServer.Test.Accounts.Mailbox do end describe "mailbox status" do + @tag :wip + test "can get default mailbox status", ~m(user)a do + {:ok, status} = Accounts.mailbox_status(user) + assert status == @default_mailbox_status + end + test "can get mailbox status", ~m(post user user2)a do notify_attrs = %{ thread: :post, diff --git a/test/groupher_server_web/mutation/cms/articles/job_test.exs b/test/groupher_server_web/mutation/cms/articles/job_test.exs index 1e3f6ad57..e8ebcd078 100644 --- a/test/groupher_server_web/mutation/cms/articles/job_test.exs +++ b/test/groupher_server_web/mutation/cms/articles/job_test.exs @@ -2,7 +2,7 @@ defmodule GroupherServer.Test.Mutation.Articles.Job do use GroupherServer.TestTools alias Helper.ORM - alias GroupherServer.{CMS, Delivery} + alias GroupherServer.CMS alias CMS.Model.Job @@ -26,7 +26,6 @@ defmodule GroupherServer.Test.Mutation.Articles.Job do $length: Int!, $communityId: ID!, $company: String!, - $mentionUsers: [Ids], $articleTags: [Ids] ) { createJob( @@ -36,7 +35,6 @@ defmodule GroupherServer.Test.Mutation.Articles.Job do length: $length, communityId: $communityId, company: $company, - mentionUsers: $mentionUsers, articleTags: $articleTags ) { id @@ -100,34 +98,6 @@ defmodule GroupherServer.Test.Mutation.Articles.Job do assert String.contains?(job.body_html, "<script>blackmail</script>") end - test "can create job with mentionUsers" do - {:ok, user} = db_insert(:user) - {:ok, user2} = db_insert(:user) - user_conn = simu_conn(:user, user) - - {:ok, community} = db_insert(:community) - job_attr = mock_attrs(:job) - - variables = - job_attr - |> camelize_map_key - |> Map.merge(%{communityId: community.id}) - |> 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_job_query, variables, "createJob") - - {:ok, mentions} = Delivery.fetch_mentions(user2, filter) - the_mention = mentions.entries |> List.first() - - assert mentions.total_count == 1 - assert the_mention.source_type == "job" - assert the_mention.read == false - end - @query """ mutation($id: ID!, $title: String, $body: String, $articleTags: [Ids]){ updateJob(id: $id, title: $title, body: $body, articleTags: $articleTags) { diff --git a/test/groupher_server_web/mutation/cms/articles/post_test.exs b/test/groupher_server_web/mutation/cms/articles/post_test.exs index b2a35349b..d6c11174d 100644 --- a/test/groupher_server_web/mutation/cms/articles/post_test.exs +++ b/test/groupher_server_web/mutation/cms/articles/post_test.exs @@ -2,7 +2,7 @@ defmodule GroupherServer.Test.Mutation.Articles.Post do use GroupherServer.TestTools alias Helper.ORM - alias GroupherServer.{CMS, Delivery} + alias GroupherServer.CMS alias CMS.Model.{Post, Author} @@ -26,7 +26,6 @@ defmodule GroupherServer.Test.Mutation.Articles.Post do $length: Int! $communityId: ID! $articleTags: [Ids] - $mentionUsers: [Ids] ) { createPost( title: $title @@ -35,7 +34,6 @@ defmodule GroupherServer.Test.Mutation.Articles.Post do length: $length communityId: $communityId articleTags: $articleTags - mentionUsers: $mentionUsers ) { title body @@ -104,31 +102,6 @@ defmodule GroupherServer.Test.Mutation.Articles.Post do assert user_conn |> mutation_get_error?(@create_post_query, variables) end - test "can create post with mentionUsers" do - {:ok, user} = db_insert(:user) - {:ok, user2} = db_insert(:user) - user_conn = simu_conn(:user, user) - - {:ok, community} = db_insert(:community) - post_attr = mock_attrs(:post) - - variables = - post_attr - |> Map.merge(%{communityId: community.id}) - |> 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_post_query, variables, "createPost") - - {:ok, mentions} = Delivery.fetch_mentions(user2, filter) - - assert mentions.total_count == 1 - assert mentions.entries |> List.first() |> Map.get(:community) !== nil - end - @query """ mutation($id: ID!){ deletePost(id: $id) { diff --git a/test/groupher_server_web/mutation/delivery/delivery_test.exs b/test/groupher_server_web/mutation/delivery/delivery_test.exs deleted file mode 100644 index c7a18f8e6..000000000 --- a/test/groupher_server_web/mutation/delivery/delivery_test.exs +++ /dev/null @@ -1,327 +0,0 @@ -defmodule GroupherServer.Test.Mutation.Delivery do - use GroupherServer.TestTools - - alias GroupherServer.Accounts - - setup do - {:ok, user} = db_insert(:user) - - user_conn = simu_conn(:user) - guest_conn = simu_conn(:guest) - - {:ok, ~m(user_conn guest_conn user)a} - end - - @account_query """ - query($login: String, $filter: MessagesFilter!) { - user(login: $login) { - id - mentions(filter: $filter) { - entries { - id - fromUserId - toUserId - read - } - totalCount - } - notifications(filter: $filter) { - entries { - id - fromUserId - toUserId - read - } - totalCount - } - sysNotifications(filter: $filter) { - entries { - id - read - } - totalCount - } - } - } - """ - - describe "[delivery system notification]" do - @query """ - mutation($sourceTitle: String!, $sourceId: ID!, $sourceType: String!) { - publishSystemNotification(sourceTitle: $sourceTitle, sourceId: $sourceId ,sourceType: $sourceType) { - done - } - } - """ - - test "auth user can publish system notifications" do - {:ok, user} = db_insert(:user) - - passport_rules = %{"system_notification.publish" => true} - # middleware(M.Passport, claim: "cms->editor.set") - rule_conn = simu_conn(:user, cms: passport_rules) - - user_conn = simu_conn(:user, user) - - variables = %{ - sourceId: "1", - sourceTitle: "fake post title", - sourceType: "post" - } - - %{"done" => true} = - rule_conn |> mutation_result(@query, variables, "publishSystemNotification") - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - result = user_conn |> query_result(@account_query, variables, "user") - sys_notifications = result["sysNotifications"] - - assert sys_notifications["totalCount"] == 1 - end - - test "unauth user publish system notification fails", ~m(user_conn guest_conn)a do - variables = %{ - sourceId: "1", - sourceTitle: "fake post title", - sourceType: "post" - } - - 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!) { - markSysNotificationRead(id: $id) { - id - } - } - """ - - test "auth user can mark a system notification as read" do - {:ok, user} = db_insert(:user) - user_conn = simu_conn(:user, user) - - mock_sys_notification(3) - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - - result = user_conn |> query_result(@account_query, variables, "user") - - notifications = result["sysNotifications"] - assert notifications["totalCount"] == 3 - - first_notification_id = notifications["entries"] |> List.first() |> Map.get("id") - variables = %{id: first_notification_id} - - user_conn |> mutation_result(@query, variables, "markSysNotificationRead") - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - result = user_conn |> query_result(@account_query, variables, "user") - - notifications = result["sysNotifications"] - assert notifications["totalCount"] == 2 - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: true}} - - result = user_conn |> query_result(@account_query, variables, "user") - notifications = result["sysNotifications"] - assert notifications["totalCount"] == 1 - end - end - - describe "[delivery mutations]" do - @query """ - mutation( - $userIds: [Ids]! - $sourceTitle: String! - $sourceId: ID! - $sourceType: String! - $sourcePreview: String! - $community: String! - ) { - mentionOthers( - userIds: $userIds - sourceTitle: $sourceTitle - sourceId: $sourceId - sourceType: $sourceType - sourcePreview: $sourcePreview - community: $community - ) { - done - } - } - """ - test "login user can mention other user" do - {:ok, user} = db_insert(:user) - {:ok, user2} = db_insert(:user) - - user_conn = simu_conn(:user, user) - - variables = %{ - sourceId: "1", - sourceTitle: "fake post title", - sourceType: "post", - sourcePreview: "preview", - community: "elixir", - userIds: [%{id: user2.id}] - } - - user_conn |> mutation_result(@query, variables, "mentionOthers") - filter = %{page: 1, size: 20, read: false} - {:ok, mentions} = Accounts.fetch_mentions(user2, filter) - - assert mentions.entries |> List.first() |> Map.get(:source_title) == variables.sourceTitle - assert mentions.entries |> List.first() |> Map.get(:from_user_id) == user.id - assert mentions.entries |> List.first() |> Map.get(:community) == "elixir" - end - - test "unauth user send mention fails", ~m(guest_conn)a do - {:ok, user2} = db_insert(:user) - - variables = %{ - sourceId: "1", - sourceTitle: "fake post title", - sourceType: "post", - sourcePreview: "preview", - community: "elixir", - userIds: [%{id: user2.id}] - } - - assert guest_conn |> mutation_get_error?(@query, variables, ecode(:account_login)) - end - - @query """ - mutation($id: ID!) { - markMentionRead(id: $id) { - id - } - } - """ - - test "user can mark a mention as read" do - {:ok, user} = db_insert(:user) - user_conn = simu_conn(:user, user) - - mock_mentions_for(user, 3) - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - - result = user_conn |> query_result(@account_query, variables, "user") - mentions = result["mentions"] - assert mentions["totalCount"] == 3 - - first_mention_id = mentions["entries"] |> List.first() |> Map.get("id") - variables = %{id: first_mention_id} - - user_conn |> mutation_result(@query, variables, "markMentionRead") - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - - result = user_conn |> query_result(@account_query, variables, "user") - mentions = result["mentions"] - assert mentions["totalCount"] == 2 - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: true}} - - result = user_conn |> query_result(@account_query, variables, "user") - mentions = result["mentions"] - assert mentions["totalCount"] == 1 - end - - @query """ - mutation { - markMentionReadAll { - done - } - } - """ - - test "user can mark all unread mentions as read" do - {:ok, user} = db_insert(:user) - user_conn = simu_conn(:user, user) - - mock_mentions_for(user, 3) - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - result = user_conn |> query_result(@account_query, variables, "user") - mentions = result["mentions"] - assert mentions["totalCount"] == 3 - - user_conn |> mutation_result(@query, %{}, "markMentionReadAll") - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - result = user_conn |> query_result(@account_query, variables, "user") - mentions = result["mentions"] - - assert mentions["totalCount"] == 0 - end - - @query """ - mutation($id: ID!) { - markNotificationRead(id: $id) { - id - } - } - """ - - test "user can mark a notification as read" do - {:ok, user} = db_insert(:user) - user_conn = simu_conn(:user, user) - - mock_notifications_for(user, 3) - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - - result = user_conn |> query_result(@account_query, variables, "user") - - notifications = result["notifications"] - assert notifications["totalCount"] == 3 - - first_notification_id = notifications["entries"] |> List.first() |> Map.get("id") - variables = %{id: first_notification_id} - - user_conn |> mutation_result(@query, variables, "markNotificationRead") - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - result = user_conn |> query_result(@account_query, variables, "user") - - notifications = result["notifications"] - assert notifications["totalCount"] == 2 - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: true}} - - result = user_conn |> query_result(@account_query, variables, "user") - notifications = result["notifications"] - assert notifications["totalCount"] == 1 - end - - @query """ - mutation { - markNotificationReadAll { - done - } - } - """ - - test "user can mark all unread notifications as read" do - {:ok, user} = db_insert(:user) - user_conn = simu_conn(:user, user) - - mock_notifications_for(user, 3) - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - result = user_conn |> query_result(@account_query, variables, "user") - notifications = result["notifications"] - assert notifications["totalCount"] == 3 - - user_conn |> mutation_result(@query, %{}, "markNotificationReadAll") - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - result = user_conn |> query_result(@account_query, variables, "user") - notifications = result["notifications"] - - assert notifications["totalCount"] == 0 - end - end -end diff --git a/test/groupher_server_web/query/accounts/mailbox_test.exs b/test/groupher_server_web/query/accounts/mailbox_test.exs new file mode 100644 index 000000000..4353c841c --- /dev/null +++ b/test/groupher_server_web/query/accounts/mailbox_test.exs @@ -0,0 +1,158 @@ +defmodule GroupherServer.Test.Query.Accounts.Mailbox do + use GroupherServer.TestTools + + alias GroupherServer.Delivery + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + + user_conn = simu_conn(:user) + guest_conn = simu_conn(:guest) + + {:ok, ~m(user_conn guest_conn user user2)a} + end + + defp mock_mention_for(user, from_user) do + {:ok, post} = db_insert(:post) + + mention_attr = %{ + thread: "POST", + title: post.title, + article_id: post.id, + comment_id: nil, + block_linker: ["tmp"], + inserted_at: post.updated_at |> DateTime.truncate(:second), + updated_at: post.updated_at |> DateTime.truncate(:second) + } + + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: from_user.id, to_user_id: user.id}) + ] + + Delivery.send(:mention, post, mention_contents, from_user) + end + + defp mock_nofity_for(user, from_user) do + {:ok, post} = db_insert(:post) + + notify_attrs = %{ + thread: :post, + article_id: post.id, + title: post.title, + action: :upvote, + user_id: user.id, + read: false + } + + Delivery.send(:notify, notify_attrs, from_user) + end + + describe "[accounts mailbox status]" do + @query """ + query($login: String!) { + user(login: $login) { + id + mailbox { + isEmpty + unreadTotalCount + unreadMentionsCount + unreadNotificationsCount + } + } + } + """ + @tag :wip + test "auth user can get it's own default mailbox status", ~m(user)a do + user_conn = simu_conn(:user, user) + + results = user_conn |> query_result(@query, %{login: user.login}, "user") + mailbox = results["mailbox"] + + assert mailbox["isEmpty"] == true + assert mailbox["unreadTotalCount"] == 0 + assert mailbox["unreadMentionsCount"] == 0 + assert mailbox["unreadNotificationsCount"] == 0 + end + + @tag :wip + test "auth user can get latest mailbox status after being mentioned", ~m(user user2)a do + {:ok, _} = mock_mention_for(user, user2) + + user_conn = simu_conn(:user, user) + + results = user_conn |> query_result(@query, %{login: user.login}, "user") + mailbox = results["mailbox"] + + assert mailbox["isEmpty"] == false + assert mailbox["unreadTotalCount"] == 1 + assert mailbox["unreadMentionsCount"] == 1 + assert mailbox["unreadNotificationsCount"] == 0 + end + + @tag :wip + test "auth user can get latest mailbox status after being notified", ~m(user user2)a do + mock_nofity_for(user, user2) + + user_conn = simu_conn(:user, user) + + results = user_conn |> query_result(@query, %{login: user.login}, "user") + mailbox = results["mailbox"] + + assert mailbox["isEmpty"] == false + assert mailbox["unreadTotalCount"] == 1 + assert mailbox["unreadMentionsCount"] == 0 + assert mailbox["unreadNotificationsCount"] == 1 + end + end + + # describe "[accounts mention]" do + # @query """ + # query($filter: MessagesFilter!) { + # mentions(filter: $filter) { + # entries { + # id + # fromUserId + # fromUser { + # id + # avatar + # nickname + # } + # toUserId + # toUser { + # id + # avatar + # nickname + # } + # sourceTitle + # sourcePreview + # sourceType + # community + # read + # } + # totalPages + # totalCount + # pageSize + # pageNumber + # } + # } + # """ + # test "auth user can get it's own mentions" do + # {:ok, [user, user2]} = db_insert_multi(:user, 2) + + # mock_mentions_for(user, 1) + # mock_mentions_for(user2, 1) + + # user_conn = simu_conn(:user, user) + + # variables = %{filter: %{page: 1, size: 20, read: false}} + # results = user_conn |> query_result(@query, variables, "mentions") + + # assert results |> is_valid_pagination? + # assert results["totalCount"] == 1 + + # assert results["entries"] |> Enum.any?(&(&1["toUserId"] == to_string(user.id))) + # assert results["entries"] |> Enum.any?(&(&1["community"] == "elixir")) + # end + # end +end diff --git a/test/groupher_server_web/query/accounts/mention_test.exs b/test/groupher_server_web/query/accounts/mention_test.exs deleted file mode 100644 index a05538020..000000000 --- a/test/groupher_server_web/query/accounts/mention_test.exs +++ /dev/null @@ -1,97 +0,0 @@ -defmodule GroupherServer.Test.Query.Accounts.OldMention do - use GroupherServer.TestTools - - # alias GroupherServer.Accounts - - setup do - {:ok, user} = db_insert(:user) - - user_conn = simu_conn(:user) - guest_conn = simu_conn(:guest) - - {:ok, ~m(user_conn guest_conn user)a} - end - - describe "[accounts mailbox status]" do - @query """ - query($login: String!) { - user(login: $login) { - id - mailBox { - hasMail - totalCount - mentionCount - notificationCount - } - } - } - """ - - test "auth user can get it's own mailbox status" do - {:ok, [user, user2]} = db_insert_multi(:user, 2) - - mock_mentions_for(user, 2) - mock_mentions_for(user2, 1) - - user_conn = simu_conn(:user, user) - - variables = %{login: user.login} - results = user_conn |> query_result(@query, variables, "user") - mail_Box = results["mailBox"] - - assert mail_Box["hasMail"] == true - assert mail_Box["mentionCount"] == 2 - assert mail_Box["totalCount"] == 2 - end - end - - describe "[accounts mention]" do - @query """ - query($filter: MessagesFilter!) { - mentions(filter: $filter) { - entries { - id - fromUserId - fromUser { - id - avatar - nickname - } - toUserId - toUser { - id - avatar - nickname - } - sourceTitle - sourcePreview - sourceType - community - read - } - totalPages - totalCount - pageSize - pageNumber - } - } - """ - test "auth user can get it's own mentions" do - {:ok, [user, user2]} = db_insert_multi(:user, 2) - - mock_mentions_for(user, 1) - mock_mentions_for(user2, 1) - - user_conn = simu_conn(:user, user) - - variables = %{filter: %{page: 1, size: 20, read: false}} - results = user_conn |> query_result(@query, variables, "mentions") - - assert results |> is_valid_pagination? - assert results["totalCount"] == 1 - - assert results["entries"] |> Enum.any?(&(&1["toUserId"] == to_string(user.id))) - assert results["entries"] |> Enum.any?(&(&1["community"] == "elixir")) - end - end -end diff --git a/test/groupher_server_web/query/accounts/messages_test.exs b/test/groupher_server_web/query/accounts/messages_test.exs deleted file mode 100644 index da5a68326..000000000 --- a/test/groupher_server_web/query/accounts/messages_test.exs +++ /dev/null @@ -1,146 +0,0 @@ -defmodule GroupherServer.Test.Query.Accounts.Messages do - use GroupherServer.TestTools - - # alias GroupherServer.{Accounts} - setup do - {:ok, user} = db_insert(:user) - - user_conn = simu_conn(:user) - guest_conn = simu_conn(:guest) - - {:ok, ~m(user_conn guest_conn user)a} - end - - describe "[account messages queries]" do - @query """ - query($login: String!) { - user(login: $login) { - id - mailBox { - hasMail - totalCount - mentionCount - notificationCount - } - } - } - """ - - test "login user can get mail box status" do - {:ok, user} = db_insert(:user) - user_conn = simu_conn(:user, user) - - result = user_conn |> query_result(@query, %{login: user.login}, "user") - mail_box = result["mailBox"] - assert mail_box["hasMail"] == false - assert mail_box["totalCount"] == 0 - assert mail_box["mentionCount"] == 0 - assert mail_box["notificationCount"] == 0 - - mock_mentions_for(user, 2) - mock_notifications_for(user, 18) - - result = user_conn |> query_result(@query, %{login: user.login}, "user") - mail_box = result["mailBox"] - assert mail_box["hasMail"] == true - assert mail_box["totalCount"] == 20 - assert mail_box["mentionCount"] == 2 - assert mail_box["notificationCount"] == 18 - end - - test "unauth user get mailBox status fails", ~m(guest_conn user)a do - variables = %{login: user.login} - - assert guest_conn |> query_get_error?(@query, variables, ecode(:account_login)) - end - - @query """ - query($login: String!, $filter: MessagesFilter!) { - user(login: $login) { - id - mentions(filter: $filter) { - entries { - id - fromUserId - toUserId - read - } - totalCount - } - notifications(filter: $filter) { - entries { - id - fromUserId - toUserId - read - } - totalCount - } - sysNotifications(filter: $filter) { - entries { - id - read - } - totalCount - } - } - } - """ - - test "user can get mentions send by others" do - {:ok, user} = db_insert(:user) - user_conn = simu_conn(:user, user) - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - result = user_conn |> query_result(@query, variables, "user") - mentions = result["mentions"] - assert mentions["totalCount"] == 0 - - mock_mentions_for(user, 3) - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - result = user_conn |> query_result(@query, variables, "user") - mentions = result["mentions"] - - assert mentions["totalCount"] == 3 - assert mentions["entries"] |> List.first() |> Map.get("toUserId") == to_string(user.id) - end - - test "user can get notifications send by others" do - {:ok, user} = db_insert(:user) - user_conn = simu_conn(:user, user) - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - result = user_conn |> query_result(@query, variables, "user") - notifications = result["notifications"] - assert notifications["totalCount"] == 0 - - mock_notifications_for(user, 3) - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - result = user_conn |> query_result(@query, variables, "user") - notifications = result["notifications"] - - assert notifications["totalCount"] == 3 - assert notifications["entries"] |> List.first() |> Map.get("toUserId") == to_string(user.id) - end - - test "user can get system notifications" do - {:ok, user} = db_insert(:user) - user_conn = simu_conn(:user, user) - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - result = user_conn |> query_result(@query, variables, "user") - notifications = result["sysNotifications"] - assert notifications["totalCount"] == 0 - - mock_sys_notification(5) - - variables = %{login: user.login, filter: %{page: 1, size: 20, read: false}} - result = user_conn |> query_result(@query, variables, "user") - notifications = result["sysNotifications"] - - assert notifications["totalCount"] == 5 - end - end -end diff --git a/test/support/factory.ex b/test/support/factory.ex index 93bac7d70..f5276102b 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -8,7 +8,7 @@ defmodule GroupherServer.Support.Factory do import Helper.Utils, only: [done: 1] import GroupherServer.CMS.Helper.Matcher - alias GroupherServer.{Accounts, CMS, Delivery} + alias GroupherServer.{Accounts, CMS} alias Accounts.Model.User alias CMS.Model.{ @@ -23,8 +23,6 @@ defmodule GroupherServer.Support.Factory do Comment } - alias Delivery.Model.{OldMention, SysNotification} - @default_article_meta CMS.Model.Embeds.ArticleMeta.default_meta() @default_emotions CMS.Model.Embeds.CommentEmotion.default_emotions() @@ -383,14 +381,10 @@ defmodule GroupherServer.Support.Factory do 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)) - defp mock(:mention), do: OldMention |> struct(mock_meta(:mention)) defp mock(:author), do: Author |> struct(mock_meta(:author)) defp mock(:category), do: Category |> struct(mock_meta(:category)) defp mock(:article_tag), do: ArticleTag |> struct(mock_meta(:article_tag)) - defp mock(:sys_notification), - do: SysNotification |> struct(mock_meta(:sys_notification)) - defp mock(:user), do: User |> struct(mock_meta(:user)) defp mock(:community), do: Community |> struct(mock_meta(:community)) defp mock(:thread), do: Thread |> struct(mock_meta(:thread)) @@ -427,47 +421,6 @@ defmodule GroupherServer.Support.Factory do results |> done end - def mock_sys_notification(count \\ 3) do - # {:ok, sys_notifications} = db_insert_multi(:sys_notification, count) - db_insert_multi(:sys_notification, count) - end - - def mock_mentions_for(%User{id: _to_user_id} = user, count \\ 3) do - {:ok, users} = db_insert_multi(:user, count) - - Enum.map(users, fn u -> - unique_num = System.unique_integer([:positive, :monotonic]) - - info = %{ - community: "elixir", - source_id: "1", - source_title: "Title #{unique_num}", - source_type: "post", - source_preview: "preview #{unique_num}" - } - - {:ok, _} = Delivery.mention_others(u, [%{id: user.id}], info) - end) - end - - def mock_notifications_for(%User{id: _to_user_id} = user, count \\ 3) do - {:ok, users} = db_insert_multi(:user, count) - - Enum.map(users, fn u -> - unique_num = System.unique_integer([:positive, :monotonic]) - - info = %{ - source_id: "1", - source_title: "Title #{unique_num}", - source_type: "post", - source_preview: "preview #{unique_num}", - action: "like" - } - - {:ok, _} = Delivery.notify_someone(u, user, info) - end) - end - @images [ "https://rmt.dogedoge.com/fetch/~/source/unsplash/photo-1557555187-23d685287bc3?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1000&q=80", "https://rmt.dogedoge.com/fetch/~/source/unsplash/photo-1484399172022-72a90b12e3c1?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1000&q=80", From 61fcd0e248cc7516e45c55b8329d58e564d4bb4a Mon Sep 17 00:00:00 2001 From: mydearxym Date: Mon, 21 Jun 2021 22:26:39 +0800 Subject: [PATCH 46/54] refactor(notify): fix notify update --- .../delivery/delegates/notification.ex | 2 +- .../query/accounts/mailbox_test.exs | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/groupher_server/delivery/delegates/notification.ex b/lib/groupher_server/delivery/delegates/notification.ex index 4ba1dc05f..4aa7b4eeb 100644 --- a/lib/groupher_server/delivery/delegates/notification.ex +++ b/lib/groupher_server/delivery/delegates/notification.ex @@ -68,7 +68,7 @@ defmodule GroupherServer.Delivery.Delegate.Notification do |> done end) |> Multi.run(:update_user_mailbox_status, fn _, _ -> - Enum.each(notifications, &Accounts.update_mailbox_status(&1.to_user_id)) |> done + Enum.each(notifications, &Accounts.update_mailbox_status(&1.user_id)) |> done end) |> Repo.transaction() |> result() diff --git a/test/groupher_server_web/query/accounts/mailbox_test.exs b/test/groupher_server_web/query/accounts/mailbox_test.exs index 4353c841c..7efada769 100644 --- a/test/groupher_server_web/query/accounts/mailbox_test.exs +++ b/test/groupher_server_web/query/accounts/mailbox_test.exs @@ -106,6 +106,40 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do end end + describe "[mark_read/all]" do + test "can mark read a mention" do + # + true + end + + test "can mark read all mentions" do + # + true + end + + test "can mark read a notification" do + # + true + end + + test "can mark read all notifications" do + # + true + end + end + + describe "[paged messages]" do + test "can get paged mentions" do + # + true + end + + test "can get paged notifications" do + # + true + end + end + # describe "[accounts mention]" do # @query """ # query($filter: MessagesFilter!) { From 2cfc57e115072698ffb510111992529ce83e14d0 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 22 Jun 2021 12:27:07 +0800 Subject: [PATCH 47/54] refactor(mailbox): mark read test & re-org --- lib/groupher_server/accounts/accounts.ex | 2 + .../accounts/delegates/mailbox.ex | 6 ++ .../delivery/delegates/notification.ex | 4 +- .../resolvers/accounts_resolver.ex | 31 ++------ .../schema/account/account_mutations.ex | 41 ++-------- .../schema/account/account_types.ex | 5 ++ lib/helper/utils/utils.ex | 6 +- .../accounts/hooks/notify_test.exs | 4 +- .../cms/hooks/notify_blog_test.exs | 21 ++--- .../cms/hooks/notify_job_test.exs | 21 ++--- .../cms/hooks/notify_post_test.exs | 21 ++--- .../delivery/notification_test.exs | 38 ++++----- .../mutation/accounts/fans_test.exs | 3 +- .../mutation/accounts/mailbox_test.exs | 77 +++++++++++++++++++ .../query/accounts/mailbox_test.exs | 73 +----------------- test/support/factory.ex | 49 ++++++++---- 16 files changed, 189 insertions(+), 213 deletions(-) create mode 100644 test/groupher_server_web/mutation/accounts/mailbox_test.exs diff --git a/lib/groupher_server/accounts/accounts.ex b/lib/groupher_server/accounts/accounts.ex index da43d0f61..e02d34f31 100644 --- a/lib/groupher_server/accounts/accounts.ex +++ b/lib/groupher_server/accounts/accounts.ex @@ -64,6 +64,8 @@ defmodule GroupherServer.Accounts do defdelegate mailbox_status(user), to: Mailbox defdelegate update_mailbox_status(user_id), to: Mailbox + defdelegate mark_read(type, ids, user_id), to: Mailbox + defdelegate mark_read_all(tyoe, user_id), to: Mailbox # customization defdelegate get_customization(user), to: Customization diff --git a/lib/groupher_server/accounts/delegates/mailbox.ex b/lib/groupher_server/accounts/delegates/mailbox.ex index 3567dd181..9c2d45257 100644 --- a/lib/groupher_server/accounts/delegates/mailbox.ex +++ b/lib/groupher_server/accounts/delegates/mailbox.ex @@ -13,6 +13,12 @@ defmodule GroupherServer.Accounts.Delegate.Mailbox do def mailbox_status(%User{mailbox: nil}), do: @default_mailbox_status |> done def mailbox_status(%User{mailbox: mailbox}), do: mailbox |> done + def mark_read(type, ids, %User{} = user) do + Delivery.mark_read(type, ids, user) + end + + def mark_read_all(type, %User{} = user), do: Delivery.mark_read_all(type, user) + @doc "update messages count in mailbox" def update_mailbox_status(user_id) do with {:ok, user} <- ORM.find(User, user_id), diff --git a/lib/groupher_server/delivery/delegates/notification.ex b/lib/groupher_server/delivery/delegates/notification.ex index 4aa7b4eeb..adc487223 100644 --- a/lib/groupher_server/delivery/delegates/notification.ex +++ b/lib/groupher_server/delivery/delegates/notification.ex @@ -78,11 +78,11 @@ defmodule GroupherServer.Delivery.Delegate.Notification do end end - def paged_notifications(user_id, %{page: page, size: size} = filter) do + def paged_notifications(%User{} = user, %{page: page, size: size} = filter) do read = Map.get(filter, :read, false) Notification - |> where([n], n.user_id == ^user_id and n.read == ^read) + |> where([n], n.user_id == ^user.id and n.read == ^read) |> ORM.paginater(~m(page size)a) |> done end diff --git a/lib/groupher_server_web/resolvers/accounts_resolver.ex b/lib/groupher_server_web/resolvers/accounts_resolver.ex index b0cf0dd0f..740b6be1d 100644 --- a/lib/groupher_server_web/resolvers/accounts_resolver.ex +++ b/lib/groupher_server_web/resolvers/accounts_resolver.ex @@ -220,39 +220,20 @@ defmodule GroupherServerWeb.Resolvers.Accounts do Accounts.paged_editable_communities(cur_user, filter) end + # mailbox def mailbox_status(_root, _args, %{context: %{cur_user: cur_user}}) do Accounts.mailbox_status(cur_user) end - # mentions - def fetch_mentions(_root, %{filter: filter}, %{context: %{cur_user: cur_user}}) do - Accounts.fetch_mentions(cur_user, filter) + def mark_read(_root, ~m(type ids)a, %{context: %{cur_user: cur_user}}) do + Accounts.mark_read(type, ids, cur_user) end - def mark_mention_read(_root, %{id: id}, %{context: %{cur_user: cur_user}}) do - Accounts.mark_mail_read(%MentionMail{id: id}, cur_user) + def mark_read_all(_root, ~m(type)a, %{context: %{cur_user: cur_user}}) do + Accounts.mark_read_all(type, cur_user) end - def mark_mention_read_all(_root, _args, %{context: %{cur_user: cur_user}}) do - Accounts.mark_mail_read_all(cur_user, :mention) - end - - # notification - def fetch_notifications(_root, %{filter: filter}, %{context: %{cur_user: cur_user}}) do - Accounts.fetch_notifications(cur_user, filter) - end - - def mark_notification_read(_root, %{id: id}, %{context: %{cur_user: cur_user}}) do - Accounts.mark_mail_read(%NotificationMail{id: id}, cur_user) - end - - def mark_notification_read_all(_root, _args, %{context: %{cur_user: cur_user}}) do - Accounts.mark_mail_read_all(cur_user, :notification) - end - - def mark_sys_notification_read(_root, %{id: id}, %{context: %{cur_user: cur_user}}) do - Accounts.mark_mail_read(%SysNotificationMail{id: id}, cur_user) - end + # mailbox end # for check other users subscribed_communities def subscribed_communities(_root, %{login: login, filter: filter}, _info) do diff --git a/lib/groupher_server_web/schema/account/account_mutations.ex b/lib/groupher_server_web/schema/account/account_mutations.ex index a880a1cbc..5bb739eb7 100644 --- a/lib/groupher_server_web/schema/account/account_mutations.ex +++ b/lib/groupher_server_web/schema/account/account_mutations.ex @@ -23,7 +23,7 @@ defmodule GroupherServerWeb.Schema.Account.Mutations do resolve(&R.Accounts.github_signin/3) end - @doc "follow a user" + @desc "follow a user" field :follow, :user do arg(:login, non_null(:string)) @@ -31,7 +31,7 @@ defmodule GroupherServerWeb.Schema.Account.Mutations do resolve(&R.Accounts.follow/3) end - @doc "undo follow to a user" + @desc "unfollow a user" field :undo_follow, :user do arg(:login, non_null(:string)) @@ -97,40 +97,13 @@ defmodule GroupherServerWeb.Schema.Account.Mutations do resolve(&R.Accounts.set_customization/3) end - @desc "mark a mention as read" - field :mark_mention_read, :status do - arg(:id, non_null(:id)) - - middleware(M.Authorize, :login) - resolve(&R.Accounts.mark_mention_read/3) - end - - @desc "mark a all unread mention as read" - field :mark_mention_read_all, :status do - middleware(M.Authorize, :login) - resolve(&R.Accounts.mark_mention_read_all/3) - end - - @desc "mark a notification as read" - field :mark_notification_read, :status do - arg(:id, non_null(:id)) - - middleware(M.Authorize, :login) - resolve(&R.Accounts.mark_notification_read/3) - end - - @desc "mark a all unread notifications as read" - field :mark_notification_read_all, :status do - middleware(M.Authorize, :login) - resolve(&R.Accounts.mark_notification_read_all/3) - end - - @desc "mark a system notification as read" - field :mark_sys_notification_read, :status do - arg(:id, non_null(:id)) + @desc "mark a message as read" + field :mark_read, :done do + arg(:ids, list_of(:id)) + arg(:type, :mailbox_type, default_value: :mention) middleware(M.Authorize, :login) - resolve(&R.Accounts.mark_sys_notification_read/3) + resolve(&R.Accounts.mark_read/3) end end end diff --git a/lib/groupher_server_web/schema/account/account_types.ex b/lib/groupher_server_web/schema/account/account_types.ex index 1d8dbd4f5..8972f732e 100644 --- a/lib/groupher_server_web/schema/account/account_types.ex +++ b/lib/groupher_server_web/schema/account/account_types.ex @@ -199,4 +199,9 @@ defmodule GroupherServerWeb.Schema.Account.Types do field(:entries, list_of(:user)) pagination_fields() end + + enum :mailbox_type do + value(:mention) + value(:notification) + end end diff --git a/lib/helper/utils/utils.ex b/lib/helper/utils/utils.ex index 4d321b318..cc7baa8d4 100644 --- a/lib/helper/utils/utils.ex +++ b/lib/helper/utils/utils.ex @@ -57,6 +57,7 @@ defmodule Helper.Utils do """ def done(false), do: {:error, false} def done(true), do: {:ok, true} + def done(nil), do: {:error, "record not found."} def done(nil, :boolean), do: {:ok, false} def done(_, :boolean), do: {:ok, true} def done(nil, err_msg), do: {:error, err_msg} @@ -69,11 +70,12 @@ defmodule Helper.Utils do def done(nil, queryable, id), do: {:error, not_found_formater(queryable, id)} def done(result, _, _), do: {:ok, result} - def done(nil), do: {:error, "record not found."} - # for delete_all, update_all # see: https://groups.google.com/forum/#!topic/elixir-ecto/1g5Pp6ceqFE + # def done({0, nil}), do: {:error, %{done: false}} def done({n, nil}) when is_integer(n), do: {:ok, %{done: true}} + # def done({n, nil}, extra: extra) when is_integer(n), do: {:ok, %{done: true}} + def done(result), do: {:ok, result} def done_and_cache(result, pool, scope, expire_sec: expire_sec) do diff --git a/test/groupher_server/accounts/hooks/notify_test.exs b/test/groupher_server/accounts/hooks/notify_test.exs index d1d81b2bf..58280d6c0 100644 --- a/test/groupher_server/accounts/hooks/notify_test.exs +++ b/test/groupher_server/accounts/hooks/notify_test.exs @@ -18,7 +18,7 @@ defmodule GroupherServer.Test.Accounts.Hooks.Notify do {:ok, _} = Accounts.follow(user, user2) Hooks.Notify.handle(:follow, user, user2) - {:ok, notifications} = Delivery.fetch(:notification, user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, user, %{page: 1, size: 20}) assert notifications.total_count == 1 notify = notifications.entries |> List.first() @@ -32,7 +32,7 @@ defmodule GroupherServer.Test.Accounts.Hooks.Notify do Hooks.Notify.handle(:follow, user, user2) Hooks.Notify.handle(:undo, :follow, user, user2) - {:ok, notifications} = Delivery.fetch(:notification, user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, user, %{page: 1, size: 20}) assert notifications.total_count == 0 end end diff --git a/test/groupher_server/cms/hooks/notify_blog_test.exs b/test/groupher_server/cms/hooks/notify_blog_test.exs index 89001ee54..dc03a0fe2 100644 --- a/test/groupher_server/cms/hooks/notify_blog_test.exs +++ b/test/groupher_server/cms/hooks/notify_blog_test.exs @@ -27,8 +27,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do {:ok, article} = CMS.upvote_article(:blog, blog.id, user2) Hooks.Notify.handle(:upvote, article, user2) - {:ok, notifications} = - Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, blog.author.user, %{page: 1, size: 20}) assert notifications.total_count == 1 @@ -46,8 +45,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do Hooks.Notify.handle(:upvote, comment, user2) - {:ok, notifications} = - Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, comment.author, %{page: 1, size: 20}) assert notifications.total_count == 1 @@ -69,8 +67,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do {:ok, article} = CMS.undo_upvote_article(:blog, blog.id, user2) Hooks.Notify.handle(:undo, :upvote, article, user2) - {:ok, notifications} = - Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, blog.author.user, %{page: 1, size: 20}) assert notifications.total_count == 0 end @@ -85,8 +82,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do {:ok, comment} = preload_author(comment) - {:ok, notifications} = - Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, comment.author, %{page: 1, size: 20}) assert notifications.total_count == 0 end @@ -99,8 +95,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do {:ok, _} = CMS.collect_article(:blog, blog.id, user2) Hooks.Notify.handle(:collect, blog, user2) - {:ok, notifications} = - Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, blog.author.user, %{page: 1, size: 20}) assert notifications.total_count == 1 @@ -121,8 +116,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do {:ok, _} = CMS.undo_upvote_article(:blog, blog.id, user2) Hooks.Notify.handle(:undo, :collect, blog, user2) - {:ok, notifications} = - Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, blog.author.user, %{page: 1, size: 20}) assert notifications.total_count == 0 end @@ -135,8 +129,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do {:ok, comment} = CMS.create_comment(:blog, blog.id, mock_comment(), user2) Hooks.Notify.handle(:comment, comment, user2) - {:ok, notifications} = - Delivery.fetch(:notification, blog.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, blog.author.user, %{page: 1, size: 20}) assert notifications.total_count == 1 diff --git a/test/groupher_server/cms/hooks/notify_job_test.exs b/test/groupher_server/cms/hooks/notify_job_test.exs index eb9686f3b..02db6ea6a 100644 --- a/test/groupher_server/cms/hooks/notify_job_test.exs +++ b/test/groupher_server/cms/hooks/notify_job_test.exs @@ -27,8 +27,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do {:ok, article} = CMS.upvote_article(:job, job.id, user2) Hooks.Notify.handle(:upvote, article, user2) - {:ok, notifications} = - Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, job.author.user, %{page: 1, size: 20}) assert notifications.total_count == 1 @@ -46,8 +45,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do Hooks.Notify.handle(:upvote, comment, user2) - {:ok, notifications} = - Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, comment.author, %{page: 1, size: 20}) assert notifications.total_count == 1 @@ -69,8 +67,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do {:ok, article} = CMS.undo_upvote_article(:job, job.id, user2) Hooks.Notify.handle(:undo, :upvote, article, user2) - {:ok, notifications} = - Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, job.author.user, %{page: 1, size: 20}) assert notifications.total_count == 0 end @@ -85,8 +82,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do {:ok, comment} = preload_author(comment) - {:ok, notifications} = - Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, comment.author, %{page: 1, size: 20}) assert notifications.total_count == 0 end @@ -99,8 +95,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do {:ok, _} = CMS.collect_article(:job, job.id, user2) Hooks.Notify.handle(:collect, job, user2) - {:ok, notifications} = - Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, job.author.user, %{page: 1, size: 20}) assert notifications.total_count == 1 @@ -121,8 +116,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do {:ok, _} = CMS.undo_upvote_article(:job, job.id, user2) Hooks.Notify.handle(:undo, :collect, job, user2) - {:ok, notifications} = - Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, job.author.user, %{page: 1, size: 20}) assert notifications.total_count == 0 end @@ -135,8 +129,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do {:ok, comment} = CMS.create_comment(:job, job.id, mock_comment(), user2) Hooks.Notify.handle(:comment, comment, user2) - {:ok, notifications} = - Delivery.fetch(:notification, job.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, job.author.user, %{page: 1, size: 20}) assert notifications.total_count == 1 diff --git a/test/groupher_server/cms/hooks/notify_post_test.exs b/test/groupher_server/cms/hooks/notify_post_test.exs index fe23b3210..ca54aadbe 100644 --- a/test/groupher_server/cms/hooks/notify_post_test.exs +++ b/test/groupher_server/cms/hooks/notify_post_test.exs @@ -27,8 +27,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do {:ok, article} = CMS.upvote_article(:post, post.id, user2) Hooks.Notify.handle(:upvote, article, user2) - {:ok, notifications} = - Delivery.fetch(:notification, post.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, post.author.user, %{page: 1, size: 20}) assert notifications.total_count == 1 @@ -46,8 +45,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do Hooks.Notify.handle(:upvote, comment, user2) - {:ok, notifications} = - Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, comment.author, %{page: 1, size: 20}) assert notifications.total_count == 1 @@ -69,8 +67,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do {:ok, article} = CMS.undo_upvote_article(:post, post.id, user2) Hooks.Notify.handle(:undo, :upvote, article, user2) - {:ok, notifications} = - Delivery.fetch(:notification, post.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, post.author.user, %{page: 1, size: 20}) assert notifications.total_count == 0 end @@ -85,8 +82,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do {:ok, comment} = preload_author(comment) - {:ok, notifications} = - Delivery.fetch(:notification, comment.author.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, comment.author, %{page: 1, size: 20}) assert notifications.total_count == 0 end @@ -99,8 +95,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do {:ok, _} = CMS.collect_article(:post, post.id, user2) Hooks.Notify.handle(:collect, post, user2) - {:ok, notifications} = - Delivery.fetch(:notification, post.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, post.author.user, %{page: 1, size: 20}) assert notifications.total_count == 1 @@ -121,8 +116,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do {:ok, _} = CMS.undo_upvote_article(:post, post.id, user2) Hooks.Notify.handle(:undo, :collect, post, user2) - {:ok, notifications} = - Delivery.fetch(:notification, post.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, post.author.user, %{page: 1, size: 20}) assert notifications.total_count == 0 end @@ -135,8 +129,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do {:ok, comment} = CMS.create_comment(:post, post.id, mock_comment(), user2) Hooks.Notify.handle(:comment, comment, user2) - {:ok, notifications} = - Delivery.fetch(:notification, post.author.user.id, %{page: 1, size: 20}) + {:ok, notifications} = Delivery.fetch(:notification, post.author.user, %{page: 1, size: 20}) assert notifications.total_count == 1 diff --git a/test/groupher_server/delivery/notification_test.exs b/test/groupher_server/delivery/notification_test.exs index 7006f889a..122d45b3d 100644 --- a/test/groupher_server/delivery/notification_test.exs +++ b/test/groupher_server/delivery/notification_test.exs @@ -48,7 +48,7 @@ defmodule GroupherServer.Test.Delivery.Notification do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) - {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, paged_notifies} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert paged_notifies.total_count == 1 notify = paged_notifies.entries |> List.first() @@ -67,7 +67,7 @@ defmodule GroupherServer.Test.Delivery.Notification do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) - {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, paged_notifies} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) notify = paged_notifies.entries |> List.first() @@ -93,7 +93,7 @@ defmodule GroupherServer.Test.Delivery.Notification do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) - {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, paged_notifies} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) notify = paged_notifies.entries |> List.first() @@ -109,7 +109,7 @@ defmodule GroupherServer.Test.Delivery.Notification do notify_attrs = notify_attrs |> Map.put(:action, :collect) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) - {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, paged_notifies} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert paged_notifies.total_count == 2 @@ -126,7 +126,7 @@ defmodule GroupherServer.Test.Delivery.Notification do move_insert_at_long_ago(notify) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) - {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, paged_notifies} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert paged_notifies.total_count == 2 @@ -146,12 +146,12 @@ defmodule GroupherServer.Test.Delivery.Notification do test "can revoke a notification", ~m(user user2 notify_attrs)a do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) - {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, paged_notifies} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert paged_notifies.total_count == 1 Delivery.revoke(:notify, notify_attrs, user2) - {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, paged_notifies} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert paged_notifies.total_count == 0 end @@ -159,7 +159,7 @@ defmodule GroupherServer.Test.Delivery.Notification do {:ok, _} = Delivery.send(:notify, notify_attrs, user2) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) - {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, paged_notifies} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert paged_notifies.total_count == 1 notify = paged_notifies.entries |> List.first() assert user_exist_in?(user2, notify.from_users) @@ -167,7 +167,7 @@ defmodule GroupherServer.Test.Delivery.Notification do Delivery.revoke(:notify, notify_attrs, user2) - {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, paged_notifies} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert paged_notifies.total_count == 1 notify = paged_notifies.entries |> List.first() @@ -182,12 +182,12 @@ defmodule GroupherServer.Test.Delivery.Notification do {:ok, _} = Delivery.send(:notify, notify_attrs, user3) - {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, paged_notifies} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert paged_notifies.total_count == 2 Delivery.revoke(:notify, notify_attrs, user2) - {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, paged_notifies} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert paged_notifies.total_count == 1 notify = paged_notifies.entries |> List.first() assert not user_exist_in?(user2, notify.from_users) @@ -202,12 +202,12 @@ defmodule GroupherServer.Test.Delivery.Notification do {:ok, _} = Delivery.send(:notify, notify_attrs, user4) - {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, paged_notifies} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert paged_notifies.total_count == 2 Delivery.revoke(:notify, notify_attrs, user2) - {:ok, paged_notifies} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, paged_notifies} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert paged_notifies.total_count == 2 notify1 = paged_notifies.entries |> List.first() notify2 = paged_notifies.entries |> List.last() @@ -345,7 +345,7 @@ defmodule GroupherServer.Test.Delivery.Notification do move_insert_at_long_ago(notify) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) - {:ok, result} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) notify1 = result.entries |> List.first() notify2 = result.entries |> List.last() @@ -353,10 +353,10 @@ defmodule GroupherServer.Test.Delivery.Notification do {:ok, _} = Delivery.mark_read(:notification, [notify1.id, notify2.id], user) - {:ok, result} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert result.total_count == 0 - {:ok, result} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10, read: true}) + {:ok, result} = Delivery.fetch(:notification, user, %{page: 1, size: 10, read: true}) assert result.total_count == 2 end @@ -365,16 +365,16 @@ defmodule GroupherServer.Test.Delivery.Notification do move_insert_at_long_ago(notify) {:ok, _} = Delivery.send(:notify, notify_attrs, user3) - {:ok, result} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert result.total_count == 2 {:ok, _} = Delivery.mark_read_all(:notification, user) - {:ok, result} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10}) + {:ok, result} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) assert result.total_count == 0 - {:ok, result} = Delivery.fetch(:notification, user.id, %{page: 1, size: 10, read: true}) + {:ok, result} = Delivery.fetch(:notification, user, %{page: 1, size: 10, read: true}) assert result.total_count == 2 end end diff --git a/test/groupher_server_web/mutation/accounts/fans_test.exs b/test/groupher_server_web/mutation/accounts/fans_test.exs index 37fbc3adc..250b1d5bd 100644 --- a/test/groupher_server_web/mutation/accounts/fans_test.exs +++ b/test/groupher_server_web/mutation/accounts/fans_test.exs @@ -3,6 +3,7 @@ defmodule GroupherServer.Test.Mutation.Accounts.Fans do alias Helper.ORM alias GroupherServer.Accounts + alias Accounts.Model.User setup do {:ok, user} = db_insert(:user) @@ -14,8 +15,6 @@ defmodule GroupherServer.Test.Mutation.Accounts.Fans do end describe "[Accounts follower]" do - alias Accounts.Model.User - @query """ mutation($login: String!) { follow(login: $login) { diff --git a/test/groupher_server_web/mutation/accounts/mailbox_test.exs b/test/groupher_server_web/mutation/accounts/mailbox_test.exs new file mode 100644 index 000000000..edc7736b1 --- /dev/null +++ b/test/groupher_server_web/mutation/accounts/mailbox_test.exs @@ -0,0 +1,77 @@ +defmodule GroupherServer.Test.Query.Accounts.Mailbox do + use GroupherServer.TestTools + + alias GroupherServer.Delivery + + setup do + {:ok, user} = db_insert(:user) + {:ok, user2} = db_insert(:user) + + user_conn = simu_conn(:user, user) + guest_conn = simu_conn(:guest) + + {:ok, ~m(user_conn guest_conn user user2)a} + end + + describe "[mark_read/all]" do + @query """ + mutation($type: MailboxType, $ids: [Id]) { + markRead(ids: $ids, type: $type) { + done + } + } + """ + # @tag :wip + test "can mark read a mention", ~m(user_conn user user2)a do + {:ok, _} = mock_mention_for(user, user2) + + {:ok, mentions} = Delivery.fetch(:mention, user, %{page: 1, size: 10}) + mention = mentions.entries |> List.first() + + variables = %{ids: [mention.id], type: "MENTION"} + result = user_conn |> mutation_result(@query, variables, "markRead") + + {:ok, mentions} = Delivery.fetch(:mention, user, %{page: 1, size: 10, read: true}) + mention = mentions.entries |> List.first() + assert mention.read + end + + @tag :wip + test "can mark read a notification", ~m(user_conn user user2)a do + {:ok, _} = mock_notification_for(user, user2) + + {:ok, notifications} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) + notify = notifications.entries |> List.first() + + variables = %{ids: [notify.id], type: "NOTIFICATION"} + result = user_conn |> mutation_result(@query, variables, "markRead") + + {:ok, notifications} = Delivery.fetch(:notification, user, %{page: 1, size: 10, read: true}) + notify = notifications.entries |> List.first() + + assert notify.read + end + + test "can mark read all mentions" do + # + true + end + + test "can mark read all notifications" do + # + true + end + end + + describe "[paged messages]" do + test "can get paged mentions" do + # + true + end + + test "can get paged notifications" do + # + true + end + end +end diff --git a/test/groupher_server_web/query/accounts/mailbox_test.exs b/test/groupher_server_web/query/accounts/mailbox_test.exs index 7efada769..abc679f2c 100644 --- a/test/groupher_server_web/query/accounts/mailbox_test.exs +++ b/test/groupher_server_web/query/accounts/mailbox_test.exs @@ -1,8 +1,6 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do use GroupherServer.TestTools - alias GroupherServer.Delivery - setup do {:ok, user} = db_insert(:user) {:ok, user2} = db_insert(:user) @@ -13,41 +11,6 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do {:ok, ~m(user_conn guest_conn user user2)a} end - defp mock_mention_for(user, from_user) do - {:ok, post} = db_insert(:post) - - mention_attr = %{ - thread: "POST", - title: post.title, - article_id: post.id, - comment_id: nil, - block_linker: ["tmp"], - inserted_at: post.updated_at |> DateTime.truncate(:second), - updated_at: post.updated_at |> DateTime.truncate(:second) - } - - mention_contents = [ - Map.merge(mention_attr, %{from_user_id: from_user.id, to_user_id: user.id}) - ] - - Delivery.send(:mention, post, mention_contents, from_user) - end - - defp mock_nofity_for(user, from_user) do - {:ok, post} = db_insert(:post) - - notify_attrs = %{ - thread: :post, - article_id: post.id, - title: post.title, - action: :upvote, - user_id: user.id, - read: false - } - - Delivery.send(:notify, notify_attrs, from_user) - end - describe "[accounts mailbox status]" do @query """ query($login: String!) { @@ -92,7 +55,7 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do @tag :wip test "auth user can get latest mailbox status after being notified", ~m(user user2)a do - mock_nofity_for(user, user2) + mock_notification_for(user, user2) user_conn = simu_conn(:user, user) @@ -106,40 +69,6 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do end end - describe "[mark_read/all]" do - test "can mark read a mention" do - # - true - end - - test "can mark read all mentions" do - # - true - end - - test "can mark read a notification" do - # - true - end - - test "can mark read all notifications" do - # - true - end - end - - describe "[paged messages]" do - test "can get paged mentions" do - # - true - end - - test "can get paged notifications" do - # - true - end - end - # describe "[accounts mention]" do # @query """ # query($filter: MessagesFilter!) { diff --git a/test/support/factory.ex b/test/support/factory.ex index f5276102b..05fe0b582 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -8,7 +8,7 @@ defmodule GroupherServer.Support.Factory do import Helper.Utils, only: [done: 1] import GroupherServer.CMS.Helper.Matcher - alias GroupherServer.{Accounts, CMS} + alias GroupherServer.{Accounts, CMS, Delivery} alias Accounts.Model.User alias CMS.Model.{ @@ -291,17 +291,6 @@ defmodule GroupherServer.Support.Factory do } end - defp mock_meta(:sys_notification) do - unique_num = System.unique_integer([:positive, :monotonic]) - - %{ - source_id: "#{unique_num}", - source_title: "#{Faker.Pizza.cheese()}", - source_type: "post", - source_preview: "#{Faker.Pizza.cheese()}" - } - end - defp mock_meta(:user) do unique_num = System.unique_integer([:positive, :monotonic]) @@ -369,7 +358,6 @@ defmodule GroupherServer.Support.Factory do do: mock_meta(:communities_threads) |> Map.merge(attrs) def mock_attrs(:article_tag, attrs), do: mock_meta(:article_tag) |> Map.merge(attrs) - 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) @@ -446,4 +434,39 @@ defmodule GroupherServer.Support.Factory do def mock_images(count \\ 1) do @images |> Enum.slice(0, count) end + + def mock_mention_for(user, from_user) do + {:ok, post} = db_insert(:post) + + mention_attr = %{ + thread: "POST", + title: post.title, + article_id: post.id, + comment_id: nil, + block_linker: ["tmp"], + inserted_at: post.updated_at |> DateTime.truncate(:second), + updated_at: post.updated_at |> DateTime.truncate(:second) + } + + mention_contents = [ + Map.merge(mention_attr, %{from_user_id: from_user.id, to_user_id: user.id}) + ] + + Delivery.send(:mention, post, mention_contents, from_user) + end + + def mock_notification_for(user, from_user) do + {:ok, post} = db_insert(:post) + + notify_attrs = %{ + thread: :post, + article_id: post.id, + title: post.title, + action: :upvote, + user_id: user.id, + read: false + } + + Delivery.send(:notify, notify_attrs, from_user) + end end From 2136175623e7eaf0f64016195e619ed7fe991db7 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 22 Jun 2021 12:33:49 +0800 Subject: [PATCH 48/54] refactor(mailbox): remove old account mails tables --- .../accounts/models/mention_mail.ex | 45 ------------------- .../accounts/models/notification.mail.ex | 45 ------------------- .../accounts/models/sys_notification_mail.ex | 39 ---------------- .../resolvers/accounts_resolver.ex | 2 +- ...0210622042857_remove_old_account_mails.exs | 9 ++++ 5 files changed, 10 insertions(+), 130 deletions(-) delete mode 100644 lib/groupher_server/accounts/models/mention_mail.ex delete mode 100644 lib/groupher_server/accounts/models/notification.mail.ex delete mode 100644 lib/groupher_server/accounts/models/sys_notification_mail.ex create mode 100644 priv/repo/migrations/20210622042857_remove_old_account_mails.exs diff --git a/lib/groupher_server/accounts/models/mention_mail.ex b/lib/groupher_server/accounts/models/mention_mail.ex deleted file mode 100644 index 3388747a5..000000000 --- a/lib/groupher_server/accounts/models/mention_mail.ex +++ /dev/null @@ -1,45 +0,0 @@ -defmodule GroupherServer.Accounts.Model.MentionMail do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - alias GroupherServer.Accounts.Model.User - - @required_fields ~w(from_user_id to_user_id source_id source_type source_preview)a - @optional_fields ~w(parent_id parent_type read floor community)a - - @type t :: %MentionMail{} - schema "mention_mails" do - belongs_to(:from_user, User) - belongs_to(:to_user, User) - field(:source_id, :string) - field(:source_preview, :string) - field(:source_title, :string) - field(:source_type, :string) - field(:parent_id, :string) - field(:parent_type, :string) - field(:community, :string) - field(:floor, :integer) - field(:read, :boolean) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%MentionMail{} = mention, attrs) do - mention - |> cast(attrs, @optional_fields ++ @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:from_user_id) - |> foreign_key_constraint(:to_user_id) - end - - @doc false - def update_changeset(%MentionMail{} = mention, attrs) do - mention - |> cast(attrs, @optional_fields ++ @required_fields) - |> foreign_key_constraint(:from_user_id) - |> foreign_key_constraint(:to_user_id) - end -end diff --git a/lib/groupher_server/accounts/models/notification.mail.ex b/lib/groupher_server/accounts/models/notification.mail.ex deleted file mode 100644 index 97ab8b82a..000000000 --- a/lib/groupher_server/accounts/models/notification.mail.ex +++ /dev/null @@ -1,45 +0,0 @@ -defmodule GroupherServer.Accounts.Model.NotificationMail do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - alias GroupherServer.Accounts.Model.User - - @required_fields ~w(from_user_id to_user_id action source_id source_type source_preview)a - @optional_fields ~w(parent_id parent_type read)a - - @type t :: %NotificationMail{} - schema "notification_mails" do - belongs_to(:from_user, User) - belongs_to(:to_user, User) - field(:action, :string) - - field(:source_id, :string) - field(:source_preview, :string) - field(:source_title, :string) - field(:source_type, :string) - field(:parent_id, :string) - field(:parent_type, :string) - field(:read, :boolean) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%NotificationMail{} = notication_mail, attrs) do - notication_mail - |> cast(attrs, @optional_fields ++ @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:from_user_id) - |> foreign_key_constraint(:to_user_id) - end - - @doc false - def update_changeset(%NotificationMail{} = notication_mail, attrs) do - notication_mail - |> cast(attrs, @optional_fields ++ @required_fields) - |> foreign_key_constraint(:from_user_id) - |> foreign_key_constraint(:to_user_id) - end -end diff --git a/lib/groupher_server/accounts/models/sys_notification_mail.ex b/lib/groupher_server/accounts/models/sys_notification_mail.ex deleted file mode 100644 index b679c40df..000000000 --- a/lib/groupher_server/accounts/models/sys_notification_mail.ex +++ /dev/null @@ -1,39 +0,0 @@ -defmodule GroupherServer.Accounts.Model.SysNotificationMail do - @moduledoc false - alias __MODULE__ - - use Ecto.Schema - import Ecto.Changeset - alias GroupherServer.Accounts.Model.User - - @required_fields ~w(user_id source_id source_type)a - @optional_fields ~w(source_preview read)a - - @type t :: %SysNotificationMail{} - schema "sys_notification_mails" do - belongs_to(:user, User) - - field(:source_id, :string) - field(:source_preview, :string) - field(:source_title, :string) - field(:source_type, :string) - field(:read, :boolean) - - timestamps(type: :utc_datetime) - end - - @doc false - def changeset(%SysNotificationMail{} = sys_notication_mail, attrs) do - sys_notication_mail - |> cast(attrs, @optional_fields ++ @required_fields) - |> validate_required(@required_fields) - |> foreign_key_constraint(:user_id) - end - - @doc false - def update_changeset(%SysNotificationMail{} = sys_notication_mail, attrs) do - sys_notication_mail - |> cast(attrs, @optional_fields ++ @required_fields) - |> foreign_key_constraint(:user_id) - end -end diff --git a/lib/groupher_server_web/resolvers/accounts_resolver.ex b/lib/groupher_server_web/resolvers/accounts_resolver.ex index 740b6be1d..b1ae3e505 100644 --- a/lib/groupher_server_web/resolvers/accounts_resolver.ex +++ b/lib/groupher_server_web/resolvers/accounts_resolver.ex @@ -7,7 +7,7 @@ defmodule GroupherServerWeb.Resolvers.Accounts do alias GroupherServer.{Accounts, CMS} - alias Accounts.Model.{MentionMail, NotificationMail, SysNotificationMail, User} + alias Accounts.Model.User alias Helper.Certification def user(_root, %{login: login}, %{context: %{cur_user: cur_user}}) do diff --git a/priv/repo/migrations/20210622042857_remove_old_account_mails.exs b/priv/repo/migrations/20210622042857_remove_old_account_mails.exs new file mode 100644 index 000000000..98bddd1a0 --- /dev/null +++ b/priv/repo/migrations/20210622042857_remove_old_account_mails.exs @@ -0,0 +1,9 @@ +defmodule GroupherServer.Repo.Migrations.RemoveOldAccountMails do + use Ecto.Migration + + def change do + drop(table(:mention_mails)) + drop(table(:notification_mails)) + drop(table(:sys_notification_mails)) + end +end From 88034368504b465dec9bc27386ad15712f02064e Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 22 Jun 2021 12:51:21 +0800 Subject: [PATCH 49/54] refactor(mailbox): read_all test --- .../schema/account/account_mutations.ex | 8 ++++ .../mutation/accounts/mailbox_test.exs | 41 +++++++++++++++---- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/lib/groupher_server_web/schema/account/account_mutations.ex b/lib/groupher_server_web/schema/account/account_mutations.ex index 5bb739eb7..bfc44b95f 100644 --- a/lib/groupher_server_web/schema/account/account_mutations.ex +++ b/lib/groupher_server_web/schema/account/account_mutations.ex @@ -105,5 +105,13 @@ defmodule GroupherServerWeb.Schema.Account.Mutations do middleware(M.Authorize, :login) resolve(&R.Accounts.mark_read/3) end + + @desc "mark all unread message as read" + field :mark_read_all, :done do + arg(:type, :mailbox_type, default_value: :mention) + + middleware(M.Authorize, :login) + resolve(&R.Accounts.mark_read_all/3) + end end end diff --git a/test/groupher_server_web/mutation/accounts/mailbox_test.exs b/test/groupher_server_web/mutation/accounts/mailbox_test.exs index edc7736b1..b0aa95516 100644 --- a/test/groupher_server_web/mutation/accounts/mailbox_test.exs +++ b/test/groupher_server_web/mutation/accounts/mailbox_test.exs @@ -6,11 +6,12 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do setup do {:ok, user} = db_insert(:user) {:ok, user2} = db_insert(:user) + {:ok, user3} = db_insert(:user) user_conn = simu_conn(:user, user) guest_conn = simu_conn(:guest) - {:ok, ~m(user_conn guest_conn user user2)a} + {:ok, ~m(user_conn guest_conn user user2 user3)a} end describe "[mark_read/all]" do @@ -52,14 +53,40 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do assert notify.read end - test "can mark read all mentions" do - # - true + @query """ + mutation($type: MailboxType) { + markReadAll(type: $type) { + done + } + } + """ + @tag :wip + test "can mark read all mentions", ~m(user_conn user user2 user3)a do + {:ok, _} = mock_mention_for(user, user2) + {:ok, _} = mock_mention_for(user, user3) + + {:ok, mentions} = Delivery.fetch(:mention, user, %{page: 1, size: 10}) + assert mentions.total_count == 2 + + variables = %{type: "MENTION"} + result = user_conn |> mutation_result(@query, variables, "markReadAll") + + {:ok, mentions} = Delivery.fetch(:mention, user, %{page: 1, size: 10, read: true}) + assert mentions.total_count == 2 end - test "can mark read all notifications" do - # - true + @tag :wip + test "can mark read all notifications", ~m(user_conn user user2)a do + {:ok, _} = mock_notification_for(user, user2) + + {:ok, notifications} = Delivery.fetch(:notification, user, %{page: 1, size: 10}) + assert notifications.total_count == 1 + + variables = %{type: "NOTIFICATION"} + result = user_conn |> mutation_result(@query, variables, "markReadAll") + + {:ok, notifications} = Delivery.fetch(:notification, user, %{page: 1, size: 10, read: true}) + assert notifications.total_count == 1 end end From 834391f0078966abe515efa1df1a890972b75f5c Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 22 Jun 2021 14:23:27 +0800 Subject: [PATCH 50/54] refactor(mailbox): paged mentions & test --- lib/groupher_server/accounts/accounts.ex | 2 + .../accounts/delegates/mailbox.ex | 4 ++ .../resolvers/accounts_resolver.ex | 5 ++ .../schema/account/account_metrics.ex | 5 ++ .../schema/account/account_queries.ex | 16 ++--- .../schema/account/account_types.ex | 20 ++++++ test/groupher_server/accounts/mailbx_test.exs | 2 +- .../mutation/accounts/mailbox_test.exs | 20 ++---- .../query/accounts/mailbox_test.exs | 65 +++++++++++++++---- 9 files changed, 101 insertions(+), 38 deletions(-) diff --git a/lib/groupher_server/accounts/accounts.ex b/lib/groupher_server/accounts/accounts.ex index e02d34f31..8844a7502 100644 --- a/lib/groupher_server/accounts/accounts.ex +++ b/lib/groupher_server/accounts/accounts.ex @@ -67,6 +67,8 @@ defmodule GroupherServer.Accounts do defdelegate mark_read(type, ids, user_id), to: Mailbox defdelegate mark_read_all(tyoe, user_id), to: Mailbox + defdelegate paged_mailbox_messages(type, user, filter), to: Mailbox + # customization defdelegate get_customization(user), to: Customization defdelegate set_customization(user, key, value), to: Customization diff --git a/lib/groupher_server/accounts/delegates/mailbox.ex b/lib/groupher_server/accounts/delegates/mailbox.ex index 9c2d45257..25b7c2299 100644 --- a/lib/groupher_server/accounts/delegates/mailbox.ex +++ b/lib/groupher_server/accounts/delegates/mailbox.ex @@ -19,6 +19,10 @@ defmodule GroupherServer.Accounts.Delegate.Mailbox do def mark_read_all(type, %User{} = user), do: Delivery.mark_read_all(type, user) + def paged_mailbox_messages(type, user, filter) do + Delivery.fetch(type, user, filter) + end + @doc "update messages count in mailbox" def update_mailbox_status(user_id) do with {:ok, user} <- ORM.find(User, user_id), diff --git a/lib/groupher_server_web/resolvers/accounts_resolver.ex b/lib/groupher_server_web/resolvers/accounts_resolver.ex index b1ae3e505..2a9ee1320 100644 --- a/lib/groupher_server_web/resolvers/accounts_resolver.ex +++ b/lib/groupher_server_web/resolvers/accounts_resolver.ex @@ -233,6 +233,11 @@ defmodule GroupherServerWeb.Resolvers.Accounts do Accounts.mark_read_all(type, cur_user) end + def paged_mailbox_mentions(_root, ~m(filter)a, %{context: %{cur_user: cur_user}}) do + IO.inspect(cur_user.login, label: "in resolver") + Accounts.paged_mailbox_messages(:mention, cur_user, filter) + end + # mailbox end # for check other users subscribed_communities diff --git a/lib/groupher_server_web/schema/account/account_metrics.ex b/lib/groupher_server_web/schema/account/account_metrics.ex index 436998bc7..40b7e291a 100644 --- a/lib/groupher_server_web/schema/account/account_metrics.ex +++ b/lib/groupher_server_web/schema/account/account_metrics.ex @@ -4,6 +4,11 @@ defmodule GroupherServerWeb.Schema.Account.Metrics do use Absinthe.Schema.Notation import GroupherServerWeb.Schema.Helper.Fields + input_object :mailbox_mentions_filter do + field(:read, :boolean, default_value: false) + pagination_args() + end + @desc "article_filter doc" input_object :paged_users_filter do pagination_args() diff --git a/lib/groupher_server_web/schema/account/account_queries.ex b/lib/groupher_server_web/schema/account/account_queries.ex index 34e231d6a..652184a0b 100644 --- a/lib/groupher_server_web/schema/account/account_queries.ex +++ b/lib/groupher_server_web/schema/account/account_queries.ex @@ -35,14 +35,14 @@ defmodule GroupherServerWeb.Schema.Account.Queries do resolve(&R.Accounts.subscribed_communities/3) end - # @desc "get user's mentions" - # field :mentions, :paged_mentions do - # arg(:filter, :messages_filter) - - # middleware(M.Authorize, :login) - # middleware(M.PageSizeProof) - # resolve(&R.Accounts.fetch_mentions/3) - # end + @desc "get login user's mentions in mailbox" + field :paged_mentions, :paged_mailbox_mentions do + arg(:filter, :mailbox_mentions_filter) + + middleware(M.Authorize, :login) + middleware(M.PageSizeProof) + resolve(&R.Accounts.paged_mailbox_mentions/3) + end @desc "get user's follower" field :paged_followers, :paged_users do diff --git a/lib/groupher_server_web/schema/account/account_types.ex b/lib/groupher_server_web/schema/account/account_types.ex index 8972f732e..59f2ecde2 100644 --- a/lib/groupher_server_web/schema/account/account_types.ex +++ b/lib/groupher_server_web/schema/account/account_types.ex @@ -97,6 +97,21 @@ defmodule GroupherServerWeb.Schema.Account.Types do field(:unread_notifications_count, :integer) end + object :mailbox_mention do + field(:id, :id) + field(:thread, :string) + field(:article_id, :id) + field(:title, :string) + field(:comment_id, :id) + field(:read, :boolean) + + field(:block_linker, list_of(:string)) + + field(:user, :common_user) + + timestamp_fields() + end + # field(:sidebar_layout, :map) object :customization do field(:theme, :string) @@ -200,6 +215,11 @@ defmodule GroupherServerWeb.Schema.Account.Types do pagination_fields() end + object :paged_mailbox_mentions do + field(:entries, list_of(:mailbox_mention)) + pagination_fields() + end + enum :mailbox_type do value(:mention) value(:notification) diff --git a/test/groupher_server/accounts/mailbx_test.exs b/test/groupher_server/accounts/mailbx_test.exs index 57ecaa4ce..2ed735b2d 100644 --- a/test/groupher_server/accounts/mailbx_test.exs +++ b/test/groupher_server/accounts/mailbx_test.exs @@ -17,7 +17,7 @@ defmodule GroupherServer.Test.Accounts.Mailbox do end describe "mailbox status" do - @tag :wip + @tag :wip2 test "can get default mailbox status", ~m(user)a do {:ok, status} = Accounts.mailbox_status(user) assert status == @default_mailbox_status diff --git a/test/groupher_server_web/mutation/accounts/mailbox_test.exs b/test/groupher_server_web/mutation/accounts/mailbox_test.exs index b0aa95516..00fca24e6 100644 --- a/test/groupher_server_web/mutation/accounts/mailbox_test.exs +++ b/test/groupher_server_web/mutation/accounts/mailbox_test.exs @@ -22,7 +22,7 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do } } """ - # @tag :wip + # @tag :wip2 test "can mark read a mention", ~m(user_conn user user2)a do {:ok, _} = mock_mention_for(user, user2) @@ -37,7 +37,7 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do assert mention.read end - @tag :wip + @tag :wip2 test "can mark read a notification", ~m(user_conn user user2)a do {:ok, _} = mock_notification_for(user, user2) @@ -60,7 +60,7 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do } } """ - @tag :wip + @tag :wip2 test "can mark read all mentions", ~m(user_conn user user2 user3)a do {:ok, _} = mock_mention_for(user, user2) {:ok, _} = mock_mention_for(user, user3) @@ -75,7 +75,7 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do assert mentions.total_count == 2 end - @tag :wip + @tag :wip2 test "can mark read all notifications", ~m(user_conn user user2)a do {:ok, _} = mock_notification_for(user, user2) @@ -89,16 +89,4 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do assert notifications.total_count == 1 end end - - describe "[paged messages]" do - test "can get paged mentions" do - # - true - end - - test "can get paged notifications" do - # - true - end - end end diff --git a/test/groupher_server_web/query/accounts/mailbox_test.exs b/test/groupher_server_web/query/accounts/mailbox_test.exs index abc679f2c..7e7e29924 100644 --- a/test/groupher_server_web/query/accounts/mailbox_test.exs +++ b/test/groupher_server_web/query/accounts/mailbox_test.exs @@ -5,7 +5,7 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do {:ok, user} = db_insert(:user) {:ok, user2} = db_insert(:user) - user_conn = simu_conn(:user) + user_conn = simu_conn(:user, user) guest_conn = simu_conn(:guest) {:ok, ~m(user_conn guest_conn user user2)a} @@ -25,10 +25,8 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do } } """ - @tag :wip - test "auth user can get it's own default mailbox status", ~m(user)a do - user_conn = simu_conn(:user, user) - + @tag :wip2 + test "auth user can get it's own default mailbox status", ~m(user_conn user)a do results = user_conn |> query_result(@query, %{login: user.login}, "user") mailbox = results["mailbox"] @@ -38,12 +36,11 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do assert mailbox["unreadNotificationsCount"] == 0 end - @tag :wip - test "auth user can get latest mailbox status after being mentioned", ~m(user user2)a do + @tag :wip2 + test "auth user can get latest mailbox status after being mentioned", + ~m(user_conn user user2)a do {:ok, _} = mock_mention_for(user, user2) - user_conn = simu_conn(:user, user) - results = user_conn |> query_result(@query, %{login: user.login}, "user") mailbox = results["mailbox"] @@ -53,12 +50,11 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do assert mailbox["unreadNotificationsCount"] == 0 end - @tag :wip - test "auth user can get latest mailbox status after being notified", ~m(user user2)a do + @tag :wip2 + test "auth user can get latest mailbox status after being notified", + ~m(user_conn user user2)a do mock_notification_for(user, user2) - user_conn = simu_conn(:user, user) - results = user_conn |> query_result(@query, %{login: user.login}, "user") mailbox = results["mailbox"] @@ -69,6 +65,49 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do end end + describe "[paged messages]" do + @query """ + query($filter: MailboxMentionsFilter!) { + pagedMentions(filter: $filter) { + entries { + id + thread + articleId + title + commentId + read + blockLinker + user { + login + nickname + } + } + totalPages + totalCount + pageSize + pageNumber + } + } + """ + @tag :wip + test "can get paged mentions", ~m(user_conn user user2)a do + mock_mention_for(user, user2) + + varibles = %{filter: %{page: 1, size: 20}} + + results = user_conn |> query_result(@query, varibles, "pagedMentions") + + assert results |> is_valid_pagination? + mention = results["entries"] |> List.first() + assert user2.login == mention |> get_in(["user", "login"]) + end + + test "can get paged notifications" do + # + true + end + end + # describe "[accounts mention]" do # @query """ # query($filter: MessagesFilter!) { From 28ecfe57d512c46f028b1e635125cadcd1519c32 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 22 Jun 2021 14:55:39 +0800 Subject: [PATCH 51/54] refactor(mailbox): paged notification & test --- .../resolvers/accounts_resolver.ex | 5 +- .../schema/account/account_metrics.ex | 5 ++ .../schema/account/account_queries.ex | 9 ++ .../schema/account/account_types.ex | 19 ++++ .../query/accounts/mailbox_test.exs | 89 +++++++------------ 5 files changed, 71 insertions(+), 56 deletions(-) diff --git a/lib/groupher_server_web/resolvers/accounts_resolver.ex b/lib/groupher_server_web/resolvers/accounts_resolver.ex index 2a9ee1320..e924144c4 100644 --- a/lib/groupher_server_web/resolvers/accounts_resolver.ex +++ b/lib/groupher_server_web/resolvers/accounts_resolver.ex @@ -234,10 +234,13 @@ defmodule GroupherServerWeb.Resolvers.Accounts do end def paged_mailbox_mentions(_root, ~m(filter)a, %{context: %{cur_user: cur_user}}) do - IO.inspect(cur_user.login, label: "in resolver") Accounts.paged_mailbox_messages(:mention, cur_user, filter) end + def paged_mailbox_notifications(_root, ~m(filter)a, %{context: %{cur_user: cur_user}}) do + Accounts.paged_mailbox_messages(:notification, cur_user, filter) + end + # mailbox end # for check other users subscribed_communities diff --git a/lib/groupher_server_web/schema/account/account_metrics.ex b/lib/groupher_server_web/schema/account/account_metrics.ex index 40b7e291a..aece6f296 100644 --- a/lib/groupher_server_web/schema/account/account_metrics.ex +++ b/lib/groupher_server_web/schema/account/account_metrics.ex @@ -9,6 +9,11 @@ defmodule GroupherServerWeb.Schema.Account.Metrics do pagination_args() end + input_object :mailbox_notifications_filter do + field(:read, :boolean, default_value: false) + pagination_args() + end + @desc "article_filter doc" input_object :paged_users_filter do pagination_args() diff --git a/lib/groupher_server_web/schema/account/account_queries.ex b/lib/groupher_server_web/schema/account/account_queries.ex index 652184a0b..abf429943 100644 --- a/lib/groupher_server_web/schema/account/account_queries.ex +++ b/lib/groupher_server_web/schema/account/account_queries.ex @@ -44,6 +44,15 @@ defmodule GroupherServerWeb.Schema.Account.Queries do resolve(&R.Accounts.paged_mailbox_mentions/3) end + @desc "get login user's notifications in mailbox" + field :paged_notifications, :paged_mailbox_notifications do + arg(:filter, :mailbox_notifications_filter) + + middleware(M.Authorize, :login) + middleware(M.PageSizeProof) + resolve(&R.Accounts.paged_mailbox_notifications/3) + end + @desc "get user's follower" field :paged_followers, :paged_users do arg(:login, non_null(:string)) diff --git a/lib/groupher_server_web/schema/account/account_types.ex b/lib/groupher_server_web/schema/account/account_types.ex index 59f2ecde2..268e0dbe6 100644 --- a/lib/groupher_server_web/schema/account/account_types.ex +++ b/lib/groupher_server_web/schema/account/account_types.ex @@ -112,6 +112,20 @@ defmodule GroupherServerWeb.Schema.Account.Types do timestamp_fields() end + object :mailbox_notification do + field(:id, :id) + field(:action, :string) + field(:thread, :string) + field(:article_id, :id) + field(:title, :string) + field(:comment_id, :id) + field(:read, :boolean) + + field(:from_users, list_of(:common_user)) + + timestamp_fields() + end + # field(:sidebar_layout, :map) object :customization do field(:theme, :string) @@ -220,6 +234,11 @@ defmodule GroupherServerWeb.Schema.Account.Types do pagination_fields() end + object :paged_mailbox_notifications do + field(:entries, list_of(:mailbox_notification)) + pagination_fields() + end + enum :mailbox_type do value(:mention) value(:notification) diff --git a/test/groupher_server_web/query/accounts/mailbox_test.exs b/test/groupher_server_web/query/accounts/mailbox_test.exs index 7e7e29924..8f297ae28 100644 --- a/test/groupher_server_web/query/accounts/mailbox_test.exs +++ b/test/groupher_server_web/query/accounts/mailbox_test.exs @@ -89,12 +89,11 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do } } """ - @tag :wip + @tag :wip2 test "can get paged mentions", ~m(user_conn user user2)a do mock_mention_for(user, user2) varibles = %{filter: %{page: 1, size: 20}} - results = user_conn |> query_result(@query, varibles, "pagedMentions") assert results |> is_valid_pagination? @@ -102,59 +101,39 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do assert user2.login == mention |> get_in(["user", "login"]) end - test "can get paged notifications" do - # - true + @query """ + query($filter: MailboxNotificationsFilter!) { + pagedNotifications(filter: $filter) { + entries { + id + action + thread + articleId + title + commentId + read + fromUsers { + login + nickname + } + } + totalPages + totalCount + pageSize + pageNumber + } + } + """ + + @tag :wip + test "can get paged notifications", ~m(user_conn user user2)a do + mock_notification_for(user, user2) + + varibles = %{filter: %{page: 1, size: 20}} + results = user_conn |> query_result(@query, varibles, "pagedNotifications") + + assert results |> is_valid_pagination? + assert results["totalCount"] == 1 end end - - # describe "[accounts mention]" do - # @query """ - # query($filter: MessagesFilter!) { - # mentions(filter: $filter) { - # entries { - # id - # fromUserId - # fromUser { - # id - # avatar - # nickname - # } - # toUserId - # toUser { - # id - # avatar - # nickname - # } - # sourceTitle - # sourcePreview - # sourceType - # community - # read - # } - # totalPages - # totalCount - # pageSize - # pageNumber - # } - # } - # """ - # test "auth user can get it's own mentions" do - # {:ok, [user, user2]} = db_insert_multi(:user, 2) - - # mock_mentions_for(user, 1) - # mock_mentions_for(user2, 1) - - # user_conn = simu_conn(:user, user) - - # variables = %{filter: %{page: 1, size: 20, read: false}} - # results = user_conn |> query_result(@query, variables, "mentions") - - # assert results |> is_valid_pagination? - # assert results["totalCount"] == 1 - - # assert results["entries"] |> Enum.any?(&(&1["toUserId"] == to_string(user.id))) - # assert results["entries"] |> Enum.any?(&(&1["community"] == "elixir")) - # end - # end end From 9954878cf4bed0c59e4dcd87c954d7de6923294e Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 22 Jun 2021 15:02:16 +0800 Subject: [PATCH 52/54] refactor(mailbox): read in filter --- .../query/accounts/mailbox_test.exs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/groupher_server_web/query/accounts/mailbox_test.exs b/test/groupher_server_web/query/accounts/mailbox_test.exs index 8f297ae28..95c50fc08 100644 --- a/test/groupher_server_web/query/accounts/mailbox_test.exs +++ b/test/groupher_server_web/query/accounts/mailbox_test.exs @@ -99,6 +99,12 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do assert results |> is_valid_pagination? mention = results["entries"] |> List.first() assert user2.login == mention |> get_in(["user", "login"]) + + varibles = %{filter: %{page: 1, size: 20, read: true}} + results = user_conn |> query_result(@query, varibles, "pagedMentions") + + assert results |> is_valid_pagination? + assert results["totalCount"] == 0 end @query """ @@ -134,6 +140,12 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do assert results |> is_valid_pagination? assert results["totalCount"] == 1 + + varibles = %{filter: %{page: 1, size: 20, read: true}} + results = user_conn |> query_result(@query, varibles, "pagedNotifications") + + assert results |> is_valid_pagination? + assert results["totalCount"] == 0 end end end From c85886feddc2c43c85d4a40227edba9157fda8bf Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 22 Jun 2021 15:02:51 +0800 Subject: [PATCH 53/54] refactor(mailbox): clean up wip --- test/groupher_server/accounts/mailbx_test.exs | 1 - .../groupher_server_web/mutation/accounts/mailbox_test.exs | 6 ++---- test/groupher_server_web/query/accounts/mailbox_test.exs | 7 ++----- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/test/groupher_server/accounts/mailbx_test.exs b/test/groupher_server/accounts/mailbx_test.exs index 2ed735b2d..88dc9c0c4 100644 --- a/test/groupher_server/accounts/mailbx_test.exs +++ b/test/groupher_server/accounts/mailbx_test.exs @@ -17,7 +17,6 @@ defmodule GroupherServer.Test.Accounts.Mailbox do end describe "mailbox status" do - @tag :wip2 test "can get default mailbox status", ~m(user)a do {:ok, status} = Accounts.mailbox_status(user) assert status == @default_mailbox_status diff --git a/test/groupher_server_web/mutation/accounts/mailbox_test.exs b/test/groupher_server_web/mutation/accounts/mailbox_test.exs index 00fca24e6..6a7f82312 100644 --- a/test/groupher_server_web/mutation/accounts/mailbox_test.exs +++ b/test/groupher_server_web/mutation/accounts/mailbox_test.exs @@ -22,7 +22,7 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do } } """ - # @tag :wip2 + # test "can mark read a mention", ~m(user_conn user user2)a do {:ok, _} = mock_mention_for(user, user2) @@ -37,7 +37,6 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do assert mention.read end - @tag :wip2 test "can mark read a notification", ~m(user_conn user user2)a do {:ok, _} = mock_notification_for(user, user2) @@ -60,7 +59,7 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do } } """ - @tag :wip2 + test "can mark read all mentions", ~m(user_conn user user2 user3)a do {:ok, _} = mock_mention_for(user, user2) {:ok, _} = mock_mention_for(user, user3) @@ -75,7 +74,6 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do assert mentions.total_count == 2 end - @tag :wip2 test "can mark read all notifications", ~m(user_conn user user2)a do {:ok, _} = mock_notification_for(user, user2) diff --git a/test/groupher_server_web/query/accounts/mailbox_test.exs b/test/groupher_server_web/query/accounts/mailbox_test.exs index 95c50fc08..4bdd28404 100644 --- a/test/groupher_server_web/query/accounts/mailbox_test.exs +++ b/test/groupher_server_web/query/accounts/mailbox_test.exs @@ -25,7 +25,7 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do } } """ - @tag :wip2 + test "auth user can get it's own default mailbox status", ~m(user_conn user)a do results = user_conn |> query_result(@query, %{login: user.login}, "user") mailbox = results["mailbox"] @@ -36,7 +36,6 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do assert mailbox["unreadNotificationsCount"] == 0 end - @tag :wip2 test "auth user can get latest mailbox status after being mentioned", ~m(user_conn user user2)a do {:ok, _} = mock_mention_for(user, user2) @@ -50,7 +49,6 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do assert mailbox["unreadNotificationsCount"] == 0 end - @tag :wip2 test "auth user can get latest mailbox status after being notified", ~m(user_conn user user2)a do mock_notification_for(user, user2) @@ -89,7 +87,7 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do } } """ - @tag :wip2 + test "can get paged mentions", ~m(user_conn user user2)a do mock_mention_for(user, user2) @@ -131,7 +129,6 @@ defmodule GroupherServer.Test.Query.Accounts.Mailbox do } """ - @tag :wip test "can get paged notifications", ~m(user_conn user user2)a do mock_notification_for(user, user2) From 1bf1976622e36e8990dc4aa2d4c96990f30ea0de Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 22 Jun 2021 15:11:21 +0800 Subject: [PATCH 54/54] refactor(mailbox): fix tests --- test/groupher_server/cms/hooks/notify_blog_test.exs | 6 +++--- test/groupher_server/cms/hooks/notify_job_test.exs | 7 +++---- test/groupher_server/cms/hooks/notify_post_test.exs | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/test/groupher_server/cms/hooks/notify_blog_test.exs b/test/groupher_server/cms/hooks/notify_blog_test.exs index dc03a0fe2..b0f32d64e 100644 --- a/test/groupher_server/cms/hooks/notify_blog_test.exs +++ b/test/groupher_server/cms/hooks/notify_blog_test.exs @@ -3,7 +3,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] - alias GroupherServer.{CMS, Delivery} + alias GroupherServer.{CMS, Delivery, Repo} alias CMS.Delegate.Hooks setup do @@ -149,8 +149,8 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyBlog do Hooks.Notify.handle(:reply, replyed_comment, user3) - {:ok, notifications} = - Delivery.fetch(:notification, comment.author_id, %{page: 1, size: 20}) + comment = Repo.preload(comment, :author) + {:ok, notifications} = Delivery.fetch(:notification, comment.author, %{page: 1, size: 20}) assert notifications.total_count == 1 diff --git a/test/groupher_server/cms/hooks/notify_job_test.exs b/test/groupher_server/cms/hooks/notify_job_test.exs index 02db6ea6a..e283922df 100644 --- a/test/groupher_server/cms/hooks/notify_job_test.exs +++ b/test/groupher_server/cms/hooks/notify_job_test.exs @@ -3,7 +3,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] - alias GroupherServer.{CMS, Delivery} + alias GroupherServer.{CMS, Delivery, Repo} alias CMS.Delegate.Hooks setup do @@ -81,7 +81,6 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do Hooks.Notify.handle(:undo, :upvote, comment, user2) {:ok, comment} = preload_author(comment) - {:ok, notifications} = Delivery.fetch(:notification, comment.author, %{page: 1, size: 20}) assert notifications.total_count == 0 @@ -149,8 +148,8 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyJob do Hooks.Notify.handle(:reply, replyed_comment, user3) - {:ok, notifications} = - Delivery.fetch(:notification, comment.author_id, %{page: 1, size: 20}) + comment = Repo.preload(comment, :author) + {:ok, notifications} = Delivery.fetch(:notification, comment.author, %{page: 1, size: 20}) assert notifications.total_count == 1 diff --git a/test/groupher_server/cms/hooks/notify_post_test.exs b/test/groupher_server/cms/hooks/notify_post_test.exs index ca54aadbe..77504cad9 100644 --- a/test/groupher_server/cms/hooks/notify_post_test.exs +++ b/test/groupher_server/cms/hooks/notify_post_test.exs @@ -3,7 +3,7 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do import GroupherServer.CMS.Delegate.Helper, only: [preload_author: 1] - alias GroupherServer.{CMS, Delivery} + alias GroupherServer.{CMS, Delivery, Repo} alias CMS.Delegate.Hooks setup do @@ -149,8 +149,8 @@ defmodule GroupherServer.Test.CMS.Hooks.NotifyPost do Hooks.Notify.handle(:reply, replyed_comment, user3) - {:ok, notifications} = - Delivery.fetch(:notification, comment.author_id, %{page: 1, size: 20}) + comment = Repo.preload(comment, :author) + {:ok, notifications} = Delivery.fetch(:notification, comment.author, %{page: 1, size: 20}) assert notifications.total_count == 1