aboutsummaryrefslogtreecommitdiff
path: root/lib/pleroma/web
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pleroma/web')
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex141
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub_controller.ex8
-rw-r--r--lib/pleroma/web/activity_pub/mrf.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf/keyword_policy.ex38
-rw-r--r--lib/pleroma/web/activity_pub/relay.ex6
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex98
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex69
-rw-r--r--lib/pleroma/web/activity_pub/views/object_view.ex4
-rw-r--r--lib/pleroma/web/activity_pub/views/user_view.ex31
-rw-r--r--lib/pleroma/web/admin_api/admin_api_controller.ex53
-rw-r--r--lib/pleroma/web/admin_api/search.ex54
-rw-r--r--lib/pleroma/web/admin_api/views/account_view.ex (renamed from lib/pleroma/web/mastodon_api/views/admin/account_view.ex)10
-rw-r--r--lib/pleroma/web/auth/ldap_authenticator.ex143
-rw-r--r--lib/pleroma/web/auth/pleroma_authenticator.ex11
-rw-r--r--lib/pleroma/web/channels/user_socket.ex4
-rw-r--r--lib/pleroma/web/chat_channel.ex4
-rw-r--r--lib/pleroma/web/common_api/common_api.ex100
-rw-r--r--lib/pleroma/web/common_api/utils.ex58
-rw-r--r--lib/pleroma/web/controller_helper.ex8
-rw-r--r--lib/pleroma/web/endpoint.ex3
-rw-r--r--lib/pleroma/web/federator/federator.ex33
-rw-r--r--lib/pleroma/web/federator/retry_queue.ex10
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api.ex50
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api_controller.ex213
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/views/app_view.ex41
-rw-r--r--lib/pleroma/web/mastodon_api/views/notification_view.ex64
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex24
-rw-r--r--lib/pleroma/web/mastodon_api/websocket_handler.ex4
-rw-r--r--lib/pleroma/web/media_proxy/media_proxy.ex3
-rw-r--r--lib/pleroma/web/metadata/opengraph.ex2
-rw-r--r--lib/pleroma/web/metadata/twitter_card.ex3
-rw-r--r--lib/pleroma/web/metadata/utils.ex4
-rw-r--r--lib/pleroma/web/nodeinfo/nodeinfo.ex1
-rw-r--r--lib/pleroma/web/nodeinfo/nodeinfo_controller.ex3
-rw-r--r--lib/pleroma/web/oauth/authorization.ex6
-rw-r--r--lib/pleroma/web/oauth/oauth_controller.ex70
-rw-r--r--lib/pleroma/web/oauth/token.ex8
-rw-r--r--lib/pleroma/web/ostatus/activity_representer.ex2
-rw-r--r--lib/pleroma/web/ostatus/feed_representer.ex2
-rw-r--r--lib/pleroma/web/ostatus/handlers/delete_handler.ex2
-rw-r--r--lib/pleroma/web/ostatus/handlers/follow_handler.ex6
-rw-r--r--lib/pleroma/web/ostatus/handlers/note_handler.ex34
-rw-r--r--lib/pleroma/web/ostatus/handlers/unfollow_handler.ex6
-rw-r--r--lib/pleroma/web/ostatus/ostatus.ex22
-rw-r--r--lib/pleroma/web/ostatus/ostatus_controller.ex19
-rw-r--r--lib/pleroma/web/push/impl.ex18
-rw-r--r--lib/pleroma/web/push/push.ex6
-rw-r--r--lib/pleroma/web/push/subscription.ex4
-rw-r--r--lib/pleroma/web/rel_me.ex1
-rw-r--r--lib/pleroma/web/rich_media/helpers.ex8
-rw-r--r--lib/pleroma/web/rich_media/parser.ex1
-rw-r--r--lib/pleroma/web/router.ex26
-rw-r--r--lib/pleroma/web/salmon/salmon.ex6
-rw-r--r--lib/pleroma/web/streamer.ex32
-rw-r--r--lib/pleroma/web/templates/layout/app.html.eex140
-rw-r--r--lib/pleroma/web/templates/o_auth/o_auth/show.html.eex35
-rw-r--r--lib/pleroma/web/twitter_api/controllers/util_controller.ex28
-rw-r--r--lib/pleroma/web/twitter_api/representers/activity_representer.ex15
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api.ex51
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api_controller.ex51
-rw-r--r--lib/pleroma/web/twitter_api/views/activity_view.ex7
-rw-r--r--lib/pleroma/web/web_finger/web_finger.ex6
-rw-r--r--lib/pleroma/web/websub/websub.ex18
-rw-r--r--lib/pleroma/web/websub/websub_client_subscription.ex2
-rw-r--r--lib/pleroma/web/websub/websub_controller.ex2
66 files changed, 1363 insertions, 573 deletions
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index adb42b9ab..6e1ed7ec9 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -4,17 +4,17 @@
defmodule Pleroma.Web.ActivityPub.ActivityPub do
alias Pleroma.Activity
- alias Pleroma.Repo
+ alias Pleroma.Instances
+ alias Pleroma.Notification
alias Pleroma.Object
+ alias Pleroma.Repo
alias Pleroma.Upload
alias Pleroma.User
- alias Pleroma.Notification
- alias Pleroma.Instances
- alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.MRF
- alias Pleroma.Web.WebFinger
+ alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.Federator
alias Pleroma.Web.OStatus
+ alias Pleroma.Web.WebFinger
import Ecto.Query
import Pleroma.Web.ActivityPub.Utils
@@ -89,13 +89,37 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
if is_public?(object), do: User.decrease_note_count(actor), else: {:ok, actor}
end
+ def increase_replies_count_if_reply(%{
+ "object" =>
+ %{"inReplyTo" => reply_ap_id, "inReplyToStatusId" => reply_status_id} = object,
+ "type" => "Create"
+ }) do
+ if is_public?(object) do
+ Activity.increase_replies_count(reply_status_id)
+ Object.increase_replies_count(reply_ap_id)
+ end
+ end
+
+ def increase_replies_count_if_reply(_create_data), do: :noop
+
+ def decrease_replies_count_if_reply(%Object{
+ data: %{"inReplyTo" => reply_ap_id, "inReplyToStatusId" => reply_status_id} = object
+ }) do
+ if is_public?(object) do
+ Activity.decrease_replies_count(reply_status_id)
+ Object.decrease_replies_count(reply_ap_id)
+ end
+ end
+
+ def decrease_replies_count_if_reply(_object), do: :noop
+
def insert(map, local \\ true) when is_map(map) do
with nil <- Activity.normalize(map),
map <- lazy_put_activity_defaults(map),
:ok <- check_actor_is_active(map["actor"]),
{_, true} <- {:remote_limit_error, check_remote_limit(map)},
{:ok, map} <- MRF.filter(map),
- :ok <- insert_full_object(map) do
+ {:ok, object} <- insert_full_object(map) do
{recipients, _, _} = get_recipients(map)
{:ok, activity} =
@@ -106,6 +130,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
recipients: recipients
})
+ # Splice in the child object if we have one.
+ activity =
+ if !is_nil(object) do
+ Map.put(activity, :object, object)
+ else
+ activity
+ end
+
Task.start(fn ->
Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
end)
@@ -170,7 +202,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
additional
),
{:ok, activity} <- insert(create_data, local),
- # Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info
+ _ <- increase_replies_count_if_reply(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),
:ok <- maybe_federate(activity) do
{:ok, activity}
@@ -309,18 +343,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def delete(%Object{data: %{"id" => id, "actor" => actor}} = object, local \\ true) do
user = User.get_cached_by_ap_id(actor)
- to = object.data["to"] || [] ++ object.data["cc"] || []
+ to = (object.data["to"] || []) ++ (object.data["cc"] || [])
- data = %{
- "type" => "Delete",
- "actor" => actor,
- "object" => id,
- "to" => to
- }
-
- with {:ok, _} <- Object.delete(object),
+ with {:ok, object, activity} <- Object.delete(object),
+ data <- %{
+ "type" => "Delete",
+ "actor" => actor,
+ "object" => id,
+ "to" => to,
+ "deleted_activity_id" => activity && activity.id
+ },
{:ok, activity} <- insert(data, local),
- # Changing note count prior to enqueuing federation task in order to avoid race conditions on updating user.info
+ _ <- decrease_replies_count_if_reply(object),
+ # Changing note count prior to enqueuing federation task in order to avoid
+ # race conditions on updating user.info
{:ok, _actor} <- decrease_note_count_if_public(user, object),
:ok <- maybe_federate(activity) do
{:ok, activity}
@@ -368,20 +404,38 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
content: content
} = params
) do
- additional = params[:additional] || %{}
-
# only accept false as false value
local = !(params[:local] == false)
+ forward = !(params[:forward] == false)
+
+ additional = params[:additional] || %{}
- %{
+ params = %{
actor: actor,
context: context,
account: account,
statuses: statuses,
content: content
}
- |> make_flag_data(additional)
- |> insert(local)
+
+ additional =
+ if forward do
+ Map.merge(additional, %{"to" => [], "cc" => [account.ap_id]})
+ else
+ Map.merge(additional, %{"to" => [], "cc" => []})
+ end
+
+ with flag_data <- make_flag_data(params, additional),
+ {:ok, activity} <- insert(flag_data, local),
+ :ok <- maybe_federate(activity) do
+ Enum.each(User.all_superusers(), fn superuser ->
+ superuser
+ |> Pleroma.AdminEmail.report(actor, account, statuses, content)
+ |> Pleroma.Mailer.deliver_async()
+ end)
+
+ {:ok, activity}
+ end
end
def fetch_activities_for_context(context, opts \\ %{}) do
@@ -410,6 +464,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
),
order_by: [desc: :id]
)
+ |> Activity.with_preloaded_object()
Repo.all(query)
end
@@ -502,7 +557,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
when is_list(tag_reject) and tag_reject != [] do
from(
activity in query,
- where: fragment("(not (? #> '{\"object\",\"tag\"}') \\?| ?)", activity.data, ^tag_reject)
+ where: fragment(~s(\(not \(? #> '{"object","tag"}'\) \\?| ?\)), activity.data, ^tag_reject)
)
end
@@ -512,7 +567,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
when is_list(tag_all) and tag_all != [] do
from(
activity in query,
- where: fragment("(? #> '{\"object\",\"tag\"}') \\?& ?", activity.data, ^tag_all)
+ where: fragment(~s(\(? #> '{"object","tag"}'\) \\?& ?), activity.data, ^tag_all)
)
end
@@ -521,14 +576,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_tag(query, %{"tag" => tag}) when is_list(tag) do
from(
activity in query,
- where: fragment("(? #> '{\"object\",\"tag\"}') \\?| ?", activity.data, ^tag)
+ where: fragment(~s(\(? #> '{"object","tag"}'\) \\?| ?), activity.data, ^tag)
)
end
defp restrict_tag(query, %{"tag" => tag}) when is_binary(tag) do
from(
activity in query,
- where: fragment("? <@ (? #> '{\"object\",\"tag\"}')", ^tag, activity.data)
+ where: fragment(~s(? <@ (? #> '{"object","tag"}'\)), ^tag, activity.data)
)
end
@@ -601,7 +656,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_favorited_by(query, %{"favorited_by" => ap_id}) do
from(
activity in query,
- where: fragment("? <@ (? #> '{\"object\",\"likes\"}')", ^ap_id, activity.data)
+ where: fragment(~s(? <@ (? #> '{"object","likes"}'\)), ^ap_id, activity.data)
)
end
@@ -610,7 +665,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_media(query, %{"only_media" => val}) when val == "true" or val == "1" do
from(
activity in query,
- where: fragment("not (? #> '{\"object\",\"attachment\"}' = ?)", activity.data, ^[])
+ where: fragment(~s(not (? #> '{"object","attachment"}' = ?\)), activity.data, ^[])
)
end
@@ -677,6 +732,30 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_pinned(query, _), do: query
+ defp restrict_muted_reblogs(query, %{"muting_user" => %User{info: info}}) do
+ muted_reblogs = info.muted_reblogs || []
+
+ from(
+ activity in query,
+ where:
+ fragment(
+ "not ( ?->>'type' = 'Announce' and ? = ANY(?))",
+ activity.data,
+ activity.actor,
+ ^muted_reblogs
+ )
+ )
+ end
+
+ defp restrict_muted_reblogs(query, _), do: query
+
+ defp maybe_preload_objects(query, %{"skip_preload" => true}), do: query
+
+ defp maybe_preload_objects(query, _) do
+ query
+ |> Activity.with_preloaded_object()
+ end
+
def fetch_activities_query(recipients, opts \\ %{}) do
base_query =
from(
@@ -686,6 +765,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
)
base_query
+ |> maybe_preload_objects(opts)
|> restrict_recipients(recipients, opts["user"])
|> restrict_tag(opts)
|> restrict_tag_reject(opts)
@@ -704,6 +784,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> restrict_replies(opts)
|> restrict_reblogs(opts)
|> restrict_pinned(opts)
+ |> restrict_muted_reblogs(opts)
end
def fetch_activities(recipients, opts \\ %{}) do
@@ -907,7 +988,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
},
:ok <- Transmogrifier.contain_origin(id, params),
{:ok, activity} <- Transmogrifier.handle_incoming(params) do
- {:ok, Object.normalize(activity.data["object"])}
+ {:ok, Object.normalize(activity)}
else
{:error, {:reject, nil}} ->
{:reject, nil}
@@ -919,7 +1000,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
Logger.info("Couldn't get object via AP, trying out OStatus fetching...")
case OStatus.fetch_activity_from_url(id) do
- {:ok, [activity | _]} -> {:ok, Object.normalize(activity.data["object"])}
+ {:ok, [activity | _]} -> {:ok, Object.normalize(activity)}
e -> e
end
end
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index ff924a536..7091d6927 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -6,15 +6,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
use Pleroma.Web, :controller
alias Pleroma.Activity
- alias Pleroma.User
alias Pleroma.Object
- alias Pleroma.Web.ActivityPub.ObjectView
- alias Pleroma.Web.ActivityPub.UserView
+ alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.ActivityPub.Visibility
+ alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Web.ActivityPub.UserView
alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator
require Logger
diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex
index eebea207c..1aaa20050 100644
--- a/lib/pleroma/web/activity_pub/mrf.ex
+++ b/lib/pleroma/web/activity_pub/mrf.ex
@@ -16,7 +16,7 @@ defmodule Pleroma.Web.ActivityPub.MRF do
end)
end
- def get_policies() do
+ def get_policies do
Application.get_env(:pleroma, :instance, [])
|> Keyword.get(:rewrite_policy, [])
|> get_policies()
diff --git a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
index 5fdc03414..e8dfba672 100644
--- a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
@@ -4,6 +4,10 @@
defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
@behaviour Pleroma.Web.ActivityPub.MRF
+ defp string_matches?(string, _) when not is_binary(string) do
+ false
+ end
+
defp string_matches?(string, pattern) when is_binary(pattern) do
String.contains?(string, pattern)
end
@@ -44,14 +48,29 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
end
defp check_replace(%{"object" => %{"content" => content, "summary" => summary}} = message) do
+ content =
+ if is_binary(content) do
+ content
+ else
+ ""
+ end
+
+ summary =
+ if is_binary(summary) do
+ summary
+ else
+ ""
+ end
+
{content, summary} =
- Enum.reduce(Pleroma.Config.get([:mrf_keyword, :replace]), {content, summary}, fn {pattern,
- replacement},
- {content_acc,
- summary_acc} ->
- {String.replace(content_acc, pattern, replacement),
- String.replace(summary_acc, pattern, replacement)}
- end)
+ Enum.reduce(
+ Pleroma.Config.get([:mrf_keyword, :replace]),
+ {content, summary},
+ fn {pattern, replacement}, {content_acc, summary_acc} ->
+ {String.replace(content_acc, pattern, replacement),
+ String.replace(summary_acc, pattern, replacement)}
+ end
+ )
{:ok,
message
@@ -60,11 +79,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
end
@impl true
- def filter(%{"object" => %{"content" => nil}} = message) do
- {:ok, message}
- end
-
- @impl true
def filter(%{"type" => "Create", "object" => %{"content" => _content}} = message) do
with {:ok, message} <- check_reject(message),
{:ok, message} <- check_ftl_removal(message),
diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex
index c496063ea..a7a20ca37 100644
--- a/lib/pleroma/web/activity_pub/relay.ex
+++ b/lib/pleroma/web/activity_pub/relay.ex
@@ -3,9 +3,9 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Relay do
- alias Pleroma.User
- alias Pleroma.Object
alias Pleroma.Activity
+ alias Pleroma.Object
+ alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
require Logger
@@ -41,7 +41,7 @@ defmodule Pleroma.Web.ActivityPub.Relay do
def publish(%Activity{data: %{"type" => "Create"}} = activity) do
with %User{} = user <- get_actor(),
- %Object{} = object <- Object.normalize(activity.data["object"]["id"]) do
+ %Object{} = object <- Object.normalize(activity) do
ActivityPub.announce(user, object, nil, true, false)
else
e -> Logger.error("error: #{inspect(e)}")
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 88007aa16..f733ae7e1 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -7,9 +7,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
A module to handle coding from internal to wire ActivityPub and back.
"""
alias Pleroma.Activity
- alias Pleroma.User
alias Pleroma.Object
alias Pleroma.Repo
+ alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
@@ -86,11 +86,15 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
def fix_addressing_list(map, field) do
- if is_binary(map[field]) do
- map
- |> Map.put(field, [map[field]])
- else
- map
+ cond do
+ is_binary(map[field]) ->
+ Map.put(map, field, [map[field]])
+
+ is_nil(map[field]) ->
+ Map.put(map, field, [])
+
+ true ->
+ map
end
end
@@ -128,13 +132,42 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> fix_explicit_addressing(explicit_mentions)
end
+ # if as:Public is addressed, then make sure the followers collection is also addressed
+ # so that the activities will be delivered to local users.
+ def fix_implicit_addressing(%{"to" => to, "cc" => cc} = object, followers_collection) do
+ recipients = to ++ cc
+
+ if followers_collection not in recipients do
+ cond do
+ "https://www.w3.org/ns/activitystreams#Public" in cc ->
+ to = to ++ [followers_collection]
+ Map.put(object, "to", to)
+
+ "https://www.w3.org/ns/activitystreams#Public" in to ->
+ cc = cc ++ [followers_collection]
+ Map.put(object, "cc", cc)
+
+ true ->
+ object
+ end
+ else
+ object
+ end
+ end
+
+ def fix_implicit_addressing(object, _), do: object
+
def fix_addressing(object) do
+ %User{} = user = User.get_or_fetch_by_ap_id(object["actor"])
+ followers_collection = User.ap_followers(user)
+
object
|> fix_addressing_list("to")
|> fix_addressing_list("cc")
|> fix_addressing_list("bto")
|> fix_addressing_list("bcc")
|> fix_explicit_addressing
+ |> fix_implicit_addressing(followers_collection)
end
def fix_actor(%{"attributedTo" => actor} = object) do
@@ -355,6 +388,40 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
+ # Flag objects are placed ahead of the ID check because Mastodon 2.8 and earlier send them
+ # with nil ID.
+ def handle_incoming(%{"type" => "Flag", "object" => objects, "actor" => actor} = data) do
+ with context <- data["context"] || Utils.generate_context_id(),
+ content <- data["content"] || "",
+ %User{} = actor <- User.get_cached_by_ap_id(actor),
+
+ # Reduce the object list to find the reported user.
+ %User{} = account <-
+ Enum.reduce_while(objects, nil, fn ap_id, _ ->
+ with %User{} = user <- User.get_cached_by_ap_id(ap_id) do
+ {:halt, user}
+ else
+ _ -> {:cont, nil}
+ end
+ end),
+
+ # Remove the reported user from the object list.
+ statuses <- Enum.filter(objects, fn ap_id -> ap_id != account.ap_id end) do
+ params = %{
+ actor: actor,
+ context: context,
+ account: account,
+ statuses: statuses,
+ content: content,
+ additional: %{
+ "cc" => [account.ap_id]
+ }
+ }
+
+ ActivityPub.flag(params)
+ end
+ end
+
# disallow objects with bogus IDs
def handle_incoming(%{"id" => nil}), do: :error
def handle_incoming(%{"id" => ""}), do: :error
@@ -650,10 +717,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
if object = Object.normalize(id), do: {:ok, object}, else: nil
end
- def set_reply_to_uri(%{"inReplyTo" => inReplyTo} = object) when is_binary(inReplyTo) do
- with false <- String.starts_with?(inReplyTo, "http"),
- {:ok, %{data: replied_to_object}} <- get_obj_helper(inReplyTo) do
- Map.put(object, "inReplyTo", replied_to_object["external_url"] || inReplyTo)
+ def set_reply_to_uri(%{"inReplyTo" => in_reply_to} = object) when is_binary(in_reply_to) do
+ with false <- String.starts_with?(in_reply_to, "http"),
+ {:ok, %{data: replied_to_object}} <- get_obj_helper(in_reply_to) do
+ Map.put(object, "inReplyTo", replied_to_object["external_url"] || in_reply_to)
else
_e -> object
end
@@ -736,6 +803,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def prepare_outgoing(%{"type" => _type} = data) do
data =
data
+ |> strip_internal_fields
|> maybe_fix_object_url
|> Map.merge(Utils.make_json_ld_header())
@@ -829,10 +897,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
def add_attributed_to(object) do
- attributedTo = object["attributedTo"] || object["actor"]
+ attributed_to = object["attributedTo"] || object["actor"]
object
- |> Map.put("attributedTo", attributedTo)
+ |> Map.put("attributedTo", attributed_to)
end
def add_likes(%{"id" => id, "like_count" => likes} = object) do
@@ -870,7 +938,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
"announcements",
"announcement_count",
"emoji",
- "context_id"
+ "context_id",
+ "deleted_activity_id"
])
end
@@ -886,7 +955,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
defp strip_internal_tags(object), do: object
defp user_upgrade_task(user) do
- old_follower_address = User.ap_followers(user)
+ # we pass a fake user so that the followers collection is stripped away
+ old_follower_address = User.ap_followers(%User{nickname: user.nickname})
q =
from(
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 9e50789db..77841278a 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -3,17 +3,17 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Utils do
+ alias Ecto.Changeset
+ alias Ecto.UUID
+ alias Pleroma.Activity
+ alias Pleroma.Notification
+ alias Pleroma.Object
alias Pleroma.Repo
+ alias Pleroma.User
alias Pleroma.Web
- alias Pleroma.Object
- alias Pleroma.Activity
alias Pleroma.Web.ActivityPub.Visibility
- alias Pleroma.User
- alias Pleroma.Notification
- alias Pleroma.Web.Router.Helpers
alias Pleroma.Web.Endpoint
- alias Ecto.Changeset
- alias Ecto.UUID
+ alias Pleroma.Web.Router.Helpers
import Ecto.Query
@@ -209,12 +209,12 @@ defmodule Pleroma.Web.ActivityPub.Utils do
"""
def insert_full_object(%{"object" => %{"type" => type} = object_data})
when is_map(object_data) and type in @supported_object_types do
- with {:ok, _} <- Object.create(object_data) do
- :ok
+ with {:ok, object} <- Object.create(object_data) do
+ {:ok, object}
end
end
- def insert_full_object(_), do: :ok
+ def insert_full_object(_), do: {:ok, nil}
def update_object_in_activities(%{data: %{"id" => id}} = object) do
# TODO
@@ -354,7 +354,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
[state, actor, object]
)
- activity = Repo.get(Activity, activity.id)
+ activity = Activity.get_by_id(activity.id)
{:ok, activity}
rescue
e ->
@@ -621,7 +621,13 @@ defmodule Pleroma.Web.ActivityPub.Utils do
#### Flag-related helpers
def make_flag_data(params, additional) do
- status_ap_ids = Enum.map(params.statuses || [], & &1.data["id"])
+ status_ap_ids =
+ Enum.map(params.statuses || [], fn
+ %Activity{} = act -> act.data["id"]
+ act when is_map(act) -> act["id"]
+ act when is_binary(act) -> act
+ end)
+
object = [params.account.ap_id] ++ status_ap_ids
%{
@@ -633,4 +639,43 @@ defmodule Pleroma.Web.ActivityPub.Utils do
}
|> Map.merge(additional)
end
+
+ @doc """
+ Fetches the OrderedCollection/OrderedCollectionPage from `from`, limiting the amount of pages fetched after
+ the first one to `pages_left` pages.
+ If the amount of pages is higher than the collection has, it returns whatever was there.
+ """
+ def fetch_ordered_collection(from, pages_left, acc \\ []) do
+ with {:ok, response} <- Tesla.get(from),
+ {:ok, collection} <- Poison.decode(response.body) do
+ case collection["type"] do
+ "OrderedCollection" ->
+ # If we've encountered the OrderedCollection and not the page,
+ # just call the same function on the page address
+ fetch_ordered_collection(collection["first"], pages_left)
+
+ "OrderedCollectionPage" ->
+ if pages_left > 0 do
+ # There are still more pages
+ if Map.has_key?(collection, "next") do
+ # There are still more pages, go deeper saving what we have into the accumulator
+ fetch_ordered_collection(
+ collection["next"],
+ pages_left - 1,
+ acc ++ collection["orderedItems"]
+ )
+ else
+ # No more pages left, just return whatever we already have
+ acc ++ collection["orderedItems"]
+ end
+ else
+ # Got the amount of pages needed, add them all to the accumulator
+ acc ++ collection["orderedItems"]
+ end
+
+ _ ->
+ {:error, "Not an OrderedCollection or OrderedCollectionPage"}
+ end
+ end
+ end
end
diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex
index 84fa94e32..6028b773c 100644
--- a/lib/pleroma/web/activity_pub/views/object_view.ex
+++ b/lib/pleroma/web/activity_pub/views/object_view.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do
def render("object.json", %{object: %Activity{data: %{"type" => "Create"}} = activity}) do
base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
additional =
Transmogrifier.prepare_object(activity.data)
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do
def render("object.json", %{object: %Activity{} = activity}) do
base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
additional =
Transmogrifier.prepare_object(activity.data)
diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
index 415cbd47a..5926a3294 100644
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -5,15 +5,15 @@
defmodule Pleroma.Web.ActivityPub.UserView do
use Pleroma.Web, :view
- alias Pleroma.Web.WebFinger
- alias Pleroma.Web.Salmon
- alias Pleroma.User
alias Pleroma.Repo
+ alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
- alias Pleroma.Web.Router.Helpers
alias Pleroma.Web.Endpoint
+ alias Pleroma.Web.Router.Helpers
+ alias Pleroma.Web.Salmon
+ alias Pleroma.Web.WebFinger
import Ecto.Query
@@ -87,16 +87,10 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"publicKeyPem" => public_key
},
"endpoints" => endpoints,
- "icon" => %{
- "type" => "Image",
- "url" => User.avatar_url(user)
- },
- "image" => %{
- "type" => "Image",
- "url" => User.banner_url(user)
- },
"tag" => user.info.source_data["tag"] || []
}
+ |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))
+ |> Map.merge(maybe_make_image(&User.banner_url/2, "image", user))
|> Map.merge(Utils.make_json_ld_header())
end
@@ -294,4 +288,17 @@ defmodule Pleroma.Web.ActivityPub.UserView do
map
end
end
+
+ defp maybe_make_image(func, key, user) do
+ if image = func.(user, no_default: true) do
+ %{
+ key => %{
+ "type" => "Image",
+ "url" => image
+ }
+ }
+ else
+ %{}
+ end
+ end
end
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 75c2c6061..b3a09e49e 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -3,17 +3,18 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.AdminAPIController do
- @users_page_size 50
-
use Pleroma.Web, :controller
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Relay
- alias Pleroma.Web.MastodonAPI.Admin.AccountView
+ alias Pleroma.Web.AdminAPI.AccountView
+ alias Pleroma.Web.AdminAPI.Search
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
require Logger
+ @users_page_size 50
+
action_fallback(:errors)
def user_delete(conn, %{"nickname" => nickname}) do
@@ -44,6 +45,15 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|> json(user.nickname)
end
+ def user_show(conn, %{"nickname" => nickname}) do
+ with %User{} = user <- User.get_by_nickname(nickname) do
+ conn
+ |> json(AccountView.render("show.json", %{user: user}))
+ else
+ _ -> {:error, :not_found}
+ end
+ end
+
def user_toggle_activation(conn, %{"nickname" => nickname}) do
user = User.get_by_nickname(nickname)
@@ -63,17 +73,17 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
do: json_response(conn, :no_content, "")
end
- def list_users(%{assigns: %{user: admin}} = conn, params) do
+ def list_users(conn, params) do
{page, page_size} = page_params(params)
+ filters = maybe_parse_filters(params["filters"])
- with {:ok, users, count} <-
- User.search_for_admin(%{
- query: params["query"],
- admin: admin,
- local: params["local_only"] == "true",
- page: page,
- page_size: page_size
- }),
+ search_params = %{
+ query: params["query"],
+ page: page,
+ page_size: page_size
+ }
+
+ with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)),
do:
conn
|> json(
@@ -85,6 +95,19 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
)
end
+ @filters ~w(local external active deactivated)
+
+ defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
+
+ @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
+ defp maybe_parse_filters(filters) do
+ filters
+ |> String.split(",")
+ |> Enum.filter(&Enum.member?(@filters, &1))
+ |> Enum.map(&String.to_atom(&1))
+ |> Enum.into(%{}, &{&1, true})
+ end
+
def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
when permission_group in ["moderator", "admin"] do
user = User.get_by_nickname(nickname)
@@ -217,6 +240,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|> json(token.token)
end
+ def errors(conn, {:error, :not_found}) do
+ conn
+ |> put_status(404)
+ |> json("Not found")
+ end
+
def errors(conn, {:param_cast, _}) do
conn
|> put_status(400)
diff --git a/lib/pleroma/web/admin_api/search.ex b/lib/pleroma/web/admin_api/search.ex
new file mode 100644
index 000000000..9a8e41c2a
--- /dev/null
+++ b/lib/pleroma/web/admin_api/search.ex
@@ -0,0 +1,54 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.Search do
+ import Ecto.Query
+
+ alias Pleroma.Repo
+ alias Pleroma.User
+
+ @page_size 50
+
+ def user(%{query: term} = params) when is_nil(term) or term == "" do
+ query = maybe_filtered_query(params)
+
+ paginated_query =
+ maybe_filtered_query(params)
+ |> paginate(params[:page] || 1, params[:page_size] || @page_size)
+
+ count = query |> Repo.aggregate(:count, :id)
+
+ results = Repo.all(paginated_query)
+
+ {:ok, results, count}
+ end
+
+ def user(%{query: term} = params) when is_binary(term) do
+ search_query = from(u in maybe_filtered_query(params), where: ilike(u.nickname, ^"%#{term}%"))
+
+ count = search_query |> Repo.aggregate(:count, :id)
+
+ results =
+ search_query
+ |> paginate(params[:page] || 1, params[:page_size] || @page_size)
+ |> Repo.all()
+
+ {:ok, results, count}
+ end
+
+ defp maybe_filtered_query(params) do
+ from(u in User, order_by: u.nickname)
+ |> User.maybe_local_user_query(params[:local])
+ |> User.maybe_external_user_query(params[:external])
+ |> User.maybe_active_user_query(params[:active])
+ |> User.maybe_deactivated_user_query(params[:deactivated])
+ end
+
+ defp paginate(query, page, page_size) do
+ from(u in query,
+ limit: ^page_size,
+ offset: ^((page - 1) * page_size)
+ )
+ end
+end
diff --git a/lib/pleroma/web/mastodon_api/views/admin/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex
index 74ca13564..4d6f921ef 100644
--- a/lib/pleroma/web/mastodon_api/views/admin/account_view.ex
+++ b/lib/pleroma/web/admin_api/views/account_view.ex
@@ -2,10 +2,11 @@
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.MastodonAPI.Admin.AccountView do
+defmodule Pleroma.Web.AdminAPI.AccountView do
use Pleroma.Web, :view
- alias Pleroma.Web.MastodonAPI.Admin.AccountView
+ alias Pleroma.User.Info
+ alias Pleroma.Web.AdminAPI.AccountView
def render("index.json", %{users: users, count: count, page_size: page_size}) do
%{
@@ -19,7 +20,10 @@ defmodule Pleroma.Web.MastodonAPI.Admin.AccountView do
%{
"id" => user.id,
"nickname" => user.nickname,
- "deactivated" => user.info.deactivated
+ "deactivated" => user.info.deactivated,
+ "local" => user.local,
+ "roles" => Info.roles(user.info),
+ "tags" => user.tags || []
}
end
end
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
new file mode 100644
index 000000000..88217aab8
--- /dev/null
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -0,0 +1,143 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Auth.LDAPAuthenticator do
+ alias Pleroma.User
+
+ require Logger
+
+ @behaviour Pleroma.Web.Auth.Authenticator
+
+ @connection_timeout 10_000
+ @search_timeout 10_000
+
+ def get_user(%Plug.Conn{} = conn) do
+ if Pleroma.Config.get([:ldap, :enabled]) do
+ {name, password} =
+ case conn.params do
+ %{"authorization" => %{"name" => name, "password" => password}} ->
+ {name, password}
+
+ %{"grant_type" => "password", "username" => name, "password" => password} ->
+ {name, password}
+ end
+
+ case ldap_user(name, password) do
+ %User{} = user ->
+ {:ok, user}
+
+ {:error, {:ldap_connection_error, _}} ->
+ # When LDAP is unavailable, try default authenticator
+ Pleroma.Web.Auth.PleromaAuthenticator.get_user(conn)
+
+ error ->
+ error
+ end
+ else
+ # Fall back to default authenticator
+ Pleroma.Web.Auth.PleromaAuthenticator.get_user(conn)
+ end
+ end
+
+ def handle_error(%Plug.Conn{} = _conn, error) do
+ error
+ end
+
+ def auth_template, do: nil
+
+ defp ldap_user(name, password) do
+ ldap = Pleroma.Config.get(:ldap, [])
+ host = Keyword.get(ldap, :host, "localhost")
+ port = Keyword.get(ldap, :port, 389)
+ ssl = Keyword.get(ldap, :ssl, false)
+ sslopts = Keyword.get(ldap, :sslopts, [])
+
+ options =
+ [{:port, port}, {:ssl, ssl}, {:timeout, @connection_timeout}] ++
+ if sslopts != [], do: [{:sslopts, sslopts}], else: []
+
+ case :eldap.open([to_charlist(host)], options) do
+ {:ok, connection} ->
+ try do
+ if Keyword.get(ldap, :tls, false) do
+ :application.ensure_all_started(:ssl)
+
+ case :eldap.start_tls(
+ connection,
+ Keyword.get(ldap, :tlsopts, []),
+ @connection_timeout
+ ) do
+ :ok ->
+ :ok
+
+ error ->
+ Logger.error("Could not start TLS: #{inspect(error)}")
+ end
+ end
+
+ bind_user(connection, ldap, name, password)
+ after
+ :eldap.close(connection)
+ end
+
+ {:error, error} ->
+ Logger.error("Could not open LDAP connection: #{inspect(error)}")
+ {:error, {:ldap_connection_error, error}}
+ end
+ end
+
+ defp bind_user(connection, ldap, name, password) do
+ uid = Keyword.get(ldap, :uid, "cn")
+ base = Keyword.get(ldap, :base)
+
+ case :eldap.simple_bind(connection, "#{uid}=#{name},#{base}", password) do
+ :ok ->
+ case User.get_by_nickname_or_email(name) do
+ %User{} = user ->
+ user
+
+ _ ->
+ register_user(connection, base, uid, name, password)
+ end
+
+ error ->
+ error
+ end
+ end
+
+ defp register_user(connection, base, uid, name, password) do
+ case :eldap.search(connection, [
+ {:base, to_charlist(base)},
+ {:filter, :eldap.equalityMatch(to_charlist(uid), to_charlist(name))},
+ {:scope, :eldap.wholeSubtree()},
+ {:attributes, ['mail', 'email']},
+ {:timeout, @search_timeout}
+ ]) do
+ {:ok, {:eldap_search_result, [{:eldap_entry, _, attributes}], _}} ->
+ with {_, [mail]} <- List.keyfind(attributes, 'mail', 0) do
+ params = %{
+ email: :erlang.list_to_binary(mail),
+ name: name,
+ nickname: name,
+ password: password,
+ password_confirmation: password
+ }
+
+ changeset = User.register_changeset(%User{}, params)
+
+ case User.register(changeset) do
+ {:ok, user} -> user
+ error -> error
+ end
+ else
+ _ ->
+ Logger.error("Could not find LDAP attribute mail: #{inspect(attributes)}")
+ {:error, :ldap_registration_missing_attributes}
+ end
+
+ error ->
+ error
+ end
+ end
+end
diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
index 3cc19af01..94a19ad49 100644
--- a/lib/pleroma/web/auth/pleroma_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_authenticator.ex
@@ -3,13 +3,20 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Auth.PleromaAuthenticator do
- alias Pleroma.User
alias Comeonin.Pbkdf2
+ alias Pleroma.User
@behaviour Pleroma.Web.Auth.Authenticator
def get_user(%Plug.Conn{} = conn) do
- %{"authorization" => %{"name" => name, "password" => password}} = conn.params
+ {name, password} =
+ case conn.params do
+ %{"authorization" => %{"name" => name, "password" => password}} ->
+ {name, password}
+
+ %{"grant_type" => "password", "username" => name, "password" => password} ->
+ {name, password}
+ end
with {_, %User{} = user} <- {:user, User.get_by_nickname_or_email(name)},
{_, true} <- {:checkpw, Pbkdf2.checkpw(password, user.password_hash)} do
diff --git a/lib/pleroma/web/channels/user_socket.ex b/lib/pleroma/web/channels/user_socket.ex
index aed8475fd..6503979a1 100644
--- a/lib/pleroma/web/channels/user_socket.ex
+++ b/lib/pleroma/web/channels/user_socket.ex
@@ -23,8 +23,8 @@ defmodule Pleroma.Web.UserSocket do
# performing token verification on connect.
def connect(%{"token" => token}, socket) do
with true <- Pleroma.Config.get([:chat, :enabled]),
- {:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84600),
- %User{} = user <- Pleroma.Repo.get(User, user_id) do
+ {:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84_600),
+ %User{} = user <- Pleroma.User.get_by_id(user_id) do
{:ok, assign(socket, :user_name, user.nickname)}
else
_e -> :error
diff --git a/lib/pleroma/web/chat_channel.ex b/lib/pleroma/web/chat_channel.ex
index fe63ede66..f63f4bda1 100644
--- a/lib/pleroma/web/chat_channel.ex
+++ b/lib/pleroma/web/chat_channel.ex
@@ -4,8 +4,8 @@
defmodule Pleroma.Web.ChatChannel do
use Phoenix.Channel
- alias Pleroma.Web.ChatChannel.ChatChannelState
alias Pleroma.User
+ alias Pleroma.Web.ChatChannel.ChatChannelState
def join("chat:public", _message, socket) do
send(self(), :after_join)
@@ -48,7 +48,7 @@ defmodule Pleroma.Web.ChatChannel.ChatChannelState do
end)
end
- def messages() do
+ def messages do
Agent.get(__MODULE__, fn state -> state[:messages] |> Enum.reverse() end)
end
end
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 55a9c2572..25b990677 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -3,14 +3,13 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.CommonAPI do
- alias Pleroma.User
- alias Pleroma.Repo
alias Pleroma.Activity
+ alias Pleroma.Formatter
alias Pleroma.Object
alias Pleroma.ThreadMute
+ alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils
- alias Pleroma.Formatter
import Pleroma.Web.CommonAPI.Utils
@@ -27,10 +26,47 @@ defmodule Pleroma.Web.CommonAPI do
end
end
+ def unfollow(follower, unfollowed) do
+ with {:ok, follower, _follow_activity} <- User.unfollow(follower, unfollowed),
+ {:ok, _activity} <- ActivityPub.unfollow(follower, unfollowed) do
+ {:ok, follower}
+ end
+ end
+
+ def accept_follow_request(follower, followed) do
+ with {:ok, follower} <- User.maybe_follow(follower, followed),
+ %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
+ {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "accept"),
+ {:ok, _activity} <-
+ ActivityPub.accept(%{
+ to: [follower.ap_id],
+ actor: followed,
+ object: follow_activity.data["id"],
+ type: "Accept"
+ }) do
+ {:ok, follower}
+ end
+ end
+
+ def reject_follow_request(follower, followed) do
+ with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
+ {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "reject"),
+ {:ok, _activity} <-
+ ActivityPub.reject(%{
+ to: [follower.ap_id],
+ actor: followed,
+ object: follow_activity.data["id"],
+ type: "Reject"
+ }) do
+ {:ok, follower}
+ end
+ end
+
def delete(activity_id, user) do
- with %Activity{data: %{"object" => %{"id" => object_id}}} <- Repo.get(Activity, activity_id),
- %Object{} = object <- Object.normalize(object_id),
- true <- user.info.is_moderator || user.ap_id == object.data["actor"],
+ with %Activity{data: %{"object" => _}} = activity <-
+ Activity.get_by_id_with_object(activity_id),
+ %Object{} = object <- Object.normalize(activity),
+ true <- User.superuser?(user) || user.ap_id == object.data["actor"],
{:ok, _} <- unpin(activity_id, user),
{:ok, delete} <- ActivityPub.delete(object) do
{:ok, delete}
@@ -39,7 +75,7 @@ defmodule Pleroma.Web.CommonAPI do
def repeat(id_or_ap_id, user) do
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
- object <- Object.normalize(activity.data["object"]["id"]),
+ object <- Object.normalize(activity),
nil <- Utils.get_existing_announce(user.ap_id, object) do
ActivityPub.announce(user, object)
else
@@ -50,7 +86,7 @@ defmodule Pleroma.Web.CommonAPI do
def unrepeat(id_or_ap_id, user) do
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
- object <- Object.normalize(activity.data["object"]["id"]) do
+ object <- Object.normalize(activity) do
ActivityPub.unannounce(user, object)
else
_ ->
@@ -60,7 +96,7 @@ defmodule Pleroma.Web.CommonAPI do
def favorite(id_or_ap_id, user) do
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
- object <- Object.normalize(activity.data["object"]["id"]),
+ object <- Object.normalize(activity),
nil <- Utils.get_existing_like(user.ap_id, object) do
ActivityPub.like(user, object)
else
@@ -71,7 +107,7 @@ defmodule Pleroma.Web.CommonAPI do
def unfavorite(id_or_ap_id, user) do
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
- object <- Object.normalize(activity.data["object"]["id"]) do
+ object <- Object.normalize(activity) do
ActivityPub.unlike(user, object)
else
_ ->
@@ -88,8 +124,8 @@ defmodule Pleroma.Web.CommonAPI do
nil ->
"public"
- inReplyTo ->
- Pleroma.Web.MastodonAPI.StatusView.get_visibility(inReplyTo.data["object"])
+ in_reply_to ->
+ Pleroma.Web.MastodonAPI.StatusView.get_visibility(in_reply_to.data["object"])
end
end
@@ -101,15 +137,16 @@ defmodule Pleroma.Web.CommonAPI do
with status <- String.trim(status),
attachments <- attachments_from_ids(data),
- inReplyTo <- get_replied_to_activity(data["in_reply_to_status_id"]),
+ in_reply_to <- get_replied_to_activity(data["in_reply_to_status_id"]),
{content_html, mentions, tags} <-
make_content_html(
status,
attachments,
- data
+ data,
+ visibility
),
- {to, cc} <- to_for_user_and_mentions(user, mentions, inReplyTo, visibility),
- context <- make_context(inReplyTo),
+ {to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility),
+ context <- make_context(in_reply_to),
cw <- data["spoiler_text"],
full_payload <- String.trim(status <> (data["spoiler_text"] || "")),
length when length in 1..limit <- String.length(full_payload),
@@ -120,7 +157,7 @@ defmodule Pleroma.Web.CommonAPI do
context,
content_html,
attachments,
- inReplyTo,
+ in_reply_to,
tags,
cw,
cc
@@ -248,14 +285,9 @@ defmodule Pleroma.Web.CommonAPI do
actor: user,
account: account,
statuses: statuses,
- content: content_html
+ content: content_html,
+ forward: data["forward"] || false
}) do
- Enum.each(User.all_superusers(), fn superuser ->
- superuser
- |> Pleroma.AdminEmail.report(user, account, statuses, content_html)
- |> Pleroma.Mailer.deliver_async()
- end)
-
{:ok, activity}
else
{:error, err} -> {:error, err}
@@ -263,4 +295,24 @@ defmodule Pleroma.Web.CommonAPI do
{:account, nil} -> {:error, "Account not found"}
end
end
+
+ def hide_reblogs(user, muted) do
+ ap_id = muted.ap_id
+
+ if ap_id not in user.info.muted_reblogs do
+ info_changeset = User.Info.add_reblog_mute(user.info, ap_id)
+ changeset = Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset)
+ User.update_and_set_cache(changeset)
+ end
+ end
+
+ def show_reblogs(user, muted) do
+ ap_id = muted.ap_id
+
+ if ap_id in user.info.muted_reblogs do
+ info_changeset = User.Info.remove_reblog_mute(user.info, ap_id)
+ changeset = Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset)
+ User.update_and_set_cache(changeset)
+ end
+ end
end
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index e4b9102c5..40cea3090 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -6,31 +6,32 @@ defmodule Pleroma.Web.CommonAPI.Utils do
alias Calendar.Strftime
alias Comeonin.Pbkdf2
alias Pleroma.Activity
+ alias Pleroma.Config
alias Pleroma.Formatter
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
- alias Pleroma.Config
+ alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.Endpoint
alias Pleroma.Web.MediaProxy
- alias Pleroma.Web.ActivityPub.Utils
# This is a hack for twidere.
def get_by_id_or_ap_id(id) do
- activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id)
+ activity =
+ Activity.get_by_id_with_object(id) || Activity.get_create_by_object_ap_id_with_object(id)
activity &&
if activity.data["type"] == "Create" do
activity
else
- Activity.get_create_by_object_ap_id(activity.data["object"])
+ Activity.get_create_by_object_ap_id_with_object(activity.data["object"])
end
end
def get_replied_to_activity(""), do: nil
def get_replied_to_activity(id) when not is_nil(id) do
- Repo.get(Activity, id)
+ Activity.get_by_id(id)
end
def get_replied_to_activity(_), do: nil
@@ -101,7 +102,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def make_content_html(
status,
attachments,
- data
+ data,
+ visibility
) do
no_attachment_links =
data
@@ -110,8 +112,15 @@ defmodule Pleroma.Web.CommonAPI.Utils do
content_type = get_content_type(data["content_type"])
+ options =
+ if visibility == "direct" && Config.get([:instance, :safe_dm_mentions]) do
+ [safe_mention: true]
+ else
+ []
+ end
+
status
- |> format_input(content_type)
+ |> format_input(content_type, options)
|> maybe_add_attachments(attachments, no_attachment_links)
|> maybe_add_nsfw_tag(data)
end
@@ -266,7 +275,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end
def confirm_current_password(user, password) do
- with %User{local: true} = db_user <- Repo.get(User, user.id),
+ with %User{local: true} = db_user <- User.get_by_id(user.id),
true <- Pbkdf2.checkpw(password, db_user.password_hash) do
{:ok, db_user}
else
@@ -294,10 +303,10 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def maybe_notify_mentioned_recipients(
recipients,
- %Activity{data: %{"to" => _to, "type" => type} = data} = _activity
+ %Activity{data: %{"to" => _to, "type" => type} = data} = activity
)
when type == "Create" do
- object = Object.normalize(data["object"])
+ object = Object.normalize(activity)
object_data =
cond do
@@ -344,4 +353,33 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end
def get_report_statuses(_, _), do: {:ok, nil}
+
+ # DEPRECATED mostly, context objects are now created at insertion time.
+ def context_to_conversation_id(context) do
+ with %Object{id: id} <- Object.get_cached_by_ap_id(context) do
+ id
+ else
+ _e ->
+ changeset = Object.context_mapping(context)
+
+ case Repo.insert(changeset) do
+ {:ok, %{id: id}} ->
+ id
+
+ # This should be solved by an upsert, but it seems ecto
+ # has problems accessing the constraint inside the jsonb.
+ {:error, _} ->
+ Object.get_cached_by_ap_id(context).id
+ end
+ end
+ end
+
+ def conversation_id_to_context(id) do
+ with %Object{data: %{"id" => context}} <- Repo.get(Object, id) do
+ context
+ else
+ _e ->
+ {:error, "No such conversation"}
+ end
+ end
end
diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex
index 5915ea40e..181483664 100644
--- a/lib/pleroma/web/controller_helper.ex
+++ b/lib/pleroma/web/controller_helper.ex
@@ -5,8 +5,14 @@
defmodule Pleroma.Web.ControllerHelper do
use Pleroma.Web, :controller
+ # As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
+ @falsy_param_values [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"]
+ def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil
+ def truthy_param?(value), do: value not in @falsy_param_values
+
def oauth_scopes(params, default) do
- # Note: `scopes` is used by Mastodon — supporting it but sticking to OAuth's standard `scope` wherever we control it
+ # Note: `scopes` is used by Mastodon — supporting it but sticking to
+ # OAuth's standard `scope` wherever we control it
Pleroma.Web.OAuth.parse_scopes(params["scope"] || params["scopes"], default)
end
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index 3eed047ca..fa2d1cbe7 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -25,7 +25,8 @@ defmodule Pleroma.Web.Endpoint do
at: "/",
from: :pleroma,
only:
- ~w(index.html static finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc)
+ ~w(index.html robots.txt static finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc)
+ # credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength
)
# Code reloading can be explicitly enabled under the
diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex
index fbfe97dbc..c47328e13 100644
--- a/lib/pleroma/web/federator/federator.ex
+++ b/lib/pleroma/web/federator/federator.ex
@@ -5,65 +5,64 @@
defmodule Pleroma.Web.Federator do
alias Pleroma.Activity
alias Pleroma.User
- alias Pleroma.Web.WebFinger
- alias Pleroma.Web.Websub
- alias Pleroma.Web.Salmon
alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator.RetryQueue
alias Pleroma.Web.OStatus
- alias Pleroma.Jobs
+ alias Pleroma.Web.Salmon
+ alias Pleroma.Web.WebFinger
+ alias Pleroma.Web.Websub
require Logger
@websub Application.get_env(:pleroma, :websub)
@ostatus Application.get_env(:pleroma, :ostatus)
- def init() do
+ def init do
# 1 minute
- Process.sleep(1000 * 60 * 1)
+ Process.sleep(1000 * 60)
refresh_subscriptions()
end
# Client API
def incoming_doc(doc) do
- Jobs.enqueue(:federator_incoming, __MODULE__, [:incoming_doc, doc])
+ PleromaJobQueue.enqueue(:federator_incoming, __MODULE__, [:incoming_doc, doc])
end
def incoming_ap_doc(params) do
- Jobs.enqueue(:federator_incoming, __MODULE__, [:incoming_ap_doc, params])
+ PleromaJobQueue.enqueue(:federator_incoming, __MODULE__, [:incoming_ap_doc, params])
end
def publish(activity, priority \\ 1) do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish, activity], priority)
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish, activity], priority)
end
def publish_single_ap(params) do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish_single_ap, params])
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_ap, params])
end
def publish_single_websub(websub) do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish_single_websub, websub])
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_websub, websub])
end
def verify_websub(websub) do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:verify_websub, websub])
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:verify_websub, websub])
end
def request_subscription(sub) do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:request_subscription, sub])
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:request_subscription, sub])
end
- def refresh_subscriptions() do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:refresh_subscriptions])
+ def refresh_subscriptions do
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:refresh_subscriptions])
end
def publish_single_salmon(params) do
- Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish_single_salmon, params])
+ PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_salmon, params])
end
# Job Worker Callbacks
diff --git a/lib/pleroma/web/federator/retry_queue.ex b/lib/pleroma/web/federator/retry_queue.ex
index e0ce251d2..71e49494f 100644
--- a/lib/pleroma/web/federator/retry_queue.ex
+++ b/lib/pleroma/web/federator/retry_queue.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.Federator.RetryQueue do
{:ok, %{args | queue_table: queue_table, running_jobs: :sets.new()}}
end
- def start_link() do
+ def start_link do
enabled =
if Mix.env() == :test, do: true, else: Pleroma.Config.get([__MODULE__, :enabled], false)
@@ -39,11 +39,11 @@ defmodule Pleroma.Web.Federator.RetryQueue do
GenServer.cast(__MODULE__, {:maybe_enqueue, data, transport, retries + 1})
end
- def get_stats() do
+ def get_stats do
GenServer.call(__MODULE__, :get_stats)
end
- def reset_stats() do
+ def reset_stats do
GenServer.call(__MODULE__, :reset_stats)
end
@@ -55,7 +55,7 @@ defmodule Pleroma.Web.Federator.RetryQueue do
end
end
- def get_retry_timer_interval() do
+ def get_retry_timer_interval do
Pleroma.Config.get([:retry_queue, :interval], 1000)
end
@@ -231,7 +231,7 @@ defmodule Pleroma.Web.Federator.RetryQueue do
end
end
- defp maybe_kickoff_timer() do
+ defp maybe_kickoff_timer do
GenServer.cast(__MODULE__, :kickoff_timer)
end
end
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex
index 8b1378917..08ea5f967 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex
@@ -1 +1,51 @@
+defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
+ import Ecto.Query
+ import Ecto.Changeset
+ alias Pleroma.Activity
+ alias Pleroma.Notification
+ alias Pleroma.Pagination
+ alias Pleroma.User
+
+ def get_followers(user, params \\ %{}) do
+ user
+ |> User.get_followers_query()
+ |> Pagination.fetch_paginated(params)
+ end
+
+ def get_friends(user, params \\ %{}) do
+ user
+ |> User.get_friends_query()
+ |> Pagination.fetch_paginated(params)
+ end
+
+ def get_notifications(user, params \\ %{}) do
+ options = cast_params(params)
+
+ user
+ |> Notification.for_user_query()
+ |> restrict(:exclude_types, options)
+ |> Pagination.fetch_paginated(params)
+ end
+
+ defp cast_params(params) do
+ param_types = %{
+ exclude_types: {:array, :string}
+ }
+
+ changeset = cast({%{}, param_types}, params, Map.keys(param_types))
+ changeset.changes
+ end
+
+ defp restrict(query, :exclude_types, %{exclude_types: mastodon_types = [_ | _]}) do
+ ap_types =
+ mastodon_types
+ |> Enum.map(&Activity.from_mastodon_notification_type/1)
+ |> Enum.filter(& &1)
+
+ query
+ |> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data))
+ end
+
+ defp restrict(query, _, _), do: query
+end
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 8c58f4545..0141186d8 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -4,6 +4,7 @@
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller
+
alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Filter
@@ -13,18 +14,19 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
alias Pleroma.Stats
alias Pleroma.User
alias Pleroma.Web
+ alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI
- alias Pleroma.Web.MediaProxy
-
alias Pleroma.Web.MastodonAPI.AccountView
+ alias Pleroma.Web.MastodonAPI.AppView
alias Pleroma.Web.MastodonAPI.FilterView
alias Pleroma.Web.MastodonAPI.ListView
+ alias Pleroma.Web.MastodonAPI.MastodonAPI
alias Pleroma.Web.MastodonAPI.MastodonView
- alias Pleroma.Web.MastodonAPI.StatusView
+ alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.MastodonAPI.ReportView
- alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.ActivityPub.Utils
- alias Pleroma.Web.ActivityPub.Visibility
+ alias Pleroma.Web.MastodonAPI.StatusView
+ alias Pleroma.Web.MediaProxy
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
@@ -50,16 +52,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
with cs <- App.register_changeset(%App{}, app_attrs),
false <- cs.changes[:client_name] == @local_mastodon_name,
{:ok, app} <- Repo.insert(cs) do
- res = %{
- id: app.id |> to_string,
- name: app.client_name,
- client_id: app.client_id,
- client_secret: app.client_secret,
- redirect_uri: app.redirect_uris,
- website: app.website
- }
-
- json(conn, res)
+ conn
+ |> put_view(AppView)
+ |> render("show.json", %{app: app})
end
end
@@ -131,8 +126,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
json(conn, account)
end
- def user(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do
- with %User{} = user <- Repo.get(User, id),
+ def verify_app_credentials(%{assigns: %{user: _user, token: token}} = conn, _) do
+ with %Token{app: %App{} = app} <- Repo.preload(token, :app) do
+ conn
+ |> put_view(AppView)
+ |> render("short.json", %{app: app})
+ end
+ end
+
+ def user(%{assigns: %{user: for_user}} = conn, %{"id" => nickname_or_id}) do
+ with %User{} = user <- User.get_cached_by_nickname_or_id(nickname_or_id),
true <- User.auth_active?(user) || user.id == for_user.id || User.superuser?(for_user) do
account = AccountView.render("account.json", %{user: user, for: for_user})
json(conn, account)
@@ -160,6 +163,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
},
stats: Stats.get_stats(),
thumbnail: Web.base_url() <> "/instance/thumbnail.jpeg",
+ languages: ["en"],
+ registrations: Pleroma.Config.get([:instance, :registrations_open]),
+ # Extra (not present in Mastodon):
max_toot_chars: Keyword.get(instance, :limit)
}
@@ -279,7 +285,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do
- with %User{} = user <- Repo.get(User, params["id"]) do
+ with %User{} = user <- User.get_by_id(params["id"]) do
activities = ActivityPub.fetch_user_activities(user, reading_user, params)
conn
@@ -313,7 +319,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
true <- Visibility.visible_for_user?(activity, user) do
conn
|> put_view(StatusView)
@@ -322,7 +328,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
activities <-
ActivityPub.fetch_activities_for_context(activity.data["context"], %{
"blocking_user" => user,
@@ -454,7 +460,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
%User{} = user <- User.get_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
{:ok, user} <- User.bookmark(user, activity.data["object"]["id"]) do
@@ -465,7 +471,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
%User{} = user <- User.get_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
{:ok, user} <- User.unbookmark(user, activity.data["object"]["id"]) do
@@ -501,21 +507,19 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def notifications(%{assigns: %{user: user}} = conn, params) do
- notifications = Notification.for_user(user, params)
-
- result =
- notifications
- |> Enum.map(fn x -> render_notification(user, x) end)
- |> Enum.filter(& &1)
+ notifications = MastodonAPI.get_notifications(user, params)
conn
|> add_link_headers(:notifications, notifications)
- |> json(result)
+ |> put_view(NotificationView)
+ |> render("index.json", %{notifications: notifications, for: user})
end
def get_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
with {:ok, notification} <- Notification.get(user, id) do
- json(conn, render_notification(user, notification))
+ conn
+ |> put_view(NotificationView)
+ |> render("show.json", %{notification: notification, for: user})
else
{:error, reason} ->
conn
@@ -589,7 +593,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def favourited_by(conn, %{"id" => id}) do
- with %Activity{data: %{"object" => %{"likes" => likes}}} <- Repo.get(Activity, id) do
+ with %Activity{data: %{"object" => %{"likes" => likes}}} <- Activity.get_by_id(id) do
q = from(u in User, where: u.ap_id in ^likes)
users = Repo.all(q)
@@ -602,7 +606,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def reblogged_by(conn, %{"id" => id}) do
- with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Repo.get(Activity, id) do
+ with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Activity.get_by_id(id) do
q = from(u in User, where: u.ap_id in ^announces)
users = Repo.all(q)
@@ -652,9 +656,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> render("index.json", %{activities: activities, for: user, as: :activity})
end
- def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do
- with %User{} = user <- Repo.get(User, id),
- {:ok, followers} <- User.get_followers(user) do
+ def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
+ with %User{} = user <- User.get_by_id(id),
+ followers <- MastodonAPI.get_followers(user, params) do
followers =
cond do
for_user && user.id == for_user.id -> followers
@@ -663,14 +667,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
conn
+ |> add_link_headers(:followers, followers, user)
|> put_view(AccountView)
|> render("accounts.json", %{users: followers, as: :user})
end
end
- def following(%{assigns: %{user: for_user}} = conn, %{"id" => id}) do
- with %User{} = user <- Repo.get(User, id),
- {:ok, followers} <- User.get_friends(user) do
+ def following(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
+ with %User{} = user <- User.get_by_id(id),
+ followers <- MastodonAPI.get_friends(user, params) do
followers =
cond do
for_user && user.id == for_user.id -> followers
@@ -679,6 +684,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
conn
+ |> add_link_headers(:following, followers, user)
|> put_view(AccountView)
|> render("accounts.json", %{users: followers, as: :user})
end
@@ -693,17 +699,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
- with %User{} = follower <- Repo.get(User, id),
- {:ok, follower} <- User.maybe_follow(follower, followed),
- %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
- {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "accept"),
- {:ok, _activity} <-
- ActivityPub.accept(%{
- to: [follower.ap_id],
- actor: followed,
- object: follow_activity.data["id"],
- type: "Accept"
- }) do
+ with %User{} = follower <- User.get_by_id(id),
+ {:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: followed, target: follower})
@@ -716,16 +713,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
- with %User{} = follower <- Repo.get(User, id),
- %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
- {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "reject"),
- {:ok, _activity} <-
- ActivityPub.reject(%{
- to: [follower.ap_id],
- actor: followed,
- object: follow_activity.data["id"],
- type: "Reject"
- }) do
+ with %User{} = follower <- User.get_by_id(id),
+ {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: followed, target: follower})
@@ -738,12 +727,26 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
- with %User{} = followed <- Repo.get(User, id),
+ with %User{} = followed <- User.get_by_id(id),
+ false <- User.following?(follower, followed),
{:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: follower, target: followed})
else
+ true ->
+ followed = User.get_cached_by_id(id)
+
+ {:ok, follower} =
+ case conn.params["reblogs"] do
+ true -> CommonAPI.show_reblogs(follower, followed)
+ false -> CommonAPI.hide_reblogs(follower, followed)
+ end
+
+ conn
+ |> put_view(AccountView)
+ |> render("relationship.json", %{user: follower, target: followed})
+
{:error, message} ->
conn
|> put_resp_content_type("application/json")
@@ -766,9 +769,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
- with %User{} = followed <- Repo.get(User, id),
- {:ok, _activity} <- ActivityPub.unfollow(follower, followed),
- {:ok, follower, _} <- User.unfollow(follower, followed) do
+ with %User{} = followed <- User.get_by_id(id),
+ {:ok, follower} <- CommonAPI.unfollow(follower, followed) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: follower, target: followed})
@@ -776,7 +778,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def mute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do
- with %User{} = muted <- Repo.get(User, id),
+ with %User{} = muted <- User.get_by_id(id),
{:ok, muter} <- User.mute(muter, muted) do
conn
|> put_view(AccountView)
@@ -790,7 +792,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def unmute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do
- with %User{} = muted <- Repo.get(User, id),
+ with %User{} = muted <- User.get_by_id(id),
{:ok, muter} <- User.unmute(muter, muted) do
conn
|> put_view(AccountView)
@@ -811,7 +813,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def block(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
- with %User{} = blocked <- Repo.get(User, id),
+ with %User{} = blocked <- User.get_by_id(id),
{:ok, blocker} <- User.block(blocker, blocked),
{:ok, _activity} <- ActivityPub.block(blocker, blocked) do
conn
@@ -826,7 +828,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def unblock(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
- with %User{} = blocked <- Repo.get(User, id),
+ with %User{} = blocked <- User.get_by_id(id),
{:ok, blocker} <- User.unblock(blocker, blocked),
{:ok, _activity} <- ActivityPub.unblock(blocker, blocked) do
conn
@@ -947,12 +949,14 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def favourites(%{assigns: %{user: user}} = conn, params) do
- activities =
+ params =
params
|> Map.put("type", "Create")
|> Map.put("favorited_by", user.ap_id)
|> Map.put("blocking_user", user)
- |> ActivityPub.fetch_public_activities()
+
+ activities =
+ ActivityPub.fetch_activities([], params)
|> Enum.reverse()
conn
@@ -962,7 +966,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def bookmarks(%{assigns: %{user: user}} = conn, _) do
- user = Repo.get(User, user.id)
+ user = User.get_by_id(user.id)
activities =
user.bookmarks
@@ -1019,7 +1023,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
accounts
|> Enum.each(fn account_id ->
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
- %User{} = followed <- Repo.get(User, account_id) do
+ %User{} = followed <- User.get_by_id(account_id) do
Pleroma.List.follow(list, followed)
end
end)
@@ -1031,7 +1035,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
accounts
|> Enum.each(fn account_id ->
with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
- %User{} = followed <- Repo.get(Pleroma.User, account_id) do
+ %User{} = followed <- Pleroma.User.get_by_id(account_id) do
Pleroma.List.unfollow(list, followed)
end
end)
@@ -1126,7 +1130,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
compose: %{
me: "#{user.id}",
default_privacy: user.info.default_scope,
- default_sensitive: false
+ default_sensitive: false,
+ allow_content_types: Config.get([:instance, :allowed_post_formats])
},
media_attachments: %{
accept_content_types: [
@@ -1244,16 +1249,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
"glitch"
end
- def login(conn, %{"code" => code}) do
+ def login(%{assigns: %{user: %User{}}} = conn, _params) do
+ redirect(conn, to: local_mastodon_root_path(conn))
+ end
+
+ @doc "Local Mastodon FE login init action"
+ def login(conn, %{"code" => auth_token}) do
with {:ok, app} <- get_or_make_app(),
- %Authorization{} = auth <- Repo.get_by(Authorization, token: code, app_id: app.id),
+ %Authorization{} = auth <- Repo.get_by(Authorization, token: auth_token, app_id: app.id),
{:ok, token} <- Token.exchange_token(app, auth) do
conn
|> put_session(:oauth_token, token.token)
- |> redirect(to: "/web/getting-started")
+ |> redirect(to: local_mastodon_root_path(conn))
end
end
+ @doc "Local Mastodon FE callback action"
def login(conn, _) do
with {:ok, app} <- get_or_make_app() do
path =
@@ -1271,7 +1282,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end
- defp get_or_make_app() do
+ defp local_mastodon_root_path(conn), do: mastodon_api_path(conn, :index, ["getting-started"])
+
+ defp get_or_make_app do
find_attrs = %{client_name: @local_mastodon_name, redirect_uris: "."}
scopes = ["read", "write", "follow", "push"]
@@ -1307,7 +1320,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
def relationship_noop(%{assigns: %{user: user}} = conn, %{"id" => id}) do
Logger.debug("Unimplemented, returning unmodified relationship")
- with %User{} = target <- Repo.get(User, id) do
+ with %User{} = target <- User.get_by_id(id) do
conn
|> put_view(AccountView)
|> render("relationship.json", %{user: user, target: target})
@@ -1324,45 +1337,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
json(conn, %{})
end
- def render_notification(user, %{id: id, activity: activity, inserted_at: created_at} = _params) do
- actor = User.get_cached_by_ap_id(activity.data["actor"])
- parent_activity = Activity.get_create_by_object_ap_id(activity.data["object"])
- mastodon_type = Activity.mastodon_notification_type(activity)
-
- response = %{
- id: to_string(id),
- type: mastodon_type,
- created_at: CommonAPI.Utils.to_masto_date(created_at),
- account: AccountView.render("account.json", %{user: actor, for: user})
- }
-
- case mastodon_type do
- "mention" ->
- response
- |> Map.merge(%{
- status: StatusView.render("status.json", %{activity: activity, for: user})
- })
-
- "favourite" ->
- response
- |> Map.merge(%{
- status: StatusView.render("status.json", %{activity: parent_activity, for: user})
- })
-
- "reblog" ->
- response
- |> Map.merge(%{
- status: StatusView.render("status.json", %{activity: parent_activity, for: user})
- })
-
- "follow" ->
- response
-
- _ ->
- nil
- end
- end
-
def get_filters(%{assigns: %{user: user}} = conn, _) do
filters = Filter.get_filters(user)
res = FilterView.render("filters.json", filters: filters)
@@ -1452,7 +1426,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
url,
[],
adapter: [
- timeout: timeout,
recv_timeout: timeout,
pool: :default
]
@@ -1489,7 +1462,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do
- with %Activity{} = activity <- Repo.get(Activity, status_id),
+ with %Activity{} = activity <- Activity.get_by_id(status_id),
true <- Visibility.visible_for_user?(activity, user) do
data =
StatusView.render(
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index c32f27be2..b5f3bbb9d 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -55,7 +55,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
muting_notifications: false,
requested: requested,
domain_blocking: false,
- showing_reblogs: false,
+ showing_reblogs: User.showing_reblogs?(user, target),
endorsed: false
}
end
diff --git a/lib/pleroma/web/mastodon_api/views/app_view.ex b/lib/pleroma/web/mastodon_api/views/app_view.ex
new file mode 100644
index 000000000..f52b693a6
--- /dev/null
+++ b/lib/pleroma/web/mastodon_api/views/app_view.ex
@@ -0,0 +1,41 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.AppView do
+ use Pleroma.Web, :view
+
+ alias Pleroma.Web.OAuth.App
+
+ @vapid_key :web_push_encryption
+ |> Application.get_env(:vapid_details, [])
+ |> Keyword.get(:public_key)
+
+ def render("show.json", %{app: %App{} = app}) do
+ %{
+ id: app.id |> to_string,
+ name: app.client_name,
+ client_id: app.client_id,
+ client_secret: app.client_secret,
+ redirect_uri: app.redirect_uris,
+ website: app.website
+ }
+ |> with_vapid_key()
+ end
+
+ def render("short.json", %{app: %App{website: webiste, client_name: name}}) do
+ %{
+ name: name,
+ website: webiste
+ }
+ |> with_vapid_key()
+ end
+
+ defp with_vapid_key(data) do
+ if @vapid_key do
+ Map.put(data, "vapid_key", @vapid_key)
+ else
+ data
+ end
+ end
+end
diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex
new file mode 100644
index 000000000..27e9cab06
--- /dev/null
+++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex
@@ -0,0 +1,64 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.NotificationView do
+ use Pleroma.Web, :view
+
+ alias Pleroma.Activity
+ alias Pleroma.Notification
+ alias Pleroma.User
+ alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.MastodonAPI.AccountView
+ alias Pleroma.Web.MastodonAPI.NotificationView
+ alias Pleroma.Web.MastodonAPI.StatusView
+
+ def render("index.json", %{notifications: notifications, for: user}) do
+ render_many(notifications, NotificationView, "show.json", %{for: user})
+ end
+
+ def render("show.json", %{
+ notification: %Notification{activity: activity} = notification,
+ for: user
+ }) do
+ actor = User.get_cached_by_ap_id(activity.data["actor"])
+ parent_activity = Activity.get_create_by_object_ap_id(activity.data["object"])
+ mastodon_type = Activity.mastodon_notification_type(activity)
+
+ response = %{
+ id: to_string(notification.id),
+ type: mastodon_type,
+ created_at: CommonAPI.Utils.to_masto_date(notification.inserted_at),
+ account: AccountView.render("account.json", %{user: actor, for: user}),
+ pleroma: %{
+ is_seen: notification.seen
+ }
+ }
+
+ case mastodon_type do
+ "mention" ->
+ response
+ |> Map.merge(%{
+ status: StatusView.render("status.json", %{activity: activity, for: user})
+ })
+
+ "favourite" ->
+ response
+ |> Map.merge(%{
+ status: StatusView.render("status.json", %{activity: parent_activity, for: user})
+ })
+
+ "reblog" ->
+ response
+ |> Map.merge(%{
+ status: StatusView.render("status.json", %{activity: parent_activity, for: user})
+ })
+
+ "follow" ->
+ response
+
+ _ ->
+ nil
+ end
+ end
+end
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 3468c0e1c..200bb453d 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -46,6 +46,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
end
+ defp get_context_id(%{data: %{"context_id" => context_id}}) when not is_nil(context_id),
+ do: context_id
+
+ defp get_context_id(%{data: %{"context" => context}}) when is_binary(context),
+ do: Utils.context_to_conversation_id(context)
+
+ defp get_context_id(_), do: nil
+
def render("index.json", opts) do
replied_to_activities = get_replied_to_activities(opts.activities)
@@ -102,7 +110,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
website: nil
},
language: nil,
- emojis: []
+ emojis: [],
+ pleroma: %{
+ local: activity.local
+ }
}
end
@@ -163,7 +174,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
content: content,
created_at: created_at,
reblogs_count: announcement_count,
- replies_count: 0,
+ replies_count: object["repliesCount"] || 0,
favourites_count: like_count,
reblogged: present?(repeated),
favourited: present?(favorited),
@@ -181,7 +192,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
website: nil
},
language: nil,
- emojis: build_emojis(activity.data["object"]["emoji"])
+ emojis: build_emojis(activity.data["object"]["emoji"]),
+ pleroma: %{
+ local: activity.local,
+ conversation_id: get_context_id(activity)
+ }
}
end
@@ -251,7 +266,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
preview_url: href,
text_url: href,
type: type,
- description: attachment["name"]
+ description: attachment["name"],
+ pleroma: %{mime_type: media_type}
}
end
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index 8efe2efd5..1b3721e2b 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -5,9 +5,9 @@
defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
require Logger
- alias Pleroma.Web.OAuth.Token
alias Pleroma.Repo
alias Pleroma.User
+ alias Pleroma.Web.OAuth.Token
@behaviour :cowboy_websocket
@@ -90,7 +90,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
# Authenticated streams.
defp allow_request(stream, {"access_token", access_token}) when stream in @streams do
with %Token{user_id: user_id} <- Repo.get_by(Token, token: access_token),
- user = %User{} <- Repo.get(User, user_id) do
+ user = %User{} <- User.get_by_id(user_id) do
{:ok, user}
else
_ -> {:error, 403}
diff --git a/lib/pleroma/web/media_proxy/media_proxy.ex b/lib/pleroma/web/media_proxy/media_proxy.ex
index 39a725a69..3bd2affe9 100644
--- a/lib/pleroma/web/media_proxy/media_proxy.ex
+++ b/lib/pleroma/web/media_proxy/media_proxy.ex
@@ -19,7 +19,8 @@ defmodule Pleroma.Web.MediaProxy do
else
secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
- # Must preserve `%2F` for compatibility with S3 (https://git.pleroma.social/pleroma/pleroma/issues/580)
+ # Must preserve `%2F` for compatibility with S3
+ # https://git.pleroma.social/pleroma/pleroma/issues/580
replacement = get_replacement(url, ":2F:")
# The URL is url-decoded and encoded again to ensure it is correctly encoded and not twice.
diff --git a/lib/pleroma/web/metadata/opengraph.ex b/lib/pleroma/web/metadata/opengraph.ex
index cafb8134b..357b80a2d 100644
--- a/lib/pleroma/web/metadata/opengraph.ex
+++ b/lib/pleroma/web/metadata/opengraph.ex
@@ -88,7 +88,7 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
# TODO: Add additional properties to objects when we have the data available.
# Also, Whatsapp only wants JPEG or PNGs. It seems that if we add a second og:image
- # object when a Video or GIF is attached it will display that in the Whatsapp Rich Preview.
+ # object when a Video or GIF is attached it will display that in Whatsapp Rich Preview.
case media_type do
"audio" ->
[
diff --git a/lib/pleroma/web/metadata/twitter_card.ex b/lib/pleroma/web/metadata/twitter_card.ex
index a0be383e5..040b872e7 100644
--- a/lib/pleroma/web/metadata/twitter_card.ex
+++ b/lib/pleroma/web/metadata/twitter_card.ex
@@ -97,7 +97,8 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
| acc
]
- # TODO: Need the true width and height values here or Twitter renders an iFrame with a bad aspect ratio
+ # TODO: Need the true width and height values here or Twitter renders an iFrame with
+ # a bad aspect ratio
"video" ->
[
{:meta, [property: "twitter:card", content: "player"], []},
diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex
index 5fc9c9e7b..23bbde1a6 100644
--- a/lib/pleroma/web/metadata/utils.ex
+++ b/lib/pleroma/web/metadata/utils.ex
@@ -1,10 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright \xc2\xa9 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Metadata.Utils do
- alias Pleroma.HTML
alias Pleroma.Formatter
+ alias Pleroma.HTML
alias Pleroma.Web.MediaProxy
def scrub_html_and_truncate(%{data: %{"content" => content}} = object) do
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo.ex b/lib/pleroma/web/nodeinfo/nodeinfo.ex
deleted file mode 100644
index 8b1378917..000000000
--- a/lib/pleroma/web/nodeinfo/nodeinfo.ex
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
index 8c775ce24..216a962bd 100644
--- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
+++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
@@ -124,6 +124,9 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
end,
if Keyword.get(instance, :allow_relay) do
"relay"
+ end,
+ if Keyword.get(instance, :safe_dm_mentions) do
+ "safe_dm_mentions"
end
]
|> Enum.filter(& &1)
diff --git a/lib/pleroma/web/oauth/authorization.ex b/lib/pleroma/web/oauth/authorization.ex
index d37c2cb83..3461f9983 100644
--- a/lib/pleroma/web/oauth/authorization.ex
+++ b/lib/pleroma/web/oauth/authorization.ex
@@ -5,10 +5,10 @@
defmodule Pleroma.Web.OAuth.Authorization do
use Ecto.Schema
- alias Pleroma.User
alias Pleroma.Repo
- alias Pleroma.Web.OAuth.Authorization
+ alias Pleroma.User
alias Pleroma.Web.OAuth.App
+ alias Pleroma.Web.OAuth.Authorization
import Ecto.Changeset
import Ecto.Query
@@ -16,7 +16,7 @@ defmodule Pleroma.Web.OAuth.Authorization do
schema "oauth_authorizations" do
field(:token, :string)
field(:scopes, {:array, :string}, default: [])
- field(:valid_until, :naive_datetime)
+ field(:valid_until, :naive_datetime_usec)
field(:used, :boolean, default: false)
belongs_to(:user, Pleroma.User, type: Pleroma.FlakeId)
belongs_to(:app, App)
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 36318d69b..26d53df1a 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -5,13 +5,13 @@
defmodule Pleroma.Web.OAuth.OAuthController do
use Pleroma.Web, :controller
+ alias Pleroma.Repo
+ alias Pleroma.User
alias Pleroma.Web.Auth.Authenticator
+ alias Pleroma.Web.ControllerHelper
+ alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
- alias Pleroma.Web.OAuth.App
- alias Pleroma.Repo
- alias Pleroma.User
- alias Comeonin.Pbkdf2
import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2]
@@ -20,7 +20,28 @@ defmodule Pleroma.Web.OAuth.OAuthController do
action_fallback(Pleroma.Web.OAuth.FallbackController)
- def authorize(conn, params) do
+ def authorize(%{assigns: %{token: %Token{} = token}} = conn, params) do
+ if ControllerHelper.truthy_param?(params["force_login"]) do
+ do_authorize(conn, params)
+ else
+ redirect_uri =
+ if is_binary(params["redirect_uri"]) do
+ params["redirect_uri"]
+ else
+ app = Repo.preload(token, :app).app
+
+ app.redirect_uris
+ |> String.split()
+ |> Enum.at(0)
+ end
+
+ redirect(conn, external: redirect_uri(conn, redirect_uri))
+ end
+ end
+
+ def authorize(conn, params), do: do_authorize(conn, params)
+
+ defp do_authorize(conn, params) do
app = Repo.get_by(App, client_id: params["client_id"])
available_scopes = (app && app.scopes) || []
scopes = oauth_scopes(params, nil) || available_scopes
@@ -52,13 +73,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
{:missing_scopes, false} <- {:missing_scopes, scopes == []},
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
{:ok, auth} <- Authorization.create_authorization(app, user, scopes) do
- redirect_uri =
- if redirect_uri == "." do
- # Special case: Local MastodonFE
- mastodon_api_url(conn, :login)
- else
- redirect_uri
- end
+ redirect_uri = redirect_uri(conn, redirect_uri)
cond do
redirect_uri == "urn:ietf:wg:oauth:2.0:oob" ->
@@ -84,14 +99,18 @@ defmodule Pleroma.Web.OAuth.OAuthController do
end
else
{scopes_issue, _} when scopes_issue in [:unsupported_scopes, :missing_scopes] ->
+ # Per https://github.com/tootsuite/mastodon/blob/
+ # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L39
conn
- |> put_flash(:error, "Permissions not specified.")
+ |> put_flash(:error, "This action is outside the authorized scopes")
|> put_status(:unauthorized)
|> authorize(auth_params)
{:auth_active, false} ->
+ # Per https://github.com/tootsuite/mastodon/blob/
+ # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76
conn
- |> put_flash(:error, "Account confirmation pending.")
+ |> put_flash(:error, "Your login is missing a confirmed e-mail address")
|> put_status(:forbidden)
|> authorize(auth_params)
@@ -105,6 +124,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
fixed_token = fix_padding(params["code"]),
%Authorization{} = auth <-
Repo.get_by(Authorization, token: fixed_token, app_id: app.id),
+ %User{} = user <- User.get_by_id(auth.user_id),
{:ok, token} <- Token.exchange_token(app, auth),
{:ok, inserted_at} <- DateTime.from_naive(token.inserted_at, "Etc/UTC") do
response = %{
@@ -113,7 +133,8 @@ defmodule Pleroma.Web.OAuth.OAuthController do
refresh_token: token.refresh_token,
created_at: DateTime.to_unix(inserted_at),
expires_in: 60 * 10,
- scope: Enum.join(token.scopes, " ")
+ scope: Enum.join(token.scopes, " "),
+ me: user.ap_id
}
json(conn, response)
@@ -126,11 +147,10 @@ defmodule Pleroma.Web.OAuth.OAuthController do
def token_exchange(
conn,
- %{"grant_type" => "password", "username" => name, "password" => password} = params
+ %{"grant_type" => "password"} = params
) do
- with %App{} = app <- get_app_from_request(conn, params),
- %User{} = user <- User.get_by_nickname_or_email(name),
- true <- Pbkdf2.checkpw(password, user.password_hash),
+ with {_, {:ok, %User{} = user}} <- {:get_user, Authenticator.get_user(conn)},
+ %App{} = app <- get_app_from_request(conn, params),
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
scopes <- oauth_scopes(params, app.scopes),
[] <- scopes -- app.scopes,
@@ -142,15 +162,18 @@ defmodule Pleroma.Web.OAuth.OAuthController do
access_token: token.token,
refresh_token: token.refresh_token,
expires_in: 60 * 10,
- scope: Enum.join(token.scopes, " ")
+ scope: Enum.join(token.scopes, " "),
+ me: user.ap_id
}
json(conn, response)
else
{:auth_active, false} ->
+ # Per https://github.com/tootsuite/mastodon/blob/
+ # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76
conn
|> put_status(:forbidden)
- |> json(%{error: "Account confirmation pending"})
+ |> json(%{error: "Your login is missing a confirmed e-mail address"})
_error ->
put_status(conn, 400)
@@ -214,4 +237,9 @@ defmodule Pleroma.Web.OAuth.OAuthController do
nil
end
end
+
+ # Special case: Local MastodonFE
+ defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :login)
+
+ defp redirect_uri(_conn, redirect_uri), do: redirect_uri
end
diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
index ca67632ba..2b5ad9b94 100644
--- a/lib/pleroma/web/oauth/token.ex
+++ b/lib/pleroma/web/oauth/token.ex
@@ -7,17 +7,17 @@ defmodule Pleroma.Web.OAuth.Token do
import Ecto.Query
- alias Pleroma.User
alias Pleroma.Repo
- alias Pleroma.Web.OAuth.Token
+ alias Pleroma.User
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
+ alias Pleroma.Web.OAuth.Token
schema "oauth_tokens" do
field(:token, :string)
field(:refresh_token, :string)
field(:scopes, {:array, :string}, default: [])
- field(:valid_until, :naive_datetime)
+ field(:valid_until, :naive_datetime_usec)
belongs_to(:user, Pleroma.User, type: Pleroma.FlakeId)
belongs_to(:app, App)
@@ -27,7 +27,7 @@ defmodule Pleroma.Web.OAuth.Token do
def exchange_token(app, auth) do
with {:ok, auth} <- Authorization.use_token(auth),
true <- auth.app_id == app.id do
- create_token(app, Repo.get(User, auth.user_id), auth.scopes)
+ create_token(app, User.get_by_id(auth.user_id), auth.scopes)
end
end
diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex
index 9e1f24bc4..1a1b74bb0 100644
--- a/lib/pleroma/web/ostatus/activity_representer.ex
+++ b/lib/pleroma/web/ostatus/activity_representer.ex
@@ -4,8 +4,8 @@
defmodule Pleroma.Web.OStatus.ActivityRepresenter do
alias Pleroma.Activity
- alias Pleroma.User
alias Pleroma.Object
+ alias Pleroma.User
alias Pleroma.Web.OStatus.UserRepresenter
require Logger
diff --git a/lib/pleroma/web/ostatus/feed_representer.ex b/lib/pleroma/web/ostatus/feed_representer.ex
index 025d4731c..b7b97e505 100644
--- a/lib/pleroma/web/ostatus/feed_representer.ex
+++ b/lib/pleroma/web/ostatus/feed_representer.ex
@@ -4,8 +4,8 @@
defmodule Pleroma.Web.OStatus.FeedRepresenter do
alias Pleroma.User
- alias Pleroma.Web.OStatus
alias Pleroma.Web.MediaProxy
+ alias Pleroma.Web.OStatus
alias Pleroma.Web.OStatus.ActivityRepresenter
alias Pleroma.Web.OStatus.UserRepresenter
diff --git a/lib/pleroma/web/ostatus/handlers/delete_handler.ex b/lib/pleroma/web/ostatus/handlers/delete_handler.ex
index 01b52f08f..b2f9f3946 100644
--- a/lib/pleroma/web/ostatus/handlers/delete_handler.ex
+++ b/lib/pleroma/web/ostatus/handlers/delete_handler.ex
@@ -4,9 +4,9 @@
defmodule Pleroma.Web.OStatus.DeleteHandler do
require Logger
- alias Pleroma.Web.XML
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.XML
def handle_delete(entry, _doc \\ nil) do
with id <- XML.string_from_xpath("//id", entry),
diff --git a/lib/pleroma/web/ostatus/handlers/follow_handler.ex b/lib/pleroma/web/ostatus/handlers/follow_handler.ex
index 91ad4bc40..263d3b2dc 100644
--- a/lib/pleroma/web/ostatus/handlers/follow_handler.ex
+++ b/lib/pleroma/web/ostatus/handlers/follow_handler.ex
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OStatus.FollowHandler do
- alias Pleroma.Web.XML
- alias Pleroma.Web.OStatus
- alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.OStatus
+ alias Pleroma.Web.XML
def handle(entry, doc) do
with {:ok, actor} <- OStatus.find_make_or_update_user(doc),
diff --git a/lib/pleroma/web/ostatus/handlers/note_handler.ex b/lib/pleroma/web/ostatus/handlers/note_handler.ex
index c2e585cac..db995ec77 100644
--- a/lib/pleroma/web/ostatus/handlers/note_handler.ex
+++ b/lib/pleroma/web/ostatus/handlers/note_handler.ex
@@ -4,13 +4,14 @@
defmodule Pleroma.Web.OStatus.NoteHandler do
require Logger
- alias Pleroma.Web.OStatus
- alias Pleroma.Web.XML
+
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.OStatus
+ alias Pleroma.Web.XML
@doc """
Get the context for this note. Uses this:
@@ -18,13 +19,13 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
2. The conversation reference in the ostatus xml
3. A newly generated context id.
"""
- def get_context(entry, inReplyTo) do
+ def get_context(entry, in_reply_to) do
context =
(XML.string_from_xpath("//ostatus:conversation[1]", entry) ||
XML.string_from_xpath("//ostatus:conversation[1]/@ref", entry) || "")
|> String.trim()
- with %{data: %{"context" => context}} <- Object.get_cached_by_ap_id(inReplyTo) do
+ with %{data: %{"context" => context}} <- Object.get_cached_by_ap_id(in_reply_to) do
context
else
_e ->
@@ -87,14 +88,14 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
Map.put(note, "external_url", url)
end
- def fetch_replied_to_activity(entry, inReplyTo) do
- with %Activity{} = activity <- Activity.get_create_by_object_ap_id(inReplyTo) do
+ def fetch_replied_to_activity(entry, in_reply_to) do
+ with %Activity{} = activity <- Activity.get_create_by_object_ap_id(in_reply_to) do
activity
else
_e ->
- with inReplyToHref when not is_nil(inReplyToHref) <-
+ with in_reply_to_href when not is_nil(in_reply_to_href) <-
XML.string_from_xpath("//thr:in-reply-to[1]/@href", entry),
- {:ok, [activity | _]} <- OStatus.fetch_activity_from_url(inReplyToHref) do
+ {:ok, [activity | _]} <- OStatus.fetch_activity_from_url(in_reply_to_href) do
activity
else
_e -> nil
@@ -105,16 +106,17 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
# TODO: Clean this up a bit.
def handle_note(entry, doc \\ nil) do
with id <- XML.string_from_xpath("//id", entry),
- activity when is_nil(activity) <- Activity.get_create_by_object_ap_id(id),
+ activity when is_nil(activity) <- Activity.get_create_by_object_ap_id_with_object(id),
[author] <- :xmerl_xpath.string('//author[1]', doc),
{:ok, actor} <- OStatus.find_make_or_update_user(author),
content_html <- OStatus.get_content(entry),
cw <- OStatus.get_cw(entry),
- inReplyTo <- XML.string_from_xpath("//thr:in-reply-to[1]/@ref", entry),
- inReplyToActivity <- fetch_replied_to_activity(entry, inReplyTo),
- inReplyTo <- (inReplyToActivity && inReplyToActivity.data["object"]["id"]) || inReplyTo,
+ in_reply_to <- XML.string_from_xpath("//thr:in-reply-to[1]/@ref", entry),
+ in_reply_to_activity <- fetch_replied_to_activity(entry, in_reply_to),
+ in_reply_to <-
+ (in_reply_to_activity && in_reply_to_activity.data["object"]["id"]) || in_reply_to,
attachments <- OStatus.get_attachments(entry),
- context <- get_context(entry, inReplyTo),
+ context <- get_context(entry, in_reply_to),
tags <- OStatus.get_tags(entry),
mentions <- get_mentions(entry),
to <- make_to_list(actor, mentions),
@@ -128,7 +130,7 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
context,
content_html,
attachments,
- inReplyToActivity,
+ in_reply_to_activity,
[],
cw
),
@@ -140,8 +142,8 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
# TODO: Handle this case in make_note_data
note <-
if(
- inReplyTo && !inReplyToActivity,
- do: note |> Map.put("inReplyTo", inReplyTo),
+ in_reply_to && !in_reply_to_activity,
+ do: note |> Map.put("inReplyTo", in_reply_to),
else: note
) do
ActivityPub.create(%{
diff --git a/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex b/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex
index c9085894d..6596ada3b 100644
--- a/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex
+++ b/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OStatus.UnfollowHandler do
- alias Pleroma.Web.XML
- alias Pleroma.Web.OStatus
- alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.OStatus
+ alias Pleroma.Web.XML
def handle(entry, doc) do
with {:ok, actor} <- OStatus.find_make_or_update_user(doc),
diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex
index b4f5761ac..9a34d7ad5 100644
--- a/lib/pleroma/web/ostatus/ostatus.ex
+++ b/lib/pleroma/web/ostatus/ostatus.ex
@@ -9,22 +9,22 @@ defmodule Pleroma.Web.OStatus do
import Pleroma.Web.XML
require Logger
+ alias Pleroma.Activity
+ alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web
- alias Pleroma.Object
- alias Pleroma.Activity
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Transmogrifier
- alias Pleroma.Web.WebFinger
- alias Pleroma.Web.Websub
+ alias Pleroma.Web.OStatus.DeleteHandler
alias Pleroma.Web.OStatus.FollowHandler
- alias Pleroma.Web.OStatus.UnfollowHandler
alias Pleroma.Web.OStatus.NoteHandler
- alias Pleroma.Web.OStatus.DeleteHandler
+ alias Pleroma.Web.OStatus.UnfollowHandler
+ alias Pleroma.Web.WebFinger
+ alias Pleroma.Web.Websub
- def is_representable?(%Activity{data: data}) do
- object = Object.normalize(data["object"])
+ def is_representable?(%Activity{} = activity) do
+ object = Object.normalize(activity)
cond do
is_nil(object) ->
@@ -119,7 +119,7 @@ defmodule Pleroma.Web.OStatus do
def make_share(entry, doc, retweeted_activity) do
with {:ok, actor} <- find_make_or_update_user(doc),
- %Object{} = object <- Object.normalize(retweeted_activity.data["object"]),
+ %Object{} = object <- Object.normalize(retweeted_activity),
id when not is_nil(id) <- string_from_xpath("/entry/id", entry),
{:ok, activity, _object} = ActivityPub.announce(actor, object, id, false) do
{:ok, activity}
@@ -137,7 +137,7 @@ defmodule Pleroma.Web.OStatus do
def make_favorite(entry, doc, favorited_activity) do
with {:ok, actor} <- find_make_or_update_user(doc),
- %Object{} = object <- Object.normalize(favorited_activity.data["object"]),
+ %Object{} = object <- Object.normalize(favorited_activity),
id when not is_nil(id) <- string_from_xpath("/entry/id", entry),
{:ok, activity, _object} = ActivityPub.like(actor, object, id, false) do
{:ok, activity}
@@ -159,7 +159,7 @@ defmodule Pleroma.Web.OStatus do
Logger.debug("Trying to get entry from db")
with id when not is_nil(id) <- string_from_xpath("//activity:object[1]/id", entry),
- %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id_with_object(id) do
{:ok, activity}
else
_ ->
diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex
index 4e963774a..2fb6ce41b 100644
--- a/lib/pleroma/web/ostatus/ostatus_controller.ex
+++ b/lib/pleroma/web/ostatus/ostatus_controller.ex
@@ -9,13 +9,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.ActivityPub.ActivityPubController
alias Pleroma.Web.ActivityPub.ObjectView
- alias Pleroma.Web.OStatus.ActivityRepresenter
- alias Pleroma.Web.OStatus.FeedRepresenter
+ alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator
alias Pleroma.Web.OStatus
+ alias Pleroma.Web.OStatus.ActivityRepresenter
+ alias Pleroma.Web.OStatus.FeedRepresenter
alias Pleroma.Web.XML
plug(Pleroma.Web.FederatingPlug when action in [:salmon_incoming])
@@ -102,7 +102,8 @@ defmodule Pleroma.Web.OStatus.OStatusController do
ActivityPubController.call(conn, :object)
else
with id <- o_status_url(conn, :object, uuid),
- {_, %Activity{} = activity} <- {:activity, Activity.get_create_by_object_ap_id(id)},
+ {_, %Activity{} = activity} <-
+ {:activity, Activity.get_create_by_object_ap_id_with_object(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)},
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
case get_format(conn) do
@@ -148,13 +149,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do
end
def notice(conn, %{"id" => id}) do
- with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id(id)},
+ with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)},
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
case format = get_format(conn) do
"html" ->
if activity.data["type"] == "Create" do
- %Object{} = object = Object.normalize(activity.data["object"])
+ %Object{} = object = Object.normalize(activity)
Fallback.RedirectController.redirector_with_meta(conn, %{
activity_id: activity.id,
@@ -191,9 +192,9 @@ defmodule Pleroma.Web.OStatus.OStatusController do
# Returns an HTML embedded <audio> or <video> player suitable for embed iframes.
def notice_player(conn, %{"id" => id}) do
- with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id(id),
+ with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id_with_object(id),
true <- Visibility.is_public?(activity),
- %Object{} = object <- Object.normalize(activity.data["object"]),
+ %Object{} = object <- Object.normalize(activity),
%{data: %{"attachment" => [%{"url" => [url | _]} | _]}} <- object,
true <- String.starts_with?(url["mediaType"], ["audio", "video"]) do
conn
@@ -219,7 +220,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do
%Activity{data: %{"type" => "Create"}} = activity,
_user
) do
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity)
conn
|> put_resp_header("content-type", "application/activity+json")
diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex
index 33f912d34..863573185 100644
--- a/lib/pleroma/web/push/impl.ex
+++ b/lib/pleroma/web/push/impl.ex
@@ -5,13 +5,13 @@
defmodule Pleroma.Web.Push.Impl do
@moduledoc "The module represents implementation push web notification"
- alias Pleroma.Repo
- alias Pleroma.User
alias Pleroma.Activity
+ alias Pleroma.Notification
alias Pleroma.Object
- alias Pleroma.Web.Push.Subscription
+ alias Pleroma.Repo
+ alias Pleroma.User
alias Pleroma.Web.Metadata.Utils
- alias Pleroma.Notification
+ alias Pleroma.Web.Push.Subscription
require Logger
import Ecto.Query
@@ -20,7 +20,10 @@ defmodule Pleroma.Web.Push.Impl do
@doc "Performs sending notifications for user subscriptions"
@spec perform_send(Notification.t()) :: list(any)
- def perform_send(%{activity: %{data: %{"type" => activity_type}}, user_id: user_id} = notif)
+ def perform_send(
+ %{activity: %{data: %{"type" => activity_type}, id: activity_id}, user_id: user_id} =
+ notif
+ )
when activity_type in @types do
actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
@@ -37,7 +40,10 @@ defmodule Pleroma.Web.Push.Impl do
notification_id: notif.id,
notification_type: type,
icon: avatar_url,
- preferred_locale: "en"
+ preferred_locale: "en",
+ pleroma: %{
+ activity_id: activity_id
+ }
}
|> Jason.encode!()
|> push_message(build_sub(subscription), gcm_api_key, subscription)
diff --git a/lib/pleroma/web/push/push.ex b/lib/pleroma/web/push/push.ex
index 951dab535..5259e8e33 100644
--- a/lib/pleroma/web/push/push.ex
+++ b/lib/pleroma/web/push/push.ex
@@ -13,15 +13,15 @@ defmodule Pleroma.Web.Push do
# Client API #
##############
- def start_link() do
+ def start_link do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
- def vapid_config() do
+ def vapid_config do
Application.get_env(:web_push_encryption, :vapid_details, [])
end
- def enabled() do
+ def enabled do
case vapid_config() do
[] -> false
list when is_list(list) -> true
diff --git a/lib/pleroma/web/push/subscription.ex b/lib/pleroma/web/push/subscription.ex
index c90bd2bda..da301fbbc 100644
--- a/lib/pleroma/web/push/subscription.ex
+++ b/lib/pleroma/web/push/subscription.ex
@@ -82,8 +82,8 @@ defmodule Pleroma.Web.Push.Subscription do
end
# Some webpush clients (e.g. iOS Toot!) use an non urlsafe base64 as an encoding for the key.
- # However, the web push rfs specify to use base64 urlsafe, and the `web_push_encryption` library we use
- # requires the key to be properly encoded. So we just convert base64 to urlsafe base64.
+ # However, the web push rfs specify to use base64 urlsafe, and the `web_push_encryption` library
+ # we use requires the key to be properly encoded. So we just convert base64 to urlsafe base64.
defp ensure_base64_urlsafe(string) do
string
|> String.replace("+", "-")
diff --git a/lib/pleroma/web/rel_me.ex b/lib/pleroma/web/rel_me.ex
index ab29a36e3..eaca41132 100644
--- a/lib/pleroma/web/rel_me.ex
+++ b/lib/pleroma/web/rel_me.ex
@@ -5,7 +5,6 @@
defmodule Pleroma.Web.RelMe do
@hackney_options [
pool: :media,
- timeout: 2_000,
recv_timeout: 2_000,
max_body: 2_000_000
]
diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
index 8317a1162..f67aaf58b 100644
--- a/lib/pleroma/web/rich_media/helpers.ex
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -4,8 +4,8 @@
defmodule Pleroma.Web.RichMedia.Helpers do
alias Pleroma.Activity
- alias Pleroma.Object
alias Pleroma.HTML
+ alias Pleroma.Object
alias Pleroma.Web.RichMedia.Parser
defp validate_page_url(page_url) when is_binary(page_url) do
@@ -21,9 +21,9 @@ defmodule Pleroma.Web.RichMedia.Helpers do
defp validate_page_url(%URI{}), do: :ok
defp validate_page_url(_), do: :error
- def fetch_data_for_activity(%Activity{} = activity) do
+ def fetch_data_for_activity(%Activity{data: %{"type" => "Create"}} = activity) do
with true <- Pleroma.Config.get([:rich_media, :enabled]),
- %Object{} = object <- Object.normalize(activity.data["object"]),
+ %Object{} = object <- Object.normalize(activity),
{:ok, page_url} <- HTML.extract_first_external_url(object, object.data["content"]),
:ok <- validate_page_url(page_url),
{:ok, rich_media} <- Parser.parse(page_url) do
@@ -32,4 +32,6 @@ defmodule Pleroma.Web.RichMedia.Helpers do
_ -> %{}
end
end
+
+ def fetch_data_for_activity(_), do: %{}
end
diff --git a/lib/pleroma/web/rich_media/parser.ex b/lib/pleroma/web/rich_media/parser.ex
index 4341141df..4bd271d8e 100644
--- a/lib/pleroma/web/rich_media/parser.ex
+++ b/lib/pleroma/web/rich_media/parser.ex
@@ -11,7 +11,6 @@ defmodule Pleroma.Web.RichMedia.Parser do
@hackney_options [
pool: :media,
- timeout: 2_000,
recv_timeout: 2_000,
max_body: 2_000_000
]
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 65a90e31e..605a327fc 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -5,6 +5,11 @@
defmodule Pleroma.Web.Router do
use Pleroma.Web, :router
+ pipeline :oauth do
+ plug(:fetch_session)
+ plug(Pleroma.Plugs.OAuthPlug)
+ end
+
pipeline :api do
plug(:accepts, ["json"])
plug(:fetch_session)
@@ -105,10 +110,6 @@ defmodule Pleroma.Web.Router do
plug(:accepts, ["json", "xml"])
end
- pipeline :oauth do
- plug(:accepts, ["html", "json"])
- end
-
pipeline :pleroma_api do
plug(:accepts, ["html", "json"])
end
@@ -140,6 +141,7 @@ defmodule Pleroma.Web.Router do
pipe_through([:admin_api, :oauth_write])
get("/users", AdminAPIController, :list_users)
+ get("/users/:nickname", AdminAPIController, :user_show)
delete("/user", AdminAPIController, :user_delete)
patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation)
post("/user", AdminAPIController, :user_create)
@@ -190,10 +192,20 @@ defmodule Pleroma.Web.Router do
post("/blocks_import", UtilController, :blocks_import)
post("/follow_import", UtilController, :follow_import)
end
+
+ scope [] do
+ pipe_through(:oauth_read)
+
+ post("/notifications/read", UtilController, :notifications_read)
+ end
end
scope "/oauth", Pleroma.Web.OAuth do
- get("/authorize", OAuthController, :authorize)
+ scope [] do
+ pipe_through(:oauth)
+ get("/authorize", OAuthController, :authorize)
+ end
+
post("/authorize", OAuthController, :create_authorization)
post("/token", OAuthController, :token_exchange)
post("/revoke", OAuthController, :token_revoke)
@@ -211,6 +223,7 @@ defmodule Pleroma.Web.Router do
get("/accounts/search", MastodonAPIController, :account_search)
get("/accounts/:id/lists", MastodonAPIController, :account_lists)
+ get("/accounts/:id/identity_proofs", MastodonAPIController, :empty_array)
get("/follow_requests", MastodonAPIController, :follow_requests)
get("/blocks", MastodonAPIController, :blocks)
@@ -322,6 +335,7 @@ defmodule Pleroma.Web.Router do
get("/instance", MastodonAPIController, :masto_instance)
get("/instance/peers", MastodonAPIController, :peers)
post("/apps", MastodonAPIController, :create_app)
+ get("/apps/verify_credentials", MastodonAPIController, :verify_app_credentials)
get("/custom_emojis", MastodonAPIController, :custom_emojis)
get("/statuses/:id/card", MastodonAPIController, :status_card)
@@ -631,8 +645,8 @@ end
defmodule Fallback.RedirectController do
use Pleroma.Web, :controller
- alias Pleroma.Web.Metadata
alias Pleroma.User
+ alias Pleroma.Web.Metadata
def redirector(conn, _params, code \\ 200) do
conn
diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex
index 0a69aa1ec..0a9e51656 100644
--- a/lib/pleroma/web/salmon/salmon.ex
+++ b/lib/pleroma/web/salmon/salmon.ex
@@ -9,8 +9,8 @@ defmodule Pleroma.Web.Salmon do
alias Pleroma.Instances
alias Pleroma.User
- alias Pleroma.Web.XML
alias Pleroma.Web.OStatus.ActivityRepresenter
+ alias Pleroma.Web.XML
require Logger
@@ -86,10 +86,10 @@ defmodule Pleroma.Web.Salmon do
# Native generation of RSA keys is only available since OTP 20+ and in default build conditions
# We try at compile time to generate natively an RSA key otherwise we fallback on the old way.
try do
- _ = :public_key.generate_key({:rsa, 2048, 65537})
+ _ = :public_key.generate_key({:rsa, 2048, 65_537})
def generate_rsa_pem do
- key = :public_key.generate_key({:rsa, 2048, 65537})
+ key = :public_key.generate_key({:rsa, 2048, 65_537})
entry = :public_key.pem_entry_encode(:RSAPrivateKey, key)
pem = :public_key.pem_encode([entry]) |> String.trim_trailing()
{:ok, pem}
diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex
index 27e8020f4..a82109f92 100644
--- a/lib/pleroma/web/streamer.ex
+++ b/lib/pleroma/web/streamer.ex
@@ -5,12 +5,13 @@
defmodule Pleroma.Web.Streamer do
use GenServer
require Logger
- alias Pleroma.User
- alias Pleroma.Notification
alias Pleroma.Activity
+ alias Pleroma.Notification
alias Pleroma.Object
- alias Pleroma.Repo
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
+ alias Pleroma.Web.MastodonAPI.NotificationView
@keepalive_interval :timer.seconds(30)
@@ -80,7 +81,7 @@ defmodule Pleroma.Web.Streamer do
_ ->
Pleroma.List.get_lists_from_activity(item)
|> Enum.filter(fn list ->
- owner = Repo.get(User, list.user_id)
+ owner = User.get_by_id(list.user_id)
Visibility.visible_for_user?(item, owner)
end)
@@ -106,10 +107,10 @@ defmodule Pleroma.Web.Streamer do
%{
event: "notification",
payload:
- Pleroma.Web.MastodonAPI.MastodonAPIController.render_notification(
- socket.assigns["user"],
- item
- )
+ NotificationView.render("show.json", %{
+ notification: item,
+ for: socket.assigns["user"]
+ })
|> Jason.encode!()
}
|> Jason.encode!()
@@ -198,10 +199,12 @@ defmodule Pleroma.Web.Streamer do
user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
blocks = user.info.blocks || []
mutes = user.info.mutes || []
+ reblog_mutes = user.info.muted_reblogs || []
- parent = Object.normalize(item.data["object"])
+ parent = Object.normalize(item)
unless is_nil(parent) or item.actor in blocks or item.actor in mutes or
+ item.actor in reblog_mutes or not ActivityPub.contain_activity(item, user) or
parent.data["actor"] in blocks or parent.data["actor"] in mutes do
send(socket.transport_pid, {:text, represent_update(item, user)})
end
@@ -211,15 +214,19 @@ defmodule Pleroma.Web.Streamer do
end)
end
- def push_to_socket(topics, topic, %Activity{id: id, data: %{"type" => "Delete"}}) do
+ def push_to_socket(topics, topic, %Activity{
+ data: %{"type" => "Delete", "deleted_activity_id" => deleted_activity_id}
+ }) do
Enum.each(topics[topic] || [], fn socket ->
send(
socket.transport_pid,
- {:text, %{event: "delete", payload: to_string(id)} |> Jason.encode!()}
+ {:text, %{event: "delete", payload: to_string(deleted_activity_id)} |> Jason.encode!()}
)
end)
end
+ def push_to_socket(_topics, _topic, %Activity{data: %{"type" => "Delete"}}), do: :noop
+
def push_to_socket(topics, topic, item) do
Enum.each(topics[topic] || [], fn socket ->
# Get the current user so we have up-to-date blocks etc.
@@ -228,7 +235,8 @@ defmodule Pleroma.Web.Streamer do
blocks = user.info.blocks || []
mutes = user.info.mutes || []
- unless item.actor in blocks or item.actor in mutes do
+ unless item.actor in blocks or item.actor in mutes or
+ not ActivityPub.contain_activity(item, user) do
send(socket.transport_pid, {:text, represent_update(item, user)})
end
else
diff --git a/lib/pleroma/web/templates/layout/app.html.eex b/lib/pleroma/web/templates/layout/app.html.eex
index db97ccac2..8333bc921 100644
--- a/lib/pleroma/web/templates/layout/app.html.eex
+++ b/lib/pleroma/web/templates/layout/app.html.eex
@@ -8,75 +8,145 @@
</title>
<style>
body {
- background-color: #282c37;
+ background-color: #121a24;
font-family: sans-serif;
- color:white;
+ color: #b9b9ba;
text-align: center;
}
.container {
- margin: 50px auto;
- max-width: 320px;
- padding: 0;
- padding: 40px 40px 40px 40px;
- background-color: #313543;
+ max-width: 420px;
+ padding: 20px;
+ background-color: #182230;
border-radius: 4px;
+ margin: auto;
+ margin-top: 10vh;
+ box-shadow: 0 1px 4px 0px rgba(0, 0, 0, 0.5);
}
h1 {
margin: 0;
+ font-size: 24px;
}
h2 {
- color: #9baec8;
+ color: #b9b9ba;
font-weight: normal;
- font-size: 20px;
- margin-bottom: 40px;
+ font-size: 18px;
+ margin-bottom: 20px;
}
form {
width: 100%;
}
+ .input {
+ text-align: left;
+ color: #89898a;
+ display: flex;
+ flex-direction: column;
+ }
+
input {
- box-sizing: border-box;
- width: 100%;
+ box-sizing: content-box;
padding: 10px;
- margin-top: 20px;
- background-color: rgba(0,0,0,.1);
- color: white;
+ margin-top: 5px;
+ margin-bottom: 10px;
+ background-color: #121a24;
+ color: #b9b9ba;
border: 0;
- border-bottom: 2px solid #9baec8;
+ transition-property: border-bottom;
+ transition-duration: 0.35s;
+ border-bottom: 2px solid #2a384a;
font-size: 14px;
}
- input:focus {
- border-bottom: 2px solid #4b8ed8;
+ .scopes-input {
+ display: flex;
+ margin-top: 1em;
+ text-align: left;
+ color: #89898a;
+ }
+
+ .scopes-input label:first-child {
+ flex-basis: 40%;
}
- input[type="checkbox"] {
- width: auto;
+ .scopes {
+ display: flex;
+ flex-wrap: wrap;
+ text-align: left;
+ color: #b9b9ba;
+ }
+
+ .scope {
+ flex-basis: 100%;
+ display: flex;
+ height: 2em;
+ align-items: center;
+ }
+
+ [type="checkbox"] + label {
+ margin: 0.5em;
+ }
+
+ [type="checkbox"] {
+ display: none;
+ }
+
+ [type="checkbox"] + label:before {
+ display: inline-block;
+ color: white;
+ background-color: #121a24;
+ border: 4px solid #121a24;
+ box-sizing: border-box;
+ width: 1.2em;
+ height: 1.2em;
+ margin-right: 1.0em;
+ content: "";
+ transition-property: background-color;
+ transition-duration: 0.35s;
+ color: #121a24;
+ margin-bottom: -0.2em;
+ border-radius: 2px;
+ }
+
+ [type="checkbox"]:checked + label:before {
+ background-color: #d8a070;
+ }
+
+ input:focus {
+ outline: none;
+ border-bottom: 2px solid #d8a070;
}
button {
box-sizing: border-box;
width: 100%;
- color: white;
- background-color: #419bdd;
+ background-color: #1c2a3a;
+ color: #b9b9ba;
border-radius: 4px;
border: none;
padding: 10px;
margin-top: 30px;
text-transform: uppercase;
- font-weight: 500;
font-size: 16px;
+ box-shadow: 0px 0px 2px 0px black,
+ 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset,
+ 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
+ }
+
+ button:hover {
+ cursor: pointer;
+ box-shadow: 0px 0px 0px 1px #d8a070,
+ 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset,
+ 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
}
.alert-danger {
box-sizing: border-box;
width: 100%;
- color: #D8000C;
- background-color: #FFD2D2;
+ background-color: #931014;
border-radius: 4px;
border: none;
padding: 10px;
@@ -88,20 +158,32 @@
.alert-info {
box-sizing: border-box;
width: 100%;
- color: #00529B;
- background-color: #BDE5F8;
border-radius: 4px;
- border: none;
+ border: 1px solid #7d796a;
padding: 10px;
margin-top: 20px;
font-weight: 500;
font-size: 16px;
}
+
+ @media all and (max-width: 440px) {
+ .container {
+ margin-top: 0
+ }
+
+ .scopes-input {
+ flex-direction: column;
+ }
+
+ .scope {
+ flex-basis: 50%;
+ }
+ }
</style>
</head>
<body>
<div class="container">
- <h1>Pleroma</h1>
+ <h1><%= Application.get_env(:pleroma, :instance)[:name] %></h1>
<%= render @view_module, @view_template, assigns %>
</div>
</body>
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
index f50599bdb..161333847 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
@@ -6,23 +6,26 @@
<% end %>
<h2>OAuth Authorization</h2>
<%= form_for @conn, o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %>
-<%= label f, :name, "Name or email" %>
-<%= text_input f, :name %>
-<br>
-<br>
-<%= label f, :password, "Password" %>
-<%= password_input f, :password %>
-<br>
-<br>
-
+<div class="input">
+ <%= label f, :name, "Name or email" %>
+ <%= text_input f, :name %>
+</div>
+<div class="input">
+ <%= label f, :password, "Password" %>
+ <%= password_input f, :password %>
+</div>
+<div class="scopes-input">
<%= label f, :scope, "Permissions" %>
-<br>
-<%= for scope <- @available_scopes do %>
- <%# Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %>
- <%= checkbox f, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %>
- <%= label f, :"scope_#{scope}", String.capitalize(scope) %>
- <br>
-<% end %>
+ <div class="scopes">
+ <%= for scope <- @available_scopes do %>
+ <%# Note: using hidden input with `unchecked_value` in order to distinguish user's empty selection from `scope` param being omitted %>
+ <div class="scope">
+ <%= checkbox f, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %>
+ <%= label f, :"scope_#{scope}", String.capitalize(scope) %>
+ </div>
+ <% end %>
+ </div>
+</div>
<%= hidden_input f, :client_id, value: @client_id %>
<%= hidden_input f, :response_type, value: @response_type %>
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index e2fdedb25..e817f0d79 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -9,18 +9,19 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
alias Comeonin.Pbkdf2
alias Pleroma.Emoji
+ alias Pleroma.Notification
alias Pleroma.PasswordResetToken
- alias Pleroma.User
alias Pleroma.Repo
+ alias Pleroma.User
alias Pleroma.Web
+ alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.OStatus
alias Pleroma.Web.WebFinger
- alias Pleroma.Web.ActivityPub.ActivityPub
def show_password_reset(conn, %{"token" => token}) do
with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
- %User{} = user <- Repo.get(User, token.user_id) do
+ %User{} = user <- User.get_by_id(token.user_id) do
render(conn, "password_reset.html", %{
token: token,
user: user
@@ -95,13 +96,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
def do_remote_follow(conn, %{
"authorization" => %{"name" => username, "password" => password, "id" => id}
}) do
- followee = Repo.get(User, id)
+ followee = User.get_by_id(id)
avatar = User.avatar_url(followee)
name = followee.nickname
with %User{} = user <- User.get_cached_by_nickname(username),
true <- Pbkdf2.checkpw(password, user.password_hash),
- %User{} = _followed <- Repo.get(User, id),
+ %User{} = _followed <- User.get_by_id(id),
{:ok, follower} <- User.follow(user, followee),
{:ok, _activity} <- ActivityPub.follow(follower, followee) do
conn
@@ -123,7 +124,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
- with %User{} = followee <- Repo.get(User, id),
+ with %User{} = followee <- User.get_by_id(id),
{:ok, follower} <- User.follow(user, followee),
{:ok, _activity} <- ActivityPub.follow(follower, followee) do
conn
@@ -142,6 +143,17 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
end
+ def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
+ with {:ok, _} <- Notification.read_one(user, notification_id) do
+ json(conn, %{status: "success"})
+ else
+ {:error, message} ->
+ conn
+ |> put_resp_content_type("application/json")
+ |> send_resp(403, Jason.encode!(%{"error" => message}))
+ end
+ end
+
def config(conn, _params) do
instance = Pleroma.Config.get(:instance)
instance_fe = Pleroma.Config.get(:fe)
@@ -185,7 +197,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
vapidPublicKey: vapid_public_key,
accountActivationRequired:
if(Keyword.get(instance, :account_activation_required, false), do: "1", else: "0"),
- invitesEnabled: if(Keyword.get(instance, :invites_enabled, false), do: "1", else: "0")
+ invitesEnabled: if(Keyword.get(instance, :invites_enabled, false), do: "1", else: "0"),
+ safeDMMentionsEnabled:
+ if(Pleroma.Config.get([:instance, :safe_dm_mentions]), do: "1", else: "0")
}
pleroma_fe =
diff --git a/lib/pleroma/web/twitter_api/representers/activity_representer.ex b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
deleted file mode 100644
index 55c612ddd..000000000
--- a/lib/pleroma/web/twitter_api/representers/activity_representer.ex
+++ /dev/null
@@ -1,15 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-# FIXME: Remove this module?
-# THIS MODULE IS DEPRECATED! DON'T USE IT!
-# USE THE Pleroma.Web.TwitterAPI.Views.ActivityView MODULE!
-defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
- def to_map(activity, opts) do
- Pleroma.Web.TwitterAPI.ActivityView.render(
- "activity.json",
- Map.put(opts, :activity, activity)
- )
- end
-end
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index dcb15b9a9..d0e58e71b 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -3,16 +3,15 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
- alias Pleroma.UserInviteToken
- alias Pleroma.User
alias Pleroma.Activity
+ alias Pleroma.Mailer
alias Pleroma.Repo
- alias Pleroma.Object
+ alias Pleroma.User
alias Pleroma.UserEmail
- alias Pleroma.Mailer
+ alias Pleroma.UserInviteToken
alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.TwitterAPI.UserView
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.TwitterAPI.UserView
import Ecto.Query
@@ -21,7 +20,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end
def delete(%User{} = user, id) do
- with %Activity{data: %{"type" => _type}} <- Repo.get(Activity, id),
+ with %Activity{data: %{"type" => _type}} <- Activity.get_by_id(id),
{:ok, activity} <- CommonAPI.delete(id, user) do
{:ok, activity}
end
@@ -35,11 +34,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
def unfollow(%User{} = follower, params) do
with {:ok, %User{} = unfollowed} <- get_user(params),
- {:ok, follower, _follow_activity} <- User.unfollow(follower, unfollowed),
- {:ok, _activity} <- ActivityPub.unfollow(follower, unfollowed) do
+ {:ok, follower} <- CommonAPI.unfollow(follower, unfollowed) do
{:ok, follower, unfollowed}
- else
- err -> err
end
end
@@ -133,7 +129,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end
def register_user(params) do
- tokenString = params["token"]
+ token_string = params["token"]
params = %{
nickname: params["nickname"],
@@ -170,8 +166,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
# no need to query DB if registration is open
token =
- unless registrations_open || is_nil(tokenString) do
- Repo.get_by(UserInviteToken, %{token: tokenString})
+ unless registrations_open || is_nil(token_string) do
+ Repo.get_by(UserInviteToken, %{token: token_string})
end
cond do
@@ -285,35 +281,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
_activities = Repo.all(q)
end
- # DEPRECATED mostly, context objects are now created at insertion time.
- def context_to_conversation_id(context) do
- with %Object{id: id} <- Object.get_cached_by_ap_id(context) do
- id
- else
- _e ->
- changeset = Object.context_mapping(context)
-
- case Repo.insert(changeset) do
- {:ok, %{id: id}} ->
- id
-
- # This should be solved by an upsert, but it seems ecto
- # has problems accessing the constraint inside the jsonb.
- {:error, _} ->
- Object.get_cached_by_ap_id(context).id
- end
- end
- end
-
- def conversation_id_to_context(id) do
- with %Object{data: %{"id" => context}} <- Repo.get(Object, id) do
- context
- else
- _e ->
- {:error, "No such conversation"}
- end
- end
-
def get_external_profile(for_user, uri) do
with %User{} = user <- User.get_or_fetch(uri) do
{:ok, UserView.render("show.json", %{user: user, for: for_user})}
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 5e4ebb8e8..a7ec9949c 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -8,23 +8,21 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
alias Ecto.Changeset
- alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView, ActivityView, NotificationView, TokenView}
- alias Pleroma.Web.CommonAPI
- alias Pleroma.{Repo, Activity, Object, User, Notification}
- alias Pleroma.Web.OAuth.Token
+ alias Pleroma.Activity
+ alias Pleroma.Notification
+ alias Pleroma.Object
+ alias Pleroma.Repo
+ alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Visibility
- alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.CommonAPI.Utils
+ alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.TwitterAPI.ActivityView
alias Pleroma.Web.TwitterAPI.NotificationView
+ alias Pleroma.Web.TwitterAPI.TokenView
alias Pleroma.Web.TwitterAPI.TwitterAPI
alias Pleroma.Web.TwitterAPI.UserView
- alias Pleroma.Activity
- alias Pleroma.Object
- alias Pleroma.Notification
- alias Pleroma.Repo
- alias Pleroma.User
require Logger
@@ -272,7 +270,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with %Activity{} = activity <- Repo.get(Activity, id),
+ with %Activity{} = activity <- Activity.get_by_id(id),
true <- Visibility.visible_for_user?(activity, user) do
conn
|> put_view(ActivityView)
@@ -281,7 +279,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def fetch_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with context when is_binary(context) <- TwitterAPI.conversation_id_to_context(id),
+ with context when is_binary(context) <- Utils.conversation_id_to_context(id),
activities <-
ActivityPub.fetch_activities_for_context(context, %{
"blocking_user" => user,
@@ -344,7 +342,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def get_by_id_or_ap_id(id) do
- activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id)
+ activity = Activity.get_by_id(id) || Activity.get_create_by_object_ap_id(id)
if activity.data["type"] == "Create" do
activity
@@ -436,7 +434,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def confirm_email(conn, %{"user_id" => uid, "token" => token}) do
- with %User{} = user <- Repo.get(User, uid),
+ with %User{} = user <- User.get_by_id(uid),
true <- user.local,
true <- user.info.confirmation_pending,
true <- user.info.confirmation_token == token,
@@ -589,17 +587,8 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
def approve_friend_request(conn, %{"user_id" => uid} = _params) do
with followed <- conn.assigns[:user],
- %User{} = follower <- Repo.get(User, uid),
- {:ok, follower} <- User.maybe_follow(follower, followed),
- %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
- {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "accept"),
- {:ok, _activity} <-
- ActivityPub.accept(%{
- to: [follower.ap_id],
- actor: followed,
- object: follow_activity.data["id"],
- type: "Accept"
- }) do
+ %User{} = follower <- User.get_by_id(uid),
+ {:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
conn
|> put_view(UserView)
|> render("show.json", %{user: follower, for: followed})
@@ -610,16 +599,8 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
def deny_friend_request(conn, %{"user_id" => uid} = _params) do
with followed <- conn.assigns[:user],
- %User{} = follower <- Repo.get(User, uid),
- %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
- {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "reject"),
- {:ok, _activity} <-
- ActivityPub.reject(%{
- to: [follower.ap_id],
- actor: followed,
- object: follow_activity.data["id"],
- type: "Reject"
- }) do
+ %User{} = follower <- User.get_by_id(uid),
+ {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
conn
|> put_view(UserView)
|> render("show.json", %{user: follower, for: followed})
diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex
index 02ca4ee42..aa1d41fa2 100644
--- a/lib/pleroma/web/twitter_api/views/activity_view.ex
+++ b/lib/pleroma/web/twitter_api/views/activity_view.ex
@@ -14,9 +14,8 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.TwitterAPI.ActivityView
- alias Pleroma.Web.TwitterAPI.TwitterAPI
- alias Pleroma.Web.TwitterAPI.UserView
alias Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter
+ alias Pleroma.Web.TwitterAPI.UserView
import Ecto.Query
require Logger
@@ -78,7 +77,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
defp get_context_id(%{data: %{"context" => context}}, options) do
cond do
id = options[:context_ids][context] -> id
- true -> TwitterAPI.context_to_conversation_id(context)
+ true -> Utils.context_to_conversation_id(context)
end
end
@@ -267,6 +266,8 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
content
|> String.replace(~r/<br\s?\/?>/, "\n")
|> HTML.get_cached_stripped_html_for_object(activity, __MODULE__)
+ else
+ ""
end
reply_parent = Activity.get_in_reply_to_activity(activity)
diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex
index 5ea5ae48e..32c3455f5 100644
--- a/lib/pleroma/web/web_finger/web_finger.ex
+++ b/lib/pleroma/web/web_finger/web_finger.ex
@@ -6,11 +6,11 @@ defmodule Pleroma.Web.WebFinger do
@httpoison Application.get_env(:pleroma, :httpoison)
alias Pleroma.User
- alias Pleroma.XmlBuilder
alias Pleroma.Web
- alias Pleroma.Web.XML
- alias Pleroma.Web.Salmon
alias Pleroma.Web.OStatus
+ alias Pleroma.Web.Salmon
+ alias Pleroma.Web.XML
+ alias Pleroma.XmlBuilder
require Jason
require Logger
diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex
index c00ec0858..3ffa6b416 100644
--- a/lib/pleroma/web/websub/websub.ex
+++ b/lib/pleroma/web/websub/websub.ex
@@ -6,14 +6,14 @@ defmodule Pleroma.Web.Websub do
alias Ecto.Changeset
alias Pleroma.Instances
alias Pleroma.Repo
- alias Pleroma.Web.Websub.WebsubServerSubscription
- alias Pleroma.Web.Websub.WebsubClientSubscription
- alias Pleroma.Web.OStatus.FeedRepresenter
- alias Pleroma.Web.XML
alias Pleroma.Web.Endpoint
+ alias Pleroma.Web.Federator
alias Pleroma.Web.OStatus
+ alias Pleroma.Web.OStatus.FeedRepresenter
alias Pleroma.Web.Router.Helpers
- alias Pleroma.Web.Federator
+ alias Pleroma.Web.Websub.WebsubClientSubscription
+ alias Pleroma.Web.Websub.WebsubServerSubscription
+ alias Pleroma.Web.XML
require Logger
import Ecto.Query
@@ -200,8 +200,8 @@ defmodule Pleroma.Web.Websub do
uri when not is_nil(uri) <- XML.string_from_xpath("/feed/author[1]/uri", doc),
hub when not is_nil(hub) <- XML.string_from_xpath(~S{/feed/link[@rel="hub"]/@href}, doc) do
name = XML.string_from_xpath("/feed/author[1]/name", doc)
- preferredUsername = XML.string_from_xpath("/feed/author[1]/poco:preferredUsername", doc)
- displayName = XML.string_from_xpath("/feed/author[1]/poco:displayName", doc)
+ preferred_username = XML.string_from_xpath("/feed/author[1]/poco:preferredUsername", doc)
+ display_name = XML.string_from_xpath("/feed/author[1]/poco:displayName", doc)
avatar = OStatus.make_avatar_object(doc)
bio = XML.string_from_xpath("/feed/author[1]/summary", doc)
@@ -209,8 +209,8 @@ defmodule Pleroma.Web.Websub do
%{
"uri" => uri,
"hub" => hub,
- "nickname" => preferredUsername || name,
- "name" => displayName || name,
+ "nickname" => preferred_username || name,
+ "name" => display_name || name,
"host" => URI.parse(uri).host,
"avatar" => avatar,
"bio" => bio
diff --git a/lib/pleroma/web/websub/websub_client_subscription.ex b/lib/pleroma/web/websub/websub_client_subscription.ex
index 969ee0684..77703c496 100644
--- a/lib/pleroma/web/websub/websub_client_subscription.ex
+++ b/lib/pleroma/web/websub/websub_client_subscription.ex
@@ -9,7 +9,7 @@ defmodule Pleroma.Web.Websub.WebsubClientSubscription do
schema "websub_client_subscriptions" do
field(:topic, :string)
field(:secret, :string)
- field(:valid_until, :naive_datetime)
+ field(:valid_until, :naive_datetime_usec)
field(:state, :string)
field(:subscribers, {:array, :string}, default: [])
field(:hub, :string)
diff --git a/lib/pleroma/web/websub/websub_controller.ex b/lib/pleroma/web/websub/websub_controller.ex
index ad40f1b94..9e8b48b80 100644
--- a/lib/pleroma/web/websub/websub_controller.ex
+++ b/lib/pleroma/web/websub/websub_controller.ex
@@ -7,8 +7,8 @@ defmodule Pleroma.Web.Websub.WebsubController do
alias Pleroma.Repo
alias Pleroma.User
- alias Pleroma.Web.Websub
alias Pleroma.Web.Federator
+ alias Pleroma.Web.Websub
alias Pleroma.Web.Websub.WebsubClientSubscription
require Logger