mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-27 13:47:58 +01:00
add commenting and notifications generation
This commit is contained in:
parent
c9d14359e7
commit
551c7515ae
10 changed files with 234 additions and 24 deletions
|
@ -4,22 +4,12 @@ defmodule Philomena.Comments do
|
|||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Ecto.Multi
|
||||
alias Philomena.Repo
|
||||
|
||||
alias Philomena.Comments.Comment
|
||||
|
||||
@doc """
|
||||
Returns the list of comments.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_comments()
|
||||
[%Comment{}, ...]
|
||||
|
||||
"""
|
||||
def list_comments do
|
||||
Repo.all(Comment)
|
||||
end
|
||||
alias Philomena.Images.Image
|
||||
alias Philomena.Notifications
|
||||
|
||||
@doc """
|
||||
Gets a single comment.
|
||||
|
@ -49,10 +39,48 @@ defmodule Philomena.Comments do
|
|||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_comment(attrs \\ %{}) do
|
||||
%Comment{}
|
||||
|> Comment.changeset(attrs)
|
||||
|> Repo.insert()
|
||||
def create_comment(image, user, attrs \\ %{}) do
|
||||
user_id = if user, do: user.id, else: nil
|
||||
comment =
|
||||
%Comment{image_id: image.id, user_id: user_id}
|
||||
|> Comment.creation_changeset(attrs)
|
||||
|
||||
image_query =
|
||||
Image
|
||||
|> where(id: ^image.id)
|
||||
|
||||
Multi.new
|
||||
|> Multi.insert(:comment, comment)
|
||||
|> Multi.update_all(:image, image_query, inc: [comments_count: 1])
|
||||
|> Repo.transaction()
|
||||
end
|
||||
|
||||
def notify_comment(comment) do
|
||||
spawn fn ->
|
||||
image =
|
||||
comment
|
||||
|> Repo.preload(:image)
|
||||
|> Map.fetch!(:image)
|
||||
|
||||
subscriptions =
|
||||
image
|
||||
|> Repo.preload(:subscriptions)
|
||||
|> Map.fetch!(:subscriptions)
|
||||
|
||||
Notifications.notify(
|
||||
comment,
|
||||
subscriptions,
|
||||
%{
|
||||
actor_id: image.id,
|
||||
actor_type: "Image",
|
||||
actor_child_id: comment.id,
|
||||
actor_child_type: "Comment",
|
||||
action: "commented on"
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
comment
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
@ -101,4 +129,20 @@ defmodule Philomena.Comments do
|
|||
def change_comment(%Comment{} = comment) do
|
||||
Comment.changeset(comment, %{})
|
||||
end
|
||||
|
||||
def reindex_comment(%Comment{} = comment) do
|
||||
spawn fn ->
|
||||
Comment
|
||||
|> preload(^indexing_preloads())
|
||||
|> where(id: ^comment.id)
|
||||
|> Repo.one()
|
||||
|> Comment.index_document()
|
||||
end
|
||||
|
||||
comment
|
||||
end
|
||||
|
||||
def indexing_preloads do
|
||||
[:user, image: :tags]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -31,9 +31,18 @@ defmodule Philomena.Comments.Comment do
|
|||
end
|
||||
|
||||
@doc false
|
||||
def creation_changeset(comment, attrs) do
|
||||
comment
|
||||
|> cast(attrs, [:body, :anonymous])
|
||||
|> validate_required([:body])
|
||||
|> validate_length(:body, min: 1, max: 300_000, count: :bytes)
|
||||
end
|
||||
|
||||
def changeset(comment, attrs) do
|
||||
comment
|
||||
|> cast(attrs, [])
|
||||
|> validate_required([])
|
||||
|> cast(attrs, [:body, :edit_reason])
|
||||
|> validate_required([:body])
|
||||
|> validate_length(:body, min: 1, max: 300_000, count: :bytes)
|
||||
|> validate_length(:edit_reason, max: 70, count: :bytes)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,6 +11,7 @@ defmodule Philomena.Images.Image do
|
|||
alias Philomena.ImageVotes.ImageVote
|
||||
alias Philomena.ImageFaves.ImageFave
|
||||
alias Philomena.ImageHides.ImageHide
|
||||
alias Philomena.Images.Subscription
|
||||
alias Philomena.Users.User
|
||||
alias Philomena.Images.Tagging
|
||||
alias Philomena.Galleries
|
||||
|
@ -24,6 +25,7 @@ defmodule Philomena.Images.Image do
|
|||
has_many :hides, ImageHide
|
||||
has_many :taggings, Tagging
|
||||
has_many :gallery_interactions, Galleries.Interaction
|
||||
has_many :subscriptions, Subscription
|
||||
has_many :tags, through: [:taggings, :tag]
|
||||
has_many :upvoters, through: [:upvotes, :user]
|
||||
has_many :downvoters, through: [:downvotes, :user]
|
||||
|
|
|
@ -70,7 +70,7 @@ defmodule Philomena.Notifications do
|
|||
def update_notification(%Notification{} = notification, attrs) do
|
||||
notification
|
||||
|> Notification.changeset(attrs)
|
||||
|> Repo.update()
|
||||
|> Repo.insert_or_update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
@ -197,4 +197,36 @@ defmodule Philomena.Notifications do
|
|||
def change_unread_notification(%UnreadNotification{} = unread_notification) do
|
||||
UnreadNotification.changeset(unread_notification, %{})
|
||||
end
|
||||
|
||||
def notify(_actor_child, [], _params), do: nil
|
||||
def notify(actor_child, subscriptions, params) do
|
||||
# Don't push to the user that created the notification
|
||||
subscriptions =
|
||||
case actor_child do
|
||||
%{user_id: id} ->
|
||||
subscriptions
|
||||
|> Enum.reject(& &1.user_id == id)
|
||||
|
||||
_ ->
|
||||
subscriptions
|
||||
end
|
||||
|
||||
Repo.transaction(fn ->
|
||||
notification =
|
||||
Notification
|
||||
|> Repo.get_by(actor_id: params.actor_id, actor_type: params.actor_type)
|
||||
|
||||
{:ok, notification} =
|
||||
(notification || %Notification{})
|
||||
|> update_notification(params)
|
||||
|
||||
# Insert the notification to any watchers who do not have it
|
||||
unreads =
|
||||
subscriptions
|
||||
|> Enum.map(&%{user_id: &1.user_id, notification_id: notification.id})
|
||||
|
||||
UnreadNotification
|
||||
|> Repo.insert_all(unreads, on_conflict: :nothing)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,7 +20,7 @@ defmodule Philomena.Notifications.Notification do
|
|||
@doc false
|
||||
def changeset(notification, attrs) do
|
||||
notification
|
||||
|> cast(attrs, [])
|
||||
|> validate_required([])
|
||||
|> cast(attrs, [:actor_id, :actor_type, :actor_child_id, :actor_child_type, :action])
|
||||
|> validate_required([:actor_id, :actor_type, :action])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,12 +2,40 @@ defmodule PhilomenaWeb.Image.CommentController do
|
|||
use PhilomenaWeb, :controller
|
||||
|
||||
alias Philomena.{Images.Image, Comments.Comment, Textile.Renderer}
|
||||
alias Philomena.Comments
|
||||
alias Philomena.Images
|
||||
alias Philomena.Repo
|
||||
import Ecto.Query
|
||||
|
||||
plug PhilomenaWeb.Plugs.CanaryMapPlug, create: :show, edit: :show, update: :show
|
||||
plug :load_and_authorize_resource, model: Image, id_name: "image_id", persisted: true
|
||||
|
||||
# Undo the previous private parameter screwery
|
||||
plug PhilomenaWeb.Plugs.CanaryMapPlug, create: :create, edit: :edit, update: :update
|
||||
plug :load_and_authorize_resource, model: Comment, only: [:show], preload: [:image, user: [awards: :badge]]
|
||||
|
||||
plug PhilomenaWeb.Plugs.FilterBannedUsers when action in [:create, :edit, :update]
|
||||
|
||||
def index(conn, %{"comment_id" => comment_id}) do
|
||||
comment =
|
||||
Comment
|
||||
|> where(image_id: ^conn.assigns.image.id)
|
||||
|> where(id: ^comment_id)
|
||||
|> Repo.one!()
|
||||
|
||||
offset =
|
||||
Comment
|
||||
|> where(image_id: ^conn.assigns.image.id)
|
||||
|> where([c], c.created_at > ^comment.created_at)
|
||||
|> Repo.aggregate(:count, :id)
|
||||
|
||||
%{page_size: page_size} = conn.assigns.pagination
|
||||
page = div(offset, page_size)
|
||||
|
||||
conn
|
||||
|> redirect(to: Routes.image_comment_path(conn, :index, conn.assigns.image, page: page))
|
||||
end
|
||||
|
||||
def index(conn, _params) do
|
||||
comments =
|
||||
Comment
|
||||
|
@ -30,4 +58,47 @@ defmodule PhilomenaWeb.Image.CommentController do
|
|||
rendered = Renderer.render_one(conn.assigns.comment)
|
||||
render(conn, "show.html", layout: false, image: conn.assigns.image, comment: conn.assigns.comment, body: rendered)
|
||||
end
|
||||
|
||||
def create(conn, %{"comment" => comment_params}) do
|
||||
user = conn.assigns.current_user
|
||||
image = conn.assigns.image
|
||||
|
||||
case Comments.create_comment(image, user, comment_params) do
|
||||
{:ok, %{comment: comment}} ->
|
||||
Comments.notify_comment(comment)
|
||||
Comments.reindex_comment(comment)
|
||||
Images.reindex_image(conn.assigns.image)
|
||||
|
||||
conn
|
||||
|> put_flash(:info, "Comment created successfully.")
|
||||
|> redirect(to: Routes.image_path(conn, :show, image) <> "#comment_#{comment.id}")
|
||||
|
||||
_error ->
|
||||
conn
|
||||
|> put_flash(:error, "There was an error posting your comment")
|
||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||
end
|
||||
end
|
||||
|
||||
def edit(conn, _params) do
|
||||
changeset =
|
||||
conn.assigns.comment
|
||||
|> Comments.change_comment()
|
||||
|
||||
render(conn, "edit.html", comment: conn.assigns.comment, changeset: changeset)
|
||||
end
|
||||
|
||||
def update(conn, %{"comment" => comment_params}) do
|
||||
case Comments.update_comment(conn.assigns.comment, comment_params) do
|
||||
{:ok, _comment} ->
|
||||
conn
|
||||
|> put_flash(:info, "Comment updated successfully.")
|
||||
|> redirect(to: Routes.image_path(conn, :show, conn.assigns.image) <> "#comment_#{conn.assigns.comment.id}")
|
||||
|
||||
_error ->
|
||||
conn
|
||||
|> put_flash(:error, "There was an error editing your comment")
|
||||
|> redirect(to: Routes.image_path(conn, :show, conn.assigns.image))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ defmodule PhilomenaWeb.ImageController do
|
|||
|
||||
alias Philomena.{Images.Image, Comments.Comment, Textile.Renderer}
|
||||
alias Philomena.Interactions
|
||||
alias Philomena.Comments
|
||||
alias Philomena.Repo
|
||||
import Ecto.Query
|
||||
|
||||
|
@ -52,6 +53,18 @@ defmodule PhilomenaWeb.ImageController do
|
|||
interactions =
|
||||
Interactions.user_interactions([image], conn.assigns.current_user)
|
||||
|
||||
render(conn, "show.html", image: image, comments: comments, description: description, interactions: interactions)
|
||||
comment_changeset =
|
||||
%Comment{}
|
||||
|> Comments.change_comment()
|
||||
|
||||
render(
|
||||
conn,
|
||||
"show.html",
|
||||
image: image,
|
||||
comments: comments,
|
||||
comment_changeset: comment_changeset,
|
||||
description: description,
|
||||
interactions: interactions
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -68,7 +68,7 @@ defmodule PhilomenaWeb.Router do
|
|||
|
||||
resources "/activity", ActivityController, only: [:index]
|
||||
resources "/images", ImageController, only: [:index, :show] do
|
||||
resources "/comments", Image.CommentController, only: [:index, :show]
|
||||
resources "/comments", Image.CommentController, only: [:index, :show, :create]
|
||||
end
|
||||
resources "/tags", TagController, only: [:index, :show]
|
||||
resources "/search", SearchController, only: [:index]
|
||||
|
|
25
lib/philomena_web/templates/image/comment/_form.html.slime
Normal file
25
lib/philomena_web/templates/image/comment/_form.html.slime
Normal file
|
@ -0,0 +1,25 @@
|
|||
= form_for @changeset, Routes.image_comment_path(@conn, :create, @image), fn f ->
|
||||
= if @changeset.action do
|
||||
.alert.alert-danger
|
||||
p Oops, something went wrong! Please check the errors below.
|
||||
|
||||
.block
|
||||
.block__header.block__header--js-tabbed
|
||||
a.selected href="#" data-click-tab="write"
|
||||
i.fa.fa-pencil>
|
||||
' Edit
|
||||
|
||||
a href="#" data-click-tab="preview"
|
||||
i.fa.fa-eye>
|
||||
' Preview
|
||||
|
||||
.block__tab.communication-edit__tab.selected data-tab="write"
|
||||
.field
|
||||
= textarea f, :body, class: "input input--wide input--text js-preview-input js-toolbar-input", placeholder: "Please read the site rules before posting and use [spoiler][/spoiler] for above-rating stuff.", required: true
|
||||
= error_tag f, :body
|
||||
|
||||
.block__tab.communication-edit__tab.hidden data-tab="preview"
|
||||
' [Loading preview...]
|
||||
|
||||
.block__content.communication-edit__actions
|
||||
= submit "Post", class: "button"
|
|
@ -19,5 +19,19 @@
|
|||
em> no source provided yet
|
||||
|
||||
h4 Comments
|
||||
= cond do
|
||||
- @conn.assigns.current_ban ->
|
||||
.block.block--fixed.block--warning
|
||||
h4 You've been banned!
|
||||
p
|
||||
' You cannnot post comments or update metadata (or do anything but
|
||||
' read, really) until
|
||||
= pretty_time(@conn.assigns.current_ban.valid_until)
|
||||
|
||||
- @image.commenting_allowed ->
|
||||
= render PhilomenaWeb.Image.CommentView, "_form.html", image: @image, changeset: @comment_changeset, conn: @conn
|
||||
|
||||
- true ->
|
||||
|
||||
#comments data-current-url=Routes.image_comment_path(@conn, :index, @image, page: 1) data-loaded="true"
|
||||
= render PhilomenaWeb.Image.CommentView, "index.html", image: @image, comments: @comments, conn: @conn
|
Loading…
Reference in a new issue