aboutsummaryrefslogtreecommitdiff
path: root/lib/pleroma/web
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pleroma/web')
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex34
-rw-r--r--lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex14
-rw-r--r--lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex2
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/types/object_id.ex16
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex29
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex101
-rw-r--r--lib/pleroma/web/activity_pub/visibility.ex14
-rw-r--r--lib/pleroma/web/admin_api/admin_api_controller.ex59
-rw-r--r--lib/pleroma/web/admin_api/views/account_view.ex40
-rw-r--r--lib/pleroma/web/admin_api/views/report_view.ex28
-rw-r--r--lib/pleroma/web/common_api/common_api.ex2
-rw-r--r--lib/pleroma/web/controller_helper.ex14
-rw-r--r--lib/pleroma/web/feed/tag_controller.ex6
-rw-r--r--lib/pleroma/web/feed/user_controller.ex17
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/account_controller.ex77
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/status_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex35
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex140
-rw-r--r--lib/pleroma/web/mastodon_api/views/notification_view.ex111
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex99
-rw-r--r--lib/pleroma/web/metadata.ex7
-rw-r--r--lib/pleroma/web/metadata/opengraph.ex2
-rw-r--r--lib/pleroma/web/metadata/restrict_indexing.ex25
-rw-r--r--lib/pleroma/web/nodeinfo/nodeinfo_controller.ex3
-rw-r--r--lib/pleroma/web/rel_me.ex18
-rw-r--r--lib/pleroma/web/rich_media/parser.ex18
-rw-r--r--lib/pleroma/web/router.ex5
-rw-r--r--lib/pleroma/web/static_fe/static_fe_controller.ex4
-rw-r--r--lib/pleroma/web/streamer/worker.ex2
-rw-r--r--lib/pleroma/web/templates/feed/feed/_activity.atom.eex (renamed from lib/pleroma/web/templates/feed/feed/_activity.xml.eex)0
-rw-r--r--lib/pleroma/web/templates/feed/feed/_activity.rss.eex49
-rw-r--r--lib/pleroma/web/templates/feed/feed/_author.atom.eex (renamed from lib/pleroma/web/templates/feed/feed/_author.xml.eex)0
-rw-r--r--lib/pleroma/web/templates/feed/feed/_author.rss.eex17
-rw-r--r--lib/pleroma/web/templates/feed/feed/user.atom.eex (renamed from lib/pleroma/web/templates/feed/feed/user.xml.eex)4
-rw-r--r--lib/pleroma/web/templates/feed/feed/user.rss.eex20
-rw-r--r--lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex2
-rw-r--r--lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex2
-rw-r--r--lib/pleroma/web/web_finger/web_finger.ex5
39 files changed, 689 insertions, 336 deletions
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 55f4de693..19286fd01 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -518,8 +518,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp do_follow(follower, followed, activity_id, local) do
with data <- make_follow_data(follower, followed, activity_id),
{:ok, activity} <- insert(data, local),
- :ok <- maybe_federate(activity),
- _ <- User.set_follow_state_cache(follower.ap_id, followed.ap_id, activity.data["state"]) do
+ :ok <- maybe_federate(activity) do
{:ok, activity}
else
{:error, error} -> Repo.rollback(error)
@@ -599,6 +598,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
+ defp do_delete(%Object{data: %{"type" => "Tombstone", "id" => ap_id}}, _) do
+ activity =
+ ap_id
+ |> Activity.Queries.by_object_id()
+ |> Activity.Queries.by_type("Delete")
+ |> Repo.one()
+
+ {:ok, activity}
+ end
+
@spec block(User.t(), User.t(), String.t() | nil, boolean()) ::
{:ok, Activity.t()} | {:error, any()}
def block(blocker, blocked, activity_id \\ nil, local \\ true) do
@@ -1245,17 +1254,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp fetch_activities_query_ap_ids_ops(opts) do
source_user = opts["muting_user"]
- ap_id_relations = if source_user, do: [:mute, :reblog_mute], else: []
+ ap_id_relationships = if source_user, do: [:mute, :reblog_mute], else: []
- ap_id_relations =
- ap_id_relations ++
+ ap_id_relationships =
+ ap_id_relationships ++
if opts["blocking_user"] && opts["blocking_user"] == source_user do
[:block]
else
[]
end
- preloaded_ap_ids = User.outgoing_relations_ap_ids(source_user, ap_id_relations)
+ preloaded_ap_ids = User.outgoing_relationships_ap_ids(source_user, ap_id_relationships)
restrict_blocked_opts = Map.merge(%{"blocked_users_ap_ids" => preloaded_ap_ids[:block]}, opts)
restrict_muted_opts = Map.merge(%{"muted_users_ap_ids" => preloaded_ap_ids[:mute]}, opts)
@@ -1385,6 +1394,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
+ @spec get_actor_url(any()) :: binary() | nil
+ defp get_actor_url(url) when is_binary(url), do: url
+ defp get_actor_url(%{"href" => href}) when is_binary(href), do: href
+
+ defp get_actor_url(url) when is_list(url) do
+ url
+ |> List.first()
+ |> get_actor_url()
+ end
+
+ defp get_actor_url(_url), do: nil
+
defp object_to_user_data(data) do
avatar =
data["icon"]["url"] &&
@@ -1414,6 +1435,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
user_data = %{
ap_id: data["id"],
+ uri: get_actor_url(data["url"]),
ap_enabled: true,
source_data: data,
banner: banner,
diff --git a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
index b3547ecd4..0270b96ae 100644
--- a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do
diff --git a/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex b/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex
index d9a0acfd3..dfab105a3 100644
--- a/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex
@@ -12,17 +12,23 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
require Logger
- @hackney_options [
- pool: :media,
- recv_timeout: 10_000
+ @options [
+ pool: :media
]
def perform(:prefetch, url) do
Logger.debug("Prefetching #{inspect(url)}")
+ opts =
+ if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do
+ Keyword.put(@options, :recv_timeout, 10_000)
+ else
+ @options
+ end
+
url
|> MediaProxy.url()
- |> HTTP.get([], adapter: @hackney_options)
+ |> HTTP.get([], adapter: opts)
end
def perform(:preload, %{"object" => %{"attachment" => attachments}} = _message) do
diff --git a/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex b/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex
index f67f48ab6..fc3475048 100644
--- a/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy do
diff --git a/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex b/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex
index 8e70effe4..ee10be0b0 100644
--- a/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex
@@ -4,14 +4,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.ObjectID do
def type, do: :string
def cast(object) when is_binary(object) do
- with %URI{
- scheme: scheme,
- host: host
- }
- when scheme in ["https", "http"] and not is_nil(host) <-
- URI.parse(object) do
- {:ok, object}
- else
+ # Host has to be present and scheme has to be an http scheme (for now)
+ case URI.parse(object) do
+ %URI{host: nil} ->
+ :error
+
+ %URI{scheme: scheme} when scheme in ["https", "http"] ->
+ {:ok, object}
+
_ ->
:error
end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index a4b385cd5..0a8ad62ad 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -232,7 +232,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
Map.put(object, "url", url["href"])
end
- def fix_url(%{"type" => "Video", "url" => url} = object) when is_list(url) do
+ def fix_url(%{"type" => object_type, "url" => url} = object)
+ when object_type in ["Video", "Audio"] and is_list(url) do
first_element = Enum.at(url, 0)
link_element = Enum.find(url, fn x -> is_map(x) and x["mimeType"] == "text/html" end)
@@ -401,7 +402,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
%{"type" => "Create", "object" => %{"type" => objtype} = object} = data,
options
)
- when objtype in ["Article", "Event", "Note", "Video", "Page", "Question", "Answer"] do
+ when objtype in ["Article", "Event", "Note", "Video", "Page", "Question", "Answer", "Audio"] do
actor = Containment.get_actor(data)
data =
@@ -617,9 +618,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
data |> LikeValidator.cast_data() |> Ecto.Changeset.apply_action(:insert)},
cast_data = ObjectValidator.stringify_keys(Map.from_struct(cast_data_sym)),
:ok <- ObjectValidator.fetch_actor_and_object(cast_data),
- {_, {:ok, cast_data}} <- {:maybe_add_context, maybe_add_context_from_object(cast_data)},
+ {_, {:ok, cast_data}} <- {:ensure_context_presence, ensure_context_presence(cast_data)},
{_, {:ok, cast_data}} <-
- {:maybe_add_recipients, maybe_add_recipients_from_object(cast_data)},
+ {:ensure_recipients_presence, ensure_recipients_presence(cast_data)},
{_, {:ok, activity, _meta}} <-
{:common_pipeline, Pipeline.common_pipeline(cast_data, local: false)} do
{:ok, activity}
@@ -1114,13 +1115,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
def add_mention_tags(object) do
- mentions =
- object
- |> Utils.get_notified_from_object()
- |> Enum.map(&build_mention_tag/1)
+ {enabled_receivers, disabled_receivers} = Utils.get_notified_from_object(object)
+ potential_receivers = enabled_receivers ++ disabled_receivers
+ mentions = Enum.map(potential_receivers, &build_mention_tag/1)
tags = object["tag"] || []
-
Map.put(object, "tag", tags ++ mentions)
end
@@ -1251,10 +1250,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def maybe_fix_user_object(data), do: maybe_fix_user_url(data)
- defp maybe_add_context_from_object(%{"context" => context} = data) when is_binary(context),
+ defp ensure_context_presence(%{"context" => context} = data) when is_binary(context),
do: {:ok, data}
- defp maybe_add_context_from_object(%{"object" => object} = data) when is_binary(object) do
+ defp ensure_context_presence(%{"object" => object} = data) when is_binary(object) do
with %{data: %{"context" => context}} when is_binary(context) <- Object.normalize(object) do
{:ok, Map.put(data, "context", context)}
else
@@ -1263,14 +1262,14 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
- defp maybe_add_context_from_object(_) do
+ defp ensure_context_presence(_) do
{:error, :no_context}
end
- defp maybe_add_recipients_from_object(%{"to" => [_ | _], "cc" => [_ | _]} = data),
+ defp ensure_recipients_presence(%{"to" => [_ | _], "cc" => [_ | _]} = data),
do: {:ok, data}
- defp maybe_add_recipients_from_object(%{"object" => object} = data) do
+ defp ensure_recipients_presence(%{"object" => object} = data) do
case Object.normalize(object) do
%{data: %{"actor" => actor}} ->
data =
@@ -1288,7 +1287,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
- defp maybe_add_recipients_from_object(_) do
+ defp ensure_recipients_presence(_) do
{:error, :no_object}
end
end
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 15dd2ed45..2d685ecc0 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -440,22 +440,19 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> update(set: [data: fragment("jsonb_set(data, '{state}', ?)", ^state)])
|> Repo.update_all([])
- User.set_follow_state_cache(actor, object, state)
-
activity = Activity.get_by_id(activity.id)
{:ok, activity}
end
def update_follow_state(
- %Activity{data: %{"actor" => actor, "object" => object}} = activity,
+ %Activity{} = activity,
state
) do
new_data = Map.put(activity.data, "state", state)
changeset = Changeset.change(activity, data: new_data)
with {:ok, activity} <- Repo.update(changeset) do
- User.set_follow_state_cache(actor, object, state)
{:ok, activity}
end
end
@@ -798,102 +795,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do
ActivityPub.fetch_activities([], params, :offset)
end
- def parse_report_group(activity) do
- reports = get_reports_by_status_id(activity["id"])
- max_date = Enum.max_by(reports, &NaiveDateTime.from_iso8601!(&1.data["published"]))
- actors = Enum.map(reports, & &1.user_actor)
- [%{data: %{"object" => [account_id | _]}} | _] = reports
-
- account =
- AccountView.render("show.json", %{
- user: User.get_by_ap_id(account_id)
- })
-
- status = get_status_data(activity)
-
- %{
- date: max_date.data["published"],
- account: account,
- status: status,
- actors: Enum.uniq(actors),
- reports: reports
- }
- end
-
- defp get_status_data(status) do
- case status["deleted"] do
- true ->
- %{
- "id" => status["id"],
- "deleted" => true
- }
-
- _ ->
- Activity.get_by_ap_id(status["id"])
- end
- end
-
- def get_reports_by_status_id(ap_id) do
- from(a in Activity,
- where: fragment("(?)->>'type' = 'Flag'", a.data),
- where: fragment("(?)->'object' @> ?", a.data, ^[%{id: ap_id}]),
- or_where: fragment("(?)->'object' @> ?", a.data, ^[ap_id])
- )
- |> Activity.with_preloaded_user_actor()
- |> Repo.all()
- end
-
- @spec get_reports_grouped_by_status([String.t()]) :: %{
- required(:groups) => [
- %{
- required(:date) => String.t(),
- required(:account) => %{},
- required(:status) => %{},
- required(:actors) => [%User{}],
- required(:reports) => [%Activity{}]
- }
- ]
- }
- def get_reports_grouped_by_status(activity_ids) do
- parsed_groups =
- activity_ids
- |> Enum.map(fn id ->
- id
- |> build_flag_object()
- |> parse_report_group()
- end)
-
- %{
- groups: parsed_groups
- }
- end
-
- @spec get_reported_activities() :: [
- %{
- required(:activity) => String.t(),
- required(:date) => String.t()
- }
- ]
- def get_reported_activities do
- reported_activities_query =
- from(a in Activity,
- where: fragment("(?)->>'type' = 'Flag'", a.data),
- select: %{
- activity: fragment("jsonb_array_elements((? #- '{object,0}')->'object')", a.data)
- },
- group_by: fragment("activity")
- )
-
- from(a in subquery(reported_activities_query),
- distinct: true,
- select: %{
- id: fragment("COALESCE(?->>'id'::text, ? #>> '{}')", a.activity, a.activity)
- }
- )
- |> Repo.all()
- |> Enum.map(& &1.id)
- end
-
def update_report_state(%Activity{} = activity, state)
when state in @strip_status_report_states do
{:ok, stripped_activity} = strip_report_status_data(activity)
diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex
index 6f226fc92..453a6842e 100644
--- a/lib/pleroma/web/activity_pub/visibility.ex
+++ b/lib/pleroma/web/activity_pub/visibility.ex
@@ -44,6 +44,7 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
def is_list?(%{data: %{"listMessage" => _}}), do: true
def is_list?(_), do: false
+ @spec visible_for_user?(Activity.t(), User.t() | nil) :: boolean()
def visible_for_user?(%{actor: ap_id}, %User{ap_id: ap_id}), do: true
def visible_for_user?(%{data: %{"listMessage" => list_ap_id}} = activity, %User{} = user) do
@@ -55,14 +56,21 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
def visible_for_user?(%{data: %{"listMessage" => _}}, nil), do: false
- def visible_for_user?(activity, nil) do
- is_public?(activity)
+ def visible_for_user?(%{local: local} = activity, nil) do
+ cfg_key =
+ if local,
+ do: :local,
+ else: :remote
+
+ if Pleroma.Config.get([:restrict_unauthenticated, :activities, cfg_key]),
+ do: false,
+ else: is_public?(activity)
end
def visible_for_user?(activity, user) do
x = [user.ap_id | User.following(user)]
y = [activity.actor] ++ activity.data["to"] ++ (activity.data["cc"] || [])
- visible_for_user?(activity, nil) || Enum.any?(x, &(&1 in y))
+ is_public?(activity) || Enum.any?(x, &(&1 in y))
end
def entire_thread_visible_for_user?(%Activity{} = activity, %User{} = user) do
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 175260bc2..ca5439920 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -38,7 +38,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
plug(
OAuthScopesPlug,
%{scopes: ["read:accounts"], admin: true}
- when action in [:list_users, :user_show, :right_get]
+ when action in [:list_users, :user_show, :right_get, :show_user_credentials]
)
plug(
@@ -54,7 +54,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
:tag_users,
:untag_users,
:right_add,
- :right_delete
+ :right_delete,
+ :update_user_credentials
]
)
@@ -658,6 +659,52 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
json_response(conn, :no_content, "")
end
+ @doc "Show a given user's credentials"
+ def show_user_credentials(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
+ with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
+ conn
+ |> put_view(AccountView)
+ |> render("credentials.json", %{user: user, for: admin})
+ else
+ _ -> {:error, :not_found}
+ end
+ end
+
+ @doc "Updates a given user"
+ def update_user_credentials(
+ %{assigns: %{user: admin}} = conn,
+ %{"nickname" => nickname} = params
+ ) do
+ with {_, user} <- {:user, User.get_cached_by_nickname(nickname)},
+ {:ok, _user} <-
+ User.update_as_admin(user, params) do
+ ModerationLog.insert_log(%{
+ actor: admin,
+ subject: [user],
+ action: "updated_users"
+ })
+
+ if params["password"] do
+ User.force_password_reset_async(user)
+ end
+
+ ModerationLog.insert_log(%{
+ actor: admin,
+ subject: [user],
+ action: "force_password_reset"
+ })
+
+ json(conn, %{status: "success"})
+ else
+ {:error, changeset} ->
+ {_, {error, _}} = Enum.at(changeset.errors, 0)
+ json(conn, %{error: "New password #{error}."})
+
+ _ ->
+ json(conn, %{error: "Unable to change password."})
+ end
+ end
+
def list_reports(conn, params) do
{page, page_size} = page_params(params)
@@ -668,14 +715,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|> render("index.json", %{reports: reports})
end
- def list_grouped_reports(conn, _params) do
- statuses = Utils.get_reported_activities()
-
- conn
- |> put_view(ReportView)
- |> render("index_grouped.json", Utils.get_reports_grouped_by_status(statuses))
- end
-
def report_show(conn, %{"id" => id}) do
with %Activity{} = report <- Activity.get_by_id(id) do
conn
diff --git a/lib/pleroma/web/admin_api/views/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex
index 1e03849de..a16a3ebf0 100644
--- a/lib/pleroma/web/admin_api/views/account_view.ex
+++ b/lib/pleroma/web/admin_api/views/account_view.ex
@@ -23,6 +23,43 @@ defmodule Pleroma.Web.AdminAPI.AccountView do
}
end
+ def render("credentials.json", %{user: user, for: for_user}) do
+ user = User.sanitize_html(user, User.html_filter_policy(for_user))
+ avatar = User.avatar_url(user) |> MediaProxy.url()
+ banner = User.banner_url(user) |> MediaProxy.url()
+ background = image_url(user.background) |> MediaProxy.url()
+
+ user
+ |> Map.take([
+ :id,
+ :bio,
+ :email,
+ :fields,
+ :name,
+ :nickname,
+ :locked,
+ :no_rich_text,
+ :default_scope,
+ :hide_follows,
+ :hide_followers_count,
+ :hide_follows_count,
+ :hide_followers,
+ :hide_favorites,
+ :allow_following_move,
+ :show_role,
+ :skip_thread_containment,
+ :pleroma_settings_store,
+ :raw_fields,
+ :discoverable,
+ :actor_type
+ ])
+ |> Map.merge(%{
+ "avatar" => avatar,
+ "banner" => banner,
+ "background" => background
+ })
+ end
+
def render("show.json", %{user: user}) do
avatar = User.avatar_url(user) |> MediaProxy.url()
display_name = Pleroma.HTML.strip_tags(user.name || user.nickname)
@@ -104,4 +141,7 @@ defmodule Pleroma.Web.AdminAPI.AccountView do
""
end
end
+
+ defp image_url(%{"url" => [%{"href" => href} | _]}), do: href
+ defp image_url(_), do: nil
end
diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex
index fc8733ce8..ca0bcebc7 100644
--- a/lib/pleroma/web/admin_api/views/report_view.ex
+++ b/lib/pleroma/web/admin_api/views/report_view.ex
@@ -4,7 +4,7 @@
defmodule Pleroma.Web.AdminAPI.ReportView do
use Pleroma.Web, :view
- alias Pleroma.Activity
+
alias Pleroma.HTML
alias Pleroma.User
alias Pleroma.Web.AdminAPI.Report
@@ -44,32 +44,6 @@ defmodule Pleroma.Web.AdminAPI.ReportView do
}
end
- def render("index_grouped.json", %{groups: groups}) do
- reports =
- Enum.map(groups, fn group ->
- status =
- case group.status do
- %Activity{} = activity -> StatusView.render("show.json", %{activity: activity})
- _ -> group.status
- end
-
- %{
- date: group[:date],
- account: group[:account],
- status: Map.put_new(status, "deleted", false),
- actors: Enum.map(group[:actors], &merge_account_views/1),
- reports:
- group[:reports]
- |> Enum.map(&Report.extract_report_info(&1))
- |> Enum.map(&render(__MODULE__, "show.json", &1))
- }
- end)
-
- %{
- reports: reports
- }
- end
-
def render("index_notes.json", %{notes: notes}) when is_list(notes) do
Enum.map(notes, &render(__MODULE__, "show_note.json", &1))
end
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 74adcca55..636cf3301 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -394,7 +394,7 @@ defmodule Pleroma.Web.CommonAPI do
def thread_muted?(%{id: nil} = _user, _activity), do: false
def thread_muted?(user, activity) do
- ThreadMute.check_muted(user.id, activity.data["context"]) != []
+ ThreadMute.exists?(user.id, activity.data["context"])
end
def report(user, %{"account_id" => account_id} = data) do
diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex
index c9a3a2585..b49523ec3 100644
--- a/lib/pleroma/web/controller_helper.ex
+++ b/lib/pleroma/web/controller_helper.ex
@@ -34,7 +34,12 @@ defmodule Pleroma.Web.ControllerHelper do
defp param_to_integer(_, default), do: default
- def add_link_headers(conn, activities, extra_params \\ %{}) do
+ def add_link_headers(conn, activities, extra_params \\ %{})
+
+ def add_link_headers(%{assigns: %{skip_link_headers: true}} = conn, _activities, _extra_params),
+ do: conn
+
+ def add_link_headers(conn, activities, extra_params) do
case List.last(activities) do
%{id: max_id} ->
params =
@@ -87,7 +92,8 @@ defmodule Pleroma.Web.ControllerHelper do
render_error(conn, :not_implemented, "Can't display this activity")
end
- @spec put_in_if_exist(map(), atom() | String.t(), any) :: map()
- def put_in_if_exist(map, _key, nil), do: map
- def put_in_if_exist(map, key, value), do: put_in(map, key, value)
+ @spec put_if_exist(map(), atom() | String.t(), any) :: map()
+ def put_if_exist(map, _key, nil), do: map
+
+ def put_if_exist(map, key, value), do: Map.put(map, key, value)
end
diff --git a/lib/pleroma/web/feed/tag_controller.ex b/lib/pleroma/web/feed/tag_controller.ex
index 75c9ea17e..8133f8480 100644
--- a/lib/pleroma/web/feed/tag_controller.ex
+++ b/lib/pleroma/web/feed/tag_controller.ex
@@ -9,18 +9,18 @@ defmodule Pleroma.Web.Feed.TagController do
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.Feed.FeedView
- import Pleroma.Web.ControllerHelper, only: [put_in_if_exist: 3]
+ import Pleroma.Web.ControllerHelper, only: [put_if_exist: 3]
def feed(conn, %{"tag" => raw_tag} = params) do
{format, tag} = parse_tag(raw_tag)
activities =
%{"type" => ["Create"], "tag" => tag}
- |> put_in_if_exist("max_id", params["max_id"])
+ |> put_if_exist("max_id", params["max_id"])
|> ActivityPub.fetch_public_activities()
conn
- |> put_resp_content_type("application/atom+xml")
+ |> put_resp_content_type("application/#{format}+xml")
|> put_view(FeedView)
|> render("tag.#{format}",
activities: activities,
diff --git a/lib/pleroma/web/feed/user_controller.ex b/lib/pleroma/web/feed/user_controller.ex
index 9ba602d9f..e27f85929 100644
--- a/lib/pleroma/web/feed/user_controller.ex
+++ b/lib/pleroma/web/feed/user_controller.ex
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.Feed.UserController do
alias Pleroma.Web.ActivityPub.ActivityPubController
alias Pleroma.Web.Feed.FeedView
- import Pleroma.Web.ControllerHelper, only: [put_in_if_exist: 3]
+ import Pleroma.Web.ControllerHelper, only: [put_if_exist: 3]
plug(Pleroma.Plugs.SetFormatPlug when action in [:feed_redirect])
@@ -40,19 +40,28 @@ defmodule Pleroma.Web.Feed.UserController do
end
def feed(conn, %{"nickname" => nickname} = params) do
+ format = get_format(conn)
+
+ format =
+ if format in ["rss", "atom"] do
+ format
+ else
+ "atom"
+ end
+
with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do
activities =
%{
"type" => ["Create"],
"actor_id" => user.ap_id
}
- |> put_in_if_exist("max_id", params["max_id"])
+ |> put_if_exist("max_id", params["max_id"])
|> ActivityPub.fetch_public_activities()
conn
- |> put_resp_content_type("application/atom+xml")
+ |> put_resp_content_type("application/#{format}+xml")
|> put_view(FeedView)
- |> render("user.xml",
+ |> render("user.#{format}",
user: user,
activities: activities,
feed_config: Pleroma.Config.get([:feed])
diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
index 88c997b9f..21bc3d5a5 100644
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -8,7 +8,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
import Pleroma.Web.ControllerHelper,
only: [add_link_headers: 2, truthy_param?: 1, assign_account_by_id: 2, json_response: 3]
- alias Pleroma.Emoji
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Plugs.RateLimiter
alias Pleroma.User
@@ -60,14 +59,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
plug(
Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
- when action != :create
+ when action not in [:create, :show, :statuses]
)
- @relations [:follow, :unfollow]
+ @relationship_actions [:follow, :unfollow]
@needs_account ~W(followers following lists follow unfollow mute unmute block unblock)a
- plug(RateLimiter, [name: :relations_id_action, params: ["id", "uri"]] when action in @relations)
- plug(RateLimiter, [name: :relations_actions] when action in @relations)
+ plug(
+ RateLimiter,
+ [name: :relation_id_action, params: ["id", "uri"]] when action in @relationship_actions
+ )
+
+ plug(RateLimiter, [name: :relations_actions] when action in @relationship_actions)
plug(RateLimiter, [name: :app_account_creation] when action == :create)
plug(:assign_account_by_id when action in @needs_account)
@@ -140,17 +143,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
def update_credentials(%{assigns: %{user: original_user}} = conn, params) do
user = original_user
- params =
- if Map.has_key?(params, "fields_attributes") do
- Map.update!(params, "fields_attributes", fn fields ->
- fields
- |> normalize_fields_attributes()
- |> Enum.filter(fn %{"name" => n} -> n != "" end)
- end)
- else
- params
- end
-
user_params =
[
:no_rich_text,
@@ -169,46 +161,20 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
add_if_present(acc, params, to_string(key), key, &{:ok, truthy_param?(&1)})
end)
|> add_if_present(params, "display_name", :name)
- |> add_if_present(params, "note", :bio, fn value -> {:ok, User.parse_bio(value, user)} end)
- |> add_if_present(params, "avatar", :avatar, fn value ->
- with %Plug.Upload{} <- value,
- {:ok, object} <- ActivityPub.upload(value, type: :avatar) do
- {:ok, object.data}
- end
- end)
- |> add_if_present(params, "header", :banner, fn value ->
- with %Plug.Upload{} <- value,
- {:ok, object} <- ActivityPub.upload(value, type: :banner) do
- {:ok, object.data}
- end
- end)
- |> add_if_present(params, "pleroma_background_image", :background, fn value ->
- with %Plug.Upload{} <- value,
- {:ok, object} <- ActivityPub.upload(value, type: :background) do
- {:ok, object.data}
- end
- end)
- |> add_if_present(params, "fields_attributes", :fields, fn fields ->
- fields = Enum.map(fields, fn f -> Map.update!(f, "value", &AutoLinker.link(&1)) end)
-
- {:ok, fields}
- end)
- |> add_if_present(params, "fields_attributes", :raw_fields)
- |> add_if_present(params, "pleroma_settings_store", :pleroma_settings_store, fn value ->
- {:ok, Map.merge(user.pleroma_settings_store, value)}
- end)
+ |> add_if_present(params, "note", :bio)
+ |> add_if_present(params, "avatar", :avatar)
+ |> add_if_present(params, "header", :banner)
+ |> add_if_present(params, "pleroma_background_image", :background)
+ |> add_if_present(
+ params,
+ "fields_attributes",
+ :raw_fields,
+ &{:ok, normalize_fields_attributes(&1)}
+ )
+ |> add_if_present(params, "pleroma_settings_store", :pleroma_settings_store)
|> add_if_present(params, "default_scope", :default_scope)
|> add_if_present(params, "actor_type", :actor_type)
- emojis_text = (user_params["display_name"] || "") <> (user_params["note"] || "")
-
- user_emojis =
- user
- |> Map.get(:emoji, [])
- |> Enum.concat(Emoji.Formatter.get_emoji_map(emojis_text))
- |> Enum.dedup()
-
- user_params = Map.put(user_params, :emoji, user_emojis)
changeset = User.update_changeset(user, user_params)
with {:ok, user} <- User.update_and_set_cache(changeset) do
@@ -259,7 +225,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
@doc "GET /api/v1/accounts/:id/statuses"
def statuses(%{assigns: %{user: reading_user}} = conn, params) do
- with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do
+ with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user),
+ true <- User.visible_for?(user, reading_user) do
params =
params
|> Map.put("tag", params["tagged"])
@@ -271,6 +238,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|> add_link_headers(activities)
|> put_view(StatusView)
|> render("index.json", activities: activities, for: reading_user, as: :activity)
+ else
+ _e -> render_error(conn, :not_found, "Can't find user")
end
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
index 83cd2c768..ec8f0d8a0 100644
--- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
@@ -76,7 +76,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
%{scopes: ["write:bookmarks"]} when action in [:bookmark, :unbookmark]
)
- plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
+ plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug when action not in [:index, :show])
@rate_limited_status_actions ~w(reblog unreblog favourite unfavourite create delete)a
diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
index 09e08271b..91f41416d 100644
--- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
@@ -27,7 +27,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in [:home, :direct])
plug(OAuthScopesPlug, %{scopes: ["read:lists"]} when action == :list)
- plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
+ plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug when action != :public)
plug(:put_view, Pleroma.Web.MastodonAPI.StatusView)
@@ -75,17 +75,30 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
def public(%{assigns: %{user: user}} = conn, params) do
local_only = truthy_param?(params["local"])
- activities =
- params
- |> Map.put("type", ["Create", "Announce"])
- |> Map.put("local_only", local_only)
- |> Map.put("blocking_user", user)
- |> Map.put("muting_user", user)
- |> ActivityPub.fetch_public_activities()
+ cfg_key =
+ if local_only do
+ :local
+ else
+ :federated
+ end
- conn
- |> add_link_headers(activities, %{"local" => local_only})
- |> render("index.json", activities: activities, for: user, as: :activity)
+ restrict? = Pleroma.Config.get([:restrict_unauthenticated, :timelines, cfg_key])
+
+ if not (restrict? and is_nil(user)) do
+ activities =
+ params
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", local_only)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> ActivityPub.fetch_public_activities()
+
+ conn
+ |> add_link_headers(activities, %{"local" => local_only})
+ |> render("index.json", activities: activities, for: user, as: :activity)
+ else
+ render_error(conn, :unauthorized, "authorization required for timeline view")
+ end
end
def hashtag_fetching(params, user, local_only) do
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 341dc2c91..99e62f580 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -5,12 +5,30 @@
defmodule Pleroma.Web.MastodonAPI.AccountView do
use Pleroma.Web, :view
+ alias Pleroma.FollowingRelationship
alias Pleroma.User
+ alias Pleroma.UserRelationship
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MediaProxy
def render("index.json", %{users: users} = opts) do
+ reading_user = opts[:for]
+
+ relationships_opt =
+ cond do
+ Map.has_key?(opts, :relationships) ->
+ opts[:relationships]
+
+ is_nil(reading_user) ->
+ UserRelationship.view_relationships_option(nil, [])
+
+ true ->
+ UserRelationship.view_relationships_option(reading_user, users)
+ end
+
+ opts = Map.put(opts, :relationships, relationships_opt)
+
users
|> render_many(AccountView, "show.json", opts)
|> Enum.filter(&Enum.any?/1)
@@ -27,7 +45,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
id: to_string(user.id),
acct: user.nickname,
username: username_from_nickname(user.nickname),
- url: User.profile_url(user)
+ url: user.uri || user.ap_id
}
end
@@ -35,34 +53,107 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
%{}
end
- def render("relationship.json", %{user: %User{} = user, target: %User{} = target}) do
- follow_state = User.get_cached_follow_state(user, target)
+ def render(
+ "relationship.json",
+ %{user: %User{} = reading_user, target: %User{} = target} = opts
+ ) do
+ user_relationships = get_in(opts, [:relationships, :user_relationships])
+ following_relationships = get_in(opts, [:relationships, :following_relationships])
+
+ follow_state =
+ if following_relationships do
+ user_to_target_following_relation =
+ FollowingRelationship.find(following_relationships, reading_user, target)
- requested =
- if follow_state && !User.following?(user, target) do
- follow_state == "pending"
+ User.get_follow_state(reading_user, target, user_to_target_following_relation)
else
- false
+ User.get_follow_state(reading_user, target)
end
+ followed_by =
+ if following_relationships do
+ case FollowingRelationship.find(following_relationships, target, reading_user) do
+ %{state: "accept"} -> true
+ _ -> false
+ end
+ else
+ User.following?(target, reading_user)
+ end
+
+ # NOTE: adjust UserRelationship.view_relationships_option/2 on new relation-related flags
%{
id: to_string(target.id),
- following: User.following?(user, target),
- followed_by: User.following?(target, user),
- blocking: User.blocks_user?(user, target),
- blocked_by: User.blocks_user?(target, user),
- muting: User.mutes?(user, target),
- muting_notifications: User.muted_notifications?(user, target),
- subscribing: User.subscribed_to?(user, target),
- requested: requested,
- domain_blocking: User.blocks_domain?(user, target),
- showing_reblogs: User.showing_reblogs?(user, target),
+ following: follow_state == "accept",
+ followed_by: followed_by,
+ blocking:
+ UserRelationship.exists?(
+ user_relationships,
+ :block,
+ reading_user,
+ target,
+ &User.blocks_user?(&1, &2)
+ ),
+ blocked_by:
+ UserRelationship.exists?(
+ user_relationships,
+ :block,
+ target,
+ reading_user,
+ &User.blocks_user?(&1, &2)
+ ),
+ muting:
+ UserRelationship.exists?(
+ user_relationships,
+ :mute,
+ reading_user,
+ target,
+ &User.mutes?(&1, &2)
+ ),
+ muting_notifications:
+ UserRelationship.exists?(
+ user_relationships,
+ :notification_mute,
+ reading_user,
+ target,
+ &User.muted_notifications?(&1, &2)
+ ),
+ subscribing:
+ UserRelationship.exists?(
+ user_relationships,
+ :inverse_subscription,
+ target,
+ reading_user,
+ &User.subscribed_to?(&2, &1)
+ ),
+ requested: follow_state == "pending",
+ domain_blocking: User.blocks_domain?(reading_user, target),
+ showing_reblogs:
+ not UserRelationship.exists?(
+ user_relationships,
+ :reblog_mute,
+ reading_user,
+ target,
+ &User.muting_reblogs?(&1, &2)
+ ),
endorsed: false
}
end
- def render("relationships.json", %{user: user, targets: targets}) do
- render_many(targets, AccountView, "relationship.json", user: user, as: :target)
+ def render("relationships.json", %{user: user, targets: targets} = opts) do
+ relationships_opt =
+ cond do
+ Map.has_key?(opts, :relationships) ->
+ opts[:relationships]
+
+ is_nil(user) ->
+ UserRelationship.view_relationships_option(nil, [])
+
+ true ->
+ UserRelationship.view_relationships_option(user, targets)
+ end
+
+ render_opts = %{as: :target, user: user, relationships: relationships_opt}
+ render_many(targets, AccountView, "relationship.json", render_opts)
end
defp do_render("show.json", %{user: user} = opts) do
@@ -100,7 +191,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
}
end)
- relationship = render("relationship.json", %{user: opts[:for], target: user})
+ relationship =
+ render("relationship.json", %{
+ user: opts[:for],
+ target: user,
+ relationships: opts[:relationships]
+ })
%{
id: to_string(user.id),
@@ -113,7 +209,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
following_count: following_count,
statuses_count: user.note_count,
note: user.bio || "",
- url: User.profile_url(user),
+ url: user.uri || user.ap_id,
avatar: image,
avatar_static: image,
header: header,
@@ -122,7 +218,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
fields: user.fields,
bot: bot,
source: %{
- note: Pleroma.HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")),
+ note: (user.bio || "") |> String.replace(~r(<br */?>), "\n") |> Pleroma.HTML.strip_tags(),
sensitive: false,
fields: user.raw_fields,
pleroma: %{
diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex
index 33145c484..ae87d4701 100644
--- a/lib/pleroma/web/mastodon_api/views/notification_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex
@@ -8,24 +8,86 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
alias Pleroma.Activity
alias Pleroma.Notification
alias Pleroma.User
+ alias Pleroma.UserRelationship
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.MastodonAPI.StatusView
- def render("index.json", %{notifications: notifications, for: user}) do
- safe_render_many(notifications, NotificationView, "show.json", %{for: user})
+ def render("index.json", %{notifications: notifications, for: reading_user} = opts) do
+ activities = Enum.map(notifications, & &1.activity)
+
+ parent_activities =
+ activities
+ |> Enum.filter(
+ &(Activity.mastodon_notification_type(&1) in [
+ "favourite",
+ "reblog",
+ "pleroma:emoji_reaction"
+ ])
+ )
+ |> Enum.map(& &1.data["object"])
+ |> Activity.create_by_object_ap_id()
+ |> Activity.with_preloaded_object(:left)
+ |> Pleroma.Repo.all()
+
+ relationships_opt =
+ cond do
+ Map.has_key?(opts, :relationships) ->
+ opts[:relationships]
+
+ is_nil(reading_user) ->
+ UserRelationship.view_relationships_option(nil, [])
+
+ true ->
+ move_activities_targets =
+ activities
+ |> Enum.filter(&(Activity.mastodon_notification_type(&1) == "move"))
+ |> Enum.map(&User.get_cached_by_ap_id(&1.data["target"]))
+
+ actors =
+ activities
+ |> Enum.map(fn a -> User.get_cached_by_ap_id(a.data["actor"]) end)
+ |> Enum.filter(& &1)
+ |> Kernel.++(move_activities_targets)
+
+ UserRelationship.view_relationships_option(reading_user, actors)
+ end
+
+ opts = %{
+ for: reading_user,
+ parent_activities: parent_activities,
+ relationships: relationships_opt
+ }
+
+ safe_render_many(notifications, NotificationView, "show.json", opts)
end
- def render("show.json", %{
- notification: %Notification{activity: activity} = notification,
- for: user
- }) do
+ def render(
+ "show.json",
+ %{
+ notification: %Notification{activity: activity} = notification,
+ for: reading_user
+ } = opts
+ ) do
actor = User.get_cached_by_ap_id(activity.data["actor"])
- parent_activity = Activity.get_create_by_object_ap_id(activity.data["object"])
+
+ parent_activity_fn = fn ->
+ if opts[:parent_activities] do
+ Activity.Queries.find_by_object_ap_id(opts[:parent_activities], activity.data["object"])
+ else
+ Activity.get_create_by_object_ap_id(activity.data["object"])
+ end
+ end
+
mastodon_type = Activity.mastodon_notification_type(activity)
- with %{id: _} = account <- AccountView.render("show.json", %{user: actor, for: user}) do
+ with %{id: _} = account <-
+ AccountView.render("show.json", %{
+ user: actor,
+ for: reading_user,
+ relationships: opts[:relationships]
+ }) do
response = %{
id: to_string(notification.id),
type: mastodon_type,
@@ -36,24 +98,28 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
}
}
+ render_opts = %{relationships: opts[:relationships]}
+
case mastodon_type do
"mention" ->
- put_status(response, activity, user)
+ put_status(response, activity, reading_user, render_opts)
"favourite" ->
- put_status(response, parent_activity, user)
+ put_status(response, parent_activity_fn.(), reading_user, render_opts)
"reblog" ->
- put_status(response, parent_activity, user)
+ put_status(response, parent_activity_fn.(), reading_user, render_opts)
"move" ->
- put_target(response, activity, user)
+ put_target(response, activity, reading_user, render_opts)
"follow" ->
response
"pleroma:emoji_reaction" ->
- put_status(response, parent_activity, user) |> put_emoji(activity)
+ response
+ |> put_status(parent_activity_fn.(), reading_user, render_opts)
+ |> put_emoji(activity)
_ ->
nil
@@ -64,16 +130,21 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
end
defp put_emoji(response, activity) do
- response
- |> Map.put(:emoji, activity.data["content"])
+ Map.put(response, :emoji, activity.data["content"])
end
- defp put_status(response, activity, user) do
- Map.put(response, :status, StatusView.render("show.json", %{activity: activity, for: user}))
+ defp put_status(response, activity, reading_user, opts) do
+ status_render_opts = Map.merge(opts, %{activity: activity, for: reading_user})
+ status_render = StatusView.render("show.json", status_render_opts)
+
+ Map.put(response, :status, status_render)
end
- defp put_target(response, activity, user) do
- target = User.get_cached_by_ap_id(activity.data["target"])
- Map.put(response, :target, AccountView.render("show.json", %{user: target, for: user}))
+ defp put_target(response, activity, reading_user, opts) do
+ target_user = User.get_cached_by_ap_id(activity.data["target"])
+ target_render_opts = Map.merge(opts, %{user: target_user, for: reading_user})
+ target_render = AccountView.render("show.json", target_render_opts)
+
+ Map.put(response, :target, target_render)
end
end
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index f7469cdff..cea76e735 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -13,6 +13,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
+ alias Pleroma.UserRelationship
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.AccountView
@@ -71,10 +72,43 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
def render("index.json", opts) do
- replied_to_activities = get_replied_to_activities(opts.activities)
- opts = Map.put(opts, :replied_to_activities, replied_to_activities)
+ reading_user = opts[:for]
- safe_render_many(opts.activities, StatusView, "show.json", opts)
+ # To do: check AdminAPIControllerTest on the reasons behind nil activities in the list
+ activities = Enum.filter(opts.activities, & &1)
+ replied_to_activities = get_replied_to_activities(activities)
+
+ parent_activities =
+ activities
+ |> Enum.filter(&(&1.data["type"] == "Announce" && &1.data["object"]))
+ |> Enum.map(&Object.normalize(&1).data["id"])
+ |> Activity.create_by_object_ap_id()
+ |> Activity.with_preloaded_object(:left)
+ |> Activity.with_preloaded_bookmark(reading_user)
+ |> Activity.with_set_thread_muted_field(reading_user)
+ |> Repo.all()
+
+ relationships_opt =
+ cond do
+ Map.has_key?(opts, :relationships) ->
+ opts[:relationships]
+
+ is_nil(reading_user) ->
+ UserRelationship.view_relationships_option(nil, [])
+
+ true ->
+ actors = Enum.map(activities ++ parent_activities, &get_user(&1.data["actor"]))
+
+ UserRelationship.view_relationships_option(reading_user, actors)
+ end
+
+ opts =
+ opts
+ |> Map.put(:replied_to_activities, replied_to_activities)
+ |> Map.put(:parent_activities, parent_activities)
+ |> Map.put(:relationships, relationships_opt)
+
+ safe_render_many(activities, StatusView, "show.json", opts)
end
def render(
@@ -85,17 +119,25 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
created_at = Utils.to_masto_date(activity.data["published"])
activity_object = Object.normalize(activity)
- reblogged_activity =
- Activity.create_by_object_ap_id(activity_object.data["id"])
- |> Activity.with_preloaded_bookmark(opts[:for])
- |> Activity.with_set_thread_muted_field(opts[:for])
- |> Repo.one()
+ reblogged_parent_activity =
+ if opts[:parent_activities] do
+ Activity.Queries.find_by_object_ap_id(
+ opts[:parent_activities],
+ activity_object.data["id"]
+ )
+ else
+ Activity.create_by_object_ap_id(activity_object.data["id"])
+ |> Activity.with_preloaded_bookmark(opts[:for])
+ |> Activity.with_set_thread_muted_field(opts[:for])
+ |> Repo.one()
+ end
- reblogged = render("show.json", Map.put(opts, :activity, reblogged_activity))
+ reblog_rendering_opts = Map.put(opts, :activity, reblogged_parent_activity)
+ reblogged = render("show.json", reblog_rendering_opts)
favorited = opts[:for] && opts[:for].ap_id in (activity_object.data["likes"] || [])
- bookmarked = Activity.get_bookmark(reblogged_activity, opts[:for]) != nil
+ bookmarked = Activity.get_bookmark(reblogged_parent_activity, opts[:for]) != nil
mentions =
activity.recipients
@@ -107,7 +149,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
id: to_string(activity.id),
uri: activity_object.data["id"],
url: activity_object.data["id"],
- account: AccountView.render("show.json", %{user: user, for: opts[:for]}),
+ account:
+ AccountView.render("show.json", %{
+ user: user,
+ for: opts[:for],
+ relationships: opts[:relationships]
+ }),
in_reply_to_id: nil,
in_reply_to_account_id: nil,
reblog: reblogged,
@@ -116,7 +163,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
reblogs_count: 0,
replies_count: 0,
favourites_count: 0,
- reblogged: reblogged?(reblogged_activity, opts[:for]),
+ reblogged: reblogged?(reblogged_parent_activity, opts[:for]),
favourited: present?(favorited),
bookmarked: present?(bookmarked),
muted: false,
@@ -183,9 +230,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
thread_muted? =
- case activity.thread_muted? do
- thread_muted? when is_boolean(thread_muted?) -> thread_muted?
- nil -> (opts[:for] && CommonAPI.thread_muted?(opts[:for], activity)) || false
+ cond do
+ is_nil(opts[:for]) -> false
+ is_boolean(activity.thread_muted?) -> activity.thread_muted?
+ true -> CommonAPI.thread_muted?(opts[:for], activity)
end
attachment_data = object.data["attachment"] || []
@@ -253,11 +301,26 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
_ -> []
end
+ muted =
+ thread_muted? ||
+ UserRelationship.exists?(
+ get_in(opts, [:relationships, :user_relationships]),
+ :mute,
+ opts[:for],
+ user,
+ fn for_user, user -> User.mutes?(for_user, user) end
+ )
+
%{
id: to_string(activity.id),
uri: object.data["id"],
url: url,
- account: AccountView.render("show.json", %{user: user, for: opts[:for]}),
+ account:
+ AccountView.render("show.json", %{
+ user: user,
+ for: opts[:for],
+ relationships: opts[:relationships]
+ }),
in_reply_to_id: reply_to && to_string(reply_to.id),
in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id),
reblog: nil,
@@ -270,7 +333,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
reblogged: reblogged?(activity, opts[:for]),
favourited: present?(favorited),
bookmarked: present?(bookmarked),
- muted: thread_muted? || User.mutes?(opts[:for], user),
+ muted: muted,
pinned: pinned?(activity, user),
sensitive: sensitive,
spoiler_text: summary,
@@ -421,7 +484,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
def render_content(%{data: %{"type" => object_type}} = object)
- when object_type in ["Video", "Event"] do
+ when object_type in ["Video", "Event", "Audio"] do
with name when not is_nil(name) and name != "" <- object.data["name"] do
"<p><a href=\"#{object.data["id"]}\">#{name}</a></p>#{object.data["content"]}"
else
diff --git a/lib/pleroma/web/metadata.ex b/lib/pleroma/web/metadata.ex
index c9aac27dc..a9f70c43e 100644
--- a/lib/pleroma/web/metadata.ex
+++ b/lib/pleroma/web/metadata.ex
@@ -6,7 +6,12 @@ defmodule Pleroma.Web.Metadata do
alias Phoenix.HTML
def build_tags(params) do
- Enum.reduce(Pleroma.Config.get([__MODULE__, :providers], []), "", fn parser, acc ->
+ providers = [
+ Pleroma.Web.Metadata.Providers.RestrictIndexing
+ | Pleroma.Config.get([__MODULE__, :providers], [])
+ ]
+
+ Enum.reduce(providers, "", fn parser, acc ->
rendered_html =
params
|> parser.build_tags()
diff --git a/lib/pleroma/web/metadata/opengraph.ex b/lib/pleroma/web/metadata/opengraph.ex
index 21446ac77..68c871e71 100644
--- a/lib/pleroma/web/metadata/opengraph.ex
+++ b/lib/pleroma/web/metadata/opengraph.ex
@@ -68,7 +68,7 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
property: "og:title",
content: Utils.user_name_string(user)
], []},
- {:meta, [property: "og:url", content: User.profile_url(user)], []},
+ {:meta, [property: "og:url", content: user.uri || user.ap_id], []},
{:meta, [property: "og:description", content: truncated_bio], []},
{:meta, [property: "og:type", content: "website"], []},
{:meta, [property: "og:image", content: Utils.attachment_url(User.avatar_url(user))], []},
diff --git a/lib/pleroma/web/metadata/restrict_indexing.ex b/lib/pleroma/web/metadata/restrict_indexing.ex
new file mode 100644
index 000000000..f15607896
--- /dev/null
+++ b/lib/pleroma/web/metadata/restrict_indexing.ex
@@ -0,0 +1,25 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Metadata.Providers.RestrictIndexing do
+ @behaviour Pleroma.Web.Metadata.Providers.Provider
+
+ @moduledoc """
+ Restricts indexing of remote users.
+ """
+
+ @impl true
+ def build_tags(%{user: %{local: false}}) do
+ [
+ {:meta,
+ [
+ name: "robots",
+ content: "noindex, noarchive"
+ ], []}
+ ]
+ end
+
+ @impl true
+ def build_tags(%{user: %{local: true}}), do: []
+end
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
index 30838b1eb..f9a5ddcc0 100644
--- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
+++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
@@ -75,7 +75,8 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
end,
if Config.get([:instance, :safe_dm_mentions]) do
"safe_dm_mentions"
- end
+ end,
+ "pleroma_emoji_reactions"
]
|> Enum.filter(& &1)
diff --git a/lib/pleroma/web/rel_me.ex b/lib/pleroma/web/rel_me.ex
index e97c398dc..8e2b51508 100644
--- a/lib/pleroma/web/rel_me.ex
+++ b/lib/pleroma/web/rel_me.ex
@@ -3,11 +3,9 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RelMe do
- @hackney_options [
+ @options [
pool: :media,
- recv_timeout: 2_000,
- max_body: 2_000_000,
- with_body: true
+ max_body: 2_000_000
]
if Pleroma.Config.get(:env) == :test do
@@ -25,8 +23,18 @@ defmodule Pleroma.Web.RelMe do
def parse(_), do: {:error, "No URL provided"}
defp parse_url(url) do
+ opts =
+ if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do
+ Keyword.merge(@options,
+ recv_timeout: 2_000,
+ with_body: true
+ )
+ else
+ @options
+ end
+
with {:ok, %Tesla.Env{body: html, status: status}} when status in 200..299 <-
- Pleroma.HTTP.get(url, [], adapter: @hackney_options),
+ Pleroma.HTTP.get(url, [], adapter: opts),
{:ok, html_tree} <- Floki.parse_document(html),
data <-
Floki.attribute(html_tree, "link[rel~=me]", "href") ++
diff --git a/lib/pleroma/web/rich_media/parser.ex b/lib/pleroma/web/rich_media/parser.ex
index 0779065ee..40980def8 100644
--- a/lib/pleroma/web/rich_media/parser.ex
+++ b/lib/pleroma/web/rich_media/parser.ex
@@ -3,11 +3,9 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RichMedia.Parser do
- @hackney_options [
+ @options [
pool: :media,
- recv_timeout: 2_000,
- max_body: 2_000_000,
- with_body: true
+ max_body: 2_000_000
]
defp parsers do
@@ -77,8 +75,18 @@ defmodule Pleroma.Web.RichMedia.Parser do
end
defp parse_url(url) do
+ opts =
+ if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do
+ Keyword.merge(@options,
+ recv_timeout: 2_000,
+ with_body: true
+ )
+ else
+ @options
+ end
+
try do
- {:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: @hackney_options)
+ {:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: opts)
html
|> parse_html()
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index e4e3ee704..5a0902739 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -173,6 +173,8 @@ defmodule Pleroma.Web.Router do
get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset)
patch("/users/force_password_reset", AdminAPIController, :force_password_reset)
+ get("/users/:nickname/credentials", AdminAPIController, :show_user_credentials)
+ patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials)
get("/users", AdminAPIController, :list_users)
get("/users/:nickname", AdminAPIController, :user_show)
@@ -184,7 +186,6 @@ defmodule Pleroma.Web.Router do
patch("/users/resend_confirmation_email", AdminAPIController, :resend_confirmation_email)
get("/reports", AdminAPIController, :list_reports)
- get("/grouped_reports", AdminAPIController, :list_grouped_reports)
get("/reports/:id", AdminAPIController, :report_show)
patch("/reports", AdminAPIController, :reports_update)
post("/reports/:id/notes", AdminAPIController, :report_notes_create)
@@ -513,7 +514,7 @@ defmodule Pleroma.Web.Router do
end
pipeline :ostatus do
- plug(:accepts, ["html", "xml", "atom", "activity+json", "json"])
+ plug(:accepts, ["html", "xml", "rss", "atom", "activity+json", "json"])
plug(Pleroma.Plugs.StaticFEPlug)
end
diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex
index 7f9464268..7a35238d7 100644
--- a/lib/pleroma/web/static_fe/static_fe_controller.ex
+++ b/lib/pleroma/web/static_fe/static_fe_controller.ex
@@ -60,7 +60,9 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
content =
if data["content"] do
- Pleroma.HTML.filter_tags(data["content"])
+ data["content"]
+ |> Pleroma.HTML.filter_tags()
+ |> Pleroma.Emoji.Formatter.emojify(Map.get(data, "emoji", %{}))
else
nil
end
diff --git a/lib/pleroma/web/streamer/worker.ex b/lib/pleroma/web/streamer/worker.ex
index 29f992a67..abfed21c8 100644
--- a/lib/pleroma/web/streamer/worker.ex
+++ b/lib/pleroma/web/streamer/worker.ex
@@ -130,7 +130,7 @@ defmodule Pleroma.Web.Streamer.Worker do
defp should_send?(%User{} = user, %Activity{} = item) do
%{block: blocked_ap_ids, mute: muted_ap_ids, reblog_mute: reblog_muted_ap_ids} =
- User.outgoing_relations_ap_ids(user, [:block, :mute, :reblog_mute])
+ User.outgoing_relationships_ap_ids(user, [:block, :mute, :reblog_mute])
recipient_blocks = MapSet.new(blocked_ap_ids ++ muted_ap_ids)
recipients = MapSet.new(item.recipients)
diff --git a/lib/pleroma/web/templates/feed/feed/_activity.xml.eex b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex
index ac8a75009..ac8a75009 100644
--- a/lib/pleroma/web/templates/feed/feed/_activity.xml.eex
+++ b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex
diff --git a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex
new file mode 100644
index 000000000..a4dbed638
--- /dev/null
+++ b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex
@@ -0,0 +1,49 @@
+<item>
+ <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
+ <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
+ <guid><%= @data["id"] %></guid>
+ <title><%= activity_title(@object, Keyword.get(@feed_config, :post_title, %{})) %></title>
+ <description><%= activity_content(@object) %></description>
+ <pubDate><%= @data["published"] %></pubDate>
+ <updated><%= @data["published"] %></updated>
+ <ostatus:conversation ref="<%= activity_context(@activity) %>">
+ <%= activity_context(@activity) %>
+ </ostatus:conversation>
+ <link rel="ostatus:conversation"><%= activity_context(@activity) %></link>
+
+ <%= if @data["summary"] do %>
+ <description><%= @data["summary"] %></description>
+ <% end %>
+
+ <%= if @activity.local do %>
+ <link><%= @data["id"] %></link>
+ <% else %>
+ <link><%= @data["external_url"] %></link>
+ <% end %>
+
+ <%= for tag <- @data["tag"] || [] do %>
+ <category term="<%= tag %>"></category>
+ <% end %>
+
+ <%= for attachment <- @data["attachment"] || [] do %>
+ <link type="<%= attachment_type(attachment) %>"><%= attachment_href(attachment) %></link>
+ <% end %>
+
+ <%= if @data["inReplyTo"] do %>
+ <thr:in-reply-to ref='<%= @data["inReplyTo"] %>' href='<%= get_href(@data["inReplyTo"]) %>'/>
+ <% end %>
+
+ <%= for id <- @activity.recipients do %>
+ <%= if id == Pleroma.Constants.as_public() do %>
+ <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection">http://activityschema.org/collection/public</link>
+ <% else %>
+ <%= unless Regex.match?(~r/^#{Pleroma.Web.base_url()}.+followers$/, id) do %>
+ <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person"><%= id %></link>
+ <% end %>
+ <% end %>
+ <% end %>
+
+ <%= for {emoji, file} <- @data["emoji"] || %{} do %>
+ <link name="<%= emoji %>" rel="emoji"><%= file %></link>
+ <% end %>
+</item>
diff --git a/lib/pleroma/web/templates/feed/feed/_author.xml.eex b/lib/pleroma/web/templates/feed/feed/_author.atom.eex
index 25cbffada..25cbffada 100644
--- a/lib/pleroma/web/templates/feed/feed/_author.xml.eex
+++ b/lib/pleroma/web/templates/feed/feed/_author.atom.eex
diff --git a/lib/pleroma/web/templates/feed/feed/_author.rss.eex b/lib/pleroma/web/templates/feed/feed/_author.rss.eex
new file mode 100644
index 000000000..526aeddcf
--- /dev/null
+++ b/lib/pleroma/web/templates/feed/feed/_author.rss.eex
@@ -0,0 +1,17 @@
+<managingEditor>
+ <guid><%= @user.ap_id %></guid>
+ <activity:object>http://activitystrea.ms/schema/1.0/person</activity:object>
+ <uri><%= @user.ap_id %></uri>
+ <poco:preferredUsername><%= @user.nickname %></poco:preferredUsername>
+ <poco:displayName><%= @user.name %></poco:displayName>
+ <poco:note><%= escape(@user.bio) %></poco:note>
+ <description><%= escape(@user.bio) %></description>
+ <name><%= @user.nickname %></name>
+ <link rel="avatar"><%= User.avatar_url(@user) %></link>
+ <%= if User.banner_url(@user) do %>
+ <link rel="header"><%= User.banner_url(@user) %></link>
+ <% end %>
+ <%= if @user.local do %>
+ <ap_enabled>true</ap_enabled>
+ <% end %>
+</managingEditor>
diff --git a/lib/pleroma/web/templates/feed/feed/user.xml.eex b/lib/pleroma/web/templates/feed/feed/user.atom.eex
index d274c08ae..c6acd848f 100644
--- a/lib/pleroma/web/templates/feed/feed/user.xml.eex
+++ b/lib/pleroma/web/templates/feed/feed/user.atom.eex
@@ -12,13 +12,13 @@
<logo><%= logo(@user) %></logo>
<link rel="self" href="<%= '#{user_feed_url(@conn, :feed, @user.nickname)}.atom' %>" type="application/atom+xml"/>
- <%= render @view_module, "_author.xml", assigns %>
+ <%= render @view_module, "_author.atom", assigns %>
<%= if last_activity(@activities) do %>
<link rel="next" href="<%= '#{user_feed_url(@conn, :feed, @user.nickname)}.atom?max_id=#{last_activity(@activities).id}' %>" type="application/atom+xml"/>
<% end %>
<%= for activity <- @activities do %>
- <%= render @view_module, "_activity.xml", Map.merge(assigns, prepare_activity(activity)) %>
+ <%= render @view_module, "_activity.atom", Map.merge(assigns, prepare_activity(activity)) %>
<% end %>
</feed>
diff --git a/lib/pleroma/web/templates/feed/feed/user.rss.eex b/lib/pleroma/web/templates/feed/feed/user.rss.eex
new file mode 100644
index 000000000..d69120480
--- /dev/null
+++ b/lib/pleroma/web/templates/feed/feed/user.rss.eex
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<rss version="2.0">
+ <channel>
+ <guid><%= user_feed_url(@conn, :feed, @user.nickname) <> ".rss" %></guid>
+ <title><%= @user.nickname <> "'s timeline" %></title>
+ <updated><%= most_recent_update(@activities, @user) %></updated>
+ <image><%= logo(@user) %></image>
+ <link><%= '#{user_feed_url(@conn, :feed, @user.nickname)}.rss' %></link>
+
+ <%= render @view_module, "_author.rss", assigns %>
+
+ <%= if last_activity(@activities) do %>
+ <link rel="next"><%= '#{user_feed_url(@conn, :feed, @user.nickname)}.rss?max_id=#{last_activity(@activities).id}' %></link>
+ <% end %>
+
+ <%= for activity <- @activities do %>
+ <%= render @view_module, "_activity.rss", Map.merge(assigns, prepare_activity(activity)) %>
+ <% end %>
+ </channel>
+</rss>
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex
index c7789f9ac..2a7582d45 100644
--- a/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex
+++ b/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex
@@ -1,5 +1,5 @@
<div class="p-author h-card">
- <a class="u-url" rel="author noopener" href="<%= User.profile_url(@user) %>">
+ <a class="u-url" rel="author noopener" href="<%= (@user.uri || @user.ap_id) %>">
<div class="avatar">
<img src="<%= User.avatar_url(@user) |> MediaProxy.url %>" width="48" height="48" alt="">
</div>
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex
index 94063c92d..e7d2aecad 100644
--- a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex
+++ b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex
@@ -8,7 +8,7 @@
<button type="submit" class="collapse">Remote follow</button>
</form>
<%= raw Formatter.emojify(@user.name, emoji_for_user(@user)) %> |
- <%= link "@#{@user.nickname}@#{Endpoint.host()}", to: User.profile_url(@user) %>
+ <%= link "@#{@user.nickname}@#{Endpoint.host()}", to: (@user.uri || @user.ap_id) %>
</h3>
<p><%= raw @user.bio %></p>
</header>
diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex
index 43a81c75d..7ffd0e51b 100644
--- a/lib/pleroma/web/web_finger/web_finger.ex
+++ b/lib/pleroma/web/web_finger/web_finger.ex
@@ -173,7 +173,8 @@ defmodule Pleroma.Web.WebFinger do
get_template_from_xml(body)
else
_ ->
- with {:ok, %{body: body}} <- HTTP.get("https://#{domain}/.well-known/host-meta", []) do
+ with {:ok, %{body: body, status: status}} when status in 200..299 <-
+ HTTP.get("https://#{domain}/.well-known/host-meta", []) do
get_template_from_xml(body)
else
e -> {:error, "Can't find LRDD template: #{inspect(e)}"}
@@ -205,7 +206,7 @@ defmodule Pleroma.Web.WebFinger do
with response <-
HTTP.get(
address,
- Accept: "application/xrd+xml,application/jrd+json"
+ [{"accept", "application/xrd+xml,application/jrd+json"}]
),
{:ok, %{status: status, body: body}} when status in 200..299 <- response do
doc = XML.parse_document(body)