tentative comment editing

This commit is contained in:
byte[] 2019-12-06 09:43:01 -05:00
parent 76de12d69d
commit d22ab9aa58
9 changed files with 122 additions and 52 deletions

View file

@ -11,6 +11,7 @@ defmodule Philomena.Comments do
alias Philomena.Images.Image
alias Philomena.Images
alias Philomena.Notifications
alias Philomena.Versions
@doc """
Gets a single comment.
@ -98,10 +99,23 @@ defmodule Philomena.Comments do
{:error, %Ecto.Changeset{}}
"""
def update_comment(%Comment{} = comment, attrs) do
comment
|> Comment.changeset(attrs)
|> Repo.update()
def update_comment(%Comment{} = comment, editor, attrs) do
now = DateTime.utc_now() |> DateTime.truncate(:second)
current_body = comment.body
current_reason = comment.edit_reason
comment_changes =
Comment.changeset(comment, attrs, now)
Multi.new
|> Multi.update(:comment, comment_changes)
|> Multi.run(:version, fn _repo, _changes ->
Versions.create_version("Comment", comment.id, editor.id, %{
"body" => current_body,
"edit_reason" => current_reason
})
end)
|> Repo.isolated_transaction(:serializable)
end
@doc """

View file

@ -23,6 +23,7 @@ defmodule Philomena.Comments.Comment do
field :anonymous, :boolean, default: false
field :hidden_from_users, :boolean, default: false
field :edit_reason, :string
field :edited_at, :utc_datetime
field :deletion_reason, :string, default: ""
field :destroyed_content, :boolean, default: false
field :name_at_post_time, :string
@ -40,9 +41,10 @@ defmodule Philomena.Comments.Comment do
|> put_name_at_post_time(attribution[:user])
end
def changeset(comment, attrs) do
def changeset(comment, attrs, edited_at \\ nil) do
comment
|> cast(attrs, [:body, :edit_reason])
|> put_change(:edited_at, edited_at)
|> validate_required([:body])
|> validate_length(:body, min: 1, max: 300_000, count: :bytes)
|> validate_length(:edit_reason, max: 70, count: :bytes)

View file

@ -85,6 +85,14 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do
# Comment on images where that is allowed
def can?(_user, :create_comment, %Image{hidden_from_users: false, commenting_allowed: true}), do: true
# Edit comments on images
def can?(%User{id: id}, :edit, %Comment{hidden_from_users: false, user_id: id} = comment) do
# comment must have been made no later than 15 minutes ago
time_ago = DateTime.utc_now() |> DateTime.add(-15 * 60)
DateTime.diff(comment.created_at, time_ago) > 0
end
# Edit metadata on images where that is allowed
def can?(_user, :edit_metadata, %Image{hidden_from_users: false, tag_editing_allowed: true}), do: true
def can?(%User{id: id}, :edit_description, %Image{user_id: id, hidden_from_users: false, description_editing_allowed: true}), do: true
@ -101,6 +109,9 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do
def can?(_user, :show, %Topic{hidden_from_users: false}), do: true
def can?(_user, :show, %Post{hidden_from_users: false}), do: true
# Edit posts
def can?(%User{id: id}, :edit, %Post{hidden_from_users: false, user_id: id}), do: true
# View profile pages
def can?(_user, :show, %User{}), do: true

View file

@ -61,8 +61,12 @@ defmodule Philomena.Versions do
"""
def create_version(item_type, item_id, whodunnit, attrs \\ %{}) do
%Version{item_type: item_type, item_id: item_id, whodunnit: whodunnit}
%Version{item_type: item_type, item_id: item_id, event: "update", whodunnit: whodunnit(whodunnit)}
|> Version.changeset(attrs, item_id)
|> Repo.insert()
end
# revolver ocelot
defp whodunnit(user_id) when is_integer(user_id), do: to_string(user_id)
defp whodunnit(nil), do: nil
end

View file

@ -12,8 +12,8 @@ defmodule PhilomenaWeb.Image.CommentController do
plug :load_and_authorize_resource, model: Image, id_name: "image_id", persisted: true
# Undo the previous private parameter screwery
plug PhilomenaWeb.CanaryMapPlug, create: :create, edit: :edit, update: :update
plug :load_and_authorize_resource, model: Comment, only: [:show], preload: [:image, user: [awards: :badge]]
plug PhilomenaWeb.CanaryMapPlug, create: :create, edit: :edit, update: :edit
plug :load_and_authorize_resource, model: Comment, only: [:show, :edit, :update], preload: [:image, user: [awards: :badge]]
plug PhilomenaWeb.FilterBannedUsersPlug when action in [:create, :edit, :update]
plug PhilomenaWeb.UserAttributionPlug when action in [:create]
@ -92,11 +92,13 @@ defmodule PhilomenaWeb.Image.CommentController do
end
def update(conn, %{"comment" => comment_params}) do
case Comments.update_comment(conn.assigns.comment, comment_params) do
{:ok, _comment} ->
case Comments.update_comment(conn.assigns.comment, conn.assigns.current_user, comment_params) do
{:ok, %{comment: comment}} ->
Comments.reindex_comment(comment)
conn
|> put_flash(:info, "Comment updated successfully.")
|> redirect(to: Routes.image_path(conn, :show, conn.assigns.image) <> "#comment_#{conn.assigns.comment.id}")
|> redirect(to: Routes.image_path(conn, :show, conn.assigns.image) <> "#comment_#{comment.id}")
_error ->
conn

View file

@ -100,6 +100,7 @@ defmodule PhilomenaWeb.Router do
resources "/hide", Image.HideController, only: [:create, :delete], singleton: true
resources "/subscription", Image.SubscriptionController, only: [:create, :delete], singleton: true
resources "/read", Image.ReadController, only: [:create], singleton: true
resources "/comments", Image.CommentController, only: [:edit, :update]
end
resources "/forums", ForumController, only: [] do

View file

@ -6,14 +6,16 @@ div
i.fa.fa-flag>
' Report
/- if comment.edited_at && can?(:read, comment)
/ br
/ a href=image_comment_history_path(comment.image, comment)
/ | Edited
/ =<> friendly_time(comment.edited_at)
/ - if comment.edit_reason.present?
/ | because:
/ =<> comment.edit_reason
= if not is_nil(@comment.edited_at) and can?(@conn, :read, @comment) do
br
a href=Routes.image_comment_history_path(@conn, :index, @comment.image, @comment)
' Edited
=> pretty_time(@comment.edited_at)
= if @comment.edit_reason not in [nil, ""] do
' because:
=> @comment.edit_reason
div
- link_path = Routes.image_path(@conn, :show, @comment.image) <> "#comment_#{@comment.id}"
- safe_author = PhilomenaWeb.PostView.textile_safe_author(@comment)
@ -30,7 +32,10 @@ div
a.communication__interaction.post-reply href=link_path data-reply-url=link_path data-author=safe_author
i.fa.fa-reply>
' Reply
/span.owner-options.hidden
/ strong =<> link_to edit_image_comment_path(comment.image, comment), class: 'communication__interaction' do
/ i.fas.fa-edit
/ ' Edit
= if can?(@conn, :edit, @comment) do
span.owner-options
strong
a.communication__interaction href=Routes.image_comment_path(@conn, :edit, @comment.image, @comment)
i.fa.fa-pencil>
' Edit

View file

@ -0,0 +1,31 @@
= form_for @changeset, Routes.image_comment_path(@conn, :update, @comment.image, @comment), 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"
= render PhilomenaWeb.TextileView, "_help.html", conn: @conn
= render PhilomenaWeb.TextileView, "_toolbar.html", conn: @conn
.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
.field
= text_input f, :edit_reason, class: "input input--wide", placeholder: "Reason for edit"
.block__tab.communication-edit__tab.hidden data-tab="preview"
' [Loading preview...]
.block__content.communication-edit__actions
=> submit "Edit", class: "button", data: [disable_with: raw("Posting&hellip;")]

View file

@ -8,39 +8,39 @@ h1
= for version <- @versions do
article.block.communication
.block__content.flex.flex--no-wrap
.flex__fixed.spacing-right
= render PhilomenaWeb.UserAttributionView, "_anon_user_avatar.html", object: @comment, conn: @conn
.block__content.flex.flex--no-wrap
.flex__fixed.spacing-right
= render PhilomenaWeb.UserAttributionView, "_anon_user_avatar.html", object: @comment, conn: @conn
.flex__grow.communication__body
span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @comment, awards: true, conn: @conn
br
.flex__grow.communication__body
span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @comment, awards: true, conn: @conn
br
= render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @comment, conn: @conn
= render PhilomenaWeb.UserAttributionView, "_anon_user_title.html", object: @comment, conn: @conn
.communication__body__text
= for edit <- version.difference do
= case edit do
- {:eq, value} ->
= escape_nl2br(value)
.communication__body__text
= for edit <- version.difference do
= case edit do
- {:eq, value} ->
= escape_nl2br(value)
- {:ins, value} ->
ins.differ = escape_nl2br(value)
- {:ins, value} ->
ins.differ = escape_nl2br(value)
- {:del, value} ->
del.differ = escape_nl2br(value)
- {:del, value} ->
del.differ = escape_nl2br(value)
.block__content.communication__options
.flex.flex--wrap.flex--spaced-out
div
= if version.edit_reason not in [nil, ""] do
' Reason:
= version.edit_reason
- else
' No reason given
.block__content.communication__options
.flex.flex--wrap.flex--spaced-out
div
= if version.edit_reason not in [nil, ""] do
' Reason:
= version.edit_reason
- else
' No reason given
.flex__right
' Edited
=> pretty_time(version.created_at)
' by
=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: version, conn: @conn
.flex__right
' Edited
=> pretty_time(version.created_at)
' by
=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: version, conn: @conn