Merge branch 'develop' into feature/digest-email
This commit is contained in:
commit
6ef145b4fc
73 changed files with 2589 additions and 518 deletions
|
|
@ -29,13 +29,13 @@ defmodule Pleroma.Healthcheck do
|
|||
end
|
||||
|
||||
defp assign_db_info(healthcheck) do
|
||||
database = Application.get_env(:pleroma, Repo)[:database]
|
||||
database = Pleroma.Config.get([Repo, :database])
|
||||
|
||||
query =
|
||||
"select state, count(pid) from pg_stat_activity where datname = '#{database}' group by state;"
|
||||
|
||||
result = Repo.query!(query)
|
||||
pool_size = Application.get_env(:pleroma, Repo)[:pool_size]
|
||||
pool_size = Pleroma.Config.get([Repo, :pool_size])
|
||||
|
||||
db_info =
|
||||
Enum.reduce(result.rows, %{active: 0, idle: 0}, fn [state, cnt], states ->
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ defmodule Pleroma.Conversation do
|
|||
with true <- Pleroma.Web.ActivityPub.Visibility.is_direct?(activity),
|
||||
"Create" <- activity.data["type"],
|
||||
object <- Pleroma.Object.normalize(activity),
|
||||
"Note" <- object.data["type"],
|
||||
true <- object.data["type"] in ["Note", "Question"],
|
||||
ap_id when is_binary(ap_id) and byte_size(ap_id) > 0 <- object.data["context"] do
|
||||
{:ok, conversation} = create_for_ap_id(ap_id)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ defmodule Pleroma.Emoji do
|
|||
|
||||
@ets __MODULE__.Ets
|
||||
@ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}]
|
||||
@groups Application.get_env(:pleroma, :emoji)[:groups]
|
||||
@groups Pleroma.Config.get([:emoji, :groups])
|
||||
|
||||
@doc false
|
||||
def start_link do
|
||||
|
|
@ -112,7 +112,7 @@ defmodule Pleroma.Emoji do
|
|||
|
||||
# Compat thing for old custom emoji handling & default emoji,
|
||||
# it should run even if there are no emoji packs
|
||||
shortcode_globs = Application.get_env(:pleroma, :emoji)[:shortcode_globs] || []
|
||||
shortcode_globs = Pleroma.Config.get([:emoji, :shortcode_globs], [])
|
||||
|
||||
emojis =
|
||||
(load_from_file("config/emoji.txt") ++
|
||||
|
|
|
|||
|
|
@ -104,7 +104,6 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
|
|||
paragraphs, breaks and links are allowed through the filter.
|
||||
"""
|
||||
|
||||
@markup Application.get_env(:pleroma, :markup)
|
||||
@valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], [])
|
||||
|
||||
require HtmlSanitizeEx.Scrubber.Meta
|
||||
|
|
@ -142,9 +141,7 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
|
|||
Meta.allow_tag_with_these_attributes("span", [])
|
||||
|
||||
# allow inline images for custom emoji
|
||||
@allow_inline_images Keyword.get(@markup, :allow_inline_images)
|
||||
|
||||
if @allow_inline_images do
|
||||
if Pleroma.Config.get([:markup, :allow_inline_images]) do
|
||||
# restrict img tags to http/https only, because of MediaProxy.
|
||||
Meta.allow_tag_with_uri_attributes("img", ["src"], ["http", "https"])
|
||||
|
||||
|
|
@ -168,7 +165,6 @@ defmodule Pleroma.HTML.Scrubber.Default do
|
|||
# credo:disable-for-previous-line
|
||||
# No idea how to fix this one…
|
||||
|
||||
@markup Application.get_env(:pleroma, :markup)
|
||||
@valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], [])
|
||||
|
||||
Meta.remove_cdata_sections_before_scrub()
|
||||
|
|
@ -213,7 +209,7 @@ defmodule Pleroma.HTML.Scrubber.Default do
|
|||
Meta.allow_tag_with_this_attribute_values("span", "class", ["h-card"])
|
||||
Meta.allow_tag_with_these_attributes("span", [])
|
||||
|
||||
@allow_inline_images Keyword.get(@markup, :allow_inline_images)
|
||||
@allow_inline_images Pleroma.Config.get([:markup, :allow_inline_images])
|
||||
|
||||
if @allow_inline_images do
|
||||
# restrict img tags to http/https only, because of MediaProxy.
|
||||
|
|
@ -228,9 +224,7 @@ defmodule Pleroma.HTML.Scrubber.Default do
|
|||
])
|
||||
end
|
||||
|
||||
@allow_tables Keyword.get(@markup, :allow_tables)
|
||||
|
||||
if @allow_tables do
|
||||
if Pleroma.Config.get([:markup, :allow_tables]) do
|
||||
Meta.allow_tag_with_these_attributes("table", [])
|
||||
Meta.allow_tag_with_these_attributes("tbody", [])
|
||||
Meta.allow_tag_with_these_attributes("td", [])
|
||||
|
|
@ -239,9 +233,7 @@ defmodule Pleroma.HTML.Scrubber.Default do
|
|||
Meta.allow_tag_with_these_attributes("tr", [])
|
||||
end
|
||||
|
||||
@allow_headings Keyword.get(@markup, :allow_headings)
|
||||
|
||||
if @allow_headings do
|
||||
if Pleroma.Config.get([:markup, :allow_headings]) do
|
||||
Meta.allow_tag_with_these_attributes("h1", [])
|
||||
Meta.allow_tag_with_these_attributes("h2", [])
|
||||
Meta.allow_tag_with_these_attributes("h3", [])
|
||||
|
|
@ -249,9 +241,7 @@ defmodule Pleroma.HTML.Scrubber.Default do
|
|||
Meta.allow_tag_with_these_attributes("h5", [])
|
||||
end
|
||||
|
||||
@allow_fonts Keyword.get(@markup, :allow_fonts)
|
||||
|
||||
if @allow_fonts do
|
||||
if Pleroma.Config.get([:markup, :allow_fonts]) do
|
||||
Meta.allow_tag_with_these_attributes("font", ["face"])
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -65,12 +65,9 @@ defmodule Pleroma.HTTP do
|
|||
end
|
||||
|
||||
def process_request_options(options) do
|
||||
config = Application.get_env(:pleroma, :http, [])
|
||||
proxy = Keyword.get(config, :proxy_url, nil)
|
||||
|
||||
case proxy do
|
||||
case Pleroma.Config.get([:http, :proxy_url]) do
|
||||
nil -> options
|
||||
_ -> options ++ [proxy: proxy]
|
||||
proxy -> options ++ [proxy: proxy]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -151,10 +151,15 @@ defmodule Pleroma.Notification do
|
|||
|
||||
def create_notifications(%Activity{data: %{"to" => _, "type" => type}} = activity)
|
||||
when type in ["Create", "Like", "Announce", "Follow"] do
|
||||
users = get_notified_from_activity(activity)
|
||||
object = Object.normalize(activity)
|
||||
|
||||
notifications = Enum.map(users, fn user -> create_notification(activity, user) end)
|
||||
{:ok, notifications}
|
||||
unless object && object.data["type"] == "Answer" do
|
||||
users = get_notified_from_activity(activity)
|
||||
notifications = Enum.map(users, fn user -> create_notification(activity, user) end)
|
||||
{:ok, notifications}
|
||||
else
|
||||
{:ok, []}
|
||||
end
|
||||
end
|
||||
|
||||
def create_notifications(_), do: {:ok, []}
|
||||
|
|
@ -190,7 +195,16 @@ defmodule Pleroma.Notification do
|
|||
def get_notified_from_activity(_, _local_only), do: []
|
||||
|
||||
def skip?(activity, user) do
|
||||
[:self, :blocked, :local, :muted, :followers, :follows, :recently_followed]
|
||||
[
|
||||
:self,
|
||||
:blocked,
|
||||
:muted,
|
||||
:followers,
|
||||
:follows,
|
||||
:non_followers,
|
||||
:non_follows,
|
||||
:recently_followed
|
||||
]
|
||||
|> Enum.any?(&skip?(&1, activity, user))
|
||||
end
|
||||
|
||||
|
|
@ -203,12 +217,6 @@ defmodule Pleroma.Notification do
|
|||
User.blocks?(user, %{ap_id: actor})
|
||||
end
|
||||
|
||||
def skip?(:local, %{local: true}, %{info: %{notification_settings: %{"local" => false}}}),
|
||||
do: true
|
||||
|
||||
def skip?(:local, %{local: false}, %{info: %{notification_settings: %{"remote" => false}}}),
|
||||
do: true
|
||||
|
||||
def skip?(:muted, activity, user) do
|
||||
actor = activity.data["actor"]
|
||||
|
||||
|
|
@ -225,12 +233,32 @@ defmodule Pleroma.Notification do
|
|||
User.following?(follower, user)
|
||||
end
|
||||
|
||||
def skip?(
|
||||
:non_followers,
|
||||
activity,
|
||||
%{info: %{notification_settings: %{"non_followers" => false}}} = user
|
||||
) do
|
||||
actor = activity.data["actor"]
|
||||
follower = User.get_cached_by_ap_id(actor)
|
||||
!User.following?(follower, user)
|
||||
end
|
||||
|
||||
def skip?(:follows, activity, %{info: %{notification_settings: %{"follows" => false}}} = user) do
|
||||
actor = activity.data["actor"]
|
||||
followed = User.get_cached_by_ap_id(actor)
|
||||
User.following?(user, followed)
|
||||
end
|
||||
|
||||
def skip?(
|
||||
:non_follows,
|
||||
activity,
|
||||
%{info: %{notification_settings: %{"non_follows" => false}}} = user
|
||||
) do
|
||||
actor = activity.data["actor"]
|
||||
followed = User.get_cached_by_ap_id(actor)
|
||||
!User.following?(user, followed)
|
||||
end
|
||||
|
||||
def skip?(:recently_followed, %{data: %{"type" => "Follow"}} = activity, user) do
|
||||
actor = activity.data["actor"]
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ defmodule Pleroma.Object do
|
|||
|> unique_constraint(:ap_id, name: :objects_unique_apid_index)
|
||||
end
|
||||
|
||||
def get_by_id(nil), do: nil
|
||||
def get_by_id(id), do: Repo.get(Object, id)
|
||||
|
||||
def get_by_ap_id(nil), do: nil
|
||||
|
||||
def get_by_ap_id(ap_id) do
|
||||
|
|
@ -195,4 +198,34 @@ defmodule Pleroma.Object do
|
|||
_ -> {:error, "Not found"}
|
||||
end
|
||||
end
|
||||
|
||||
def increase_vote_count(ap_id, name) do
|
||||
with %Object{} = object <- Object.normalize(ap_id),
|
||||
"Question" <- object.data["type"] do
|
||||
multiple = Map.has_key?(object.data, "anyOf")
|
||||
|
||||
options =
|
||||
(object.data["anyOf"] || object.data["oneOf"] || [])
|
||||
|> Enum.map(fn
|
||||
%{"name" => ^name} = option ->
|
||||
Kernel.update_in(option["replies"]["totalItems"], &(&1 + 1))
|
||||
|
||||
option ->
|
||||
option
|
||||
end)
|
||||
|
||||
data =
|
||||
if multiple do
|
||||
Map.put(object.data, "anyOf", options)
|
||||
else
|
||||
Map.put(object.data, "oneOf", options)
|
||||
end
|
||||
|
||||
object
|
||||
|> Object.change(%{data: data})
|
||||
|> update_and_set_cache()
|
||||
else
|
||||
_ -> :noop
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ defmodule Pleroma.Web.FederatingPlug do
|
|||
end
|
||||
|
||||
def call(conn, _opts) do
|
||||
if Keyword.get(Application.get_env(:pleroma, :instance), :federating) do
|
||||
if Pleroma.Config.get([:instance, :federating]) do
|
||||
conn
|
||||
else
|
||||
conn
|
||||
|
|
|
|||
|
|
@ -61,8 +61,6 @@ defmodule Pleroma.ReverseProxy do
|
|||
* `http`: options for [hackney](https://github.com/benoitc/hackney).
|
||||
|
||||
"""
|
||||
@hackney Application.get_env(:pleroma, :hackney, :hackney)
|
||||
|
||||
@default_hackney_options []
|
||||
|
||||
@inline_content_types [
|
||||
|
|
@ -148,7 +146,7 @@ defmodule Pleroma.ReverseProxy do
|
|||
Logger.debug("#{__MODULE__} #{method} #{url} #{inspect(headers)}")
|
||||
method = method |> String.downcase() |> String.to_existing_atom()
|
||||
|
||||
case @hackney.request(method, url, headers, "", hackney_opts) do
|
||||
case :hackney.request(method, url, headers, "", hackney_opts) do
|
||||
{:ok, code, headers, client} when code in @valid_resp_codes ->
|
||||
{:ok, code, downcase_headers(headers), client}
|
||||
|
||||
|
|
@ -198,7 +196,7 @@ defmodule Pleroma.ReverseProxy do
|
|||
duration,
|
||||
Keyword.get(opts, :max_read_duration, @max_read_duration)
|
||||
),
|
||||
{:ok, data} <- @hackney.stream_body(client),
|
||||
{:ok, data} <- :hackney.stream_body(client),
|
||||
{:ok, duration} <- increase_read_duration(duration),
|
||||
sent_so_far = sent_so_far + byte_size(data),
|
||||
:ok <- body_size_constraint(sent_so_far, Keyword.get(opts, :max_body_size)),
|
||||
|
|
|
|||
|
|
@ -367,9 +367,7 @@ defmodule Pleroma.User do
|
|||
end
|
||||
|
||||
def follow(%User{} = follower, %User{info: info} = followed) do
|
||||
user_config = Application.get_env(:pleroma, :user)
|
||||
deny_follow_blocked = Keyword.get(user_config, :deny_follow_blocked)
|
||||
|
||||
deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked])
|
||||
ap_followers = followed.follower_address
|
||||
|
||||
cond do
|
||||
|
|
@ -761,7 +759,7 @@ defmodule Pleroma.User do
|
|||
|
||||
from(s in subquery(boost_search_rank_query(distinct_query, for_user)),
|
||||
order_by: [desc: s.search_rank],
|
||||
limit: 20
|
||||
limit: 40
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,12 @@ defmodule Pleroma.User.Info do
|
|||
field(:emoji, {:array, :map}, default: [])
|
||||
|
||||
field(:notification_settings, :map,
|
||||
default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true}
|
||||
default: %{
|
||||
"followers" => true,
|
||||
"follows" => true,
|
||||
"non_follows" => true,
|
||||
"non_followers" => true
|
||||
}
|
||||
)
|
||||
|
||||
# Found in the wild
|
||||
|
|
@ -69,10 +74,15 @@ defmodule Pleroma.User.Info do
|
|||
end
|
||||
|
||||
def update_notification_settings(info, settings) do
|
||||
settings =
|
||||
settings
|
||||
|> Enum.map(fn {k, v} -> {k, v in [true, "true", "True", "1"]} end)
|
||||
|> Map.new()
|
||||
|
||||
notification_settings =
|
||||
info.notification_settings
|
||||
|> Map.merge(settings)
|
||||
|> Map.take(["remote", "local", "followers", "follows"])
|
||||
|> Map.take(["followers", "follows", "non_follows", "non_followers"])
|
||||
|
||||
params = %{notification_settings: notification_settings}
|
||||
|
||||
|
|
@ -266,14 +276,6 @@ defmodule Pleroma.User.Info do
|
|||
|> validate_required([:settings])
|
||||
end
|
||||
|
||||
def mastodon_flavour_update(info, flavour) do
|
||||
params = %{flavour: flavour}
|
||||
|
||||
info
|
||||
|> cast(params, [:flavour])
|
||||
|> validate_required([:flavour])
|
||||
end
|
||||
|
||||
def mascot_update(info, url) do
|
||||
params = %{mascot: url}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,6 +108,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
def decrease_replies_count_if_reply(_object), do: :noop
|
||||
|
||||
def increase_poll_votes_if_vote(%{
|
||||
"object" => %{"inReplyTo" => reply_ap_id, "name" => name},
|
||||
"type" => "Create"
|
||||
}) do
|
||||
Object.increase_vote_count(reply_ap_id, name)
|
||||
end
|
||||
|
||||
def increase_poll_votes_if_vote(_create_data), do: :noop
|
||||
|
||||
def insert(map, local \\ true, fake \\ false) when is_map(map) do
|
||||
with nil <- Activity.normalize(map),
|
||||
map <- lazy_put_activity_defaults(map, fake),
|
||||
|
|
@ -183,40 +192,42 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
public = "https://www.w3.org/ns/activitystreams#Public"
|
||||
|
||||
if activity.data["type"] in ["Create", "Announce", "Delete"] do
|
||||
Pleroma.Web.Streamer.stream("user", activity)
|
||||
Pleroma.Web.Streamer.stream("list", activity)
|
||||
object = Object.normalize(activity)
|
||||
# Do not stream out poll replies
|
||||
unless object.data["type"] == "Answer" do
|
||||
Pleroma.Web.Streamer.stream("user", activity)
|
||||
Pleroma.Web.Streamer.stream("list", activity)
|
||||
|
||||
if Enum.member?(activity.data["to"], public) do
|
||||
Pleroma.Web.Streamer.stream("public", activity)
|
||||
if Enum.member?(activity.data["to"], public) do
|
||||
Pleroma.Web.Streamer.stream("public", activity)
|
||||
|
||||
if activity.local do
|
||||
Pleroma.Web.Streamer.stream("public:local", activity)
|
||||
end
|
||||
if activity.local do
|
||||
Pleroma.Web.Streamer.stream("public:local", activity)
|
||||
end
|
||||
|
||||
if activity.data["type"] in ["Create"] do
|
||||
object = Object.normalize(activity)
|
||||
if activity.data["type"] in ["Create"] do
|
||||
object.data
|
||||
|> Map.get("tag", [])
|
||||
|> Enum.filter(fn tag -> is_bitstring(tag) end)
|
||||
|> Enum.each(fn tag -> Pleroma.Web.Streamer.stream("hashtag:" <> tag, activity) end)
|
||||
|
||||
object.data
|
||||
|> Map.get("tag", [])
|
||||
|> Enum.filter(fn tag -> is_bitstring(tag) end)
|
||||
|> Enum.each(fn tag -> Pleroma.Web.Streamer.stream("hashtag:" <> tag, activity) end)
|
||||
if object.data["attachment"] != [] do
|
||||
Pleroma.Web.Streamer.stream("public:media", activity)
|
||||
|
||||
if object.data["attachment"] != [] do
|
||||
Pleroma.Web.Streamer.stream("public:media", activity)
|
||||
|
||||
if activity.local do
|
||||
Pleroma.Web.Streamer.stream("public:local:media", activity)
|
||||
if activity.local do
|
||||
Pleroma.Web.Streamer.stream("public:local:media", activity)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
# TODO: Write test, replace with visibility test
|
||||
if !Enum.member?(activity.data["cc"] || [], public) &&
|
||||
!Enum.member?(
|
||||
activity.data["to"],
|
||||
User.get_cached_by_ap_id(activity.data["actor"]).follower_address
|
||||
),
|
||||
do: Pleroma.Web.Streamer.stream("direct", activity)
|
||||
end
|
||||
else
|
||||
# TODO: Write test, replace with visibility test
|
||||
if !Enum.member?(activity.data["cc"] || [], public) &&
|
||||
!Enum.member?(
|
||||
activity.data["to"],
|
||||
User.get_cached_by_ap_id(activity.data["actor"]).follower_address
|
||||
),
|
||||
do: Pleroma.Web.Streamer.stream("direct", activity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -235,6 +246,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
{:ok, activity} <- insert(create_data, local, fake),
|
||||
{:fake, false, activity} <- {:fake, fake, activity},
|
||||
_ <- increase_replies_count_if_reply(create_data),
|
||||
_ <- increase_poll_votes_if_vote(create_data),
|
||||
# Changing note count prior to enqueuing federation task in order to avoid
|
||||
# race conditions on updating user.info
|
||||
{:ok, _actor} <- increase_note_count_if_public(actor, activity),
|
||||
|
|
@ -399,16 +411,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
end
|
||||
|
||||
def block(blocker, blocked, activity_id \\ nil, local \\ true) do
|
||||
ap_config = Application.get_env(:pleroma, :activitypub)
|
||||
unfollow_blocked = Keyword.get(ap_config, :unfollow_blocked)
|
||||
outgoing_blocks = Keyword.get(ap_config, :outgoing_blocks)
|
||||
outgoing_blocks = Pleroma.Config.get([:activitypub, :outgoing_blocks])
|
||||
unfollow_blocked = Pleroma.Config.get([:activitypub, :unfollow_blocked])
|
||||
|
||||
with true <- unfollow_blocked do
|
||||
if unfollow_blocked do
|
||||
follow_activity = fetch_latest_follow(blocker, blocked)
|
||||
|
||||
if follow_activity do
|
||||
unfollow(blocker, blocked, nil, local)
|
||||
end
|
||||
if follow_activity, do: unfollow(blocker, blocked, nil, local)
|
||||
end
|
||||
|
||||
with true <- outgoing_blocks,
|
||||
|
|
@ -480,6 +488,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public
|
||||
|
||||
from(activity in Activity)
|
||||
|> maybe_preload_objects(opts)
|
||||
|> restrict_blocked(opts)
|
||||
|> restrict_recipients(recipients, opts["user"])
|
||||
|> where(
|
||||
|
|
@ -492,6 +501,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
^context
|
||||
)
|
||||
)
|
||||
|> exclude_poll_votes(opts)
|
||||
|> order_by([activity], desc: activity.id)
|
||||
end
|
||||
|
||||
|
|
@ -499,7 +509,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
def fetch_activities_for_context(context, opts \\ %{}) do
|
||||
context
|
||||
|> fetch_activities_for_context_query(opts)
|
||||
|> Activity.with_preloaded_object()
|
||||
|> Repo.all()
|
||||
end
|
||||
|
||||
|
|
@ -507,7 +516,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
Pleroma.FlakeId.t() | nil
|
||||
def fetch_latest_activity_id_for_context(context, opts \\ %{}) do
|
||||
context
|
||||
|> fetch_activities_for_context_query(opts)
|
||||
|> fetch_activities_for_context_query(Map.merge(%{"skip_preload" => true}, opts))
|
||||
|> limit(1)
|
||||
|> select([a], a.id)
|
||||
|> Repo.one()
|
||||
|
|
@ -653,20 +662,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
defp restrict_tag(query, _), do: query
|
||||
|
||||
defp restrict_to_cc(query, recipients_to, recipients_cc) do
|
||||
from(
|
||||
activity in query,
|
||||
where:
|
||||
fragment(
|
||||
"(?->'to' \\?| ?) or (?->'cc' \\?| ?)",
|
||||
activity.data,
|
||||
^recipients_to,
|
||||
activity.data,
|
||||
^recipients_cc
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
defp restrict_recipients(query, [], _user), do: query
|
||||
|
||||
defp restrict_recipients(query, recipients, nil) do
|
||||
|
|
@ -820,6 +815,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
defp restrict_muted_reblogs(query, _), do: query
|
||||
|
||||
defp exclude_poll_votes(query, %{"include_poll_votes" => "true"}), do: query
|
||||
|
||||
defp exclude_poll_votes(query, _) do
|
||||
if has_named_binding?(query, :object) do
|
||||
from([activity, object: o] in query,
|
||||
where: fragment("not(?->>'type' = ?)", o.data, "Answer")
|
||||
)
|
||||
else
|
||||
query
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_preload_objects(query, %{"skip_preload" => true}), do: query
|
||||
|
||||
defp maybe_preload_objects(query, _) do
|
||||
|
|
@ -881,6 +888,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|> restrict_pinned(opts)
|
||||
|> restrict_muted_reblogs(opts)
|
||||
|> Activity.restrict_deactivated_users()
|
||||
|> exclude_poll_votes(opts)
|
||||
end
|
||||
|
||||
def fetch_activities(recipients, opts \\ %{}) do
|
||||
|
|
@ -889,9 +897,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|> Enum.reverse()
|
||||
end
|
||||
|
||||
def fetch_activities_bounded(recipients_to, recipients_cc, opts \\ %{}) do
|
||||
def fetch_activities_bounded_query(query, recipients, recipients_with_public) do
|
||||
from(activity in query,
|
||||
where:
|
||||
fragment("? && ?", activity.recipients, ^recipients) or
|
||||
(fragment("? && ?", activity.recipients, ^recipients_with_public) and
|
||||
"https://www.w3.org/ns/activitystreams#Public" in activity.recipients)
|
||||
)
|
||||
end
|
||||
|
||||
def fetch_activities_bounded(recipients, recipients_with_public, opts \\ %{}) do
|
||||
fetch_activities_query([], opts)
|
||||
|> restrict_to_cc(recipients_to, recipients_cc)
|
||||
|> fetch_activities_bounded_query(recipients, recipients_with_public)
|
||||
|> Pagination.fetch_paginated(opts)
|
||||
|> Enum.reverse()
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
plug(:relay_active? when action in [:relay])
|
||||
|
||||
def relay_active?(conn, _) do
|
||||
if Keyword.get(Application.get_env(:pleroma, :instance), :allow_relay) do
|
||||
if Pleroma.Config.get([:instance, :allow_relay]) do
|
||||
conn
|
||||
else
|
||||
conn
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@ defmodule Pleroma.Web.ActivityPub.MRF do
|
|||
end
|
||||
|
||||
def get_policies do
|
||||
Application.get_env(:pleroma, :instance, [])
|
||||
|> Keyword.get(:rewrite_policy, [])
|
||||
|> get_policies()
|
||||
Pleroma.Config.get([:instance, :rewrite_policy], []) |> get_policies()
|
||||
end
|
||||
|
||||
defp get_policies(policy) when is_atom(policy), do: [policy]
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|> fix_likes
|
||||
|> fix_addressing
|
||||
|> fix_summary
|
||||
|> fix_type
|
||||
end
|
||||
|
||||
def fix_summary(%{"summary" => nil} = object) do
|
||||
|
|
@ -65,7 +66,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
end
|
||||
end
|
||||
|
||||
def fix_explicit_addressing(%{"to" => to, "cc" => cc} = object, explicit_mentions) do
|
||||
def fix_explicit_addressing(
|
||||
%{"to" => to, "cc" => cc} = object,
|
||||
explicit_mentions,
|
||||
follower_collection
|
||||
) do
|
||||
explicit_to =
|
||||
to
|
||||
|> Enum.filter(fn x -> x in explicit_mentions end)
|
||||
|
|
@ -76,6 +81,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|
||||
final_cc =
|
||||
(cc ++ explicit_cc)
|
||||
|> Enum.reject(fn x -> String.ends_with?(x, "/followers") and x != follower_collection end)
|
||||
|> Enum.uniq()
|
||||
|
||||
object
|
||||
|
|
@ -83,7 +89,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|> Map.put("cc", final_cc)
|
||||
end
|
||||
|
||||
def fix_explicit_addressing(object, _explicit_mentions), do: object
|
||||
def fix_explicit_addressing(object, _explicit_mentions, _followers_collection), do: object
|
||||
|
||||
# if directMessage flag is set to true, leave the addressing alone
|
||||
def fix_explicit_addressing(%{"directMessage" => true} = object), do: object
|
||||
|
|
@ -93,10 +99,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
object
|
||||
|> Utils.determine_explicit_mentions()
|
||||
|
||||
explicit_mentions = explicit_mentions ++ ["https://www.w3.org/ns/activitystreams#Public"]
|
||||
follower_collection = User.get_cached_by_ap_id(Containment.get_actor(object)).follower_address
|
||||
|
||||
object
|
||||
|> fix_explicit_addressing(explicit_mentions)
|
||||
explicit_mentions =
|
||||
explicit_mentions ++ ["https://www.w3.org/ns/activitystreams#Public", follower_collection]
|
||||
|
||||
fix_explicit_addressing(object, explicit_mentions, follower_collection)
|
||||
end
|
||||
|
||||
# if as:Public is addressed, then make sure the followers collection is also addressed
|
||||
|
|
@ -133,7 +141,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|> fix_addressing_list("cc")
|
||||
|> fix_addressing_list("bto")
|
||||
|> fix_addressing_list("bcc")
|
||||
|> fix_explicit_addressing
|
||||
|> fix_explicit_addressing()
|
||||
|> fix_implicit_addressing(followers_collection)
|
||||
end
|
||||
|
||||
|
|
@ -328,6 +336,18 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|
||||
def fix_content_map(object), do: object
|
||||
|
||||
def fix_type(%{"inReplyTo" => reply_id} = object) when is_binary(reply_id) do
|
||||
reply = Object.normalize(reply_id)
|
||||
|
||||
if reply.data["type"] == "Question" and object["name"] do
|
||||
Map.put(object, "type", "Answer")
|
||||
else
|
||||
object
|
||||
end
|
||||
end
|
||||
|
||||
def fix_type(object), do: object
|
||||
|
||||
defp mastodon_follow_hack(%{"id" => id, "actor" => follower_id}, followed) do
|
||||
with true <- id =~ "follows",
|
||||
%User{local: true} = follower <- User.get_cached_by_ap_id(follower_id),
|
||||
|
|
@ -398,7 +418,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
# - tags
|
||||
# - emoji
|
||||
def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = object} = data)
|
||||
when objtype in ["Article", "Note", "Video", "Page"] do
|
||||
when objtype in ["Article", "Note", "Video", "Page", "Question", "Answer"] do
|
||||
actor = Containment.get_actor(data)
|
||||
|
||||
data =
|
||||
|
|
@ -731,6 +751,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
|> set_reply_to_uri
|
||||
|> strip_internal_fields
|
||||
|> strip_internal_tags
|
||||
|> set_type
|
||||
end
|
||||
|
||||
# @doc
|
||||
|
|
@ -895,6 +916,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|
|||
Map.put(object, "sensitive", "nsfw" in tags)
|
||||
end
|
||||
|
||||
def set_type(%{"type" => "Answer"} = object) do
|
||||
Map.put(object, "type", "Note")
|
||||
end
|
||||
|
||||
def set_type(object), do: object
|
||||
|
||||
def add_attributed_to(object) do
|
||||
attributed_to = object["attributedTo"] || object["actor"]
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
|
||||
require Logger
|
||||
|
||||
@supported_object_types ["Article", "Note", "Video", "Page"]
|
||||
@supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer"]
|
||||
@supported_report_states ~w(open closed resolved)
|
||||
@valid_visibilities ~w(public unlisted private direct)
|
||||
|
||||
|
|
@ -789,4 +789,21 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
|||
[to, cc, recipients]
|
||||
end
|
||||
end
|
||||
|
||||
def get_existing_votes(actor, %{data: %{"id" => id}}) do
|
||||
query =
|
||||
from(
|
||||
[activity, object: object] in Activity.with_preloaded_object(Activity),
|
||||
where: fragment("(?)->>'actor' = ?", activity.data, ^actor),
|
||||
where:
|
||||
fragment(
|
||||
"(?)->'inReplyTo' = ?",
|
||||
object.data,
|
||||
^to_string(id)
|
||||
),
|
||||
where: fragment("(?)->>'type' = 'Answer'", object.data)
|
||||
)
|
||||
|
||||
Repo.all(query)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -66,6 +66,9 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
|
|||
Enum.any?(to, &String.contains?(&1, "/followers")) ->
|
||||
"private"
|
||||
|
||||
object.data["directMessage"] == true ->
|
||||
"direct"
|
||||
|
||||
length(cc) > 0 ->
|
||||
"private"
|
||||
|
||||
|
|
|
|||
|
|
@ -119,6 +119,53 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
end
|
||||
end
|
||||
|
||||
def vote(user, object, choices) do
|
||||
with "Question" <- object.data["type"],
|
||||
{:author, false} <- {:author, object.data["actor"] == user.ap_id},
|
||||
{:existing_votes, []} <- {:existing_votes, Utils.get_existing_votes(user.ap_id, object)},
|
||||
{options, max_count} <- get_options_and_max_count(object),
|
||||
option_count <- Enum.count(options),
|
||||
{:choice_check, {choices, true}} <-
|
||||
{:choice_check, normalize_and_validate_choice_indices(choices, option_count)},
|
||||
{:count_check, true} <- {:count_check, Enum.count(choices) <= max_count} do
|
||||
answer_activities =
|
||||
Enum.map(choices, fn index ->
|
||||
answer_data = make_answer_data(user, object, Enum.at(options, index)["name"])
|
||||
|
||||
ActivityPub.create(%{
|
||||
to: answer_data["to"],
|
||||
actor: user,
|
||||
context: object.data["context"],
|
||||
object: answer_data,
|
||||
additional: %{"cc" => answer_data["cc"]}
|
||||
})
|
||||
end)
|
||||
|
||||
object = Object.get_cached_by_ap_id(object.data["id"])
|
||||
{:ok, answer_activities, object}
|
||||
else
|
||||
{:author, _} -> {:error, "Poll's author can't vote"}
|
||||
{:existing_votes, _} -> {:error, "Already voted"}
|
||||
{:choice_check, {_, false}} -> {:error, "Invalid indices"}
|
||||
{:count_check, false} -> {:error, "Too many choices"}
|
||||
end
|
||||
end
|
||||
|
||||
defp get_options_and_max_count(object) do
|
||||
if Map.has_key?(object.data, "anyOf") do
|
||||
{object.data["anyOf"], Enum.count(object.data["anyOf"])}
|
||||
else
|
||||
{object.data["oneOf"], 1}
|
||||
end
|
||||
end
|
||||
|
||||
defp normalize_and_validate_choice_indices(choices, count) do
|
||||
Enum.map_reduce(choices, true, fn index, valid ->
|
||||
index = if is_binary(index), do: String.to_integer(index), else: index
|
||||
{index, if(valid, do: index < count, else: valid)}
|
||||
end)
|
||||
end
|
||||
|
||||
def get_visibility(%{"visibility" => visibility}, in_reply_to)
|
||||
when visibility in ~w{public unlisted private direct},
|
||||
do: {visibility, get_replied_to_visibility(in_reply_to)}
|
||||
|
|
@ -154,6 +201,7 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
data,
|
||||
visibility
|
||||
),
|
||||
{poll, poll_emoji} <- make_poll_data(data),
|
||||
{to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility),
|
||||
context <- make_context(in_reply_to),
|
||||
cw <- data["spoiler_text"] || "",
|
||||
|
|
@ -171,13 +219,14 @@ defmodule Pleroma.Web.CommonAPI do
|
|||
tags,
|
||||
cw,
|
||||
cc,
|
||||
sensitive
|
||||
sensitive,
|
||||
poll
|
||||
),
|
||||
object <-
|
||||
Map.put(
|
||||
object,
|
||||
"emoji",
|
||||
Formatter.get_emoji_map(full_payload)
|
||||
Map.merge(Formatter.get_emoji_map(full_payload), poll_emoji)
|
||||
) do
|
||||
res =
|
||||
ActivityPub.create(
|
||||
|
|
|
|||
|
|
@ -102,6 +102,72 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
end
|
||||
end
|
||||
|
||||
def make_poll_data(%{"poll" => %{"options" => options, "expires_in" => expires_in}} = data)
|
||||
when is_list(options) do
|
||||
%{max_expiration: max_expiration, min_expiration: min_expiration} =
|
||||
limits = Pleroma.Config.get([:instance, :poll_limits])
|
||||
|
||||
# XXX: There is probably a cleaner way of doing this
|
||||
try do
|
||||
# In some cases mastofe sends out strings instead of integers
|
||||
expires_in = if is_binary(expires_in), do: String.to_integer(expires_in), else: expires_in
|
||||
|
||||
if Enum.count(options) > limits.max_options do
|
||||
raise ArgumentError, message: "Poll can't contain more than #{limits.max_options} options"
|
||||
end
|
||||
|
||||
{poll, emoji} =
|
||||
Enum.map_reduce(options, %{}, fn option, emoji ->
|
||||
if String.length(option) > limits.max_option_chars do
|
||||
raise ArgumentError,
|
||||
message:
|
||||
"Poll options cannot be longer than #{limits.max_option_chars} characters each"
|
||||
end
|
||||
|
||||
{%{
|
||||
"name" => option,
|
||||
"type" => "Note",
|
||||
"replies" => %{"type" => "Collection", "totalItems" => 0}
|
||||
}, Map.merge(emoji, Formatter.get_emoji_map(option))}
|
||||
end)
|
||||
|
||||
case expires_in do
|
||||
expires_in when expires_in > max_expiration ->
|
||||
raise ArgumentError, message: "Expiration date is too far in the future"
|
||||
|
||||
expires_in when expires_in < min_expiration ->
|
||||
raise ArgumentError, message: "Expiration date is too soon"
|
||||
|
||||
_ ->
|
||||
:noop
|
||||
end
|
||||
|
||||
end_time =
|
||||
NaiveDateTime.utc_now()
|
||||
|> NaiveDateTime.add(expires_in)
|
||||
|> NaiveDateTime.to_iso8601()
|
||||
|
||||
poll =
|
||||
if Pleroma.Web.ControllerHelper.truthy_param?(data["poll"]["multiple"]) do
|
||||
%{"type" => "Question", "anyOf" => poll, "closed" => end_time}
|
||||
else
|
||||
%{"type" => "Question", "oneOf" => poll, "closed" => end_time}
|
||||
end
|
||||
|
||||
{poll, emoji}
|
||||
rescue
|
||||
e in ArgumentError -> e.message
|
||||
end
|
||||
end
|
||||
|
||||
def make_poll_data(%{"poll" => poll}) when is_map(poll) do
|
||||
"Invalid poll"
|
||||
end
|
||||
|
||||
def make_poll_data(_data) do
|
||||
{%{}, %{}}
|
||||
end
|
||||
|
||||
def make_content_html(
|
||||
status,
|
||||
attachments,
|
||||
|
|
@ -224,7 +290,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
tags,
|
||||
cw \\ nil,
|
||||
cc \\ [],
|
||||
sensitive \\ false
|
||||
sensitive \\ false,
|
||||
merge \\ %{}
|
||||
) do
|
||||
object = %{
|
||||
"type" => "Note",
|
||||
|
|
@ -239,12 +306,15 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
"tag" => tags |> Enum.map(fn {_, tag} -> tag end) |> Enum.uniq()
|
||||
}
|
||||
|
||||
with false <- is_nil(in_reply_to),
|
||||
%Object{} = in_reply_to_object <- Object.normalize(in_reply_to) do
|
||||
Map.put(object, "inReplyTo", in_reply_to_object.data["id"])
|
||||
else
|
||||
_ -> object
|
||||
end
|
||||
object =
|
||||
with false <- is_nil(in_reply_to),
|
||||
%Object{} = in_reply_to_object <- Object.normalize(in_reply_to) do
|
||||
Map.put(object, "inReplyTo", in_reply_to_object.data["id"])
|
||||
else
|
||||
_ -> object
|
||||
end
|
||||
|
||||
Map.merge(object, merge)
|
||||
end
|
||||
|
||||
def format_naive_asctime(date) do
|
||||
|
|
@ -421,4 +491,15 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
|||
{:error, "No such conversation"}
|
||||
end
|
||||
end
|
||||
|
||||
def make_answer_data(%User{ap_id: ap_id}, object, name) do
|
||||
%{
|
||||
"type" => "Answer",
|
||||
"actor" => ap_id,
|
||||
"cc" => [object.data["actor"]],
|
||||
"to" => [],
|
||||
"name" => name,
|
||||
"inReplyTo" => object.data["id"]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ defmodule Pleroma.Web.Endpoint do
|
|||
parsers: [:urlencoded, :multipart, :json],
|
||||
pass: ["*/*"],
|
||||
json_decoder: Jason,
|
||||
length: Application.get_env(:pleroma, :instance) |> Keyword.get(:upload_limit),
|
||||
length: Pleroma.Config.get([:instance, :upload_limit]),
|
||||
body_reader: {Pleroma.Web.Plugs.DigestPlug, :read_body, []}
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -197,7 +197,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
languages: ["en"],
|
||||
registrations: Pleroma.Config.get([:instance, :registrations_open]),
|
||||
# Extra (not present in Mastodon):
|
||||
max_toot_chars: Keyword.get(instance, :limit)
|
||||
max_toot_chars: Keyword.get(instance, :limit),
|
||||
poll_limits: Keyword.get(instance, :poll_limits)
|
||||
}
|
||||
|
||||
json(conn, response)
|
||||
|
|
@ -409,6 +410,53 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
end
|
||||
end
|
||||
|
||||
def get_poll(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
with %Object{} = object <- Object.get_by_id(id),
|
||||
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
|
||||
true <- Visibility.visible_for_user?(activity, user) do
|
||||
conn
|
||||
|> put_view(StatusView)
|
||||
|> try_render("poll.json", %{object: object, for: user})
|
||||
else
|
||||
nil ->
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Record not found"})
|
||||
|
||||
false ->
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Record not found"})
|
||||
end
|
||||
end
|
||||
|
||||
def poll_vote(%{assigns: %{user: user}} = conn, %{"id" => id, "choices" => choices}) do
|
||||
with %Object{} = object <- Object.get_by_id(id),
|
||||
true <- object.data["type"] == "Question",
|
||||
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
|
||||
true <- Visibility.visible_for_user?(activity, user),
|
||||
{:ok, _activities, object} <- CommonAPI.vote(user, object, choices) do
|
||||
conn
|
||||
|> put_view(StatusView)
|
||||
|> try_render("poll.json", %{object: object, for: user})
|
||||
else
|
||||
nil ->
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Record not found"})
|
||||
|
||||
false ->
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "Record not found"})
|
||||
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_status(422)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
def scheduled_statuses(%{assigns: %{user: user}} = conn, params) do
|
||||
with scheduled_activities <- MastodonAPI.get_scheduled_activities(user, params) do
|
||||
conn
|
||||
|
|
@ -472,12 +520,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
params
|
||||
|> Map.put("in_reply_to_status_id", params["in_reply_to_id"])
|
||||
|
||||
idempotency_key =
|
||||
case get_req_header(conn, "idempotency-key") do
|
||||
[key] -> key
|
||||
_ -> Ecto.UUID.generate()
|
||||
end
|
||||
|
||||
scheduled_at = params["scheduled_at"]
|
||||
|
||||
if scheduled_at && ScheduledActivity.far_enough?(scheduled_at) do
|
||||
|
|
@ -490,17 +532,40 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
else
|
||||
params = Map.drop(params, ["scheduled_at"])
|
||||
|
||||
{:ok, activity} =
|
||||
Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ ->
|
||||
CommonAPI.post(user, params)
|
||||
end)
|
||||
case get_cached_status_or_post(conn, params) do
|
||||
{:ignore, message} ->
|
||||
conn
|
||||
|> put_status(422)
|
||||
|> json(%{error: message})
|
||||
|
||||
conn
|
||||
|> put_view(StatusView)
|
||||
|> try_render("status.json", %{activity: activity, for: user, as: :activity})
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_status(422)
|
||||
|> json(%{error: message})
|
||||
|
||||
{_, activity} ->
|
||||
conn
|
||||
|> put_view(StatusView)
|
||||
|> try_render("status.json", %{activity: activity, for: user, as: :activity})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp get_cached_status_or_post(%{assigns: %{user: user}} = conn, params) do
|
||||
idempotency_key =
|
||||
case get_req_header(conn, "idempotency-key") do
|
||||
[key] -> key
|
||||
_ -> Ecto.UUID.generate()
|
||||
end
|
||||
|
||||
Cachex.fetch(:idempotency_cache, idempotency_key, fn _ ->
|
||||
case CommonAPI.post(user, params) do
|
||||
{:ok, activity} -> activity
|
||||
{:error, message} -> {:ignore, message}
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
def delete_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
|
||||
with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
|
||||
json(conn, %{})
|
||||
|
|
@ -1084,7 +1149,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
from([a, o] in Activity.with_preloaded_object(Activity),
|
||||
where: fragment("?->>'type' = 'Create'", a.data),
|
||||
where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients,
|
||||
limit: 20
|
||||
limit: 40
|
||||
)
|
||||
|
||||
q =
|
||||
|
|
@ -1346,8 +1411,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
accounts =
|
||||
Map.put(%{}, user.id, AccountView.render("account.json", %{user: user, for: user}))
|
||||
|
||||
flavour = get_user_flavour(user)
|
||||
|
||||
initial_state =
|
||||
%{
|
||||
meta: %{
|
||||
|
|
@ -1366,6 +1429,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
max_toot_chars: limit,
|
||||
mascot: User.get_mascot(user)["url"]
|
||||
},
|
||||
poll_limits: Config.get([:instance, :poll_limits]),
|
||||
rights: %{
|
||||
delete_others_notice: present?(user.info.is_moderator),
|
||||
admin: present?(user.info.is_admin)
|
||||
|
|
@ -1433,7 +1497,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
conn
|
||||
|> put_layout(false)
|
||||
|> put_view(MastodonView)
|
||||
|> render("index.html", %{initial_state: initial_state, flavour: flavour})
|
||||
|> render("index.html", %{initial_state: initial_state})
|
||||
else
|
||||
conn
|
||||
|> put_session(:return_to, conn.request_path)
|
||||
|
|
@ -1456,43 +1520,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
end
|
||||
end
|
||||
|
||||
@supported_flavours ["glitch", "vanilla"]
|
||||
|
||||
def set_flavour(%{assigns: %{user: user}} = conn, %{"flavour" => flavour} = _params)
|
||||
when flavour in @supported_flavours do
|
||||
flavour_cng = User.Info.mastodon_flavour_update(user.info, flavour)
|
||||
|
||||
with changeset <- Ecto.Changeset.change(user),
|
||||
changeset <- Ecto.Changeset.put_embed(changeset, :info, flavour_cng),
|
||||
{:ok, user} <- User.update_and_set_cache(changeset),
|
||||
flavour <- user.info.flavour do
|
||||
json(conn, flavour)
|
||||
else
|
||||
e ->
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(500, Jason.encode!(%{"error" => inspect(e)}))
|
||||
end
|
||||
end
|
||||
|
||||
def set_flavour(conn, _params) do
|
||||
conn
|
||||
|> put_status(400)
|
||||
|> json(%{error: "Unsupported flavour"})
|
||||
end
|
||||
|
||||
def get_flavour(%{assigns: %{user: user}} = conn, _params) do
|
||||
json(conn, get_user_flavour(user))
|
||||
end
|
||||
|
||||
defp get_user_flavour(%User{info: %{flavour: flavour}}) when flavour in @supported_flavours do
|
||||
flavour
|
||||
end
|
||||
|
||||
defp get_user_flavour(_) do
|
||||
"glitch"
|
||||
end
|
||||
|
||||
def login(%{assigns: %{user: %User{}}} = conn, _params) do
|
||||
redirect(conn, to: local_mastodon_root_path(conn))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,9 +22,14 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do
|
|||
|
||||
last_status = StatusView.render("status.json", %{activity: activity, for: user})
|
||||
|
||||
# Conversations return all users except the current user.
|
||||
users =
|
||||
participation.conversation.users
|
||||
|> Enum.reject(&(&1.id == user.id))
|
||||
|
||||
accounts =
|
||||
AccountView.render("accounts.json", %{
|
||||
users: participation.conversation.users,
|
||||
users: users,
|
||||
as: :user
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -240,6 +240,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
spoiler_text: summary_html,
|
||||
visibility: get_visibility(object),
|
||||
media_attachments: attachments,
|
||||
poll: render("poll.json", %{object: object, for: opts[:for]}),
|
||||
mentions: mentions,
|
||||
tags: build_tags(tags),
|
||||
application: %{
|
||||
|
|
@ -290,8 +291,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
provider_url: page_url_data.scheme <> "://" <> page_url_data.host,
|
||||
url: page_url,
|
||||
image: image_url |> MediaProxy.url(),
|
||||
title: rich_media[:title],
|
||||
description: rich_media[:description],
|
||||
title: rich_media[:title] || "",
|
||||
description: rich_media[:description] || "",
|
||||
pleroma: %{
|
||||
opengraph: rich_media
|
||||
}
|
||||
|
|
@ -329,6 +330,64 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
}
|
||||
end
|
||||
|
||||
def render("poll.json", %{object: object} = opts) do
|
||||
{multiple, options} =
|
||||
case object.data do
|
||||
%{"anyOf" => options} when is_list(options) -> {true, options}
|
||||
%{"oneOf" => options} when is_list(options) -> {false, options}
|
||||
_ -> {nil, nil}
|
||||
end
|
||||
|
||||
if options do
|
||||
end_time =
|
||||
(object.data["closed"] || object.data["endTime"])
|
||||
|> NaiveDateTime.from_iso8601!()
|
||||
|
||||
expired =
|
||||
end_time
|
||||
|> NaiveDateTime.compare(NaiveDateTime.utc_now())
|
||||
|> case do
|
||||
:lt -> true
|
||||
_ -> false
|
||||
end
|
||||
|
||||
voted =
|
||||
if opts[:for] do
|
||||
existing_votes =
|
||||
Pleroma.Web.ActivityPub.Utils.get_existing_votes(opts[:for].ap_id, object)
|
||||
|
||||
existing_votes != [] or opts[:for].ap_id == object.data["actor"]
|
||||
else
|
||||
false
|
||||
end
|
||||
|
||||
{options, votes_count} =
|
||||
Enum.map_reduce(options, 0, fn %{"name" => name} = option, count ->
|
||||
current_count = option["replies"]["totalItems"] || 0
|
||||
|
||||
{%{
|
||||
title: HTML.strip_tags(name),
|
||||
votes_count: current_count
|
||||
}, current_count + count}
|
||||
end)
|
||||
|
||||
%{
|
||||
# Mastodon uses separate ids for polls, but an object can't have
|
||||
# more than one poll embedded so object id is fine
|
||||
id: object.id,
|
||||
expires_at: Utils.to_masto_date(end_time),
|
||||
expired: expired,
|
||||
multiple: multiple,
|
||||
votes_count: votes_count,
|
||||
options: options,
|
||||
voted: voted,
|
||||
emojis: build_emojis(object.data["emoji"])
|
||||
}
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def get_reply_to(activity, %{replied_to_activities: replied_to_activities}) do
|
||||
object = Object.normalize(activity)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,25 +12,27 @@ defmodule Pleroma.Web.MediaProxy do
|
|||
def url("/" <> _ = url), do: url
|
||||
|
||||
def url(url) do
|
||||
config = Application.get_env(:pleroma, :media_proxy, [])
|
||||
domain = URI.parse(url).host
|
||||
|
||||
cond do
|
||||
!Keyword.get(config, :enabled, false) or String.starts_with?(url, Pleroma.Web.base_url()) ->
|
||||
url
|
||||
|
||||
Enum.any?(Pleroma.Config.get([:media_proxy, :whitelist]), fn pattern ->
|
||||
String.equivalent?(domain, pattern)
|
||||
end) ->
|
||||
url
|
||||
|
||||
true ->
|
||||
encode_url(url)
|
||||
if !enabled?() or local?(url) or whitelisted?(url) do
|
||||
url
|
||||
else
|
||||
encode_url(url)
|
||||
end
|
||||
end
|
||||
|
||||
defp enabled?, do: Pleroma.Config.get([:media_proxy, :enabled], false)
|
||||
|
||||
defp local?(url), do: String.starts_with?(url, Pleroma.Web.base_url())
|
||||
|
||||
defp whitelisted?(url) do
|
||||
%{host: domain} = URI.parse(url)
|
||||
|
||||
Enum.any?(Pleroma.Config.get([:media_proxy, :whitelist]), fn pattern ->
|
||||
String.equivalent?(domain, pattern)
|
||||
end)
|
||||
end
|
||||
|
||||
def encode_url(url) do
|
||||
secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
|
||||
secret = Pleroma.Config.get([Pleroma.Web.Endpoint, :secret_key_base])
|
||||
|
||||
# Must preserve `%2F` for compatibility with S3
|
||||
# https://git.pleroma.social/pleroma/pleroma/issues/580
|
||||
|
|
@ -52,7 +54,7 @@ defmodule Pleroma.Web.MediaProxy do
|
|||
end
|
||||
|
||||
def decode_url(sig, url) do
|
||||
secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
|
||||
secret = Pleroma.Config.get([Pleroma.Web.Endpoint, :secret_key_base])
|
||||
sig = Base.url_decode64!(sig, @base64_opts)
|
||||
local_sig = :crypto.hmac(:sha, secret, url)
|
||||
|
||||
|
|
|
|||
|
|
@ -32,20 +32,15 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
|
|||
# returns a nodeinfo 2.0 map, since 2.1 just adds a repository field
|
||||
# under software.
|
||||
def raw_nodeinfo do
|
||||
instance = Application.get_env(:pleroma, :instance)
|
||||
media_proxy = Application.get_env(:pleroma, :media_proxy)
|
||||
suggestions = Application.get_env(:pleroma, :suggestions)
|
||||
chat = Application.get_env(:pleroma, :chat)
|
||||
gopher = Application.get_env(:pleroma, :gopher)
|
||||
stats = Stats.get_stats()
|
||||
|
||||
mrf_simple =
|
||||
Application.get_env(:pleroma, :mrf_simple)
|
||||
Config.get(:mrf_simple)
|
||||
|> Enum.into(%{})
|
||||
|
||||
# This horror is needed to convert regex sigils to strings
|
||||
mrf_keyword =
|
||||
Application.get_env(:pleroma, :mrf_keyword, [])
|
||||
Config.get(:mrf_keyword, [])
|
||||
|> Enum.map(fn {key, value} ->
|
||||
{key,
|
||||
Enum.map(value, fn
|
||||
|
|
@ -74,14 +69,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
|
|||
MRF.get_policies()
|
||||
|> Enum.map(fn policy -> to_string(policy) |> String.split(".") |> List.last() end)
|
||||
|
||||
quarantined = Keyword.get(instance, :quarantined_instances)
|
||||
|
||||
quarantined =
|
||||
if is_list(quarantined) do
|
||||
quarantined
|
||||
else
|
||||
[]
|
||||
end
|
||||
quarantined = Config.get([:instance, :quarantined_instances], [])
|
||||
|
||||
staff_accounts =
|
||||
User.all_superusers()
|
||||
|
|
@ -92,7 +80,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
|
|||
|> Enum.into(%{}, fn {k, v} -> {k, length(v)} end)
|
||||
|
||||
federation_response =
|
||||
if Keyword.get(instance, :mrf_transparency) do
|
||||
if Config.get([:instance, :mrf_transparency]) do
|
||||
%{
|
||||
mrf_policies: mrf_policies,
|
||||
mrf_simple: mrf_simple,
|
||||
|
|
@ -109,22 +97,22 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
|
|||
"pleroma_api",
|
||||
"mastodon_api",
|
||||
"mastodon_api_streaming",
|
||||
if Keyword.get(media_proxy, :enabled) do
|
||||
if Config.get([:media_proxy, :enabled]) do
|
||||
"media_proxy"
|
||||
end,
|
||||
if Keyword.get(gopher, :enabled) do
|
||||
if Config.get([:gopher, :enabled]) do
|
||||
"gopher"
|
||||
end,
|
||||
if Keyword.get(chat, :enabled) do
|
||||
if Config.get([:chat, :enabled]) do
|
||||
"chat"
|
||||
end,
|
||||
if Keyword.get(suggestions, :enabled) do
|
||||
if Config.get([:suggestions, :enabled]) do
|
||||
"suggestions"
|
||||
end,
|
||||
if Keyword.get(instance, :allow_relay) do
|
||||
if Config.get([:instance, :allow_relay]) do
|
||||
"relay"
|
||||
end,
|
||||
if Keyword.get(instance, :safe_dm_mentions) do
|
||||
if Config.get([:instance, :safe_dm_mentions]) do
|
||||
"safe_dm_mentions"
|
||||
end
|
||||
]
|
||||
|
|
@ -141,7 +129,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
|
|||
inbound: [],
|
||||
outbound: []
|
||||
},
|
||||
openRegistrations: Keyword.get(instance, :registrations_open),
|
||||
openRegistrations: Config.get([:instance, :registrations_open]),
|
||||
usage: %{
|
||||
users: %{
|
||||
total: stats.user_count || 0
|
||||
|
|
@ -149,29 +137,29 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
|
|||
localPosts: stats.status_count || 0
|
||||
},
|
||||
metadata: %{
|
||||
nodeName: Keyword.get(instance, :name),
|
||||
nodeDescription: Keyword.get(instance, :description),
|
||||
private: !Keyword.get(instance, :public, true),
|
||||
nodeName: Config.get([:instance, :name]),
|
||||
nodeDescription: Config.get([:instance, :description]),
|
||||
private: !Config.get([:instance, :public], true),
|
||||
suggestions: %{
|
||||
enabled: Keyword.get(suggestions, :enabled, false),
|
||||
thirdPartyEngine: Keyword.get(suggestions, :third_party_engine, ""),
|
||||
timeout: Keyword.get(suggestions, :timeout, 5000),
|
||||
limit: Keyword.get(suggestions, :limit, 23),
|
||||
web: Keyword.get(suggestions, :web, "")
|
||||
enabled: Config.get([:suggestions, :enabled], false),
|
||||
thirdPartyEngine: Config.get([:suggestions, :third_party_engine], ""),
|
||||
timeout: Config.get([:suggestions, :timeout], 5000),
|
||||
limit: Config.get([:suggestions, :limit], 23),
|
||||
web: Config.get([:suggestions, :web], "")
|
||||
},
|
||||
staffAccounts: staff_accounts,
|
||||
federation: federation_response,
|
||||
postFormats: Keyword.get(instance, :allowed_post_formats),
|
||||
postFormats: Config.get([:instance, :allowed_post_formats]),
|
||||
uploadLimits: %{
|
||||
general: Keyword.get(instance, :upload_limit),
|
||||
avatar: Keyword.get(instance, :avatar_upload_limit),
|
||||
banner: Keyword.get(instance, :banner_upload_limit),
|
||||
background: Keyword.get(instance, :background_upload_limit)
|
||||
general: Config.get([:instance, :upload_limit]),
|
||||
avatar: Config.get([:instance, :avatar_upload_limit]),
|
||||
banner: Config.get([:instance, :banner_upload_limit]),
|
||||
background: Config.get([:instance, :background_upload_limit])
|
||||
},
|
||||
accountActivationRequired: Keyword.get(instance, :account_activation_required, false),
|
||||
invitesEnabled: Keyword.get(instance, :invites_enabled, false),
|
||||
accountActivationRequired: Config.get([:instance, :account_activation_required], false),
|
||||
invitesEnabled: Config.get([:instance, :invites_enabled], false),
|
||||
features: features,
|
||||
restrictedNicknames: Pleroma.Config.get([Pleroma.User, :restricted_nicknames])
|
||||
restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames])
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -37,7 +37,10 @@ defmodule Pleroma.Web.RichMedia.Parser do
|
|||
try do
|
||||
{:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: @hackney_options)
|
||||
|
||||
html |> maybe_parse() |> clean_parsed_data() |> check_parsed_data()
|
||||
html
|
||||
|> maybe_parse()
|
||||
|> clean_parsed_data()
|
||||
|> check_parsed_data()
|
||||
rescue
|
||||
e ->
|
||||
{:error, "Parsing error: #{inspect(e)}"}
|
||||
|
|
|
|||
|
|
@ -309,8 +309,6 @@ defmodule Pleroma.Web.Router do
|
|||
post("/conversations/:id/read", MastodonAPIController, :conversation_read)
|
||||
|
||||
get("/endorsements", MastodonAPIController, :empty_array)
|
||||
|
||||
get("/pleroma/flavour", MastodonAPIController, :get_flavour)
|
||||
end
|
||||
|
||||
scope [] do
|
||||
|
|
@ -335,6 +333,8 @@ defmodule Pleroma.Web.Router do
|
|||
put("/scheduled_statuses/:id", MastodonAPIController, :update_scheduled_status)
|
||||
delete("/scheduled_statuses/:id", MastodonAPIController, :delete_scheduled_status)
|
||||
|
||||
post("/polls/:id/votes", MastodonAPIController, :poll_vote)
|
||||
|
||||
post("/media", MastodonAPIController, :upload)
|
||||
put("/media/:id", MastodonAPIController, :update_media)
|
||||
|
||||
|
|
@ -350,8 +350,6 @@ defmodule Pleroma.Web.Router do
|
|||
put("/filters/:id", MastodonAPIController, :update_filter)
|
||||
delete("/filters/:id", MastodonAPIController, :delete_filter)
|
||||
|
||||
post("/pleroma/flavour/:flavour", MastodonAPIController, :set_flavour)
|
||||
|
||||
get("/pleroma/mascot", MastodonAPIController, :get_mascot)
|
||||
put("/pleroma/mascot", MastodonAPIController, :set_mascot)
|
||||
|
||||
|
|
@ -414,12 +412,7 @@ defmodule Pleroma.Web.Router do
|
|||
|
||||
get("/trends", MastodonAPIController, :empty_array)
|
||||
|
||||
scope [] do
|
||||
pipe_through(:oauth_read)
|
||||
|
||||
get("/search", MastodonAPIController, :search)
|
||||
get("/accounts/search", MastodonAPIController, :account_search)
|
||||
end
|
||||
get("/accounts/search", MastodonAPIController, :account_search)
|
||||
|
||||
scope [] do
|
||||
pipe_through(:oauth_read_or_public)
|
||||
|
|
@ -431,17 +424,21 @@ defmodule Pleroma.Web.Router do
|
|||
get("/statuses/:id", MastodonAPIController, :get_status)
|
||||
get("/statuses/:id/context", MastodonAPIController, :get_context)
|
||||
|
||||
get("/polls/:id", MastodonAPIController, :get_poll)
|
||||
|
||||
get("/accounts/:id/statuses", MastodonAPIController, :user_statuses)
|
||||
get("/accounts/:id/followers", MastodonAPIController, :followers)
|
||||
get("/accounts/:id/following", MastodonAPIController, :following)
|
||||
get("/accounts/:id", MastodonAPIController, :user)
|
||||
|
||||
get("/search", MastodonAPIController, :search)
|
||||
|
||||
get("/pleroma/accounts/:id/favourites", MastodonAPIController, :user_favourites)
|
||||
end
|
||||
end
|
||||
|
||||
scope "/api/v2", Pleroma.Web.MastodonAPI do
|
||||
pipe_through([:api, :oauth_read])
|
||||
pipe_through([:api, :oauth_read_or_public])
|
||||
get("/search", MastodonAPIController, :search2)
|
||||
end
|
||||
|
||||
|
|
@ -483,13 +480,8 @@ defmodule Pleroma.Web.Router do
|
|||
get("/statuses/show/:id", TwitterAPI.Controller, :fetch_status)
|
||||
get("/statusnet/conversation/:id", TwitterAPI.Controller, :fetch_conversation)
|
||||
|
||||
get("/statusnet/tags/timeline/:tag", TwitterAPI.Controller, :public_and_external_timeline)
|
||||
end
|
||||
|
||||
scope [] do
|
||||
pipe_through(:oauth_read)
|
||||
|
||||
get("/search", TwitterAPI.Controller, :search)
|
||||
get("/statusnet/tags/timeline/:tag", TwitterAPI.Controller, :public_and_external_timeline)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -508,7 +500,7 @@ defmodule Pleroma.Web.Router do
|
|||
end
|
||||
|
||||
scope "/api", Pleroma.Web, as: :twitter_api_search do
|
||||
pipe_through([:api, :oauth_read])
|
||||
pipe_through([:api, :oauth_read_or_public])
|
||||
get("/pleroma/search_user", TwitterAPI.Controller, :search_user)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,minimal-ui" />
|
||||
<title>
|
||||
<%= Application.get_env(:pleroma, :instance)[:name] %>
|
||||
<%= Pleroma.Config.get([:instance, :name]) %>
|
||||
</title>
|
||||
<style>
|
||||
body {
|
||||
|
|
@ -194,7 +194,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1><%= Application.get_env(:pleroma, :instance)[:name] %></h1>
|
||||
<h1><%= Pleroma.Config.get([:instance, :name]) %></h1>
|
||||
<%= render @view_module, @view_template, assigns %>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
<meta charset='utf-8'>
|
||||
<meta content='width=device-width, initial-scale=1' name='viewport'>
|
||||
<title>
|
||||
<%= Application.get_env(:pleroma, :instance)[:name] %>
|
||||
<%= Pleroma.Config.get([:instance, :name]) %>
|
||||
</title>
|
||||
<link rel="icon" type="image/png" href="/favicon.png"/>
|
||||
<script crossorigin='anonymous' src="/packs/locales.js"></script>
|
||||
<script crossorigin='anonymous' src="/packs/locales/<%= @flavour %>/en.js"></script>
|
||||
<script crossorigin='anonymous' src="/packs/locales/glitch/en.js"></script>
|
||||
|
||||
<link rel='preload' as='script' crossorigin='anonymous' href='/packs/features/getting_started.js'>
|
||||
<link rel='preload' as='script' crossorigin='anonymous' href='/packs/features/compose.js'>
|
||||
|
|
@ -19,10 +19,10 @@
|
|||
<script src="/packs/core/common.js"></script>
|
||||
<link rel="stylesheet" media="all" href="/packs/core/common.css" />
|
||||
|
||||
<script src="/packs/flavours/<%= @flavour %>/common.js"></script>
|
||||
<link rel="stylesheet" media="all" href="/packs/flavours/<%= @flavour %>/common.css" />
|
||||
<script src="/packs/flavours/glitch/common.js"></script>
|
||||
<link rel="stylesheet" media="all" href="/packs/flavours/glitch/common.css" />
|
||||
|
||||
<script src="/packs/flavours/<%= @flavour %>/home.js"></script>
|
||||
<script src="/packs/flavours/glitch/home.js"></script>
|
||||
</head>
|
||||
<body class='app-body no-reduce-motion system-font'>
|
||||
<div class='app-holder' data-props='{"locale":"en"}' id='mastodon'>
|
||||
|
|
|
|||
|
|
@ -728,7 +728,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
def only_if_public_instance(%{assigns: %{user: %User{}}} = conn, _), do: conn
|
||||
|
||||
def only_if_public_instance(conn, _) do
|
||||
if Keyword.get(Application.get_env(:pleroma, :instance), :public) do
|
||||
if Pleroma.Config.get([:instance, :public]) do
|
||||
conn
|
||||
else
|
||||
conn
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
|
|||
"tags" => user.tags
|
||||
}
|
||||
|> maybe_with_activation_status(user, for_user)
|
||||
|> with_notification_settings(user, for_user)
|
||||
}
|
||||
|> maybe_with_user_settings(user, for_user)
|
||||
|> maybe_with_role(user, for_user)
|
||||
|
|
@ -132,6 +133,12 @@ defmodule Pleroma.Web.TwitterAPI.UserView do
|
|||
end
|
||||
end
|
||||
|
||||
defp with_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do
|
||||
Map.put(data, "notification_settings", user.info.notification_settings)
|
||||
end
|
||||
|
||||
defp with_notification_settings(data, _, _), do: data
|
||||
|
||||
defp maybe_with_activation_status(data, user, %User{info: %{is_admin: true}}) do
|
||||
Map.put(data, "deactivated", user.info.deactivated)
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue