merge develop
This commit is contained in:
commit
eae991b06a
160 changed files with 4263 additions and 1310 deletions
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Healthcheck do
|
||||
@moduledoc """
|
||||
Module collects metrics about app and assign healthy status.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
Postgrex.Types.define(
|
||||
Pleroma.PostgresTypes,
|
||||
[] ++ Ecto.Adapters.Postgres.extensions(),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.Tasks.Pleroma.Benchmark do
|
||||
import Mix.Pleroma
|
||||
use Mix.Task
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Mix.Tasks.Pleroma.Config do
|
||||
use Mix.Task
|
||||
import Mix.Pleroma
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
|||
- `--db-configurable Y/N` - Allow/disallow configuring instance from admin part
|
||||
- `--uploads-dir` - the directory uploads go in when using a local uploader
|
||||
- `--static-dir` - the directory custom public files should be read from (custom emojis, frontend bundle overrides, robots.txt, etc.)
|
||||
- `--listen-ip` - the ip the app should listen to, defaults to 127.0.0.1
|
||||
- `--listen-port` - the port the app should listen to, defaults to 4000
|
||||
"""
|
||||
|
||||
def run(["gen" | rest]) do
|
||||
|
|
@ -56,7 +58,9 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
|||
indexable: :string,
|
||||
db_configurable: :string,
|
||||
uploads_dir: :string,
|
||||
static_dir: :string
|
||||
static_dir: :string,
|
||||
listen_ip: :string,
|
||||
listen_port: :string
|
||||
],
|
||||
aliases: [
|
||||
o: :output,
|
||||
|
|
@ -146,6 +150,22 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
|||
"n"
|
||||
) === "y"
|
||||
|
||||
listen_port =
|
||||
get_option(
|
||||
options,
|
||||
:listen_port,
|
||||
"What port will the app listen to (leave it if you are using the default setup with nginx)?",
|
||||
4000
|
||||
)
|
||||
|
||||
listen_ip =
|
||||
get_option(
|
||||
options,
|
||||
:listen_ip,
|
||||
"What ip will the app listen to (leave it if you are using the default setup with nginx)?",
|
||||
"127.0.0.1"
|
||||
)
|
||||
|
||||
uploads_dir =
|
||||
get_option(
|
||||
options,
|
||||
|
|
@ -188,7 +208,9 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
|||
db_configurable?: db_configurable?,
|
||||
static_dir: static_dir,
|
||||
uploads_dir: uploads_dir,
|
||||
rum_enabled: rum_enabled
|
||||
rum_enabled: rum_enabled,
|
||||
listen_ip: listen_ip,
|
||||
listen_port: listen_port
|
||||
)
|
||||
|
||||
result_psql =
|
||||
|
|
|
|||
|
|
@ -344,5 +344,5 @@ defmodule Pleroma.Activity do
|
|||
)
|
||||
end
|
||||
|
||||
defdelegate search(user, query), to: Pleroma.Activity.Search
|
||||
defdelegate search(user, query, options \\ []), to: Pleroma.Activity.Search
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,14 +5,17 @@
|
|||
defmodule Pleroma.Activity.Search do
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Object.Fetcher
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.Pagination
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
def search(user, search_query) do
|
||||
def search(user, search_query, options \\ []) do
|
||||
index_type = if Pleroma.Config.get([:database, :rum_enabled]), do: :rum, else: :gin
|
||||
limit = Enum.min([Keyword.get(options, :limit), 40])
|
||||
offset = Keyword.get(options, :offset, 0)
|
||||
author = Keyword.get(options, :author)
|
||||
|
||||
Activity
|
||||
|> Activity.with_preloaded_object()
|
||||
|
|
@ -20,15 +23,23 @@ defmodule Pleroma.Activity.Search do
|
|||
|> restrict_public()
|
||||
|> query_with(index_type, search_query)
|
||||
|> maybe_restrict_local(user)
|
||||
|> Repo.all()
|
||||
|> maybe_restrict_author(author)
|
||||
|> Pagination.fetch_paginated(%{"offset" => offset, "limit" => limit}, :offset)
|
||||
|> maybe_fetch(user, search_query)
|
||||
end
|
||||
|
||||
def maybe_restrict_author(query, %User{} = author) do
|
||||
from([a, o] in query,
|
||||
where: a.actor == ^author.ap_id
|
||||
)
|
||||
end
|
||||
|
||||
def maybe_restrict_author(query, _), do: query
|
||||
|
||||
defp restrict_public(q) do
|
||||
from([a, o] in q,
|
||||
where: fragment("?->>'type' = 'Create'", a.data),
|
||||
where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients,
|
||||
limit: 40
|
||||
where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -155,11 +155,7 @@ defmodule Pleroma.Application do
|
|||
start: {Pleroma.Web.Endpoint, :start_link, []},
|
||||
type: :supervisor
|
||||
},
|
||||
%{id: Pleroma.Gopher.Server, start: {Pleroma.Gopher.Server, :start_link, []}},
|
||||
%{
|
||||
id: Pleroma.User.SynchronizationWorker,
|
||||
start: {Pleroma.User.SynchronizationWorker, :start_link, []}
|
||||
}
|
||||
%{id: Pleroma.Gopher.Server, start: {Pleroma.Gopher.Server, :start_link, []}}
|
||||
]
|
||||
|
||||
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.BBS.Authenticator do
|
||||
use Sshd.PasswordAuthenticator
|
||||
alias Comeonin.Pbkdf2
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.BBS.Handler do
|
||||
use Sshd.ShellHandler
|
||||
alias Pleroma.Activity
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Bookmark do
|
||||
use Ecto.Schema
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Captcha do
|
||||
import Pleroma.Web.Gettext
|
||||
|
||||
alias Calendar.DateTime
|
||||
alias Plug.Crypto.KeyGenerator
|
||||
alias Plug.Crypto.MessageEncryptor
|
||||
|
|
@ -83,10 +85,11 @@ defmodule Pleroma.Captcha do
|
|||
with {: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), do: throw({:error, "CAPTCHA expired"})
|
||||
if DateTime.before?(at, valid_if_after),
|
||||
do: throw({:error, dgettext("errors", "CAPTCHA expired")})
|
||||
|
||||
if not is_nil(Cachex.get!(:used_captcha_cache, token)),
|
||||
do: throw({:error, "CAPTCHA already used"})
|
||||
do: throw({:error, dgettext("errors", "CAPTCHA already used")})
|
||||
|
||||
res = method().validate(token, captcha, answer_md5)
|
||||
# Throw if an error occurs
|
||||
|
|
@ -101,7 +104,7 @@ defmodule Pleroma.Captcha do
|
|||
:throw, e -> e
|
||||
end
|
||||
else
|
||||
_ -> {:error, "Invalid answer data"}
|
||||
_ -> {:error, dgettext("errors", "Invalid answer data")}
|
||||
end
|
||||
|
||||
{:reply, result, state}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Captcha.Kocaptcha do
|
||||
import Pleroma.Web.Gettext
|
||||
alias Pleroma.Captcha.Service
|
||||
@behaviour Service
|
||||
|
||||
|
|
@ -12,7 +13,7 @@ defmodule Pleroma.Captcha.Kocaptcha do
|
|||
|
||||
case Tesla.get(endpoint <> "/new") do
|
||||
{:error, _} ->
|
||||
%{error: "Kocaptcha service unavailable"}
|
||||
%{error: dgettext("errors", "Kocaptcha service unavailable")}
|
||||
|
||||
{:ok, res} ->
|
||||
json_resp = Jason.decode!(res.body)
|
||||
|
|
@ -32,6 +33,6 @@ defmodule Pleroma.Captcha.Kocaptcha do
|
|||
if not is_nil(captcha) and
|
||||
:crypto.hash(:md5, captcha) |> Base.encode16() == String.upcase(answer_data),
|
||||
do: :ok,
|
||||
else: {:error, "Invalid CAPTCHA"}
|
||||
else: {:error, dgettext("errors", "Invalid CAPTCHA")}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Config.TransferTask do
|
||||
use Task
|
||||
alias Pleroma.Web.AdminAPI.Config
|
||||
|
|
|
|||
|
|
@ -3,11 +3,58 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Emails.Mailer do
|
||||
use Swoosh.Mailer, otp_app: :pleroma
|
||||
@moduledoc """
|
||||
Defines the Pleroma mailer.
|
||||
|
||||
The module contains functions to delivery email using Swoosh.Mailer.
|
||||
"""
|
||||
|
||||
alias Swoosh.DeliveryError
|
||||
|
||||
@otp_app :pleroma
|
||||
@mailer_config [otp: :pleroma]
|
||||
|
||||
@spec enabled?() :: boolean()
|
||||
def enabled?, do: Pleroma.Config.get([__MODULE__, :enabled])
|
||||
|
||||
@doc "add email to queue"
|
||||
def deliver_async(email, config \\ []) do
|
||||
PleromaJobQueue.enqueue(:mailer, __MODULE__, [:deliver_async, email, config])
|
||||
end
|
||||
|
||||
@doc "callback to perform send email from queue"
|
||||
def perform(:deliver_async, email, config), do: deliver(email, config)
|
||||
|
||||
@spec deliver(Swoosh.Email.t(), Keyword.t()) :: {:ok, term} | {:error, term}
|
||||
def deliver(email, config \\ [])
|
||||
|
||||
def deliver(email, config) do
|
||||
case enabled?() do
|
||||
true -> Swoosh.Mailer.deliver(email, parse_config(config))
|
||||
false -> {:error, :deliveries_disabled}
|
||||
end
|
||||
end
|
||||
|
||||
@spec deliver!(Swoosh.Email.t(), Keyword.t()) :: term | no_return
|
||||
def deliver!(email, config \\ [])
|
||||
|
||||
def deliver!(email, config) do
|
||||
case deliver(email, config) do
|
||||
{:ok, result} -> result
|
||||
{:error, reason} -> raise DeliveryError, reason: reason
|
||||
end
|
||||
end
|
||||
|
||||
@on_load :validate_dependency
|
||||
|
||||
@doc false
|
||||
def validate_dependency do
|
||||
parse_config([])
|
||||
|> Keyword.get(:adapter)
|
||||
|> Swoosh.Mailer.validate_dependency()
|
||||
end
|
||||
|
||||
defp parse_config(config) do
|
||||
Swoosh.Mailer.parse_config(@otp_app, __MODULE__, @mailer_config, config)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Instances do
|
||||
@moduledoc "Instances context."
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Instances.Instance do
|
||||
@moduledoc "Instance."
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,15 @@ defmodule Pleroma.Object do
|
|||
Repo.one(from(object in Object, where: fragment("(?)->>'id' = ?", object.data, ^ap_id)))
|
||||
end
|
||||
|
||||
defp warn_on_no_object_preloaded(ap_id) do
|
||||
"Object.normalize() called without preloaded object (#{ap_id}). Consider preloading the object"
|
||||
|> Logger.debug()
|
||||
|
||||
Logger.debug("Backtrace: #{inspect(Process.info(:erlang.self(), :current_stacktrace))}")
|
||||
end
|
||||
|
||||
def normalize(_, fetch_remote \\ true, options \\ [])
|
||||
|
||||
# If we pass an Activity to Object.normalize(), we can try to use the preloaded object.
|
||||
# Use this whenever possible, especially when walking graphs in an O(N) loop!
|
||||
def normalize(%Object{} = object, _, _), do: object
|
||||
|
|
@ -55,25 +63,15 @@ defmodule Pleroma.Object do
|
|||
%Object{id: "pleroma:fake_object_id", data: data}
|
||||
end
|
||||
|
||||
# Catch and log Object.normalize() calls where the Activity's child object is not
|
||||
# preloaded.
|
||||
# No preloaded object
|
||||
def normalize(%Activity{data: %{"object" => %{"id" => ap_id}}}, fetch_remote, _) do
|
||||
Logger.debug(
|
||||
"Object.normalize() called without preloaded object (#{ap_id}). Consider preloading the object!"
|
||||
)
|
||||
|
||||
Logger.debug("Backtrace: #{inspect(Process.info(:erlang.self(), :current_stacktrace))}")
|
||||
|
||||
warn_on_no_object_preloaded(ap_id)
|
||||
normalize(ap_id, fetch_remote)
|
||||
end
|
||||
|
||||
# No preloaded object
|
||||
def normalize(%Activity{data: %{"object" => ap_id}}, fetch_remote, _) do
|
||||
Logger.debug(
|
||||
"Object.normalize() called without preloaded object (#{ap_id}). Consider preloading the object!"
|
||||
)
|
||||
|
||||
Logger.debug("Backtrace: #{inspect(Process.info(:erlang.self(), :current_stacktrace))}")
|
||||
|
||||
warn_on_no_object_preloaded(ap_id)
|
||||
normalize(ap_id, fetch_remote)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Object.Fetcher do
|
||||
alias Pleroma.HTTP
|
||||
alias Pleroma.Object
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.ObjectTombstone do
|
||||
@enforce_keys [:id, :formerType, :deleted]
|
||||
defstruct [:id, :formerType, :deleted, type: "Tombstone"]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Pagination do
|
||||
@moduledoc """
|
||||
Implements Mastodon-compatible pagination.
|
||||
|
|
@ -10,16 +14,28 @@ defmodule Pleroma.Pagination do
|
|||
|
||||
@default_limit 20
|
||||
|
||||
def fetch_paginated(query, params) do
|
||||
def fetch_paginated(query, params, type \\ :keyset)
|
||||
|
||||
def fetch_paginated(query, params, :keyset) do
|
||||
options = cast_params(params)
|
||||
|
||||
query
|
||||
|> paginate(options)
|
||||
|> paginate(options, :keyset)
|
||||
|> Repo.all()
|
||||
|> enforce_order(options)
|
||||
end
|
||||
|
||||
def paginate(query, options) do
|
||||
def fetch_paginated(query, params, :offset) do
|
||||
options = cast_params(params)
|
||||
|
||||
query
|
||||
|> paginate(options, :offset)
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
def paginate(query, options, method \\ :keyset)
|
||||
|
||||
def paginate(query, options, :keyset) do
|
||||
query
|
||||
|> restrict(:min_id, options)
|
||||
|> restrict(:since_id, options)
|
||||
|
|
@ -28,11 +44,18 @@ defmodule Pleroma.Pagination do
|
|||
|> restrict(:limit, options)
|
||||
end
|
||||
|
||||
def paginate(query, options, :offset) do
|
||||
query
|
||||
|> restrict(:offset, options)
|
||||
|> restrict(:limit, options)
|
||||
end
|
||||
|
||||
defp cast_params(params) do
|
||||
param_types = %{
|
||||
min_id: :string,
|
||||
since_id: :string,
|
||||
max_id: :string,
|
||||
offset: :integer,
|
||||
limit: :integer
|
||||
}
|
||||
|
||||
|
|
@ -66,6 +89,10 @@ defmodule Pleroma.Pagination do
|
|||
order_by(query, [u], fragment("? desc nulls last", u.id))
|
||||
end
|
||||
|
||||
defp restrict(query, :offset, %{offset: offset}) do
|
||||
offset(query, ^offset)
|
||||
end
|
||||
|
||||
defp restrict(query, :limit, options) do
|
||||
limit = Map.get(options, :limit, @default_limit)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
defmodule Pleroma.Plugs.EnsureAuthenticatedPlug do
|
||||
import Plug.Conn
|
||||
import Pleroma.Web.TranslationHelpers
|
||||
alias Pleroma.User
|
||||
|
||||
def init(options) do
|
||||
|
|
@ -16,8 +17,7 @@ defmodule Pleroma.Plugs.EnsureAuthenticatedPlug do
|
|||
|
||||
def call(conn, _) do
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{error: "Invalid credentials."}))
|
||||
|> render_error(:forbidden, "Invalid credentials.")
|
||||
|> halt
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug do
|
||||
import Pleroma.Web.TranslationHelpers
|
||||
import Plug.Conn
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.User
|
||||
|
|
@ -23,8 +24,7 @@ defmodule Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug do
|
|||
|
||||
{false, _} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{error: "This resource requires authentication."}))
|
||||
|> render_error(:forbidden, "This resource requires authentication.")
|
||||
|> halt
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
defmodule Pleroma.Plugs.OAuthScopesPlug do
|
||||
import Plug.Conn
|
||||
import Pleroma.Web.Gettext
|
||||
|
||||
@behaviour Plug
|
||||
|
||||
|
|
@ -30,11 +31,14 @@ defmodule Pleroma.Plugs.OAuthScopesPlug do
|
|||
|
||||
true ->
|
||||
missing_scopes = scopes -- token.scopes
|
||||
error_message = "Insufficient permissions: #{Enum.join(missing_scopes, " #{op} ")}."
|
||||
permissions = Enum.join(missing_scopes, " #{op} ")
|
||||
|
||||
error_message =
|
||||
dgettext("errors", "Insufficient permissions: %{permissions}.", permissions: permissions)
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{error: error_message}))
|
||||
|> send_resp(:forbidden, Jason.encode!(%{error: error_message}))
|
||||
|> halt()
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -44,8 +44,7 @@ defmodule Pleroma.Plugs.RateLimiter do
|
|||
...
|
||||
end
|
||||
"""
|
||||
|
||||
import Phoenix.Controller, only: [json: 2]
|
||||
import Pleroma.Web.TranslationHelpers
|
||||
import Plug.Conn
|
||||
|
||||
alias Pleroma.User
|
||||
|
|
@ -63,7 +62,7 @@ defmodule Pleroma.Plugs.RateLimiter do
|
|||
def call(conn, opts) do
|
||||
case check_rate(conn, opts) do
|
||||
{:ok, _count} -> conn
|
||||
{:error, _count} -> render_error(conn)
|
||||
{:error, _count} -> render_throttled_error(conn)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -85,10 +84,9 @@ defmodule Pleroma.Plugs.RateLimiter do
|
|||
|> Enum.join(".")
|
||||
end
|
||||
|
||||
defp render_error(conn) do
|
||||
defp render_throttled_error(conn) do
|
||||
conn
|
||||
|> put_status(:too_many_requests)
|
||||
|> json(%{error: "Throttled"})
|
||||
|> render_error(:too_many_requests, "Throttled")
|
||||
|> halt()
|
||||
end
|
||||
end
|
||||
|
|
|
|||
63
lib/pleroma/plugs/set_locale_plug.ex
Normal file
63
lib/pleroma/plugs/set_locale_plug.ex
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
# NOTE: this module is based on https://github.com/smeevil/set_locale
|
||||
defmodule Pleroma.Plugs.SetLocalePlug do
|
||||
import Plug.Conn, only: [get_req_header: 2, assign: 3]
|
||||
|
||||
def init(_), do: nil
|
||||
|
||||
def call(conn, _) do
|
||||
locale = get_locale_from_header(conn) || Gettext.get_locale()
|
||||
Gettext.put_locale(locale)
|
||||
assign(conn, :locale, locale)
|
||||
end
|
||||
|
||||
defp get_locale_from_header(conn) do
|
||||
conn
|
||||
|> extract_accept_language()
|
||||
|> Enum.find(&supported_locale?/1)
|
||||
end
|
||||
|
||||
defp extract_accept_language(conn) do
|
||||
case get_req_header(conn, "accept-language") do
|
||||
[value | _] ->
|
||||
value
|
||||
|> String.split(",")
|
||||
|> Enum.map(&parse_language_option/1)
|
||||
|> Enum.sort(&(&1.quality > &2.quality))
|
||||
|> Enum.map(& &1.tag)
|
||||
|> Enum.reject(&is_nil/1)
|
||||
|> ensure_language_fallbacks()
|
||||
|
||||
_ ->
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
defp supported_locale?(locale) do
|
||||
Pleroma.Web.Gettext
|
||||
|> Gettext.known_locales()
|
||||
|> Enum.member?(locale)
|
||||
end
|
||||
|
||||
defp parse_language_option(string) do
|
||||
captures = Regex.named_captures(~r/^\s?(?<tag>[\w\-]+)(?:;q=(?<quality>[\d\.]+))?$/i, string)
|
||||
|
||||
quality =
|
||||
case Float.parse(captures["quality"] || "1.0") do
|
||||
{val, _} -> val
|
||||
:error -> 1.0
|
||||
end
|
||||
|
||||
%{tag: captures["tag"], quality: quality}
|
||||
end
|
||||
|
||||
defp ensure_language_fallbacks(tags) do
|
||||
Enum.flat_map(tags, fn tag ->
|
||||
[language | _] = String.split(tag, "-")
|
||||
if Enum.member?(tags, language), do: [tag], else: [tag, language]
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Plugs.UploadedMedia do
|
|||
"""
|
||||
|
||||
import Plug.Conn
|
||||
import Pleroma.Web.Gettext
|
||||
require Logger
|
||||
|
||||
@behaviour Plug
|
||||
|
|
@ -45,7 +46,7 @@ defmodule Pleroma.Plugs.UploadedMedia do
|
|||
else
|
||||
_ ->
|
||||
conn
|
||||
|> send_resp(500, "Failed")
|
||||
|> send_resp(:internal_server_error, dgettext("errors", "Failed"))
|
||||
|> halt()
|
||||
end
|
||||
end
|
||||
|
|
@ -64,7 +65,7 @@ defmodule Pleroma.Plugs.UploadedMedia do
|
|||
conn
|
||||
else
|
||||
conn
|
||||
|> send_resp(404, "Not found")
|
||||
|> send_resp(:not_found, dgettext("errors", "Not found"))
|
||||
|> halt()
|
||||
end
|
||||
end
|
||||
|
|
@ -84,7 +85,7 @@ defmodule Pleroma.Plugs.UploadedMedia do
|
|||
Logger.error("#{__MODULE__}: Unknown get startegy: #{inspect(unknown)}")
|
||||
|
||||
conn
|
||||
|> send_resp(500, "Internal Error")
|
||||
|> send_resp(:internal_server_error, dgettext("errors", "Internal Error"))
|
||||
|> halt()
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Plugs.UserIsAdminPlug do
|
||||
import Pleroma.Web.TranslationHelpers
|
||||
import Plug.Conn
|
||||
alias Pleroma.User
|
||||
|
||||
|
|
@ -16,8 +17,7 @@ defmodule Pleroma.Plugs.UserIsAdminPlug do
|
|||
|
||||
def call(conn, _) do
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{error: "User is not admin."}))
|
||||
|> render_error(:forbidden, "User is not admin.")
|
||||
|> halt
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.ReverseProxy.Client do
|
||||
@callback request(atom(), String.t(), [tuple()], String.t(), list()) ::
|
||||
{:ok, pos_integer(), [tuple()], reference() | map()}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Uploaders.Uploader do
|
||||
import Pleroma.Web.Gettext
|
||||
|
||||
@moduledoc """
|
||||
Defines the contract to put and get an uploaded file to any backend.
|
||||
"""
|
||||
|
|
@ -66,7 +68,7 @@ defmodule Pleroma.Uploaders.Uploader do
|
|||
{:error, error}
|
||||
end
|
||||
after
|
||||
30_000 -> {:error, "Uploader callback timeout"}
|
||||
30_000 -> {:error, dgettext("errors", "Uploader callback timeout")}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ defmodule Pleroma.User do
|
|||
field(:avatar, :map)
|
||||
field(:local, :boolean, default: true)
|
||||
field(:follower_address, :string)
|
||||
field(:following_address, :string)
|
||||
field(:search_rank, :float, virtual: true)
|
||||
field(:search_type, :integer, virtual: true)
|
||||
field(:tags, {:array, :string}, default: [])
|
||||
|
|
@ -108,6 +109,10 @@ defmodule Pleroma.User do
|
|||
def ap_followers(%User{follower_address: fa}) when is_binary(fa), do: fa
|
||||
def ap_followers(%User{} = user), do: "#{ap_id(user)}/followers"
|
||||
|
||||
@spec ap_following(User.t()) :: Sring.t()
|
||||
def ap_following(%User{following_address: fa}) when is_binary(fa), do: fa
|
||||
def ap_following(%User{} = user), do: "#{ap_id(user)}/following"
|
||||
|
||||
def user_info(%User{} = user, args \\ %{}) do
|
||||
following_count =
|
||||
if args[:following_count], do: args[:following_count], else: following_count(user)
|
||||
|
|
@ -129,6 +134,7 @@ defmodule Pleroma.User do
|
|||
Cachex.put(:user_cache, "user_info:#{user.id}", user_info(user, args))
|
||||
end
|
||||
|
||||
@spec restrict_deactivated(Ecto.Query.t()) :: Ecto.Query.t()
|
||||
def restrict_deactivated(query) do
|
||||
from(u in query,
|
||||
where: not fragment("? \\? 'deactivated' AND ?->'deactivated' @> 'true'", u.info, u.info)
|
||||
|
|
@ -163,9 +169,10 @@ defmodule Pleroma.User do
|
|||
|
||||
if changes.valid? do
|
||||
case info_cng.changes[:source_data] do
|
||||
%{"followers" => followers} ->
|
||||
%{"followers" => followers, "following" => following} ->
|
||||
changes
|
||||
|> put_change(:follower_address, followers)
|
||||
|> put_change(:following_address, following)
|
||||
|
||||
_ ->
|
||||
followers = User.ap_followers(%User{nickname: changes.changes[:nickname]})
|
||||
|
|
@ -197,7 +204,14 @@ defmodule Pleroma.User do
|
|||
|> User.Info.user_upgrade(params[:info])
|
||||
|
||||
struct
|
||||
|> cast(params, [:bio, :name, :follower_address, :avatar, :last_refreshed_at])
|
||||
|> cast(params, [
|
||||
:bio,
|
||||
:name,
|
||||
:follower_address,
|
||||
:following_address,
|
||||
:avatar,
|
||||
:last_refreshed_at
|
||||
])
|
||||
|> unique_constraint(:nickname)
|
||||
|> validate_format(:nickname, local_nickname_regex())
|
||||
|> validate_length(:bio, max: 5000)
|
||||
|
|
@ -938,6 +952,8 @@ defmodule Pleroma.User do
|
|||
|
||||
@spec perform(atom(), User.t()) :: {:ok, User.t()}
|
||||
def perform(:delete, %User{} = user) do
|
||||
{:ok, _user} = ActivityPub.delete(user)
|
||||
|
||||
# Remove all relationships
|
||||
{:ok, followers} = User.get_followers(user)
|
||||
|
||||
|
|
@ -954,8 +970,8 @@ defmodule Pleroma.User do
|
|||
end)
|
||||
|
||||
delete_user_activities(user)
|
||||
|
||||
{:ok, _user} = Repo.delete(user)
|
||||
invalidate_cache(user)
|
||||
Repo.delete(user)
|
||||
end
|
||||
|
||||
@spec perform(atom(), User.t()) :: {:ok, User.t()}
|
||||
|
|
@ -1011,42 +1027,20 @@ defmodule Pleroma.User do
|
|||
)
|
||||
end
|
||||
|
||||
@spec sync_follow_counter() :: :ok
|
||||
def sync_follow_counter,
|
||||
do: PleromaJobQueue.enqueue(:background, __MODULE__, [:sync_follow_counters])
|
||||
|
||||
@spec perform(:sync_follow_counters) :: :ok
|
||||
def perform(:sync_follow_counters) do
|
||||
{:ok, _pid} = Agent.start_link(fn -> %{} end, name: :domain_errors)
|
||||
config = Pleroma.Config.get([:instance, :external_user_synchronization])
|
||||
|
||||
:ok = sync_follow_counters(config)
|
||||
Agent.stop(:domain_errors)
|
||||
end
|
||||
|
||||
@spec sync_follow_counters(keyword()) :: :ok
|
||||
def sync_follow_counters(opts \\ []) do
|
||||
users = external_users(opts)
|
||||
|
||||
if length(users) > 0 do
|
||||
errors = Agent.get(:domain_errors, fn state -> state end)
|
||||
{last, updated_errors} = User.Synchronization.call(users, errors, opts)
|
||||
Agent.update(:domain_errors, fn _state -> updated_errors end)
|
||||
sync_follow_counters(max_id: last.id, limit: opts[:limit])
|
||||
else
|
||||
:ok
|
||||
end
|
||||
@spec external_users_query() :: Ecto.Query.t()
|
||||
def external_users_query do
|
||||
User.Query.build(%{
|
||||
external: true,
|
||||
active: true,
|
||||
order_by: :id
|
||||
})
|
||||
end
|
||||
|
||||
@spec external_users(keyword()) :: [User.t()]
|
||||
def external_users(opts \\ []) do
|
||||
query =
|
||||
User.Query.build(%{
|
||||
external: true,
|
||||
active: true,
|
||||
order_by: :id,
|
||||
select: [:id, :ap_id, :info]
|
||||
})
|
||||
external_users_query()
|
||||
|> select([u], struct(u, [:id, :ap_id, :info]))
|
||||
|
||||
query =
|
||||
if opts[:max_id],
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.User.Search do
|
||||
alias Pleroma.Pagination
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
import Ecto.Query
|
||||
|
|
@ -18,8 +19,7 @@ defmodule Pleroma.User.Search do
|
|||
|
||||
for_user = Keyword.get(opts, :for_user)
|
||||
|
||||
# Strip the beginning @ off if there is a query
|
||||
query_string = String.trim_leading(query_string, "@")
|
||||
query_string = format_query(query_string)
|
||||
|
||||
maybe_resolve(resolve, for_user, query_string)
|
||||
|
||||
|
|
@ -33,13 +33,24 @@ defmodule Pleroma.User.Search do
|
|||
|
||||
query_string
|
||||
|> search_query(for_user, following)
|
||||
|> paginate(result_limit, offset)
|
||||
|> Repo.all()
|
||||
|> Pagination.fetch_paginated(%{"offset" => offset, "limit" => result_limit}, :offset)
|
||||
end)
|
||||
|
||||
results
|
||||
end
|
||||
|
||||
defp format_query(query_string) 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/[!-\-|@|[-`|{-~|\/|:]+/, "") do
|
||||
name <> "@" <> to_string(:idna.encode(formatted_domain))
|
||||
else
|
||||
_ -> query_string
|
||||
end
|
||||
end
|
||||
|
||||
defp search_query(query_string, for_user, following) do
|
||||
for_user
|
||||
|> base_query(following)
|
||||
|
|
@ -76,10 +87,6 @@ defmodule Pleroma.User.Search do
|
|||
|
||||
defp filter_blocked_domains(query, _), do: query
|
||||
|
||||
defp paginate(query, limit, offset) do
|
||||
from(q in query, limit: ^limit, offset: ^offset)
|
||||
end
|
||||
|
||||
defp union_subqueries({fts_subquery, trigram_subquery}) do
|
||||
from(s in trigram_subquery, union_all: ^fts_subquery)
|
||||
end
|
||||
|
|
@ -151,7 +158,7 @@ defmodule Pleroma.User.Search do
|
|||
defp fts_search_subquery(query, term) do
|
||||
processed_query =
|
||||
String.trim_trailing(term, "@" <> local_domain())
|
||||
|> String.replace(~r/\W+/, " ")
|
||||
|> String.replace(~r/[!-\/|@|[-`|{-~|:-?]+/, " ")
|
||||
|> String.trim()
|
||||
|> String.split()
|
||||
|> Enum.map(&(&1 <> ":*"))
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.User.Synchronization do
|
||||
alias Pleroma.HTTP
|
||||
alias Pleroma.User
|
||||
|
||||
@spec call([User.t()], map(), keyword()) :: {User.t(), map()}
|
||||
def call(users, errors, opts \\ []) do
|
||||
do_call(users, errors, opts)
|
||||
end
|
||||
|
||||
defp do_call([user | []], errors, opts) do
|
||||
updated = fetch_counters(user, errors, opts)
|
||||
{user, updated}
|
||||
end
|
||||
|
||||
defp do_call([user | others], errors, opts) do
|
||||
updated = fetch_counters(user, errors, opts)
|
||||
do_call(others, updated, opts)
|
||||
end
|
||||
|
||||
defp fetch_counters(user, errors, opts) do
|
||||
%{host: host} = URI.parse(user.ap_id)
|
||||
|
||||
info = %{}
|
||||
{following, errors} = fetch_counter(user.ap_id <> "/following", host, errors, opts)
|
||||
info = if following, do: Map.put(info, :following_count, following), else: info
|
||||
|
||||
{followers, errors} = fetch_counter(user.ap_id <> "/followers", host, errors, opts)
|
||||
info = if followers, do: Map.put(info, :follower_count, followers), else: info
|
||||
|
||||
User.set_info_cache(user, info)
|
||||
errors
|
||||
end
|
||||
|
||||
defp available_domain?(domain, errors, opts) do
|
||||
max_retries = Keyword.get(opts, :max_retries, 3)
|
||||
not (Map.has_key?(errors, domain) && errors[domain] >= max_retries)
|
||||
end
|
||||
|
||||
defp fetch_counter(url, host, errors, opts) do
|
||||
with true <- available_domain?(host, errors, opts),
|
||||
{:ok, %{body: body, status: code}} when code in 200..299 <-
|
||||
HTTP.get(
|
||||
url,
|
||||
[{:Accept, "application/activity+json"}]
|
||||
),
|
||||
{:ok, data} <- Jason.decode(body) do
|
||||
{data["totalItems"], errors}
|
||||
else
|
||||
false ->
|
||||
{nil, errors}
|
||||
|
||||
_ ->
|
||||
{nil, Map.update(errors, host, 1, &(&1 + 1))}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-onl
|
||||
|
||||
defmodule Pleroma.User.SynchronizationWorker do
|
||||
use GenServer
|
||||
|
||||
def start_link do
|
||||
config = Pleroma.Config.get([:instance, :external_user_synchronization])
|
||||
|
||||
if config[:enabled] do
|
||||
GenServer.start_link(__MODULE__, interval: config[:interval])
|
||||
else
|
||||
:ignore
|
||||
end
|
||||
end
|
||||
|
||||
def init(opts) do
|
||||
schedule_next(opts)
|
||||
{:ok, opts}
|
||||
end
|
||||
|
||||
def handle_info(:sync_follow_counters, opts) do
|
||||
Pleroma.User.sync_follow_counter()
|
||||
schedule_next(opts)
|
||||
{:noreply, opts}
|
||||
end
|
||||
|
||||
defp schedule_next(opts) do
|
||||
Process.send_after(self(), :sync_follow_counters, opts[:interval])
|
||||
end
|
||||
end
|
||||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.User.WelcomeMessage do
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
|
|
|||
|
|
@ -405,6 +405,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
end
|
||||
|
||||
def delete(%User{ap_id: ap_id, follower_address: follower_address} = user) do
|
||||
with data <- %{
|
||||
"to" => [follower_address],
|
||||
"type" => "Delete",
|
||||
"actor" => ap_id,
|
||||
"object" => %{"type" => "Person", "id" => ap_id}
|
||||
},
|
||||
{:ok, activity} <- insert(data, true, true),
|
||||
:ok <- maybe_federate(activity) do
|
||||
{:ok, user}
|
||||
end
|
||||
end
|
||||
|
||||
def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do
|
||||
user = User.get_cached_by_ap_id(actor)
|
||||
to = (object.data["to"] || []) ++ (object.data["cc"] || [])
|
||||
|
|
@ -981,6 +994,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
avatar: avatar,
|
||||
name: data["name"],
|
||||
follower_address: data["followers"],
|
||||
following_address: data["following"],
|
||||
bio: data["summary"]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,9 +31,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
conn
|
||||
else
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "not found"})
|
||||
|> halt
|
||||
|> render_error(:not_found, "not found")
|
||||
|> halt()
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -190,7 +189,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
Logger.info(inspect(conn.req_headers))
|
||||
end
|
||||
|
||||
json(conn, "error")
|
||||
json(conn, dgettext("errors", "error"))
|
||||
end
|
||||
|
||||
def relay(conn, _params) do
|
||||
|
|
@ -218,9 +217,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
|> put_resp_header("content-type", "application/activity+json")
|
||||
|> json(UserView.render("inbox.json", %{user: user, max_id: params["max_id"]}))
|
||||
else
|
||||
err =
|
||||
dgettext("errors", "can't read inbox of %{nickname} as %{as_nickname}",
|
||||
nickname: nickname,
|
||||
as_nickname: user.nickname
|
||||
)
|
||||
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json("can't read inbox of #{nickname} as #{user.nickname}")
|
||||
|> json(err)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -246,7 +251,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
{:ok, delete} <- ActivityPub.delete(object) do
|
||||
{:ok, delete}
|
||||
else
|
||||
_ -> {:error, "Can't delete object"}
|
||||
_ -> {:error, dgettext("errors", "Can't delete object")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -255,12 +260,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
{:ok, activity, _object} <- ActivityPub.like(user, object) do
|
||||
{:ok, activity}
|
||||
else
|
||||
_ -> {:error, "Can't like object"}
|
||||
_ -> {:error, dgettext("errors", "Can't like object")}
|
||||
end
|
||||
end
|
||||
|
||||
def handle_user_activity(_, _) do
|
||||
{:error, "Unhandled activity type"}
|
||||
{:error, dgettext("errors", "Unhandled activity type")}
|
||||
end
|
||||
|
||||
def update_outbox(
|
||||
|
|
@ -288,22 +293,28 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
|> json(message)
|
||||
end
|
||||
else
|
||||
err =
|
||||
dgettext("errors", "can't update outbox of %{nickname} as %{as_nickname}",
|
||||
nickname: nickname,
|
||||
as_nickname: user.nickname
|
||||
)
|
||||
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json("can't update outbox of #{nickname} as #{user.nickname}")
|
||||
|> json(err)
|
||||
end
|
||||
end
|
||||
|
||||
def errors(conn, {:error, :not_found}) do
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json("Not found")
|
||||
|> put_status(:not_found)
|
||||
|> json(dgettext("errors", "Not found"))
|
||||
end
|
||||
|
||||
def errors(conn, _e) do
|
||||
conn
|
||||
|> put_status(500)
|
||||
|> json("error")
|
||||
|> put_status(:internal_server_error)
|
||||
|> json(dgettext("errors", "error"))
|
||||
end
|
||||
|
||||
defp set_requester_reachable(%Plug.Conn{} = conn, _) do
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrepended do
|
|||
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
@reply_prefix Regex.compile!("^re:[[:space:]]*", [:caseless])
|
||||
|
||||
def filter_by_summary(
|
||||
%{"summary" => parent_summary} = _parent,
|
||||
%{data: %{"summary" => parent_summary}} = _in_reply_to,
|
||||
%{"summary" => child_summary} = child
|
||||
)
|
||||
when not is_nil(child_summary) and byte_size(child_summary) > 0 and
|
||||
|
|
@ -24,17 +25,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrepended do
|
|||
end
|
||||
end
|
||||
|
||||
def filter_by_summary(_parent, child), do: child
|
||||
|
||||
def filter(%{"type" => activity_type} = object) when activity_type == "Create" do
|
||||
child = object["object"]
|
||||
in_reply_to = Object.normalize(child["inReplyTo"])
|
||||
def filter_by_summary(_in_reply_to, child), do: child
|
||||
|
||||
def filter(%{"type" => "Create", "object" => child_object} = object) do
|
||||
child =
|
||||
if(in_reply_to,
|
||||
do: filter_by_summary(in_reply_to.data, child),
|
||||
else: child
|
||||
)
|
||||
child_object["inReplyTo"]
|
||||
|> Object.normalize(child_object["inReplyTo"])
|
||||
|> filter_by_summary(child_object)
|
||||
|
||||
object = Map.put(object, "object", child)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,19 +10,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy do
|
|||
def filter(
|
||||
%{
|
||||
"type" => "Create",
|
||||
"object" => %{"content" => content, "attachment" => _attachment} = child_object
|
||||
"object" => %{"content" => content, "attachment" => _} = _child_object
|
||||
} = object
|
||||
)
|
||||
when content in [".", "<p>.</p>"] do
|
||||
child_object =
|
||||
child_object
|
||||
|> Map.put("content", "")
|
||||
|
||||
object =
|
||||
object
|
||||
|> Map.put("object", child_object)
|
||||
|
||||
{:ok, object}
|
||||
{:ok, put_in(object, ["object", "content"], "")}
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
|
|
|||
|
|
@ -8,18 +8,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkup do
|
|||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
def filter(%{"type" => activity_type} = object) when activity_type == "Create" do
|
||||
def filter(%{"type" => "Create", "object" => child_object} = object) do
|
||||
scrub_policy = Pleroma.Config.get([:mrf_normalize_markup, :scrub_policy])
|
||||
|
||||
child = object["object"]
|
||||
|
||||
content =
|
||||
child["content"]
|
||||
child_object["content"]
|
||||
|> HTML.filter_tags(scrub_policy)
|
||||
|
||||
child = Map.put(child, "content", content)
|
||||
|
||||
object = Map.put(object, "object", child)
|
||||
object = put_in(object, ["object", "content"], content)
|
||||
|
||||
{:ok, object}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,46 +3,42 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
|
||||
alias Pleroma.User
|
||||
@moduledoc "Rejects non-public (followers-only, direct) activities"
|
||||
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.User
|
||||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
@public "https://www.w3.org/ns/activitystreams#Public"
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Create"} = object) do
|
||||
user = User.get_cached_by_ap_id(object["actor"])
|
||||
public = "https://www.w3.org/ns/activitystreams#Public"
|
||||
|
||||
# Determine visibility
|
||||
visibility =
|
||||
cond do
|
||||
public in object["to"] -> "public"
|
||||
public in object["cc"] -> "unlisted"
|
||||
@public in object["to"] -> "public"
|
||||
@public in object["cc"] -> "unlisted"
|
||||
user.follower_address in object["to"] -> "followers"
|
||||
true -> "direct"
|
||||
end
|
||||
|
||||
policy = Pleroma.Config.get(:mrf_rejectnonpublic)
|
||||
policy = Config.get(:mrf_rejectnonpublic)
|
||||
|
||||
case visibility do
|
||||
"public" ->
|
||||
cond do
|
||||
visibility in ["public", "unlisted"] ->
|
||||
{:ok, object}
|
||||
|
||||
"unlisted" ->
|
||||
visibility == "followers" and Keyword.get(policy, :allow_followersonly) ->
|
||||
{:ok, object}
|
||||
|
||||
"followers" ->
|
||||
with true <- Keyword.get(policy, :allow_followersonly) do
|
||||
{:ok, object}
|
||||
else
|
||||
_e -> {:reject, nil}
|
||||
end
|
||||
visibility == "direct" and Keyword.get(policy, :allow_direct) ->
|
||||
{:ok, object}
|
||||
|
||||
"direct" ->
|
||||
with true <- Keyword.get(policy, :allow_direct) do
|
||||
{:ok, object}
|
||||
else
|
||||
_e -> {:reject, nil}
|
||||
end
|
||||
true ->
|
||||
{:reject, nil}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -19,12 +19,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
|||
- `mrf_tag:disable-any-subscription`: Reject any follow requests
|
||||
"""
|
||||
|
||||
@public "https://www.w3.org/ns/activitystreams#Public"
|
||||
|
||||
defp get_tags(%User{tags: tags}) when is_list(tags), do: tags
|
||||
defp get_tags(_), do: []
|
||||
|
||||
defp process_tag(
|
||||
"mrf_tag:media-force-nsfw",
|
||||
%{"type" => "Create", "object" => %{"attachment" => child_attachment} = object} = message
|
||||
%{
|
||||
"type" => "Create",
|
||||
"object" => %{"attachment" => child_attachment} = object
|
||||
} = message
|
||||
)
|
||||
when length(child_attachment) > 0 do
|
||||
tags = (object["tag"] || []) ++ ["nsfw"]
|
||||
|
|
@ -41,7 +46,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
|||
|
||||
defp process_tag(
|
||||
"mrf_tag:media-strip",
|
||||
%{"type" => "Create", "object" => %{"attachment" => child_attachment} = object} = message
|
||||
%{
|
||||
"type" => "Create",
|
||||
"object" => %{"attachment" => child_attachment} = object
|
||||
} = message
|
||||
)
|
||||
when length(child_attachment) > 0 do
|
||||
object = Map.delete(object, "attachment")
|
||||
|
|
@ -52,19 +60,22 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
|||
|
||||
defp process_tag(
|
||||
"mrf_tag:force-unlisted",
|
||||
%{"type" => "Create", "to" => to, "cc" => cc, "actor" => actor} = message
|
||||
%{
|
||||
"type" => "Create",
|
||||
"to" => to,
|
||||
"cc" => cc,
|
||||
"actor" => actor,
|
||||
"object" => object
|
||||
} = message
|
||||
) do
|
||||
user = User.get_cached_by_ap_id(actor)
|
||||
|
||||
if Enum.member?(to, "https://www.w3.org/ns/activitystreams#Public") do
|
||||
to =
|
||||
List.delete(to, "https://www.w3.org/ns/activitystreams#Public") ++ [user.follower_address]
|
||||
|
||||
cc =
|
||||
List.delete(cc, user.follower_address) ++ ["https://www.w3.org/ns/activitystreams#Public"]
|
||||
if Enum.member?(to, @public) do
|
||||
to = List.delete(to, @public) ++ [user.follower_address]
|
||||
cc = List.delete(cc, user.follower_address) ++ [@public]
|
||||
|
||||
object =
|
||||
message["object"]
|
||||
object
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|
||||
|
|
@ -82,19 +93,22 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
|||
|
||||
defp process_tag(
|
||||
"mrf_tag:sandbox",
|
||||
%{"type" => "Create", "to" => to, "cc" => cc, "actor" => actor} = message
|
||||
%{
|
||||
"type" => "Create",
|
||||
"to" => to,
|
||||
"cc" => cc,
|
||||
"actor" => actor,
|
||||
"object" => object
|
||||
} = message
|
||||
) do
|
||||
user = User.get_cached_by_ap_id(actor)
|
||||
|
||||
if Enum.member?(to, "https://www.w3.org/ns/activitystreams#Public") or
|
||||
Enum.member?(cc, "https://www.w3.org/ns/activitystreams#Public") do
|
||||
to =
|
||||
List.delete(to, "https://www.w3.org/ns/activitystreams#Public") ++ [user.follower_address]
|
||||
|
||||
cc = List.delete(cc, "https://www.w3.org/ns/activitystreams#Public")
|
||||
if Enum.member?(to, @public) or Enum.member?(cc, @public) do
|
||||
to = List.delete(to, @public) ++ [user.follower_address]
|
||||
cc = List.delete(cc, @public)
|
||||
|
||||
object =
|
||||
message["object"]
|
||||
object
|
||||
|> Map.put("to", to)
|
||||
|> Map.put("cc", cc)
|
||||
|
||||
|
|
@ -123,7 +137,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
|
|||
end
|
||||
end
|
||||
|
||||
defp process_tag("mrf_tag:disable-any-subscription", %{"type" => "Follow"}), do: {:reject, nil}
|
||||
defp process_tag("mrf_tag:disable-any-subscription", %{"type" => "Follow"}),
|
||||
do: {:reject, nil}
|
||||
|
||||
defp process_tag(_, message), do: {:ok, message}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do
|
|||
@impl true
|
||||
def filter(%{"actor" => actor} = object) do
|
||||
actor_info = URI.parse(actor)
|
||||
allow_list = Config.get([:mrf_user_allowlist, String.to_atom(actor_info.host)], [])
|
||||
|
||||
allow_list =
|
||||
Config.get(
|
||||
[:mrf_user_allowlist, String.to_atom(actor_info.host)],
|
||||
[]
|
||||
)
|
||||
|
||||
filter_by_list(object, allow_list)
|
||||
end
|
||||
|
|
@ -641,7 +641,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
# an error or a tombstone. This would allow us to verify that a deletion actually took
|
||||
# place.
|
||||
def handle_incoming(
|
||||
%{"type" => "Delete", "object" => object_id, "actor" => _actor, "id" => _id} = data,
|
||||
%{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => _id} = data,
|
||||
_options
|
||||
) do
|
||||
object_id = Utils.get_ap_id(object_id)
|
||||
|
|
@ -653,7 +653,30 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
{:ok, activity} <- ActivityPub.delete(object, false) do
|
||||
{:ok, activity}
|
||||
else
|
||||
_e -> :error
|
||||
nil ->
|
||||
case User.get_cached_by_ap_id(object_id) do
|
||||
%User{ap_id: ^actor} = user ->
|
||||
{:ok, followers} = User.get_followers(user)
|
||||
|
||||
Enum.each(followers, fn follower ->
|
||||
User.unfollow(follower, user)
|
||||
end)
|
||||
|
||||
{:ok, friends} = User.get_friends(user)
|
||||
|
||||
Enum.each(friends, fn followed ->
|
||||
User.unfollow(user, followed)
|
||||
end)
|
||||
|
||||
User.invalidate_cache(user)
|
||||
Repo.delete(user)
|
||||
|
||||
nil ->
|
||||
:error
|
||||
end
|
||||
|
||||
_e ->
|
||||
:error
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1064,6 +1087,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
PleromaJobQueue.enqueue(:transmogrifier, __MODULE__, [:user_upgrade, user])
|
||||
end
|
||||
|
||||
if Pleroma.Config.get([:instance, :external_user_synchronization]) do
|
||||
update_following_followers_counters(user)
|
||||
end
|
||||
|
||||
{:ok, user}
|
||||
else
|
||||
%User{} = user -> {:ok, user}
|
||||
|
|
@ -1096,4 +1123,27 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
data
|
||||
|> maybe_fix_user_url
|
||||
end
|
||||
|
||||
def update_following_followers_counters(user) do
|
||||
info = %{}
|
||||
|
||||
following = fetch_counter(user.following_address)
|
||||
info = if following, do: Map.put(info, :following_count, following), else: info
|
||||
|
||||
followers = fetch_counter(user.follower_address)
|
||||
info = if followers, do: Map.put(info, :follower_count, followers), else: info
|
||||
|
||||
User.set_info_cache(user, info)
|
||||
end
|
||||
|
||||
defp fetch_counter(url) do
|
||||
with {:ok, %{body: body, status: code}} when code in 200..299 <-
|
||||
Pleroma.HTTP.get(
|
||||
url,
|
||||
[{:Accept, "application/activity+json"}]
|
||||
),
|
||||
{:ok, data} <- Jason.decode(body) do
|
||||
data["totalItems"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.Visibility do
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Object
|
||||
|
|
|
|||
|
|
@ -160,9 +160,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
end
|
||||
|
||||
def right_add(conn, _) do
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "No such permission_group"})
|
||||
render_error(conn, :not_found, "No such permission_group")
|
||||
end
|
||||
|
||||
def right_get(conn, %{"nickname" => nickname}) do
|
||||
|
|
@ -184,9 +182,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
)
|
||||
when permission_group in ["moderator", "admin"] do
|
||||
if admin_nickname == nickname do
|
||||
conn
|
||||
|> put_status(403)
|
||||
|> json(%{error: "You can't revoke your own admin status."})
|
||||
render_error(conn, :forbidden, "You can't revoke your own admin status.")
|
||||
else
|
||||
user = User.get_cached_by_nickname(nickname)
|
||||
|
||||
|
|
@ -207,9 +203,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
end
|
||||
|
||||
def right_delete(conn, _) do
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "No such permission_group"})
|
||||
render_error(conn, :not_found, "No such permission_group")
|
||||
end
|
||||
|
||||
def set_activation_status(conn, %{"nickname" => nickname, "status" => status}) do
|
||||
|
|
@ -377,13 +371,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
if Pleroma.Config.get([:instance, :dynamic_configuration]) do
|
||||
updated =
|
||||
Enum.map(configs, fn
|
||||
%{"group" => group, "key" => key, "value" => value} ->
|
||||
{:ok, config} = Config.update_or_create(%{group: group, key: key, value: value})
|
||||
config
|
||||
|
||||
%{"group" => group, "key" => key, "delete" => "true"} ->
|
||||
{:ok, _} = Config.delete(%{group: group, key: key})
|
||||
nil
|
||||
|
||||
%{"group" => group, "key" => key, "value" => value} ->
|
||||
{:ok, config} = Config.update_or_create(%{group: group, key: key, value: value})
|
||||
config
|
||||
end)
|
||||
|> Enum.reject(&is_nil(&1))
|
||||
|
||||
|
|
@ -401,26 +395,26 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
|||
|
||||
def errors(conn, {:error, :not_found}) do
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json("Not found")
|
||||
|> put_status(:not_found)
|
||||
|> json(dgettext("errors", "Not found"))
|
||||
end
|
||||
|
||||
def errors(conn, {:error, reason}) do
|
||||
conn
|
||||
|> put_status(400)
|
||||
|> put_status(:bad_request)
|
||||
|> json(reason)
|
||||
end
|
||||
|
||||
def errors(conn, {:param_cast, _}) do
|
||||
conn
|
||||
|> put_status(400)
|
||||
|> json("Invalid parameters")
|
||||
|> put_status(:bad_request)
|
||||
|> json(dgettext("errors", "Invalid parameters"))
|
||||
end
|
||||
|
||||
def errors(conn, _) do
|
||||
conn
|
||||
|> put_status(500)
|
||||
|> json("Something went wrong")
|
||||
|> put_status(:internal_server_error)
|
||||
|> json(dgettext("errors", "Something went wrong"))
|
||||
end
|
||||
|
||||
defp page_params(params) do
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
defmodule Pleroma.Web.AdminAPI.Config do
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
import Pleroma.Web.Gettext
|
||||
alias __MODULE__
|
||||
alias Pleroma.Repo
|
||||
|
||||
|
|
@ -57,104 +58,95 @@ defmodule Pleroma.Web.AdminAPI.Config do
|
|||
with %Config{} = config <- Config.get_by_params(params) do
|
||||
Repo.delete(config)
|
||||
else
|
||||
nil -> {:error, "Config with params #{inspect(params)} not found"}
|
||||
nil ->
|
||||
err =
|
||||
dgettext("errors", "Config with params %{params} not found", params: inspect(params))
|
||||
|
||||
{:error, err}
|
||||
end
|
||||
end
|
||||
|
||||
@spec from_binary(binary()) :: term()
|
||||
def from_binary(value), do: :erlang.binary_to_term(value)
|
||||
def from_binary(binary), do: :erlang.binary_to_term(binary)
|
||||
|
||||
@spec from_binary_to_map(binary()) :: any()
|
||||
def from_binary_to_map(binary) do
|
||||
@spec from_binary_with_convert(binary()) :: any()
|
||||
def from_binary_with_convert(binary) do
|
||||
from_binary(binary)
|
||||
|> do_convert()
|
||||
end
|
||||
|
||||
defp do_convert([{k, v}] = value) when is_list(value) and length(value) == 1,
|
||||
do: %{k => do_convert(v)}
|
||||
defp do_convert(entity) when is_list(entity) do
|
||||
for v <- entity, into: [], do: do_convert(v)
|
||||
end
|
||||
|
||||
defp do_convert(values) when is_list(values), do: for(val <- values, do: do_convert(val))
|
||||
defp do_convert(entity) when is_map(entity) do
|
||||
for {k, v} <- entity, into: %{}, do: {do_convert(k), do_convert(v)}
|
||||
end
|
||||
|
||||
defp do_convert({k, v} = value) when is_tuple(value),
|
||||
do: %{k => do_convert(v)}
|
||||
defp do_convert({:dispatch, [entity]}), do: %{"tuple" => [":dispatch", [inspect(entity)]]}
|
||||
|
||||
defp do_convert(value) when is_tuple(value), do: %{"tuple" => do_convert(Tuple.to_list(value))}
|
||||
defp do_convert(entity) when is_tuple(entity),
|
||||
do: %{"tuple" => do_convert(Tuple.to_list(entity))}
|
||||
|
||||
defp do_convert(value) when is_binary(value) or is_map(value) or is_number(value), do: value
|
||||
defp do_convert(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity),
|
||||
do: entity
|
||||
|
||||
defp do_convert(value) when is_atom(value) do
|
||||
string = to_string(value)
|
||||
defp do_convert(entity) when is_atom(entity) do
|
||||
string = to_string(entity)
|
||||
|
||||
if String.starts_with?(string, "Elixir."),
|
||||
do: String.trim_leading(string, "Elixir."),
|
||||
else: value
|
||||
do: do_convert(string),
|
||||
else: ":" <> string
|
||||
end
|
||||
|
||||
defp do_convert("Elixir." <> module_name), do: module_name
|
||||
|
||||
defp do_convert(entity) when is_binary(entity), do: entity
|
||||
|
||||
@spec transform(any()) :: binary()
|
||||
def transform(%{"tuple" => _} = entity), do: :erlang.term_to_binary(do_transform(entity))
|
||||
|
||||
def transform(entity) when is_map(entity) do
|
||||
tuples =
|
||||
for {k, v} <- entity,
|
||||
into: [],
|
||||
do: {if(is_atom(k), do: k, else: String.to_atom(k)), do_transform(v)}
|
||||
|
||||
Enum.reject(tuples, fn {_k, v} -> is_nil(v) end)
|
||||
|> Enum.sort()
|
||||
|> :erlang.term_to_binary()
|
||||
end
|
||||
|
||||
def transform(entity) when is_list(entity) do
|
||||
list = Enum.map(entity, &do_transform(&1))
|
||||
:erlang.term_to_binary(list)
|
||||
def transform(entity) when is_binary(entity) or is_map(entity) or is_list(entity) do
|
||||
:erlang.term_to_binary(do_transform(entity))
|
||||
end
|
||||
|
||||
def transform(entity), do: :erlang.term_to_binary(entity)
|
||||
|
||||
defp do_transform(%Regex{} = value) when is_map(value), do: value
|
||||
defp do_transform(%Regex{} = entity) when is_map(entity), do: entity
|
||||
|
||||
defp do_transform(%{"tuple" => [k, values] = entity}) when length(entity) == 2 do
|
||||
{do_transform(k), do_transform(values)}
|
||||
defp do_transform(%{"tuple" => [":dispatch", [entity]]}) do
|
||||
cleaned_string = String.replace(entity, ~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "")
|
||||
{dispatch_settings, []} = Code.eval_string(cleaned_string, [], requires: [], macros: [])
|
||||
{:dispatch, [dispatch_settings]}
|
||||
end
|
||||
|
||||
defp do_transform(%{"tuple" => values}) do
|
||||
Enum.reduce(values, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end)
|
||||
defp do_transform(%{"tuple" => entity}) do
|
||||
Enum.reduce(entity, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end)
|
||||
end
|
||||
|
||||
defp do_transform(value) when is_map(value) do
|
||||
values = for {key, val} <- value, into: [], do: {String.to_atom(key), do_transform(val)}
|
||||
|
||||
Enum.sort(values)
|
||||
defp do_transform(entity) when is_map(entity) do
|
||||
for {k, v} <- entity, into: %{}, do: {do_transform(k), do_transform(v)}
|
||||
end
|
||||
|
||||
defp do_transform(value) when is_list(value) do
|
||||
Enum.map(value, &do_transform(&1))
|
||||
defp do_transform(entity) when is_list(entity) do
|
||||
for v <- entity, into: [], do: do_transform(v)
|
||||
end
|
||||
|
||||
defp do_transform(entity) when is_list(entity) and length(entity) == 1, do: hd(entity)
|
||||
|
||||
defp do_transform(value) when is_binary(value) do
|
||||
String.trim(value)
|
||||
defp do_transform(entity) when is_binary(entity) do
|
||||
String.trim(entity)
|
||||
|> do_transform_string()
|
||||
end
|
||||
|
||||
defp do_transform(value), do: value
|
||||
defp do_transform(entity), do: entity
|
||||
|
||||
defp do_transform_string(value) when byte_size(value) == 0, do: nil
|
||||
defp do_transform_string("~r/" <> pattern) do
|
||||
pattern = String.trim_trailing(pattern, "/")
|
||||
~r/#{pattern}/
|
||||
end
|
||||
|
||||
defp do_transform_string(":" <> atom), do: String.to_atom(atom)
|
||||
|
||||
defp do_transform_string(value) do
|
||||
cond do
|
||||
String.starts_with?(value, "Pleroma") or String.starts_with?(value, "Phoenix") ->
|
||||
String.to_existing_atom("Elixir." <> value)
|
||||
|
||||
String.starts_with?(value, ":") ->
|
||||
String.replace(value, ":", "") |> String.to_existing_atom()
|
||||
|
||||
String.starts_with?(value, "i:") ->
|
||||
String.replace(value, "i:", "") |> String.to_integer()
|
||||
|
||||
true ->
|
||||
value
|
||||
end
|
||||
if String.starts_with?(value, "Pleroma") or String.starts_with?(value, "Phoenix"),
|
||||
do: String.to_existing_atom("Elixir." <> value),
|
||||
else: value
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.AdminAPI.ConfigView do
|
||||
use Pleroma.Web, :view
|
||||
|
||||
|
|
@ -11,7 +15,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigView do
|
|||
%{
|
||||
key: config.key,
|
||||
group: config.group,
|
||||
value: Pleroma.Web.AdminAPI.Config.from_binary_to_map(config.value)
|
||||
value: Pleroma.Web.AdminAPI.Config.from_binary_with_convert(config.value)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
|
||||
import Pleroma.Web.Gettext
|
||||
import Pleroma.Web.CommonAPI.Utils
|
||||
|
||||
def follow(follower, followed) do
|
||||
|
|
@ -74,7 +75,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
{:ok, delete}
|
||||
else
|
||||
_ ->
|
||||
{:error, "Could not delete"}
|
||||
{:error, dgettext("errors", "Could not delete")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -85,7 +86,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
ActivityPub.announce(user, object)
|
||||
else
|
||||
_ ->
|
||||
{:error, "Could not repeat"}
|
||||
{:error, dgettext("errors", "Could not repeat")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -95,7 +96,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
ActivityPub.unannounce(user, object)
|
||||
else
|
||||
_ ->
|
||||
{:error, "Could not unrepeat"}
|
||||
{:error, dgettext("errors", "Could not unrepeat")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -106,7 +107,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
ActivityPub.like(user, object)
|
||||
else
|
||||
_ ->
|
||||
{:error, "Could not favorite"}
|
||||
{:error, dgettext("errors", "Could not favorite")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -116,7 +117,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
ActivityPub.unlike(user, object)
|
||||
else
|
||||
_ ->
|
||||
{:error, "Could not unfavorite"}
|
||||
{:error, dgettext("errors", "Could not unfavorite")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -148,10 +149,10 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
object = Object.get_cached_by_ap_id(object.data["id"])
|
||||
{:ok, answer_activities, object}
|
||||
else
|
||||
{:author, _} -> {:error, "Poll's author can't vote"}
|
||||
{:existing_votes, _} -> {:error, "Already voted"}
|
||||
{:choice_check, {_, false}} -> {:error, "Invalid indices"}
|
||||
{:count_check, false} -> {:error, "Too many choices"}
|
||||
{:author, _} -> {:error, dgettext("errors", "Poll's author can't vote")}
|
||||
{:existing_votes, _} -> {:error, dgettext("errors", "Already voted")}
|
||||
{:choice_check, {_, false}} -> {:error, dgettext("errors", "Invalid indices")}
|
||||
{:count_check, false} -> {:error, dgettext("errors", "Too many choices")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -248,9 +249,14 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
|
||||
res
|
||||
else
|
||||
{:private_to_public, true} -> {:error, "The message visibility must be direct"}
|
||||
{:error, _} = e -> e
|
||||
e -> {:error, e}
|
||||
{:private_to_public, true} ->
|
||||
{:error, dgettext("errors", "The message visibility must be direct")}
|
||||
|
||||
{:error, _} = e ->
|
||||
e
|
||||
|
||||
e ->
|
||||
{:error, e}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -301,7 +307,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
{:error, err}
|
||||
|
||||
_ ->
|
||||
{:error, "Could not pin"}
|
||||
{:error, dgettext("errors", "Could not pin")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -318,7 +324,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
{:error, err}
|
||||
|
||||
_ ->
|
||||
{:error, "Could not unpin"}
|
||||
{:error, dgettext("errors", "Could not unpin")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -326,7 +332,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
with {:ok, _} <- ThreadMute.add_mute(user.id, activity.data["context"]) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:error, _} -> {:error, "conversation is already muted"}
|
||||
{:error, _} -> {:error, dgettext("errors", "conversation is already muted")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -371,8 +377,8 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
{:ok, activity}
|
||||
else
|
||||
{:error, err} -> {:error, err}
|
||||
{:account_id, %{}} -> {:error, "Valid `account_id` required"}
|
||||
{:account, nil} -> {:error, "Account not found"}
|
||||
{:account_id, %{}} -> {:error, dgettext("errors", "Valid `account_id` required")}
|
||||
{:account, nil} -> {:error, dgettext("errors", "Account not found")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -381,14 +387,9 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
{:ok, activity} <- Utils.update_report_state(activity, state) do
|
||||
{:ok, activity}
|
||||
else
|
||||
nil ->
|
||||
{:error, :not_found}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
|
||||
_ ->
|
||||
{:error, "Could not update state"}
|
||||
nil -> {:error, :not_found}
|
||||
{:error, reason} -> {:error, reason}
|
||||
_ -> {:error, dgettext("errors", "Could not update state")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -398,11 +399,8 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
{:ok, activity} <- set_visibility(activity, opts) do
|
||||
{:ok, activity}
|
||||
else
|
||||
nil ->
|
||||
{:error, :not_found}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
nil -> {:error, :not_found}
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.CommonAPI.Utils do
|
||||
import Pleroma.Web.Gettext
|
||||
|
||||
alias Calendar.Strftime
|
||||
alias Comeonin.Pbkdf2
|
||||
alias Pleroma.Activity
|
||||
|
|
@ -372,7 +374,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
true <- Pbkdf2.checkpw(password, db_user.password_hash) do
|
||||
{:ok, db_user}
|
||||
else
|
||||
_ -> {:error, "Invalid password."}
|
||||
_ -> {:error, dgettext("errors", "Invalid password.")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -455,7 +457,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
if String.length(comment) <= max_size do
|
||||
{:ok, format_input(comment, "text/plain")}
|
||||
else
|
||||
{:error, "Comment must be up to #{max_size} characters"}
|
||||
{:error,
|
||||
dgettext("errors", "Comment must be up to %{max_size} characters", max_size: max_size)}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -490,7 +493,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
context
|
||||
else
|
||||
_e ->
|
||||
{:error, "No such conversation"}
|
||||
{:error, dgettext("errors", "No such conversation")}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -512,10 +515,10 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
if length > 0 or Enum.count(attachments) > 0 do
|
||||
:ok
|
||||
else
|
||||
{:error, "Cannot post an empty status without attachments"}
|
||||
{:error, dgettext("errors", "Cannot post an empty status without attachments")}
|
||||
end
|
||||
else
|
||||
{:error, "The status is over the character limit"}
|
||||
{:error, dgettext("errors", "The status is over the character limit")}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,13 +7,9 @@ defmodule Pleroma.Web.Endpoint do
|
|||
|
||||
socket("/socket", Pleroma.Web.UserSocket)
|
||||
|
||||
# Serve at "/" the static files from "priv/static" directory.
|
||||
#
|
||||
# You should set gzip to true if you are running phoenix.digest
|
||||
# when deploying your static files in production.
|
||||
plug(Pleroma.Plugs.SetLocalePlug)
|
||||
plug(CORSPlug)
|
||||
plug(Pleroma.Plugs.HTTPSecurityPlug)
|
||||
|
||||
plug(Pleroma.Plugs.UploadedMedia)
|
||||
|
||||
@static_cache_control "public, no-cache"
|
||||
|
|
@ -30,6 +26,10 @@ defmodule Pleroma.Web.Endpoint do
|
|||
}
|
||||
)
|
||||
|
||||
# Serve at "/" the static files from "priv/static" directory.
|
||||
#
|
||||
# You should set gzip to true if you are running phoenix.digest
|
||||
# when deploying your static files in production.
|
||||
plug(
|
||||
Plug.Static,
|
||||
at: "/",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
|
||||
import Ecto.Query
|
||||
import Ecto.Changeset
|
||||
|
|
|
|||
|
|
@ -160,10 +160,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
AccountView.render("account.json", %{user: user, for: user, with_pleroma_settings: true})
|
||||
)
|
||||
else
|
||||
_e ->
|
||||
conn
|
||||
|> put_status(403)
|
||||
|> json(%{error: "Invalid request"})
|
||||
_e -> render_error(conn, :forbidden, "Invalid request")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -258,10 +255,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
account = AccountView.render("account.json", %{user: user, for: for_user})
|
||||
json(conn, account)
|
||||
else
|
||||
_e ->
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Can't find user"})
|
||||
_e -> render_error(conn, :not_found, "Can't find user")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -305,7 +299,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
"static_url" => url,
|
||||
"visible_in_picker" => true,
|
||||
"url" => url,
|
||||
"tags" => tags
|
||||
"tags" => tags,
|
||||
# Assuming that a comma is authorized in the category name
|
||||
"category" => (tags -- ["Custom"]) |> Enum.join(",")
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
|
@ -509,15 +505,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|> put_view(StatusView)
|
||||
|> try_render("poll.json", %{object: object, for: user})
|
||||
else
|
||||
nil ->
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Record not found"})
|
||||
|
||||
false ->
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Record not found"})
|
||||
nil -> render_error(conn, :not_found, "Record not found")
|
||||
false -> render_error(conn, :not_found, "Record not found")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -546,18 +535,14 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|> try_render("poll.json", %{object: object, for: user})
|
||||
else
|
||||
nil ->
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Record not found"})
|
||||
render_error(conn, :not_found, "Record not found")
|
||||
|
||||
false ->
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Record not found"})
|
||||
render_error(conn, :not_found, "Record not found")
|
||||
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_status(422)
|
||||
|> put_status(:unprocessable_entity)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
|
@ -646,10 +631,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
|
||||
json(conn, %{})
|
||||
else
|
||||
_e ->
|
||||
conn
|
||||
|> put_status(403)
|
||||
|> json(%{error: "Can't delete this post"})
|
||||
_e -> render_error(conn, :forbidden, "Can't delete this post")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -697,8 +679,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
{:error, reason} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(:bad_request, Jason.encode!(%{"error" => reason}))
|
||||
|> put_status(:bad_request)
|
||||
|> json(%{"error" => reason})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -774,8 +756,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
{:error, reason} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{"error" => reason}))
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{"error" => reason})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -790,8 +772,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
{:error, reason} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{"error" => reason}))
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{"error" => reason})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -869,9 +851,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
conn
|
||||
|> json(rendered)
|
||||
else
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(415, Jason.encode!(%{"error" => "mascots can only be images"}))
|
||||
render_error(conn, :unsupported_media_type, "mascots can only be images")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1000,8 +980,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{"error" => message}))
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1014,8 +994,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{"error" => message}))
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1032,8 +1012,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{"error" => message}))
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1050,8 +1030,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{"error" => message}))
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1080,8 +1060,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{"error" => message}))
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1094,8 +1074,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{"error" => message}))
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1116,8 +1096,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{"error" => message}))
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1131,8 +1111,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{"error" => message}))
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1166,8 +1146,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{"error" => message}))
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1180,8 +1160,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{"error" => message}))
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1229,13 +1209,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|> put_view(StatusView)
|
||||
|> render("index.json", %{activities: activities, for: for_user, as: :activity})
|
||||
else
|
||||
nil ->
|
||||
{:error, :not_found}
|
||||
|
||||
true ->
|
||||
conn
|
||||
|> put_status(403)
|
||||
|> json(%{error: "Can't get favorites"})
|
||||
nil -> {:error, :not_found}
|
||||
true -> render_error(conn, :forbidden, "Can't get favorites")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1267,10 +1242,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
res = ListView.render("list.json", list: list)
|
||||
json(conn, res)
|
||||
else
|
||||
_e ->
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Record not found"})
|
||||
_e -> render_error(conn, :not_found, "Record not found")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1286,7 +1258,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
json(conn, %{})
|
||||
else
|
||||
_e ->
|
||||
json(conn, "error")
|
||||
json(conn, dgettext("errors", "error"))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1337,7 +1309,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
json(conn, res)
|
||||
else
|
||||
_e ->
|
||||
json(conn, "error")
|
||||
json(conn, dgettext("errors", "error"))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1361,10 +1333,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|> put_view(StatusView)
|
||||
|> render("index.json", %{activities: activities, for: user, as: :activity})
|
||||
else
|
||||
_e ->
|
||||
conn
|
||||
|> put_status(403)
|
||||
|> json(%{error: "Error."})
|
||||
_e -> render_error(conn, :forbidden, "Error.")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1483,8 +1452,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
e ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(500, Jason.encode!(%{"error" => inspect(e)}))
|
||||
|> put_status(:internal_server_error)
|
||||
|> json(%{error: inspect(e)})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -1652,20 +1621,18 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|> Enum.map_join(", ", fn {_k, v} -> v end)
|
||||
|
||||
conn
|
||||
|> put_status(422)
|
||||
|> put_status(:unprocessable_entity)
|
||||
|> json(%{error: error_message})
|
||||
end
|
||||
|
||||
def errors(conn, {:error, :not_found}) do
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Record not found"})
|
||||
render_error(conn, :not_found, "Record not found")
|
||||
end
|
||||
|
||||
def errors(conn, _) do
|
||||
conn
|
||||
|> put_status(500)
|
||||
|> json("Something went wrong")
|
||||
|> put_status(:internal_server_error)
|
||||
|> json(dgettext("errors", "Something went wrong"))
|
||||
end
|
||||
|
||||
def suggestions(%{assigns: %{user: user}} = conn, _) do
|
||||
|
|
@ -1785,21 +1752,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
{:error, errors} ->
|
||||
conn
|
||||
|> put_status(400)
|
||||
|> json(Jason.encode!(errors))
|
||||
|> put_status(:bad_request)
|
||||
|> json(errors)
|
||||
end
|
||||
end
|
||||
|
||||
def account_register(%{assigns: %{app: _app}} = conn, _params) do
|
||||
conn
|
||||
|> put_status(400)
|
||||
|> json(%{error: "Missing parameters"})
|
||||
render_error(conn, :bad_request, "Missing parameters")
|
||||
end
|
||||
|
||||
def account_register(conn, _) do
|
||||
conn
|
||||
|> put_status(403)
|
||||
|> json(%{error: "Invalid credentials"})
|
||||
render_error(conn, :forbidden, "Invalid credentials")
|
||||
end
|
||||
|
||||
def conversations(%{assigns: %{user: user}} = conn, params) do
|
||||
|
|
@ -1829,21 +1792,14 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|
||||
def try_render(conn, target, params)
|
||||
when is_binary(target) do
|
||||
res = render(conn, target, params)
|
||||
|
||||
if res == nil do
|
||||
conn
|
||||
|> put_status(501)
|
||||
|> json(%{error: "Can't display this activity"})
|
||||
else
|
||||
res
|
||||
case render(conn, target, params) do
|
||||
nil -> render_error(conn, :not_implemented, "Can't display this activity")
|
||||
res -> res
|
||||
end
|
||||
end
|
||||
|
||||
def try_render(conn, _, _) do
|
||||
conn
|
||||
|> put_status(501)
|
||||
|> json(%{error: "Can't display this activity"})
|
||||
render_error(conn, :not_implemented, "Can't display this activity")
|
||||
end
|
||||
|
||||
defp present?(nil), do: false
|
||||
|
|
|
|||
|
|
@ -4,61 +4,18 @@
|
|||
|
||||
defmodule Pleroma.Web.MastodonAPI.SearchController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Plugs.RateLimiter
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web
|
||||
alias Pleroma.Web.ControllerHelper
|
||||
alias Pleroma.Web.MastodonAPI.AccountView
|
||||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
|
||||
alias Pleroma.Web.ControllerHelper
|
||||
|
||||
require Logger
|
||||
|
||||
plug(Pleroma.Plugs.RateLimiter, :search when action in [:search, :search2, :account_search])
|
||||
|
||||
def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
|
||||
accounts = with_fallback(fn -> User.search(query, search_options(params, user)) end, [])
|
||||
statuses = with_fallback(fn -> Activity.search(user, query) end, [])
|
||||
tags_path = Web.base_url() <> "/tag/"
|
||||
|
||||
tags =
|
||||
query
|
||||
|> String.split()
|
||||
|> Enum.uniq()
|
||||
|> Enum.filter(fn tag -> String.starts_with?(tag, "#") end)
|
||||
|> Enum.map(fn tag -> String.slice(tag, 1..-1) end)
|
||||
|> Enum.map(fn tag -> %{name: tag, url: tags_path <> tag} end)
|
||||
|
||||
res = %{
|
||||
"accounts" => AccountView.render("accounts.json", users: accounts, for: user, as: :user),
|
||||
"statuses" =>
|
||||
StatusView.render("index.json", activities: statuses, for: user, as: :activity),
|
||||
"hashtags" => tags
|
||||
}
|
||||
|
||||
json(conn, res)
|
||||
end
|
||||
|
||||
def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
|
||||
accounts = with_fallback(fn -> User.search(query, search_options(params, user)) end, [])
|
||||
statuses = with_fallback(fn -> Activity.search(user, query) end, [])
|
||||
|
||||
tags =
|
||||
query
|
||||
|> String.split()
|
||||
|> Enum.uniq()
|
||||
|> Enum.filter(fn tag -> String.starts_with?(tag, "#") end)
|
||||
|> Enum.map(fn tag -> String.slice(tag, 1..-1) end)
|
||||
|
||||
res = %{
|
||||
"accounts" => AccountView.render("accounts.json", users: accounts, for: user, as: :user),
|
||||
"statuses" =>
|
||||
StatusView.render("index.json", activities: statuses, for: user, as: :activity),
|
||||
"hashtags" => tags
|
||||
}
|
||||
|
||||
json(conn, res)
|
||||
end
|
||||
plug(RateLimiter, :search when action in [:search, :search2, :account_search])
|
||||
|
||||
def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
|
||||
accounts = User.search(query, search_options(params, user))
|
||||
|
|
@ -67,17 +24,86 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
|
|||
json(conn, res)
|
||||
end
|
||||
|
||||
def search2(conn, params), do: do_search(:v2, conn, params)
|
||||
def search(conn, params), do: do_search(:v1, conn, params)
|
||||
|
||||
defp do_search(version, %{assigns: %{user: user}} = conn, %{"q" => query} = params) do
|
||||
options = search_options(params, user)
|
||||
timeout = Keyword.get(Repo.config(), :timeout, 15_000)
|
||||
default_values = %{"statuses" => [], "accounts" => [], "hashtags" => []}
|
||||
|
||||
result =
|
||||
default_values
|
||||
|> Enum.map(fn {resource, default_value} ->
|
||||
if params["type"] == nil or params["type"] == resource do
|
||||
{resource, fn -> resource_search(version, resource, query, options) end}
|
||||
else
|
||||
{resource, fn -> default_value end}
|
||||
end
|
||||
end)
|
||||
|> Task.async_stream(fn {resource, f} -> {resource, with_fallback(f)} end,
|
||||
timeout: timeout,
|
||||
on_timeout: :kill_task
|
||||
)
|
||||
|> Enum.reduce(default_values, fn
|
||||
{:ok, {resource, result}}, acc ->
|
||||
Map.put(acc, resource, result)
|
||||
|
||||
_error, acc ->
|
||||
acc
|
||||
end)
|
||||
|
||||
json(conn, result)
|
||||
end
|
||||
|
||||
defp search_options(params, user) do
|
||||
[
|
||||
resolve: params["resolve"] == "true",
|
||||
following: params["following"] == "true",
|
||||
limit: ControllerHelper.fetch_integer_param(params, "limit"),
|
||||
offset: ControllerHelper.fetch_integer_param(params, "offset"),
|
||||
type: params["type"],
|
||||
author: get_author(params),
|
||||
for_user: user
|
||||
]
|
||||
|> Enum.filter(&elem(&1, 1))
|
||||
end
|
||||
|
||||
defp with_fallback(f, fallback) do
|
||||
defp resource_search(_, "accounts", query, options) do
|
||||
accounts = with_fallback(fn -> User.search(query, options) end)
|
||||
AccountView.render("accounts.json", users: accounts, for: options[:for_user], as: :user)
|
||||
end
|
||||
|
||||
defp resource_search(_, "statuses", query, options) do
|
||||
statuses = with_fallback(fn -> Activity.search(options[:for_user], query, options) end)
|
||||
StatusView.render("index.json", activities: statuses, for: options[:for_user], as: :activity)
|
||||
end
|
||||
|
||||
defp resource_search(:v2, "hashtags", query, _options) do
|
||||
tags_path = Web.base_url() <> "/tag/"
|
||||
|
||||
query
|
||||
|> prepare_tags()
|
||||
|> Enum.map(fn tag ->
|
||||
tag = String.trim_leading(tag, "#")
|
||||
%{name: tag, url: tags_path <> tag}
|
||||
end)
|
||||
end
|
||||
|
||||
defp resource_search(:v1, "hashtags", query, _options) do
|
||||
query
|
||||
|> prepare_tags()
|
||||
|> Enum.map(fn tag -> String.trim_leading(tag, "#") end)
|
||||
end
|
||||
|
||||
defp prepare_tags(query) do
|
||||
query
|
||||
|> String.split()
|
||||
|> Enum.uniq()
|
||||
|> Enum.filter(fn tag -> String.starts_with?(tag, "#") end)
|
||||
end
|
||||
|
||||
defp with_fallback(f, fallback \\ []) do
|
||||
try do
|
||||
f.()
|
||||
rescue
|
||||
|
|
@ -86,4 +112,9 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
|
|||
fallback
|
||||
end
|
||||
end
|
||||
|
||||
defp get_author(%{"account_id" => account_id}) when is_binary(account_id),
|
||||
do: User.get_cached_by_id(account_id)
|
||||
|
||||
defp get_author(_params), do: nil
|
||||
end
|
||||
|
|
|
|||
|
|
@ -59,13 +59,13 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionController do
|
|||
#
|
||||
def errors(conn, {:error, :not_found}) do
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json("Not found")
|
||||
|> put_status(:not_found)
|
||||
|> json(dgettext("errors", "Not found"))
|
||||
end
|
||||
|
||||
def errors(conn, _) do
|
||||
conn
|
||||
|> put_status(500)
|
||||
|> json("Something went wrong")
|
||||
|> put_status(:internal_server_error)
|
||||
|> json(dgettext("errors", "Something went wrong"))
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.MastodonAPI.ConversationView do
|
||||
use Pleroma.Web, :view
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1]
|
||||
|
||||
# TODO: Add cached version.
|
||||
defp get_replied_to_activities([]), do: %{}
|
||||
|
||||
defp get_replied_to_activities(activities) do
|
||||
activities
|
||||
|> Enum.map(fn
|
||||
|
|
@ -147,8 +149,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
tags = object.data["tag"] || []
|
||||
sensitive = object.data["sensitive"] || Enum.member?(tags, "nsfw")
|
||||
|
||||
tag_mentions =
|
||||
tags
|
||||
|> Enum.filter(fn tag -> is_map(tag) and tag["type"] == "Mention" end)
|
||||
|> Enum.map(fn tag -> tag["href"] end)
|
||||
|
||||
mentions =
|
||||
activity.recipients
|
||||
(object.data["to"] ++ tag_mentions)
|
||||
|> Enum.uniq()
|
||||
|> Enum.map(fn ap_id -> User.get_cached_by_ap_id(ap_id) end)
|
||||
|> Enum.filter(& &1)
|
||||
|> Enum.map(fn user -> AccountView.render("mention.json", %{user: user}) end)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.Metadata.PlayerView do
|
||||
use Pleroma.Web, :view
|
||||
import Phoenix.HTML.Tag, only: [content_tag: 3, tag: 2]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.Metadata.Providers.RelMe do
|
||||
alias Pleroma.Web.Metadata.Providers.Provider
|
||||
@behaviour Provider
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ defmodule Pleroma.Web.MongooseIM.MongooseIMController do
|
|||
else
|
||||
false ->
|
||||
conn
|
||||
|> put_status(403)
|
||||
|> put_status(:forbidden)
|
||||
|> json(false)
|
||||
|
||||
_ ->
|
||||
|
|
|
|||
|
|
@ -201,8 +201,6 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
|
|||
end
|
||||
|
||||
def nodeinfo(conn, _) do
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Nodeinfo schema version not handled"})
|
||||
render_error(conn, :not_found, "Nodeinfo schema version not handled")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,21 +9,24 @@ defmodule Pleroma.Web.OAuth.FallbackController do
|
|||
def call(conn, {:register, :generic_error}) do
|
||||
conn
|
||||
|> put_status(:internal_server_error)
|
||||
|> put_flash(:error, "Unknown error, please check the details and try again.")
|
||||
|> put_flash(
|
||||
:error,
|
||||
dgettext("errors", "Unknown error, please check the details and try again.")
|
||||
)
|
||||
|> OAuthController.registration_details(conn.params)
|
||||
end
|
||||
|
||||
def call(conn, {:register, _error}) do
|
||||
conn
|
||||
|> put_status(:unauthorized)
|
||||
|> put_flash(:error, "Invalid Username/Password")
|
||||
|> put_flash(:error, dgettext("errors", "Invalid Username/Password"))
|
||||
|> OAuthController.registration_details(conn.params)
|
||||
end
|
||||
|
||||
def call(conn, _error) do
|
||||
conn
|
||||
|> put_status(:unauthorized)
|
||||
|> put_flash(:error, "Invalid Username/Password")
|
||||
|> put_flash(:error, dgettext("errors", "Invalid Username/Password"))
|
||||
|> OAuthController.authorize(conn.params)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
redirect(conn, external: url)
|
||||
else
|
||||
conn
|
||||
|> put_flash(:error, "Unlisted redirect_uri.")
|
||||
|> put_flash(:error, dgettext("errors", "Unlisted redirect_uri."))
|
||||
|> redirect(external: redirect_uri(conn, redirect_uri))
|
||||
end
|
||||
end
|
||||
|
|
@ -128,7 +128,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
redirect(conn, external: url)
|
||||
else
|
||||
conn
|
||||
|> put_flash(:error, "Unlisted redirect_uri.")
|
||||
|> put_flash(:error, dgettext("errors", "Unlisted redirect_uri."))
|
||||
|> redirect(external: redirect_uri(conn, redirect_uri))
|
||||
end
|
||||
end
|
||||
|
|
@ -142,7 +142,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
# Per https://github.com/tootsuite/mastodon/blob/
|
||||
# 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L39
|
||||
conn
|
||||
|> put_flash(:error, "This action is outside the authorized scopes")
|
||||
|> put_flash(:error, dgettext("errors", "This action is outside the authorized scopes"))
|
||||
|> put_status(:unauthorized)
|
||||
|> authorize(params)
|
||||
end
|
||||
|
|
@ -155,7 +155,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
# Per https://github.com/tootsuite/mastodon/blob/
|
||||
# 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76
|
||||
conn
|
||||
|> put_flash(:error, "Your login is missing a confirmed e-mail address")
|
||||
|> put_flash(:error, dgettext("errors", "Your login is missing a confirmed e-mail address"))
|
||||
|> put_status(:forbidden)
|
||||
|> authorize(params)
|
||||
end
|
||||
|
|
@ -176,9 +176,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
|
||||
json(conn, Token.Response.build(user, token, response_attrs))
|
||||
else
|
||||
_error ->
|
||||
put_status(conn, 400)
|
||||
|> json(%{error: "Invalid credentials"})
|
||||
_error -> render_invalid_credentials_error(conn)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -192,9 +190,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
|
||||
json(conn, Token.Response.build(user, token, response_attrs))
|
||||
else
|
||||
_error ->
|
||||
put_status(conn, 400)
|
||||
|> json(%{error: "Invalid credentials"})
|
||||
_error -> render_invalid_credentials_error(conn)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -214,18 +210,13 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
{:auth_active, false} ->
|
||||
# Per https://github.com/tootsuite/mastodon/blob/
|
||||
# 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: "Your login is missing a confirmed e-mail address"})
|
||||
render_error(conn, :forbidden, "Your login is missing a confirmed e-mail address")
|
||||
|
||||
{:user_active, false} ->
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: "Your account is currently disabled"})
|
||||
render_error(conn, :forbidden, "Your account is currently disabled")
|
||||
|
||||
_error ->
|
||||
put_status(conn, 400)
|
||||
|> json(%{error: "Invalid credentials"})
|
||||
render_invalid_credentials_error(conn)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -247,9 +238,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
{:ok, token} <- Token.exchange_token(app, auth) do
|
||||
json(conn, Token.Response.build_for_client_credentials(token))
|
||||
else
|
||||
_error ->
|
||||
put_status(conn, 400)
|
||||
|> json(%{error: "Invalid credentials"})
|
||||
_error -> render_invalid_credentials_error(conn)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -271,9 +260,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
|
||||
# Response for bad request
|
||||
defp bad_request(%Plug.Conn{} = conn, _) do
|
||||
conn
|
||||
|> put_status(500)
|
||||
|> json(%{error: "Bad request"})
|
||||
render_error(conn, :internal_server_error, "Bad request")
|
||||
end
|
||||
|
||||
@doc "Prepares OAuth request to provider for Ueberauth"
|
||||
|
|
@ -304,9 +291,11 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
def request(%Plug.Conn{} = conn, params) do
|
||||
message =
|
||||
if params["provider"] do
|
||||
"Unsupported OAuth provider: #{params["provider"]}."
|
||||
dgettext("errors", "Unsupported OAuth provider: %{provider}.",
|
||||
provider: params["provider"]
|
||||
)
|
||||
else
|
||||
"Bad OAuth request."
|
||||
dgettext("errors", "Bad OAuth request.")
|
||||
end
|
||||
|
||||
conn
|
||||
|
|
@ -320,7 +309,10 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
message = Enum.join(messages, "; ")
|
||||
|
||||
conn
|
||||
|> put_flash(:error, "Failed to authenticate: #{message}.")
|
||||
|> put_flash(
|
||||
:error,
|
||||
dgettext("errors", "Failed to authenticate: %{message}.", message: message)
|
||||
)
|
||||
|> redirect(external: redirect_uri(conn, params["redirect_uri"]))
|
||||
end
|
||||
|
||||
|
|
@ -350,7 +342,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
Logger.debug(inspect(["OAUTH_ERROR", error, conn.assigns]))
|
||||
|
||||
conn
|
||||
|> put_flash(:error, "Failed to set up user account.")
|
||||
|> put_flash(:error, dgettext("errors", "Failed to set up user account."))
|
||||
|> redirect(external: redirect_uri(conn, params["redirect_uri"]))
|
||||
end
|
||||
end
|
||||
|
|
@ -468,4 +460,8 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
|||
|> String.split()
|
||||
|> Enum.at(0)
|
||||
end
|
||||
|
||||
defp render_invalid_credentials_error(conn) do
|
||||
render_error(conn, :bad_request, "Invalid credentials")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.OAuth.Token.Response do
|
||||
@moduledoc false
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.OAuth.Token.Strategy.RefreshToken do
|
||||
@moduledoc """
|
||||
Functions for dealing with refresh token strategy.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.OAuth.Token.Strategy.Revoke do
|
||||
@moduledoc """
|
||||
Functions for dealing with revocation.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.OAuth.Token.Utils do
|
||||
@moduledoc """
|
||||
Auxiliary functions for dealing with tokens.
|
||||
|
|
|
|||
|
|
@ -245,14 +245,10 @@ defmodule Pleroma.Web.OStatus.OStatusController do
|
|||
end
|
||||
|
||||
def errors(conn, {:error, :not_found}) do
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> text("Not found")
|
||||
render_error(conn, :not_found, "Not found")
|
||||
end
|
||||
|
||||
def errors(conn, _) do
|
||||
conn
|
||||
|> put_status(500)
|
||||
|> text("Something went wrong")
|
||||
render_error(conn, :internal_server_error, "Something went wrong")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.RichMedia.Parsers.MetaTagsParser do
|
||||
def parse(html, data, prefix, error_message, key_name, value_name \\ "content") do
|
||||
meta_data =
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.RichMedia.Parsers.OEmbed do
|
||||
def parse(html, _data) do
|
||||
with elements = [_ | _] <- get_discovery_data(html),
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.RichMedia.Parsers.OGP do
|
||||
def parse(html, data) do
|
||||
Pleroma.Web.RichMedia.Parsers.MetaTagsParser.parse(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.RichMedia.Parsers.TwitterCard do
|
||||
def parse(html, data) do
|
||||
Pleroma.Web.RichMedia.Parsers.MetaTagsParser.parse(
|
||||
|
|
|
|||
17
lib/pleroma/web/translation_helpers.ex
Normal file
17
lib/pleroma/web/translation_helpers.ex
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.TranslationHelpers do
|
||||
defmacro render_error(conn, status, msgid, bindings \\ Macro.escape(%{})) do
|
||||
quote do
|
||||
require Pleroma.Web.Gettext
|
||||
|
||||
unquote(conn)
|
||||
|> Plug.Conn.put_status(unquote(status))
|
||||
|> Phoenix.Controller.json(%{
|
||||
error: Pleroma.Web.Gettext.dgettext("errors", unquote(msgid), unquote(bindings))
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.UploaderController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
|
|
@ -8,7 +12,7 @@ defmodule Pleroma.Web.UploaderController do
|
|||
end
|
||||
|
||||
def callbacks(conn, _) do
|
||||
send_resp(conn, 400, "bad request")
|
||||
render_error(conn, :bad_request, "bad request")
|
||||
end
|
||||
|
||||
defp process_callback(conn, pid, params) when is_pid(pid) do
|
||||
|
|
@ -20,6 +24,6 @@ defmodule Pleroma.Web.UploaderController do
|
|||
end
|
||||
|
||||
defp process_callback(conn, _, _) do
|
||||
send_resp(conn, 400, "bad request")
|
||||
render_error(conn, :bad_request, "bad request")
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -23,9 +23,11 @@ defmodule Pleroma.Web do
|
|||
def controller do
|
||||
quote do
|
||||
use Phoenix.Controller, namespace: Pleroma.Web
|
||||
|
||||
import Plug.Conn
|
||||
import Pleroma.Web.Gettext
|
||||
import Pleroma.Web.Router.Helpers
|
||||
import Pleroma.Web.TranslationHelpers
|
||||
|
||||
plug(:set_put_layout)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Phoenix.Transports.WebSocket.Raw do
|
||||
import Plug.Conn,
|
||||
only: [
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.XmlBuilder do
|
||||
def to_xml({tag, attributes, content}) do
|
||||
open_tag = make_open_tag(tag, attributes)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue