add image subscriptions

This commit is contained in:
byte[] 2019-11-17 12:50:42 -05:00
parent 29453f060f
commit 8131782a20
11 changed files with 98 additions and 82 deletions

View file

@ -8,7 +8,7 @@ import { $ } from './utils/dom';
import { fetchHtml, handleError } from './utils/requests'; import { fetchHtml, handleError } from './utils/requests';
import { showBlock } from './utils/image'; import { showBlock } from './utils/image';
import { addTag } from './tagsinput'; import { addTag } from './tagsinput';
import { toggleSubscription, markRead } from './notifications'; import { markRead } from './notifications';
// Event types and any qualifying conditions - return true to not run action // Event types and any qualifying conditions - return true to not run action
const types = { const types = {
@ -74,8 +74,6 @@ const actions = {
unfilter(data) { showBlock(data.el.closest('.image-show-container')); }, unfilter(data) { showBlock(data.el.closest('.image-show-container')); },
toggleSubscription,
markRead, markRead,
}; };

View file

@ -4,6 +4,7 @@
import { fetchJson, handleError } from './utils/requests'; import { fetchJson, handleError } from './utils/requests';
import { $, $$, hideEl, toggleEl } from './utils/dom'; import { $, $$, hideEl, toggleEl } from './utils/dom';
import { delegate } from './utils/events';
import store from './utils/store'; import store from './utils/store';
const NOTIFICATION_INTERVAL = 600000, const NOTIFICATION_INTERVAL = 600000,
@ -14,15 +15,16 @@ function makeRequest(verb, action, body) {
} }
function toggleSubscription(data) { function bindSubscriptionLinks() {
const { subscriptionId, subscriptionType } = data.el.dataset; delegate(document, 'fetchcomplete', {
const subscriptionElements = $$(`.js-notification-${subscriptionType + subscriptionId}`); '.js-subscription-link': event => {
const target = $("#js-subscription-target");
makeRequest('PUT', data.value, { id: subscriptionId, actor_class: subscriptionType }) // eslint-disable-line camelcase event.detail.text().then(text => {
.then(() => toggleEl(subscriptionElements)) target.outerHTML = text;
.catch(() => data.el.textContent = 'Error!'); });
}
});
} }
function markRead(data) { function markRead(data) {
const notificationId = data.value; const notificationId = data.value;
@ -72,6 +74,8 @@ function setupNotifications() {
// Update ticker when the stored value changes - this will occur in all open tabs // Update ticker when the stored value changes - this will occur in all open tabs
store.watch('notificationCount', updateNotificationTicker); store.watch('notificationCount', updateNotificationTicker);
bindSubscriptionLinks();
} }
export { setupNotifications, toggleSubscription, markRead }; export { setupNotifications, markRead };

View file

@ -122,35 +122,13 @@ defmodule Philomena.Images do
alias Philomena.Images.Subscription alias Philomena.Images.Subscription
@doc """ def subscribed?(image, nil), do: false
Returns the list of image_subscriptions. def subscribed?(image, user) do
Subscription
## Examples |> where(image_id: ^image.id, user_id: ^user.id)
|> Repo.exists?()
iex> list_image_subscriptions()
[%Subscription{}, ...]
"""
def list_image_subscriptions do
Repo.all(Subscription)
end end
@doc """
Gets a single subscription.
Raises `Ecto.NoResultsError` if the Subscription does not exist.
## Examples
iex> get_subscription!(123)
%Subscription{}
iex> get_subscription!(456)
** (Ecto.NoResultsError)
"""
def get_subscription!(id), do: Repo.get!(Subscription, id)
@doc """ @doc """
Creates a subscription. Creates a subscription.
@ -163,28 +141,10 @@ defmodule Philomena.Images do
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
def create_subscription(attrs \\ %{}) do def create_subscription(image, user) do
%Subscription{} %Subscription{image_id: image.id, user_id: user.id}
|> Subscription.changeset(attrs) |> Subscription.changeset(%{})
|> Repo.insert() |> Repo.insert(on_conflict: :nothing)
end
@doc """
Updates a subscription.
## Examples
iex> update_subscription(subscription, %{field: new_value})
{:ok, %Subscription{}}
iex> update_subscription(subscription, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_subscription(%Subscription{} = subscription, attrs) do
subscription
|> Subscription.changeset(attrs)
|> Repo.update()
end end
@doc """ @doc """
@ -199,20 +159,8 @@ defmodule Philomena.Images do
{:error, %Ecto.Changeset{}} {:error, %Ecto.Changeset{}}
""" """
def delete_subscription(%Subscription{} = subscription) do def delete_subscription(image, user) do
Repo.delete(subscription) %Subscription{image_id: image.id, user_id: user.id}
end |> Repo.delete()
@doc """
Returns an `%Ecto.Changeset{}` for tracking subscription changes.
## Examples
iex> change_subscription(subscription)
%Ecto.Changeset{source: %Subscription{}}
"""
def change_subscription(%Subscription{} = subscription) do
Subscription.changeset(subscription, %{})
end end
end end

View file

@ -0,0 +1,35 @@
defmodule PhilomenaWeb.Image.SubscriptionController do
use PhilomenaWeb, :controller
alias Philomena.Images.Image
alias Philomena.Images
plug PhilomenaWeb.Plugs.CanaryMapPlug, create: :show, delete: :show
plug :load_and_authorize_resource, model: Image, id_name: "image_id", persisted: true
def create(conn, _params) do
image = conn.assigns.image
user = conn.assigns.current_user
case Images.create_subscription(image, user) do
{:ok, _subscription} ->
render(conn, "_subscription.html", image: image, watching: true, layout: false)
{:error, _changeset} ->
render(conn, "_error.html", layout: false)
end
end
def delete(conn, _params) do
image = conn.assigns.image
user = conn.assigns.current_user
case Images.delete_subscription(image, user) do
{:ok, _subscription} ->
render(conn, "_subscription.html", image: image, watching: false, layout: false)
{:error, _changeset} ->
render(conn, "_error.html", layout: false)
end
end
end

View file

@ -1,7 +1,7 @@
defmodule PhilomenaWeb.ImageController do defmodule PhilomenaWeb.ImageController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias Philomena.{Images.Image, Comments.Comment, Textile.Renderer} alias Philomena.{Images, Images.Image, Comments.Comment, Textile.Renderer}
alias Philomena.Interactions alias Philomena.Interactions
alias Philomena.Comments alias Philomena.Comments
alias Philomena.Repo alias Philomena.Repo
@ -57,6 +57,9 @@ defmodule PhilomenaWeb.ImageController do
%Comment{} %Comment{}
|> Comments.change_comment() |> Comments.change_comment()
watching =
Images.subscribed?(image, conn.assigns.current_user)
render( render(
conn, conn,
"show.html", "show.html",
@ -64,7 +67,8 @@ defmodule PhilomenaWeb.ImageController do
comments: comments, comments: comments,
comment_changeset: comment_changeset, comment_changeset: comment_changeset,
description: description, description: description,
interactions: interactions interactions: interactions,
watching: watching
) )
end end
end end

View file

@ -58,6 +58,7 @@ defmodule PhilomenaWeb.Router do
resources "/vote", Image.VoteController, only: [:create, :delete], singleton: true resources "/vote", Image.VoteController, only: [:create, :delete], singleton: true
resources "/fave", Image.FaveController, only: [:create, :delete], singleton: true resources "/fave", Image.FaveController, only: [:create, :delete], singleton: true
resources "/hide", Image.HideController, only: [:create, :delete], singleton: true resources "/hide", Image.HideController, only: [:create, :delete], singleton: true
resources "/subscription", Image.SubscriptionController, only: [:create, :delete], singleton: true
end end
end end

View file

@ -30,9 +30,7 @@
span.hide-span title="Hide" span.hide-span title="Hide"
i.fa.fa-eye-slash i.fa.fa-eye-slash
.stretched-mobile-links .stretched-mobile-links
a href="/" title="Related Images" = render PhilomenaWeb.Image.SubscriptionView, "_subscription.html", watching: @watching, image: @image, conn: @conn
i.fa.fa-sitemap>
span.hide-limited-desktop.hide-mobile Related
.stretched-mobile-links .stretched-mobile-links
a href="#{pretty_url(@image, false, false)}" rel="nofollow" title="View (tags in filename)" a href="#{pretty_url(@image, false, false)}" rel="nofollow" title="View (tags in filename)"
i.fa.fa-eye> i.fa.fa-eye>

View file

@ -1,4 +1,4 @@
= render PhilomenaWeb.ImageView, "_image_meta.html", image: @image, conn: @conn = render PhilomenaWeb.ImageView, "_image_meta.html", image: @image, watching: @watching, conn: @conn
= render PhilomenaWeb.ImageView, "_image_page.html", image: @image, conn: @conn = render PhilomenaWeb.ImageView, "_image_page.html", image: @image, conn: @conn
.layout--narrow .layout--narrow

View file

@ -0,0 +1,2 @@
#js-subscription-target
' Error!

View file

@ -0,0 +1,23 @@
elixir:
watch_path = Routes.image_subscription_path(@conn, :create, @image)
watch_class = if @watching, do: "hidden", else: ""
unwatch_path = Routes.image_subscription_path(@conn, :delete, @image)
unwatch_class = if @watching, do: "", else: "hidden"
= if @conn.assigns.current_user do
#js-subscription-target
a.js-subscription-link href=watch_path class=watch_class data-remote="true" data-method="post"
i.fa.fa-bell>
span.hide-mobile
' Subscribe
a.js-subscription-link href=unwatch_path class=unwatch_class data-remote="true" data-method="delete"
i.fa.fa-bell-slash>
span.hide-mobile
' Unsubscribe
- else
a href=Routes.pow_session_path(@conn, :new)
i.fa.fa-bell>
span.hide-mobile
' Subscribe

View file

@ -0,0 +1,3 @@
defmodule PhilomenaWeb.Image.SubscriptionView do
use PhilomenaWeb, :view
end