From 02fc81f23ba33587e3398f20c2da94327f5ba544 Mon Sep 17 00:00:00 2001 From: "byte[]" Date: Fri, 15 Nov 2019 22:50:58 -0500 Subject: [PATCH] add notification controller --- lib/philomena/polymorphic.ex | 12 ++++++- lib/philomena/users/user.ex | 2 ++ .../controllers/notification_controller.ex | 33 +++++++++++++++++++ lib/philomena_web/router.ex | 6 ++++ .../notification/_channel.html.slime | 4 +++ .../templates/notification/_forum.html.slime | 14 ++++++++ .../notification/_gallery.html.slime | 6 ++++ .../templates/notification/_image.html.slime | 5 +++ .../notification/_notification.html.slime | 14 ++++++++ .../templates/notification/_topic.html.slime | 8 +++++ .../templates/notification/index.html.slime | 12 +++++++ lib/philomena_web/views/notification_view.ex | 16 +++++++++ 12 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 lib/philomena_web/controllers/notification_controller.ex create mode 100644 lib/philomena_web/templates/notification/_channel.html.slime create mode 100644 lib/philomena_web/templates/notification/_forum.html.slime create mode 100644 lib/philomena_web/templates/notification/_gallery.html.slime create mode 100644 lib/philomena_web/templates/notification/_image.html.slime create mode 100644 lib/philomena_web/templates/notification/_topic.html.slime create mode 100644 lib/philomena_web/templates/notification/index.html.slime create mode 100644 lib/philomena_web/views/notification_view.ex diff --git a/lib/philomena/polymorphic.ex b/lib/philomena/polymorphic.ex index b1592ced..29eee2b3 100644 --- a/lib/philomena/polymorphic.ex +++ b/lib/philomena/polymorphic.ex @@ -17,12 +17,20 @@ defmodule Philomena.Polymorphic do "User" => Philomena.Users.User } + @preloads %{ + "Comment" => [:user], + "Gallery" => [:creator], + "Image" => [:user], + "Post" => [:user], + "Topic" => [:forum, :user] + } + # Deal with Rails polymorphism BS def load_polymorphic(structs, associations) when is_list(associations) do Enum.reduce(associations, structs, fn asc, acc -> load_polymorphic(acc, asc) end) end - def load_polymorphic(structs, {name, {id, type}}) do + def load_polymorphic(structs, {name, [{id, type}]}) do modules_and_ids = structs |> Enum.group_by(&Map.get(&1, type), &Map.get(&1, id)) @@ -34,9 +42,11 @@ defmodule Philomena.Polymorphic do {nil, []} {type, ids} -> + pre = Map.get(@preloads, type, []) rows = @classes[type] |> where([m], m.id in ^ids) + |> preload(^pre) |> Repo.all() |> Map.new(fn r -> {r.id, r} end) diff --git a/lib/philomena/users/user.ex b/lib/philomena/users/user.ex index 48177bbc..f3b33adf 100644 --- a/lib/philomena/users/user.ex +++ b/lib/philomena/users/user.ex @@ -21,6 +21,8 @@ defmodule Philomena.Users.User do has_many :public_links, Philomena.UserLinks.UserLink, where: [public: true, aasm_state: "verified"] has_many :galleries, Philomena.Galleries.Gallery, foreign_key: :creator_id has_many :awards, Philomena.Badges.Award + has_many :unread_notifications, Philomena.Notifications.UnreadNotification + has_many :notifications, through: [:unread_notifications, :notification] belongs_to :current_filter, Philomena.Filters.Filter belongs_to :deleted_by_user, Philomena.Users.User diff --git a/lib/philomena_web/controllers/notification_controller.ex b/lib/philomena_web/controllers/notification_controller.ex new file mode 100644 index 00000000..bef8cd3f --- /dev/null +++ b/lib/philomena_web/controllers/notification_controller.ex @@ -0,0 +1,33 @@ +defmodule PhilomenaWeb.NotificationController do + use PhilomenaWeb, :controller + + alias Philomena.Notifications.{UnreadNotification, Notification} + alias Philomena.Polymorphic + alias Philomena.Repo + import Ecto.Query + + def index(conn, _params) do + user = conn.assigns.current_user + + notifications = + from n in Notification, + join: un in UnreadNotification, on: un.notification_id == n.id, + where: un.user_id == ^user.id + + notifications = + notifications + |> Repo.paginate(conn.assigns.scrivener) + + entries = + notifications.entries + |> Polymorphic.load_polymorphic( + actor: [actor_id: :actor_type], + actor_child: [actor_child_id: :actor_child_type] + ) + + notifications = + %{notifications | entries: entries} + + render(conn, "index.html", notifications: notifications) + end +end \ No newline at end of file diff --git a/lib/philomena_web/router.ex b/lib/philomena_web/router.ex index 3a371a9c..f4afaea7 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -49,6 +49,12 @@ defmodule PhilomenaWeb.Router do end end + scope "/", PhilomenaWeb do + pipe_through [:browser, :ensure_totp, :protected] + + resources "/notifications", NotificationController, only: [:index, :delete] + end + scope "/", PhilomenaWeb do pipe_through [:browser, :ensure_totp] diff --git a/lib/philomena_web/templates/notification/_channel.html.slime b/lib/philomena_web/templates/notification/_channel.html.slime new file mode 100644 index 00000000..18c01f84 --- /dev/null +++ b/lib/philomena_web/templates/notification/_channel.html.slime @@ -0,0 +1,4 @@ +strong> + = link @notification.actor.title, to: "#" + /= link @notification.actor.title, to: Routes.channel_path(@conn, :show, notification.actor) +=<> @notification.action diff --git a/lib/philomena_web/templates/notification/_forum.html.slime b/lib/philomena_web/templates/notification/_forum.html.slime new file mode 100644 index 00000000..81fcfcfa --- /dev/null +++ b/lib/philomena_web/templates/notification/_forum.html.slime @@ -0,0 +1,14 @@ +- forum = @notification.actor +- topic = @notification.actor_child + +=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: topic +=> @notification.action + +' titled + +strong> + = link topic.title, to: Routes.forum_topic_path(@conn, :show, forum, topic) + +' in + +=> link forum.name, to: Routes.forum_path(@conn, :show, forum) \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/_gallery.html.slime b/lib/philomena_web/templates/notification/_gallery.html.slime new file mode 100644 index 00000000..cc25b25d --- /dev/null +++ b/lib/philomena_web/templates/notification/_gallery.html.slime @@ -0,0 +1,6 @@ +=> render PhilomenaWeb.UserAttributionView, "_user.html", object: %{user: @notification.actor.creator} +=> @notification.action + +strong> + = link @notification.actor.title, to: "#" + /= link @notification.actor.title, to: Routes.gallery_path(@conn, :show, @notification.actor) \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/_image.html.slime b/lib/philomena_web/templates/notification/_image.html.slime new file mode 100644 index 00000000..7ab04e72 --- /dev/null +++ b/lib/philomena_web/templates/notification/_image.html.slime @@ -0,0 +1,5 @@ +=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @notification.actor_child +=> @notification.action + +strong + = link "##{@notification.actor_id}", to: Routes.image_path(@conn, :show, @notification.actor) <> "#comments" \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/_notification.html.slime b/lib/philomena_web/templates/notification/_notification.html.slime index e69de29b..d076099e 100644 --- a/lib/philomena_web/templates/notification/_notification.html.slime +++ b/lib/philomena_web/templates/notification/_notification.html.slime @@ -0,0 +1,14 @@ += if @notification.actor do + .block.block--fixed.flex class="js-notification-id-#{@notification.id}" + = if @notification.actor_type == "Image" and @notification.actor do + .flex.flex--centered.flex__fixed.thumb-tiny-container.spacing-right + = render PhilomenaWeb.ImageView, "_image_container.html", image: @notification.actor, size: :thumb_tiny, conn: @conn + .flex.flex--centered.flex__grow + div + => render PhilomenaWeb.NotificationView, notification_template_path(@notification.actor_type), notification: @notification + => pretty_time @notification.updated_at + .flex.flex--centered.flex--no-wrap + a.button.button--separate-right title="Delete" data-click-markread=@notification.id + i.fa.fa-trash + a.button title="Unsubscribe" data-subscription-id=@notification.actor_id data-subscription-type=@notification.actor_type data-click-togglesubscription="unwatch" data-click-hide=".js-notification-id-#{@notification.id}" + .fa.fa-bell-slash \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/_topic.html.slime b/lib/philomena_web/templates/notification/_topic.html.slime new file mode 100644 index 00000000..d2edd3bc --- /dev/null +++ b/lib/philomena_web/templates/notification/_topic.html.slime @@ -0,0 +1,8 @@ +- topic = @notification.actor +- post = @notification.actor_child + +=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: post +=> @notification.action + +strong + = link topic.title, to: Routes.forum_topic_path(@conn, :show, topic.forum, topic, post_id: post.id) <> "#post_#{post.id}" \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/index.html.slime b/lib/philomena_web/templates/notification/index.html.slime new file mode 100644 index 00000000..508a13cc --- /dev/null +++ b/lib/philomena_web/templates/notification/index.html.slime @@ -0,0 +1,12 @@ +- route = fn p -> Routes.notification_path(@conn, :index, p) end + +h1 Notification Area +.walloftext + .block__header + = render PhilomenaWeb.PaginationView, "_pagination.html", page: @notifications, route: route + + = for notification <- @notifications do + = render PhilomenaWeb.NotificationView, "_notification.html", notification: notification + +p To get notifications on new comments and forum posts, click the 'Subscribe' button in the bar at the top of an image or forum topic. You'll get notifications here for any new posts or comments. +p By default you'll be subscribed to any images or topics you reply to. You can configure this in your user settings page. diff --git a/lib/philomena_web/views/notification_view.ex b/lib/philomena_web/views/notification_view.ex new file mode 100644 index 00000000..b3ef40ce --- /dev/null +++ b/lib/philomena_web/views/notification_view.ex @@ -0,0 +1,16 @@ +defmodule PhilomenaWeb.NotificationView do + use PhilomenaWeb, :view + + @template_paths %{ + "Channel" => "_channel.html", + "Forum" => "_forum.html", + "Gallery" => "_gallery.html", + "Image" => "_image.html", + "LivestreamChannel" => "_channel.html", + "Topic" => "_topic.html" + } + + def notification_template_path(actor_type) do + @template_paths[actor_type] + end +end \ No newline at end of file