Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into qdrant-search-2
This commit is contained in:
commit
f726e5fbbd
|
@ -0,0 +1 @@
|
||||||
|
Implement `/api/v1/accounts/familiar_followers`
|
|
@ -0,0 +1 @@
|
||||||
|
Fix webfinger spoofing.
|
|
@ -0,0 +1 @@
|
||||||
|
Add "status" notification type
|
|
@ -0,0 +1 @@
|
||||||
|
Fix validate_webfinger when running a different domain for Webfinger
|
|
@ -162,7 +162,8 @@ defp cachex_children do
|
||||||
expiration: chat_message_id_idempotency_key_expiration(),
|
expiration: chat_message_id_idempotency_key_expiration(),
|
||||||
limit: 500_000
|
limit: 500_000
|
||||||
),
|
),
|
||||||
build_cachex("rel_me", limit: 2500)
|
build_cachex("rel_me", limit: 2500),
|
||||||
|
build_cachex("host_meta", default_ttl: :timer.minutes(120), limit: 5000)
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ def unread_notifications_count(%User{id: user_id}) do
|
||||||
pleroma:report
|
pleroma:report
|
||||||
reblog
|
reblog
|
||||||
poll
|
poll
|
||||||
|
status
|
||||||
}
|
}
|
||||||
|
|
||||||
def changeset(%Notification{} = notification, attrs) do
|
def changeset(%Notification{} = notification, attrs) do
|
||||||
|
@ -375,10 +376,15 @@ def create_notifications(_), do: {:ok, []}
|
||||||
defp do_create_notifications(%Activity{} = activity) do
|
defp do_create_notifications(%Activity{} = activity) do
|
||||||
enabled_receivers = get_notified_from_activity(activity)
|
enabled_receivers = get_notified_from_activity(activity)
|
||||||
|
|
||||||
|
enabled_subscribers = get_notified_subscribers_from_activity(activity)
|
||||||
|
|
||||||
notifications =
|
notifications =
|
||||||
Enum.map(enabled_receivers, fn user ->
|
(Enum.map(enabled_receivers, fn user ->
|
||||||
create_notification(activity, user)
|
create_notification(activity, user)
|
||||||
end)
|
end) ++
|
||||||
|
Enum.map(enabled_subscribers -- enabled_receivers, fn user ->
|
||||||
|
create_notification(activity, user, type: "status")
|
||||||
|
end))
|
||||||
|> Enum.reject(&is_nil/1)
|
|> Enum.reject(&is_nil/1)
|
||||||
|
|
||||||
{:ok, notifications}
|
{:ok, notifications}
|
||||||
|
@ -511,7 +517,25 @@ def get_notified_from_activity(%Activity{data: %{"type" => type}} = activity, lo
|
||||||
Enum.filter(potential_receivers, fn u -> u.ap_id in notification_enabled_ap_ids end)
|
Enum.filter(potential_receivers, fn u -> u.ap_id in notification_enabled_ap_ids end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_notified_from_activity(_, _local_only), do: {[], []}
|
def get_notified_from_activity(_, _local_only), do: []
|
||||||
|
|
||||||
|
def get_notified_subscribers_from_activity(activity, local_only \\ true)
|
||||||
|
|
||||||
|
def get_notified_subscribers_from_activity(
|
||||||
|
%Activity{data: %{"type" => "Create"}} = activity,
|
||||||
|
local_only
|
||||||
|
) do
|
||||||
|
notification_enabled_ap_ids =
|
||||||
|
[]
|
||||||
|
|> Utils.maybe_notify_subscribers(activity)
|
||||||
|
|
||||||
|
potential_receivers =
|
||||||
|
User.get_users_from_set(notification_enabled_ap_ids, local_only: local_only)
|
||||||
|
|
||||||
|
Enum.filter(potential_receivers, fn u -> u.ap_id in notification_enabled_ap_ids end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_notified_subscribers_from_activity(_, _), do: []
|
||||||
|
|
||||||
# For some activities, only notify the author of the object
|
# For some activities, only notify the author of the object
|
||||||
def get_potential_receiver_ap_ids(%{data: %{"type" => type, "object" => object_id}})
|
def get_potential_receiver_ap_ids(%{data: %{"type" => type, "object" => object_id}})
|
||||||
|
@ -554,7 +578,6 @@ def get_potential_receiver_ap_ids(activity) do
|
||||||
[]
|
[]
|
||||||
|> Utils.maybe_notify_to_recipients(activity)
|
|> Utils.maybe_notify_to_recipients(activity)
|
||||||
|> Utils.maybe_notify_mentioned_recipients(activity)
|
|> Utils.maybe_notify_mentioned_recipients(activity)
|
||||||
|> Utils.maybe_notify_subscribers(activity)
|
|
||||||
|> Utils.maybe_notify_followers(activity)
|
|> Utils.maybe_notify_followers(activity)
|
||||||
|> Enum.uniq()
|
|> Enum.uniq()
|
||||||
end
|
end
|
||||||
|
|
|
@ -1404,6 +1404,40 @@ def get_friends_ids(%User{} = user, page \\ nil) do
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec get_familiar_followers_query(User.t(), User.t(), pos_integer() | nil) :: Ecto.Query.t()
|
||||||
|
def get_familiar_followers_query(%User{} = user, %User{} = current_user, nil) do
|
||||||
|
friends =
|
||||||
|
get_friends_query(current_user)
|
||||||
|
|> where([u], not u.hide_follows)
|
||||||
|
|> select([u], u.id)
|
||||||
|
|
||||||
|
User.Query.build(%{is_active: true})
|
||||||
|
|> where([u], u.id not in ^[user.id, current_user.id])
|
||||||
|
|> join(:inner, [u], r in FollowingRelationship,
|
||||||
|
as: :followers_relationships,
|
||||||
|
on: r.following_id == ^user.id and r.follower_id == u.id
|
||||||
|
)
|
||||||
|
|> where([followers_relationships: r], r.state == ^:follow_accept)
|
||||||
|
|> where([followers_relationships: r], r.follower_id in subquery(friends))
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_familiar_followers_query(%User{} = user, %User{} = current_user, page) do
|
||||||
|
user
|
||||||
|
|> get_familiar_followers_query(current_user, nil)
|
||||||
|
|> User.Query.paginate(page, 20)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec get_familiar_followers_query(User.t(), User.t()) :: Ecto.Query.t()
|
||||||
|
def get_familiar_followers_query(%User{} = user, %User{} = current_user),
|
||||||
|
do: get_familiar_followers_query(user, current_user, nil)
|
||||||
|
|
||||||
|
@spec get_familiar_followers(User.t(), User.t(), pos_integer() | nil) :: {:ok, list(User.t())}
|
||||||
|
def get_familiar_followers(%User{} = user, %User{} = current_user, page \\ nil) do
|
||||||
|
user
|
||||||
|
|> get_familiar_followers_query(current_user, page)
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
|
|
||||||
def increase_note_count(%User{} = user) do
|
def increase_note_count(%User{} = user) do
|
||||||
User
|
User
|
||||||
|> where(id: ^user.id)
|
|> where(id: ^user.id)
|
||||||
|
|
|
@ -11,6 +11,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.ActorType
|
alias Pleroma.Web.ApiSpec.Schemas.ActorType
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
|
alias Pleroma.Web.ApiSpec.Schemas.BooleanLike
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.List
|
alias Pleroma.Web.ApiSpec.Schemas.List
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.Status
|
alias Pleroma.Web.ApiSpec.Schemas.Status
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
|
alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
|
||||||
|
@ -513,6 +514,48 @@ def identity_proofs_operation do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def familiar_followers_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["Retrieve account information"],
|
||||||
|
summary: "Followers that you follow",
|
||||||
|
operationId: "AccountController.familiar_followers",
|
||||||
|
description:
|
||||||
|
"Obtain a list of all accounts that follow a given account, filtered for accounts you follow.",
|
||||||
|
security: [%{"oAuth" => ["read:follows"]}],
|
||||||
|
parameters: [
|
||||||
|
Operation.parameter(
|
||||||
|
:id,
|
||||||
|
:query,
|
||||||
|
%Schema{
|
||||||
|
oneOf: [%Schema{type: :array, items: %Schema{type: :string}}, %Schema{type: :string}]
|
||||||
|
},
|
||||||
|
"Account IDs",
|
||||||
|
example: "123"
|
||||||
|
)
|
||||||
|
],
|
||||||
|
responses: %{
|
||||||
|
200 =>
|
||||||
|
Operation.response("Accounts", "application/json", %Schema{
|
||||||
|
title: "ArrayOfAccounts",
|
||||||
|
type: :array,
|
||||||
|
items: %Schema{
|
||||||
|
title: "Account",
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
id: FlakeID,
|
||||||
|
accounts: %Schema{
|
||||||
|
title: "ArrayOfAccounts",
|
||||||
|
type: :array,
|
||||||
|
items: Account,
|
||||||
|
example: [Account.schema().example]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
defp create_request do
|
defp create_request do
|
||||||
%Schema{
|
%Schema{
|
||||||
title: "AccountCreateRequest",
|
title: "AccountCreateRequest",
|
||||||
|
|
|
@ -202,7 +202,8 @@ defp notification_type do
|
||||||
"pleroma:report",
|
"pleroma:report",
|
||||||
"move",
|
"move",
|
||||||
"follow_request",
|
"follow_request",
|
||||||
"poll"
|
"poll",
|
||||||
|
"status"
|
||||||
],
|
],
|
||||||
description: """
|
description: """
|
||||||
The type of event that resulted in the notification.
|
The type of event that resulted in the notification.
|
||||||
|
@ -216,6 +217,7 @@ defp notification_type do
|
||||||
- `pleroma:emoji_reaction` - Someone reacted with emoji to your status
|
- `pleroma:emoji_reaction` - Someone reacted with emoji to your status
|
||||||
- `pleroma:chat_mention` - Someone mentioned you in a chat message
|
- `pleroma:chat_mention` - Someone mentioned you in a chat message
|
||||||
- `pleroma:report` - Someone was reported
|
- `pleroma:report` - Someone was reported
|
||||||
|
- `status` - Someone you are subscribed to created a status
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -72,7 +72,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||||
%{scopes: ["follow", "write:blocks"]} when action in [:block, :unblock]
|
%{scopes: ["follow", "write:blocks"]} when action in [:block, :unblock]
|
||||||
)
|
)
|
||||||
|
|
||||||
plug(OAuthScopesPlug, %{scopes: ["read:follows"]} when action == :relationships)
|
plug(
|
||||||
|
OAuthScopesPlug,
|
||||||
|
%{scopes: ["read:follows"]} when action in [:relationships, :familiar_followers]
|
||||||
|
)
|
||||||
|
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
|
@ -629,6 +632,35 @@ def endorsements(%{assigns: %{user: user}} = conn, params) do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc "GET /api/v1/accounts/familiar_followers"
|
||||||
|
def familiar_followers(
|
||||||
|
%{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn,
|
||||||
|
_id
|
||||||
|
) do
|
||||||
|
users =
|
||||||
|
User.get_all_by_ids(List.wrap(id))
|
||||||
|
|> Enum.map(&%{id: &1.id, accounts: get_familiar_followers(&1, user)})
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> render("familiar_followers.json",
|
||||||
|
for: user,
|
||||||
|
users: users,
|
||||||
|
as: :user
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_familiar_followers(%{id: id} = user, %{id: id}) do
|
||||||
|
User.get_familiar_followers(user, user)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_familiar_followers(%{hide_followers: true}, _current_user) do
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_familiar_followers(user, current_user) do
|
||||||
|
User.get_familiar_followers(user, current_user)
|
||||||
|
end
|
||||||
|
|
||||||
@doc "GET /api/v1/identity_proofs"
|
@doc "GET /api/v1/identity_proofs"
|
||||||
def identity_proofs(conn, params), do: MastodonAPIController.empty_array(conn, params)
|
def identity_proofs(conn, params), do: MastodonAPIController.empty_array(conn, params)
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,6 +34,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
|
||||||
pleroma:emoji_reaction
|
pleroma:emoji_reaction
|
||||||
poll
|
poll
|
||||||
update
|
update
|
||||||
|
status
|
||||||
}
|
}
|
||||||
|
|
||||||
# GET /api/v1/notifications
|
# GET /api/v1/notifications
|
||||||
|
|
|
@ -193,6 +193,25 @@ def render("relationships.json", %{user: user, targets: targets} = opts) do
|
||||||
render_many(targets, AccountView, "relationship.json", render_opts)
|
render_many(targets, AccountView, "relationship.json", render_opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def render("familiar_followers.json", %{users: users} = opts) do
|
||||||
|
opts =
|
||||||
|
opts
|
||||||
|
|> Map.merge(%{as: :user})
|
||||||
|
|> Map.delete(:users)
|
||||||
|
|
||||||
|
users
|
||||||
|
|> render_many(AccountView, "familiar_followers.json", opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def render("familiar_followers.json", %{user: %{id: id, accounts: accounts}} = opts) do
|
||||||
|
accounts =
|
||||||
|
accounts
|
||||||
|
|> render_many(AccountView, "show.json", opts)
|
||||||
|
|> Enum.filter(&Enum.any?/1)
|
||||||
|
|
||||||
|
%{id: id, accounts: accounts}
|
||||||
|
end
|
||||||
|
|
||||||
defp do_render("show.json", %{user: user} = opts) do
|
defp do_render("show.json", %{user: user} = opts) do
|
||||||
self = opts[:for] == user
|
self = opts[:for] == user
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,9 @@ def render(
|
||||||
"mention" ->
|
"mention" ->
|
||||||
put_status(response, activity, reading_user, status_render_opts)
|
put_status(response, activity, reading_user, status_render_opts)
|
||||||
|
|
||||||
|
"status" ->
|
||||||
|
put_status(response, activity, reading_user, status_render_opts)
|
||||||
|
|
||||||
"favourite" ->
|
"favourite" ->
|
||||||
put_status(response, parent_activity_fn.(), reading_user, status_render_opts)
|
put_status(response, parent_activity_fn.(), reading_user, status_render_opts)
|
||||||
|
|
||||||
|
|
|
@ -192,6 +192,7 @@ def format_title(%{activity: %{data: %{"directMessage" => true}}}, _mastodon_typ
|
||||||
def format_title(%{type: type}, mastodon_type) do
|
def format_title(%{type: type}, mastodon_type) do
|
||||||
case mastodon_type || type do
|
case mastodon_type || type do
|
||||||
"mention" -> "New Mention"
|
"mention" -> "New Mention"
|
||||||
|
"status" -> "New Status"
|
||||||
"follow" -> "New Follower"
|
"follow" -> "New Follower"
|
||||||
"follow_request" -> "New Follow Request"
|
"follow_request" -> "New Follow Request"
|
||||||
"reblog" -> "New Repeat"
|
"reblog" -> "New Repeat"
|
||||||
|
|
|
@ -638,6 +638,7 @@ defmodule Pleroma.Web.Router do
|
||||||
patch("/accounts/update_credentials", AccountController, :update_credentials)
|
patch("/accounts/update_credentials", AccountController, :update_credentials)
|
||||||
|
|
||||||
get("/accounts/relationships", AccountController, :relationships)
|
get("/accounts/relationships", AccountController, :relationships)
|
||||||
|
get("/accounts/familiar_followers", AccountController, :familiar_followers)
|
||||||
get("/accounts/:id/lists", AccountController, :lists)
|
get("/accounts/:id/lists", AccountController, :lists)
|
||||||
get("/accounts/:id/identity_proofs", AccountController, :identity_proofs)
|
get("/accounts/:id/identity_proofs", AccountController, :identity_proofs)
|
||||||
get("/endorsements", AccountController, :endorsements)
|
get("/endorsements", AccountController, :endorsements)
|
||||||
|
|
|
@ -155,7 +155,16 @@ def get_template_from_xml(body) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
|
||||||
def find_lrdd_template(domain) do
|
def find_lrdd_template(domain) do
|
||||||
|
@cachex.fetch!(:host_meta_cache, domain, fn _ ->
|
||||||
|
{:commit, fetch_lrdd_template(domain)}
|
||||||
|
end)
|
||||||
|
rescue
|
||||||
|
e -> {:error, "Cachex error: #{inspect(e)}"}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp fetch_lrdd_template(domain) do
|
||||||
# WebFinger is restricted to HTTPS - https://tools.ietf.org/html/rfc7033#section-9.1
|
# WebFinger is restricted to HTTPS - https://tools.ietf.org/html/rfc7033#section-9.1
|
||||||
meta_url = "https://#{domain}/.well-known/host-meta"
|
meta_url = "https://#{domain}/.well-known/host-meta"
|
||||||
|
|
||||||
|
@ -168,7 +177,7 @@ def find_lrdd_template(domain) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_address_from_domain(domain, encoded_account) when is_binary(domain) do
|
defp get_address_from_domain(domain, "acct:" <> _ = encoded_account) when is_binary(domain) do
|
||||||
case find_lrdd_template(domain) do
|
case find_lrdd_template(domain) do
|
||||||
{:ok, template} ->
|
{:ok, template} ->
|
||||||
String.replace(template, "{uri}", encoded_account)
|
String.replace(template, "{uri}", encoded_account)
|
||||||
|
@ -178,6 +187,11 @@ defp get_address_from_domain(domain, encoded_account) when is_binary(domain) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp get_address_from_domain(domain, account) when is_binary(domain) do
|
||||||
|
encoded_account = URI.encode("acct:#{account}")
|
||||||
|
get_address_from_domain(domain, encoded_account)
|
||||||
|
end
|
||||||
|
|
||||||
defp get_address_from_domain(_, _), do: {:error, :webfinger_no_domain}
|
defp get_address_from_domain(_, _), do: {:error, :webfinger_no_domain}
|
||||||
|
|
||||||
@spec finger(String.t()) :: {:ok, map()} | {:error, any()}
|
@spec finger(String.t()) :: {:ok, map()} | {:error, any()}
|
||||||
|
@ -192,9 +206,7 @@ def finger(account) do
|
||||||
URI.parse(account).host
|
URI.parse(account).host
|
||||||
end
|
end
|
||||||
|
|
||||||
encoded_account = URI.encode("acct:#{account}")
|
with address when is_binary(address) <- get_address_from_domain(domain, account),
|
||||||
|
|
||||||
with address when is_binary(address) <- get_address_from_domain(domain, encoded_account),
|
|
||||||
{:ok, %{status: status, body: body, headers: headers}} when status in 200..299 <-
|
{:ok, %{status: status, body: body, headers: headers}} when status in 200..299 <-
|
||||||
HTTP.get(
|
HTTP.get(
|
||||||
address,
|
address,
|
||||||
|
@ -216,10 +228,28 @@ def finger(account) do
|
||||||
_ ->
|
_ ->
|
||||||
{:error, {:content_type, nil}}
|
{:error, {:content_type, nil}}
|
||||||
end
|
end
|
||||||
|
|> case do
|
||||||
|
{:ok, data} -> validate_webfinger(address, data)
|
||||||
|
error -> error
|
||||||
|
end
|
||||||
else
|
else
|
||||||
error ->
|
error ->
|
||||||
Logger.debug("Couldn't finger #{account}: #{inspect(error)}")
|
Logger.debug("Couldn't finger #{account}: #{inspect(error)}")
|
||||||
error
|
error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp validate_webfinger(request_url, %{"subject" => "acct:" <> acct = subject} = data) do
|
||||||
|
with [_name, acct_host] <- String.split(acct, "@"),
|
||||||
|
{_, url} <- {:address, get_address_from_domain(acct_host, subject)},
|
||||||
|
%URI{host: request_host} <- URI.parse(request_url),
|
||||||
|
%URI{host: acct_host} <- URI.parse(url),
|
||||||
|
{_, true} <- {:hosts_match, acct_host == request_host} do
|
||||||
|
{:ok, data}
|
||||||
|
else
|
||||||
|
_ -> {:error, {:webfinger_invalid, request_url, data}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp validate_webfinger(url, data), do: {:error, {:webfinger_invalid, url, data}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.AddStatusToNotificationsEnum do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
@disable_ddl_transaction true
|
||||||
|
|
||||||
|
def up do
|
||||||
|
"""
|
||||||
|
alter type notification_type add value 'status'
|
||||||
|
"""
|
||||||
|
|> execute()
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
alter table(:notifications) do
|
||||||
|
modify(:type, :string)
|
||||||
|
end
|
||||||
|
|
||||||
|
"""
|
||||||
|
delete from notifications where type = 'status'
|
||||||
|
"""
|
||||||
|
|> execute()
|
||||||
|
|
||||||
|
"""
|
||||||
|
drop type if exists notification_type
|
||||||
|
"""
|
||||||
|
|> execute()
|
||||||
|
|
||||||
|
"""
|
||||||
|
create type notification_type as enum (
|
||||||
|
'follow',
|
||||||
|
'follow_request',
|
||||||
|
'mention',
|
||||||
|
'move',
|
||||||
|
'pleroma:emoji_reaction',
|
||||||
|
'pleroma:chat_mention',
|
||||||
|
'reblog',
|
||||||
|
'favourite',
|
||||||
|
'pleroma:report',
|
||||||
|
'poll',
|
||||||
|
'update'
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|> execute()
|
||||||
|
|
||||||
|
"""
|
||||||
|
alter table notifications
|
||||||
|
alter column type type notification_type using (type::notification_type)
|
||||||
|
"""
|
||||||
|
|> execute()
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
|
||||||
|
<Link rel="lrdd" template="https://gleasonator.com/.well-known/webfinger?resource={uri}" type="application/xrd+xml" />
|
||||||
|
</XRD>
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"aliases": [
|
||||||
|
"https://gleasonator.com/users/alex",
|
||||||
|
"https://mitra.social/users/alex"
|
||||||
|
],
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "https://gleasonator.com/users/alex",
|
||||||
|
"rel": "http://webfinger.net/rel/profile-page",
|
||||||
|
"type": "text/html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://gleasonator.com/users/alex",
|
||||||
|
"rel": "self",
|
||||||
|
"type": "application/activity+json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://gleasonator.com/users/alex",
|
||||||
|
"rel": "self",
|
||||||
|
"type": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://ostatus.org/schema/1.0/subscribe",
|
||||||
|
"template": "https://gleasonator.com/ostatus_subscribe?acct={uri}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"subject": "acct:trump@whitehouse.gov"
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"subject": "acct:graf@poa.st",
|
||||||
|
"aliases": [
|
||||||
|
"https://fba.ryona.agenc/webfingertest"
|
||||||
|
],
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"rel": "http://webfinger.net/rel/profile-page",
|
||||||
|
"type": "text/html",
|
||||||
|
"href": "https://fba.ryona.agenc/webfingertest"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "self",
|
||||||
|
"type": "application/activity+json",
|
||||||
|
"href": "https://fba.ryona.agenc/webfingertest"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://ostatus.org/schema/1.0/subscribe",
|
||||||
|
"template": "https://fba.ryona.agenc/contact/follow?url={uri}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://schemas.google.com/g/2010#updates-from",
|
||||||
|
"type": "application/atom+xml",
|
||||||
|
"href": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "salmon",
|
||||||
|
"href": "https://fba.ryona.agenc/salmon/friendica"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://microformats.org/profile/hcard",
|
||||||
|
"type": "text/html",
|
||||||
|
"href": "https://fba.ryona.agenc/hcard/friendica"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rel": "http://joindiaspora.com/seed_location",
|
||||||
|
"type": "text/html",
|
||||||
|
"href": "https://fba.ryona.agenc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -112,6 +112,7 @@ test "it creates a notification for subscribed users" do
|
||||||
{:ok, [notification]} = Notification.create_notifications(status)
|
{:ok, [notification]} = Notification.create_notifications(status)
|
||||||
|
|
||||||
assert notification.user_id == subscriber.id
|
assert notification.user_id == subscriber.id
|
||||||
|
assert notification.type == "status"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "does not create a notification for subscribed users if status is a reply" do
|
test "does not create a notification for subscribed users if status is a reply" do
|
||||||
|
@ -136,6 +137,21 @@ test "does not create a notification for subscribed users if status is a reply"
|
||||||
assert Enum.empty?(subscriber_notifications)
|
assert Enum.empty?(subscriber_notifications)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "does not create subscriber notification if mentioned" do
|
||||||
|
user = insert(:user)
|
||||||
|
subscriber = insert(:user)
|
||||||
|
|
||||||
|
User.subscribe(subscriber, user)
|
||||||
|
|
||||||
|
{:ok, status} = CommonAPI.post(user, %{status: "mentioning @#{subscriber.nickname}"})
|
||||||
|
{:ok, [notification] = notifications} = Notification.create_notifications(status)
|
||||||
|
|
||||||
|
assert length(notifications) == 1
|
||||||
|
|
||||||
|
assert notification.user_id == subscriber.id
|
||||||
|
assert notification.type == "mention"
|
||||||
|
end
|
||||||
|
|
||||||
test "it sends edited notifications to those who repeated a status" do
|
test "it sends edited notifications to those who repeated a status" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
repeated_user = insert(:user)
|
repeated_user = insert(:user)
|
||||||
|
|
|
@ -877,109 +877,19 @@ test "gets an existing user by nickname starting with http" do
|
||||||
setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true)
|
setup do: clear_config([Pleroma.Web.WebFinger, :update_nickname_on_user_fetch], true)
|
||||||
|
|
||||||
test "for mastodon" do
|
test "for mastodon" do
|
||||||
Tesla.Mock.mock(fn
|
ap_id = "a@mastodon.example"
|
||||||
%{url: "https://example.com/.well-known/host-meta"} ->
|
|
||||||
%Tesla.Env{
|
|
||||||
status: 302,
|
|
||||||
headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
|
|
||||||
}
|
|
||||||
|
|
||||||
%{url: "https://sub.example.com/.well-known/host-meta"} ->
|
|
||||||
%Tesla.Env{
|
|
||||||
status: 200,
|
|
||||||
body:
|
|
||||||
"test/fixtures/webfinger/masto-host-meta.xml"
|
|
||||||
|> File.read!()
|
|
||||||
|> String.replace("{{domain}}", "sub.example.com")
|
|
||||||
}
|
|
||||||
|
|
||||||
%{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
|
|
||||||
%Tesla.Env{
|
|
||||||
status: 200,
|
|
||||||
body:
|
|
||||||
"test/fixtures/webfinger/masto-webfinger.json"
|
|
||||||
|> File.read!()
|
|
||||||
|> String.replace("{{nickname}}", "a")
|
|
||||||
|> String.replace("{{domain}}", "example.com")
|
|
||||||
|> String.replace("{{subdomain}}", "sub.example.com"),
|
|
||||||
headers: [{"content-type", "application/jrd+json"}]
|
|
||||||
}
|
|
||||||
|
|
||||||
%{url: "https://sub.example.com/users/a"} ->
|
|
||||||
%Tesla.Env{
|
|
||||||
status: 200,
|
|
||||||
body:
|
|
||||||
"test/fixtures/webfinger/masto-user.json"
|
|
||||||
|> File.read!()
|
|
||||||
|> String.replace("{{nickname}}", "a")
|
|
||||||
|> String.replace("{{domain}}", "sub.example.com"),
|
|
||||||
headers: [{"content-type", "application/activity+json"}]
|
|
||||||
}
|
|
||||||
|
|
||||||
%{url: "https://sub.example.com/users/a/collections/featured"} ->
|
|
||||||
%Tesla.Env{
|
|
||||||
status: 200,
|
|
||||||
body:
|
|
||||||
File.read!("test/fixtures/users_mock/masto_featured.json")
|
|
||||||
|> String.replace("{{domain}}", "sub.example.com")
|
|
||||||
|> String.replace("{{nickname}}", "a"),
|
|
||||||
headers: [{"content-type", "application/activity+json"}]
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
|
|
||||||
ap_id = "a@example.com"
|
|
||||||
{:ok, fetched_user} = User.get_or_fetch(ap_id)
|
{:ok, fetched_user} = User.get_or_fetch(ap_id)
|
||||||
|
|
||||||
assert fetched_user.ap_id == "https://sub.example.com/users/a"
|
assert fetched_user.ap_id == "https://sub.mastodon.example/users/a"
|
||||||
assert fetched_user.nickname == "a@example.com"
|
assert fetched_user.nickname == "a@mastodon.example"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "for pleroma" do
|
test "for pleroma" do
|
||||||
Tesla.Mock.mock(fn
|
ap_id = "a@pleroma.example"
|
||||||
%{url: "https://example.com/.well-known/host-meta"} ->
|
|
||||||
%Tesla.Env{
|
|
||||||
status: 302,
|
|
||||||
headers: [{"location", "https://sub.example.com/.well-known/host-meta"}]
|
|
||||||
}
|
|
||||||
|
|
||||||
%{url: "https://sub.example.com/.well-known/host-meta"} ->
|
|
||||||
%Tesla.Env{
|
|
||||||
status: 200,
|
|
||||||
body:
|
|
||||||
"test/fixtures/webfinger/pleroma-host-meta.xml"
|
|
||||||
|> File.read!()
|
|
||||||
|> String.replace("{{domain}}", "sub.example.com")
|
|
||||||
}
|
|
||||||
|
|
||||||
%{url: "https://sub.example.com/.well-known/webfinger?resource=acct:a@example.com"} ->
|
|
||||||
%Tesla.Env{
|
|
||||||
status: 200,
|
|
||||||
body:
|
|
||||||
"test/fixtures/webfinger/pleroma-webfinger.json"
|
|
||||||
|> File.read!()
|
|
||||||
|> String.replace("{{nickname}}", "a")
|
|
||||||
|> String.replace("{{domain}}", "example.com")
|
|
||||||
|> String.replace("{{subdomain}}", "sub.example.com"),
|
|
||||||
headers: [{"content-type", "application/jrd+json"}]
|
|
||||||
}
|
|
||||||
|
|
||||||
%{url: "https://sub.example.com/users/a"} ->
|
|
||||||
%Tesla.Env{
|
|
||||||
status: 200,
|
|
||||||
body:
|
|
||||||
"test/fixtures/webfinger/pleroma-user.json"
|
|
||||||
|> File.read!()
|
|
||||||
|> String.replace("{{nickname}}", "a")
|
|
||||||
|> String.replace("{{domain}}", "sub.example.com"),
|
|
||||||
headers: [{"content-type", "application/activity+json"}]
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
|
|
||||||
ap_id = "a@example.com"
|
|
||||||
{:ok, fetched_user} = User.get_or_fetch(ap_id)
|
{:ok, fetched_user} = User.get_or_fetch(ap_id)
|
||||||
|
|
||||||
assert fetched_user.ap_id == "https://sub.example.com/users/a"
|
assert fetched_user.ap_id == "https://sub.pleroma.example/users/a"
|
||||||
assert fetched_user.nickname == "a@example.com"
|
assert fetched_user.nickname == "a@pleroma.example"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2894,6 +2804,20 @@ test "should report error on non-existing alias" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "get_familiar_followers/3" do
|
||||||
|
test "returns familiar followers for a pair of users" do
|
||||||
|
user1 = insert(:user)
|
||||||
|
%{id: id2} = user2 = insert(:user)
|
||||||
|
user3 = insert(:user)
|
||||||
|
_user4 = insert(:user)
|
||||||
|
|
||||||
|
User.follow(user1, user2)
|
||||||
|
User.follow(user2, user3)
|
||||||
|
|
||||||
|
assert [%{id: ^id2}] = User.get_familiar_followers(user3, user1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "account endorsements" do
|
describe "account endorsements" do
|
||||||
test "it pins people" do
|
test "it pins people" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
|
@ -2172,6 +2172,55 @@ test "max pinned accounts", %{user: user, conn: conn} do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "familiar followers" do
|
||||||
|
setup do: oauth_access(["read:follows"])
|
||||||
|
|
||||||
|
test "fetch user familiar followers", %{user: user, conn: conn} do
|
||||||
|
%{id: id1} = other_user1 = insert(:user)
|
||||||
|
%{id: id2} = other_user2 = insert(:user)
|
||||||
|
_ = insert(:user)
|
||||||
|
|
||||||
|
User.follow(user, other_user1)
|
||||||
|
User.follow(other_user1, other_user2)
|
||||||
|
|
||||||
|
assert [%{"accounts" => [%{"id" => ^id1}], "id" => ^id2}] =
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> get("/api/v1/accounts/familiar_followers?id[]=#{id2}")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns empty array if followers are hidden", %{user: user, conn: conn} do
|
||||||
|
other_user1 = insert(:user, hide_follows: true)
|
||||||
|
%{id: id2} = other_user2 = insert(:user)
|
||||||
|
_ = insert(:user)
|
||||||
|
|
||||||
|
User.follow(user, other_user1)
|
||||||
|
User.follow(other_user1, other_user2)
|
||||||
|
|
||||||
|
assert [%{"accounts" => [], "id" => ^id2}] =
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> get("/api/v1/accounts/familiar_followers?id[]=#{id2}")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it respects hide_followers", %{user: user, conn: conn} do
|
||||||
|
other_user1 = insert(:user)
|
||||||
|
%{id: id2} = other_user2 = insert(:user, hide_followers: true)
|
||||||
|
_ = insert(:user)
|
||||||
|
|
||||||
|
User.follow(user, other_user1)
|
||||||
|
User.follow(other_user1, other_user2)
|
||||||
|
|
||||||
|
assert [%{"accounts" => [], "id" => ^id2}] =
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> get("/api/v1/accounts/familiar_followers?id[]=#{id2}")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "remove from followers" do
|
describe "remove from followers" do
|
||||||
setup do: oauth_access(["follow"])
|
setup do: oauth_access(["follow"])
|
||||||
|
|
||||||
|
|
|
@ -331,4 +331,31 @@ test "muted notification" do
|
||||||
|
|
||||||
test_notifications_rendering([notification], user, [expected])
|
test_notifications_rendering([notification], user, [expected])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "Subscribed status notification" do
|
||||||
|
user = insert(:user)
|
||||||
|
subscriber = insert(:user)
|
||||||
|
|
||||||
|
User.subscribe(subscriber, user)
|
||||||
|
|
||||||
|
{:ok, activity} = CommonAPI.post(user, %{status: "hi"})
|
||||||
|
{:ok, [notification]} = Notification.create_notifications(activity)
|
||||||
|
|
||||||
|
user = User.get_cached_by_id(user.id)
|
||||||
|
|
||||||
|
expected = %{
|
||||||
|
id: to_string(notification.id),
|
||||||
|
pleroma: %{is_seen: false, is_muted: false},
|
||||||
|
type: "status",
|
||||||
|
account:
|
||||||
|
AccountView.render("show.json", %{
|
||||||
|
user: user,
|
||||||
|
for: subscriber
|
||||||
|
}),
|
||||||
|
status: StatusView.render("show.json", %{activity: activity, for: subscriber}),
|
||||||
|
created_at: Utils.to_masto_date(notification.inserted_at)
|
||||||
|
}
|
||||||
|
|
||||||
|
test_notifications_rendering([notification], subscriber, [expected])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -76,15 +76,6 @@ test "returns the ActivityPub actor URI for an ActivityPub user" do
|
||||||
{:ok, _data} = WebFinger.finger(user)
|
{:ok, _data} = WebFinger.finger(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns the ActivityPub actor URI and subscribe address for an ActivityPub user with the ld+json mimetype" do
|
|
||||||
user = "kaniini@gerzilla.de"
|
|
||||||
|
|
||||||
{:ok, data} = WebFinger.finger(user)
|
|
||||||
|
|
||||||
assert data["ap_id"] == "https://gerzilla.de/channel/kaniini"
|
|
||||||
assert data["subscribe_address"] == "https://gerzilla.de/follow?f=&url={uri}"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it work for AP-only user" do
|
test "it work for AP-only user" do
|
||||||
user = "kpherox@mstdn.jp"
|
user = "kpherox@mstdn.jp"
|
||||||
|
|
||||||
|
@ -99,12 +90,6 @@ test "it work for AP-only user" do
|
||||||
assert data["subscribe_address"] == "https://mstdn.jp/authorize_interaction?acct={uri}"
|
assert data["subscribe_address"] == "https://mstdn.jp/authorize_interaction?acct={uri}"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it works for friendica" do
|
|
||||||
user = "lain@squeet.me"
|
|
||||||
|
|
||||||
{:ok, _data} = WebFinger.finger(user)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it gets the xrd endpoint" do
|
test "it gets the xrd endpoint" do
|
||||||
{:ok, template} = WebFinger.find_lrdd_template("social.heldscal.la")
|
{:ok, template} = WebFinger.find_lrdd_template("social.heldscal.la")
|
||||||
|
|
||||||
|
@ -203,5 +188,44 @@ test "refuses to process XML remote entities" do
|
||||||
|
|
||||||
assert :error = WebFinger.finger("pekorino@pawoo.net")
|
assert :error = WebFinger.finger("pekorino@pawoo.net")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "prevents spoofing" do
|
||||||
|
Tesla.Mock.mock(fn
|
||||||
|
%{
|
||||||
|
url: "https://gleasonator.com/.well-known/webfinger?resource=acct:alex@gleasonator.com"
|
||||||
|
} ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: File.read!("test/fixtures/tesla_mock/webfinger_spoof.json"),
|
||||||
|
headers: [{"content-type", "application/jrd+json"}]
|
||||||
|
}}
|
||||||
|
|
||||||
|
%{url: "https://gleasonator.com/.well-known/host-meta"} ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: File.read!("test/fixtures/tesla_mock/gleasonator.com_host_meta")
|
||||||
|
}}
|
||||||
|
end)
|
||||||
|
|
||||||
|
{:error, _data} = WebFinger.finger("alex@gleasonator.com")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@tag capture_log: true
|
||||||
|
test "prevents forgeries" do
|
||||||
|
Tesla.Mock.mock(fn
|
||||||
|
%{url: "https://fba.ryona.agency/.well-known/webfinger?resource=acct:graf@fba.ryona.agency"} ->
|
||||||
|
fake_webfinger =
|
||||||
|
File.read!("test/fixtures/webfinger/graf-imposter-webfinger.json") |> Jason.decode!()
|
||||||
|
|
||||||
|
Tesla.Mock.json(fake_webfinger)
|
||||||
|
|
||||||
|
%{url: "https://fba.ryona.agency/.well-known/host-meta"} ->
|
||||||
|
{:ok, %Tesla.Env{status: 404}}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert {:error, _} = WebFinger.finger("graf@fba.ryona.agency")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1521,6 +1521,120 @@ def get("https://friends.grishka.me/users/1", _, _, _) do
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get("https://mastodon.example/.well-known/host-meta", _, _, _) do
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 302,
|
||||||
|
headers: [{"location", "https://sub.mastodon.example/.well-known/host-meta"}]
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def get("https://sub.mastodon.example/.well-known/host-meta", _, _, _) do
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
"test/fixtures/webfinger/masto-host-meta.xml"
|
||||||
|
|> File.read!()
|
||||||
|
|> String.replace("{{domain}}", "sub.mastodon.example")
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(
|
||||||
|
"https://sub.mastodon.example/.well-known/webfinger?resource=acct:a@mastodon.example",
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_
|
||||||
|
) do
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
"test/fixtures/webfinger/masto-webfinger.json"
|
||||||
|
|> File.read!()
|
||||||
|
|> String.replace("{{nickname}}", "a")
|
||||||
|
|> String.replace("{{domain}}", "mastodon.example")
|
||||||
|
|> String.replace("{{subdomain}}", "sub.mastodon.example"),
|
||||||
|
headers: [{"content-type", "application/jrd+json"}]
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def get("https://sub.mastodon.example/users/a", _, _, _) do
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
"test/fixtures/webfinger/masto-user.json"
|
||||||
|
|> File.read!()
|
||||||
|
|> String.replace("{{nickname}}", "a")
|
||||||
|
|> String.replace("{{domain}}", "sub.mastodon.example"),
|
||||||
|
headers: [{"content-type", "application/activity+json"}]
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def get("https://sub.mastodon.example/users/a/collections/featured", _, _, _) do
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
File.read!("test/fixtures/users_mock/masto_featured.json")
|
||||||
|
|> String.replace("{{domain}}", "sub.mastodon.example")
|
||||||
|
|> String.replace("{{nickname}}", "a"),
|
||||||
|
headers: [{"content-type", "application/activity+json"}]
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def get("https://pleroma.example/.well-known/host-meta", _, _, _) do
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 302,
|
||||||
|
headers: [{"location", "https://sub.pleroma.example/.well-known/host-meta"}]
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def get("https://sub.pleroma.example/.well-known/host-meta", _, _, _) do
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
"test/fixtures/webfinger/pleroma-host-meta.xml"
|
||||||
|
|> File.read!()
|
||||||
|
|> String.replace("{{domain}}", "sub.pleroma.example")
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(
|
||||||
|
"https://sub.pleroma.example/.well-known/webfinger?resource=acct:a@pleroma.example",
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
_
|
||||||
|
) do
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
"test/fixtures/webfinger/pleroma-webfinger.json"
|
||||||
|
|> File.read!()
|
||||||
|
|> String.replace("{{nickname}}", "a")
|
||||||
|
|> String.replace("{{domain}}", "pleroma.example")
|
||||||
|
|> String.replace("{{subdomain}}", "sub.pleroma.example"),
|
||||||
|
headers: [{"content-type", "application/jrd+json"}]
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
|
def get("https://sub.pleroma.example/users/a", _, _, _) do
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body:
|
||||||
|
"test/fixtures/webfinger/pleroma-user.json"
|
||||||
|
|> File.read!()
|
||||||
|
|> String.replace("{{nickname}}", "a")
|
||||||
|
|> String.replace("{{domain}}", "sub.pleroma.example"),
|
||||||
|
headers: [{"content-type", "application/activity+json"}]
|
||||||
|
}}
|
||||||
|
end
|
||||||
|
|
||||||
def get(url, query, body, headers) do
|
def get(url, query, body, headers) do
|
||||||
{:error,
|
{:error,
|
||||||
"Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}
|
"Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}
|
||||||
|
|
Loading…
Reference in New Issue