Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

150 lines
5.8KB

  1. defmodule Pleroma.Repo.Migrations.CreateFollowingRelationships do
  2. use Ecto.Migration
  3. def change do
  4. create_if_not_exists table(:following_relationships) do
  5. add(:follower_id, references(:users, type: :uuid, on_delete: :delete_all), null: false)
  6. add(:following_id, references(:users, type: :uuid, on_delete: :delete_all), null: false)
  7. add(:state, :string, null: false)
  8. timestamps()
  9. end
  10. create_if_not_exists(index(:following_relationships, :follower_id))
  11. create_if_not_exists(unique_index(:following_relationships, [:follower_id, :following_id]))
  12. execute(update_thread_visibility(), restore_thread_visibility())
  13. end
  14. # The only difference between the original version: `actor_user` replaced with `actor_user_following`
  15. def update_thread_visibility do
  16. """
  17. CREATE OR REPLACE FUNCTION thread_visibility(actor varchar, activity_id varchar) RETURNS boolean AS $$
  18. DECLARE
  19. public varchar := 'https://www.w3.org/ns/activitystreams#Public';
  20. child objects%ROWTYPE;
  21. activity activities%ROWTYPE;
  22. author_fa varchar;
  23. valid_recipients varchar[];
  24. actor_user_following varchar[];
  25. BEGIN
  26. --- Fetch actor following
  27. SELECT array_agg(following.follower_address) INTO actor_user_following FROM following_relationships
  28. JOIN users ON users.id = following_relationships.follower_id
  29. JOIN users AS following ON following.id = following_relationships.following_id
  30. WHERE users.ap_id = actor;
  31. --- Fetch our initial activity.
  32. SELECT * INTO activity FROM activities WHERE activities.data->>'id' = activity_id;
  33. LOOP
  34. --- Ensure that we have an activity before continuing.
  35. --- If we don't, the thread is not satisfiable.
  36. IF activity IS NULL THEN
  37. RETURN false;
  38. END IF;
  39. --- We only care about Create activities.
  40. IF activity.data->>'type' != 'Create' THEN
  41. RETURN true;
  42. END IF;
  43. --- Normalize the child object into child.
  44. SELECT * INTO child FROM objects
  45. INNER JOIN activities ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id'
  46. WHERE COALESCE(activity.data->'object'->>'id', activity.data->>'object') = objects.data->>'id';
  47. --- Fetch the author's AS2 following collection.
  48. SELECT COALESCE(users.follower_address, '') INTO author_fa FROM users WHERE users.ap_id = activity.actor;
  49. --- Prepare valid recipients array.
  50. valid_recipients := ARRAY[actor, public];
  51. IF ARRAY[author_fa] && actor_user_following THEN
  52. valid_recipients := valid_recipients || author_fa;
  53. END IF;
  54. --- Check visibility.
  55. IF NOT valid_recipients && activity.recipients THEN
  56. --- activity not visible, break out of the loop
  57. RETURN false;
  58. END IF;
  59. --- If there's a parent, load it and do this all over again.
  60. IF (child.data->'inReplyTo' IS NOT NULL) AND (child.data->'inReplyTo' != 'null'::jsonb) THEN
  61. SELECT * INTO activity FROM activities
  62. INNER JOIN objects ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id'
  63. WHERE child.data->>'inReplyTo' = objects.data->>'id';
  64. ELSE
  65. RETURN true;
  66. END IF;
  67. END LOOP;
  68. END;
  69. $$ LANGUAGE plpgsql IMMUTABLE;
  70. """
  71. end
  72. # priv/repo/migrations/20190515222404_add_thread_visibility_function.exs
  73. def restore_thread_visibility do
  74. """
  75. CREATE OR REPLACE FUNCTION thread_visibility(actor varchar, activity_id varchar) RETURNS boolean AS $$
  76. DECLARE
  77. public varchar := 'https://www.w3.org/ns/activitystreams#Public';
  78. child objects%ROWTYPE;
  79. activity activities%ROWTYPE;
  80. actor_user users%ROWTYPE;
  81. author_fa varchar;
  82. valid_recipients varchar[];
  83. BEGIN
  84. --- Fetch our actor.
  85. SELECT * INTO actor_user FROM users WHERE users.ap_id = actor;
  86. --- Fetch our initial activity.
  87. SELECT * INTO activity FROM activities WHERE activities.data->>'id' = activity_id;
  88. LOOP
  89. --- Ensure that we have an activity before continuing.
  90. --- If we don't, the thread is not satisfiable.
  91. IF activity IS NULL THEN
  92. RETURN false;
  93. END IF;
  94. --- We only care about Create activities.
  95. IF activity.data->>'type' != 'Create' THEN
  96. RETURN true;
  97. END IF;
  98. --- Normalize the child object into child.
  99. SELECT * INTO child FROM objects
  100. INNER JOIN activities ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id'
  101. WHERE COALESCE(activity.data->'object'->>'id', activity.data->>'object') = objects.data->>'id';
  102. --- Fetch the author's AS2 following collection.
  103. SELECT COALESCE(users.follower_address, '') INTO author_fa FROM users WHERE users.ap_id = activity.actor;
  104. --- Prepare valid recipients array.
  105. valid_recipients := ARRAY[actor, public];
  106. IF ARRAY[author_fa] && actor_user.following THEN
  107. valid_recipients := valid_recipients || author_fa;
  108. END IF;
  109. --- Check visibility.
  110. IF NOT valid_recipients && activity.recipients THEN
  111. --- activity not visible, break out of the loop
  112. RETURN false;
  113. END IF;
  114. --- If there's a parent, load it and do this all over again.
  115. IF (child.data->'inReplyTo' IS NOT NULL) AND (child.data->'inReplyTo' != 'null'::jsonb) THEN
  116. SELECT * INTO activity FROM activities
  117. INNER JOIN objects ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id'
  118. WHERE child.data->>'inReplyTo' = objects.data->>'id';
  119. ELSE
  120. RETURN true;
  121. END IF;
  122. END LOOP;
  123. END;
  124. $$ LANGUAGE plpgsql IMMUTABLE;
  125. """
  126. end
  127. end