Introduce backend for reports
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -41,7 +41,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
@spec insert(map(), boolean()) :: {:ok, %Activity{}} | {:error, any()}
|
||||
def insert(map, local \\ true) when is_map(map) do
|
||||
with map <- lazy_put_activity_defaults(map),
|
||||
:ok <- insert_full_object(map) do
|
||||
{:ok, object} <- insert_full_object(map) do
|
||||
object_id = if is_map(map["object"]), do: map["object"]["id"], else: map["id"]
|
||||
|
||||
map = if local, do: Map.put(map, "id", "#{object_id}/activity"), else: map
|
||||
@@ -55,7 +55,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
|
||||
# Notification.create_notifications(activity)
|
||||
# stream_out(activity)
|
||||
{:ok, activity}
|
||||
{:ok, activity, object}
|
||||
else
|
||||
%Activity{} = activity -> {:ok, activity}
|
||||
error -> {:error, error}
|
||||
@@ -130,7 +130,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
additional
|
||||
),
|
||||
:ok <- Logger.debug(inspect(create_data)),
|
||||
{:ok, activity} <- insert(create_data, local),
|
||||
{:ok, activity, _object} <- insert(create_data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
# {:ok, actor} <- Actors.increase_event_count(actor) do
|
||||
{:ok, activity}
|
||||
@@ -147,7 +147,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
local = !(params[:local] == false)
|
||||
|
||||
with data <- %{"to" => to, "type" => "Accept", "actor" => actor, "object" => object},
|
||||
{:ok, activity} <- insert(data, local),
|
||||
{:ok, activity, _object} <- insert(data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
@@ -164,7 +164,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
"actor" => actor,
|
||||
"object" => object
|
||||
},
|
||||
{:ok, activity} <- insert(data, local),
|
||||
{:ok, activity, _object} <- insert(data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
@@ -179,7 +179,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
# ) do
|
||||
# with nil <- get_existing_like(url, object),
|
||||
# like_data <- make_like_data(user, object, activity_id),
|
||||
# {:ok, activity} <- insert(like_data, local),
|
||||
# {:ok, activity, _object} <- insert(like_data, local),
|
||||
# {:ok, object} <- add_like_to_object(activity, object),
|
||||
# :ok <- maybe_federate(activity) do
|
||||
# {:ok, activity, object}
|
||||
@@ -197,7 +197,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
# ) do
|
||||
# with %Activity{} = like_activity <- get_existing_like(actor.ap_id, object),
|
||||
# unlike_data <- make_unlike_data(actor, like_activity, activity_id),
|
||||
# {:ok, unlike_activity} <- insert(unlike_data, local),
|
||||
# {:ok, unlike_activity, _object} <- insert(unlike_data, local),
|
||||
# {:ok, _activity} <- Repo.delete(like_activity),
|
||||
# {:ok, object} <- remove_like_from_object(like_activity, object),
|
||||
# :ok <- maybe_federate(unlike_activity) do
|
||||
@@ -215,7 +215,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
# ) do
|
||||
# #with true <- is_public?(object),
|
||||
# with announce_data <- make_announce_data(actor, object, activity_id),
|
||||
# {:ok, activity} <- insert(announce_data, local),
|
||||
# {:ok, activity, _object} <- insert(announce_data, local),
|
||||
# # {:ok, object} <- add_announce_to_object(activity, object),
|
||||
# :ok <- maybe_federate(activity) do
|
||||
# {:ok, activity, object}
|
||||
@@ -232,7 +232,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
# ) do
|
||||
# with %Activity{} = announce_activity <- get_existing_announce(actor.ap_id, object),
|
||||
# unannounce_data <- make_unannounce_data(actor, announce_activity, activity_id),
|
||||
# {:ok, unannounce_activity} <- insert(unannounce_data, local),
|
||||
# {:ok, unannounce_activity, _object} <- insert(unannounce_data, local),
|
||||
# :ok <- maybe_federate(unannounce_activity),
|
||||
# {:ok, _activity} <- Repo.delete(announce_activity),
|
||||
# {:ok, object} <- remove_announce_from_object(announce_activity, object) do
|
||||
@@ -250,7 +250,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
activity_follow_id <-
|
||||
activity_id || "#{MobilizonWeb.Endpoint.url()}/follow/#{follow_id}/activity",
|
||||
data <- make_follow_data(followed, follower, activity_follow_id),
|
||||
{:ok, activity} <- insert(data, local),
|
||||
{:ok, activity, _object} <- insert(data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
@@ -267,9 +267,9 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
with {:ok, %Follower{id: follow_id}} <- Actor.unfollow(followed, follower),
|
||||
# We recreate the follow activity
|
||||
data <- make_follow_data(followed, follower, follow_id),
|
||||
{:ok, follow_activity} <- insert(data, local),
|
||||
{:ok, follow_activity, _object} <- insert(data, local),
|
||||
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
|
||||
{:ok, activity} <- insert(unfollow_data, local),
|
||||
{:ok, activity, _object} <- insert(unfollow_data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
@@ -290,7 +290,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
}
|
||||
|
||||
with Events.delete_event(event),
|
||||
{:ok, activity} <- insert(data, local),
|
||||
{:ok, activity, _object} <- insert(data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
@@ -305,7 +305,7 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
}
|
||||
|
||||
with Events.delete_comment(comment),
|
||||
{:ok, activity} <- insert(data, local),
|
||||
{:ok, activity, _object} <- insert(data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
@@ -320,12 +320,33 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
}
|
||||
|
||||
with Actors.delete_actor(actor),
|
||||
{:ok, activity} <- insert(data, local),
|
||||
{:ok, activity, _object} <- insert(data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
||||
def flag(params) do
|
||||
# only accept false as false value
|
||||
local = !(params[:local] == false)
|
||||
forward = !(params[:forward] == false)
|
||||
|
||||
additional = params[:additional] || %{}
|
||||
|
||||
additional =
|
||||
if forward do
|
||||
Map.merge(additional, %{"to" => [], "cc" => [params.reported_actor_url]})
|
||||
else
|
||||
Map.merge(additional, %{"to" => [], "cc" => []})
|
||||
end
|
||||
|
||||
with flag_data <- make_flag_data(params, additional),
|
||||
{:ok, activity, report} <- insert(flag_data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity, report}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Create an actor locally by it's URL (AP ID)
|
||||
"""
|
||||
|
||||
85
lib/service/activity_pub/converters/flag.ex
Normal file
85
lib/service/activity_pub/converters/flag.ex
Normal file
@@ -0,0 +1,85 @@
|
||||
defmodule Mobilizon.Service.ActivityPub.Converters.Flag do
|
||||
@moduledoc """
|
||||
Flag converter
|
||||
|
||||
This module allows to convert reports from ActivityStream format to our own internal one, and back.
|
||||
|
||||
Note: Reports are named Flag in AS.
|
||||
"""
|
||||
alias Mobilizon.Actors
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Events
|
||||
alias Mobilizon.Events.Event
|
||||
alias Mobilizon.Reports.Report
|
||||
alias Mobilizon.Service.ActivityPub.Converter
|
||||
|
||||
@behaviour Converter
|
||||
|
||||
@doc """
|
||||
Converts an AP object data to our internal data structure
|
||||
"""
|
||||
@impl Converter
|
||||
@spec as_to_model_data(map()) :: map()
|
||||
def as_to_model_data(object) do
|
||||
with params <- as_to_model(object) do
|
||||
%{
|
||||
"reporter_id" => params["reporter"].id,
|
||||
"uri" => params["uri"],
|
||||
"content" => params["content"],
|
||||
"reported_id" => params["reported"].id,
|
||||
"event_id" => (!is_nil(params["event"]) && params["event"].id) || nil,
|
||||
"comments" => params["comments"]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def as_to_model(%{"object" => objects} = object) do
|
||||
with {:ok, %Actor{} = reporter} <- Actors.get_actor_by_url(object["actor"]),
|
||||
%Actor{} = reported <-
|
||||
Enum.reduce_while(objects, nil, fn url, _ ->
|
||||
with {:ok, %Actor{} = actor} <- Actors.get_actor_by_url(url) do
|
||||
{:halt, actor}
|
||||
else
|
||||
_ -> {:cont, nil}
|
||||
end
|
||||
end),
|
||||
event <-
|
||||
Enum.reduce_while(objects, nil, fn url, _ ->
|
||||
with %Event{} = event <- Events.get_event_by_url(url) do
|
||||
{:halt, event}
|
||||
else
|
||||
_ -> {:cont, nil}
|
||||
end
|
||||
end),
|
||||
|
||||
# Remove the reported user from the object list.
|
||||
comments <-
|
||||
Enum.filter(objects, fn url ->
|
||||
!(url == reported.url || (!is_nil(event) && event.url == url))
|
||||
end),
|
||||
comments <- Enum.map(comments, &Events.get_comment_from_url/1) do
|
||||
%{
|
||||
"reporter" => reporter,
|
||||
"uri" => object["id"],
|
||||
"content" => object["content"],
|
||||
"reported" => reported,
|
||||
"event" => event,
|
||||
"comments" => comments
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Convert an event struct to an ActivityStream representation
|
||||
"""
|
||||
@impl Converter
|
||||
@spec model_to_as(EventModel.t()) :: map()
|
||||
def model_to_as(%Report{} = report) do
|
||||
%{
|
||||
"type" => "Flag",
|
||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"actor" => report.reporter.url,
|
||||
"id" => report.url
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -116,6 +116,22 @@ defmodule Mobilizon.Service.ActivityPub.Transmogrifier do
|
||||
|> Map.put("tag", combined)
|
||||
end
|
||||
|
||||
def handle_incoming(%{"type" => "Flag"} = data) do
|
||||
with params <- Mobilizon.Service.ActivityPub.Converters.Flag.as_to_model(data) do
|
||||
params = %{
|
||||
reporter_url: params["reporter"].url,
|
||||
reported_actor_url: params["reported"].url,
|
||||
comments_url: params["comments"] |> Enum.map(& &1.url),
|
||||
content: params["content"] || "",
|
||||
additional: %{
|
||||
"cc" => [params["reported"].url]
|
||||
}
|
||||
}
|
||||
|
||||
ActivityPub.flag(params)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: validate those with a Ecto scheme
|
||||
# - tags
|
||||
# - emoji
|
||||
|
||||
@@ -18,6 +18,10 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
|
||||
alias Mobilizon.Media.Picture
|
||||
alias Mobilizon.Events
|
||||
alias Mobilizon.Activity
|
||||
alias Mobilizon.Reports
|
||||
alias Mobilizon.Reports.Report
|
||||
alias Mobilizon.Users
|
||||
alias Mobilizon.Service.ActivityPub.Converters
|
||||
alias Ecto.Changeset
|
||||
require Logger
|
||||
alias MobilizonWeb.Router.Helpers, as: Routes
|
||||
@@ -119,9 +123,9 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
|
||||
def insert_full_object(%{"object" => %{"type" => "Event"} = object_data})
|
||||
when is_map(object_data) do
|
||||
with object_data <-
|
||||
Mobilizon.Service.ActivityPub.Converters.Event.as_to_model_data(object_data),
|
||||
{:ok, _} <- Events.create_event(object_data) do
|
||||
:ok
|
||||
Converters.Event.as_to_model_data(object_data),
|
||||
{:ok, %Event{} = event} <- Events.create_event(object_data) do
|
||||
{:ok, event}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -129,8 +133,8 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
|
||||
when is_map(object_data) do
|
||||
with object_data <-
|
||||
Map.put(object_data, "preferred_username", object_data["preferredUsername"]),
|
||||
{:ok, _} <- Actors.create_group(object_data) do
|
||||
:ok
|
||||
{:ok, %Actor{} = group} <- Actors.create_group(object_data) do
|
||||
{:ok, group}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -139,9 +143,9 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
|
||||
"""
|
||||
def insert_full_object(%{"object" => %{"type" => "Note"} = object_data})
|
||||
when is_map(object_data) do
|
||||
with data <- Mobilizon.Service.ActivityPub.Converters.Comment.as_to_model_data(object_data),
|
||||
{:ok, _comment} <- Events.create_comment(data) do
|
||||
:ok
|
||||
with data <- Converters.Comment.as_to_model_data(object_data),
|
||||
{:ok, %Comment{} = comment} <- Events.create_comment(data) do
|
||||
{:ok, comment}
|
||||
else
|
||||
err ->
|
||||
Logger.error("Error while inserting a remote comment inside database")
|
||||
@@ -150,7 +154,29 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
|
||||
end
|
||||
end
|
||||
|
||||
def insert_full_object(_), do: :ok
|
||||
@doc """
|
||||
Inserts a full object if it is contained in an activity.
|
||||
"""
|
||||
def insert_full_object(%{"type" => "Flag"} = object_data)
|
||||
when is_map(object_data) do
|
||||
with data <- Converters.Flag.as_to_model_data(object_data),
|
||||
{:ok, %Report{} = report} <- Reports.create_report(data) do
|
||||
Enum.each(Users.list_moderators(), fn moderator ->
|
||||
moderator
|
||||
|> Mobilizon.Email.Admin.report(moderator, report)
|
||||
|> Mobilizon.Mailer.deliver_later()
|
||||
end)
|
||||
|
||||
{:ok, report}
|
||||
else
|
||||
err ->
|
||||
Logger.error("Error while inserting a remote comment inside database")
|
||||
Logger.error(inspect(err))
|
||||
{:error, err}
|
||||
end
|
||||
end
|
||||
|
||||
def insert_full_object(_), do: {:ok, nil}
|
||||
|
||||
#### Like-related helpers
|
||||
|
||||
@@ -497,6 +523,24 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
|
||||
|> Map.merge(additional)
|
||||
end
|
||||
|
||||
#### Flag-related helpers
|
||||
@spec make_flag_data(map(), map()) :: map()
|
||||
def make_flag_data(params, additional) do
|
||||
object = [params.reported_actor_url] ++ params.comments_url
|
||||
|
||||
object = if params[:event_url], do: object ++ [params.event_url], else: object
|
||||
|
||||
%{
|
||||
"type" => "Flag",
|
||||
"id" => "#{MobilizonWeb.Endpoint.url()}/report/#{Ecto.UUID.generate()}",
|
||||
"actor" => params.reporter_url,
|
||||
"content" => params.content,
|
||||
"object" => object,
|
||||
"state" => "open"
|
||||
}
|
||||
|> Map.merge(additional)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Converts PEM encoded keys to a public key representation
|
||||
"""
|
||||
|
||||
30
lib/service/admin/action_log_service.ex
Normal file
30
lib/service/admin/action_log_service.ex
Normal file
@@ -0,0 +1,30 @@
|
||||
defmodule Mobilizon.Service.Admin.ActionLogService do
|
||||
@moduledoc """
|
||||
Module to handle action log creations
|
||||
"""
|
||||
|
||||
alias Mobilizon.Users
|
||||
alias Mobilizon.Users.User
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Admin
|
||||
alias Mobilizon.Admin.ActionLog
|
||||
|
||||
@doc """
|
||||
Log an admin action
|
||||
"""
|
||||
@spec log_action(Actor.t(), String.t(), String.t()) :: {:ok, ActionLog.t()}
|
||||
def log_action(%Actor{user_id: user_id, id: actor_id}, action, target) do
|
||||
with %User{role: role} <- Users.get_user!(user_id),
|
||||
{:role, true} <- {:role, role in [:administrator, :moderator]},
|
||||
{:ok, %ActionLog{} = create_action_log} <-
|
||||
Admin.create_action_log(%{
|
||||
"actor_id" => actor_id,
|
||||
"target_type" => to_string(target.__struct__),
|
||||
"target_id" => target.id,
|
||||
"action" => action,
|
||||
"changes" => Map.from_struct(target) |> Map.take([:status, :uri, :content])
|
||||
}) do
|
||||
{:ok, create_action_log}
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user