forked from AkkomaGang/akkoma
Compare commits
46 commits
reprocess-
...
develop
Author | SHA1 | Date | |
---|---|---|---|
59b886e86e | |||
22333f13e8 | |||
a8f8ecce31 | |||
e9f1897cfd | |||
aaf78e2b52 | |||
11ec9daa5b | |||
89ffc01c23 | |||
61641957cb | |||
37a1001b97 | |||
5796d81d98 | |||
7544939c83 | |||
5192e21e53 | |||
19ccdc8762 | |||
967c325b0d | |||
d3b9cfb03f | |||
ceeeefc707 | |||
366889f97c | |||
74dbea4cf8 | |||
|
8bca9a7dbe | ||
|
fcb5e4a48d | ||
|
b1e2f3f646 | ||
|
2f074a6966 | ||
|
fd35a66312 | ||
|
5022ecd766 | ||
d16eff1c0f | |||
55179d4214 | |||
e5a2548521 | |||
1245141779 | |||
5d23df84c9 | |||
b3e4d81362 | |||
b9bb093600 | |||
62e179f446 | |||
21ec1edbb6 | |||
e8806fdc42 | |||
ec162b496b | |||
3b973d0627 | |||
273e51cb4a | |||
0ec3a11895 | |||
2781faaa7b | |||
a82fb2acc1 | |||
499d8a1056 | |||
6b85b36e3a | |||
8bfd01b9c7 | |||
d0b7d37cd8 | |||
6ff6f12fec | |||
a4a7f4cad1 |
77 changed files with 16480 additions and 2070 deletions
|
@ -93,7 +93,6 @@ pipeline:
|
|||
MIX_ENV: prod
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
commands:
|
||||
- rm config/emoji.txt
|
||||
- apt-get update && apt-get install -y cmake libmagic-dev rclone zip imagemagick libmagic-dev git build-essential g++ wget
|
||||
- *clean
|
||||
- echo "import Config" > config/prod.secret.exs
|
||||
|
|
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- support for fedibird-fe, and non-breaking API parity for it to function
|
||||
|
||||
### Changed
|
||||
- MFM parsing is now done on the backend by a modified version of ilja's parser -> https://akkoma.dev/AkkomaGang/mfm-parser
|
||||
|
||||
### Fixed
|
||||
- Compatibility with latest meilisearch
|
||||
- Resolution of nested mix tasks (i.e search.meilisearch) in OTP releases
|
||||
- Elasticsearch returning likes and repeats, displaying as posts
|
||||
|
||||
### Removed
|
||||
- Non-finch HTTP adapters. `:tesla, :adapter` is now highly recommended to be set to the default.
|
||||
|
||||
## 2022.08
|
||||
|
||||
### Added
|
||||
- extended runtime module support, see config cheatsheet
|
||||
- quote posting; quotes are limited to public posts
|
||||
|
|
|
@ -734,6 +734,14 @@
|
|||
"build_dir" => "distribution",
|
||||
"ref" => "akkoma"
|
||||
},
|
||||
"fedibird-fe" => %{
|
||||
"name" => "fedibird-fe",
|
||||
"git" => "https://akkoma.dev/AkkomaGang/fedibird-fe",
|
||||
"build_url" =>
|
||||
"https://akkoma-updates.s3-website.fr-par.scw.cloud/frontend/${ref}/fedibird-fe.zip",
|
||||
"build_dir" => "distribution",
|
||||
"ref" => "akkoma"
|
||||
},
|
||||
"admin-fe" => %{
|
||||
"name" => "admin-fe",
|
||||
"git" => "https://akkoma.dev/AkkomaGang/admin-fe",
|
||||
|
@ -746,7 +754,7 @@
|
|||
"git" => "https://gitlab.com/soapbox-pub/soapbox-fe",
|
||||
"build_url" =>
|
||||
"https://gitlab.com/soapbox-pub/soapbox-fe/-/jobs/artifacts/${ref}/download?job=build-production",
|
||||
"ref" => "v1.0.0",
|
||||
"ref" => "v2.0.0",
|
||||
"build_dir" => "static"
|
||||
},
|
||||
# For developers - enables a swagger frontend to view the openapi spec
|
||||
|
|
|
@ -1169,7 +1169,6 @@
|
|||
hideFilteredStatuses: false,
|
||||
hideMutedPosts: false,
|
||||
hidePostStats: false,
|
||||
hideSitename: false,
|
||||
hideUserStats: false,
|
||||
loginMethod: "password",
|
||||
logo: "/static/logo.svg",
|
||||
|
@ -1235,12 +1234,6 @@
|
|||
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",
|
||||
|
@ -1350,6 +1343,42 @@
|
|||
type: :string,
|
||||
description: "Which theme to use. Available themes are defined in styles.json",
|
||||
suggestions: ["pleroma-dark"]
|
||||
},
|
||||
%{
|
||||
key: :showPanelNavShortcuts,
|
||||
label: "Show timeline panel nav shortcuts",
|
||||
type: :boolean,
|
||||
description: "Whether to put timeline nav tabs on the top of the panel"
|
||||
},
|
||||
%{
|
||||
key: :showNavShortcuts,
|
||||
label: "Show navbar shortcuts",
|
||||
type: :boolean,
|
||||
description: "Whether to put extra navigation options on the navbar"
|
||||
},
|
||||
%{
|
||||
key: :showWiderShortcuts,
|
||||
label: "Increase navbar shortcut spacing",
|
||||
type: :boolean,
|
||||
description: "Whether to add extra space between navbar icons"
|
||||
},
|
||||
%{
|
||||
key: :hideSiteFavicon,
|
||||
label: "Hide site favicon",
|
||||
type: :boolean,
|
||||
description: "Whether to hide the instance favicon from the navbar"
|
||||
},
|
||||
%{
|
||||
key: :hideSiteName,
|
||||
label: "Hide site name",
|
||||
type: :boolean,
|
||||
description: "Whether to hide the site name from the navbar"
|
||||
},
|
||||
%{
|
||||
key: :renderMisskeyMarkdown,
|
||||
label: "Render misskey markdown",
|
||||
type: :boolean,
|
||||
description: "Whether to render Misskey-flavoured markdown"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -1442,13 +1471,14 @@
|
|||
%{
|
||||
key: :theme_color,
|
||||
type: :string,
|
||||
description: "Describe the theme color of the app",
|
||||
description: "Describe the theme color of the app - this is only used for mastodon-fe",
|
||||
suggestions: ["#282c37", "mediumpurple"]
|
||||
},
|
||||
%{
|
||||
key: :background_color,
|
||||
type: :string,
|
||||
description: "Describe the background color of the app",
|
||||
description:
|
||||
"Describe the background color of the app - this is only used for mastodon-fe",
|
||||
suggestions: ["#191b22", "aliceblue"]
|
||||
}
|
||||
]
|
||||
|
@ -2597,9 +2627,10 @@
|
|||
%{
|
||||
key: :proxy_url,
|
||||
label: "Proxy URL",
|
||||
type: [:string, :tuple],
|
||||
description: "Proxy URL",
|
||||
suggestions: ["localhost:9020", {:socks5, :localhost, 3090}]
|
||||
type: :string,
|
||||
description:
|
||||
"Proxy URL - of the format http://host:port. Advise setting in .exs instead of admin-fe due to this being set at boot-time.",
|
||||
suggestions: ["http://localhost:3128"]
|
||||
},
|
||||
%{
|
||||
key: :user_agent,
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
firefox, /emoji/Firefox.gif, Gif,Fun
|
||||
blank, /emoji/blank.png, Fun
|
||||
dinosaur, /emoji/dino walking.gif, Gif
|
||||
100a, /emoji/100a.png, Fun
|
|
@ -283,14 +283,19 @@ config :pleroma, :frontends,
|
|||
"name" => "swagger-ui",
|
||||
"ref" => "stable",
|
||||
"enabled" => true
|
||||
},
|
||||
mastodon: %{
|
||||
"name" => "mastodon-fe",
|
||||
"ref" => "akkoma"
|
||||
}
|
||||
```
|
||||
|
||||
* `:primary` - The frontend that will be served at `/`
|
||||
* `:admin` - The frontend that will be served at `/pleroma/admin`
|
||||
* `:swagger` - Config for developers to act as an API reference to be served at `/akkoma/swaggerui/` (trailing slash _needed_). Disabled by default.
|
||||
* `:mastodon` - The mastodon-fe configuration. This shouldn't need to be changed. This is served at `/web` when installed.
|
||||
|
||||
### :static_fe
|
||||
### :static\_fe
|
||||
|
||||
Render profiles and posts using server-generated HTML that is viewable without using JavaScript.
|
||||
|
||||
|
@ -516,7 +521,7 @@ Available caches:
|
|||
|
||||
### :http
|
||||
|
||||
* `proxy_url`: an upstream proxy to fetch posts and/or media with, (default: `nil`)
|
||||
* `proxy_url`: an upstream proxy to fetch posts and/or media with, (default: `nil`); for example `http://127.0.0.1:3192`. Does not support SOCKS5 proxy, only http(s).
|
||||
* `send_user_agent`: should we include a user agent with HTTP requests? (default: `true`)
|
||||
* `user_agent`: what user agent should we use? (default: `:default`), must be string or `:default`
|
||||
* `adapter`: array of adapter options
|
||||
|
|
|
@ -19,6 +19,10 @@ config :pleroma, :frontends,
|
|||
admin: %{
|
||||
"name" => "admin-fe",
|
||||
"ref" => "stable"
|
||||
},
|
||||
mastodon: %{
|
||||
"name" => "mastodon-fe",
|
||||
"ref" => "akkoma"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -26,12 +30,18 @@ This would serve the frontend from the the folder at `$instance_static/frontends
|
|||
|
||||
Refer to [the frontend CLI task](../../administration/CLI_tasks/frontend) for how to install the frontend's files
|
||||
|
||||
If you wish masto-fe to also be enabled, you will also need to run the install task for `mastodon-fe`. Not doing this will lead to the frontend not working.
|
||||
|
||||
If you choose not to install a frontend for whatever reason, it is recommended that you enable [`:static_fe`](#static_fe) to allow remote users to click "view remote source". Don't bother with this if you've got no unauthenticated access though.
|
||||
|
||||
You can also replace the default "no frontend" page by placing an `index.html` file under your `instance/static/` directory.
|
||||
|
||||
## Mastodon-FE
|
||||
|
||||
Akkoma supports both [glitchsoc](https://github.com/glitch-soc/mastodon)'s more "vanilla" mastodon frontend,
|
||||
as well as [fedibird](https://github.com/fedibird/mastodon)'s extended frontend which has near-feature-parity with akkoma (with quoting and reactions).
|
||||
|
||||
To enable either one, you must run the `frontend.install` task for either `mastodon-fe` or `fedibird-fe` (both `--ref akkoma`), then make sure
|
||||
`:pleroma, :frontends, :mastodon` references the one you want.
|
||||
|
||||
## Swagger (openAPI) documentation viewer
|
||||
|
||||
If you're a developer and you'd like a human-readable rendering of the
|
||||
|
|
|
@ -25,7 +25,16 @@ sudo dnf upgrade --refresh
|
|||
* Install some of the above mentioned programs:
|
||||
|
||||
```shell
|
||||
sudo dnf install git gcc g++ make cmake file-devel postgresql postgresql-contrib
|
||||
sudo dnf install git gcc g++ make cmake file-devel postgresql-server postgresql-contrib
|
||||
```
|
||||
|
||||
* Enable and initialize Postgres:
|
||||
```shell
|
||||
sudo systemctl enable postgresql.service
|
||||
sudo postgresql-setup --initdb --unit postgresql
|
||||
# Allow password auth for postgres
|
||||
sudo sed -E -i 's|(host +all +all +127.0.0.1/32 +)ident|\1md5|' /var/lib/pgsql/data/pg_hba.conf
|
||||
sudo systemctl start postgresql.service
|
||||
```
|
||||
|
||||
### Install Elixir and Erlang
|
||||
|
|
|
@ -60,13 +60,18 @@ your upgrade path here depends on your setup
|
|||
|
||||
### I just run with the built-in frontend
|
||||
|
||||
You'll need to run a single command,
|
||||
You'll need to run a couple of commands,
|
||||
|
||||
```bash
|
||||
# From source
|
||||
mix pleroma.frontend install pleroma-fe
|
||||
# you'll probably want this too
|
||||
mix pleroma.frontend install admin-fe
|
||||
|
||||
# OTP
|
||||
./bin/pleroma_ctl frontend install pleroma-fe
|
||||
# you'll probably want this too
|
||||
./bin/pleroma_ctl frontend install admin-fe
|
||||
```
|
||||
|
||||
### I've run the mix task to install a frontend
|
||||
|
|
|
@ -9,7 +9,7 @@ defmodule Mix.Tasks.Pleroma.Search.Meilisearch do
|
|||
import Ecto.Query
|
||||
|
||||
import Pleroma.Search.Meilisearch,
|
||||
only: [meili_post: 2, meili_put: 2, meili_get: 1, meili_delete!: 1]
|
||||
only: [meili_put: 2, meili_get: 1, meili_delete!: 1]
|
||||
|
||||
def run(["index"]) do
|
||||
start_pleroma()
|
||||
|
@ -27,7 +27,7 @@ def run(["index"]) do
|
|||
end
|
||||
|
||||
{:ok, _} =
|
||||
meili_post(
|
||||
meili_put(
|
||||
"/indexes/objects/settings/ranking-rules",
|
||||
[
|
||||
"published:desc",
|
||||
|
@ -41,7 +41,7 @@ def run(["index"]) do
|
|||
)
|
||||
|
||||
{:ok, _} =
|
||||
meili_post(
|
||||
meili_put(
|
||||
"/indexes/objects/settings/searchable-attributes",
|
||||
[
|
||||
"content"
|
||||
|
@ -91,7 +91,7 @@ def run(["index"]) do
|
|||
)
|
||||
|
||||
with {:ok, res} <- result do
|
||||
if not Map.has_key?(res, "uid") do
|
||||
if not Map.has_key?(res, "indexUid") do
|
||||
IO.puts("\nFailed to index: #{inspect(result)}")
|
||||
end
|
||||
else
|
||||
|
|
|
@ -248,9 +248,13 @@ def limiters_setup do
|
|||
end
|
||||
|
||||
defp http_children do
|
||||
proxy_url = Config.get([:http, :proxy_url])
|
||||
proxy = Pleroma.HTTP.AdapterHelper.format_proxy(proxy_url)
|
||||
|
||||
config =
|
||||
[:http, :adapter]
|
||||
|> Config.get([])
|
||||
|> Pleroma.HTTP.AdapterHelper.maybe_add_proxy_pool(proxy)
|
||||
|> Keyword.put(:name, MyFinch)
|
||||
|
||||
[{Finch, config}]
|
||||
|
|
|
@ -32,9 +32,9 @@ defp get_default, do: Pleroma.Config.get(:default_config)
|
|||
def release_defaults do
|
||||
[
|
||||
pleroma: [
|
||||
{:instance, [static_dir: "/var/lib/pleroma/static"]},
|
||||
{Pleroma.Uploaders.Local, [uploads: "/var/lib/pleroma/uploads"]},
|
||||
{:modules, [runtime_dir: "/var/lib/pleroma/modules"]},
|
||||
{:instance, [static_dir: "/var/lib/akkoma/static"]},
|
||||
{Pleroma.Uploaders.Local, [uploads: "/var/lib/akkoma/uploads"]},
|
||||
{:modules, [runtime_dir: "/var/lib/akkoma/modules"]},
|
||||
{:release, true}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -6,7 +6,7 @@ defmodule Pleroma.HTTP.AdapterHelper do
|
|||
@moduledoc """
|
||||
Configure Tesla.Client with default and customized adapter options.
|
||||
"""
|
||||
@defaults [name: MyFinch, connect_timeout: 5_000, recv_timeout: 5_000]
|
||||
@defaults [name: MyFinch, pool_timeout: 5_000, receive_timeout: 5_000]
|
||||
|
||||
@type proxy_type() :: :socks4 | :socks5
|
||||
@type host() :: charlist() | :inet.ip_address()
|
||||
|
@ -25,15 +25,58 @@ def format_proxy(nil), do: nil
|
|||
|
||||
def format_proxy(proxy_url) do
|
||||
case parse_proxy(proxy_url) do
|
||||
{:ok, host, port} -> {host, port}
|
||||
{:ok, type, host, port} -> {type, host, port}
|
||||
{:ok, host, port} -> {:http, host, port, []}
|
||||
{:ok, type, host, port} -> {type, host, port, []}
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
@spec maybe_add_proxy(keyword(), proxy() | nil) :: keyword()
|
||||
def maybe_add_proxy(opts, nil), do: opts
|
||||
def maybe_add_proxy(opts, proxy), do: Keyword.put_new(opts, :proxy, proxy)
|
||||
|
||||
def maybe_add_proxy(opts, proxy) do
|
||||
Keyword.put(opts, :proxy, proxy)
|
||||
end
|
||||
|
||||
def maybe_add_proxy_pool(opts, nil), do: opts
|
||||
|
||||
def maybe_add_proxy_pool(opts, proxy) do
|
||||
Logger.info("Using HTTP Proxy: #{inspect(proxy)}")
|
||||
|
||||
opts
|
||||
|> maybe_add_pools()
|
||||
|> maybe_add_default_pool()
|
||||
|> maybe_add_conn_opts()
|
||||
|> put_in([:pools, :default, :conn_opts, :proxy], proxy)
|
||||
end
|
||||
|
||||
defp maybe_add_pools(opts) do
|
||||
if Keyword.has_key?(opts, :pools) do
|
||||
opts
|
||||
else
|
||||
Keyword.put(opts, :pools, %{})
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_add_default_pool(opts) do
|
||||
pools = Keyword.get(opts, :pools)
|
||||
|
||||
if Map.has_key?(pools, :default) do
|
||||
opts
|
||||
else
|
||||
put_in(opts, [:pools, :default], [])
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_add_conn_opts(opts) do
|
||||
conn_opts = get_in(opts, [:pools, :default, :conn_opts])
|
||||
|
||||
unless is_nil(conn_opts) do
|
||||
opts
|
||||
else
|
||||
put_in(opts, [:pools, :default, :conn_opts], [])
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Merge default connection & adapter options with received ones.
|
||||
|
@ -46,36 +89,31 @@ def options(%URI{} = uri, opts \\ []) do
|
|||
|> AdapterHelper.Default.options(uri)
|
||||
end
|
||||
|
||||
defp proxy_type("http"), do: {:ok, :http}
|
||||
defp proxy_type("https"), do: {:ok, :https}
|
||||
defp proxy_type(_), do: {:error, :unknown}
|
||||
|
||||
@spec parse_proxy(String.t() | tuple() | nil) ::
|
||||
{:ok, host(), pos_integer()}
|
||||
| {:ok, proxy_type(), host(), pos_integer()}
|
||||
| {:error, atom()}
|
||||
| nil
|
||||
|
||||
def parse_proxy(nil), do: nil
|
||||
|
||||
def parse_proxy(proxy) when is_binary(proxy) do
|
||||
with [host, port] <- String.split(proxy, ":"),
|
||||
{port, ""} <- Integer.parse(port) do
|
||||
{:ok, parse_host(host), port}
|
||||
with %URI{} = uri <- URI.parse(proxy),
|
||||
{:ok, type} <- proxy_type(uri.scheme) do
|
||||
{:ok, type, uri.host, uri.port}
|
||||
else
|
||||
{_, _} ->
|
||||
Logger.warn("Parsing port failed #{inspect(proxy)}")
|
||||
{:error, :invalid_proxy_port}
|
||||
|
||||
:error ->
|
||||
Logger.warn("Parsing port failed #{inspect(proxy)}")
|
||||
{:error, :invalid_proxy_port}
|
||||
|
||||
_ ->
|
||||
Logger.warn("Parsing proxy failed #{inspect(proxy)}")
|
||||
e ->
|
||||
Logger.warn("Parsing proxy failed #{inspect(proxy)}, #{inspect(e)}")
|
||||
{:error, :invalid_proxy}
|
||||
end
|
||||
end
|
||||
|
||||
def parse_proxy(proxy) when is_tuple(proxy) do
|
||||
with {type, host, port} <- proxy do
|
||||
{:ok, type, parse_host(host), port}
|
||||
{:ok, type, host, port}
|
||||
else
|
||||
_ ->
|
||||
Logger.warn("Parsing proxy failed #{inspect(proxy)}")
|
||||
|
|
|
@ -9,7 +9,7 @@ defmodule Pleroma.HTTP.AdapterHelper.Default do
|
|||
|
||||
@spec options(keyword(), URI.t()) :: keyword()
|
||||
def options(opts, _uri) do
|
||||
proxy = Pleroma.Config.get([:http, :proxy_url], nil)
|
||||
proxy = Pleroma.Config.get([:http, :proxy_url])
|
||||
AdapterHelper.maybe_add_proxy(opts, AdapterHelper.format_proxy(proxy))
|
||||
end
|
||||
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.HTTP.AdapterHelper.Gun do
|
||||
@behaviour Pleroma.HTTP.AdapterHelper
|
||||
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.HTTP.AdapterHelper
|
||||
|
||||
require Logger
|
||||
|
||||
@defaults [
|
||||
retry: 1,
|
||||
retry_timeout: 1_000
|
||||
]
|
||||
|
||||
@type pool() :: :federation | :upload | :media | :default
|
||||
|
||||
@spec options(keyword(), URI.t()) :: keyword()
|
||||
def options(incoming_opts \\ [], %URI{} = uri) do
|
||||
proxy =
|
||||
[:http, :proxy_url]
|
||||
|> Config.get()
|
||||
|> AdapterHelper.format_proxy()
|
||||
|
||||
config_opts = Config.get([:http, :adapter], [])
|
||||
|
||||
@defaults
|
||||
|> Keyword.merge(config_opts)
|
||||
|> add_scheme_opts(uri)
|
||||
|> AdapterHelper.maybe_add_proxy(proxy)
|
||||
|> Keyword.merge(incoming_opts)
|
||||
|> put_timeout()
|
||||
end
|
||||
|
||||
defp add_scheme_opts(opts, %{scheme: "http"}), do: opts
|
||||
|
||||
defp add_scheme_opts(opts, %{scheme: "https"}) do
|
||||
Keyword.put(opts, :certificates_verification, true)
|
||||
end
|
||||
|
||||
defp put_timeout(opts) do
|
||||
{recv_timeout, opts} = Keyword.pop(opts, :recv_timeout, pool_timeout(opts[:pool]))
|
||||
# this is the timeout to receive a message from Gun
|
||||
# `:timeout` key is used in Tesla
|
||||
Keyword.put(opts, :timeout, recv_timeout)
|
||||
end
|
||||
|
||||
@spec pool_timeout(pool()) :: non_neg_integer()
|
||||
def pool_timeout(pool) do
|
||||
default = Config.get([:pools, :default, :recv_timeout], 5_000)
|
||||
|
||||
Config.get([:pools, pool, :recv_timeout], default)
|
||||
end
|
||||
|
||||
def limiter_setup do
|
||||
prefix = Pleroma.Gun.ConnectionPool
|
||||
wait = Config.get([:connections_pool, :connection_acquisition_wait])
|
||||
retries = Config.get([:connections_pool, :connection_acquisition_retries])
|
||||
|
||||
:pools
|
||||
|> Config.get([])
|
||||
|> Enum.each(fn {name, opts} ->
|
||||
max_running = Keyword.get(opts, :size, 50)
|
||||
max_waiting = Keyword.get(opts, :max_waiting, 10)
|
||||
|
||||
result =
|
||||
ConcurrentLimiter.new(:"#{prefix}.#{name}", max_running, max_waiting,
|
||||
wait: wait,
|
||||
max_retries: retries
|
||||
)
|
||||
|
||||
case result do
|
||||
:ok -> :ok
|
||||
{:error, :existing} -> :ok
|
||||
end
|
||||
end)
|
||||
|
||||
:ok
|
||||
end
|
||||
end
|
|
@ -1,40 +0,0 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.HTTP.AdapterHelper.Hackney do
|
||||
@behaviour Pleroma.HTTP.AdapterHelper
|
||||
|
||||
@defaults [
|
||||
follow_redirect: true,
|
||||
force_redirect: true
|
||||
]
|
||||
|
||||
@spec options(keyword(), URI.t()) :: keyword()
|
||||
def options(connection_opts \\ [], %URI{} = uri) do
|
||||
proxy = Pleroma.Config.get([:http, :proxy_url])
|
||||
|
||||
config_opts = Pleroma.Config.get([:http, :adapter], [])
|
||||
|
||||
@defaults
|
||||
|> Keyword.merge(config_opts)
|
||||
|> Keyword.merge(connection_opts)
|
||||
|> add_scheme_opts(uri)
|
||||
|> maybe_add_with_body()
|
||||
|> Pleroma.HTTP.AdapterHelper.maybe_add_proxy(proxy)
|
||||
end
|
||||
|
||||
defp add_scheme_opts(opts, %URI{scheme: "https"}) do
|
||||
Keyword.put(opts, :ssl_options, versions: [:"tlsv1.3", :"tlsv1.2", :"tlsv1.1", :tlsv1])
|
||||
end
|
||||
|
||||
defp add_scheme_opts(opts, _), do: opts
|
||||
|
||||
defp maybe_add_with_body(opts) do
|
||||
if opts[:max_body] do
|
||||
Keyword.put(opts, :with_body, true)
|
||||
else
|
||||
opts
|
||||
end
|
||||
end
|
||||
end
|
|
@ -208,10 +208,6 @@ def get_cached_by_ap_id(ap_id) do
|
|||
end
|
||||
end
|
||||
|
||||
def context_mapping(context) do
|
||||
Object.change(%Object{}, %{data: %{"id" => context}})
|
||||
end
|
||||
|
||||
def make_tombstone(%Object{data: %{"id" => id, "type" => type}}, deleted \\ DateTime.utc_now()) do
|
||||
%ObjectTombstone{
|
||||
id: id,
|
||||
|
|
|
@ -25,7 +25,7 @@ defp mix_task(task, args) do
|
|||
module = Module.split(module)
|
||||
|
||||
match?(["Mix", "Tasks", "Pleroma" | _], module) and
|
||||
String.downcase(List.last(module)) == task
|
||||
task_match?(module, task)
|
||||
end)
|
||||
|
||||
if module do
|
||||
|
@ -35,6 +35,13 @@ defp mix_task(task, args) do
|
|||
end
|
||||
end
|
||||
|
||||
defp task_match?(["Mix", "Tasks", "Pleroma" | module_path], task) do
|
||||
module_path
|
||||
|> Enum.join(".")
|
||||
|> String.downcase()
|
||||
|> String.equivalent?(String.downcase(task))
|
||||
end
|
||||
|
||||
def migrate(args) do
|
||||
Mix.Tasks.Pleroma.Ecto.Migrate.run(args)
|
||||
end
|
||||
|
|
|
@ -23,7 +23,7 @@ def es_query(:activity, query, offset, limit) do
|
|||
timeout: "5s",
|
||||
sort: [
|
||||
"_score",
|
||||
%{_timestamp: %{order: "desc", format: "basic_date_time"}}
|
||||
%{"_timestamp" => %{order: "desc", format: "basic_date_time"}}
|
||||
],
|
||||
query: %{
|
||||
bool: %{
|
||||
|
@ -62,8 +62,12 @@ def search(user, query, options) do
|
|||
Task.async(fn ->
|
||||
q = es_query(:activity, parsed_query, offset, limit)
|
||||
|
||||
Pleroma.Search.Elasticsearch.Store.search(:activities, q)
|
||||
|> Enum.filter(fn x -> Visibility.visible_for_user?(x, user) end)
|
||||
:activities
|
||||
|> Pleroma.Search.Elasticsearch.Store.search(q)
|
||||
|> Enum.filter(fn x ->
|
||||
x.data["type"] == "Create" && x.object.data["type"] == "Note" &&
|
||||
Visibility.visible_for_user?(x, user)
|
||||
end)
|
||||
end)
|
||||
|
||||
activity_results = Task.await(activity_task)
|
||||
|
|
|
@ -42,7 +42,6 @@ def search(:activities, q) do
|
|||
results
|
||||
|> Enum.map(fn result -> result["_id"] end)
|
||||
|> Pleroma.Activity.all_by_ids_with_object()
|
||||
|> Enum.sort(&(&1.inserted_at >= &2.inserted_at))
|
||||
else
|
||||
e ->
|
||||
Logger.error(e)
|
||||
|
|
|
@ -107,22 +107,18 @@ def persist(%{"type" => type} = object, meta) when type in @object_types do
|
|||
|
||||
@impl true
|
||||
def persist(object, meta) do
|
||||
if meta[:activity] do
|
||||
{:ok, meta[:activity], meta}
|
||||
else
|
||||
with local <- Keyword.fetch!(meta, :local),
|
||||
{recipients, _, _} <- get_recipients(object),
|
||||
{:ok, activity} <-
|
||||
Repo.insert(%Activity{
|
||||
data: object,
|
||||
local: local,
|
||||
recipients: recipients,
|
||||
actor: object["actor"]
|
||||
}),
|
||||
# TODO: add tests for expired activities, when Note type will be supported in new pipeline
|
||||
{:ok, _} <- maybe_create_activity_expiration(activity) do
|
||||
{:ok, activity, meta}
|
||||
end
|
||||
with local <- Keyword.fetch!(meta, :local),
|
||||
{recipients, _, _} <- get_recipients(object),
|
||||
{:ok, activity} <-
|
||||
Repo.insert(%Activity{
|
||||
data: object,
|
||||
local: local,
|
||||
recipients: recipients,
|
||||
actor: object["actor"]
|
||||
}),
|
||||
# TODO: add tests for expired activities, when Note type will be supported in new pipeline
|
||||
{:ok, _} <- maybe_create_activity_expiration(activity) do
|
||||
{:ok, activity, meta}
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -331,7 +327,9 @@ def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
|
|||
end
|
||||
end
|
||||
|
||||
defp do_unfollow(follower, followed, activity_id, local) do
|
||||
defp do_unfollow(follower, followed, activity_id, local)
|
||||
|
||||
defp do_unfollow(follower, followed, activity_id, local) when local == true do
|
||||
with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
|
||||
{:ok, follow_activity} <- update_follow_state(follow_activity, "cancelled"),
|
||||
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
|
||||
|
@ -345,6 +343,32 @@ defp do_unfollow(follower, followed, activity_id, local) do
|
|||
end
|
||||
end
|
||||
|
||||
defp do_unfollow(follower, followed, activity_id, false) do
|
||||
# On a remote unfollow, _remove_ their activity from the database, since some software (MISSKEEEEY)
|
||||
# uses deterministic ids for follows.
|
||||
with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
|
||||
{:ok, _activity} <- Repo.delete(follow_activity),
|
||||
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
|
||||
unfollow_activity <- remote_unfollow_data(unfollow_data),
|
||||
_ <- notify_and_stream(unfollow_activity) do
|
||||
{:ok, unfollow_activity}
|
||||
else
|
||||
nil -> nil
|
||||
{:error, error} -> Repo.rollback(error)
|
||||
end
|
||||
end
|
||||
|
||||
defp remote_unfollow_data(data) do
|
||||
{recipients, _, _} = get_recipients(data)
|
||||
|
||||
%Activity{
|
||||
data: data,
|
||||
local: false,
|
||||
actor: data["actor"],
|
||||
recipients: recipients
|
||||
}
|
||||
end
|
||||
|
||||
@spec flag(map()) :: {:ok, Activity.t()} | {:error, any()}
|
||||
def flag(params) do
|
||||
with {:ok, result} <- Repo.transaction(fn -> do_flag(params) end) do
|
||||
|
|
|
@ -108,6 +108,8 @@ defp remote_mention_resolver(
|
|||
end
|
||||
|
||||
# https://github.com/misskey-dev/misskey/pull/8787
|
||||
# Misskey has an awful tendency to drop all custom formatting when it sends remotely
|
||||
# So this basically reprocesses their MFM source
|
||||
defp fix_misskey_content(
|
||||
%{"source" => %{"mediaType" => "text/x.misskeymarkdown", "content" => content}} = object
|
||||
)
|
||||
|
@ -174,7 +176,7 @@ def changeset(struct, data) do
|
|||
defp validate_data(data_cng) do
|
||||
data_cng
|
||||
|> validate_inclusion(:type, ["Article", "Note", "Page"])
|
||||
|> validate_required([:id, :actor, :attributedTo, :type, :context, :context_id])
|
||||
|> validate_required([:id, :actor, :attributedTo, :type, :context])
|
||||
|> CommonValidations.validate_any_presence([:cc, :to])
|
||||
|> CommonValidations.validate_fields_match([:actor, :attributedTo])
|
||||
|> CommonValidations.validate_actor_presence()
|
||||
|
|
|
@ -51,8 +51,6 @@ defmacro status_object_fields do
|
|||
field(:summary, :string)
|
||||
|
||||
field(:context, :string)
|
||||
# short identifier for PleromaFE to group statuses by context
|
||||
field(:context_id, :integer)
|
||||
|
||||
field(:sensitive, :boolean, default: false)
|
||||
field(:replies_count, :integer, default: 0)
|
||||
|
|
|
@ -22,14 +22,12 @@ def cast_and_filter_recipients(message, field, follower_collection, field_fallba
|
|||
end
|
||||
|
||||
def fix_object_defaults(data) do
|
||||
%{data: %{"id" => context}, id: context_id} =
|
||||
Utils.create_context(data["context"] || data["conversation"])
|
||||
context = Utils.maybe_create_context(data["context"] || data["conversation"])
|
||||
|
||||
%User{follower_address: follower_collection} = User.get_cached_by_ap_id(data["attributedTo"])
|
||||
|
||||
data
|
||||
|> Map.put("context", context)
|
||||
|> Map.put("context_id", context_id)
|
||||
|> cast_and_filter_recipients("to", follower_collection)
|
||||
|> cast_and_filter_recipients("cc", follower_collection)
|
||||
|> cast_and_filter_recipients("bto", follower_collection)
|
||||
|
|
|
@ -62,7 +62,7 @@ def changeset(struct, data) do
|
|||
defp validate_data(data_cng) do
|
||||
data_cng
|
||||
|> validate_inclusion(:type, ["Event"])
|
||||
|> validate_required([:id, :actor, :attributedTo, :type, :context, :context_id])
|
||||
|> validate_required([:id, :actor, :attributedTo, :type, :context])
|
||||
|> CommonValidations.validate_any_presence([:cc, :to])
|
||||
|> CommonValidations.validate_fields_match([:actor, :attributedTo])
|
||||
|> CommonValidations.validate_actor_presence()
|
||||
|
|
|
@ -80,7 +80,7 @@ def changeset(struct, data) do
|
|||
defp validate_data(data_cng) do
|
||||
data_cng
|
||||
|> validate_inclusion(:type, ["Question"])
|
||||
|> validate_required([:id, :actor, :attributedTo, :type, :context, :context_id])
|
||||
|> validate_required([:id, :actor, :attributedTo, :type, :context])
|
||||
|> CommonValidations.validate_any_presence([:cc, :to])
|
||||
|> CommonValidations.validate_fields_match([:actor, :attributedTo])
|
||||
|> CommonValidations.validate_actor_presence()
|
||||
|
|
|
@ -509,13 +509,12 @@ def handle_incoming(%{"type" => type} = data, _options)
|
|||
|
||||
def handle_incoming(
|
||||
%{"type" => type} = data,
|
||||
options
|
||||
_options
|
||||
)
|
||||
when type in ~w{Update Block Follow Accept Reject} do
|
||||
|
||||
with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
|
||||
{:ok, activity, _} <-
|
||||
Pipeline.common_pipeline(data, Keyword.put(options, :local, false)) do
|
||||
Pipeline.common_pipeline(data, local: false) do
|
||||
{:ok, activity}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -154,22 +154,7 @@ def get_notified_from_object(object) do
|
|||
Notification.get_notified_from_activity(%Activity{data: object}, false)
|
||||
end
|
||||
|
||||
def create_context(context) do
|
||||
context = context || generate_id("contexts")
|
||||
|
||||
# Ecto has problems accessing the constraint inside the jsonb,
|
||||
# so we explicitly check for the existed object before insert
|
||||
object = Object.get_cached_by_ap_id(context)
|
||||
|
||||
with true <- is_nil(object),
|
||||
changeset <- Object.context_mapping(context),
|
||||
{:ok, inserted_object} <- Repo.insert(changeset) do
|
||||
inserted_object
|
||||
else
|
||||
_ ->
|
||||
object
|
||||
end
|
||||
end
|
||||
def maybe_create_context(context), do: context || generate_id("contexts")
|
||||
|
||||
@doc """
|
||||
Enqueues an activity for federation if it's local
|
||||
|
@ -201,18 +186,16 @@ def lazy_put_activity_defaults(map, true) do
|
|||
|> Map.put_new("id", "pleroma:fakeid")
|
||||
|> Map.put_new_lazy("published", &make_date/0)
|
||||
|> Map.put_new("context", "pleroma:fakecontext")
|
||||
|> Map.put_new("context_id", -1)
|
||||
|> lazy_put_object_defaults(true)
|
||||
end
|
||||
|
||||
def lazy_put_activity_defaults(map, _fake?) do
|
||||
%{data: %{"id" => context}, id: context_id} = create_context(map["context"])
|
||||
context = maybe_create_context(map["context"])
|
||||
|
||||
map
|
||||
|> Map.put_new_lazy("id", &generate_activity_id/0)
|
||||
|> Map.put_new_lazy("published", &make_date/0)
|
||||
|> Map.put_new("context", context)
|
||||
|> Map.put_new("context_id", context_id)
|
||||
|> lazy_put_object_defaults(false)
|
||||
end
|
||||
|
||||
|
@ -226,7 +209,6 @@ defp lazy_put_object_defaults(%{"object" => map} = activity, true)
|
|||
|> Map.put_new("id", "pleroma:fake_object_id")
|
||||
|> Map.put_new_lazy("published", &make_date/0)
|
||||
|> Map.put_new("context", activity["context"])
|
||||
|> Map.put_new("context_id", activity["context_id"])
|
||||
|> Map.put_new("fake", true)
|
||||
|
||||
%{activity | "object" => object}
|
||||
|
@ -239,7 +221,6 @@ defp lazy_put_object_defaults(%{"object" => map} = activity, _)
|
|||
|> Map.put_new_lazy("id", &generate_object_id/0)
|
||||
|> Map.put_new_lazy("published", &make_date/0)
|
||||
|> Map.put_new("context", activity["context"])
|
||||
|> Map.put_new("context_id", activity["context_id"])
|
||||
|
||||
%{activity | "object" => object}
|
||||
end
|
||||
|
|
|
@ -152,9 +152,15 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
|
|||
description:
|
||||
"A map consisting of alternate representations of the `content` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`"
|
||||
},
|
||||
context: %Schema{
|
||||
type: :string,
|
||||
description: "The thread identifier the status is associated with"
|
||||
},
|
||||
conversation_id: %Schema{
|
||||
type: :integer,
|
||||
description: "The ID of the AP context the status is associated with (if any)"
|
||||
deprecated: true,
|
||||
description:
|
||||
"The ID of the AP context the status is associated with (if any); deprecated, please use `context` instead"
|
||||
},
|
||||
direct_conversation_id: %Schema{
|
||||
type: :integer,
|
||||
|
@ -356,6 +362,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
|
|||
"pinned" => false,
|
||||
"pleroma" => %{
|
||||
"content" => %{"text/plain" => "foobar"},
|
||||
"context" => "http://localhost:4001/objects/8b4c0c80-6a37-4d2a-b1b9-05a19e3875aa",
|
||||
"conversation_id" => 345_972,
|
||||
"direct_conversation_id" => nil,
|
||||
"emoji_reactions" => [],
|
||||
|
|
|
@ -285,11 +285,11 @@ def format_input(text, "text/html", options) do
|
|||
|
||||
def format_input(text, "text/x.misskeymarkdown", options) do
|
||||
text
|
||||
|> Formatter.markdown_to_html()
|
||||
|> MfmParser.Parser.parse()
|
||||
|> MfmParser.Encoder.to_html()
|
||||
|> Formatter.linkify(options)
|
||||
|> Formatter.html_escape("text/x.misskeymarkdown")
|
||||
|> (fn {text, mentions, tags} ->
|
||||
{String.replace(text, ~r/\r?\n/, "<br>"), mentions, tags}
|
||||
end).()
|
||||
|> Formatter.html_escape("text/html")
|
||||
end
|
||||
|
||||
def format_input(text, "text/markdown", options) do
|
||||
|
@ -458,35 +458,6 @@ def get_report_statuses(%User{ap_id: actor}, %{status_ids: status_ids})
|
|||
|
||||
def get_report_statuses(_, _), do: {:ok, nil}
|
||||
|
||||
# DEPRECATED mostly, context objects are now created at insertion time.
|
||||
def context_to_conversation_id(context) do
|
||||
with %Object{id: id} <- Object.get_cached_by_ap_id(context) do
|
||||
id
|
||||
else
|
||||
_e ->
|
||||
changeset = Object.context_mapping(context)
|
||||
|
||||
case Repo.insert(changeset) do
|
||||
{:ok, %{id: id}} ->
|
||||
id
|
||||
|
||||
# This should be solved by an upsert, but it seems ecto
|
||||
# has problems accessing the constraint inside the jsonb.
|
||||
{:error, _} ->
|
||||
Object.get_cached_by_ap_id(context).id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def conversation_id_to_context(id) do
|
||||
with %Object{data: %{"id" => context}} <- Repo.get(Object, id) do
|
||||
context
|
||||
else
|
||||
_e ->
|
||||
{:error, dgettext("errors", "No such conversation")}
|
||||
end
|
||||
end
|
||||
|
||||
def validate_character_limit("" = _full_payload, [] = _attachments) do
|
||||
{:error, dgettext("errors", "Cannot post an empty status without attachments")}
|
||||
end
|
||||
|
|
|
@ -86,17 +86,17 @@ def perform(:incoming_ap_doc, params) do
|
|||
# NOTE: we use the actor ID to do the containment, this is fine because an
|
||||
# actor shouldn't be acting on objects outside their own AP server.
|
||||
with {_, {:ok, _user}} <- {:actor, ap_enabled_actor(actor)},
|
||||
{true, activity} <- should_process?(Activity.normalize(params["id"])),
|
||||
nil <- Activity.normalize(params["id"]),
|
||||
{_, :ok} <-
|
||||
{:correct_origin?, Containment.contain_origin_from_id(actor, params)},
|
||||
{:ok, activity} <- Transmogrifier.handle_incoming(params, activity: activity) do
|
||||
{:ok, activity} <- Transmogrifier.handle_incoming(params) do
|
||||
{:ok, activity}
|
||||
else
|
||||
{:correct_origin?, _} ->
|
||||
Logger.debug("Origin containment failure for #{params["id"]}")
|
||||
{:error, :origin_containment_failed}
|
||||
|
||||
{false, nil} ->
|
||||
%Activity{} ->
|
||||
Logger.debug("Already had #{params["id"]}")
|
||||
{:error, :already_present}
|
||||
|
||||
|
@ -111,7 +111,6 @@ def perform(:incoming_ap_doc, params) do
|
|||
|
||||
e ->
|
||||
# Just drop those for now
|
||||
IO.inspect(e)
|
||||
Logger.debug(fn -> "Unhandled activity\n" <> Jason.encode!(params, pretty: true) end)
|
||||
{:error, e}
|
||||
end
|
||||
|
@ -126,23 +125,4 @@ def ap_enabled_actor(id) do
|
|||
ActivityPub.make_user_from_ap_id(id)
|
||||
end
|
||||
end
|
||||
|
||||
defp should_process?(%Activity{data: %{"type" => "Follow"}} = activity) do
|
||||
# Misskey can resend follows when it shouldn't
|
||||
# A follow/unfollow/follow in misskey land will die because it
|
||||
# reuses the same ID
|
||||
{true, activity}
|
||||
end
|
||||
|
||||
defp should_process?(
|
||||
%Activity{data: %{"type" => "Undo", "object" => %{"type" => "Follow"}}} = activity
|
||||
) do
|
||||
{true, activity}
|
||||
end
|
||||
|
||||
defp should_process?(%Activity{} = e) do
|
||||
{false, nil}
|
||||
end
|
||||
|
||||
defp should_process?(_), do: {true, nil}
|
||||
end
|
||||
|
|
|
@ -27,9 +27,21 @@ defmodule Pleroma.Web.MastoFEController do
|
|||
def index(conn, _params) do
|
||||
with %{assigns: %{user: %User{} = user, token: %Token{app_id: token_app_id} = token}} <- conn,
|
||||
{:ok, %{id: ^token_app_id}} <- AuthController.local_mastofe_app() do
|
||||
flavour =
|
||||
[:frontends, :mastodon]
|
||||
|> Pleroma.Config.get()
|
||||
|> Map.get("name", "mastodon-fe")
|
||||
|
||||
index =
|
||||
if flavour == "fedibird-fe" do
|
||||
"fedibird.index.html"
|
||||
else
|
||||
"glitchsoc.index.html"
|
||||
end
|
||||
|
||||
conn
|
||||
|> put_layout(false)
|
||||
|> render("index.html",
|
||||
|> render(index,
|
||||
token: token.token,
|
||||
user: user,
|
||||
custom_emojis: Pleroma.Emoji.get_all()
|
||||
|
|
|
@ -57,11 +57,19 @@ defp get_replied_to_activities(activities) do
|
|||
end)
|
||||
end
|
||||
|
||||
defp get_context_id(%{data: %{"context_id" => context_id}}) when not is_nil(context_id),
|
||||
do: context_id
|
||||
# DEPRECATED This field seems to be a left-over from the StatusNet era.
|
||||
# If your application uses `pleroma.conversation_id`: this field is deprecated.
|
||||
# It is currently stubbed instead by doing a CRC32 of the context, and
|
||||
# clearing the MSB to avoid overflow exceptions with signed integers on the
|
||||
# different clients using this field (Java/Kotlin code, mostly; see Husky.)
|
||||
# This should be removed in a future version of Pleroma. Pleroma-FE currently
|
||||
# depends on this field, as well.
|
||||
defp get_context_id(%{data: %{"context" => context}}) when is_binary(context) do
|
||||
use Bitwise
|
||||
|
||||
defp get_context_id(%{data: %{"context" => context}}) when is_binary(context),
|
||||
do: Utils.context_to_conversation_id(context)
|
||||
:erlang.crc32(context)
|
||||
|> band(bnot(0x8000_0000))
|
||||
end
|
||||
|
||||
defp get_context_id(_), do: nil
|
||||
|
||||
|
@ -367,9 +375,11 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
|
|||
emojis: build_emojis(object.data["emoji"]),
|
||||
quote_id: if(quote, do: quote.id, else: nil),
|
||||
quote: maybe_render_quote(quote, opts),
|
||||
emoji_reactions: emoji_reactions,
|
||||
pleroma: %{
|
||||
local: activity.local,
|
||||
conversation_id: get_context_id(activity),
|
||||
context: object.data["context"],
|
||||
in_reply_to_account_acct: reply_to_user && reply_to_user.nickname,
|
||||
content: %{"text/plain" => content_plaintext},
|
||||
spoiler_text: %{"text/plain" => summary},
|
||||
|
@ -580,7 +590,8 @@ defp build_emoji_map(emoji, users, url, current_user) do
|
|||
name: emoji,
|
||||
count: length(users),
|
||||
url: MediaProxy.url(url),
|
||||
me: !!(current_user && current_user.ap_id in users)
|
||||
me: !!(current_user && current_user.ap_id in users),
|
||||
account_ids: Enum.map(users, fn user -> User.get_cached_by_ap_id(user).id end)
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -32,8 +32,15 @@ def init(%{qs: qs} = req, state) do
|
|||
req
|
||||
end
|
||||
|
||||
{:cowboy_websocket, req, %{user: user, topic: topic, count: 0, timer: nil},
|
||||
%{idle_timeout: @timeout}}
|
||||
{:cowboy_websocket, req,
|
||||
%{
|
||||
user: user,
|
||||
topic: topic,
|
||||
count: 0,
|
||||
timer: nil,
|
||||
subscriptions: [],
|
||||
oauth_token: oauth_token
|
||||
}, %{idle_timeout: @timeout}}
|
||||
else
|
||||
{:error, :bad_topic} ->
|
||||
Logger.debug("#{__MODULE__} bad topic #{inspect(req)}")
|
||||
|
@ -65,21 +72,50 @@ def websocket_handle(:pong, state) do
|
|||
# We only receive pings for now
|
||||
def websocket_handle(:ping, state), do: {:ok, state}
|
||||
|
||||
def websocket_handle({:text, "ping"}, state) do
|
||||
def websocket_handle({:text, ping}, state) when ping in ~w[ping PING] do
|
||||
if state.timer, do: Process.cancel_timer(state.timer)
|
||||
{:reply, {:text, "pong"}, %{state | timer: timer()}}
|
||||
end
|
||||
|
||||
def websocket_handle({:text, text}, state) do
|
||||
with {:ok, json} <- Jason.decode(text) do
|
||||
websocket_handle({:json, json}, state)
|
||||
else
|
||||
_ ->
|
||||
Logger.error("#{__MODULE__} received text frame: #{text}")
|
||||
{:ok, state}
|
||||
end
|
||||
end
|
||||
|
||||
def websocket_handle(
|
||||
{:json, %{"type" => "subscribe", "stream" => stream_name}},
|
||||
%{user: user, oauth_token: token} = state
|
||||
) do
|
||||
with {:ok, topic} <- Streamer.get_topic(stream_name, user, token, %{}) do
|
||||
new_subscriptions =
|
||||
[topic | Map.get(state, :subscriptions, [])]
|
||||
|> Enum.uniq()
|
||||
|
||||
{:ok, _topic} = Streamer.add_socket(topic, user)
|
||||
|
||||
{:ok, Map.put(state, :subscriptions, new_subscriptions)}
|
||||
else
|
||||
_ ->
|
||||
Logger.error("#{__MODULE__} received invalid topic: #{stream_name}")
|
||||
{:ok, state}
|
||||
end
|
||||
end
|
||||
|
||||
def websocket_handle(frame, state) do
|
||||
Logger.error("#{__MODULE__} received frame: #{inspect(frame)}")
|
||||
{:ok, state}
|
||||
end
|
||||
|
||||
def websocket_info({:render_with_user, view, template, item}, state) do
|
||||
def websocket_info({:render_with_user, view, template, item, topic}, state) do
|
||||
user = %User{} = User.get_cached_by_ap_id(state.user.ap_id)
|
||||
|
||||
unless Streamer.filtered_by_user?(user, item) do
|
||||
websocket_info({:text, view.render(template, item, user)}, %{state | user: user})
|
||||
websocket_info({:text, view.render(template, item, user, topic)}, %{state | user: user})
|
||||
else
|
||||
{:ok, state}
|
||||
end
|
||||
|
|
|
@ -74,6 +74,8 @@ defp filter(reactions, %{emoji: emoji}) when is_binary(emoji) do
|
|||
defp filter(reactions, _), do: reactions
|
||||
|
||||
def create(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
|
||||
emoji = Pleroma.Emoji.maybe_quote(emoji)
|
||||
|
||||
with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji) do
|
||||
activity = Activity.get_by_id(activity_id)
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
|
||||
import Plug.Conn
|
||||
import Phoenix.Controller, only: [get_format: 1, text: 2]
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Web.Router
|
||||
require Logger
|
||||
|
||||
def init(options) do
|
||||
|
@ -25,21 +27,45 @@ def call(conn, _opts) do
|
|||
end
|
||||
end
|
||||
|
||||
def route_aliases(%{path_info: ["objects", id]}) do
|
||||
ap_id = Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :object, id)
|
||||
|
||||
with %Activity{} = activity <- Activity.get_by_object_ap_id_with_object(ap_id) do
|
||||
["/notice/#{activity.id}"]
|
||||
else
|
||||
_ -> []
|
||||
end
|
||||
end
|
||||
|
||||
def route_aliases(_), do: []
|
||||
|
||||
defp assign_valid_signature_on_route_aliases(conn, []), do: conn
|
||||
|
||||
defp assign_valid_signature_on_route_aliases(%{assigns: %{valid_signature: true}} = conn, _),
|
||||
do: conn
|
||||
|
||||
defp assign_valid_signature_on_route_aliases(conn, [path | rest]) do
|
||||
request_target = String.downcase("#{conn.method}") <> " #{path}"
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header("(request-target)", request_target)
|
||||
|> case do
|
||||
%{assigns: %{digest: digest}} = conn -> put_req_header(conn, "digest", digest)
|
||||
conn -> conn
|
||||
end
|
||||
|
||||
conn
|
||||
|> assign(:valid_signature, HTTPSignatures.validate_conn(conn))
|
||||
|> assign_valid_signature_on_route_aliases(rest)
|
||||
end
|
||||
|
||||
defp maybe_assign_valid_signature(conn) do
|
||||
if has_signature_header?(conn) do
|
||||
# set (request-target) header to the appropriate value
|
||||
# we also replace the digest header with the one we computed
|
||||
request_target = String.downcase("#{conn.method}") <> " #{conn.request_path}"
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header("(request-target)", request_target)
|
||||
|> case do
|
||||
%{assigns: %{digest: digest}} = conn -> put_req_header(conn, "digest", digest)
|
||||
conn -> conn
|
||||
end
|
||||
|
||||
assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn))
|
||||
possible_paths = route_aliases(conn) ++ [conn.request_path]
|
||||
assign_valid_signature_on_route_aliases(conn, possible_paths)
|
||||
else
|
||||
Logger.debug("No signature header!")
|
||||
conn
|
||||
|
|
|
@ -457,6 +457,11 @@ defmodule Pleroma.Web.Router do
|
|||
get("/federation_status", InstancesController, :show)
|
||||
end
|
||||
|
||||
scope "/api/v1", Pleroma.Web.PleromaAPI do
|
||||
pipe_through(:authenticated_api)
|
||||
put("/statuses/:id/emoji_reactions/:emoji", EmojiReactionController, :create)
|
||||
end
|
||||
|
||||
scope "/api/v1", Pleroma.Web.MastodonAPI do
|
||||
pipe_through(:authenticated_api)
|
||||
|
||||
|
|
|
@ -114,6 +114,11 @@ def get_topic("list", _user, _oauth_token, _params) do
|
|||
{:error, :unauthorized}
|
||||
end
|
||||
|
||||
# mastodon multi-topic WS
|
||||
def get_topic(nil, _user, _oauth_token, _params) do
|
||||
{:ok, :multi}
|
||||
end
|
||||
|
||||
def get_topic(_stream, _user, _oauth_token, _params) do
|
||||
{:error, :bad_topic}
|
||||
end
|
||||
|
@ -186,8 +191,8 @@ defp do_stream("direct", item) do
|
|||
end
|
||||
|
||||
defp do_stream("follow_relationship", item) do
|
||||
text = StreamerView.render("follow_relationships_update.json", item)
|
||||
user_topic = "user:#{item.follower.id}"
|
||||
text = StreamerView.render("follow_relationships_update.json", item, user_topic)
|
||||
|
||||
Logger.debug("Trying to push follow relationship update to #{user_topic}\n\n")
|
||||
|
||||
|
@ -235,7 +240,7 @@ defp do_stream(topic, %Notification{} = item)
|
|||
when topic in ["user", "user:notification"] do
|
||||
Registry.dispatch(@registry, "#{topic}:#{item.user_id}", fn list ->
|
||||
Enum.each(list, fn {pid, _auth} ->
|
||||
send(pid, {:render_with_user, StreamerView, "notification.json", item})
|
||||
send(pid, {:render_with_user, StreamerView, "notification.json", item, topic})
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
@ -259,7 +264,7 @@ defp do_stream(topic, item) do
|
|||
end
|
||||
|
||||
defp push_to_socket(topic, %Participation{} = participation) do
|
||||
rendered = StreamerView.render("conversation.json", participation)
|
||||
rendered = StreamerView.render("conversation.json", participation, topic)
|
||||
|
||||
Registry.dispatch(@registry, topic, fn list ->
|
||||
Enum.each(list, fn {pid, _} ->
|
||||
|
@ -283,12 +288,12 @@ defp push_to_socket(topic, %Activity{
|
|||
defp push_to_socket(_topic, %Activity{data: %{"type" => "Delete"}}), do: :noop
|
||||
|
||||
defp push_to_socket(topic, item) do
|
||||
anon_render = StreamerView.render("update.json", item)
|
||||
anon_render = StreamerView.render("update.json", item, topic)
|
||||
|
||||
Registry.dispatch(@registry, topic, fn list ->
|
||||
Enum.each(list, fn {pid, auth?} ->
|
||||
if auth? do
|
||||
send(pid, {:render_with_user, StreamerView, "update.json", item})
|
||||
send(pid, {:render_with_user, StreamerView, "update.json", item, topic})
|
||||
else
|
||||
send(pid, {:text, anon_render})
|
||||
end
|
||||
|
|
34
lib/pleroma/web/templates/masto_fe/fedibird.index.html.eex
Normal file
34
lib/pleroma/web/templates/masto_fe/fedibird.index.html.eex
Normal file
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta content='width=device-width, initial-scale=1' name='viewport'>
|
||||
<title>
|
||||
<%= Config.get([:instance, :name]) %>
|
||||
</title>
|
||||
<link rel="icon" type="image/png" href="/favicon.png"/>
|
||||
<link rel="manifest" type="applicaton/manifest+json" href="<%= Routes.masto_fe_path(Pleroma.Web.Endpoint, :manifest) %>" />
|
||||
|
||||
<meta name="theme-color" content="<%= Config.get([:manifest, :theme_color]) %>" />
|
||||
|
||||
<script id='initial-state' type='application/json'><%= initial_state(@token, @user, @custom_emojis) %></script>
|
||||
|
||||
<script crossorigin='anonymous' src="/packs/js/common.js"></script>
|
||||
<script crossorigin='anonymous' src="/packs/js/locale_en.js"></script>
|
||||
|
||||
<link rel='preload' as='script' crossorigin='anonymous' href='/packs/js/features/getting_started.js'>
|
||||
<link rel='preload' as='script' crossorigin='anonymous' href='/packs/js/features/compose.js'>
|
||||
<link rel='preload' as='script' crossorigin='anonymous' href='/packs/js/features/home_timeline.js'>
|
||||
<link rel='preload' as='script' crossorigin='anonymous' href='/packs/js/features/notifications.js'>
|
||||
<script crossorigin='anonymous' src="/packs/js/application.js"></script>
|
||||
|
||||
|
||||
<link rel="stylesheet" media="all" href="/packs/css/common.css" />
|
||||
<link rel="stylesheet" media="all" href="/packs/css/default.css" />
|
||||
|
||||
</head>
|
||||
<body class='app-body no-reduce-motion system-font'>
|
||||
<div class='app-holder' data-props='{"locale":"en"}' id='mastodon'>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -14,6 +14,7 @@ def initial_state(token, user, custom_emojis) do
|
|||
|
||||
%{
|
||||
meta: %{
|
||||
title: Config.get([:instance, :name]),
|
||||
streaming_api_base_url: Pleroma.Web.Endpoint.websocket_url(),
|
||||
access_token: token,
|
||||
locale: "en",
|
||||
|
@ -27,7 +28,11 @@ def initial_state(token, user, custom_emojis) do
|
|||
display_sensitive_media: false,
|
||||
reduce_motion: false,
|
||||
max_toot_chars: limit,
|
||||
mascot: User.get_mascot(user)["url"]
|
||||
mascot: User.get_mascot(user)["url"],
|
||||
show_quote_button: true,
|
||||
enable_reaction: true,
|
||||
compact_reaction: false,
|
||||
advanced_layout: true
|
||||
},
|
||||
poll_limits: Config.get([:instance, :poll_limits]),
|
||||
rights: %{
|
||||
|
@ -56,6 +61,7 @@ def initial_state(token, user, custom_emojis) do
|
|||
"video\/mp4"
|
||||
]
|
||||
},
|
||||
lists: [],
|
||||
settings: user.mastofe_settings || %{},
|
||||
push_subscription: nil,
|
||||
accounts: %{user.id => render(AccountView, "show.json", user: user, for: user)},
|
||||
|
|
|
@ -11,8 +11,9 @@ defmodule Pleroma.Web.StreamerView do
|
|||
alias Pleroma.User
|
||||
alias Pleroma.Web.MastodonAPI.NotificationView
|
||||
|
||||
def render("update.json", %Activity{} = activity, %User{} = user) do
|
||||
def render("update.json", %Activity{} = activity, %User{} = user, topic) do
|
||||
%{
|
||||
stream: [topic],
|
||||
event: "update",
|
||||
payload:
|
||||
Pleroma.Web.MastodonAPI.StatusView.render(
|
||||
|
@ -25,8 +26,9 @@ def render("update.json", %Activity{} = activity, %User{} = user) do
|
|||
|> Jason.encode!()
|
||||
end
|
||||
|
||||
def render("notification.json", %Notification{} = notify, %User{} = user) do
|
||||
def render("notification.json", %Notification{} = notify, %User{} = user, topic) do
|
||||
%{
|
||||
stream: [topic],
|
||||
event: "notification",
|
||||
payload:
|
||||
NotificationView.render(
|
||||
|
@ -38,8 +40,9 @@ def render("notification.json", %Notification{} = notify, %User{} = user) do
|
|||
|> Jason.encode!()
|
||||
end
|
||||
|
||||
def render("update.json", %Activity{} = activity) do
|
||||
def render("update.json", %Activity{} = activity, topic) do
|
||||
%{
|
||||
stream: [topic],
|
||||
event: "update",
|
||||
payload:
|
||||
Pleroma.Web.MastodonAPI.StatusView.render(
|
||||
|
@ -51,8 +54,9 @@ def render("update.json", %Activity{} = activity) do
|
|||
|> Jason.encode!()
|
||||
end
|
||||
|
||||
def render("follow_relationships_update.json", item) do
|
||||
def render("follow_relationships_update.json", item, topic) do
|
||||
%{
|
||||
stream: [topic],
|
||||
event: "pleroma:follow_relationships_update",
|
||||
payload:
|
||||
%{
|
||||
|
@ -73,8 +77,9 @@ def render("follow_relationships_update.json", item) do
|
|||
|> Jason.encode!()
|
||||
end
|
||||
|
||||
def render("conversation.json", %Participation{} = participation) do
|
||||
def render("conversation.json", %Participation{} = participation, topic) do
|
||||
%{
|
||||
stream: [topic],
|
||||
event: "conversation",
|
||||
payload:
|
||||
Pleroma.Web.MastodonAPI.ConversationView.render("participation.json", %{
|
||||
|
|
|
@ -9,6 +9,12 @@ defmodule Pleroma.Workers.ReceiverWorker do
|
|||
|
||||
@impl Oban.Worker
|
||||
def perform(%Job{args: %{"op" => "incoming_ap_doc", "params" => params}}) do
|
||||
Federator.perform(:incoming_ap_doc, params)
|
||||
with {:ok, res} <- Federator.perform(:incoming_ap_doc, params) do
|
||||
{:ok, res}
|
||||
else
|
||||
{:error, :origin_containment_failed} -> {:discard, :origin_containment_failed}
|
||||
{:error, {:reject, reason}} -> {:discard, reason}
|
||||
e -> e
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
7
mix.exs
7
mix.exs
|
@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
|
|||
def project do
|
||||
[
|
||||
app: :pleroma,
|
||||
version: version("3.0.1"),
|
||||
version: version("3.1.0"),
|
||||
elixir: "~> 1.9",
|
||||
elixirc_paths: elixirc_paths(Mix.env()),
|
||||
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
|
||||
|
@ -129,7 +129,7 @@ defp deps do
|
|||
override: true},
|
||||
{:bcrypt_elixir, "~> 2.2"},
|
||||
{:trailing_format_plug, "~> 0.0.7"},
|
||||
{:fast_sanitize, "~> 0.2.0"},
|
||||
{:fast_sanitize, "~> 0.2.3"},
|
||||
{:html_entities, "~> 0.5", override: true},
|
||||
{:phoenix_html, "~> 3.1", override: true},
|
||||
{:calendar, "~> 1.0"},
|
||||
|
@ -191,6 +191,9 @@ defp deps do
|
|||
{:ecto_psql_extras, "~> 0.6"},
|
||||
{:elasticsearch,
|
||||
git: "https://akkoma.dev/AkkomaGang/elasticsearch-elixir.git", ref: "main"},
|
||||
{:mfm_parser,
|
||||
git: "https://akkoma.dev/AkkomaGang/mfm-parser.git",
|
||||
ref: "5054e0ba1ebcbd9a7916aec219528e3e58057241"},
|
||||
|
||||
# indirect dependency version override
|
||||
{:plug, "~> 1.10.4", override: true},
|
||||
|
|
1
mix.lock
1
mix.lock
|
@ -67,6 +67,7 @@
|
|||
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
|
||||
"meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"},
|
||||
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
|
||||
"mfm_parser": {:git, "https://akkoma.dev/AkkomaGang/mfm-parser.git", "5054e0ba1ebcbd9a7916aec219528e3e58057241", [ref: "5054e0ba1ebcbd9a7916aec219528e3e58057241"]},
|
||||
"mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"},
|
||||
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
|
||||
"mint": {:hex, :mint, "1.4.2", "50330223429a6e1260b2ca5415f69b0ab086141bc76dc2fbf34d7c389a6675b2", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "ce75a5bbcc59b4d7d8d70f8b2fc284b1751ffb35c7b6a6302b5192f8ab4ddd80"},
|
||||
|
|
File diff suppressed because it is too large
Load diff
6396
priv/gettext/es/LC_MESSAGES/config_descriptions.po
Normal file
6396
priv/gettext/es/LC_MESSAGES/config_descriptions.po
Normal file
File diff suppressed because it is too large
Load diff
163
priv/gettext/es/LC_MESSAGES/posix_errors.po
Normal file
163
priv/gettext/es/LC_MESSAGES/posix_errors.po
Normal file
|
@ -0,0 +1,163 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-08-06 22:24+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Translate Toolkit 3.7.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.
|
||||
msgid "eperm"
|
||||
msgstr ""
|
||||
|
||||
msgid "eacces"
|
||||
msgstr ""
|
||||
|
||||
msgid "eagain"
|
||||
msgstr ""
|
||||
|
||||
msgid "ebadf"
|
||||
msgstr ""
|
||||
|
||||
msgid "ebadmsg"
|
||||
msgstr ""
|
||||
|
||||
msgid "ebusy"
|
||||
msgstr ""
|
||||
|
||||
msgid "edeadlk"
|
||||
msgstr ""
|
||||
|
||||
msgid "edeadlock"
|
||||
msgstr ""
|
||||
|
||||
msgid "edquot"
|
||||
msgstr ""
|
||||
|
||||
msgid "eexist"
|
||||
msgstr ""
|
||||
|
||||
msgid "efault"
|
||||
msgstr ""
|
||||
|
||||
msgid "efbig"
|
||||
msgstr ""
|
||||
|
||||
msgid "eftype"
|
||||
msgstr ""
|
||||
|
||||
msgid "eintr"
|
||||
msgstr ""
|
||||
|
||||
msgid "einval"
|
||||
msgstr ""
|
||||
|
||||
msgid "eio"
|
||||
msgstr ""
|
||||
|
||||
msgid "eisdir"
|
||||
msgstr ""
|
||||
|
||||
msgid "eloop"
|
||||
msgstr ""
|
||||
|
||||
msgid "emfile"
|
||||
msgstr ""
|
||||
|
||||
msgid "emlink"
|
||||
msgstr ""
|
||||
|
||||
msgid "emultihop"
|
||||
msgstr ""
|
||||
|
||||
msgid "enametoolong"
|
||||
msgstr ""
|
||||
|
||||
msgid "enfile"
|
||||
msgstr ""
|
||||
|
||||
msgid "enobufs"
|
||||
msgstr ""
|
||||
|
||||
msgid "enodev"
|
||||
msgstr ""
|
||||
|
||||
msgid "enolck"
|
||||
msgstr ""
|
||||
|
||||
msgid "enolink"
|
||||
msgstr ""
|
||||
|
||||
msgid "enoent"
|
||||
msgstr ""
|
||||
|
||||
msgid "enomem"
|
||||
msgstr ""
|
||||
|
||||
msgid "enospc"
|
||||
msgstr ""
|
||||
|
||||
msgid "enosr"
|
||||
msgstr ""
|
||||
|
||||
msgid "enostr"
|
||||
msgstr ""
|
||||
|
||||
msgid "enosys"
|
||||
msgstr ""
|
||||
|
||||
msgid "enotblk"
|
||||
msgstr ""
|
||||
|
||||
msgid "enotdir"
|
||||
msgstr ""
|
||||
|
||||
msgid "enotsup"
|
||||
msgstr ""
|
||||
|
||||
msgid "enxio"
|
||||
msgstr ""
|
||||
|
||||
msgid "eopnotsupp"
|
||||
msgstr ""
|
||||
|
||||
msgid "eoverflow"
|
||||
msgstr ""
|
||||
|
||||
msgid "epipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "erange"
|
||||
msgstr ""
|
||||
|
||||
msgid "erofs"
|
||||
msgstr ""
|
||||
|
||||
msgid "espipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "esrch"
|
||||
msgstr ""
|
||||
|
||||
msgid "estale"
|
||||
msgstr ""
|
||||
|
||||
msgid "etxtbsy"
|
||||
msgstr ""
|
||||
|
||||
msgid "exdev"
|
||||
msgstr ""
|
6396
priv/gettext/nl/LC_MESSAGES/config_descriptions.po
Normal file
6396
priv/gettext/nl/LC_MESSAGES/config_descriptions.po
Normal file
File diff suppressed because it is too large
Load diff
|
@ -3,16 +3,16 @@ 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: 2020-06-02 07:36+0000\n"
|
||||
"PO-Revision-Date: 2022-08-07 10:46+0000\n"
|
||||
"Last-Translator: Fristi <fristi@subcon.town>\n"
|
||||
"Language-Team: Dutch <https://translate.pleroma.social/projects/pleroma/"
|
||||
"pleroma/nl/>\n"
|
||||
"Language-Team: Dutch <http://translate.akkoma.dev/projects/akkoma/"
|
||||
"akkoma-backend-errors/nl/>\n"
|
||||
"Language: nl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.0.4\n"
|
||||
"X-Generator: Weblate 4.13.1\n"
|
||||
|
||||
## This file is a PO Template file.
|
||||
##
|
||||
|
@ -118,7 +118,7 @@ msgstr "Al gestemd"
|
|||
#: lib/pleroma/web/oauth/oauth_controller.ex:360
|
||||
#, elixir-format
|
||||
msgid "Bad request"
|
||||
msgstr "Bad request"
|
||||
msgstr "Ongeldig request"
|
||||
|
||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:425
|
||||
#, elixir-format
|
||||
|
@ -155,7 +155,7 @@ msgstr "Object kan niet geliked worden"
|
|||
#: lib/pleroma/web/common_api/utils.ex:556
|
||||
#, elixir-format
|
||||
msgid "Cannot post an empty status without attachments"
|
||||
msgstr "Status kan niet geplaatst worden zonder tekst of bijlagen"
|
||||
msgstr "Bericht kan niet geplaatst worden zonder tekst of bijlagen"
|
||||
|
||||
#: lib/pleroma/web/common_api/utils.ex:504
|
||||
#, elixir-format
|
||||
|
@ -165,122 +165,122 @@ msgstr "Opmerking dient maximaal %{max_size} karakters te bevatten"
|
|||
#: lib/pleroma/config/config_db.ex:222
|
||||
#, elixir-format
|
||||
msgid "Config with params %{params} not found"
|
||||
msgstr ""
|
||||
msgstr "Instelling met parameters %{params} kon niet gevonden worden"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:95
|
||||
#, elixir-format
|
||||
msgid "Could not delete"
|
||||
msgstr ""
|
||||
msgstr "Verwijderen mislukt"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:141
|
||||
#, elixir-format
|
||||
msgid "Could not favorite"
|
||||
msgstr ""
|
||||
msgstr "Favoriet maken mislukt"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:370
|
||||
#, elixir-format
|
||||
msgid "Could not pin"
|
||||
msgstr ""
|
||||
msgstr "Vastmaken mislukt"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:112
|
||||
#, elixir-format
|
||||
msgid "Could not repeat"
|
||||
msgstr ""
|
||||
msgstr "Herhalen mislukt"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:188
|
||||
#, elixir-format
|
||||
msgid "Could not unfavorite"
|
||||
msgstr ""
|
||||
msgstr "Favoriet ongedaan maken mislukt"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:380
|
||||
#, elixir-format
|
||||
msgid "Could not unpin"
|
||||
msgstr ""
|
||||
msgstr "Vastmaken ongedaan maken mislukt"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:126
|
||||
#, elixir-format
|
||||
msgid "Could not unrepeat"
|
||||
msgstr ""
|
||||
msgstr "Herhalen ongedaan maken mislukt"
|
||||
|
||||
#: 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 ""
|
||||
msgstr "Status bijwerken mislukt"
|
||||
|
||||
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:202
|
||||
#, elixir-format
|
||||
msgid "Error."
|
||||
msgstr ""
|
||||
msgstr "Fout."
|
||||
|
||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:106
|
||||
#, elixir-format
|
||||
msgid "Invalid CAPTCHA"
|
||||
msgstr ""
|
||||
msgstr "Ongeldige CAPTCHA"
|
||||
|
||||
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:117
|
||||
#: lib/pleroma/web/oauth/oauth_controller.ex:569
|
||||
#, elixir-format
|
||||
msgid "Invalid credentials"
|
||||
msgstr ""
|
||||
msgstr "Ongeldige inloggegevens"
|
||||
|
||||
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:38
|
||||
#, elixir-format
|
||||
msgid "Invalid credentials."
|
||||
msgstr ""
|
||||
msgstr "Ongeldige inloggegevens."
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:265
|
||||
#, elixir-format
|
||||
msgid "Invalid indices"
|
||||
msgstr ""
|
||||
msgstr "Ongeldige indexen"
|
||||
|
||||
#: lib/pleroma/web/admin_api/admin_api_controller.ex:1147
|
||||
#, elixir-format
|
||||
msgid "Invalid parameters"
|
||||
msgstr ""
|
||||
msgstr "Ongeldige parameters"
|
||||
|
||||
#: lib/pleroma/web/common_api/utils.ex:411
|
||||
#, elixir-format
|
||||
msgid "Invalid password."
|
||||
msgstr ""
|
||||
msgstr "Ongeldig wachtwoord."
|
||||
|
||||
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:187
|
||||
#, elixir-format
|
||||
msgid "Invalid request"
|
||||
msgstr ""
|
||||
msgstr "Ongeldig request"
|
||||
|
||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:109
|
||||
#, elixir-format
|
||||
msgid "Kocaptcha service unavailable"
|
||||
msgstr ""
|
||||
msgstr "Kocaptcha service niet beschikbaar"
|
||||
|
||||
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:113
|
||||
#, elixir-format
|
||||
msgid "Missing parameters"
|
||||
msgstr ""
|
||||
msgstr "Ontbrekende parameters"
|
||||
|
||||
#: lib/pleroma/web/common_api/utils.ex:540
|
||||
#, elixir-format
|
||||
msgid "No such conversation"
|
||||
msgstr ""
|
||||
msgstr "Gesprek niet gevonden"
|
||||
|
||||
#: 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 ""
|
||||
msgstr "Permission_group niet gevonden"
|
||||
|
||||
#: 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 ""
|
||||
msgstr "Niet gevonden"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:241
|
||||
#, elixir-format
|
||||
msgid "Poll's author can't vote"
|
||||
msgstr ""
|
||||
msgstr "De peiling-auteur kan niet stemmen"
|
||||
|
||||
#: 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
|
||||
|
@ -288,215 +288,215 @@ msgstr ""
|
|||
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:71
|
||||
#, elixir-format
|
||||
msgid "Record not found"
|
||||
msgstr ""
|
||||
msgstr "Record niet gevonden"
|
||||
|
||||
#: 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 ""
|
||||
msgstr "Er is iets misgegaan"
|
||||
|
||||
#: lib/pleroma/web/common_api/activity_draft.ex:107
|
||||
#, elixir-format
|
||||
msgid "The message visibility must be direct"
|
||||
msgstr ""
|
||||
msgstr "De zichtbaarheid van het bericht dient privé te zijn"
|
||||
|
||||
#: lib/pleroma/web/common_api/utils.ex:566
|
||||
#, elixir-format
|
||||
msgid "The status is over the character limit"
|
||||
msgstr ""
|
||||
msgstr "Het bericht is langer dan het karakter-limiet"
|
||||
|
||||
#: lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex:31
|
||||
#, elixir-format
|
||||
msgid "This resource requires authentication."
|
||||
msgstr ""
|
||||
msgstr "Deze gegevens vereisen authenticatie."
|
||||
|
||||
#: lib/pleroma/plugs/rate_limiter/rate_limiter.ex:206
|
||||
#, elixir-format
|
||||
msgid "Throttled"
|
||||
msgstr ""
|
||||
msgstr "Geremd"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:266
|
||||
#, elixir-format
|
||||
msgid "Too many choices"
|
||||
msgstr ""
|
||||
msgstr "Teveel keuzes"
|
||||
|
||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:442
|
||||
#, elixir-format
|
||||
msgid "Unhandled activity type"
|
||||
msgstr ""
|
||||
msgstr "Niet-ondersteund activiteits-type"
|
||||
|
||||
#: lib/pleroma/web/admin_api/admin_api_controller.ex:536
|
||||
#, elixir-format
|
||||
msgid "You can't revoke your own admin status."
|
||||
msgstr ""
|
||||
msgstr "Je kan je eigen beheerdersrechten niet intrekken."
|
||||
|
||||
#: 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 ""
|
||||
msgstr "Je account is momenteel uitgeschakeld"
|
||||
|
||||
#: 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 ""
|
||||
msgstr "Je login bevat geen bevestigd e-mailadres"
|
||||
|
||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:389
|
||||
#, elixir-format
|
||||
msgid "can't read inbox of %{nickname} as %{as_nickname}"
|
||||
msgstr ""
|
||||
msgstr "kan de inbox van %{nickname} niet lezen als %{as_nickname}"
|
||||
|
||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:472
|
||||
#, elixir-format
|
||||
msgid "can't update outbox of %{nickname} as %{as_nickname}"
|
||||
msgstr ""
|
||||
msgstr "kan de outbox van %{nickname} niet bijwerken als %{as_nickname}"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:388
|
||||
#, elixir-format
|
||||
msgid "conversation is already muted"
|
||||
msgstr ""
|
||||
msgstr "gesprek is al genegeerd"
|
||||
|
||||
#: 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 ""
|
||||
msgstr "fout"
|
||||
|
||||
#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:29
|
||||
#, elixir-format
|
||||
msgid "mascots can only be images"
|
||||
msgstr ""
|
||||
msgstr "mascottes kunnen alleen afbeeldingen zijn"
|
||||
|
||||
#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:60
|
||||
#, elixir-format
|
||||
msgid "not found"
|
||||
msgstr ""
|
||||
msgstr "niet gevonden"
|
||||
|
||||
#: lib/pleroma/web/oauth/oauth_controller.ex:395
|
||||
#, elixir-format
|
||||
msgid "Bad OAuth request."
|
||||
msgstr ""
|
||||
msgstr "Ongeldig OAuth request."
|
||||
|
||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:115
|
||||
#, elixir-format
|
||||
msgid "CAPTCHA already used"
|
||||
msgstr ""
|
||||
msgstr "CAPTCHA is al gebruikt"
|
||||
|
||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:112
|
||||
#, elixir-format
|
||||
msgid "CAPTCHA expired"
|
||||
msgstr ""
|
||||
msgstr "CAPTCHA is verlopen"
|
||||
|
||||
#: lib/pleroma/plugs/uploaded_media.ex:55
|
||||
#, elixir-format
|
||||
msgid "Failed"
|
||||
msgstr ""
|
||||
msgstr "Mislukt"
|
||||
|
||||
#: lib/pleroma/web/oauth/oauth_controller.ex:411
|
||||
#, elixir-format
|
||||
msgid "Failed to authenticate: %{message}."
|
||||
msgstr ""
|
||||
msgstr "Authenticatie mislukt: %{message}."
|
||||
|
||||
#: lib/pleroma/web/oauth/oauth_controller.ex:442
|
||||
#, elixir-format
|
||||
msgid "Failed to set up user account."
|
||||
msgstr ""
|
||||
msgstr "Aanmaken van gebruikersaccount is mislukt."
|
||||
|
||||
#: lib/pleroma/plugs/oauth_scopes_plug.ex:38
|
||||
#, elixir-format
|
||||
msgid "Insufficient permissions: %{permissions}."
|
||||
msgstr ""
|
||||
msgstr "Niet voldoende rechten: %{permissions}."
|
||||
|
||||
#: lib/pleroma/plugs/uploaded_media.ex:94
|
||||
#, elixir-format
|
||||
msgid "Internal Error"
|
||||
msgstr ""
|
||||
msgstr "Interne Fout"
|
||||
|
||||
#: lib/pleroma/web/oauth/fallback_controller.ex:22
|
||||
#: lib/pleroma/web/oauth/fallback_controller.ex:29
|
||||
#, elixir-format
|
||||
msgid "Invalid Username/Password"
|
||||
msgstr ""
|
||||
msgstr "Ongeldige Gebruikersnaam/Wachtwoord"
|
||||
|
||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:118
|
||||
#, elixir-format
|
||||
msgid "Invalid answer data"
|
||||
msgstr ""
|
||||
msgstr "Ongeldig antwoord"
|
||||
|
||||
#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:128
|
||||
#, elixir-format
|
||||
msgid "Nodeinfo schema version not handled"
|
||||
msgstr ""
|
||||
msgstr "Nodeinfo schema wordt niet ondersteund"
|
||||
|
||||
#: lib/pleroma/web/oauth/oauth_controller.ex:169
|
||||
#, elixir-format
|
||||
msgid "This action is outside the authorized scopes"
|
||||
msgstr ""
|
||||
msgstr "Deze actie bevindt zich buiten de gemachtigde scopes"
|
||||
|
||||
#: lib/pleroma/web/oauth/fallback_controller.ex:14
|
||||
#, elixir-format
|
||||
msgid "Unknown error, please check the details and try again."
|
||||
msgstr ""
|
||||
msgstr "Onbekende fout, controleer a.u.b. de details en probeer het opnieuw."
|
||||
|
||||
#: lib/pleroma/web/oauth/oauth_controller.ex:116
|
||||
#: lib/pleroma/web/oauth/oauth_controller.ex:155
|
||||
#, elixir-format
|
||||
msgid "Unlisted redirect_uri."
|
||||
msgstr ""
|
||||
msgstr "Niet-vermelde redirect_uri."
|
||||
|
||||
#: lib/pleroma/web/oauth/oauth_controller.ex:391
|
||||
#, elixir-format
|
||||
msgid "Unsupported OAuth provider: %{provider}."
|
||||
msgstr ""
|
||||
msgstr "Niet ondersteunde OAuth provider: %{provider}."
|
||||
|
||||
#: lib/pleroma/uploaders/uploader.ex:72
|
||||
#, elixir-format
|
||||
msgid "Uploader callback timeout"
|
||||
msgstr ""
|
||||
msgstr "Uploader terugkoppeling timeout"
|
||||
|
||||
#: lib/pleroma/web/uploader_controller.ex:23
|
||||
#, elixir-format
|
||||
msgid "bad request"
|
||||
msgstr ""
|
||||
msgstr "ongeldig request"
|
||||
|
||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:103
|
||||
#, elixir-format
|
||||
msgid "CAPTCHA Error"
|
||||
msgstr ""
|
||||
msgstr "CAPTCHA Fout"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:200
|
||||
#, elixir-format
|
||||
msgid "Could not add reaction emoji"
|
||||
msgstr ""
|
||||
msgstr "Reactie-emoji toevoegen mislukt"
|
||||
|
||||
#: lib/pleroma/web/common_api/common_api.ex:211
|
||||
#, elixir-format
|
||||
msgid "Could not remove reaction emoji"
|
||||
msgstr ""
|
||||
msgstr "Reactie-emoji verwijderen mislukt"
|
||||
|
||||
#: lib/pleroma/web/twitter_api/twitter_api.ex:129
|
||||
#, elixir-format
|
||||
msgid "Invalid CAPTCHA (Missing parameter: %{name})"
|
||||
msgstr ""
|
||||
msgstr "Ongeldige CAPTCHA (Ontbrekende parameter: %{name})"
|
||||
|
||||
#: lib/pleroma/web/mastodon_api/controllers/list_controller.ex:92
|
||||
#, elixir-format
|
||||
msgid "List not found"
|
||||
msgstr ""
|
||||
msgstr "Lijst niet gevonden"
|
||||
|
||||
#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:124
|
||||
#, elixir-format
|
||||
msgid "Missing parameter: %{name}"
|
||||
msgstr ""
|
||||
msgstr "Ontbrekende parameter: %{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 ""
|
||||
msgstr "Wachtwoordherstel is vereist"
|
||||
|
||||
#: 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
|
||||
|
@ -528,53 +528,63 @@ msgstr ""
|
|||
#, elixir-format
|
||||
msgid "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
|
||||
msgstr ""
|
||||
"Schending van beveiliging: OAuth scope-controle is niet uitgevoerd en niet "
|
||||
"expliciet overgeslagen."
|
||||
|
||||
#: lib/pleroma/plugs/ensure_authenticated_plug.ex:28
|
||||
#, elixir-format
|
||||
msgid "Two-factor authentication enabled, you must use a access token."
|
||||
msgstr ""
|
||||
"Tweefactor authenticatie is ingeschakeld, een toegangssleutel is verplicht."
|
||||
|
||||
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:210
|
||||
#, elixir-format
|
||||
msgid "Unexpected error occurred while adding file to pack."
|
||||
msgstr ""
|
||||
"Er is een onverwachte fout opgetreden tijdens het toevoegen van het bestand."
|
||||
|
||||
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:138
|
||||
#, elixir-format
|
||||
msgid "Unexpected error occurred while creating pack."
|
||||
msgstr ""
|
||||
"Er is een onverwachte fout opgetreden tijdens het aanmaken van het pakket."
|
||||
|
||||
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:278
|
||||
#, elixir-format
|
||||
msgid "Unexpected error occurred while removing file from pack."
|
||||
msgstr ""
|
||||
"Er is een onverwachte fout opgetreden tijdens het verwijderen van het "
|
||||
"bestand."
|
||||
|
||||
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:250
|
||||
#, elixir-format
|
||||
msgid "Unexpected error occurred while updating file in pack."
|
||||
msgstr ""
|
||||
"Er is een onverwachte fout opgetreden tijdens het bijwerken van het bestand."
|
||||
|
||||
#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:179
|
||||
#, elixir-format
|
||||
msgid "Unexpected error occurred while updating pack metadata."
|
||||
msgstr ""
|
||||
"Er is een onverwachte fout opgetreden tijdens het bijwerken van de pakket-"
|
||||
"metadata."
|
||||
|
||||
#: lib/pleroma/plugs/user_is_admin_plug.ex:21
|
||||
#, elixir-format
|
||||
msgid "User is not an admin."
|
||||
msgstr ""
|
||||
msgstr "Gebruiker is niet een beheerder."
|
||||
|
||||
#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
|
||||
#, elixir-format
|
||||
msgid "Web push subscription is disabled on this Pleroma instance"
|
||||
msgstr ""
|
||||
msgstr "Web push abbonement is uitgeschakeld op deze Pleroma instantie"
|
||||
|
||||
#: lib/pleroma/web/admin_api/admin_api_controller.ex:502
|
||||
#, elixir-format
|
||||
msgid "You can't revoke your own admin/moderator status."
|
||||
msgstr ""
|
||||
msgstr "Je kan je eigen beheerders- of moderatorrechten niet intrekken."
|
||||
|
||||
#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:105
|
||||
#, elixir-format
|
||||
msgid "authorization required for timeline view"
|
||||
msgstr ""
|
||||
msgstr "machtiging is vereist voor de tijdlijn weergave"
|
||||
|
|
567
priv/gettext/nl/LC_MESSAGES/static_pages.po
Normal file
567
priv/gettext/nl/LC_MESSAGES/static_pages.po
Normal file
|
@ -0,0 +1,567 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-08-07 10:48+0000\n"
|
||||
"PO-Revision-Date: 2022-08-07 19:52+0000\n"
|
||||
"Last-Translator: Fristi <fristi@subcon.town>\n"
|
||||
"Language-Team: Dutch <http://translate.akkoma.dev/projects/akkoma/"
|
||||
"akkoma-backend-static-pages/nl/>\n"
|
||||
"Language: nl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.13.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.
|
||||
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex:9
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "remote follow authorization button"
|
||||
msgid "Authorize"
|
||||
msgstr "Machtigen"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex:2
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "remote follow error"
|
||||
msgid "Error fetching user"
|
||||
msgstr "Fout bij ophalen gebruiker"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex:4
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "remote follow header"
|
||||
msgid "Remote follow"
|
||||
msgstr "Extern volgen"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex:8
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "placeholder text for auth code entry"
|
||||
msgid "Authentication code"
|
||||
msgstr "Authenticatiecode"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex:10
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "placeholder text for password entry"
|
||||
msgid "Password"
|
||||
msgstr "Wachtwoord"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex:8
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "placeholder text for username entry"
|
||||
msgid "Username"
|
||||
msgstr "Gebruikersnaam"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex:13
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "remote follow authorization button for login"
|
||||
msgid "Authorize"
|
||||
msgstr "Machtigen"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex:12
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "remote follow authorization button for mfa"
|
||||
msgid "Authorize"
|
||||
msgstr "Machtigen"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex:2
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "remote follow error"
|
||||
msgid "Error following account"
|
||||
msgstr "Fout bij volgen van account"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex:4
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "remote follow header, need login"
|
||||
msgid "Log in to follow"
|
||||
msgstr "Log in om te volgen"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex:4
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "remote follow mfa header"
|
||||
msgid "Two-factor authentication"
|
||||
msgstr "Tweefactor authenticatie"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex:4
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "remote follow success"
|
||||
msgid "Account followed!"
|
||||
msgstr "Account gevolgd!"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex:7
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "placeholder text for account id"
|
||||
msgid "Your account ID, e.g. lain@quitter.se"
|
||||
msgstr "Je account ID, b.v. gebruiker@instantie.net"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex:8
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "remote follow authorization button for following with a remote account"
|
||||
msgid "Follow"
|
||||
msgstr "Volgen"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex:2
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "remote follow error"
|
||||
msgid "Error: %{error}"
|
||||
msgstr "Fout: %{error}"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex:4
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "remote follow header"
|
||||
msgid "Remotely follow %{nickname}"
|
||||
msgstr "%{nickname} extern volgen"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/password/reset.html.eex:12
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "password reset button"
|
||||
msgid "Reset"
|
||||
msgstr "Herstellen"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex:4
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "password reset failed homepage link"
|
||||
msgid "Homepage"
|
||||
msgstr "Homepagina"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex:1
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "password reset failed message"
|
||||
msgid "Password reset failed"
|
||||
msgstr "Wachtwoordherstel mislukt"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/password/reset.html.eex:8
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "password reset form confirm password prompt"
|
||||
msgid "Confirmation"
|
||||
msgstr "Bevestiging"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/password/reset.html.eex:4
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "password reset form password prompt"
|
||||
msgid "Password"
|
||||
msgstr "Wachtwoord"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/password/invalid_token.html.eex:1
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "password reset invalid token message"
|
||||
msgid "Invalid Token"
|
||||
msgstr "Ongeldige Token"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex:2
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "password reset successful homepage link"
|
||||
msgid "Homepage"
|
||||
msgstr "Homepagina"
|
||||
|
||||
#: lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex:1
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "password reset successful message"
|
||||
msgid "Password changed!"
|
||||
msgstr "Wachtwoord gewijzigd!"
|
||||
|
||||
#: lib/pleroma/web/templates/feed/feed/tag.atom.eex:15
|
||||
#: lib/pleroma/web/templates/feed/feed/tag.rss.eex:7
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "tag feed description"
|
||||
msgid "These are public toots tagged with #%{tag}. You can interact with them if you have an account anywhere in the fediverse."
|
||||
msgstr ""
|
||||
"Dit zijn openbare berichten die getagd zijn met #%{tag}. Je kunt op deze "
|
||||
"reageren indien je een account hebt in de fediverse."
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/oob_token_exists.html.eex:1
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth authorization exists page title"
|
||||
msgid "Authorization exists"
|
||||
msgstr "Machtiging bestaat"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:32
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth authorize approve button"
|
||||
msgid "Approve"
|
||||
msgstr "Goedkeuren"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:30
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth authorize cancel button"
|
||||
msgid "Cancel"
|
||||
msgstr "Annuleren"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:23
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth authorize message"
|
||||
msgid "Application <strong>%{client_name}</strong> is requesting access to your account."
|
||||
msgstr ""
|
||||
"Applicatie <strong>%{client_name}</strong> vraagt om toegang tot je account."
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/oob_authorization_created.html.eex:1
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth authorized page title"
|
||||
msgid "Successfully authorized"
|
||||
msgstr "Machtiging is geslaagd"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex:1
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth external provider page title"
|
||||
msgid "Sign in with external provider"
|
||||
msgstr "Inloggen bij externe provider"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex:13
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth external provider sign in button"
|
||||
msgid "Sign in with %{strategy}"
|
||||
msgstr "Inloggen met %{strategy}"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:54
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth login button"
|
||||
msgid "Log In"
|
||||
msgstr "Inloggen"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:51
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth login password prompt"
|
||||
msgid "Password"
|
||||
msgstr "Wachtwoord"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:47
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth login username prompt"
|
||||
msgid "Username"
|
||||
msgstr "Gebruikersnaam"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:39
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth register nickname prompt"
|
||||
msgid "Pleroma Handle"
|
||||
msgstr "Pleroma Gebruiker"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:37
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth register nickname unchangeable warning"
|
||||
msgid "Choose carefully! You won't be able to change this later. You will be able to change your display name, though."
|
||||
msgstr ""
|
||||
"Let op! Je kunt je accountnaam hierna niet meer wijzigen. Je kunt echter wel "
|
||||
"nog je weergavenaam wijzigen."
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:18
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth register page email prompt"
|
||||
msgid "Email"
|
||||
msgstr "E-mail"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:10
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth register page fill form prompt"
|
||||
msgid "If you'd like to register a new account, please provide the details below."
|
||||
msgstr ""
|
||||
"Indien je graag een nieuw account wilt registreren, vul dan a.u.b de "
|
||||
"onderstaande details in."
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:35
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth register page login button"
|
||||
msgid "Proceed as existing user"
|
||||
msgstr "Doorgaan als bestaande gebruiker"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:31
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth register page login password prompt"
|
||||
msgid "Password"
|
||||
msgstr "Wachtwoord"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:24
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth register page login prompt"
|
||||
msgid "Alternatively, sign in to connect to existing account."
|
||||
msgstr "Alternatief, log in om te verbinden met een bestaand account."
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:27
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth register page login username prompt"
|
||||
msgid "Name or email"
|
||||
msgstr "Naam of e-mail"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:14
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth register page nickname prompt"
|
||||
msgid "Nickname"
|
||||
msgstr "Weergavenaam"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:22
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth register page register button"
|
||||
msgid "Proceed as new user"
|
||||
msgstr "Doorgaan als nieuwe gebruiker"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/register.html.eex:8
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth register page title"
|
||||
msgid "Registration Details"
|
||||
msgstr "Registratiegegevens"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/show.html.eex:36
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth register page title"
|
||||
msgid "This is the first time you visit! Please enter your Pleroma handle."
|
||||
msgstr "Dit is je eerste bezoek! Vul a.u.b. je Pleroma gebruikersnaam in."
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex:2
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth scopes message"
|
||||
msgid "The following permissions will be granted"
|
||||
msgstr "De volgende rechten zullen worden toegekend"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/oob_authorization_created.html.eex:2
|
||||
#: lib/pleroma/web/templates/o_auth/o_auth/oob_token_exists.html.eex:2
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "oauth token code message"
|
||||
msgid "Token code is <br>%{token}"
|
||||
msgstr "Token code is <br>%{token}"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/mfa/totp.html.eex:12
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "mfa auth code prompt"
|
||||
msgid "Authentication code"
|
||||
msgstr "Authenticatiecode"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/mfa/totp.html.eex:8
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "mfa auth page title"
|
||||
msgid "Two-factor authentication"
|
||||
msgstr "Tweefactor authenticatie"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/mfa/totp.html.eex:23
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "mfa auth page use recovery code link"
|
||||
msgid "Enter a two-factor recovery code"
|
||||
msgstr "Voer een tweefactor herstelcode in"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/mfa/totp.html.eex:20
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "mfa auth verify code button"
|
||||
msgid "Verify"
|
||||
msgstr "Controleren"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex:8
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "mfa recover page title"
|
||||
msgid "Two-factor recovery"
|
||||
msgstr "Tweefactor herstel"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex:12
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "mfa recover recovery code prompt"
|
||||
msgid "Recovery code"
|
||||
msgstr "Herstelcode"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex:23
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "mfa recover use 2fa code link"
|
||||
msgid "Enter a two-factor code"
|
||||
msgstr "Voer een tweefactor code in"
|
||||
|
||||
#: lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex:20
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "mfa recover verify recovery code button"
|
||||
msgid "Verify"
|
||||
msgstr "Controleren"
|
||||
|
||||
#: lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex:8
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "static fe profile page remote follow button"
|
||||
msgid "Remote follow"
|
||||
msgstr "Extern volgen"
|
||||
|
||||
#: lib/pleroma/web/templates/email/digest.html.eex:163
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "digest email header line"
|
||||
msgid "Hey %{nickname}, here is what you've missed!"
|
||||
msgstr "Hoi %{nickname}, dit is wat je hebt gemist!"
|
||||
|
||||
#: lib/pleroma/web/templates/email/digest.html.eex:544
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "digest email receiver address"
|
||||
msgid "The email address you are subscribed as is <a href='mailto:%{@user.email}' style='color: %{color};text-decoration: none;'>%{email}</a>. "
|
||||
msgstr ""
|
||||
"Het e-mailadres waarmee je bent ingeschreven is <a href='mailto:%{@user."
|
||||
"email}' style='color: %{color};text-decoration: none;'>%{email}</a>. "
|
||||
|
||||
#: lib/pleroma/web/templates/email/digest.html.eex:538
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "digest email sending reason"
|
||||
msgid "You have received this email because you have signed up to receive digest emails from <b>%{instance}</b> Pleroma instance."
|
||||
msgstr ""
|
||||
"Je ontvangt deze e-mail omdat je bent ingeschreven voor overzichts-mails te "
|
||||
"ontvangen van <b>%{instance}</b> Pleroma instantie."
|
||||
|
||||
#: lib/pleroma/web/templates/email/digest.html.eex:547
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "digest email unsubscribe action"
|
||||
msgid "To unsubscribe, please go %{here}."
|
||||
msgstr "Je kunt je %{here} uitschrijven voor deze e-mails."
|
||||
|
||||
#: lib/pleroma/web/templates/email/digest.html.eex:547
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "digest email unsubscribe action link text"
|
||||
msgid "here"
|
||||
msgstr "hier"
|
||||
|
||||
#: lib/pleroma/web/templates/mailer/subscription/unsubscribe_failure.html.eex:1
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "mailer unsubscribe failed message"
|
||||
msgid "UNSUBSCRIBE FAILURE"
|
||||
msgstr "UITSCHRIJVEN MISLUKT"
|
||||
|
||||
#: lib/pleroma/web/templates/mailer/subscription/unsubscribe_success.html.eex:1
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "mailer unsubscribe successful message"
|
||||
msgid "UNSUBSCRIBE SUCCESSFUL"
|
||||
msgstr "UITSCHRIJVEN GESLAAGD"
|
||||
|
||||
#: lib/pleroma/web/templates/email/digest.html.eex:385
|
||||
#, elixir-format
|
||||
msgctxt "new followers count header"
|
||||
msgid "%{count} New Follower"
|
||||
msgid_plural "%{count} New Followers"
|
||||
msgstr[0] "%{count} Nieuwe Volger"
|
||||
msgstr[1] "%{count} Nieuwe Volgers"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:356
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "account archive email body - self-requested"
|
||||
msgid "<p>You requested a full backup of your Pleroma account. It's ready for download:</p>\n<p><a href=\"%{download_url}\">%{download_url}</a></p>\n"
|
||||
msgstr ""
|
||||
"<p>Je hebt een verzoek ingediend voor een volledige back-up van je Pleroma "
|
||||
"account. Deze is gereed om te downloaden:</p>\n"
|
||||
"<p><a href=\"%{download_url}\">%{download_url}</a></p>\n"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:384
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "account archive email subject"
|
||||
msgid "Your account archive is ready"
|
||||
msgstr "Je account archief is gereed"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:188
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "approval pending email body"
|
||||
msgid "<h3>Awaiting Approval</h3>\n<p>Your account at %{instance_name} is being reviewed by staff. You will receive another email once your account is approved.</p>\n"
|
||||
msgstr ""
|
||||
"<h3>Goedkeuring in afwachting</h3>\n"
|
||||
"<p>Je account bij %{instance_name} zal worden beoordeeld door de beheerders. "
|
||||
"Je zult een opvolgende e-mail ontvangen wanneer je account goed gekeurd "
|
||||
"is.</p>\n"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:202
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "approval pending email subject"
|
||||
msgid "Your account is awaiting approval"
|
||||
msgstr "Je account is in afwachting van goedkeuring"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:158
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "confirmation email body"
|
||||
msgid "<h3>Thank you for registering on %{instance_name}</h3>\n<p>Email confirmation is required to activate the account.</p>\n<p>Please click the following link to <a href=\"%{confirmation_url}\">activate your account</a>.</p>\n"
|
||||
msgstr ""
|
||||
"<h3>Bedankt voor het registreren bij %{instance_name}</h3>\n"
|
||||
"<p>Bevestiging via e-mail is vereist om je account te activeren.</p>\n"
|
||||
"<p>Je kunt je account activeren door op <a href=\"%{confirmation_url}\">deze "
|
||||
"link te klikken</a>.</p>\n"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:174
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "confirmation email subject"
|
||||
msgid "%{instance_name} account confirmation"
|
||||
msgstr "%{instance_name} account bevestiging"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:310
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "digest email subject"
|
||||
msgid "Your digest from %{instance_name}"
|
||||
msgstr "Je overzicht van %{instance_name}"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:81
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "password reset email body"
|
||||
msgid "<h3>Reset your password at %{instance_name}</h3>\n<p>Someone has requested password change for your account at %{instance_name}.</p>\n<p>If it was you, visit the following link to proceed: <a href=\"%{password_reset_url}\">reset password</a>.</p>\n<p>If it was someone else, nothing to worry about: your data is secure and your password has not been changed.</p>\n"
|
||||
msgstr ""
|
||||
"<h3>Herstel je wachtwoord bij %{instance_name}</h3>\n"
|
||||
"<p>Iemand heeft een verzoek ingediend om het wachtwoord van je account bij "
|
||||
"%{instance_name} te herstellen.</p>\n"
|
||||
"<p>Als je dit zelf geweest bent, volg dan de volgende link om door te gaan: "
|
||||
"<a href=\"%{password_reset_url}\">wachtwoord herstellen</a>.</p>\n"
|
||||
"<p>Indien je dit niet geweest bent, hoef je geen verdere acties te "
|
||||
"ondernemen: je gegevens zijn veilig en je wachtwoord is niet gewijzigd.</p>\n"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:98
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "password reset email subject"
|
||||
msgid "Password reset"
|
||||
msgstr "Wachtwoord herstellen"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:215
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "successful registration email body"
|
||||
msgid "<h3>Hello @%{nickname},</h3>\n<p>Your account at %{instance_name} has been registered successfully.</p>\n<p>No further action is required to activate your account.</p>\n"
|
||||
msgstr ""
|
||||
"<h3>Hoi @%{nickname},</h3>\n"
|
||||
"<p>Het registreren van je account bij %{instance_name} is gelukt.</p>\n"
|
||||
"<p>Er zijn geen verdere stappen vereist om je account te activeren.</p>\n"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:231
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "successful registration email subject"
|
||||
msgid "Account registered on %{instance_name}"
|
||||
msgstr "Account registratie bij %{instance_name}"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:119
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "user invitation email body"
|
||||
msgid "<h3>You are invited to %{instance_name}</h3>\n<p>%{inviter_name} invites you to join %{instance_name}, an instance of Pleroma federated social networking platform.</p>\n<p>Click the following link to register: <a href=\"%{registration_url}\">accept invitation</a>.</p>\n"
|
||||
msgstr ""
|
||||
"<h3>Je bent uitgenodigd bij %{instance_name}</h3>\n"
|
||||
"<p>%{inviter_name} nodigt je uit om je te registreren bij %{instance_name}, "
|
||||
"een instantie van het Pleroma gefedereerde sociale netwerk.</p>\n"
|
||||
"<p>Om je te registreren, klink op de volgende link: <a href=\""
|
||||
"%{registration_url}\">uitnodiging accepteren</a>.</p>\n"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:136
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "user invitation email subject"
|
||||
msgid "Invitation to %{instance_name}"
|
||||
msgstr "Uitnodiging van %{instance_name}"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:53
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "welcome email html body"
|
||||
msgid "Welcome to %{instance_name}!"
|
||||
msgstr "Welkom bij %{instance_name}!"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:41
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "welcome email subject"
|
||||
msgid "Welcome to %{instance_name}!"
|
||||
msgstr "Welkom bij %{instance_name}!"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:65
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "welcome email text body"
|
||||
msgid "Welcome to %{instance_name}!"
|
||||
msgstr "Welkom bij %{instance_name}!"
|
||||
|
||||
#: lib/pleroma/emails/user_email.ex:368
|
||||
#, elixir-autogen, elixir-format
|
||||
msgctxt "account archive email body - admin requested"
|
||||
msgid "<p>Admin @%{admin_nickname} requested a full backup of your Pleroma account. It's ready for download:</p>\n<p><a href=\"%{download_url}\">%{download_url}</a></p>\n"
|
||||
msgstr ""
|
||||
"<p>Beheerder @%{admin_nickname} heeft een verzoek ingediend voor een "
|
||||
"volledige back-up van je Pleroma account. Deze is gereed om te "
|
||||
"downloaden:</p>\n"
|
||||
"<p><a href=\"%{download_url}\">%{download_url}</a></p>\n"
|
|
@ -0,0 +1,35 @@
|
|||
defmodule Pleroma.Repo.Migrations.RemoveRemoteCancelledFollowRequests do
|
||||
use Ecto.Migration
|
||||
|
||||
def up do
|
||||
statement = """
|
||||
DELETE FROM
|
||||
activities
|
||||
WHERE
|
||||
(data->>'type') = 'Follow'
|
||||
AND
|
||||
(data->>'state') = 'cancelled'
|
||||
AND
|
||||
local = false;
|
||||
"""
|
||||
|
||||
execute(statement)
|
||||
|
||||
statement = """
|
||||
DELETE FROM
|
||||
activities
|
||||
WHERE
|
||||
(data->>'type') = 'Undo'
|
||||
AND
|
||||
(data->'object'->>'type') = 'Follow'
|
||||
AND
|
||||
local = false;
|
||||
"""
|
||||
|
||||
execute(statement)
|
||||
end
|
||||
|
||||
def down do
|
||||
:ok
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
defmodule Pleroma.Repo.Migrations.RemoveNullObjects do
|
||||
use Ecto.Migration
|
||||
|
||||
def up do
|
||||
statement = """
|
||||
DELETE FROM objects
|
||||
WHERE (data->>'type') is null;
|
||||
"""
|
||||
|
||||
execute(statement)
|
||||
end
|
||||
|
||||
def down, do: :ok
|
||||
end
|
|
@ -56,8 +56,36 @@ defmodule Pleroma.HTML.Scrubber.Default do
|
|||
Meta.allow_tag_with_these_attributes(:u, [])
|
||||
Meta.allow_tag_with_these_attributes(:ul, [])
|
||||
|
||||
Meta.allow_tag_with_this_attribute_values(:span, "class", ["h-card"])
|
||||
Meta.allow_tag_with_these_attributes(:span, [])
|
||||
Meta.allow_tags_with_style_attributes([:span])
|
||||
|
||||
Meta.allow_tag_with_this_attribute_values(:span, "class", [
|
||||
"h-card",
|
||||
"quote-inline",
|
||||
"mfm",
|
||||
"_mfm_tada_",
|
||||
"_mfm_jelly_",
|
||||
"_mfm_twitch_",
|
||||
"_mfm_shake_",
|
||||
"_mfm_spin_",
|
||||
"_mfm_jump_",
|
||||
"_mfm_bounce_",
|
||||
"_mfm_flip_",
|
||||
"_mfm_x2_",
|
||||
"_mfm_x3_",
|
||||
"_mfm_x4_",
|
||||
"_mfm_blur_",
|
||||
"_mfm_rainbow_",
|
||||
"_mfm_rotate_"
|
||||
])
|
||||
|
||||
Meta.allow_tag_with_these_attributes(:span, [
|
||||
"data-x",
|
||||
"data-y",
|
||||
"data-h",
|
||||
"data-v",
|
||||
"data-left",
|
||||
"data-right"
|
||||
])
|
||||
|
||||
Meta.allow_tag_with_this_attribute_values(:code, "class", ["inline"])
|
||||
|
||||
|
@ -101,4 +129,6 @@ defmodule Pleroma.HTML.Scrubber.Default do
|
|||
Meta.allow_tag_with_these_attributes(:small, [])
|
||||
|
||||
Meta.strip_everything_not_covered()
|
||||
|
||||
defp scrub_css(value), do: value
|
||||
end
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
# XXX: This should be removed when elixir's releases get custom command support
|
||||
|
||||
detect_flavour() {
|
||||
echo "Trying to autodetect flavour, you may want to override this with --flavour"
|
||||
arch="$(uname -m)"
|
||||
if [ "$arch" = "x86_64" ]; then
|
||||
arch="amd64"
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
[Unit]
|
||||
Description=Pleroma social network
|
||||
Description=Akkoma social network
|
||||
After=network.target postgresql.service nginx.service
|
||||
|
||||
[Service]
|
||||
KillMode=process
|
||||
Restart=on-failure
|
||||
|
||||
; Name of the user that runs the Pleroma service.
|
||||
User=pleroma
|
||||
; Name of the user that runs the Akkoma service.
|
||||
User=akkoma
|
||||
|
||||
; Make sure that all paths fit your installation.
|
||||
; Path to the home directory of the user running the Pleroma service.
|
||||
Environment="HOME=/opt/pleroma"
|
||||
; Path to the folder containing the Pleroma installation.
|
||||
WorkingDirectory=/opt/pleroma
|
||||
; Path to the Pleroma binary.
|
||||
ExecStart=/opt/pleroma/bin/pleroma start
|
||||
ExecStop=/opt/pleroma/bin/pleroma stop
|
||||
; Path to the home directory of the user running the Akkoma service.
|
||||
Environment="HOME=/opt/akkoma"
|
||||
; Path to the folder containing the Akkoma installation.
|
||||
WorkingDirectory=/opt/akkoma
|
||||
; Path to the Mix binary.
|
||||
ExecStart=/opt/akkoma/bin/pleroma start
|
||||
ExecStop=/opt/akkoma/bin/pleroma stop
|
||||
|
||||
; Some security directives.
|
||||
; Use private /tmp and /var/tmp folders inside a new file system namespace, which are discarded after the process stops.
|
||||
PrivateTmp=true
|
||||
; The /home, /root, and /run/user folders can not be accessed by this service anymore. If your Pleroma user has its home folder in one of the restricted places, or use one of these folders as its working directory, you have to set this to false.
|
||||
; The /home, /root, and /run/user folders can not be accessed by this service anymore. If your Akkoma user has its home folder in one of the restricted places, or use one of these folders as its working directory, you have to set this to false.
|
||||
ProtectHome=true
|
||||
; Mount /usr, /boot, and /etc as read-only for processes invoked by this service.
|
||||
ProtectSystem=full
|
|
@ -1 +1,5 @@
|
|||
external_emoji, https://example.com/emoji.png
|
||||
firefox, /emoji/Firefox.gif, Gif,Fun
|
||||
blank, /emoji/blank.png, Fun
|
||||
dinosaur, /emoji/dino walking.gif, Gif
|
||||
100a, /emoji/100a.png, Fun
|
||||
|
|
2
test/fixtures/misskey/mfm_x_format.json
vendored
2
test/fixtures/misskey/mfm_x_format.json
vendored
|
@ -3,7 +3,7 @@
|
|||
"type": "Note",
|
||||
"attributedTo": "https://misskey.local.live/users/92hzkskwgy",
|
||||
"summary": null,
|
||||
"content": "this gets replaced",
|
||||
"content": "this does not get replaced",
|
||||
"source": {
|
||||
"content": "@akkoma_user @remote_user @full_tag_remote_user@misskey.local.live @oops_not_a_mention linkifylink #dancedance $[jelly mfm goes here] \n\n## aaa",
|
||||
"mediaType": "text/x.misskeymarkdown"
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.HTTP.AdapterHelper.GunTest do
|
||||
use ExUnit.Case
|
||||
use Pleroma.Tests.Helpers
|
||||
|
||||
import Mox
|
||||
|
||||
alias Pleroma.HTTP.AdapterHelper.Gun
|
||||
|
||||
setup :verify_on_exit!
|
||||
|
||||
describe "options/1" do
|
||||
setup do: clear_config([:http, :adapter], a: 1, b: 2)
|
||||
|
||||
test "https url with default port" do
|
||||
uri = URI.parse("https://example.com")
|
||||
|
||||
opts = Gun.options([receive_conn: false], uri)
|
||||
assert opts[:certificates_verification]
|
||||
end
|
||||
|
||||
test "https ipv4 with default port" do
|
||||
uri = URI.parse("https://127.0.0.1")
|
||||
|
||||
opts = Gun.options([receive_conn: false], uri)
|
||||
assert opts[:certificates_verification]
|
||||
end
|
||||
|
||||
test "https ipv6 with default port" do
|
||||
uri = URI.parse("https://[2a03:2880:f10c:83:face:b00c:0:25de]")
|
||||
|
||||
opts = Gun.options([receive_conn: false], uri)
|
||||
assert opts[:certificates_verification]
|
||||
end
|
||||
|
||||
test "https url with non standart port" do
|
||||
uri = URI.parse("https://example.com:115")
|
||||
|
||||
opts = Gun.options([receive_conn: false], uri)
|
||||
|
||||
assert opts[:certificates_verification]
|
||||
end
|
||||
|
||||
test "merges with defaul http adapter config" do
|
||||
defaults = Gun.options([receive_conn: false], URI.parse("https://example.com"))
|
||||
assert Keyword.has_key?(defaults, :a)
|
||||
assert Keyword.has_key?(defaults, :b)
|
||||
end
|
||||
|
||||
test "parses string proxy host & port" do
|
||||
clear_config([:http, :proxy_url], "localhost:8123")
|
||||
|
||||
uri = URI.parse("https://some-domain.com")
|
||||
opts = Gun.options([receive_conn: false], uri)
|
||||
assert opts[:proxy] == {'localhost', 8123}
|
||||
end
|
||||
|
||||
test "parses tuple proxy scheme host and port" do
|
||||
clear_config([:http, :proxy_url], {:socks, 'localhost', 1234})
|
||||
|
||||
uri = URI.parse("https://some-domain.com")
|
||||
opts = Gun.options([receive_conn: false], uri)
|
||||
assert opts[:proxy] == {:socks, 'localhost', 1234}
|
||||
end
|
||||
|
||||
test "passed opts have more weight than defaults" do
|
||||
clear_config([:http, :proxy_url], {:socks5, 'localhost', 1234})
|
||||
uri = URI.parse("https://some-domain.com")
|
||||
opts = Gun.options([receive_conn: false, proxy: {'example.com', 4321}], uri)
|
||||
|
||||
assert opts[:proxy] == {'example.com', 4321}
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,35 +0,0 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.HTTP.AdapterHelper.HackneyTest do
|
||||
use ExUnit.Case, async: true
|
||||
use Pleroma.Tests.Helpers
|
||||
|
||||
alias Pleroma.HTTP.AdapterHelper.Hackney
|
||||
|
||||
setup_all do
|
||||
uri = URI.parse("http://domain.com")
|
||||
{:ok, uri: uri}
|
||||
end
|
||||
|
||||
describe "options/2" do
|
||||
setup do: clear_config([:http, :adapter], a: 1, b: 2)
|
||||
|
||||
test "add proxy and opts from config", %{uri: uri} do
|
||||
opts = Hackney.options([proxy: "localhost:8123"], uri)
|
||||
|
||||
assert opts[:a] == 1
|
||||
assert opts[:b] == 2
|
||||
assert opts[:proxy] == "localhost:8123"
|
||||
end
|
||||
|
||||
test "respect connection opts and no proxy", %{uri: uri} do
|
||||
opts = Hackney.options([a: 2, b: 1], uri)
|
||||
|
||||
assert opts[:a] == 2
|
||||
assert opts[:b] == 1
|
||||
refute Keyword.has_key?(opts, :proxy)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -13,16 +13,38 @@ test "with nil" do
|
|||
end
|
||||
|
||||
test "with string" do
|
||||
assert AdapterHelper.format_proxy("127.0.0.1:8123") == {{127, 0, 0, 1}, 8123}
|
||||
assert AdapterHelper.format_proxy("http://127.0.0.1:8123") == {:http, "127.0.0.1", 8123, []}
|
||||
end
|
||||
|
||||
test "localhost with port" do
|
||||
assert AdapterHelper.format_proxy("localhost:8123") == {'localhost', 8123}
|
||||
assert AdapterHelper.format_proxy("https://localhost:8123") ==
|
||||
{:https, "localhost", 8123, []}
|
||||
end
|
||||
|
||||
test "tuple" do
|
||||
assert AdapterHelper.format_proxy({:socks4, :localhost, 9050}) ==
|
||||
{:socks4, 'localhost', 9050}
|
||||
assert AdapterHelper.format_proxy({:http, "localhost", 9050}) ==
|
||||
{:http, "localhost", 9050, []}
|
||||
end
|
||||
end
|
||||
|
||||
describe "maybe_add_proxy_pool/1" do
|
||||
test "should do nothing with nil" do
|
||||
assert AdapterHelper.maybe_add_proxy_pool([], nil) == []
|
||||
end
|
||||
|
||||
test "should create pools" do
|
||||
assert AdapterHelper.maybe_add_proxy_pool([], "proxy") == [
|
||||
pools: %{default: [conn_opts: [proxy: "proxy"]]}
|
||||
]
|
||||
end
|
||||
|
||||
test "should not override conn_opts if set" do
|
||||
assert AdapterHelper.maybe_add_proxy_pool(
|
||||
[pools: %{default: [conn_opts: [already: "set"]]}],
|
||||
"proxy"
|
||||
) == [
|
||||
pools: %{default: [conn_opts: [proxy: "proxy", already: "set"]]}
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -31,9 +31,9 @@ def start_socket(qs \\ nil, headers \\ []) do
|
|||
WebsocketClient.start_link(self(), path, headers)
|
||||
end
|
||||
|
||||
test "refuses invalid requests" do
|
||||
test "allows multi-streams" do
|
||||
capture_log(fn ->
|
||||
assert {:error, {404, _}} = start_socket()
|
||||
assert {:ok, _} = start_socket()
|
||||
assert {:error, {404, _}} = start_socket("?stream=ncjdk")
|
||||
Process.sleep(30)
|
||||
end)
|
||||
|
|
|
@ -224,7 +224,7 @@ test "it creates a notification for user and send to the 'user' and the 'user:no
|
|||
task =
|
||||
Task.async(fn ->
|
||||
{:ok, _topic} = Streamer.get_topic_and_add_socket("user", user, oauth_token)
|
||||
assert_receive {:render_with_user, _, _, _}, 4_000
|
||||
assert_receive {:render_with_user, _, _, _, "user"}, 4_000
|
||||
end)
|
||||
|
||||
task_user_notification =
|
||||
|
@ -232,7 +232,7 @@ test "it creates a notification for user and send to the 'user' and the 'user:no
|
|||
{:ok, _topic} =
|
||||
Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
|
||||
|
||||
assert_receive {:render_with_user, _, _, _}, 4_000
|
||||
assert_receive {:render_with_user, _, _, _, "user:notification"}, 4_000
|
||||
end)
|
||||
|
||||
activity = insert(:note_activity)
|
||||
|
|
|
@ -523,7 +523,6 @@ test "inserts a given map into the activity database, giving it an id if it has
|
|||
assert activity.data["ok"] == data["ok"]
|
||||
assert activity.data["id"] == given_id
|
||||
assert activity.data["context"] == "blabla"
|
||||
assert activity.data["context_id"]
|
||||
end
|
||||
|
||||
test "adds a context when none is there" do
|
||||
|
@ -545,8 +544,6 @@ test "adds a context when none is there" do
|
|||
|
||||
assert is_binary(activity.data["context"])
|
||||
assert is_binary(object.data["context"])
|
||||
assert activity.data["context_id"]
|
||||
assert object.data["context_id"]
|
||||
end
|
||||
|
||||
test "adds an id to a given object if it lacks one and is a note and inserts it to the object database" do
|
||||
|
@ -1375,6 +1372,21 @@ test "creates an undo activity for a pending follow request" do
|
|||
assert embedded_object["object"] == followed.ap_id
|
||||
assert embedded_object["id"] == follow_activity.data["id"]
|
||||
end
|
||||
|
||||
test "it removes the follow activity if it was remote" do
|
||||
follower = insert(:user, local: false)
|
||||
followed = insert(:user)
|
||||
|
||||
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
|
||||
{:ok, activity} = ActivityPub.unfollow(follower, followed, nil, false)
|
||||
|
||||
assert activity.data["type"] == "Undo"
|
||||
assert activity.data["actor"] == follower.ap_id
|
||||
|
||||
activity = Activity.get_by_id(follow_activity.id)
|
||||
assert is_nil(activity)
|
||||
assert is_nil(Utils.fetch_latest_follow(follower, followed))
|
||||
end
|
||||
end
|
||||
|
||||
describe "timeline post-processing" do
|
||||
|
@ -1545,7 +1557,7 @@ test "it can create a Flag activity",
|
|||
})
|
||||
|
||||
assert Repo.aggregate(Activity, :count, :id) == 1
|
||||
assert Repo.aggregate(Object, :count, :id) == 2
|
||||
assert Repo.aggregate(Object, :count, :id) == 1
|
||||
assert Repo.aggregate(Notification, :count, :id) == 0
|
||||
end
|
||||
end
|
||||
|
|
|
@ -98,8 +98,6 @@ test "a misskey MFM status with a content field should work and be linked", _ do
|
|||
changes: %{
|
||||
content: content,
|
||||
source: %{
|
||||
"content" =>
|
||||
"@akkoma_user @remote_user @full_tag_remote_user@misskey.local.live @oops_not_a_mention linkifylink #dancedance $[jelly mfm goes here] \n\n## aaa",
|
||||
"mediaType" => "text/x.misskeymarkdown"
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +113,9 @@ test "a misskey MFM status with a content field should work and be linked", _ do
|
|||
"<span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{full_tag_remote_user.id}\" href=\"#{full_tag_remote_user.ap_id}\" rel=\"ugc\">@<span>full_tag_remote_user</span></a></span>"
|
||||
|
||||
assert content =~ "@oops_not_a_mention"
|
||||
assert content =~ "$[jelly mfm goes here] <br><br>## aaa"
|
||||
|
||||
assert content =~
|
||||
"<span class=\"mfm\" style=\"display: inline-block; animation: 1s linear 0s infinite normal both running mfm-rubberBand;\">mfm goes here</span> </p>aaa"
|
||||
end
|
||||
|
||||
test "a misskey MFM status with a _misskey_content field should work and be linked", _ do
|
||||
|
@ -129,22 +129,21 @@ test "a misskey MFM status with a _misskey_content field should work and be link
|
|||
|> File.read!()
|
||||
|> Jason.decode!()
|
||||
|
||||
expected_content =
|
||||
"<span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{local_user.id}\" href=\"#{local_user.ap_id}\" rel=\"ugc\">@<span>akkoma_user</span></a></span> linkifylink <a class=\"hashtag\" data-tag=\"dancedance\" href=\"http://localhost:4001/tag/dancedance\">#dancedance</a> $[jelly mfm goes here] <br><br>## aaa"
|
||||
|
||||
changes = ArticleNotePageValidator.cast_and_validate(note)
|
||||
|
||||
%{
|
||||
valid?: true,
|
||||
changes: %{
|
||||
content: content,
|
||||
source: %{
|
||||
"content" => "@akkoma_user linkifylink #dancedance $[jelly mfm goes here] \n\n## aaa",
|
||||
"mediaType" => "text/x.misskeymarkdown"
|
||||
"mediaType" => "text/x.misskeymarkdown",
|
||||
"content" => "@akkoma_user linkifylink #dancedance $[jelly mfm goes here] \n\n## aaa"
|
||||
}
|
||||
}
|
||||
} = changes
|
||||
|
||||
assert changes.changes[:content] == expected_content
|
||||
assert content =~
|
||||
"<span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{local_user.id}\" href=\"#{local_user.ap_id}\" rel=\"ugc\">@<span>akkoma_user</span></a></span>"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,8 +33,6 @@ test "Mastodon Question activity" do
|
|||
assert object.data["context"] ==
|
||||
"tag:mastodon.sdf.org,2019-05-10:objectId=15095122:objectType=Conversation"
|
||||
|
||||
assert object.data["context_id"]
|
||||
|
||||
assert object.data["anyOf"] == []
|
||||
|
||||
assert Enum.sort(object.data["oneOf"]) ==
|
||||
|
@ -68,7 +66,6 @@ test "Mastodon Question activity" do
|
|||
reply_object = Object.normalize(reply_activity, fetch: false)
|
||||
|
||||
assert reply_object.data["context"] == object.data["context"]
|
||||
assert reply_object.data["context_id"] == object.data["context_id"]
|
||||
end
|
||||
|
||||
test "Mastodon Question activity with HTML tags in plaintext" do
|
||||
|
|
|
@ -232,7 +232,6 @@ test "it strips internal fields" do
|
|||
assert is_nil(modified["object"]["like_count"])
|
||||
assert is_nil(modified["object"]["announcements"])
|
||||
assert is_nil(modified["object"]["announcement_count"])
|
||||
assert is_nil(modified["object"]["context_id"])
|
||||
assert is_nil(modified["object"]["generator"])
|
||||
end
|
||||
|
||||
|
@ -247,7 +246,6 @@ test "it strips internal fields of article" do
|
|||
assert is_nil(modified["object"]["like_count"])
|
||||
assert is_nil(modified["object"]["announcements"])
|
||||
assert is_nil(modified["object"]["announcement_count"])
|
||||
assert is_nil(modified["object"]["context_id"])
|
||||
assert is_nil(modified["object"]["likes"])
|
||||
end
|
||||
|
||||
|
|
|
@ -429,7 +429,6 @@ test "returns map with id and published data" do
|
|||
object = Object.normalize(note_activity, fetch: false)
|
||||
res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]})
|
||||
assert res["context"] == object.data["id"]
|
||||
assert res["context_id"] == object.id
|
||||
assert res["id"]
|
||||
assert res["published"]
|
||||
end
|
||||
|
@ -437,7 +436,6 @@ test "returns map with id and published data" do
|
|||
test "returns map with fake id and published data" do
|
||||
assert %{
|
||||
"context" => "pleroma:fakecontext",
|
||||
"context_id" => -1,
|
||||
"id" => "pleroma:fakeid",
|
||||
"published" => _
|
||||
} = Utils.lazy_put_activity_defaults(%{}, true)
|
||||
|
@ -454,13 +452,11 @@ test "returns activity data with object" do
|
|||
})
|
||||
|
||||
assert res["context"] == object.data["id"]
|
||||
assert res["context_id"] == object.id
|
||||
assert res["id"]
|
||||
assert res["published"]
|
||||
assert res["object"]["id"]
|
||||
assert res["object"]["published"]
|
||||
assert res["object"]["context"] == object.data["id"]
|
||||
assert res["object"]["context_id"] == object.id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
defmodule Pleroma.Web.CommonAPI.UtilsTest do
|
||||
alias Pleroma.Builders.UserBuilder
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.CommonAPI.ActivityDraft
|
||||
alias Pleroma.Web.CommonAPI.Utils
|
||||
|
@ -273,22 +272,6 @@ test "delegated renderers" do
|
|||
end
|
||||
end
|
||||
|
||||
describe "context_to_conversation_id" do
|
||||
test "creates a mapping object" do
|
||||
conversation_id = Utils.context_to_conversation_id("random context")
|
||||
object = Object.get_by_ap_id("random context")
|
||||
|
||||
assert conversation_id == object.id
|
||||
end
|
||||
|
||||
test "returns an existing mapping for an existing object" do
|
||||
{:ok, object} = Object.context_mapping("random context") |> Repo.insert()
|
||||
conversation_id = Utils.context_to_conversation_id("random context")
|
||||
|
||||
assert conversation_id == object.id
|
||||
end
|
||||
end
|
||||
|
||||
describe "formats date to asctime" do
|
||||
test "when date is in ISO 8601 format" do
|
||||
date = DateTime.utc_now() |> DateTime.to_iso8601()
|
||||
|
@ -517,17 +500,6 @@ test "returns empty string when date invalid" do
|
|||
end
|
||||
end
|
||||
|
||||
describe "conversation_id_to_context/1" do
|
||||
test "returns id" do
|
||||
object = insert(:note)
|
||||
assert Utils.conversation_id_to_context(object.id) == object.data["id"]
|
||||
end
|
||||
|
||||
test "returns error if object not found" do
|
||||
assert Utils.conversation_id_to_context("123") == {:error, "No such conversation"}
|
||||
end
|
||||
end
|
||||
|
||||
describe "maybe_notify_mentioned_recipients/2" do
|
||||
test "returns recipients when activity is not `Create`" do
|
||||
activity = insert(:like_activity)
|
||||
|
|
|
@ -153,7 +153,7 @@ test "rejects incoming AP docs with incorrect origin" do
|
|||
}
|
||||
|
||||
assert {:ok, job} = Federator.incoming_ap_doc(params)
|
||||
assert {:error, :origin_containment_failed} = ObanHelpers.perform(job)
|
||||
assert {:discard, :origin_containment_failed} = ObanHelpers.perform(job)
|
||||
end
|
||||
|
||||
test "it does not crash if MRF rejects the post" do
|
||||
|
@ -169,7 +169,7 @@ test "it does not crash if MRF rejects the post" do
|
|||
|> Jason.decode!()
|
||||
|
||||
assert {:ok, job} = Federator.incoming_ap_doc(params)
|
||||
assert {:error, _} = ObanHelpers.perform(job)
|
||||
assert {:discard, _} = ObanHelpers.perform(job)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
38
test/pleroma/web/masto_fe_controller_test.exs
Normal file
38
test/pleroma/web/masto_fe_controller_test.exs
Normal file
|
@ -0,0 +1,38 @@
|
|||
defmodule Pleroma.Web.MastoFEControllerTest do
|
||||
use Pleroma.Web.ConnCase, async: true
|
||||
alias Pleroma.Web.MastodonAPI.AuthController
|
||||
|
||||
describe "index/2 (main page)" do
|
||||
test "GET /web/ (glitch-soc)" do
|
||||
clear_config([:frontends, :mastodon], %{"name" => "mastodon-fe"})
|
||||
|
||||
{:ok, masto_app} = AuthController.local_mastofe_app()
|
||||
user = Pleroma.Factory.insert(:user)
|
||||
token = Pleroma.Factory.insert(:oauth_token, app: masto_app, user: user)
|
||||
%{conn: conn} = oauth_access(["read", "write"], oauth_token: token, user: user)
|
||||
|
||||
resp =
|
||||
conn
|
||||
|> get("/web/getting-started")
|
||||
|> html_response(200)
|
||||
|
||||
assert resp =~ "glitch"
|
||||
end
|
||||
|
||||
test "GET /web/ (fedibird)" do
|
||||
clear_config([:frontends, :mastodon], %{"name" => "fedibird-fe"})
|
||||
|
||||
{:ok, masto_app} = AuthController.local_mastofe_app()
|
||||
user = Pleroma.Factory.insert(:user)
|
||||
token = Pleroma.Factory.insert(:oauth_token, app: masto_app, user: user)
|
||||
%{conn: conn} = oauth_access(["read", "write"], oauth_token: token, user: user)
|
||||
|
||||
resp =
|
||||
conn
|
||||
|> get("/web/getting-started")
|
||||
|> html_response(200)
|
||||
|
||||
refute resp =~ "glitch"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -264,6 +264,7 @@ test "posting a fake status", %{conn: conn} do
|
|||
|> Map.put("url", nil)
|
||||
|> Map.put("uri", nil)
|
||||
|> Map.put("created_at", nil)
|
||||
|> Kernel.put_in(["pleroma", "context"], nil)
|
||||
|> Kernel.put_in(["pleroma", "conversation_id"], nil)
|
||||
|
||||
fake_conn =
|
||||
|
@ -287,6 +288,7 @@ test "posting a fake status", %{conn: conn} do
|
|||
|> Map.put("url", nil)
|
||||
|> Map.put("uri", nil)
|
||||
|> Map.put("created_at", nil)
|
||||
|> Kernel.put_in(["pleroma", "context"], nil)
|
||||
|> Kernel.put_in(["pleroma", "conversation_id"], nil)
|
||||
|
||||
assert real_status == fake_status
|
||||
|
|
|
@ -14,7 +14,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
|
|||
alias Pleroma.User
|
||||
alias Pleroma.UserRelationship
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.CommonAPI.Utils
|
||||
alias Pleroma.Web.MastodonAPI.AccountView
|
||||
alias Pleroma.Web.MastodonAPI.StatusView
|
||||
|
||||
|
@ -45,14 +44,15 @@ test "has an emoji reaction list" do
|
|||
assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
|
||||
|
||||
assert status[:pleroma][:emoji_reactions] == [
|
||||
%{name: "☕", count: 2, me: false, url: nil},
|
||||
%{name: "☕", count: 2, me: false, url: nil, account_ids: [other_user.id, user.id]},
|
||||
%{
|
||||
count: 2,
|
||||
me: false,
|
||||
name: "dinosaur",
|
||||
url: "http://localhost:4001/emoji/dino walking.gif"
|
||||
url: "http://localhost:4001/emoji/dino walking.gif",
|
||||
account_ids: [other_user.id, user.id]
|
||||
},
|
||||
%{name: "🍵", count: 1, me: false, url: nil}
|
||||
%{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
|
||||
]
|
||||
|
||||
status = StatusView.render("show.json", activity: activity, for: user)
|
||||
|
@ -60,14 +60,15 @@ test "has an emoji reaction list" do
|
|||
assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
|
||||
|
||||
assert status[:pleroma][:emoji_reactions] == [
|
||||
%{name: "☕", count: 2, me: true, url: nil},
|
||||
%{name: "☕", count: 2, me: true, url: nil, account_ids: [other_user.id, user.id]},
|
||||
%{
|
||||
count: 2,
|
||||
me: true,
|
||||
name: "dinosaur",
|
||||
url: "http://localhost:4001/emoji/dino walking.gif"
|
||||
url: "http://localhost:4001/emoji/dino walking.gif",
|
||||
account_ids: [other_user.id, user.id]
|
||||
},
|
||||
%{name: "🍵", count: 1, me: false, url: nil}
|
||||
%{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -83,7 +84,7 @@ test "works correctly with badly formatted emojis" do
|
|||
status = StatusView.render("show.json", activity: activity, for: user)
|
||||
|
||||
assert status[:pleroma][:emoji_reactions] == [
|
||||
%{name: "☕", count: 1, me: true, url: nil}
|
||||
%{name: "☕", count: 1, me: true, url: nil, account_ids: [user.id]}
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -103,7 +104,7 @@ test "doesn't show reactions from muted and blocked users" do
|
|||
status = StatusView.render("show.json", activity: activity)
|
||||
|
||||
assert status[:pleroma][:emoji_reactions] == [
|
||||
%{name: "☕", count: 1, me: false, url: nil}
|
||||
%{name: "☕", count: 1, me: false, url: nil, account_ids: [other_user.id]}
|
||||
]
|
||||
|
||||
status = StatusView.render("show.json", activity: activity, for: user)
|
||||
|
@ -115,19 +116,25 @@ test "doesn't show reactions from muted and blocked users" do
|
|||
status = StatusView.render("show.json", activity: activity)
|
||||
|
||||
assert status[:pleroma][:emoji_reactions] == [
|
||||
%{name: "☕", count: 2, me: false, url: nil}
|
||||
%{
|
||||
name: "☕",
|
||||
count: 2,
|
||||
me: false,
|
||||
url: nil,
|
||||
account_ids: [third_user.id, other_user.id]
|
||||
}
|
||||
]
|
||||
|
||||
status = StatusView.render("show.json", activity: activity, for: user)
|
||||
|
||||
assert status[:pleroma][:emoji_reactions] == [
|
||||
%{name: "☕", count: 1, me: false, url: nil}
|
||||
%{name: "☕", count: 1, me: false, url: nil, account_ids: [third_user.id]}
|
||||
]
|
||||
|
||||
status = StatusView.render("show.json", activity: activity, for: other_user)
|
||||
|
||||
assert status[:pleroma][:emoji_reactions] == [
|
||||
%{name: "☕", count: 1, me: true, url: nil}
|
||||
%{name: "☕", count: 1, me: true, url: nil, account_ids: [other_user.id]}
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -240,7 +247,7 @@ test "a note activity" do
|
|||
object_data = Object.normalize(note, fetch: false).data
|
||||
user = User.get_cached_by_ap_id(note.data["actor"])
|
||||
|
||||
convo_id = Utils.context_to_conversation_id(object_data["context"])
|
||||
convo_id = :erlang.crc32(object_data["context"]) |> Bitwise.band(Bitwise.bnot(0x8000_0000))
|
||||
|
||||
status = StatusView.render("show.json", %{activity: note})
|
||||
|
||||
|
@ -273,6 +280,7 @@ test "a note activity" do
|
|||
spoiler_text: HTML.filter_tags(object_data["summary"]),
|
||||
visibility: "public",
|
||||
media_attachments: [],
|
||||
emoji_reactions: [],
|
||||
mentions: [],
|
||||
tags: [
|
||||
%{
|
||||
|
@ -293,6 +301,7 @@ test "a note activity" do
|
|||
pleroma: %{
|
||||
local: true,
|
||||
conversation_id: convo_id,
|
||||
context: object_data["context"],
|
||||
in_reply_to_account_acct: nil,
|
||||
content: %{"text/plain" => HTML.strip_tags(object_data["content"])},
|
||||
spoiler_text: %{"text/plain" => HTML.strip_tags(object_data["summary"])},
|
||||
|
|
|
@ -31,7 +31,13 @@ test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do
|
|||
assert to_string(activity.id) == id
|
||||
|
||||
assert result["pleroma"]["emoji_reactions"] == [
|
||||
%{"name" => "☕", "count" => 1, "me" => true, "url" => nil}
|
||||
%{
|
||||
"name" => "☕",
|
||||
"count" => 1,
|
||||
"me" => true,
|
||||
"url" => nil,
|
||||
"account_ids" => [other_user.id]
|
||||
}
|
||||
]
|
||||
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
|
||||
|
@ -54,7 +60,8 @@ test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do
|
|||
"name" => "dinosaur",
|
||||
"count" => 1,
|
||||
"me" => true,
|
||||
"url" => "http://localhost:4001/emoji/dino walking.gif"
|
||||
"url" => "http://localhost:4001/emoji/dino walking.gif",
|
||||
"account_ids" => [other_user.id]
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do
|
||||
use Pleroma.Web.ConnCase
|
||||
import Pleroma.Factory
|
||||
alias Pleroma.Web.Plugs.HTTPSignaturePlug
|
||||
|
||||
import Plug.Conn
|
||||
|
@ -81,5 +82,14 @@ test "halts the connection when `signature` header is not present", %{conn: conn
|
|||
assert conn.state == :sent
|
||||
assert conn.resp_body == "Request not signed"
|
||||
end
|
||||
|
||||
test "aliases redirected /object endpoints", _ do
|
||||
obj = insert(:note)
|
||||
act = insert(:note_activity, note: obj)
|
||||
params = %{"actor" => "http://mastodon.example.org/users/admin"}
|
||||
path = URI.parse(obj.data["id"]).path
|
||||
conn = build_conn(:get, path, params)
|
||||
assert ["/notice/#{act.id}"] == HTTPSignaturePlug.route_aliases(conn)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -157,7 +157,8 @@ test "it streams the user's post in the 'user' stream", %{user: user, token: oau
|
|||
Streamer.get_topic_and_add_socket("user", user, oauth_token)
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
|
||||
|
||||
assert_receive {:render_with_user, _, _, ^activity}
|
||||
stream_name = "user:#{user.id}"
|
||||
assert_receive {:render_with_user, _, _, ^activity, ^stream_name}
|
||||
refute Streamer.filtered_by_user?(user, activity)
|
||||
end
|
||||
|
||||
|
@ -168,7 +169,11 @@ test "it streams boosts of the user in the 'user' stream", %{user: user, token:
|
|||
{:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
|
||||
{:ok, announce} = CommonAPI.repeat(activity.id, user)
|
||||
|
||||
assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce}
|
||||
stream_name = "user:#{user.id}"
|
||||
|
||||
assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce,
|
||||
^stream_name}
|
||||
|
||||
refute Streamer.filtered_by_user?(user, announce)
|
||||
end
|
||||
|
||||
|
@ -221,7 +226,11 @@ test "it streams boosts of mastodon user in the 'user' stream", %{
|
|||
{:ok, %Pleroma.Activity{data: _data, local: false} = announce} =
|
||||
Pleroma.Web.ActivityPub.Transmogrifier.handle_incoming(data)
|
||||
|
||||
assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce}
|
||||
stream_name = "user:#{user.id}"
|
||||
|
||||
assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce,
|
||||
^stream_name}
|
||||
|
||||
refute Streamer.filtered_by_user?(user, announce)
|
||||
end
|
||||
|
||||
|
@ -233,7 +242,7 @@ test "it sends notify to in the 'user' stream", %{
|
|||
Streamer.get_topic_and_add_socket("user", user, oauth_token)
|
||||
Streamer.stream("user", notify)
|
||||
|
||||
assert_receive {:render_with_user, _, _, ^notify}
|
||||
assert_receive {:render_with_user, _, _, ^notify, "user"}
|
||||
refute Streamer.filtered_by_user?(user, notify)
|
||||
end
|
||||
|
||||
|
@ -245,7 +254,7 @@ test "it sends notify to in the 'user:notification' stream", %{
|
|||
Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
|
||||
Streamer.stream("user:notification", notify)
|
||||
|
||||
assert_receive {:render_with_user, _, _, ^notify}
|
||||
assert_receive {:render_with_user, _, _, ^notify, "user:notification"}
|
||||
refute Streamer.filtered_by_user?(user, notify)
|
||||
end
|
||||
|
||||
|
@ -291,7 +300,7 @@ test "it sends favorite to 'user:notification' stream'", %{
|
|||
Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
|
||||
{:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id)
|
||||
|
||||
assert_receive {:render_with_user, _, "notification.json", notif}
|
||||
assert_receive {:render_with_user, _, "notification.json", notif, "user:notification"}
|
||||
assert notif.activity.id == favorite_activity.id
|
||||
refute Streamer.filtered_by_user?(user, notif)
|
||||
end
|
||||
|
@ -320,7 +329,7 @@ test "it sends follow activities to the 'user:notification' stream", %{
|
|||
Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
|
||||
{:ok, _follower, _followed, follow_activity} = CommonAPI.follow(user2, user)
|
||||
|
||||
assert_receive {:render_with_user, _, "notification.json", notif}
|
||||
assert_receive {:render_with_user, _, "notification.json", notif, "user:notification"}
|
||||
assert notif.activity.id == follow_activity.id
|
||||
refute Streamer.filtered_by_user?(user, notif)
|
||||
end
|
||||
|
@ -384,7 +393,7 @@ test "it sends to public (authenticated)" do
|
|||
Streamer.get_topic_and_add_socket("public", user, oauth_token)
|
||||
|
||||
{:ok, activity} = CommonAPI.post(other_user, %{status: "Test"})
|
||||
assert_receive {:render_with_user, _, _, ^activity}
|
||||
assert_receive {:render_with_user, _, _, ^activity, "public"}
|
||||
refute Streamer.filtered_by_user?(other_user, activity)
|
||||
end
|
||||
|
||||
|
@ -436,7 +445,7 @@ test "it filters to user if recipients invalid and thread containment is enabled
|
|||
|
||||
Streamer.get_topic_and_add_socket("public", user, oauth_token)
|
||||
Streamer.stream("public", activity)
|
||||
assert_receive {:render_with_user, _, _, ^activity}
|
||||
assert_receive {:render_with_user, _, _, ^activity, "public"}
|
||||
assert Streamer.filtered_by_user?(user, activity)
|
||||
end
|
||||
|
||||
|
@ -458,7 +467,7 @@ test "it sends message if recipients invalid and thread containment is disabled"
|
|||
Streamer.get_topic_and_add_socket("public", user, oauth_token)
|
||||
Streamer.stream("public", activity)
|
||||
|
||||
assert_receive {:render_with_user, _, _, ^activity}
|
||||
assert_receive {:render_with_user, _, _, ^activity, "public"}
|
||||
refute Streamer.filtered_by_user?(user, activity)
|
||||
end
|
||||
|
||||
|
@ -481,7 +490,7 @@ test "it sends message if recipients invalid and thread containment is enabled b
|
|||
Streamer.get_topic_and_add_socket("public", user, oauth_token)
|
||||
Streamer.stream("public", activity)
|
||||
|
||||
assert_receive {:render_with_user, _, _, ^activity}
|
||||
assert_receive {:render_with_user, _, _, ^activity, "public"}
|
||||
refute Streamer.filtered_by_user?(user, activity)
|
||||
end
|
||||
end
|
||||
|
@ -495,7 +504,7 @@ test "it filters messages involving blocked users", %{user: user, token: oauth_t
|
|||
|
||||
Streamer.get_topic_and_add_socket("public", user, oauth_token)
|
||||
{:ok, activity} = CommonAPI.post(blocked_user, %{status: "Test"})
|
||||
assert_receive {:render_with_user, _, _, ^activity}
|
||||
assert_receive {:render_with_user, _, _, ^activity, "public"}
|
||||
assert Streamer.filtered_by_user?(user, activity)
|
||||
end
|
||||
|
||||
|
@ -512,17 +521,17 @@ test "it filters messages transitively involving blocked users", %{
|
|||
|
||||
{:ok, activity_one} = CommonAPI.post(friend, %{status: "hey! @#{blockee.nickname}"})
|
||||
|
||||
assert_receive {:render_with_user, _, _, ^activity_one}
|
||||
assert_receive {:render_with_user, _, _, ^activity_one, "public"}
|
||||
assert Streamer.filtered_by_user?(blocker, activity_one)
|
||||
|
||||
{:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"})
|
||||
|
||||
assert_receive {:render_with_user, _, _, ^activity_two}
|
||||
assert_receive {:render_with_user, _, _, ^activity_two, "public"}
|
||||
assert Streamer.filtered_by_user?(blocker, activity_two)
|
||||
|
||||
{:ok, activity_three} = CommonAPI.post(blockee, %{status: "hey! @#{blocker.nickname}"})
|
||||
|
||||
assert_receive {:render_with_user, _, _, ^activity_three}
|
||||
assert_receive {:render_with_user, _, _, ^activity_three, "public"}
|
||||
assert Streamer.filtered_by_user?(blocker, activity_three)
|
||||
end
|
||||
end
|
||||
|
@ -583,7 +592,8 @@ test "it sends wanted private posts to list", %{user: user_a, token: user_a_toke
|
|||
visibility: "private"
|
||||
})
|
||||
|
||||
assert_receive {:render_with_user, _, _, ^activity}
|
||||
stream_name = "list:#{list.id}"
|
||||
assert_receive {:render_with_user, _, _, ^activity, ^stream_name}
|
||||
refute Streamer.filtered_by_user?(user_a, activity)
|
||||
end
|
||||
end
|
||||
|
@ -601,7 +611,8 @@ test "it filters muted reblogs", %{user: user1, token: user1_token} do
|
|||
|
||||
Streamer.get_topic_and_add_socket("user", user1, user1_token)
|
||||
{:ok, announce_activity} = CommonAPI.repeat(create_activity.id, user2)
|
||||
assert_receive {:render_with_user, _, _, ^announce_activity}
|
||||
stream_name = "user:#{user1.id}"
|
||||
assert_receive {:render_with_user, _, _, ^announce_activity, ^stream_name}
|
||||
assert Streamer.filtered_by_user?(user1, announce_activity)
|
||||
end
|
||||
|
||||
|
@ -617,7 +628,7 @@ test "it filters reblog notification for reblog-muted actors", %{
|
|||
Streamer.get_topic_and_add_socket("user", user1, user1_token)
|
||||
{:ok, _announce_activity} = CommonAPI.repeat(create_activity.id, user2)
|
||||
|
||||
assert_receive {:render_with_user, _, "notification.json", notif}
|
||||
assert_receive {:render_with_user, _, "notification.json", notif, "user"}
|
||||
assert Streamer.filtered_by_user?(user1, notif)
|
||||
end
|
||||
|
||||
|
@ -633,7 +644,7 @@ test "it send non-reblog notification for reblog-muted actors", %{
|
|||
Streamer.get_topic_and_add_socket("user", user1, user1_token)
|
||||
{:ok, _favorite_activity} = CommonAPI.favorite(user2, create_activity.id)
|
||||
|
||||
assert_receive {:render_with_user, _, "notification.json", notif}
|
||||
assert_receive {:render_with_user, _, "notification.json", notif, "user"}
|
||||
refute Streamer.filtered_by_user?(user1, notif)
|
||||
end
|
||||
end
|
||||
|
@ -648,7 +659,8 @@ test "it filters posts from muted threads" do
|
|||
{:ok, activity} = CommonAPI.post(user, %{status: "super hot take"})
|
||||
{:ok, _} = CommonAPI.add_mute(user2, activity)
|
||||
|
||||
assert_receive {:render_with_user, _, _, ^activity}
|
||||
stream_name = "user:#{user2.id}"
|
||||
assert_receive {:render_with_user, _, _, ^activity, ^stream_name}
|
||||
assert Streamer.filtered_by_user?(user2, activity)
|
||||
end
|
||||
end
|
||||
|
@ -690,7 +702,8 @@ test "it doesn't send conversation update to the 'direct' stream when the last m
|
|||
})
|
||||
|
||||
create_activity_id = create_activity.id
|
||||
assert_receive {:render_with_user, _, _, ^create_activity}
|
||||
stream_name = "direct:#{user.id}"
|
||||
assert_receive {:render_with_user, _, _, ^create_activity, ^stream_name}
|
||||
assert_receive {:text, received_conversation1}
|
||||
assert %{"event" => "conversation", "payload" => _} = Jason.decode!(received_conversation1)
|
||||
|
||||
|
@ -725,8 +738,9 @@ test "it sends conversation update to the 'direct' stream when a message is dele
|
|||
visibility: "direct"
|
||||
})
|
||||
|
||||
assert_receive {:render_with_user, _, _, ^create_activity}
|
||||
assert_receive {:render_with_user, _, _, ^create_activity2}
|
||||
stream_name = "direct:#{user.id}"
|
||||
assert_receive {:render_with_user, _, _, ^create_activity, ^stream_name}
|
||||
assert_receive {:render_with_user, _, _, ^create_activity2, ^stream_name}
|
||||
assert_receive {:text, received_conversation1}
|
||||
assert %{"event" => "conversation", "payload" => _} = Jason.decode!(received_conversation1)
|
||||
assert_receive {:text, received_conversation1}
|
||||
|
|
25
test/pleroma/workers/receiver_worker_test.exs
Normal file
25
test/pleroma/workers/receiver_worker_test.exs
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Workers.ReceiverWorkerTest do
|
||||
use Pleroma.DataCase, async: true
|
||||
use Oban.Testing, repo: Pleroma.Repo
|
||||
|
||||
import Mock
|
||||
import Pleroma.Factory
|
||||
|
||||
alias Pleroma.Workers.ReceiverWorker
|
||||
|
||||
test "it ignores MRF reject" do
|
||||
params = insert(:note).data
|
||||
|
||||
with_mock Pleroma.Web.ActivityPub.Transmogrifier,
|
||||
handle_incoming: fn _ -> {:reject, "MRF"} end do
|
||||
assert {:discard, "MRF"} =
|
||||
ReceiverWorker.perform(%Oban.Job{
|
||||
args: %{"op" => "incoming_ap_doc", "params" => params}
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue