1
0
Fork 1
mirror of https://akkoma.dev/AkkomaGang/akkoma.git synced 2024-12-25 04:53:06 +00:00

Merge branch 'develop' into feature/admin-api-status-count-per-instance

This commit is contained in:
Roman Chvanikov 2020-05-18 11:56:27 +03:00
commit 01bd6a1e54
83 changed files with 2550 additions and 679 deletions

View file

@ -28,6 +28,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list.
- NodeInfo: `pleroma_emoji_reactions` to the `features` list.
- Configuration: `:restrict_unauthenticated` setting, restrict access for unauthenticated users to timelines (public and federate), user profiles and statuses.
- Configuration: Add `:database_config_whitelist` setting to whitelist settings which can be configured from AdminFE.
- New HTTP adapter [gun](https://github.com/ninenines/gun). Gun adapter requires minimum OTP version of 22.2 otherwise Pleroma wont start. For hackney OTP update is not required.
- Mix task to create trusted OAuth App.
- Notifications: Added `follow_request` notification type.

View file

@ -387,56 +387,47 @@ defp render_timelines(user) do
favourites = ActivityPub.fetch_favourites(user)
output_relationships =
!!Pleroma.Config.get([:extensions, :output_relationships_in_statuses_by_default])
Benchee.run(
%{
"Rendering home timeline" => fn ->
StatusView.render("index.json", %{
activities: home_activities,
for: user,
as: :activity,
skip_relationships: !output_relationships
as: :activity
})
end,
"Rendering direct timeline" => fn ->
StatusView.render("index.json", %{
activities: direct_activities,
for: user,
as: :activity,
skip_relationships: !output_relationships
as: :activity
})
end,
"Rendering public timeline" => fn ->
StatusView.render("index.json", %{
activities: public_activities,
for: user,
as: :activity,
skip_relationships: !output_relationships
as: :activity
})
end,
"Rendering tag timeline" => fn ->
StatusView.render("index.json", %{
activities: tag_activities,
for: user,
as: :activity,
skip_relationships: !output_relationships
as: :activity
})
end,
"Rendering notifications" => fn ->
Pleroma.Web.MastodonAPI.NotificationView.render("index.json", %{
notifications: notifications,
for: user,
skip_relationships: !output_relationships
for: user
})
end,
"Rendering favourites timeline" => fn ->
StatusView.render("index.json", %{
activities: favourites,
for: user,
as: :activity,
skip_relationships: !output_relationships
as: :activity
})
end
},

View file

@ -251,8 +251,6 @@
]
]
config :pleroma, :extensions, output_relationships_in_statuses_by_default: true
config :pleroma, :feed,
post_title: %{
max_length: 100,

View file

@ -679,15 +679,6 @@
7
]
},
%{
key: :federation_publisher_modules,
type: {:list, :module},
description:
"List of modules for federation publishing. Module names are shortened (removed leading `Pleroma.Web.` part), but on adding custom module you need to use full name.",
suggestions: [
Pleroma.Web.ActivityPub.Publisher
]
},
%{
key: :allow_relay,
type: :boolean,
@ -1105,32 +1096,97 @@
description: "Settings for Pleroma FE",
suggestions: [
%{
theme: "pleroma-dark",
logo: "/static/logo.png",
background: "/images/city.jpg",
redirectRootNoLogin: "/main/all",
redirectRootLogin: "/main/friends",
showInstanceSpecificPanel: true,
scopeOptionsEnabled: false,
formattingOptionsEnabled: false,
collapseMessageWithSubject: false,
hidePostStats: false,
hideUserStats: false,
scopeCopy: true,
subjectLineBehavior: "email",
alwaysShowSubjectInput: true,
logoMask: false,
background: "/static/aurora_borealis.jpg",
collapseMessageWithSubject: false,
disableChat: false,
greentext: false,
hideFilteredStatuses: false,
hideMutedPosts: false,
hidePostStats: false,
hideSitename: false,
hideUserStats: false,
loginMethod: "password",
logo: "/static/logo.png",
logoMargin: ".1em",
stickers: false,
enableEmojiPicker: false
logoMask: true,
minimalScopesMode: false,
noAttachmentLinks: false,
nsfwCensorImage: "",
postContentType: "text/plain",
redirectRootLogin: "/main/friends",
redirectRootNoLogin: "/main/all",
scopeCopy: true,
showFeaturesPanel: true,
showInstanceSpecificPanel: false,
subjectLineBehavior: "email",
theme: "pleroma-dark",
webPushNotifications: false
}
],
children: [
%{
key: :theme,
key: :alwaysShowSubjectInput,
label: "Always show subject input",
type: :boolean,
description: "When disabled, auto-hide the subject field if it's empty"
},
%{
key: :background,
type: :string,
description: "Which theme to use, they are defined in styles.json",
suggestions: ["pleroma-dark"]
description:
"URL of the background, unless viewing a user profile with a background that is set",
suggestions: ["/images/city.jpg"]
},
%{
key: :collapseMessageWithSubject,
label: "Collapse message with subject",
type: :boolean,
description:
"When a message has a subject (aka Content Warning), collapse it by default"
},
%{
key: :disableChat,
label: "PleromaFE Chat",
type: :boolean,
description: "Disables PleromaFE Chat component"
},
%{
key: :greentext,
label: "Greentext",
type: :boolean,
description: "Enables green text on lines prefixed with the > character."
},
%{
key: :hideFilteredStatuses,
label: "Hide Filtered Statuses",
type: :boolean,
description: "Hides filtered statuses from timelines."
},
%{
key: :hideMutedPosts,
label: "Hide Muted Posts",
type: :boolean,
description: "Hides muted statuses from timelines."
},
%{
key: :hidePostStats,
label: "Hide post stats",
type: :boolean,
description: "Hide notices statistics (repeats, favorites, ...)"
},
%{
key: :hideSitename,
label: "Hide Sitename",
type: :boolean,
description: "Hides instance name from PleromaFE banner."
},
%{
key: :hideUserStats,
label: "Hide user stats",
type: :boolean,
description:
"Hide profile statistics (posts, posts per day, followers, followings, ...)"
},
%{
key: :logo,
@ -1139,11 +1195,44 @@
suggestions: ["/static/logo.png"]
},
%{
key: :background,
key: :logoMargin,
label: "Logo margin",
type: :string,
description:
"URL of the background, unless viewing a user profile with a background that is set",
suggestions: ["/images/city.jpg"]
"Allows you to adjust vertical margins between logo boundary and navbar borders. " <>
"The idea is that to have logo's image without any extra margins and instead adjust them to your need in layout.",
suggestions: [".1em"]
},
%{
key: :logoMask,
label: "Logo mask",
type: :boolean,
description:
"By default it assumes logo used will be monochrome with alpha channel to be compatible with both light and dark themes. " <>
"If you want a colorful logo you must disable logoMask."
},
%{
key: :minimalScopesMode,
label: "Minimal scopes mode",
type: :boolean,
description:
"Limit scope selection to Direct, User default, and Scope of post replying to. " <>
"Also prevents replying to a DM with a public post from PleromaFE."
},
%{
key: :nsfwCensorImage,
label: "NSFW Censor Image",
type: :string,
description:
"URL of the image to use for hiding NSFW media attachments in the timeline.",
suggestions: ["/static/img/nsfw.png"]
},
%{
key: :postContentType,
label: "Post Content Type",
type: {:dropdown, :atom},
description: "Default post formatting option.",
suggestions: ["text/plain", "text/html", "text/markdown", "text/bbcode"]
},
%{
key: :redirectRootNoLogin,
@ -1161,51 +1250,25 @@
"Relative URL which indicates where to redirect when a user is logged in",
suggestions: ["/main/friends"]
},
%{
key: :showInstanceSpecificPanel,
label: "Show instance specific panel",
type: :boolean,
description: "Whenether to show the instance's specific panel"
},
%{
key: :scopeOptionsEnabled,
label: "Scope options enabled",
type: :boolean,
description: "Enable setting a notice visibility and subject/CW when posting"
},
%{
key: :formattingOptionsEnabled,
label: "Formatting options enabled",
type: :boolean,
description:
"Enable setting a formatting different than plain-text (ie. HTML, Markdown) when posting, relates to `:instance`, `allowed_post_formats`"
},
%{
key: :collapseMessageWithSubject,
label: "Collapse message with subject",
type: :boolean,
description:
"When a message has a subject (aka Content Warning), collapse it by default"
},
%{
key: :hidePostStats,
label: "Hide post stats",
type: :boolean,
description: "Hide notices statistics (repeats, favorites, ...)"
},
%{
key: :hideUserStats,
label: "Hide user stats",
type: :boolean,
description:
"Hide profile statistics (posts, posts per day, followers, followings, ...)"
},
%{
key: :scopeCopy,
label: "Scope copy",
type: :boolean,
description: "Copy the scope (private/unlisted/public) in replies to posts by default"
},
%{
key: :showFeaturesPanel,
label: "Show instance features panel",
type: :boolean,
description:
"Enables panel displaying functionality of the instance on the About page."
},
%{
key: :showInstanceSpecificPanel,
label: "Show instance specific panel",
type: :boolean,
description: "Whether to show the instance's custom panel"
},
%{
key: :subjectLineBehavior,
label: "Subject line behavior",
@ -1217,38 +1280,10 @@
suggestions: ["email", "masto", "noop"]
},
%{
key: :alwaysShowSubjectInput,
label: "Always show subject input",
type: :boolean,
description: "When disabled, auto-hide the subject field if it's empty"
},
%{
key: :logoMask,
label: "Logo mask",
type: :boolean,
description:
"By default it assumes logo used will be monochrome with alpha channel to be compatible with both light and dark themes. " <>
"If you want a colorful logo you must disable logoMask."
},
%{
key: :logoMargin,
label: "Logo margin",
key: :theme,
type: :string,
description:
"Allows you to adjust vertical margins between logo boundary and navbar borders. " <>
"The idea is that to have logo's image without any extra margins and instead adjust them to your need in layout.",
suggestions: [".1em"]
},
%{
key: :stickers,
type: :boolean,
description: "Enables stickers."
},
%{
key: :enableEmojiPicker,
label: "Emoji picker",
type: :boolean,
description: "Enables emoji picker."
description: "Which theme to use. Available themes are defined in styles.json",
suggestions: ["pleroma-dark"]
}
]
},
@ -1858,12 +1893,6 @@
(see https://github.com/sorentwo/oban/issues/52).
""",
children: [
%{
key: :repo,
type: :module,
description: "Application's Ecto repo",
suggestions: [Pleroma.Repo]
},
%{
key: :verbose,
type: {:dropdown, :atom},
@ -2638,18 +2667,6 @@
}
]
},
%{
group: :http_signatures,
type: :group,
description: "HTTP Signatures settings",
children: [
%{
key: :adapter,
type: :module,
suggestions: [Pleroma.Signature]
}
]
},
%{
group: :pleroma,
key: :http,

View file

@ -911,6 +911,21 @@ config :auto_linker,
Boolean, enables/disables in-database configuration. Read [Transfering the config to/from the database](../administration/CLI_tasks/config.md) for more information.
## :database_config_whitelist
List of valid configuration sections which are allowed to be configured from the
database. Settings stored in the database before the whitelist is configured are
still applied, so it is suggested to only use the whitelist on instances that
have not migrated the config to the database.
Example:
```elixir
config :pleroma, :database_config_whitelist, [
{:pleroma, :instance},
{:pleroma, Pleroma.Web.Metadata},
{:auto_linker}
]
```
### Multi-factor authentication - :two_factor_authentication
* `totp` - a list containing TOTP configuration

View file

@ -1,21 +1,45 @@
#!/sbin/openrc-run
# Requires OpenRC >= 0.35
directory=/opt/pleroma
command=/usr/bin/mix
command_args="phx.server"
supervisor=supervise-daemon
command_user=pleroma:pleroma
command_background=1
export PORT=4000
export MIX_ENV=prod
# Ask process to terminate within 30 seconds, otherwise kill it
retry="SIGTERM/30/SIGKILL/5"
pidfile="/var/run/pleroma.pid"
directory=/opt/pleroma
healthcheck_delay=60
healthcheck_timer=30
: ${pleroma_port:-4000}
# Needs OpenRC >= 0.42
#respawn_max=0
#respawn_delay=5
# put pleroma_console=YES in /etc/conf.d/pleroma if you want to be able to
# connect to pleroma via an elixir console
if yesno "${pleroma_console}"; then
command=elixir
command_args="--name pleroma@127.0.0.1 --erl '-kernel inet_dist_listen_min 9001 inet_dist_listen_max 9001 inet_dist_use_interface {127,0,0,1}' -S mix phx.server"
start_post() {
einfo "You can get a console by using this command as pleroma's user:"
einfo "iex --name console@127.0.0.1 --remsh pleroma@127.0.0.1"
}
else
command=/usr/bin/mix
command_args="phx.server"
fi
export MIX_ENV=prod
depend() {
need nginx postgresql
need nginx postgresql
}
healthcheck() {
# put pleroma_health=YES in /etc/conf.d/pleroma if you want healthchecking
# and make sure you have curl installed
yesno "$pleroma_health" || return 0
curl -q "localhost:${pleroma_port}/api/pleroma/healthcheck"
}

View file

@ -67,8 +67,7 @@ def run(["render_timeline", nickname | _] = args) do
Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{
activities: activities,
for: user,
as: :activity,
skip_relationships: true
as: :activity
})
end
},

View file

@ -1,5 +1,6 @@
defmodule Mix.Tasks.Pleroma.Digest do
use Mix.Task
import Mix.Pleroma
@shortdoc "Manages digest emails"
@moduledoc File.read!("docs/administration/CLI_tasks/digest.md")
@ -22,12 +23,10 @@ def run(["test", nickname | opts]) do
with %Swoosh.Email{} = email <- Pleroma.Emails.UserEmail.digest_email(patched_user) do
{:ok, _} = Pleroma.Emails.Mailer.deliver(email)
Mix.shell().info("Digest email have been sent to #{nickname} (#{user.email})")
shell_info("Digest email have been sent to #{nickname} (#{user.email})")
else
_ ->
Mix.shell().info(
"Cound't find any mentions for #{nickname} since #{last_digest_emailed_at}"
)
shell_info("Cound't find any mentions for #{nickname} since #{last_digest_emailed_at}")
end
end
end

View file

@ -4,6 +4,7 @@
defmodule Pleroma.BBS.Authenticator do
use Sshd.PasswordAuthenticator
alias Pleroma.Plugs.AuthenticationPlug
alias Pleroma.User
def authenticate(username, password) do
@ -11,7 +12,7 @@ def authenticate(username, password) do
password = to_string(password)
with %User{} = user <- User.get_by_nickname(username) do
Pbkdf2.verify_pass(password, user.password_hash)
AuthenticationPlug.checkpw(password, user.password_hash)
else
_e -> false
end

View file

@ -278,6 +278,8 @@ defp do_convert({:proxy_url, {type, host, port}}) do
}
end
defp do_convert({:partial_chain, entity}), do: %{"tuple" => [":partial_chain", inspect(entity)]}
defp do_convert(entity) when is_tuple(entity) do
value =
entity
@ -321,6 +323,15 @@ defp do_transform(%{"tuple" => [":proxy_url", %{"tuple" => [type, host, port]}]}
{:proxy_url, {do_transform_string(type), parse_host(host), port}}
end
defp do_transform(%{"tuple" => [":partial_chain", entity]}) do
{partial_chain, []} =
entity
|> String.replace(~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "")
|> Code.eval_string()
{:partial_chain, partial_chain}
end
defp do_transform(%{"tuple" => entity}) do
Enum.reduce(entity, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end)
end

View file

@ -17,7 +17,8 @@ defmodule Pleroma.Constants do
"announcement_count",
"emoji",
"context_id",
"deleted_activity_id"
"deleted_activity_id",
"pleroma_internal"
]
)

View file

@ -18,7 +18,6 @@ def compile do
with config <- Pleroma.Config.Loader.read("config/description.exs") do
config[:pleroma][:config_description]
|> Pleroma.Docs.Generator.convert_to_strings()
|> Jason.encode!()
end
end
end

View file

@ -16,6 +16,11 @@ def checkpw(password, "$6" <> _ = password_hash) do
:crypt.crypt(password, password_hash) == password_hash
end
def checkpw(password, "$2" <> _ = password_hash) do
# Handle bcrypt passwords for Mastodon migration
Bcrypt.verify_pass(password, password_hash)
end
def checkpw(password, "$pbkdf2" <> _ = password_hash) do
Pbkdf2.verify_pass(password, password_hash)
end
@ -25,6 +30,25 @@ def checkpw(_password, _password_hash) do
false
end
def maybe_update_password(%User{password_hash: "$2" <> _} = user, password) do
do_update_password(user, password)
end
def maybe_update_password(%User{password_hash: "$6" <> _} = user, password) do
do_update_password(user, password)
end
def maybe_update_password(user, _), do: {:ok, user}
defp do_update_password(user, password) do
user
|> User.password_update_changeset(%{
"password" => password,
"password_confirmation" => password
})
|> Pleroma.Repo.update()
end
def call(%{assigns: %{user: %User{}}} = conn, _), do: conn
def call(
@ -36,7 +60,9 @@ def call(
} = conn,
_
) do
if Pbkdf2.verify_pass(password, password_hash) do
if checkpw(password, password_hash) do
{:ok, auth_user} = maybe_update_password(auth_user, password)
conn
|> assign(:user, auth_user)
|> OAuthScopesPlug.skip_plug()

View file

@ -134,7 +134,7 @@ defp prepare_upload(%Plug.Upload{} = file, opts) do
end
end
defp prepare_upload(%{"img" => "data:image/" <> image_data}, opts) do
defp prepare_upload(%{img: "data:image/" <> image_data}, opts) do
parsed = Regex.named_captures(~r/(?<filetype>jpeg|png|gif);base64,(?<data>.*)/, image_data)
data = Base.decode64!(parsed["data"], ignore: :whitespace)
hash = String.downcase(Base.encode16(:crypto.hash(:sha256, data)))

View file

@ -87,6 +87,22 @@ def dictionary(
source_to_target_rel_types \\ nil,
target_to_source_rel_types \\ nil
)
def dictionary(
_source_users,
_target_users,
[] = _source_to_target_rel_types,
[] = _target_to_source_rel_types
) do
[]
end
def dictionary(
source_users,
target_users,
source_to_target_rel_types,
target_to_source_rel_types
)
when is_list(source_users) and is_list(target_users) do
source_user_ids = User.binary_id(source_users)
target_user_ids = User.binary_id(target_users)
@ -138,11 +154,16 @@ def view_relationships_option(nil = _reading_user, _actors, _opts) do
def view_relationships_option(%User{} = reading_user, actors, opts) do
{source_to_target_rel_types, target_to_source_rel_types} =
if opts[:source_mutes_only] do
# This option is used for rendering statuses (FE needs `muted` flag for each one anyways)
{[:mute], []}
else
{[:block, :mute, :notification_mute, :reblog_mute], [:block, :inverse_subscription]}
case opts[:subset] do
:source_mutes ->
# Used for statuses rendering (FE needs `muted` flag for each status when statuses load)
{[:mute], []}
nil ->
{[:block, :mute, :notification_mute, :reblog_mute], [:block, :inverse_subscription]}
unknown ->
raise "Unsupported :subset option value: #{inspect(unknown)}"
end
user_relationships =
@ -153,7 +174,17 @@ def view_relationships_option(%User{} = reading_user, actors, opts) do
target_to_source_rel_types
)
following_relationships = FollowingRelationship.all_between_user_sets([reading_user], actors)
following_relationships =
case opts[:subset] do
:source_mutes ->
[]
nil ->
FollowingRelationship.all_between_user_sets([reading_user], actors)
unknown ->
raise "Unsupported :subset option value: #{inspect(unknown)}"
end
%{user_relationships: user_relationships, following_relationships: following_relationships}
end

View file

@ -22,6 +22,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.AdminAPI
alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.AdminAPI.ConfigView
alias Pleroma.Web.AdminAPI.ModerationLogView
@ -30,14 +31,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
alias Pleroma.Web.AdminAPI.Search
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Endpoint
alias Pleroma.Web.MastodonAPI
alias Pleroma.Web.MastodonAPI.AppView
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.Router
require Logger
@descriptions_json Pleroma.Docs.JSON.compile()
@descriptions Pleroma.Docs.JSON.compile()
@users_page_size 50
plug(
@ -280,8 +281,8 @@ def list_instance_statuses(conn, %{"instance" => instance} = params) do
})
conn
|> put_view(Pleroma.Web.AdminAPI.StatusView)
|> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
|> put_view(AdminAPI.StatusView)
|> render("index.json", %{activities: activities, as: :activity})
end
def list_user_statuses(conn, %{"nickname" => nickname} = params) do
@ -299,8 +300,8 @@ def list_user_statuses(conn, %{"nickname" => nickname} = params) do
})
conn
|> put_view(StatusView)
|> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
|> put_view(MastodonAPI.StatusView)
|> render("index.json", %{activities: activities, as: :activity})
else
_ -> {:error, :not_found}
end
@ -829,14 +830,14 @@ def list_statuses(%{assigns: %{user: _admin}} = conn, params) do
})
conn
|> put_view(Pleroma.Web.AdminAPI.StatusView)
|> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
|> put_view(AdminAPI.StatusView)
|> render("index.json", %{activities: activities, as: :activity})
end
def status_show(conn, %{"id" => id}) do
with %Activity{} = activity <- Activity.get_by_id(id) do
conn
|> put_view(StatusView)
|> put_view(MastodonAPI.StatusView)
|> render("show.json", %{activity: activity})
else
_ -> errors(conn, {:error, :not_found})
@ -861,7 +862,7 @@ def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do
})
conn
|> put_view(StatusView)
|> put_view(MastodonAPI.StatusView)
|> render("show.json", %{activity: activity})
end
end
@ -897,9 +898,9 @@ def list_log(conn, params) do
end
def config_descriptions(conn, _params) do
conn
|> Plug.Conn.put_resp_content_type("application/json")
|> Plug.Conn.send_resp(200, @descriptions_json)
descriptions = Enum.filter(@descriptions, &whitelisted_config?/1)
json(conn, descriptions)
end
def config_show(conn, %{"only_db" => true}) do
@ -954,7 +955,9 @@ def config_show(conn, _params) do
def config_update(conn, %{"configs" => configs}) do
with :ok <- configurable_from_database(conn) do
{_errors, results} =
Enum.map(configs, fn
configs
|> Enum.filter(&whitelisted_config?/1)
|> Enum.map(fn
%{"group" => group, "key" => key, "delete" => true} = params ->
ConfigDB.delete(%{group: group, key: key, subkeys: params["subkeys"]})
@ -1016,6 +1019,28 @@ defp configurable_from_database(conn) do
end
end
defp whitelisted_config?(group, key) do
if whitelisted_configs = Config.get(:database_config_whitelist) do
Enum.any?(whitelisted_configs, fn
{whitelisted_group} ->
group == inspect(whitelisted_group)
{whitelisted_group, whitelisted_key} ->
group == inspect(whitelisted_group) && key == inspect(whitelisted_key)
end)
else
true
end
end
defp whitelisted_config?(%{"group" => group, "key" => key}) do
whitelisted_config?(group, key)
end
defp whitelisted_config?(%{:group => group} = config) do
whitelisted_config?(group, config[:key])
end
def reload_emoji(conn, _params) do
Pleroma.Emoji.reload()

View file

@ -6,7 +6,9 @@ defmodule Pleroma.Web.AdminAPI.AccountView do
use Pleroma.Web, :view
alias Pleroma.User
alias Pleroma.Web.AdminAPI
alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.MastodonAPI
alias Pleroma.Web.MediaProxy
def render("index.json", %{users: users, count: count, page_size: page_size}) do
@ -119,6 +121,13 @@ def render("create-error.json", %{changeset: %Ecto.Changeset{changes: changes, e
}
end
def merge_account_views(%User{} = user) do
MastodonAPI.AccountView.render("show.json", %{user: user})
|> Map.merge(AdminAPI.AccountView.render("show.json", %{user: user}))
end
def merge_account_views(_), do: %{}
defp parse_error([]), do: ""
defp parse_error(errors) do

View file

@ -7,10 +7,13 @@ defmodule Pleroma.Web.AdminAPI.ReportView do
alias Pleroma.HTML
alias Pleroma.User
alias Pleroma.Web.AdminAPI
alias Pleroma.Web.AdminAPI.Report
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.StatusView
defdelegate merge_account_views(user), to: AdminAPI.AccountView
def render("index.json", %{reports: reports}) do
%{
reports:
@ -41,8 +44,7 @@ def render("show.json", %{report: report, user: user, account: account, statuses
statuses:
StatusView.render("index.json", %{
activities: statuses,
as: :activity,
skip_relationships: false
as: :activity
}),
state: report.data["state"],
notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes})
@ -70,11 +72,4 @@ def render("show_note.json", %{
created_at: Utils.to_masto_date(inserted_at)
}
end
defp merge_account_views(%User{} = user) do
Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user})
|> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user}))
end
defp merge_account_views(_), do: %{}
end

View file

@ -7,24 +7,19 @@ defmodule Pleroma.Web.AdminAPI.StatusView do
require Pleroma.Constants
alias Pleroma.User
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.AdminAPI
alias Pleroma.Web.MastodonAPI
defdelegate merge_account_views(user), to: AdminAPI.AccountView
def render("index.json", opts) do
safe_render_many(opts.activities, __MODULE__, "show.json", opts)
end
def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do
user = StatusView.get_user(activity.data["actor"])
user = MastodonAPI.StatusView.get_user(activity.data["actor"])
StatusView.render("show.json", opts)
MastodonAPI.StatusView.render("show.json", opts)
|> Map.merge(%{account: merge_account_views(user)})
end
defp merge_account_views(%User{} = user) do
Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user})
|> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user}))
end
defp merge_account_views(_), do: %{}
end

View file

@ -5,6 +5,7 @@
defmodule Pleroma.Web.ApiSpec.Helpers do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
def request_body(description, schema_ref, opts \\ []) do
media_types = ["application/json", "multipart/form-data", "application/x-www-form-urlencoded"]
@ -47,6 +48,15 @@ def pagination_params do
]
end
def with_relationships_param do
Operation.parameter(
:with_relationships,
:query,
BooleanLike,
"Embed relationships into accounts."
)
end
def empty_object_response do
Operation.response("Empty object", "application/json", %Schema{type: :object, example: %{}})
end
@ -54,4 +64,8 @@ def empty_object_response do
def empty_array_response do
Operation.response("Empty array", "application/json", %Schema{type: :array, example: []})
end
def no_content_response do
Operation.response("No Content", "application/json", %Schema{type: :string, example: ""})
end
end

View file

@ -155,8 +155,10 @@ def followers_operation do
security: [%{"oAuth" => ["read:accounts"]}],
description:
"Accounts which follow the given account, if network is not hidden by the account owner.",
parameters:
[%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}] ++ pagination_params(),
parameters: [
%Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
with_relationships_param() | pagination_params()
],
responses: %{
200 => Operation.response("Accounts", "application/json", array_of_accounts())
}
@ -171,8 +173,10 @@ def following_operation do
security: [%{"oAuth" => ["read:accounts"]}],
description:
"Accounts which the given account is following, if network is not hidden by the account owner.",
parameters:
[%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}] ++ pagination_params(),
parameters: [
%Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
with_relationships_param() | pagination_params()
],
responses: %{200 => Operation.response("Accounts", "application/json", array_of_accounts())}
}
end
@ -367,15 +371,18 @@ defp create_request do
title: "AccountCreateRequest",
description: "POST body for creating an account",
type: :object,
required: [:username, :password, :agreement],
properties: %{
reason: %Schema{
type: :string,
nullable: true,
description:
"Text that will be reviewed by moderators if registrations require manual approval"
},
username: %Schema{type: :string, description: "The desired username for the account"},
email: %Schema{
type: :string,
nullable: true,
description:
"The email address to be used for login. Required when `account_activation_required` is enabled.",
format: :email
@ -392,23 +399,33 @@ defp create_request do
},
locale: %Schema{
type: :string,
nullable: true,
description: "The language of the confirmation email that will be sent"
},
# Pleroma-specific properties:
fullname: %Schema{type: :string, description: "Full name"},
bio: %Schema{type: :string, description: "Bio", default: ""},
fullname: %Schema{type: :string, nullable: true, description: "Full name"},
bio: %Schema{type: :string, description: "Bio", nullable: true, default: ""},
captcha_solution: %Schema{
type: :string,
nullable: true,
description: "Provider-specific captcha solution"
},
captcha_token: %Schema{type: :string, description: "Provider-specific captcha token"},
captcha_answer_data: %Schema{type: :string, description: "Provider-specific captcha data"},
captcha_token: %Schema{
type: :string,
nullable: true,
description: "Provider-specific captcha token"
},
captcha_answer_data: %Schema{
type: :string,
nullable: true,
description: "Provider-specific captcha data"
},
token: %Schema{
type: :string,
nullable: true,
description: "Invite token required when the registrations aren't public"
}
},
required: [:username, :password, :agreement],
example: %{
"username" => "cofe",
"email" => "cofe@example.com",
@ -447,28 +464,34 @@ defp update_creadentials_request do
properties: %{
bot: %Schema{
type: :boolean,
nullable: true,
description: "Whether the account has a bot flag."
},
display_name: %Schema{
type: :string,
nullable: true,
description: "The display name to use for the profile."
},
note: %Schema{type: :string, description: "The account bio."},
avatar: %Schema{
type: :string,
nullable: true,
description: "Avatar image encoded using multipart/form-data",
format: :binary
},
header: %Schema{
type: :string,
nullable: true,
description: "Header image encoded using multipart/form-data",
format: :binary
},
locked: %Schema{
type: :boolean,
nullable: true,
description: "Whether manual approval of follow requests is required."
},
fields_attributes: %Schema{
nullable: true,
oneOf: [
%Schema{type: :array, items: attribute_field()},
%Schema{type: :object, additionalProperties: %Schema{type: attribute_field()}}
@ -488,47 +511,65 @@ defp update_creadentials_request do
# Pleroma-specific fields
no_rich_text: %Schema{
type: :boolean,
nullable: true,
description: "html tags are stripped from all statuses requested from the API"
},
hide_followers: %Schema{type: :boolean, description: "user's followers will be hidden"},
hide_follows: %Schema{type: :boolean, description: "user's follows will be hidden"},
hide_followers: %Schema{
type: :boolean,
nullable: true,
description: "user's followers will be hidden"
},
hide_follows: %Schema{
type: :boolean,
nullable: true,
description: "user's follows will be hidden"
},
hide_followers_count: %Schema{
type: :boolean,
nullable: true,
description: "user's follower count will be hidden"
},
hide_follows_count: %Schema{
type: :boolean,
nullable: true,
description: "user's follow count will be hidden"
},
hide_favorites: %Schema{
type: :boolean,
nullable: true,
description: "user's favorites timeline will be hidden"
},
show_role: %Schema{
type: :boolean,
nullable: true,
description: "user's role (e.g admin, moderator) will be exposed to anyone in the
API"
},
default_scope: VisibilityScope,
pleroma_settings_store: %Schema{
type: :object,
nullable: true,
description: "Opaque user settings to be saved on the backend."
},
skip_thread_containment: %Schema{
type: :boolean,
nullable: true,
description: "Skip filtering out broken threads"
},
allow_following_move: %Schema{
type: :boolean,
nullable: true,
description: "Allows automatically follow moved following accounts"
},
pleroma_background_image: %Schema{
type: :string,
nullable: true,
description: "Sets the background image of the user.",
format: :binary
},
discoverable: %Schema{
type: :boolean,
nullable: true,
description:
"Discovery of this account in search results and other services is allowed."
},
@ -624,7 +665,7 @@ defp follow_by_uri_request do
description: "POST body for muting an account",
type: :object,
properties: %{
uri: %Schema{type: :string, format: :uri}
uri: %Schema{type: :string, nullable: true, format: :uri}
},
required: [:uri]
}
@ -638,6 +679,7 @@ defp mute_request do
properties: %{
notifications: %Schema{
type: :boolean,
nullable: true,
description: "Mute notifications in addition to statuses? Defaults to true.",
default: true
}

View file

@ -105,7 +105,11 @@ defp create_request do
description: "Space separated list of scopes",
default: "read"
},
website: %Schema{type: :string, description: "A URL to the homepage of your app"}
website: %Schema{
type: :string,
nullable: true,
description: "A URL to the homepage of your app"
}
},
required: [:client_name, :redirect_uris],
example: %{

View file

@ -199,12 +199,14 @@ defp update_request do
"Array of enumerable strings `home`, `notifications`, `public`, `thread`. At least one context must be specified."
},
irreversible: %Schema{
type: :bolean,
type: :boolean,
nullable: true,
description:
"Should the server irreversibly drop matching entities from home and notifications?"
},
whole_word: %Schema{
type: :bolean,
type: :boolean,
nullable: true,
description: "Consider word boundaries?",
default: true
}

View file

@ -110,14 +110,16 @@ defp upsert_request do
properties: %{
notifications: %Schema{
type: :object,
nullable: true,
properties: %{
last_read_id: %Schema{type: :string}
last_read_id: %Schema{nullable: true, type: :string}
}
},
home: %Schema{
type: :object,
nullable: true,
properties: %{
last_read_id: %Schema{type: :string}
last_read_id: %Schema{nullable: true, type: :string}
}
}
},

View file

@ -0,0 +1,132 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.MediaOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Helpers
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.Attachment
def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, [])
end
def create_operation do
%Operation{
tags: ["media"],
summary: "Upload media as attachment",
description: "Creates an attachment to be used with a new status.",
operationId: "MediaController.create",
security: [%{"oAuth" => ["write:media"]}],
requestBody: Helpers.request_body("Parameters", create_request()),
responses: %{
200 => Operation.response("Media", "application/json", Attachment),
401 => Operation.response("Media", "application/json", ApiError),
422 => Operation.response("Media", "application/json", ApiError)
}
}
end
defp create_request do
%Schema{
title: "MediaCreateRequest",
description: "POST body for creating an attachment",
type: :object,
required: [:file],
properties: %{
file: %Schema{
type: :string,
format: :binary,
description: "The file to be attached, using multipart form data."
},
description: %Schema{
type: :string,
description: "A plain-text description of the media, for accessibility purposes."
},
focus: %Schema{
type: :string,
description: "Two floating points (x,y), comma-delimited, ranging from -1.0 to 1.0."
}
}
}
end
def update_operation do
%Operation{
tags: ["media"],
summary: "Upload media as attachment",
description: "Creates an attachment to be used with a new status.",
operationId: "MediaController.update",
security: [%{"oAuth" => ["write:media"]}],
parameters: [id_param()],
requestBody: Helpers.request_body("Parameters", update_request()),
responses: %{
200 => Operation.response("Media", "application/json", Attachment),
400 => Operation.response("Media", "application/json", ApiError),
401 => Operation.response("Media", "application/json", ApiError),
422 => Operation.response("Media", "application/json", ApiError)
}
}
end
defp update_request do
%Schema{
title: "MediaUpdateRequest",
description: "POST body for updating an attachment",
type: :object,
properties: %{
file: %Schema{
type: :string,
format: :binary,
description: "The file to be attached, using multipart form data."
},
description: %Schema{
type: :string,
description: "A plain-text description of the media, for accessibility purposes."
},
focus: %Schema{
type: :string,
description: "Two floating points (x,y), comma-delimited, ranging from -1.0 to 1.0."
}
}
}
end
def show_operation do
%Operation{
tags: ["media"],
summary: "Show Uploaded media attachment",
operationId: "MediaController.show",
parameters: [id_param()],
security: [%{"oAuth" => ["read:media"]}],
responses: %{
200 => Operation.response("Media", "application/json", Attachment),
401 => Operation.response("Media", "application/json", ApiError),
422 => Operation.response("Media", "application/json", ApiError)
}
}
end
def create2_operation do
%Operation{
tags: ["media"],
summary: "Upload media as attachment",
description: "Creates an attachment to be used with a new status.",
operationId: "MediaController.create2",
security: [%{"oAuth" => ["write:media"]}],
requestBody: Helpers.request_body("Parameters", create_request()),
responses: %{
202 => Operation.response("Media", "application/json", Attachment),
422 => Operation.response("Media", "application/json", ApiError),
500 => Operation.response("Media", "application/json", ApiError)
}
}
end
defp id_param do
Operation.parameter(:id, :path, :string, "The ID of the Attachment entity")
end
end

View file

@ -0,0 +1,187 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do
alias OpenApiSpex.Operation
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.Schemas.AccountRelationship
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
alias Pleroma.Web.ApiSpec.StatusOperation
import Pleroma.Web.ApiSpec.Helpers
def open_api_operation(action) do
operation = String.to_existing_atom("#{action}_operation")
apply(__MODULE__, operation, [])
end
def confirmation_resend_operation do
%Operation{
tags: ["Accounts"],
summary: "Resend confirmation email. Expects `email` or `nickname`",
operationId: "PleromaAPI.AccountController.confirmation_resend",
parameters: [
Operation.parameter(:email, :query, :string, "Email of that needs to be verified",
example: "cofe@cofe.io"
),
Operation.parameter(
:nickname,
:query,
:string,
"Nickname of user that needs to be verified",
example: "cofefe"
)
],
responses: %{
204 => no_content_response()
}
}
end
def update_avatar_operation do
%Operation{
tags: ["Accounts"],
summary: "Set/clear user avatar image",
operationId: "PleromaAPI.AccountController.update_avatar",
requestBody:
request_body("Parameters", update_avatar_or_background_request(), required: true),
security: [%{"oAuth" => ["write:accounts"]}],
responses: %{
200 => update_response(),
403 => Operation.response("Forbidden", "application/json", ApiError)
}
}
end
def update_banner_operation do
%Operation{
tags: ["Accounts"],
summary: "Set/clear user banner image",
operationId: "PleromaAPI.AccountController.update_banner",
requestBody: request_body("Parameters", update_banner_request(), required: true),
security: [%{"oAuth" => ["write:accounts"]}],
responses: %{
200 => update_response()
}
}
end
def update_background_operation do
%Operation{
tags: ["Accounts"],
summary: "Set/clear user background image",
operationId: "PleromaAPI.AccountController.update_background",
security: [%{"oAuth" => ["write:accounts"]}],
requestBody:
request_body("Parameters", update_avatar_or_background_request(), required: true),
responses: %{
200 => update_response()
}
}
end
def favourites_operation do
%Operation{
tags: ["Accounts"],
summary: "Returns favorites timeline of any user",
operationId: "PleromaAPI.AccountController.favourites",
parameters: [id_param() | pagination_params()],
security: [%{"oAuth" => ["read:favourites"]}],
responses: %{
200 =>
Operation.response(
"Array of Statuses",
"application/json",
StatusOperation.array_of_statuses()
),
403 => Operation.response("Forbidden", "application/json", ApiError),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
def subscribe_operation do
%Operation{
tags: ["Accounts"],
summary: "Subscribe to receive notifications for all statuses posted by a user",
operationId: "PleromaAPI.AccountController.subscribe",
parameters: [id_param()],
security: [%{"oAuth" => ["follow", "write:follows"]}],
responses: %{
200 => Operation.response("Relationship", "application/json", AccountRelationship),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
def unsubscribe_operation do
%Operation{
tags: ["Accounts"],
summary: "Unsubscribe to stop receiving notifications from user statuses",
operationId: "PleromaAPI.AccountController.unsubscribe",
parameters: [id_param()],
security: [%{"oAuth" => ["follow", "write:follows"]}],
responses: %{
200 => Operation.response("Relationship", "application/json", AccountRelationship),
404 => Operation.response("Not Found", "application/json", ApiError)
}
}
end
defp id_param do
Operation.parameter(:id, :path, FlakeID, "Account ID",
example: "9umDrYheeY451cQnEe",
required: true
)
end
defp update_avatar_or_background_request do
%Schema{
title: "PleromaAccountUpdateAvatarOrBackgroundRequest",
type: :object,
properties: %{
img: %Schema{
nullable: true,
type: :string,
format: :binary,
description: "Image encoded using `multipart/form-data` or an empty string to clear"
}
}
}
end
defp update_banner_request do
%Schema{
title: "PleromaAccountUpdateBannerRequest",
type: :object,
properties: %{
banner: %Schema{
type: :string,
nullable: true,
format: :binary,
description: "Image encoded using `multipart/form-data` or an empty string to clear"
}
}
}
end
defp update_response do
Operation.response("PleromaAccountUpdateResponse", "application/json", %Schema{
type: :object,
properties: %{
url: %Schema{
type: :string,
format: :uri,
nullable: true,
description: "Image URL"
}
},
example: %{
"url" =>
"https://cofe.party/media/9d0add56-bcb6-4c0f-8225-cbbd0b6dd773/13eadb6972c9ccd3f4ffa3b8196f0e0d38b4d2f27594457c52e52946c054cd9a.gif"
}
})
end
end

View file

@ -37,15 +37,18 @@ defp create_request do
account_id: %Schema{type: :string, description: "ID of the account to report"},
status_ids: %Schema{
type: :array,
nullable: true,
items: %Schema{type: :string},
description: "Array of Statuses to attach to the report, for context"
},
comment: %Schema{
type: :string,
nullable: true,
description: "Reason for the report"
},
forward: %Schema{
type: :boolean,
nullable: true,
default: false,
description:
"If the account is remote, should the report be forwarded to the remote admin?"

View file

@ -19,6 +19,7 @@ def open_api_operation(action) do
apply(__MODULE__, operation, [])
end
# Note: `with_relationships` param is not supported (PleromaFE uses this op for autocomplete)
def account_search_operation do
%Operation{
tags: ["Search"],
@ -96,8 +97,8 @@ def search_operation do
:query,
%Schema{type: :integer},
"Offset"
)
| pagination_params()
),
with_relationships_param() | pagination_params()
],
responses: %{
200 => Operation.response("Results", "application/json", results())
@ -138,8 +139,8 @@ def search2_operation do
:query,
%Schema{allOf: [BooleanLike], default: false},
"Only include accounts that the user is following"
)
| pagination_params()
),
with_relationships_param() | pagination_params()
],
responses: %{
200 => Operation.response("Results", "application/json", results2())

View file

@ -7,7 +7,6 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.AccountOperation
alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
alias Pleroma.Web.ApiSpec.Schemas.ScheduledStatus
alias Pleroma.Web.ApiSpec.Schemas.Status
@ -349,10 +348,7 @@ def bookmarks_operation do
summary: "Bookmarked statuses",
description: "Statuses the user has bookmarked",
operationId: "StatusController.bookmarks",
parameters: [
Operation.parameter(:with_relationships, :query, BooleanLike, "Include relationships")
| pagination_params()
],
parameters: pagination_params(),
security: [%{"oAuth" => ["read:bookmarks"]}],
responses: %{
200 => Operation.response("Array of Statuses", "application/json", array_of_statuses())
@ -360,7 +356,7 @@ def bookmarks_operation do
}
end
defp array_of_statuses do
def array_of_statuses do
%Schema{type: :array, items: Status, example: [Status.schema().example]}
end
@ -371,15 +367,18 @@ defp create_request do
properties: %{
status: %Schema{
type: :string,
nullable: true,
description:
"Text content of the status. If `media_ids` is provided, this becomes optional. Attaching a `poll` is optional while `status` is provided."
},
media_ids: %Schema{
nullable: true,
type: :array,
items: %Schema{type: :string},
description: "Array of Attachment ids to be attached as media."
},
poll: %Schema{
nullable: true,
type: :object,
required: [:options],
properties: %{
@ -390,26 +389,35 @@ defp create_request do
},
expires_in: %Schema{
type: :integer,
nullable: true,
description:
"Duration the poll should be open, in seconds. Must be provided with `poll[options]`"
},
multiple: %Schema{type: :boolean, description: "Allow multiple choices?"},
multiple: %Schema{
type: :boolean,
nullable: true,
description: "Allow multiple choices?"
},
hide_totals: %Schema{
type: :boolean,
nullable: true,
description: "Hide vote counts until the poll ends?"
}
}
},
in_reply_to_id: %Schema{
nullable: true,
allOf: [FlakeID],
description: "ID of the status being replied to, if status is a reply"
},
sensitive: %Schema{
type: :boolean,
nullable: true,
description: "Mark status and attached media as sensitive?"
},
spoiler_text: %Schema{
type: :string,
nullable: true,
description:
"Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field."
},
@ -420,25 +428,33 @@ defp create_request do
description:
"ISO 8601 Datetime at which to schedule a status. Providing this paramter will cause ScheduledStatus to be returned instead of Status. Must be at least 5 minutes in the future."
},
language: %Schema{type: :string, description: "ISO 639 language code for this status."},
language: %Schema{
type: :string,
nullable: true,
description: "ISO 639 language code for this status."
},
# Pleroma-specific properties:
preview: %Schema{
type: :boolean,
nullable: true,
description:
"If set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example"
},
content_type: %Schema{
type: :string,
nullable: true,
description:
"The MIME type of the status, it is transformed into HTML by the backend. You can get the list of the supported MIME types with the nodeinfo endpoint."
},
to: %Schema{
type: :array,
nullable: true,
items: %Schema{type: :string},
description:
"A list of nicknames (like `lain@soykaf.club` or `lain` on the local server) that will be used to determine who is going to be addressed by this post. Using this will disable the implicit addressing by mentioned names in the `status` body, only the people in the `to` list will be addressed. The normal rules for for post visibility are not affected by this and will still apply"
},
visibility: %Schema{
nullable: true,
anyOf: [
VisibilityScope,
%Schema{type: :string, description: "`list:LIST_ID`", example: "LIST:123"}
@ -447,11 +463,13 @@ defp create_request do
"Visibility of the posted status. Besides standard MastoAPI values (`direct`, `private`, `unlisted` or `public`) it can be used to address a List by setting it to `list:LIST_ID`"
},
expires_in: %Schema{
nullable: true,
type: :integer,
description:
"The number of seconds the posted activity should expire in. When a posted activity expires it will be deleted from the server, and a delete request for it will be federated. This needs to be longer than an hour."
},
in_reply_to_conversation_id: %Schema{
nullable: true,
type: :string,
description:
"Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`."

View file

@ -109,19 +109,38 @@ defp create_request do
required: [:endpoint, :keys]
},
data: %Schema{
nullable: true,
type: :object,
properties: %{
alerts: %Schema{
nullable: true,
type: :object,
properties: %{
follow: %Schema{type: :boolean, description: "Receive follow notifications?"},
follow: %Schema{
type: :boolean,
nullable: true,
description: "Receive follow notifications?"
},
favourite: %Schema{
type: :boolean,
nullable: true,
description: "Receive favourite notifications?"
},
reblog: %Schema{type: :boolean, description: "Receive reblog notifications?"},
mention: %Schema{type: :boolean, description: "Receive mention notifications?"},
poll: %Schema{type: :boolean, description: "Receive poll notifications?"}
reblog: %Schema{
type: :boolean,
nullable: true,
description: "Receive reblog notifications?"
},
mention: %Schema{
type: :boolean,
nullable: true,
description: "Receive mention notifications?"
},
poll: %Schema{
type: :boolean,
nullable: true,
description: "Receive poll notifications?"
}
}
}
}
@ -154,19 +173,38 @@ defp update_request do
type: :object,
properties: %{
data: %Schema{
nullable: true,
type: :object,
properties: %{
alerts: %Schema{
nullable: true,
type: :object,
properties: %{
follow: %Schema{type: :boolean, description: "Receive follow notifications?"},
follow: %Schema{
type: :boolean,
nullable: true,
description: "Receive follow notifications?"
},
favourite: %Schema{
type: :boolean,
nullable: true,
description: "Receive favourite notifications?"
},
reblog: %Schema{type: :boolean, description: "Receive reblog notifications?"},
mention: %Schema{type: :boolean, description: "Receive mention notifications?"},
poll: %Schema{type: :boolean, description: "Receive poll notifications?"}
reblog: %Schema{
type: :boolean,
nullable: true,
description: "Receive reblog notifications?"
},
mention: %Schema{
type: :boolean,
nullable: true,
description: "Receive mention notifications?"
},
poll: %Schema{
type: :boolean,
nullable: true,
description: "Receive poll notifications?"
}
}
}
}

View file

@ -27,8 +27,7 @@ def home_operation do
local_param(),
with_muted_param(),
exclude_visibilities_param(),
reply_visibility_param(),
with_relationships_param() | pagination_params()
reply_visibility_param() | pagination_params()
],
operationId: "TimelineController.home",
responses: %{
@ -63,8 +62,7 @@ def public_operation do
only_media_param(),
with_muted_param(),
exclude_visibilities_param(),
reply_visibility_param(),
with_relationships_param() | pagination_params()
reply_visibility_param() | pagination_params()
],
operationId: "TimelineController.public",
responses: %{
@ -109,8 +107,7 @@ def hashtag_operation do
local_param(),
only_media_param(),
with_muted_param(),
exclude_visibilities_param(),
with_relationships_param() | pagination_params()
exclude_visibilities_param() | pagination_params()
],
operationId: "TimelineController.hashtag",
responses: %{
@ -134,8 +131,7 @@ def list_operation do
required: true
),
with_muted_param(),
exclude_visibilities_param(),
with_relationships_param() | pagination_params()
exclude_visibilities_param() | pagination_params()
],
operationId: "TimelineController.list",
responses: %{
@ -153,10 +149,6 @@ defp array_of_statuses do
}
end
defp with_relationships_param do
Operation.parameter(:with_relationships, :query, BooleanLike, "Include relationships")
end
defp local_param do
Operation.parameter(
:local,

View file

@ -13,7 +13,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Attachment do
type: :object,
requried: [:id, :url, :preview_url],
properties: %{
id: %Schema{type: :string},
id: %Schema{type: :string, description: "The ID of the attachment in the database."},
url: %Schema{
type: :string,
format: :uri,

View file

@ -16,7 +16,8 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
def get_user(%Plug.Conn{} = conn) do
with {:ok, {name, password}} <- fetch_credentials(conn),
{_, %User{} = user} <- {:user, fetch_user(name)},
{_, true} <- {:checkpw, AuthenticationPlug.checkpw(password, user.password_hash)} do
{_, true} <- {:checkpw, AuthenticationPlug.checkpw(password, user.password_hash)},
{:ok, user} <- AuthenticationPlug.maybe_update_password(user, password) do
{:ok, user}
else
{:error, _reason} = error -> error

View file

@ -5,6 +5,7 @@
defmodule Pleroma.Web.Auth.TOTPAuthenticator do
alias Pleroma.MFA
alias Pleroma.MFA.TOTP
alias Pleroma.Plugs.AuthenticationPlug
alias Pleroma.User
@doc "Verify code or check backup code."
@ -30,7 +31,7 @@ def verify_recovery_code(
code
)
when is_list(codes) and is_binary(code) do
hash_code = Enum.find(codes, fn hash -> Pbkdf2.verify_pass(code, hash) end)
hash_code = Enum.find(codes, fn hash -> AuthenticationPlug.checkpw(code, hash) end)
if hash_code do
MFA.invalidate_backup_code(user, hash_code)

View file

@ -23,6 +23,7 @@ def handle_in("new_msg", %{"text" => text}, %{assigns: %{user_name: user_name}}
if String.length(text) in 1..Pleroma.Config.get([:instance, :chat_limit]) do
author = User.get_cached_by_nickname(user_name)
author = Pleroma.Web.MastodonAPI.AccountView.render("show.json", user: author)
message = ChatChannelState.add_message(%{text: text, author: author})
broadcast!(socket, "new_msg", message)

View file

@ -25,10 +25,21 @@ defmodule Pleroma.Web.CommonAPI do
require Logger
def unblock(blocker, blocked) do
with %Activity{} = block <- Utils.fetch_latest_block(blocker, blocked),
with {_, %Activity{} = block} <- {:fetch_block, Utils.fetch_latest_block(blocker, blocked)},
{:ok, unblock_data, _} <- Builder.undo(blocker, block),
{:ok, unblock, _} <- Pipeline.common_pipeline(unblock_data, local: true) do
{:ok, unblock}
else
{:fetch_block, nil} ->
if User.blocks?(blocker, blocked) do
User.unblock(blocker, blocked)
{:ok, :no_activity}
else
{:error, :not_blocking}
end
e ->
e
end
end

View file

@ -5,8 +5,6 @@
defmodule Pleroma.Web.ControllerHelper do
use Pleroma.Web, :controller
alias Pleroma.Config
# As in Mastodon API, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
@falsy_param_values [false, 0, "0", "f", "F", "false", "False", "FALSE", "off", "OFF"]
@ -106,13 +104,16 @@ def put_if_exist(map, _key, nil), do: map
def put_if_exist(map, key, value), do: Map.put(map, key, value)
@doc "Whether to skip rendering `[:account][:pleroma][:relationship]`for statuses/notifications"
def skip_relationships?(params) do
if Config.get([:extensions, :output_relationships_in_statuses_by_default]) do
false
else
# BREAKING: older PleromaFE versions do not send this param but _do_ expect relationships.
not truthy_param?(params["with_relationships"])
end
@doc """
Returns true if request specifies to include embedded relationships in account objects.
May only be used in selected account-related endpoints; has no effect for status- or
notification-related endpoints.
"""
# Intended for PleromaFE: https://git.pleroma.social/pleroma/pleroma-fe/-/issues/838
def embed_relationships?(params) do
# To do once OpenAPI transition mess is over: just `truthy_param?(params[:with_relationships])`
params
|> Map.get(:with_relationships, params["with_relationships"])
|> truthy_param?()
end
end

View file

@ -10,8 +10,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
add_link_headers: 2,
truthy_param?: 1,
assign_account_by_id: 2,
json_response: 3,
skip_relationships?: 1
embed_relationships?: 1,
json_response: 3
]
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
@ -247,8 +247,7 @@ def statuses(%{assigns: %{user: reading_user}} = conn, params) do
|> render("index.json",
activities: activities,
for: reading_user,
as: :activity,
skip_relationships: skip_relationships?(params)
as: :activity
)
else
_e -> render_error(conn, :not_found, "Can't find user")
@ -271,7 +270,13 @@ def followers(%{assigns: %{user: for_user, account: user}} = conn, params) do
conn
|> add_link_headers(followers)
|> render("index.json", for: for_user, users: followers, as: :user)
# https://git.pleroma.social/pleroma/pleroma-fe/-/issues/838#note_59223
|> render("index.json",
for: for_user,
users: followers,
as: :user,
embed_relationships: embed_relationships?(params)
)
end
@doc "GET /api/v1/accounts/:id/following"
@ -290,7 +295,13 @@ def following(%{assigns: %{user: for_user, account: user}} = conn, params) do
conn
|> add_link_headers(followers)
|> render("index.json", for: for_user, users: followers, as: :user)
# https://git.pleroma.social/pleroma/pleroma-fe/-/issues/838#note_59223
|> render("index.json",
for: for_user,
users: followers,
as: :user,
embed_relationships: embed_relationships?(params)
)
end
@doc "GET /api/v1/accounts/:id/lists"

View file

@ -11,17 +11,20 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
alias Pleroma.Web.ActivityPub.ActivityPub
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(:put_view, Pleroma.Web.MastodonAPI.StatusView)
plug(OAuthScopesPlug, %{scopes: ["write:media"]})
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.MediaOperation
@doc "POST /api/v1/media"
def create(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do
def create(%{assigns: %{user: user}, body_params: %{file: file} = data} = conn, _) do
with {:ok, object} <-
ActivityPub.upload(
file,
actor: User.ap_id(user),
description: Map.get(data, "description")
description: Map.get(data, :description)
) do
attachment_data = Map.put(object.data, "id", object.id)
@ -29,9 +32,28 @@ def create(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do
end
end
def create(_conn, _data), do: {:error, :bad_request}
@doc "POST /api/v2/media"
def create2(%{assigns: %{user: user}, body_params: %{file: file} = data} = conn, _) do
with {:ok, object} <-
ActivityPub.upload(
file,
actor: User.ap_id(user),
description: Map.get(data, :description)
) do
attachment_data = Map.put(object.data, "id", object.id)
conn
|> put_status(202)
|> render("attachment.json", %{attachment: attachment_data})
end
end
def create2(_conn, _data), do: {:error, :bad_request}
@doc "PUT /api/v1/media/:id"
def update(%{assigns: %{user: user}} = conn, %{"id" => id, "description" => description})
when is_binary(description) do
def update(%{assigns: %{user: user}, body_params: %{description: description}} = conn, %{id: id}) do
with %Object{} = object <- Object.get_by_id(id),
true <- Object.authorize_mutation(object, user),
{:ok, %Object{data: data}} <- Object.update_data(object, %{"name" => description}) do
@ -41,5 +63,16 @@ def update(%{assigns: %{user: user}} = conn, %{"id" => id, "description" => desc
end
end
def update(_conn, _data), do: {:error, :bad_request}
def update(conn, data), do: show(conn, data)
@doc "GET /api/v1/media/:id"
def show(conn, %{id: id}) do
with %Object{data: data, id: object_id} <- Object.get_by_id(id) do
attachment_data = Map.put(data, "id", object_id)
render(conn, "attachment.json", %{attachment: attachment_data})
end
end
def get_media(_conn, _data), do: {:error, :bad_request}
end

View file

@ -5,7 +5,7 @@
defmodule Pleroma.Web.MastodonAPI.NotificationController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, skip_relationships?: 1]
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
alias Pleroma.Notification
alias Pleroma.Plugs.OAuthScopesPlug
@ -50,8 +50,7 @@ def index(%{assigns: %{user: user}} = conn, params) do
|> add_link_headers(notifications)
|> render("index.json",
notifications: notifications,
for: user,
skip_relationships: skip_relationships?(params)
for: user
)
end

View file

@ -5,14 +5,13 @@
defmodule Pleroma.Web.MastodonAPI.SearchController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper, only: [skip_relationships?: 1]
alias Pleroma.Activity
alias Pleroma.Plugs.OAuthScopesPlug
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
@ -34,7 +33,11 @@ def account_search(%{assigns: %{user: user}} = conn, %{q: query} = params) do
conn
|> put_view(AccountView)
|> render("index.json", users: accounts, for: user, as: :user)
|> render("index.json",
users: accounts,
for: user,
as: :user
)
end
def search2(conn, params), do: do_search(:v2, conn, params)
@ -71,13 +74,13 @@ defp do_search(version, %{assigns: %{user: user}} = conn, %{q: query} = params)
defp search_options(params, user) do
[
skip_relationships: skip_relationships?(params),
resolve: params[:resolve],
following: params[:following],
limit: params[:limit],
offset: params[:offset],
type: params[:type],
author: get_author(params),
embed_relationships: ControllerHelper.embed_relationships?(params),
for_user: user
]
|> Enum.filter(&elem(&1, 1))
@ -90,7 +93,7 @@ defp resource_search(_, "accounts", query, options) do
users: accounts,
for: options[:for_user],
as: :user,
skip_relationships: false
embed_relationships: options[:embed_relationships]
)
end
@ -100,8 +103,7 @@ defp resource_search(_, "statuses", query, options) do
StatusView.render("index.json",
activities: statuses,
for: options[:for_user],
as: :activity,
skip_relationships: options[:skip_relationships]
as: :activity
)
end

View file

@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper,
only: [try_render: 3, add_link_headers: 2, skip_relationships?: 1]
only: [try_render: 3, add_link_headers: 2]
require Ecto.Query
@ -105,7 +105,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
`ids` query param is required
"""
def index(%{assigns: %{user: user}} = conn, %{ids: ids} = params) do
def index(%{assigns: %{user: user}} = conn, %{ids: ids} = _params) do
limit = 100
activities =
@ -117,8 +117,7 @@ def index(%{assigns: %{user: user}} = conn, %{ids: ids} = params) do
render(conn, "index.json",
activities: activities,
for: user,
as: :activity,
skip_relationships: skip_relationships?(params)
as: :activity
)
end
@ -383,8 +382,7 @@ def favourites(%{assigns: %{user: %User{} = user}} = conn, params) do
|> render("index.json",
activities: activities,
for: user,
as: :activity,
skip_relationships: skip_relationships?(params)
as: :activity
)
end
@ -406,8 +404,7 @@ def bookmarks(%{assigns: %{user: user}} = conn, params) do
|> render("index.json",
activities: activities,
for: user,
as: :activity,
skip_relationships: skip_relationships?(params)
as: :activity
)
end
end

View file

@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper,
only: [add_link_headers: 2, add_link_headers: 3, skip_relationships?: 1]
only: [add_link_headers: 2, add_link_headers: 3]
alias Pleroma.Pagination
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
@ -63,8 +63,7 @@ def home(%{assigns: %{user: user}} = conn, params) do
|> render("index.json",
activities: activities,
for: user,
as: :activity,
skip_relationships: skip_relationships?(params)
as: :activity
)
end
@ -88,8 +87,7 @@ def direct(%{assigns: %{user: user}} = conn, params) do
|> render("index.json",
activities: activities,
for: user,
as: :activity,
skip_relationships: skip_relationships?(params)
as: :activity
)
end
@ -125,8 +123,7 @@ def public(%{assigns: %{user: user}} = conn, params) do
|> render("index.json",
activities: activities,
for: user,
as: :activity,
skip_relationships: skip_relationships?(params)
as: :activity
)
end
end
@ -173,8 +170,7 @@ def hashtag(%{assigns: %{user: user}} = conn, params) do
|> render("index.json",
activities: activities,
for: user,
as: :activity,
skip_relationships: skip_relationships?(params)
as: :activity
)
end
@ -203,8 +199,7 @@ def list(%{assigns: %{user: user}} = conn, %{list_id: id} = params) do
render(conn, "index.json",
activities: activities,
for: user,
as: :activity,
skip_relationships: skip_relationships?(params)
as: :activity
)
else
_e -> render_error(conn, :forbidden, "Error.")

View file

@ -15,13 +15,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
def render("index.json", %{users: users} = opts) do
reading_user = opts[:for]
# Note: :skip_relationships option is currently intentionally not supported for accounts
relationships_opt =
cond do
Map.has_key?(opts, :relationships) ->
opts[:relationships]
is_nil(reading_user) ->
is_nil(reading_user) || !opts[:embed_relationships] ->
UserRelationship.view_relationships_option(nil, [])
true ->
@ -193,14 +192,14 @@ defp do_render("show.json", %{user: user} = opts) do
end)
relationship =
if opts[:skip_relationships] do
%{}
else
if opts[:embed_relationships] do
render("relationship.json", %{
user: opts[:for],
target: user,
relationships: opts[:relationships]
})
else
%{}
end
%{

View file

@ -51,9 +51,7 @@ def render("index.json", %{notifications: notifications, for: reading_user} = op
|> Enum.filter(& &1)
|> Kernel.++(move_activities_targets)
UserRelationship.view_relationships_option(reading_user, actors,
source_mutes_only: opts[:skip_relationships]
)
UserRelationship.view_relationships_option(reading_user, actors, subset: :source_mutes)
end
opts =
@ -83,15 +81,13 @@ def render(
mastodon_type = Activity.mastodon_notification_type(activity)
render_opts = %{
relationships: opts[:relationships],
skip_relationships: opts[:skip_relationships]
}
# Note: :relationships contain user mutes (needed for :muted flag in :status)
status_render_opts = %{relationships: opts[:relationships]}
with %{id: _} = account <-
AccountView.render(
"show.json",
Map.merge(render_opts, %{user: actor, for: reading_user})
%{user: actor, for: reading_user}
) do
response = %{
id: to_string(notification.id),
@ -105,21 +101,20 @@ def render(
case mastodon_type do
"mention" ->
put_status(response, activity, reading_user, render_opts)
put_status(response, activity, reading_user, status_render_opts)
"favourite" ->
put_status(response, parent_activity_fn.(), reading_user, render_opts)
put_status(response, parent_activity_fn.(), reading_user, status_render_opts)
"reblog" ->
put_status(response, parent_activity_fn.(), reading_user, render_opts)
put_status(response, parent_activity_fn.(), reading_user, status_render_opts)
"move" ->
# Note: :skip_relationships option being applied to _account_ rendering (here)
put_target(response, activity, reading_user, render_opts)
put_target(response, activity, reading_user, %{})
"pleroma:emoji_reaction" ->
response
|> put_status(parent_activity_fn.(), reading_user, render_opts)
|> put_status(parent_activity_fn.(), reading_user, status_render_opts)
|> put_emoji(activity)
type when type in ["follow", "follow_request"] ->

View file

@ -107,9 +107,7 @@ def render("index.json", opts) do
|> Enum.map(&get_user(&1.data["actor"], false))
|> Enum.filter(& &1)
UserRelationship.view_relationships_option(reading_user, actors,
source_mutes_only: opts[:skip_relationships]
)
UserRelationship.view_relationships_option(reading_user, actors, subset: :source_mutes)
end
opts =
@ -162,9 +160,7 @@ def render(
account:
AccountView.render("show.json", %{
user: user,
for: opts[:for],
relationships: opts[:relationships],
skip_relationships: opts[:skip_relationships]
for: opts[:for]
}),
in_reply_to_id: nil,
in_reply_to_account_id: nil,
@ -330,9 +326,7 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
account:
AccountView.render("show.json", %{
user: user,
for: opts[:for],
relationships: opts[:relationships],
skip_relationships: opts[:skip_relationships]
for: opts[:for]
}),
in_reply_to_id: reply_to && to_string(reply_to.id),
in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id),

View file

@ -5,6 +5,7 @@
defmodule Pleroma.Web.MongooseIM.MongooseIMController do
use Pleroma.Web, :controller
alias Pleroma.Plugs.AuthenticationPlug
alias Pleroma.Plugs.RateLimiter
alias Pleroma.Repo
alias Pleroma.User
@ -27,7 +28,7 @@ def user_exists(conn, %{"user" => username}) do
def check_password(conn, %{"user" => username, "pass" => password}) do
with %User{password_hash: password_hash, deactivated: false} <-
Repo.get_by(User, nickname: username, local: true),
true <- Pbkdf2.verify_pass(password, password_hash) do
true <- AuthenticationPlug.checkpw(password, password_hash) do
conn
|> json(true)
else

View file

@ -6,7 +6,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper,
only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2, skip_relationships?: 1]
only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2]
alias Ecto.Changeset
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
@ -18,6 +18,13 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
require Pleroma.Constants
plug(
OpenApiSpex.Plug.PutApiSpec,
[module: Pleroma.Web.ApiSpec] when action == :confirmation_resend
)
plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(
:skip_plug,
[OAuthScopesPlug, EnsurePublicOrAuthenticatedPlug] when action == :confirmation_resend
@ -49,9 +56,11 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
plug(:assign_account_by_id when action in [:favourites, :subscribe, :unsubscribe])
plug(:put_view, Pleroma.Web.MastodonAPI.AccountView)
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaAccountOperation
@doc "POST /api/v1/pleroma/accounts/confirmation_resend"
def confirmation_resend(conn, params) do
nickname_or_email = params["email"] || params["nickname"]
nickname_or_email = params[:email] || params[:nickname]
with %User{} = user <- User.get_by_nickname_or_email(nickname_or_email),
{:ok, _} <- User.try_send_confirmation_email(user) do
@ -60,7 +69,7 @@ def confirmation_resend(conn, params) do
end
@doc "PATCH /api/v1/pleroma/accounts/update_avatar"
def update_avatar(%{assigns: %{user: user}} = conn, %{"img" => ""}) do
def update_avatar(%{assigns: %{user: user}, body_params: %{img: ""}} = conn, _) do
{:ok, _user} =
user
|> Changeset.change(%{avatar: nil})
@ -69,7 +78,7 @@ def update_avatar(%{assigns: %{user: user}} = conn, %{"img" => ""}) do
json(conn, %{url: nil})
end
def update_avatar(%{assigns: %{user: user}} = conn, params) do
def update_avatar(%{assigns: %{user: user}, body_params: params} = conn, _params) do
{:ok, %{data: data}} = ActivityPub.upload(params, type: :avatar)
{:ok, _user} = user |> Changeset.change(%{avatar: data}) |> User.update_and_set_cache()
%{"url" => [%{"href" => href} | _]} = data
@ -78,14 +87,14 @@ def update_avatar(%{assigns: %{user: user}} = conn, params) do
end
@doc "PATCH /api/v1/pleroma/accounts/update_banner"
def update_banner(%{assigns: %{user: user}} = conn, %{"banner" => ""}) do
def update_banner(%{assigns: %{user: user}, body_params: %{banner: ""}} = conn, _) do
with {:ok, _user} <- User.update_banner(user, %{}) do
json(conn, %{url: nil})
end
end
def update_banner(%{assigns: %{user: user}} = conn, params) do
with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner),
def update_banner(%{assigns: %{user: user}, body_params: params} = conn, _) do
with {:ok, object} <- ActivityPub.upload(%{img: params[:banner]}, type: :banner),
{:ok, _user} <- User.update_banner(user, object.data) do
%{"url" => [%{"href" => href} | _]} = object.data
@ -94,13 +103,13 @@ def update_banner(%{assigns: %{user: user}} = conn, params) do
end
@doc "PATCH /api/v1/pleroma/accounts/update_background"
def update_background(%{assigns: %{user: user}} = conn, %{"img" => ""}) do
def update_background(%{assigns: %{user: user}, body_params: %{img: ""}} = conn, _) do
with {:ok, _user} <- User.update_background(user, %{}) do
json(conn, %{url: nil})
end
end
def update_background(%{assigns: %{user: user}} = conn, params) do
def update_background(%{assigns: %{user: user}, body_params: params} = conn, _) do
with {:ok, object} <- ActivityPub.upload(params, type: :background),
{:ok, _user} <- User.update_background(user, object.data) do
%{"url" => [%{"href" => href} | _]} = object.data
@ -117,6 +126,7 @@ def favourites(%{assigns: %{account: %{hide_favorites: true}}} = conn, _params)
def favourites(%{assigns: %{user: for_user, account: user}} = conn, params) do
params =
params
|> Map.new(fn {key, value} -> {to_string(key), value} end)
|> Map.put("type", "Create")
|> Map.put("favorited_by", user.ap_id)
|> Map.put("blocking_user", for_user)
@ -139,8 +149,7 @@ def favourites(%{assigns: %{user: for_user, account: user}} = conn, params) do
|> render("index.json",
activities: activities,
for: for_user,
as: :activity,
skip_relationships: skip_relationships?(params)
as: :activity
)
end

View file

@ -5,7 +5,7 @@
defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, skip_relationships?: 1]
import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
alias Pleroma.Activity
alias Pleroma.Conversation.Participation
@ -69,7 +69,12 @@ def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}
%{
name: emoji,
count: length(users),
accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}),
accounts:
AccountView.render("index.json", %{
users: users,
for: user,
as: :user
}),
me: !!(user && user.ap_id in user_ap_ids)
}
end
@ -145,8 +150,7 @@ def conversation_statuses(
|> render("index.json",
activities: activities,
for: user,
as: :activity,
skip_relationships: skip_relationships?(params)
as: :activity
)
else
_error ->
@ -201,7 +205,7 @@ def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"id" => notif
end
end
def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"max_id" => max_id} = params) do
def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) do
with notifications <- Notification.set_read_up_to(user, max_id) do
notifications = Enum.take(notifications, 80)
@ -209,8 +213,7 @@ def mark_notifications_as_read(%{assigns: %{user: user}} = conn, %{"max_id" => m
|> put_view(NotificationView)
|> render("index.json",
notifications: notifications,
for: user,
skip_relationships: skip_relationships?(params)
for: user
)
end
end

View file

@ -403,6 +403,7 @@ defmodule Pleroma.Web.Router do
post("/markers", MarkerController, :upsert)
post("/media", MediaController, :create)
get("/media/:id", MediaController, :show)
put("/media/:id", MediaController, :update)
get("/notifications", NotificationController, :index)
@ -497,6 +498,8 @@ defmodule Pleroma.Web.Router do
scope "/api/v2", Pleroma.Web.MastodonAPI do
pipe_through(:api)
get("/search", SearchController, :search2)
post("/media", MediaController, :create2)
end
scope "/api", Pleroma.Web do

View file

@ -127,6 +127,7 @@ defp deps do
{:oban, "~> 1.2"},
{:gettext, "~> 0.15"},
{:pbkdf2_elixir, "~> 1.0"},
{:bcrypt_elixir, "~> 2.0"},
{:trailing_format_plug, "~> 0.0.7"},
{:fast_sanitize, "~> 0.1"},
{:html_entities, "~> 0.5", override: true},

View file

@ -5,6 +5,7 @@
"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"},
"bbcode": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/bbcode.git", "f2d267675e9a7e1ad1ea9beb4cc23382762b66c2", [ref: "v0.2.0"]},
"bbcode_pleroma": {:hex, :bbcode_pleroma, "0.2.0", "d36f5bca6e2f62261c45be30fa9b92725c0655ad45c99025cb1c3e28e25803ef", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "19851074419a5fedb4ef49e1f01b30df504bb5dbb6d6adfc135238063bebd1c3"},
"bcrypt_elixir": {:hex, :bcrypt_elixir, "2.2.0", "3df902b81ce7fa8867a2ae30d20a1da6877a2c056bfb116fd0bc8a5f0190cea4", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "762be3fcb779f08207531bc6612cca480a338e4b4357abb49f5ce00240a77d1e"},
"benchee": {:hex, :benchee, "1.0.1", "66b211f9bfd84bd97e6d1beaddf8fc2312aaabe192f776e8931cb0c16f53a521", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}], "hexpm", "3ad58ae787e9c7c94dd7ceda3b587ec2c64604563e049b2a0e8baafae832addb"},
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"},
"cachex": {:hex, :cachex, "3.2.0", "a596476c781b0646e6cb5cd9751af2e2974c3e0d5498a8cab71807618b74fe2f", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "aef93694067a43697ae0531727e097754a9e992a1e7946296f5969d6dd9ac986"},
@ -29,6 +30,7 @@
"ecto": {:hex, :ecto, "3.4.0", "a7a83ab8359bf816ce729e5e65981ce25b9fc5adfc89c2ea3980f4fed0bfd7c1", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "5eed18252f5b5bbadec56a24112b531343507dbe046273133176b12190ce19cc"},
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
"ecto_sql": {:hex, :ecto_sql, "3.3.4", "aa18af12eb875fbcda2f75e608b3bd534ebf020fc4f6448e4672fcdcbb081244", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4 or ~> 3.3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5eccbdbf92e3c6f213007a82d5dbba4cd9bb659d1a21331f89f408e4c0efd7a8"},
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"},
"esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
"eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"},
"ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"},

View file

@ -8,8 +8,16 @@
## to merge POT files into PO files.
msgid ""
msgstr ""
"PO-Revision-Date: 2020-05-12 15:52+0000\n"
"Last-Translator: Haelwenn (lanodan) Monnier "
"<contact+translate.pleroma.social@hacktivis.me>\n"
"Language-Team: French <https://translate.pleroma.social/projects/pleroma/"
"pleroma/fr/>\n"
"Language: fr\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 4.0.4\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "can't be blank"
msgstr "ne peut être vide"
@ -35,10 +43,10 @@ msgid "does not match confirmation"
msgstr "ne correspondent pas"
msgid "is still associated with this entry"
msgstr ""
msgstr "est toujours associé à cette entrée"
msgid "are still associated with this entry"
msgstr ""
msgstr "sont toujours associés à cette entrée"
msgid "should be %{count} character(s)"
msgid_plural "should be %{count} character(s)"
@ -85,375 +93,375 @@ msgstr "doit être supérieur ou égal à %{number}"
msgid "must be equal to %{number}"
msgstr "doit égal à %{number}"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:381
#, elixir-format
msgid "Account not found"
msgstr "Compte non trouvé"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:153
#, elixir-format
msgid "Already voted"
msgstr "A déjà voté"
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:263
#, elixir-format
msgid "Bad request"
msgstr "Requête Invalide"
#, elixir-format
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:254
#, elixir-format
msgid "Can't delete object"
msgstr "Ne peut supprimer cet objet"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:569
#, elixir-format
msgid "Can't delete this post"
msgstr "Ne peut supprimer ce message"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1731
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1737
#, elixir-format
msgid "Can't display this activity"
msgstr "Ne peut afficher cette activitée"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:195
#, elixir-format
msgid "Can't find user"
msgstr "Compte non trouvé"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1148
#, elixir-format
msgid "Can't get favorites"
msgstr "Favoris non trouvables"
#, elixir-format
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:263
#, elixir-format
msgid "Can't like object"
msgstr "Ne peut aimer cet objet"
#, elixir-format
#: lib/pleroma/web/common_api/utils.ex:518
#, elixir-format
msgid "Cannot post an empty status without attachments"
msgstr "Ne peut envoyer un status vide sans attachements"
#, elixir-format
#: lib/pleroma/web/common_api/utils.ex:461
#, elixir-format
msgid "Comment must be up to %{max_size} characters"
msgstr "Le commentaire ne doit faire plus de %{max_size} charactères"
#, elixir-format
#: lib/pleroma/web/admin_api/config.ex:63
#, elixir-format
msgid "Config with params %{params} not found"
msgstr "Configuration avec les paramètres %{params} non trouvée"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:78
#, elixir-format
msgid "Could not delete"
msgstr "Échec de la suppression"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:110
#, elixir-format
msgid "Could not favorite"
msgstr "Échec de mise en favoris"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:310
#, elixir-format
msgid "Could not pin"
msgstr "Échec de l'épinglage"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:89
#, elixir-format
msgid "Could not repeat"
msgstr "Échec de création la répétition"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:120
#, elixir-format
msgid "Could not unfavorite"
msgstr "Échec de suppression des favoris"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:327
#, elixir-format
msgid "Could not unpin"
msgstr "Échec du dépinglage"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:99
#, elixir-format
msgid "Could not unrepeat"
msgstr "Échec de suppression de la répétition"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:392
#, elixir-format
msgid "Could not update state"
msgstr "Échec de la mise à jour du status"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1271
#, elixir-format
msgid "Error."
msgstr "Erreur."
#, elixir-format
#: lib/pleroma/captcha/kocaptcha.ex:36
#, elixir-format
msgid "Invalid CAPTCHA"
msgstr "CAPTCHA invalide"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1700
#: lib/pleroma/web/oauth/oauth_controller.ex:465
#, elixir-format
msgid "Invalid credentials"
msgstr "Paramètres d'authentification invalides"
#, elixir-format
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:20
#, elixir-format
msgid "Invalid credentials."
msgstr "Paramètres d'authentification invalides."
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:154
#, elixir-format
msgid "Invalid indices"
msgstr "Indices invalides"
#, elixir-format
#: lib/pleroma/web/admin_api/admin_api_controller.ex:411
#, elixir-format
msgid "Invalid parameters"
msgstr "Paramètres invalides"
#, elixir-format
#: lib/pleroma/web/common_api/utils.ex:377
#, elixir-format
msgid "Invalid password."
msgstr "Mot de passe invalide."
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:163
#, elixir-format
msgid "Invalid request"
msgstr "Requête invalide"
#, elixir-format
#: lib/pleroma/captcha/kocaptcha.ex:16
#, elixir-format
msgid "Kocaptcha service unavailable"
msgstr "Service Kocaptcha non disponible"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1696
#, elixir-format
msgid "Missing parameters"
msgstr "Paramètres manquants"
#, elixir-format
#: lib/pleroma/web/common_api/utils.ex:496
#, elixir-format
msgid "No such conversation"
msgstr "Conversation inconnue"
#, elixir-format
#: lib/pleroma/web/admin_api/admin_api_controller.ex:163
#: lib/pleroma/web/admin_api/admin_api_controller.ex:206
#, elixir-format
msgid "No such permission_group"
msgstr "Groupe de permission inconnu"
#, elixir-format
#: lib/pleroma/plugs/uploaded_media.ex:69
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:311
#: lib/pleroma/web/admin_api/admin_api_controller.ex:399
#: lib/pleroma/web/mastodon_api/subscription_controller.ex:63
#: lib/pleroma/web/ostatus/ostatus_controller.ex:248
#, elixir-format
msgid "Not found"
msgstr "Non Trouvé"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:152
#, elixir-format
msgid "Poll's author can't vote"
msgstr "L'auteur·rice d'un sondage ne peut voter"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:443
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:444
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:473
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:476
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1180
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1564
#, elixir-format
msgid "Record not found"
msgstr "Enregistrement non trouvé"
#, elixir-format
#: lib/pleroma/web/admin_api/admin_api_controller.ex:417
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1570
#: lib/pleroma/web/mastodon_api/subscription_controller.ex:69
#: lib/pleroma/web/ostatus/ostatus_controller.ex:252
#, elixir-format
msgid "Something went wrong"
msgstr "Erreur inconnue"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:253
#, elixir-format
msgid "The message visibility must be direct"
msgstr "La visibilitée du message doit être « direct »"
#, elixir-format
#: lib/pleroma/web/common_api/utils.ex:521
#, elixir-format
msgid "The status is over the character limit"
msgstr "Le status est au-delà de la limite de charactères"
#, elixir-format
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:27
#, elixir-format
msgid "This resource requires authentication."
msgstr "Cette resource nécessite une authentification."
#, elixir-format
#: lib/pleroma/plugs/rate_limiter.ex:89
#, elixir-format
msgid "Throttled"
msgstr "Limité"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:155
#, elixir-format
msgid "Too many choices"
msgstr "Trop de choix"
#, elixir-format
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:268
#, elixir-format
msgid "Unhandled activity type"
msgstr "Type d'activitée non-gérée"
#, elixir-format
#: lib/pleroma/plugs/user_is_admin_plug.ex:20
#, elixir-format
msgid "User is not admin."
msgstr "Le compte n'est pas admin."
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:380
#, elixir-format
msgid "Valid `account_id` required"
msgstr "Un `account_id` valide est requis"
#, elixir-format
#: lib/pleroma/web/admin_api/admin_api_controller.ex:185
#, elixir-format
msgid "You can't revoke your own admin status."
msgstr "Vous ne pouvez révoquer votre propre status d'admin."
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:216
#, elixir-format
msgid "Your account is currently disabled"
msgstr "Votre compte est actuellement désactivé"
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:158
#: lib/pleroma/web/oauth/oauth_controller.ex:213
#, elixir-format
msgid "Your login is missing a confirmed e-mail address"
msgstr "Une confirmation de l'addresse de couriel est requise pour l'authentification"
#, elixir-format
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:221
#, elixir-format
msgid "can't read inbox of %{nickname} as %{as_nickname}"
msgstr "Ne peut lire la boite de réception de %{nickname} en tant que %{as_nickname}"
#, elixir-format
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:297
#, elixir-format
msgid "can't update outbox of %{nickname} as %{as_nickname}"
msgstr "Ne peut poster dans la boite d'émission de %{nickname} en tant que %{as_nickname}"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:335
#, elixir-format
msgid "conversation is already muted"
msgstr "la conversation est déjà baillonée"
#, elixir-format
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:192
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:317
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1196
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1247
#, elixir-format
msgid "error"
msgstr "erreur"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:789
#, elixir-format
msgid "mascots can only be images"
msgstr "les mascottes ne peuvent être que des images"
#, elixir-format
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:34
#, elixir-format
msgid "not found"
msgstr "non trouvé"
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:298
#, elixir-format
msgid "Bad OAuth request."
msgstr "Requête OAuth invalide."
#, elixir-format
#: lib/pleroma/captcha/captcha.ex:92
#, elixir-format
msgid "CAPTCHA already used"
msgstr "CAPTCHA déjà utilisé"
#, elixir-format
#: lib/pleroma/captcha/captcha.ex:89
#, elixir-format
msgid "CAPTCHA expired"
msgstr "CAPTCHA expiré"
#, elixir-format
#: lib/pleroma/plugs/uploaded_media.ex:50
#, elixir-format
msgid "Failed"
msgstr "Échec"
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:314
msgid "Failed to authenticate: %{message}."
msgstr "Échec de l'authentification: %{message}"
#, elixir-format
msgid "Failed to authenticate: %{message}."
msgstr "Échec de l'authentification : %{message}."
#: lib/pleroma/web/oauth/oauth_controller.ex:345
#, elixir-format
msgid "Failed to set up user account."
msgstr "Échec de création de votre compte."
#, elixir-format
#: lib/pleroma/plugs/oauth_scopes_plug.ex:37
msgid "Insufficient permissions: %{permissions}."
msgstr "Permissions insuffisantes: %{permissions}."
#, elixir-format
msgid "Insufficient permissions: %{permissions}."
msgstr "Permissions insuffisantes : %{permissions}."
#: lib/pleroma/plugs/uploaded_media.ex:89
#, elixir-format
msgid "Internal Error"
msgstr "Erreur interne"
#, elixir-format
#: lib/pleroma/web/oauth/fallback_controller.ex:22
#: lib/pleroma/web/oauth/fallback_controller.ex:29
#, elixir-format
msgid "Invalid Username/Password"
msgstr "Nom d'utilisateur/mot de passe invalide"
#, elixir-format
#: lib/pleroma/captcha/captcha.ex:107
#, elixir-format
msgid "Invalid answer data"
msgstr "Réponse invalide"
#, elixir-format
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:204
#, elixir-format
msgid "Nodeinfo schema version not handled"
msgstr "Version du schéma nodeinfo non géré"
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:145
msgid "This action is outside the authorized scopes"
msgstr "Cette action est en dehors des authorisations" # "scopes" ?
#, elixir-format
msgid "This action is outside the authorized scopes"
msgstr "Cette action est en dehors des authorisations" # "scopes"
#: lib/pleroma/web/oauth/fallback_controller.ex:14
#, elixir-format
msgid "Unknown error, please check the details and try again."
msgstr "Erreur inconnue, veuillez vérifier les détails et réessayer."
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:93
#: lib/pleroma/web/oauth/oauth_controller.ex:131
#, elixir-format
msgid "Unlisted redirect_uri."
msgstr "redirect_uri non listé."
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:294
#, elixir-format
msgid "Unsupported OAuth provider: %{provider}."
msgstr "Fournisseur OAuth non supporté : %{provider}."
#, elixir-format
#: lib/pleroma/uploaders/uploader.ex:71
msgid "Uploader callback timeout"
msgstr ""
## msgstr "Attente écoulée"
#, elixir-format
msgid "Uploader callback timeout"
msgstr "Temps d'attente du téléverseur écoulé"
## msgstr "Attente écoulée"
#: lib/pleroma/web/uploader_controller.ex:11
#: lib/pleroma/web/uploader_controller.ex:23
#, elixir-format
msgid "bad request"
msgstr "requête invalide"

View file

@ -0,0 +1,578 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-15 09:37+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: nl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Translate Toolkit 2.5.1\n"
## This file is a PO Template file.
##
## `msgid`s here are often extracted from source code.
## Add new translations manually only if they're dynamic
## translations that can't be statically extracted.
##
## Run `mix gettext.extract` to bring this file up to
## date. Leave `msgstr`s empty as changing them here as no
## effect: edit them in PO (`.po`) files instead.
## From Ecto.Changeset.cast/4
msgid "can't be blank"
msgstr ""
## From Ecto.Changeset.unique_constraint/3
msgid "has already been taken"
msgstr ""
## From Ecto.Changeset.put_change/3
msgid "is invalid"
msgstr ""
## From Ecto.Changeset.validate_format/3
msgid "has invalid format"
msgstr ""
## From Ecto.Changeset.validate_subset/3
msgid "has an invalid entry"
msgstr ""
## From Ecto.Changeset.validate_exclusion/3
msgid "is reserved"
msgstr ""
## From Ecto.Changeset.validate_confirmation/3
msgid "does not match confirmation"
msgstr ""
## From Ecto.Changeset.no_assoc_constraint/3
msgid "is still associated with this entry"
msgstr ""
msgid "are still associated with this entry"
msgstr ""
## From Ecto.Changeset.validate_length/3
msgid "should be %{count} character(s)"
msgid_plural "should be %{count} character(s)"
msgstr[0] ""
msgstr[1] ""
msgid "should have %{count} item(s)"
msgid_plural "should have %{count} item(s)"
msgstr[0] ""
msgstr[1] ""
msgid "should be at least %{count} character(s)"
msgid_plural "should be at least %{count} character(s)"
msgstr[0] ""
msgstr[1] ""
msgid "should have at least %{count} item(s)"
msgid_plural "should have at least %{count} item(s)"
msgstr[0] ""
msgstr[1] ""
msgid "should be at most %{count} character(s)"
msgid_plural "should be at most %{count} character(s)"
msgstr[0] ""
msgstr[1] ""
msgid "should have at most %{count} item(s)"
msgid_plural "should have at most %{count} item(s)"
msgstr[0] ""
msgstr[1] ""
## From Ecto.Changeset.validate_number/3
msgid "must be less than %{number}"
msgstr ""
msgid "must be greater than %{number}"
msgstr ""
msgid "must be less than or equal to %{number}"
msgstr ""
msgid "must be greater than or equal to %{number}"
msgstr ""
msgid "must be equal to %{number}"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:421
#, elixir-format
msgid "Account not found"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:249
#, elixir-format
msgid "Already voted"
msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:360
#, elixir-format
msgid "Bad request"
msgstr ""
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:425
#, elixir-format
msgid "Can't delete object"
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/status_controller.ex:196
#, elixir-format
msgid "Can't delete this post"
msgstr ""
#: lib/pleroma/web/controller_helper.ex:95
#: lib/pleroma/web/controller_helper.ex:101
#, elixir-format
msgid "Can't display this activity"
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:227
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:254
#, elixir-format
msgid "Can't find user"
msgstr ""
#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:114
#, elixir-format
msgid "Can't get favorites"
msgstr ""
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:437
#, elixir-format
msgid "Can't like object"
msgstr ""
#: lib/pleroma/web/common_api/utils.ex:556
#, elixir-format
msgid "Cannot post an empty status without attachments"
msgstr ""
#: lib/pleroma/web/common_api/utils.ex:504
#, elixir-format
msgid "Comment must be up to %{max_size} characters"
msgstr ""
#: lib/pleroma/config/config_db.ex:222
#, elixir-format
msgid "Config with params %{params} not found"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:95
#, elixir-format
msgid "Could not delete"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:141
#, elixir-format
msgid "Could not favorite"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:370
#, elixir-format
msgid "Could not pin"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:112
#, elixir-format
msgid "Could not repeat"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:188
#, elixir-format
msgid "Could not unfavorite"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:380
#, elixir-format
msgid "Could not unpin"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:126
#, elixir-format
msgid "Could not unrepeat"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:428
#: lib/pleroma/web/common_api/common_api.ex:437
#, elixir-format
msgid "Could not update state"
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:202
#, elixir-format
msgid "Error."
msgstr ""
#: lib/pleroma/web/twitter_api/twitter_api.ex:106
#, elixir-format
msgid "Invalid CAPTCHA"
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:117
#: lib/pleroma/web/oauth/oauth_controller.ex:569
#, elixir-format
msgid "Invalid credentials"
msgstr ""
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
#, elixir-format
msgid "Invalid credentials."
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:265
#, elixir-format
msgid "Invalid indices"
msgstr ""
#: lib/pleroma/web/admin_api/admin_api_controller.ex:1147
#, elixir-format
msgid "Invalid parameters"
msgstr ""
#: lib/pleroma/web/common_api/utils.ex:411
#, elixir-format
msgid "Invalid password."
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:187
#, elixir-format
msgid "Invalid request"
msgstr ""
#: lib/pleroma/web/twitter_api/twitter_api.ex:109
#, elixir-format
msgid "Kocaptcha service unavailable"
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:113
#, elixir-format
msgid "Missing parameters"
msgstr ""
#: lib/pleroma/web/common_api/utils.ex:540
#, elixir-format
msgid "No such conversation"
msgstr ""
#: lib/pleroma/web/admin_api/admin_api_controller.ex:439
#: lib/pleroma/web/admin_api/admin_api_controller.ex:465 lib/pleroma/web/admin_api/admin_api_controller.ex:507
#, elixir-format
msgid "No such permission_group"
msgstr ""
#: lib/pleroma/plugs/uploaded_media.ex:74
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:485 lib/pleroma/web/admin_api/admin_api_controller.ex:1135
#: lib/pleroma/web/feed/user_controller.ex:73 lib/pleroma/web/ostatus/ostatus_controller.ex:143
#, elixir-format
msgid "Not found"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:241
#, elixir-format
msgid "Poll's author can't vote"
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:20
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:37 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:49
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:50 lib/pleroma/web/mastodon_api/controllers/status_controller.ex:290
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:71
#, elixir-format
msgid "Record not found"
msgstr ""
#: lib/pleroma/web/admin_api/admin_api_controller.ex:1153
#: lib/pleroma/web/feed/user_controller.ex:79 lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:32
#: lib/pleroma/web/ostatus/ostatus_controller.ex:149
#, elixir-format
msgid "Something went wrong"
msgstr ""
#: lib/pleroma/web/common_api/activity_draft.ex:107
#, elixir-format
msgid "The message visibility must be direct"
msgstr ""
#: lib/pleroma/web/common_api/utils.ex:566
#, elixir-format
msgid "The status is over the character limit"
msgstr ""
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
#, elixir-format
msgid "This resource requires authentication."
msgstr ""
#: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
#, elixir-format
msgid "Throttled"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:266
#, elixir-format
msgid "Too many choices"
msgstr ""
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:442
#, elixir-format
msgid "Unhandled activity type"
msgstr ""
#: lib/pleroma/web/admin_api/admin_api_controller.ex:536
#, elixir-format
msgid "You can't revoke your own admin status."
msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:218
#: lib/pleroma/web/oauth/oauth_controller.ex:309
#, elixir-format
msgid "Your account is currently disabled"
msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:180
#: lib/pleroma/web/oauth/oauth_controller.ex:332
#, elixir-format
msgid "Your login is missing a confirmed e-mail address"
msgstr ""
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:389
#, elixir-format
msgid "can't read inbox of %{nickname} as %{as_nickname}"
msgstr ""
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:472
#, elixir-format
msgid "can't update outbox of %{nickname} as %{as_nickname}"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:388
#, elixir-format
msgid "conversation is already muted"
msgstr ""
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:316
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:491
#, elixir-format
msgid "error"
msgstr ""
#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:29
#, elixir-format
msgid "mascots can only be images"
msgstr ""
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:60
#, elixir-format
msgid "not found"
msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:395
#, elixir-format
msgid "Bad OAuth request."
msgstr ""
#: lib/pleroma/web/twitter_api/twitter_api.ex:115
#, elixir-format
msgid "CAPTCHA already used"
msgstr ""
#: lib/pleroma/web/twitter_api/twitter_api.ex:112
#, elixir-format
msgid "CAPTCHA expired"
msgstr ""
#: lib/pleroma/plugs/uploaded_media.ex:55
#, elixir-format
msgid "Failed"
msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:411
#, elixir-format
msgid "Failed to authenticate: %{message}."
msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:442
#, elixir-format
msgid "Failed to set up user account."
msgstr ""
#: lib/pleroma/plugs/oauth_scopes_plug.ex:38
#, elixir-format
msgid "Insufficient permissions: %{permissions}."
msgstr ""
#: lib/pleroma/plugs/uploaded_media.ex:94
#, elixir-format
msgid "Internal Error"
msgstr ""
#: lib/pleroma/web/oauth/fallback_controller.ex:22
#: lib/pleroma/web/oauth/fallback_controller.ex:29
#, elixir-format
msgid "Invalid Username/Password"
msgstr ""
#: lib/pleroma/web/twitter_api/twitter_api.ex:118
#, elixir-format
msgid "Invalid answer data"
msgstr ""
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:128
#, elixir-format
msgid "Nodeinfo schema version not handled"
msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:169
#, elixir-format
msgid "This action is outside the authorized scopes"
msgstr ""
#: lib/pleroma/web/oauth/fallback_controller.ex:14
#, elixir-format
msgid "Unknown error, please check the details and try again."
msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:116
#: lib/pleroma/web/oauth/oauth_controller.ex:155
#, elixir-format
msgid "Unlisted redirect_uri."
msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:391
#, elixir-format
msgid "Unsupported OAuth provider: %{provider}."
msgstr ""
#: lib/pleroma/uploaders/uploader.ex:72
#, elixir-format
msgid "Uploader callback timeout"
msgstr ""
#: lib/pleroma/web/uploader_controller.ex:23
#, elixir-format
msgid "bad request"
msgstr ""
#: lib/pleroma/web/twitter_api/twitter_api.ex:103
#, elixir-format
msgid "CAPTCHA Error"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:200
#, elixir-format
msgid "Could not add reaction emoji"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:211
#, elixir-format
msgid "Could not remove reaction emoji"
msgstr ""
#: lib/pleroma/web/twitter_api/twitter_api.ex:129
#, elixir-format
msgid "Invalid CAPTCHA (Missing parameter: %{name})"
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/list_controller.ex:92
#, elixir-format
msgid "List not found"
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:124
#, elixir-format
msgid "Missing parameter: %{name}"
msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:207
#: lib/pleroma/web/oauth/oauth_controller.ex:322
#, elixir-format
msgid "Password reset is required"
msgstr ""
#: lib/pleroma/tests/auth_test_controller.ex:9
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:6 lib/pleroma/web/admin_api/admin_api_controller.ex:6
#: lib/pleroma/web/controller_helper.ex:6 lib/pleroma/web/fallback_redirect_controller.ex:6
#: lib/pleroma/web/feed/tag_controller.ex:6 lib/pleroma/web/feed/user_controller.ex:6
#: lib/pleroma/web/mailer/subscription_controller.ex:2 lib/pleroma/web/masto_fe_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/app_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/auth_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/filter_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/instance_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/list_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/marker_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex:14 lib/pleroma/web/mastodon_api/controllers/media_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/notification_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/report_controller.ex:8 lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/search_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/status_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:7 lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:6 lib/pleroma/web/media_proxy/media_proxy_controller.ex:6
#: lib/pleroma/web/mongooseim/mongoose_im_controller.ex:6 lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:6
#: lib/pleroma/web/oauth/fallback_controller.ex:6 lib/pleroma/web/oauth/mfa_controller.ex:10
#: lib/pleroma/web/oauth/oauth_controller.ex:6 lib/pleroma/web/ostatus/ostatus_controller.ex:6
#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:2
#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex:6
#: lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex:6
#: lib/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller.ex:7 lib/pleroma/web/static_fe/static_fe_controller.ex:6
#: lib/pleroma/web/twitter_api/controllers/password_controller.ex:10 lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex:6
#: lib/pleroma/web/twitter_api/controllers/util_controller.ex:6 lib/pleroma/web/twitter_api/twitter_api_controller.ex:6
#: lib/pleroma/web/uploader_controller.ex:6 lib/pleroma/web/web_finger/web_finger_controller.ex:6
#, elixir-format
msgid "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
msgstr ""
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
#, elixir-format
msgid "Two-factor authentication enabled, you must use a access token."
msgstr ""
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:210
#, elixir-format
msgid "Unexpected error occurred while adding file to pack."
msgstr ""
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:138
#, elixir-format
msgid "Unexpected error occurred while creating pack."
msgstr ""
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:278
#, elixir-format
msgid "Unexpected error occurred while removing file from pack."
msgstr ""
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:250
#, elixir-format
msgid "Unexpected error occurred while updating file in pack."
msgstr ""
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:179
#, elixir-format
msgid "Unexpected error occurred while updating pack metadata."
msgstr ""
#: lib/pleroma/plugs/user_is_admin_plug.ex:40
#, elixir-format
msgid "User is not an admin or OAuth admin scope is not granted."
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
#, elixir-format
msgid "Web push subscription is disabled on this Pleroma instance"
msgstr ""
#: lib/pleroma/web/admin_api/admin_api_controller.ex:502
#, elixir-format
msgid "You can't revoke your own admin/moderator status."
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:105
#, elixir-format
msgid "authorization required for timeline view"
msgstr ""

View file

@ -0,0 +1,587 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-05-13 16:37+0000\n"
"PO-Revision-Date: 2020-05-16 17:13+0000\n"
"Last-Translator: Jędrzej Tomaszewski <jederow@hotmail.com>\n"
"Language-Team: Polish <https://translate.pleroma.social/projects/pleroma/"
"pleroma/pl/>\n"
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 4.0.4\n"
## This file is a PO Template file.
##
## `msgid`s here are often extracted from source code.
## Add new translations manually only if they're dynamic
## translations that can't be statically extracted.
##
## Run `mix gettext.extract` to bring this file up to
## date. Leave `msgstr`s empty as changing them here as no
## effect: edit them in PO (`.po`) files instead.
## From Ecto.Changeset.cast/4
msgid "can't be blank"
msgstr "nie może być pusty"
## From Ecto.Changeset.unique_constraint/3
msgid "has already been taken"
msgstr "jest już zajęty"
## From Ecto.Changeset.put_change/3
msgid "is invalid"
msgstr "jest nieprawidłowy"
## From Ecto.Changeset.validate_format/3
msgid "has invalid format"
msgstr "ma niepoprawny format"
## From Ecto.Changeset.validate_subset/3
msgid "has an invalid entry"
msgstr "ma niepoprawny wpis"
## From Ecto.Changeset.validate_exclusion/3
msgid "is reserved"
msgstr "jest zarezerwowany"
## From Ecto.Changeset.validate_confirmation/3
msgid "does not match confirmation"
msgstr ""
## From Ecto.Changeset.no_assoc_constraint/3
msgid "is still associated with this entry"
msgstr "jest wciąż powiązane z tym wpisem"
msgid "are still associated with this entry"
msgstr "są wciąż powiązane z tym wpisem"
## From Ecto.Changeset.validate_length/3
msgid "should be %{count} character(s)"
msgid_plural "should be %{count} character(s)"
msgstr[0] "powinno mieć %{count} znak"
msgstr[1] "powinno mieć %{count} znaki"
msgstr[2] "powinno mieć %{count} znaków"
msgid "should have %{count} item(s)"
msgid_plural "should have %{count} item(s)"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
msgid "should be at least %{count} character(s)"
msgid_plural "should be at least %{count} character(s)"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
msgid "should have at least %{count} item(s)"
msgid_plural "should have at least %{count} item(s)"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
msgid "should be at most %{count} character(s)"
msgid_plural "should be at most %{count} character(s)"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
msgid "should have at most %{count} item(s)"
msgid_plural "should have at most %{count} item(s)"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
## From Ecto.Changeset.validate_number/3
msgid "must be less than %{number}"
msgstr ""
msgid "must be greater than %{number}"
msgstr ""
msgid "must be less than or equal to %{number}"
msgstr ""
msgid "must be greater than or equal to %{number}"
msgstr ""
msgid "must be equal to %{number}"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:421
#, elixir-format
msgid "Account not found"
msgstr "Nie znaleziono konta"
#: lib/pleroma/web/common_api/common_api.ex:249
#, elixir-format
msgid "Already voted"
msgstr "Już zagłosowano"
#: lib/pleroma/web/oauth/oauth_controller.ex:360
#, elixir-format
msgid "Bad request"
msgstr "Nieprawidłowe żądanie"
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:425
#, elixir-format
msgid "Can't delete object"
msgstr "Nie można usunąć obiektu"
#: lib/pleroma/web/mastodon_api/controllers/status_controller.ex:196
#, elixir-format
msgid "Can't delete this post"
msgstr "Nie udało się usunąć tego statusu"
#: lib/pleroma/web/controller_helper.ex:95
#: lib/pleroma/web/controller_helper.ex:101
#, elixir-format
msgid "Can't display this activity"
msgstr "Nie można wyświetlić tej aktywności"
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:227
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:254
#, elixir-format
msgid "Can't find user"
msgstr "Nie znaleziono użytkownika"
#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:114
#, elixir-format
msgid "Can't get favorites"
msgstr ""
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:437
#, elixir-format
msgid "Can't like object"
msgstr "Nie udało się polubić obiektu"
#: lib/pleroma/web/common_api/utils.ex:556
#, elixir-format
msgid "Cannot post an empty status without attachments"
msgstr "Nie można opublikować pustego statusu bez załączników"
#: lib/pleroma/web/common_api/utils.ex:504
#, elixir-format
msgid "Comment must be up to %{max_size} characters"
msgstr "Komentarz może mieć co najwyżej %{max_size} znaków"
#: lib/pleroma/config/config_db.ex:222
#, elixir-format
msgid "Config with params %{params} not found"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:95
#, elixir-format
msgid "Could not delete"
msgstr "Nie udało się usunąć"
#: lib/pleroma/web/common_api/common_api.ex:141
#, elixir-format
msgid "Could not favorite"
msgstr "Nie udało się dodać do ulubionych"
#: lib/pleroma/web/common_api/common_api.ex:370
#, elixir-format
msgid "Could not pin"
msgstr "Nie udało się przypiąć"
#: lib/pleroma/web/common_api/common_api.ex:112
#, elixir-format
msgid "Could not repeat"
msgstr "Nie udało się powtórzyć"
#: lib/pleroma/web/common_api/common_api.ex:188
#, elixir-format
msgid "Could not unfavorite"
msgstr "Nie udało się usunąć z ulubionych"
#: lib/pleroma/web/common_api/common_api.ex:380
#, elixir-format
msgid "Could not unpin"
msgstr "Nie udało się odpiąć"
#: lib/pleroma/web/common_api/common_api.ex:126
#, elixir-format
msgid "Could not unrepeat"
msgstr "Nie udało się cofnąć powtórzenia"
#: lib/pleroma/web/common_api/common_api.ex:428
#: lib/pleroma/web/common_api/common_api.ex:437
#, elixir-format
msgid "Could not update state"
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:202
#, elixir-format
msgid "Error."
msgstr ""
#: lib/pleroma/web/twitter_api/twitter_api.ex:106
#, elixir-format
msgid "Invalid CAPTCHA"
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:117
#: lib/pleroma/web/oauth/oauth_controller.ex:569
#, elixir-format
msgid "Invalid credentials"
msgstr ""
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
#, elixir-format
msgid "Invalid credentials."
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:265
#, elixir-format
msgid "Invalid indices"
msgstr ""
#: lib/pleroma/web/admin_api/admin_api_controller.ex:1147
#, elixir-format
msgid "Invalid parameters"
msgstr ""
#: lib/pleroma/web/common_api/utils.ex:411
#, elixir-format
msgid "Invalid password."
msgstr "Nieprawidłowe hasło."
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:187
#, elixir-format
msgid "Invalid request"
msgstr "Nieprawidłowe żądanie"
#: lib/pleroma/web/twitter_api/twitter_api.ex:109
#, elixir-format
msgid "Kocaptcha service unavailable"
msgstr "Usługa Kocaptcha niedostępna"
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:113
#, elixir-format
msgid "Missing parameters"
msgstr "Brakujące parametry"
#: lib/pleroma/web/common_api/utils.ex:540
#, elixir-format
msgid "No such conversation"
msgstr "Nie ma takiej rozmowy"
#: lib/pleroma/web/admin_api/admin_api_controller.ex:439
#: lib/pleroma/web/admin_api/admin_api_controller.ex:465 lib/pleroma/web/admin_api/admin_api_controller.ex:507
#, elixir-format
msgid "No such permission_group"
msgstr "Nie ma takiej grupy uprawnień"
#: lib/pleroma/plugs/uploaded_media.ex:74
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:485 lib/pleroma/web/admin_api/admin_api_controller.ex:1135
#: lib/pleroma/web/feed/user_controller.ex:73 lib/pleroma/web/ostatus/ostatus_controller.ex:143
#, elixir-format
msgid "Not found"
msgstr "Nie znaleziono"
#: lib/pleroma/web/common_api/common_api.ex:241
#, elixir-format
msgid "Poll's author can't vote"
msgstr "Autor ankiety nie może głosować"
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:20
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:37 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:49
#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:50 lib/pleroma/web/mastodon_api/controllers/status_controller.ex:290
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:71
#, elixir-format
msgid "Record not found"
msgstr "Nie znaleziono rekordu"
#: lib/pleroma/web/admin_api/admin_api_controller.ex:1153
#: lib/pleroma/web/feed/user_controller.ex:79 lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:32
#: lib/pleroma/web/ostatus/ostatus_controller.ex:149
#, elixir-format
msgid "Something went wrong"
msgstr "Coś się zepsuło"
#: lib/pleroma/web/common_api/activity_draft.ex:107
#, elixir-format
msgid "The message visibility must be direct"
msgstr ""
#: lib/pleroma/web/common_api/utils.ex:566
#, elixir-format
msgid "The status is over the character limit"
msgstr "Ten status przekracza limit znaków"
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
#, elixir-format
msgid "This resource requires authentication."
msgstr ""
#: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
#, elixir-format
msgid "Throttled"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:266
#, elixir-format
msgid "Too many choices"
msgstr ""
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:442
#, elixir-format
msgid "Unhandled activity type"
msgstr "Nieobsługiwany typ aktywności"
#: lib/pleroma/web/admin_api/admin_api_controller.ex:536
#, elixir-format
msgid "You can't revoke your own admin status."
msgstr "Nie możesz odebrać samemu sobie statusu administratora."
#: lib/pleroma/web/oauth/oauth_controller.ex:218
#: lib/pleroma/web/oauth/oauth_controller.ex:309
#, elixir-format
msgid "Your account is currently disabled"
msgstr "Twoje konto jest obecnie nieaktywne"
#: lib/pleroma/web/oauth/oauth_controller.ex:180
#: lib/pleroma/web/oauth/oauth_controller.ex:332
#, elixir-format
msgid "Your login is missing a confirmed e-mail address"
msgstr ""
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:389
#, elixir-format
msgid "can't read inbox of %{nickname} as %{as_nickname}"
msgstr ""
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:472
#, elixir-format
msgid "can't update outbox of %{nickname} as %{as_nickname}"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:388
#, elixir-format
msgid "conversation is already muted"
msgstr "rozmowa jest już wyciszona"
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:316
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:491
#, elixir-format
msgid "error"
msgstr "błąd"
#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:29
#, elixir-format
msgid "mascots can only be images"
msgstr "maskotki muszą być obrazkami"
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:60
#, elixir-format
msgid "not found"
msgstr "nie znaleziono"
#: lib/pleroma/web/oauth/oauth_controller.ex:395
#, elixir-format
msgid "Bad OAuth request."
msgstr "Niepoprawne żądanie OAuth."
#: lib/pleroma/web/twitter_api/twitter_api.ex:115
#, elixir-format
msgid "CAPTCHA already used"
msgstr "Zużyta CAPTCHA"
#: lib/pleroma/web/twitter_api/twitter_api.ex:112
#, elixir-format
msgid "CAPTCHA expired"
msgstr "CAPTCHA wygasła"
#: lib/pleroma/plugs/uploaded_media.ex:55
#, elixir-format
msgid "Failed"
msgstr "Nie udało się"
#: lib/pleroma/web/oauth/oauth_controller.ex:411
#, elixir-format
msgid "Failed to authenticate: %{message}."
msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:442
#, elixir-format
msgid "Failed to set up user account."
msgstr ""
#: lib/pleroma/plugs/oauth_scopes_plug.ex:38
#, elixir-format
msgid "Insufficient permissions: %{permissions}."
msgstr "Niewystarczające uprawnienia: %{permissions}."
#: lib/pleroma/plugs/uploaded_media.ex:94
#, elixir-format
msgid "Internal Error"
msgstr "Błąd wewnętrzny"
#: lib/pleroma/web/oauth/fallback_controller.ex:22
#: lib/pleroma/web/oauth/fallback_controller.ex:29
#, elixir-format
msgid "Invalid Username/Password"
msgstr "Nieprawidłowa nazwa użytkownika lub hasło"
#: lib/pleroma/web/twitter_api/twitter_api.ex:118
#, elixir-format
msgid "Invalid answer data"
msgstr ""
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:128
#, elixir-format
msgid "Nodeinfo schema version not handled"
msgstr "Nieobsługiwana wersja schematu Nodeinfo"
#: lib/pleroma/web/oauth/oauth_controller.ex:169
#, elixir-format
msgid "This action is outside the authorized scopes"
msgstr ""
#: lib/pleroma/web/oauth/fallback_controller.ex:14
#, elixir-format
msgid "Unknown error, please check the details and try again."
msgstr "Nieznany błąd, sprawdź szczegóły i spróbuj ponownie."
#: lib/pleroma/web/oauth/oauth_controller.ex:116
#: lib/pleroma/web/oauth/oauth_controller.ex:155
#, elixir-format
msgid "Unlisted redirect_uri."
msgstr ""
#: lib/pleroma/web/oauth/oauth_controller.ex:391
#, elixir-format
msgid "Unsupported OAuth provider: %{provider}."
msgstr "Nieobsługiwany dostawca OAuth: %{provider}."
#: lib/pleroma/uploaders/uploader.ex:72
#, elixir-format
msgid "Uploader callback timeout"
msgstr ""
#: lib/pleroma/web/uploader_controller.ex:23
#, elixir-format
msgid "bad request"
msgstr "nieprawidłowe żądanie"
#: lib/pleroma/web/twitter_api/twitter_api.ex:103
#, elixir-format
msgid "CAPTCHA Error"
msgstr "Błąd CAPTCHA"
#: lib/pleroma/web/common_api/common_api.ex:200
#, elixir-format
msgid "Could not add reaction emoji"
msgstr ""
#: lib/pleroma/web/common_api/common_api.ex:211
#, elixir-format
msgid "Could not remove reaction emoji"
msgstr ""
#: lib/pleroma/web/twitter_api/twitter_api.ex:129
#, elixir-format
msgid "Invalid CAPTCHA (Missing parameter: %{name})"
msgstr "Nieprawidłowa CAPTCHA (Brakujący parametr: %{name})"
#: lib/pleroma/web/mastodon_api/controllers/list_controller.ex:92
#, elixir-format
msgid "List not found"
msgstr "Nie znaleziono listy"
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:124
#, elixir-format
msgid "Missing parameter: %{name}"
msgstr "Brakujący parametr: %{name}"
#: lib/pleroma/web/oauth/oauth_controller.ex:207
#: lib/pleroma/web/oauth/oauth_controller.ex:322
#, elixir-format
msgid "Password reset is required"
msgstr "Wymagany reset hasła"
#: lib/pleroma/tests/auth_test_controller.ex:9
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:6 lib/pleroma/web/admin_api/admin_api_controller.ex:6
#: lib/pleroma/web/controller_helper.ex:6 lib/pleroma/web/fallback_redirect_controller.ex:6
#: lib/pleroma/web/feed/tag_controller.ex:6 lib/pleroma/web/feed/user_controller.ex:6
#: lib/pleroma/web/mailer/subscription_controller.ex:2 lib/pleroma/web/masto_fe_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/app_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/auth_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/filter_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/instance_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/list_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/marker_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex:14 lib/pleroma/web/mastodon_api/controllers/media_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/notification_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/report_controller.ex:8 lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/search_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/status_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:7 lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex:6
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:6 lib/pleroma/web/media_proxy/media_proxy_controller.ex:6
#: lib/pleroma/web/mongooseim/mongoose_im_controller.ex:6 lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:6
#: lib/pleroma/web/oauth/fallback_controller.ex:6 lib/pleroma/web/oauth/mfa_controller.ex:10
#: lib/pleroma/web/oauth/oauth_controller.ex:6 lib/pleroma/web/ostatus/ostatus_controller.ex:6
#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:2
#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex:6
#: lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex:6
#: lib/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller.ex:7 lib/pleroma/web/static_fe/static_fe_controller.ex:6
#: lib/pleroma/web/twitter_api/controllers/password_controller.ex:10 lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex:6
#: lib/pleroma/web/twitter_api/controllers/util_controller.ex:6 lib/pleroma/web/twitter_api/twitter_api_controller.ex:6
#: lib/pleroma/web/uploader_controller.ex:6 lib/pleroma/web/web_finger/web_finger_controller.ex:6
#, elixir-format
msgid "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
msgstr ""
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
#, elixir-format
msgid "Two-factor authentication enabled, you must use a access token."
msgstr "Uwierzytelnienie dwuskładnikowe jest włączone, musisz użyć tokenu."
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:210
#, elixir-format
msgid "Unexpected error occurred while adding file to pack."
msgstr "Nieoczekiwany błąd podczas dodawania pliku do paczki."
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:138
#, elixir-format
msgid "Unexpected error occurred while creating pack."
msgstr "Nieoczekiwany błąd podczas tworzenia paczki."
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:278
#, elixir-format
msgid "Unexpected error occurred while removing file from pack."
msgstr "Nieoczekiwany błąd podczas usuwania pliku z paczki."
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:250
#, elixir-format
msgid "Unexpected error occurred while updating file in pack."
msgstr "Nieoczekiwany błąd podczas zmieniania pliku w paczce."
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:179
#, elixir-format
msgid "Unexpected error occurred while updating pack metadata."
msgstr "Nieoczekiwany błąd podczas zmieniania metadanych paczki."
#: lib/pleroma/plugs/user_is_admin_plug.ex:40
#, elixir-format
msgid "User is not an admin or OAuth admin scope is not granted."
msgstr ""
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
#, elixir-format
msgid "Web push subscription is disabled on this Pleroma instance"
msgstr "Powiadomienia web push są wyłączone na tej instancji Pleromy"
#: lib/pleroma/web/admin_api/admin_api_controller.ex:502
#, elixir-format
msgid "You can't revoke your own admin/moderator status."
msgstr "Nie możesz odebrać samemu sobie statusu administratora/moderatora."
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:105
#, elixir-format
msgid "authorization required for timeline view"
msgstr "logowanie wymagane do przeglądania osi czasu"

View file

@ -1 +1 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1,user-scalable=no"><title>Pleroma</title><!--server-generated-meta--><link rel=icon type=image/png href=/favicon.png><link href=/static/css/vendors~app.18fea621d430000acc27.css rel=stylesheet><link href=/static/css/app.613cef07981cd95ccceb.css rel=stylesheet><link href=/static/fontello.1588947937982.css rel=stylesheet></head><body class=hidden><noscript>To use Pleroma, please enable JavaScript.</noscript><div id=app></div><script type=text/javascript src=/static/js/vendors~app.561a1c605d1dfb0e6f74.js></script><script type=text/javascript src=/static/js/app.996428ccaaaa7f28cb8d.js></script></body></html>
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1,user-scalable=no"><title>Pleroma</title><!--server-generated-meta--><link rel=icon type=image/png href=/favicon.png><link href=/static/css/vendors~app.18fea621d430000acc27.css rel=stylesheet><link href=/static/css/app.613cef07981cd95ccceb.css rel=stylesheet><link href=/static/fontello.1589385935077.css rel=stylesheet></head><body class=hidden><noscript>To use Pleroma, please enable JavaScript.</noscript><div id=app></div><script type=text/javascript src=/static/js/vendors~app.561a1c605d1dfb0e6f74.js></script><script type=text/javascript src=/static/js/app.838ffa9aecf210c7d744.js></script></body></html>

View file

@ -1,23 +1,28 @@
{
"theme": "pleroma-dark",
"background": "/static/aurora_borealis.jpg",
"logo": "/static/logo.png",
"logoMask": true,
"logoMargin": ".1em",
"redirectRootNoLogin": "/main/all",
"redirectRootLogin": "/main/friends",
"showInstanceSpecificPanel": false,
"collapseMessageWithSubject": false,
"scopeCopy": true,
"subjectLineBehavior": "email",
"postContentType": "text/plain",
"alwaysShowSubjectInput": true,
"background": "/static/aurora_borealis.jpg",
"collapseMessageWithSubject": false,
"disableChat": false,
"greentext": false,
"hideFilteredStatuses": false,
"hideMutedPosts": false,
"hidePostStats": false,
"hideSitename": false,
"hideUserStats": false,
"loginMethod": "password",
"webPushNotifications": false,
"logo": "/static/logo.png",
"logoMargin": ".1em",
"logoMask": true,
"minimalScopesMode": false,
"noAttachmentLinks": false,
"nsfwCensorImage": "",
"postContentType": "text/plain",
"redirectRootLogin": "/main/friends",
"redirectRootNoLogin": "/main/all",
"scopeCopy": true,
"showFeaturesPanel": true,
"minimalScopesMode": false
"showInstanceSpecificPanel": false,
"subjectLineBehavior": "email",
"theme": "pleroma-dark",
"webPushNotifications": false
}

View file

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

View file

@ -1,11 +1,11 @@
@font-face {
font-family: "Icons";
src: url("./font/fontello.1588947937982.eot");
src: url("./font/fontello.1588947937982.eot") format("embedded-opentype"),
url("./font/fontello.1588947937982.woff2") format("woff2"),
url("./font/fontello.1588947937982.woff") format("woff"),
url("./font/fontello.1588947937982.ttf") format("truetype"),
url("./font/fontello.1588947937982.svg") format("svg");
src: url("./font/fontello.1589385935077.eot");
src: url("./font/fontello.1589385935077.eot") format("embedded-opentype"),
url("./font/fontello.1589385935077.woff2") format("woff2"),
url("./font/fontello.1589385935077.woff") format("woff"),
url("./font/fontello.1589385935077.ttf") format("truetype"),
url("./font/fontello.1589385935077.svg") format("svg");
font-weight: normal;
font-style: normal;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,4 @@
var serviceWorkerOption = {"assets":["/static/fontello.1588947937982.css","/static/font/fontello.1588947937982.eot","/static/font/fontello.1588947937982.svg","/static/font/fontello.1588947937982.ttf","/static/font/fontello.1588947937982.woff","/static/font/fontello.1588947937982.woff2","/static/img/nsfw.74818f9.png","/static/css/app.613cef07981cd95ccceb.css","/static/js/app.996428ccaaaa7f28cb8d.js","/static/css/vendors~app.18fea621d430000acc27.css","/static/js/vendors~app.561a1c605d1dfb0e6f74.js","/static/js/2.18e4adec273c4ce867a8.js"]};
var serviceWorkerOption = {"assets":["/static/fontello.1589385935077.css","/static/font/fontello.1589385935077.eot","/static/font/fontello.1589385935077.svg","/static/font/fontello.1589385935077.ttf","/static/font/fontello.1589385935077.woff","/static/font/fontello.1589385935077.woff2","/static/img/nsfw.74818f9.png","/static/css/app.613cef07981cd95ccceb.css","/static/js/app.838ffa9aecf210c7d744.js","/static/css/vendors~app.18fea621d430000acc27.css","/static/js/vendors~app.561a1c605d1dfb0e6f74.js","/static/js/2.18e4adec273c4ce867a8.js"]};
!function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="/",t(t.s=1)}([function(e,n){
/*!

View file

@ -476,6 +476,14 @@ test "simple keyword" do
assert ConfigDB.from_binary(binary) == [key: "value"]
end
test "keyword with partial_chain key" do
binary =
ConfigDB.transform([%{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]}])
assert binary == :erlang.term_to_binary(partial_chain: &:hackney_connect.partial_chain/1)
assert ConfigDB.from_binary(binary) == [partial_chain: &:hackney_connect.partial_chain/1]
end
test "keyword" do
binary =
ConfigDB.transform([

View file

@ -11,6 +11,7 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do
alias Pleroma.User
import ExUnit.CaptureLog
import Pleroma.Factory
setup %{conn: conn} do
user = %User{
@ -50,16 +51,41 @@ test "with a correct password in the credentials, " <>
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
end
test "with a wrong password in the credentials, it does nothing", %{conn: conn} do
test "with a bcrypt hash, it updates to a pkbdf2 hash", %{conn: conn} do
user = insert(:user, password_hash: Bcrypt.hash_pwd_salt("123"))
assert "$2" <> _ = user.password_hash
conn =
conn
|> assign(:auth_credentials, %{password: "wrong"})
ret_conn =
conn
|> assign(:auth_user, user)
|> assign(:auth_credentials, %{password: "123"})
|> AuthenticationPlug.call(%{})
assert conn == ret_conn
assert conn.assigns.user.id == conn.assigns.auth_user.id
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
user = User.get_by_id(user.id)
assert "$pbkdf2" <> _ = user.password_hash
end
test "with a crypt hash, it updates to a pkbdf2 hash", %{conn: conn} do
user =
insert(:user,
password_hash:
"$6$9psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"
)
conn =
conn
|> assign(:auth_user, user)
|> assign(:auth_credentials, %{password: "password"})
|> AuthenticationPlug.call(%{})
assert conn.assigns.user.id == conn.assigns.auth_user.id
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
user = User.get_by_id(user.id)
assert "$pbkdf2" <> _ = user.password_hash
end
describe "checkpw/2" do
@ -79,6 +105,13 @@ test "check sha512-crypt hash" do
assert AuthenticationPlug.checkpw("password", hash)
end
test "check bcrypt hash" do
hash = "$2a$10$uyhC/R/zoE1ndwwCtMusK.TLVzkQ/Ugsbqp3uXI.CTTz0gBw.24jS"
assert AuthenticationPlug.checkpw("password", hash)
refute AuthenticationPlug.checkpw("password1", hash)
end
test "it returns false when hash invalid" do
hash =
"psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"

View file

@ -951,7 +951,7 @@ test "copies the file to the configured folder" do
test "works with base64 encoded images" do
file = %{
"img" => data_uri()
img: data_uri()
}
{:ok, %Object{}} = ActivityPub.upload(file)

View file

@ -2509,6 +2509,7 @@ test "common config example", %{conn: conn} do
%{"tuple" => [":seconds_valid", 60]},
%{"tuple" => [":path", ""]},
%{"tuple" => [":key1", nil]},
%{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
%{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
%{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
%{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
@ -2532,6 +2533,7 @@ test "common config example", %{conn: conn} do
%{"tuple" => [":seconds_valid", 60]},
%{"tuple" => [":path", ""]},
%{"tuple" => [":key1", nil]},
%{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
%{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
%{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
%{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
@ -2544,6 +2546,7 @@ test "common config example", %{conn: conn} do
":seconds_valid",
":path",
":key1",
":partial_chain",
":regex1",
":regex2",
":regex3",
@ -2940,6 +2943,33 @@ test "proxy tuple ip", %{conn: conn} do
assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value
assert ":proxy_url" in db
end
test "doesn't set keys not in the whitelist", %{conn: conn} do
clear_config(:database_config_whitelist, [
{:pleroma, :key1},
{:pleroma, :key2},
{:pleroma, Pleroma.Captcha.NotReal},
{:not_real}
])
post(conn, "/api/pleroma/admin/config", %{
configs: [
%{group: ":pleroma", key: ":key1", value: "value1"},
%{group: ":pleroma", key: ":key2", value: "value2"},
%{group: ":pleroma", key: ":key3", value: "value3"},
%{group: ":pleroma", key: "Pleroma.Web.Endpoint.NotReal", value: "value4"},
%{group: ":pleroma", key: "Pleroma.Captcha.NotReal", value: "value5"},
%{group: ":not_real", key: ":anything", value: "value6"}
]
})
assert Application.get_env(:pleroma, :key1) == "value1"
assert Application.get_env(:pleroma, :key2) == "value2"
assert Application.get_env(:pleroma, :key3) == nil
assert Application.get_env(:pleroma, Pleroma.Web.Endpoint.NotReal) == nil
assert Application.get_env(:pleroma, Pleroma.Captcha.NotReal) == "value5"
assert Application.get_env(:not_real, :anything) == "value6"
end
end
describe "GET /api/pleroma/admin/restart" do
@ -3571,19 +3601,54 @@ test "it deletes the note", %{conn: conn, report_id: report_id} do
end
end
test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
admin = insert(:user, is_admin: true)
describe "GET /api/pleroma/admin/config/descriptions" do
test "structure", %{conn: conn} do
admin = insert(:user, is_admin: true)
conn =
assign(conn, :user, admin)
|> get("/api/pleroma/admin/config/descriptions")
conn =
assign(conn, :user, admin)
|> get("/api/pleroma/admin/config/descriptions")
assert [child | _others] = json_response(conn, 200)
assert [child | _others] = json_response(conn, 200)
assert child["children"]
assert child["key"]
assert String.starts_with?(child["group"], ":")
assert child["description"]
assert child["children"]
assert child["key"]
assert String.starts_with?(child["group"], ":")
assert child["description"]
end
test "filters by database configuration whitelist", %{conn: conn} do
clear_config(:database_config_whitelist, [
{:pleroma, :instance},
{:pleroma, :activitypub},
{:pleroma, Pleroma.Upload},
{:esshd}
])
admin = insert(:user, is_admin: true)
conn =
assign(conn, :user, admin)
|> get("/api/pleroma/admin/config/descriptions")
children = json_response(conn, 200)
assert length(children) == 4
assert Enum.count(children, fn c -> c["group"] == ":pleroma" end) == 3
instance = Enum.find(children, fn c -> c["key"] == ":instance" end)
assert instance["children"]
activitypub = Enum.find(children, fn c -> c["key"] == ":activitypub" end)
assert activitypub["children"]
web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end)
assert web_endpoint["children"]
esshd = Enum.find(children, fn c -> c["group"] == ":esshd" end)
assert esshd["children"]
end
end
describe "/api/pleroma/admin/stats" do

View file

@ -15,11 +15,16 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticatorTest do
{:ok, [user: user, name: name, password: password]}
end
test "get_user/authorization", %{user: user, name: name, password: password} do
test "get_user/authorization", %{name: name, password: password} do
name = name <> "1"
user = insert(:user, nickname: name, password_hash: Bcrypt.hash_pwd_salt(password))
params = %{"authorization" => %{"name" => name, "password" => password}}
res = PleromaAuthenticator.get_user(%Plug.Conn{params: params})
assert {:ok, user} == res
assert {:ok, returned_user} = res
assert returned_user.id == user.id
assert "$pbkdf2" <> _ = returned_user.password_hash
end
test "get_user/authorization with invalid password", %{name: name} do

View file

@ -23,6 +23,18 @@ defmodule Pleroma.Web.CommonAPITest do
setup do: clear_config([:instance, :limit])
setup do: clear_config([:instance, :max_pinned_statuses])
describe "unblocking" do
test "it works even without an existing block activity" do
blocked = insert(:user)
blocker = insert(:user)
User.block(blocker, blocked)
assert User.blocks?(blocker, blocked)
assert {:ok, :no_activity} == CommonAPI.unblock(blocker, blocked)
refute User.blocks?(blocker, blocked)
end
end
describe "deletion" do
test "it works with pruned objects" do
user = insert(:user)

View file

@ -11,7 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
setup do: oauth_access(["write:media"])
describe "media upload" do
describe "Upload media" do
setup do
image = %Plug.Upload{
content_type: "image/jpg",
@ -25,13 +25,14 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
setup do: clear_config([:media_proxy])
setup do: clear_config([Pleroma.Upload])
test "returns uploaded image", %{conn: conn, image: image} do
test "/api/v1/media", %{conn: conn, image: image} do
desc = "Description of the image"
media =
conn
|> put_req_header("content-type", "multipart/form-data")
|> post("/api/v1/media", %{"file" => image, "description" => desc})
|> json_response(:ok)
|> json_response_and_validate_schema(:ok)
assert media["type"] == "image"
assert media["description"] == desc
@ -40,9 +41,32 @@ test "returns uploaded image", %{conn: conn, image: image} do
object = Object.get_by_id(media["id"])
assert object.data["actor"] == User.ap_id(conn.assigns[:user])
end
test "/api/v2/media", %{conn: conn, image: image} do
desc = "Description of the image"
response =
conn
|> put_req_header("content-type", "multipart/form-data")
|> post("/api/v2/media", %{"file" => image, "description" => desc})
|> json_response_and_validate_schema(202)
assert media_id = response["id"]
media =
conn
|> get("/api/v1/media/#{media_id}")
|> json_response_and_validate_schema(200)
assert media["type"] == "image"
assert media["description"] == desc
assert media["id"]
object = Object.get_by_id(media["id"])
assert object.data["actor"] == User.ap_id(conn.assigns[:user])
end
end
describe "PUT /api/v1/media/:id" do
describe "Update media description" do
setup %{user: actor} do
file = %Plug.Upload{
content_type: "image/jpg",
@ -60,23 +84,45 @@ test "returns uploaded image", %{conn: conn, image: image} do
[object: object]
end
test "updates name of media", %{conn: conn, object: object} do
test "/api/v1/media/:id good request", %{conn: conn, object: object} do
media =
conn
|> put_req_header("content-type", "multipart/form-data")
|> put("/api/v1/media/#{object.id}", %{"description" => "test-media"})
|> json_response(:ok)
|> json_response_and_validate_schema(:ok)
assert media["description"] == "test-media"
assert refresh_record(object).data["name"] == "test-media"
end
end
test "returns error when request is bad", %{conn: conn, object: object} do
describe "Get media by id" do
setup %{user: actor} do
file = %Plug.Upload{
content_type: "image/jpg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
{:ok, %Object{} = object} =
ActivityPub.upload(
file,
actor: User.ap_id(actor),
description: "test-media"
)
[object: object]
end
test "/api/v1/media/:id", %{conn: conn, object: object} do
media =
conn
|> put("/api/v1/media/#{object.id}", %{})
|> json_response(400)
|> get("/api/v1/media/#{object.id}")
|> json_response_and_validate_schema(:ok)
assert media == %{"error" => "bad_request"}
assert media["description"] == "test-media"
assert media["type"] == "image"
assert media["id"]
end
end
end

View file

@ -12,9 +12,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
import Pleroma.Factory
test "does NOT render account/pleroma/relationship if this is disabled by default" do
clear_config([:extensions, :output_relationships_in_statuses_by_default], false)
test "does NOT render account/pleroma/relationship by default" do
%{user: user, conn: conn} = oauth_access(["read:notifications"])
other_user = insert(:user)

View file

@ -1176,7 +1176,7 @@ test "replaces missing description with an empty string", %{conn: conn, user: us
end
test "bookmarks" do
bookmarks_uri = "/api/v1/bookmarks?with_relationships=true"
bookmarks_uri = "/api/v1/bookmarks"
%{conn: conn} = oauth_access(["write:bookmarks", "read:bookmarks"])
author = insert(:user)

View file

@ -20,12 +20,10 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
describe "home" do
setup do: oauth_access(["read:statuses"])
test "does NOT render account/pleroma/relationship if this is disabled by default", %{
test "does NOT embed account/pleroma/relationship in statuses", %{
user: user,
conn: conn
} do
clear_config([:extensions, :output_relationships_in_statuses_by_default], false)
other_user = insert(:user)
{:ok, _} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
@ -41,72 +39,6 @@ test "does NOT render account/pleroma/relationship if this is disabled by defaul
end)
end
test "the home timeline", %{user: user, conn: conn} do
uri = "/api/v1/timelines/home?with_relationships=1"
following = insert(:user, nickname: "followed")
third_user = insert(:user, nickname: "repeated")
{:ok, _activity} = CommonAPI.post(following, %{status: "post"})
{:ok, activity} = CommonAPI.post(third_user, %{status: "repeated post"})
{:ok, _, _} = CommonAPI.repeat(activity.id, following)
ret_conn = get(conn, uri)
assert Enum.empty?(json_response_and_validate_schema(ret_conn, :ok))
{:ok, _user} = User.follow(user, following)
ret_conn = get(conn, uri)
assert [
%{
"reblog" => %{
"content" => "repeated post",
"account" => %{
"pleroma" => %{
"relationship" => %{"following" => false, "followed_by" => false}
}
}
},
"account" => %{"pleroma" => %{"relationship" => %{"following" => true}}}
},
%{
"content" => "post",
"account" => %{
"acct" => "followed",
"pleroma" => %{"relationship" => %{"following" => true}}
}
}
] = json_response_and_validate_schema(ret_conn, :ok)
{:ok, _user} = User.follow(third_user, user)
ret_conn = get(conn, uri)
assert [
%{
"reblog" => %{
"content" => "repeated post",
"account" => %{
"acct" => "repeated",
"pleroma" => %{
"relationship" => %{"following" => false, "followed_by" => true}
}
}
},
"account" => %{"pleroma" => %{"relationship" => %{"following" => true}}}
},
%{
"content" => "post",
"account" => %{
"acct" => "followed",
"pleroma" => %{"relationship" => %{"following" => true}}
}
}
] = json_response_and_validate_schema(ret_conn, :ok)
end
test "the home timeline when the direct messages are excluded", %{user: user, conn: conn} do
{:ok, public_activity} = CommonAPI.post(user, %{status: ".", visibility: "public"})
{:ok, direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})

View file

@ -302,82 +302,6 @@ test "represent a relationship for the user with a pending follow request" do
end
end
test "represent an embedded relationship" do
user =
insert(:user, %{
follower_count: 0,
note_count: 5,
actor_type: "Service",
nickname: "shp@shitposter.club",
inserted_at: ~N[2017-08-15 15:47:06.597036]
})
other_user = insert(:user)
{:ok, other_user} = User.follow(other_user, user)
{:ok, _user_relationship} = User.block(other_user, user)
{:ok, _} = User.follow(insert(:user), user)
expected = %{
id: to_string(user.id),
username: "shp",
acct: user.nickname,
display_name: user.name,
locked: false,
created_at: "2017-08-15T15:47:06.000Z",
followers_count: 1,
following_count: 0,
statuses_count: 5,
note: user.bio,
url: user.ap_id,
avatar: "http://localhost:4001/images/avi.png",
avatar_static: "http://localhost:4001/images/avi.png",
header: "http://localhost:4001/images/banner.png",
header_static: "http://localhost:4001/images/banner.png",
emojis: [],
fields: [],
bot: true,
source: %{
note: user.bio,
sensitive: false,
pleroma: %{
actor_type: "Service",
discoverable: false
},
fields: []
},
pleroma: %{
background_image: nil,
confirmation_pending: false,
tags: [],
is_admin: false,
is_moderator: false,
hide_favorites: true,
hide_followers: false,
hide_follows: false,
hide_followers_count: false,
hide_follows_count: false,
relationship: %{
id: to_string(user.id),
following: false,
followed_by: false,
blocking: true,
blocked_by: false,
subscribing: false,
muting: false,
muting_notifications: false,
requested: false,
domain_blocking: false,
showing_reblogs: true,
endorsed: false
},
skip_thread_containment: false
}
}
assert expected ==
AccountView.render("show.json", %{user: refresh_record(user), for: other_user})
end
test "returns the settings store if the requesting user is the represented user and it's requested specifically" do
user = insert(:user, pleroma_settings_store: %{fe: "test"})

View file

@ -42,7 +42,11 @@ test "Mention notification" do
id: to_string(notification.id),
pleroma: %{is_seen: false},
type: "mention",
account: AccountView.render("show.json", %{user: user, for: mentioned_user}),
account:
AccountView.render("show.json", %{
user: user,
for: mentioned_user
}),
status: StatusView.render("show.json", %{activity: activity, for: mentioned_user}),
created_at: Utils.to_masto_date(notification.inserted_at)
}

View file

@ -576,7 +576,7 @@ test "a rich media card with all relevant data renders correctly" do
end
end
test "embeds a relationship in the account" do
test "does not embed a relationship in the account" do
user = insert(:user)
other_user = insert(:user)
@ -587,13 +587,11 @@ test "embeds a relationship in the account" do
result = StatusView.render("show.json", %{activity: activity, for: other_user})
assert result[:account][:pleroma][:relationship] ==
AccountView.render("relationship.json", %{user: other_user, target: user})
assert result[:account][:pleroma][:relationship] == %{}
assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec())
end
test "embeds a relationship in the account in reposts" do
test "does not embed a relationship in the account in reposts" do
user = insert(:user)
other_user = insert(:user)
@ -606,12 +604,8 @@ test "embeds a relationship in the account in reposts" do
result = StatusView.render("show.json", %{activity: activity, for: user})
assert result[:account][:pleroma][:relationship] ==
AccountView.render("relationship.json", %{user: user, target: other_user})
assert result[:reblog][:account][:pleroma][:relationship] ==
AccountView.render("relationship.json", %{user: user, target: user})
assert result[:account][:pleroma][:relationship] == %{}
assert result[:reblog][:account][:pleroma][:relationship] == %{}
assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec())
end

View file

@ -31,8 +31,28 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
test "resend account confirmation email", %{conn: conn, user: user} do
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}")
|> json_response(:no_content)
|> json_response_and_validate_schema(:no_content)
ObanHelpers.perform_all()
email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
notify_email = Config.get([:instance, :notify_email])
instance_name = Config.get([:instance, :name])
assert_email_sent(
from: {instance_name, notify_email},
to: {user.name, user.email},
html_body: email.html_body
)
end
test "resend account confirmation email (with nickname)", %{conn: conn, user: user} do
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/pleroma/accounts/confirmation_resend?nickname=#{user.nickname}")
|> json_response_and_validate_schema(:no_content)
ObanHelpers.perform_all()
@ -54,7 +74,10 @@ test "resend account confirmation email", %{conn: conn, user: user} do
test "user avatar can be set", %{user: user, conn: conn} do
avatar_image = File.read!("test/fixtures/avatar_data_uri")
conn = patch(conn, "/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image})
conn =
conn
|> put_req_header("content-type", "multipart/form-data")
|> patch("/api/v1/pleroma/accounts/update_avatar", %{img: avatar_image})
user = refresh_record(user)
@ -70,17 +93,20 @@ test "user avatar can be set", %{user: user, conn: conn} do
]
} = user.avatar
assert %{"url" => _} = json_response(conn, 200)
assert %{"url" => _} = json_response_and_validate_schema(conn, 200)
end
test "user avatar can be reset", %{user: user, conn: conn} do
conn = patch(conn, "/api/v1/pleroma/accounts/update_avatar", %{img: ""})
conn =
conn
|> put_req_header("content-type", "multipart/form-data")
|> patch("/api/v1/pleroma/accounts/update_avatar", %{img: ""})
user = User.get_cached_by_id(user.id)
assert user.avatar == nil
assert %{"url" => nil} = json_response(conn, 200)
assert %{"url" => nil} = json_response_and_validate_schema(conn, 200)
end
end
@ -88,21 +114,27 @@ test "user avatar can be reset", %{user: user, conn: conn} do
setup do: oauth_access(["write:accounts"])
test "can set profile banner", %{user: user, conn: conn} do
conn = patch(conn, "/api/v1/pleroma/accounts/update_banner", %{"banner" => @image})
conn =
conn
|> put_req_header("content-type", "multipart/form-data")
|> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => @image})
user = refresh_record(user)
assert user.banner["type"] == "Image"
assert %{"url" => _} = json_response(conn, 200)
assert %{"url" => _} = json_response_and_validate_schema(conn, 200)
end
test "can reset profile banner", %{user: user, conn: conn} do
conn = patch(conn, "/api/v1/pleroma/accounts/update_banner", %{"banner" => ""})
conn =
conn
|> put_req_header("content-type", "multipart/form-data")
|> patch("/api/v1/pleroma/accounts/update_banner", %{"banner" => ""})
user = refresh_record(user)
assert user.banner == %{}
assert %{"url" => nil} = json_response(conn, 200)
assert %{"url" => nil} = json_response_and_validate_schema(conn, 200)
end
end
@ -110,19 +142,26 @@ test "can reset profile banner", %{user: user, conn: conn} do
setup do: oauth_access(["write:accounts"])
test "background image can be set", %{user: user, conn: conn} do
conn = patch(conn, "/api/v1/pleroma/accounts/update_background", %{"img" => @image})
conn =
conn
|> put_req_header("content-type", "multipart/form-data")
|> patch("/api/v1/pleroma/accounts/update_background", %{"img" => @image})
user = refresh_record(user)
assert user.background["type"] == "Image"
assert %{"url" => _} = json_response(conn, 200)
# assert %{"url" => _} = json_response(conn, 200)
assert %{"url" => _} = json_response_and_validate_schema(conn, 200)
end
test "background image can be reset", %{user: user, conn: conn} do
conn = patch(conn, "/api/v1/pleroma/accounts/update_background", %{"img" => ""})
conn =
conn
|> put_req_header("content-type", "multipart/form-data")
|> patch("/api/v1/pleroma/accounts/update_background", %{"img" => ""})
user = refresh_record(user)
assert user.background == %{}
assert %{"url" => nil} = json_response(conn, 200)
assert %{"url" => nil} = json_response_and_validate_schema(conn, 200)
end
end
@ -143,7 +182,7 @@ test "returns list of statuses favorited by specified user", %{
response =
conn
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
|> json_response(:ok)
|> json_response_and_validate_schema(:ok)
[like] = response
@ -160,7 +199,7 @@ test "returns favorites for specified user_id when requester is not logged in",
response =
build_conn()
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
|> json_response(200)
|> json_response_and_validate_schema(200)
assert length(response) == 1
end
@ -183,7 +222,7 @@ test "returns favorited DM only when user is logged in and he is one of recipien
|> assign(:user, u)
|> assign(:token, insert(:oauth_token, user: u, scopes: ["read:favourites"]))
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
|> json_response(:ok)
|> json_response_and_validate_schema(:ok)
assert length(response) == 1
end
@ -191,7 +230,7 @@ test "returns favorited DM only when user is logged in and he is one of recipien
response =
build_conn()
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
|> json_response(200)
|> json_response_and_validate_schema(200)
assert length(response) == 0
end
@ -213,7 +252,7 @@ test "does not return others' favorited DM when user is not one of recipients",
response =
conn
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
|> json_response(:ok)
|> json_response_and_validate_schema(:ok)
assert Enum.empty?(response)
end
@ -233,11 +272,12 @@ test "paginates favorites using since_id and max_id", %{
response =
conn
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
since_id: third_activity.id,
max_id: seventh_activity.id
})
|> json_response(:ok)
|> get(
"/api/v1/pleroma/accounts/#{user.id}/favourites?since_id=#{third_activity.id}&max_id=#{
seventh_activity.id
}"
)
|> json_response_and_validate_schema(:ok)
assert length(response) == 3
refute third_activity in response
@ -256,8 +296,8 @@ test "limits favorites using limit parameter", %{
response =
conn
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
|> json_response(:ok)
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites?limit=3")
|> json_response_and_validate_schema(:ok)
assert length(response) == 3
end
@ -269,7 +309,7 @@ test "returns empty response when user does not have any favorited statuses", %{
response =
conn
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
|> json_response(:ok)
|> json_response_and_validate_schema(:ok)
assert Enum.empty?(response)
end
@ -277,7 +317,7 @@ test "returns empty response when user does not have any favorited statuses", %{
test "returns 404 error when specified user is not exist", %{conn: conn} do
conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
assert json_response(conn, 404) == %{"error" => "Record not found"}
assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"}
end
test "returns 403 error when user has hidden own favorites", %{conn: conn} do
@ -287,7 +327,7 @@ test "returns 403 error when user has hidden own favorites", %{conn: conn} do
conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/favourites")
assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
assert json_response_and_validate_schema(conn, 403) == %{"error" => "Can't get favorites"}
end
test "hides favorites for new users by default", %{conn: conn} do
@ -298,7 +338,7 @@ test "hides favorites for new users by default", %{conn: conn} do
assert user.hide_favorites
conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/favourites")
assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
assert json_response_and_validate_schema(conn, 403) == %{"error" => "Can't get favorites"}
end
end
@ -312,11 +352,12 @@ test "subscribing / unsubscribing to a user" do
|> assign(:user, user)
|> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
assert %{"id" => _id, "subscribing" => true} = json_response(ret_conn, 200)
assert %{"id" => _id, "subscribing" => true} =
json_response_and_validate_schema(ret_conn, 200)
conn = post(conn, "/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
assert %{"id" => _id, "subscribing" => false} = json_response_and_validate_schema(conn, 200)
end
end
@ -326,7 +367,7 @@ test "returns 404 when subscription_target not found" do
conn = post(conn, "/api/v1/pleroma/accounts/target_id/subscribe")
assert %{"error" => "Record not found"} = json_response(conn, 404)
assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn, 404)
end
end
@ -336,7 +377,7 @@ test "returns 404 when subscription_target not found" do
conn = post(conn, "/api/v1/pleroma/accounts/target_id/unsubscribe")
assert %{"error" => "Record not found"} = json_response(conn, 404)
assert %{"error" => "Record not found"} = json_response_and_validate_schema(conn, 404)
end
end
end