Merge branch 'develop' into issue/1934-welcome-email

This commit is contained in:
Maksim Pechnikov 2020-07-23 16:36:27 +03:00
commit 67ab9a7928
47 changed files with 579 additions and 174 deletions

View file

@ -16,6 +16,7 @@ defmodule Pleroma.ApplicationRequirements do
@spec verify!() :: :ok | VerifyError.t()
def verify! do
:ok
|> check_confirmation_accounts!
|> check_migrations_applied!()
|> check_welcome_message_config!()
|> check_rum!()
@ -41,6 +42,24 @@ defmodule Pleroma.ApplicationRequirements do
defp check_welcome_message_config!(result), do: result
# Checks account confirmation email
#
def check_confirmation_accounts!(:ok) do
if Pleroma.Config.get([:instance, :account_activation_required]) &&
not Pleroma.Config.get([Pleroma.Emails.Mailer, :enabled]) do
Logger.error(
"Account activation enabled, but no Mailer settings enabled.\nPlease set config :pleroma, :instance, account_activation_required: false\nOtherwise setup and enable Mailer."
)
{:error,
"Account activation enabled, but Mailer is disabled. Cannot send confirmation emails."}
else
:ok
end
end
def check_confirmation_accounts!(result), do: result
# Checks for pending migrations.
#
def check_migrations_applied!(:ok) do

View file

@ -156,7 +156,6 @@ defmodule Pleroma.ConfigDB do
{:quack, :meta},
{:mime, :types},
{:cors_plug, [:max_age, :methods, :expose, :headers]},
{:auto_linker, :opts},
{:swarm, :node_blacklist},
{:logger, :backends}
]

View file

@ -10,11 +10,15 @@ defmodule Pleroma.Formatter do
@link_regex ~r"((?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~%:/?#[\]@!\$&'\(\)\*\+,;=.]+)|[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+"ui
@markdown_characters_regex ~r/(`|\*|_|{|}|[|]|\(|\)|#|\+|-|\.|!)/
@auto_linker_config hashtag: true,
hashtag_handler: &Pleroma.Formatter.hashtag_handler/4,
mention: true,
mention_handler: &Pleroma.Formatter.mention_handler/4,
scheme: true
defp linkify_opts do
Pleroma.Config.get(Pleroma.Formatter) ++
[
hashtag: true,
hashtag_handler: &Pleroma.Formatter.hashtag_handler/4,
mention: true,
mention_handler: &Pleroma.Formatter.mention_handler/4
]
end
def escape_mention_handler("@" <> nickname = mention, buffer, _, _) do
case User.get_cached_by_nickname(nickname) do
@ -80,19 +84,19 @@ defmodule Pleroma.Formatter do
@spec linkify(String.t(), keyword()) ::
{String.t(), [{String.t(), User.t()}], [{String.t(), String.t()}]}
def linkify(text, options \\ []) do
options = options ++ @auto_linker_config
options = linkify_opts() ++ options
if options[:safe_mention] && Regex.named_captures(@safe_mention_regex, text) do
%{"mentions" => mentions, "rest" => rest} = Regex.named_captures(@safe_mention_regex, text)
acc = %{mentions: MapSet.new(), tags: MapSet.new()}
{text_mentions, %{mentions: mentions}} = AutoLinker.link_map(mentions, acc, options)
{text_rest, %{tags: tags}} = AutoLinker.link_map(rest, acc, options)
{text_mentions, %{mentions: mentions}} = Linkify.link_map(mentions, acc, options)
{text_rest, %{tags: tags}} = Linkify.link_map(rest, acc, options)
{text_mentions <> text_rest, MapSet.to_list(mentions), MapSet.to_list(tags)}
else
acc = %{mentions: MapSet.new(), tags: MapSet.new()}
{text, %{mentions: mentions, tags: tags}} = AutoLinker.link_map(text, acc, options)
{text, %{mentions: mentions, tags: tags}} = Linkify.link_map(text, acc, options)
{text, MapSet.to_list(mentions), MapSet.to_list(tags)}
end
@ -111,9 +115,9 @@ defmodule Pleroma.Formatter do
if options[:safe_mention] && Regex.named_captures(@safe_mention_regex, text) do
%{"mentions" => mentions, "rest" => rest} = Regex.named_captures(@safe_mention_regex, text)
AutoLinker.link(mentions, options) <> AutoLinker.link(rest, options)
Linkify.link(mentions, options) <> Linkify.link(rest, options)
else
AutoLinker.link(text, options)
Linkify.link(text, options)
end
end

View file

@ -96,16 +96,18 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
def response("/main/public") do
posts =
ActivityPub.fetch_public_activities(%{"type" => ["Create"], "local_only" => true})
|> render_activities
%{type: ["Create"], local_only: true}
|> ActivityPub.fetch_public_activities()
|> render_activities()
info("Welcome to the Public Timeline!") <> posts <> ".\r\n"
end
def response("/main/all") do
posts =
ActivityPub.fetch_public_activities(%{"type" => ["Create"]})
|> render_activities
%{type: ["Create"]}
|> ActivityPub.fetch_public_activities()
|> render_activities()
info("Welcome to the Federated Timeline!") <> posts <> ".\r\n"
end
@ -130,13 +132,14 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
def response("/users/" <> nickname) do
with %User{} = user <- User.get_cached_by_nickname(nickname) do
params = %{
"type" => ["Create"],
"actor_id" => user.ap_id
type: ["Create"],
actor_id: user.ap_id
}
activities =
ActivityPub.fetch_public_activities(params)
|> render_activities
params
|> ActivityPub.fetch_public_activities()
|> render_activities()
info("Posts by #{user.nickname}") <> activities <> ".\r\n"
else

View file

@ -124,6 +124,10 @@ defmodule Pleroma.Object.Fetcher do
{:error, "Object has been deleted"} ->
nil
{:reject, reason} ->
Logger.info("Rejected #{id} while fetching: #{inspect(reason)}")
nil
e ->
Logger.error("Error while fetching #{id}: #{inspect(e)}")
nil

View file

@ -740,21 +740,25 @@ defmodule Pleroma.User do
def send_welcome_email(_), do: {:ok, :noop}
def try_send_confirmation_email(%User{} = user) do
if user.confirmation_pending &&
Config.get([:instance, :account_activation_required]) do
user
|> Pleroma.Emails.UserEmail.account_confirmation_email()
|> Pleroma.Emails.Mailer.deliver_async()
@spec try_send_confirmation_email(User.t()) :: {:ok, :enqueued | :noop}
def try_send_confirmation_email(%User{confirmation_pending: true} = user) do
if Config.get([:instance, :account_activation_required]) do
send_confirmation_email(user)
{:ok, :enqueued}
else
{:ok, :noop}
end
end
def try_send_confirmation_email(users) do
Enum.each(users, &try_send_confirmation_email/1)
def try_send_confirmation_email(_), do: {:ok, :noop}
@spec send_confirmation_email(Uset.t()) :: User.t()
def send_confirmation_email(%User{} = user) do
user
|> Pleroma.Emails.UserEmail.account_confirmation_email()
|> Pleroma.Emails.Mailer.deliver_async()
user
end
def needs_update?(%User{local: true}), do: false

View file

@ -1370,6 +1370,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
Logger.debug("Could not decode user at fetch #{ap_id}, #{inspect(e)}")
{:error, e}
{:error, {:reject, reason} = e} ->
Logger.info("Rejected user #{ap_id}: #{inspect(reason)}")
{:error, e}
{:error, e} ->
Logger.error("Could not decode user at fetch #{ap_id}, #{inspect(e)}")
{:error, e}

View file

@ -178,7 +178,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> Map.drop(["conversation"])
else
e ->
Logger.error("Couldn't fetch #{inspect(in_reply_to_id)}, error: #{inspect(e)}")
Logger.warn("Couldn't fetch #{inspect(in_reply_to_id)}, error: #{inspect(e)}")
object
end
else

View file

@ -719,15 +719,18 @@ defmodule Pleroma.Web.ActivityPub.Utils do
case Activity.get_by_ap_id_with_object(id) do
%Activity{} = activity ->
activity_actor = User.get_by_ap_id(activity.object.data["actor"])
%{
"type" => "Note",
"id" => activity.data["id"],
"content" => activity.object.data["content"],
"published" => activity.object.data["published"],
"actor" =>
AccountView.render("show.json", %{
user: User.get_by_ap_id(activity.object.data["actor"])
})
AccountView.render(
"show.json",
%{user: activity_actor, skip_visibility_check: true}
)
}
_ ->

View file

@ -345,7 +345,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)) do
json(
conn,
AccountView.render("index.json", users: users, count: count, page_size: page_size)
AccountView.render("index.json",
users: users,
count: count,
page_size: page_size
)
)
end
end
@ -616,29 +620,24 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
def confirm_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
User.toggle_confirmation(users)
ModerationLog.insert_log(%{
actor: admin,
subject: users,
action: "confirm_email"
})
ModerationLog.insert_log(%{actor: admin, subject: users, action: "confirm_email"})
json(conn, "")
end
def resend_confirmation_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
users =
Enum.map(nicknames, fn nickname ->
nickname
|> User.get_cached_by_nickname()
|> User.send_confirmation_email()
end)
User.try_send_confirmation_email(users)
ModerationLog.insert_log(%{
actor: admin,
subject: users,
action: "resend_confirmation_email"
})
ModerationLog.insert_log(%{actor: admin, subject: users, action: "resend_confirmation_email"})
json(conn, "")
end

View file

@ -105,7 +105,7 @@ defmodule Pleroma.Web.AdminAPI.AccountView do
end
def merge_account_views(%User{} = user) do
MastodonAPI.AccountView.render("show.json", %{user: user})
MastodonAPI.AccountView.render("show.json", %{user: user, skip_visibility_check: true})
|> Map.merge(AdminAPI.AccountView.render("show.json", %{user: user}))
end

View file

@ -4,8 +4,10 @@
defmodule Pleroma.Web.ChatChannel do
use Phoenix.Channel
alias Pleroma.User
alias Pleroma.Web.ChatChannel.ChatChannelState
alias Pleroma.Web.MastodonAPI.AccountView
def join("chat:public", _message, socket) do
send(self(), :after_join)
@ -22,9 +24,9 @@ defmodule Pleroma.Web.ChatChannel do
if String.length(text) in 1..Pleroma.Config.get([:instance, :chat_limit]) do
author = User.get_cached_by_nickname(user_name)
author = Pleroma.Web.MastodonAPI.AccountView.render("show.json", user: author)
author_json = AccountView.render("show.json", user: author, skip_visibility_check: true)
message = ChatChannelState.add_message(%{text: text, author: author})
message = ChatChannelState.add_message(%{text: text, author: author_json})
broadcast!(socket, "new_msg", message)
end

View file

@ -93,7 +93,6 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
AccountView.render("index.json",
users: accounts,
for: options[:for_user],
as: :user,
embed_relationships: options[:embed_relationships]
)
end

View file

@ -27,21 +27,40 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
UserRelationship.view_relationships_option(reading_user, users)
end
opts = Map.put(opts, :relationships, relationships_opt)
opts =
opts
|> Map.merge(%{relationships: relationships_opt, as: :user})
|> Map.delete(:users)
users
|> render_many(AccountView, "show.json", opts)
|> Enum.filter(&Enum.any?/1)
end
def render("show.json", %{user: user} = opts) do
if User.visible_for(user, opts[:for]) == :visible do
@doc """
Renders specified user account.
:skip_visibility_check option skips visibility check and renders any user (local or remote)
regardless of [:pleroma, :restrict_unauthenticated] setting.
:for option specifies the requester and can be a User record or nil.
Only use `user: user, for: user` when `user` is the actual requester of own profile.
"""
def render("show.json", %{user: _user, skip_visibility_check: true} = opts) do
do_render("show.json", opts)
end
def render("show.json", %{user: user, for: for_user_or_nil} = opts) do
if User.visible_for(user, for_user_or_nil) == :visible do
do_render("show.json", opts)
else
%{}
end
end
def render("show.json", _) do
raise "In order to prevent account accessibility issues, " <>
":skip_visibility_check or :for option is required."
end
def render("mention.json", %{user: user}) do
%{
id: to_string(user.id),

View file

@ -38,7 +38,7 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do
%{
id: participation.id |> to_string(),
accounts: render(AccountView, "index.json", users: users, as: :user),
accounts: render(AccountView, "index.json", users: users, for: user),
unread: !participation.read,
last_status:
render(StatusView, "show.json",

View file

@ -89,11 +89,11 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
cm_ref <- MessageReference.for_chat_and_object(chat, message) do
conn
|> put_view(MessageReferenceView)
|> render("show.json", for: user, chat_message_reference: cm_ref)
|> render("show.json", chat_message_reference: cm_ref)
end
end
def mark_message_as_read(%{assigns: %{user: %{id: user_id} = user}} = conn, %{
def mark_message_as_read(%{assigns: %{user: %{id: user_id}}} = conn, %{
id: chat_id,
message_id: message_id
}) do
@ -104,12 +104,15 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
{:ok, cm_ref} <- MessageReference.mark_as_read(cm_ref) do
conn
|> put_view(MessageReferenceView)
|> render("show.json", for: user, chat_message_reference: cm_ref)
|> render("show.json", chat_message_reference: cm_ref)
end
end
def mark_as_read(
%{body_params: %{last_read_id: last_read_id}, assigns: %{user: %{id: user_id}}} = conn,
%{
body_params: %{last_read_id: last_read_id},
assigns: %{user: %{id: user_id}}
} = conn,
%{id: id}
) do
with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id),
@ -121,7 +124,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
end
end
def messages(%{assigns: %{user: %{id: user_id} = user}} = conn, %{id: id} = params) do
def messages(%{assigns: %{user: %{id: user_id}}} = conn, %{id: id} = params) do
with %Chat{} = chat <- Repo.get_by(Chat, id: id, user_id: user_id) do
cm_refs =
chat
@ -130,7 +133,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatController do
conn
|> put_view(MessageReferenceView)
|> render("index.json", for: user, chat_message_references: cm_refs)
|> render("index.json", chat_message_references: cm_refs)
else
_ ->
conn

View file

@ -21,8 +21,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackController do
]
)
@skip_plugs [Pleroma.Plugs.OAuthScopesPlug, Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug]
plug(:skip_plug, @skip_plugs when action in [:archive, :show, :list])
@skip_plugs [Pleroma.Plugs.OAuthScopesPlug, Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug]
plug(:skip_plug, @skip_plugs when action in [:index, :show, :archive])
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaEmojiPackOperation

View file

@ -15,10 +15,11 @@ defmodule Pleroma.Web.PleromaAPI.ChatView do
def render("show.json", %{chat: %Chat{} = chat} = opts) do
recipient = User.get_cached_by_ap_id(chat.recipient)
last_message = opts[:last_message] || MessageReference.last_message_for_chat(chat)
account_view_opts = account_view_opts(opts, recipient)
%{
id: chat.id |> to_string(),
account: AccountView.render("show.json", Map.put(opts, :user, recipient)),
account: AccountView.render("show.json", account_view_opts),
unread: MessageReference.unread_count_for_chat(chat),
last_message:
last_message &&
@ -27,7 +28,17 @@ defmodule Pleroma.Web.PleromaAPI.ChatView do
}
end
def render("index.json", %{chats: chats}) do
render_many(chats, __MODULE__, "show.json")
def render("index.json", %{chats: chats} = opts) do
render_many(chats, __MODULE__, "show.json", Map.delete(opts, :chats))
end
defp account_view_opts(opts, recipient) do
account_view_opts = Map.put(opts, :user, recipient)
if Map.has_key?(account_view_opts, :for) do
account_view_opts
else
Map.put(account_view_opts, :skip_visibility_check, true)
end
end
end

View file

@ -17,7 +17,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionView do
%{
name: emoji,
count: length(users),
accounts: render(AccountView, "index.json", users: users, for: user, as: :user),
accounts: render(AccountView, "index.json", users: users, for: user),
me: !!(user && user.ap_id in user_ap_ids)
}
end

View file

@ -11,10 +11,10 @@ defmodule Pleroma.Web.RichMedia.Helpers do
@spec validate_page_url(URI.t() | binary()) :: :ok | :error
defp validate_page_url(page_url) when is_binary(page_url) do
validate_tld = Application.get_env(:auto_linker, :opts)[:validate_tld]
validate_tld = Pleroma.Config.get([Pleroma.Formatter, :validate_tld])
page_url
|> AutoLinker.Parser.url?(scheme: true, validate_tld: validate_tld)
|> Linkify.Parser.url?(validate_tld: validate_tld)
|> parse_uri(page_url)
end