Merge branch 'develop' into issue/1276

This commit is contained in:
Maksim Pechnikov 2020-02-10 07:59:52 +03:00
commit b87533760b
96 changed files with 1659 additions and 445 deletions

View file

@ -1,5 +1,6 @@
defmodule Mix.Tasks.Pleroma.Email do
use Mix.Task
import Mix.Pleroma
@shortdoc "Simple Email test"
@moduledoc File.read!("docs/administration/CLI_tasks/email.md")
@ -18,8 +19,6 @@ defmodule Mix.Tasks.Pleroma.Email do
email = Pleroma.Emails.AdminEmail.test_email(options[:to])
{:ok, _} = Pleroma.Emails.Mailer.deliver(email)
Mix.shell().info(
"Test email has been sent to #{inspect(email.to)} from #{inspect(email.from)}"
)
shell_info("Test email has been sent to #{inspect(email.to)} from #{inspect(email.from)}")
end
end

View file

@ -31,7 +31,7 @@ defmodule Pleroma.Activity do
"Announce" => "reblog",
"Like" => "favourite",
"Move" => "move",
"EmojiReaction" => "pleroma:emoji_reaction"
"EmojiReact" => "pleroma:emoji_reaction"
}
@mastodon_to_ap_notification_types for {k, v} <- @mastodon_notification_types,

View file

@ -33,6 +33,7 @@ defmodule Pleroma.Application do
def start(_type, _args) do
Pleroma.HTML.compile_scrubbers()
Pleroma.Config.DeprecationWarnings.warn()
Pleroma.Plugs.HTTPSecurityPlug.warn_if_disabled()
Pleroma.Repo.check_migrations_applied!()
setup_instrumenters()
load_custom_modules()

View file

@ -3,8 +3,6 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Config.Loader do
@paths ["config/config.exs", "config/#{Mix.env()}.exs"]
@reject_keys [
Pleroma.Repo,
Pleroma.Web.Endpoint,
@ -35,8 +33,8 @@ defmodule Pleroma.Config.Loader do
def load_and_merge do
all_paths =
if Pleroma.Config.get(:release),
do: @paths ++ ["config/releases.exs"],
else: @paths
do: ["config/config.exs", "config/releases.exs"],
else: ["config/config.exs"]
all_paths
|> Enum.map(&load(&1))

View file

@ -10,6 +10,30 @@ defmodule Pleroma.Config.TransferTask do
require Logger
@type env() :: :test | :benchmark | :dev | :prod
@reboot_time_keys [
{:pleroma, :hackney_pools},
{:pleroma, :chat},
{:pleroma, Oban},
{:pleroma, :rate_limit},
{:pleroma, :markup},
{:plerome, :streamer}
]
@reboot_time_subkeys [
{:pleroma, Pleroma.Captcha, [:seconds_valid]},
{:pleroma, Pleroma.Upload, [:proxy_remote]},
{:pleroma, :instance, [:upload_limit]},
{:pleroma, :email_notifications, [:digest]},
{:pleroma, :oauth2, [:clean_expired_tokens]},
{:pleroma, Pleroma.ActivityExpiration, [:enabled]},
{:pleroma, Pleroma.ScheduledActivity, [:enabled]},
{:pleroma, :gopher, [:enabled]}
]
@reject [nil, :prometheus]
def start_link(_) do
load_and_update_env()
if Pleroma.Config.get(:env) == :test, do: Ecto.Adapters.SQL.Sandbox.checkin(Repo)
@ -17,21 +41,34 @@ defmodule Pleroma.Config.TransferTask do
end
@spec load_and_update_env([ConfigDB.t()]) :: :ok | false
def load_and_update_env(deleted \\ []) do
def load_and_update_env(deleted \\ [], restart_pleroma? \\ true) do
with true <- Pleroma.Config.get(:configurable_from_database),
true <- Ecto.Adapters.SQL.table_exists?(Repo, "config"),
started_applications <- Application.started_applications() do
# We need to restart applications for loaded settings take effect
in_db = Repo.all(ConfigDB)
with_deleted = in_db ++ deleted
with_deleted
|> Enum.map(&merge_and_update(&1))
|> Enum.uniq()
# TODO: some problem with prometheus after restart!
|> Enum.reject(&(&1 in [:pleroma, nil, :prometheus]))
|> Enum.each(&restart(started_applications, &1))
reject_for_restart = if restart_pleroma?, do: @reject, else: [:pleroma | @reject]
applications =
with_deleted
|> Enum.map(&merge_and_update(&1))
|> Enum.uniq()
# TODO: some problem with prometheus after restart!
|> Enum.reject(&(&1 in reject_for_restart))
# to be ensured that pleroma will be restarted last
applications =
if :pleroma in applications do
List.delete(applications, :pleroma) ++ [:pleroma]
else
applications
end
Enum.each(applications, &restart(started_applications, &1, Pleroma.Config.get(:env)))
:ok
end
@ -43,12 +80,25 @@ defmodule Pleroma.Config.TransferTask do
group = ConfigDB.from_string(setting.group)
default = Pleroma.Config.Holder.config(group, key)
merged_value = merge_value(setting, default, group, key)
value = ConfigDB.from_binary(setting.value)
merged_value =
if Ecto.get_meta(setting, :state) == :deleted do
default
else
if can_be_merged?(default, value) do
ConfigDB.merge_group(group, key, default, value)
else
value
end
end
:ok = update_env(group, key, merged_value)
if group != :logger do
group
if group != :pleroma or pleroma_need_restart?(group, key, value) do
group
end
else
# change logger configuration in runtime, without restart
if Keyword.keyword?(merged_value) and
@ -76,22 +126,31 @@ defmodule Pleroma.Config.TransferTask do
end
end
defp merge_value(%{__meta__: %{state: :deleted}}, default, _group, _key), do: default
@spec pleroma_need_restart?(atom(), atom(), any()) :: boolean()
def pleroma_need_restart?(group, key, value) do
group_and_key_need_reboot?(group, key) or group_and_subkey_need_reboot?(group, key, value)
end
defp merge_value(setting, default, group, key) do
value = ConfigDB.from_binary(setting.value)
defp group_and_key_need_reboot?(group, key) do
Enum.any?(@reboot_time_keys, fn {g, k} -> g == group and k == key end)
end
if can_be_merged?(default, value) do
ConfigDB.merge_group(group, key, default, value)
else
value
end
defp group_and_subkey_need_reboot?(group, key, value) do
Keyword.keyword?(value) and
Enum.any?(@reboot_time_subkeys, fn {g, k, subkeys} ->
g == group and k == key and
Enum.any?(Keyword.keys(value), &(&1 in subkeys))
end)
end
defp update_env(group, key, nil), do: Application.delete_env(group, key)
defp update_env(group, key, value), do: Application.put_env(group, key, value)
defp restart(started_applications, app) do
defp restart(_, :pleroma, :test), do: Logger.warn("pleroma restarted")
defp restart(_, :pleroma, _), do: send(Restarter.Pleroma, :after_boot)
defp restart(started_applications, app, _) do
with {^app, _, _} <- List.keyfind(started_applications, app, 0),
:ok <- Application.stop(app) do
:ok = Application.start(app)

View file

@ -58,8 +58,8 @@ defmodule Pleroma.FollowingRelationship do
def unfollow(%User{} = follower, %User{} = following) do
case get(follower, following) do
nil -> {:ok, nil}
%__MODULE__{} = following_relationship -> Repo.delete(following_relationship)
_ -> {:ok, nil}
end
end

View file

@ -13,7 +13,8 @@ defmodule Pleroma.Formatter do
@auto_linker_config hashtag: true,
hashtag_handler: &Pleroma.Formatter.hashtag_handler/4,
mention: true,
mention_handler: &Pleroma.Formatter.mention_handler/4
mention_handler: &Pleroma.Formatter.mention_handler/4,
scheme: true
def escape_mention_handler("@" <> nickname = mention, buffer, _, _) do
case User.get_cached_by_nickname(nickname) do

View file

@ -323,7 +323,7 @@ defmodule Pleroma.Notification do
end
def create_notifications(%Activity{data: %{"type" => type}} = activity)
when type in ["Like", "Announce", "Follow", "Move", "EmojiReaction"] do
when type in ["Like", "Announce", "Follow", "Move", "EmojiReact"] do
notifications =
activity
|> get_notified_from_activity()
@ -354,7 +354,7 @@ defmodule Pleroma.Notification do
def get_notified_from_activity(activity, local_only \\ true)
def get_notified_from_activity(%Activity{data: %{"type" => type}} = activity, local_only)
when type in ["Create", "Like", "Announce", "Follow", "Move", "EmojiReaction"] do
when type in ["Create", "Like", "Announce", "Follow", "Move", "EmojiReact"] do
[]
|> Utils.maybe_notify_to_recipients(activity)
|> Utils.maybe_notify_mentioned_recipients(activity)

View file

@ -184,11 +184,14 @@ defmodule Pleroma.Object do
with {:ok, _obj} = swap_object_with_tombstone(object),
deleted_activity = Activity.delete_all_by_object_ap_id(id),
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
{:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path),
{:ok, _} <-
Pleroma.Workers.AttachmentsCleanupWorker.enqueue("cleanup_attachments", %{
"object" => object
}) do
{:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do
with true <- Pleroma.Config.get([:instance, :cleanup_attachments]) do
{:ok, _} =
Pleroma.Workers.AttachmentsCleanupWorker.enqueue("cleanup_attachments", %{
"object" => object
})
end
{:ok, object, deleted_activity}
end
end

View file

@ -6,6 +6,8 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do
alias Pleroma.Config
import Plug.Conn
require Logger
def init(opts), do: opts
def call(conn, _options) do
@ -90,6 +92,51 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do
|> Enum.join("; ")
end
def warn_if_disabled do
unless Config.get([:http_security, :enabled]) do
Logger.warn("
.i;;;;i.
iYcviii;vXY:
.YXi .i1c.
.YC. . in7.
.vc. ...... ;1c.
i7, .. .;1;
i7, .. ... .Y1i
,7v .6MMM@; .YX,
.7;. ..IMMMMMM1 :t7.
.;Y. ;$MMMMMM9. :tc.
vY. .. .nMMM@MMU. ;1v.
i7i ... .#MM@M@C. .....:71i
it: .... $MMM@9;.,i;;;i,;tti
:t7. ..... 0MMMWv.,iii:::,,;St.
.nC. ..... IMMMQ..,::::::,.,czX.
.ct: ....... .ZMMMI..,:::::::,,:76Y.
c2: ......,i..Y$M@t..:::::::,,..inZY
vov ......:ii..c$MBc..,,,,,,,,,,..iI9i
i9Y ......iii:..7@MA,..,,,,,,,,,....;AA:
iIS. ......:ii::..;@MI....,............;Ez.
.I9. ......:i::::...8M1..................C0z.
.z9; ......:i::::,.. .i:...................zWX.
vbv ......,i::::,,. ................. :AQY
c6Y. .,...,::::,,..:t0@@QY. ................ :8bi
:6S. ..,,...,:::,,,..EMMMMMMI. ............... .;bZ,
:6o, .,,,,..:::,,,..i#MMMMMM#v................. YW2.
.n8i ..,,,,,,,::,,,,.. tMMMMM@C:.................. .1Wn
7Uc. .:::,,,,,::,,,,.. i1t;,..................... .UEi
7C...::::::::::::,,,,.. .................... vSi.
;1;...,,::::::,......... .................. Yz:
v97,......... .voC.
izAotX7777777777777777777777777777777777777777Y7n92:
.;CoIIIIIUAA666666699999ZZZZZZZZZZZZZZZZZZZZ6ov.
HTTP Security is disabled. Please re-enable it to prevent users from attacking
your instance and your users via malicious posts:
config :pleroma, :http_security, enabled: true
")
end
end
defp maybe_send_sts_header(conn, true) do
max_age_sts = Config.get([:http_security, :sts_max_age])
max_age_ct = Config.get([:http_security, :ct_max_age])

View file

@ -1,21 +0,0 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Plugs.Parsers do
@moduledoc "Initializes Plug.Parsers with upload limit set at boot time"
@behaviour Plug
def init(_opts) do
Plug.Parsers.init(
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Jason,
length: Pleroma.Config.get([:instance, :upload_limit]),
body_reader: {Pleroma.Web.Plugs.DigestPlug, :read_body, []}
)
end
defdelegate call(conn, opts), to: Plug.Parsers
end

View file

@ -67,6 +67,8 @@ defmodule Pleroma.Plugs.RateLimiter do
alias Pleroma.Plugs.RateLimiter.LimiterSupervisor
alias Pleroma.User
require Logger
def init(opts) do
limiter_name = Keyword.get(opts, :name)
@ -89,18 +91,39 @@ defmodule Pleroma.Plugs.RateLimiter do
def call(conn, nil), do: conn
def call(conn, settings) do
settings
|> incorporate_conn_info(conn)
|> check_rate()
|> case do
{:ok, _count} ->
case disabled?() do
true ->
if Pleroma.Config.get(:env) == :prod,
do: Logger.warn("Rate limiter is disabled for localhost/socket")
conn
{:error, _count} ->
render_throttled_error(conn)
false ->
settings
|> incorporate_conn_info(conn)
|> check_rate()
|> case do
{:ok, _count} ->
conn
{:error, _count} ->
render_throttled_error(conn)
end
end
end
def disabled? do
localhost_or_socket =
Pleroma.Config.get([Pleroma.Web.Endpoint, :http, :ip])
|> Tuple.to_list()
|> Enum.join(".")
|> String.match?(~r/^local|^127.0.0.1/)
remote_ip_disabled = not Pleroma.Config.get([Pleroma.Plugs.RemoteIp, :enabled])
localhost_or_socket and remote_ip_disabled
end
def inspect_bucket(conn, name_root, settings) do
settings =
settings

View file

@ -10,10 +10,7 @@ defmodule Pleroma.Plugs.RemoteIp do
@behaviour Plug
@headers ~w[
forwarded
x-forwarded-for
x-client-ip
x-real-ip
]
# https://en.wikipedia.org/wiki/Localhost

View file

@ -647,25 +647,48 @@ defmodule Pleroma.User do
end
end
def unfollow(%User{ap_id: ap_id}, %User{ap_id: ap_id}) do
{:error, "Not subscribed!"}
end
def unfollow(%User{} = follower, %User{} = followed) do
if following?(follower, followed) and follower.ap_id != followed.ap_id do
FollowingRelationship.unfollow(follower, followed)
case get_follow_state(follower, followed) do
state when state in ["accept", "pending"] ->
FollowingRelationship.unfollow(follower, followed)
{:ok, followed} = update_follower_count(followed)
{:ok, followed} = update_follower_count(followed)
{:ok, follower} =
follower
|> update_following_count()
|> set_cache()
{:ok, follower} =
follower
|> update_following_count()
|> set_cache()
{:ok, follower, Utils.fetch_latest_follow(follower, followed)}
{:ok, follower, Utils.fetch_latest_follow(follower, followed)}
else
{:error, "Not subscribed!"}
nil ->
{:error, "Not subscribed!"}
end
end
defdelegate following?(follower, followed), to: FollowingRelationship
def get_follow_state(%User{} = follower, %User{} = following) do
following_relationship = FollowingRelationship.get(follower, following)
case {following_relationship, following.local} do
{nil, false} ->
case Utils.fetch_latest_follow(follower, following) do
%{data: %{"state" => state}} when state in ["pending", "accept"] -> state
_ -> nil
end
{%{state: state}, _} ->
state
{nil, _} ->
nil
end
end
def locked?(%User{} = user) do
user.locked || false
end

View file

@ -325,12 +325,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def react_with_emoji(user, object, emoji, options \\ []) do
with local <- Keyword.get(options, :local, true),
activity_id <- Keyword.get(options, :activity_id, nil),
Pleroma.Emoji.is_unicode_emoji?(emoji),
true <- Pleroma.Emoji.is_unicode_emoji?(emoji),
reaction_data <- make_emoji_reaction_data(user, object, emoji, activity_id),
{:ok, activity} <- insert(reaction_data, local),
{:ok, object} <- add_emoji_reaction_to_object(activity, object),
:ok <- maybe_federate(activity) do
{:ok, activity, object}
else
e -> {:error, e}
end
end
@ -345,6 +347,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
{:ok, object} <- remove_emoji_reaction_from_object(reaction_activity, object),
:ok <- maybe_federate(activity) do
{:ok, activity, object}
else
e -> {:error, e}
end
end

View file

@ -580,7 +580,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
"star" => ""
}
@doc "Rewrite misskey likes into EmojiReactions"
@doc "Rewrite misskey likes into EmojiReacts"
def handle_incoming(
%{
"type" => "Like",
@ -589,7 +589,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
options
) do
data
|> Map.put("type", "EmojiReaction")
|> Map.put("type", "EmojiReact")
|> Map.put("content", @misskey_reactions[reaction] || reaction)
|> handle_incoming(options)
end
@ -610,7 +610,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def handle_incoming(
%{
"type" => "EmojiReaction",
"type" => "EmojiReact",
"object" => object_id,
"actor" => _actor,
"id" => id,
@ -751,7 +751,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def handle_incoming(
%{
"type" => "Undo",
"object" => %{"type" => "EmojiReaction", "id" => reaction_activity_id},
"object" => %{"type" => "EmojiReact", "id" => reaction_activity_id},
"actor" => _actor,
"id" => id
} = data,

View file

@ -308,7 +308,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
def make_emoji_reaction_data(user, object, emoji, activity_id) do
make_like_data(user, object, activity_id)
|> Map.put("type", "EmojiReaction")
|> Map.put("type", "EmojiReact")
|> Map.put("content", emoji)
end
@ -490,10 +490,19 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> Repo.one()
end
def fetch_latest_undo(%User{ap_id: ap_id}) do
"Undo"
|> Activity.Queries.by_type()
|> where(actor: ^ap_id)
|> order_by([activity], fragment("? desc nulls last", activity.id))
|> limit(1)
|> Repo.one()
end
def get_latest_reaction(internal_activity_id, %{ap_id: ap_id}, emoji) do
%{data: %{"object" => object_ap_id}} = Activity.get_by_id(internal_activity_id)
"EmojiReaction"
"EmojiReact"
|> Activity.Queries.by_type()
|> where(actor: ^ap_id)
|> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji))

View file

@ -97,7 +97,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
plug(
OAuthScopesPlug,
%{scopes: ["read"], admin: true}
when action in [:config_show, :migrate_from_db, :list_log]
when action in [:config_show, :list_log]
)
plug(
@ -793,33 +793,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|> Plug.Conn.send_resp(200, @descriptions_json)
end
def migrate_from_db(conn, _params) do
with :ok <- configurable_from_database(conn) do
Mix.Tasks.Pleroma.Config.run([
"migrate_from_db",
"--env",
to_string(Pleroma.Config.get(:env)),
"-d"
])
json(conn, %{})
end
end
def config_show(conn, %{"only_db" => true}) do
with :ok <- configurable_from_database(conn) do
configs = Pleroma.Repo.all(ConfigDB)
if configs == [] do
errors(
conn,
{:error, "To use configuration from database migrate your settings to database."}
)
else
conn
|> put_view(ConfigView)
|> render("index.json", %{configs: configs})
end
conn
|> put_view(ConfigView)
|> render("index.json", %{configs: configs})
end
end
@ -827,45 +807,38 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
with :ok <- configurable_from_database(conn) do
configs = ConfigDB.get_all_as_keyword()
if configs == [] do
errors(
conn,
{:error, "To use configuration from database migrate your settings to database."}
)
else
merged =
Pleroma.Config.Holder.config()
|> ConfigDB.merge(configs)
|> Enum.map(fn {group, values} ->
Enum.map(values, fn {key, value} ->
db =
if configs[group][key] do
ConfigDB.get_db_keys(configs[group][key], key)
end
merged =
Pleroma.Config.Holder.config()
|> ConfigDB.merge(configs)
|> Enum.map(fn {group, values} ->
Enum.map(values, fn {key, value} ->
db =
if configs[group][key] do
ConfigDB.get_db_keys(configs[group][key], key)
end
db_value = configs[group][key]
db_value = configs[group][key]
merged_value =
if !is_nil(db_value) and Keyword.keyword?(db_value) and
ConfigDB.sub_key_full_update?(group, key, Keyword.keys(db_value)) do
ConfigDB.merge_group(group, key, value, db_value)
else
value
end
merged_value =
if !is_nil(db_value) and Keyword.keyword?(db_value) and
ConfigDB.sub_key_full_update?(group, key, Keyword.keys(db_value)) do
ConfigDB.merge_group(group, key, value, db_value)
else
value
end
setting = %{
group: ConfigDB.convert(group),
key: ConfigDB.convert(key),
value: ConfigDB.convert(merged_value)
}
setting = %{
group: ConfigDB.convert(group),
key: ConfigDB.convert(key),
value: ConfigDB.convert(merged_value)
}
if db, do: Map.put(setting, :db, db), else: setting
end)
if db, do: Map.put(setting, :db, db), else: setting
end)
|> List.flatten()
end)
|> List.flatten()
json(conn, %{configs: merged})
end
json(conn, %{configs: merged})
end
end
@ -890,17 +863,36 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
Ecto.get_meta(config, :state) == :deleted
end)
Pleroma.Config.TransferTask.load_and_update_env(deleted)
Pleroma.Config.TransferTask.load_and_update_env(deleted, false)
Mix.Tasks.Pleroma.Config.run([
"migrate_from_db",
"--env",
to_string(Pleroma.Config.get(:env))
])
need_reboot? =
Enum.any?(updated, fn config ->
group = ConfigDB.from_string(config.group)
key = ConfigDB.from_string(config.key)
value = ConfigDB.from_binary(config.value)
Pleroma.Config.TransferTask.pleroma_need_restart?(group, key, value)
end)
response = %{configs: updated}
response =
if need_reboot?, do: Map.put(response, :need_reboot, need_reboot?), else: response
conn
|> put_view(ConfigView)
|> render("index.json", %{configs: updated})
|> render("index.json", response)
end
end
def restart(conn, _params) do
with :ok <- configurable_from_database(conn) do
if Pleroma.Config.get(:env) == :test do
Logger.warn("pleroma restarted")
else
send(Restarter.Pleroma, {:restart, 50})
end
json(conn, %{})
end
end

View file

@ -5,10 +5,16 @@
defmodule Pleroma.Web.AdminAPI.ConfigView do
use Pleroma.Web, :view
def render("index.json", %{configs: configs}) do
%{
def render("index.json", %{configs: configs} = params) do
map = %{
configs: render_many(configs, __MODULE__, "show.json", as: :config)
}
if params[:need_reboot] do
Map.put(map, :need_reboot, true)
else
map
end
end
def render("show.json", %{config: config}) do

View file

@ -315,8 +315,9 @@ defmodule Pleroma.Web.CommonAPI do
with %Activity{
actor: ^user_ap_id,
data: %{"type" => "Create"},
object: %Object{data: %{"type" => "Note"}}
object: %Object{data: %{"type" => object_type}}
} = activity <- get_by_id_or_ap_id(id_or_ap_id),
true <- object_type in ["Note", "Article", "Question"],
true <- Visibility.is_public?(activity),
{:ok, _user} <- User.add_pinnned_activity(user, activity) do
{:ok, activity}

View file

@ -179,9 +179,9 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end)
end_time =
NaiveDateTime.utc_now()
|> NaiveDateTime.add(expires_in)
|> NaiveDateTime.to_iso8601()
DateTime.utc_now()
|> DateTime.add(expires_in)
|> DateTime.to_iso8601()
key = if truthy_param?(data["poll"]["multiple"]), do: "anyOf", else: "oneOf"
poll = %{"type" => "Question", key => option_notes, "closed" => end_time}

View file

@ -61,7 +61,17 @@ defmodule Pleroma.Web.Endpoint do
plug(Plug.RequestId)
plug(Plug.Logger, log: :debug)
plug(Pleroma.Plugs.Parsers)
plug(Plug.Parsers,
parsers: [
:urlencoded,
{:multipart, length: {Pleroma.Config, :get, [[:instance, :upload_limit]]}},
:json
],
pass: ["*/*"],
json_decoder: Jason,
length: Pleroma.Config.get([:instance, :upload_limit]),
body_reader: {Pleroma.Web.Plugs.DigestPlug, :read_body, []}
)
plug(Plug.MethodOverride)
plug(Plug.Head)

View file

@ -67,7 +67,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
end
defp do_render("show.json", %{user: user} = opts) do
display_name = HTML.strip_tags(user.name || user.nickname)
display_name = user.name || user.nickname
image = User.avatar_url(user) |> MediaProxy.url()
header = User.banner_url(user) |> MediaProxy.url()
@ -105,7 +105,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|> User.fields()
|> Enum.map(fn %{"name" => name, "value" => value} ->
%{
"name" => Pleroma.HTML.strip_tags(name),
"name" => name,
"value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
}
end)

View file

@ -5,7 +5,6 @@
defmodule Pleroma.Web.MastodonAPI.PollView do
use Pleroma.Web, :view
alias Pleroma.HTML
alias Pleroma.Web.CommonAPI.Utils
def render("show.json", %{object: object, multiple: multiple, options: options} = params) do
@ -57,7 +56,7 @@ defmodule Pleroma.Web.MastodonAPI.PollView do
current_count = option["replies"]["totalItems"] || 0
{%{
title: HTML.strip_tags(name),
title: name,
votes_count: current_count
}, current_count + count}
end)

View file

@ -216,21 +216,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
summary = object.data["summary"] || ""
summary_html =
summary
|> HTML.get_cached_scrubbed_html_for_activity(
User.html_filter_policy(opts[:for]),
activity,
"mastoapi:summary"
)
summary_plaintext =
summary
|> HTML.get_cached_stripped_html_for_activity(
activity,
"mastoapi:summary"
)
card = render("card.json", Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity))
url =
@ -256,7 +241,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
emoji_reactions =
with %{data: %{"reactions" => emoji_reactions}} <- object do
Enum.map(emoji_reactions, fn [emoji, users] ->
%{emoji: emoji, count: length(users)}
%{
emoji: emoji,
count: length(users),
reacted: !!(opts[:for] && opts[:for].ap_id in users)
}
end)
else
_ -> []
@ -282,7 +271,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
muted: thread_muted? || User.mutes?(opts[:for], user),
pinned: pinned?(activity, user),
sensitive: sensitive,
spoiler_text: summary_html,
spoiler_text: summary,
visibility: get_visibility(object),
media_attachments: attachments,
poll: render(PollView, "show.json", object: object, for: opts[:for]),
@ -299,7 +288,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
conversation_id: get_context_id(activity),
in_reply_to_account_acct: reply_to_user && reply_to_user.nickname,
content: %{"text/plain" => content_plaintext},
spoiler_text: %{"text/plain" => summary_plaintext},
spoiler_text: %{"text/plain" => summary},
expires_at: expires_at,
direct_conversation_id: direct_conversation_id,
thread_muted: thread_muted?,

View file

@ -573,11 +573,14 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
assumed to be emojis and stored in the new `pack.json` file.
"""
def import_from_fs(conn, _params) do
with {:ok, results} <- File.ls(emoji_dir_path()) do
emoji_path = emoji_dir_path()
with {:ok, %{access: :read_write}} <- File.stat(emoji_path),
{:ok, results} <- File.ls(emoji_path) do
imported_pack_names =
results
|> Enum.filter(fn file ->
dir_path = Path.join(emoji_dir_path(), file)
dir_path = Path.join(emoji_path, file)
# Find the directories that do NOT have pack.json
File.dir?(dir_path) and not File.exists?(Path.join(dir_path, "pack.json"))
end)
@ -585,6 +588,11 @@ keeping it in cache for #{div(cache_ms, 1000)}s")
json(conn, imported_pack_names)
else
{:ok, %{access: _}} ->
conn
|> put_status(:internal_server_error)
|> json(%{error: "Error: emoji pack directory must be writable"})
{:error, _} ->
conn
|> put_status(:internal_server_error)

View file

@ -47,13 +47,16 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
Object.normalize(activity) do
reactions =
emoji_reactions
|> Enum.map(fn [emoji, users] ->
users = Enum.map(users, &User.get_cached_by_ap_id/1)
|> Enum.map(fn [emoji, user_ap_ids] ->
users =
Enum.map(user_ap_ids, &User.get_cached_by_ap_id/1)
|> Enum.filter(& &1)
%{
emoji: emoji,
count: length(users),
accounts: AccountView.render("index.json", %{users: users, for: user, as: :user})
accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}),
reacted: !!(user && user.ap_id in user_ap_ids)
}
end)

View file

@ -48,6 +48,6 @@ defmodule Pleroma.Web.RichMedia.Parsers.MetaTagsParser do
defp maybe_put_title(meta, _), do: meta
defp get_page_title(html) do
Floki.find(html, "title") |> List.first() |> Floki.text()
Floki.find(html, "html head title") |> List.first() |> Floki.text()
end
end

View file

@ -196,7 +196,7 @@ defmodule Pleroma.Web.Router do
get("/config", AdminAPIController, :config_show)
post("/config", AdminAPIController, :config_update)
get("/config/descriptions", AdminAPIController, :config_descriptions)
get("/config/migrate_from_db", AdminAPIController, :migrate_from_db)
get("/restart", AdminAPIController, :restart)
get("/moderation_log", AdminAPIController, :list_log)

View file

@ -138,7 +138,8 @@ defmodule Pleroma.Web.Streamer.Worker do
with parent <- Object.normalize(item) || item,
true <-
Enum.all?([blocked_ap_ids, muted_ap_ids, reblog_muted_ap_ids], &(item.actor not in &1)),
Enum.all?([blocked_ap_ids, muted_ap_ids], &(item.actor not in &1)),
true <- item.data["type"] != "Announce" || item.actor not in reblog_muted_ap_ids,
true <- Enum.all?([blocked_ap_ids, muted_ap_ids], &(parent.data["actor"] not in &1)),
true <- MapSet.disjoint?(recipients, recipient_blocks),
%{host: item_host} <- URI.parse(item.actor),