Refactoring of Reports context
This commit is contained in:
parent
c2b4fb6cff
commit
d0c9974558
@ -1,236 +0,0 @@
|
||||
defmodule Mobilizon.Reports do
|
||||
@moduledoc """
|
||||
The Reports context.
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Mobilizon.Repo
|
||||
import Mobilizon.Ecto
|
||||
|
||||
alias Mobilizon.Reports.Report
|
||||
alias Mobilizon.Reports.Note
|
||||
|
||||
@doc false
|
||||
def data() do
|
||||
Dataloader.Ecto.new(Mobilizon.Repo, query: &query/2)
|
||||
end
|
||||
|
||||
@doc false
|
||||
def query(queryable, _params) do
|
||||
queryable
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the list of reports.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_reports()
|
||||
[%Report{}, ...]
|
||||
|
||||
"""
|
||||
@spec list_reports(integer(), integer(), atom(), atom()) :: list(Report.t())
|
||||
def list_reports(page \\ nil, limit \\ nil, sort \\ :updated_at, direction \\ :asc) do
|
||||
from(
|
||||
r in Report,
|
||||
preload: [:reported, :reporter, :manager, :event, :comments, :notes]
|
||||
)
|
||||
|> paginate(page, limit)
|
||||
|> sort(sort, direction)
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single report.
|
||||
|
||||
Raises `Ecto.NoResultsError` if the Report does not exist.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_report!(123)
|
||||
%Report{}
|
||||
|
||||
iex> get_report!(456)
|
||||
** (Ecto.NoResultsError)
|
||||
|
||||
"""
|
||||
def get_report!(id) do
|
||||
with %Report{} = report <- Repo.get!(Report, id) do
|
||||
Repo.preload(report, [:reported, :reporter, :manager, :event, :comments, :notes])
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single report.
|
||||
|
||||
Returns `nil` if the Report does not exist.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_report(123)
|
||||
%Report{}
|
||||
|
||||
iex> get_report(456)
|
||||
nil
|
||||
|
||||
"""
|
||||
def get_report(id) do
|
||||
with %Report{} = report <- Repo.get(Report, id) do
|
||||
Repo.preload(report, [:reported, :reporter, :manager, :event, :comments, :notes])
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get a report by it's URL
|
||||
"""
|
||||
@spec get_report_by_url(String.t()) :: Report.t() | nil
|
||||
def get_report_by_url(url) do
|
||||
from(
|
||||
r in Report,
|
||||
where: r.uri == ^url
|
||||
)
|
||||
|> Repo.one()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Creates a report.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> create_report(%{field: value})
|
||||
{:ok, %Report{}}
|
||||
|
||||
iex> create_report(%{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_report(attrs \\ %{}) do
|
||||
with {:ok, %Report{} = report} <-
|
||||
%Report{}
|
||||
|> Report.creation_changeset(attrs)
|
||||
|> Repo.insert() do
|
||||
{:ok, Repo.preload(report, [:event, :reported, :reporter, :comments])}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates a report.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> update_report(report, %{field: new_value})
|
||||
{:ok, %Report{}}
|
||||
|
||||
iex> update_report(report, %{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def update_report(%Report{} = report, attrs) do
|
||||
report
|
||||
|> Report.changeset(attrs)
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a Report.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> delete_report(report)
|
||||
{:ok, %Report{}}
|
||||
|
||||
iex> delete_report(report)
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def delete_report(%Report{} = report) do
|
||||
Repo.delete(report)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns an `%Ecto.Changeset{}` for tracking report changes.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> change_report(report)
|
||||
%Ecto.Changeset{source: %Report{}}
|
||||
|
||||
"""
|
||||
def change_report(%Report{} = report) do
|
||||
Report.changeset(report, %{})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the list of notes for a report.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_notes_for_report(%Report{id: 1})
|
||||
[%Note{}, ...]
|
||||
|
||||
"""
|
||||
@spec list_notes_for_report(Report.t()) :: list(Report.t())
|
||||
def list_notes_for_report(%Report{id: report_id}) do
|
||||
from(
|
||||
n in Note,
|
||||
where: n.report_id == ^report_id,
|
||||
preload: [:report, :moderator]
|
||||
)
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single note.
|
||||
|
||||
Raises `Ecto.NoResultsError` if the Note does not exist.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> get_note!(123)
|
||||
%Note{}
|
||||
|
||||
iex> get_note!(456)
|
||||
** (Ecto.NoResultsError)
|
||||
|
||||
"""
|
||||
def get_note!(id), do: Repo.get!(Note, id)
|
||||
|
||||
def get_note(id), do: Repo.get(Note, id)
|
||||
|
||||
@doc """
|
||||
Creates a note report.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> create_report_note(%{field: value})
|
||||
{:ok, %Note{}}
|
||||
|
||||
iex> create_report_note(%{field: bad_value})
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def create_report_note(attrs \\ %{}) do
|
||||
with {:ok, %Note{} = note} <-
|
||||
%Note{}
|
||||
|> Note.changeset(attrs)
|
||||
|> Repo.insert() do
|
||||
{:ok, Repo.preload(note, [:report, :moderator])}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a note report.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> delete_report_note(note)
|
||||
{:ok, %Note{}}
|
||||
|
||||
iex> delete_report_note(note)
|
||||
{:error, %Ecto.Changeset{}}
|
||||
|
||||
"""
|
||||
def delete_report_note(%Note{} = note) do
|
||||
Repo.delete(note)
|
||||
end
|
||||
end
|
@ -1,27 +1,39 @@
|
||||
defmodule Mobilizon.Reports.Note do
|
||||
@moduledoc """
|
||||
Report Note entity
|
||||
Represents a note entity.
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
|
||||
import Ecto.Changeset, only: [cast: 3, validate_required: 2]
|
||||
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Reports.Report
|
||||
|
||||
@attrs [:content, :moderator_id, :report_id]
|
||||
@required_attrs [:content, :moderator_id, :report_id]
|
||||
@attrs @required_attrs
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
content: String.t(),
|
||||
report: Report.t(),
|
||||
moderator: Actor.t()
|
||||
}
|
||||
|
||||
@derive {Jason.Encoder, only: [:content]}
|
||||
schema "report_notes" do
|
||||
field(:content, :string)
|
||||
belongs_to(:moderator, Actor)
|
||||
|
||||
belongs_to(:report, Report)
|
||||
belongs_to(:moderator, Actor)
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@doc false
|
||||
@spec changeset(t | Ecto.Changeset.t(), map) :: Ecto.Changeset.t()
|
||||
def changeset(note, attrs) do
|
||||
note
|
||||
|> cast(attrs, @attrs)
|
||||
|> validate_required(@attrs)
|
||||
|> validate_required(@required_attrs)
|
||||
end
|
||||
end
|
||||
|
@ -1,43 +1,48 @@
|
||||
import EctoEnum
|
||||
|
||||
defenum(Mobilizon.Reports.ReportStateEnum, :report_state, [
|
||||
:open,
|
||||
:closed,
|
||||
:resolved
|
||||
])
|
||||
|
||||
defmodule Mobilizon.Reports.Report do
|
||||
@moduledoc """
|
||||
Report entity
|
||||
Represents a report entity.
|
||||
"""
|
||||
|
||||
use Ecto.Schema
|
||||
|
||||
import Ecto.Changeset
|
||||
alias Mobilizon.Events.Comment
|
||||
alias Mobilizon.Events.Event
|
||||
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Reports.Note
|
||||
alias Mobilizon.Events.{Comment, Event}
|
||||
alias Mobilizon.Reports.{Note, ReportStatus}
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
content: String.t(),
|
||||
status: ReportStatus.t(),
|
||||
uri: String.t(),
|
||||
reported: Actor.t(),
|
||||
reporter: Actor.t(),
|
||||
manager: Actor.t(),
|
||||
event: Event.t(),
|
||||
comments: [Comment.t()],
|
||||
notes: [Note.t()]
|
||||
}
|
||||
|
||||
@required_attrs [:content, :uri, :reported_id, :reporter_id]
|
||||
@optional_attrs [:status, :manager_id, :event_id]
|
||||
@attrs @required_attrs ++ @optional_attrs
|
||||
|
||||
@derive {Jason.Encoder, only: [:status, :uri]}
|
||||
schema "reports" do
|
||||
field(:content, :string)
|
||||
field(:status, Mobilizon.Reports.ReportStateEnum, default: :open)
|
||||
field(:status, ReportStatus, default: :open)
|
||||
field(:uri, :string)
|
||||
|
||||
# The reported actor
|
||||
belongs_to(:reported, Actor)
|
||||
|
||||
# The actor who reported
|
||||
belongs_to(:reporter, Actor)
|
||||
|
||||
# The actor who last acted on this report
|
||||
belongs_to(:manager, Actor)
|
||||
|
||||
# The eventual Event inside the report
|
||||
belongs_to(:event, Event)
|
||||
|
||||
# The eventual Comments inside the report
|
||||
many_to_many(:comments, Comment, join_through: "reports_comments", on_replace: :delete)
|
||||
|
||||
# The notes associated to the report
|
||||
has_many(:notes, Note, foreign_key: :report_id)
|
||||
|
||||
@ -45,12 +50,15 @@ defmodule Mobilizon.Reports.Report do
|
||||
end
|
||||
|
||||
@doc false
|
||||
@spec changeset(t | Ecto.Changeset.t(), map) :: Ecto.Changeset.t()
|
||||
def changeset(report, attrs) do
|
||||
report
|
||||
|> cast(attrs, [:content, :status, :uri, :reported_id, :reporter_id, :manager_id, :event_id])
|
||||
|> validate_required([:content, :uri, :reported_id, :reporter_id])
|
||||
|> cast(attrs, @attrs)
|
||||
|> validate_required(@required_attrs)
|
||||
end
|
||||
|
||||
@doc false
|
||||
@spec creation_changeset(Report.t(), map) :: Ecto.Changeset.t()
|
||||
def creation_changeset(report, attrs) do
|
||||
report
|
||||
|> changeset(attrs)
|
||||
|
162
lib/mobilizon/reports/reports.ex
Normal file
162
lib/mobilizon/reports/reports.ex
Normal file
@ -0,0 +1,162 @@
|
||||
defmodule Mobilizon.Reports do
|
||||
@moduledoc """
|
||||
The Reports context.
|
||||
"""
|
||||
|
||||
import Ecto.Query
|
||||
import EctoEnum
|
||||
|
||||
import Mobilizon.Ecto
|
||||
|
||||
alias Mobilizon.{Page, Repo}
|
||||
alias Mobilizon.Reports.{Note, Report}
|
||||
|
||||
defenum(ReportStatus, :report_status, [:open, :closed, :resolved])
|
||||
|
||||
@doc false
|
||||
@spec data :: Dataloader.Ecto.t()
|
||||
def data, do: Dataloader.Ecto.new(Mobilizon.Repo, query: &query/2)
|
||||
|
||||
@doc false
|
||||
@spec query(Ecto.Query.t(), map) :: Ecto.Query.t()
|
||||
def query(queryable, _params), do: queryable
|
||||
|
||||
@doc """
|
||||
Returns the list of reports.
|
||||
"""
|
||||
@spec list_reports(integer | nil, integer | nil, atom, atom) :: [Report.t()]
|
||||
def list_reports(page \\ nil, limit \\ nil, sort \\ :updated_at, direction \\ :asc) do
|
||||
list_reports_query()
|
||||
|> Page.paginate(page, limit)
|
||||
|> sort(sort, direction)
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single report.
|
||||
"""
|
||||
@spec get_report(integer | String.t()) :: Report.t() | nil
|
||||
def get_report(id) do
|
||||
Report
|
||||
|> Repo.get(id)
|
||||
|> Repo.preload([:reported, :reporter, :manager, :event, :comments, :notes])
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single report.
|
||||
Raises `Ecto.NoResultsError` if the report does not exist.
|
||||
"""
|
||||
@spec get_report!(integer | String.t()) :: Report.t()
|
||||
def get_report!(id) do
|
||||
Report
|
||||
|> Repo.get!(id)
|
||||
|> Repo.preload([:reported, :reporter, :manager, :event, :comments, :notes])
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get a report by its URL
|
||||
"""
|
||||
@spec get_report_by_url(String.t()) :: Report.t() | nil
|
||||
def get_report_by_url(url) do
|
||||
url
|
||||
|> report_by_url_query()
|
||||
|> Repo.one()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Creates a report.
|
||||
"""
|
||||
@spec create_report(map) :: {:ok, Report.t()} | {:error, Ecto.Changeset.t()}
|
||||
def create_report(attrs \\ %{}) do
|
||||
with {:ok, %Report{} = report} <-
|
||||
%Report{}
|
||||
|> Report.changeset(attrs)
|
||||
|> Repo.insert() do
|
||||
{:ok, Repo.preload(report, [:event, :reported, :reporter, :comments])}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates a report.
|
||||
"""
|
||||
@spec update_report(Report.t(), map) :: {:ok, Report.t()} | {:error, Ecto.Changeset.t()}
|
||||
def update_report(%Report{} = report, attrs) do
|
||||
report
|
||||
|> Report.changeset(attrs)
|
||||
|> Repo.update()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a report.
|
||||
"""
|
||||
@spec delete_report(Report.t()) :: {:ok, Report.t()} | {:error, Ecto.Changeset.t()}
|
||||
def delete_report(%Report{} = report) do
|
||||
Repo.delete(report)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the list of notes for a report.
|
||||
"""
|
||||
@spec list_notes_for_report(Report.t()) :: [Note.t()]
|
||||
def list_notes_for_report(%Report{id: report_id}) do
|
||||
report_id
|
||||
|> list_notes_for_report_query()
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets a single note.
|
||||
"""
|
||||
@spec get_note(integer | String.t()) :: Note.t() | nil
|
||||
def get_note(id), do: Repo.get(Note, id)
|
||||
|
||||
@doc """
|
||||
Gets a single note.
|
||||
Raises `Ecto.NoResultsError` if the Note does not exist.
|
||||
"""
|
||||
@spec get_note!(integer | String.t()) :: Note.t()
|
||||
def get_note!(id), do: Repo.get!(Note, id)
|
||||
|
||||
@doc """
|
||||
Creates a note.
|
||||
"""
|
||||
@spec create_note(map) :: {:ok, Note.t()} | {:error, Ecto.Changeset.t()}
|
||||
def create_note(attrs \\ %{}) do
|
||||
with {:ok, %Note{} = note} <-
|
||||
%Note{}
|
||||
|> Note.changeset(attrs)
|
||||
|> Repo.insert() do
|
||||
{:ok, Repo.preload(note, [:report, :moderator])}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes a note.
|
||||
"""
|
||||
@spec delete_note(Note.t()) :: {:ok, Note.t()} | {:error, Ecto.Changeset.t()}
|
||||
def delete_note(%Note{} = note) do
|
||||
Repo.delete(note)
|
||||
end
|
||||
|
||||
@spec list_reports_query :: Ecto.Query.t()
|
||||
defp list_reports_query do
|
||||
from(
|
||||
r in Report,
|
||||
preload: [:reported, :reporter, :manager, :event, :comments, :notes]
|
||||
)
|
||||
end
|
||||
|
||||
@spec report_by_url_query(String.t()) :: Ecto.Query.t()
|
||||
defp report_by_url_query(url) do
|
||||
from(r in Report, where: r.uri == ^url)
|
||||
end
|
||||
|
||||
@spec list_notes_for_report_query(integer | String.t()) :: Ecto.Query.t()
|
||||
defp list_notes_for_report_query(report_id) do
|
||||
from(
|
||||
n in Note,
|
||||
where: n.report_id == ^report_id,
|
||||
preload: [:report, :moderator]
|
||||
)
|
||||
end
|
||||
end
|
@ -61,7 +61,7 @@ defmodule MobilizonWeb.API.Reports do
|
||||
"""
|
||||
def update_report_status(%Actor{} = actor, %Report{} = report, state) do
|
||||
with {:valid_state, true} <-
|
||||
{:valid_state, Mobilizon.Reports.ReportStateEnum.valid_value?(state)},
|
||||
{:valid_state, Mobilizon.Reports.ReportStatus.valid_value?(state)},
|
||||
{:ok, report} <- ReportsAction.update_report(report, %{"status" => state}),
|
||||
{:ok, _} <- log_action(actor, "update", report) do
|
||||
{:ok, report}
|
||||
@ -89,7 +89,7 @@ defmodule MobilizonWeb.API.Reports do
|
||||
with %User{role: role} <- Users.get_user!(user_id),
|
||||
{:role, true} <- {:role, role in [:administrator, :moderator]},
|
||||
{:ok, %Note{} = note} <-
|
||||
Mobilizon.Reports.create_report_note(%{
|
||||
Mobilizon.Reports.create_note(%{
|
||||
"report_id" => report_id,
|
||||
"moderator_id" => moderator_id,
|
||||
"content" => content
|
||||
@ -114,7 +114,7 @@ defmodule MobilizonWeb.API.Reports do
|
||||
%User{role: role} <- Users.get_user!(user_id),
|
||||
{:role, true} <- {:role, role in [:administrator, :moderator]},
|
||||
{:ok, %Note{} = note} <-
|
||||
Mobilizon.Reports.delete_report_note(note),
|
||||
Mobilizon.Reports.delete_note(note),
|
||||
{:ok, _} <- log_action(moderator, "delete", note) do
|
||||
{:ok, note}
|
||||
else
|
||||
|
@ -1,13 +1,13 @@
|
||||
defmodule Mobilizon.Repo.Migrations.CreateReports do
|
||||
use Ecto.Migration
|
||||
alias Mobilizon.Reports.ReportStateEnum
|
||||
alias Mobilizon.Reports.ReportStatus
|
||||
|
||||
def up do
|
||||
ReportStateEnum.create_type()
|
||||
ReportStatus.create_type()
|
||||
|
||||
create table(:reports) do
|
||||
add(:content, :string)
|
||||
add(:status, ReportStateEnum.type(), default: "open", null: false)
|
||||
add(:status, ReportStatus.type(), default: "open", null: false)
|
||||
add(:uri, :string, null: false)
|
||||
|
||||
add(:reported_id, references(:actors, on_delete: :delete_all), null: false)
|
||||
@ -28,6 +28,6 @@ defmodule Mobilizon.Repo.Migrations.CreateReports do
|
||||
drop(table(:reports_comments))
|
||||
drop(table(:reports))
|
||||
|
||||
ReportStateEnum.drop_type()
|
||||
ReportStatus.drop_type()
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user