fix(reports): remove on delete cascade for reports

Deleting an actor should not remove the reports

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2023-08-31 18:29:28 +02:00
parent 69588dbf4c
commit 4f530cabcf
No known key found for this signature in database
GPG key ID: A061B9DDE0CA0773
3 changed files with 125 additions and 47 deletions

View file

@ -0,0 +1,70 @@
defmodule Mobilizon.Storage.Views.Instances do
@moduledoc """
SQL code for PostgreSQL instances materialized view
"""
def create_materialized_view do
"""
CREATE MATERIALIZED VIEW instances AS
SELECT
a.domain,
COUNT(DISTINCT(p.id)) AS person_count,
COUNT(DISTINCT(g.id)) AS group_count,
COUNT(DISTINCT(e.id)) AS event_count,
COUNT(f1.id) AS followers_count,
COUNT(f2.id) AS followings_count,
COUNT(r.id) AS reports_count,
SUM(COALESCE((m.file->>'size')::int, 0)) AS media_size
FROM actors a
LEFT JOIN actors p ON a.id = p.id AND p.type = 'Person'
LEFT JOIN actors g ON a.id = g.id AND g.type = 'Group'
LEFT JOIN events e ON a.id = e.organizer_actor_id
LEFT JOIN followers f1 ON a.id = f1.actor_id
LEFT JOIN followers f2 ON a.id = f2.target_actor_id
LEFT JOIN reports r ON r.reported_id = a.id
LEFT JOIN medias m ON m.actor_id = a.id
WHERE a.domain IS NOT NULL
GROUP BY a.domain;
"""
end
def refresh_instances do
"""
CREATE OR REPLACE FUNCTION refresh_instances()
RETURNS trigger AS $$
BEGIN
REFRESH MATERIALIZED VIEW instances;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
"""
end
def drop_trigger do
"""
DROP TRIGGER IF EXISTS refresh_instances_trigger ON actors;
"""
end
def create_trigger do
"""
CREATE TRIGGER refresh_instances_trigger
AFTER INSERT OR UPDATE OR DELETE
ON actors
FOR EACH STATEMENT
EXECUTE PROCEDURE refresh_instances();
"""
end
def drop_refresh_instances do
"""
DROP FUNCTION IF EXISTS refresh_instances() CASCADE;
"""
end
def drop_view do
"""
DROP MATERIALIZED VIEW IF EXISTS instances;
"""
end
end

View file

@ -1,51 +1,15 @@
defmodule Mobilizon.Storage.Repo.Migrations.AddInstanceMaterializedView do
use Ecto.Migration
alias Mobilizon.Storage.Views.Instances
def up do
execute("""
CREATE MATERIALIZED VIEW instances AS
SELECT
a.domain,
COUNT(DISTINCT(p.id)) AS person_count,
COUNT(DISTINCT(g.id)) AS group_count,
COUNT(DISTINCT(e.id)) AS event_count,
COUNT(f1.id) AS followers_count,
COUNT(f2.id) AS followings_count,
COUNT(r.id) AS reports_count,
SUM(COALESCE((m.file->>'size')::int, 0)) AS media_size
FROM actors a
LEFT JOIN actors p ON a.id = p.id AND p.type = 'Person'
LEFT JOIN actors g ON a.id = g.id AND g.type = 'Group'
LEFT JOIN events e ON a.id = e.organizer_actor_id
LEFT JOIN followers f1 ON a.id = f1.actor_id
LEFT JOIN followers f2 ON a.id = f2.target_actor_id
LEFT JOIN reports r ON r.reported_id = a.id
LEFT JOIN medias m ON m.actor_id = a.id
WHERE a.domain IS NOT NULL
GROUP BY a.domain;
""")
execute(Instances.create_materialized_view())
execute("""
CREATE OR REPLACE FUNCTION refresh_instances()
RETURNS trigger AS $$
BEGIN
REFRESH MATERIALIZED VIEW instances;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
""")
execute(Instances.refresh_instances())
execute("""
DROP TRIGGER IF EXISTS refresh_instances_trigger ON actors;
""")
execute(Instances.drop_trigger())
execute("""
CREATE TRIGGER refresh_instances_trigger
AFTER INSERT OR UPDATE OR DELETE
ON actors
FOR EACH STATEMENT
EXECUTE PROCEDURE refresh_instances();
""")
execute(Instances.create_trigger())
create_if_not_exists(unique_index("instances", [:domain]))
end
@ -53,12 +17,8 @@ defmodule Mobilizon.Storage.Repo.Migrations.AddInstanceMaterializedView do
def down do
drop_if_exists(unique_index("instances", [:domain]))
execute("""
DROP FUNCTION IF EXISTS refresh_instances() CASCADE;
""")
execute(Instances.drop_refresh_instances())
execute("""
DROP MATERIALIZED VIEW IF EXISTS instances;
""")
execute(Instances.drop_view())
end
end

View file

@ -0,0 +1,48 @@
defmodule Mobilizon.Storage.Repo.Migrations.RemoveOnDeleteCascadeForReports do
use Ecto.Migration
alias Mobilizon.Storage.Views.Instances
def up do
execute(Instances.drop_view())
drop(constraint(:reports, "reports_reported_id_fkey"))
drop(constraint(:reports, "reports_reporter_id_fkey"))
drop(constraint(:reports, "reports_manager_id_fkey"))
alter table(:reports) do
modify(:reported_id, references(:actors, on_delete: :nilify_all), null: true)
modify(:reporter_id, references(:actors, on_delete: :nilify_all), null: true)
modify(:manager_id, references(:actors, on_delete: :nilify_all), null: true)
end
drop(constraint(:report_notes, "report_notes_moderator_id_fkey"))
alter table(:report_notes) do
modify(:moderator_id, references(:actors, on_delete: :nilify_all), null: true)
end
execute(Instances.create_materialized_view())
end
def down do
execute(Instances.drop_view())
drop(constraint(:reports, "reports_reported_id_fkey"))
drop(constraint(:reports, "reports_reporter_id_fkey"))
drop(constraint(:reports, "reports_manager_id_fkey"))
alter table(:reports) do
modify(:reported_id, references(:actors, on_delete: :delete_all), null: false)
modify(:reporter_id, references(:actors, on_delete: :delete_all), null: false)
modify(:manager_id, references(:actors, on_delete: :delete_all), null: true)
end
drop(constraint(:report_notes, "report_notes_moderator_id_fkey"))
alter table(:report_notes) do
modify(:moderator_id, references(:actors, on_delete: :delete_all), null: false)
end
execute(Instances.create_materialized_view())
end
end