mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-27 13:47:58 +01:00
Merge pull request #146 from philomena-dev/modlogs
basic moderation logs
This commit is contained in:
commit
4f561b9c16
50 changed files with 803 additions and 27 deletions
|
@ -9,6 +9,7 @@ background() {
|
||||||
mix run -e 'Philomena.Release.update_channels()'
|
mix run -e 'Philomena.Release.update_channels()'
|
||||||
mix run -e 'Philomena.Release.verify_artist_links()'
|
mix run -e 'Philomena.Release.verify_artist_links()'
|
||||||
mix run -e 'Philomena.Release.update_stats()'
|
mix run -e 'Philomena.Release.update_stats()'
|
||||||
|
mix run -e 'Philomena.Release.clean_moderation_logs()'
|
||||||
|
|
||||||
sleep 300
|
sleep 300
|
||||||
done
|
done
|
||||||
|
|
83
lib/philomena/moderation_logs.ex
Normal file
83
lib/philomena/moderation_logs.ex
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
defmodule Philomena.ModerationLogs do
|
||||||
|
@moduledoc """
|
||||||
|
The ModerationLogs context.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import Ecto.Query, warn: false
|
||||||
|
alias Philomena.Repo
|
||||||
|
|
||||||
|
alias Philomena.ModerationLogs.ModerationLog
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns the list of moderation_logs.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> list_moderation_logs()
|
||||||
|
[%ModerationLog{}, ...]
|
||||||
|
|
||||||
|
"""
|
||||||
|
def list_moderation_logs(conn) do
|
||||||
|
ModerationLog
|
||||||
|
|> where([ml], ml.created_at > ago(2, "week"))
|
||||||
|
|> preload(:user)
|
||||||
|
|> order_by(desc: :created_at)
|
||||||
|
|> Repo.paginate(conn.assigns.scrivener)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Gets a single moderation_log.
|
||||||
|
|
||||||
|
Raises `Ecto.NoResultsError` if the Moderation log does not exist.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> get_moderation_log!(123)
|
||||||
|
%ModerationLog{}
|
||||||
|
|
||||||
|
iex> get_moderation_log!(456)
|
||||||
|
** (Ecto.NoResultsError)
|
||||||
|
|
||||||
|
"""
|
||||||
|
def get_moderation_log!(id), do: Repo.get!(ModerationLog, id)
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Creates a moderation_log.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> create_moderation_log(%{field: value})
|
||||||
|
{:ok, %ModerationLog{}}
|
||||||
|
|
||||||
|
iex> create_moderation_log(%{field: bad_value})
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def create_moderation_log(user, type, subject_path, body) do
|
||||||
|
%ModerationLog{user_id: user.id}
|
||||||
|
|> ModerationLog.changeset(%{type: type, subject_path: subject_path, body: body})
|
||||||
|
|> Repo.insert()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Deletes a moderation_log.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> delete_moderation_log(moderation_log)
|
||||||
|
{:ok, %ModerationLog{}}
|
||||||
|
|
||||||
|
iex> delete_moderation_log(moderation_log)
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def delete_moderation_log(%ModerationLog{} = moderation_log) do
|
||||||
|
Repo.delete(moderation_log)
|
||||||
|
end
|
||||||
|
|
||||||
|
def cleanup! do
|
||||||
|
ModerationLog
|
||||||
|
|> where([ml], ml.created_at < ago(2, "week"))
|
||||||
|
|> Repo.delete_all()
|
||||||
|
end
|
||||||
|
end
|
23
lib/philomena/moderation_logs/moderation_log.ex
Normal file
23
lib/philomena/moderation_logs/moderation_log.ex
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
defmodule Philomena.ModerationLogs.ModerationLog do
|
||||||
|
use Ecto.Schema
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
alias Philomena.Users.User
|
||||||
|
|
||||||
|
schema "moderation_logs" do
|
||||||
|
belongs_to :user, User
|
||||||
|
|
||||||
|
field :body, :string
|
||||||
|
field :type, :string
|
||||||
|
field :subject_path, :string
|
||||||
|
|
||||||
|
timestamps(inserted_at: :created_at, updated_at: false, type: :utc_datetime)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def changeset(moderation_log, attrs) do
|
||||||
|
moderation_log
|
||||||
|
|> cast(attrs, [:body, :type, :subject_path])
|
||||||
|
|> validate_required([:body, :type, :subject_path])
|
||||||
|
end
|
||||||
|
end
|
|
@ -29,6 +29,11 @@ defmodule Philomena.Release do
|
||||||
PhilomenaWeb.StatsUpdater.update_stats!()
|
PhilomenaWeb.StatsUpdater.update_stats!()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clean_moderation_logs do
|
||||||
|
start_app()
|
||||||
|
Philomena.ModerationLogs.cleanup!()
|
||||||
|
end
|
||||||
|
|
||||||
defp repos do
|
defp repos do
|
||||||
Application.fetch_env!(@app, :ecto_repos)
|
Application.fetch_env!(@app, :ecto_repos)
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,6 +24,7 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do
|
||||||
alias Philomena.StaticPages.StaticPage
|
alias Philomena.StaticPages.StaticPage
|
||||||
alias Philomena.Adverts.Advert
|
alias Philomena.Adverts.Advert
|
||||||
alias Philomena.SiteNotices.SiteNotice
|
alias Philomena.SiteNotices.SiteNotice
|
||||||
|
alias Philomena.ModerationLogs.ModerationLog
|
||||||
|
|
||||||
alias Philomena.Bans.User, as: UserBan
|
alias Philomena.Bans.User, as: UserBan
|
||||||
alias Philomena.Bans.Subnet, as: SubnetBan
|
alias Philomena.Bans.Subnet, as: SubnetBan
|
||||||
|
@ -127,6 +128,9 @@ defimpl Canada.Can, for: [Atom, Philomena.Users.User] do
|
||||||
# Manage galleries
|
# Manage galleries
|
||||||
def can?(%User{role: "moderator"}, _action, %Gallery{}), do: true
|
def can?(%User{role: "moderator"}, _action, %Gallery{}), do: true
|
||||||
|
|
||||||
|
# See moderation logs
|
||||||
|
def can?(%User{role: "moderator"}, _action, ModerationLog), do: true
|
||||||
|
|
||||||
# And some privileged moderators can...
|
# And some privileged moderators can...
|
||||||
|
|
||||||
# Manage site notices
|
# Manage site notices
|
||||||
|
|
|
@ -24,6 +24,7 @@ defmodule PhilomenaWeb do
|
||||||
import Plug.Conn
|
import Plug.Conn
|
||||||
import PhilomenaWeb.Gettext
|
import PhilomenaWeb.Gettext
|
||||||
import Canary.Plugs
|
import Canary.Plugs
|
||||||
|
import PhilomenaWeb.ModerationLogPlug, only: [moderation_log: 2]
|
||||||
alias PhilomenaWeb.Router.Helpers, as: Routes
|
alias PhilomenaWeb.Router.Helpers, as: Routes
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,11 +13,19 @@ defmodule PhilomenaWeb.Admin.ArtistLink.ContactController do
|
||||||
preload: [:user]
|
preload: [:user]
|
||||||
|
|
||||||
def create(conn, _params) do
|
def create(conn, _params) do
|
||||||
{:ok, _} =
|
{:ok, artist_link} =
|
||||||
ArtistLinks.contact_artist_link(conn.assigns.artist_link, conn.assigns.current_user)
|
ArtistLinks.contact_artist_link(conn.assigns.artist_link, conn.assigns.current_user)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Artist successfully marked as contacted.")
|
|> put_flash(:info, "Artist successfully marked as contacted.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: artist_link)
|
||||||
|> redirect(to: Routes.admin_artist_link_path(conn, :index))
|
|> redirect(to: Routes.admin_artist_link_path(conn, :index))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, artist_link) do
|
||||||
|
%{
|
||||||
|
body: "Contacted artist #{artist_link.user.name} at #{artist_link.uri}",
|
||||||
|
subject_path: Routes.profile_artist_link_path(conn, :show, artist_link.user, artist_link)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,10 +13,18 @@ defmodule PhilomenaWeb.Admin.ArtistLink.RejectController do
|
||||||
preload: [:user]
|
preload: [:user]
|
||||||
|
|
||||||
def create(conn, _params) do
|
def create(conn, _params) do
|
||||||
{:ok, _} = ArtistLinks.reject_artist_link(conn.assigns.artist_link)
|
{:ok, artist_link} = ArtistLinks.reject_artist_link(conn.assigns.artist_link)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Artist link successfully marked as rejected.")
|
|> put_flash(:info, "Artist link successfully marked as rejected.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: artist_link)
|
||||||
|> redirect(to: Routes.admin_artist_link_path(conn, :index))
|
|> redirect(to: Routes.admin_artist_link_path(conn, :index))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, artist_link) do
|
||||||
|
%{
|
||||||
|
body: "Rejected artist link #{artist_link.uri} created by #{artist_link.user.name}",
|
||||||
|
subject_path: Routes.profile_artist_link_path(conn, :show, artist_link.user, artist_link)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,10 +13,19 @@ defmodule PhilomenaWeb.Admin.ArtistLink.VerificationController do
|
||||||
preload: [:user]
|
preload: [:user]
|
||||||
|
|
||||||
def create(conn, _params) do
|
def create(conn, _params) do
|
||||||
{:ok, _} = ArtistLinks.verify_artist_link(conn.assigns.artist_link, conn.assigns.current_user)
|
{:ok, result} =
|
||||||
|
ArtistLinks.verify_artist_link(conn.assigns.artist_link, conn.assigns.current_user)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Artist link successfully verified.")
|
|> put_flash(:info, "Artist link successfully verified.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: result.artist_link)
|
||||||
|> redirect(to: Routes.admin_artist_link_path(conn, :index))
|
|> redirect(to: Routes.admin_artist_link_path(conn, :index))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, artist_link) do
|
||||||
|
%{
|
||||||
|
body: "Verified artist link #{artist_link.uri} created by #{artist_link.user.name}",
|
||||||
|
subject_path: Routes.profile_artist_link_path(conn, :show, artist_link.user, artist_link)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,8 +9,8 @@ defmodule PhilomenaWeb.Admin.Batch.TagController do
|
||||||
plug :verify_authorized
|
plug :verify_authorized
|
||||||
plug PhilomenaWeb.UserAttributionPlug
|
plug PhilomenaWeb.UserAttributionPlug
|
||||||
|
|
||||||
def update(conn, %{"tags" => tags, "image_ids" => image_ids}) do
|
def update(conn, %{"tags" => tag_list, "image_ids" => image_ids}) do
|
||||||
tags = Tag.parse_tag_list(tags)
|
tags = Tag.parse_tag_list(tag_list)
|
||||||
|
|
||||||
added_tag_names = Enum.reject(tags, &String.starts_with?(&1, "-"))
|
added_tag_names = Enum.reject(tags, &String.starts_with?(&1, "-"))
|
||||||
|
|
||||||
|
@ -46,7 +46,15 @@ defmodule PhilomenaWeb.Admin.Batch.TagController do
|
||||||
|
|
||||||
case Images.batch_update(image_ids, added_tags, removed_tags, attributes) do
|
case Images.batch_update(image_ids, added_tags, removed_tags, attributes) do
|
||||||
{:ok, _} ->
|
{:ok, _} ->
|
||||||
json(conn, %{succeeded: image_ids, failed: []})
|
conn
|
||||||
|
|> moderation_log(
|
||||||
|
details: &log_details/3,
|
||||||
|
data: %{
|
||||||
|
tag_list: tag_list,
|
||||||
|
image_count: Enum.count(image_ids)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|> json(%{succeeded: image_ids, failed: []})
|
||||||
|
|
||||||
_error ->
|
_error ->
|
||||||
json(conn, %{succeeded: [], failed: image_ids})
|
json(conn, %{succeeded: [], failed: image_ids})
|
||||||
|
@ -59,4 +67,11 @@ defmodule PhilomenaWeb.Admin.Batch.TagController do
|
||||||
_false -> PhilomenaWeb.NotAuthorizedPlug.call(conn)
|
_false -> PhilomenaWeb.NotAuthorizedPlug.call(conn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, data) do
|
||||||
|
%{
|
||||||
|
body: "Batch tagged '#{data.tag_list}' on #{data.image_count} images",
|
||||||
|
subject_path: Routes.profile_path(conn, :show, conn.assigns.current_user)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,9 +44,10 @@ defmodule PhilomenaWeb.Admin.FingerprintBanController do
|
||||||
|
|
||||||
def create(conn, %{"fingerprint" => fingerprint_ban_params}) do
|
def create(conn, %{"fingerprint" => fingerprint_ban_params}) do
|
||||||
case Bans.create_fingerprint(conn.assigns.current_user, fingerprint_ban_params) do
|
case Bans.create_fingerprint(conn.assigns.current_user, fingerprint_ban_params) do
|
||||||
{:ok, _fingerprint_ban} ->
|
{:ok, fingerprint_ban} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Fingerprint was successfully banned.")
|
|> put_flash(:info, "Fingerprint was successfully banned.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: fingerprint_ban)
|
||||||
|> redirect(to: Routes.admin_fingerprint_ban_path(conn, :index))
|
|> redirect(to: Routes.admin_fingerprint_ban_path(conn, :index))
|
||||||
|
|
||||||
{:error, changeset} ->
|
{:error, changeset} ->
|
||||||
|
@ -61,9 +62,10 @@ defmodule PhilomenaWeb.Admin.FingerprintBanController do
|
||||||
|
|
||||||
def update(conn, %{"fingerprint" => fingerprint_ban_params}) do
|
def update(conn, %{"fingerprint" => fingerprint_ban_params}) do
|
||||||
case Bans.update_fingerprint(conn.assigns.fingerprint, fingerprint_ban_params) do
|
case Bans.update_fingerprint(conn.assigns.fingerprint, fingerprint_ban_params) do
|
||||||
{:ok, _fingerprint_ban} ->
|
{:ok, fingerprint_ban} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Fingerprint ban successfully updated.")
|
|> put_flash(:info, "Fingerprint ban successfully updated.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: fingerprint_ban)
|
||||||
|> redirect(to: Routes.admin_fingerprint_ban_path(conn, :index))
|
|> redirect(to: Routes.admin_fingerprint_ban_path(conn, :index))
|
||||||
|
|
||||||
{:error, changeset} ->
|
{:error, changeset} ->
|
||||||
|
@ -72,10 +74,11 @@ defmodule PhilomenaWeb.Admin.FingerprintBanController do
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete(conn, _params) do
|
def delete(conn, _params) do
|
||||||
{:ok, _fingerprint_ban} = Bans.delete_fingerprint(conn.assigns.fingerprint)
|
{:ok, fingerprint_ban} = Bans.delete_fingerprint(conn.assigns.fingerprint)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Fingerprint ban successfully deleted.")
|
|> put_flash(:info, "Fingerprint ban successfully deleted.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: fingerprint_ban)
|
||||||
|> redirect(to: Routes.admin_fingerprint_ban_path(conn, :index))
|
|> redirect(to: Routes.admin_fingerprint_ban_path(conn, :index))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -106,4 +109,15 @@ defmodule PhilomenaWeb.Admin.FingerprintBanController do
|
||||||
false -> PhilomenaWeb.NotAuthorizedPlug.call(conn)
|
false -> PhilomenaWeb.NotAuthorizedPlug.call(conn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, ban) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:create -> "Created a fingerprint ban #{ban.generated_ban_id}"
|
||||||
|
:update -> "Updated a fingerprint ban #{ban.generated_ban_id}"
|
||||||
|
:delete -> "Deleted a fingerprint ban #{ban.generated_ban_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{body: body, subject_path: Routes.admin_fingerprint_ban_path(conn, :index)}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -46,9 +46,10 @@ defmodule PhilomenaWeb.Admin.SubnetBanController do
|
||||||
|
|
||||||
def create(conn, %{"subnet" => subnet_ban_params}) do
|
def create(conn, %{"subnet" => subnet_ban_params}) do
|
||||||
case Bans.create_subnet(conn.assigns.current_user, subnet_ban_params) do
|
case Bans.create_subnet(conn.assigns.current_user, subnet_ban_params) do
|
||||||
{:ok, _subnet_ban} ->
|
{:ok, subnet_ban} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Subnet was successfully banned.")
|
|> put_flash(:info, "Subnet was successfully banned.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: subnet_ban)
|
||||||
|> redirect(to: Routes.admin_subnet_ban_path(conn, :index))
|
|> redirect(to: Routes.admin_subnet_ban_path(conn, :index))
|
||||||
|
|
||||||
{:error, changeset} ->
|
{:error, changeset} ->
|
||||||
|
@ -63,9 +64,10 @@ defmodule PhilomenaWeb.Admin.SubnetBanController do
|
||||||
|
|
||||||
def update(conn, %{"subnet" => subnet_ban_params}) do
|
def update(conn, %{"subnet" => subnet_ban_params}) do
|
||||||
case Bans.update_subnet(conn.assigns.subnet, subnet_ban_params) do
|
case Bans.update_subnet(conn.assigns.subnet, subnet_ban_params) do
|
||||||
{:ok, _subnet_ban} ->
|
{:ok, subnet_ban} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Subnet ban successfully updated.")
|
|> put_flash(:info, "Subnet ban successfully updated.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: subnet_ban)
|
||||||
|> redirect(to: Routes.admin_subnet_ban_path(conn, :index))
|
|> redirect(to: Routes.admin_subnet_ban_path(conn, :index))
|
||||||
|
|
||||||
{:error, changeset} ->
|
{:error, changeset} ->
|
||||||
|
@ -74,10 +76,11 @@ defmodule PhilomenaWeb.Admin.SubnetBanController do
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete(conn, _params) do
|
def delete(conn, _params) do
|
||||||
{:ok, _subnet_ban} = Bans.delete_subnet(conn.assigns.subnet)
|
{:ok, subnet_ban} = Bans.delete_subnet(conn.assigns.subnet)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Subnet ban successfully deleted.")
|
|> put_flash(:info, "Subnet ban successfully deleted.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: subnet_ban)
|
||||||
|> redirect(to: Routes.admin_subnet_ban_path(conn, :index))
|
|> redirect(to: Routes.admin_subnet_ban_path(conn, :index))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -108,4 +111,15 @@ defmodule PhilomenaWeb.Admin.SubnetBanController do
|
||||||
false -> PhilomenaWeb.NotAuthorizedPlug.call(conn)
|
false -> PhilomenaWeb.NotAuthorizedPlug.call(conn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, ban) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:create -> "Created a subnet ban #{ban.generated_ban_id}"
|
||||||
|
:update -> "Updated a subnet ban #{ban.generated_ban_id}"
|
||||||
|
:delete -> "Deleted a subnet ban #{ban.generated_ban_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{body: body, subject_path: Routes.admin_subnet_ban_path(conn, :index)}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -47,9 +47,10 @@ defmodule PhilomenaWeb.Admin.UserBanController do
|
||||||
|
|
||||||
def create(conn, %{"user" => user_ban_params}) do
|
def create(conn, %{"user" => user_ban_params}) do
|
||||||
case Bans.create_user(conn.assigns.current_user, user_ban_params) do
|
case Bans.create_user(conn.assigns.current_user, user_ban_params) do
|
||||||
{:ok, _user_ban} ->
|
{:ok, user_ban} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "User was successfully banned.")
|
|> put_flash(:info, "User was successfully banned.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: user_ban)
|
||||||
|> redirect(to: Routes.admin_user_ban_path(conn, :index))
|
|> redirect(to: Routes.admin_user_ban_path(conn, :index))
|
||||||
|
|
||||||
{:error, :user_ban, changeset, _changes} ->
|
{:error, :user_ban, changeset, _changes} ->
|
||||||
|
@ -67,9 +68,10 @@ defmodule PhilomenaWeb.Admin.UserBanController do
|
||||||
|
|
||||||
def update(conn, %{"user" => user_ban_params}) do
|
def update(conn, %{"user" => user_ban_params}) do
|
||||||
case Bans.update_user(conn.assigns.user, user_ban_params) do
|
case Bans.update_user(conn.assigns.user, user_ban_params) do
|
||||||
{:ok, _user_ban} ->
|
{:ok, user_ban} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "User ban successfully updated.")
|
|> put_flash(:info, "User ban successfully updated.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: user_ban)
|
||||||
|> redirect(to: Routes.admin_user_ban_path(conn, :index))
|
|> redirect(to: Routes.admin_user_ban_path(conn, :index))
|
||||||
|
|
||||||
{:error, changeset} ->
|
{:error, changeset} ->
|
||||||
|
@ -78,10 +80,11 @@ defmodule PhilomenaWeb.Admin.UserBanController do
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete(conn, _params) do
|
def delete(conn, _params) do
|
||||||
{:ok, _user_ban} = Bans.delete_user(conn.assigns.user)
|
{:ok, user_ban} = Bans.delete_user(conn.assigns.user)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "User ban successfully deleted.")
|
|> put_flash(:info, "User ban successfully deleted.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: user_ban)
|
||||||
|> redirect(to: Routes.admin_user_ban_path(conn, :index))
|
|> redirect(to: Routes.admin_user_ban_path(conn, :index))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -112,4 +115,15 @@ defmodule PhilomenaWeb.Admin.UserBanController do
|
||||||
false -> PhilomenaWeb.NotAuthorizedPlug.call(conn)
|
false -> PhilomenaWeb.NotAuthorizedPlug.call(conn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, ban) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:create -> "Created a user ban #{ban.generated_ban_id}"
|
||||||
|
:update -> "Updated a user ban #{ban.generated_ban_id}"
|
||||||
|
:delete -> "Deleted a user ban #{ban.generated_ban_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{body: body, subject_path: Routes.admin_user_ban_path(conn, :index)}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -59,9 +59,10 @@ defmodule PhilomenaWeb.Admin.UserController do
|
||||||
|
|
||||||
def update(conn, %{"user" => user_params}) do
|
def update(conn, %{"user" => user_params}) do
|
||||||
case Users.update_user(conn.assigns.user, user_params) do
|
case Users.update_user(conn.assigns.user, user_params) do
|
||||||
{:ok, _user} ->
|
{:ok, user} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "User successfully updated.")
|
|> put_flash(:info, "User successfully updated.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: user)
|
||||||
|> redirect(to: Routes.profile_path(conn, :show, conn.assigns.user))
|
|> redirect(to: Routes.profile_path(conn, :show, conn.assigns.user))
|
||||||
|
|
||||||
{:error, %{user: changeset}} ->
|
{:error, %{user: changeset}} ->
|
||||||
|
@ -79,4 +80,11 @@ defmodule PhilomenaWeb.Admin.UserController do
|
||||||
defp load_roles(conn, _opts) do
|
defp load_roles(conn, _opts) do
|
||||||
assign(conn, :roles, Repo.all(Role))
|
assign(conn, :roles, Repo.all(Role))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, user) do
|
||||||
|
%{
|
||||||
|
body: "Updated user details for #{user.name}",
|
||||||
|
subject_path: Routes.profile_path(conn, :show, user)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,9 +17,10 @@ defmodule PhilomenaWeb.DuplicateReport.AcceptController do
|
||||||
user = conn.assigns.current_user
|
user = conn.assigns.current_user
|
||||||
|
|
||||||
case DuplicateReports.accept_duplicate_report(report, user) do
|
case DuplicateReports.accept_duplicate_report(report, user) do
|
||||||
{:ok, _report} ->
|
{:ok, report} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully accepted report.")
|
|> put_flash(:info, "Successfully accepted report.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: report.duplicate_report)
|
||||||
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
||||||
|
|
||||||
_error ->
|
_error ->
|
||||||
|
@ -28,4 +29,12 @@ defmodule PhilomenaWeb.DuplicateReport.AcceptController do
|
||||||
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, report) do
|
||||||
|
%{
|
||||||
|
body:
|
||||||
|
"Accepted duplicate report, merged #{report.image.id} into #{report.duplicate_of_image.id}",
|
||||||
|
subject_path: Routes.image_path(conn, :show, report.image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,9 +17,10 @@ defmodule PhilomenaWeb.DuplicateReport.AcceptReverseController do
|
||||||
user = conn.assigns.current_user
|
user = conn.assigns.current_user
|
||||||
|
|
||||||
case DuplicateReports.accept_reverse_duplicate_report(report, user) do
|
case DuplicateReports.accept_reverse_duplicate_report(report, user) do
|
||||||
{:ok, _report} ->
|
{:ok, report} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully accepted report in reverse.")
|
|> put_flash(:info, "Successfully accepted report in reverse.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: report.duplicate_report)
|
||||||
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
||||||
|
|
||||||
_error ->
|
_error ->
|
||||||
|
@ -28,4 +29,12 @@ defmodule PhilomenaWeb.DuplicateReport.AcceptReverseController do
|
||||||
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, report) do
|
||||||
|
%{
|
||||||
|
body:
|
||||||
|
"Reverse-accepted duplicate report, merged #{report.image.id} into #{report.duplicate_of_image.id}",
|
||||||
|
subject_path: Routes.image_path(conn, :show, report.image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,7 +12,7 @@ defmodule PhilomenaWeb.DuplicateReport.ClaimController do
|
||||||
persisted: true
|
persisted: true
|
||||||
|
|
||||||
def create(conn, _params) do
|
def create(conn, _params) do
|
||||||
{:ok, _report} =
|
{:ok, report} =
|
||||||
DuplicateReports.claim_duplicate_report(
|
DuplicateReports.claim_duplicate_report(
|
||||||
conn.assigns.duplicate_report,
|
conn.assigns.duplicate_report,
|
||||||
conn.assigns.current_user
|
conn.assigns.current_user
|
||||||
|
@ -20,14 +20,29 @@ defmodule PhilomenaWeb.DuplicateReport.ClaimController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully claimed report.")
|
|> put_flash(:info, "Successfully claimed report.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: report)
|
||||||
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete(conn, _params) do
|
def delete(conn, _params) do
|
||||||
{:ok, _report} = DuplicateReports.unclaim_duplicate_report(conn.assigns.duplicate_report)
|
{:ok, report} = DuplicateReports.unclaim_duplicate_report(conn.assigns.duplicate_report)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully released report.")
|
|> put_flash(:info, "Successfully released report.")
|
||||||
|
|> moderation_log(details: &log_details/3)
|
||||||
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, _) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:create -> "Claimed a duplicate report"
|
||||||
|
:delete -> "Released a duplicate report"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
body: body,
|
||||||
|
subject_path: Routes.duplicate_report_path(conn, :index)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,7 @@ defmodule PhilomenaWeb.DuplicateReport.RejectController do
|
||||||
preload: [:image, :duplicate_of_image]
|
preload: [:image, :duplicate_of_image]
|
||||||
|
|
||||||
def create(conn, _params) do
|
def create(conn, _params) do
|
||||||
{:ok, _report} =
|
{:ok, report} =
|
||||||
DuplicateReports.reject_duplicate_report(
|
DuplicateReports.reject_duplicate_report(
|
||||||
conn.assigns.duplicate_report,
|
conn.assigns.duplicate_report,
|
||||||
conn.assigns.current_user
|
conn.assigns.current_user
|
||||||
|
@ -21,6 +21,14 @@ defmodule PhilomenaWeb.DuplicateReport.RejectController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully rejected report.")
|
|> put_flash(:info, "Successfully rejected report.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: report)
|
||||||
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
|> redirect(to: Routes.duplicate_report_path(conn, :index))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, report) do
|
||||||
|
%{
|
||||||
|
body: "Rejected duplicate report (#{report.image.id} -> #{report.duplicate_of_image.id})",
|
||||||
|
subject_path: Routes.duplicate_report_path(conn, :index)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,6 +22,7 @@ defmodule PhilomenaWeb.Image.AnonymousController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully updated anonymity.")
|
|> put_flash(:info, "Successfully updated anonymity.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,4 +32,11 @@ defmodule PhilomenaWeb.Image.AnonymousController do
|
||||||
_false -> PhilomenaWeb.NotAuthorizedPlug.call(conn)
|
_false -> PhilomenaWeb.NotAuthorizedPlug.call(conn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, image) do
|
||||||
|
%{
|
||||||
|
body: "Updated anonymity of image >>#{image.id}",
|
||||||
|
subject_path: Routes.image_path(conn, :show, image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,6 +16,7 @@ defmodule PhilomenaWeb.Image.Comment.DeleteController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Comment successfully destroyed!")
|
|> put_flash(:info, "Comment successfully destroyed!")
|
||||||
|
|> moderation_log(details: &log_details/3, data: comment)
|
||||||
|> redirect(
|
|> redirect(
|
||||||
to: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}"
|
to: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}"
|
||||||
)
|
)
|
||||||
|
@ -28,4 +29,11 @@ defmodule PhilomenaWeb.Image.Comment.DeleteController do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, comment) do
|
||||||
|
%{
|
||||||
|
body: "Destroyed comment on image >>#{comment.image_id}",
|
||||||
|
subject_path: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}"
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,7 @@ defmodule PhilomenaWeb.Image.Comment.HideController do
|
||||||
{:ok, comment} ->
|
{:ok, comment} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Comment successfully hidden!")
|
|> put_flash(:info, "Comment successfully hidden!")
|
||||||
|
|> moderation_log(details: &log_details/3, data: comment)
|
||||||
|> redirect(
|
|> redirect(
|
||||||
to: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}"
|
to: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}"
|
||||||
)
|
)
|
||||||
|
@ -35,6 +36,7 @@ defmodule PhilomenaWeb.Image.Comment.HideController do
|
||||||
{:ok, comment} ->
|
{:ok, comment} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Comment successfully unhidden!")
|
|> put_flash(:info, "Comment successfully unhidden!")
|
||||||
|
|> moderation_log(details: &log_details/3, data: comment)
|
||||||
|> redirect(
|
|> redirect(
|
||||||
to: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}"
|
to: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}"
|
||||||
)
|
)
|
||||||
|
@ -47,4 +49,17 @@ defmodule PhilomenaWeb.Image.Comment.HideController do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, comment) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:create -> "Hidden comment on image >>#{comment.image_id} (#{comment.deletion_reason})"
|
||||||
|
:delete -> "Restored comment on image >>#{comment.image_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
body: body,
|
||||||
|
subject_path: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}"
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,6 +12,7 @@ defmodule PhilomenaWeb.Image.CommentLockController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully locked comments.")
|
|> put_flash(:info, "Successfully locked comments.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -20,6 +21,20 @@ defmodule PhilomenaWeb.Image.CommentLockController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully unlocked comments.")
|
|> put_flash(:info, "Successfully unlocked comments.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, image) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:create -> "Locked comments on image >>#{image.id}"
|
||||||
|
:delete -> "Unlocked comments on image >>#{image.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
body: body,
|
||||||
|
subject_path: Routes.image_path(conn, :show, image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,9 +16,10 @@ defmodule PhilomenaWeb.Image.DeleteController do
|
||||||
user = conn.assigns.current_user
|
user = conn.assigns.current_user
|
||||||
|
|
||||||
case Images.hide_image(image, user, image_params) do
|
case Images.hide_image(image, user, image_params) do
|
||||||
{:ok, _image} ->
|
{:ok, result} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Image successfully hidden.")
|
|> put_flash(:info, "Image successfully hidden.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: result.image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
|
|
||||||
_error ->
|
_error ->
|
||||||
|
@ -35,6 +36,7 @@ defmodule PhilomenaWeb.Image.DeleteController do
|
||||||
{:ok, image} ->
|
{:ok, image} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Hide reason updated.")
|
|> put_flash(:info, "Hide reason updated.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
|
|
||||||
{:error, _changeset} ->
|
{:error, _changeset} ->
|
||||||
|
@ -60,10 +62,25 @@ defmodule PhilomenaWeb.Image.DeleteController do
|
||||||
def delete(conn, _params) do
|
def delete(conn, _params) do
|
||||||
image = conn.assigns.image
|
image = conn.assigns.image
|
||||||
|
|
||||||
{:ok, _image} = Images.unhide_image(image)
|
{:ok, image} = Images.unhide_image(image)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Image successfully unhidden.")
|
|> put_flash(:info, "Image successfully unhidden.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, image) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:create -> "Hidden image >>#{image.id} (#{image.deletion_reason})"
|
||||||
|
:update -> "Changed hide reason of >>#{image.id} (#{image.deletion_reason})"
|
||||||
|
:delete -> "Restored image >>#{image.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
body: body,
|
||||||
|
subject_path: Routes.image_path(conn, :show, image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,6 +12,7 @@ defmodule PhilomenaWeb.Image.DescriptionLockController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully locked description.")
|
|> put_flash(:info, "Successfully locked description.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -20,6 +21,20 @@ defmodule PhilomenaWeb.Image.DescriptionLockController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully unlocked description.")
|
|> put_flash(:info, "Successfully unlocked description.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, image) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:create -> "Locked description editing on image >>#{image.id}"
|
||||||
|
:delete -> "Unlocked description editing on image >>#{image.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
body: body,
|
||||||
|
subject_path: Routes.image_path(conn, :show, image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,7 @@ defmodule PhilomenaWeb.Image.DestroyController do
|
||||||
{:ok, image} ->
|
{:ok, image} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Image contents destroyed.")
|
|> put_flash(:info, "Image contents destroyed.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
|
|
||||||
_error ->
|
_error ->
|
||||||
|
@ -36,4 +37,11 @@ defmodule PhilomenaWeb.Image.DestroyController do
|
||||||
|> halt()
|
|> halt()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, image) do
|
||||||
|
%{
|
||||||
|
body: "Hard-deleted image >>#{image.id}",
|
||||||
|
subject_path: Routes.image_path(conn, :show, image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,6 +16,7 @@ defmodule PhilomenaWeb.Image.FeatureController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Image marked as featured image.")
|
|> put_flash(:info, "Image marked as featured image.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,4 +32,11 @@ defmodule PhilomenaWeb.Image.FeatureController do
|
||||||
conn
|
conn
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, image) do
|
||||||
|
%{
|
||||||
|
body: "Featured image >>#{image.id}",
|
||||||
|
subject_path: Routes.image_path(conn, :show, image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,6 +12,14 @@ defmodule PhilomenaWeb.Image.HashController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully cleared hash.")
|
|> put_flash(:info, "Successfully cleared hash.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, image) do
|
||||||
|
%{
|
||||||
|
body: "Cleared hash of image >>#{image.id}",
|
||||||
|
subject_path: Routes.image_path(conn, :show, image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,6 +13,14 @@ defmodule PhilomenaWeb.Image.RepairController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Repair job enqueued.")
|
|> put_flash(:info, "Repair job enqueued.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: conn.assigns.image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, conn.assigns.image))
|
|> redirect(to: Routes.image_path(conn, :show, conn.assigns.image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, image) do
|
||||||
|
%{
|
||||||
|
body: "Repaired image >>#{image.id}",
|
||||||
|
subject_path: Routes.image_path(conn, :show, image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,6 +17,14 @@ defmodule PhilomenaWeb.Image.ScratchpadController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully updated moderation notes.")
|
|> put_flash(:info, "Successfully updated moderation notes.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, image) do
|
||||||
|
%{
|
||||||
|
body: "Updated mod notes on image >>#{image.id} (#{image.scratchpad})",
|
||||||
|
subject_path: Routes.image_path(conn, :show, image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,6 +14,14 @@ defmodule PhilomenaWeb.Image.SourceHistoryController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully deleted source history.")
|
|> put_flash(:info, "Successfully deleted source history.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, image) do
|
||||||
|
%{
|
||||||
|
body: "Deleted source history for image >>#{image.id}",
|
||||||
|
subject_path: Routes.image_path(conn, :show, image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,6 +23,7 @@ defmodule PhilomenaWeb.Image.TagLockController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully updated list of locked tags.")
|
|> put_flash(:info, "Successfully updated list of locked tags.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@ defmodule PhilomenaWeb.Image.TagLockController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully locked tags.")
|
|> put_flash(:info, "Successfully locked tags.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -39,6 +41,21 @@ defmodule PhilomenaWeb.Image.TagLockController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Successfully unlocked tags.")
|
|> put_flash(:info, "Successfully unlocked tags.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: image)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, image))
|
|> redirect(to: Routes.image_path(conn, :show, image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, image) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:create -> "Locked tags on image >>#{image.id}"
|
||||||
|
:update -> "Updated list of locked tags on image >>#{image.id}"
|
||||||
|
:delete -> "Unlocked tags on image >>#{image.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
body: body,
|
||||||
|
subject_path: Routes.image_path(conn, :show, image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,7 +16,7 @@ defmodule PhilomenaWeb.Image.TamperController do
|
||||||
image = conn.assigns.image
|
image = conn.assigns.image
|
||||||
user = conn.assigns.user
|
user = conn.assigns.user
|
||||||
|
|
||||||
{:ok, _result} =
|
{:ok, result} =
|
||||||
ImageVotes.delete_vote_transaction(image, user)
|
ImageVotes.delete_vote_transaction(image, user)
|
||||||
|> Repo.transaction()
|
|> Repo.transaction()
|
||||||
|
|
||||||
|
@ -24,6 +24,26 @@ defmodule PhilomenaWeb.Image.TamperController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Vote removed.")
|
|> put_flash(:info, "Vote removed.")
|
||||||
|
|> moderation_log(
|
||||||
|
details: &log_details/3,
|
||||||
|
data: %{vote: result, image: image}
|
||||||
|
)
|
||||||
|> redirect(to: Routes.image_path(conn, :show, conn.assigns.image))
|
|> redirect(to: Routes.image_path(conn, :show, conn.assigns.image))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, data) do
|
||||||
|
image = data.image
|
||||||
|
|
||||||
|
vote_type =
|
||||||
|
case data.vote do
|
||||||
|
%{undownvote: {1, _}} -> "downvote"
|
||||||
|
%{unupvote: {1, _}} -> "upvote"
|
||||||
|
_ -> "vote"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
body: "Deleted #{vote_type} by #{conn.assigns.user.name} on image >>#{data.image.id}",
|
||||||
|
subject_path: Routes.image_path(conn, :show, image)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
15
lib/philomena_web/controllers/moderation_log_controller.ex
Normal file
15
lib/philomena_web/controllers/moderation_log_controller.ex
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
defmodule PhilomenaWeb.ModerationLogController do
|
||||||
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
|
alias Philomena.ModerationLogs
|
||||||
|
alias Philomena.ModerationLogs.ModerationLog
|
||||||
|
|
||||||
|
plug :load_and_authorize_resource,
|
||||||
|
model: ModerationLog,
|
||||||
|
preload: [:user]
|
||||||
|
|
||||||
|
def index(conn, _params) do
|
||||||
|
moderation_logs = ModerationLogs.list_moderation_logs(conn)
|
||||||
|
render(conn, "index.html", title: "Moderation Logs", moderation_logs: moderation_logs)
|
||||||
|
end
|
||||||
|
end
|
|
@ -23,6 +23,7 @@ defmodule PhilomenaWeb.Tag.ImageController do
|
||||||
{:ok, tag} ->
|
{:ok, tag} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Tag image successfully updated.")
|
|> put_flash(:info, "Tag image successfully updated.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: tag)
|
||||||
|> redirect(to: Routes.tag_path(conn, :show, tag))
|
|> redirect(to: Routes.tag_path(conn, :show, tag))
|
||||||
|
|
||||||
{:error, :tag, changeset, _changes} ->
|
{:error, :tag, changeset, _changes} ->
|
||||||
|
@ -31,10 +32,24 @@ defmodule PhilomenaWeb.Tag.ImageController do
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete(conn, _params) do
|
def delete(conn, _params) do
|
||||||
{:ok, _tag} = Tags.remove_tag_image(conn.assigns.tag)
|
{:ok, tag} = Tags.remove_tag_image(conn.assigns.tag)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Tag image successfully removed.")
|
|> put_flash(:info, "Tag image successfully removed.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: tag)
|
||||||
|> redirect(to: Routes.tag_path(conn, :show, conn.assigns.tag))
|
|> redirect(to: Routes.tag_path(conn, :show, conn.assigns.tag))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, tag) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:update -> "Updated image on tag '#{tag.name}'"
|
||||||
|
:delete -> "Removed image on tag '#{tag.name}'"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
body: body,
|
||||||
|
subject_path: Routes.tag_path(conn, :show, tag)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -97,6 +97,7 @@ defmodule PhilomenaWeb.TagController do
|
||||||
{:ok, tag} ->
|
{:ok, tag} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Tag successfully updated.")
|
|> put_flash(:info, "Tag successfully updated.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: tag)
|
||||||
|> redirect(to: Routes.tag_path(conn, :show, tag))
|
|> redirect(to: Routes.tag_path(conn, :show, tag))
|
||||||
|
|
||||||
{:error, changeset} ->
|
{:error, changeset} ->
|
||||||
|
@ -105,10 +106,11 @@ defmodule PhilomenaWeb.TagController do
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete(conn, _params) do
|
def delete(conn, _params) do
|
||||||
{:ok, _tag} = Tags.delete_tag(conn.assigns.tag)
|
{:ok, tag} = Tags.delete_tag(conn.assigns.tag)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Tag queued for deletion.")
|
|> put_flash(:info, "Tag queued for deletion.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: tag)
|
||||||
|> redirect(to: "/")
|
|> redirect(to: "/")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -169,4 +171,17 @@ defmodule PhilomenaWeb.TagController do
|
||||||
|> halt()
|
|> halt()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, tag) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:update -> "Updated details on tag '#{tag.name}'"
|
||||||
|
:delete -> "Deleted tag '#{tag.name}'"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
body: body,
|
||||||
|
subject_path: Routes.tag_path(conn, :show, tag)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,6 +27,7 @@ defmodule PhilomenaWeb.Topic.HideController do
|
||||||
{:ok, topic} ->
|
{:ok, topic} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Topic successfully hidden!")
|
|> put_flash(:info, "Topic successfully hidden!")
|
||||||
|
|> moderation_log(details: &log_details/3, data: topic)
|
||||||
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
||||||
|
|
||||||
{:error, _changeset} ->
|
{:error, _changeset} ->
|
||||||
|
@ -43,6 +44,7 @@ defmodule PhilomenaWeb.Topic.HideController do
|
||||||
{:ok, topic} ->
|
{:ok, topic} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Topic successfully restored!")
|
|> put_flash(:info, "Topic successfully restored!")
|
||||||
|
|> moderation_log(details: &log_details/3, data: topic)
|
||||||
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
||||||
|
|
||||||
{:error, _changeset} ->
|
{:error, _changeset} ->
|
||||||
|
@ -51,4 +53,20 @@ defmodule PhilomenaWeb.Topic.HideController do
|
||||||
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, topic) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:create ->
|
||||||
|
"Hidden topic '#{topic.title}' (#{topic.deletion_reason}) in #{topic.forum.name}"
|
||||||
|
|
||||||
|
:delete ->
|
||||||
|
"Restored topic '#{topic.title}' in #{topic.forum.name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
body: body,
|
||||||
|
subject_path: Routes.forum_topic_path(conn, :show, topic.forum, topic)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,6 +26,7 @@ defmodule PhilomenaWeb.Topic.LockController do
|
||||||
{:ok, topic} ->
|
{:ok, topic} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Topic successfully locked!")
|
|> put_flash(:info, "Topic successfully locked!")
|
||||||
|
|> moderation_log(details: &log_details/3, data: topic)
|
||||||
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
||||||
|
|
||||||
{:error, _changeset} ->
|
{:error, _changeset} ->
|
||||||
|
@ -42,6 +43,7 @@ defmodule PhilomenaWeb.Topic.LockController do
|
||||||
{:ok, topic} ->
|
{:ok, topic} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Topic successfully unlocked!")
|
|> put_flash(:info, "Topic successfully unlocked!")
|
||||||
|
|> moderation_log(details: &log_details/3, data: topic)
|
||||||
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
||||||
|
|
||||||
{:error, _changeset} ->
|
{:error, _changeset} ->
|
||||||
|
@ -50,4 +52,17 @@ defmodule PhilomenaWeb.Topic.LockController do
|
||||||
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, topic) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:create -> "Locked topic '#{topic.title}' (#{topic.lock_reason}) in #{topic.forum.name}"
|
||||||
|
:delete -> "Unlocked topic '#{topic.title}' in #{topic.forum.name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
body: body,
|
||||||
|
subject_path: Routes.forum_topic_path(conn, :show, topic.forum, topic)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -29,6 +29,7 @@ defmodule PhilomenaWeb.Topic.MoveController do
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Topic successfully moved!")
|
|> put_flash(:info, "Topic successfully moved!")
|
||||||
|
|> moderation_log(details: &log_details/3, data: topic)
|
||||||
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
||||||
|
|
||||||
{:error, _changeset} ->
|
{:error, _changeset} ->
|
||||||
|
@ -37,4 +38,11 @@ defmodule PhilomenaWeb.Topic.MoveController do
|
||||||
|> redirect(to: Routes.forum_topic_path(conn, :show, conn.assigns.forum, topic))
|
|> redirect(to: Routes.forum_topic_path(conn, :show, conn.assigns.forum, topic))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, topic) do
|
||||||
|
%{
|
||||||
|
body: "Topic '#{topic.title}' moved to #{topic.forum.name}",
|
||||||
|
subject_path: Routes.forum_topic_path(conn, :show, topic.forum, topic)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,6 +19,7 @@ defmodule PhilomenaWeb.Topic.Post.DeleteController do
|
||||||
{:ok, post} ->
|
{:ok, post} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Post successfully destroyed!")
|
|> put_flash(:info, "Post successfully destroyed!")
|
||||||
|
|> moderation_log(details: &log_details/3, data: post)
|
||||||
|> redirect(
|
|> redirect(
|
||||||
to:
|
to:
|
||||||
Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <>
|
Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <>
|
||||||
|
@ -35,4 +36,13 @@ defmodule PhilomenaWeb.Topic.Post.DeleteController do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, _action, post) do
|
||||||
|
%{
|
||||||
|
body: "Destroyed forum post ##{post.id} in topic '#{post.topic.title}'",
|
||||||
|
subject_path:
|
||||||
|
Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <>
|
||||||
|
"#post_#{post.id}"
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,6 +20,7 @@ defmodule PhilomenaWeb.Topic.Post.HideController do
|
||||||
{:ok, post} ->
|
{:ok, post} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Post successfully hidden.")
|
|> put_flash(:info, "Post successfully hidden.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: post)
|
||||||
|> redirect(
|
|> redirect(
|
||||||
to:
|
to:
|
||||||
Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <>
|
Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <>
|
||||||
|
@ -44,6 +45,7 @@ defmodule PhilomenaWeb.Topic.Post.HideController do
|
||||||
{:ok, post} ->
|
{:ok, post} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Post successfully unhidden.")
|
|> put_flash(:info, "Post successfully unhidden.")
|
||||||
|
|> moderation_log(details: &log_details/3, data: post)
|
||||||
|> redirect(
|
|> redirect(
|
||||||
to:
|
to:
|
||||||
Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <>
|
Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <>
|
||||||
|
@ -60,4 +62,22 @@ defmodule PhilomenaWeb.Topic.Post.HideController do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, post) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:create ->
|
||||||
|
"Hidden forum post ##{post.id} in topic '#{post.topic.title}' (#{post.deletion_reason})"
|
||||||
|
|
||||||
|
:delete ->
|
||||||
|
"Restored forum post ##{post.id} in topic '#{post.topic.title}'"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
body: body,
|
||||||
|
subject_path:
|
||||||
|
Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <>
|
||||||
|
"#post_#{post.id}"
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,6 +25,7 @@ defmodule PhilomenaWeb.Topic.StickController do
|
||||||
{:ok, topic} ->
|
{:ok, topic} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Topic successfully stickied!")
|
|> put_flash(:info, "Topic successfully stickied!")
|
||||||
|
|> moderation_log(details: &log_details/3, data: topic)
|
||||||
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
||||||
|
|
||||||
{:error, _changeset} ->
|
{:error, _changeset} ->
|
||||||
|
@ -41,6 +42,7 @@ defmodule PhilomenaWeb.Topic.StickController do
|
||||||
{:ok, topic} ->
|
{:ok, topic} ->
|
||||||
conn
|
conn
|
||||||
|> put_flash(:info, "Topic successfully unstickied!")
|
|> put_flash(:info, "Topic successfully unstickied!")
|
||||||
|
|> moderation_log(details: &log_details/3, data: topic)
|
||||||
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
||||||
|
|
||||||
{:error, _changeset} ->
|
{:error, _changeset} ->
|
||||||
|
@ -49,4 +51,17 @@ defmodule PhilomenaWeb.Topic.StickController do
|
||||||
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
|> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp log_details(conn, action, topic) do
|
||||||
|
body =
|
||||||
|
case action do
|
||||||
|
:create -> "Stickied topic '#{topic.title}' in #{topic.forum.name}"
|
||||||
|
:delete -> "Unstickied topic '#{topic.title}' in #{topic.forum.name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
body: body,
|
||||||
|
subject_path: Routes.forum_topic_path(conn, :show, topic.forum, topic)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
46
lib/philomena_web/plugs/moderation_log_plug.ex
Normal file
46
lib/philomena_web/plugs/moderation_log_plug.ex
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
defmodule PhilomenaWeb.ModerationLogPlug do
|
||||||
|
@moduledoc """
|
||||||
|
This plug writes moderation logs.
|
||||||
|
## Example
|
||||||
|
|
||||||
|
plug PhilomenaWeb.ModerationLogPlug, [details: &log_details/2]
|
||||||
|
"""
|
||||||
|
|
||||||
|
@controller_regex ~r/PhilomenaWeb\.([\w\.]+)Controller\z/
|
||||||
|
|
||||||
|
alias Plug.Conn
|
||||||
|
alias Phoenix.Controller
|
||||||
|
alias Philomena.ModerationLogs
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec init(any()) :: any()
|
||||||
|
def init(opts), do: opts
|
||||||
|
|
||||||
|
@type log_details :: %{subject_path: String.t(), body: String.t()}
|
||||||
|
@type details_func :: (Plug.Conn.t(), atom(), any() -> log_details())
|
||||||
|
@type call_opts :: [details: details_func, data: any()]
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec call(Conn.t(), call_opts) :: Conn.t()
|
||||||
|
def call(conn, opts) do
|
||||||
|
details_func = Keyword.fetch!(opts, :details)
|
||||||
|
userdata = Keyword.get(opts, :data, nil)
|
||||||
|
|
||||||
|
user = conn.assigns.current_user
|
||||||
|
action = Controller.action_name(conn)
|
||||||
|
|
||||||
|
%{subject_path: subject_path, body: body} = details_func.(conn, action, userdata)
|
||||||
|
|
||||||
|
mod = Controller.controller_module(conn)
|
||||||
|
[mod_name] = Regex.run(@controller_regex, to_string(mod), capture: :all_but_first)
|
||||||
|
type = "#{mod_name}:#{action}"
|
||||||
|
|
||||||
|
ModerationLogs.create_moderation_log(user, type, subject_path, body)
|
||||||
|
|
||||||
|
conn
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec moderation_log(Conn.t(), call_opts()) :: Conn.t()
|
||||||
|
def moderation_log(conn, opts), do: call(conn, opts)
|
||||||
|
end
|
|
@ -327,6 +327,8 @@ defmodule PhilomenaWeb.Router do
|
||||||
resources "/source_changes", FingerprintProfile.SourceChangeController, only: [:index]
|
resources "/source_changes", FingerprintProfile.SourceChangeController, only: [:index]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
resources "/moderation_logs", ModerationLogController, only: [:index]
|
||||||
|
|
||||||
scope "/admin", Admin, as: :admin do
|
scope "/admin", Admin, as: :admin do
|
||||||
resources "/reports", ReportController, only: [:index, :show] do
|
resources "/reports", ReportController, only: [:index, :show] do
|
||||||
resources "/claim", Report.ClaimController, only: [:create, :delete], singleton: true
|
resources "/claim", Report.ClaimController, only: [:create, :delete], singleton: true
|
||||||
|
|
|
@ -38,9 +38,14 @@
|
||||||
|
|
||||||
= if manages_mod_notes?(@conn) do
|
= if manages_mod_notes?(@conn) do
|
||||||
= link to: Routes.admin_mod_note_path(@conn, :index), class: "header__link" do
|
= link to: Routes.admin_mod_note_path(@conn, :index), class: "header__link" do
|
||||||
i.fa.fa-fw.fa-sticky-note>
|
i.fa.fa-fw.fa-clipboard>
|
||||||
' Mod Notes
|
' Mod Notes
|
||||||
|
|
||||||
|
= if can_see_moderation_log?(@conn) do
|
||||||
|
= link to: Routes.moderation_log_path(@conn, :index), class: "header__link" do
|
||||||
|
i.fa.fa-fw.fa-list-alt>
|
||||||
|
' Mod Logs
|
||||||
|
|
||||||
= if @duplicate_report_count do
|
= if @duplicate_report_count do
|
||||||
= link to: Routes.duplicate_report_path(@conn, :index), class: "header__link", title: "Duplicates" do
|
= link to: Routes.duplicate_report_path(@conn, :index), class: "header__link", title: "Duplicates" do
|
||||||
' D
|
' D
|
||||||
|
|
33
lib/philomena_web/templates/moderation_log/index.html.slime
Normal file
33
lib/philomena_web/templates/moderation_log/index.html.slime
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
elixir:
|
||||||
|
route = fn p -> Routes.moderation_log_path(@conn, :index, p) end
|
||||||
|
pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @moderation_logs, route: route, conn: @conn
|
||||||
|
|
||||||
|
h1 Listing Moderation Logs
|
||||||
|
|
||||||
|
block
|
||||||
|
.block__header
|
||||||
|
.page__pagination = pagination
|
||||||
|
|
||||||
|
table
|
||||||
|
thead
|
||||||
|
tr
|
||||||
|
th Moderator
|
||||||
|
th Type
|
||||||
|
th Body
|
||||||
|
th Creation time
|
||||||
|
th Actions
|
||||||
|
tbody
|
||||||
|
= for log <- @moderation_logs do
|
||||||
|
tr
|
||||||
|
td = render PhilomenaWeb.UserAttributionView, "_user.html", object: %{user: log.user}, conn: @conn
|
||||||
|
td = log.type
|
||||||
|
td = log.body
|
||||||
|
td = pretty_time(log.created_at)
|
||||||
|
td
|
||||||
|
= link to: log.subject_path do
|
||||||
|
i.fa.fa-eye>
|
||||||
|
' View subject
|
||||||
|
|
||||||
|
block
|
||||||
|
.block__header
|
||||||
|
.page__pagination = pagination
|
|
@ -117,6 +117,9 @@ defmodule PhilomenaWeb.LayoutView do
|
||||||
def manages_bans?(conn),
|
def manages_bans?(conn),
|
||||||
do: can?(conn, :create, Philomena.Bans.User)
|
do: can?(conn, :create, Philomena.Bans.User)
|
||||||
|
|
||||||
|
def can_see_moderation_log?(conn),
|
||||||
|
do: can?(conn, :index, Philomena.ModerationLogs.ModerationLog)
|
||||||
|
|
||||||
def viewport_meta_tag(conn) do
|
def viewport_meta_tag(conn) do
|
||||||
ua = get_user_agent(conn)
|
ua = get_user_agent(conn)
|
||||||
|
|
||||||
|
|
3
lib/philomena_web/views/moderation_log_view.ex
Normal file
3
lib/philomena_web/views/moderation_log_view.ex
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
defmodule PhilomenaWeb.ModerationLogView do
|
||||||
|
use PhilomenaWeb, :view
|
||||||
|
end
|
|
@ -0,0 +1,20 @@
|
||||||
|
defmodule Philomena.Repo.Migrations.CreateModerationLogs do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
create table(:moderation_logs) do
|
||||||
|
add :user_id, references(:users, on_delete: :delete_all), null: false
|
||||||
|
add :body, :varchar, null: false
|
||||||
|
add :subject_path, :varchar, null: false
|
||||||
|
add :type, :varchar, null: false
|
||||||
|
|
||||||
|
timestamps(inserted_at: :created_at, updated_at: false, type: :utc_datetime)
|
||||||
|
end
|
||||||
|
|
||||||
|
create index(:moderation_logs, [:user_id])
|
||||||
|
create index(:moderation_logs, [:type])
|
||||||
|
create index(:moderation_logs, [:created_at])
|
||||||
|
create index(:moderation_logs, [:user_id, :created_at])
|
||||||
|
create index(:moderation_logs, [:type, :created_at])
|
||||||
|
end
|
||||||
|
end
|
|
@ -1054,6 +1054,39 @@ CREATE SEQUENCE public.mod_notes_id_seq
|
||||||
ALTER SEQUENCE public.mod_notes_id_seq OWNED BY public.mod_notes.id;
|
ALTER SEQUENCE public.mod_notes_id_seq OWNED BY public.mod_notes.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: moderation_logs; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.moderation_logs (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
user_id bigint NOT NULL,
|
||||||
|
body character varying NOT NULL,
|
||||||
|
subject_path character varying NOT NULL,
|
||||||
|
type character varying NOT NULL,
|
||||||
|
created_at timestamp(0) without time zone NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: moderation_logs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.moderation_logs_id_seq
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: moderation_logs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.moderation_logs_id_seq OWNED BY public.moderation_logs.id;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: notifications; Type: TABLE; Schema: public; Owner: -
|
-- Name: notifications; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -2244,6 +2277,13 @@ ALTER TABLE ONLY public.messages ALTER COLUMN id SET DEFAULT nextval('public.mes
|
||||||
ALTER TABLE ONLY public.mod_notes ALTER COLUMN id SET DEFAULT nextval('public.mod_notes_id_seq'::regclass);
|
ALTER TABLE ONLY public.mod_notes ALTER COLUMN id SET DEFAULT nextval('public.mod_notes_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: moderation_logs id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.moderation_logs ALTER COLUMN id SET DEFAULT nextval('public.moderation_logs_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: notifications id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: notifications id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -2603,6 +2643,14 @@ ALTER TABLE ONLY public.mod_notes
|
||||||
ADD CONSTRAINT mod_notes_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT mod_notes_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: moderation_logs moderation_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.moderation_logs
|
||||||
|
ADD CONSTRAINT moderation_logs_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: notifications notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: notifications notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -4001,6 +4049,41 @@ CREATE INDEX index_vpns_on_ip ON public.vpns USING gist (ip inet_ops);
|
||||||
CREATE INDEX intensities_index ON public.images USING btree (se_intensity, sw_intensity, ne_intensity, nw_intensity, average_intensity);
|
CREATE INDEX intensities_index ON public.images USING btree (se_intensity, sw_intensity, ne_intensity, nw_intensity, average_intensity);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: moderation_logs_created_at_index; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX moderation_logs_created_at_index ON public.moderation_logs USING btree (created_at);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: moderation_logs_type_created_at_index; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX moderation_logs_type_created_at_index ON public.moderation_logs USING btree (type, created_at);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: moderation_logs_type_index; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX moderation_logs_type_index ON public.moderation_logs USING btree (type);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: moderation_logs_user_id_created_at_index; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX moderation_logs_user_id_created_at_index ON public.moderation_logs USING btree (user_id, created_at);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: moderation_logs_user_id_index; Type: INDEX; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX moderation_logs_user_id_index ON public.moderation_logs USING btree (user_id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: user_tokens_context_token_index; Type: INDEX; Schema: public; Owner: -
|
-- Name: user_tokens_context_token_index; Type: INDEX; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -4831,6 +4914,14 @@ ALTER TABLE ONLY public.image_tag_locks
|
||||||
ADD CONSTRAINT image_tag_locks_tag_id_fkey FOREIGN KEY (tag_id) REFERENCES public.tags(id) ON DELETE CASCADE;
|
ADD CONSTRAINT image_tag_locks_tag_id_fkey FOREIGN KEY (tag_id) REFERENCES public.tags(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: moderation_logs moderation_logs_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.moderation_logs
|
||||||
|
ADD CONSTRAINT moderation_logs_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: user_tokens user_tokens_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: user_tokens user_tokens_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -4867,3 +4958,4 @@ INSERT INTO public."schema_migrations" (version) VALUES (20210912171343);
|
||||||
INSERT INTO public."schema_migrations" (version) VALUES (20210917190346);
|
INSERT INTO public."schema_migrations" (version) VALUES (20210917190346);
|
||||||
INSERT INTO public."schema_migrations" (version) VALUES (20210921025336);
|
INSERT INTO public."schema_migrations" (version) VALUES (20210921025336);
|
||||||
INSERT INTO public."schema_migrations" (version) VALUES (20210929181319);
|
INSERT INTO public."schema_migrations" (version) VALUES (20210929181319);
|
||||||
|
INSERT INTO public."schema_migrations" (version) VALUES (20211107130226);
|
||||||
|
|
30
test/philomena/moderation_logs_test.exs
Normal file
30
test/philomena/moderation_logs_test.exs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
defmodule Philomena.ModerationLogsTest do
|
||||||
|
use Philomena.DataCase
|
||||||
|
|
||||||
|
alias Philomena.ModerationLogs
|
||||||
|
|
||||||
|
describe "moderation_logs" do
|
||||||
|
alias Philomena.ModerationLogs.ModerationLog
|
||||||
|
|
||||||
|
import Philomena.UsersFixtures
|
||||||
|
|
||||||
|
test "create_moderation_log/4 with valid data creates a moderation_log" do
|
||||||
|
user = user_fixture()
|
||||||
|
|
||||||
|
assert {:ok, %ModerationLog{} = _moderation_log} =
|
||||||
|
ModerationLogs.create_moderation_log(
|
||||||
|
user,
|
||||||
|
"User:update",
|
||||||
|
"/path/to/subject",
|
||||||
|
"Updated user"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create_moderation_log/4 with invalid data returns error changeset" do
|
||||||
|
user = user_fixture()
|
||||||
|
|
||||||
|
assert {:error, %Ecto.Changeset{}} =
|
||||||
|
ModerationLogs.create_moderation_log(user, nil, nil, nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue