Merge remote-tracking branch 'origin/develop' into global-status-expiration
This commit is contained in:
commit
0f386110c6
1688 changed files with 7671 additions and 5249 deletions
|
|
@ -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 Mix.Tasks.Pleroma.Config do
|
||||
|
|
|
|||
|
|
@ -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 Mix.Tasks.Pleroma.Emoji do
|
||||
|
|
@ -186,11 +186,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
|
|||
|
||||
tmp_pack_dir = Path.join(System.tmp_dir!(), "emoji-pack-#{name}")
|
||||
|
||||
{:ok, _} =
|
||||
:zip.unzip(
|
||||
binary_archive,
|
||||
cwd: tmp_pack_dir
|
||||
)
|
||||
{:ok, _} = :zip.unzip(binary_archive, cwd: String.to_charlist(tmp_pack_dir))
|
||||
|
||||
emoji_map = Pleroma.Emoji.Loader.make_shortcode_to_file_map(tmp_pack_dir, exts)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
# 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 Mix.Tasks.Pleroma.Instance do
|
||||
use Mix.Task
|
||||
import Mix.Pleroma
|
||||
|
||||
alias Pleroma.Config
|
||||
|
||||
@shortdoc "Manages Pleroma instance"
|
||||
@moduledoc File.read!("docs/administration/CLI_tasks/instance.md")
|
||||
|
||||
|
|
@ -63,7 +65,8 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
|||
get_option(
|
||||
options,
|
||||
:instance_name,
|
||||
"What is the name of your instance? (e.g. Pleroma/Soykaf)"
|
||||
"What is the name of your instance? (e.g. The Corndog Emporium)",
|
||||
domain
|
||||
)
|
||||
|
||||
email = get_option(options, :admin_email, "What is your admin email address?")
|
||||
|
|
@ -153,6 +156,8 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
|||
Pleroma.Config.get([:instance, :static_dir])
|
||||
)
|
||||
|
||||
Config.put([:instance, :static_dir], static_dir)
|
||||
|
||||
secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
|
||||
jwt_secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
|
||||
signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode64() |> binary_part(0, 8)
|
||||
|
|
@ -202,8 +207,14 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
|||
write_robots_txt(indexable, template_dir)
|
||||
|
||||
shell_info(
|
||||
"\n All files successfully written! Refer to the installation instructions for your platform for next steps"
|
||||
"\n All files successfully written! Refer to the installation instructions for your platform for next steps."
|
||||
)
|
||||
|
||||
if db_configurable? do
|
||||
shell_info(
|
||||
" Please transfer your config to the database after running database migrations. Refer to \"Transfering the config to/from the database\" section of the docs for more information."
|
||||
)
|
||||
end
|
||||
else
|
||||
shell_error(
|
||||
"The task would have overwritten the following files:\n" <>
|
||||
|
|
|
|||
46
lib/mix/tasks/pleroma/refresh_counter_cache.ex
Normal file
46
lib/mix/tasks/pleroma/refresh_counter_cache.ex
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.Tasks.Pleroma.RefreshCounterCache do
|
||||
@shortdoc "Refreshes counter cache"
|
||||
|
||||
use Mix.Task
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.CounterCache
|
||||
alias Pleroma.Repo
|
||||
|
||||
require Logger
|
||||
import Ecto.Query
|
||||
|
||||
def run([]) do
|
||||
Mix.Pleroma.start_pleroma()
|
||||
|
||||
["public", "unlisted", "private", "direct"]
|
||||
|> Enum.each(fn visibility ->
|
||||
count = status_visibility_count_query(visibility)
|
||||
name = "status_visibility_#{visibility}"
|
||||
CounterCache.set(name, count)
|
||||
Mix.Pleroma.shell_info("Set #{name} to #{count}")
|
||||
end)
|
||||
|
||||
Mix.Pleroma.shell_info("Done")
|
||||
end
|
||||
|
||||
defp status_visibility_count_query(visibility) do
|
||||
Activity
|
||||
|> where(
|
||||
[a],
|
||||
fragment(
|
||||
"activity_visibility(?, ?, ?) = ?",
|
||||
a.actor,
|
||||
a.recipients,
|
||||
a.data,
|
||||
^visibility
|
||||
)
|
||||
)
|
||||
|> where([a], fragment("(? ->> 'type'::text) = 'Create'", a.data))
|
||||
|> Repo.aggregate(:count, :id, timeout: :timer.minutes(30))
|
||||
end
|
||||
end
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.Tasks.Pleroma.RobotsTxt do
|
||||
|
|
|
|||
|
|
@ -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 Mix.Tasks.Pleroma.User do
|
||||
|
|
@ -100,8 +100,7 @@ defmodule Mix.Tasks.Pleroma.User do
|
|||
User.perform(:delete, user)
|
||||
shell_info("User #{nickname} deleted.")
|
||||
else
|
||||
_ ->
|
||||
shell_error("No local user #{nickname}")
|
||||
_ -> shell_error("No local user #{nickname}")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -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.Activity do
|
||||
|
|
@ -310,7 +310,7 @@ defmodule Pleroma.Activity do
|
|||
|
||||
def restrict_deactivated_users(query) do
|
||||
deactivated_users =
|
||||
from(u in User.Query.build(deactivated: true), select: u.ap_id)
|
||||
from(u in User.Query.build(%{deactivated: true}), select: u.ap_id)
|
||||
|> Repo.all()
|
||||
|
||||
Activity.Queries.exclude_authors(query, deactivated_users)
|
||||
|
|
|
|||
|
|
@ -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.Activity.Queries do
|
||||
|
|
@ -7,7 +7,7 @@ defmodule Pleroma.Activity.Queries do
|
|||
Contains queries for Activity.
|
||||
"""
|
||||
|
||||
import Ecto.Query, only: [from: 2]
|
||||
import Ecto.Query, only: [from: 2, where: 3]
|
||||
|
||||
@type query :: Ecto.Queryable.t() | Activity.t()
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ defmodule Pleroma.Activity.Queries do
|
|||
)
|
||||
end
|
||||
|
||||
@spec by_author(query, String.t()) :: query
|
||||
@spec by_author(query, User.t()) :: query
|
||||
def by_author(query \\ Activity, %User{ap_id: ap_id}) do
|
||||
from(a in query, where: a.actor == ^ap_id)
|
||||
end
|
||||
|
|
@ -63,6 +63,22 @@ defmodule Pleroma.Activity.Queries do
|
|||
)
|
||||
end
|
||||
|
||||
@spec by_object_in_reply_to_id(query, String.t(), keyword()) :: query
|
||||
def by_object_in_reply_to_id(query, in_reply_to_id, opts \\ []) do
|
||||
query =
|
||||
if opts[:skip_preloading] do
|
||||
Activity.with_joined_object(query)
|
||||
else
|
||||
Activity.with_preloaded_object(query)
|
||||
end
|
||||
|
||||
where(
|
||||
query,
|
||||
[activity, object: o],
|
||||
fragment("(?)->>'inReplyTo' = ?", o.data, ^to_string(in_reply_to_id))
|
||||
)
|
||||
end
|
||||
|
||||
@spec by_type(query, String.t()) :: query
|
||||
def by_type(query \\ Activity, activity_type) do
|
||||
from(
|
||||
|
|
|
|||
|
|
@ -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.Activity.Search do
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.ActivityExpiration do
|
||||
|
|
@ -62,6 +62,6 @@ defmodule Pleroma.ActivityExpiration do
|
|||
def expires_late_enough?(scheduled_at) do
|
||||
now = NaiveDateTime.utc_now()
|
||||
diff = NaiveDateTime.diff(scheduled_at, now, :millisecond)
|
||||
diff >= @min_activity_lifetime
|
||||
diff > @min_activity_lifetime
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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.Application do
|
||||
|
|
|
|||
|
|
@ -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.Captcha do
|
||||
|
|
@ -50,7 +50,7 @@ defmodule Pleroma.Captcha do
|
|||
token = new_captcha[:token]
|
||||
secret = KeyGenerator.generate(secret_key_base, token <> "_encrypt")
|
||||
sign_secret = KeyGenerator.generate(secret_key_base, token <> "_sign")
|
||||
# Basicallty copy what Phoenix.Token does here, add the time to
|
||||
# Basically copy what Phoenix.Token does here, add the time to
|
||||
# the actual data and make it a binary to then encrypt it
|
||||
encrypted_captcha_answer =
|
||||
%{
|
||||
|
|
@ -62,7 +62,7 @@ defmodule Pleroma.Captcha do
|
|||
|
||||
{
|
||||
:reply,
|
||||
# Repalce the answer with the encrypted answer
|
||||
# Replace the answer with the encrypted answer
|
||||
%{new_captcha | answer_data: encrypted_captcha_answer},
|
||||
state
|
||||
}
|
||||
|
|
@ -82,7 +82,8 @@ defmodule Pleroma.Captcha do
|
|||
valid_if_after = DateTime.subtract!(DateTime.now_utc(), seconds_valid)
|
||||
|
||||
result =
|
||||
with {:ok, data} <- MessageEncryptor.decrypt(answer_data, secret, sign_secret),
|
||||
with false <- is_nil(answer_data),
|
||||
{:ok, data} <- MessageEncryptor.decrypt(answer_data, secret, sign_secret),
|
||||
%{at: at, answer_data: answer_md5} <- :erlang.binary_to_term(data) do
|
||||
try do
|
||||
if DateTime.before?(at, valid_if_after),
|
||||
|
|
|
|||
|
|
@ -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.Captcha.Native do
|
||||
|
|
@ -10,8 +10,8 @@ defmodule Pleroma.Captcha.Native do
|
|||
@impl Service
|
||||
def new do
|
||||
case Captcha.get() do
|
||||
{:timeout} ->
|
||||
%{error: dgettext("errors", "Captcha timeout")}
|
||||
:error ->
|
||||
%{error: dgettext("errors", "Captcha error")}
|
||||
|
||||
{:ok, answer_data, img_binary} ->
|
||||
%{
|
||||
|
|
|
|||
|
|
@ -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.ConfigDB do
|
||||
|
|
|
|||
|
|
@ -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.Config.Holder do
|
||||
|
|
|
|||
|
|
@ -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.Config.Loader do
|
||||
|
|
|
|||
|
|
@ -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.Config.TransferTask do
|
||||
|
|
@ -146,9 +146,7 @@ defmodule Pleroma.Config.TransferTask do
|
|||
defp update_env(group, key, nil), do: Application.delete_env(group, key)
|
||||
defp update_env(group, key, value), do: Application.put_env(group, key, value)
|
||||
|
||||
defp restart(_, :pleroma, :test), do: Logger.warn("pleroma restarted")
|
||||
|
||||
defp restart(_, :pleroma, _), do: send(Restarter.Pleroma, :after_boot)
|
||||
defp restart(_, :pleroma, env), do: Restarter.Pleroma.restart_after_boot(env)
|
||||
|
||||
defp restart(started_applications, app, _) do
|
||||
with {^app, _, _} <- List.keyfind(started_applications, app, 0),
|
||||
|
|
|
|||
|
|
@ -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.Conversation.Participation do
|
||||
|
|
@ -133,10 +133,8 @@ defmodule Pleroma.Conversation.Participation do
|
|||
[user.id | user_ids]
|
||||
|> Enum.uniq()
|
||||
|> Enum.reduce([], fn user_id, acc ->
|
||||
case FlakeId.Ecto.CompatType.dump(user_id) do
|
||||
{:ok, user_id} -> [user_id | acc]
|
||||
_ -> acc
|
||||
end
|
||||
{:ok, user_id} = FlakeId.Ecto.CompatType.dump(user_id)
|
||||
[user_id | acc]
|
||||
end)
|
||||
|
||||
conversation_subquery =
|
||||
|
|
|
|||
41
lib/pleroma/counter_cache.ex
Normal file
41
lib/pleroma/counter_cache.ex
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.CounterCache do
|
||||
alias Pleroma.CounterCache
|
||||
alias Pleroma.Repo
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
import Ecto.Query
|
||||
|
||||
schema "counter_cache" do
|
||||
field(:name, :string)
|
||||
field(:count, :integer)
|
||||
end
|
||||
|
||||
def changeset(struct, params) do
|
||||
struct
|
||||
|> cast(params, [:name, :count])
|
||||
|> validate_required([:name])
|
||||
|> unique_constraint(:name)
|
||||
end
|
||||
|
||||
def get_as_map(names) when is_list(names) do
|
||||
CounterCache
|
||||
|> where([cc], cc.name in ^names)
|
||||
|> Repo.all()
|
||||
|> Enum.group_by(& &1.name, & &1.count)
|
||||
|> Map.new(fn {k, v} -> {k, hd(v)} end)
|
||||
end
|
||||
|
||||
def set(name, count) do
|
||||
%CounterCache{}
|
||||
|> changeset(%{"name" => name, "count" => count})
|
||||
|> Repo.insert(
|
||||
on_conflict: [set: [count: count]],
|
||||
returning: true,
|
||||
conflict_target: :name
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
@ -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.Emails.AdminEmail do
|
||||
|
|
|
|||
32
lib/pleroma/emails/new_users_digest_email.ex
Normal file
32
lib/pleroma/emails/new_users_digest_email.ex
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Emails.NewUsersDigestEmail do
|
||||
use Phoenix.Swoosh, view: Pleroma.Web.EmailView, layout: {Pleroma.Web.LayoutView, :email_styled}
|
||||
|
||||
defp instance_notify_email do
|
||||
Pleroma.Config.get([:instance, :notify_email]) || Pleroma.Config.get([:instance, :email])
|
||||
end
|
||||
|
||||
def new_users(to, users_and_statuses) do
|
||||
instance_name = Pleroma.Config.get([:instance, :name])
|
||||
styling = Pleroma.Config.get([Pleroma.Emails.UserEmail, :styling])
|
||||
|
||||
logo_url =
|
||||
Pleroma.Web.Endpoint.url() <>
|
||||
Pleroma.Config.get([:frontend_configurations, :pleroma_fe, :logo])
|
||||
|
||||
new()
|
||||
|> to({to.name, to.email})
|
||||
|> from({instance_name, instance_notify_email()})
|
||||
|> subject("#{instance_name} New Users")
|
||||
|> render_body("new_users_digest.html", %{
|
||||
title: "New Users",
|
||||
users_and_statuses: users_and_statuses,
|
||||
instance: instance_name,
|
||||
styling: styling,
|
||||
logo_url: logo_url
|
||||
})
|
||||
end
|
||||
end
|
||||
|
|
@ -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.FollowingRelationship do
|
||||
|
|
|
|||
|
|
@ -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.Formatter do
|
||||
|
|
|
|||
|
|
@ -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.HTML do
|
||||
|
|
@ -108,6 +108,7 @@ defmodule Pleroma.HTML do
|
|||
Cachex.fetch!(:scrubber_cache, key, fn _key ->
|
||||
result =
|
||||
content
|
||||
|> Floki.parse_fragment!()
|
||||
|> Floki.filter_out("a.mention,a.hashtag,a[rel~=\"tag\"]")
|
||||
|> Floki.attribute("a", "href")
|
||||
|> Enum.at(0)
|
||||
|
|
|
|||
|
|
@ -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.MIME do
|
||||
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.MIME do
|
|||
@default "application/octet-stream"
|
||||
@read_bytes 35
|
||||
|
||||
@spec file_mime_type(String.t()) ::
|
||||
@spec file_mime_type(String.t(), String.t()) ::
|
||||
{:ok, content_type :: String.t(), filename :: String.t()} | {:error, any()} | :error
|
||||
def file_mime_type(path, filename) do
|
||||
with {:ok, content_type} <- file_mime_type(path),
|
||||
|
|
|
|||
|
|
@ -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.Notification do
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
# 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.Object do
|
||||
use Ecto.Schema
|
||||
|
||||
import Ecto.Query
|
||||
import Ecto.Changeset
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Object.Fetcher
|
||||
|
|
@ -12,9 +15,6 @@ defmodule Pleroma.Object do
|
|||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
|
||||
import Ecto.Query
|
||||
import Ecto.Changeset
|
||||
|
||||
require Logger
|
||||
|
||||
@type t() :: %__MODULE__{}
|
||||
|
|
@ -145,18 +145,18 @@ defmodule Pleroma.Object do
|
|||
# Legacy objects can be mutated by anybody
|
||||
def authorize_mutation(%Object{}, %User{}), do: true
|
||||
|
||||
@spec get_cached_by_ap_id(String.t()) :: Object.t() | nil
|
||||
def get_cached_by_ap_id(ap_id) do
|
||||
key = "object:#{ap_id}"
|
||||
|
||||
Cachex.fetch!(:object_cache, key, fn _ ->
|
||||
object = get_by_ap_id(ap_id)
|
||||
|
||||
if object do
|
||||
{:commit, object}
|
||||
else
|
||||
{:ignore, object}
|
||||
end
|
||||
end)
|
||||
with {:ok, nil} <- Cachex.get(:object_cache, key),
|
||||
object when not is_nil(object) <- get_by_ap_id(ap_id),
|
||||
{:ok, true} <- Cachex.put(:object_cache, key, object) do
|
||||
object
|
||||
else
|
||||
{:ok, object} -> object
|
||||
nil -> nil
|
||||
end
|
||||
end
|
||||
|
||||
def context_mapping(context) do
|
||||
|
|
@ -301,4 +301,26 @@ defmodule Pleroma.Object do
|
|||
def local?(%Object{data: %{"id" => id}}) do
|
||||
String.starts_with?(id, Pleroma.Web.base_url() <> "/")
|
||||
end
|
||||
|
||||
def replies(object, opts \\ []) do
|
||||
object = Object.normalize(object)
|
||||
|
||||
query =
|
||||
Object
|
||||
|> where(
|
||||
[o],
|
||||
fragment("(?)->>'inReplyTo' = ?", o.data, ^object.data["id"])
|
||||
)
|
||||
|> order_by([o], asc: o.id)
|
||||
|
||||
if opts[:self_only] do
|
||||
actor = object.data["actor"]
|
||||
where(query, [o], fragment("(?)->>'actor' = ?", o.data, ^actor))
|
||||
else
|
||||
query
|
||||
end
|
||||
end
|
||||
|
||||
def self_replies(object, opts \\ []),
|
||||
do: replies(object, Keyword.put(opts, :self_only, true))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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.Object.Containment do
|
||||
|
|
@ -39,15 +39,8 @@ defmodule Pleroma.Object.Containment do
|
|||
defp compare_uris(_, %URI{scheme: "tag"}), do: :ok
|
||||
end
|
||||
|
||||
defp compare_uris(%URI{} = id_uri, %URI{} = other_uri) do
|
||||
if id_uri.host == other_uri.host do
|
||||
:ok
|
||||
else
|
||||
:error
|
||||
end
|
||||
end
|
||||
|
||||
defp compare_uris(_, _), do: :error
|
||||
defp compare_uris(%URI{host: host} = _id_uri, %URI{host: host} = _other_uri), do: :ok
|
||||
defp compare_uris(_id_uri, _other_uri), do: :error
|
||||
|
||||
@doc """
|
||||
Checks that an imported AP object's actor matches the domain it came from.
|
||||
|
|
|
|||
|
|
@ -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.Object.Fetcher do
|
||||
|
|
@ -10,6 +10,7 @@ defmodule Pleroma.Object.Fetcher do
|
|||
alias Pleroma.Signature
|
||||
alias Pleroma.Web.ActivityPub.InternalFetchActor
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
alias Pleroma.Web.Federator
|
||||
|
||||
require Logger
|
||||
require Pleroma.Constants
|
||||
|
|
@ -59,20 +60,23 @@ defmodule Pleroma.Object.Fetcher do
|
|||
end
|
||||
end
|
||||
|
||||
# TODO:
|
||||
# This will create a Create activity, which we need internally at the moment.
|
||||
# Note: will create a Create activity, which we need internally at the moment.
|
||||
def fetch_object_from_id(id, options \\ []) do
|
||||
with {:fetch_object, nil} <- {:fetch_object, Object.get_cached_by_ap_id(id)},
|
||||
{:fetch, {:ok, data}} <- {:fetch, fetch_and_contain_remote_object_from_id(id)},
|
||||
{:normalize, nil} <- {:normalize, Object.normalize(data, false)},
|
||||
with {_, nil} <- {:fetch_object, Object.get_cached_by_ap_id(id)},
|
||||
{_, true} <- {:allowed_depth, Federator.allowed_thread_distance?(options[:depth])},
|
||||
{_, {:ok, data}} <- {:fetch, fetch_and_contain_remote_object_from_id(id)},
|
||||
{_, nil} <- {:normalize, Object.normalize(data, false)},
|
||||
params <- prepare_activity_params(data),
|
||||
{:containment, :ok} <- {:containment, Containment.contain_origin(id, params)},
|
||||
{:transmogrifier, {:ok, activity}} <-
|
||||
{_, :ok} <- {:containment, Containment.contain_origin(id, params)},
|
||||
{_, {:ok, activity}} <-
|
||||
{:transmogrifier, Transmogrifier.handle_incoming(params, options)},
|
||||
{:object, _data, %Object{} = object} <-
|
||||
{_, _data, %Object{} = object} <-
|
||||
{:object, data, Object.normalize(activity, false)} do
|
||||
{:ok, object}
|
||||
else
|
||||
{:allowed_depth, false} ->
|
||||
{:error, "Max thread distance exceeded."}
|
||||
|
||||
{:containment, _} ->
|
||||
{:error, "Object containment failed."}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.Pagination do
|
||||
|
|
@ -12,11 +12,15 @@ defmodule Pleroma.Pagination do
|
|||
|
||||
alias Pleroma.Repo
|
||||
|
||||
@type type :: :keyset | :offset
|
||||
|
||||
@default_limit 20
|
||||
@max_limit 40
|
||||
@page_keys ["max_id", "min_id", "limit", "since_id", "order"]
|
||||
|
||||
def page_keys, do: @page_keys
|
||||
|
||||
@spec fetch_paginated(Ecto.Query.t(), map(), type(), atom() | nil) :: [Ecto.Schema.t()]
|
||||
def fetch_paginated(query, params, type \\ :keyset, table_binding \\ nil)
|
||||
|
||||
def fetch_paginated(query, %{"total" => true} = params, :keyset, table_binding) do
|
||||
|
|
@ -57,6 +61,7 @@ defmodule Pleroma.Pagination do
|
|||
|> Repo.all()
|
||||
end
|
||||
|
||||
@spec paginate(Ecto.Query.t(), map(), type(), atom() | nil) :: [Ecto.Schema.t()]
|
||||
def paginate(query, options, method \\ :keyset, table_binding \\ nil)
|
||||
|
||||
def paginate(query, options, :keyset, table_binding) do
|
||||
|
|
@ -130,7 +135,11 @@ defmodule Pleroma.Pagination do
|
|||
end
|
||||
|
||||
defp restrict(query, :limit, options, _table_binding) do
|
||||
limit = Map.get(options, :limit, @default_limit)
|
||||
limit =
|
||||
case Map.get(options, :limit, @default_limit) do
|
||||
limit when limit < @max_limit -> limit
|
||||
_ -> @max_limit
|
||||
end
|
||||
|
||||
query
|
||||
|> limit(^limit)
|
||||
|
|
|
|||
|
|
@ -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.Plugs.HTTPSecurityPlug do
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
# 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.Web.Plugs.HTTPSignaturePlug do
|
||||
import Plug.Conn
|
||||
import Phoenix.Controller, only: [get_format: 1, text: 2]
|
||||
require Logger
|
||||
|
||||
def init(options) do
|
||||
|
|
@ -15,25 +16,27 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
|
|||
end
|
||||
|
||||
def call(conn, _opts) do
|
||||
headers = get_req_header(conn, "signature")
|
||||
signature = Enum.at(headers, 0)
|
||||
if get_format(conn) == "activity+json" do
|
||||
conn
|
||||
|> maybe_assign_valid_signature()
|
||||
|> maybe_require_signature()
|
||||
else
|
||||
conn
|
||||
end
|
||||
end
|
||||
|
||||
if signature do
|
||||
defp maybe_assign_valid_signature(conn) do
|
||||
if has_signature_header?(conn) do
|
||||
# set (request-target) header to the appropriate value
|
||||
# we also replace the digest header with the one we computed
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header(
|
||||
"(request-target)",
|
||||
String.downcase("#{conn.method}") <> " #{conn.request_path}"
|
||||
)
|
||||
request_target = String.downcase("#{conn.method}") <> " #{conn.request_path}"
|
||||
|
||||
conn =
|
||||
if conn.assigns[:digest] do
|
||||
conn
|
||||
|> put_req_header("digest", conn.assigns[:digest])
|
||||
else
|
||||
conn
|
||||
conn
|
||||
|> put_req_header("(request-target)", request_target)
|
||||
|> case do
|
||||
%{assigns: %{digest: digest}} = conn -> put_req_header(conn, "digest", digest)
|
||||
conn -> conn
|
||||
end
|
||||
|
||||
assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn))
|
||||
|
|
@ -42,4 +45,21 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
|
|||
conn
|
||||
end
|
||||
end
|
||||
|
||||
defp has_signature_header?(conn) do
|
||||
conn |> get_req_header("signature") |> Enum.at(0, false)
|
||||
end
|
||||
|
||||
defp maybe_require_signature(%{assigns: %{valid_signature: true}} = conn), do: conn
|
||||
|
||||
defp maybe_require_signature(conn) do
|
||||
if Pleroma.Config.get([:activitypub, :authorized_fetch_mode], false) do
|
||||
conn
|
||||
|> put_status(:unauthorized)
|
||||
|> text("Request not signed")
|
||||
|> halt()
|
||||
else
|
||||
conn
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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.Plugs.OAuthScopesPlug do
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ defmodule Pleroma.Plugs.RateLimiter.LimiterSupervisor do
|
|||
DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
|
||||
end
|
||||
|
||||
def add_limiter(limiter_name, expiration) do
|
||||
{:ok, _pid} =
|
||||
def add_or_return_limiter(limiter_name, expiration) do
|
||||
result =
|
||||
DynamicSupervisor.start_child(
|
||||
__MODULE__,
|
||||
%{
|
||||
|
|
@ -28,6 +28,12 @@ defmodule Pleroma.Plugs.RateLimiter.LimiterSupervisor do
|
|||
]}
|
||||
}
|
||||
)
|
||||
|
||||
case result do
|
||||
{:ok, _pid} = result -> result
|
||||
{:error, {:already_started, pid}} -> {:ok, pid}
|
||||
_ -> result
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
|
|
|||
|
|
@ -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.Plugs.RateLimiter do
|
||||
|
|
@ -7,12 +7,14 @@ defmodule Pleroma.Plugs.RateLimiter do
|
|||
|
||||
## Configuration
|
||||
|
||||
A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration. The basic configuration is a tuple where:
|
||||
A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration.
|
||||
The basic configuration is a tuple where:
|
||||
|
||||
* The first element: `scale` (Integer). The time scale in milliseconds.
|
||||
* The second element: `limit` (Integer). How many requests to limit in the time scale provided.
|
||||
|
||||
It is also possible to have different limits for unauthenticated and authenticated users: the keyword value must be a list of two tuples where the first one is a config for unauthenticated users and the second one is for authenticated.
|
||||
It is also possible to have different limits for unauthenticated and authenticated users: the keyword value must be a
|
||||
list of two tuples where the first one is a config for unauthenticated users and the second one is for authenticated.
|
||||
|
||||
To disable a limiter set its value to `nil`.
|
||||
|
||||
|
|
@ -64,91 +66,102 @@ defmodule Pleroma.Plugs.RateLimiter do
|
|||
import Pleroma.Web.TranslationHelpers
|
||||
import Plug.Conn
|
||||
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Plugs.RateLimiter.LimiterSupervisor
|
||||
alias Pleroma.User
|
||||
|
||||
require Logger
|
||||
|
||||
def init(opts) do
|
||||
limiter_name = Keyword.get(opts, :name)
|
||||
@doc false
|
||||
def init(plug_opts) do
|
||||
plug_opts
|
||||
end
|
||||
|
||||
case Pleroma.Config.get([:rate_limit, limiter_name]) do
|
||||
nil ->
|
||||
nil
|
||||
|
||||
config ->
|
||||
name_root = Keyword.get(opts, :bucket_name, limiter_name)
|
||||
|
||||
%{
|
||||
name: name_root,
|
||||
limits: config,
|
||||
opts: opts
|
||||
}
|
||||
def call(conn, plug_opts) do
|
||||
if disabled?() do
|
||||
handle_disabled(conn)
|
||||
else
|
||||
action_settings = action_settings(plug_opts)
|
||||
handle(conn, action_settings)
|
||||
end
|
||||
end
|
||||
|
||||
# Do not limit if there is no limiter configuration
|
||||
def call(conn, nil), do: conn
|
||||
defp handle_disabled(conn) do
|
||||
if Config.get(:env) == :prod do
|
||||
Logger.warn("Rate limiter is disabled for localhost/socket")
|
||||
end
|
||||
|
||||
def call(conn, settings) do
|
||||
case disabled?() do
|
||||
true ->
|
||||
if Pleroma.Config.get(:env) == :prod,
|
||||
do: Logger.warn("Rate limiter is disabled for localhost/socket")
|
||||
conn
|
||||
end
|
||||
|
||||
defp handle(conn, nil), do: conn
|
||||
|
||||
defp handle(conn, action_settings) do
|
||||
action_settings
|
||||
|> incorporate_conn_info(conn)
|
||||
|> check_rate()
|
||||
|> case do
|
||||
{:ok, _count} ->
|
||||
conn
|
||||
|
||||
false ->
|
||||
settings
|
||||
|> incorporate_conn_info(conn)
|
||||
|> check_rate()
|
||||
|> case do
|
||||
{:ok, _count} ->
|
||||
conn
|
||||
|
||||
{:error, _count} ->
|
||||
render_throttled_error(conn)
|
||||
end
|
||||
{:error, _count} ->
|
||||
render_throttled_error(conn)
|
||||
end
|
||||
end
|
||||
|
||||
def disabled? do
|
||||
localhost_or_socket =
|
||||
Pleroma.Config.get([Pleroma.Web.Endpoint, :http, :ip])
|
||||
Config.get([Pleroma.Web.Endpoint, :http, :ip])
|
||||
|> Tuple.to_list()
|
||||
|> Enum.join(".")
|
||||
|> String.match?(~r/^local|^127.0.0.1/)
|
||||
|
||||
remote_ip_disabled = not Pleroma.Config.get([Pleroma.Plugs.RemoteIp, :enabled])
|
||||
remote_ip_disabled = not Config.get([Pleroma.Plugs.RemoteIp, :enabled])
|
||||
|
||||
localhost_or_socket and remote_ip_disabled
|
||||
end
|
||||
|
||||
def inspect_bucket(conn, name_root, settings) do
|
||||
settings =
|
||||
settings
|
||||
|> incorporate_conn_info(conn)
|
||||
@inspect_bucket_not_found {:error, :not_found}
|
||||
|
||||
bucket_name = make_bucket_name(%{settings | name: name_root})
|
||||
key_name = make_key_name(settings)
|
||||
limit = get_limits(settings)
|
||||
def inspect_bucket(conn, bucket_name_root, plug_opts) do
|
||||
with %{name: _} = action_settings <- action_settings(plug_opts) do
|
||||
action_settings = incorporate_conn_info(action_settings, conn)
|
||||
bucket_name = make_bucket_name(%{action_settings | name: bucket_name_root})
|
||||
key_name = make_key_name(action_settings)
|
||||
limit = get_limits(action_settings)
|
||||
|
||||
case Cachex.get(bucket_name, key_name) do
|
||||
{:error, :no_cache} ->
|
||||
{:err, :not_found}
|
||||
case Cachex.get(bucket_name, key_name) do
|
||||
{:error, :no_cache} ->
|
||||
@inspect_bucket_not_found
|
||||
|
||||
{:ok, nil} ->
|
||||
{0, limit}
|
||||
{:ok, nil} ->
|
||||
{0, limit}
|
||||
|
||||
{:ok, value} ->
|
||||
{value, limit - value}
|
||||
{:ok, value} ->
|
||||
{value, limit - value}
|
||||
end
|
||||
else
|
||||
_ -> @inspect_bucket_not_found
|
||||
end
|
||||
end
|
||||
|
||||
defp check_rate(settings) do
|
||||
bucket_name = make_bucket_name(settings)
|
||||
key_name = make_key_name(settings)
|
||||
limit = get_limits(settings)
|
||||
def action_settings(plug_opts) do
|
||||
with limiter_name when is_atom(limiter_name) <- plug_opts[:name],
|
||||
limits when not is_nil(limits) <- Config.get([:rate_limit, limiter_name]) do
|
||||
bucket_name_root = Keyword.get(plug_opts, :bucket_name, limiter_name)
|
||||
|
||||
%{
|
||||
name: bucket_name_root,
|
||||
limits: limits,
|
||||
opts: plug_opts
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
defp check_rate(action_settings) do
|
||||
bucket_name = make_bucket_name(action_settings)
|
||||
key_name = make_key_name(action_settings)
|
||||
limit = get_limits(action_settings)
|
||||
|
||||
case Cachex.get_and_update(bucket_name, key_name, &increment_value(&1, limit)) do
|
||||
{:commit, value} ->
|
||||
|
|
@ -158,8 +171,8 @@ defmodule Pleroma.Plugs.RateLimiter do
|
|||
{:error, value}
|
||||
|
||||
{:error, :no_cache} ->
|
||||
initialize_buckets(settings)
|
||||
check_rate(settings)
|
||||
initialize_buckets!(action_settings)
|
||||
check_rate(action_settings)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -169,16 +182,19 @@ defmodule Pleroma.Plugs.RateLimiter do
|
|||
|
||||
defp increment_value(val, _limit), do: {:commit, val + 1}
|
||||
|
||||
defp incorporate_conn_info(settings, %{assigns: %{user: %User{id: user_id}}, params: params}) do
|
||||
Map.merge(settings, %{
|
||||
defp incorporate_conn_info(action_settings, %{
|
||||
assigns: %{user: %User{id: user_id}},
|
||||
params: params
|
||||
}) do
|
||||
Map.merge(action_settings, %{
|
||||
mode: :user,
|
||||
conn_params: params,
|
||||
conn_info: "#{user_id}"
|
||||
})
|
||||
end
|
||||
|
||||
defp incorporate_conn_info(settings, %{params: params} = conn) do
|
||||
Map.merge(settings, %{
|
||||
defp incorporate_conn_info(action_settings, %{params: params} = conn) do
|
||||
Map.merge(action_settings, %{
|
||||
mode: :anon,
|
||||
conn_params: params,
|
||||
conn_info: "#{ip(conn)}"
|
||||
|
|
@ -197,10 +213,10 @@ defmodule Pleroma.Plugs.RateLimiter do
|
|||
|> halt()
|
||||
end
|
||||
|
||||
defp make_key_name(settings) do
|
||||
defp make_key_name(action_settings) do
|
||||
""
|
||||
|> attach_params(settings)
|
||||
|> attach_identity(settings)
|
||||
|> attach_selected_params(action_settings)
|
||||
|> attach_identity(action_settings)
|
||||
end
|
||||
|
||||
defp get_scale(_, {scale, _}), do: scale
|
||||
|
|
@ -215,28 +231,35 @@ defmodule Pleroma.Plugs.RateLimiter do
|
|||
|
||||
defp get_limits(%{limits: [{_, limit}, _]}), do: limit
|
||||
|
||||
defp make_bucket_name(%{mode: :user, name: name_root}),
|
||||
do: user_bucket_name(name_root)
|
||||
defp make_bucket_name(%{mode: :user, name: bucket_name_root}),
|
||||
do: user_bucket_name(bucket_name_root)
|
||||
|
||||
defp make_bucket_name(%{mode: :anon, name: name_root}),
|
||||
do: anon_bucket_name(name_root)
|
||||
defp make_bucket_name(%{mode: :anon, name: bucket_name_root}),
|
||||
do: anon_bucket_name(bucket_name_root)
|
||||
|
||||
defp attach_params(input, %{conn_params: conn_params, opts: opts}) do
|
||||
param_string =
|
||||
opts
|
||||
defp attach_selected_params(input, %{conn_params: conn_params, opts: plug_opts}) do
|
||||
params_string =
|
||||
plug_opts
|
||||
|> Keyword.get(:params, [])
|
||||
|> Enum.sort()
|
||||
|> Enum.map(&Map.get(conn_params, &1, ""))
|
||||
|> Enum.join(":")
|
||||
|
||||
"#{input}#{param_string}"
|
||||
[input, params_string]
|
||||
|> Enum.join(":")
|
||||
|> String.replace_leading(":", "")
|
||||
end
|
||||
|
||||
defp initialize_buckets(%{name: _name, limits: nil}), do: :ok
|
||||
defp initialize_buckets!(%{name: _name, limits: nil}), do: :ok
|
||||
|
||||
defp initialize_buckets(%{name: name, limits: limits}) do
|
||||
LimiterSupervisor.add_limiter(anon_bucket_name(name), get_scale(:anon, limits))
|
||||
LimiterSupervisor.add_limiter(user_bucket_name(name), get_scale(:user, limits))
|
||||
defp initialize_buckets!(%{name: name, limits: limits}) do
|
||||
{:ok, _pid} =
|
||||
LimiterSupervisor.add_or_return_limiter(anon_bucket_name(name), get_scale(:anon, limits))
|
||||
|
||||
{:ok, _pid} =
|
||||
LimiterSupervisor.add_or_return_limiter(user_bucket_name(name), get_scale(:user, limits))
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
defp attach_identity(base, %{mode: :user, conn_info: conn_info}),
|
||||
|
|
@ -245,6 +268,6 @@ defmodule Pleroma.Plugs.RateLimiter do
|
|||
defp attach_identity(base, %{mode: :anon, conn_info: conn_info}),
|
||||
do: "ip:#{base}:#{conn_info}"
|
||||
|
||||
defp user_bucket_name(name_root), do: "user:#{name_root}" |> String.to_atom()
|
||||
defp anon_bucket_name(name_root), do: "anon:#{name_root}" |> String.to_atom()
|
||||
defp user_bucket_name(bucket_name_root), do: "user:#{bucket_name_root}" |> String.to_atom()
|
||||
defp anon_bucket_name(bucket_name_root), do: "anon:#{bucket_name_root}" |> String.to_atom()
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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.Plugs.RemoteIp do
|
||||
|
|
|
|||
|
|
@ -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.Plugs.UserEnabledPlug do
|
||||
|
|
|
|||
|
|
@ -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.Plugs.UserIsAdminPlug do
|
||||
|
|
|
|||
|
|
@ -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 do
|
||||
|
|
|
|||
|
|
@ -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.ScheduledActivity do
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
# 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.Stats do
|
||||
import Ecto.Query
|
||||
alias Pleroma.CounterCache
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
|
||||
|
|
@ -96,4 +97,21 @@ defmodule Pleroma.Stats do
|
|||
}
|
||||
}
|
||||
end
|
||||
|
||||
def get_status_visibility_count do
|
||||
counter_cache =
|
||||
CounterCache.get_as_map([
|
||||
"status_visibility_public",
|
||||
"status_visibility_private",
|
||||
"status_visibility_unlisted",
|
||||
"status_visibility_direct"
|
||||
])
|
||||
|
||||
%{
|
||||
public: counter_cache["status_visibility_public"] || 0,
|
||||
unlisted: counter_cache["status_visibility_unlisted"] || 0,
|
||||
private: counter_cache["status_visibility_private"] || 0,
|
||||
direct: counter_cache["status_visibility_direct"] || 0
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ defmodule Pleroma.Upload do
|
|||
Plug.Upload.t()
|
||||
| (data_uri_string :: String.t())
|
||||
| {:from_local, name :: String.t(), id :: String.t(), path :: String.t()}
|
||||
| map()
|
||||
|
||||
@type option ::
|
||||
{:type, :avatar | :banner | :background}
|
||||
|
|
|
|||
|
|
@ -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.Uploaders.Local do
|
||||
|
|
|
|||
|
|
@ -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.Uploaders.S3 do
|
||||
|
|
|
|||
|
|
@ -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.Uploaders.Uploader do
|
||||
|
|
|
|||
|
|
@ -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.User do
|
||||
|
|
@ -749,9 +749,18 @@ defmodule Pleroma.User do
|
|||
Cachex.del(:user_cache, "nickname:#{user.nickname}")
|
||||
end
|
||||
|
||||
@spec get_cached_by_ap_id(String.t()) :: User.t() | nil
|
||||
def get_cached_by_ap_id(ap_id) do
|
||||
key = "ap_id:#{ap_id}"
|
||||
Cachex.fetch!(:user_cache, key, fn _ -> get_by_ap_id(ap_id) end)
|
||||
|
||||
with {:ok, nil} <- Cachex.get(:user_cache, key),
|
||||
user when not is_nil(user) <- get_by_ap_id(ap_id),
|
||||
{:ok, true} <- Cachex.put(:user_cache, key, user) do
|
||||
user
|
||||
else
|
||||
{:ok, user} -> user
|
||||
nil -> nil
|
||||
end
|
||||
end
|
||||
|
||||
def get_cached_by_id(id) do
|
||||
|
|
@ -853,14 +862,14 @@ defmodule Pleroma.User do
|
|||
@spec get_followers_query(User.t()) :: Ecto.Query.t()
|
||||
def get_followers_query(user), do: get_followers_query(user, nil)
|
||||
|
||||
@spec get_followers(User.t(), pos_integer()) :: {:ok, list(User.t())}
|
||||
@spec get_followers(User.t(), pos_integer() | nil) :: {:ok, list(User.t())}
|
||||
def get_followers(user, page \\ nil) do
|
||||
user
|
||||
|> get_followers_query(page)
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
@spec get_external_followers(User.t(), pos_integer()) :: {:ok, list(User.t())}
|
||||
@spec get_external_followers(User.t(), pos_integer() | nil) :: {:ok, list(User.t())}
|
||||
def get_external_followers(user, page \\ nil) do
|
||||
user
|
||||
|> get_followers_query(page)
|
||||
|
|
@ -1304,7 +1313,6 @@ defmodule Pleroma.User do
|
|||
Repo.delete(user)
|
||||
end
|
||||
|
||||
@spec perform(atom(), User.t()) :: {:ok, User.t()}
|
||||
def perform(:fetch_initial_posts, %User{} = user) do
|
||||
pages = Pleroma.Config.get!([:fetch_initial_posts, :pages])
|
||||
|
||||
|
|
@ -1336,7 +1344,6 @@ defmodule Pleroma.User do
|
|||
)
|
||||
end
|
||||
|
||||
@spec perform(atom(), User.t(), list()) :: list() | {:error, any()}
|
||||
def perform(:follow_import, %User{} = follower, followed_identifiers)
|
||||
when is_list(followed_identifiers) do
|
||||
Enum.map(
|
||||
|
|
|
|||
|
|
@ -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.User.Query do
|
||||
|
|
@ -48,7 +48,7 @@ defmodule Pleroma.User.Query do
|
|||
followers: User.t(),
|
||||
friends: User.t(),
|
||||
recipients_from_activity: [String.t()],
|
||||
nickname: [String.t()],
|
||||
nickname: [String.t()] | String.t(),
|
||||
ap_id: [String.t()],
|
||||
order_by: term(),
|
||||
select: term(),
|
||||
|
|
|
|||
|
|
@ -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.User.Search do
|
||||
|
|
@ -33,9 +33,15 @@ defmodule Pleroma.User.Search do
|
|||
# Strip the beginning @ off if there is a query
|
||||
query_string = String.trim_leading(query_string, "@")
|
||||
|
||||
with [name, domain] <- String.split(query_string, "@"),
|
||||
formatted_domain <- String.replace(domain, ~r/[!-\-|@|[-`|{-~|\/|:|\s]+/, "") do
|
||||
name <> "@" <> to_string(:idna.encode(formatted_domain))
|
||||
with [name, domain] <- String.split(query_string, "@") do
|
||||
encoded_domain =
|
||||
domain
|
||||
|> String.replace(~r/[!-\-|@|[-`|{-~|\/|:|\s]+/, "")
|
||||
|> String.to_charlist()
|
||||
|> :idna.encode()
|
||||
|> to_string()
|
||||
|
||||
name <> "@" <> encoded_domain
|
||||
else
|
||||
_ -> query_string
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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.UserRelationship do
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
alias Pleroma.Activity.Ir.Topics
|
||||
alias Pleroma.ActivityExpiration
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Constants
|
||||
alias Pleroma.Conversation
|
||||
alias Pleroma.Conversation.Participation
|
||||
alias Pleroma.Notification
|
||||
|
|
@ -125,6 +126,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
def increase_poll_votes_if_vote(_create_data), do: :noop
|
||||
|
||||
@spec insert(map(), boolean(), boolean(), boolean()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when is_map(map) do
|
||||
with nil <- Activity.normalize(map),
|
||||
map <- lazy_put_activity_defaults(map, fake),
|
||||
|
|
@ -242,12 +244,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
:noop
|
||||
end
|
||||
|
||||
def create(%{to: to, actor: actor, context: context, object: object} = params, fake \\ false) do
|
||||
@spec create(map(), boolean()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def create(params, fake \\ false) do
|
||||
with {:ok, result} <- Repo.transaction(fn -> do_create(params, fake) end) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defp do_create(%{to: to, actor: actor, context: context, object: object} = params, fake) do
|
||||
additional = params[:additional] || %{}
|
||||
# only accept false as false value
|
||||
local = !(params[:local] == false)
|
||||
published = params[:published]
|
||||
quick_insert? = Pleroma.Config.get([:env]) == :benchmark
|
||||
quick_insert? = Config.get([:env]) == :benchmark
|
||||
|
||||
with create_data <-
|
||||
make_create_data(
|
||||
|
|
@ -270,10 +279,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
{:ok, activity}
|
||||
|
||||
{:error, message} ->
|
||||
{:error, message}
|
||||
Repo.rollback(message)
|
||||
end
|
||||
end
|
||||
|
||||
@spec listen(map()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def listen(%{to: to, actor: actor, context: context, object: object} = params) do
|
||||
additional = params[:additional] || %{}
|
||||
# only accept false as false value
|
||||
|
|
@ -288,20 +298,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
{:ok, activity} <- insert(listen_data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:error, message} ->
|
||||
{:error, message}
|
||||
end
|
||||
end
|
||||
|
||||
@spec accept(map()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def accept(params) do
|
||||
accept_or_reject("Accept", params)
|
||||
end
|
||||
|
||||
@spec reject(map()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def reject(params) do
|
||||
accept_or_reject("Reject", params)
|
||||
end
|
||||
|
||||
@spec accept_or_reject(String.t(), map()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def accept_or_reject(type, %{to: to, actor: actor, object: object} = params) do
|
||||
local = Map.get(params, :local, true)
|
||||
activity_id = Map.get(params, :activity_id, nil)
|
||||
|
|
@ -315,6 +325,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
end
|
||||
|
||||
@spec update(map()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def update(%{to: to, cc: cc, actor: actor, object: object} = params) do
|
||||
local = !(params[:local] == false)
|
||||
activity_id = params[:activity_id]
|
||||
|
|
@ -333,7 +344,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
end
|
||||
|
||||
@spec react_with_emoji(User.t(), Object.t(), String.t(), keyword()) ::
|
||||
{:ok, Activity.t(), Object.t()} | {:error, any()}
|
||||
def react_with_emoji(user, object, emoji, options \\ []) do
|
||||
with {:ok, result} <-
|
||||
Repo.transaction(fn -> do_react_with_emoji(user, object, emoji, options) end) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defp do_react_with_emoji(user, object, emoji, options) do
|
||||
with local <- Keyword.get(options, :local, true),
|
||||
activity_id <- Keyword.get(options, :activity_id, nil),
|
||||
true <- Pleroma.Emoji.is_unicode_emoji?(emoji),
|
||||
|
|
@ -343,11 +363,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity, object}
|
||||
else
|
||||
e -> {:error, e}
|
||||
false -> {:error, false}
|
||||
{:error, error} -> Repo.rollback(error)
|
||||
end
|
||||
end
|
||||
|
||||
@spec unreact_with_emoji(User.t(), String.t(), keyword()) ::
|
||||
{:ok, Activity.t(), Object.t()} | {:error, any()}
|
||||
def unreact_with_emoji(user, reaction_id, options \\ []) do
|
||||
with {:ok, result} <-
|
||||
Repo.transaction(fn -> do_unreact_with_emoji(user, reaction_id, options) end) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defp do_unreact_with_emoji(user, reaction_id, options) do
|
||||
with local <- Keyword.get(options, :local, true),
|
||||
activity_id <- Keyword.get(options, :activity_id, nil),
|
||||
user_ap_id <- user.ap_id,
|
||||
|
|
@ -359,17 +389,25 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity, object}
|
||||
else
|
||||
e -> {:error, e}
|
||||
{:error, error} -> Repo.rollback(error)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: This is weird, maybe we shouldn't check here if we can make the activity.
|
||||
def like(
|
||||
%User{ap_id: ap_id} = user,
|
||||
%Object{data: %{"id" => _}} = object,
|
||||
activity_id \\ nil,
|
||||
local \\ true
|
||||
) do
|
||||
@spec like(User.t(), Object.t(), String.t() | nil, boolean()) ::
|
||||
{:ok, Activity.t(), Object.t()} | {:error, any()}
|
||||
def like(user, object, activity_id \\ nil, local \\ true) do
|
||||
with {:ok, result} <- Repo.transaction(fn -> do_like(user, object, activity_id, local) end) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defp do_like(
|
||||
%User{ap_id: ap_id} = user,
|
||||
%Object{data: %{"id" => _}} = object,
|
||||
activity_id,
|
||||
local
|
||||
) do
|
||||
with nil <- get_existing_like(ap_id, object),
|
||||
like_data <- make_like_data(user, object, activity_id),
|
||||
{:ok, activity} <- insert(like_data, local),
|
||||
|
|
@ -377,12 +415,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity, object}
|
||||
else
|
||||
%Activity{} = activity -> {:ok, activity, object}
|
||||
error -> {:error, error}
|
||||
%Activity{} = activity ->
|
||||
{:ok, activity, object}
|
||||
|
||||
{:error, error} ->
|
||||
Repo.rollback(error)
|
||||
end
|
||||
end
|
||||
|
||||
@spec unlike(User.t(), Object.t(), String.t() | nil, boolean()) ::
|
||||
{:ok, Activity.t(), Activity.t(), Object.t()} | {:ok, Object.t()} | {:error, any()}
|
||||
def unlike(%User{} = actor, %Object{} = object, activity_id \\ nil, local \\ true) do
|
||||
with {:ok, result} <-
|
||||
Repo.transaction(fn -> do_unlike(actor, object, activity_id, local) end) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defp do_unlike(actor, object, activity_id, local) do
|
||||
with %Activity{} = like_activity <- get_existing_like(actor.ap_id, object),
|
||||
unlike_data <- make_unlike_data(actor, like_activity, activity_id),
|
||||
{:ok, unlike_activity} <- insert(unlike_data, local),
|
||||
|
|
@ -391,10 +441,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
:ok <- maybe_federate(unlike_activity) do
|
||||
{:ok, unlike_activity, like_activity, object}
|
||||
else
|
||||
_e -> {:ok, object}
|
||||
nil -> {:ok, object}
|
||||
{:error, error} -> Repo.rollback(error)
|
||||
end
|
||||
end
|
||||
|
||||
@spec announce(User.t(), Object.t(), String.t() | nil, boolean(), boolean()) ::
|
||||
{:ok, Activity.t(), Object.t()} | {:error, any()}
|
||||
def announce(
|
||||
%User{ap_id: _} = user,
|
||||
%Object{data: %{"id" => _}} = object,
|
||||
|
|
@ -402,6 +455,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
local \\ true,
|
||||
public \\ true
|
||||
) do
|
||||
with {:ok, result} <-
|
||||
Repo.transaction(fn -> do_announce(user, object, activity_id, local, public) end) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defp do_announce(user, object, activity_id, local, public) do
|
||||
with true <- is_announceable?(object, user, public),
|
||||
announce_data <- make_announce_data(user, object, activity_id, public),
|
||||
{:ok, activity} <- insert(announce_data, local),
|
||||
|
|
@ -409,16 +469,26 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity, object}
|
||||
else
|
||||
error -> {:error, error}
|
||||
false -> {:error, false}
|
||||
{:error, error} -> Repo.rollback(error)
|
||||
end
|
||||
end
|
||||
|
||||
@spec unannounce(User.t(), Object.t(), String.t() | nil, boolean()) ::
|
||||
{:ok, Activity.t(), Object.t()} | {:ok, Object.t()} | {:error, any()}
|
||||
def unannounce(
|
||||
%User{} = actor,
|
||||
%Object{} = object,
|
||||
activity_id \\ nil,
|
||||
local \\ true
|
||||
) do
|
||||
with {:ok, result} <-
|
||||
Repo.transaction(fn -> do_unannounce(actor, object, activity_id, local) end) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defp do_unannounce(actor, object, activity_id, local) do
|
||||
with %Activity{} = announce_activity <- get_existing_announce(actor.ap_id, object),
|
||||
unannounce_data <- make_unannounce_data(actor, announce_activity, activity_id),
|
||||
{:ok, unannounce_activity} <- insert(unannounce_data, local),
|
||||
|
|
@ -427,30 +497,61 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
{:ok, object} <- remove_announce_from_object(announce_activity, object) do
|
||||
{:ok, unannounce_activity, object}
|
||||
else
|
||||
_e -> {:ok, object}
|
||||
nil -> {:ok, object}
|
||||
{:error, error} -> Repo.rollback(error)
|
||||
end
|
||||
end
|
||||
|
||||
@spec follow(User.t(), User.t(), String.t() | nil, boolean()) ::
|
||||
{:ok, Activity.t()} | {:error, any()}
|
||||
def follow(follower, followed, activity_id \\ nil, local \\ true) do
|
||||
with {:ok, result} <-
|
||||
Repo.transaction(fn -> do_follow(follower, followed, activity_id, local) end) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defp do_follow(follower, followed, activity_id, local) do
|
||||
with data <- make_follow_data(follower, followed, activity_id),
|
||||
{:ok, activity} <- insert(data, local),
|
||||
:ok <- maybe_federate(activity),
|
||||
_ <- User.set_follow_state_cache(follower.ap_id, followed.ap_id, activity.data["state"]) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:error, error} -> Repo.rollback(error)
|
||||
end
|
||||
end
|
||||
|
||||
@spec unfollow(User.t(), User.t(), String.t() | nil, boolean()) ::
|
||||
{:ok, Activity.t()} | nil | {:error, any()}
|
||||
def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
|
||||
with {:ok, result} <-
|
||||
Repo.transaction(fn -> do_unfollow(follower, followed, activity_id, local) end) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defp do_unfollow(follower, followed, activity_id, local) do
|
||||
with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
|
||||
{:ok, follow_activity} <- update_follow_state(follow_activity, "cancelled"),
|
||||
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
|
||||
{:ok, activity} <- insert(unfollow_data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
nil -> nil
|
||||
{:error, error} -> Repo.rollback(error)
|
||||
end
|
||||
end
|
||||
|
||||
def delete(%User{ap_id: ap_id, follower_address: follower_address} = user) do
|
||||
@spec delete(User.t() | Object.t(), keyword()) :: {:ok, User.t() | Object.t()} | {:error, any()}
|
||||
def delete(entity, options \\ []) do
|
||||
with {:ok, result} <- Repo.transaction(fn -> do_delete(entity, options) end) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defp do_delete(%User{ap_id: ap_id, follower_address: follower_address} = user, _) do
|
||||
with data <- %{
|
||||
"to" => [follower_address],
|
||||
"type" => "Delete",
|
||||
|
|
@ -463,7 +564,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
end
|
||||
|
||||
def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, options \\ []) do
|
||||
defp do_delete(%Object{data: %{"id" => id, "actor" => actor}} = object, options) do
|
||||
local = Keyword.get(options, :local, true)
|
||||
activity_id = Keyword.get(options, :activity_id, nil)
|
||||
actor = Keyword.get(options, :actor, actor)
|
||||
|
|
@ -488,11 +589,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
{:ok, _actor} <- decrease_note_count_if_public(user, object),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:error, error} ->
|
||||
Repo.rollback(error)
|
||||
end
|
||||
end
|
||||
|
||||
@spec block(User.t(), User.t(), String.t() | nil, boolean) :: {:ok, Activity.t() | nil}
|
||||
@spec block(User.t(), User.t(), String.t() | nil, boolean()) ::
|
||||
{:ok, Activity.t()} | {:error, any()}
|
||||
def block(blocker, blocked, activity_id \\ nil, local \\ true) do
|
||||
with {:ok, result} <-
|
||||
Repo.transaction(fn -> do_block(blocker, blocked, activity_id, local) end) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defp do_block(blocker, blocked, activity_id, local) do
|
||||
outgoing_blocks = Config.get([:activitypub, :outgoing_blocks])
|
||||
unfollow_blocked = Config.get([:activitypub, :unfollow_blocked])
|
||||
|
||||
|
|
@ -507,20 +619,32 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
_e -> {:ok, nil}
|
||||
{:error, error} -> Repo.rollback(error)
|
||||
end
|
||||
end
|
||||
|
||||
@spec unblock(User.t(), User.t(), String.t() | nil, boolean()) ::
|
||||
{:ok, Activity.t()} | {:error, any()} | nil
|
||||
def unblock(blocker, blocked, activity_id \\ nil, local \\ true) do
|
||||
with {:ok, result} <-
|
||||
Repo.transaction(fn -> do_unblock(blocker, blocked, activity_id, local) end) do
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
defp do_unblock(blocker, blocked, activity_id, local) do
|
||||
with %Activity{} = block_activity <- fetch_latest_block(blocker, blocked),
|
||||
unblock_data <- make_unblock_data(blocker, blocked, block_activity, activity_id),
|
||||
{:ok, activity} <- insert(unblock_data, local),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, activity}
|
||||
else
|
||||
nil -> nil
|
||||
{:error, error} -> Repo.rollback(error)
|
||||
end
|
||||
end
|
||||
|
||||
@spec flag(map()) :: {:ok, Activity.t()} | any
|
||||
@spec flag(map()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def flag(
|
||||
%{
|
||||
actor: actor,
|
||||
|
|
@ -557,6 +681,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
end
|
||||
|
||||
@spec move(User.t(), User.t(), boolean()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def move(%User{} = origin, %User{} = target, local \\ true) do
|
||||
params = %{
|
||||
"type" => "Move",
|
||||
|
|
@ -582,7 +707,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
defp fetch_activities_for_context_query(context, opts) do
|
||||
public = [Pleroma.Constants.as_public()]
|
||||
public = [Constants.as_public()]
|
||||
|
||||
recipients =
|
||||
if opts["user"],
|
||||
|
|
@ -627,10 +752,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|> Repo.one()
|
||||
end
|
||||
|
||||
@spec fetch_public_activities(map(), Pagination.type()) :: [Activity.t()]
|
||||
def fetch_public_activities(opts \\ %{}, pagination \\ :keyset) do
|
||||
opts = Map.drop(opts, ["user"])
|
||||
|
||||
[Pleroma.Constants.as_public()]
|
||||
[Constants.as_public()]
|
||||
|> fetch_activities_query(opts)
|
||||
|> restrict_unlisted()
|
||||
|> Pagination.fetch_paginated(opts, pagination)
|
||||
|
|
@ -781,13 +907,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|> Enum.reverse()
|
||||
end
|
||||
|
||||
def fetch_instance_activities(params) do
|
||||
def fetch_statuses(reading_user, params) do
|
||||
params =
|
||||
params
|
||||
|> Map.put("type", ["Create", "Announce"])
|
||||
|> Map.put("instance", params["instance"])
|
||||
|
||||
fetch_activities([Pleroma.Constants.as_public()], params, :offset)
|
||||
recipients =
|
||||
user_activities_recipients(%{
|
||||
"godmode" => params["godmode"],
|
||||
"reading_user" => reading_user
|
||||
})
|
||||
|
||||
fetch_activities(recipients, params, :offset)
|
||||
|> Enum.reverse()
|
||||
end
|
||||
|
||||
|
|
@ -797,9 +928,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
defp user_activities_recipients(%{"reading_user" => reading_user}) do
|
||||
if reading_user do
|
||||
[Pleroma.Constants.as_public()] ++ [reading_user.ap_id | User.following(reading_user)]
|
||||
[Constants.as_public()] ++ [reading_user.ap_id | User.following(reading_user)]
|
||||
else
|
||||
[Pleroma.Constants.as_public()]
|
||||
[Constants.as_public()]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1006,7 +1137,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
fragment(
|
||||
"not (coalesce(?->'cc', '{}'::jsonb) \\?| ?)",
|
||||
activity.data,
|
||||
^[Pleroma.Constants.as_public()]
|
||||
^[Constants.as_public()]
|
||||
)
|
||||
)
|
||||
end
|
||||
|
|
@ -1180,7 +1311,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
@doc """
|
||||
Fetch favorites activities of user with order by sort adds to favorites
|
||||
"""
|
||||
@spec fetch_favourites(User.t(), map(), atom()) :: list(Activity.t())
|
||||
@spec fetch_favourites(User.t(), map(), Pagination.type()) :: list(Activity.t())
|
||||
def fetch_favourites(user, params \\ %{}, pagination \\ :keyset) do
|
||||
user.ap_id
|
||||
|> Activity.Queries.by_actor()
|
||||
|
|
@ -1218,7 +1349,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
where:
|
||||
fragment("? && ?", activity.recipients, ^recipients) or
|
||||
(fragment("? && ?", activity.recipients, ^recipients_with_public) and
|
||||
^Pleroma.Constants.as_public() in activity.recipients)
|
||||
^Constants.as_public() in activity.recipients)
|
||||
)
|
||||
end
|
||||
|
||||
|
|
@ -1234,6 +1365,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|> Enum.reverse()
|
||||
end
|
||||
|
||||
@spec upload(Upload.source(), keyword()) :: {:ok, Object.t()} | {:error, any()}
|
||||
def upload(file, opts \\ []) do
|
||||
with {:ok, data} <- Upload.store(file, opts) do
|
||||
obj_data =
|
||||
|
|
@ -1331,8 +1463,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
defp normalize_counter(_), do: 0
|
||||
|
||||
defp maybe_update_follow_information(data) do
|
||||
with {:enabled, true} <-
|
||||
{:enabled, Pleroma.Config.get([:instance, :external_user_synchronization])},
|
||||
with {:enabled, true} <- {:enabled, Config.get([:instance, :external_user_synchronization])},
|
||||
{:ok, info} <- fetch_follow_information_for_user(data) do
|
||||
info = Map.merge(data[:info] || %{}, info)
|
||||
Map.put(data, :info, info)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
|
||||
|
|
@ -17,6 +17,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
|
|||
# does the post contain links?
|
||||
defp contains_links?(%{"content" => content} = _object) do
|
||||
content
|
||||
|> Floki.parse_fragment!()
|
||||
|> Floki.filter_out("a.mention,a.hashtag,a[rel~=\"tag\"],a.zrl")
|
||||
|> Floki.attribute("a", "href")
|
||||
|> length() > 0
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
|
||||
|
|
|
|||
|
|
@ -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.Web.ActivityPub.MRF.NoOpPolicy do
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
# 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.Web.ActivityPub.MRF.ObjectAgePolicy do
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
require Pleroma.Constants
|
||||
|
||||
@moduledoc "Filter activities depending on their age"
|
||||
@behaviour MRF
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
defp check_date(%{"published" => published} = message) do
|
||||
with %DateTime{} = now <- DateTime.utc_now(),
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
# 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.Web.ActivityPub.MRF.SimplePolicy do
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.MRF
|
||||
@moduledoc "Filter activities depending on their origin instance"
|
||||
@behaviour MRF
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
require Pleroma.Constants
|
||||
|
||||
|
|
|
|||
|
|
@ -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.Web.ActivityPub.MRF.SubchainPolicy do
|
||||
|
|
@ -8,7 +8,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicy do
|
|||
|
||||
require Logger
|
||||
|
||||
@behaviour MRF
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
defp lookup_subchain(actor) do
|
||||
with matches <- Config.get([:mrf_subchain, :match_actor]),
|
||||
|
|
|
|||
|
|
@ -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.Web.ActivityPub.MRF.UserAllowListPolicy do
|
||||
|
|
|
|||
|
|
@ -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.Web.ActivityPub.MRF.VocabularyPolicy do
|
||||
|
|
|
|||
|
|
@ -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.Web.ActivityPub.Publisher do
|
||||
|
|
|
|||
|
|
@ -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.Web.ActivityPub.Relay do
|
||||
|
|
|
|||
|
|
@ -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.Web.ActivityPub.Transmogrifier do
|
||||
|
|
@ -156,10 +156,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
when not is_nil(in_reply_to) do
|
||||
in_reply_to_id = prepare_in_reply_to(in_reply_to)
|
||||
object = Map.put(object, "inReplyToAtomUri", in_reply_to_id)
|
||||
depth = (options[:depth] || 0) + 1
|
||||
|
||||
if Federator.allowed_incoming_reply_depth?(options[:depth]) do
|
||||
if Federator.allowed_thread_distance?(depth) do
|
||||
with {:ok, replied_object} <- get_obj_helper(in_reply_to_id, options),
|
||||
%Activity{} = _ <- Activity.get_create_by_object_ap_id(replied_object.data["id"]) do
|
||||
%Activity{} <- Activity.get_create_by_object_ap_id(replied_object.data["id"]) do
|
||||
object
|
||||
|> Map.put("inReplyTo", replied_object.data["id"])
|
||||
|> Map.put("inReplyToAtomUri", object["inReplyToAtomUri"] || in_reply_to_id)
|
||||
|
|
@ -312,7 +313,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|
||||
def fix_type(%{"inReplyTo" => reply_id, "name" => _} = object, options)
|
||||
when is_binary(reply_id) do
|
||||
with true <- Federator.allowed_incoming_reply_depth?(options[:depth]),
|
||||
with true <- Federator.allowed_thread_distance?(options[:depth]),
|
||||
{:ok, %{data: %{"type" => "Question"} = _} = _} <- get_obj_helper(reply_id, options) do
|
||||
Map.put(object, "type", "Answer")
|
||||
else
|
||||
|
|
@ -406,8 +407,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|
||||
with nil <- Activity.get_create_by_object_ap_id(object["id"]),
|
||||
{:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(data["actor"]) do
|
||||
options = Keyword.put(options, :depth, (options[:depth] || 0) + 1)
|
||||
object = fix_object(data["object"], options)
|
||||
object = fix_object(object, options)
|
||||
|
||||
params = %{
|
||||
to: data["to"],
|
||||
|
|
@ -424,7 +424,20 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
])
|
||||
}
|
||||
|
||||
ActivityPub.create(params)
|
||||
with {:ok, created_activity} <- ActivityPub.create(params) do
|
||||
reply_depth = (options[:depth] || 0) + 1
|
||||
|
||||
if Federator.allowed_thread_distance?(reply_depth) do
|
||||
for reply_id <- replies(object) do
|
||||
Pleroma.Workers.RemoteFetcherWorker.enqueue("fetch_remote", %{
|
||||
"id" => reply_id,
|
||||
"depth" => reply_depth
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
{:ok, created_activity}
|
||||
end
|
||||
else
|
||||
%Activity{} = activity -> {:ok, activity}
|
||||
_e -> :error
|
||||
|
|
@ -442,7 +455,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|> fix_addressing
|
||||
|
||||
with {:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(data["actor"]) do
|
||||
options = Keyword.put(options, :depth, (options[:depth] || 0) + 1)
|
||||
reply_depth = (options[:depth] || 0) + 1
|
||||
options = Keyword.put(options, :depth, reply_depth)
|
||||
object = fix_object(object, options)
|
||||
|
||||
params = %{
|
||||
|
|
@ -903,6 +917,50 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|
||||
def set_reply_to_uri(obj), do: obj
|
||||
|
||||
@doc """
|
||||
Serialized Mastodon-compatible `replies` collection containing _self-replies_.
|
||||
Based on Mastodon's ActivityPub::NoteSerializer#replies.
|
||||
"""
|
||||
def set_replies(obj_data) do
|
||||
replies_uris =
|
||||
with limit when limit > 0 <-
|
||||
Pleroma.Config.get([:activitypub, :note_replies_output_limit], 0),
|
||||
%Object{} = object <- Object.get_cached_by_ap_id(obj_data["id"]) do
|
||||
object
|
||||
|> Object.self_replies()
|
||||
|> select([o], fragment("?->>'id'", o.data))
|
||||
|> limit(^limit)
|
||||
|> Repo.all()
|
||||
else
|
||||
_ -> []
|
||||
end
|
||||
|
||||
set_replies(obj_data, replies_uris)
|
||||
end
|
||||
|
||||
defp set_replies(obj, []) do
|
||||
obj
|
||||
end
|
||||
|
||||
defp set_replies(obj, replies_uris) do
|
||||
replies_collection = %{
|
||||
"type" => "Collection",
|
||||
"items" => replies_uris
|
||||
}
|
||||
|
||||
Map.merge(obj, %{"replies" => replies_collection})
|
||||
end
|
||||
|
||||
def replies(%{"replies" => %{"first" => %{"items" => items}}}) when not is_nil(items) do
|
||||
items
|
||||
end
|
||||
|
||||
def replies(%{"replies" => %{"items" => items}}) when not is_nil(items) do
|
||||
items
|
||||
end
|
||||
|
||||
def replies(_), do: []
|
||||
|
||||
# Prepares the object of an outgoing create activity.
|
||||
def prepare_object(object) do
|
||||
object
|
||||
|
|
@ -914,6 +972,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|> prepare_attachments
|
||||
|> set_conversation
|
||||
|> set_reply_to_uri
|
||||
|> set_replies
|
||||
|> strip_internal_fields
|
||||
|> strip_internal_tags
|
||||
|> set_type
|
||||
|
|
|
|||
|
|
@ -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.Web.ActivityPub.Utils do
|
||||
|
|
@ -45,8 +45,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
Map.put(params, "actor", get_ap_id(params["actor"]))
|
||||
end
|
||||
|
||||
@spec determine_explicit_mentions(map()) :: map()
|
||||
def determine_explicit_mentions(%{"tag" => tag} = _) when is_list(tag) do
|
||||
@spec determine_explicit_mentions(map()) :: [any]
|
||||
def determine_explicit_mentions(%{"tag" => tag}) when is_list(tag) do
|
||||
Enum.flat_map(tag, fn
|
||||
%{"type" => "Mention", "href" => href} -> [href]
|
||||
_ -> []
|
||||
|
|
@ -427,7 +427,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
@doc """
|
||||
Updates a follow activity's state (for locked accounts).
|
||||
"""
|
||||
@spec update_follow_state_for_all(Activity.t(), String.t()) :: {:ok, Activity} | {:error, any()}
|
||||
@spec update_follow_state_for_all(Activity.t(), String.t()) :: {:ok, Activity | nil}
|
||||
def update_follow_state_for_all(
|
||||
%Activity{data: %{"actor" => actor, "object" => object}} = activity,
|
||||
state
|
||||
|
|
|
|||
|
|
@ -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.Web.AdminAPI.AdminAPIController do
|
||||
|
|
@ -8,10 +8,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.ConfigDB
|
||||
alias Pleroma.ModerationLog
|
||||
alias Pleroma.Plugs.OAuthScopesPlug
|
||||
alias Pleroma.ReportNote
|
||||
alias Pleroma.Stats
|
||||
alias Pleroma.User
|
||||
alias Pleroma.UserInviteToken
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
|
|
@ -97,7 +99,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
plug(
|
||||
OAuthScopesPlug,
|
||||
%{scopes: ["read"], admin: true}
|
||||
when action in [:config_show, :list_log]
|
||||
when action in [:config_show, :list_log, :stats]
|
||||
)
|
||||
|
||||
plug(
|
||||
|
|
@ -242,13 +244,15 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
end
|
||||
|
||||
def list_instance_statuses(conn, %{"instance" => instance} = params) do
|
||||
with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
|
||||
{page, page_size} = page_params(params)
|
||||
|
||||
activities =
|
||||
ActivityPub.fetch_instance_activities(%{
|
||||
ActivityPub.fetch_statuses(nil, %{
|
||||
"instance" => instance,
|
||||
"limit" => page_size,
|
||||
"offset" => (page - 1) * page_size
|
||||
"offset" => (page - 1) * page_size,
|
||||
"exclude_reblogs" => !with_reblogs && "true"
|
||||
})
|
||||
|
||||
conn
|
||||
|
|
@ -257,6 +261,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
end
|
||||
|
||||
def list_user_statuses(conn, %{"nickname" => nickname} = params) do
|
||||
with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
|
||||
godmode = params["godmode"] == "true" || params["godmode"] == true
|
||||
|
||||
with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
|
||||
|
|
@ -265,7 +270,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
activities =
|
||||
ActivityPub.fetch_user_activities(user, nil, %{
|
||||
"limit" => page_size,
|
||||
"godmode" => godmode
|
||||
"godmode" => godmode,
|
||||
"exclude_reblogs" => !with_reblogs && "true"
|
||||
})
|
||||
|
||||
conn
|
||||
|
|
@ -570,8 +576,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
@doc "Sends registration invite via email"
|
||||
def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do
|
||||
with true <-
|
||||
Pleroma.Config.get([:instance, :invites_enabled]) &&
|
||||
!Pleroma.Config.get([:instance, :registrations_open]),
|
||||
Config.get([:instance, :invites_enabled]) &&
|
||||
!Config.get([:instance, :registrations_open]),
|
||||
{:ok, invite_token} <- UserInviteToken.create_invite(),
|
||||
email <-
|
||||
Pleroma.Emails.UserEmail.user_invitation_email(
|
||||
|
|
@ -739,6 +745,24 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
end
|
||||
end
|
||||
|
||||
def list_statuses(%{assigns: %{user: admin}} = conn, params) do
|
||||
godmode = params["godmode"] == "true" || params["godmode"] == true
|
||||
local_only = params["local_only"] == "true" || params["local_only"] == true
|
||||
{page, page_size} = page_params(params)
|
||||
|
||||
activities =
|
||||
ActivityPub.fetch_statuses(admin, %{
|
||||
"godmode" => godmode,
|
||||
"local_only" => local_only,
|
||||
"limit" => page_size,
|
||||
"offset" => (page - 1) * page_size
|
||||
})
|
||||
|
||||
conn
|
||||
|> put_view(Pleroma.Web.AdminAPI.StatusView)
|
||||
|> render("index.json", %{activities: activities, as: :activity})
|
||||
end
|
||||
|
||||
def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do
|
||||
with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do
|
||||
{:ok, sensitive} = Ecto.Type.cast(:boolean, params["sensitive"])
|
||||
|
|
@ -808,7 +832,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
configs = ConfigDB.get_all_as_keyword()
|
||||
|
||||
merged =
|
||||
Pleroma.Config.Holder.config()
|
||||
Config.Holder.config()
|
||||
|> ConfigDB.merge(configs)
|
||||
|> Enum.map(fn {group, values} ->
|
||||
Enum.map(values, fn {key, value} ->
|
||||
|
|
@ -838,7 +862,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
end)
|
||||
|> List.flatten()
|
||||
|
||||
json(conn, %{configs: merged})
|
||||
response = %{configs: merged}
|
||||
|
||||
response =
|
||||
if Restarter.Pleroma.need_reboot?() do
|
||||
Map.put(response, :need_reboot, true)
|
||||
else
|
||||
response
|
||||
end
|
||||
|
||||
json(conn, response)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -863,20 +896,26 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
Ecto.get_meta(config, :state) == :deleted
|
||||
end)
|
||||
|
||||
Pleroma.Config.TransferTask.load_and_update_env(deleted, false)
|
||||
Config.TransferTask.load_and_update_env(deleted, false)
|
||||
|
||||
need_reboot? =
|
||||
Enum.any?(updated, fn config ->
|
||||
group = ConfigDB.from_string(config.group)
|
||||
key = ConfigDB.from_string(config.key)
|
||||
value = ConfigDB.from_binary(config.value)
|
||||
Pleroma.Config.TransferTask.pleroma_need_restart?(group, key, value)
|
||||
end)
|
||||
Restarter.Pleroma.need_reboot?() ||
|
||||
Enum.any?(updated, fn config ->
|
||||
group = ConfigDB.from_string(config.group)
|
||||
key = ConfigDB.from_string(config.key)
|
||||
value = ConfigDB.from_binary(config.value)
|
||||
Config.TransferTask.pleroma_need_restart?(group, key, value)
|
||||
end)
|
||||
|
||||
response = %{configs: updated}
|
||||
|
||||
response =
|
||||
if need_reboot?, do: Map.put(response, :need_reboot, need_reboot?), else: response
|
||||
if need_reboot? do
|
||||
Restarter.Pleroma.need_reboot()
|
||||
Map.put(response, :need_reboot, need_reboot?)
|
||||
else
|
||||
response
|
||||
end
|
||||
|
||||
conn
|
||||
|> put_view(ConfigView)
|
||||
|
|
@ -886,18 +925,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
|
||||
def restart(conn, _params) do
|
||||
with :ok <- configurable_from_database(conn) do
|
||||
if Pleroma.Config.get(:env) == :test do
|
||||
Logger.warn("pleroma restarted")
|
||||
else
|
||||
send(Restarter.Pleroma, {:restart, 50})
|
||||
end
|
||||
Restarter.Pleroma.restart(Config.get(:env), 50)
|
||||
|
||||
json(conn, %{})
|
||||
end
|
||||
end
|
||||
|
||||
defp configurable_from_database(conn) do
|
||||
if Pleroma.Config.get(:configurable_from_database) do
|
||||
if Config.get(:configurable_from_database) do
|
||||
:ok
|
||||
else
|
||||
errors(
|
||||
|
|
@ -941,6 +976,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
conn |> json("")
|
||||
end
|
||||
|
||||
def stats(conn, _) do
|
||||
count = Stats.get_status_visibility_count()
|
||||
|
||||
conn
|
||||
|> json(%{"status_visibility" => count})
|
||||
end
|
||||
|
||||
def errors(conn, {:error, :not_found}) do
|
||||
conn
|
||||
|> put_status(:not_found)
|
||||
|
|
|
|||
|
|
@ -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.Web.AdminAPI.Search do
|
||||
|
|
@ -18,7 +18,11 @@ defmodule Pleroma.Web.AdminAPI.Search do
|
|||
|
||||
@spec user(map()) :: {:ok, [User.t()], pos_integer()}
|
||||
def user(params \\ %{}) do
|
||||
query = User.Query.build(params) |> order_by([u], u.nickname)
|
||||
query =
|
||||
params
|
||||
|> Map.drop([:page, :page_size])
|
||||
|> User.Query.build()
|
||||
|> order_by([u], u.nickname)
|
||||
|
||||
paginated_query =
|
||||
User.Query.paginate(query, params[:page] || 1, params[:page_size] || @page_size)
|
||||
|
|
|
|||
|
|
@ -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.Web.AdminAPI.ConfigView do
|
||||
|
|
|
|||
|
|
@ -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.Web.AdminAPI.StatusView do
|
||||
|
|
@ -10,7 +10,7 @@ defmodule Pleroma.Web.AdminAPI.StatusView do
|
|||
alias Pleroma.User
|
||||
|
||||
def render("index.json", opts) do
|
||||
render_many(opts.activities, __MODULE__, "show.json", opts)
|
||||
safe_render_many(opts.activities, __MODULE__, "show.json", opts)
|
||||
end
|
||||
|
||||
def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do
|
||||
|
|
|
|||
|
|
@ -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.Web.CommonAPI do
|
||||
|
|
|
|||
|
|
@ -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.Web.CommonAPI.Utils do
|
||||
|
|
@ -228,9 +228,9 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
data,
|
||||
visibility
|
||||
) do
|
||||
no_attachment_links =
|
||||
attachment_links =
|
||||
data
|
||||
|> Map.get("no_attachment_links", Config.get([:instance, :no_attachment_links]))
|
||||
|> Map.get("attachment_links", Config.get([:instance, :attachment_links]))
|
||||
|> truthy_param?()
|
||||
|
||||
content_type = get_content_type(data["content_type"])
|
||||
|
|
@ -244,7 +244,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
|
||||
status
|
||||
|> format_input(content_type, options)
|
||||
|> maybe_add_attachments(attachments, no_attachment_links)
|
||||
|> maybe_add_attachments(attachments, attachment_links)
|
||||
|> maybe_add_nsfw_tag(data)
|
||||
end
|
||||
|
||||
|
|
@ -270,7 +270,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
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
|
||||
def maybe_add_attachments(parsed, _attachments, false = _no_links), do: parsed
|
||||
|
||||
def maybe_add_attachments({text, mentions, tags}, attachments, _no_links) do
|
||||
text = add_attachments(text, attachments)
|
||||
|
|
|
|||
|
|
@ -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.Web.ControllerHelper do
|
||||
|
|
|
|||
|
|
@ -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.Web.Endpoint do
|
||||
|
|
|
|||
|
|
@ -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.Web.Federator do
|
||||
|
|
@ -15,13 +15,19 @@ defmodule Pleroma.Web.Federator do
|
|||
|
||||
require Logger
|
||||
|
||||
@doc "Addresses [memory leaks on recursive replies fetching](https://git.pleroma.social/pleroma/pleroma/issues/161)"
|
||||
@doc """
|
||||
Returns `true` if the distance to target object does not exceed max configured value.
|
||||
Serves to prevent fetching of very long threads, especially useful on smaller instances.
|
||||
Addresses [memory leaks on recursive replies fetching](https://git.pleroma.social/pleroma/pleroma/issues/161).
|
||||
Applies to fetching of both ancestor (reply-to) and child (reply) objects.
|
||||
"""
|
||||
# credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength
|
||||
def allowed_incoming_reply_depth?(depth) do
|
||||
max_replies_depth = Pleroma.Config.get([:instance, :federation_incoming_replies_max_depth])
|
||||
def allowed_thread_distance?(distance) do
|
||||
max_distance = Pleroma.Config.get([:instance, :federation_incoming_replies_max_depth])
|
||||
|
||||
if max_replies_depth do
|
||||
(depth || 1) <= max_replies_depth
|
||||
if max_distance && max_distance >= 0 do
|
||||
# Default depth is 0 (an object has zero distance from itself in its thread)
|
||||
(distance || 0) <= max_distance
|
||||
else
|
||||
true
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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.Web.Feed.FeedView do
|
||||
|
|
|
|||
|
|
@ -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.Web.Feed.TagController do
|
||||
|
|
|
|||
|
|
@ -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.Web.Feed.UserController do
|
||||
|
|
|
|||
|
|
@ -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.Web.MastoFEController do
|
||||
|
|
|
|||
|
|
@ -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.Web.MastodonAPI.NotificationController do
|
||||
|
|
|
|||
|
|
@ -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.Web.MastodonAPI.SearchController do
|
||||
|
|
|
|||
|
|
@ -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.Web.MastodonAPI.StatusController do
|
||||
|
|
|
|||
|
|
@ -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.Web.MastodonAPI.SubscriptionController do
|
||||
|
|
|
|||
|
|
@ -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.Web.MastodonAPI.SuggestionController do
|
||||
|
|
|
|||
|
|
@ -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.Web.MastodonAPI.TimelineController do
|
||||
|
|
@ -10,9 +10,20 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|
|||
|
||||
alias Pleroma.Pagination
|
||||
alias Pleroma.Plugs.OAuthScopesPlug
|
||||
alias Pleroma.Plugs.RateLimiter
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
|
||||
# TODO: Replace with a macro when there is a Phoenix release with
|
||||
# https://github.com/phoenixframework/phoenix/commit/2e8c63c01fec4dde5467dbbbf9705ff9e780735e
|
||||
# in it
|
||||
|
||||
plug(RateLimiter, [name: :timeline, bucket_name: :direct_timeline] when action == :direct)
|
||||
plug(RateLimiter, [name: :timeline, bucket_name: :public_timeline] when action == :public)
|
||||
plug(RateLimiter, [name: :timeline, bucket_name: :home_timeline] when action == :home)
|
||||
plug(RateLimiter, [name: :timeline, bucket_name: :hashtag_timeline] when action == :hashtag)
|
||||
plug(RateLimiter, [name: :timeline, bucket_name: :list_timeline] when action == :list)
|
||||
|
||||
plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in [:home, :direct])
|
||||
plug(OAuthScopesPlug, %{scopes: ["read:lists"]} when action == :list)
|
||||
|
||||
|
|
|
|||
|
|
@ -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.Web.MastodonAPI.MastodonAPI do
|
||||
|
|
|
|||
|
|
@ -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.Web.MastodonAPI.AccountView do
|
||||
|
|
|
|||
|
|
@ -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.Web.MastodonAPI.AppView do
|
||||
|
|
|
|||
|
|
@ -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.Web.MastodonAPI.NotificationView do
|
||||
|
|
|
|||
|
|
@ -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.Web.MastodonAPI.PollView do
|
||||
|
|
|
|||
|
|
@ -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.Web.MastodonAPI.StatusView do
|
||||
|
|
@ -175,9 +175,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
|
||||
expires_at =
|
||||
with true <- client_posted_this_activity,
|
||||
expiration when not is_nil(expiration) <-
|
||||
%ActivityExpiration{scheduled_at: scheduled_at} <-
|
||||
ActivityExpiration.get_by_activity_id(activity.id) do
|
||||
expiration.scheduled_at
|
||||
scheduled_at
|
||||
else
|
||||
_ -> nil
|
||||
end
|
||||
|
||||
thread_muted? =
|
||||
|
|
@ -321,11 +323,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
nil
|
||||
end
|
||||
|
||||
site_name = rich_media[:site_name] || page_url_data.host
|
||||
|
||||
%{
|
||||
type: "link",
|
||||
provider_name: site_name,
|
||||
provider_name: page_url_data.host,
|
||||
provider_url: page_url_data.scheme <> "://" <> page_url_data.host,
|
||||
url: page_url,
|
||||
image: image_url |> MediaProxy.url(),
|
||||
|
|
|
|||
|
|
@ -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.Web.Metadata.Providers.Feed do
|
||||
|
|
|
|||
|
|
@ -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.Web.Metadata.Providers.RelMe do
|
||||
|
|
@ -8,8 +8,10 @@ defmodule Pleroma.Web.Metadata.Providers.RelMe do
|
|||
|
||||
@impl Provider
|
||||
def build_tags(%{user: user}) do
|
||||
(Floki.attribute(user.bio, "link[rel~=me]", "href") ++
|
||||
Floki.attribute(user.bio, "a[rel~=me]", "href"))
|
||||
bio_tree = Floki.parse_fragment!(user.bio)
|
||||
|
||||
(Floki.attribute(bio_tree, "link[rel~=me]", "href") ++
|
||||
Floki.attribute(bio_tree, "a[rel~=me]", "href"))
|
||||
|> Enum.map(fn link ->
|
||||
{:link, [rel: "me", href: link], []}
|
||||
end)
|
||||
|
|
|
|||
|
|
@ -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.Web.Metadata.Utils do
|
||||
|
|
|
|||
|
|
@ -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.Web.Nodeinfo.NodeinfoController do
|
||||
|
|
@ -46,10 +46,10 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
|
|||
|
||||
data
|
||||
|> Map.merge(%{quarantined_instances: quarantined})
|
||||
|> Map.put(:enabled, Config.get([:instance, :federating]))
|
||||
else
|
||||
%{}
|
||||
end
|
||||
|> Map.put(:enabled, Config.get([:instance, :federating]))
|
||||
|
||||
features =
|
||||
[
|
||||
|
|
@ -92,9 +92,9 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
|
|||
openRegistrations: Config.get([:instance, :registrations_open]),
|
||||
usage: %{
|
||||
users: %{
|
||||
total: stats.user_count || 0
|
||||
total: Map.get(stats, :user_count, 0)
|
||||
},
|
||||
localPosts: stats.status_count || 0
|
||||
localPosts: Map.get(stats, :status_count, 0)
|
||||
},
|
||||
metadata: %{
|
||||
nodeName: Config.get([:instance, :name]),
|
||||
|
|
|
|||
|
|
@ -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.Web.OAuth.OAuthController do
|
||||
|
|
|
|||
|
|
@ -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.Web.OAuth.Scopes do
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
|
|||
{:ok, _} ->
|
||||
conn |> json("ok")
|
||||
|
||||
{:error, _} ->
|
||||
{:error, _, _} ->
|
||||
conn
|
||||
|> put_status(:internal_server_error)
|
||||
|> json(%{error: "Couldn't delete the pack #{name}"})
|
||||
|
|
|
|||
|
|
@ -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.Web.PleromaAPI.PleromaAPIController do
|
||||
|
|
@ -41,24 +41,29 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
|
|||
|
||||
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
|
||||
|
||||
def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do
|
||||
def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id} = params) do
|
||||
with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
|
||||
%Object{data: %{"reactions" => emoji_reactions}} when is_list(emoji_reactions) <-
|
||||
Object.normalize(activity) do
|
||||
reactions =
|
||||
emoji_reactions
|
||||
|> Enum.map(fn [emoji, user_ap_ids] ->
|
||||
users =
|
||||
Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1)
|
||||
|> Enum.filter(& &1)
|
||||
if params["emoji"] && params["emoji"] != emoji do
|
||||
nil
|
||||
else
|
||||
users =
|
||||
Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1)
|
||||
|> Enum.filter(& &1)
|
||||
|
||||
%{
|
||||
name: emoji,
|
||||
count: length(users),
|
||||
accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}),
|
||||
me: !!(user && user.ap_id in user_ap_ids)
|
||||
}
|
||||
%{
|
||||
name: emoji,
|
||||
count: length(users),
|
||||
accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}),
|
||||
me: !!(user && user.ap_id in user_ap_ids)
|
||||
}
|
||||
end
|
||||
end)
|
||||
|> Enum.filter(& &1)
|
||||
|
||||
conn
|
||||
|> json(reactions)
|
||||
|
|
|
|||
|
|
@ -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.Web.RelMe do
|
||||
|
|
@ -27,9 +27,10 @@ defmodule Pleroma.Web.RelMe do
|
|||
defp parse_url(url) do
|
||||
with {:ok, %Tesla.Env{body: html, status: status}} when status in 200..299 <-
|
||||
Pleroma.HTTP.get(url, [], adapter: @hackney_options),
|
||||
{:ok, html_tree} <- Floki.parse_document(html),
|
||||
data <-
|
||||
Floki.attribute(html, "link[rel~=me]", "href") ++
|
||||
Floki.attribute(html, "a[rel~=me]", "href") do
|
||||
Floki.attribute(html_tree, "link[rel~=me]", "href") ++
|
||||
Floki.attribute(html_tree, "a[rel~=me]", "href") do
|
||||
{:ok, data}
|
||||
end
|
||||
rescue
|
||||
|
|
|
|||
|
|
@ -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.Web.RichMedia.Parser do
|
||||
|
|
@ -81,18 +81,18 @@ defmodule Pleroma.Web.RichMedia.Parser do
|
|||
{:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: @hackney_options)
|
||||
|
||||
html
|
||||
|> parse_html
|
||||
|> parse_html()
|
||||
|> maybe_parse()
|
||||
|> Map.put(:url, url)
|
||||
|> clean_parsed_data()
|
||||
|> check_parsed_data()
|
||||
rescue
|
||||
e ->
|
||||
{:error, "Parsing error: #{inspect(e)}"}
|
||||
{:error, "Parsing error: #{inspect(e)} #{inspect(__STACKTRACE__)}"}
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_html(html), do: Floki.parse(html)
|
||||
defp parse_html(html), do: Floki.parse_document!(html)
|
||||
|
||||
defp maybe_parse(html) do
|
||||
Enum.reduce_while(parsers(), %{}, fn parser, acc ->
|
||||
|
|
|
|||
|
|
@ -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.Web.RichMedia.Parsers.MetaTagsParser do
|
||||
|
|
|
|||
|
|
@ -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.Web.Router do
|
||||
|
|
@ -192,6 +192,7 @@ defmodule Pleroma.Web.Router do
|
|||
|
||||
put("/statuses/:id", AdminAPIController, :status_update)
|
||||
delete("/statuses/:id", AdminAPIController, :status_delete)
|
||||
get("/statuses", AdminAPIController, :list_statuses)
|
||||
|
||||
get("/config", AdminAPIController, :config_show)
|
||||
post("/config", AdminAPIController, :config_update)
|
||||
|
|
@ -201,6 +202,7 @@ defmodule Pleroma.Web.Router do
|
|||
get("/moderation_log", AdminAPIController, :list_log)
|
||||
|
||||
post("/reload_emoji", AdminAPIController, :reload_emoji)
|
||||
get("/stats", AdminAPIController, :stats)
|
||||
end
|
||||
|
||||
scope "/api/pleroma/emoji", Pleroma.Web.PleromaAPI do
|
||||
|
|
@ -271,6 +273,7 @@ defmodule Pleroma.Web.Router do
|
|||
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
|
||||
pipe_through(:api)
|
||||
|
||||
get("/statuses/:id/reactions/:emoji", PleromaAPIController, :emoji_reactions_by)
|
||||
get("/statuses/:id/reactions", PleromaAPIController, :emoji_reactions_by)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -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.Web.Streamer.Worker do
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue