philomena/lib/philomena/reports.ex

301 lines
6.5 KiB
Elixir
Raw Normal View History

2019-08-28 19:31:59 +02:00
defmodule Philomena.Reports do
@moduledoc """
The Reports context.
"""
import Ecto.Query, warn: false
alias Philomena.Repo
alias PhilomenaQuery.Search
2019-08-28 19:31:59 +02:00
alias Philomena.Reports.Report
alias Philomena.Reports.SearchIndex, as: ReportIndex
2020-12-06 17:42:14 +01:00
alias Philomena.IndexWorker
2019-12-04 05:14:56 +01:00
alias Philomena.Polymorphic
2019-08-28 19:31:59 +02:00
2024-07-21 04:30:58 +02:00
@doc """
Returns the current number of open reports.
If the user is allowed to view reports, returns the current count.
If the user is not allowed to view reports, returns `nil`.
## Examples
iex> count_reports(%User{})
nil
iex> count_reports(%User{role: "admin"})
4
"""
def count_open_reports(user) do
if Canada.Can.can?(user, :index, Report) do
Report
|> where(open: true)
|> Repo.aggregate(:count)
else
nil
end
end
2019-08-28 19:31:59 +02:00
@doc """
Returns the list of reports.
## Examples
iex> list_reports()
[%Report{}, ...]
"""
def list_reports do
Repo.all(Report)
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: Repo.get!(Report, id)
@doc """
Creates a report.
## Examples
iex> create_report(%{field: value})
{:ok, %Report{}}
iex> create_report(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
2024-07-21 04:40:57 +02:00
def create_report({reportable_type, reportable_id} = _type_and_id, attribution, attrs \\ %{}) do
%Report{reportable_type: reportable_type, reportable_id: reportable_id}
2019-12-04 05:14:56 +01:00
|> Report.creation_changeset(attrs, attribution)
2019-08-28 19:31:59 +02:00
|> Repo.insert()
|> reindex_after_update()
2019-08-28 19:31:59 +02:00
end
2024-07-21 03:23:55 +02:00
@doc """
Returns an `m:Ecto.Query` which updates all reports for the given `reportable_type`
and `reportable_id` to close them.
Because this is only a query due to the limitations of `m:Ecto.Multi`, this must be
coupled with an associated call to `reindex_reports/1` to operate correctly, e.g.:
2024-07-21 04:40:57 +02:00
report_query = Reports.close_system_report_query({"Image", image.id}, user)
2024-07-21 03:23:55 +02:00
Multi.new()
|> Multi.update_all(:reports, report_query, [])
|> Repo.transaction()
|> case do
{:ok, %{reports: {_count, reports}} = result} ->
Reports.reindex_reports(reports)
{:ok, result}
error ->
error
end
## Examples
iex> close_system_report_query("Image", 1, %User{})
#Ecto.Query<...>
"""
2024-07-21 04:40:57 +02:00
def close_report_query({reportable_type, reportable_id} = _type_and_id, closing_user) do
2024-07-21 03:23:55 +02:00
from r in Report,
where: r.reportable_type == ^reportable_type and r.reportable_id == ^reportable_id,
select: r.id,
update: [set: [open: false, state: "closed", admin_id: ^closing_user.id]]
end
@doc """
Automatically create a report with the given category and reason on the given
`reportable_id` and `reportable_type`.
## Examples
2024-07-21 04:40:57 +02:00
iex> create_system_report({"Comment", 1}, "Other", "Custom report reason")
{:ok, %Report{}}
"""
2024-07-21 04:40:57 +02:00
def create_system_report({reportable_type, reportable_id} = _type_and_id, category, reason) do
2022-03-22 22:23:30 +01:00
attrs = %{
reason: reason,
2024-12-05 18:53:24 +01:00
category: category,
user_agent: "system"
2022-03-22 22:23:30 +01:00
}
2024-12-05 18:53:24 +01:00
attribution = %{
2022-03-22 22:23:30 +01:00
system: true,
ip: %Postgrex.INET{address: {127, 0, 0, 1}, netmask: 32},
fingerprint: "ffff"
2022-03-22 22:23:30 +01:00
}
%Report{reportable_type: reportable_type, reportable_id: reportable_id}
2024-12-05 18:53:24 +01:00
|> Report.creation_changeset(attrs, attribution)
2022-03-22 22:23:30 +01:00
|> Repo.insert()
|> reindex_after_update()
end
2019-08-28 19:31:59 +02:00
@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()
|> reindex_after_update()
2019-08-28 19:31:59 +02:00
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
2019-12-04 05:14:56 +01:00
2024-07-21 04:30:58 +02:00
@doc """
Marks the report as claimed by the given user.
## Example
iex> claim_report(%Report{}, %User{})
{:ok, %Report{}}
"""
2019-12-09 04:16:13 +01:00
def claim_report(%Report{} = report, user) do
report
|> Report.claim_changeset(user)
|> Repo.update()
|> reindex_after_update()
2019-12-09 04:16:13 +01:00
end
2024-07-21 04:30:58 +02:00
@doc """
Marks the report as unclaimed.
## Example
iex> unclaim_report(%Report{})
{:ok, %Report{}}
"""
2019-12-09 04:16:13 +01:00
def unclaim_report(%Report{} = report) do
report
|> Report.unclaim_changeset()
|> Repo.update()
|> reindex_after_update()
2019-12-09 04:16:13 +01:00
end
2024-07-21 04:30:58 +02:00
@doc """
Marks the report as closed by the given user.
## Example
iex> close_report(%Report{}, %User{})
{:ok, %Report{}}
"""
2019-12-09 04:16:13 +01:00
def close_report(%Report{} = report, user) do
report
|> Report.close_changeset(user)
|> Repo.update()
|> reindex_after_update()
2019-12-09 04:16:13 +01:00
end
2024-07-21 04:30:58 +02:00
@doc """
Reindex all reports where the user or admin has `old_name`.
## Example
iex> user_name_reindex("Administrator", "Administrator2")
{:ok, %Req.Response{}}
"""
def user_name_reindex(old_name, new_name) do
data = ReportIndex.user_name_update_by_query(old_name, new_name)
Search.update_by_query(Report, data.query, data.set_replacements, data.replacements)
end
defp reindex_after_update({:ok, report}) do
reindex_report(report)
{:ok, report}
end
2020-05-20 20:23:57 +02:00
defp reindex_after_update(result) do
result
end
2024-07-21 04:30:58 +02:00
@doc """
Callback for post-transaction update.
See `close_report_query/2` for more information and example.
"""
def reindex_reports(report_ids) do
2020-12-06 17:42:14 +01:00
Exq.enqueue(Exq, "indexing", IndexWorker, ["Reports", "id", report_ids])
2019-12-04 05:14:56 +01:00
report_ids
end
2024-07-21 04:30:58 +02:00
@doc false
def reindex_report(%Report{} = report) do
2020-12-06 17:42:14 +01:00
Exq.enqueue(Exq, "indexing", IndexWorker, ["Reports", "id", [report.id]])
2019-12-04 05:14:56 +01:00
report
end
2019-12-05 00:15:54 +01:00
2024-07-21 04:30:58 +02:00
@doc false
2020-12-06 17:42:14 +01:00
def perform_reindex(column, condition) do
Report
|> where([r], field(r, ^column) in ^condition)
|> preload([:user, :admin])
|> Repo.all()
|> Polymorphic.load_polymorphic(reportable: [reportable_id: :reportable_type])
|> Enum.map(&Search.index_document(&1, Report))
2020-12-06 17:42:14 +01:00
end
2019-08-28 19:31:59 +02:00
end