Merge branch 'develop' of https://git.pleroma.social/pleroma/pleroma into emr_develop
This commit is contained in:
commit
a42c39dc3c
|
@ -34,6 +34,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||
- Make backend-rendered pages translatable. This includes emails. Pages returned as a HTTP response are translated using the language specified in the `userLanguage` cookie, or the `Accept-Language` header. Emails are translated using the `language` field when registering. This language can be changed by `PATCH /api/v1/accounts/update_credentials` with the `language` field.
|
||||
- Uploadfilter `Pleroma.Upload.Filter.Exiftool.ReadDescription` returns description values to the FE so they can pre fill the image description field
|
||||
- Added move account API
|
||||
- Enable remote users to interact with posts
|
||||
|
||||
### Fixed
|
||||
- Subscription(Bell) Notifications: Don't create from Pipeline Ingested replies
|
||||
|
|
|
@ -673,6 +673,8 @@ config :pleroma, :features, improved_hashtag_timeline: :auto
|
|||
|
||||
config :pleroma, :populate_hashtags_table, fault_rate_allowance: 0.01
|
||||
|
||||
config :pleroma, :delete_context_objects, fault_rate_allowance: 0.01
|
||||
|
||||
config :pleroma, :env, Mix.env()
|
||||
|
||||
config :http_signatures,
|
||||
|
|
|
@ -495,6 +495,27 @@ config :pleroma, :config_description, [
|
|||
}
|
||||
]
|
||||
},
|
||||
%{
|
||||
group: :pleroma,
|
||||
key: :delete_context_objects,
|
||||
type: :group,
|
||||
description: "`delete_context_objects` background migration settings",
|
||||
children: [
|
||||
%{
|
||||
key: :fault_rate_allowance,
|
||||
type: :float,
|
||||
description:
|
||||
"Max accepted rate of objects that failed in the migration. Any value from 0.0 which tolerates no errors to 1.0 which will enable the feature even if context object deletion failed for all records.",
|
||||
suggestions: [0.01]
|
||||
},
|
||||
%{
|
||||
key: :sleep_interval_ms,
|
||||
type: :integer,
|
||||
description:
|
||||
"Sleep interval between each chunk of processed records in order to decrease the load on the system (defaults to 0 and should be keep default on most instances)."
|
||||
}
|
||||
]
|
||||
},
|
||||
%{
|
||||
group: :pleroma,
|
||||
key: :instance,
|
||||
|
|
|
@ -154,9 +154,8 @@ defmodule Mix.Tasks.Pleroma.Database do
|
|||
|> join(:inner, [a], o in Object,
|
||||
on:
|
||||
fragment(
|
||||
"(?->>'id') = COALESCE((?)->'object'->> 'id', (?)->>'object')",
|
||||
"(?->>'id') = associated_object_id((?))",
|
||||
o.data,
|
||||
a.data,
|
||||
a.data
|
||||
)
|
||||
)
|
||||
|
|
|
@ -53,7 +53,7 @@ defmodule Pleroma.Activity do
|
|||
#
|
||||
# ```
|
||||
# |> join(:inner, [activity], o in Object,
|
||||
# on: fragment("(?->>'id') = COALESCE((?)->'object'->> 'id', (?)->>'object')",
|
||||
# on: fragment("(?->>'id') = associated_object_id((?))",
|
||||
# o.data, activity.data, activity.data))
|
||||
# |> preload([activity, object], [object: object])
|
||||
# ```
|
||||
|
@ -69,9 +69,8 @@ defmodule Pleroma.Activity do
|
|||
join(query, join_type, [activity], o in Object,
|
||||
on:
|
||||
fragment(
|
||||
"(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')",
|
||||
"(?->>'id') = associated_object_id(?)",
|
||||
o.data,
|
||||
activity.data,
|
||||
activity.data
|
||||
),
|
||||
as: :object
|
||||
|
|
|
@ -13,6 +13,14 @@ defmodule Pleroma.Activity.Ir.Topics do
|
|||
|> List.flatten()
|
||||
end
|
||||
|
||||
defp generate_topics(%{data: %{"type" => "ChatMessage"}}, %{data: %{"type" => "Delete"}}) do
|
||||
["user", "user:pleroma_chat"]
|
||||
end
|
||||
|
||||
defp generate_topics(%{data: %{"type" => "ChatMessage"}}, %{data: %{"type" => "Create"}}) do
|
||||
[]
|
||||
end
|
||||
|
||||
defp generate_topics(%{data: %{"type" => "Answer"}}, _) do
|
||||
[]
|
||||
end
|
||||
|
@ -21,7 +29,7 @@ defmodule Pleroma.Activity.Ir.Topics do
|
|||
["user", "list"] ++ visibility_tags(object, activity)
|
||||
end
|
||||
|
||||
defp visibility_tags(object, activity) do
|
||||
defp visibility_tags(object, %{data: %{"type" => type}} = activity) when type != "Announce" do
|
||||
case Visibility.get_visibility(activity) do
|
||||
"public" ->
|
||||
if activity.local do
|
||||
|
@ -31,6 +39,10 @@ defmodule Pleroma.Activity.Ir.Topics do
|
|||
end
|
||||
|> item_creation_tags(object, activity)
|
||||
|
||||
"local" ->
|
||||
["public:local"]
|
||||
|> item_creation_tags(object, activity)
|
||||
|
||||
"direct" ->
|
||||
["direct"]
|
||||
|
||||
|
@ -39,6 +51,10 @@ defmodule Pleroma.Activity.Ir.Topics do
|
|||
end
|
||||
end
|
||||
|
||||
defp visibility_tags(_object, _activity) do
|
||||
[]
|
||||
end
|
||||
|
||||
defp item_creation_tags(tags, object, %{data: %{"type" => "Create"}} = activity) do
|
||||
tags ++
|
||||
remote_topics(activity) ++ hashtags_to_topics(object) ++ attachment_topics(object, activity)
|
||||
|
@ -63,7 +79,18 @@ defmodule Pleroma.Activity.Ir.Topics do
|
|||
|
||||
defp attachment_topics(%{data: %{"attachment" => []}}, _act), do: []
|
||||
|
||||
defp attachment_topics(_object, %{local: true}), do: ["public:media", "public:local:media"]
|
||||
defp attachment_topics(_object, %{local: true} = activity) do
|
||||
case Visibility.get_visibility(activity) do
|
||||
"public" ->
|
||||
["public:media", "public:local:media"]
|
||||
|
||||
"local" ->
|
||||
["public:local:media"]
|
||||
|
||||
_ ->
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
defp attachment_topics(_object, %{actor: actor}) when is_binary(actor),
|
||||
do: ["public:media", "public:remote:media:" <> URI.parse(actor).host]
|
||||
|
|
|
@ -52,8 +52,7 @@ defmodule Pleroma.Activity.Queries do
|
|||
activity in query,
|
||||
where:
|
||||
fragment(
|
||||
"coalesce((?)->'object'->>'id', (?)->>'object') = ANY(?)",
|
||||
activity.data,
|
||||
"associated_object_id((?)) = ANY(?)",
|
||||
activity.data,
|
||||
^object_ids
|
||||
)
|
||||
|
@ -64,8 +63,7 @@ defmodule Pleroma.Activity.Queries do
|
|||
from(activity in query,
|
||||
where:
|
||||
fragment(
|
||||
"coalesce((?)->'object'->>'id', (?)->>'object') = ?",
|
||||
activity.data,
|
||||
"associated_object_id((?)) = ?",
|
||||
activity.data,
|
||||
^object_id
|
||||
)
|
||||
|
|
|
@ -249,7 +249,8 @@ defmodule Pleroma.Application do
|
|||
|
||||
defp background_migrators do
|
||||
[
|
||||
Pleroma.Migrators.HashtagsTableMigrator
|
||||
Pleroma.Migrators.HashtagsTableMigrator,
|
||||
Pleroma.Migrators.ContextObjectsDeletionMigrator
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -42,8 +42,45 @@ defmodule Pleroma.BBS.Handler do
|
|||
|
||||
def puts_activity(activity) do
|
||||
status = Pleroma.Web.MastodonAPI.StatusView.render("show.json", %{activity: activity})
|
||||
|
||||
IO.puts("-- #{status.id} by #{status.account.display_name} (#{status.account.acct})")
|
||||
IO.puts(HTML.strip_tags(status.content))
|
||||
|
||||
status.content
|
||||
|> String.split("<br/>")
|
||||
|> Enum.map(&HTML.strip_tags/1)
|
||||
|> Enum.map(&HtmlEntities.decode/1)
|
||||
|> Enum.map(&IO.puts/1)
|
||||
end
|
||||
|
||||
def puts_notification(activity, user) do
|
||||
notification =
|
||||
Pleroma.Web.MastodonAPI.NotificationView.render("show.json", %{
|
||||
notification: activity,
|
||||
for: user
|
||||
})
|
||||
|
||||
IO.puts(
|
||||
"== (#{notification.type}) #{notification.status.id} by #{notification.account.display_name} (#{notification.account.acct})"
|
||||
)
|
||||
|
||||
notification.status.content
|
||||
|> String.split("<br/>")
|
||||
|> Enum.map(&HTML.strip_tags/1)
|
||||
|> Enum.map(&HtmlEntities.decode/1)
|
||||
|> (fn x ->
|
||||
case x do
|
||||
[content] ->
|
||||
"> " <> content
|
||||
|
||||
[head | _tail] ->
|
||||
# "> " <> hd <> "..."
|
||||
head
|
||||
|> String.slice(1, 80)
|
||||
|> (fn x -> "> " <> x <> "..." end).()
|
||||
end
|
||||
end).()
|
||||
|> IO.puts()
|
||||
|
||||
IO.puts("")
|
||||
end
|
||||
|
||||
|
@ -53,6 +90,11 @@ defmodule Pleroma.BBS.Handler do
|
|||
IO.puts("home - Show the home timeline")
|
||||
IO.puts("p <text> - Post the given text")
|
||||
IO.puts("r <id> <text> - Reply to the post with the given id")
|
||||
IO.puts("t <id> - Show a thread from the given id")
|
||||
IO.puts("n - Show notifications")
|
||||
IO.puts("n read - Mark all notifactions as read")
|
||||
IO.puts("f <id> - Favourites the post with the given id")
|
||||
IO.puts("R <id> - Repeat the post with the given id")
|
||||
IO.puts("quit - Quit")
|
||||
|
||||
state
|
||||
|
@ -73,11 +115,53 @@ defmodule Pleroma.BBS.Handler do
|
|||
state
|
||||
end
|
||||
|
||||
def handle_command(%{user: user} = state, "t " <> activity_id) do
|
||||
with %Activity{} = activity <- Activity.get_by_id(activity_id) do
|
||||
activities =
|
||||
ActivityPub.fetch_activities_for_context(activity.data["context"], %{
|
||||
blocking_user: user,
|
||||
user: user,
|
||||
exclude_id: activity.id
|
||||
})
|
||||
|
||||
case activities do
|
||||
[] ->
|
||||
activity_id
|
||||
|> Activity.get_by_id()
|
||||
|> puts_activity()
|
||||
|
||||
_ ->
|
||||
activities
|
||||
|> Enum.reverse()
|
||||
|> Enum.each(&puts_activity/1)
|
||||
end
|
||||
else
|
||||
_e -> IO.puts("Could not show this thread...")
|
||||
end
|
||||
|
||||
state
|
||||
end
|
||||
|
||||
def handle_command(%{user: user} = state, "n read") do
|
||||
Pleroma.Notification.clear(user)
|
||||
IO.puts("All notifications were marked as read")
|
||||
|
||||
state
|
||||
end
|
||||
|
||||
def handle_command(%{user: user} = state, "n") do
|
||||
user
|
||||
|> Pleroma.Web.MastodonAPI.MastodonAPI.get_notifications(%{})
|
||||
|> Enum.each(&puts_notification(&1, user))
|
||||
|
||||
state
|
||||
end
|
||||
|
||||
def handle_command(%{user: user} = state, "p " <> text) do
|
||||
text = String.trim(text)
|
||||
|
||||
with {:ok, _activity} <- CommonAPI.post(user, %{status: text}) do
|
||||
IO.puts("Posted!")
|
||||
with {:ok, activity} <- CommonAPI.post(user, %{status: text}) do
|
||||
IO.puts("Posted! ID: #{activity.id}")
|
||||
else
|
||||
_e -> IO.puts("Could not post...")
|
||||
end
|
||||
|
@ -85,6 +169,19 @@ defmodule Pleroma.BBS.Handler do
|
|||
state
|
||||
end
|
||||
|
||||
def handle_command(%{user: user} = state, "f " <> id) do
|
||||
id = String.trim(id)
|
||||
|
||||
with %Activity{} = activity <- Activity.get_by_id(id),
|
||||
{:ok, _activity} <- CommonAPI.favorite(user, activity) do
|
||||
IO.puts("Favourited!")
|
||||
else
|
||||
_e -> IO.puts("Could not Favourite...")
|
||||
end
|
||||
|
||||
state
|
||||
end
|
||||
|
||||
def handle_command(state, "home") do
|
||||
user = state.user
|
||||
|
||||
|
@ -123,7 +220,7 @@ defmodule Pleroma.BBS.Handler do
|
|||
|
||||
loop(%{state | counter: state.counter + 1})
|
||||
|
||||
{:error, :interrupted} ->
|
||||
{:input, ^input, {:error, :interrupted}} ->
|
||||
IO.puts("Caught Ctrl+C...")
|
||||
loop(%{state | counter: state.counter + 1})
|
||||
|
||||
|
|
|
@ -42,4 +42,5 @@ defmodule Pleroma.DataMigration do
|
|||
end
|
||||
|
||||
def populate_hashtags_table, do: get_by_name("populate_hashtags_table")
|
||||
def delete_context_objects, do: get_by_name("delete_context_objects")
|
||||
end
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Migrators.ContextObjectsDeletionMigrator do
|
||||
defmodule State do
|
||||
use Pleroma.Migrators.Support.BaseMigratorState
|
||||
|
||||
@impl Pleroma.Migrators.Support.BaseMigratorState
|
||||
defdelegate data_migration(), to: Pleroma.DataMigration, as: :delete_context_objects
|
||||
end
|
||||
|
||||
use Pleroma.Migrators.Support.BaseMigrator
|
||||
|
||||
alias Pleroma.Migrators.Support.BaseMigrator
|
||||
alias Pleroma.Object
|
||||
|
||||
@doc "This migration removes objects created exclusively for contexts, containing only an `id` field."
|
||||
|
||||
@impl BaseMigrator
|
||||
def feature_config_path, do: [:features, :delete_context_objects]
|
||||
|
||||
@impl BaseMigrator
|
||||
def fault_rate_allowance, do: Config.get([:delete_context_objects, :fault_rate_allowance], 0)
|
||||
|
||||
@impl BaseMigrator
|
||||
def perform do
|
||||
data_migration_id = data_migration_id()
|
||||
max_processed_id = get_stat(:max_processed_id, 0)
|
||||
|
||||
Logger.info("Deleting context objects from `objects` (from oid: #{max_processed_id})...")
|
||||
|
||||
query()
|
||||
|> where([object], object.id > ^max_processed_id)
|
||||
|> Repo.chunk_stream(100, :batches, timeout: :infinity)
|
||||
|> Stream.each(fn objects ->
|
||||
object_ids = Enum.map(objects, & &1.id)
|
||||
|
||||
results = Enum.map(object_ids, &delete_context_object(&1))
|
||||
|
||||
failed_ids =
|
||||
results
|
||||
|> Enum.filter(&(elem(&1, 0) == :error))
|
||||
|> Enum.map(&elem(&1, 1))
|
||||
|
||||
chunk_affected_count =
|
||||
results
|
||||
|> Enum.filter(&(elem(&1, 0) == :ok))
|
||||
|> length()
|
||||
|
||||
for failed_id <- failed_ids do
|
||||
_ =
|
||||
Repo.query(
|
||||
"INSERT INTO data_migration_failed_ids(data_migration_id, record_id) " <>
|
||||
"VALUES ($1, $2) ON CONFLICT DO NOTHING;",
|
||||
[data_migration_id, failed_id]
|
||||
)
|
||||
end
|
||||
|
||||
_ =
|
||||
Repo.query(
|
||||
"DELETE FROM data_migration_failed_ids " <>
|
||||
"WHERE data_migration_id = $1 AND record_id = ANY($2)",
|
||||
[data_migration_id, object_ids -- failed_ids]
|
||||
)
|
||||
|
||||
max_object_id = Enum.at(object_ids, -1)
|
||||
|
||||
put_stat(:max_processed_id, max_object_id)
|
||||
increment_stat(:iteration_processed_count, length(object_ids))
|
||||
increment_stat(:processed_count, length(object_ids))
|
||||
increment_stat(:failed_count, length(failed_ids))
|
||||
increment_stat(:affected_count, chunk_affected_count)
|
||||
put_stat(:records_per_second, records_per_second())
|
||||
persist_state()
|
||||
|
||||
# A quick and dirty approach to controlling the load this background migration imposes
|
||||
sleep_interval = Config.get([:delete_context_objects, :sleep_interval_ms], 0)
|
||||
Process.sleep(sleep_interval)
|
||||
end)
|
||||
|> Stream.run()
|
||||
end
|
||||
|
||||
@impl BaseMigrator
|
||||
def query do
|
||||
# Context objects have no activity type, and only one field, `id`.
|
||||
# Only those context objects are without types.
|
||||
from(
|
||||
object in Object,
|
||||
where: fragment("(?)->'type' IS NULL", object.data),
|
||||
select: %{
|
||||
id: object.id
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
@spec delete_context_object(integer()) :: {:ok | :error, integer()}
|
||||
defp delete_context_object(id) do
|
||||
result =
|
||||
%Object{id: id}
|
||||
|> Repo.delete()
|
||||
|> elem(0)
|
||||
|
||||
{result, id}
|
||||
end
|
||||
|
||||
@impl BaseMigrator
|
||||
def retry_failed do
|
||||
data_migration_id = data_migration_id()
|
||||
|
||||
failed_objects_query()
|
||||
|> Repo.chunk_stream(100, :one)
|
||||
|> Stream.each(fn object ->
|
||||
with {res, _} when res != :error <- delete_context_object(object.id) do
|
||||
_ =
|
||||
Repo.query(
|
||||
"DELETE FROM data_migration_failed_ids " <>
|
||||
"WHERE data_migration_id = $1 AND record_id = $2",
|
||||
[data_migration_id, object.id]
|
||||
)
|
||||
end
|
||||
end)
|
||||
|> Stream.run()
|
||||
|
||||
put_stat(:failed_count, failures_count())
|
||||
persist_state()
|
||||
|
||||
force_continue()
|
||||
end
|
||||
|
||||
defp failed_objects_query do
|
||||
from(o in Object)
|
||||
|> join(:inner, [o], dmf in fragment("SELECT * FROM data_migration_failed_ids"),
|
||||
on: dmf.record_id == o.id
|
||||
)
|
||||
|> where([_o, dmf], dmf.data_migration_id == ^data_migration_id())
|
||||
|> order_by([o], asc: o.id)
|
||||
end
|
||||
end
|
|
@ -183,7 +183,7 @@ defmodule Pleroma.Migrators.HashtagsTableMigrator do
|
|||
DELETE FROM hashtags_objects WHERE object_id IN
|
||||
(SELECT DISTINCT objects.id FROM objects
|
||||
JOIN hashtags_objects ON hashtags_objects.object_id = objects.id LEFT JOIN activities
|
||||
ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') =
|
||||
ON associated_object_id(activities) =
|
||||
(objects.data->>'id')
|
||||
AND activities.data->>'type' = 'Create'
|
||||
WHERE activities.id IS NULL);
|
||||
|
|
|
@ -117,9 +117,8 @@ defmodule Pleroma.Notification do
|
|||
|> join(:left, [n, a], object in Object,
|
||||
on:
|
||||
fragment(
|
||||
"(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')",
|
||||
"(?->>'id') = associated_object_id(?)",
|
||||
object.data,
|
||||
a.data,
|
||||
a.data
|
||||
)
|
||||
)
|
||||
|
@ -193,13 +192,11 @@ defmodule Pleroma.Notification do
|
|||
|> join(:left, [n, a], mutated_activity in Pleroma.Activity,
|
||||
on:
|
||||
fragment(
|
||||
"COALESCE((?->'object')->>'id', ?->>'object')",
|
||||
a.data,
|
||||
"associated_object_id(?)",
|
||||
a.data
|
||||
) ==
|
||||
fragment(
|
||||
"COALESCE((?->'object')->>'id', ?->>'object')",
|
||||
mutated_activity.data,
|
||||
"associated_object_id(?)",
|
||||
mutated_activity.data
|
||||
) and
|
||||
fragment("(?->>'type' = 'Like' or ?->>'type' = 'Announce')", a.data, a.data) and
|
||||
|
|
|
@ -40,8 +40,7 @@ defmodule Pleroma.Object do
|
|||
join(query, join_type, [{object, object_position}], a in Activity,
|
||||
on:
|
||||
fragment(
|
||||
"COALESCE(?->'object'->>'id', ?->>'object') = (? ->> 'id') AND (?->>'type' = ?) ",
|
||||
a.data,
|
||||
"associated_object_id(?) = (? ->> 'id') AND (?->>'type' = ?) ",
|
||||
a.data,
|
||||
object.data,
|
||||
a.data,
|
||||
|
@ -208,10 +207,6 @@ defmodule Pleroma.Object 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,
|
||||
|
|
|
@ -10,17 +10,14 @@ defmodule Pleroma.Signature do
|
|||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
|
||||
@known_suffixes ["/publickey", "/main-key"]
|
||||
|
||||
def key_id_to_actor_id(key_id) do
|
||||
uri =
|
||||
URI.parse(key_id)
|
||||
key_id
|
||||
|> URI.parse()
|
||||
|> Map.put(:fragment, nil)
|
||||
|
||||
uri =
|
||||
if not is_nil(uri.path) and String.ends_with?(uri.path, "/publickey") do
|
||||
Map.put(uri, :path, String.replace(uri.path, "/publickey", ""))
|
||||
else
|
||||
uri
|
||||
end
|
||||
|> remove_suffix(@known_suffixes)
|
||||
|
||||
maybe_ap_id = URI.to_string(uri)
|
||||
|
||||
|
@ -36,6 +33,16 @@ defmodule Pleroma.Signature do
|
|||
end
|
||||
end
|
||||
|
||||
defp remove_suffix(uri, [test | rest]) do
|
||||
if not is_nil(uri.path) and String.ends_with?(uri.path, test) do
|
||||
Map.put(uri, :path, String.replace(uri.path, test, ""))
|
||||
else
|
||||
remove_suffix(uri, rest)
|
||||
end
|
||||
end
|
||||
|
||||
defp remove_suffix(uri, []), do: uri
|
||||
|
||||
def fetch_public_key(conn) do
|
||||
with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn),
|
||||
{:ok, actor_id} <- key_id_to_actor_id(kid),
|
||||
|
|
|
@ -1159,8 +1159,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
[activity, object: o] in query,
|
||||
where:
|
||||
fragment(
|
||||
"(?)->>'type' = 'Create' and coalesce((?)->'object'->>'id', (?)->>'object') = any (?)",
|
||||
activity.data,
|
||||
"(?)->>'type' = 'Create' and associated_object_id((?)) = any (?)",
|
||||
activity.data,
|
||||
activity.data,
|
||||
^ids
|
||||
|
|
|
@ -63,7 +63,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do
|
|||
defp fix_replies(%{"replies" => %{"items" => replies}} = data) when is_list(replies),
|
||||
do: Map.put(data, "replies", replies)
|
||||
|
||||
defp fix_replies(%{"replies" => replies} = data) when is_bitstring(replies),
|
||||
# TODO: Pleroma does not have any support for Collections at the moment.
|
||||
# If the `replies` field is not something the ObjectID validator can handle,
|
||||
# the activity/object would be rejected, which is bad behavior.
|
||||
defp fix_replies(%{"replies" => replies} = data) when not is_list(replies),
|
||||
do: Map.drop(data, ["replies"])
|
||||
|
||||
defp fix_replies(data), do: data
|
||||
|
@ -97,7 +100,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator 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()
|
||||
|
|
|
@ -52,8 +52,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields 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,15 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
|
|||
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"] || data["inReplyTo"] || data["id"]
|
||||
)
|
||||
|
||||
%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)
|
||||
|
|
|
@ -75,7 +75,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do
|
|||
|
||||
data
|
||||
|> CommonFixes.fix_actor()
|
||||
|> Map.put_new("context", object["context"])
|
||||
|> Map.put("context", object["context"])
|
||||
|> fix_addressing(object)
|
||||
end
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator 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 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator 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()
|
||||
|
|
|
@ -154,22 +154,7 @@ defmodule Pleroma.Web.ActivityPub.Utils 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 @@ defmodule Pleroma.Web.ActivityPub.Utils 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 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
|> 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 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
|> 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
|
||||
|
|
|
@ -405,6 +405,16 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
|
|||
}
|
||||
end
|
||||
|
||||
def show_subscribe_form_operation do
|
||||
%Operation{
|
||||
tags: ["Accounts"],
|
||||
summary: "Show remote subscribe form",
|
||||
operationId: "UtilController.show_subscribe_form",
|
||||
parameters: [],
|
||||
responses: %{200 => Operation.response("Web Page", "test/html", %Schema{type: :string})}
|
||||
}
|
||||
end
|
||||
|
||||
defp delete_account_request do
|
||||
%Schema{
|
||||
title: "AccountDeleteRequest",
|
||||
|
|
|
@ -148,9 +148,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,
|
||||
|
@ -325,6 +331,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" => [],
|
||||
|
|
|
@ -453,35 +453,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
|
||||
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
|
||||
|
|
|
@ -99,7 +99,8 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
|
|||
end,
|
||||
if Config.get([:instance, :profile_directory]) do
|
||||
"profile_directory"
|
||||
end
|
||||
end,
|
||||
"pleroma:get:main/ostatus"
|
||||
]
|
||||
|> Enum.filter(& &1)
|
||||
end
|
||||
|
|
|
@ -57,11 +57,19 @@ defmodule Pleroma.Web.MastodonAPI.StatusView 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
|
||||
|
||||
|
@ -388,6 +396,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
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},
|
||||
|
|
|
@ -8,8 +8,8 @@ defmodule Pleroma.Web.Metadata.Utils do
|
|||
alias Pleroma.Formatter
|
||||
alias Pleroma.HTML
|
||||
|
||||
def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do
|
||||
content
|
||||
defp scrub_html_and_truncate_object_field(field, object) do
|
||||
field
|
||||
# html content comes from DB already encoded, decode first and scrub after
|
||||
|> HtmlEntities.decode()
|
||||
|> String.replace(~r/<br\s?\/?>/, " ")
|
||||
|
@ -19,6 +19,17 @@ defmodule Pleroma.Web.Metadata.Utils do
|
|||
|> Formatter.truncate()
|
||||
end
|
||||
|
||||
def scrub_html_and_truncate(%{data: %{"summary" => summary}} = object)
|
||||
when is_binary(summary) and summary != "" do
|
||||
summary
|
||||
|> scrub_html_and_truncate_object_field(object)
|
||||
end
|
||||
|
||||
def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do
|
||||
content
|
||||
|> scrub_html_and_truncate_object_field(object)
|
||||
end
|
||||
|
||||
def scrub_html_and_truncate(content, max_length \\ 200) when is_binary(content) do
|
||||
content
|
||||
|> scrub_html
|
||||
|
|
|
@ -25,21 +25,58 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
|
|||
end
|
||||
end
|
||||
|
||||
defp validate_signature(conn, request_target) do
|
||||
# Newer drafts for HTTP signatures now use @request-target instead of the
|
||||
# old (request-target). We'll now support both for incoming signatures.
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header("(request-target)", request_target)
|
||||
|> put_req_header("@request-target", request_target)
|
||||
|
||||
HTTPSignatures.validate_conn(conn)
|
||||
end
|
||||
|
||||
defp validate_signature(conn) do
|
||||
# This (request-target) is non-standard, but many implementations do it
|
||||
# this way due to a misinterpretation of
|
||||
# https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-06
|
||||
# "path" was interpreted as not having the query, though later examples
|
||||
# show that it must be the absolute path + query. This behavior is kept to
|
||||
# make sure most software (Pleroma itself, Mastodon, and probably others)
|
||||
# do not break.
|
||||
request_target = String.downcase("#{conn.method}") <> " #{conn.request_path}"
|
||||
|
||||
# This is the proper way to build the @request-target, as expected by
|
||||
# many HTTP signature libraries, clarified in the following draft:
|
||||
# https://www.ietf.org/archive/id/draft-ietf-httpbis-message-signatures-11.html#section-2.2.6
|
||||
# It is the same as before, but containing the query part as well.
|
||||
proper_target = request_target <> "?#{conn.query_string}"
|
||||
|
||||
cond do
|
||||
# Normal, non-standard behavior but expected by Pleroma and more.
|
||||
validate_signature(conn, request_target) ->
|
||||
true
|
||||
|
||||
# Has query string and the previous one failed: let's try the standard.
|
||||
conn.query_string != "" ->
|
||||
validate_signature(conn, proper_target)
|
||||
|
||||
# If there's no query string and signature fails, it's rotten.
|
||||
true ->
|
||||
false
|
||||
end
|
||||
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}"
|
||||
|
||||
# we replace the digest header with the one we computed in DigestPlug
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header("(request-target)", request_target)
|
||||
|> case do
|
||||
case conn do
|
||||
%{assigns: %{digest: digest}} = conn -> put_req_header(conn, "digest", digest)
|
||||
conn -> conn
|
||||
end
|
||||
|
||||
assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn))
|
||||
assign(conn, :valid_signature, validate_signature(conn))
|
||||
else
|
||||
Logger.debug("No signature header!")
|
||||
conn
|
||||
|
|
|
@ -337,6 +337,7 @@ defmodule Pleroma.Web.Router do
|
|||
pipe_through(:pleroma_html)
|
||||
|
||||
post("/main/ostatus", UtilController, :remote_subscribe)
|
||||
get("/main/ostatus", UtilController, :show_subscribe_form)
|
||||
get("/ostatus_subscribe", RemoteFollowController, :follow)
|
||||
post("/ostatus_subscribe", RemoteFollowController, :do_follow)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<%= if @error do %>
|
||||
<h2><%= Gettext.dpgettext("static_pages", "status interact error", "Error: %{error}", error: @error) %></h2>
|
||||
<% else %>
|
||||
<h2><%= raw Gettext.dpgettext("static_pages", "status interact header", "Interacting with %{nickname}'s %{status_link}", nickname: safe_to_string(html_escape(@nickname)), status_link: safe_to_string(link(Gettext.dpgettext("static_pages", "status interact header - status link text", "status"), to: @status_link))) %></h2>
|
||||
<%= form_for @conn, Routes.util_path(@conn, :remote_subscribe), [as: "status"], fn f -> %>
|
||||
<%= hidden_input f, :status_id, value: @status_id %>
|
||||
<%= text_input f, :profile, placeholder: Gettext.dpgettext("static_pages", "placeholder text for account id", "Your account ID, e.g. lain@quitter.se") %>
|
||||
<%= submit Gettext.dpgettext("static_pages", "status interact authorization button", "Interact") %>
|
||||
<% end %>
|
||||
<% end %>
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
|
||||
require Logger
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Emoji
|
||||
alias Pleroma.Healthcheck
|
||||
|
@ -16,8 +17,16 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||
alias Pleroma.Web.WebFinger
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate when action != :remote_subscribe)
|
||||
plug(Pleroma.Web.Plugs.FederatingPlug when action == :remote_subscribe)
|
||||
plug(
|
||||
Pleroma.Web.ApiSpec.CastAndValidate
|
||||
when action != :remote_subscribe and action != :show_subscribe_form
|
||||
)
|
||||
|
||||
plug(
|
||||
Pleroma.Web.Plugs.FederatingPlug
|
||||
when action == :remote_subscribe
|
||||
when action == :show_subscribe_form
|
||||
)
|
||||
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
|
@ -44,7 +53,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
|
||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TwitterUtilOperation
|
||||
|
||||
def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
|
||||
def show_subscribe_form(conn, %{"nickname" => nick}) do
|
||||
with %User{} = user <- User.get_cached_by_nickname(nick),
|
||||
avatar = User.avatar_url(user) do
|
||||
conn
|
||||
|
@ -54,11 +63,52 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
render(conn, "subscribe.html", %{
|
||||
nickname: nick,
|
||||
avatar: nil,
|
||||
error: "Could not find user"
|
||||
error:
|
||||
Pleroma.Web.Gettext.dpgettext(
|
||||
"static_pages",
|
||||
"remote follow error message - user not found",
|
||||
"Could not find user"
|
||||
)
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
def show_subscribe_form(conn, %{"status_id" => id}) do
|
||||
with %Activity{} = activity <- Activity.get_by_id(id),
|
||||
{:ok, ap_id} <- get_ap_id(activity),
|
||||
%User{} = user <- User.get_cached_by_ap_id(activity.actor),
|
||||
avatar = User.avatar_url(user) do
|
||||
conn
|
||||
|> render("status_interact.html", %{
|
||||
status_link: ap_id,
|
||||
status_id: id,
|
||||
nickname: user.nickname,
|
||||
avatar: avatar,
|
||||
error: false
|
||||
})
|
||||
else
|
||||
_e ->
|
||||
render(conn, "status_interact.html", %{
|
||||
status_id: id,
|
||||
avatar: nil,
|
||||
error:
|
||||
Pleroma.Web.Gettext.dpgettext(
|
||||
"static_pages",
|
||||
"status interact error message - status not found",
|
||||
"Could not find status"
|
||||
)
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
|
||||
show_subscribe_form(conn, %{"nickname" => nick})
|
||||
end
|
||||
|
||||
def remote_subscribe(conn, %{"status_id" => id, "profile" => _}) do
|
||||
show_subscribe_form(conn, %{"status_id" => id})
|
||||
end
|
||||
|
||||
def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do
|
||||
with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
|
||||
%User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do
|
||||
|
@ -69,7 +119,33 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
render(conn, "subscribe.html", %{
|
||||
nickname: nick,
|
||||
avatar: nil,
|
||||
error: "Something went wrong."
|
||||
error:
|
||||
Pleroma.Web.Gettext.dpgettext(
|
||||
"static_pages",
|
||||
"remote follow error message - unknown error",
|
||||
"Something went wrong."
|
||||
)
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
def remote_subscribe(conn, %{"status" => %{"status_id" => id, "profile" => profile}}) do
|
||||
with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
|
||||
%Activity{} = activity <- Activity.get_by_id(id),
|
||||
{:ok, ap_id} <- get_ap_id(activity) do
|
||||
conn
|
||||
|> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id))
|
||||
else
|
||||
_e ->
|
||||
render(conn, "status_interact.html", %{
|
||||
status_id: id,
|
||||
avatar: nil,
|
||||
error:
|
||||
Pleroma.Web.Gettext.dpgettext(
|
||||
"static_pages",
|
||||
"status interact error message - unknown error",
|
||||
"Something went wrong."
|
||||
)
|
||||
})
|
||||
end
|
||||
end
|
||||
|
@ -83,6 +159,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
end
|
||||
end
|
||||
|
||||
defp get_ap_id(activity) do
|
||||
object = Pleroma.Object.normalize(activity, fetch: false)
|
||||
|
||||
case object do
|
||||
%{data: %{"id" => ap_id}} -> {:ok, ap_id}
|
||||
_ -> {:no_ap_id, nil}
|
||||
end
|
||||
end
|
||||
|
||||
def frontend_configurations(conn, _params) do
|
||||
render(conn, "frontend_configurations.json")
|
||||
end
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
defmodule Pleroma.Web.TwitterAPI.UtilView do
|
||||
use Pleroma.Web, :view
|
||||
import Phoenix.HTML
|
||||
import Phoenix.HTML.Form
|
||||
import Phoenix.HTML.Link
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Web.Endpoint
|
||||
alias Pleroma.Web.Gettext
|
||||
|
|
3
mix.exs
3
mix.exs
|
@ -80,7 +80,8 @@ defmodule Pleroma.Mixfile do
|
|||
:quack,
|
||||
:fast_sanitize,
|
||||
:os_mon,
|
||||
:ssl
|
||||
:ssl,
|
||||
:esshd
|
||||
],
|
||||
included_applications: [:ex_syslogger]
|
||||
]
|
||||
|
|
|
@ -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-14 11:04+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://weblate.pleroma-dev.ebin.club/projects/pleroma/"
|
||||
"pleroma-backend-domain-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"
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-08-13 13:32+0300\n"
|
||||
"PO-Revision-Date: 2022-08-14 11:04+0000\n"
|
||||
"Last-Translator: Fristi <fristi@subcon.town>\n"
|
||||
"Language-Team: Dutch <http://weblate.pleroma-dev.ebin.club/projects/pleroma/"
|
||||
"pleroma-backend-domain-posix_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.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.
|
||||
msgid "eperm"
|
||||
msgstr "Uitvoering niet toegestaan"
|
||||
|
||||
msgid "eacces"
|
||||
msgstr "Toegang geweigerd"
|
||||
|
||||
msgid "eagain"
|
||||
msgstr "Resource tijdelijk niet beschikbaar"
|
||||
|
||||
msgid "ebadf"
|
||||
msgstr "Ongeldige file descriptor"
|
||||
|
||||
msgid "ebadmsg"
|
||||
msgstr "Ongeldig bericht"
|
||||
|
||||
msgid "ebusy"
|
||||
msgstr "Apparaat of resource bezet"
|
||||
|
||||
msgid "edeadlk"
|
||||
msgstr "Resource deadlock vermeden"
|
||||
|
||||
msgid "edeadlock"
|
||||
msgstr "Resource deadlock vermeden"
|
||||
|
||||
msgid "edquot"
|
||||
msgstr "Schijf-quota overschreden"
|
||||
|
||||
msgid "eexist"
|
||||
msgstr "Bestand bestaat"
|
||||
|
||||
msgid "efault"
|
||||
msgstr "Ongeldig adres"
|
||||
|
||||
msgid "efbig"
|
||||
msgstr "Bestand is te groot"
|
||||
|
||||
msgid "eftype"
|
||||
msgstr "Ongepast bestands-type of formaat"
|
||||
|
||||
msgid "eintr"
|
||||
msgstr "Onderbroken systeem aanroep"
|
||||
|
||||
msgid "einval"
|
||||
msgstr "Ongeldig argument"
|
||||
|
||||
msgid "eio"
|
||||
msgstr "Input/output fout"
|
||||
|
||||
msgid "eisdir"
|
||||
msgstr "Illegale bewerking op een directory"
|
||||
|
||||
msgid "eloop"
|
||||
msgstr "Te veel niveau's van symbolische koppelingen"
|
||||
|
||||
msgid "emfile"
|
||||
msgstr "Te veel geopende bestanden"
|
||||
|
||||
msgid "emlink"
|
||||
msgstr "Te veel koppelingen"
|
||||
|
||||
msgid "emultihop"
|
||||
msgstr "Multihop geprobeerd"
|
||||
|
||||
msgid "enametoolong"
|
||||
msgstr "Bestandsnaam is te lang"
|
||||
|
||||
msgid "enfile"
|
||||
msgstr "Te veel geopende bestanden in systeem"
|
||||
|
||||
msgid "enobufs"
|
||||
msgstr "Geen buffer-ruimte beschikbaar"
|
||||
|
||||
msgid "enodev"
|
||||
msgstr "Apparaat bestaat niet"
|
||||
|
||||
msgid "enolck"
|
||||
msgstr "Geen sloten beschikbaar"
|
||||
|
||||
msgid "enolink"
|
||||
msgstr "Koppeling is ongedaan gemaakt"
|
||||
|
||||
msgid "enoent"
|
||||
msgstr "Bestand of directory bestaat niet"
|
||||
|
||||
msgid "enomem"
|
||||
msgstr "Geheugen kon niet toegewezen worden"
|
||||
|
||||
msgid "enospc"
|
||||
msgstr "Geen ruimte over op apparaat"
|
||||
|
||||
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 ""
|
|
@ -0,0 +1,567 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-08-13 13:24+0300\n"
|
||||
"PO-Revision-Date: 2022-08-14 11:04+0000\n"
|
||||
"Last-Translator: Fristi <fristi@subcon.town>\n"
|
||||
"Language-Team: Dutch <http://weblate.pleroma-dev.ebin.club/projects/pleroma/"
|
||||
"pleroma-backend-domain-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,37 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Repo.Migrations.AddAssociatedObjectIdFunction do
|
||||
use Ecto.Migration
|
||||
|
||||
def up do
|
||||
statement = """
|
||||
CREATE OR REPLACE FUNCTION associated_object_id(data jsonb) RETURNS varchar AS $$
|
||||
DECLARE
|
||||
object_data jsonb;
|
||||
BEGIN
|
||||
IF jsonb_typeof(data->'object') = 'array' THEN
|
||||
object_data := data->'object'->0;
|
||||
ELSE
|
||||
object_data := data->'object';
|
||||
END IF;
|
||||
|
||||
IF jsonb_typeof(object_data->'id') = 'string' THEN
|
||||
RETURN object_data->>'id';
|
||||
ELSIF jsonb_typeof(object_data) = 'string' THEN
|
||||
RETURN object_data#>>'{}';
|
||||
ELSE
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql IMMUTABLE;
|
||||
"""
|
||||
|
||||
execute(statement)
|
||||
end
|
||||
|
||||
def down do
|
||||
execute("DROP FUNCTION IF EXISTS associated_object_id(data jsonb)")
|
||||
end
|
||||
end
|
|
@ -0,0 +1,37 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Repo.Migrations.SwitchToAssociatedObjectIdIndex do
|
||||
use Ecto.Migration
|
||||
@disable_ddl_transaction true
|
||||
@disable_migration_lock true
|
||||
|
||||
def up do
|
||||
drop_if_exists(
|
||||
index(:activities, ["(coalesce(data->'object'->>'id', data->>'object'))"],
|
||||
name: :activities_create_objects_index
|
||||
)
|
||||
)
|
||||
|
||||
create(
|
||||
index(:activities, ["associated_object_id(data)"],
|
||||
name: :activities_create_objects_index,
|
||||
concurrently: true
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def down do
|
||||
drop_if_exists(
|
||||
index(:activities, ["associated_object_id(data)"], name: :activities_create_objects_index)
|
||||
)
|
||||
|
||||
create(
|
||||
index(:activities, ["(coalesce(data->'object'->>'id', data->>'object'))"],
|
||||
name: :activities_create_objects_index,
|
||||
concurrently: true
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
defmodule Pleroma.Repo.Migrations.DataMigrationDeleteContextObjects do
|
||||
use Ecto.Migration
|
||||
|
||||
require Logger
|
||||
|
||||
def up do
|
||||
dt = NaiveDateTime.utc_now()
|
||||
|
||||
execute(
|
||||
"INSERT INTO data_migrations(name, inserted_at, updated_at) " <>
|
||||
"VALUES ('delete_context_objects', '#{dt}', '#{dt}') ON CONFLICT DO NOTHING;"
|
||||
)
|
||||
end
|
||||
|
||||
def down do
|
||||
execute("DELETE FROM data_migrations WHERE name = 'delete_context_objects';")
|
||||
end
|
||||
end
|
|
@ -0,0 +1,156 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Repo.Migrations.ChangeThreadVisibilityToUseNewObjectIdIndex do
|
||||
use Ecto.Migration
|
||||
|
||||
def up do
|
||||
execute(update_thread_visibility())
|
||||
end
|
||||
|
||||
def down do
|
||||
execute(restore_thread_visibility())
|
||||
end
|
||||
|
||||
def update_thread_visibility do
|
||||
"""
|
||||
CREATE OR REPLACE FUNCTION thread_visibility(actor varchar, activity_id varchar, local_public varchar default '') RETURNS boolean AS $$
|
||||
DECLARE
|
||||
public varchar := 'https://www.w3.org/ns/activitystreams#Public';
|
||||
child objects%ROWTYPE;
|
||||
activity activities%ROWTYPE;
|
||||
author_fa varchar;
|
||||
valid_recipients varchar[];
|
||||
actor_user_following varchar[];
|
||||
BEGIN
|
||||
--- Fetch actor following
|
||||
SELECT array_agg(following.follower_address) INTO actor_user_following FROM following_relationships
|
||||
JOIN users ON users.id = following_relationships.follower_id
|
||||
JOIN users AS following ON following.id = following_relationships.following_id
|
||||
WHERE users.ap_id = actor;
|
||||
|
||||
--- Fetch our initial activity.
|
||||
SELECT * INTO activity FROM activities WHERE activities.data->>'id' = activity_id;
|
||||
|
||||
LOOP
|
||||
--- Ensure that we have an activity before continuing.
|
||||
--- If we don't, the thread is not satisfiable.
|
||||
IF activity IS NULL THEN
|
||||
RETURN false;
|
||||
END IF;
|
||||
|
||||
--- We only care about Create activities.
|
||||
IF activity.data->>'type' != 'Create' THEN
|
||||
RETURN true;
|
||||
END IF;
|
||||
|
||||
--- Normalize the child object into child.
|
||||
SELECT * INTO child FROM objects
|
||||
INNER JOIN activities ON associated_object_id(activities.data) = objects.data->>'id'
|
||||
WHERE associated_object_id(activity.data) = objects.data->>'id';
|
||||
|
||||
--- Fetch the author's AS2 following collection.
|
||||
SELECT COALESCE(users.follower_address, '') INTO author_fa FROM users WHERE users.ap_id = activity.actor;
|
||||
|
||||
--- Prepare valid recipients array.
|
||||
valid_recipients := ARRAY[actor, public];
|
||||
--- If we specified local public, add it.
|
||||
IF local_public <> '' THEN
|
||||
valid_recipients := valid_recipients || local_public;
|
||||
END IF;
|
||||
IF ARRAY[author_fa] && actor_user_following THEN
|
||||
valid_recipients := valid_recipients || author_fa;
|
||||
END IF;
|
||||
|
||||
--- Check visibility.
|
||||
IF NOT valid_recipients && activity.recipients THEN
|
||||
--- activity not visible, break out of the loop
|
||||
RETURN false;
|
||||
END IF;
|
||||
|
||||
--- If there's a parent, load it and do this all over again.
|
||||
IF (child.data->'inReplyTo' IS NOT NULL) AND (child.data->'inReplyTo' != 'null'::jsonb) THEN
|
||||
SELECT * INTO activity FROM activities
|
||||
INNER JOIN objects ON associated_object_id(activities.data) = objects.data->>'id'
|
||||
WHERE child.data->>'inReplyTo' = objects.data->>'id';
|
||||
ELSE
|
||||
RETURN true;
|
||||
END IF;
|
||||
END LOOP;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql IMMUTABLE;
|
||||
"""
|
||||
end
|
||||
|
||||
# priv/repo/migrations/20220509180452_change_thread_visibility_to_be_local_only_aware.exs
|
||||
def restore_thread_visibility do
|
||||
"""
|
||||
CREATE OR REPLACE FUNCTION thread_visibility(actor varchar, activity_id varchar, local_public varchar default '') RETURNS boolean AS $$
|
||||
DECLARE
|
||||
public varchar := 'https://www.w3.org/ns/activitystreams#Public';
|
||||
child objects%ROWTYPE;
|
||||
activity activities%ROWTYPE;
|
||||
author_fa varchar;
|
||||
valid_recipients varchar[];
|
||||
actor_user_following varchar[];
|
||||
BEGIN
|
||||
--- Fetch actor following
|
||||
SELECT array_agg(following.follower_address) INTO actor_user_following FROM following_relationships
|
||||
JOIN users ON users.id = following_relationships.follower_id
|
||||
JOIN users AS following ON following.id = following_relationships.following_id
|
||||
WHERE users.ap_id = actor;
|
||||
|
||||
--- Fetch our initial activity.
|
||||
SELECT * INTO activity FROM activities WHERE activities.data->>'id' = activity_id;
|
||||
|
||||
LOOP
|
||||
--- Ensure that we have an activity before continuing.
|
||||
--- If we don't, the thread is not satisfiable.
|
||||
IF activity IS NULL THEN
|
||||
RETURN false;
|
||||
END IF;
|
||||
|
||||
--- We only care about Create activities.
|
||||
IF activity.data->>'type' != 'Create' THEN
|
||||
RETURN true;
|
||||
END IF;
|
||||
|
||||
--- Normalize the child object into child.
|
||||
SELECT * INTO child FROM objects
|
||||
INNER JOIN activities ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id'
|
||||
WHERE COALESCE(activity.data->'object'->>'id', activity.data->>'object') = objects.data->>'id';
|
||||
|
||||
--- Fetch the author's AS2 following collection.
|
||||
SELECT COALESCE(users.follower_address, '') INTO author_fa FROM users WHERE users.ap_id = activity.actor;
|
||||
|
||||
--- Prepare valid recipients array.
|
||||
valid_recipients := ARRAY[actor, public];
|
||||
--- If we specified local public, add it.
|
||||
IF local_public <> '' THEN
|
||||
valid_recipients := valid_recipients || local_public;
|
||||
END IF;
|
||||
IF ARRAY[author_fa] && actor_user_following THEN
|
||||
valid_recipients := valid_recipients || author_fa;
|
||||
END IF;
|
||||
|
||||
--- Check visibility.
|
||||
IF NOT valid_recipients && activity.recipients THEN
|
||||
--- activity not visible, break out of the loop
|
||||
RETURN false;
|
||||
END IF;
|
||||
|
||||
--- If there's a parent, load it and do this all over again.
|
||||
IF (child.data->'inReplyTo' IS NOT NULL) AND (child.data->'inReplyTo' != 'null'::jsonb) THEN
|
||||
SELECT * INTO activity FROM activities
|
||||
INNER JOIN objects ON COALESCE(activities.data->'object'->>'id', activities.data->>'object') = objects.data->>'id'
|
||||
WHERE child.data->>'inReplyTo' = objects.data->>'id';
|
||||
ELSE
|
||||
RETURN true;
|
||||
END IF;
|
||||
END LOOP;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql IMMUTABLE;
|
||||
"""
|
||||
end
|
||||
end
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://p.helene.moe/schemas/litepub-0.1.jsonld",
|
||||
{
|
||||
"@language": "und"
|
||||
}
|
||||
],
|
||||
"actor": "https://p.helene.moe/users/helene",
|
||||
"attachment": [],
|
||||
"attributedTo": "https://p.helene.moe/users/helene",
|
||||
"cc": [
|
||||
"https://p.helene.moe/users/helene/followers"
|
||||
],
|
||||
"context": "https://p.helene.moe/contexts/cc324643-5583-4c3f-91d2-c6ed37db159d",
|
||||
"conversation": "https://p.helene.moe/contexts/cc324643-5583-4c3f-91d2-c6ed37db159d",
|
||||
"directMessage": false,
|
||||
"id": "https://p.helene.moe/activities/5f80db86-a9bb-4883-9845-fbdbd1478f3a",
|
||||
"object": {
|
||||
"actor": "https://p.helene.moe/users/helene",
|
||||
"attachment": [],
|
||||
"attributedTo": "https://p.helene.moe/users/helene",
|
||||
"cc": [
|
||||
"https://p.helene.moe/users/helene/followers"
|
||||
],
|
||||
"content": "<span class=\"h-card\"><a class=\"u-url mention\" data-user=\"AHntpQ4T3J4OSnpgMC\" href=\"https://mk.absturztau.be/@mametsuko\" rel=\"ugc\">@<span>mametsuko</span></a></span> meow",
|
||||
"context": "https://p.helene.moe/contexts/cc324643-5583-4c3f-91d2-c6ed37db159d",
|
||||
"conversation": "https://p.helene.moe/contexts/cc324643-5583-4c3f-91d2-c6ed37db159d",
|
||||
"id": "https://p.helene.moe/objects/fd5910ac-d9dc-412e-8d1d-914b203296c4",
|
||||
"inReplyTo": "https://mk.absturztau.be/notes/93e7nm8wqg",
|
||||
"published": "2022-08-02T13:46:58.403996Z",
|
||||
"sensitive": null,
|
||||
"source": "@mametsuko@mk.absturztau.be meow",
|
||||
"summary": "",
|
||||
"tag": [
|
||||
{
|
||||
"href": "https://mk.absturztau.be/users/8ozbzjs3o8",
|
||||
"name": "@mametsuko@mk.absturztau.be",
|
||||
"type": "Mention"
|
||||
}
|
||||
],
|
||||
"to": [
|
||||
"https://mk.absturztau.be/users/8ozbzjs3o8",
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"type": "Note"
|
||||
},
|
||||
"published": "2022-08-02T13:46:58.403883Z",
|
||||
"tag": [
|
||||
{
|
||||
"href": "https://mk.absturztau.be/users/8ozbzjs3o8",
|
||||
"name": "@mametsuko@mk.absturztau.be",
|
||||
"type": "Mention"
|
||||
}
|
||||
],
|
||||
"to": [
|
||||
"https://mk.absturztau.be/users/8ozbzjs3o8",
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"type": "Create"
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://p.helene.moe/schemas/litepub-0.1.jsonld",
|
||||
{
|
||||
"@language": "und"
|
||||
}
|
||||
],
|
||||
"alsoKnownAs": [],
|
||||
"attachment": [
|
||||
{
|
||||
"name": "Timezone",
|
||||
"type": "PropertyValue",
|
||||
"value": "UTC+2 (Paris/Berlin)"
|
||||
}
|
||||
],
|
||||
"capabilities": {
|
||||
"acceptsChatMessages": true
|
||||
},
|
||||
"discoverable": true,
|
||||
"endpoints": {
|
||||
"oauthAuthorizationEndpoint": "https://p.helene.moe/oauth/authorize",
|
||||
"oauthRegistrationEndpoint": "https://p.helene.moe/api/v1/apps",
|
||||
"oauthTokenEndpoint": "https://p.helene.moe/oauth/token",
|
||||
"sharedInbox": "https://p.helene.moe/inbox",
|
||||
"uploadMedia": "https://p.helene.moe/api/ap/upload_media"
|
||||
},
|
||||
"featured": "https://p.helene.moe/users/helene/collections/featured",
|
||||
"followers": "https://p.helene.moe/users/helene/followers",
|
||||
"following": "https://p.helene.moe/users/helene/following",
|
||||
"icon": {
|
||||
"type": "Image",
|
||||
"url": "https://p.helene.moe/media/9a39209daa5a66b7ebb0547b08bf8360aa9d8d65a4ffba2603c6ffbe6aecb432.jpg"
|
||||
},
|
||||
"id": "https://p.helene.moe/users/helene",
|
||||
"inbox": "https://p.helene.moe/users/helene/inbox",
|
||||
"manuallyApprovesFollowers": false,
|
||||
"name": "Hélène",
|
||||
"outbox": "https://p.helene.moe/users/helene/outbox",
|
||||
"preferredUsername": "helene",
|
||||
"publicKey": {
|
||||
"id": "https://p.helene.moe/users/helene#main-key",
|
||||
"owner": "https://p.helene.moe/users/helene",
|
||||
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtoSBPU/VS2Kx3f6ap3zv\nZVacJsgUfaoFb3c2ii/FRh9RmRVlarq8sJXcjsQt1e0oxWaWJaIDDwyKZPt6hXae\nrY/AiGGeNu+NA+BtY7l7+9Yu67HUyT62+1qAwYHKBXX3fLOPs/YmQI0Tt0c4wKAG\nKEkiYsRizghgpzUC6jqdKV71DJkUZ8yhckCGb2fLko1ajbWEssdaP51aLsyRMyC2\nuzeWrxtD4O/HG0ea4S6y5X6hnsAHIK4Y3nnyIQ6pn4tOsl3HgqkjXE9MmZSvMCFx\nBq89TfZrVXNa2gSZdZLdbbJstzEScQWNt1p6tA6rM+e4JXYGr+rMdF3G+jV7afI2\nFQIDAQAB\n-----END PUBLIC KEY-----\n\n"
|
||||
},
|
||||
"summary": "I can speak: Français, English, Deutsch (nicht sehr gut), 日本語 (not very well)",
|
||||
"tag": [],
|
||||
"type": "Person",
|
||||
"url": "https://p.helene.moe/users/helene"
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://w3id.org/security/v1",
|
||||
{
|
||||
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||
"sensitive": "as:sensitive",
|
||||
"Hashtag": "as:Hashtag",
|
||||
"quoteUrl": "as:quoteUrl",
|
||||
"toot": "http://joinmastodon.org/ns#",
|
||||
"Emoji": "toot:Emoji",
|
||||
"featured": "toot:featured",
|
||||
"discoverable": "toot:discoverable",
|
||||
"schema": "http://schema.org#",
|
||||
"PropertyValue": "schema:PropertyValue",
|
||||
"value": "schema:value",
|
||||
"misskey": "https://misskey-hub.net/ns#",
|
||||
"_misskey_content": "misskey:_misskey_content",
|
||||
"_misskey_quote": "misskey:_misskey_quote",
|
||||
"_misskey_reaction": "misskey:_misskey_reaction",
|
||||
"_misskey_votes": "misskey:_misskey_votes",
|
||||
"_misskey_talk": "misskey:_misskey_talk",
|
||||
"isCat": "misskey:isCat",
|
||||
"vcard": "http://www.w3.org/2006/vcard/ns#"
|
||||
}
|
||||
],
|
||||
"type": "Person",
|
||||
"id": "https://mk.absturztau.be/users/8ozbzjs3o8",
|
||||
"inbox": "https://mk.absturztau.be/users/8ozbzjs3o8/inbox",
|
||||
"outbox": "https://mk.absturztau.be/users/8ozbzjs3o8/outbox",
|
||||
"followers": "https://mk.absturztau.be/users/8ozbzjs3o8/followers",
|
||||
"following": "https://mk.absturztau.be/users/8ozbzjs3o8/following",
|
||||
"featured": "https://mk.absturztau.be/users/8ozbzjs3o8/collections/featured",
|
||||
"sharedInbox": "https://mk.absturztau.be/inbox",
|
||||
"endpoints": {
|
||||
"sharedInbox": "https://mk.absturztau.be/inbox"
|
||||
},
|
||||
"url": "https://mk.absturztau.be/@mametsuko",
|
||||
"preferredUsername": "mametsuko",
|
||||
"name": "mametschko",
|
||||
"summary": "<p><span>nya, ich bin eine Brotperson</span></p>",
|
||||
"icon": {
|
||||
"type": "Image",
|
||||
"url": "https://mk.absturztau.be/files/webpublic-3b5594f4-fa52-4548-b4e3-c379ae2143ed",
|
||||
"sensitive": false,
|
||||
"name": null
|
||||
},
|
||||
"image": {
|
||||
"type": "Image",
|
||||
"url": "https://mk.absturztau.be/files/webpublic-0d03b03d-b14b-4916-ac3d-8a137118ec84",
|
||||
"sensitive": false,
|
||||
"name": null
|
||||
},
|
||||
"tag": [],
|
||||
"manuallyApprovesFollowers": true,
|
||||
"discoverable": false,
|
||||
"publicKey": {
|
||||
"id": "https://mk.absturztau.be/users/8ozbzjs3o8#main-key",
|
||||
"type": "Key",
|
||||
"owner": "https://mk.absturztau.be/users/8ozbzjs3o8",
|
||||
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuN/S1spBGmh8FXI1Bt16\nXB7Cc0QutBp7UPgmDNHjOfsq0zrF4g3L1UBxvrpU0XX77XPMCd9yPvGwAYURH2mv\ntIcYuE+R90VLDmBu5MTVthcG2D874eCZ2rD2YsEYmN5AjTX7QBIqCck+qDhVWkkM\nEZ6S5Ht6IJ5Of74eKffXElQI/C6QB+9uEDOmPk0jCzgI5gw7xvJqFj/DIF4kUUAu\nA89JqaFZzZlkrSrj4cr48bLN/YOmpdaHu0BKHaDSHct4+MqlixqovgdB6RboCEDw\ne4Aeav7+Q0Y9oGIvuggg0Q+nCubnVNnaPyzd817tpPVzyZmTts+DKyDuv90SX3nR\nsPaNa5Ty60eqplUk4b7X1gSvuzBJUFBxTVV84WnjwoeoydaS6rSyjCDPGLBjaByc\nFyWMMEb/zlQyhLZfBlvT7k96wRSsMszh2hDALWmgYIhq/jNwINvALJ1GKLNHHKZ4\nyz2LnxVpRm2rWrZzbvtcnSQOt3LaPSZn8Wgwv4buyHF02iuVuIamZVtKexsE1Ixl\nIi9qa3AKEc5gOzYXhRhvHaruzoCehUbb/UHC5c8Tto8L5G1xYzjLP3qj3PT9w/wM\n+k1Ra/4JhuAnVFROOoOmx9rIELLHH7juY2nhM7plGhyt1M5gysgqEloij8QzyQU2\nZK1YlAERG2XFO6br8omhcmECAwEAAQ==\n-----END PUBLIC KEY-----\n"
|
||||
},
|
||||
"isCat": true,
|
||||
"vcard:Address": "Vienna, Austria"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"manuallyApprovesFollowers":"as:manuallyApprovesFollowers","sensitive":"as:sensitive","Hashtag":"as:Hashtag","quoteUrl":"as:quoteUrl","toot":"http://joinmastodon.org/ns#","Emoji":"toot:Emoji","featured":"toot:featured","discoverable":"toot:discoverable","schema":"http://schema.org#","PropertyValue":"schema:PropertyValue","value":"schema:value","misskey":"https://misskey-hub.net/ns#","_misskey_content":"misskey:_misskey_content","_misskey_quote":"misskey:_misskey_quote","_misskey_reaction":"misskey:_misskey_reaction","_misskey_votes":"misskey:_misskey_votes","_misskey_talk":"misskey:_misskey_talk","isCat":"misskey:isCat","vcard":"http://www.w3.org/2006/vcard/ns#"}],"id":"https://mk.absturztau.be/notes/93e7nm8wqg/activity","actor":"https://mk.absturztau.be/users/8ozbzjs3o8","type":"Create","published":"2022-08-01T11:06:49.568Z","object":{"id":"https://mk.absturztau.be/notes/93e7nm8wqg","type":"Note","attributedTo":"https://mk.absturztau.be/users/8ozbzjs3o8","summary":null,"content":"<p><span>meow</span></p>","_misskey_content":"meow","published":"2022-08-01T11:06:49.568Z","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://mk.absturztau.be/users/8ozbzjs3o8/followers"],"inReplyTo":null,"attachment":[],"sensitive":false,"tag":[]},"to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://mk.absturztau.be/users/8ozbzjs3o8/followers"]}
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://w3id.org/security/v1",
|
||||
{
|
||||
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
||||
"sensitive": "as:sensitive",
|
||||
"Hashtag": "as:Hashtag",
|
||||
"quoteUrl": "as:quoteUrl",
|
||||
"toot": "http://joinmastodon.org/ns#",
|
||||
"Emoji": "toot:Emoji",
|
||||
"featured": "toot:featured",
|
||||
"discoverable": "toot:discoverable",
|
||||
"schema": "http://schema.org#",
|
||||
"PropertyValue": "schema:PropertyValue",
|
||||
"value": "schema:value",
|
||||
"misskey": "https://misskey-hub.net/ns#",
|
||||
"_misskey_content": "misskey:_misskey_content",
|
||||
"_misskey_quote": "misskey:_misskey_quote",
|
||||
"_misskey_reaction": "misskey:_misskey_reaction",
|
||||
"_misskey_votes": "misskey:_misskey_votes",
|
||||
"_misskey_talk": "misskey:_misskey_talk",
|
||||
"isCat": "misskey:isCat",
|
||||
"vcard": "http://www.w3.org/2006/vcard/ns#"
|
||||
}
|
||||
],
|
||||
"id": "https://mk.absturztau.be/notes/93e7nm8wqg",
|
||||
"type": "Note",
|
||||
"attributedTo": "https://mk.absturztau.be/users/8ozbzjs3o8",
|
||||
"summary": null,
|
||||
"content": "<p><span>meow</span></p>",
|
||||
"_misskey_content": "meow",
|
||||
"published": "2022-08-01T11:06:49.568Z",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [
|
||||
"https://mk.absturztau.be/users/8ozbzjs3o8/followers"
|
||||
],
|
||||
"inReplyTo": null,
|
||||
"attachment": [],
|
||||
"sensitive": false,
|
||||
"tag": []
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
"https://p.helene.moe/schemas/litepub-0.1.jsonld",
|
||||
{
|
||||
"@language": "und"
|
||||
}
|
||||
],
|
||||
"actor": "https://p.helene.moe/users/helene",
|
||||
"attachment": [],
|
||||
"attributedTo": "https://p.helene.moe/users/helene",
|
||||
"cc": [
|
||||
"https://p.helene.moe/users/helene/followers"
|
||||
],
|
||||
"content": "<span class=\"h-card\"><a class=\"u-url mention\" data-user=\"AHntpQ4T3J4OSnpgMC\" href=\"https://mk.absturztau.be/@mametsuko\" rel=\"ugc\">@<span>mametsuko</span></a></span> meow",
|
||||
"context": "https://p.helene.moe/contexts/cc324643-5583-4c3f-91d2-c6ed37db159d",
|
||||
"conversation": "https://p.helene.moe/contexts/cc324643-5583-4c3f-91d2-c6ed37db159d",
|
||||
"id": "https://p.helene.moe/objects/fd5910ac-d9dc-412e-8d1d-914b203296c4",
|
||||
"inReplyTo": "https://mk.absturztau.be/notes/93e7nm8wqg",
|
||||
"published": "2022-08-02T13:46:58.403996Z",
|
||||
"sensitive": null,
|
||||
"source": "@mametsuko@mk.absturztau.be meow",
|
||||
"summary": "",
|
||||
"tag": [
|
||||
{
|
||||
"href": "https://mk.absturztau.be/users/8ozbzjs3o8",
|
||||
"name": "@mametsuko@mk.absturztau.be",
|
||||
"type": "Mention"
|
||||
}
|
||||
],
|
||||
"to": [
|
||||
"https://mk.absturztau.be/users/8ozbzjs3o8",
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"type": "Note"
|
||||
}
|
|
@ -13,6 +13,29 @@ defmodule Pleroma.Activity.Ir.TopicsTest do
|
|||
|
||||
import Mock
|
||||
|
||||
describe "chat message" do
|
||||
test "Create produces no topics" do
|
||||
activity = %Activity{
|
||||
object: %Object{data: %{"type" => "ChatMessage"}},
|
||||
data: %{"type" => "Create"}
|
||||
}
|
||||
|
||||
assert [] == Topics.get_activity_topics(activity)
|
||||
end
|
||||
|
||||
test "Delete produces user and user:pleroma_chat" do
|
||||
activity = %Activity{
|
||||
object: %Object{data: %{"type" => "ChatMessage"}},
|
||||
data: %{"type" => "Delete"}
|
||||
}
|
||||
|
||||
topics = Topics.get_activity_topics(activity)
|
||||
assert [_, _] = topics
|
||||
assert "user" in topics
|
||||
assert "user:pleroma_chat" in topics
|
||||
end
|
||||
end
|
||||
|
||||
describe "poll answer" do
|
||||
test "produce no topics" do
|
||||
activity = %Activity{object: %Object{data: %{"type" => "Answer"}}}
|
||||
|
@ -35,7 +58,7 @@ defmodule Pleroma.Activity.Ir.TopicsTest do
|
|||
setup do
|
||||
activity = %Activity{
|
||||
object: %Object{data: %{"type" => "Note"}},
|
||||
data: %{"to" => [Pleroma.Constants.as_public()]}
|
||||
data: %{"to" => [Pleroma.Constants.as_public()], "type" => "Create"}
|
||||
}
|
||||
|
||||
{:ok, activity: activity}
|
||||
|
@ -114,6 +137,55 @@ defmodule Pleroma.Activity.Ir.TopicsTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "public visibility Announces" do
|
||||
setup do
|
||||
activity = %Activity{
|
||||
object: %Object{data: %{"attachment" => []}},
|
||||
data: %{"type" => "Announce", "to" => [Pleroma.Constants.as_public()]}
|
||||
}
|
||||
|
||||
{:ok, activity: activity}
|
||||
end
|
||||
|
||||
test "does not generate public topics", %{activity: activity} do
|
||||
topics = Topics.get_activity_topics(activity)
|
||||
|
||||
refute "public" in topics
|
||||
refute "public:remote" in topics
|
||||
refute "public:local" in topics
|
||||
end
|
||||
end
|
||||
|
||||
describe "local-public visibility create events" do
|
||||
setup do
|
||||
activity = %Activity{
|
||||
object: %Object{data: %{"attachment" => []}},
|
||||
data: %{"type" => "Create", "to" => [Pleroma.Web.ActivityPub.Utils.as_local_public()]}
|
||||
}
|
||||
|
||||
{:ok, activity: activity}
|
||||
end
|
||||
|
||||
test "doesn't produce public topics", %{activity: activity} do
|
||||
topics = Topics.get_activity_topics(activity)
|
||||
|
||||
refute Enum.member?(topics, "public")
|
||||
end
|
||||
|
||||
test "produces public:local topics", %{activity: activity} do
|
||||
topics = Topics.get_activity_topics(activity)
|
||||
|
||||
assert Enum.member?(topics, "public:local")
|
||||
end
|
||||
|
||||
test "with no attachments doesn't produce public:media topics", %{activity: activity} do
|
||||
topics = Topics.get_activity_topics(activity)
|
||||
|
||||
refute Enum.member?(topics, "public:media")
|
||||
refute Enum.member?(topics, "public:local:media")
|
||||
end
|
||||
end
|
||||
|
||||
describe "public visibility create events with attachments" do
|
||||
setup do
|
||||
activity = %Activity{
|
||||
|
@ -152,9 +224,36 @@ defmodule Pleroma.Activity.Ir.TopicsTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "local-public visibility create events with attachments" do
|
||||
setup do
|
||||
activity = %Activity{
|
||||
object: %Object{data: %{"attachment" => ["foo"]}},
|
||||
data: %{"type" => "Create", "to" => [Pleroma.Web.ActivityPub.Utils.as_local_public()]}
|
||||
}
|
||||
|
||||
{:ok, activity: activity}
|
||||
end
|
||||
|
||||
test "do not produce public:media topics", %{activity: activity} do
|
||||
topics = Topics.get_activity_topics(activity)
|
||||
|
||||
refute Enum.member?(topics, "public:media")
|
||||
end
|
||||
|
||||
test "produces public:local:media topics", %{activity: activity} do
|
||||
topics = Topics.get_activity_topics(activity)
|
||||
|
||||
assert Enum.member?(topics, "public:local:media")
|
||||
end
|
||||
end
|
||||
|
||||
describe "non-public visibility" do
|
||||
test "produces direct topic" do
|
||||
activity = %Activity{object: %Object{data: %{"type" => "Note"}}, data: %{"to" => []}}
|
||||
activity = %Activity{
|
||||
object: %Object{data: %{"type" => "Note"}},
|
||||
data: %{"to" => [], "type" => "Create"}
|
||||
}
|
||||
|
||||
topics = Topics.get_activity_topics(activity)
|
||||
|
||||
assert Enum.member?(topics, "direct")
|
||||
|
|
|
@ -278,4 +278,78 @@ defmodule Pleroma.ActivityTest do
|
|||
|
||||
assert Repo.aggregate(Activity, :count, :id) == 2
|
||||
end
|
||||
|
||||
describe "associated_object_id() sql function" do
|
||||
test "with json object" do
|
||||
%{rows: [[object_id]]} =
|
||||
Ecto.Adapters.SQL.query!(
|
||||
Pleroma.Repo,
|
||||
"""
|
||||
select associated_object_id('{"object": {"id":"foobar"}}'::jsonb);
|
||||
"""
|
||||
)
|
||||
|
||||
assert object_id == "foobar"
|
||||
end
|
||||
|
||||
test "with string object" do
|
||||
%{rows: [[object_id]]} =
|
||||
Ecto.Adapters.SQL.query!(
|
||||
Pleroma.Repo,
|
||||
"""
|
||||
select associated_object_id('{"object": "foobar"}'::jsonb);
|
||||
"""
|
||||
)
|
||||
|
||||
assert object_id == "foobar"
|
||||
end
|
||||
|
||||
test "with array object" do
|
||||
%{rows: [[object_id]]} =
|
||||
Ecto.Adapters.SQL.query!(
|
||||
Pleroma.Repo,
|
||||
"""
|
||||
select associated_object_id('{"object": ["foobar", {}]}'::jsonb);
|
||||
"""
|
||||
)
|
||||
|
||||
assert object_id == "foobar"
|
||||
end
|
||||
|
||||
test "invalid" do
|
||||
%{rows: [[object_id]]} =
|
||||
Ecto.Adapters.SQL.query!(
|
||||
Pleroma.Repo,
|
||||
"""
|
||||
select associated_object_id('{"object": {}}'::jsonb);
|
||||
"""
|
||||
)
|
||||
|
||||
assert is_nil(object_id)
|
||||
end
|
||||
|
||||
test "invalid object id" do
|
||||
%{rows: [[object_id]]} =
|
||||
Ecto.Adapters.SQL.query!(
|
||||
Pleroma.Repo,
|
||||
"""
|
||||
select associated_object_id('{"object": {"id": 123}}'::jsonb);
|
||||
"""
|
||||
)
|
||||
|
||||
assert is_nil(object_id)
|
||||
end
|
||||
|
||||
test "no object field" do
|
||||
%{rows: [[object_id]]} =
|
||||
Ecto.Adapters.SQL.query!(
|
||||
Pleroma.Repo,
|
||||
"""
|
||||
select associated_object_id('{}'::jsonb);
|
||||
"""
|
||||
)
|
||||
|
||||
assert is_nil(object_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -109,6 +109,11 @@ defmodule Pleroma.SignatureTest do
|
|||
{:ok, "https://example.com/users/1234"}
|
||||
end
|
||||
|
||||
test "it deduces the actor id for gotoSocial" do
|
||||
assert Signature.key_id_to_actor_id("https://example.com/users/1234/main-key") ==
|
||||
{:ok, "https://example.com/users/1234"}
|
||||
end
|
||||
|
||||
test "it calls webfinger for 'acct:' accounts" do
|
||||
with_mock(Pleroma.Web.WebFinger,
|
||||
finger: fn _ -> %{"ap_id" => "https://gensokyo.2hu/users/raymoo"} end
|
||||
|
|
|
@ -554,7 +554,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
|
|||
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
|
||||
|
@ -576,8 +575,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest 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
|
||||
|
@ -1612,7 +1609,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
|
|||
})
|
||||
|
||||
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
|
||||
|
|
|
@ -103,4 +103,17 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest
|
|||
|
||||
%{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
|
||||
end
|
||||
|
||||
test "a Note without replies/first/items validates" do
|
||||
insert(:user, ap_id: "https://mastodon.social/users/emelie")
|
||||
|
||||
note =
|
||||
"test/fixtures/tesla_mock/status.emelie.json"
|
||||
|> File.read!()
|
||||
|> Jason.decode!()
|
||||
|> pop_in(["replies", "first", "items"])
|
||||
|> elem(1)
|
||||
|
||||
%{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,10 +23,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidatorTest do
|
|||
{:ok, object_data} = ObjectValidator.cast_and_apply(note_activity["object"])
|
||||
meta = [object_data: ObjectValidator.stringify_keys(object_data)]
|
||||
|
||||
%{valid?: true} = CreateGenericValidator.cast_and_validate(note_activity, meta)
|
||||
assert %{valid?: true} = CreateGenericValidator.cast_and_validate(note_activity, meta)
|
||||
end
|
||||
|
||||
test "a Create/Note with mismatched context is invalid" do
|
||||
test "a Create/Note with mismatched context uses the Note's context" do
|
||||
user = insert(:user)
|
||||
|
||||
note = %{
|
||||
|
@ -54,6 +54,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidatorTest do
|
|||
{:ok, object_data} = ObjectValidator.cast_and_apply(note_activity["object"])
|
||||
meta = [object_data: ObjectValidator.stringify_keys(object_data)]
|
||||
|
||||
%{valid?: false} = CreateGenericValidator.cast_and_validate(note_activity, meta)
|
||||
validated = CreateGenericValidator.cast_and_validate(note_activity, meta)
|
||||
|
||||
assert validated.valid?
|
||||
assert {:context, note["context"]} in validated.changes
|
||||
end
|
||||
end
|
||||
|
|
|
@ -839,9 +839,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
|
|||
]) do
|
||||
{:ok, announce, _} = SideEffects.handle(announce)
|
||||
|
||||
assert called(
|
||||
Pleroma.Web.Streamer.stream(["user", "list", "public", "public:local"], announce)
|
||||
)
|
||||
assert called(Pleroma.Web.Streamer.stream(["user", "list"], announce))
|
||||
|
||||
assert called(Pleroma.Web.Push.send(:_))
|
||||
end
|
||||
|
|
|
@ -707,4 +707,42 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
|
|||
}
|
||||
]
|
||||
end
|
||||
|
||||
test "the standalone note uses its own ID when context is missing" do
|
||||
insert(:user, ap_id: "https://mk.absturztau.be/users/8ozbzjs3o8")
|
||||
|
||||
activity =
|
||||
"test/fixtures/tesla_mock/mk.absturztau.be-93e7nm8wqg-activity.json"
|
||||
|> File.read!()
|
||||
|> Jason.decode!()
|
||||
|
||||
{:ok, %Activity{} = modified} = Transmogrifier.handle_incoming(activity)
|
||||
object = Object.normalize(modified, fetch: false)
|
||||
|
||||
assert object.data["context"] == object.data["id"]
|
||||
assert modified.data["context"] == object.data["id"]
|
||||
end
|
||||
|
||||
test "the reply note uses its parent's ID when context is missing and reply is unreachable" do
|
||||
insert(:user, ap_id: "https://mk.absturztau.be/users/8ozbzjs3o8")
|
||||
|
||||
activity =
|
||||
"test/fixtures/tesla_mock/mk.absturztau.be-93e7nm8wqg-activity.json"
|
||||
|> File.read!()
|
||||
|> Jason.decode!()
|
||||
|
||||
object =
|
||||
activity["object"]
|
||||
|> Map.put("inReplyTo", "https://404.site/object/went-to-buy-milk")
|
||||
|
||||
activity =
|
||||
activity
|
||||
|> Map.put("object", object)
|
||||
|
||||
{:ok, %Activity{} = modified} = Transmogrifier.handle_incoming(activity)
|
||||
object = Object.normalize(modified, fetch: false)
|
||||
|
||||
assert object.data["context"] == object.data["inReplyTo"]
|
||||
assert modified.data["context"] == object.data["inReplyTo"]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,8 +33,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest 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 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest 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
|
||||
|
|
|
@ -108,15 +108,20 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
|
|||
assert activity.data["type"] == "Move"
|
||||
end
|
||||
|
||||
test "a reply with mismatched context is rejected" do
|
||||
insert(:user, ap_id: "https://macgirvin.com/channel/mike")
|
||||
test "it fixes both the Create and object contexts in a reply" do
|
||||
insert(:user, ap_id: "https://mk.absturztau.be/users/8ozbzjs3o8")
|
||||
insert(:user, ap_id: "https://p.helene.moe/users/helene")
|
||||
|
||||
note_activity =
|
||||
"test/fixtures/roadhouse-create-activity.json"
|
||||
create_activity =
|
||||
"test/fixtures/create-pleroma-reply-to-misskey-thread.json"
|
||||
|> File.read!()
|
||||
|> Jason.decode!()
|
||||
|
||||
assert {:error, _} = Transmogrifier.handle_incoming(note_activity)
|
||||
assert {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(create_activity)
|
||||
|
||||
object = Object.normalize(activity, fetch: false)
|
||||
|
||||
assert activity.data["context"] == object.data["context"]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -227,7 +232,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest 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
|
||||
|
||||
|
@ -242,7 +246,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest 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 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest 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 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest 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 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest 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 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest 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 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest 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)
|
||||
|
|
|
@ -262,6 +262,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest 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 =
|
||||
|
@ -285,6 +286,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest 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,10 +14,11 @@ 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
|
||||
|
||||
require Bitwise
|
||||
|
||||
import Pleroma.Factory
|
||||
import Tesla.Mock
|
||||
import OpenApiSpex.TestAssertions
|
||||
|
@ -226,7 +227,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest 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})
|
||||
|
||||
|
@ -280,6 +281,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest 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"])},
|
||||
|
|
|
@ -39,6 +39,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
|
|||
"actor" => user.ap_id,
|
||||
"tag" => [],
|
||||
"id" => "https://pleroma.gov/objects/whatever",
|
||||
"summary" => "",
|
||||
"content" => "pleroma in a nutshell"
|
||||
}
|
||||
})
|
||||
|
@ -54,6 +55,36 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
|
|||
] == result
|
||||
end
|
||||
|
||||
test "it uses summary as description if post has one" do
|
||||
user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
|
||||
{:ok, activity} = CommonAPI.post(user, %{status: "HI"})
|
||||
|
||||
note =
|
||||
insert(:note, %{
|
||||
data: %{
|
||||
"actor" => user.ap_id,
|
||||
"tag" => [],
|
||||
"id" => "https://pleroma.gov/objects/whatever",
|
||||
"summary" => "Public service announcement on caffeine consumption",
|
||||
"content" => "cofe"
|
||||
}
|
||||
})
|
||||
|
||||
result = TwitterCard.build_tags(%{object: note, user: user, activity_id: activity.id})
|
||||
|
||||
assert [
|
||||
{:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []},
|
||||
{:meta,
|
||||
[
|
||||
property: "twitter:description",
|
||||
content: "Public service announcement on caffeine consumption"
|
||||
], []},
|
||||
{:meta, [property: "twitter:image", content: "http://localhost:4001/images/avi.png"],
|
||||
[]},
|
||||
{:meta, [property: "twitter:card", content: "summary"], []}
|
||||
] == result
|
||||
end
|
||||
|
||||
test "it renders avatar not attachment if post is nsfw and unfurl_nsfw is disabled" do
|
||||
clear_config([Pleroma.Web.Metadata, :unfurl_nsfw], false)
|
||||
user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
|
||||
|
@ -65,6 +96,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
|
|||
"actor" => user.ap_id,
|
||||
"tag" => [],
|
||||
"id" => "https://pleroma.gov/objects/whatever",
|
||||
"summary" => "",
|
||||
"content" => "pleroma in a nutshell",
|
||||
"sensitive" => true,
|
||||
"attachment" => [
|
||||
|
@ -109,6 +141,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
|
|||
"actor" => user.ap_id,
|
||||
"tag" => [],
|
||||
"id" => "https://pleroma.gov/objects/whatever",
|
||||
"summary" => "",
|
||||
"content" => "pleroma in a nutshell",
|
||||
"attachment" => [
|
||||
%{
|
||||
|
|
|
@ -8,7 +8,7 @@ defmodule Pleroma.Web.Metadata.UtilsTest do
|
|||
alias Pleroma.Web.Metadata.Utils
|
||||
|
||||
describe "scrub_html_and_truncate/1" do
|
||||
test "it returns text without encode HTML" do
|
||||
test "it returns content text without encode HTML if summary is nil" do
|
||||
user = insert(:user)
|
||||
|
||||
note =
|
||||
|
@ -16,6 +16,7 @@ defmodule Pleroma.Web.Metadata.UtilsTest do
|
|||
data: %{
|
||||
"actor" => user.ap_id,
|
||||
"id" => "https://pleroma.gov/objects/whatever",
|
||||
"summary" => nil,
|
||||
"content" => "Pleroma's really cool!"
|
||||
}
|
||||
})
|
||||
|
@ -23,6 +24,39 @@ defmodule Pleroma.Web.Metadata.UtilsTest do
|
|||
assert Utils.scrub_html_and_truncate(note) == "Pleroma's really cool!"
|
||||
end
|
||||
|
||||
test "it returns context text without encode HTML if summary is empty" do
|
||||
user = insert(:user)
|
||||
|
||||
note =
|
||||
insert(:note, %{
|
||||
data: %{
|
||||
"actor" => user.ap_id,
|
||||
"id" => "https://pleroma.gov/objects/whatever",
|
||||
"summary" => "",
|
||||
"content" => "Pleroma's really cool!"
|
||||
}
|
||||
})
|
||||
|
||||
assert Utils.scrub_html_and_truncate(note) == "Pleroma's really cool!"
|
||||
end
|
||||
|
||||
test "it returns summary text without encode HTML if summary is filled" do
|
||||
user = insert(:user)
|
||||
|
||||
note =
|
||||
insert(:note, %{
|
||||
data: %{
|
||||
"actor" => user.ap_id,
|
||||
"id" => "https://pleroma.gov/objects/whatever",
|
||||
"summary" => "Public service announcement on caffeine consumption",
|
||||
"content" => "cofe"
|
||||
}
|
||||
})
|
||||
|
||||
assert Utils.scrub_html_and_truncate(note) ==
|
||||
"Public service announcement on caffeine consumption"
|
||||
end
|
||||
|
||||
test "it does not return old content after editing" do
|
||||
user = insert(:user)
|
||||
|
||||
|
|
|
@ -233,6 +233,102 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "POST /main/ostatus - remote_subscribe/2 - with statuses" do
|
||||
setup do: clear_config([:instance, :federating], true)
|
||||
|
||||
test "renders subscribe form", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
status = insert(:note_activity, %{user: user})
|
||||
status_id = status.id
|
||||
|
||||
assert is_binary(status_id)
|
||||
|
||||
response =
|
||||
conn
|
||||
|> post("/main/ostatus", %{"status_id" => status_id, "profile" => ""})
|
||||
|> response(:ok)
|
||||
|
||||
refute response =~ "Could not find status"
|
||||
assert response =~ "Interacting with"
|
||||
end
|
||||
|
||||
test "renders subscribe form with error when status not found", %{conn: conn} do
|
||||
response =
|
||||
conn
|
||||
|> post("/main/ostatus", %{"status_id" => "somerandomid", "profile" => ""})
|
||||
|> response(:ok)
|
||||
|
||||
assert response =~ "Could not find status"
|
||||
refute response =~ "Interacting with"
|
||||
end
|
||||
|
||||
test "it redirect to webfinger url", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
status = insert(:note_activity, %{user: user})
|
||||
status_id = status.id
|
||||
status_ap_id = status.data["object"]
|
||||
|
||||
assert is_binary(status_id)
|
||||
assert is_binary(status_ap_id)
|
||||
|
||||
user2 = insert(:user, ap_id: "shp@social.heldscal.la")
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> post("/main/ostatus", %{
|
||||
"status" => %{"status_id" => status_id, "profile" => user2.ap_id}
|
||||
})
|
||||
|
||||
assert redirected_to(conn) ==
|
||||
"https://social.heldscal.la/main/ostatussub?profile=#{status_ap_id}"
|
||||
end
|
||||
|
||||
test "it renders form with error when status not found", %{conn: conn} do
|
||||
user2 = insert(:user, ap_id: "shp@social.heldscal.la")
|
||||
|
||||
response =
|
||||
conn
|
||||
|> post("/main/ostatus", %{
|
||||
"status" => %{"status_id" => "somerandomid", "profile" => user2.ap_id}
|
||||
})
|
||||
|> response(:ok)
|
||||
|
||||
assert response =~ "Something went wrong."
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /main/ostatus - show_subscribe_form/2" do
|
||||
setup do: clear_config([:instance, :federating], true)
|
||||
|
||||
test "it works with users", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
|
||||
response =
|
||||
conn
|
||||
|> get("/main/ostatus", %{"nickname" => user.nickname})
|
||||
|> response(:ok)
|
||||
|
||||
refute response =~ "Could not find user"
|
||||
assert response =~ "Remotely follow #{user.nickname}"
|
||||
end
|
||||
|
||||
test "it works with statuses", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
status = insert(:note_activity, %{user: user})
|
||||
status_id = status.id
|
||||
|
||||
assert is_binary(status_id)
|
||||
|
||||
response =
|
||||
conn
|
||||
|> get("/main/ostatus", %{"status_id" => status_id})
|
||||
|> response(:ok)
|
||||
|
||||
refute response =~ "Could not find status"
|
||||
assert response =~ "Interacting with"
|
||||
end
|
||||
end
|
||||
|
||||
test "it returns new captcha", %{conn: conn} do
|
||||
with_mock Pleroma.Captcha,
|
||||
new: fn -> "test_captcha" end do
|
||||
|
|
|
@ -1084,6 +1084,14 @@ defmodule HttpRequestMock do
|
|||
}}
|
||||
end
|
||||
|
||||
def get("https://404.site" <> _, _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 404,
|
||||
body: ""
|
||||
}}
|
||||
end
|
||||
|
||||
def get(
|
||||
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=acct:lain@zetsubou.xn--q9jyb4c",
|
||||
_,
|
||||
|
@ -1401,6 +1409,51 @@ defmodule HttpRequestMock do
|
|||
}}
|
||||
end
|
||||
|
||||
def get("https://mk.absturztau.be/users/8ozbzjs3o8", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: File.read!("test/fixtures/tesla_mock/mametsuko@mk.absturztau.be.json"),
|
||||
headers: activitypub_object_headers()
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://p.helene.moe/users/helene", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: File.read!("test/fixtures/tesla_mock/helene@p.helene.moe.json"),
|
||||
headers: activitypub_object_headers()
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://mk.absturztau.be/notes/93e7nm8wqg", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: File.read!("test/fixtures/tesla_mock/mk.absturztau.be-93e7nm8wqg.json"),
|
||||
headers: activitypub_object_headers()
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://mk.absturztau.be/notes/93e7nm8wqg/activity", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: File.read!("test/fixtures/tesla_mock/mk.absturztau.be-93e7nm8wqg-activity.json"),
|
||||
headers: activitypub_object_headers()
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://p.helene.moe/objects/fd5910ac-d9dc-412e-8d1d-914b203296c4", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: File.read!("test/fixtures/tesla_mock/p.helene.moe-AM7S6vZQmL6pI9TgPY.json"),
|
||||
headers: activitypub_object_headers()
|
||||
}}
|
||||
end
|
||||
|
||||
def get(url, query, body, headers) do
|
||||
{:error,
|
||||
"Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}
|
||||
|
|
Loading…
Reference in New Issue