mirror of
https://git.pleroma.social/pleroma/pleroma.git
synced 2024-11-13 12:31:13 +00:00
Merge branch 'develop' into 'bookmark-folders'
# Conflicts: # docs/development/API/differences_in_mastoapi_responses.md
This commit is contained in:
commit
2b71f4897f
47 changed files with 485 additions and 81 deletions
|
@ -169,25 +169,6 @@ unit-testing-1.12-erratic:
|
|||
- mix ecto.migrate
|
||||
- mix test --only=erratic
|
||||
|
||||
unit-testing-1.12-rum:
|
||||
extends:
|
||||
- .build_changes_policy
|
||||
- .using-ci-base
|
||||
stage: test
|
||||
cache: *testing_cache_policy
|
||||
services:
|
||||
- name: git.pleroma.social:5050/pleroma/pleroma/postgres-with-rum-13
|
||||
alias: postgres
|
||||
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
|
||||
variables:
|
||||
<<: *global_variables
|
||||
RUM_ENABLED: "true"
|
||||
script:
|
||||
- mix ecto.create
|
||||
- mix ecto.migrate
|
||||
- "mix ecto.migrate --migrations-path priv/repo/optional_migrations/rum_indexing/"
|
||||
- mix test --preload-modules
|
||||
|
||||
formatting-1.13:
|
||||
extends: .build_changes_policy
|
||||
image: &formatting_elixir elixir:1.13-alpine
|
||||
|
|
1
changelog.d/backups-follows.add
Normal file
1
changelog.d/backups-follows.add
Normal file
|
@ -0,0 +1 @@
|
|||
Include following/followers in backups
|
0
changelog.d/exile-freebsd.skip
Normal file
0
changelog.d/exile-freebsd.skip
Normal file
1
changelog.d/force-mention-mrf.add
Normal file
1
changelog.d/force-mention-mrf.add
Normal file
|
@ -0,0 +1 @@
|
|||
Add ForceMention MRF
|
1
changelog.d/framegrabs.fix
Normal file
1
changelog.d/framegrabs.fix
Normal file
|
@ -0,0 +1 @@
|
|||
Video framegrabs were not working correctly after the change to use Exile to execute ffmpeg
|
1
changelog.d/gun_pool2.fix
Normal file
1
changelog.d/gun_pool2.fix
Normal file
|
@ -0,0 +1 @@
|
|||
Connection pool errors when publishing an activity is a soft-error that will be retried shortly.
|
0
changelog.d/gun_pool3.skip
Normal file
0
changelog.d/gun_pool3.skip
Normal file
1
changelog.d/instance-contact-account.add
Normal file
1
changelog.d/instance-contact-account.add
Normal file
|
@ -0,0 +1 @@
|
|||
Add contact account to InstanceView
|
0
changelog.d/instance-v2.skip
Normal file
0
changelog.d/instance-v2.skip
Normal file
1
changelog.d/issue-3241.fix
Normal file
1
changelog.d/issue-3241.fix
Normal file
|
@ -0,0 +1 @@
|
|||
Handle cases when users.inbox is nil.
|
1
changelog.d/link-verification.add
Normal file
1
changelog.d/link-verification.add
Normal file
|
@ -0,0 +1 @@
|
|||
Verify profile link ownership with rel="me"
|
1
changelog.d/notifications.fix
Normal file
1
changelog.d/notifications.fix
Normal file
|
@ -0,0 +1 @@
|
|||
Notifications: improve performance by filtering on users table instead of activities table
|
1
changelog.d/public-polls.add
Normal file
1
changelog.d/public-polls.add
Normal file
|
@ -0,0 +1 @@
|
|||
Expose nonAnonymous field from Smithereen polls
|
0
changelog.d/remote-fetcher-error.skip
Normal file
0
changelog.d/remote-fetcher-error.skip
Normal file
|
@ -415,6 +415,10 @@ config :pleroma, :mrf_follow_bot, follower_nickname: nil
|
|||
|
||||
config :pleroma, :mrf_inline_quote, template: "<bdi>RT:</bdi> {url}"
|
||||
|
||||
config :pleroma, :mrf_force_mention,
|
||||
mention_parent: true,
|
||||
mention_quoted: true
|
||||
|
||||
config :pleroma, :rich_media,
|
||||
enabled: true,
|
||||
ignore_hosts: [],
|
||||
|
|
|
@ -566,6 +566,20 @@ config :pleroma, :config_description, [
|
|||
"Cool instance"
|
||||
]
|
||||
},
|
||||
%{
|
||||
key: :status_page,
|
||||
type: :string,
|
||||
description: "A page where people can see the status of the server during an outage",
|
||||
suggestions: [
|
||||
"https://status.pleroma.example.org"
|
||||
]
|
||||
},
|
||||
%{
|
||||
key: :contact_username,
|
||||
type: :string,
|
||||
description: "Instance owner username",
|
||||
suggestions: ["admin"]
|
||||
},
|
||||
%{
|
||||
key: :limit,
|
||||
type: :integer,
|
||||
|
|
|
@ -161,7 +161,8 @@ To add configuration to your config file, you can copy it from the base config.
|
|||
* `Pleroma.Web.ActivityPub.MRF.KeywordPolicy`: Rejects or removes from the federated timeline or replaces keywords. (See [`:mrf_keyword`](#mrf_keyword)).
|
||||
* `Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent`: Forces every mentioned user to be reflected in the post content.
|
||||
* `Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy`: Forces quote post URLs to be reflected in the message content inline.
|
||||
* `Pleroma.Web.ActivityPub.MRF.QuoteToLinkTagPolicy`: Force a Link tag for posts quoting another post. (may break outgoing federation of quote posts with older Pleroma versions)
|
||||
* `Pleroma.Web.ActivityPub.MRF.QuoteToLinkTagPolicy`: Force a Link tag for posts quoting another post. (may break outgoing federation of quote posts with older Pleroma versions).
|
||||
* `Pleroma.Web.ActivityPub.MRF.ForceMention`: Forces posts to include a mention of the author of parent post or the author of quoted post.
|
||||
* `transparency`: Make the content of your Message Rewrite Facility settings public (via nodeinfo).
|
||||
* `transparency_exclusions`: Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value.
|
||||
|
||||
|
@ -272,6 +273,10 @@ Notes:
|
|||
#### :mrf_inline_quote
|
||||
* `template`: The template to append to the post. `{url}` will be replaced with the actual link to the quoted post. Default: `<bdi>RT:</bdi> {url}`
|
||||
|
||||
#### :mrf_force_mention
|
||||
* `mention_parent`: Whether to append mention of parent post author
|
||||
* `mention_quoted`: Whether to append mention of parent quoted author
|
||||
|
||||
### :activitypub
|
||||
* `unfollow_blocked`: Whether blocks result in people getting unfollowed
|
||||
* `outgoing_blocks`: Whether to federate blocks to other instances
|
||||
|
|
|
@ -40,6 +40,7 @@ Has these additional fields under the `pleroma` object:
|
|||
- `parent_visible`: If the parent of this post is visible to the user or not.
|
||||
- `pinned_at`: a datetime (iso8601) when status was pinned, `null` otherwise.
|
||||
- `quotes_count`: the count of status quotes.
|
||||
- `non_anonymous`: true if the source post specifies the poll results are not anonymous. Currently only implemented by Smithereen.
|
||||
- `bookmark_folder`: the ID of the folder bookmark is stored within (if any).
|
||||
|
||||
The `GET /api/v1/statuses/:id/source` endpoint additionally has the following attributes:
|
||||
|
|
|
@ -241,13 +241,13 @@ defmodule Pleroma.FollowingRelationship do
|
|||
end
|
||||
|
||||
@doc """
|
||||
For a query with joined activity,
|
||||
keeps rows where activity's actor is followed by user -or- is NOT domain-blocked by user.
|
||||
For a query with joined activity's actor,
|
||||
keeps rows where actor is followed by user -or- is NOT domain-blocked by user.
|
||||
"""
|
||||
def keep_following_or_not_domain_blocked(query, user) do
|
||||
where(
|
||||
query,
|
||||
[_, activity],
|
||||
[_, user_actor: user_actor],
|
||||
fragment(
|
||||
# "(actor's domain NOT in domain_blocks) OR (actor IS in followed AP IDs)"
|
||||
"""
|
||||
|
@ -255,9 +255,9 @@ defmodule Pleroma.FollowingRelationship do
|
|||
? = ANY(SELECT ap_id FROM users AS u INNER JOIN following_relationships AS fr
|
||||
ON u.id = fr.following_id WHERE fr.follower_id = ? AND fr.state = ?)
|
||||
""",
|
||||
activity.actor,
|
||||
user_actor.ap_id,
|
||||
^user.domain_blocks,
|
||||
activity.actor,
|
||||
user_actor.ap_id,
|
||||
^User.binary_id(user.id),
|
||||
^accept_state_code()
|
||||
)
|
||||
|
|
|
@ -18,10 +18,10 @@ defmodule Pleroma.Gun.ConnectionPool.WorkerSupervisor do
|
|||
)
|
||||
end
|
||||
|
||||
def start_worker(opts, retry \\ false) do
|
||||
def start_worker(opts, last_attempt \\ false) do
|
||||
case DynamicSupervisor.start_child(__MODULE__, {Pleroma.Gun.ConnectionPool.Worker, opts}) do
|
||||
{:error, :max_children} ->
|
||||
funs = [fn -> !retry end, fn -> match?(:error, free_pool()) end]
|
||||
funs = [fn -> last_attempt end, fn -> match?(:error, free_pool()) end]
|
||||
|
||||
if Enum.any?(funs, fn fun -> fun.() end) do
|
||||
:telemetry.execute([:pleroma, :connection_pool, :provision_failure], %{opts: opts})
|
||||
|
|
|
@ -40,28 +40,32 @@ defmodule Pleroma.Helpers.MediaHelper do
|
|||
end
|
||||
|
||||
# Note: video thumbnail is intentionally not resized (always has original dimensions)
|
||||
@spec video_framegrab(String.t()) :: {:ok, binary()} | {:error, any()}
|
||||
def video_framegrab(url) do
|
||||
with executable when is_binary(executable) <- System.find_executable("ffmpeg"),
|
||||
{:ok, env} <- HTTP.get(url, [], pool: :media),
|
||||
{:ok, pid} <- StringIO.open(env.body) do
|
||||
body_stream = IO.binstream(pid, 1)
|
||||
|
||||
Exile.stream!(
|
||||
[
|
||||
executable,
|
||||
"-i",
|
||||
"pipe:0",
|
||||
"-vframes",
|
||||
"1",
|
||||
"-f",
|
||||
"mjpeg",
|
||||
"pipe:1"
|
||||
],
|
||||
input: body_stream,
|
||||
ignore_epipe: true,
|
||||
stderr: :disable
|
||||
)
|
||||
|> Enum.into(<<>>)
|
||||
result =
|
||||
Exile.stream!(
|
||||
[
|
||||
executable,
|
||||
"-i",
|
||||
"pipe:0",
|
||||
"-vframes",
|
||||
"1",
|
||||
"-f",
|
||||
"mjpeg",
|
||||
"pipe:1"
|
||||
],
|
||||
input: body_stream,
|
||||
ignore_epipe: true,
|
||||
stderr: :disable
|
||||
)
|
||||
|> Enum.into(<<>>)
|
||||
|
||||
{:ok, result}
|
||||
else
|
||||
nil -> {:error, {:ffmpeg, :command_not_found}}
|
||||
{:error, _} = error -> error
|
||||
|
|
|
@ -137,7 +137,7 @@ defmodule Pleroma.Notification do
|
|||
blocked_ap_ids = opts[:blocked_users_ap_ids] || User.blocked_users_ap_ids(user)
|
||||
|
||||
query
|
||||
|> where([n, a], a.actor not in ^blocked_ap_ids)
|
||||
|> where([..., user_actor: user_actor], user_actor.ap_id not in ^blocked_ap_ids)
|
||||
|> FollowingRelationship.keep_following_or_not_domain_blocked(user)
|
||||
end
|
||||
|
||||
|
@ -148,7 +148,7 @@ defmodule Pleroma.Notification do
|
|||
blocker_ap_ids = User.incoming_relationships_ungrouped_ap_ids(user, [:block])
|
||||
|
||||
query
|
||||
|> where([n, a], a.actor not in ^blocker_ap_ids)
|
||||
|> where([..., user_actor: user_actor], user_actor.ap_id not in ^blocker_ap_ids)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -161,7 +161,7 @@ defmodule Pleroma.Notification do
|
|||
opts[:notification_muted_users_ap_ids] || User.notification_muted_users_ap_ids(user)
|
||||
|
||||
query
|
||||
|> where([n, a], a.actor not in ^notification_muted_ap_ids)
|
||||
|> where([..., user_actor: user_actor], user_actor.ap_id not in ^notification_muted_ap_ids)
|
||||
|> join(:left, [n, a], tm in ThreadMute,
|
||||
on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data),
|
||||
as: :thread_mute
|
||||
|
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.User do
|
|||
import Ecto.Changeset
|
||||
import Ecto.Query
|
||||
import Ecto, only: [assoc: 2]
|
||||
import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
|
||||
|
||||
alias Ecto.Multi
|
||||
alias Pleroma.Activity
|
||||
|
@ -596,9 +597,23 @@ defmodule Pleroma.User do
|
|||
|
||||
defp put_fields(changeset) do
|
||||
if raw_fields = get_change(changeset, :raw_fields) do
|
||||
old_fields = changeset.data.raw_fields
|
||||
|
||||
raw_fields =
|
||||
raw_fields
|
||||
|> Enum.filter(fn %{"name" => n} -> n != "" end)
|
||||
|> Enum.map(fn field ->
|
||||
previous =
|
||||
old_fields
|
||||
|> Enum.find(fn %{"value" => value} -> field["value"] == value end)
|
||||
|
||||
if previous && Map.has_key?(previous, "verified_at") do
|
||||
field
|
||||
|> Map.put("verified_at", previous["verified_at"])
|
||||
else
|
||||
field
|
||||
end
|
||||
end)
|
||||
|
||||
fields =
|
||||
raw_fields
|
||||
|
@ -1200,6 +1215,10 @@ defmodule Pleroma.User do
|
|||
|
||||
def update_and_set_cache(changeset) do
|
||||
with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do
|
||||
if get_change(changeset, :raw_fields) do
|
||||
BackgroundWorker.enqueue("verify_fields_links", %{"user_id" => user.id})
|
||||
end
|
||||
|
||||
set_cache(user)
|
||||
end
|
||||
end
|
||||
|
@ -1975,8 +1994,45 @@ defmodule Pleroma.User do
|
|||
maybe_delete_from_db(user)
|
||||
end
|
||||
|
||||
def perform(:verify_fields_links, user) do
|
||||
profile_urls = [user.ap_id]
|
||||
|
||||
fields =
|
||||
user.raw_fields
|
||||
|> Enum.map(&verify_field_link(&1, profile_urls))
|
||||
|
||||
changeset =
|
||||
user
|
||||
|> update_changeset(%{raw_fields: fields})
|
||||
|
||||
with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do
|
||||
set_cache(user)
|
||||
end
|
||||
end
|
||||
|
||||
def perform(:set_activation_async, user, status), do: set_activation(user, status)
|
||||
|
||||
defp verify_field_link(field, profile_urls) do
|
||||
verified_at =
|
||||
with %{"value" => value} <- field,
|
||||
{:verified_at, nil} <- {:verified_at, Map.get(field, "verified_at")},
|
||||
%{scheme: scheme, userinfo: nil, host: host}
|
||||
when not_empty_string(host) and scheme in ["http", "https"] <-
|
||||
URI.parse(value),
|
||||
{:not_idn, true} <- {:not_idn, to_string(:idna.encode(host)) == host},
|
||||
"me" <- Pleroma.Web.RelMe.maybe_put_rel_me(value, profile_urls) do
|
||||
CommonUtils.to_masto_date(NaiveDateTime.utc_now())
|
||||
else
|
||||
{:verified_at, value} when not_empty_string(value) ->
|
||||
value
|
||||
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
|
||||
Map.put(field, "verified_at", verified_at)
|
||||
end
|
||||
|
||||
@spec external_users_query() :: Ecto.Query.t()
|
||||
def external_users_query do
|
||||
User.Query.build(%{
|
||||
|
@ -2664,10 +2720,11 @@ defmodule Pleroma.User do
|
|||
# - display name
|
||||
def sanitize_html(%User{} = user, filter) do
|
||||
fields =
|
||||
Enum.map(user.fields, fn %{"name" => name, "value" => value} ->
|
||||
Enum.map(user.fields, fn %{"name" => name, "value" => value} = fields ->
|
||||
%{
|
||||
"name" => name,
|
||||
"value" => HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
|
||||
"value" => HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly),
|
||||
"verified_at" => Map.get(fields, "verified_at")
|
||||
}
|
||||
end)
|
||||
|
||||
|
|
|
@ -196,7 +196,14 @@ defmodule Pleroma.User.Backup do
|
|||
end
|
||||
end
|
||||
|
||||
@files ['actor.json', 'outbox.json', 'likes.json', 'bookmarks.json']
|
||||
@files [
|
||||
'actor.json',
|
||||
'outbox.json',
|
||||
'likes.json',
|
||||
'bookmarks.json',
|
||||
'followers.json',
|
||||
'following.json'
|
||||
]
|
||||
@spec export(Pleroma.User.Backup.t(), pid()) :: {:ok, String.t()} | :error
|
||||
def export(%__MODULE__{} = backup, caller_pid) do
|
||||
backup = Repo.preload(backup, :user)
|
||||
|
@ -207,6 +214,8 @@ defmodule Pleroma.User.Backup do
|
|||
:ok <- statuses(dir, backup.user, caller_pid),
|
||||
:ok <- likes(dir, backup.user, caller_pid),
|
||||
:ok <- bookmarks(dir, backup.user, caller_pid),
|
||||
:ok <- followers(dir, backup.user, caller_pid),
|
||||
:ok <- following(dir, backup.user, caller_pid),
|
||||
{:ok, zip_path} <- :zip.create(backup.file_name, @files, cwd: dir),
|
||||
{:ok, _} <- File.rm_rf(dir) do
|
||||
{:ok, zip_path}
|
||||
|
@ -357,6 +366,16 @@ defmodule Pleroma.User.Backup do
|
|||
caller_pid
|
||||
)
|
||||
end
|
||||
|
||||
defp followers(dir, user, caller_pid) do
|
||||
User.get_followers_query(user)
|
||||
|> write(dir, "followers", fn a -> {:ok, a.ap_id} end, caller_pid)
|
||||
end
|
||||
|
||||
defp following(dir, user, caller_pid) do
|
||||
User.get_friends_query(user)
|
||||
|> write(dir, "following", fn a -> {:ok, a.ap_id} end, caller_pid)
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Pleroma.User.Backup.ProcessorAPI do
|
||||
|
|
59
lib/pleroma/web/activity_pub/mrf/force_mention.ex
Normal file
59
lib/pleroma/web/activity_pub/mrf/force_mention.ex
Normal file
|
@ -0,0 +1,59 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.ForceMention do
|
||||
require Pleroma.Constants
|
||||
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
defp get_author(url) do
|
||||
with %Object{data: %{"actor" => actor}} <- Object.normalize(url, fetch: false),
|
||||
%User{ap_id: ap_id, nickname: nickname} <- User.get_cached_by_ap_id(actor) do
|
||||
%{"type" => "Mention", "href" => ap_id, "name" => "@#{nickname}"}
|
||||
else
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp prepend_author(tags, _, false), do: tags
|
||||
|
||||
defp prepend_author(tags, nil, _), do: tags
|
||||
|
||||
defp prepend_author(tags, url, _) do
|
||||
actor = get_author(url)
|
||||
|
||||
if not is_nil(actor) do
|
||||
[actor | tags]
|
||||
else
|
||||
tags
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Create", "object" => %{"tag" => tag} = object} = activity) do
|
||||
tag =
|
||||
tag
|
||||
|> prepend_author(
|
||||
object["inReplyTo"],
|
||||
Config.get([:mrf_force_mention, :mention_parent, true])
|
||||
)
|
||||
|> prepend_author(
|
||||
object["quoteUrl"],
|
||||
Config.get([:mrf_force_mention, :mention_quoted, true])
|
||||
)
|
||||
|> Enum.uniq()
|
||||
|
||||
{:ok, put_in(activity["object"]["tag"], tag)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(object), do: {:ok, object}
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
end
|
|
@ -29,6 +29,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
|
|||
|
||||
field(:closed, ObjectValidators.DateTime)
|
||||
field(:voters, {:array, ObjectValidators.ObjectID}, default: [])
|
||||
field(:nonAnonymous, :boolean)
|
||||
embeds_many(:anyOf, QuestionOptionsValidator)
|
||||
embeds_many(:oneOf, QuestionOptionsValidator)
|
||||
end
|
||||
|
|
|
@ -129,6 +129,10 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
_ -> {:error, e}
|
||||
end
|
||||
|
||||
{:error, :pool_full} ->
|
||||
Logger.debug("Publisher snoozing worker job due to full connection pool")
|
||||
{:snooze, 30}
|
||||
|
||||
e ->
|
||||
unless params[:unreachable_since], do: Instances.set_unreachable(inbox)
|
||||
Logger.metadata(activity: id, inbox: inbox)
|
||||
|
@ -154,19 +158,18 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
end
|
||||
end
|
||||
|
||||
defp should_federate?(inbox, public) do
|
||||
if public do
|
||||
true
|
||||
else
|
||||
%{host: host} = URI.parse(inbox)
|
||||
def should_federate?(nil, _), do: false
|
||||
def should_federate?(_, true), do: true
|
||||
|
||||
quarantined_instances =
|
||||
Config.get([:instance, :quarantined_instances], [])
|
||||
|> Pleroma.Web.ActivityPub.MRF.instance_list_from_tuples()
|
||||
|> Pleroma.Web.ActivityPub.MRF.subdomains_regex()
|
||||
def should_federate?(inbox, _) do
|
||||
%{host: host} = URI.parse(inbox)
|
||||
|
||||
!Pleroma.Web.ActivityPub.MRF.subdomain_match?(quarantined_instances, host)
|
||||
end
|
||||
quarantined_instances =
|
||||
Config.get([:instance, :quarantined_instances], [])
|
||||
|> Pleroma.Web.ActivityPub.MRF.instance_list_from_tuples()
|
||||
|> Pleroma.Web.ActivityPub.MRF.subdomains_regex()
|
||||
|
||||
!Pleroma.Web.ActivityPub.MRF.subdomain_match?(quarantined_instances, host)
|
||||
end
|
||||
|
||||
@spec recipients(User.t(), Activity.t()) :: [[User.t()]]
|
||||
|
|
|
@ -56,6 +56,15 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Poll do
|
|||
}
|
||||
},
|
||||
description: "Possible answers for the poll."
|
||||
},
|
||||
pleroma: %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
non_anonymous: %Schema{
|
||||
type: :boolean,
|
||||
description: "Can voters be publicly identified?"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
example: %{
|
||||
|
@ -79,7 +88,10 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Poll do
|
|||
votes_count: 4
|
||||
}
|
||||
],
|
||||
emojis: []
|
||||
emojis: [],
|
||||
pleroma: %{
|
||||
non_anonymous: false
|
||||
}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
|
|
@ -28,6 +28,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
|
|||
|> to_string,
|
||||
registrations: Keyword.get(instance, :registrations_open),
|
||||
approval_required: Keyword.get(instance, :account_approval_required),
|
||||
contact_account: contact_account(Keyword.get(instance, :contact_username)),
|
||||
configuration: configuration(),
|
||||
# Extra (not present in Mastodon):
|
||||
max_toot_chars: Keyword.get(instance, :limit),
|
||||
|
@ -63,11 +64,12 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
|
|||
registrations: %{
|
||||
enabled: Keyword.get(instance, :registrations_open),
|
||||
approval_required: Keyword.get(instance, :account_approval_required),
|
||||
message: nil
|
||||
message: nil,
|
||||
url: nil
|
||||
},
|
||||
contact: %{
|
||||
email: Keyword.get(instance, :email),
|
||||
account: nil
|
||||
account: contact_account(Keyword.get(instance, :contact_username))
|
||||
},
|
||||
# Extra (not present in Mastodon):
|
||||
pleroma: pleroma_configuration2(instance)
|
||||
|
@ -78,7 +80,8 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
|
|||
%{
|
||||
title: Keyword.get(instance, :name),
|
||||
version: "#{@mastodon_api_level} (compatible; #{Pleroma.Application.named_version()})",
|
||||
languages: Keyword.get(instance, :languages, ["en"])
|
||||
languages: Keyword.get(instance, :languages, ["en"]),
|
||||
rules: []
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -168,15 +171,35 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
|
|||
}
|
||||
end
|
||||
|
||||
defp contact_account(nil), do: nil
|
||||
|
||||
defp contact_account("@" <> username) do
|
||||
contact_account(username)
|
||||
end
|
||||
|
||||
defp contact_account(username) do
|
||||
user = Pleroma.User.get_cached_by_nickname(username)
|
||||
|
||||
if user do
|
||||
Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user, for: nil})
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
defp configuration do
|
||||
%{
|
||||
accounts: %{
|
||||
max_featured_tags: 0
|
||||
},
|
||||
statuses: %{
|
||||
max_characters: Config.get([:instance, :limit]),
|
||||
max_media_attachments: Config.get([:instance, :max_media_attachments])
|
||||
},
|
||||
media_attachments: %{
|
||||
image_size_limit: Config.get([:instance, :upload_limit]),
|
||||
video_size_limit: Config.get([:instance, :upload_limit])
|
||||
video_size_limit: Config.get([:instance, :upload_limit]),
|
||||
supported_mime_types: ["application/octet-stream"]
|
||||
},
|
||||
polls: %{
|
||||
max_options: Config.get([:instance, :poll_limits, :max_options]),
|
||||
|
@ -190,7 +213,13 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
|
|||
defp configuration2 do
|
||||
configuration()
|
||||
|> Map.merge(%{
|
||||
urls: %{streaming: Pleroma.Web.Endpoint.websocket_url()}
|
||||
urls: %{
|
||||
streaming: Pleroma.Web.Endpoint.websocket_url(),
|
||||
status: Config.get([:instance, :status_page])
|
||||
},
|
||||
vapid: %{
|
||||
public_key: Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key)
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
|
|
|
@ -21,7 +21,10 @@ defmodule Pleroma.Web.MastodonAPI.PollView do
|
|||
votes_count: votes_count,
|
||||
voters_count: voters_count(object),
|
||||
options: options,
|
||||
emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"])
|
||||
emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"]),
|
||||
pleroma: %{
|
||||
non_anonymous: object.data["nonAnonymous"] || false
|
||||
}
|
||||
}
|
||||
|
||||
if params[:for] do
|
||||
|
|
|
@ -40,6 +40,11 @@ defmodule Pleroma.Workers.BackgroundWorker do
|
|||
Pleroma.FollowingRelationship.move_following(origin, target)
|
||||
end
|
||||
|
||||
def perform(%Job{args: %{"op" => "verify_fields_links", "user_id" => user_id}}) do
|
||||
user = User.get_by_id(user_id)
|
||||
User.perform(:verify_fields_links, user)
|
||||
end
|
||||
|
||||
def perform(%Job{args: %{"op" => "delete_instance", "host" => host}}) do
|
||||
Instance.perform(:delete_instance, host)
|
||||
end
|
||||
|
|
|
@ -22,8 +22,11 @@ defmodule Pleroma.Workers.RemoteFetcherWorker do
|
|||
{:error, :allowed_depth} ->
|
||||
{:discard, :allowed_depth}
|
||||
|
||||
_ ->
|
||||
:error
|
||||
{:error, _} = e ->
|
||||
e
|
||||
|
||||
e ->
|
||||
{:error, e}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
4
mix.exs
4
mix.exs
|
@ -186,8 +186,8 @@ defmodule Pleroma.Mixfile do
|
|||
{:elixir_make, "~> 0.7.7", override: true},
|
||||
{:blurhash, "~> 0.1.0", hex: :rinpatch_blurhash},
|
||||
{:exile,
|
||||
git: "https://git.pleroma.social/pleroma/elixir-libraries/exile.git",
|
||||
ref: "0d6337cf68e7fbc8a093cae000955aa93b067f91"},
|
||||
git: "https://github.com/akash-akya/exile.git",
|
||||
ref: "be87c33b02a7c3c5d22d2ece01fbd462355b28ef"},
|
||||
{:bandit, "~> 1.2"},
|
||||
|
||||
## dev & test
|
||||
|
|
2
mix.lock
2
mix.lock
|
@ -47,7 +47,7 @@
|
|||
"ex_doc": {:hex, :ex_doc, "0.31.1", "8a2355ac42b1cc7b2379da9e40243f2670143721dd50748bf6c3b1184dae2089", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "3178c3a407c557d8343479e1ff117a96fd31bafe52a039079593fb0524ef61b0"},
|
||||
"ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"},
|
||||
"ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"},
|
||||
"exile": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/exile.git", "0d6337cf68e7fbc8a093cae000955aa93b067f91", [ref: "0d6337cf68e7fbc8a093cae000955aa93b067f91"]},
|
||||
"exile": {:git, "https://github.com/akash-akya/exile.git", "be87c33b02a7c3c5d22d2ece01fbd462355b28ef", [ref: "be87c33b02a7c3c5d22d2ece01fbd462355b28ef"]},
|
||||
"expo": {:hex, :expo, "0.5.1", "249e826a897cac48f591deba863b26c16682b43711dd15ee86b92f25eafd96d9", [:mix], [], "hexpm", "68a4233b0658a3d12ee00d27d37d856b1ba48607e7ce20fd376958d0ba6ce92b"},
|
||||
"fast_html": {:hex, :fast_html, "2.2.0", "6c5ef1be087a4ed613b0379c13f815c4d11742b36b67bb52cee7859847c84520", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "064c4f23b4a6168f9187dac8984b056f2c531bb0787f559fd6a8b34b38aefbae"},
|
||||
"fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"},
|
||||
|
|
|
@ -40,7 +40,9 @@
|
|||
"@type": "@id"
|
||||
},
|
||||
"vcard": "http://www.w3.org/2006/vcard/ns#",
|
||||
"formerRepresentations": "litepub:formerRepresentations"
|
||||
"formerRepresentations": "litepub:formerRepresentations",
|
||||
"sm": "http://smithereen.software/ns#",
|
||||
"nonAnonymous": "sm:nonAnonymous"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
1
test/fixtures/minds-invalid-mention-post.json
vendored
Normal file
1
test/fixtures/minds-invalid-mention-post.json
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
{"@context":"https://www.w3.org/ns/activitystreams","type":"Note","id":"https://www.minds.com/api/activitypub/users/1198929502760083472/entities/urn:comment:1600926863310458883:0:0:0:1600932467852709903","attributedTo":"https://www.minds.com/api/activitypub/users/1198929502760083472","content":"\u003Ca class=\u0022u-url mention\u0022 href=\u0022https://www.minds.com/lain\u0022 target=\u0022_blank\u0022\u003E@lain\u003C/a\u003E corn syrup.","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://www.minds.com/api/activitypub/users/1198929502760083472/followers","https://lain.com/users/lain"],"tag":[{"type":"Mention","href":"https://www.minds.com/api/activitypub/users/464237775479123984","name":"@lain"}],"url":"https://www.minds.com/newsfeed/1600926863310458883?focusedCommentUrn=urn:comment:1600926863310458883:0:0:0:1600932467852709903","published":"2024-02-04T17:34:03+00:00","inReplyTo":"https://lain.com/objects/36254095-c839-4167-bcc2-b361d5de9198","source":{"content":"@lain corn syrup.","mediaType":"text/plain"}}
|
1
test/fixtures/minds-pleroma-mentioned-post.json
vendored
Normal file
1
test/fixtures/minds-pleroma-mentioned-post.json
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
{"@context":["https://www.w3.org/ns/activitystreams","https://lain.com/schemas/litepub-0.1.jsonld",{"@language":"und"}],"actor":"https://lain.com/users/lain","attachment":[],"attributedTo":"https://lain.com/users/lain","cc":["https://lain.com/users/lain/followers"],"content":"which diet is the best for cognitive dissonance","context":"https://lain.com/contexts/98c8a130-e813-4797-8973-600e80114317","conversation":"https://lain.com/contexts/98c8a130-e813-4797-8973-600e80114317","id":"https://lain.com/objects/36254095-c839-4167-bcc2-b361d5de9198","published":"2024-02-04T17:11:23.931890Z","repliesCount":11,"sensitive":null,"source":{"content":"which diet is the best for cognitive dissonance","mediaType":"text/plain"},"summary":"","tag":[],"to":["https://www.w3.org/ns/activitystreams#Public"],"type":"Note"}
|
1
test/fixtures/tesla_mock/smithereen_non_anonymous_poll.json
vendored
Normal file
1
test/fixtures/tesla_mock/smithereen_non_anonymous_poll.json
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
{"type":"Question","id":"https://friends.grishka.me/posts/54642","attributedTo":"https://friends.grishka.me/users/1","content":"<p>здесь тоже можно что-то написать отдельно от опроса</p>","published":"2021-09-04T00:22:16Z","url":"https://friends.grishka.me/posts/54642","to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://friends.grishka.me/users/1/followers"],"replies":{"type":"Collection","id":"https://friends.grishka.me/posts/54642/replies","first":{"type":"CollectionPage","items":[],"partOf":"https://friends.grishka.me/posts/54642/replies","next":"https://friends.grishka.me/posts/54642/replies?page=1"}},"sensitive":false,"likes":"https://friends.grishka.me/posts/54642/likes","name":"тестовый опрос","oneOf":[{"type":"Note","id":"https://friends.grishka.me/posts/54642#options/76","name":"тестовый ответ 1","replies":{"type":"Collection","id":"https://friends.grishka.me/activitypub/objects/polls/24/options/76/votes","totalItems":4,"items":[]}},{"type":"Note","id":"https://friends.grishka.me/posts/54642#options/77","name":"тестовый ответ 2","replies":{"type":"Collection","id":"https://friends.grishka.me/activitypub/objects/polls/24/options/77/votes","totalItems":4,"items":[]}},{"type":"Note","id":"https://friends.grishka.me/posts/54642#options/78","name":"тестовый ответ 3","replies":{"type":"Collection","id":"https://friends.grishka.me/activitypub/objects/polls/24/options/78/votes","totalItems":6,"items":[]}}],"votersCount":14,"nonAnonymous":true,"@context":["https://www.w3.org/ns/activitystreams",{"sensitive":"as:sensitive","toot":"http://joinmastodon.org/ns#","sm":"http://smithereen.software/ns#","votersCount":"toot:votersCount","nonAnonymous":"sm:nonAnonymous"}]}
|
1
test/fixtures/tesla_mock/smithereen_user.json
vendored
Normal file
1
test/fixtures/tesla_mock/smithereen_user.json
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
{"type":"Person","id":"https://friends.grishka.me/users/1","name":"Григорий Клюшников","icon":{"type":"Image","image":{"type":"Image","url":"https://friends.grishka.me/i/6QLsOws97AWp5N_osd74C1IC1ijnFopyCBD9MSEeXNQ/q:93/bG9jYWw6Ly8vcy91cGxvYWRzL2F2YXRhcnMvNTYzODRhODEwODk5ZTRjMzI4YmY4YmQwM2Q2MWM3NmMud2VicA.jpg","mediaType":"image/jpeg","width":1280,"height":960},"width":573,"height":572,"cropRegion":[0.26422762870788574,0.3766937553882599,0.7113820910453796,0.9728997349739075],"url":"https://friends.grishka.me/i/ql_49PQcETAWgY_nC-Qj63H_Oa6FyOAEoWFkUSSkUvQ/c:573:572:nowe:338:362/q:93/bG9jYWw6Ly8vcy91cGxvYWRzL2F2YXRhcnMvNTYzODRhODEwODk5ZTRjMzI4YmY4YmQwM2Q2MWM3NmMud2VicA.jpg","mediaType":"image/jpeg"},"summary":"<p>Делаю эту хрень, пытаюсь вырвать социальные сети из жадных лап корпораций</p>\n<p></p>\n<p></p>\n<p></p>\n<p></p>\n<p></p>\n<p></p>\n<p></p>\n<p>This server does NOT support direct messages. Please write me <a href=\"https://t.me/grishka\">on Telegram</a> or <a href=\"https://matrix.to/#/@grishk:matrix.org\">Matrix</a>.</p>","url":"https://friends.grishka.me/grishka","preferredUsername":"grishka","inbox":"https://friends.grishka.me/users/1/inbox","outbox":"https://friends.grishka.me/users/1/outbox","followers":"https://friends.grishka.me/users/1/followers","following":"https://friends.grishka.me/users/1/following","endpoints":{"sharedInbox":"https://friends.grishka.me/activitypub/sharedInbox","collectionSimpleQuery":"https://friends.grishka.me/users/1/collectionQuery"},"publicKey":{"id":"https://friends.grishka.me/users/1#main-key","owner":"https://friends.grishka.me/users/1","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjlakm+i/d9ER/hIeR7KfiFW+SdLZj2SkKIeM8cmR+YFJuh9ghFqXrkFEjcaqUnAFqe5gYDNSQACnDLA8y4DnzjfGNIohKAnRoa9x6GORmfKQvcnjaTZ53S1NvUiPPyc0Pv/vfCtY/Ab0CEXe5BLqL38oZn817Jf7pBrPRTYH7m012kvwAUTT6k0Y8lPITBEG7nzYbbuGcrN9Y/RDdwE08jmBXlZ45bahRH3VNXVpQE17dCzJB+7k+iJ1R7YCoI+DuMlBYGXGE2KVk46NZTuLnOjFV9SyXfWX4/SrJM4oxev+SX2N75tQgmNZmVVHeqg2ZcbC0WCfNjJOi2HHS9MujwIDAQAB\n-----END PUBLIC KEY-----\n"},"wall":"https://friends.grishka.me/users/1/wall","firstName":"Григорий","lastName":"Клюшников","middleName":"Александрович","vcard:bday":"1993-01-22","gender":"http://schema.org#Male","supportsFriendRequests":true,"friends":"https://friends.grishka.me/users/1/friends","groups":"https://friends.grishka.me/users/1/groups","capabilities":{"supportsFriendRequests":true},"@context":["https://www.w3.org/ns/activitystreams",{"sm":"http://smithereen.software/ns#","cropRegion":{"@id":"sm:cropRegion","@container":"@list"},"wall":{"@id":"sm:wall","@type":"@id"},"collectionSimpleQuery":"sm:collectionSimpleQuery","sc":"http://schema.org#","firstName":"sc:givenName","lastName":"sc:familyName","middleName":"sc:additionalName","gender":{"@id":"sc:gender","@type":"sc:GenderType"},"maidenName":"sm:maidenName","friends":{"@id":"sm:friends","@type":"@id"},"groups":{"@id":"sm:groups","@type":"@id"},"vcard":"http://www.w3.org/2006/vcard/ns#","capabilities":"litepub:capabilities","supportsFriendRequests":"sm:supportsFriendRequests","litepub":"http://litepub.social/ns#"},"https://w3id.org/security/v1"]}
|
|
@ -166,6 +166,7 @@ defmodule Pleroma.User.BackupTest do
|
|||
|
||||
test "it creates a zip archive with user data" do
|
||||
user = insert(:user, %{nickname: "cofe", name: "Cofe", ap_id: "http://cofe.io/users/cofe"})
|
||||
%{ap_id: other_ap_id} = other_user = insert(:user)
|
||||
|
||||
{:ok, %{object: %{data: %{"id" => id1}}} = status1} =
|
||||
CommonAPI.post(user, %{status: "status1"})
|
||||
|
@ -182,6 +183,8 @@ defmodule Pleroma.User.BackupTest do
|
|||
Bookmark.create(user.id, status2.id)
|
||||
Bookmark.create(user.id, status3.id)
|
||||
|
||||
CommonAPI.follow(user, other_user)
|
||||
|
||||
assert {:ok, backup} = user |> Backup.new() |> Repo.insert()
|
||||
assert {:ok, path} = Backup.export(backup, self())
|
||||
assert {:ok, zipfile} = :zip.zip_open(String.to_charlist(path), [:memory])
|
||||
|
@ -261,6 +264,16 @@ defmodule Pleroma.User.BackupTest do
|
|||
"type" => "OrderedCollection"
|
||||
} = Jason.decode!(json)
|
||||
|
||||
assert {:ok, {'following.json', json}} = :zip.zip_get('following.json', zipfile)
|
||||
|
||||
assert %{
|
||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||
"id" => "following.json",
|
||||
"orderedItems" => [^other_ap_id],
|
||||
"totalItems" => 1,
|
||||
"type" => "OrderedCollection"
|
||||
} = Jason.decode!(json)
|
||||
|
||||
:zip.zip_close(zipfile)
|
||||
File.rm!(path)
|
||||
end
|
||||
|
|
|
@ -2928,4 +2928,51 @@ defmodule Pleroma.UserTest do
|
|||
refute User.endorses?(user, pinned_user)
|
||||
end
|
||||
end
|
||||
|
||||
test "it checks fields links for a backlink" do
|
||||
user = insert(:user, ap_id: "https://social.example.org/users/lain")
|
||||
|
||||
fields = [
|
||||
%{"name" => "Link", "value" => "http://example.com/rel_me/null"},
|
||||
%{"name" => "Verified link", "value" => "http://example.com/rel_me/link"},
|
||||
%{"name" => "Not a link", "value" => "i'm not a link"}
|
||||
]
|
||||
|
||||
user
|
||||
|> User.update_and_set_cache(%{raw_fields: fields})
|
||||
|
||||
ObanHelpers.perform_all()
|
||||
|
||||
user = User.get_cached_by_id(user.id)
|
||||
|
||||
assert [
|
||||
%{"verified_at" => nil},
|
||||
%{"verified_at" => verified_at},
|
||||
%{"verified_at" => nil}
|
||||
] = user.fields
|
||||
|
||||
assert is_binary(verified_at)
|
||||
end
|
||||
|
||||
test "updating fields does not invalidate previously validated links" do
|
||||
user = insert(:user, ap_id: "https://social.example.org/users/lain")
|
||||
|
||||
user
|
||||
|> User.update_and_set_cache(%{
|
||||
raw_fields: [%{"name" => "verified link", "value" => "http://example.com/rel_me/link"}]
|
||||
})
|
||||
|
||||
ObanHelpers.perform_all()
|
||||
|
||||
%User{fields: [%{"verified_at" => verified_at}]} = user = User.get_cached_by_id(user.id)
|
||||
|
||||
user
|
||||
|> User.update_and_set_cache(%{
|
||||
raw_fields: [%{"name" => "Verified link", "value" => "http://example.com/rel_me/link"}]
|
||||
})
|
||||
|
||||
user = User.get_cached_by_id(user.id)
|
||||
|
||||
assert [%{"verified_at" => ^verified_at}] = user.fields
|
||||
end
|
||||
end
|
||||
|
|
73
test/pleroma/web/activity_pub/mrf/force_mention_test.exs
Normal file
73
test/pleroma/web/activity_pub/mrf/force_mention_test.exs
Normal file
|
@ -0,0 +1,73 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionTest do
|
||||
use Pleroma.DataCase
|
||||
require Pleroma.Constants
|
||||
|
||||
alias Pleroma.Web.ActivityPub.MRF.ForceMention
|
||||
|
||||
import Pleroma.Factory
|
||||
|
||||
test "adds mention to a reply" do
|
||||
lain =
|
||||
insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain@lain.com", local: false)
|
||||
|
||||
niobleoum =
|
||||
insert(:user,
|
||||
ap_id: "https://www.minds.com/api/activitypub/users/1198929502760083472",
|
||||
nickname: "niobleoum@minds.com",
|
||||
local: false
|
||||
)
|
||||
|
||||
status = File.read!("test/fixtures/minds-pleroma-mentioned-post.json") |> Jason.decode!()
|
||||
|
||||
status_activity = %{
|
||||
"type" => "Create",
|
||||
"actor" => lain.ap_id,
|
||||
"object" => status
|
||||
}
|
||||
|
||||
Pleroma.Web.ActivityPub.Transmogrifier.handle_incoming(status_activity)
|
||||
|
||||
reply = File.read!("test/fixtures/minds-invalid-mention-post.json") |> Jason.decode!()
|
||||
|
||||
reply_activity = %{
|
||||
"type" => "Create",
|
||||
"actor" => niobleoum.ap_id,
|
||||
"object" => reply
|
||||
}
|
||||
|
||||
{:ok, %{"object" => %{"tag" => tag}}} = ForceMention.filter(reply_activity)
|
||||
|
||||
assert Enum.find(tag, fn %{"href" => href} -> href == lain.ap_id end)
|
||||
end
|
||||
|
||||
test "adds mention to a quote" do
|
||||
user1 = insert(:user, ap_id: "https://misskey.io/users/83ssedkv53")
|
||||
user2 = insert(:user, ap_id: "https://misskey.io/users/7rkrarq81i")
|
||||
|
||||
status = File.read!("test/fixtures/tesla_mock/misskey.io_8vs6wxufd0.json") |> Jason.decode!()
|
||||
|
||||
status_activity = %{
|
||||
"type" => "Create",
|
||||
"actor" => user1.ap_id,
|
||||
"object" => status
|
||||
}
|
||||
|
||||
Pleroma.Web.ActivityPub.Transmogrifier.handle_incoming(status_activity)
|
||||
|
||||
quote_post = File.read!("test/fixtures/quote_post/misskey_quote_post.json") |> Jason.decode!()
|
||||
|
||||
quote_activity = %{
|
||||
"type" => "Create",
|
||||
"actor" => user2.ap_id,
|
||||
"object" => quote_post
|
||||
}
|
||||
|
||||
{:ok, %{"object" => %{"tag" => tag}}} = ForceMention.filter(quote_activity)
|
||||
|
||||
assert Enum.find(tag, fn %{"href" => href} -> href == user1.ap_id end)
|
||||
end
|
||||
end
|
|
@ -25,6 +25,17 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
|
|||
|
||||
setup_all do: clear_config([:instance, :federating], true)
|
||||
|
||||
describe "should_federate?/1" do
|
||||
test "it returns false when the inbox is nil" do
|
||||
refute Publisher.should_federate?(nil, false)
|
||||
refute Publisher.should_federate?(nil, true)
|
||||
end
|
||||
|
||||
test "it returns true when public is true" do
|
||||
assert Publisher.should_federate?(false, true)
|
||||
end
|
||||
end
|
||||
|
||||
describe "gather_webfinger_links/1" do
|
||||
test "it returns links" do
|
||||
user = insert(:user)
|
||||
|
@ -205,6 +216,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
|
|||
refute called(Instances.set_reachable(inbox))
|
||||
end
|
||||
|
||||
@tag capture_log: true
|
||||
test_with_mock "calls `Instances.set_unreachable` on target inbox on non-2xx HTTP response code",
|
||||
Instances,
|
||||
[:passthrough],
|
||||
|
|
|
@ -107,6 +107,18 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do
|
|||
|> json_response_and_validate_schema(200)
|
||||
end
|
||||
|
||||
test "get instance contact information", %{conn: conn} do
|
||||
user = insert(:user, %{local: true})
|
||||
|
||||
clear_config([:instance, :contact_username], user.nickname)
|
||||
|
||||
conn = get(conn, "/api/v1/instance")
|
||||
|
||||
assert result = json_response_and_validate_schema(conn, 200)
|
||||
|
||||
assert result["contact_account"]["id"] == user.id
|
||||
end
|
||||
|
||||
test "get instance information v2", %{conn: conn} do
|
||||
clear_config([:auth, :oauth_consumer_strategies], [])
|
||||
|
||||
|
|
|
@ -511,10 +511,15 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
|
|||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert account_data["fields"] == [
|
||||
%{"name" => "<a href=\"http://google.com\">foo</a>", "value" => "bar"},
|
||||
%{
|
||||
"name" => "<a href=\"http://google.com\">foo</a>",
|
||||
"value" => "bar",
|
||||
"verified_at" => nil
|
||||
},
|
||||
%{
|
||||
"name" => "link.io",
|
||||
"value" => ~S(<a href="http://cofe.io" rel="ugc">cofe.io</a>)
|
||||
"value" => ~S(<a href="http://cofe.io" rel="ugc">cofe.io</a>),
|
||||
"verified_at" => nil
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -573,8 +578,8 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
|
|||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert account_data["fields"] == [
|
||||
%{"name" => ":firefox:", "value" => "is best 2hu"},
|
||||
%{"name" => "they wins", "value" => ":blank:"}
|
||||
%{"name" => ":firefox:", "value" => "is best 2hu", "verified_at" => nil},
|
||||
%{"name" => "they wins", "value" => ":blank:", "verified_at" => nil}
|
||||
]
|
||||
|
||||
assert account_data["source"]["fields"] == [
|
||||
|
@ -602,10 +607,11 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
|
|||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert account["fields"] == [
|
||||
%{"name" => "foo", "value" => "bar"},
|
||||
%{"name" => "foo", "value" => "bar", "verified_at" => nil},
|
||||
%{
|
||||
"name" => "link",
|
||||
"value" => ~S(<a href="http://cofe.io" rel="ugc">http://cofe.io</a>)
|
||||
"value" => ~S(<a href="http://cofe.io" rel="ugc">http://cofe.io</a>),
|
||||
"verified_at" => nil
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -627,7 +633,7 @@ defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
|
|||
|> json_response_and_validate_schema(200)
|
||||
|
||||
assert account["fields"] == [
|
||||
%{"name" => "foo", "value" => ""}
|
||||
%{"name" => "foo", "value" => "", "verified_at" => nil}
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -43,7 +43,8 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do
|
|||
%{title: "why are you even asking?", votes_count: 0}
|
||||
],
|
||||
votes_count: 0,
|
||||
voters_count: 0
|
||||
voters_count: 0,
|
||||
pleroma: %{non_anonymous: false}
|
||||
}
|
||||
|
||||
result = PollView.render("show.json", %{object: object})
|
||||
|
@ -165,4 +166,11 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do
|
|||
]
|
||||
} = PollView.render("show.json", %{object: object})
|
||||
end
|
||||
|
||||
test "that poll is non anonymous" do
|
||||
object = Object.normalize("https://friends.grishka.me/posts/54642", fetch: true)
|
||||
result = PollView.render("show.json", %{object: object})
|
||||
|
||||
assert result[:pleroma][:non_anonymous] == true
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1503,6 +1503,24 @@ defmodule HttpRequestMock do
|
|||
{:ok, %Tesla.Env{status: 200, body: "hello"}}
|
||||
end
|
||||
|
||||
def get("https://friends.grishka.me/posts/54642", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: File.read!("test/fixtures/tesla_mock/smithereen_non_anonymous_poll.json"),
|
||||
headers: activitypub_object_headers()
|
||||
}}
|
||||
end
|
||||
|
||||
def get("https://friends.grishka.me/users/1", _, _, _) do
|
||||
{:ok,
|
||||
%Tesla.Env{
|
||||
status: 200,
|
||||
body: File.read!("test/fixtures/tesla_mock/smithereen_user.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 a new issue