Merge branch 'develop' into refactor/notification_settings

This commit is contained in:
Mark Felder 2020-06-25 14:16:28 -05:00
commit 433c01b370
304 changed files with 14459 additions and 5927 deletions

View file

@ -0,0 +1,16 @@
defmodule Pleroma.Repo.Migrations.CreateChats do
use Ecto.Migration
def change do
create table(:chats) do
add(:user_id, references(:users, type: :uuid))
# Recipient is an ActivityPub id, to future-proof for group support.
add(:recipient, :string)
add(:unread, :integer, default: 0)
timestamps()
end
# There's only one chat between a user and a recipient.
create(index(:chats, [:user_id, :recipient], unique: true))
end
end

View file

@ -0,0 +1,9 @@
defmodule Pleroma.Repo.Migrations.UserRawBio do
use Ecto.Migration
def change do
alter table(:users) do
add_if_not_exists(:raw_bio, :text)
end
end
end

View file

@ -0,0 +1,39 @@
defmodule Pleroma.Repo.Migrations.MrfConfigMoveFromInstanceNamespace do
use Ecto.Migration
alias Pleroma.ConfigDB
@old_keys [:rewrite_policy, :mrf_transparency, :mrf_transparency_exclusions]
def change do
config = ConfigDB.get_by_params(%{group: :pleroma, key: :instance})
if config do
mrf =
config.value
|> Keyword.take(@old_keys)
|> Keyword.new(fn
{:rewrite_policy, policies} -> {:policies, policies}
{:mrf_transparency, transparency} -> {:transparency, transparency}
{:mrf_transparency_exclusions, exclusions} -> {:transparency_exclusions, exclusions}
end)
if mrf != [] do
{:ok, _} =
%ConfigDB{}
|> ConfigDB.changeset(%{group: :pleroma, key: :mrf, value: mrf})
|> Pleroma.Repo.insert()
new_instance = Keyword.drop(config.value, @old_keys)
if new_instance != [] do
{:ok, _} =
config
|> ConfigDB.changeset(%{value: new_instance})
|> Pleroma.Repo.update()
else
{:ok, _} = ConfigDB.delete(config)
end
end
end
end
end

View file

@ -0,0 +1,25 @@
defmodule Pleroma.Repo.Migrations.PopulateUserRawBio do
use Ecto.Migration
import Ecto.Query
alias Pleroma.User
alias Pleroma.Repo
def change do
{:ok, _} = Application.ensure_all_started(:fast_sanitize)
User.Query.build(%{local: true})
|> select([u], struct(u, [:id, :ap_id, :bio]))
|> Repo.stream()
|> Enum.each(fn %{bio: bio} = user ->
if bio do
raw_bio =
bio
|> String.replace(~r(<br */?>), "\n")
|> Pleroma.HTML.strip_tags()
Ecto.Changeset.cast(user, %{raw_bio: raw_bio}, [:raw_bio])
|> Repo.update()
end
end)
end
end

View file

@ -0,0 +1,143 @@
defmodule Pleroma.Repo.Migrations.UpdateCounterCacheTable do
use Ecto.Migration
@function_name "update_status_visibility_counter_cache"
@trigger_name "status_visibility_counter_cache_trigger"
def up do
execute("drop trigger if exists #{@trigger_name} on activities")
execute("drop function if exists #{@function_name}()")
drop_if_exists(unique_index(:counter_cache, [:name]))
drop_if_exists(table(:counter_cache))
create_if_not_exists table(:counter_cache) do
add(:instance, :string, null: false)
add(:direct, :bigint, null: false, default: 0)
add(:private, :bigint, null: false, default: 0)
add(:unlisted, :bigint, null: false, default: 0)
add(:public, :bigint, null: false, default: 0)
end
create_if_not_exists(unique_index(:counter_cache, [:instance]))
"""
CREATE OR REPLACE FUNCTION #{@function_name}()
RETURNS TRIGGER AS
$$
DECLARE
hostname character varying(255);
visibility_new character varying(64);
visibility_old character varying(64);
actor character varying(255);
BEGIN
IF TG_OP = 'DELETE' THEN
actor := OLD.actor;
ELSE
actor := NEW.actor;
END IF;
hostname := split_part(actor, '/', 3);
IF TG_OP = 'INSERT' THEN
visibility_new := activity_visibility(NEW.actor, NEW.recipients, NEW.data);
IF NEW.data->>'type' = 'Create'
AND visibility_new IN ('public', 'unlisted', 'private', 'direct') THEN
EXECUTE format('INSERT INTO "counter_cache" ("instance", %1$I) VALUES ($1, 1)
ON CONFLICT ("instance") DO
UPDATE SET %1$I = "counter_cache".%1$I + 1', visibility_new)
USING hostname;
END IF;
RETURN NEW;
ELSIF TG_OP = 'UPDATE' THEN
visibility_new := activity_visibility(NEW.actor, NEW.recipients, NEW.data);
visibility_old := activity_visibility(OLD.actor, OLD.recipients, OLD.data);
IF (NEW.data->>'type' = 'Create')
AND (OLD.data->>'type' = 'Create')
AND visibility_new != visibility_old
AND visibility_new IN ('public', 'unlisted', 'private', 'direct') THEN
EXECUTE format('UPDATE "counter_cache" SET
%1$I = greatest("counter_cache".%1$I - 1, 0),
%2$I = "counter_cache".%2$I + 1
WHERE "instance" = $1', visibility_old, visibility_new)
USING hostname;
END IF;
RETURN NEW;
ELSIF TG_OP = 'DELETE' THEN
IF OLD.data->>'type' = 'Create' THEN
visibility_old := activity_visibility(OLD.actor, OLD.recipients, OLD.data);
EXECUTE format('UPDATE "counter_cache" SET
%1$I = greatest("counter_cache".%1$I - 1, 0)
WHERE "instance" = $1', visibility_old)
USING hostname;
END IF;
RETURN OLD;
END IF;
END;
$$
LANGUAGE 'plpgsql';
"""
|> execute()
execute("DROP TRIGGER IF EXISTS #{@trigger_name} ON activities")
"""
CREATE TRIGGER #{@trigger_name}
BEFORE
INSERT
OR UPDATE of recipients, data
OR DELETE
ON activities
FOR EACH ROW
EXECUTE PROCEDURE #{@function_name}();
"""
|> execute()
end
def down do
execute("DROP TRIGGER IF EXISTS #{@trigger_name} ON activities")
execute("DROP FUNCTION IF EXISTS #{@function_name}()")
drop_if_exists(unique_index(:counter_cache, [:instance]))
drop_if_exists(table(:counter_cache))
create_if_not_exists table(:counter_cache) do
add(:name, :string, null: false)
add(:count, :bigint, null: false, default: 0)
end
create_if_not_exists(unique_index(:counter_cache, [:name]))
"""
CREATE OR REPLACE FUNCTION #{@function_name}()
RETURNS TRIGGER AS
$$
DECLARE
BEGIN
IF TG_OP = 'INSERT' THEN
IF NEW.data->>'type' = 'Create' THEN
EXECUTE 'INSERT INTO counter_cache (name, count) VALUES (''status_visibility_' || activity_visibility(NEW.actor, NEW.recipients, NEW.data) || ''', 1) ON CONFLICT (name) DO UPDATE SET count = counter_cache.count + 1';
END IF;
RETURN NEW;
ELSIF TG_OP = 'UPDATE' THEN
IF (NEW.data->>'type' = 'Create') and (OLD.data->>'type' = 'Create') and activity_visibility(NEW.actor, NEW.recipients, NEW.data) != activity_visibility(OLD.actor, OLD.recipients, OLD.data) THEN
EXECUTE 'INSERT INTO counter_cache (name, count) VALUES (''status_visibility_' || activity_visibility(NEW.actor, NEW.recipients, NEW.data) || ''', 1) ON CONFLICT (name) DO UPDATE SET count = counter_cache.count + 1';
EXECUTE 'update counter_cache SET count = counter_cache.count - 1 where count > 0 and name = ''status_visibility_' || activity_visibility(OLD.actor, OLD.recipients, OLD.data) || ''';';
END IF;
RETURN NEW;
ELSIF TG_OP = 'DELETE' THEN
IF OLD.data->>'type' = 'Create' THEN
EXECUTE 'update counter_cache SET count = counter_cache.count - 1 where count > 0 and name = ''status_visibility_' || activity_visibility(OLD.actor, OLD.recipients, OLD.data) || ''';';
END IF;
RETURN OLD;
END IF;
END;
$$
LANGUAGE 'plpgsql';
"""
|> execute()
"""
CREATE TRIGGER #{@trigger_name} BEFORE INSERT OR UPDATE of recipients, data OR DELETE ON activities
FOR EACH ROW
EXECUTE PROCEDURE #{@function_name}();
"""
|> execute()
end
end

View file

@ -0,0 +1,33 @@
defmodule Pleroma.Repo.Migrations.AddRecipientsContainBlockedDomainsFunction do
use Ecto.Migration
@disable_ddl_transaction true
def up do
statement = """
CREATE OR REPLACE FUNCTION recipients_contain_blocked_domains(recipients varchar[], blocked_domains varchar[]) RETURNS boolean AS $$
DECLARE
recipient_domain varchar;
recipient varchar;
BEGIN
FOREACH recipient IN ARRAY recipients LOOP
recipient_domain = split_part(recipient, '/', 3)::varchar;
IF recipient_domain = ANY(blocked_domains) THEN
RETURN TRUE;
END IF;
END LOOP;
RETURN FALSE;
END;
$$ LANGUAGE plpgsql;
"""
execute(statement)
end
def down do
execute(
"drop function if exists recipients_contain_blocked_domains(recipients varchar[], blocked_domains varchar[])"
)
end
end

View file

@ -0,0 +1,18 @@
defmodule Pleroma.Repo.Migrations.DeleteNotificationsFromInvisibleUsers do
use Ecto.Migration
import Ecto.Query
alias Pleroma.Repo
def up do
Pleroma.Notification
|> join(:inner, [n], activity in assoc(n, :activity))
|> where(
[n, a],
fragment("? in (SELECT ap_id FROM users WHERE invisible = true)", a.actor)
)
|> Repo.delete_all()
end
def down, do: :ok
end

View file

@ -0,0 +1,9 @@
defmodule Pleroma.Repo.Migrations.AddTypeToNotifications do
use Ecto.Migration
def change do
alter table(:notifications) do
add(:type, :string)
end
end
end

View file

@ -0,0 +1,10 @@
defmodule Pleroma.Repo.Migrations.BackfillNotificationTypes do
use Ecto.Migration
def up do
Pleroma.MigrationHelper.NotificationBackfill.fill_in_notification_types()
end
def down do
end
end

View file

@ -0,0 +1,20 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Repo.Migrations.CreateChatMessageReference do
use Ecto.Migration
def change do
create table(:chat_message_references, primary_key: false) do
add(:id, :uuid, primary_key: true)
add(:chat_id, references(:chats, on_delete: :delete_all), null: false)
add(:object_id, references(:objects, on_delete: :delete_all), null: false)
add(:seen, :boolean, default: false, null: false)
timestamps()
end
create(index(:chat_message_references, [:chat_id, "id desc"]))
end
end

View file

@ -0,0 +1,7 @@
defmodule Pleroma.Repo.Migrations.AddUniqueIndexToChatMessageReferences do
use Ecto.Migration
def change do
create(unique_index(:chat_message_references, [:object_id, :chat_id]))
end
end

View file

@ -0,0 +1,9 @@
defmodule Pleroma.Repo.Migrations.RemoveUnreadFromChats do
use Ecto.Migration
def change do
alter table(:chats) do
remove(:unread, :integer, default: 0)
end
end
end

View file

@ -0,0 +1,12 @@
defmodule Pleroma.Repo.Migrations.AddSeenIndexToChatMessageReferences do
use Ecto.Migration
def change do
create(
index(:chat_message_references, [:chat_id],
where: "seen = false",
name: "unseen_messages_count_index"
)
)
end
end

View file

@ -0,0 +1,30 @@
defmodule Pleroma.Repo.Migrations.MigrateSeenToUnreadInChatMessageReferences do
use Ecto.Migration
def change do
drop(
index(:chat_message_references, [:chat_id],
where: "seen = false",
name: "unseen_messages_count_index"
)
)
alter table(:chat_message_references) do
add(:unread, :boolean, default: true)
end
execute("update chat_message_references set unread = not seen")
alter table(:chat_message_references) do
modify(:unread, :boolean, default: true, null: false)
remove(:seen, :boolean, default: false, null: false)
end
create(
index(:chat_message_references, [:chat_id],
where: "unread = true",
name: "unread_messages_count_index"
)
)
end
end

View file

@ -0,0 +1,36 @@
defmodule Pleroma.Repo.Migrations.ChangeTypeToEnumForNotifications do
use Ecto.Migration
def up do
"""
create type notification_type as enum (
'follow',
'follow_request',
'mention',
'move',
'pleroma:emoji_reaction',
'pleroma:chat_mention',
'reblog',
'favourite'
)
"""
|> execute()
"""
alter table notifications
alter column type type notification_type using (type::notification_type)
"""
|> execute()
end
def down do
alter table(:notifications) do
modify(:type, :string)
end
"""
drop type notification_type
"""
|> execute()
end
end

View file

@ -0,0 +1,23 @@
defmodule Pleroma.Repo.Migrations.ChangeChatIdToFlake do
use Ecto.Migration
def up do
execute("""
alter table chats
drop constraint chats_pkey cascade,
alter column id drop default,
alter column id set data type uuid using cast( lpad( to_hex(id), 32, '0') as uuid),
add primary key (id)
""")
execute("""
alter table chat_message_references
alter column chat_id set data type uuid using cast( lpad( to_hex(chat_id), 32, '0') as uuid),
add constraint chat_message_references_chat_id_fkey foreign key (chat_id) references chats(id) on delete cascade
""")
end
def down do
:ok
end
end