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:api/v1/notifications:include_types_filter` to the `features` list.
- NodeInfo: `pleroma_emoji_reactions` 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: `: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. - 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. - Mix task to create trusted OAuth App.
- Notifications: Added `follow_request` notification type. - Notifications: Added `follow_request` notification type.

View file

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

View file

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

View file

@ -679,15 +679,6 @@
7 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, key: :allow_relay,
type: :boolean, type: :boolean,
@ -1105,32 +1096,97 @@
description: "Settings for Pleroma FE", description: "Settings for Pleroma FE",
suggestions: [ 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, 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", logoMargin: ".1em",
stickers: false, logoMask: true,
enableEmojiPicker: false 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: [ 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, type: :string,
description: "Which theme to use, they are defined in styles.json", description:
suggestions: ["pleroma-dark"] "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, key: :logo,
@ -1139,11 +1195,44 @@
suggestions: ["/static/logo.png"] suggestions: ["/static/logo.png"]
}, },
%{ %{
key: :background, key: :logoMargin,
label: "Logo margin",
type: :string, type: :string,
description: description:
"URL of the background, unless viewing a user profile with a background that is set", "Allows you to adjust vertical margins between logo boundary and navbar borders. " <>
suggestions: ["/images/city.jpg"] "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, key: :redirectRootNoLogin,
@ -1161,51 +1250,25 @@
"Relative URL which indicates where to redirect when a user is logged in", "Relative URL which indicates where to redirect when a user is logged in",
suggestions: ["/main/friends"] 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, key: :scopeCopy,
label: "Scope copy", label: "Scope copy",
type: :boolean, type: :boolean,
description: "Copy the scope (private/unlisted/public) in replies to posts by default" 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, key: :subjectLineBehavior,
label: "Subject line behavior", label: "Subject line behavior",
@ -1217,38 +1280,10 @@
suggestions: ["email", "masto", "noop"] suggestions: ["email", "masto", "noop"]
}, },
%{ %{
key: :alwaysShowSubjectInput, key: :theme,
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",
type: :string, type: :string,
description: description: "Which theme to use. Available themes are defined in styles.json",
"Allows you to adjust vertical margins between logo boundary and navbar borders. " <> suggestions: ["pleroma-dark"]
"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."
} }
] ]
}, },
@ -1858,12 +1893,6 @@
(see https://github.com/sorentwo/oban/issues/52). (see https://github.com/sorentwo/oban/issues/52).
""", """,
children: [ children: [
%{
key: :repo,
type: :module,
description: "Application's Ecto repo",
suggestions: [Pleroma.Repo]
},
%{ %{
key: :verbose, key: :verbose,
type: {:dropdown, :atom}, 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, group: :pleroma,
key: :http, 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. 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 ### Multi-factor authentication - :two_factor_authentication
* `totp` - a list containing TOTP configuration * `totp` - a list containing TOTP configuration

View file

@ -1,21 +1,45 @@
#!/sbin/openrc-run #!/sbin/openrc-run
supervisor=supervise-daemon
# Requires OpenRC >= 0.35
directory=/opt/pleroma
command=/usr/bin/mix
command_args="phx.server"
command_user=pleroma:pleroma command_user=pleroma:pleroma
command_background=1 command_background=1
export PORT=4000
export MIX_ENV=prod
# Ask process to terminate within 30 seconds, otherwise kill it # Ask process to terminate within 30 seconds, otherwise kill it
retry="SIGTERM/30/SIGKILL/5" retry="SIGTERM/30/SIGKILL/5"
pidfile="/var/run/pleroma.pid" 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() { 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", %{ Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{
activities: activities, activities: activities,
for: user, for: user,
as: :activity, as: :activity
skip_relationships: true
}) })
end end
}, },

View file

@ -1,5 +1,6 @@
defmodule Mix.Tasks.Pleroma.Digest do defmodule Mix.Tasks.Pleroma.Digest do
use Mix.Task use Mix.Task
import Mix.Pleroma
@shortdoc "Manages digest emails" @shortdoc "Manages digest emails"
@moduledoc File.read!("docs/administration/CLI_tasks/digest.md") @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 with %Swoosh.Email{} = email <- Pleroma.Emails.UserEmail.digest_email(patched_user) do
{:ok, _} = Pleroma.Emails.Mailer.deliver(email) {: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 else
_ -> _ ->
Mix.shell().info( shell_info("Cound't find any mentions for #{nickname} since #{last_digest_emailed_at}")
"Cound't find any mentions for #{nickname} since #{last_digest_emailed_at}"
)
end end
end end
end end

View file

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

View file

@ -278,6 +278,8 @@ defp do_convert({:proxy_url, {type, host, port}}) do
} }
end end
defp do_convert({:partial_chain, entity}), do: %{"tuple" => [":partial_chain", inspect(entity)]}
defp do_convert(entity) when is_tuple(entity) do defp do_convert(entity) when is_tuple(entity) do
value = value =
entity 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}} {:proxy_url, {do_transform_string(type), parse_host(host), port}}
end 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 defp do_transform(%{"tuple" => entity}) do
Enum.reduce(entity, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end) Enum.reduce(entity, {}, fn val, acc -> Tuple.append(acc, do_transform(val)) end)
end end

View file

@ -17,7 +17,8 @@ defmodule Pleroma.Constants do
"announcement_count", "announcement_count",
"emoji", "emoji",
"context_id", "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 with config <- Pleroma.Config.Loader.read("config/description.exs") do
config[:pleroma][:config_description] config[:pleroma][:config_description]
|> Pleroma.Docs.Generator.convert_to_strings() |> Pleroma.Docs.Generator.convert_to_strings()
|> Jason.encode!()
end end
end end
end end

View file

@ -16,6 +16,11 @@ def checkpw(password, "$6" <> _ = password_hash) do
:crypt.crypt(password, password_hash) == password_hash :crypt.crypt(password, password_hash) == password_hash
end 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 def checkpw(password, "$pbkdf2" <> _ = password_hash) do
Pbkdf2.verify_pass(password, password_hash) Pbkdf2.verify_pass(password, password_hash)
end end
@ -25,6 +30,25 @@ def checkpw(_password, _password_hash) do
false false
end 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(%{assigns: %{user: %User{}}} = conn, _), do: conn
def call( def call(
@ -36,7 +60,9 @@ def call(
} = conn, } = conn,
_ _
) do ) 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 conn
|> assign(:user, auth_user) |> assign(:user, auth_user)
|> OAuthScopesPlug.skip_plug() |> OAuthScopesPlug.skip_plug()

View file

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

View file

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

View file

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

View file

@ -6,7 +6,9 @@ defmodule Pleroma.Web.AdminAPI.AccountView do
use Pleroma.Web, :view use Pleroma.Web, :view
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.AdminAPI
alias Pleroma.Web.AdminAPI.AccountView alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.MastodonAPI
alias Pleroma.Web.MediaProxy alias Pleroma.Web.MediaProxy
def render("index.json", %{users: users, count: count, page_size: page_size}) do 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 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([]), do: ""
defp parse_error(errors) do defp parse_error(errors) do

View file

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

View file

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

View file

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

View file

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

View file

@ -105,7 +105,11 @@ defp create_request do
description: "Space separated list of scopes", description: "Space separated list of scopes",
default: "read" 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], required: [:client_name, :redirect_uris],
example: %{ 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." "Array of enumerable strings `home`, `notifications`, `public`, `thread`. At least one context must be specified."
}, },
irreversible: %Schema{ irreversible: %Schema{
type: :bolean, type: :boolean,
nullable: true,
description: description:
"Should the server irreversibly drop matching entities from home and notifications?" "Should the server irreversibly drop matching entities from home and notifications?"
}, },
whole_word: %Schema{ whole_word: %Schema{
type: :bolean, type: :boolean,
nullable: true,
description: "Consider word boundaries?", description: "Consider word boundaries?",
default: true default: true
} }

View file

@ -110,14 +110,16 @@ defp upsert_request do
properties: %{ properties: %{
notifications: %Schema{ notifications: %Schema{
type: :object, type: :object,
nullable: true,
properties: %{ properties: %{
last_read_id: %Schema{type: :string} last_read_id: %Schema{nullable: true, type: :string}
} }
}, },
home: %Schema{ home: %Schema{
type: :object, type: :object,
nullable: true,
properties: %{ 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"}, account_id: %Schema{type: :string, description: "ID of the account to report"},
status_ids: %Schema{ status_ids: %Schema{
type: :array, type: :array,
nullable: true,
items: %Schema{type: :string}, items: %Schema{type: :string},
description: "Array of Statuses to attach to the report, for context" description: "Array of Statuses to attach to the report, for context"
}, },
comment: %Schema{ comment: %Schema{
type: :string, type: :string,
nullable: true,
description: "Reason for the report" description: "Reason for the report"
}, },
forward: %Schema{ forward: %Schema{
type: :boolean, type: :boolean,
nullable: true,
default: false, default: false,
description: description:
"If the account is remote, should the report be forwarded to the remote admin?" "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, []) apply(__MODULE__, operation, [])
end end
# Note: `with_relationships` param is not supported (PleromaFE uses this op for autocomplete)
def account_search_operation do def account_search_operation do
%Operation{ %Operation{
tags: ["Search"], tags: ["Search"],
@ -96,8 +97,8 @@ def search_operation do
:query, :query,
%Schema{type: :integer}, %Schema{type: :integer},
"Offset" "Offset"
) ),
| pagination_params() with_relationships_param() | pagination_params()
], ],
responses: %{ responses: %{
200 => Operation.response("Results", "application/json", results()) 200 => Operation.response("Results", "application/json", results())
@ -138,8 +139,8 @@ def search2_operation do
:query, :query,
%Schema{allOf: [BooleanLike], default: false}, %Schema{allOf: [BooleanLike], default: false},
"Only include accounts that the user is following" "Only include accounts that the user is following"
) ),
| pagination_params() with_relationships_param() | pagination_params()
], ],
responses: %{ responses: %{
200 => Operation.response("Results", "application/json", results2()) 200 => Operation.response("Results", "application/json", results2())

View file

@ -7,7 +7,6 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
alias OpenApiSpex.Schema alias OpenApiSpex.Schema
alias Pleroma.Web.ApiSpec.AccountOperation alias Pleroma.Web.ApiSpec.AccountOperation
alias Pleroma.Web.ApiSpec.Schemas.ApiError alias Pleroma.Web.ApiSpec.Schemas.ApiError
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
alias Pleroma.Web.ApiSpec.Schemas.FlakeID alias Pleroma.Web.ApiSpec.Schemas.FlakeID
alias Pleroma.Web.ApiSpec.Schemas.ScheduledStatus alias Pleroma.Web.ApiSpec.Schemas.ScheduledStatus
alias Pleroma.Web.ApiSpec.Schemas.Status alias Pleroma.Web.ApiSpec.Schemas.Status
@ -349,10 +348,7 @@ def bookmarks_operation do
summary: "Bookmarked statuses", summary: "Bookmarked statuses",
description: "Statuses the user has bookmarked", description: "Statuses the user has bookmarked",
operationId: "StatusController.bookmarks", operationId: "StatusController.bookmarks",
parameters: [ parameters: pagination_params(),
Operation.parameter(:with_relationships, :query, BooleanLike, "Include relationships")
| pagination_params()
],
security: [%{"oAuth" => ["read:bookmarks"]}], security: [%{"oAuth" => ["read:bookmarks"]}],
responses: %{ responses: %{
200 => Operation.response("Array of Statuses", "application/json", array_of_statuses()) 200 => Operation.response("Array of Statuses", "application/json", array_of_statuses())
@ -360,7 +356,7 @@ def bookmarks_operation do
} }
end end
defp array_of_statuses do def array_of_statuses do
%Schema{type: :array, items: Status, example: [Status.schema().example]} %Schema{type: :array, items: Status, example: [Status.schema().example]}
end end
@ -371,15 +367,18 @@ defp create_request do
properties: %{ properties: %{
status: %Schema{ status: %Schema{
type: :string, type: :string,
nullable: true,
description: description:
"Text content of the status. If `media_ids` is provided, this becomes optional. Attaching a `poll` is optional while `status` is provided." "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{ media_ids: %Schema{
nullable: true,
type: :array, type: :array,
items: %Schema{type: :string}, items: %Schema{type: :string},
description: "Array of Attachment ids to be attached as media." description: "Array of Attachment ids to be attached as media."
}, },
poll: %Schema{ poll: %Schema{
nullable: true,
type: :object, type: :object,
required: [:options], required: [:options],
properties: %{ properties: %{
@ -390,26 +389,35 @@ defp create_request do
}, },
expires_in: %Schema{ expires_in: %Schema{
type: :integer, type: :integer,
nullable: true,
description: description:
"Duration the poll should be open, in seconds. Must be provided with `poll[options]`" "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{ hide_totals: %Schema{
type: :boolean, type: :boolean,
nullable: true,
description: "Hide vote counts until the poll ends?" description: "Hide vote counts until the poll ends?"
} }
} }
}, },
in_reply_to_id: %Schema{ in_reply_to_id: %Schema{
nullable: true,
allOf: [FlakeID], allOf: [FlakeID],
description: "ID of the status being replied to, if status is a reply" description: "ID of the status being replied to, if status is a reply"
}, },
sensitive: %Schema{ sensitive: %Schema{
type: :boolean, type: :boolean,
nullable: true,
description: "Mark status and attached media as sensitive?" description: "Mark status and attached media as sensitive?"
}, },
spoiler_text: %Schema{ spoiler_text: %Schema{
type: :string, type: :string,
nullable: true,
description: description:
"Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field." "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: 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." "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: # Pleroma-specific properties:
preview: %Schema{ preview: %Schema{
type: :boolean, type: :boolean,
nullable: true,
description: 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" "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{ content_type: %Schema{
type: :string, type: :string,
nullable: true,
description: 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." "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{ to: %Schema{
type: :array, type: :array,
nullable: true,
items: %Schema{type: :string}, items: %Schema{type: :string},
description: 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" "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{ visibility: %Schema{
nullable: true,
anyOf: [ anyOf: [
VisibilityScope, VisibilityScope,
%Schema{type: :string, description: "`list:LIST_ID`", example: "LIST:123"} %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`" "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{ expires_in: %Schema{
nullable: true,
type: :integer, type: :integer,
description: 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." "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{ in_reply_to_conversation_id: %Schema{
nullable: true,
type: :string, type: :string,
description: 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`." "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] required: [:endpoint, :keys]
}, },
data: %Schema{ data: %Schema{
nullable: true,
type: :object, type: :object,
properties: %{ properties: %{
alerts: %Schema{ alerts: %Schema{
nullable: true,
type: :object, type: :object,
properties: %{ properties: %{
follow: %Schema{type: :boolean, description: "Receive follow notifications?"}, follow: %Schema{
type: :boolean,
nullable: true,
description: "Receive follow notifications?"
},
favourite: %Schema{ favourite: %Schema{
type: :boolean, type: :boolean,
nullable: true,
description: "Receive favourite notifications?" description: "Receive favourite notifications?"
}, },
reblog: %Schema{type: :boolean, description: "Receive reblog notifications?"}, reblog: %Schema{
mention: %Schema{type: :boolean, description: "Receive mention notifications?"}, type: :boolean,
poll: %Schema{type: :boolean, description: "Receive poll notifications?"} 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, type: :object,
properties: %{ properties: %{
data: %Schema{ data: %Schema{
nullable: true,
type: :object, type: :object,
properties: %{ properties: %{
alerts: %Schema{ alerts: %Schema{
nullable: true,
type: :object, type: :object,
properties: %{ properties: %{
follow: %Schema{type: :boolean, description: "Receive follow notifications?"}, follow: %Schema{
type: :boolean,
nullable: true,
description: "Receive follow notifications?"
},
favourite: %Schema{ favourite: %Schema{
type: :boolean, type: :boolean,
nullable: true,
description: "Receive favourite notifications?" description: "Receive favourite notifications?"
}, },
reblog: %Schema{type: :boolean, description: "Receive reblog notifications?"}, reblog: %Schema{
mention: %Schema{type: :boolean, description: "Receive mention notifications?"}, type: :boolean,
poll: %Schema{type: :boolean, description: "Receive poll notifications?"} 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(), local_param(),
with_muted_param(), with_muted_param(),
exclude_visibilities_param(), exclude_visibilities_param(),
reply_visibility_param(), reply_visibility_param() | pagination_params()
with_relationships_param() | pagination_params()
], ],
operationId: "TimelineController.home", operationId: "TimelineController.home",
responses: %{ responses: %{
@ -63,8 +62,7 @@ def public_operation do
only_media_param(), only_media_param(),
with_muted_param(), with_muted_param(),
exclude_visibilities_param(), exclude_visibilities_param(),
reply_visibility_param(), reply_visibility_param() | pagination_params()
with_relationships_param() | pagination_params()
], ],
operationId: "TimelineController.public", operationId: "TimelineController.public",
responses: %{ responses: %{
@ -109,8 +107,7 @@ def hashtag_operation do
local_param(), local_param(),
only_media_param(), only_media_param(),
with_muted_param(), with_muted_param(),
exclude_visibilities_param(), exclude_visibilities_param() | pagination_params()
with_relationships_param() | pagination_params()
], ],
operationId: "TimelineController.hashtag", operationId: "TimelineController.hashtag",
responses: %{ responses: %{
@ -134,8 +131,7 @@ def list_operation do
required: true required: true
), ),
with_muted_param(), with_muted_param(),
exclude_visibilities_param(), exclude_visibilities_param() | pagination_params()
with_relationships_param() | pagination_params()
], ],
operationId: "TimelineController.list", operationId: "TimelineController.list",
responses: %{ responses: %{
@ -153,10 +149,6 @@ defp array_of_statuses do
} }
end end
defp with_relationships_param do
Operation.parameter(:with_relationships, :query, BooleanLike, "Include relationships")
end
defp local_param do defp local_param do
Operation.parameter( Operation.parameter(
:local, :local,

View file

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

View file

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

View file

@ -5,6 +5,7 @@
defmodule Pleroma.Web.Auth.TOTPAuthenticator do defmodule Pleroma.Web.Auth.TOTPAuthenticator do
alias Pleroma.MFA alias Pleroma.MFA
alias Pleroma.MFA.TOTP alias Pleroma.MFA.TOTP
alias Pleroma.Plugs.AuthenticationPlug
alias Pleroma.User alias Pleroma.User
@doc "Verify code or check backup code." @doc "Verify code or check backup code."
@ -30,7 +31,7 @@ def verify_recovery_code(
code code
) )
when is_list(codes) and is_binary(code) do 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 if hash_code do
MFA.invalidate_backup_code(user, hash_code) 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 if String.length(text) in 1..Pleroma.Config.get([:instance, :chat_limit]) do
author = User.get_cached_by_nickname(user_name) author = User.get_cached_by_nickname(user_name)
author = Pleroma.Web.MastodonAPI.AccountView.render("show.json", user: author) author = Pleroma.Web.MastodonAPI.AccountView.render("show.json", user: author)
message = ChatChannelState.add_message(%{text: text, author: author}) message = ChatChannelState.add_message(%{text: text, author: author})
broadcast!(socket, "new_msg", message) broadcast!(socket, "new_msg", message)

View file

@ -25,10 +25,21 @@ defmodule Pleroma.Web.CommonAPI do
require Logger require Logger
def unblock(blocker, blocked) do 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_data, _} <- Builder.undo(blocker, block),
{:ok, unblock, _} <- Pipeline.common_pipeline(unblock_data, local: true) do {:ok, unblock, _} <- Pipeline.common_pipeline(unblock_data, local: true) do
{:ok, unblock} {: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
end end

View file

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

View file

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

View file

@ -11,17 +11,20 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
action_fallback(Pleroma.Web.MastodonAPI.FallbackController) action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
plug(Pleroma.Web.ApiSpec.CastAndValidate)
plug(:put_view, Pleroma.Web.MastodonAPI.StatusView) plug(:put_view, Pleroma.Web.MastodonAPI.StatusView)
plug(OAuthScopesPlug, %{scopes: ["write:media"]}) plug(OAuthScopesPlug, %{scopes: ["write:media"]})
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.MediaOperation
@doc "POST /api/v1/media" @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} <- with {:ok, object} <-
ActivityPub.upload( ActivityPub.upload(
file, file,
actor: User.ap_id(user), actor: User.ap_id(user),
description: Map.get(data, "description") description: Map.get(data, :description)
) do ) do
attachment_data = Map.put(object.data, "id", object.id) 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
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" @doc "PUT /api/v1/media/:id"
def update(%{assigns: %{user: user}} = conn, %{"id" => id, "description" => description}) def update(%{assigns: %{user: user}, body_params: %{description: description}} = conn, %{id: id}) do
when is_binary(description) do
with %Object{} = object <- Object.get_by_id(id), with %Object{} = object <- Object.get_by_id(id),
true <- Object.authorize_mutation(object, user), true <- Object.authorize_mutation(object, user),
{:ok, %Object{data: data}} <- Object.update_data(object, %{"name" => description}) do {: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
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 end

View file

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

View file

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

View file

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

View file

@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
use Pleroma.Web, :controller use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper, 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.Pagination
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
@ -63,8 +63,7 @@ def home(%{assigns: %{user: user}} = conn, params) do
|> render("index.json", |> render("index.json",
activities: activities, activities: activities,
for: user, for: user,
as: :activity, as: :activity
skip_relationships: skip_relationships?(params)
) )
end end
@ -88,8 +87,7 @@ def direct(%{assigns: %{user: user}} = conn, params) do
|> render("index.json", |> render("index.json",
activities: activities, activities: activities,
for: user, for: user,
as: :activity, as: :activity
skip_relationships: skip_relationships?(params)
) )
end end
@ -125,8 +123,7 @@ def public(%{assigns: %{user: user}} = conn, params) do
|> render("index.json", |> render("index.json",
activities: activities, activities: activities,
for: user, for: user,
as: :activity, as: :activity
skip_relationships: skip_relationships?(params)
) )
end end
end end
@ -173,8 +170,7 @@ def hashtag(%{assigns: %{user: user}} = conn, params) do
|> render("index.json", |> render("index.json",
activities: activities, activities: activities,
for: user, for: user,
as: :activity, as: :activity
skip_relationships: skip_relationships?(params)
) )
end end
@ -203,8 +199,7 @@ def list(%{assigns: %{user: user}} = conn, %{list_id: id} = params) do
render(conn, "index.json", render(conn, "index.json",
activities: activities, activities: activities,
for: user, for: user,
as: :activity, as: :activity
skip_relationships: skip_relationships?(params)
) )
else else
_e -> render_error(conn, :forbidden, "Error.") _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 def render("index.json", %{users: users} = opts) do
reading_user = opts[:for] reading_user = opts[:for]
# Note: :skip_relationships option is currently intentionally not supported for accounts
relationships_opt = relationships_opt =
cond do cond do
Map.has_key?(opts, :relationships) -> Map.has_key?(opts, :relationships) ->
opts[:relationships] opts[:relationships]
is_nil(reading_user) -> is_nil(reading_user) || !opts[:embed_relationships] ->
UserRelationship.view_relationships_option(nil, []) UserRelationship.view_relationships_option(nil, [])
true -> true ->
@ -193,14 +192,14 @@ defp do_render("show.json", %{user: user} = opts) do
end) end)
relationship = relationship =
if opts[:skip_relationships] do if opts[:embed_relationships] do
%{}
else
render("relationship.json", %{ render("relationship.json", %{
user: opts[:for], user: opts[:for],
target: user, target: user,
relationships: opts[:relationships] relationships: opts[:relationships]
}) })
else
%{}
end end
%{ %{

View file

@ -51,9 +51,7 @@ def render("index.json", %{notifications: notifications, for: reading_user} = op
|> Enum.filter(& &1) |> Enum.filter(& &1)
|> Kernel.++(move_activities_targets) |> Kernel.++(move_activities_targets)
UserRelationship.view_relationships_option(reading_user, actors, UserRelationship.view_relationships_option(reading_user, actors, subset: :source_mutes)
source_mutes_only: opts[:skip_relationships]
)
end end
opts = opts =
@ -83,15 +81,13 @@ def render(
mastodon_type = Activity.mastodon_notification_type(activity) mastodon_type = Activity.mastodon_notification_type(activity)
render_opts = %{ # Note: :relationships contain user mutes (needed for :muted flag in :status)
relationships: opts[:relationships], status_render_opts = %{relationships: opts[:relationships]}
skip_relationships: opts[:skip_relationships]
}
with %{id: _} = account <- with %{id: _} = account <-
AccountView.render( AccountView.render(
"show.json", "show.json",
Map.merge(render_opts, %{user: actor, for: reading_user}) %{user: actor, for: reading_user}
) do ) do
response = %{ response = %{
id: to_string(notification.id), id: to_string(notification.id),
@ -105,21 +101,20 @@ def render(
case mastodon_type do case mastodon_type do
"mention" -> "mention" ->
put_status(response, activity, reading_user, render_opts) put_status(response, activity, reading_user, status_render_opts)
"favourite" -> "favourite" ->
put_status(response, parent_activity_fn.(), reading_user, render_opts) put_status(response, parent_activity_fn.(), reading_user, status_render_opts)
"reblog" -> "reblog" ->
put_status(response, parent_activity_fn.(), reading_user, render_opts) put_status(response, parent_activity_fn.(), reading_user, status_render_opts)
"move" -> "move" ->
# Note: :skip_relationships option being applied to _account_ rendering (here) put_target(response, activity, reading_user, %{})
put_target(response, activity, reading_user, render_opts)
"pleroma:emoji_reaction" -> "pleroma:emoji_reaction" ->
response response
|> put_status(parent_activity_fn.(), reading_user, render_opts) |> put_status(parent_activity_fn.(), reading_user, status_render_opts)
|> put_emoji(activity) |> put_emoji(activity)
type when type in ["follow", "follow_request"] -> 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.map(&get_user(&1.data["actor"], false))
|> Enum.filter(& &1) |> Enum.filter(& &1)
UserRelationship.view_relationships_option(reading_user, actors, UserRelationship.view_relationships_option(reading_user, actors, subset: :source_mutes)
source_mutes_only: opts[:skip_relationships]
)
end end
opts = opts =
@ -162,9 +160,7 @@ def render(
account: account:
AccountView.render("show.json", %{ AccountView.render("show.json", %{
user: user, user: user,
for: opts[:for], for: opts[:for]
relationships: opts[:relationships],
skip_relationships: opts[:skip_relationships]
}), }),
in_reply_to_id: nil, in_reply_to_id: nil,
in_reply_to_account_id: nil, in_reply_to_account_id: nil,
@ -330,9 +326,7 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
account: account:
AccountView.render("show.json", %{ AccountView.render("show.json", %{
user: user, user: user,
for: opts[:for], for: opts[:for]
relationships: opts[:relationships],
skip_relationships: opts[:skip_relationships]
}), }),
in_reply_to_id: reply_to && to_string(reply_to.id), 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), 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 defmodule Pleroma.Web.MongooseIM.MongooseIMController do
use Pleroma.Web, :controller use Pleroma.Web, :controller
alias Pleroma.Plugs.AuthenticationPlug
alias Pleroma.Plugs.RateLimiter alias Pleroma.Plugs.RateLimiter
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.User alias Pleroma.User
@ -27,7 +28,7 @@ def user_exists(conn, %{"user" => username}) do
def check_password(conn, %{"user" => username, "pass" => password}) do def check_password(conn, %{"user" => username, "pass" => password}) do
with %User{password_hash: password_hash, deactivated: false} <- with %User{password_hash: password_hash, deactivated: false} <-
Repo.get_by(User, nickname: username, local: true), Repo.get_by(User, nickname: username, local: true),
true <- Pbkdf2.verify_pass(password, password_hash) do true <- AuthenticationPlug.checkpw(password, password_hash) do
conn conn
|> json(true) |> json(true)
else else

View file

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

View file

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

View file

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

View file

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

View file

@ -5,6 +5,7 @@
"base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"}, "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": {: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"}, "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"}, "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"}, "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"}, "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": {: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_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"}, "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"}, "esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
"eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"}, "eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"},
"ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"}, "ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"},

View file

@ -8,8 +8,16 @@
## to merge POT files into PO files. ## to merge POT files into PO files.
msgid "" msgid ""
msgstr "" 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" "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" msgid "can't be blank"
msgstr "ne peut être vide" msgstr "ne peut être vide"
@ -35,10 +43,10 @@ msgid "does not match confirmation"
msgstr "ne correspondent pas" msgstr "ne correspondent pas"
msgid "is still associated with this entry" msgid "is still associated with this entry"
msgstr "" msgstr "est toujours associé à cette entrée"
msgid "are still associated with this entry" msgid "are still associated with this entry"
msgstr "" msgstr "sont toujours associés à cette entrée"
msgid "should be %{count} character(s)" msgid "should be %{count} character(s)"
msgid_plural "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}" msgid "must be equal to %{number}"
msgstr "doit égal à %{number}" msgstr "doit égal à %{number}"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:381 #: lib/pleroma/web/common_api/common_api.ex:381
#, elixir-format
msgid "Account not found" msgid "Account not found"
msgstr "Compte non trouvé" msgstr "Compte non trouvé"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:153 #: lib/pleroma/web/common_api/common_api.ex:153
#, elixir-format
msgid "Already voted" msgid "Already voted"
msgstr "A déjà voté" msgstr "A déjà voté"
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:263 #: lib/pleroma/web/oauth/oauth_controller.ex:263
#, elixir-format
msgid "Bad request" msgid "Bad request"
msgstr "Requête Invalide" msgstr "Requête Invalide"
#, elixir-format
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:254 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:254
#, elixir-format
msgid "Can't delete object" msgid "Can't delete object"
msgstr "Ne peut supprimer cet objet" msgstr "Ne peut supprimer cet objet"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:569 #: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:569
#, elixir-format
msgid "Can't delete this post" msgid "Can't delete this post"
msgstr "Ne peut supprimer ce message" 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:1731
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1737 #: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1737
#, elixir-format
msgid "Can't display this activity" msgid "Can't display this activity"
msgstr "Ne peut afficher cette activitée" msgstr "Ne peut afficher cette activitée"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:195 #: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:195
#, elixir-format
msgid "Can't find user" msgid "Can't find user"
msgstr "Compte non trouvé" msgstr "Compte non trouvé"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1148 #: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1148
#, elixir-format
msgid "Can't get favorites" msgid "Can't get favorites"
msgstr "Favoris non trouvables" msgstr "Favoris non trouvables"
#, elixir-format
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:263 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:263
#, elixir-format
msgid "Can't like object" msgid "Can't like object"
msgstr "Ne peut aimer cet objet" msgstr "Ne peut aimer cet objet"
#, elixir-format
#: lib/pleroma/web/common_api/utils.ex:518 #: lib/pleroma/web/common_api/utils.ex:518
#, elixir-format
msgid "Cannot post an empty status without attachments" msgid "Cannot post an empty status without attachments"
msgstr "Ne peut envoyer un status vide sans attachements" msgstr "Ne peut envoyer un status vide sans attachements"
#, elixir-format
#: lib/pleroma/web/common_api/utils.ex:461 #: lib/pleroma/web/common_api/utils.ex:461
#, elixir-format
msgid "Comment must be up to %{max_size} characters" msgid "Comment must be up to %{max_size} characters"
msgstr "Le commentaire ne doit faire plus de %{max_size} charactères" msgstr "Le commentaire ne doit faire plus de %{max_size} charactères"
#, elixir-format
#: lib/pleroma/web/admin_api/config.ex:63 #: lib/pleroma/web/admin_api/config.ex:63
#, elixir-format
msgid "Config with params %{params} not found" msgid "Config with params %{params} not found"
msgstr "Configuration avec les paramètres %{params} non trouvée" msgstr "Configuration avec les paramètres %{params} non trouvée"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:78 #: lib/pleroma/web/common_api/common_api.ex:78
#, elixir-format
msgid "Could not delete" msgid "Could not delete"
msgstr "Échec de la suppression" msgstr "Échec de la suppression"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:110 #: lib/pleroma/web/common_api/common_api.ex:110
#, elixir-format
msgid "Could not favorite" msgid "Could not favorite"
msgstr "Échec de mise en favoris" msgstr "Échec de mise en favoris"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:310 #: lib/pleroma/web/common_api/common_api.ex:310
#, elixir-format
msgid "Could not pin" msgid "Could not pin"
msgstr "Échec de l'épinglage" msgstr "Échec de l'épinglage"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:89 #: lib/pleroma/web/common_api/common_api.ex:89
#, elixir-format
msgid "Could not repeat" msgid "Could not repeat"
msgstr "Échec de création la répétition" msgstr "Échec de création la répétition"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:120 #: lib/pleroma/web/common_api/common_api.ex:120
#, elixir-format
msgid "Could not unfavorite" msgid "Could not unfavorite"
msgstr "Échec de suppression des favoris" msgstr "Échec de suppression des favoris"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:327 #: lib/pleroma/web/common_api/common_api.ex:327
#, elixir-format
msgid "Could not unpin" msgid "Could not unpin"
msgstr "Échec du dépinglage" msgstr "Échec du dépinglage"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:99 #: lib/pleroma/web/common_api/common_api.ex:99
#, elixir-format
msgid "Could not unrepeat" msgid "Could not unrepeat"
msgstr "Échec de suppression de la répétition" msgstr "Échec de suppression de la répétition"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:392 #: lib/pleroma/web/common_api/common_api.ex:392
#, elixir-format
msgid "Could not update state" msgid "Could not update state"
msgstr "Échec de la mise à jour du status" msgstr "Échec de la mise à jour du status"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1271 #: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1271
#, elixir-format
msgid "Error." msgid "Error."
msgstr "Erreur." msgstr "Erreur."
#, elixir-format
#: lib/pleroma/captcha/kocaptcha.ex:36 #: lib/pleroma/captcha/kocaptcha.ex:36
#, elixir-format
msgid "Invalid CAPTCHA" msgid "Invalid CAPTCHA"
msgstr "CAPTCHA invalide" msgstr "CAPTCHA invalide"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1700 #: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1700
#: lib/pleroma/web/oauth/oauth_controller.ex:465 #: lib/pleroma/web/oauth/oauth_controller.ex:465
#, elixir-format
msgid "Invalid credentials" msgid "Invalid credentials"
msgstr "Paramètres d'authentification invalides" msgstr "Paramètres d'authentification invalides"
#, elixir-format
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:20 #: lib/pleroma/plugs/ensure_authenticated_plug.ex:20
#, elixir-format
msgid "Invalid credentials." msgid "Invalid credentials."
msgstr "Paramètres d'authentification invalides." msgstr "Paramètres d'authentification invalides."
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:154 #: lib/pleroma/web/common_api/common_api.ex:154
#, elixir-format
msgid "Invalid indices" msgid "Invalid indices"
msgstr "Indices invalides" msgstr "Indices invalides"
#, elixir-format
#: lib/pleroma/web/admin_api/admin_api_controller.ex:411 #: lib/pleroma/web/admin_api/admin_api_controller.ex:411
#, elixir-format
msgid "Invalid parameters" msgid "Invalid parameters"
msgstr "Paramètres invalides" msgstr "Paramètres invalides"
#, elixir-format
#: lib/pleroma/web/common_api/utils.ex:377 #: lib/pleroma/web/common_api/utils.ex:377
#, elixir-format
msgid "Invalid password." msgid "Invalid password."
msgstr "Mot de passe invalide." msgstr "Mot de passe invalide."
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:163 #: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:163
#, elixir-format
msgid "Invalid request" msgid "Invalid request"
msgstr "Requête invalide" msgstr "Requête invalide"
#, elixir-format
#: lib/pleroma/captcha/kocaptcha.ex:16 #: lib/pleroma/captcha/kocaptcha.ex:16
#, elixir-format
msgid "Kocaptcha service unavailable" msgid "Kocaptcha service unavailable"
msgstr "Service Kocaptcha non disponible" msgstr "Service Kocaptcha non disponible"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1696 #: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1696
#, elixir-format
msgid "Missing parameters" msgid "Missing parameters"
msgstr "Paramètres manquants" msgstr "Paramètres manquants"
#, elixir-format
#: lib/pleroma/web/common_api/utils.ex:496 #: lib/pleroma/web/common_api/utils.ex:496
#, elixir-format
msgid "No such conversation" msgid "No such conversation"
msgstr "Conversation inconnue" msgstr "Conversation inconnue"
#, elixir-format
#: lib/pleroma/web/admin_api/admin_api_controller.ex:163 #: lib/pleroma/web/admin_api/admin_api_controller.ex:163
#: lib/pleroma/web/admin_api/admin_api_controller.ex:206 #: lib/pleroma/web/admin_api/admin_api_controller.ex:206
#, elixir-format
msgid "No such permission_group" msgid "No such permission_group"
msgstr "Groupe de permission inconnu" msgstr "Groupe de permission inconnu"
#, elixir-format
#: lib/pleroma/plugs/uploaded_media.ex:69 #: lib/pleroma/plugs/uploaded_media.ex:69
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:311 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:311
#: lib/pleroma/web/admin_api/admin_api_controller.ex:399 #: lib/pleroma/web/admin_api/admin_api_controller.ex:399
#: lib/pleroma/web/mastodon_api/subscription_controller.ex:63 #: lib/pleroma/web/mastodon_api/subscription_controller.ex:63
#: lib/pleroma/web/ostatus/ostatus_controller.ex:248 #: lib/pleroma/web/ostatus/ostatus_controller.ex:248
#, elixir-format
msgid "Not found" msgid "Not found"
msgstr "Non Trouvé" msgstr "Non Trouvé"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:152 #: lib/pleroma/web/common_api/common_api.ex:152
#, elixir-format
msgid "Poll's author can't vote" msgid "Poll's author can't vote"
msgstr "L'auteur·rice d'un sondage ne peut voter" 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:443
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:444 #: 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:473
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:476 #: 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:1180
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1564 #: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1564
#, elixir-format
msgid "Record not found" msgid "Record not found"
msgstr "Enregistrement non trouvé" msgstr "Enregistrement non trouvé"
#, elixir-format
#: lib/pleroma/web/admin_api/admin_api_controller.ex:417 #: 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/mastodon_api_controller.ex:1570
#: lib/pleroma/web/mastodon_api/subscription_controller.ex:69 #: lib/pleroma/web/mastodon_api/subscription_controller.ex:69
#: lib/pleroma/web/ostatus/ostatus_controller.ex:252 #: lib/pleroma/web/ostatus/ostatus_controller.ex:252
#, elixir-format
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Erreur inconnue" msgstr "Erreur inconnue"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:253 #: lib/pleroma/web/common_api/common_api.ex:253
#, elixir-format
msgid "The message visibility must be direct" msgid "The message visibility must be direct"
msgstr "La visibilitée du message doit être « direct »" msgstr "La visibilitée du message doit être « direct »"
#, elixir-format
#: lib/pleroma/web/common_api/utils.ex:521 #: lib/pleroma/web/common_api/utils.ex:521
#, elixir-format
msgid "The status is over the character limit" msgid "The status is over the character limit"
msgstr "Le status est au-delà de la limite de charactères" msgstr "Le status est au-delà de la limite de charactères"
#, elixir-format
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:27 #: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:27
#, elixir-format
msgid "This resource requires authentication." msgid "This resource requires authentication."
msgstr "Cette resource nécessite une authentification." msgstr "Cette resource nécessite une authentification."
#, elixir-format
#: lib/pleroma/plugs/rate_limiter.ex:89 #: lib/pleroma/plugs/rate_limiter.ex:89
#, elixir-format
msgid "Throttled" msgid "Throttled"
msgstr "Limité" msgstr "Limité"
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:155 #: lib/pleroma/web/common_api/common_api.ex:155
#, elixir-format
msgid "Too many choices" msgid "Too many choices"
msgstr "Trop de choix" msgstr "Trop de choix"
#, elixir-format
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:268 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:268
#, elixir-format
msgid "Unhandled activity type" msgid "Unhandled activity type"
msgstr "Type d'activitée non-gérée" msgstr "Type d'activitée non-gérée"
#, elixir-format
#: lib/pleroma/plugs/user_is_admin_plug.ex:20 #: lib/pleroma/plugs/user_is_admin_plug.ex:20
#, elixir-format
msgid "User is not admin." msgid "User is not admin."
msgstr "Le compte n'est pas admin." msgstr "Le compte n'est pas admin."
#, elixir-format
#: lib/pleroma/web/common_api/common_api.ex:380 #: lib/pleroma/web/common_api/common_api.ex:380
#, elixir-format
msgid "Valid `account_id` required" msgid "Valid `account_id` required"
msgstr "Un `account_id` valide est requis" msgstr "Un `account_id` valide est requis"
#, elixir-format
#: lib/pleroma/web/admin_api/admin_api_controller.ex:185 #: lib/pleroma/web/admin_api/admin_api_controller.ex:185
#, elixir-format
msgid "You can't revoke your own admin status." msgid "You can't revoke your own admin status."
msgstr "Vous ne pouvez révoquer votre propre status d'admin." msgstr "Vous ne pouvez révoquer votre propre status d'admin."
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:216 #: lib/pleroma/web/oauth/oauth_controller.ex:216
#, elixir-format
msgid "Your account is currently disabled" msgid "Your account is currently disabled"
msgstr "Votre compte est actuellement désactivé" msgstr "Votre compte est actuellement désactivé"
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:158 #: lib/pleroma/web/oauth/oauth_controller.ex:158
#: lib/pleroma/web/oauth/oauth_controller.ex:213 #: lib/pleroma/web/oauth/oauth_controller.ex:213
#, elixir-format
msgid "Your login is missing a confirmed e-mail address" msgid "Your login is missing a confirmed e-mail address"
msgstr "Une confirmation de l'addresse de couriel est requise pour l'authentification" 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 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:221
#, elixir-format
msgid "can't read inbox of %{nickname} as %{as_nickname}" 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}" 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 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:297
#, elixir-format
msgid "can't update outbox of %{nickname} as %{as_nickname}" 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}" 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 #: lib/pleroma/web/common_api/common_api.ex:335
#, elixir-format
msgid "conversation is already muted" msgid "conversation is already muted"
msgstr "la conversation est déjà baillonée" 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:192
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:317 #: 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:1196
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1247 #: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:1247
#, elixir-format
msgid "error" msgid "error"
msgstr "erreur" msgstr "erreur"
#, elixir-format
#: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:789 #: lib/pleroma/web/mastodon_api/mastodon_api_controller.ex:789
#, elixir-format
msgid "mascots can only be images" msgid "mascots can only be images"
msgstr "les mascottes ne peuvent être que des images" msgstr "les mascottes ne peuvent être que des images"
#, elixir-format
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:34 #: lib/pleroma/web/activity_pub/activity_pub_controller.ex:34
#, elixir-format
msgid "not found" msgid "not found"
msgstr "non trouvé" msgstr "non trouvé"
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:298 #: lib/pleroma/web/oauth/oauth_controller.ex:298
#, elixir-format
msgid "Bad OAuth request." msgid "Bad OAuth request."
msgstr "Requête OAuth invalide." msgstr "Requête OAuth invalide."
#, elixir-format
#: lib/pleroma/captcha/captcha.ex:92 #: lib/pleroma/captcha/captcha.ex:92
#, elixir-format
msgid "CAPTCHA already used" msgid "CAPTCHA already used"
msgstr "CAPTCHA déjà utilisé" msgstr "CAPTCHA déjà utilisé"
#, elixir-format
#: lib/pleroma/captcha/captcha.ex:89 #: lib/pleroma/captcha/captcha.ex:89
#, elixir-format
msgid "CAPTCHA expired" msgid "CAPTCHA expired"
msgstr "CAPTCHA expiré" msgstr "CAPTCHA expiré"
#, elixir-format
#: lib/pleroma/plugs/uploaded_media.ex:50 #: lib/pleroma/plugs/uploaded_media.ex:50
#, elixir-format
msgid "Failed" msgid "Failed"
msgstr "Échec" msgstr "Échec"
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:314 #: lib/pleroma/web/oauth/oauth_controller.ex:314
msgid "Failed to authenticate: %{message}."
msgstr "Échec de l'authentification: %{message}"
#, elixir-format #, elixir-format
msgid "Failed to authenticate: %{message}."
msgstr "Échec de l'authentification : %{message}."
#: lib/pleroma/web/oauth/oauth_controller.ex:345 #: lib/pleroma/web/oauth/oauth_controller.ex:345
#, elixir-format
msgid "Failed to set up user account." msgid "Failed to set up user account."
msgstr "Échec de création de votre compte." msgstr "Échec de création de votre compte."
#, elixir-format
#: lib/pleroma/plugs/oauth_scopes_plug.ex:37 #: lib/pleroma/plugs/oauth_scopes_plug.ex:37
msgid "Insufficient permissions: %{permissions}."
msgstr "Permissions insuffisantes: %{permissions}."
#, elixir-format #, elixir-format
msgid "Insufficient permissions: %{permissions}."
msgstr "Permissions insuffisantes : %{permissions}."
#: lib/pleroma/plugs/uploaded_media.ex:89 #: lib/pleroma/plugs/uploaded_media.ex:89
#, elixir-format
msgid "Internal Error" msgid "Internal Error"
msgstr "Erreur interne" msgstr "Erreur interne"
#, elixir-format
#: lib/pleroma/web/oauth/fallback_controller.ex:22 #: lib/pleroma/web/oauth/fallback_controller.ex:22
#: lib/pleroma/web/oauth/fallback_controller.ex:29 #: lib/pleroma/web/oauth/fallback_controller.ex:29
#, elixir-format
msgid "Invalid Username/Password" msgid "Invalid Username/Password"
msgstr "Nom d'utilisateur/mot de passe invalide" msgstr "Nom d'utilisateur/mot de passe invalide"
#, elixir-format
#: lib/pleroma/captcha/captcha.ex:107 #: lib/pleroma/captcha/captcha.ex:107
#, elixir-format
msgid "Invalid answer data" msgid "Invalid answer data"
msgstr "Réponse invalide" msgstr "Réponse invalide"
#, elixir-format
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:204 #: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:204
#, elixir-format
msgid "Nodeinfo schema version not handled" msgid "Nodeinfo schema version not handled"
msgstr "Version du schéma nodeinfo non géré" msgstr "Version du schéma nodeinfo non géré"
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:145 #: 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 #, 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 #: lib/pleroma/web/oauth/fallback_controller.ex:14
#, elixir-format
msgid "Unknown error, please check the details and try again." msgid "Unknown error, please check the details and try again."
msgstr "Erreur inconnue, veuillez vérifier les détails et réessayer." 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:93
#: lib/pleroma/web/oauth/oauth_controller.ex:131 #: lib/pleroma/web/oauth/oauth_controller.ex:131
#, elixir-format
msgid "Unlisted redirect_uri." msgid "Unlisted redirect_uri."
msgstr "redirect_uri non listé." msgstr "redirect_uri non listé."
#, elixir-format
#: lib/pleroma/web/oauth/oauth_controller.ex:294 #: lib/pleroma/web/oauth/oauth_controller.ex:294
#, elixir-format
msgid "Unsupported OAuth provider: %{provider}." msgid "Unsupported OAuth provider: %{provider}."
msgstr "Fournisseur OAuth non supporté : %{provider}." msgstr "Fournisseur OAuth non supporté : %{provider}."
#, elixir-format
#: lib/pleroma/uploaders/uploader.ex:71 #: lib/pleroma/uploaders/uploader.ex:71
msgid "Uploader callback timeout"
msgstr ""
## msgstr "Attente écoulée"
#, elixir-format #, 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:11
#: lib/pleroma/web/uploader_controller.ex:23 #: lib/pleroma/web/uploader_controller.ex:23
#, elixir-format
msgid "bad request" msgid "bad request"
msgstr "requête invalide" 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, "alwaysShowSubjectInput": true,
"background": "/static/aurora_borealis.jpg",
"collapseMessageWithSubject": false,
"disableChat": false,
"greentext": false,
"hideFilteredStatuses": false,
"hideMutedPosts": false,
"hidePostStats": false, "hidePostStats": false,
"hideSitename": false,
"hideUserStats": false, "hideUserStats": false,
"loginMethod": "password", "loginMethod": "password",
"webPushNotifications": false, "logo": "/static/logo.png",
"logoMargin": ".1em",
"logoMask": true,
"minimalScopesMode": false,
"noAttachmentLinks": false, "noAttachmentLinks": false,
"nsfwCensorImage": "", "nsfwCensorImage": "",
"postContentType": "text/plain",
"redirectRootLogin": "/main/friends",
"redirectRootNoLogin": "/main/all",
"scopeCopy": true,
"showFeaturesPanel": 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-face {
font-family: "Icons"; font-family: "Icons";
src: url("./font/fontello.1588947937982.eot"); src: url("./font/fontello.1589385935077.eot");
src: url("./font/fontello.1588947937982.eot") format("embedded-opentype"), src: url("./font/fontello.1589385935077.eot") format("embedded-opentype"),
url("./font/fontello.1588947937982.woff2") format("woff2"), url("./font/fontello.1589385935077.woff2") format("woff2"),
url("./font/fontello.1588947937982.woff") format("woff"), url("./font/fontello.1589385935077.woff") format("woff"),
url("./font/fontello.1588947937982.ttf") format("truetype"), url("./font/fontello.1589385935077.ttf") format("truetype"),
url("./font/fontello.1588947937982.svg") format("svg"); url("./font/fontello.1589385935077.svg") format("svg");
font-weight: normal; font-weight: normal;
font-style: 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){ !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"] assert ConfigDB.from_binary(binary) == [key: "value"]
end 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 test "keyword" do
binary = binary =
ConfigDB.transform([ ConfigDB.transform([

View file

@ -11,6 +11,7 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do
alias Pleroma.User alias Pleroma.User
import ExUnit.CaptureLog import ExUnit.CaptureLog
import Pleroma.Factory
setup %{conn: conn} do setup %{conn: conn} do
user = %User{ user = %User{
@ -50,16 +51,41 @@ test "with a correct password in the credentials, " <>
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug) assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
end 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 =
conn conn
|> assign(:auth_credentials, %{password: "wrong"}) |> assign(:auth_user, user)
|> assign(:auth_credentials, %{password: "123"})
ret_conn =
conn
|> AuthenticationPlug.call(%{}) |> 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 end
describe "checkpw/2" do describe "checkpw/2" do
@ -79,6 +105,13 @@ test "check sha512-crypt hash" do
assert AuthenticationPlug.checkpw("password", hash) assert AuthenticationPlug.checkpw("password", hash)
end 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 test "it returns false when hash invalid" do
hash = hash =
"psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1" "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 test "works with base64 encoded images" do
file = %{ file = %{
"img" => data_uri() img: data_uri()
} }
{:ok, %Object{}} = ActivityPub.upload(file) {:ok, %Object{}} = ActivityPub.upload(file)

View file

@ -2509,6 +2509,7 @@ test "common config example", %{conn: conn} do
%{"tuple" => [":seconds_valid", 60]}, %{"tuple" => [":seconds_valid", 60]},
%{"tuple" => [":path", ""]}, %{"tuple" => [":path", ""]},
%{"tuple" => [":key1", nil]}, %{"tuple" => [":key1", nil]},
%{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
%{"tuple" => [":regex1", "~r/https:\/\/example.com/"]}, %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
%{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]}, %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
%{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]}, %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
@ -2532,6 +2533,7 @@ test "common config example", %{conn: conn} do
%{"tuple" => [":seconds_valid", 60]}, %{"tuple" => [":seconds_valid", 60]},
%{"tuple" => [":path", ""]}, %{"tuple" => [":path", ""]},
%{"tuple" => [":key1", nil]}, %{"tuple" => [":key1", nil]},
%{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
%{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]}, %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
%{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]}, %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
%{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]}, %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
@ -2544,6 +2546,7 @@ test "common config example", %{conn: conn} do
":seconds_valid", ":seconds_valid",
":path", ":path",
":key1", ":key1",
":partial_chain",
":regex1", ":regex1",
":regex2", ":regex2",
":regex3", ":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 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value
assert ":proxy_url" in db assert ":proxy_url" in db
end 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 end
describe "GET /api/pleroma/admin/restart" do 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
end end
test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do describe "GET /api/pleroma/admin/config/descriptions" do
admin = insert(:user, is_admin: true) test "structure", %{conn: conn} do
admin = insert(:user, is_admin: true)
conn = conn =
assign(conn, :user, admin) assign(conn, :user, admin)
|> get("/api/pleroma/admin/config/descriptions") |> 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["children"]
assert child["key"] assert child["key"]
assert String.starts_with?(child["group"], ":") assert String.starts_with?(child["group"], ":")
assert child["description"] 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 end
describe "/api/pleroma/admin/stats" do 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]} {:ok, [user: user, name: name, password: password]}
end 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}} params = %{"authorization" => %{"name" => name, "password" => password}}
res = PleromaAuthenticator.get_user(%Plug.Conn{params: params}) 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 end
test "get_user/authorization with invalid password", %{name: name} do 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, :limit])
setup do: clear_config([:instance, :max_pinned_statuses]) 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 describe "deletion" do
test "it works with pruned objects" do test "it works with pruned objects" do
user = insert(:user) user = insert(:user)

View file

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

View file

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

View file

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

View file

@ -20,12 +20,10 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
describe "home" do describe "home" do
setup do: oauth_access(["read:statuses"]) 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, user: user,
conn: conn conn: conn
} do } do
clear_config([:extensions, :output_relationships_in_statuses_by_default], false)
other_user = insert(:user) other_user = insert(:user)
{:ok, _} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"}) {: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)
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 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, public_activity} = CommonAPI.post(user, %{status: ".", visibility: "public"})
{:ok, direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"}) {: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
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 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"}) user = insert(:user, pleroma_settings_store: %{fe: "test"})

View file

@ -42,7 +42,11 @@ test "Mention notification" do
id: to_string(notification.id), id: to_string(notification.id),
pleroma: %{is_seen: false}, pleroma: %{is_seen: false},
type: "mention", 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}), status: StatusView.render("show.json", %{activity: activity, for: mentioned_user}),
created_at: Utils.to_masto_date(notification.inserted_at) 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
end end
test "embeds a relationship in the account" do test "does not embed a relationship in the account" do
user = insert(:user) user = insert(:user)
other_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}) result = StatusView.render("show.json", %{activity: activity, for: other_user})
assert result[:account][:pleroma][:relationship] == assert result[:account][:pleroma][:relationship] == %{}
AccountView.render("relationship.json", %{user: other_user, target: user})
assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec()) assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec())
end 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) user = insert(:user)
other_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}) result = StatusView.render("show.json", %{activity: activity, for: user})
assert result[:account][:pleroma][:relationship] == assert result[:account][:pleroma][:relationship] == %{}
AccountView.render("relationship.json", %{user: user, target: other_user}) assert result[:reblog][:account][:pleroma][:relationship] == %{}
assert result[:reblog][:account][:pleroma][:relationship] ==
AccountView.render("relationship.json", %{user: user, target: user})
assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec()) assert_schema(result, "Status", Pleroma.Web.ApiSpec.spec())
end end

View file

@ -31,8 +31,28 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
test "resend account confirmation email", %{conn: conn, user: user} do test "resend account confirmation email", %{conn: conn, user: user} do
conn conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}") |> 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() 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 test "user avatar can be set", %{user: user, conn: conn} do
avatar_image = File.read!("test/fixtures/avatar_data_uri") 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) user = refresh_record(user)
@ -70,17 +93,20 @@ test "user avatar can be set", %{user: user, conn: conn} do
] ]
} = user.avatar } = user.avatar
assert %{"url" => _} = json_response(conn, 200) assert %{"url" => _} = json_response_and_validate_schema(conn, 200)
end end
test "user avatar can be reset", %{user: user, conn: conn} do 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) user = User.get_cached_by_id(user.id)
assert user.avatar == nil assert user.avatar == nil
assert %{"url" => nil} = json_response(conn, 200) assert %{"url" => nil} = json_response_and_validate_schema(conn, 200)
end end
end end
@ -88,21 +114,27 @@ test "user avatar can be reset", %{user: user, conn: conn} do
setup do: oauth_access(["write:accounts"]) setup do: oauth_access(["write:accounts"])
test "can set profile banner", %{user: user, conn: conn} do 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) user = refresh_record(user)
assert user.banner["type"] == "Image" assert user.banner["type"] == "Image"
assert %{"url" => _} = json_response(conn, 200) assert %{"url" => _} = json_response_and_validate_schema(conn, 200)
end end
test "can reset profile banner", %{user: user, conn: conn} do 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) user = refresh_record(user)
assert user.banner == %{} assert user.banner == %{}
assert %{"url" => nil} = json_response(conn, 200) assert %{"url" => nil} = json_response_and_validate_schema(conn, 200)
end end
end end
@ -110,19 +142,26 @@ test "can reset profile banner", %{user: user, conn: conn} do
setup do: oauth_access(["write:accounts"]) setup do: oauth_access(["write:accounts"])
test "background image can be set", %{user: user, conn: conn} do 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) user = refresh_record(user)
assert user.background["type"] == "Image" 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 end
test "background image can be reset", %{user: user, conn: conn} do 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) user = refresh_record(user)
assert user.background == %{} assert user.background == %{}
assert %{"url" => nil} = json_response(conn, 200) assert %{"url" => nil} = json_response_and_validate_schema(conn, 200)
end end
end end
@ -143,7 +182,7 @@ test "returns list of statuses favorited by specified user", %{
response = response =
conn conn
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites") |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
|> json_response(:ok) |> json_response_and_validate_schema(:ok)
[like] = response [like] = response
@ -160,7 +199,7 @@ test "returns favorites for specified user_id when requester is not logged in",
response = response =
build_conn() build_conn()
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites") |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
|> json_response(200) |> json_response_and_validate_schema(200)
assert length(response) == 1 assert length(response) == 1
end 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(:user, u)
|> assign(:token, insert(:oauth_token, user: u, scopes: ["read:favourites"])) |> assign(:token, insert(:oauth_token, user: u, scopes: ["read:favourites"]))
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites") |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
|> json_response(:ok) |> json_response_and_validate_schema(:ok)
assert length(response) == 1 assert length(response) == 1
end end
@ -191,7 +230,7 @@ test "returns favorited DM only when user is logged in and he is one of recipien
response = response =
build_conn() build_conn()
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites") |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
|> json_response(200) |> json_response_and_validate_schema(200)
assert length(response) == 0 assert length(response) == 0
end end
@ -213,7 +252,7 @@ test "does not return others' favorited DM when user is not one of recipients",
response = response =
conn conn
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites") |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
|> json_response(:ok) |> json_response_and_validate_schema(:ok)
assert Enum.empty?(response) assert Enum.empty?(response)
end end
@ -233,11 +272,12 @@ test "paginates favorites using since_id and max_id", %{
response = response =
conn conn
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{ |> get(
since_id: third_activity.id, "/api/v1/pleroma/accounts/#{user.id}/favourites?since_id=#{third_activity.id}&max_id=#{
max_id: seventh_activity.id seventh_activity.id
}) }"
|> json_response(:ok) )
|> json_response_and_validate_schema(:ok)
assert length(response) == 3 assert length(response) == 3
refute third_activity in response refute third_activity in response
@ -256,8 +296,8 @@ test "limits favorites using limit parameter", %{
response = response =
conn conn
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"}) |> get("/api/v1/pleroma/accounts/#{user.id}/favourites?limit=3")
|> json_response(:ok) |> json_response_and_validate_schema(:ok)
assert length(response) == 3 assert length(response) == 3
end end
@ -269,7 +309,7 @@ test "returns empty response when user does not have any favorited statuses", %{
response = response =
conn conn
|> get("/api/v1/pleroma/accounts/#{user.id}/favourites") |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
|> json_response(:ok) |> json_response_and_validate_schema(:ok)
assert Enum.empty?(response) assert Enum.empty?(response)
end 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 test "returns 404 error when specified user is not exist", %{conn: conn} do
conn = get(conn, "/api/v1/pleroma/accounts/test/favourites") 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 end
test "returns 403 error when user has hidden own favorites", %{conn: conn} do 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") 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
test "hides favorites for new users by default", %{conn: conn} do 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 assert user.hide_favorites
conn = get(conn, "/api/v1/pleroma/accounts/#{user.id}/favourites") 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
end end
@ -312,11 +352,12 @@ test "subscribing / unsubscribing to a user" do
|> assign(:user, user) |> assign(:user, user)
|> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe") |> 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") 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
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") 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
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") 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 end
end end