aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/pleroma/application.ex1
-rw-r--r--lib/pleroma/conversation/participation.ex10
-rw-r--r--lib/pleroma/object.ex88
-rw-r--r--lib/pleroma/plugs/oauth_scopes_plug.ex9
-rw-r--r--lib/pleroma/plugs/user_is_admin_plug.ex1
-rw-r--r--lib/pleroma/repo.ex35
-rw-r--r--lib/pleroma/uploaders/local.ex13
-rw-r--r--lib/pleroma/uploaders/mdii.ex37
-rw-r--r--lib/pleroma/uploaders/s3.ex14
-rw-r--r--lib/pleroma/uploaders/uploader.ex3
-rw-r--r--lib/pleroma/user.ex76
-rw-r--r--lib/pleroma/web/activity_pub/publisher.ex4
-rw-r--r--lib/pleroma/web/activity_pub/relay.ex4
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex18
-rw-r--r--lib/pleroma/web/admin_api/admin_api_controller.ex23
-rw-r--r--lib/pleroma/web/masto_fe_controller.ex25
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/notification_controller.ex17
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex14
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api.ex8
-rw-r--r--lib/pleroma/web/metadata/utils.ex2
-rw-r--r--lib/pleroma/web/oauth/oauth_controller.ex10
-rw-r--r--lib/pleroma/web/oauth/scopes.ex24
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex2
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex9
-rw-r--r--lib/pleroma/web/router.ex4
-rw-r--r--lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex11
-rw-r--r--lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex14
-rw-r--r--lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex (renamed from lib/pleroma/web/templates/twitter_api/util/followed.html.eex)0
-rw-r--r--lib/pleroma/web/templates/twitter_api/util/follow.html.eex11
-rw-r--r--lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex14
-rw-r--r--lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex112
-rw-r--r--lib/pleroma/web/twitter_api/controllers/util_controller.ex104
-rw-r--r--lib/pleroma/web/twitter_api/views/remote_follow_view.ex10
33 files changed, 460 insertions, 267 deletions
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index 2ae052069..e17068876 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -33,6 +33,7 @@ defmodule Pleroma.Application do
def start(_type, _args) do
Pleroma.HTML.compile_scrubbers()
Pleroma.Config.DeprecationWarnings.warn()
+ Pleroma.Repo.check_migrations_applied!()
setup_instrumenters()
load_custom_modules()
diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex
index aafe57280..e5d28ebff 100644
--- a/lib/pleroma/conversation/participation.ex
+++ b/lib/pleroma/conversation/participation.ex
@@ -64,11 +64,13 @@ defmodule Pleroma.Conversation.Participation do
end
def mark_as_read(participation) do
- participation
- |> read_cng(%{read: true})
- |> Repo.update()
+ __MODULE__
+ |> where(id: ^participation.id)
+ |> update(set: [read: true])
+ |> select([p], p)
+ |> Repo.update_all([])
|> case do
- {:ok, participation} ->
+ {1, [participation]} ->
participation = Repo.preload(participation, :user)
User.set_unread_conversation_count(participation.user)
{:ok, participation}
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index eb37b95a6..2452a7389 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -17,6 +17,8 @@ defmodule Pleroma.Object do
require Logger
+ @type t() :: %__MODULE__{}
+
schema "objects" do
field(:data, :map)
@@ -79,6 +81,20 @@ defmodule Pleroma.Object do
Repo.one(from(object in Object, where: fragment("(?)->>'id' = ?", object.data, ^ap_id)))
end
+ @doc """
+ Get a single attachment by it's name and href
+ """
+ @spec get_attachment_by_name_and_href(String.t(), String.t()) :: Object.t() | nil
+ def get_attachment_by_name_and_href(name, href) do
+ query =
+ from(o in Object,
+ where: fragment("(?)->>'name' = ?", o.data, ^name),
+ where: fragment("(?)->>'href' = ?", o.data, ^href)
+ )
+
+ Repo.one(query)
+ end
+
defp warn_on_no_object_preloaded(ap_id) do
"Object.normalize() called without preloaded object (#{inspect(ap_id)}). Consider preloading the object"
|> Logger.debug()
@@ -164,6 +180,7 @@ defmodule Pleroma.Object do
def delete(%Object{data: %{"id" => id}} = object) do
with {:ok, _obj} = swap_object_with_tombstone(object),
+ :ok <- delete_attachments(object),
deleted_activity = Activity.delete_all_by_object_ap_id(id),
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
{:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do
@@ -171,6 +188,77 @@ defmodule Pleroma.Object do
end
end
+ defp delete_attachments(%{data: %{"attachment" => [_ | _] = attachments, "actor" => actor}}) do
+ hrefs =
+ Enum.flat_map(attachments, fn attachment ->
+ Enum.map(attachment["url"], & &1["href"])
+ end)
+
+ names = Enum.map(attachments, & &1["name"])
+
+ uploader = Pleroma.Config.get([Pleroma.Upload, :uploader])
+
+ # find all objects for copies of the attachments, name and actor doesn't matter here
+ delete_ids =
+ from(o in Object,
+ where:
+ fragment(
+ "to_jsonb(array(select jsonb_array_elements((?)#>'{url}') ->> 'href'))::jsonb \\?| (?)",
+ o.data,
+ ^hrefs
+ )
+ )
+ |> Repo.all()
+ # we should delete 1 object for any given attachment, but don't delete files if
+ # there are more than 1 object for it
+ |> Enum.reduce(%{}, fn %{
+ id: id,
+ data: %{
+ "url" => [%{"href" => href}],
+ "actor" => obj_actor,
+ "name" => name
+ }
+ },
+ acc ->
+ Map.update(acc, href, %{id: id, count: 1}, fn val ->
+ case obj_actor == actor and name in names do
+ true ->
+ # set id of the actor's object that will be deleted
+ %{val | id: id, count: val.count + 1}
+
+ false ->
+ # another actor's object, just increase count to not delete file
+ %{val | count: val.count + 1}
+ end
+ end)
+ end)
+ |> Enum.map(fn {href, %{id: id, count: count}} ->
+ # only delete files that have single instance
+ with 1 <- count do
+ prefix =
+ case Pleroma.Config.get([Pleroma.Upload, :base_url]) do
+ nil -> "media"
+ _ -> ""
+ end
+
+ base_url = Pleroma.Config.get([__MODULE__, :base_url], Pleroma.Web.base_url())
+
+ file_path = String.trim_leading(href, "#{base_url}/#{prefix}")
+
+ uploader.delete_file(file_path)
+ end
+
+ id
+ end)
+
+ from(o in Object, where: o.id in ^delete_ids)
+ |> Repo.delete_all()
+
+ :ok
+ end
+
+ defp delete_attachments(%{data: _data}), do: :ok
+
def prune(%Object{data: %{"id" => id}} = object) do
with {:ok, object} <- Repo.delete(object),
{:ok, true} <- Cachex.del(:object_cache, "object:#{id}"),
diff --git a/lib/pleroma/plugs/oauth_scopes_plug.ex b/lib/pleroma/plugs/oauth_scopes_plug.ex
index 174a8389c..07c0f7fdb 100644
--- a/lib/pleroma/plugs/oauth_scopes_plug.ex
+++ b/lib/pleroma/plugs/oauth_scopes_plug.ex
@@ -18,16 +18,13 @@ defmodule Pleroma.Plugs.OAuthScopesPlug do
token = assigns[:token]
scopes = transform_scopes(scopes, options)
- matched_scopes = token && filter_descendants(scopes, token.scopes)
+ matched_scopes = (token && filter_descendants(scopes, token.scopes)) || []
cond do
- is_nil(token) ->
- maybe_perform_instance_privacy_check(conn, options)
-
- op == :| && Enum.any?(matched_scopes) ->
+ token && op == :| && Enum.any?(matched_scopes) ->
conn
- op == :& && matched_scopes == scopes ->
+ token && op == :& && matched_scopes == scopes ->
conn
options[:fallback] == :proceed_unauthenticated ->
diff --git a/lib/pleroma/plugs/user_is_admin_plug.ex b/lib/pleroma/plugs/user_is_admin_plug.ex
index 582fb1f92..3190163d3 100644
--- a/lib/pleroma/plugs/user_is_admin_plug.ex
+++ b/lib/pleroma/plugs/user_is_admin_plug.ex
@@ -23,6 +23,7 @@ defmodule Pleroma.Plugs.UserIsAdminPlug do
token && OAuth.Scopes.contains_admin_scopes?(token.scopes) ->
# Note: checking for _any_ admin scope presence, not necessarily fitting requested action.
# Thus, controller must explicitly invoke OAuthScopesPlug to verify scope requirements.
+ # Admin might opt out of admin scope for some apps to block any admin actions from them.
conn
true ->
diff --git a/lib/pleroma/repo.ex b/lib/pleroma/repo.ex
index f57e088bc..cb0b6653c 100644
--- a/lib/pleroma/repo.ex
+++ b/lib/pleroma/repo.ex
@@ -8,6 +8,8 @@ defmodule Pleroma.Repo do
adapter: Ecto.Adapters.Postgres,
migration_timestamps: [type: :naive_datetime_usec]
+ require Logger
+
defmodule Instrumenter do
use Prometheus.EctoInstrumenter
end
@@ -47,4 +49,37 @@ defmodule Pleroma.Repo do
_ -> {:error, :not_found}
end
end
+
+ def check_migrations_applied!() do
+ unless Pleroma.Config.get(
+ [:i_am_aware_this_may_cause_data_loss, :disable_migration_check],
+ false
+ ) do
+ Ecto.Migrator.with_repo(__MODULE__, fn repo ->
+ down_migrations =
+ Ecto.Migrator.migrations(repo)
+ |> Enum.reject(fn
+ {:up, _, _} -> true
+ {:down, _, _} -> false
+ end)
+
+ if length(down_migrations) > 0 do
+ down_migrations_text =
+ Enum.map(down_migrations, fn {:down, id, name} -> "- #{name} (#{id})\n" end)
+
+ Logger.error(
+ "The following migrations were not applied:\n#{down_migrations_text}If you want to start Pleroma anyway, set\nconfig :pleroma, :i_am_aware_this_may_cause_data_loss, disable_migration_check: true"
+ )
+
+ raise Pleroma.Repo.UnappliedMigrationsError
+ end
+ end)
+ else
+ :ok
+ end
+ end
+end
+
+defmodule Pleroma.Repo.UnappliedMigrationsError do
+ defexception message: "Unapplied Migrations detected"
end
diff --git a/lib/pleroma/uploaders/local.ex b/lib/pleroma/uploaders/local.ex
index 36b3c35ec..2e6fe3292 100644
--- a/lib/pleroma/uploaders/local.ex
+++ b/lib/pleroma/uploaders/local.ex
@@ -5,10 +5,12 @@
defmodule Pleroma.Uploaders.Local do
@behaviour Pleroma.Uploaders.Uploader
+ @impl true
def get_file(_) do
{:ok, {:static_dir, upload_path()}}
end
+ @impl true
def put_file(upload) do
{local_path, file} =
case Enum.reverse(Path.split(upload.path)) do
@@ -33,4 +35,15 @@ defmodule Pleroma.Uploaders.Local do
def upload_path do
Pleroma.Config.get!([__MODULE__, :uploads])
end
+
+ @impl true
+ def delete_file(path) do
+ upload_path()
+ |> Path.join(path)
+ |> File.rm()
+ |> case do
+ :ok -> :ok
+ {:error, posix_error} -> {:error, to_string(posix_error)}
+ end
+ end
end
diff --git a/lib/pleroma/uploaders/mdii.ex b/lib/pleroma/uploaders/mdii.ex
deleted file mode 100644
index c36f3d61d..000000000
--- a/lib/pleroma/uploaders/mdii.ex
+++ /dev/null
@@ -1,37 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Uploaders.MDII do
- @moduledoc "Represents uploader for https://github.com/hakaba-hitoyo/minimal-digital-image-infrastructure"
-
- alias Pleroma.Config
- alias Pleroma.HTTP
-
- @behaviour Pleroma.Uploaders.Uploader
-
- # MDII-hosted images are never passed through the MediaPlug; only local media.
- # Delegate to Pleroma.Uploaders.Local
- def get_file(file) do
- Pleroma.Uploaders.Local.get_file(file)
- end
-
- def put_file(upload) do
- cgi = Config.get([Pleroma.Uploaders.MDII, :cgi])
- files = Config.get([Pleroma.Uploaders.MDII, :files])
-
- {:ok, file_data} = File.read(upload.tempfile)
-
- extension = String.split(upload.name, ".") |> List.last()
- query = "#{cgi}?#{extension}"
-
- with {:ok, %{status: 200, body: body}} <-
- HTTP.post(query, file_data, [], adapter: [pool: :default]) do
- remote_file_name = String.split(body) |> List.first()
- public_url = "#{files}/#{remote_file_name}.#{extension}"
- {:ok, {:url, public_url}}
- else
- _ -> Pleroma.Uploaders.Local.put_file(upload)
- end
- end
-end
diff --git a/lib/pleroma/uploaders/s3.ex b/lib/pleroma/uploaders/s3.ex
index 9876b6398..feb89cea6 100644
--- a/lib/pleroma/uploaders/s3.ex
+++ b/lib/pleroma/uploaders/s3.ex
@@ -10,6 +10,7 @@ defmodule Pleroma.Uploaders.S3 do
# The file name is re-encoded with S3's constraints here to comply with previous
# links with less strict filenames
+ @impl true
def get_file(file) do
config = Config.get([__MODULE__])
bucket = Keyword.fetch!(config, :bucket)
@@ -35,6 +36,7 @@ defmodule Pleroma.Uploaders.S3 do
])}}
end
+ @impl true
def put_file(%Pleroma.Upload{} = upload) do
config = Config.get([__MODULE__])
bucket = Keyword.get(config, :bucket)
@@ -69,6 +71,18 @@ defmodule Pleroma.Uploaders.S3 do
end
end
+ @impl true
+ def delete_file(file) do
+ [__MODULE__, :bucket]
+ |> Config.get()
+ |> ExAws.S3.delete_object(file)
+ |> ExAws.request()
+ |> case do
+ {:ok, %{status_code: 204}} -> :ok
+ error -> {:error, inspect(error)}
+ end
+ end
+
@regex Regex.compile!("[^0-9a-zA-Z!.*/'()_-]")
def strict_encode(name) do
String.replace(name, @regex, "-")
diff --git a/lib/pleroma/uploaders/uploader.ex b/lib/pleroma/uploaders/uploader.ex
index c0b22c28a..d71e213d2 100644
--- a/lib/pleroma/uploaders/uploader.ex
+++ b/lib/pleroma/uploaders/uploader.ex
@@ -36,6 +36,8 @@ defmodule Pleroma.Uploaders.Uploader do
@callback put_file(Pleroma.Upload.t()) ::
:ok | {:ok, file_spec()} | {:error, String.t()} | :wait_callback
+ @callback delete_file(file :: String.t()) :: :ok | {:error, String.t()}
+
@callback http_callback(Plug.Conn.t(), Map.t()) ::
{:ok, Plug.Conn.t()}
| {:ok, Plug.Conn.t(), file_spec()}
@@ -43,7 +45,6 @@ defmodule Pleroma.Uploaders.Uploader do
@optional_callbacks http_callback: 2
@spec put_file(module(), Pleroma.Upload.t()) :: {:ok, file_spec()} | {:error, String.t()}
-
def put_file(uploader, upload) do
case uploader.put_file(upload) do
:ok -> {:ok, {:file, upload.path}}
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 706aee2ff..430f04ae9 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -1430,20 +1430,47 @@ defmodule Pleroma.User do
Creates an internal service actor by URI if missing.
Optionally takes nickname for addressing.
"""
- def get_or_create_service_actor_by_ap_id(uri, nickname \\ nil) do
- with user when is_nil(user) <- get_cached_by_ap_id(uri) do
- {:ok, user} =
- %User{
- invisible: true,
- local: true,
- ap_id: uri,
- nickname: nickname,
- follower_address: uri <> "/followers"
- }
- |> Repo.insert()
+ @spec get_or_create_service_actor_by_ap_id(String.t(), String.t()) :: User.t() | nil
+ def get_or_create_service_actor_by_ap_id(uri, nickname) do
+ {_, user} =
+ case get_cached_by_ap_id(uri) do
+ nil ->
+ with {:error, %{errors: errors}} <- create_service_actor(uri, nickname) do
+ Logger.error("Cannot create service actor: #{uri}/.\n#{inspect(errors)}")
+ {:error, nil}
+ end
- user
- end
+ %User{invisible: false} = user ->
+ set_invisible(user)
+
+ user ->
+ {:ok, user}
+ end
+
+ user
+ end
+
+ @spec set_invisible(User.t()) :: {:ok, User.t()}
+ defp set_invisible(user) do
+ user
+ |> change(%{invisible: true})
+ |> update_and_set_cache()
+ end
+
+ @spec create_service_actor(String.t(), String.t()) ::
+ {:ok, User.t()} | {:error, Ecto.Changeset.t()}
+ defp create_service_actor(uri, nickname) do
+ %User{
+ invisible: true,
+ local: true,
+ ap_id: uri,
+ nickname: nickname,
+ follower_address: uri <> "/followers"
+ }
+ |> change
+ |> unique_constraint(:nickname)
+ |> Repo.insert()
+ |> set_cache()
end
# AP style
@@ -1847,22 +1874,13 @@ defmodule Pleroma.User do
end
def admin_api_update(user, params) do
- changeset =
- cast(user, params, [
- :is_moderator,
- :is_admin,
- :show_role
- ])
-
- with {:ok, updated_user} <- update_and_set_cache(changeset) do
- if user.is_admin && !updated_user.is_admin do
- # Tokens & authorizations containing any admin scopes must be revoked (revoking all).
- # This is an extra safety measure (tokens' admin scopes won't be accepted for non-admins).
- global_sign_out(user)
- end
-
- {:ok, updated_user}
- end
+ user
+ |> cast(params, [
+ :is_moderator,
+ :is_admin,
+ :show_role
+ ])
+ |> update_and_set_cache()
end
@doc "Signs user out of all applications"
diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex
index db072bad2..e4e3ab44a 100644
--- a/lib/pleroma/web/activity_pub/publisher.ex
+++ b/lib/pleroma/web/activity_pub/publisher.ex
@@ -264,6 +264,10 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
"rel" => "self",
"type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"",
"href" => user.ap_id
+ },
+ %{
+ "rel" => "http://ostatus.org/schema/1.0/subscribe",
+ "template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}"
}
]
end
diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex
index 99a804568..48a1b71e0 100644
--- a/lib/pleroma/web/activity_pub/relay.ex
+++ b/lib/pleroma/web/activity_pub/relay.ex
@@ -9,10 +9,12 @@ defmodule Pleroma.Web.ActivityPub.Relay do
alias Pleroma.Web.ActivityPub.ActivityPub
require Logger
+ @relay_nickname "relay"
+
def get_actor do
actor =
relay_ap_id()
- |> User.get_or_create_service_actor_by_ap_id()
+ |> User.get_or_create_service_actor_by_ap_id(@relay_nickname)
actor
end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 3fa789d53..2b8bfc3bd 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -658,24 +658,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
- locked = new_user_data[:locked] || false
- attachment = get_in(new_user_data, [:source_data, "attachment"]) || []
- invisible = new_user_data[:invisible] || false
-
- fields =
- attachment
- |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
- |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
-
- update_data =
- new_user_data
- |> Map.take([:avatar, :banner, :bio, :name, :also_known_as])
- |> Map.put(:fields, fields)
- |> Map.put(:locked, locked)
- |> Map.put(:invisible, invisible)
-
actor
- |> User.upgrade_changeset(update_data, true)
+ |> User.upgrade_changeset(new_user_data, true)
|> User.update_and_set_cache()
ActivityPub.update(%{
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index ddae139c6..c9d7ab867 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -32,19 +32,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
plug(
OAuthScopesPlug,
%{scopes: ["read:accounts"], admin: true}
- when action in [:list_users, :user_show, :right_get, :invites]
+ when action in [:list_users, :user_show, :right_get]
)
plug(
OAuthScopesPlug,
%{scopes: ["write:accounts"], admin: true}
when action in [
- :get_invite_token,
- :revoke_invite,
- :email_invite,
:get_password_reset,
- :user_follow,
- :user_unfollow,
:user_delete,
:users_create,
:user_toggle_activation,
@@ -57,6 +52,20 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
]
)
+ plug(OAuthScopesPlug, %{scopes: ["read:invites"], admin: true} when action == :invites)
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["write:invites"], admin: true}
+ when action in [:create_invite_token, :revoke_invite, :email_invite]
+ )
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["write:follows"], admin: true}
+ when action in [:user_follow, :user_unfollow, :relay_follow, :relay_unfollow]
+ )
+
plug(
OAuthScopesPlug,
%{scopes: ["read:reports"], admin: true}
@@ -90,7 +99,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
plug(
OAuthScopesPlug,
%{scopes: ["write"], admin: true}
- when action in [:relay_follow, :relay_unfollow, :config_update]
+ when action == :config_update
)
@users_page_size 50
diff --git a/lib/pleroma/web/masto_fe_controller.ex b/lib/pleroma/web/masto_fe_controller.ex
index ca261ad6e..9f7e4943c 100644
--- a/lib/pleroma/web/masto_fe_controller.ex
+++ b/lib/pleroma/web/masto_fe_controller.ex
@@ -20,18 +20,21 @@ defmodule Pleroma.Web.MastoFEController do
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug when action != :index)
@doc "GET /web/*path"
- def index(%{assigns: %{user: user}} = conn, _params) do
- token = get_session(conn, :oauth_token)
+ def index(%{assigns: %{user: user, token: token}} = conn, _params)
+ when not is_nil(user) and not is_nil(token) do
+ conn
+ |> put_layout(false)
+ |> render("index.html",
+ token: token.token,
+ user: user,
+ custom_emojis: Pleroma.Emoji.get_all()
+ )
+ end
- if user && token do
- conn
- |> put_layout(false)
- |> render("index.html", token: token, user: user, custom_emojis: Pleroma.Emoji.get_all())
- else
- conn
- |> put_session(:return_to, conn.request_path)
- |> redirect(to: "/web/login")
- end
+ def index(conn, _params) do
+ conn
+ |> put_session(:return_to, conn.request_path)
+ |> redirect(to: "/web/login")
end
@doc "GET /web/manifest.json"
diff --git a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
index 16759be6a..f2508aca4 100644
--- a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
@@ -23,6 +23,23 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
# GET /api/v1/notifications
+ def index(conn, %{"account_id" => account_id} = params) do
+ case Pleroma.User.get_cached_by_id(account_id) do
+ %{ap_id: account_ap_id} ->
+ params =
+ params
+ |> Map.delete("account_id")
+ |> Map.put("account_ap_id", account_ap_id)
+
+ index(conn, params)
+
+ _ ->
+ conn
+ |> put_status(:not_found)
+ |> json(%{"error" => "Account is not found"})
+ end
+ end
+
def index(%{assigns: %{user: user}} = conn, params) do
notifications = MastodonAPI.get_notifications(user, params)
diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
index 384159336..29964a1d4 100644
--- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
@@ -77,10 +77,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> render("index.json", activities: activities, for: user, as: :activity)
end
- # GET /api/v1/timelines/tag/:tag
- def hashtag(%{assigns: %{user: user}} = conn, params) do
- local_only = truthy_param?(params["local"])
-
+ def hashtag_fetching(params, user, local_only) do
tags =
[params["tag"], params["any"]]
|> List.flatten()
@@ -98,7 +95,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> Map.get("none", [])
|> Enum.map(&String.downcase(&1))
- activities =
+ _activities =
params
|> Map.put("type", "Create")
|> Map.put("local_only", local_only)
@@ -109,6 +106,13 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> Map.put("tag_all", tag_all)
|> Map.put("tag_reject", tag_reject)
|> ActivityPub.fetch_public_activities()
+ end
+
+ # GET /api/v1/timelines/tag/:tag
+ def hashtag(%{assigns: %{user: user}} = conn, params) do
+ local_only = truthy_param?(params["local"])
+
+ activities = hashtag_fetching(params, user, local_only)
conn
|> add_link_headers(activities, %{"local" => local_only})
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex
index b1816370e..390a2b190 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex
@@ -56,6 +56,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
user
|> Notification.for_user_query(options)
|> restrict(:exclude_types, options)
+ |> restrict(:account_ap_id, options)
|> Pagination.fetch_paginated(params)
end
@@ -71,7 +72,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
exclude_visibilities: {:array, :string},
reblogs: :boolean,
with_muted: :boolean,
- with_move: :boolean
+ with_move: :boolean,
+ account_ap_id: :string
}
changeset = cast({%{}, param_types}, params, Map.keys(param_types))
@@ -88,5 +90,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
|> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data))
end
+ defp restrict(query, :account_ap_id, %{account_ap_id: account_ap_id}) do
+ where(query, [n, a], a.actor == ^account_ap_id)
+ end
+
defp restrict(query, _, _), do: query
end
diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex
index 382ecf426..589d11901 100644
--- a/lib/pleroma/web/metadata/utils.ex
+++ b/lib/pleroma/web/metadata/utils.ex
@@ -15,6 +15,7 @@ defmodule Pleroma.Web.Metadata.Utils do
|> String.replace(~r/<br\s?\/?>/, " ")
|> HTML.get_cached_stripped_html_for_activity(object, "metadata")
|> Emoji.Formatter.demojify()
+ |> HtmlEntities.decode()
|> Formatter.truncate()
end
@@ -25,6 +26,7 @@ defmodule Pleroma.Web.Metadata.Utils do
|> String.replace(~r/<br\s?\/?>/, " ")
|> HTML.strip_tags()
|> Emoji.Formatter.demojify()
+ |> HtmlEntities.decode()
|> Formatter.truncate(max_length)
end
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 87acdec97..d31a3d91c 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -222,7 +222,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
{:user_active, true} <- {:user_active, !user.deactivated},
{:password_reset_pending, false} <-
{:password_reset_pending, user.password_reset_pending},
- {:ok, scopes} <- validate_scopes(app, params, user),
+ {:ok, scopes} <- validate_scopes(app, params),
{:ok, auth} <- Authorization.create_authorization(app, user, scopes),
{:ok, token} <- Token.exchange_token(app, auth) do
json(conn, Token.Response.build(user, token))
@@ -471,7 +471,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
{:get_user, (user && {:ok, user}) || Authenticator.get_user(conn)},
%App{} = app <- Repo.get_by(App, client_id: client_id),
true <- redirect_uri in String.split(app.redirect_uris),
- {:ok, scopes} <- validate_scopes(app, auth_attrs, user),
+ {:ok, scopes} <- validate_scopes(app, auth_attrs),
{:auth_active, true} <- {:auth_active, User.auth_active?(user)} do
Authorization.create_authorization(app, user, scopes)
end
@@ -487,12 +487,12 @@ defmodule Pleroma.Web.OAuth.OAuthController do
defp put_session_registration_id(%Plug.Conn{} = conn, registration_id),
do: put_session(conn, :registration_id, registration_id)
- @spec validate_scopes(App.t(), map(), User.t()) ::
+ @spec validate_scopes(App.t(), map()) ::
{:ok, list()} | {:error, :missing_scopes | :unsupported_scopes}
- defp validate_scopes(%App{} = app, params, %User{} = user) do
+ defp validate_scopes(%App{} = app, params) do
params
|> Scopes.fetch_scopes(app.scopes)
- |> Scopes.validate(app.scopes, user)
+ |> Scopes.validate(app.scopes)
end
def default_redirect_uri(%App{} = app) do
diff --git a/lib/pleroma/web/oauth/scopes.ex b/lib/pleroma/web/oauth/scopes.ex
index 00da225b9..151467494 100644
--- a/lib/pleroma/web/oauth/scopes.ex
+++ b/lib/pleroma/web/oauth/scopes.ex
@@ -8,7 +8,6 @@ defmodule Pleroma.Web.OAuth.Scopes do
"""
alias Pleroma.Plugs.OAuthScopesPlug
- alias Pleroma.User
@doc """
Fetch scopes from request params.
@@ -56,35 +55,18 @@ defmodule Pleroma.Web.OAuth.Scopes do
@doc """
Validates scopes.
"""
- @spec validate(list() | nil, list(), User.t()) ::
+ @spec validate(list() | nil, list()) ::
{:ok, list()} | {:error, :missing_scopes | :unsupported_scopes}
- def validate(blank_scopes, _app_scopes, _user) when blank_scopes in [nil, []],
+ def validate(blank_scopes, _app_scopes) when blank_scopes in [nil, []],
do: {:error, :missing_scopes}
- def validate(scopes, app_scopes, %User{} = user) do
- with {:ok, _} <- ensure_scopes_support(scopes, app_scopes),
- {:ok, scopes} <- authorize_admin_scopes(scopes, app_scopes, user) do
- {:ok, scopes}
- end
- end
-
- defp ensure_scopes_support(scopes, app_scopes) do
+ def validate(scopes, app_scopes) do
case OAuthScopesPlug.filter_descendants(scopes, app_scopes) do
^scopes -> {:ok, scopes}
_ -> {:error, :unsupported_scopes}
end
end
- defp authorize_admin_scopes(scopes, app_scopes, %User{} = user) do
- if user.is_admin || !contains_admin_scopes?(scopes) || !contains_admin_scopes?(app_scopes) do
- {:ok, scopes}
- else
- # Gracefully dropping admin scopes from requested scopes if user isn't an admin (not raising)
- scopes = scopes -- OAuthScopesPlug.filter_descendants(scopes, ["admin"])
- validate(scopes, app_scopes, user)
- end
- end
-
def contains_admin_scopes?(scopes) do
scopes
|> OAuthScopesPlug.filter_descendants(["admin"])
diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex
index 69dfa92e3..0bbf84fd3 100644
--- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex
@@ -52,7 +52,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do
@doc """
Lists the packs available on the instance as JSON.
- The information is public and does not require authentification. The format is
+ The information is public and does not require authentication. The format is
a map of "pack directory name" to pack.json contents.
"""
def list_packs(conn, _params) do
diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
index 8fed3f5bb..772c535a4 100644
--- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
@@ -22,7 +22,14 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
plug(
OAuthScopesPlug,
- %{scopes: ["read:statuses"]} when action in [:conversation, :conversation_statuses]
+ %{scopes: ["read:statuses"]}
+ when action in [:conversation, :conversation_statuses, :emoji_reactions_by]
+ )
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["write:statuses"]}
+ when action in [:react_with_emoji, :unreact_with_emoji]
)
plug(
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index f6c128283..9654ab8a3 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -229,9 +229,9 @@ defmodule Pleroma.Web.Router do
pipe_through(:pleroma_html)
post("/main/ostatus", UtilController, :remote_subscribe)
- get("/ostatus_subscribe", UtilController, :remote_follow)
+ get("/ostatus_subscribe", RemoteFollowController, :follow)
- post("/ostatus_subscribe", UtilController, :do_remote_follow)
+ post("/ostatus_subscribe", RemoteFollowController, :do_follow)
end
scope "/api/pleroma", Pleroma.Web.TwitterAPI do
diff --git a/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex
new file mode 100644
index 000000000..5ba192cd7
--- /dev/null
+++ b/lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex
@@ -0,0 +1,11 @@
+<%= if @error == :error do %>
+ <h2>Error fetching user</h2>
+<% else %>
+ <h2>Remote follow</h2>
+ <img height="128" width="128" src="<%= avatar_url(@followee) %>">
+ <p><%= @followee.nickname %></p>
+ <%= form_for @conn, remote_follow_path(@conn, :do_follow), [as: "user"], fn f -> %>
+ <%= hidden_input f, :id, value: @followee.id %>
+ <%= submit "Authorize" %>
+ <% end %>
+<% end %>
diff --git a/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex
new file mode 100644
index 000000000..df44988ee
--- /dev/null
+++ b/lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex
@@ -0,0 +1,14 @@
+<%= if @error do %>
+<h2><%= @error %></h2>
+<% end %>
+<h2>Log in to follow</h2>
+<p><%= @followee.nickname %></p>
+<img height="128" width="128" src="<%= avatar_url(@followee) %>">
+<%= form_for @conn, remote_follow_path(@conn, :do_follow), [as: "authorization"], fn f -> %>
+<%= text_input f, :name, placeholder: "Username", required: true %>
+<br>
+<%= password_input f, :password, placeholder: "Password", required: true %>
+<br>
+<%= hidden_input f, :id, value: @followee.id %>
+<%= submit "Authorize" %>
+<% end %>
diff --git a/lib/pleroma/web/templates/twitter_api/util/followed.html.eex b/lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex
index da473d502..da473d502 100644
--- a/lib/pleroma/web/templates/twitter_api/util/followed.html.eex
+++ b/lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex
diff --git a/lib/pleroma/web/templates/twitter_api/util/follow.html.eex b/lib/pleroma/web/templates/twitter_api/util/follow.html.eex
deleted file mode 100644
index 06359fa6c..000000000
--- a/lib/pleroma/web/templates/twitter_api/util/follow.html.eex
+++ /dev/null
@@ -1,11 +0,0 @@
-<%= if @error == :error do %>
- <h2>Error fetching user</h2>
-<% else %>
- <h2>Remote follow</h2>
- <img width="128" height="128" src="<%= @avatar %>">
- <p><%= @name %></p>
- <%= form_for @conn, util_path(@conn, :do_remote_follow), [as: "user"], fn f -> %>
- <%= hidden_input f, :id, value: @id %>
- <%= submit "Authorize" %>
- <% end %>
-<% end %>
diff --git a/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex b/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex
deleted file mode 100644
index 4e3a2be67..000000000
--- a/lib/pleroma/web/templates/twitter_api/util/follow_login.html.eex
+++ /dev/null
@@ -1,14 +0,0 @@
-<%= if @error do %>
- <h2><%= @error %></h2>
-<% end %>
-<h2>Log in to follow</h2>
-<p><%= @name %></p>
-<img height="128" width="128" src="<%= @avatar %>">
-<%= form_for @conn, util_path(@conn, :do_remote_follow), [as: "authorization"], fn f -> %>
-<%= text_input f, :name, placeholder: "Username" %>
-<br>
-<%= password_input f, :password, placeholder: "Password" %>
-<br>
-<%= hidden_input f, :id, value: @id %>
-<%= submit "Authorize" %>
-<% end %>
diff --git a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex
new file mode 100644
index 000000000..e0d4d5632
--- /dev/null
+++ b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex
@@ -0,0 +1,112 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do
+ use Pleroma.Web, :controller
+
+ require Logger
+
+ alias Pleroma.Activity
+ alias Pleroma.Object.Fetcher
+ alias Pleroma.Plugs.OAuthScopesPlug
+ alias Pleroma.User
+ alias Pleroma.Web.Auth.Authenticator
+ alias Pleroma.Web.CommonAPI
+
+ @status_types ["Article", "Event", "Note", "Video", "Page", "Question"]
+
+ # Note: follower can submit the form (with password auth) not being signed in (having no token)
+ plug(
+ OAuthScopesPlug,
+ %{fallback: :proceed_unauthenticated, scopes: ["follow", "write:follows"]}
+ when action in [:do_follow]
+ )
+
+ # GET /ostatus_subscribe
+ #
+ def follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
+ case is_status?(acct) do
+ true -> follow_status(conn, user, acct)
+ _ -> follow_account(conn, user, acct)
+ end
+ end
+
+ defp follow_status(conn, _user, acct) do
+ with {:ok, object} <- Fetcher.fetch_object_from_id(acct),
+ %Activity{id: activity_id} <- Activity.get_create_by_object_ap_id(object.data["id"]) do
+ redirect(conn, to: o_status_path(conn, :notice, activity_id))
+ else
+ error ->
+ handle_follow_error(conn, error)
+ end
+ end
+
+ defp follow_account(conn, user, acct) do
+ with {:ok, followee} <- User.get_or_fetch(acct) do
+ render(conn, follow_template(user), %{error: false, followee: followee, acct: acct})
+ else
+ {:error, _reason} ->
+ render(conn, follow_template(user), %{error: :error})
+ end
+ end
+
+ defp follow_template(%User{} = _user), do: "follow.html"
+ defp follow_template(_), do: "follow_login.html"
+
+ defp is_status?(acct) do
+ case Fetcher.fetch_and_contain_remote_object_from_id(acct) do
+ {:ok, %{"type" => type}} when type in @status_types ->
+ true
+
+ _ ->
+ false
+ end
+ end
+
+ # POST /ostatus_subscribe
+ #
+ def do_follow(%{assigns: %{user: %User{} = user}} = conn, %{"user" => %{"id" => id}}) do
+ with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
+ {:ok, _, _, _} <- CommonAPI.follow(user, followee) do
+ render(conn, "followed.html", %{error: false})
+ else
+ error ->
+ handle_follow_error(conn, error)
+ end
+ end
+
+ def do_follow(conn, %{"authorization" => %{"name" => _, "password" => _, "id" => id}}) do
+ with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
+ {_, {:ok, user}, _} <- {:auth, Authenticator.get_user(conn), followee},
+ {:ok, _, _, _} <- CommonAPI.follow(user, followee) do
+ render(conn, "followed.html", %{error: false})
+ else
+ error ->
+ handle_follow_error(conn, error)
+ end
+ end
+
+ def do_follow(%{assigns: %{user: nil}} = conn, _) do
+ Logger.debug("Insufficient permissions: follow | write:follows.")
+ render(conn, "followed.html", %{error: "Insufficient permissions: follow | write:follows."})
+ end
+
+ defp handle_follow_error(conn, {:auth, _, followee} = _) do
+ render(conn, "follow_login.html", %{error: "Wrong username or password", followee: followee})
+ end
+
+ defp handle_follow_error(conn, {:fetch_user, error} = _) do
+ Logger.debug("Remote follow failed with error #{inspect(error)}")
+ render(conn, "followed.html", %{error: "Could not find user"})
+ end
+
+ defp handle_follow_error(conn, {:error, "Could not follow user:" <> _} = _) do
+ render(conn, "followed.html", %{error: "Error following account"})
+ end
+
+ defp handle_follow_error(conn, error) do
+ Logger.debug("Remote follow failed with error #{inspect(error)}")
+ render(conn, "followed.html", %{error: "Something went wrong."})
+ end
+end
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index 799dd17ae..f08b9d28c 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -7,12 +7,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
require Logger
- alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Emoji
alias Pleroma.Healthcheck
alias Pleroma.Notification
- alias Pleroma.Plugs.AuthenticationPlug
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.User
alias Pleroma.Web
@@ -22,7 +20,14 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
plug(
OAuthScopesPlug,
%{scopes: ["follow", "write:follows"]}
- when action in [:do_remote_follow, :follow_import]
+ when action == :follow_import
+ )
+
+ # Note: follower can submit the form (with password auth) not being signed in (having no token)
+ plug(
+ OAuthScopesPlug,
+ %{fallback: :proceed_unauthenticated, scopes: ["follow", "write:follows"]}
+ when action == :do_remote_follow
)
plug(OAuthScopesPlug, %{scopes: ["follow", "write:blocks"]} when action == :blocks_import)
@@ -77,95 +82,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
end
- def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
- if is_status?(acct) do
- {:ok, object} = Pleroma.Object.Fetcher.fetch_object_from_id(acct)
- %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"])
- redirect(conn, to: "/notice/#{activity_id}")
- else
- with {:ok, followee} <- User.get_or_fetch(acct) do
- conn
- |> render(follow_template(user), %{
- error: false,
- acct: acct,
- avatar: User.avatar_url(followee),
- name: followee.nickname,
- id: followee.id
- })
- else
- {:error, _reason} ->
- render(conn, follow_template(user), %{error: :error})
- end
- end
- end
-
- defp follow_template(%User{} = _user), do: "follow.html"
- defp follow_template(_), do: "follow_login.html"
-
- defp is_status?(acct) do
- case Pleroma.Object.Fetcher.fetch_and_contain_remote_object_from_id(acct) do
- {:ok, %{"type" => type}}
- when type in ["Article", "Event", "Note", "Video", "Page", "Question"] ->
- true
-
- _ ->
- false
- end
- end
-
- def do_remote_follow(conn, %{
- "authorization" => %{"name" => username, "password" => password, "id" => id}
- }) do
- with %User{} = followee <- User.get_cached_by_id(id),
- {_, %User{} = user, _} <- {:auth, User.get_cached_by_nickname(username), followee},
- {_, true, _} <- {
- :auth,
- AuthenticationPlug.checkpw(password, user.password_hash),
- followee
- },
- {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do
- conn
- |> render("followed.html", %{error: false})
- else
- # Was already following user
- {:error, "Could not follow user:" <> _rest} ->
- render(conn, "followed.html", %{error: "Error following account"})
-
- {:auth, _, followee} ->
- conn
- |> render("follow_login.html", %{
- error: "Wrong username or password",
- id: id,
- name: followee.nickname,
- avatar: User.avatar_url(followee)
- })
-
- e ->
- Logger.debug("Remote follow failed with error #{inspect(e)}")
- render(conn, "followed.html", %{error: "Something went wrong."})
- end
- end
-
- def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
- with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
- {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do
- conn
- |> render("followed.html", %{error: false})
- else
- # Was already following user
- {:error, "Could not follow user:" <> _rest} ->
- render(conn, "followed.html", %{error: "Error following account"})
-
- {:fetch_user, error} ->
- Logger.debug("Remote follow failed with error #{inspect(error)}")
- render(conn, "followed.html", %{error: "Could not find user"})
-
- e ->
- Logger.debug("Remote follow failed with error #{inspect(e)}")
- render(conn, "followed.html", %{error: "Something went wrong."})
- 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"})
@@ -346,7 +262,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
def delete_account(%{assigns: %{user: user}} = conn, params) do
- case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
+ password = params["password"] || ""
+
+ case CommonAPI.Utils.confirm_current_password(user, password) do
{:ok, user} ->
User.delete(user)
json(conn, %{status: "success"})
diff --git a/lib/pleroma/web/twitter_api/views/remote_follow_view.ex b/lib/pleroma/web/twitter_api/views/remote_follow_view.ex
new file mode 100644
index 000000000..d469c4726
--- /dev/null
+++ b/lib/pleroma/web/twitter_api/views/remote_follow_view.ex
@@ -0,0 +1,10 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.TwitterAPI.RemoteFollowView do
+ use Pleroma.Web, :view
+ import Phoenix.HTML.Form
+
+ defdelegate avatar_url(user), to: Pleroma.User
+end