From d4270397dcb2aebde8ed14fd89998ab57aaae545 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 22 Oct 2019 13:42:59 +0300 Subject: Marker: added unread_count field --- lib/pleroma/marker.ex | 5 +++-- lib/pleroma/web/mastodon_api/views/marker_view.ex | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex index 7f87c86c3..c4d554980 100644 --- a/lib/pleroma/marker.ex +++ b/lib/pleroma/marker.ex @@ -18,6 +18,7 @@ defmodule Pleroma.Marker do field(:last_read_id, :string, default: "") field(:timeline, :string, default: "") field(:lock_version, :integer, default: 0) + field(:unread_count, :integer, default: 0) belongs_to(:user, User, type: FlakeId.Ecto.CompatType) timestamps() @@ -38,7 +39,7 @@ defmodule Pleroma.Marker do Multi.insert(multi, timeline, marker, returning: true, - on_conflict: {:replace, [:last_read_id]}, + on_conflict: {:replace, [:last_read_id, :unread_count]}, conflict_target: [:user_id, :timeline] ) end) @@ -55,7 +56,7 @@ defmodule Pleroma.Marker do @doc false defp changeset(marker, attrs) do marker - |> cast(attrs, [:last_read_id]) + |> cast(attrs, [:last_read_id, :unread_count]) |> validate_required([:user_id, :timeline, :last_read_id]) |> validate_inclusion(:timeline, @timelines) end diff --git a/lib/pleroma/web/mastodon_api/views/marker_view.ex b/lib/pleroma/web/mastodon_api/views/marker_view.ex index 38fbeed5f..1501c2a30 100644 --- a/lib/pleroma/web/mastodon_api/views/marker_view.ex +++ b/lib/pleroma/web/mastodon_api/views/marker_view.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Web.MastodonAPI.MarkerView do Map.put_new(acc, m.timeline, %{ last_read_id: m.last_read_id, version: m.lock_version, + unread_count: m.unread_count, updated_at: NaiveDateTime.to_iso8601(m.updated_at) }) end) -- cgit v1.2.3 From 9a4afbd2a0486238bfaf4047d91376d32635514a Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 22 Oct 2019 16:13:22 +0300 Subject: added update unread_count for notifications --- lib/pleroma/marker.ex | 36 ++++++++++++++++++++++++++++++++ lib/pleroma/notification.ex | 50 ++++++++++++++++++++++++++++++--------------- 2 files changed, 69 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex index c4d554980..4b8198690 100644 --- a/lib/pleroma/marker.ex +++ b/lib/pleroma/marker.ex @@ -11,6 +11,7 @@ defmodule Pleroma.Marker do alias Ecto.Multi alias Pleroma.Repo alias Pleroma.User + alias __MODULE__ @timelines ["notifications"] @@ -46,6 +47,41 @@ defmodule Pleroma.Marker do |> Repo.transaction() end + @spec multi_set_unread_count(Multi.t(), User.t(), String.t()) :: Multi.t() + def multi_set_unread_count(multi, %User{} = user, "notifications") do + multi + |> Multi.run(:counters, fn _repo, _changes -> + query = + from(q in Pleroma.Notification, + where: q.user_id == ^user.id, + select: %{ + timeline: "notifications", + user_id: ^user.id, + unread_count: fragment("SUM( CASE WHEN seen = false THEN 1 ELSE 0 END ) as unread_count") + } + ) + + {:ok, Repo.one(query)} + end) + |> Multi.insert( + :marker, + fn %{counters: attrs} -> + Marker + |> struct(attrs) + |> Ecto.Changeset.change() + end, + returning: true, + on_conflict: {:replace, [:last_read_id, :unread_count]}, + conflict_target: [:user_id, :timeline] + ) + end + + def set_unread_count(%User{} = user, timeline) do + Multi.new() + |> multi_set_unread_count(user, timeline) + |> Repo.transaction() + end + defp get_marker(user, timeline) do case Repo.find_resource(get_query(user, timeline)) do {:ok, marker} -> %__MODULE__{marker | user: user} diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index e5da1492b..d339fdf64 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -5,7 +5,9 @@ defmodule Pleroma.Notification do use Ecto.Schema + alias Ecto.Multi alias Pleroma.Activity + alias Pleroma.Marker alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Pagination @@ -151,25 +153,23 @@ defmodule Pleroma.Notification do |> Repo.all() end - def set_read_up_to(%{id: user_id} = _user, id) do + def set_read_up_to(%{id: user_id} = user, id) do query = from( n in Notification, where: n.user_id == ^user_id, where: n.id <= ^id, where: n.seen == false, - update: [ - set: [ - seen: true, - updated_at: ^NaiveDateTime.utc_now() - ] - ], # Ideally we would preload object and activities here # but Ecto does not support preloads in update_all select: n.id ) - {_, notification_ids} = Repo.update_all(query, []) + {:ok, %{ids: {_, notification_ids}}} = + Multi.new() + |> Multi.update_all(:ids, query, set: [seen: true, updated_at: NaiveDateTime.utc_now()]) + |> Marker.multi_set_unread_count(user, "notifications") + |> Repo.transaction() Notification |> where([n], n.id in ^notification_ids) @@ -186,11 +186,18 @@ defmodule Pleroma.Notification do |> Repo.all() end + @spec read_one(User.t(), String.t()) :: + {:ok, Notification.t()} | {:error, Ecto.Changeset.t()} | nil def read_one(%User{} = user, notification_id) do with {:ok, %Notification{} = notification} <- get(user, notification_id) do - notification - |> changeset(%{seen: true}) - |> Repo.update() + Multi.new() + |> Multi.update(:update, changeset(notification, %{seen: true})) + |> Marker.multi_set_unread_count(user, "notifications") + |> Repo.transaction() + |> case do + {:ok, %{update: notification}} -> {:ok, notification} + {:error, :update, changeset, _} -> {:error, changeset} + end end end @@ -243,8 +250,11 @@ defmodule Pleroma.Notification do object = Object.normalize(activity) unless object && object.data["type"] == "Answer" do - users = get_notified_from_activity(activity) - notifications = Enum.map(users, fn user -> create_notification(activity, user) end) + notifications = + activity + |> get_notified_from_activity() + |> Enum.map(&create_notification(activity, &1)) + {:ok, notifications} else {:ok, []} @@ -253,8 +263,11 @@ defmodule Pleroma.Notification do def create_notifications(%Activity{data: %{"to" => _, "type" => type}} = activity) when type in ["Like", "Announce", "Follow"] do - users = get_notified_from_activity(activity) - notifications = Enum.map(users, fn user -> create_notification(activity, user) end) + notifications = + activity + |> get_notified_from_activity + |> Enum.map(&create_notification(activity, &1)) + {:ok, notifications} end @@ -263,8 +276,11 @@ defmodule Pleroma.Notification do # TODO move to sql, too. def create_notification(%Activity{} = activity, %User{} = user) do unless skip?(activity, user) do - notification = %Notification{user_id: user.id, activity: activity} - {:ok, notification} = Repo.insert(notification) + {:ok, %{notification: notification}} = + Multi.new() + |> Multi.insert(:notification, %Notification{user_id: user.id, activity: activity}) + |> Marker.multi_set_unread_count(user, "notifications") + |> Repo.transaction() ["user", "user:notification"] |> Streamer.stream(notification) -- cgit v1.2.3 From aa64b3108ba6aa4294e541e86da323ba1e1a7243 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 23 Oct 2019 11:54:52 +0300 Subject: fix migrate --- lib/pleroma/marker.ex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex index 4b8198690..098fe3bbd 100644 --- a/lib/pleroma/marker.ex +++ b/lib/pleroma/marker.ex @@ -56,8 +56,9 @@ defmodule Pleroma.Marker do where: q.user_id == ^user.id, select: %{ timeline: "notifications", - user_id: ^user.id, - unread_count: fragment("SUM( CASE WHEN seen = false THEN 1 ELSE 0 END ) as unread_count") + user_id: type(^user.id, :string), + unread_count: fragment("SUM( CASE WHEN seen = false THEN 1 ELSE 0 END )"), + last_read_id: type(fragment("MAX( CASE WHEN seen = true THEN id ELSE null END )"), :string) } ) -- cgit v1.2.3 From d3fb9e02cc0ce7dc462e587e639e117aaef5fbc5 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 23 Oct 2019 22:48:04 +0300 Subject: add tests --- lib/pleroma/marker.ex | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex index 098fe3bbd..5f6a47f38 100644 --- a/lib/pleroma/marker.ex +++ b/lib/pleroma/marker.ex @@ -58,7 +58,8 @@ defmodule Pleroma.Marker do timeline: "notifications", user_id: type(^user.id, :string), unread_count: fragment("SUM( CASE WHEN seen = false THEN 1 ELSE 0 END )"), - last_read_id: type(fragment("MAX( CASE WHEN seen = true THEN id ELSE null END )"), :string) + last_read_id: + type(fragment("MAX( CASE WHEN seen = true THEN id ELSE null END )"), :string) } ) @@ -77,11 +78,7 @@ defmodule Pleroma.Marker do ) end - def set_unread_count(%User{} = user, timeline) do - Multi.new() - |> multi_set_unread_count(user, timeline) - |> Repo.transaction() - end + def multi_set_unread_count(multi, _, _), do: multi defp get_marker(user, timeline) do case Repo.find_resource(get_query(user, timeline)) do -- cgit v1.2.3 From 922e3d082c38ccd108710e21d4bda8e65b551f9c Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Thu, 24 Oct 2019 09:50:41 +0300 Subject: add test --- lib/pleroma/marker.ex | 14 +------------- lib/pleroma/notification.ex | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex index 5f6a47f38..a7ea542dd 100644 --- a/lib/pleroma/marker.ex +++ b/lib/pleroma/marker.ex @@ -51,19 +51,7 @@ defmodule Pleroma.Marker do def multi_set_unread_count(multi, %User{} = user, "notifications") do multi |> Multi.run(:counters, fn _repo, _changes -> - query = - from(q in Pleroma.Notification, - where: q.user_id == ^user.id, - select: %{ - timeline: "notifications", - user_id: type(^user.id, :string), - unread_count: fragment("SUM( CASE WHEN seen = false THEN 1 ELSE 0 END )"), - last_read_id: - type(fragment("MAX( CASE WHEN seen = true THEN id ELSE null END )"), :string) - } - ) - - {:ok, Repo.one(query)} + {:ok, Repo.one(Pleroma.Notification.notifications_info_query(user))} end) |> Multi.insert( :marker, diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index af56cc667..373f9b06a 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -36,6 +36,20 @@ defmodule Pleroma.Notification do |> cast(attrs, [:seen]) end + @spec notifications_info_query(User.t()) :: Ecto.Queryable.t() + def notifications_info_query(user) do + from(q in Pleroma.Notification, + where: q.user_id == ^user.id, + select: %{ + timeline: "notifications", + user_id: type(^user.id, :string), + unread_count: fragment("SUM( CASE WHEN seen = false THEN 1 ELSE 0 END )"), + last_read_id: + type(fragment("MAX( CASE WHEN seen = true THEN id ELSE null END )"), :string) + } + ) + end + def for_user_query(user, opts \\ []) do Notification |> where(user_id: ^user.id) -- cgit v1.2.3 From 1b82eb6d4102bc2d7acec0a905e7714c95eadc94 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 30 Oct 2019 23:22:38 +0300 Subject: move sql (update_markers) from migrate to mix task --- lib/mix/tasks/pleroma/marker.ex | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 lib/mix/tasks/pleroma/marker.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/marker.ex b/lib/mix/tasks/pleroma/marker.ex new file mode 100644 index 000000000..1d5be11de --- /dev/null +++ b/lib/mix/tasks/pleroma/marker.ex @@ -0,0 +1,36 @@ +defmodule Mix.Tasks.Pleroma.Marker do + use Mix.Task + import Mix.Pleroma + + import Ecto.Query + alias Pleroma.Repo + alias Pleroma.Notification + + def run(["update_markers"]) do + start_pleroma() + + from(q in Notification, + select: %{ + timeline: "notifications", + user_id: q.user_id, + unread_count: fragment("SUM( CASE WHEN seen = false THEN 1 ELSE 0 END )"), + last_read_id: + type(fragment("MAX( CASE WHEN seen = true THEN id ELSE null END )"), :string) + }, + group_by: [q.user_id] + ) + |> Repo.all() + |> Enum.each(fn attrs -> + Pleroma.Marker + |> struct(attrs) + |> Ecto.Changeset.change() + |> Pleroma.Repo.insert( + returning: true, + on_conflict: {:replace, [:last_read_id, :unread_count]}, + conflict_target: [:user_id, :timeline] + ) + end) + + shell_info("Done") + end +end -- cgit v1.2.3 From 209319c8d289564653f73cbf15fb6449d91cf3ca Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 30 Oct 2019 23:49:05 +0300 Subject: update marker api --- lib/pleroma/web/mastodon_api/views/marker_view.ex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/marker_view.ex b/lib/pleroma/web/mastodon_api/views/marker_view.ex index 1501c2a30..81545cff0 100644 --- a/lib/pleroma/web/mastodon_api/views/marker_view.ex +++ b/lib/pleroma/web/mastodon_api/views/marker_view.ex @@ -10,8 +10,10 @@ defmodule Pleroma.Web.MastodonAPI.MarkerView do Map.put_new(acc, m.timeline, %{ last_read_id: m.last_read_id, version: m.lock_version, - unread_count: m.unread_count, - updated_at: NaiveDateTime.to_iso8601(m.updated_at) + updated_at: NaiveDateTime.to_iso8601(m.updated_at), + pleroma: %{ + unread_count: m.unread_count + } }) end) end -- cgit v1.2.3 From 1b3a942a84b8b612e07e3bf34801137741926911 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Thu, 31 Oct 2019 17:36:59 +0300 Subject: fix format --- lib/mix/tasks/pleroma/marker.ex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/marker.ex b/lib/mix/tasks/pleroma/marker.ex index 1d5be11de..bebef0d6a 100644 --- a/lib/mix/tasks/pleroma/marker.ex +++ b/lib/mix/tasks/pleroma/marker.ex @@ -1,10 +1,10 @@ defmodule Mix.Tasks.Pleroma.Marker do use Mix.Task import Mix.Pleroma - import Ecto.Query - alias Pleroma.Repo + alias Pleroma.Notification + alias Pleroma.Repo def run(["update_markers"]) do start_pleroma() @@ -15,7 +15,7 @@ defmodule Mix.Tasks.Pleroma.Marker do user_id: q.user_id, unread_count: fragment("SUM( CASE WHEN seen = false THEN 1 ELSE 0 END )"), last_read_id: - type(fragment("MAX( CASE WHEN seen = true THEN id ELSE null END )"), :string) + type(fragment("MAX( CASE WHEN seen = true THEN id ELSE null END )"), :string) }, group_by: [q.user_id] ) @@ -26,8 +26,8 @@ defmodule Mix.Tasks.Pleroma.Marker do |> Ecto.Changeset.change() |> Pleroma.Repo.insert( returning: true, - on_conflict: {:replace, [:last_read_id, :unread_count]}, - conflict_target: [:user_id, :timeline] + on_conflict: {:replace, [:last_read_id, :unread_count]}, + conflict_target: [:user_id, :timeline] ) end) -- cgit v1.2.3 From 57995fa8cf26c9d5cd31969b59dbafb9f8c8fdc7 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Sat, 2 Nov 2019 21:19:01 +0300 Subject: fix migrate update migrate --- lib/mix/tasks/pleroma/marker.ex | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 lib/mix/tasks/pleroma/marker.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/marker.ex b/lib/mix/tasks/pleroma/marker.ex deleted file mode 100644 index bebef0d6a..000000000 --- a/lib/mix/tasks/pleroma/marker.ex +++ /dev/null @@ -1,36 +0,0 @@ -defmodule Mix.Tasks.Pleroma.Marker do - use Mix.Task - import Mix.Pleroma - import Ecto.Query - - alias Pleroma.Notification - alias Pleroma.Repo - - def run(["update_markers"]) do - start_pleroma() - - from(q in Notification, - select: %{ - timeline: "notifications", - user_id: q.user_id, - unread_count: fragment("SUM( CASE WHEN seen = false THEN 1 ELSE 0 END )"), - last_read_id: - type(fragment("MAX( CASE WHEN seen = true THEN id ELSE null END )"), :string) - }, - group_by: [q.user_id] - ) - |> Repo.all() - |> Enum.each(fn attrs -> - Pleroma.Marker - |> struct(attrs) - |> Ecto.Changeset.change() - |> Pleroma.Repo.insert( - returning: true, - on_conflict: {:replace, [:last_read_id, :unread_count]}, - conflict_target: [:user_id, :timeline] - ) - end) - - shell_info("Done") - end -end -- cgit v1.2.3 From ddbfc995ac40db9bd1da137b03e5acf6d050ddc5 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 11 Nov 2019 17:06:41 +0300 Subject: clean sql query --- lib/pleroma/marker.ex | 2 +- lib/pleroma/notification.ex | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex index a7ea542dd..d5ca27bf2 100644 --- a/lib/pleroma/marker.ex +++ b/lib/pleroma/marker.ex @@ -56,7 +56,7 @@ defmodule Pleroma.Marker do |> Multi.insert( :marker, fn %{counters: attrs} -> - Marker + %Marker{timeline: "notifications", user_id: user.id} |> struct(attrs) |> Ecto.Changeset.change() end, diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 373f9b06a..158903c4b 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -41,8 +41,6 @@ defmodule Pleroma.Notification do from(q in Pleroma.Notification, where: q.user_id == ^user.id, select: %{ - timeline: "notifications", - user_id: type(^user.id, :string), unread_count: fragment("SUM( CASE WHEN seen = false THEN 1 ELSE 0 END )"), last_read_id: type(fragment("MAX( CASE WHEN seen = true THEN id ELSE null END )"), :string) -- cgit v1.2.3 From b5b62f42b2864dc8b95c8ba7d650321ebcc332ad Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 12 Nov 2019 15:59:34 +0300 Subject: update Marker.multi_set_unread_count --- lib/pleroma/marker.ex | 7 ++++++- lib/pleroma/notification.ex | 21 ++++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex index d5ca27bf2..a32546094 100644 --- a/lib/pleroma/marker.ex +++ b/lib/pleroma/marker.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Marker do import Ecto.Query alias Ecto.Multi + alias Pleroma.Notification alias Pleroma.Repo alias Pleroma.User alias __MODULE__ @@ -51,7 +52,11 @@ defmodule Pleroma.Marker do def multi_set_unread_count(multi, %User{} = user, "notifications") do multi |> Multi.run(:counters, fn _repo, _changes -> - {:ok, Repo.one(Pleroma.Notification.notifications_info_query(user))} + {:ok, + %{ + unread_count: Repo.aggregate(Notification.unread_count_query(user), :count, :id), + last_read_id: Repo.one(Notification.last_read_query(user)) + }} end) |> Multi.insert( :marker, diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 158903c4b..1cc6a4735 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -36,15 +36,22 @@ defmodule Pleroma.Notification do |> cast(attrs, [:seen]) end - @spec notifications_info_query(User.t()) :: Ecto.Queryable.t() - def notifications_info_query(user) do + @spec unread_count_query(User.t()) :: Ecto.Queryable.t() + def unread_count_query(user) do from(q in Pleroma.Notification, where: q.user_id == ^user.id, - select: %{ - unread_count: fragment("SUM( CASE WHEN seen = false THEN 1 ELSE 0 END )"), - last_read_id: - type(fragment("MAX( CASE WHEN seen = true THEN id ELSE null END )"), :string) - } + where: q.seen == false + ) + end + + @spec last_read_query(User.t()) :: Ecto.Queryable.t() + def last_read_query(user) do + from(q in Pleroma.Notification, + where: q.user_id == ^user.id, + where: q.seen == true, + select: type(q.id, :string), + limit: 1, + order_by: [desc: :id] ) end -- cgit v1.2.3 From b9041c209787dc279d4dc5194d65dff73684cdb9 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Fri, 15 Nov 2019 22:10:41 +0300 Subject: added recount unread notifications to markers --- lib/pleroma/marker.ex | 29 ++++++++++++++++++++-- .../mastodon_api/controllers/marker_controller.ex | 8 +++++- 2 files changed, 34 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex index a32546094..2d217a0b7 100644 --- a/lib/pleroma/marker.ex +++ b/lib/pleroma/marker.ex @@ -15,6 +15,7 @@ defmodule Pleroma.Marker do alias __MODULE__ @timelines ["notifications"] + @type t :: %__MODULE__{} schema "markers" do field(:last_read_id, :string, default: "") @@ -26,8 +27,18 @@ defmodule Pleroma.Marker do timestamps() end - def get_markers(user, timelines \\ []) do - Repo.all(get_query(user, timelines)) + @doc """ + Gets markers by user and timeline. + + opts: + `recount_unread` - run force recount unread notifications for `true` value + """ + @spec get_markers(User.t(), list(String), map()) :: list(t()) + def get_markers(user, timelines \\ [], opts \\ %{}) do + user + |> get_query(timelines) + |> recount_unread_notifications(opts[:recount_unread]) + |> Repo.all() end def upsert(%User{} = user, attrs) do @@ -99,4 +110,18 @@ defmodule Pleroma.Marker do |> by_user_id(user.id) |> by_timeline(timelines) end + + defp recount_unread_notifications(query, true) do + from( + q in query, + left_join: n in "notifications", + on: n.user_id == q.user_id and n.seen == false, + group_by: [:id], + select_merge: %{ + unread_count: fragment("count(?)", n.id) + } + ) + end + + defp recount_unread_notifications(query, _), do: query end diff --git a/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex b/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex index ce025624d..6649ffbda 100644 --- a/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex @@ -18,7 +18,13 @@ defmodule Pleroma.Web.MastodonAPI.MarkerController do # GET /api/v1/markers def index(%{assigns: %{user: user}} = conn, params) do - markers = Pleroma.Marker.get_markers(user, params["timeline"]) + markers = + Pleroma.Marker.get_markers( + user, + params["timeline"], + %{recount_unread: true} + ) + render(conn, "markers.json", %{markers: markers}) end -- cgit v1.2.3 From cd040691bd28fea1437b8f1c39bb914465e1ff46 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 10 Feb 2020 09:01:45 +0300 Subject: maked `unread_count` as virtual field --- lib/pleroma/marker.ex | 31 +++++++++------------- lib/pleroma/notification.ex | 14 +++------- .../mastodon_api/controllers/marker_controller.ex | 8 +----- 3 files changed, 17 insertions(+), 36 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex index 2d217a0b7..dab97d8b6 100644 --- a/lib/pleroma/marker.ex +++ b/lib/pleroma/marker.ex @@ -21,7 +21,7 @@ defmodule Pleroma.Marker do field(:last_read_id, :string, default: "") field(:timeline, :string, default: "") field(:lock_version, :integer, default: 0) - field(:unread_count, :integer, default: 0) + field(:unread_count, :integer, default: 0, virtual: true) belongs_to(:user, User, type: FlakeId.Ecto.CompatType) timestamps() @@ -33,14 +33,15 @@ defmodule Pleroma.Marker do opts: `recount_unread` - run force recount unread notifications for `true` value """ - @spec get_markers(User.t(), list(String), map()) :: list(t()) - def get_markers(user, timelines \\ [], opts \\ %{}) do + @spec get_markers(User.t(), list(String)) :: list(t()) + def get_markers(user, timelines \\ []) do user |> get_query(timelines) - |> recount_unread_notifications(opts[:recount_unread]) + |> unread_count_query() |> Repo.all() end + @spec upsert(User.t(), map()) :: {:ok | :error, any()} def upsert(%User{} = user, attrs) do attrs |> Map.take(@timelines) @@ -52,22 +53,18 @@ defmodule Pleroma.Marker do Multi.insert(multi, timeline, marker, returning: true, - on_conflict: {:replace, [:last_read_id, :unread_count]}, + on_conflict: {:replace, [:last_read_id]}, conflict_target: [:user_id, :timeline] ) end) |> Repo.transaction() end - @spec multi_set_unread_count(Multi.t(), User.t(), String.t()) :: Multi.t() - def multi_set_unread_count(multi, %User{} = user, "notifications") do + @spec multi_set_last_read_id(Multi.t(), User.t(), String.t()) :: Multi.t() + def multi_set_last_read_id(multi, %User{} = user, "notifications") do multi |> Multi.run(:counters, fn _repo, _changes -> - {:ok, - %{ - unread_count: Repo.aggregate(Notification.unread_count_query(user), :count, :id), - last_read_id: Repo.one(Notification.last_read_query(user)) - }} + {:ok, %{last_read_id: Repo.one(Notification.last_read_query(user))}} end) |> Multi.insert( :marker, @@ -77,12 +74,12 @@ defmodule Pleroma.Marker do |> Ecto.Changeset.change() end, returning: true, - on_conflict: {:replace, [:last_read_id, :unread_count]}, + on_conflict: {:replace, [:last_read_id]}, conflict_target: [:user_id, :timeline] ) end - def multi_set_unread_count(multi, _, _), do: multi + def multi_set_last_read_id(multi, _, _), do: multi defp get_marker(user, timeline) do case Repo.find_resource(get_query(user, timeline)) do @@ -94,7 +91,7 @@ defmodule Pleroma.Marker do @doc false defp changeset(marker, attrs) do marker - |> cast(attrs, [:last_read_id, :unread_count]) + |> cast(attrs, [:last_read_id]) |> validate_required([:user_id, :timeline, :last_read_id]) |> validate_inclusion(:timeline, @timelines) end @@ -111,7 +108,7 @@ defmodule Pleroma.Marker do |> by_timeline(timelines) end - defp recount_unread_notifications(query, true) do + defp unread_count_query(query) do from( q in query, left_join: n in "notifications", @@ -122,6 +119,4 @@ defmodule Pleroma.Marker do } ) end - - defp recount_unread_notifications(query, _), do: query end diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 2e4fe2edb..70fd97bfa 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -38,14 +38,6 @@ defmodule Pleroma.Notification do |> cast(attrs, [:seen]) end - @spec unread_count_query(User.t()) :: Ecto.Queryable.t() - def unread_count_query(user) do - from(q in Pleroma.Notification, - where: q.user_id == ^user.id, - where: q.seen == false - ) - end - @spec last_read_query(User.t()) :: Ecto.Queryable.t() def last_read_query(user) do from(q in Pleroma.Notification, @@ -229,7 +221,7 @@ defmodule Pleroma.Notification do {:ok, %{ids: {_, notification_ids}}} = Multi.new() |> Multi.update_all(:ids, query, set: [seen: true, updated_at: NaiveDateTime.utc_now()]) - |> Marker.multi_set_unread_count(user, "notifications") + |> Marker.multi_set_last_read_id(user, "notifications") |> Repo.transaction() Notification @@ -253,7 +245,7 @@ defmodule Pleroma.Notification do with {:ok, %Notification{} = notification} <- get(user, notification_id) do Multi.new() |> Multi.update(:update, changeset(notification, %{seen: true})) - |> Marker.multi_set_unread_count(user, "notifications") + |> Marker.multi_set_last_read_id(user, "notifications") |> Repo.transaction() |> case do {:ok, %{update: notification}} -> {:ok, notification} @@ -340,7 +332,7 @@ defmodule Pleroma.Notification do {:ok, %{notification: notification}} = Multi.new() |> Multi.insert(:notification, %Notification{user_id: user.id, activity: activity}) - |> Marker.multi_set_unread_count(user, "notifications") + |> Marker.multi_set_last_read_id(user, "notifications") |> Repo.transaction() ["user", "user:notification"] diff --git a/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex b/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex index 6649ffbda..ce025624d 100644 --- a/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex @@ -18,13 +18,7 @@ defmodule Pleroma.Web.MastodonAPI.MarkerController do # GET /api/v1/markers def index(%{assigns: %{user: user}} = conn, params) do - markers = - Pleroma.Marker.get_markers( - user, - params["timeline"], - %{recount_unread: true} - ) - + markers = Pleroma.Marker.get_markers(user, params["timeline"]) render(conn, "markers.json", %{markers: markers}) end -- cgit v1.2.3 From 3830cb538bd3aaee3fc48bc97b57230a558b98cf Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 10 Feb 2020 09:14:15 +0300 Subject: removed a comments --- lib/pleroma/marker.ex | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex index dab97d8b6..ff5f60351 100644 --- a/lib/pleroma/marker.ex +++ b/lib/pleroma/marker.ex @@ -27,12 +27,7 @@ defmodule Pleroma.Marker do timestamps() end - @doc """ - Gets markers by user and timeline. - - opts: - `recount_unread` - run force recount unread notifications for `true` value - """ + @doc "Gets markers by user and timeline." @spec get_markers(User.t(), list(String)) :: list(t()) def get_markers(user, timelines \\ []) do user -- cgit v1.2.3