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 { showBlock } from './utils/image';
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
const types = {
@ -74,8 +74,6 @@ const actions = {
unfilter(data) { showBlock(data.el.closest('.image-show-container')); },
toggleSubscription,
markRead,
};

View file

@ -4,6 +4,7 @@
import { fetchJson, handleError } from './utils/requests';
import { $, $$, hideEl, toggleEl } from './utils/dom';
import { delegate } from './utils/events';
import store from './utils/store';
const NOTIFICATION_INTERVAL = 600000,
@ -14,16 +15,17 @@ function makeRequest(verb, action, body) {
}
function toggleSubscription(data) {
const { subscriptionId, subscriptionType } = data.el.dataset;
const subscriptionElements = $$(`.js-notification-${subscriptionType + subscriptionId}`);
makeRequest('PUT', data.value, { id: subscriptionId, actor_class: subscriptionType }) // eslint-disable-line camelcase
.then(() => toggleEl(subscriptionElements))
.catch(() => data.el.textContent = 'Error!');
function bindSubscriptionLinks() {
delegate(document, 'fetchcomplete', {
'.js-subscription-link': event => {
const target = $("#js-subscription-target");
event.detail.text().then(text => {
target.outerHTML = text;
});
}
});
}
function markRead(data) {
const notificationId = data.value;
const notification = $(`.js-notification-id-${notificationId}`);
@ -72,6 +74,8 @@ function setupNotifications() {
// Update ticker when the stored value changes - this will occur in all open tabs
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
@doc """
Returns the list of image_subscriptions.
## Examples
iex> list_image_subscriptions()
[%Subscription{}, ...]
"""
def list_image_subscriptions do
Repo.all(Subscription)
def subscribed?(image, nil), do: false
def subscribed?(image, user) do
Subscription
|> where(image_id: ^image.id, user_id: ^user.id)
|> Repo.exists?()
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 """
Creates a subscription.
@ -163,28 +141,10 @@ defmodule Philomena.Images do
{:error, %Ecto.Changeset{}}
"""
def create_subscription(attrs \\ %{}) do
%Subscription{}
|> Subscription.changeset(attrs)
|> Repo.insert()
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()
def create_subscription(image, user) do
%Subscription{image_id: image.id, user_id: user.id}
|> Subscription.changeset(%{})
|> Repo.insert(on_conflict: :nothing)
end
@doc """
@ -199,20 +159,8 @@ defmodule Philomena.Images do
{:error, %Ecto.Changeset{}}
"""
def delete_subscription(%Subscription{} = subscription) do
Repo.delete(subscription)
end
@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, %{})
def delete_subscription(image, user) do
%Subscription{image_id: image.id, user_id: user.id}
|> Repo.delete()
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
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.Comments
alias Philomena.Repo
@ -57,6 +57,9 @@ defmodule PhilomenaWeb.ImageController do
%Comment{}
|> Comments.change_comment()
watching =
Images.subscribed?(image, conn.assigns.current_user)
render(
conn,
"show.html",
@ -64,7 +67,8 @@ defmodule PhilomenaWeb.ImageController do
comments: comments,
comment_changeset: comment_changeset,
description: description,
interactions: interactions
interactions: interactions,
watching: watching
)
end
end

View file

@ -58,6 +58,7 @@ defmodule PhilomenaWeb.Router do
resources "/vote", Image.VoteController, only: [:create, :delete], singleton: true
resources "/fave", Image.FaveController, 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

View file

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