Merge branch 'develop' into 'fix/reverse-proxy-body-too-large'
# Conflicts: # CHANGELOG.md
This commit is contained in:
commit
d2c9befc64
92 changed files with 1358 additions and 751 deletions
|
|
@ -96,6 +96,7 @@ defmodule Pleroma.Activity do
|
|||
from([a] in query,
|
||||
left_join: tm in ThreadMute,
|
||||
on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data),
|
||||
as: :thread_mute,
|
||||
select: %Activity{a | thread_muted?: not is_nil(tm.id)}
|
||||
)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,11 +3,14 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Application do
|
||||
import Cachex.Spec
|
||||
use Application
|
||||
|
||||
@name Mix.Project.config()[:name]
|
||||
@version Mix.Project.config()[:version]
|
||||
@repository Mix.Project.config()[:source_url]
|
||||
@env Mix.env()
|
||||
|
||||
def name, do: @name
|
||||
def version, do: @version
|
||||
def named_version, do: @name <> " " <> @version
|
||||
|
|
@ -21,116 +24,24 @@ defmodule Pleroma.Application do
|
|||
# See http://elixir-lang.org/docs/stable/elixir/Application.html
|
||||
# for more information on OTP Applications
|
||||
def start(_type, _args) do
|
||||
import Cachex.Spec
|
||||
|
||||
Pleroma.Config.DeprecationWarnings.warn()
|
||||
setup_instrumenters()
|
||||
|
||||
# Define workers and child supervisors to be supervised
|
||||
children =
|
||||
[
|
||||
# Start the Ecto repository
|
||||
%{id: Pleroma.Repo, start: {Pleroma.Repo, :start_link, []}, type: :supervisor},
|
||||
%{id: Pleroma.Config.TransferTask, start: {Pleroma.Config.TransferTask, :start_link, []}},
|
||||
%{id: Pleroma.Emoji, start: {Pleroma.Emoji, :start_link, []}},
|
||||
%{id: Pleroma.Captcha, start: {Pleroma.Captcha, :start_link, []}},
|
||||
%{
|
||||
id: :cachex_used_captcha_cache,
|
||||
start:
|
||||
{Cachex, :start_link,
|
||||
[
|
||||
:used_captcha_cache,
|
||||
[
|
||||
ttl_interval:
|
||||
:timer.seconds(Pleroma.Config.get!([Pleroma.Captcha, :seconds_valid]))
|
||||
]
|
||||
]}
|
||||
},
|
||||
%{
|
||||
id: :cachex_user,
|
||||
start:
|
||||
{Cachex, :start_link,
|
||||
[
|
||||
:user_cache,
|
||||
[
|
||||
default_ttl: 25_000,
|
||||
ttl_interval: 1000,
|
||||
limit: 2500
|
||||
]
|
||||
]}
|
||||
},
|
||||
%{
|
||||
id: :cachex_object,
|
||||
start:
|
||||
{Cachex, :start_link,
|
||||
[
|
||||
:object_cache,
|
||||
[
|
||||
default_ttl: 25_000,
|
||||
ttl_interval: 1000,
|
||||
limit: 2500
|
||||
]
|
||||
]}
|
||||
},
|
||||
%{
|
||||
id: :cachex_rich_media,
|
||||
start:
|
||||
{Cachex, :start_link,
|
||||
[
|
||||
:rich_media_cache,
|
||||
[
|
||||
default_ttl: :timer.minutes(120),
|
||||
limit: 5000
|
||||
]
|
||||
]}
|
||||
},
|
||||
%{
|
||||
id: :cachex_scrubber,
|
||||
start:
|
||||
{Cachex, :start_link,
|
||||
[
|
||||
:scrubber_cache,
|
||||
[
|
||||
limit: 2500
|
||||
]
|
||||
]}
|
||||
},
|
||||
%{
|
||||
id: :cachex_idem,
|
||||
start:
|
||||
{Cachex, :start_link,
|
||||
[
|
||||
:idempotency_cache,
|
||||
[
|
||||
expiration:
|
||||
expiration(
|
||||
default: :timer.seconds(6 * 60 * 60),
|
||||
interval: :timer.seconds(60)
|
||||
),
|
||||
limit: 2500
|
||||
]
|
||||
]}
|
||||
},
|
||||
%{id: Pleroma.FlakeId, start: {Pleroma.FlakeId, :start_link, []}},
|
||||
%{
|
||||
id: Pleroma.ScheduledActivityWorker,
|
||||
start: {Pleroma.ScheduledActivityWorker, :start_link, []}
|
||||
}
|
||||
Pleroma.Repo,
|
||||
Pleroma.Config.TransferTask,
|
||||
Pleroma.Emoji,
|
||||
Pleroma.Captcha,
|
||||
Pleroma.FlakeId,
|
||||
Pleroma.ScheduledActivityWorker
|
||||
] ++
|
||||
cachex_children() ++
|
||||
hackney_pool_children() ++
|
||||
[
|
||||
%{
|
||||
id: Pleroma.Web.Federator.RetryQueue,
|
||||
start: {Pleroma.Web.Federator.RetryQueue, :start_link, []}
|
||||
},
|
||||
%{
|
||||
id: Pleroma.Web.OAuth.Token.CleanWorker,
|
||||
start: {Pleroma.Web.OAuth.Token.CleanWorker, :start_link, []}
|
||||
},
|
||||
%{
|
||||
id: Pleroma.Stats,
|
||||
start: {Pleroma.Stats, :start_link, []}
|
||||
},
|
||||
Pleroma.Web.Federator.RetryQueue,
|
||||
Pleroma.Stats,
|
||||
%{
|
||||
id: :web_push_init,
|
||||
start: {Task, :start_link, [&Pleroma.Web.Push.init/0]},
|
||||
|
|
@ -147,16 +58,12 @@ defmodule Pleroma.Application do
|
|||
restart: :temporary
|
||||
}
|
||||
] ++
|
||||
streamer_child() ++
|
||||
chat_child() ++
|
||||
oauth_cleanup_child(oauth_cleanup_enabled?()) ++
|
||||
streamer_child(@env) ++
|
||||
chat_child(@env, chat_enabled?()) ++
|
||||
[
|
||||
# Start the endpoint when the application starts
|
||||
%{
|
||||
id: Pleroma.Web.Endpoint,
|
||||
start: {Pleroma.Web.Endpoint, :start_link, []},
|
||||
type: :supervisor
|
||||
},
|
||||
%{id: Pleroma.Gopher.Server, start: {Pleroma.Gopher.Server, :start_link, []}}
|
||||
Pleroma.Web.Endpoint,
|
||||
Pleroma.Gopher.Server
|
||||
]
|
||||
|
||||
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
|
||||
|
|
@ -201,28 +108,54 @@ defmodule Pleroma.Application do
|
|||
end
|
||||
end
|
||||
|
||||
if Pleroma.Config.get(:env) == :test do
|
||||
defp streamer_child, do: []
|
||||
defp chat_child, do: []
|
||||
else
|
||||
defp streamer_child do
|
||||
[%{id: Pleroma.Web.Streamer, start: {Pleroma.Web.Streamer, :start_link, []}}]
|
||||
end
|
||||
|
||||
defp chat_child do
|
||||
if Pleroma.Config.get([:chat, :enabled]) do
|
||||
[
|
||||
%{
|
||||
id: Pleroma.Web.ChatChannel.ChatChannelState,
|
||||
start: {Pleroma.Web.ChatChannel.ChatChannelState, :start_link, []}
|
||||
}
|
||||
]
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
defp cachex_children do
|
||||
[
|
||||
build_cachex("used_captcha", ttl_interval: seconds_valid_interval()),
|
||||
build_cachex("user", default_ttl: 25_000, ttl_interval: 1000, limit: 2500),
|
||||
build_cachex("object", default_ttl: 25_000, ttl_interval: 1000, limit: 2500),
|
||||
build_cachex("rich_media", default_ttl: :timer.minutes(120), limit: 5000),
|
||||
build_cachex("scrubber", limit: 2500),
|
||||
build_cachex("idempotency", expiration: idempotency_expiration(), limit: 2500)
|
||||
]
|
||||
end
|
||||
|
||||
defp idempotency_expiration,
|
||||
do: expiration(default: :timer.seconds(6 * 60 * 60), interval: :timer.seconds(60))
|
||||
|
||||
defp seconds_valid_interval,
|
||||
do: :timer.seconds(Pleroma.Config.get!([Pleroma.Captcha, :seconds_valid]))
|
||||
|
||||
defp build_cachex(type, opts),
|
||||
do: %{
|
||||
id: String.to_atom("cachex_" <> type),
|
||||
start: {Cachex, :start_link, [String.to_atom(type <> "_cache"), opts]},
|
||||
type: :worker
|
||||
}
|
||||
|
||||
defp chat_enabled?, do: Pleroma.Config.get([:chat, :enabled])
|
||||
|
||||
defp oauth_cleanup_enabled?,
|
||||
do: Pleroma.Config.get([:oauth2, :clean_expired_tokens], false)
|
||||
|
||||
defp streamer_child(:test), do: []
|
||||
|
||||
defp streamer_child(_) do
|
||||
[Pleroma.Web.Streamer]
|
||||
end
|
||||
|
||||
defp oauth_cleanup_child(true),
|
||||
do: [Pleroma.Web.OAuth.Token.CleanWorker]
|
||||
|
||||
defp oauth_cleanup_child(_), do: []
|
||||
|
||||
defp chat_child(:test, _), do: []
|
||||
|
||||
defp chat_child(_env, true) do
|
||||
[Pleroma.Web.ChatChannel.ChatChannelState]
|
||||
end
|
||||
|
||||
defp chat_child(_, _), do: []
|
||||
|
||||
defp hackney_pool_children do
|
||||
for pool <- enabled_hackney_pools() do
|
||||
options = Pleroma.Config.get([:hackney_pools, pool])
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ defmodule Pleroma.Captcha do
|
|||
use GenServer
|
||||
|
||||
@doc false
|
||||
def start_link do
|
||||
def start_link(_) do
|
||||
GenServer.start_link(__MODULE__, [], name: __MODULE__)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ defmodule Pleroma.Config.TransferTask do
|
|||
use Task
|
||||
alias Pleroma.Web.AdminAPI.Config
|
||||
|
||||
def start_link do
|
||||
def start_link(_) do
|
||||
load_and_update_env()
|
||||
if Pleroma.Config.get(:env) == :test, do: Ecto.Adapters.SQL.Sandbox.checkin(Pleroma.Repo)
|
||||
:ignore
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
defmodule Pleroma.Conversation do
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.Conversation.Participation.RecipientShip
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
use Ecto.Schema
|
||||
|
|
@ -39,6 +40,15 @@ defmodule Pleroma.Conversation do
|
|||
Repo.get_by(__MODULE__, ap_id: ap_id)
|
||||
end
|
||||
|
||||
def maybe_create_recipientships(participation, activity) do
|
||||
participation = Repo.preload(participation, :recipients)
|
||||
|
||||
if participation.recipients |> Enum.empty?() do
|
||||
recipients = User.get_all_by_ap_id(activity.recipients)
|
||||
RecipientShip.create(recipients, participation)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
This will
|
||||
1. Create a conversation if there isn't one already
|
||||
|
|
@ -60,6 +70,7 @@ defmodule Pleroma.Conversation do
|
|||
{:ok, participation} =
|
||||
Participation.create_for_user_and_conversation(user, conversation, opts)
|
||||
|
||||
maybe_create_recipientships(participation, activity)
|
||||
participation
|
||||
end)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
defmodule Pleroma.Conversation.Participation do
|
||||
use Ecto.Schema
|
||||
alias Pleroma.Conversation
|
||||
alias Pleroma.Conversation.Participation.RecipientShip
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
|
|
@ -17,6 +18,9 @@ defmodule Pleroma.Conversation.Participation do
|
|||
field(:read, :boolean, default: false)
|
||||
field(:last_activity_id, Pleroma.FlakeId, virtual: true)
|
||||
|
||||
has_many(:recipient_ships, RecipientShip)
|
||||
has_many(:recipients, through: [:recipient_ships, :user])
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
|
|
@ -65,6 +69,14 @@ defmodule Pleroma.Conversation.Participation do
|
|||
|> Pleroma.Pagination.fetch_paginated(params)
|
||||
end
|
||||
|
||||
def for_user_and_conversation(user, conversation) do
|
||||
from(p in __MODULE__,
|
||||
where: p.user_id == ^user.id,
|
||||
where: p.conversation_id == ^conversation.id
|
||||
)
|
||||
|> Repo.one()
|
||||
end
|
||||
|
||||
def for_user_with_last_activity_id(user, params \\ %{}) do
|
||||
for_user(user, params)
|
||||
|> Enum.map(fn participation ->
|
||||
|
|
@ -81,4 +93,46 @@ defmodule Pleroma.Conversation.Participation do
|
|||
end)
|
||||
|> Enum.filter(& &1.last_activity_id)
|
||||
end
|
||||
|
||||
def get(_, _ \\ [])
|
||||
def get(nil, _), do: nil
|
||||
|
||||
def get(id, params) do
|
||||
query =
|
||||
if preload = params[:preload] do
|
||||
from(p in __MODULE__,
|
||||
preload: ^preload
|
||||
)
|
||||
else
|
||||
__MODULE__
|
||||
end
|
||||
|
||||
Repo.get(query, id)
|
||||
end
|
||||
|
||||
def set_recipients(participation, user_ids) do
|
||||
user_ids =
|
||||
[participation.user_id | user_ids]
|
||||
|> Enum.uniq()
|
||||
|
||||
Repo.transaction(fn ->
|
||||
query =
|
||||
from(r in RecipientShip,
|
||||
where: r.participation_id == ^participation.id
|
||||
)
|
||||
|
||||
Repo.delete_all(query)
|
||||
|
||||
users =
|
||||
from(u in User,
|
||||
where: u.id in ^user_ids
|
||||
)
|
||||
|> Repo.all()
|
||||
|
||||
RecipientShip.create(users, participation)
|
||||
:ok
|
||||
end)
|
||||
|
||||
{:ok, Repo.preload(participation, :recipients, force: true)}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
34
lib/pleroma/conversation/participation_recipient_ship.ex
Normal file
34
lib/pleroma/conversation/participation_recipient_ship.ex
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Conversation.Participation.RecipientShip do
|
||||
use Ecto.Schema
|
||||
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
|
||||
import Ecto.Changeset
|
||||
|
||||
schema "conversation_participation_recipient_ships" do
|
||||
belongs_to(:user, User, type: Pleroma.FlakeId)
|
||||
belongs_to(:participation, Participation)
|
||||
end
|
||||
|
||||
def creation_cng(struct, params) do
|
||||
struct
|
||||
|> cast(params, [:user_id, :participation_id])
|
||||
|> validate_required([:user_id, :participation_id])
|
||||
end
|
||||
|
||||
def create(%User{} = user, participation), do: create([user], participation)
|
||||
|
||||
def create(users, participation) do
|
||||
Enum.each(users, fn user ->
|
||||
%__MODULE__{}
|
||||
|> creation_cng(%{user_id: user.id, participation_id: participation.id})
|
||||
|> Repo.insert!()
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.DigestEmailWorker do
|
||||
import Ecto.Query
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ defmodule Pleroma.Emoji do
|
|||
@ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}]
|
||||
|
||||
@doc false
|
||||
def start_link do
|
||||
def start_link(_) do
|
||||
GenServer.start_link(__MODULE__, [], name: __MODULE__)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ defmodule Pleroma.FlakeId do
|
|||
def autogenerate, do: get()
|
||||
|
||||
# -- GenServer API
|
||||
def start_link do
|
||||
def start_link(_) do
|
||||
:gen_server.start_link({:local, :flake}, __MODULE__, [], [])
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ defmodule Pleroma.Gopher.Server do
|
|||
use GenServer
|
||||
require Logger
|
||||
|
||||
def start_link do
|
||||
def start_link(_) do
|
||||
config = Pleroma.Config.get(:gopher, [])
|
||||
ip = Keyword.get(config, :ip, {0, 0, 0, 0})
|
||||
port = Keyword.get(config, :port, 1234)
|
||||
|
|
|
|||
|
|
@ -203,6 +203,8 @@ defmodule Pleroma.HTML.Scrubber.Default do
|
|||
Meta.allow_tag_with_these_attributes("p", [])
|
||||
Meta.allow_tag_with_these_attributes("pre", [])
|
||||
Meta.allow_tag_with_these_attributes("strong", [])
|
||||
Meta.allow_tag_with_these_attributes("sub", [])
|
||||
Meta.allow_tag_with_these_attributes("sup", [])
|
||||
Meta.allow_tag_with_these_attributes("u", [])
|
||||
Meta.allow_tag_with_these_attributes("ul", [])
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ defmodule Pleroma.ScheduledActivityWorker do
|
|||
|
||||
@schedule_interval :timer.minutes(1)
|
||||
|
||||
def start_link do
|
||||
def start_link(_) do
|
||||
GenServer.start_link(__MODULE__, nil)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -7,31 +7,56 @@ defmodule Pleroma.Stats do
|
|||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
|
||||
def start_link do
|
||||
agent = Agent.start_link(fn -> {[], %{}} end, name: __MODULE__)
|
||||
spawn(fn -> schedule_update() end)
|
||||
agent
|
||||
use GenServer
|
||||
|
||||
@interval 1000 * 60 * 60
|
||||
|
||||
def start_link(_) do
|
||||
GenServer.start_link(__MODULE__, initial_data(), name: __MODULE__)
|
||||
end
|
||||
|
||||
def force_update do
|
||||
GenServer.call(__MODULE__, :force_update)
|
||||
end
|
||||
|
||||
def get_stats do
|
||||
Agent.get(__MODULE__, fn {_, stats} -> stats end)
|
||||
%{stats: stats} = GenServer.call(__MODULE__, :get_state)
|
||||
|
||||
stats
|
||||
end
|
||||
|
||||
def get_peers do
|
||||
Agent.get(__MODULE__, fn {peers, _} -> peers end)
|
||||
%{peers: peers} = GenServer.call(__MODULE__, :get_state)
|
||||
|
||||
peers
|
||||
end
|
||||
|
||||
def schedule_update do
|
||||
spawn(fn ->
|
||||
# 1 hour
|
||||
Process.sleep(1000 * 60 * 60)
|
||||
schedule_update()
|
||||
end)
|
||||
|
||||
update_stats()
|
||||
def init(args) do
|
||||
Process.send(self(), :run_update, [])
|
||||
{:ok, args}
|
||||
end
|
||||
|
||||
def update_stats do
|
||||
def handle_call(:force_update, _from, _state) do
|
||||
new_stats = get_stat_data()
|
||||
{:reply, new_stats, new_stats}
|
||||
end
|
||||
|
||||
def handle_call(:get_state, _from, state) do
|
||||
{:reply, state, state}
|
||||
end
|
||||
|
||||
def handle_info(:run_update, _state) do
|
||||
new_stats = get_stat_data()
|
||||
|
||||
Process.send_after(self(), :run_update, @interval)
|
||||
{:noreply, new_stats}
|
||||
end
|
||||
|
||||
defp initial_data do
|
||||
%{peers: [], stats: %{}}
|
||||
end
|
||||
|
||||
defp get_stat_data do
|
||||
peers =
|
||||
from(
|
||||
u in User,
|
||||
|
|
@ -52,8 +77,9 @@ defmodule Pleroma.Stats do
|
|||
|
||||
user_count = Repo.aggregate(User.Query.build(%{local: true, active: true}), :count, :id)
|
||||
|
||||
Agent.update(__MODULE__, fn _ ->
|
||||
{peers, %{domain_count: domain_count, status_count: status_count, user_count: user_count}}
|
||||
end)
|
||||
%{
|
||||
peers: peers,
|
||||
stats: %{domain_count: domain_count, status_count: status_count, user_count: user_count}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ defmodule Pleroma.User do
|
|||
alias Pleroma.Web
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.CommonAPI.Utils, as: CommonUtils
|
||||
alias Pleroma.Web.OAuth
|
||||
alias Pleroma.Web.OStatus
|
||||
|
|
@ -132,6 +133,28 @@ defmodule Pleroma.User do
|
|||
|> Map.put(:follower_count, follower_count)
|
||||
end
|
||||
|
||||
def follow_state(%User{} = user, %User{} = target) do
|
||||
follow_activity = Utils.fetch_latest_follow(user, target)
|
||||
|
||||
if follow_activity,
|
||||
do: follow_activity.data["state"],
|
||||
# Ideally this would be nil, but then Cachex does not commit the value
|
||||
else: false
|
||||
end
|
||||
|
||||
def get_cached_follow_state(user, target) do
|
||||
key = "follow_state:#{user.ap_id}|#{target.ap_id}"
|
||||
Cachex.fetch!(:user_cache, key, fn _ -> {:commit, follow_state(user, target)} end)
|
||||
end
|
||||
|
||||
def set_follow_state_cache(user_ap_id, target_ap_id, state) do
|
||||
Cachex.put(
|
||||
:user_cache,
|
||||
"follow_state:#{user_ap_id}|#{target_ap_id}",
|
||||
state
|
||||
)
|
||||
end
|
||||
|
||||
def set_info_cache(user, args) do
|
||||
Cachex.put(:user_cache, "user_info:#{user.id}", user_info(user, args))
|
||||
end
|
||||
|
|
@ -463,6 +486,13 @@ defmodule Pleroma.User do
|
|||
Repo.get_by(User, ap_id: ap_id)
|
||||
end
|
||||
|
||||
def get_all_by_ap_id(ap_ids) do
|
||||
from(u in __MODULE__,
|
||||
where: u.ap_id in ^ap_ids
|
||||
)
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
# This is mostly an SPC migration fix. This guesses the user nickname by taking the last part
|
||||
# of the ap_id and the domain and tries to get that user
|
||||
def get_by_guessed_nickname(ap_id) do
|
||||
|
|
@ -720,6 +750,7 @@ defmodule Pleroma.User do
|
|||
|> update_and_set_cache()
|
||||
end
|
||||
|
||||
@spec maybe_fetch_follow_information(User.t()) :: User.t()
|
||||
def maybe_fetch_follow_information(user) do
|
||||
with {:ok, user} <- fetch_follow_information(user) do
|
||||
user
|
||||
|
|
@ -777,9 +808,10 @@ defmodule Pleroma.User do
|
|||
end
|
||||
end
|
||||
|
||||
@spec maybe_update_following_count(User.t()) :: User.t()
|
||||
def maybe_update_following_count(%User{local: false} = user) do
|
||||
if Pleroma.Config.get([:instance, :external_user_synchronization]) do
|
||||
{:ok, maybe_fetch_follow_information(user)}
|
||||
maybe_fetch_follow_information(user)
|
||||
else
|
||||
user
|
||||
end
|
||||
|
|
@ -885,6 +917,13 @@ defmodule Pleroma.User do
|
|||
blocker
|
||||
end
|
||||
|
||||
# clear any requested follows as well
|
||||
blocked =
|
||||
case CommonAPI.reject_follow_request(blocked, blocker) do
|
||||
{:ok, %User{} = updated_blocked} -> updated_blocked
|
||||
nil -> blocked
|
||||
end
|
||||
|
||||
blocker =
|
||||
if subscribed_to?(blocked, blocker) do
|
||||
{:ok, blocker} = unsubscribe(blocked, blocker)
|
||||
|
|
|
|||
|
|
@ -388,7 +388,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
def follow(follower, followed, activity_id \\ nil, local \\ true) do
|
||||
with data <- make_follow_data(follower, followed, activity_id),
|
||||
{:ok, activity} <- insert(data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
:ok <- maybe_federate(activity),
|
||||
_ <- User.set_follow_state_cache(follower.ap_id, followed.ap_id, activity.data["state"]) do
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
|
@ -790,14 +791,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
defp restrict_muted(query, %{"with_muted" => val}) when val in [true, "true", "1"], do: query
|
||||
|
||||
defp restrict_muted(query, %{"muting_user" => %User{info: info}}) do
|
||||
defp restrict_muted(query, %{"muting_user" => %User{info: info}} = opts) do
|
||||
mutes = info.mutes
|
||||
|
||||
from(
|
||||
activity in query,
|
||||
where: fragment("not (? = ANY(?))", activity.actor, ^mutes),
|
||||
where: fragment("not (?->'to' \\?| ?)", activity.data, ^mutes)
|
||||
)
|
||||
query =
|
||||
from([activity] in query,
|
||||
where: fragment("not (? = ANY(?))", activity.actor, ^mutes),
|
||||
where: fragment("not (?->'to' \\?| ?)", activity.data, ^mutes)
|
||||
)
|
||||
|
||||
unless opts["skip_preload"] do
|
||||
from([thread_mute: tm] in query, where: is_nil(tm))
|
||||
else
|
||||
query
|
||||
end
|
||||
end
|
||||
|
||||
defp restrict_muted(query, _), do: query
|
||||
|
|
@ -898,7 +905,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
defp maybe_set_thread_muted_field(query, opts) do
|
||||
query
|
||||
|> Activity.with_set_thread_muted_field(opts["user"])
|
||||
|> Activity.with_set_thread_muted_field(opts["muting_user"] || opts["user"])
|
||||
end
|
||||
|
||||
defp maybe_order(query, %{order: :desc}) do
|
||||
|
|
|
|||
|
|
@ -92,5 +92,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
|
|||
def filter(message), do: {:ok, message}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{mrf_hellthread: Pleroma.Config.get([:mrf_hellthread])}}
|
||||
def describe,
|
||||
do: {:ok, %{mrf_hellthread: Pleroma.Config.get(:mrf_hellthread) |> Enum.into(%{})}}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -46,5 +46,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
|
|||
def filter(object), do: {:ok, object}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{mrf_rejectnonpublic: Pleroma.Config.get([:mrf_rejectnonpublic])}}
|
||||
def describe,
|
||||
do: {:ok, %{mrf_rejectnonpublic: Pleroma.Config.get(:mrf_rejectnonpublic) |> Enum.into(%{})}}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -32,5 +32,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do
|
|||
|
||||
def filter(message), do: {:ok, message}
|
||||
|
||||
def describe, do: {:ok, %{mrf_vocabulary: Pleroma.Config.get(:mrf_vocabulary)}}
|
||||
def describe,
|
||||
do: {:ok, %{mrf_vocabulary: Pleroma.Config.get(:mrf_vocabulary) |> Enum.into(%{})}}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
"""
|
||||
def publish_one(%{inbox: inbox, json: json, actor: %User{} = actor, id: id} = params) do
|
||||
Logger.info("Federating #{id} to #{inbox}")
|
||||
host = URI.parse(inbox).host
|
||||
%{host: host, path: path} = URI.parse(inbox)
|
||||
|
||||
digest = "SHA-256=" <> (:crypto.hash(:sha256, json) |> Base.encode64())
|
||||
|
||||
|
|
@ -56,6 +56,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
|
||||
signature =
|
||||
Pleroma.Signature.sign(actor, %{
|
||||
"(request-target)": "post #{path}",
|
||||
host: host,
|
||||
"content-length": byte_size(json),
|
||||
digest: digest,
|
||||
|
|
|
|||
|
|
@ -374,6 +374,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
[state, actor, object]
|
||||
)
|
||||
|
||||
User.set_follow_state_cache(actor, object, state)
|
||||
activity = Activity.get_by_id(activity.id)
|
||||
{:ok, activity}
|
||||
rescue
|
||||
|
|
@ -382,12 +383,16 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
end
|
||||
end
|
||||
|
||||
def update_follow_state(%Activity{} = activity, state) do
|
||||
def update_follow_state(
|
||||
%Activity{data: %{"actor" => actor, "object" => object}} = activity,
|
||||
state
|
||||
) do
|
||||
with new_data <-
|
||||
activity.data
|
||||
|> Map.put("state", state),
|
||||
changeset <- Changeset.change(activity, data: new_data),
|
||||
{:ok, activity} <- Repo.update(changeset) do
|
||||
{:ok, activity} <- Repo.update(changeset),
|
||||
_ <- User.set_follow_state_cache(actor, object, state) do
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -33,9 +33,11 @@ defmodule Pleroma.Web.ChatChannel do
|
|||
end
|
||||
|
||||
defmodule Pleroma.Web.ChatChannel.ChatChannelState do
|
||||
use Agent
|
||||
|
||||
@max_messages 20
|
||||
|
||||
def start_link do
|
||||
def start_link(_) do
|
||||
Agent.start_link(fn -> %{max_id: 1, messages: []} end, name: __MODULE__)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
defmodule Pleroma.Web.CommonAPI do
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.Formatter
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.ThreadMute
|
||||
|
|
@ -171,21 +172,25 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
end)
|
||||
end
|
||||
|
||||
def get_visibility(%{"visibility" => visibility}, in_reply_to)
|
||||
def get_visibility(_, _, %Participation{}) do
|
||||
{"direct", "direct"}
|
||||
end
|
||||
|
||||
def get_visibility(%{"visibility" => visibility}, in_reply_to, _)
|
||||
when visibility in ~w{public unlisted private direct},
|
||||
do: {visibility, get_replied_to_visibility(in_reply_to)}
|
||||
|
||||
def get_visibility(%{"visibility" => "list:" <> list_id}, in_reply_to) do
|
||||
def get_visibility(%{"visibility" => "list:" <> list_id}, in_reply_to, _) do
|
||||
visibility = {:list, String.to_integer(list_id)}
|
||||
{visibility, get_replied_to_visibility(in_reply_to)}
|
||||
end
|
||||
|
||||
def get_visibility(_, in_reply_to) when not is_nil(in_reply_to) do
|
||||
def get_visibility(_, in_reply_to, _) when not is_nil(in_reply_to) do
|
||||
visibility = get_replied_to_visibility(in_reply_to)
|
||||
{visibility, visibility}
|
||||
end
|
||||
|
||||
def get_visibility(_, in_reply_to), do: {"public", get_replied_to_visibility(in_reply_to)}
|
||||
def get_visibility(_, in_reply_to, _), do: {"public", get_replied_to_visibility(in_reply_to)}
|
||||
|
||||
def get_replied_to_visibility(nil), do: nil
|
||||
|
||||
|
|
@ -201,7 +206,9 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
with status <- String.trim(status),
|
||||
attachments <- attachments_from_ids(data),
|
||||
in_reply_to <- get_replied_to_activity(data["in_reply_to_status_id"]),
|
||||
{visibility, in_reply_to_visibility} <- get_visibility(data, in_reply_to),
|
||||
in_reply_to_conversation <- Participation.get(data["in_reply_to_conversation_id"]),
|
||||
{visibility, in_reply_to_visibility} <-
|
||||
get_visibility(data, in_reply_to, in_reply_to_conversation),
|
||||
{_, false} <-
|
||||
{:private_to_public, in_reply_to_visibility == "direct" && visibility != "direct"},
|
||||
{content_html, mentions, tags} <-
|
||||
|
|
@ -214,8 +221,9 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
mentioned_users <- for({_, mentioned_user} <- mentions, do: mentioned_user.ap_id),
|
||||
addressed_users <- get_addressed_users(mentioned_users, data["to"]),
|
||||
{poll, poll_emoji} <- make_poll_data(data),
|
||||
{to, cc} <- get_to_and_cc(user, addressed_users, in_reply_to, visibility),
|
||||
context <- make_context(in_reply_to),
|
||||
{to, cc} <-
|
||||
get_to_and_cc(user, addressed_users, in_reply_to, visibility, in_reply_to_conversation),
|
||||
context <- make_context(in_reply_to, in_reply_to_conversation),
|
||||
cw <- data["spoiler_text"] || "",
|
||||
sensitive <- data["sensitive"] || Enum.member?(tags, {"#nsfw", "nsfw"}),
|
||||
full_payload <- String.trim(status <> cw),
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
alias Calendar.Strftime
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.Formatter
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Plugs.AuthenticationPlug
|
||||
|
|
@ -86,9 +87,21 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
|> Enum.filter(& &1)
|
||||
end
|
||||
|
||||
@spec get_to_and_cc(User.t(), list(String.t()), Activity.t() | nil, String.t()) ::
|
||||
@spec get_to_and_cc(
|
||||
User.t(),
|
||||
list(String.t()),
|
||||
Activity.t() | nil,
|
||||
String.t(),
|
||||
Participation.t() | nil
|
||||
) ::
|
||||
{list(String.t()), list(String.t())}
|
||||
def get_to_and_cc(user, mentioned_users, inReplyTo, "public") do
|
||||
|
||||
def get_to_and_cc(_, _, _, _, %Participation{} = participation) do
|
||||
participation = Repo.preload(participation, :recipients)
|
||||
{Enum.map(participation.recipients, & &1.ap_id), []}
|
||||
end
|
||||
|
||||
def get_to_and_cc(user, mentioned_users, inReplyTo, "public", _) do
|
||||
to = [Pleroma.Constants.as_public() | mentioned_users]
|
||||
cc = [user.follower_address]
|
||||
|
||||
|
|
@ -99,7 +112,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
end
|
||||
end
|
||||
|
||||
def get_to_and_cc(user, mentioned_users, inReplyTo, "unlisted") do
|
||||
def get_to_and_cc(user, mentioned_users, inReplyTo, "unlisted", _) do
|
||||
to = [user.follower_address | mentioned_users]
|
||||
cc = [Pleroma.Constants.as_public()]
|
||||
|
||||
|
|
@ -110,12 +123,12 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
end
|
||||
end
|
||||
|
||||
def get_to_and_cc(user, mentioned_users, inReplyTo, "private") do
|
||||
{to, cc} = get_to_and_cc(user, mentioned_users, inReplyTo, "direct")
|
||||
def get_to_and_cc(user, mentioned_users, inReplyTo, "private", _) do
|
||||
{to, cc} = get_to_and_cc(user, mentioned_users, inReplyTo, "direct", nil)
|
||||
{[user.follower_address | to], cc}
|
||||
end
|
||||
|
||||
def get_to_and_cc(_user, mentioned_users, inReplyTo, "direct") do
|
||||
def get_to_and_cc(_user, mentioned_users, inReplyTo, "direct", _) do
|
||||
if inReplyTo do
|
||||
{Enum.uniq([inReplyTo.data["actor"] | mentioned_users]), []}
|
||||
else
|
||||
|
|
@ -123,7 +136,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
end
|
||||
end
|
||||
|
||||
def get_to_and_cc(_user, mentions, _inReplyTo, {:list, _}), do: {mentions, []}
|
||||
def get_to_and_cc(_user, mentions, _inReplyTo, {:list, _}, _), do: {mentions, []}
|
||||
|
||||
def get_addressed_users(_, to) when is_list(to) do
|
||||
User.get_ap_ids_by_nicknames(to)
|
||||
|
|
@ -253,8 +266,12 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
|
||||
defp maybe_add_nsfw_tag(data, _), do: data
|
||||
|
||||
def make_context(%Activity{data: %{"context" => context}}), do: context
|
||||
def make_context(_), do: Utils.generate_context_id()
|
||||
def make_context(_, %Participation{} = participation) do
|
||||
Repo.preload(participation, :conversation).conversation.ap_id
|
||||
end
|
||||
|
||||
def make_context(%Activity{data: %{"context" => context}}, _), do: context
|
||||
def make_context(_, _), do: Utils.generate_context_id()
|
||||
|
||||
def maybe_add_attachments(parsed, _attachments, true = _no_links), do: parsed
|
||||
|
||||
|
|
|
|||
|
|
@ -33,4 +33,80 @@ defmodule Pleroma.Web.ControllerHelper do
|
|||
end
|
||||
|
||||
defp param_to_integer(_, default), do: default
|
||||
|
||||
def add_link_headers(
|
||||
conn,
|
||||
method,
|
||||
activities,
|
||||
param \\ nil,
|
||||
params \\ %{},
|
||||
func3 \\ nil,
|
||||
func4 \\ nil
|
||||
) do
|
||||
params =
|
||||
conn.params
|
||||
|> Map.drop(["since_id", "max_id", "min_id"])
|
||||
|> Map.merge(params)
|
||||
|
||||
last = List.last(activities)
|
||||
|
||||
func3 = func3 || (&mastodon_api_url/3)
|
||||
func4 = func4 || (&mastodon_api_url/4)
|
||||
|
||||
if last do
|
||||
max_id = last.id
|
||||
|
||||
limit =
|
||||
params
|
||||
|> Map.get("limit", "20")
|
||||
|> String.to_integer()
|
||||
|
||||
min_id =
|
||||
if length(activities) <= limit do
|
||||
activities
|
||||
|> List.first()
|
||||
|> Map.get(:id)
|
||||
else
|
||||
activities
|
||||
|> Enum.at(limit * -1)
|
||||
|> Map.get(:id)
|
||||
end
|
||||
|
||||
{next_url, prev_url} =
|
||||
if param do
|
||||
{
|
||||
func4.(
|
||||
Pleroma.Web.Endpoint,
|
||||
method,
|
||||
param,
|
||||
Map.merge(params, %{max_id: max_id})
|
||||
),
|
||||
func4.(
|
||||
Pleroma.Web.Endpoint,
|
||||
method,
|
||||
param,
|
||||
Map.merge(params, %{min_id: min_id})
|
||||
)
|
||||
}
|
||||
else
|
||||
{
|
||||
func3.(
|
||||
Pleroma.Web.Endpoint,
|
||||
method,
|
||||
Map.merge(params, %{max_id: max_id})
|
||||
),
|
||||
func3.(
|
||||
Pleroma.Web.Endpoint,
|
||||
method,
|
||||
Map.merge(params, %{min_id: min_id})
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
conn
|
||||
|> put_resp_header("link", "<#{next_url}>; rel=\"next\", <#{prev_url}>; rel=\"prev\"")
|
||||
else
|
||||
conn
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ defmodule Pleroma.Web.Federator.RetryQueue do
|
|||
{:ok, %{args | queue_table: queue_table, running_jobs: :sets.new()}}
|
||||
end
|
||||
|
||||
def start_link do
|
||||
def start_link(_) do
|
||||
enabled =
|
||||
if Pleroma.Config.get(:env) == :test,
|
||||
do: true,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
|
||||
import Pleroma.Web.ControllerHelper,
|
||||
only: [json_response: 3, add_link_headers: 5, add_link_headers: 4, add_link_headers: 3]
|
||||
|
||||
alias Ecto.Changeset
|
||||
alias Pleroma.Activity
|
||||
|
|
@ -342,71 +343,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
json(conn, mastodon_emoji)
|
||||
end
|
||||
|
||||
defp add_link_headers(conn, method, activities, param \\ nil, params \\ %{}) do
|
||||
params =
|
||||
conn.params
|
||||
|> Map.drop(["since_id", "max_id", "min_id"])
|
||||
|> Map.merge(params)
|
||||
|
||||
last = List.last(activities)
|
||||
|
||||
if last do
|
||||
max_id = last.id
|
||||
|
||||
limit =
|
||||
params
|
||||
|> Map.get("limit", "20")
|
||||
|> String.to_integer()
|
||||
|
||||
min_id =
|
||||
if length(activities) <= limit do
|
||||
activities
|
||||
|> List.first()
|
||||
|> Map.get(:id)
|
||||
else
|
||||
activities
|
||||
|> Enum.at(limit * -1)
|
||||
|> Map.get(:id)
|
||||
end
|
||||
|
||||
{next_url, prev_url} =
|
||||
if param do
|
||||
{
|
||||
mastodon_api_url(
|
||||
Pleroma.Web.Endpoint,
|
||||
method,
|
||||
param,
|
||||
Map.merge(params, %{max_id: max_id})
|
||||
),
|
||||
mastodon_api_url(
|
||||
Pleroma.Web.Endpoint,
|
||||
method,
|
||||
param,
|
||||
Map.merge(params, %{min_id: min_id})
|
||||
)
|
||||
}
|
||||
else
|
||||
{
|
||||
mastodon_api_url(
|
||||
Pleroma.Web.Endpoint,
|
||||
method,
|
||||
Map.merge(params, %{max_id: max_id})
|
||||
),
|
||||
mastodon_api_url(
|
||||
Pleroma.Web.Endpoint,
|
||||
method,
|
||||
Map.merge(params, %{min_id: min_id})
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
conn
|
||||
|> put_resp_header("link", "<#{next_url}>; rel=\"next\", <#{prev_url}>; rel=\"prev\"")
|
||||
else
|
||||
conn
|
||||
end
|
||||
end
|
||||
|
||||
def home_timeline(%{assigns: %{user: user}} = conn, params) do
|
||||
params =
|
||||
params
|
||||
|
|
@ -1797,7 +1733,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|
||||
conversations =
|
||||
Enum.map(participations, fn participation ->
|
||||
ConversationView.render("participation.json", %{participation: participation, user: user})
|
||||
ConversationView.render("participation.json", %{participation: participation, for: user})
|
||||
end)
|
||||
|
||||
conn
|
||||
|
|
@ -1810,7 +1746,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
Repo.get_by(Participation, id: participation_id, user_id: user.id),
|
||||
{:ok, participation} <- Participation.mark_as_read(participation) do
|
||||
participation_view =
|
||||
ConversationView.render("participation.json", %{participation: participation, user: user})
|
||||
ConversationView.render("participation.json", %{participation: participation, for: user})
|
||||
|
||||
conn
|
||||
|> json(participation_view)
|
||||
|
|
|
|||
|
|
@ -37,11 +37,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
end
|
||||
|
||||
def render("relationship.json", %{user: %User{} = user, target: %User{} = target}) do
|
||||
follow_activity = Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, target)
|
||||
follow_state = User.get_cached_follow_state(user, target)
|
||||
|
||||
requested =
|
||||
if follow_activity && !User.following?(target, user) do
|
||||
follow_activity.data["state"] == "pending"
|
||||
if follow_state && !User.following?(user, target) do
|
||||
follow_state == "pending"
|
||||
else
|
||||
false
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do
|
|||
alias Pleroma.Web.MastodonAPI.AccountView
|
||||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
|
||||
def render("participation.json", %{participation: participation, user: user}) do
|
||||
participation = Repo.preload(participation, conversation: :users)
|
||||
def render("participation.json", %{participation: participation, for: user}) do
|
||||
participation = Repo.preload(participation, conversation: [], recipients: [])
|
||||
|
||||
last_activity_id =
|
||||
with nil <- participation.last_activity_id do
|
||||
|
|
@ -28,7 +28,7 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do
|
|||
|
||||
# Conversations return all users except the current user.
|
||||
users =
|
||||
participation.conversation.users
|
||||
participation.recipients
|
||||
|> Enum.reject(&(&1.id == user.id))
|
||||
|
||||
accounts =
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
require Pleroma.Constants
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Conversation
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.HTML
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Repo
|
||||
|
|
@ -70,12 +72,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
|
||||
def render("index.json", opts) do
|
||||
replied_to_activities = get_replied_to_activities(opts.activities)
|
||||
parallel = unless is_nil(opts[:parallel]), do: opts[:parallel], else: true
|
||||
|
||||
opts.activities
|
||||
|> safe_render_many(
|
||||
StatusView,
|
||||
"status.json",
|
||||
Map.put(opts, :replied_to_activities, replied_to_activities)
|
||||
Map.put(opts, :replied_to_activities, replied_to_activities),
|
||||
parallel
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -233,6 +237,19 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
object.data["url"] || object.data["external_url"] || object.data["id"]
|
||||
end
|
||||
|
||||
direct_conversation_id =
|
||||
with {_, true} <- {:include_id, opts[:with_direct_conversation_id]},
|
||||
{_, %User{} = for_user} <- {:for_user, opts[:for]},
|
||||
%{data: %{"context" => context}} when is_binary(context) <- activity,
|
||||
%Conversation{} = conversation <- Conversation.get_for_ap_id(context),
|
||||
%Participation{id: participation_id} <-
|
||||
Participation.for_user_and_conversation(for_user, conversation) do
|
||||
participation_id
|
||||
else
|
||||
_e ->
|
||||
nil
|
||||
end
|
||||
|
||||
%{
|
||||
id: to_string(activity.id),
|
||||
uri: object.data["id"],
|
||||
|
|
@ -270,7 +287,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
conversation_id: get_context_id(activity),
|
||||
in_reply_to_account_acct: reply_to_user && reply_to_user.nickname,
|
||||
content: %{"text/plain" => content_plaintext},
|
||||
spoiler_text: %{"text/plain" => summary_plaintext}
|
||||
spoiler_text: %{"text/plain" => summary_plaintext},
|
||||
direct_conversation_id: direct_conversation_id
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,36 +6,30 @@ defmodule Pleroma.Web.OAuth.Token.CleanWorker do
|
|||
@moduledoc """
|
||||
The module represents functions to clean an expired oauth tokens.
|
||||
"""
|
||||
use GenServer
|
||||
|
||||
@ten_seconds 10_000
|
||||
@one_day 86_400_000
|
||||
|
||||
# 10 seconds
|
||||
@start_interval 10_000
|
||||
@interval Pleroma.Config.get(
|
||||
# 24 hours
|
||||
[:oauth2, :clean_expired_tokens_interval],
|
||||
86_400_000
|
||||
@one_day
|
||||
)
|
||||
@queue :background
|
||||
|
||||
alias Pleroma.Web.OAuth.Token
|
||||
|
||||
def start_link, do: GenServer.start_link(__MODULE__, nil)
|
||||
def start_link(_), do: GenServer.start_link(__MODULE__, %{})
|
||||
|
||||
def init(_) do
|
||||
if Pleroma.Config.get([:oauth2, :clean_expired_tokens], false) do
|
||||
Process.send_after(self(), :perform, @start_interval)
|
||||
{:ok, nil}
|
||||
else
|
||||
:ignore
|
||||
end
|
||||
Process.send_after(self(), :perform, @ten_seconds)
|
||||
{:ok, nil}
|
||||
end
|
||||
|
||||
@doc false
|
||||
def handle_info(:perform, state) do
|
||||
Token.delete_expired_tokens()
|
||||
|
||||
Process.send_after(self(), :perform, @interval)
|
||||
PleromaJobQueue.enqueue(@queue, __MODULE__, [:clean])
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
# Job Worker Callbacks
|
||||
def perform(:clean), do: Token.delete_expired_tokens()
|
||||
end
|
||||
|
|
|
|||
73
lib/pleroma/web/pleroma_api/pleroma_api_controller.ex
Normal file
73
lib/pleroma/web/pleroma_api/pleroma_api_controller.ex
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 7]
|
||||
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.MastodonAPI.ConversationView
|
||||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
|
||||
def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do
|
||||
with %Participation{} = participation <- Participation.get(participation_id),
|
||||
true <- user.id == participation.user_id do
|
||||
conn
|
||||
|> put_view(ConversationView)
|
||||
|> render("participation.json", %{participation: participation, for: user})
|
||||
end
|
||||
end
|
||||
|
||||
def conversation_statuses(
|
||||
%{assigns: %{user: user}} = conn,
|
||||
%{"id" => participation_id} = params
|
||||
) do
|
||||
params =
|
||||
params
|
||||
|> Map.put("blocking_user", user)
|
||||
|> Map.put("muting_user", user)
|
||||
|> Map.put("user", user)
|
||||
|
||||
participation =
|
||||
participation_id
|
||||
|> Participation.get(preload: [:conversation])
|
||||
|
||||
if user.id == participation.user_id do
|
||||
activities =
|
||||
participation.conversation.ap_id
|
||||
|> ActivityPub.fetch_activities_for_context(params)
|
||||
|> Enum.reverse()
|
||||
|
||||
conn
|
||||
|> add_link_headers(
|
||||
:conversation_statuses,
|
||||
activities,
|
||||
participation_id,
|
||||
params,
|
||||
nil,
|
||||
&pleroma_api_url/4
|
||||
)
|
||||
|> put_view(StatusView)
|
||||
|> render("index.json", %{activities: activities, for: user, as: :activity})
|
||||
end
|
||||
end
|
||||
|
||||
def update_conversation(
|
||||
%{assigns: %{user: user}} = conn,
|
||||
%{"id" => participation_id, "recipients" => recipients}
|
||||
) do
|
||||
participation =
|
||||
participation_id
|
||||
|> Participation.get()
|
||||
|
||||
with true <- user.id == participation.user_id,
|
||||
{:ok, participation} <- Participation.set_recipients(participation, recipients) do
|
||||
conn
|
||||
|> put_view(ConversationView)
|
||||
|> render("participation.json", %{participation: participation, for: user})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -259,6 +259,21 @@ defmodule Pleroma.Web.Router do
|
|||
end
|
||||
end
|
||||
|
||||
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
|
||||
pipe_through(:authenticated_api)
|
||||
|
||||
scope [] do
|
||||
pipe_through(:oauth_read)
|
||||
get("/conversations/:id/statuses", PleromaAPIController, :conversation_statuses)
|
||||
get("/conversations/:id", PleromaAPIController, :conversation)
|
||||
end
|
||||
|
||||
scope [] do
|
||||
pipe_through(:oauth_write)
|
||||
patch("/conversations/:id", PleromaAPIController, :update_conversation)
|
||||
end
|
||||
end
|
||||
|
||||
scope "/api/v1", Pleroma.Web.MastodonAPI do
|
||||
pipe_through(:authenticated_api)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ defmodule Pleroma.Web.Streamer do
|
|||
|
||||
@keepalive_interval :timer.seconds(30)
|
||||
|
||||
def start_link do
|
||||
def start_link(_) do
|
||||
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
|
||||
end
|
||||
|
||||
|
|
@ -35,28 +35,21 @@ defmodule Pleroma.Web.Streamer do
|
|||
end
|
||||
|
||||
def init(args) do
|
||||
spawn(fn ->
|
||||
# 30 seconds
|
||||
Process.sleep(@keepalive_interval)
|
||||
GenServer.cast(__MODULE__, %{action: :ping})
|
||||
end)
|
||||
Process.send_after(self(), %{action: :ping}, @keepalive_interval)
|
||||
|
||||
{:ok, args}
|
||||
end
|
||||
|
||||
def handle_cast(%{action: :ping}, topics) do
|
||||
Map.values(topics)
|
||||
def handle_info(%{action: :ping}, topics) do
|
||||
topics
|
||||
|> Map.values()
|
||||
|> List.flatten()
|
||||
|> Enum.each(fn socket ->
|
||||
Logger.debug("Sending keepalive ping")
|
||||
send(socket.transport_pid, {:text, ""})
|
||||
end)
|
||||
|
||||
spawn(fn ->
|
||||
# 30 seconds
|
||||
Process.sleep(@keepalive_interval)
|
||||
GenServer.cast(__MODULE__, %{action: :ping})
|
||||
end)
|
||||
Process.send_after(self(), %{action: :ping}, @keepalive_interval)
|
||||
|
||||
{:noreply, topics}
|
||||
end
|
||||
|
|
@ -120,8 +113,7 @@ defmodule Pleroma.Web.Streamer do
|
|||
|> Map.get("#{topic}:#{item.user_id}", [])
|
||||
|> Enum.each(fn socket ->
|
||||
with %User{} = user <- User.get_cached_by_ap_id(socket.assigns[:user].ap_id),
|
||||
true <- should_send?(user, item),
|
||||
false <- CommonAPI.thread_muted?(user, item.activity) do
|
||||
true <- should_send?(user, item) do
|
||||
send(
|
||||
socket.transport_pid,
|
||||
{:text, represent_notification(socket.assigns[:user], item)}
|
||||
|
|
@ -209,7 +201,7 @@ defmodule Pleroma.Web.Streamer do
|
|||
payload:
|
||||
Pleroma.Web.MastodonAPI.ConversationView.render("participation.json", %{
|
||||
participation: participation,
|
||||
user: participation.user
|
||||
for: participation.user
|
||||
})
|
||||
|> Jason.encode!()
|
||||
}
|
||||
|
|
@ -243,7 +235,8 @@ defmodule Pleroma.Web.Streamer do
|
|||
%{host: parent_host} <- URI.parse(parent.data["actor"]),
|
||||
false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, item_host),
|
||||
false <- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, parent_host),
|
||||
true <- thread_containment(item, user) do
|
||||
true <- thread_containment(item, user),
|
||||
false <- CommonAPI.thread_muted?(user, item) do
|
||||
true
|
||||
else
|
||||
_ -> false
|
||||
|
|
|
|||
|
|
@ -66,9 +66,23 @@ defmodule Pleroma.Web do
|
|||
end
|
||||
|
||||
@doc """
|
||||
Same as `render_many/4` but wrapped in rescue block.
|
||||
Same as `render_many/4` but wrapped in rescue block and parallelized (unless disabled by passing false as a fifth argument).
|
||||
"""
|
||||
def safe_render_many(collection, view, template, assigns \\ %{}) do
|
||||
def safe_render_many(collection, view, template, assigns \\ %{}, parallel \\ true)
|
||||
|
||||
def safe_render_many(collection, view, template, assigns, true) do
|
||||
Enum.map(collection, fn resource ->
|
||||
Task.async(fn ->
|
||||
as = Map.get(assigns, :as) || view.__resource__
|
||||
assigns = Map.put(assigns, as, resource)
|
||||
safe_render(view, template, assigns)
|
||||
end)
|
||||
end)
|
||||
|> Enum.map(&Task.await(&1, :infinity))
|
||||
|> Enum.filter(& &1)
|
||||
end
|
||||
|
||||
def safe_render_many(collection, view, template, assigns, false) do
|
||||
Enum.map(collection, fn resource ->
|
||||
as = Map.get(assigns, :as) || view.__resource__
|
||||
assigns = Map.put(assigns, as, resource)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue