diff options
Diffstat (limited to 'priv/repo')
63 files changed, 1689 insertions, 12 deletions
diff --git a/priv/repo/migrations/20190408123347_create_conversations.exs b/priv/repo/migrations/20190408123347_create_conversations.exs index d75459e82..3eaa6136c 100644 --- a/priv/repo/migrations/20190408123347_create_conversations.exs +++ b/priv/repo/migrations/20190408123347_create_conversations.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Repo.Migrations.CreateConversations do diff --git a/priv/repo/migrations/20190414125034_migrate_old_bookmarks.exs b/priv/repo/migrations/20190414125034_migrate_old_bookmarks.exs index f3928a149..b6f0ac66b 100644 --- a/priv/repo/migrations/20190414125034_migrate_old_bookmarks.exs +++ b/priv/repo/migrations/20190414125034_migrate_old_bookmarks.exs @@ -3,21 +3,24 @@ defmodule Pleroma.Repo.Migrations.MigrateOldBookmarks do import Ecto.Query alias Pleroma.Activity alias Pleroma.Bookmark - alias Pleroma.User alias Pleroma.Repo def up do query = - from(u in User, + from(u in "users", where: u.local == true, - where: fragment("array_length(bookmarks, 1)") > 0, - select: %{id: u.id, bookmarks: fragment("bookmarks")} + where: fragment("array_length(?, 1)", u.bookmarks) > 0, + select: %{id: u.id, bookmarks: u.bookmarks} ) Repo.stream(query) |> Enum.each(fn %{id: user_id, bookmarks: bookmarks} -> Enum.each(bookmarks, fn ap_id -> - activity = Activity.get_create_by_object_ap_id(ap_id) + activity = + ap_id + |> Activity.create_by_object_ap_id() + |> Repo.one() + unless is_nil(activity), do: {:ok, _} = Bookmark.create(user_id, activity.id) end) end) diff --git a/priv/repo/migrations/20190506054542_add_multi_factor_authentication_settings_to_user.exs b/priv/repo/migrations/20190506054542_add_multi_factor_authentication_settings_to_user.exs new file mode 100644 index 000000000..8b653c61f --- /dev/null +++ b/priv/repo/migrations/20190506054542_add_multi_factor_authentication_settings_to_user.exs @@ -0,0 +1,9 @@ +defmodule Pleroma.Repo.Migrations.AddMultiFactorAuthenticationSettingsToUser do + use Ecto.Migration + + def change do + alter table(:users) do + add(:multi_factor_authentication_settings, :map, default: %{}) + end + end +end diff --git a/priv/repo/migrations/20190508193213_create_mfa_tokens.exs b/priv/repo/migrations/20190508193213_create_mfa_tokens.exs new file mode 100644 index 000000000..da9f8fabe --- /dev/null +++ b/priv/repo/migrations/20190508193213_create_mfa_tokens.exs @@ -0,0 +1,16 @@ +defmodule Pleroma.Repo.Migrations.CreateMfaTokens do + use Ecto.Migration + + def change do + create table(:mfa_tokens) do + add(:user_id, references(:users, type: :uuid, on_delete: :delete_all)) + add(:authorization_id, references(:oauth_authorizations, on_delete: :delete_all)) + add(:token, :string) + add(:valid_until, :naive_datetime_usec) + + timestamps() + end + + create(unique_index(:mfa_tokens, :token)) + end +end diff --git a/priv/repo/migrations/20190710125158_add_following_address_from_source_data.exs b/priv/repo/migrations/20190710125158_add_following_address_from_source_data.exs index 779aa382e..44f9891b1 100644 --- a/priv/repo/migrations/20190710125158_add_following_address_from_source_data.exs +++ b/priv/repo/migrations/20190710125158_add_following_address_from_source_data.exs @@ -1,11 +1,16 @@ defmodule Pleroma.Repo.Migrations.AddFollowingAddressFromSourceData do - use Ecto.Migration - import Ecto.Query alias Pleroma.User + import Ecto.Query + require Logger + use Ecto.Migration def change do query = - User.external_users_query() + User.Query.build(%{ + external: true, + legacy_active: true, + order_by: :id + }) |> select([u], struct(u, [:id, :ap_id, :info])) Pleroma.Repo.stream(query) @@ -15,6 +20,9 @@ defmodule Pleroma.Repo.Migrations.AddFollowingAddressFromSourceData do :following_address ]) |> Pleroma.Repo.update() + + user -> + Logger.warn("User #{user.id} / #{user.nickname} does not seem to have source_data") end) end end diff --git a/priv/repo/migrations/20190711042021_create_safe_jsonb_set.exs b/priv/repo/migrations/20190711042021_create_safe_jsonb_set.exs index 2f336a5e8..43d616705 100644 --- a/priv/repo/migrations/20190711042021_create_safe_jsonb_set.exs +++ b/priv/repo/migrations/20190711042021_create_safe_jsonb_set.exs @@ -1,6 +1,5 @@ defmodule Pleroma.Repo.Migrations.CreateSafeJsonbSet do use Ecto.Migration - alias Pleroma.User def change do execute(""" diff --git a/priv/repo/migrations/20190711042024_copy_muted_to_muted_notifications.exs b/priv/repo/migrations/20190711042024_copy_muted_to_muted_notifications.exs index a5eec848b..bbd502044 100644 --- a/priv/repo/migrations/20190711042024_copy_muted_to_muted_notifications.exs +++ b/priv/repo/migrations/20190711042024_copy_muted_to_muted_notifications.exs @@ -1,8 +1,9 @@ defmodule Pleroma.Repo.Migrations.CopyMutedToMutedNotifications do use Ecto.Migration - alias Pleroma.User def change do + execute("update users set info = '{}' where info is null") + execute( "update users set info = safe_jsonb_set(info, '{muted_notifications}', info->'mutes', true) where local = true" ) diff --git a/priv/repo/migrations/20191007073319_create_following_relationships.exs b/priv/repo/migrations/20191007073319_create_following_relationships.exs new file mode 100644 index 000000000..d49e24ee4 --- /dev/null +++ b/priv/repo/migrations/20191007073319_create_following_relationships.exs @@ -0,0 +1,149 @@ +defmodule Pleroma.Repo.Migrations.CreateFollowingRelationships do + use Ecto.Migration + + def change do + create_if_not_exists table(:following_relationships) do + add(:follower_id, references(:users, type: :uuid, on_delete: :delete_all), null: false) + add(:following_id, references(:users, type: :uuid, on_delete: :delete_all), null: false) + add(:state, :string, null: false) + + timestamps() + end + + create_if_not_exists(index(:following_relationships, :follower_id)) + create_if_not_exists(unique_index(:following_relationships, [:follower_id, :following_id])) + + execute(update_thread_visibility(), restore_thread_visibility()) + end + + # The only difference between the original version: `actor_user` replaced with `actor_user_following` + def update_thread_visibility do + """ + CREATE OR REPLACE FUNCTION thread_visibility(actor varchar, activity_id varchar) RETURNS boolean AS $$ + DECLARE + public varchar := 'https://www.w3.org/ns/activitystreams#Public'; + child objects%ROWTYPE; + activity activities%ROWTYPE; + author_fa varchar; + valid_recipients varchar[]; + actor_user_following varchar[]; + BEGIN + --- Fetch actor following + SELECT array_agg(following.follower_address) INTO actor_user_following FROM following_relationships + JOIN users ON users.id = following_relationships.follower_id + JOIN users AS following ON following.id = following_relationships.following_id + WHERE users.ap_id = actor; + + --- Fetch our initial activity. + SELECT * INTO activity FROM activities WHERE activities.data->>'id' = activity_id; + + LOOP + --- Ensure that we have an activity before continuing. + --- If we don't, the thread is not satisfiable. + IF activity IS NULL THEN + RETURN false; + END IF; + + --- We only care about Create activities. + IF activity.data->>'type' != 'Create' THEN + RETURN true; + END IF; + + --- Normalize the child object into child. + SELECT * INTO child FROM objects + INNER JOIN activities ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id' + WHERE COALESCE(activity.data->'object'->>'id', activity.data->>'object') = objects.data->>'id'; + + --- Fetch the author's AS2 following collection. + SELECT COALESCE(users.follower_address, '') INTO author_fa FROM users WHERE users.ap_id = activity.actor; + + --- Prepare valid recipients array. + valid_recipients := ARRAY[actor, public]; + IF ARRAY[author_fa] && actor_user_following THEN + valid_recipients := valid_recipients || author_fa; + END IF; + + --- Check visibility. + IF NOT valid_recipients && activity.recipients THEN + --- activity not visible, break out of the loop + RETURN false; + END IF; + + --- If there's a parent, load it and do this all over again. + IF (child.data->'inReplyTo' IS NOT NULL) AND (child.data->'inReplyTo' != 'null'::jsonb) THEN + SELECT * INTO activity FROM activities + INNER JOIN objects ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id' + WHERE child.data->>'inReplyTo' = objects.data->>'id'; + ELSE + RETURN true; + END IF; + END LOOP; + END; + $$ LANGUAGE plpgsql IMMUTABLE; + """ + end + + # priv/repo/migrations/20190515222404_add_thread_visibility_function.exs + def restore_thread_visibility do + """ + CREATE OR REPLACE FUNCTION thread_visibility(actor varchar, activity_id varchar) RETURNS boolean AS $$ + DECLARE + public varchar := 'https://www.w3.org/ns/activitystreams#Public'; + child objects%ROWTYPE; + activity activities%ROWTYPE; + actor_user users%ROWTYPE; + author_fa varchar; + valid_recipients varchar[]; + BEGIN + --- Fetch our actor. + SELECT * INTO actor_user FROM users WHERE users.ap_id = actor; + + --- Fetch our initial activity. + SELECT * INTO activity FROM activities WHERE activities.data->>'id' = activity_id; + + LOOP + --- Ensure that we have an activity before continuing. + --- If we don't, the thread is not satisfiable. + IF activity IS NULL THEN + RETURN false; + END IF; + + --- We only care about Create activities. + IF activity.data->>'type' != 'Create' THEN + RETURN true; + END IF; + + --- Normalize the child object into child. + SELECT * INTO child FROM objects + INNER JOIN activities ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id' + WHERE COALESCE(activity.data->'object'->>'id', activity.data->>'object') = objects.data->>'id'; + + --- Fetch the author's AS2 following collection. + SELECT COALESCE(users.follower_address, '') INTO author_fa FROM users WHERE users.ap_id = activity.actor; + + --- Prepare valid recipients array. + valid_recipients := ARRAY[actor, public]; + IF ARRAY[author_fa] && actor_user.following THEN + valid_recipients := valid_recipients || author_fa; + END IF; + + --- Check visibility. + IF NOT valid_recipients && activity.recipients THEN + --- activity not visible, break out of the loop + RETURN false; + END IF; + + --- If there's a parent, load it and do this all over again. + IF (child.data->'inReplyTo' IS NOT NULL) AND (child.data->'inReplyTo' != 'null'::jsonb) THEN + SELECT * INTO activity FROM activities + INNER JOIN objects ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id' + WHERE child.data->>'inReplyTo' = objects.data->>'id'; + ELSE + RETURN true; + END IF; + END LOOP; + END; + $$ LANGUAGE plpgsql IMMUTABLE; + """ + end +end diff --git a/priv/repo/migrations/20191008132217_migrate_following_relationships.exs b/priv/repo/migrations/20191008132217_migrate_following_relationships.exs new file mode 100644 index 000000000..9d5c2648f --- /dev/null +++ b/priv/repo/migrations/20191008132217_migrate_following_relationships.exs @@ -0,0 +1,89 @@ +defmodule Pleroma.Repo.Migrations.MigrateFollowingRelationships do + use Ecto.Migration + + def change do + execute(import_following_from_users(), "") + execute(import_following_from_activities(), restore_following_column()) + end + + defp import_following_from_users do + """ + INSERT INTO following_relationships (follower_id, following_id, state, inserted_at, updated_at) + SELECT + relations.follower_id, + following.id, + 'accept', + now(), + now() + FROM ( + SELECT + users.id AS follower_id, + unnest(users.following) AS following_ap_id + FROM + users + WHERE + users.following != '{}' + AND users.local = false OR users.local = true AND users.email IS NOT NULL -- Exclude `internal/fetch` and `relay` + ) AS relations + JOIN users AS "following" ON "following".follower_address = relations.following_ap_id + + WHERE relations.follower_id != following.id + ON CONFLICT DO NOTHING + """ + end + + defp import_following_from_activities do + """ + INSERT INTO + following_relationships ( + follower_id, + following_id, + state, + inserted_at, + updated_at + ) + SELECT + followers.id, + following.id, + activities.data ->> 'state', + (activities.data ->> 'published') :: timestamp, + now() + FROM + activities + JOIN users AS followers ON (activities.actor = followers.ap_id) + JOIN users AS following ON (activities.data ->> 'object' = following.ap_id) + WHERE + activities.data ->> 'type' = 'Follow' + AND activities.data ->> 'state' IN ('accept', 'pending', 'reject') + ORDER BY activities.updated_at DESC + ON CONFLICT DO NOTHING + """ + end + + defp restore_following_column do + """ + UPDATE + users + SET + following = following_query.following_array, + updated_at = now() + FROM ( + SELECT + follower.id AS follower_id, + CASE follower.local + WHEN TRUE THEN + array_prepend(follower.follower_address, array_agg(following.follower_address)) + ELSE + array_agg(following.follower_address) + END AS following_array + FROM + following_relationships + JOIN users AS follower ON follower.id = following_relationships.follower_id + JOIN users AS following ON following.id = following_relationships.following_id + GROUP BY + follower.id) AS following_query + WHERE + following_query.follower_id = users.id + """ + end +end diff --git a/priv/repo/migrations/20191008132427_drop_users_following.exs b/priv/repo/migrations/20191008132427_drop_users_following.exs new file mode 100644 index 000000000..21c0af9f4 --- /dev/null +++ b/priv/repo/migrations/20191008132427_drop_users_following.exs @@ -0,0 +1,16 @@ +defmodule Pleroma.Repo.Migrations.DropUsersFollowing do + use Ecto.Migration + + # had to disable these to be able to restore `following` index concurrently + # https://hexdocs.pm/ecto_sql/Ecto.Migration.html#index/3-adding-dropping-indexes-concurrently + @disable_ddl_transaction true + @disable_migration_lock true + + def change do + drop(index(:users, [:following], concurrently: true, using: :gin)) + + alter table(:users) do + remove(:following, {:array, :string}, default: []) + end + end +end diff --git a/priv/repo/migrations/20191009154606_add_user_info_columns.exs b/priv/repo/migrations/20191009154606_add_user_info_columns.exs new file mode 100644 index 000000000..22a5a377f --- /dev/null +++ b/priv/repo/migrations/20191009154606_add_user_info_columns.exs @@ -0,0 +1,53 @@ +defmodule Pleroma.Repo.Migrations.AddUsersInfoColumns do + use Ecto.Migration + + @jsonb_array_default "'[]'::jsonb" + + def change do + alter table(:users) do + add_if_not_exists(:banner, :map, default: %{}) + add_if_not_exists(:background, :map, default: %{}) + add_if_not_exists(:source_data, :map, default: %{}) + add_if_not_exists(:note_count, :integer, default: 0) + add_if_not_exists(:follower_count, :integer, default: 0) + add_if_not_exists(:following_count, :integer, default: nil) + add_if_not_exists(:locked, :boolean, default: false, null: false) + add_if_not_exists(:confirmation_pending, :boolean, default: false, null: false) + add_if_not_exists(:password_reset_pending, :boolean, default: false, null: false) + add_if_not_exists(:confirmation_token, :text, default: nil) + add_if_not_exists(:default_scope, :string, default: "public") + add_if_not_exists(:blocks, {:array, :text}, default: []) + add_if_not_exists(:domain_blocks, {:array, :text}, default: []) + add_if_not_exists(:mutes, {:array, :text}, default: []) + add_if_not_exists(:muted_reblogs, {:array, :text}, default: []) + add_if_not_exists(:muted_notifications, {:array, :text}, default: []) + add_if_not_exists(:subscribers, {:array, :text}, default: []) + add_if_not_exists(:deactivated, :boolean, default: false, null: false) + add_if_not_exists(:no_rich_text, :boolean, default: false, null: false) + add_if_not_exists(:ap_enabled, :boolean, default: false, null: false) + add_if_not_exists(:is_moderator, :boolean, default: false, null: false) + add_if_not_exists(:is_admin, :boolean, default: false, null: false) + add_if_not_exists(:show_role, :boolean, default: true, null: false) + add_if_not_exists(:settings, :map, default: nil) + add_if_not_exists(:magic_key, :text, default: nil) + add_if_not_exists(:uri, :text, default: nil) + add_if_not_exists(:hide_followers_count, :boolean, default: false, null: false) + add_if_not_exists(:hide_follows_count, :boolean, default: false, null: false) + add_if_not_exists(:hide_followers, :boolean, default: false, null: false) + add_if_not_exists(:hide_follows, :boolean, default: false, null: false) + add_if_not_exists(:hide_favorites, :boolean, default: true, null: false) + add_if_not_exists(:unread_conversation_count, :integer, default: 0) + add_if_not_exists(:pinned_activities, {:array, :text}, default: []) + add_if_not_exists(:email_notifications, :map, default: %{"digest" => false}) + add_if_not_exists(:mascot, :map, default: nil) + add_if_not_exists(:emoji, :map, default: fragment(@jsonb_array_default)) + add_if_not_exists(:pleroma_settings_store, :map, default: %{}) + add_if_not_exists(:fields, :map, default: fragment(@jsonb_array_default)) + add_if_not_exists(:raw_fields, :map, default: fragment(@jsonb_array_default)) + add_if_not_exists(:discoverable, :boolean, default: false, null: false) + add_if_not_exists(:invisible, :boolean, default: false, null: false) + add_if_not_exists(:notification_settings, :map, default: %{}) + add_if_not_exists(:skip_thread_containment, :boolean, default: false, null: false) + end + end +end diff --git a/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs new file mode 100644 index 000000000..cc5ae6920 --- /dev/null +++ b/priv/repo/migrations/20191009154608_copy_users_info_fields_to_users.exs @@ -0,0 +1,145 @@ +defmodule Pleroma.Repo.Migrations.CopyUsersInfoFieldsToUsers do + use Ecto.Migration + + @jsonb_array_default "'[]'::jsonb" + + @info_fields [ + :banner, + :background, + :source_data, + :note_count, + :follower_count, + :following_count, + :locked, + :confirmation_pending, + :password_reset_pending, + :confirmation_token, + :default_scope, + :blocks, + :domain_blocks, + :mutes, + :muted_reblogs, + :muted_notifications, + :subscribers, + :deactivated, + :no_rich_text, + :ap_enabled, + :is_moderator, + :is_admin, + :show_role, + :settings, + :magic_key, + :uri, + :hide_followers_count, + :hide_follows_count, + :hide_followers, + :hide_follows, + :hide_favorites, + :unread_conversation_count, + :pinned_activities, + :email_notifications, + :mascot, + :emoji, + :pleroma_settings_store, + :fields, + :raw_fields, + :discoverable, + :invisible, + :skip_thread_containment, + :notification_settings + ] + + @jsonb_fields [ + :banner, + :background, + :source_data, + :settings, + :email_notifications, + :mascot, + :pleroma_settings_store, + :notification_settings + ] + + @array_jsonb_fields [:emoji, :fields, :raw_fields] + + @int_fields [:note_count, :follower_count, :following_count, :unread_conversation_count] + + @boolean_fields [ + :locked, + :confirmation_pending, + :password_reset_pending, + :deactivated, + :no_rich_text, + :ap_enabled, + :is_moderator, + :is_admin, + :show_role, + :hide_followers_count, + :hide_follows_count, + :hide_followers, + :hide_follows, + :hide_favorites, + :discoverable, + :invisible, + :skip_thread_containment + ] + + @array_text_fields [ + :blocks, + :domain_blocks, + :mutes, + :muted_reblogs, + :muted_notifications, + :subscribers, + :pinned_activities + ] + + def change do + if direction() == :up do + sets = + for f <- @info_fields do + set_field = "#{f} =" + + # Coercion of null::jsonb to NULL + jsonb = "case when info->>'#{f}' IS NULL then null else info->'#{f}' end" + + cond do + f in @jsonb_fields -> + "#{set_field} #{jsonb}" + + f in @array_jsonb_fields -> + "#{set_field} coalesce(#{jsonb}, #{@jsonb_array_default})" + + f in @int_fields -> + "#{set_field} (info->>'#{f}')::int" + + f in @boolean_fields -> + "#{set_field} coalesce((info->>'#{f}')::boolean, false)" + + f in @array_text_fields -> + "#{set_field} ARRAY(SELECT jsonb_array_elements_text(#{jsonb}))" + + true -> + "#{set_field} info->>'#{f}'" + end + end + |> Enum.join(", ") + + execute("update users set " <> sets) + + for index_name <- [ + :users_deactivated_index, + :users_is_moderator_index, + :users_is_admin_index, + :users_subscribers_index + ] do + drop_if_exists(index(:users, [], name: index_name)) + end + end + + create_if_not_exists(index(:users, [:deactivated])) + create_if_not_exists(index(:users, [:is_moderator])) + create_if_not_exists(index(:users, [:is_admin])) + create_if_not_exists(index(:users, [:subscribers])) + end +end diff --git a/priv/repo/migrations/20191017225002_drop_websub_tables.exs b/priv/repo/migrations/20191017225002_drop_websub_tables.exs index 9e483b2a1..4cf67a59c 100644 --- a/priv/repo/migrations/20191017225002_drop_websub_tables.exs +++ b/priv/repo/migrations/20191017225002_drop_websub_tables.exs @@ -1,8 +1,10 @@ defmodule Pleroma.Repo.Migrations.DropWebsubTables do use Ecto.Migration - def change do + def up do drop_if_exists(table(:websub_client_subscriptions)) drop_if_exists(table(:websub_server_subscriptions)) end + + def down, do: :noop end diff --git a/priv/repo/migrations/20191025081729_add_move_support_to_users.exs b/priv/repo/migrations/20191025081729_add_move_support_to_users.exs new file mode 100644 index 000000000..580b9eb0f --- /dev/null +++ b/priv/repo/migrations/20191025081729_add_move_support_to_users.exs @@ -0,0 +1,10 @@ +defmodule Pleroma.Repo.Migrations.AddMoveSupportToUsers do + use Ecto.Migration + + def change do + alter table(:users) do + add(:also_known_as, {:array, :string}, default: [], null: false) + add(:allow_following_move, :boolean, default: true, null: false) + end + end +end diff --git a/priv/repo/migrations/20191025143434_add_defaults_to_tables.exs b/priv/repo/migrations/20191025143434_add_defaults_to_tables.exs new file mode 100644 index 000000000..a5bc82335 --- /dev/null +++ b/priv/repo/migrations/20191025143434_add_defaults_to_tables.exs @@ -0,0 +1,68 @@ +defmodule Pleroma.Repo.Migrations.AddDefaultsToTables do + use Ecto.Migration + + def up do + execute("ALTER TABLE activities + ALTER COLUMN recipients SET DEFAULT ARRAY[]::character varying[]") + + execute("ALTER TABLE filters + ALTER COLUMN whole_word SET DEFAULT true") + + execute("ALTER TABLE push_subscriptions + ALTER COLUMN data SET DEFAULT '{}'::jsonb") + + execute(~s(ALTER TABLE users + ALTER COLUMN tags SET DEFAULT ARRAY[]::character varying[], + ALTER COLUMN notification_settings SET DEFAULT + '{"followers": true, "follows": true, "non_follows": true, "non_followers": true}'::jsonb)) + + # irreversible updates + + execute( + "UPDATE activities SET recipients = ARRAY[]::character varying[] WHERE recipients IS NULL" + ) + + execute("UPDATE filters SET whole_word = true WHERE whole_word IS NULL") + + execute("UPDATE push_subscriptions SET data = '{}'::jsonb WHERE data IS NULL") + + execute("UPDATE users SET source_data = '{}'::jsonb where source_data IS NULL") + execute("UPDATE users SET note_count = 0 where note_count IS NULL") + execute("UPDATE users SET background = '{}'::jsonb where background IS NULL") + execute("UPDATE users SET follower_count = 0 where follower_count IS NULL") + + execute( + "UPDATE users SET unread_conversation_count = 0 where unread_conversation_count IS NULL" + ) + + execute( + ~s(UPDATE users SET email_notifications = '{"digest": false}'::jsonb where email_notifications IS NULL) + ) + + execute("UPDATE users SET default_scope = 'public' where default_scope IS NULL") + + execute( + "UPDATE users SET pleroma_settings_store = '{}'::jsonb where pleroma_settings_store IS NULL" + ) + + execute("UPDATE users SET tags = ARRAY[]::character varying[] WHERE tags IS NULL") + execute(~s(UPDATE users SET notification_settings = + '{"followers": true, "follows": true, "non_follows": true, "non_followers": true}'::jsonb + WHERE notification_settings = '{}'::jsonb)) + end + + def down do + execute("ALTER TABLE activities + ALTER COLUMN recipients DROP DEFAULT") + + execute("ALTER TABLE filters + ALTER COLUMN whole_word DROP DEFAULT") + + execute("ALTER TABLE push_subscriptions + ALTER COLUMN data DROP DEFAULT") + + execute("ALTER TABLE users + ALTER COLUMN tags DROP DEFAULT, + ALTER COLUMN notification_settings SET DEFAULT '{}'::jsonb") + end +end diff --git a/priv/repo/migrations/20191026190317_set_not_null_for_activities.exs b/priv/repo/migrations/20191026190317_set_not_null_for_activities.exs new file mode 100644 index 000000000..9b66f3cff --- /dev/null +++ b/priv/repo/migrations/20191026190317_set_not_null_for_activities.exs @@ -0,0 +1,17 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForActivities do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE activities + ALTER COLUMN data SET NOT NULL, + ALTER COLUMN local SET NOT NULL") + end + + def down do + execute("ALTER TABLE activities + ALTER COLUMN data DROP NOT NULL, + ALTER COLUMN local DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026190415_set_not_null_for_activity_expirations.exs b/priv/repo/migrations/20191026190415_set_not_null_for_activity_expirations.exs new file mode 100644 index 000000000..e41c69e4c --- /dev/null +++ b/priv/repo/migrations/20191026190415_set_not_null_for_activity_expirations.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForActivityExpirations do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE activity_expirations + ALTER COLUMN activity_id SET NOT NULL") + end + + def down do + execute("ALTER TABLE activity_expirations + ALTER COLUMN activity_id DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026190500_set_not_null_for_apps.exs b/priv/repo/migrations/20191026190500_set_not_null_for_apps.exs new file mode 100644 index 000000000..a6a44ddfe --- /dev/null +++ b/priv/repo/migrations/20191026190500_set_not_null_for_apps.exs @@ -0,0 +1,17 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForApps do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE apps + ALTER COLUMN client_name SET NOT NULL, + ALTER COLUMN redirect_uris SET NOT NULL") + end + + def down do + execute("ALTER TABLE apps + ALTER COLUMN client_name DROP NOT NULL, + ALTER COLUMN redirect_uris DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026190533_set_not_null_for_bookmarks.exs b/priv/repo/migrations/20191026190533_set_not_null_for_bookmarks.exs new file mode 100644 index 000000000..5f3224003 --- /dev/null +++ b/priv/repo/migrations/20191026190533_set_not_null_for_bookmarks.exs @@ -0,0 +1,17 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForBookmarks do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE bookmarks + ALTER COLUMN user_id SET NOT NULL, + ALTER COLUMN activity_id SET NOT NULL") + end + + def down do + execute("ALTER TABLE bookmarks + ALTER COLUMN user_id DROP NOT NULL, + ALTER COLUMN activity_id DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026190622_set_not_null_for_config.exs b/priv/repo/migrations/20191026190622_set_not_null_for_config.exs new file mode 100644 index 000000000..204272442 --- /dev/null +++ b/priv/repo/migrations/20191026190622_set_not_null_for_config.exs @@ -0,0 +1,17 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForConfig do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE config + ALTER COLUMN key SET NOT NULL, + ALTER COLUMN value SET NOT NULL") + end + + def down do + execute("ALTER TABLE config + ALTER COLUMN key DROP NOT NULL, + ALTER COLUMN value DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026190712_set_not_null_for_conversation_participation_recipient_ships.exs b/priv/repo/migrations/20191026190712_set_not_null_for_conversation_participation_recipient_ships.exs new file mode 100644 index 000000000..a5ab1d3c9 --- /dev/null +++ b/priv/repo/migrations/20191026190712_set_not_null_for_conversation_participation_recipient_ships.exs @@ -0,0 +1,17 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForConversationParticipationRecipientShips do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE conversation_participation_recipient_ships + ALTER COLUMN user_id SET NOT NULL, + ALTER COLUMN participation_id SET NOT NULL") + end + + def down do + execute("ALTER TABLE conversation_participation_recipient_ships + ALTER COLUMN user_id DROP NOT NULL, + ALTER COLUMN participation_id DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026190759_set_not_null_for_conversation_participations.exs b/priv/repo/migrations/20191026190759_set_not_null_for_conversation_participations.exs new file mode 100644 index 000000000..cabb1f29f --- /dev/null +++ b/priv/repo/migrations/20191026190759_set_not_null_for_conversation_participations.exs @@ -0,0 +1,19 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForConversationParticipations do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE conversation_participations + ALTER COLUMN user_id SET NOT NULL, + ALTER COLUMN conversation_id SET NOT NULL, + ALTER COLUMN read SET NOT NULL") + end + + def down do + execute("ALTER TABLE conversation_participations + ALTER COLUMN user_id DROP NOT NULL, + ALTER COLUMN conversation_id DROP NOT NULL, + ALTER COLUMN read DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026190841_set_not_null_for_filters.exs b/priv/repo/migrations/20191026190841_set_not_null_for_filters.exs new file mode 100644 index 000000000..52d7e687a --- /dev/null +++ b/priv/repo/migrations/20191026190841_set_not_null_for_filters.exs @@ -0,0 +1,19 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForFilters do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE filters + ALTER COLUMN user_id SET NOT NULL, + ALTER COLUMN filter_id SET NOT NULL, + ALTER COLUMN whole_word SET NOT NULL") + end + + def down do + execute("ALTER TABLE filters + ALTER COLUMN user_id DROP NOT NULL, + ALTER COLUMN filter_id DROP NOT NULL, + ALTER COLUMN whole_word DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191023_set_not_null_for_instances.exs b/priv/repo/migrations/20191026191023_set_not_null_for_instances.exs new file mode 100644 index 000000000..4c2560da5 --- /dev/null +++ b/priv/repo/migrations/20191026191023_set_not_null_for_instances.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForInstances do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE instances + ALTER COLUMN host SET NOT NULL") + end + + def down do + execute("ALTER TABLE instances + ALTER COLUMN host DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191100_set_not_null_for_lists.exs b/priv/repo/migrations/20191026191100_set_not_null_for_lists.exs new file mode 100644 index 000000000..40b8b136a --- /dev/null +++ b/priv/repo/migrations/20191026191100_set_not_null_for_lists.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForLists do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE lists + ALTER COLUMN user_id SET NOT NULL") + end + + def down do + execute("ALTER TABLE lists + ALTER COLUMN user_id DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191134_set_not_null_for_markers.exs b/priv/repo/migrations/20191026191134_set_not_null_for_markers.exs new file mode 100644 index 000000000..7d7b73e7b --- /dev/null +++ b/priv/repo/migrations/20191026191134_set_not_null_for_markers.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForMarkers do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE markers + ALTER COLUMN user_id SET NOT NULL") + end + + def down do + execute("ALTER TABLE markers + ALTER COLUMN user_id DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191218_set_not_null_for_moderation_log.exs b/priv/repo/migrations/20191026191218_set_not_null_for_moderation_log.exs new file mode 100644 index 000000000..7238ca7f5 --- /dev/null +++ b/priv/repo/migrations/20191026191218_set_not_null_for_moderation_log.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForModerationLog do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE moderation_log + ALTER COLUMN data SET NOT NULL") + end + + def down do + execute("ALTER TABLE moderation_log + ALTER COLUMN data DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191249_set_not_null_for_notifications.exs b/priv/repo/migrations/20191026191249_set_not_null_for_notifications.exs new file mode 100644 index 000000000..7e2976bab --- /dev/null +++ b/priv/repo/migrations/20191026191249_set_not_null_for_notifications.exs @@ -0,0 +1,17 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForNotifications do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE notifications + ALTER COLUMN user_id SET NOT NULL, + ALTER COLUMN seen SET NOT NULL") + end + + def down do + execute("ALTER TABLE notifications + ALTER COLUMN user_id DROP NOT NULL, + ALTER COLUMN seen DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191328_set_not_null_for_oauth_authorizations.exs b/priv/repo/migrations/20191026191328_set_not_null_for_oauth_authorizations.exs new file mode 100644 index 000000000..bc6b36e69 --- /dev/null +++ b/priv/repo/migrations/20191026191328_set_not_null_for_oauth_authorizations.exs @@ -0,0 +1,19 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForOauthAuthorizations do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE oauth_authorizations + ALTER COLUMN app_id SET NOT NULL, + ALTER COLUMN token SET NOT NULL, + ALTER COLUMN used SET NOT NULL") + end + + def down do + execute("ALTER TABLE oauth_authorizations + ALTER COLUMN app_id DROP NOT NULL, + ALTER COLUMN token DROP NOT NULL, + ALTER COLUMN used DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191401_set_not_null_for_oauth_tokens.exs b/priv/repo/migrations/20191026191401_set_not_null_for_oauth_tokens.exs new file mode 100644 index 000000000..fe67db8cc --- /dev/null +++ b/priv/repo/migrations/20191026191401_set_not_null_for_oauth_tokens.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForOauthTokens do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE oauth_tokens + ALTER COLUMN app_id SET NOT NULL") + end + + def down do + execute("ALTER TABLE oauth_tokens + ALTER COLUMN app_id DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191442_set_not_null_for_objects.exs b/priv/repo/migrations/20191026191442_set_not_null_for_objects.exs new file mode 100644 index 000000000..59e89d6da --- /dev/null +++ b/priv/repo/migrations/20191026191442_set_not_null_for_objects.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForObjects do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE objects + ALTER COLUMN data SET NOT NULL") + end + + def down do + execute("ALTER TABLE objects + ALTER COLUMN data DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191524_set_not_null_for_password_reset_tokens.exs b/priv/repo/migrations/20191026191524_set_not_null_for_password_reset_tokens.exs new file mode 100644 index 000000000..51efadbd3 --- /dev/null +++ b/priv/repo/migrations/20191026191524_set_not_null_for_password_reset_tokens.exs @@ -0,0 +1,19 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForPasswordResetTokens do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE password_reset_tokens + ALTER COLUMN token SET NOT NULL, + ALTER COLUMN user_id SET NOT NULL, + ALTER COLUMN used SET NOT NULL") + end + + def down do + execute("ALTER TABLE password_reset_tokens + ALTER COLUMN token DROP NOT NULL, + ALTER COLUMN user_id DROP NOT NULL, + ALTER COLUMN used DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191603_set_not_null_for_push_subscriptions.exs b/priv/repo/migrations/20191026191603_set_not_null_for_push_subscriptions.exs new file mode 100644 index 000000000..0f3a73067 --- /dev/null +++ b/priv/repo/migrations/20191026191603_set_not_null_for_push_subscriptions.exs @@ -0,0 +1,25 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForPushSubscriptions do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE push_subscriptions + ALTER COLUMN user_id SET NOT NULL, + ALTER COLUMN token_id SET NOT NULL, + ALTER COLUMN endpoint SET NOT NULL, + ALTER COLUMN key_p256dh SET NOT NULL, + ALTER COLUMN key_auth SET NOT NULL, + ALTER COLUMN data SET NOT NULL") + end + + def down do + execute("ALTER TABLE push_subscriptions + ALTER COLUMN user_id DROP NOT NULL, + ALTER COLUMN token_id DROP NOT NULL, + ALTER COLUMN endpoint DROP NOT NULL, + ALTER COLUMN key_p256dh DROP NOT NULL, + ALTER COLUMN key_auth DROP NOT NULL, + ALTER COLUMN data DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191635_set_not_null_for_registrations.exs b/priv/repo/migrations/20191026191635_set_not_null_for_registrations.exs new file mode 100644 index 000000000..ddfbf4c5e --- /dev/null +++ b/priv/repo/migrations/20191026191635_set_not_null_for_registrations.exs @@ -0,0 +1,19 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForRegistrations do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE registrations + ALTER COLUMN provider SET NOT NULL, + ALTER COLUMN uid SET NOT NULL, + ALTER COLUMN info SET NOT NULL") + end + + def down do + execute("ALTER TABLE registrations + ALTER COLUMN provider DROP NOT NULL, + ALTER COLUMN uid DROP NOT NULL, + ALTER COLUMN info DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191711_set_not_null_for_scheduled_activities.exs b/priv/repo/migrations/20191026191711_set_not_null_for_scheduled_activities.exs new file mode 100644 index 000000000..f1830c8c3 --- /dev/null +++ b/priv/repo/migrations/20191026191711_set_not_null_for_scheduled_activities.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForScheduledActivities do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE scheduled_activities + ALTER COLUMN user_id SET NOT NULL") + end + + def down do + execute("ALTER TABLE scheduled_activities + ALTER COLUMN user_id DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191753_set_not_null_for_thread_mutes.exs b/priv/repo/migrations/20191026191753_set_not_null_for_thread_mutes.exs new file mode 100644 index 000000000..daa7ce314 --- /dev/null +++ b/priv/repo/migrations/20191026191753_set_not_null_for_thread_mutes.exs @@ -0,0 +1,17 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForThreadMutes do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE thread_mutes + ALTER COLUMN user_id SET NOT NULL, + ALTER COLUMN context SET NOT NULL") + end + + def down do + execute("ALTER TABLE thread_mutes + ALTER COLUMN user_id DROP NOT NULL, + ALTER COLUMN context DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191826_set_not_null_for_user_invite_tokens.exs b/priv/repo/migrations/20191026191826_set_not_null_for_user_invite_tokens.exs new file mode 100644 index 000000000..836544f7f --- /dev/null +++ b/priv/repo/migrations/20191026191826_set_not_null_for_user_invite_tokens.exs @@ -0,0 +1,19 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForUserInviteTokens do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + execute("ALTER TABLE user_invite_tokens + ALTER COLUMN used SET NOT NULL, + ALTER COLUMN uses SET NOT NULL, + ALTER COLUMN invite_type SET NOT NULL") + end + + def down do + execute("ALTER TABLE user_invite_tokens + ALTER COLUMN used DROP NOT NULL, + ALTER COLUMN uses DROP NOT NULL, + ALTER COLUMN invite_type DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191026191910_set_not_null_for_users.exs b/priv/repo/migrations/20191026191910_set_not_null_for_users.exs new file mode 100644 index 000000000..9d8d0ccf8 --- /dev/null +++ b/priv/repo/migrations/20191026191910_set_not_null_for_users.exs @@ -0,0 +1,44 @@ +defmodule Pleroma.Repo.Migrations.SetNotNullForUsers do + use Ecto.Migration + + # modify/3 function will require index recreation, so using execute/1 instead + + def up do + # irreversible + execute("UPDATE users SET follower_count = 0 WHERE follower_count IS NULL") + + execute("ALTER TABLE users + ALTER COLUMN local SET NOT NULL, + ALTER COLUMN source_data SET NOT NULL, + ALTER COLUMN note_count SET NOT NULL, + ALTER COLUMN follower_count SET NOT NULL, + ALTER COLUMN blocks SET NOT NULL, + ALTER COLUMN domain_blocks SET NOT NULL, + ALTER COLUMN mutes SET NOT NULL, + ALTER COLUMN muted_reblogs SET NOT NULL, + ALTER COLUMN muted_notifications SET NOT NULL, + ALTER COLUMN subscribers SET NOT NULL, + ALTER COLUMN pinned_activities SET NOT NULL, + ALTER COLUMN emoji SET NOT NULL, + ALTER COLUMN fields SET NOT NULL, + ALTER COLUMN raw_fields SET NOT NULL") + end + + def down do + execute("ALTER TABLE users + ALTER COLUMN local DROP NOT NULL, + ALTER COLUMN source_data DROP NOT NULL, + ALTER COLUMN note_count DROP NOT NULL, + ALTER COLUMN follower_count DROP NOT NULL, + ALTER COLUMN blocks DROP NOT NULL, + ALTER COLUMN domain_blocks DROP NOT NULL, + ALTER COLUMN mutes DROP NOT NULL, + ALTER COLUMN muted_reblogs DROP NOT NULL, + ALTER COLUMN muted_notifications DROP NOT NULL, + ALTER COLUMN subscribers DROP NOT NULL, + ALTER COLUMN pinned_activities DROP NOT NULL, + ALTER COLUMN emoji DROP NOT NULL, + ALTER COLUMN fields DROP NOT NULL, + ALTER COLUMN raw_fields DROP NOT NULL") + end +end diff --git a/priv/repo/migrations/20191029101340_migrate_missing_follow_requests.exs b/priv/repo/migrations/20191029101340_migrate_missing_follow_requests.exs new file mode 100644 index 000000000..90b18efc8 --- /dev/null +++ b/priv/repo/migrations/20191029101340_migrate_missing_follow_requests.exs @@ -0,0 +1,35 @@ +defmodule Pleroma.Repo.Migrations.MigrateMissingFollowingRelationships do + use Ecto.Migration + + def change do + execute(import_pending_follows_from_activities(), "") + end + + defp import_pending_follows_from_activities do + """ + INSERT INTO + following_relationships ( + follower_id, + following_id, + state, + inserted_at, + updated_at + ) + SELECT + followers.id, + following.id, + activities.data ->> 'state', + (activities.data ->> 'published') :: timestamp, + now() + FROM + activities + JOIN users AS followers ON (activities.actor = followers.ap_id) + JOIN users AS following ON (activities.data ->> 'object' = following.ap_id) + WHERE + activities.data ->> 'type' = 'Follow' + AND activities.data ->> 'state' = 'pending' + ORDER BY activities.updated_at DESC + ON CONFLICT DO NOTHING + """ + end +end diff --git a/priv/repo/migrations/20191029172832_fix_blocked_follows.exs b/priv/repo/migrations/20191029172832_fix_blocked_follows.exs new file mode 100644 index 000000000..71f8f1330 --- /dev/null +++ b/priv/repo/migrations/20191029172832_fix_blocked_follows.exs @@ -0,0 +1,112 @@ +defmodule Pleroma.Repo.Migrations.FixBlockedFollows do + use Ecto.Migration + + import Ecto.Query + alias Pleroma.Config + alias Pleroma.Repo + + def up do + unfollow_blocked = Config.get([:activitypub, :unfollow_blocked]) + + if unfollow_blocked do + "activities" + |> where([activity], fragment("? ->> 'type' = 'Block'", activity.data)) + |> distinct([activity], [ + activity.actor, + fragment( + "coalesce((?)->'object'->>'id', (?)->>'object')", + activity.data, + activity.data + ) + ]) + |> order_by([activity], [fragment("? desc nulls last", activity.id)]) + |> select([activity], %{ + blocker: activity.actor, + blocked: + fragment("coalesce((?)->'object'->>'id', (?)->>'object')", activity.data, activity.data), + created_at: activity.id + }) + |> Repo.stream() + |> Enum.map(&unfollow_if_blocked/1) + |> Enum.uniq() + |> Enum.each(&update_follower_count/1) + end + end + + def down do + end + + def unfollow_if_blocked(%{blocker: blocker_id, blocked: blocked_id, created_at: blocked_at}) do + query = + from( + activity in "activities", + where: fragment("? ->> 'type' = 'Follow'", activity.data), + where: activity.actor == ^blocked_id, + # this is to use the index + where: + fragment( + "coalesce((?)->'object'->>'id', (?)->>'object') = ?", + activity.data, + activity.data, + ^blocker_id + ), + where: activity.id > ^blocked_at, + where: fragment("(?)->>'state' = 'accept'", activity.data), + order_by: [fragment("? desc nulls last", activity.id)] + ) + + unless Repo.exists?(query) do + blocker = "users" |> select([:id, :local]) |> Repo.get_by(ap_id: blocker_id) + blocked = "users" |> select([:id]) |> Repo.get_by(ap_id: blocked_id) + + if !is_nil(blocker) && !is_nil(blocked) do + unfollow(blocked, blocker) + end + end + end + + def unfollow(%{id: follower_id}, %{id: followed_id} = followed) do + following_relationship = + "following_relationships" + |> where(follower_id: ^follower_id, following_id: ^followed_id, state: "accept") + |> select([:id]) + |> Repo.one() + + case following_relationship do + nil -> + {:ok, nil} + + %{id: following_relationship_id} -> + "following_relationships" + |> where(id: ^following_relationship_id) + |> Repo.delete_all() + + followed + end + end + + def update_follower_count(%{id: user_id} = user) do + if user.local or !Pleroma.Config.get([:instance, :external_user_synchronization]) do + follower_count_query = + "users" + |> where([u], u.id != ^user_id) + |> where([u], u.deactivated != ^true) + |> join(:inner, [u], r in "following_relationships", + as: :relationships, + on: r.following_id == ^user_id and r.follower_id == u.id + ) + |> where([relationships: r], r.state == "accept") + |> select([u], %{count: count(u.id)}) + + "users" + |> where(id: ^user_id) + |> join(:inner, [u], s in subquery(follower_count_query)) + |> update([u, s], + set: [follower_count: s.count] + ) + |> Repo.update_all([]) + end + end + + def update_follower_count(_), do: :noop +end diff --git a/priv/repo/migrations/20191104133100_set_visible_service_actors.exs b/priv/repo/migrations/20191104133100_set_visible_service_actors.exs new file mode 100644 index 000000000..62907093c --- /dev/null +++ b/priv/repo/migrations/20191104133100_set_visible_service_actors.exs @@ -0,0 +1,22 @@ +defmodule Pleroma.Repo.Migrations.SetVisibleServiceActors do + use Ecto.Migration + import Ecto.Query + alias Pleroma.Repo + + def up do + user_nicknames = ["relay", "internal.fetch"] + + from( + u in "users", + where: u.nickname in ^user_nicknames, + update: [ + set: [invisible: true] + ] + ) + |> Repo.update_all([]) + end + + def down do + :ok + end +end diff --git a/priv/repo/migrations/20191118084425_create_user_relationships.exs b/priv/repo/migrations/20191118084425_create_user_relationships.exs new file mode 100644 index 000000000..c281f887d --- /dev/null +++ b/priv/repo/migrations/20191118084425_create_user_relationships.exs @@ -0,0 +1,17 @@ +defmodule Pleroma.Repo.Migrations.CreateUserRelationships do + use Ecto.Migration + + def change do + create_if_not_exists table(:user_relationships) do + add(:source_id, references(:users, type: :uuid, on_delete: :delete_all)) + add(:target_id, references(:users, type: :uuid, on_delete: :delete_all)) + add(:relationship_type, :integer, null: false) + + timestamps(updated_at: false) + end + + create_if_not_exists( + unique_index(:user_relationships, [:source_id, :relationship_type, :target_id]) + ) + end +end diff --git a/priv/repo/migrations/20191118084500_data_migration_populate_user_relationships.exs b/priv/repo/migrations/20191118084500_data_migration_populate_user_relationships.exs new file mode 100644 index 000000000..990e9f3b8 --- /dev/null +++ b/priv/repo/migrations/20191118084500_data_migration_populate_user_relationships.exs @@ -0,0 +1,68 @@ +defmodule Pleroma.Repo.Migrations.DataMigrationPopulateUserRelationships do + use Ecto.Migration + + alias Ecto.Adapters.SQL + alias Pleroma.Repo + + require Logger + + def up do + Enum.each( + [blocks: 1, mutes: 2, muted_reblogs: 3, muted_notifications: 4, subscribers: 5], + fn {field, relationship_type_code} -> + migrate(field, relationship_type_code) + + if field == :subscribers do + drop_if_exists(index(:users, [:subscribers])) + end + end + ) + end + + def down, do: :noop + + defp migrate(field, relationship_type_code) do + Logger.info("Processing users.#{field}...") + + {:ok, %{rows: field_rows}} = + SQL.query(Repo, "SELECT id, #{field} FROM users WHERE #{field} != '{}'") + + target_ap_ids = + Enum.flat_map( + field_rows, + fn [_, ap_ids] -> ap_ids end + ) + |> Enum.uniq() + + # Selecting ids of all targets at once in order to reduce the number of SELECT queries + {:ok, %{rows: target_ap_id_id}} = + SQL.query(Repo, "SELECT ap_id, id FROM users WHERE ap_id = ANY($1)", [target_ap_ids]) + + target_id_by_ap_id = Enum.into(target_ap_id_id, %{}, fn [k, v] -> {k, v} end) + + Enum.each( + field_rows, + fn [source_id, target_ap_ids] -> + source_uuid = Ecto.UUID.cast!(source_id) + + for target_ap_id <- target_ap_ids do + target_id = target_id_by_ap_id[target_ap_id] + + with {:ok, target_uuid} <- target_id && Ecto.UUID.cast(target_id) do + execute(""" + INSERT INTO user_relationships( + source_id, target_id, relationship_type, inserted_at + ) + VALUES( + '#{source_uuid}'::uuid, '#{target_uuid}'::uuid, #{relationship_type_code}, now() + ) + ON CONFLICT (source_id, relationship_type, target_id) DO NOTHING + """) + else + _ -> Logger.warn("Unresolved #{field} reference: (#{source_uuid}, #{target_id})") + end + end + end + ) + end +end diff --git a/priv/repo/migrations/20191123030554_add_activitypub_actor_type.exs b/priv/repo/migrations/20191123030554_add_activitypub_actor_type.exs new file mode 100644 index 000000000..76d3b32c4 --- /dev/null +++ b/priv/repo/migrations/20191123030554_add_activitypub_actor_type.exs @@ -0,0 +1,9 @@ +defmodule Pleroma.Repo.Migrations.AddActivitypubActorType do + use Ecto.Migration + + def change do + alter table("users") do + add(:actor_type, :string, null: false, default: "Person") + end + end +end diff --git a/priv/repo/migrations/20191123103423_remove_info_from_users.exs b/priv/repo/migrations/20191123103423_remove_info_from_users.exs new file mode 100644 index 000000000..b251255ea --- /dev/null +++ b/priv/repo/migrations/20191123103423_remove_info_from_users.exs @@ -0,0 +1,9 @@ +defmodule Pleroma.Repo.Migrations.RemoveInfoFromUsers do + use Ecto.Migration + + def change do + alter table(:users) do + remove(:info, :map, default: %{}) + end + end +end diff --git a/priv/repo/migrations/20191128153944_fix_missing_following_count.exs b/priv/repo/migrations/20191128153944_fix_missing_following_count.exs new file mode 100644 index 000000000..3236de7a4 --- /dev/null +++ b/priv/repo/migrations/20191128153944_fix_missing_following_count.exs @@ -0,0 +1,53 @@ +defmodule Pleroma.Repo.Migrations.FixMissingFollowingCount do + use Ecto.Migration + + def up do + """ + UPDATE + users + SET + following_count = sub.count + FROM + ( + SELECT + users.id AS sub_id + ,COUNT (following_relationships.id) + FROM + following_relationships + ,users + WHERE + users.id = following_relationships.follower_id + AND following_relationships.state = 'accept' + GROUP BY + users.id + ) AS sub + WHERE + users.id = sub.sub_id + AND users.local = TRUE + ; + """ + |> execute() + + """ + UPDATE + users + SET + following_count = 0 + WHERE + following_count IS NULL + """ + |> execute() + + execute("ALTER TABLE users + ALTER COLUMN following_count SET DEFAULT 0, + ALTER COLUMN following_count SET NOT NULL + ") + end + + def down do + execute("ALTER TABLE users + ALTER COLUMN following_count DROP DEFAULT, + ALTER COLUMN following_count DROP NOT NULL + ") + end +end diff --git a/priv/repo/migrations/20191203043610_create_report_notes.exs b/priv/repo/migrations/20191203043610_create_report_notes.exs new file mode 100644 index 000000000..a4f8c096d --- /dev/null +++ b/priv/repo/migrations/20191203043610_create_report_notes.exs @@ -0,0 +1,13 @@ +defmodule Pleroma.Repo.Migrations.CreateReportNotes do + use Ecto.Migration + + def change do + create_if_not_exists table(:report_notes) do + add(:user_id, references(:users, type: :uuid)) + add(:activity_id, references(:activities, type: :uuid)) + add(:content, :string) + + timestamps() + end + end +end diff --git a/priv/repo/migrations/20191220174645_add_scopes_to_pleroma_feo_auth_records.exs b/priv/repo/migrations/20191220174645_add_scopes_to_pleroma_feo_auth_records.exs new file mode 100644 index 000000000..6b160ad16 --- /dev/null +++ b/priv/repo/migrations/20191220174645_add_scopes_to_pleroma_feo_auth_records.exs @@ -0,0 +1,17 @@ +defmodule Pleroma.Repo.Migrations.AddScopesToPleromaFEOAuthRecords do + use Ecto.Migration + + def up do + update_scopes_clause = "SET scopes = '{read,write,follow,push,admin}'" + apps_where = "WHERE apps.client_name like 'PleromaFE_%' or apps.client_name like 'AdminFE_%'" + app_id_subquery_where = "WHERE app_id IN (SELECT apps.id FROM apps #{apps_where})" + + execute("UPDATE apps #{update_scopes_clause} #{apps_where}") + + for table <- ["oauth_authorizations", "oauth_tokens"] do + execute("UPDATE #{table} #{update_scopes_clause} #{app_id_subquery_where}") + end + end + + def down, do: :noop +end diff --git a/priv/repo/migrations/20200109123126_add_counter_cache_table.exs b/priv/repo/migrations/20200109123126_add_counter_cache_table.exs new file mode 100644 index 000000000..df9e21193 --- /dev/null +++ b/priv/repo/migrations/20200109123126_add_counter_cache_table.exs @@ -0,0 +1,55 @@ +defmodule Pleroma.Repo.Migrations.AddCounterCacheTable do + use Ecto.Migration + + def up do + 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 update_status_visibility_counter_cache() + 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 status_visibility_counter_cache_trigger BEFORE INSERT OR UPDATE of recipients, data OR DELETE ON activities + FOR EACH ROW + EXECUTE PROCEDURE update_status_visibility_counter_cache(); + """ + |> execute() + end + + def down do + execute("drop trigger if exists status_visibility_counter_cache_trigger on activities") + execute("drop function if exists update_status_visibility_counter_cache()") + drop_if_exists(unique_index(:counter_cache, [:name])) + drop_if_exists(table(:counter_cache)) + end +end diff --git a/priv/repo/migrations/20200227122417_add_trusted_to_apps.exs b/priv/repo/migrations/20200227122417_add_trusted_to_apps.exs new file mode 100644 index 000000000..4e2a62af0 --- /dev/null +++ b/priv/repo/migrations/20200227122417_add_trusted_to_apps.exs @@ -0,0 +1,9 @@ +defmodule Pleroma.Repo.Migrations.AddTrustedToApps do + use Ecto.Migration + + def change do + alter table(:apps) do + add(:trusted, :boolean, default: false) + end + end +end diff --git a/priv/repo/migrations/20200307103755_fix_moderation_log_subjects.exs b/priv/repo/migrations/20200307103755_fix_moderation_log_subjects.exs new file mode 100644 index 000000000..d1c8539e1 --- /dev/null +++ b/priv/repo/migrations/20200307103755_fix_moderation_log_subjects.exs @@ -0,0 +1,9 @@ +defmodule Pleroma.Repo.Migrations.FixModerationLogSubjects do + use Ecto.Migration + + def change do + execute( + "update moderation_log set data = safe_jsonb_set(data, '{subject}', safe_jsonb_set('[]'::jsonb, '{0}', data->'subject')) where jsonb_typeof(data->'subject') != 'array' and data->>'action' = ANY('{revoke,grant,activate,deactivate,delete}');" + ) + end +end diff --git a/priv/repo/migrations/20200314123607_config_remove_fetch_initial_posts.exs b/priv/repo/migrations/20200314123607_config_remove_fetch_initial_posts.exs new file mode 100644 index 000000000..392f531e8 --- /dev/null +++ b/priv/repo/migrations/20200314123607_config_remove_fetch_initial_posts.exs @@ -0,0 +1,10 @@ +defmodule Pleroma.Repo.Migrations.ConfigRemoveFetchInitialPosts do + use Ecto.Migration + + def change do + execute( + "delete from config where config.key = ':fetch_initial_posts' and config.group = ':pleroma';", + "" + ) + end +end diff --git a/priv/repo/migrations/20200315125756_delete_fetch_initial_posts_jobs.exs b/priv/repo/migrations/20200315125756_delete_fetch_initial_posts_jobs.exs new file mode 100644 index 000000000..5b8e3ab91 --- /dev/null +++ b/priv/repo/migrations/20200315125756_delete_fetch_initial_posts_jobs.exs @@ -0,0 +1,10 @@ +defmodule Pleroma.Repo.Migrations.DeleteFetchInitialPostsJobs do + use Ecto.Migration + + def change do + execute( + "delete from oban_jobs where worker = 'Pleroma.Workers.BackgroundWorker' and args->>'op' = 'fetch_initial_posts';", + "" + ) + end +end diff --git a/priv/repo/migrations/20200328124805_change_following_relationships_state_to_integer.exs b/priv/repo/migrations/20200328124805_change_following_relationships_state_to_integer.exs new file mode 100644 index 000000000..2b0820f3f --- /dev/null +++ b/priv/repo/migrations/20200328124805_change_following_relationships_state_to_integer.exs @@ -0,0 +1,29 @@ +defmodule Pleroma.Repo.Migrations.ChangeFollowingRelationshipsStateToInteger do + use Ecto.Migration + + @alter_following_relationship_state "ALTER TABLE following_relationships ALTER COLUMN state" + + def up do + execute(""" + #{@alter_following_relationship_state} TYPE integer USING + CASE + WHEN state = 'pending' THEN 1 + WHEN state = 'accept' THEN 2 + WHEN state = 'reject' THEN 3 + ELSE 0 + END; + """) + end + + def down do + execute(""" + #{@alter_following_relationship_state} TYPE varchar(255) USING + CASE + WHEN state = 1 THEN 'pending' + WHEN state = 2 THEN 'accept' + WHEN state = 3 THEN 'reject' + ELSE '' + END; + """) + end +end diff --git a/priv/repo/migrations/20200328130139_add_following_relationships_following_id_index.exs b/priv/repo/migrations/20200328130139_add_following_relationships_following_id_index.exs new file mode 100644 index 000000000..884832f84 --- /dev/null +++ b/priv/repo/migrations/20200328130139_add_following_relationships_following_id_index.exs @@ -0,0 +1,11 @@ +defmodule Pleroma.Repo.Migrations.AddFollowingRelationshipsFollowingIdIndex do + use Ecto.Migration + + # [:follower_index] index is useless because of [:follower_id, :following_id] index + # [:following_id] index makes sense because of user's followers-targeted queries + def change do + drop_if_exists(index(:following_relationships, [:follower_id])) + + create_if_not_exists(index(:following_relationships, [:following_id])) + end +end diff --git a/priv/repo/migrations/20200401030751_users_add_public_key.exs b/priv/repo/migrations/20200401030751_users_add_public_key.exs new file mode 100644 index 000000000..04e5ad1e2 --- /dev/null +++ b/priv/repo/migrations/20200401030751_users_add_public_key.exs @@ -0,0 +1,17 @@ +defmodule Pleroma.Repo.Migrations.UsersAddPublicKey do + use Ecto.Migration + + def up do + alter table(:users) do + add_if_not_exists(:public_key, :text) + end + + execute("UPDATE users SET public_key = source_data->'publicKey'->>'publicKeyPem'") + end + + def down do + alter table(:users) do + remove_if_exists(:public_key, :text) + end + end +end diff --git a/priv/repo/migrations/20200401072456_users_add_inboxes.exs b/priv/repo/migrations/20200401072456_users_add_inboxes.exs new file mode 100644 index 000000000..0947f0ab2 --- /dev/null +++ b/priv/repo/migrations/20200401072456_users_add_inboxes.exs @@ -0,0 +1,20 @@ +defmodule Pleroma.Repo.Migrations.UsersAddInboxes do + use Ecto.Migration + + def up do + alter table(:users) do + add_if_not_exists(:inbox, :text) + add_if_not_exists(:shared_inbox, :text) + end + + execute("UPDATE users SET inbox = source_data->>'inbox'") + execute("UPDATE users SET shared_inbox = source_data->'endpoints'->>'sharedInbox'") + end + + def down do + alter table(:users) do + remove_if_exists(:inbox, :text) + remove_if_exists(:shared_inbox, :text) + end + end +end diff --git a/priv/repo/migrations/20200402063221_update_oban_jobs_table.exs b/priv/repo/migrations/20200402063221_update_oban_jobs_table.exs new file mode 100644 index 000000000..e7ff04008 --- /dev/null +++ b/priv/repo/migrations/20200402063221_update_oban_jobs_table.exs @@ -0,0 +1,11 @@ +defmodule Pleroma.Repo.Migrations.UpdateObanJobsTable do + use Ecto.Migration + + def up do + Oban.Migrations.up(version: 8) + end + + def down do + Oban.Migrations.down(version: 7) + end +end diff --git a/priv/repo/migrations/20200406100225_users_add_emoji.exs b/priv/repo/migrations/20200406100225_users_add_emoji.exs new file mode 100644 index 000000000..f248108de --- /dev/null +++ b/priv/repo/migrations/20200406100225_users_add_emoji.exs @@ -0,0 +1,38 @@ +defmodule Pleroma.Repo.Migrations.UsersPopulateEmoji do + use Ecto.Migration + + import Ecto.Query + + alias Pleroma.User + alias Pleroma.Repo + + def up do + execute("ALTER TABLE users ALTER COLUMN emoji SET DEFAULT '{}'::jsonb") + execute("UPDATE users SET emoji = DEFAULT WHERE emoji = '[]'::jsonb") + + from(u in User) + |> select([u], struct(u, [:id, :ap_id, :source_data])) + |> Repo.stream() + |> Enum.each(fn user -> + emoji = + user.source_data + |> Map.get("tag", []) + |> Enum.filter(fn + %{"type" => "Emoji"} -> true + _ -> false + end) + |> Enum.reduce(%{}, fn %{"icon" => %{"url" => url}, "name" => name}, acc -> + Map.put(acc, String.trim(name, ":"), url) + end) + + user + |> Ecto.Changeset.cast(%{emoji: emoji}, [:emoji]) + |> Repo.update() + end) + end + + def down do + execute("ALTER TABLE users ALTER COLUMN emoji SET DEFAULT '[]'::jsonb") + execute("UPDATE users SET emoji = DEFAULT WHERE emoji = '{}'::jsonb") + end +end diff --git a/priv/repo/migrations/20200406105422_users_remove_source_data.exs b/priv/repo/migrations/20200406105422_users_remove_source_data.exs new file mode 100644 index 000000000..9812d480f --- /dev/null +++ b/priv/repo/migrations/20200406105422_users_remove_source_data.exs @@ -0,0 +1,15 @@ +defmodule Pleroma.Repo.Migrations.UsersRemoveSourceData do + use Ecto.Migration + + def up do + alter table(:users) do + remove_if_exists(:source_data, :map) + end + end + + def down do + alter table(:users) do + add_if_not_exists(:source_data, :map, default: %{}) + end + end +end diff --git a/priv/repo/migrations/20200415181818_update_markers.exs b/priv/repo/migrations/20200415181818_update_markers.exs new file mode 100644 index 000000000..bb9d8e860 --- /dev/null +++ b/priv/repo/migrations/20200415181818_update_markers.exs @@ -0,0 +1,44 @@ +defmodule Pleroma.Repo.Migrations.UpdateMarkers do + use Ecto.Migration + import Ecto.Query + alias Pleroma.Repo + + def up do + update_markers() + end + + def down do + :ok + end + + defp update_markers do + now = NaiveDateTime.utc_now() + + markers_attrs = + from(q in "notifications", + select: %{ + timeline: "notifications", + user_id: q.user_id, + last_read_id: + type(fragment("MAX( CASE WHEN seen = true THEN id ELSE null END )"), :string) + }, + group_by: [q.user_id] + ) + |> Repo.all() + |> Enum.map(fn %{last_read_id: last_read_id} = attrs -> + attrs + |> Map.put(:last_read_id, last_read_id || "") + |> Map.put_new(:inserted_at, now) + |> Map.put_new(:updated_at, now) + end) + + markers_attrs + |> Enum.chunk_every(1000) + |> Enum.each(fn markers_attrs_chunked -> + Repo.insert_all("markers", markers_attrs_chunked, + on_conflict: {:replace, [:last_read_id]}, + conflict_target: [:user_id, :timeline] + ) + end) + end +end diff --git a/priv/repo/migrations/20200428221338_insert_skeletons_for_deleted_users.exs b/priv/repo/migrations/20200428221338_insert_skeletons_for_deleted_users.exs new file mode 100644 index 000000000..2adc38186 --- /dev/null +++ b/priv/repo/migrations/20200428221338_insert_skeletons_for_deleted_users.exs @@ -0,0 +1,45 @@ +defmodule Pleroma.Repo.Migrations.InsertSkeletonsForDeletedUsers do + use Ecto.Migration + + alias Pleroma.User + alias Pleroma.Repo + + import Ecto.Query + + def change do + Application.ensure_all_started(:flake_id) + + local_ap_id = + User.Query.build(%{local: true}) + |> select([u], u.ap_id) + |> limit(1) + |> Repo.one() + + unless local_ap_id == nil do + # Hack to get instance base url because getting it from Phoenix + # would require starting the whole application + instance_uri = + local_ap_id + |> URI.parse() + |> Map.put(:query, nil) + |> Map.put(:path, nil) + |> URI.to_string() + + {:ok, %{rows: ap_ids}} = + Ecto.Adapters.SQL.query( + Repo, + "select distinct unnest(nonexistent_locals.recipients) from activities, lateral (select array_agg(recipient) as recipients from unnest(activities.recipients) as recipient where recipient similar to '#{ + instance_uri + }/users/[A-Za-z0-9]*' and not(recipient in (select ap_id from users))) nonexistent_locals;", + [], + timeout: :infinity + ) + + ap_ids + |> Enum.each(fn [ap_id] -> + Ecto.Changeset.change(%User{}, deactivated: true, ap_id: ap_id) + |> Repo.insert() + end) + end + end +end diff --git a/priv/repo/migrations/20200505072231_remove_magic_key_field.exs b/priv/repo/migrations/20200505072231_remove_magic_key_field.exs new file mode 100644 index 000000000..2635e671b --- /dev/null +++ b/priv/repo/migrations/20200505072231_remove_magic_key_field.exs @@ -0,0 +1,9 @@ +defmodule Pleroma.Repo.Migrations.RemoveMagicKeyField do + use Ecto.Migration + + def change do + alter table(:users) do + remove(:magic_key, :string) + end + end +end |