Merge branch 'conversations-import' into 'develop'
Conversations import Closes #871 See merge request pleroma/pleroma!1127
This commit is contained in:
commit
ad76307a82
|
@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- A [job queue](https://git.pleroma.social/pleroma/pleroma_job_queue) for federation, emails, web push, etc.
|
- A [job queue](https://git.pleroma.social/pleroma/pleroma_job_queue) for federation, emails, web push, etc.
|
||||||
- [Prometheus](https://prometheus.io/) metrics
|
- [Prometheus](https://prometheus.io/) metrics
|
||||||
- Support for Mastodon's remote interaction
|
- Support for Mastodon's remote interaction
|
||||||
|
- Mix Tasks: `mix pleroma.database bump_all_conversations`
|
||||||
- Mix Tasks: `mix pleroma.database remove_embedded_objects`
|
- Mix Tasks: `mix pleroma.database remove_embedded_objects`
|
||||||
- Mix Tasks: `mix pleroma.user toggle_confirmed`
|
- Mix Tasks: `mix pleroma.user toggle_confirmed`
|
||||||
- Federation: Support for reports
|
- Federation: Support for reports
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
defmodule Mix.Tasks.Pleroma.Database do
|
defmodule Mix.Tasks.Pleroma.Database do
|
||||||
alias Mix.Tasks.Pleroma.Common
|
alias Mix.Tasks.Pleroma.Common
|
||||||
|
alias Pleroma.Conversation
|
||||||
require Logger
|
require Logger
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
|
|
||||||
|
@ -19,6 +20,11 @@ defmodule Mix.Tasks.Pleroma.Database do
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
- `--vacuum` - run `VACUUM FULL` after the embedded objects are replaced with their references
|
- `--vacuum` - run `VACUUM FULL` after the embedded objects are replaced with their references
|
||||||
|
|
||||||
|
## Create a conversation for all existing DMs. Can be safely re-run.
|
||||||
|
|
||||||
|
mix pleroma.database bump_all_conversations
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def run(["remove_embedded_objects" | args]) do
|
def run(["remove_embedded_objects" | args]) do
|
||||||
{options, [], []} =
|
{options, [], []} =
|
||||||
|
@ -48,4 +54,9 @@ def run(["remove_embedded_objects" | args]) do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def run(["bump_all_conversations"]) do
|
||||||
|
Common.start_pleroma()
|
||||||
|
Conversation.bump_for_all_activities()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -45,7 +45,7 @@ def get_for_ap_id(ap_id) do
|
||||||
2. Create a participation for all the people involved who don't have one already
|
2. Create a participation for all the people involved who don't have one already
|
||||||
3. Bump all relevant participations to 'unread'
|
3. Bump all relevant participations to 'unread'
|
||||||
"""
|
"""
|
||||||
def create_or_bump_for(activity) do
|
def create_or_bump_for(activity, opts \\ []) do
|
||||||
with true <- Pleroma.Web.ActivityPub.Visibility.is_direct?(activity),
|
with true <- Pleroma.Web.ActivityPub.Visibility.is_direct?(activity),
|
||||||
"Create" <- activity.data["type"],
|
"Create" <- activity.data["type"],
|
||||||
object <- Pleroma.Object.normalize(activity),
|
object <- Pleroma.Object.normalize(activity),
|
||||||
|
@ -58,7 +58,7 @@ def create_or_bump_for(activity) do
|
||||||
participations =
|
participations =
|
||||||
Enum.map(users, fn user ->
|
Enum.map(users, fn user ->
|
||||||
{:ok, participation} =
|
{:ok, participation} =
|
||||||
Participation.create_for_user_and_conversation(user, conversation)
|
Participation.create_for_user_and_conversation(user, conversation, opts)
|
||||||
|
|
||||||
participation
|
participation
|
||||||
end)
|
end)
|
||||||
|
@ -72,4 +72,21 @@ def create_or_bump_for(activity) do
|
||||||
e -> {:error, e}
|
e -> {:error, e}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
This is only meant to be run by a mix task. It creates conversations/participations for all direct messages in the database.
|
||||||
|
"""
|
||||||
|
def bump_for_all_activities do
|
||||||
|
stream =
|
||||||
|
Pleroma.Web.ActivityPub.ActivityPub.fetch_direct_messages_query()
|
||||||
|
|> Repo.stream()
|
||||||
|
|
||||||
|
Repo.transaction(
|
||||||
|
fn ->
|
||||||
|
stream
|
||||||
|
|> Enum.each(fn a -> create_or_bump_for(a, read: true) end)
|
||||||
|
end,
|
||||||
|
timeout: :infinity
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,15 +22,17 @@ defmodule Pleroma.Conversation.Participation do
|
||||||
|
|
||||||
def creation_cng(struct, params) do
|
def creation_cng(struct, params) do
|
||||||
struct
|
struct
|
||||||
|> cast(params, [:user_id, :conversation_id])
|
|> cast(params, [:user_id, :conversation_id, :read])
|
||||||
|> validate_required([:user_id, :conversation_id])
|
|> validate_required([:user_id, :conversation_id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_for_user_and_conversation(user, conversation) do
|
def create_for_user_and_conversation(user, conversation, opts \\ []) do
|
||||||
|
read = !!opts[:read]
|
||||||
|
|
||||||
%__MODULE__{}
|
%__MODULE__{}
|
||||||
|> creation_cng(%{user_id: user.id, conversation_id: conversation.id})
|
|> creation_cng(%{user_id: user.id, conversation_id: conversation.id, read: read})
|
||||||
|> Repo.insert(
|
|> Repo.insert(
|
||||||
on_conflict: [set: [read: false, updated_at: NaiveDateTime.utc_now()]],
|
on_conflict: [set: [read: read, updated_at: NaiveDateTime.utc_now()]],
|
||||||
returning: true,
|
returning: true,
|
||||||
conflict_target: [:user_id, :conversation_id]
|
conflict_target: [:user_id, :conversation_id]
|
||||||
)
|
)
|
||||||
|
|
|
@ -974,4 +974,11 @@ def contain_broken_threads(%Activity{} = activity, %User{} = user) do
|
||||||
def contain_activity(%Activity{} = activity, %User{} = user) do
|
def contain_activity(%Activity{} = activity, %User{} = user) do
|
||||||
contain_broken_threads(activity, user)
|
contain_broken_threads(activity, user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def fetch_direct_messages_query do
|
||||||
|
Activity
|
||||||
|
|> restrict_type(%{"type" => "Create"})
|
||||||
|
|> restrict_visibility(%{visibility: "direct"})
|
||||||
|
|> order_by([activity], asc: activity.id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,11 +14,12 @@ def is_public?(data) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_private?(activity) do
|
def is_private?(activity) do
|
||||||
unless is_public?(activity) do
|
with false <- is_public?(activity),
|
||||||
follower_address = User.get_cached_by_ap_id(activity.data["actor"]).follower_address
|
%User{follower_address: follower_address} <-
|
||||||
Enum.any?(activity.data["to"], &(&1 == follower_address))
|
User.get_cached_by_ap_id(activity.data["actor"]) do
|
||||||
|
follower_address in activity.data["to"]
|
||||||
else
|
else
|
||||||
false
|
_ -> false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,26 @@ defmodule Pleroma.ConversationTest do
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
test "it goes through old direct conversations" do
|
||||||
|
user = insert(:user)
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, _activity} =
|
||||||
|
CommonAPI.post(user, %{"visibility" => "direct", "status" => "hey @#{other_user.nickname}"})
|
||||||
|
|
||||||
|
Repo.delete_all(Conversation)
|
||||||
|
Repo.delete_all(Conversation.Participation)
|
||||||
|
|
||||||
|
refute Repo.one(Conversation)
|
||||||
|
|
||||||
|
Conversation.bump_for_all_activities()
|
||||||
|
|
||||||
|
assert Repo.one(Conversation)
|
||||||
|
[participation, _p2] = Repo.all(Conversation.Participation)
|
||||||
|
|
||||||
|
assert participation.read
|
||||||
|
end
|
||||||
|
|
||||||
test "it creates a conversation for given ap_id" do
|
test "it creates a conversation for given ap_id" do
|
||||||
assert {:ok, %Conversation{} = conversation} =
|
assert {:ok, %Conversation{} = conversation} =
|
||||||
Conversation.create_for_ap_id("https://some_ap_id")
|
Conversation.create_for_ap_id("https://some_ap_id")
|
||||||
|
|
|
@ -96,6 +96,16 @@ test "visible_for_user?", %{
|
||||||
refute Visibility.visible_for_user?(direct, unrelated)
|
refute Visibility.visible_for_user?(direct, unrelated)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "doesn't die when the user doesn't exist",
|
||||||
|
%{
|
||||||
|
direct: direct,
|
||||||
|
user: user
|
||||||
|
} do
|
||||||
|
Repo.delete(user)
|
||||||
|
Cachex.clear(:user_cache)
|
||||||
|
refute Visibility.is_private?(direct)
|
||||||
|
end
|
||||||
|
|
||||||
test "get_visibility", %{
|
test "get_visibility", %{
|
||||||
public: public,
|
public: public,
|
||||||
private: private,
|
private: private,
|
||||||
|
|
Loading…
Reference in New Issue