forked from YokaiRick/akkoma
Merge branch 'feature/locked-accounts-part-1' into 'develop'
locked accounts See merge request pleroma/pleroma!180
This commit is contained in:
commit
a6e0c31518
12 changed files with 474 additions and 11 deletions
30
lib/mix/tasks/set_locked.ex
Normal file
30
lib/mix/tasks/set_locked.ex
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
defmodule Mix.Tasks.SetLocked do
|
||||||
|
use Mix.Task
|
||||||
|
import Mix.Ecto
|
||||||
|
alias Pleroma.{Repo, User}
|
||||||
|
|
||||||
|
@shortdoc "Set locked status"
|
||||||
|
def run([nickname | rest]) do
|
||||||
|
ensure_started(Repo, [])
|
||||||
|
|
||||||
|
locked =
|
||||||
|
case rest do
|
||||||
|
[locked] -> locked == "true"
|
||||||
|
_ -> true
|
||||||
|
end
|
||||||
|
|
||||||
|
with %User{local: true} = user <- User.get_by_nickname(nickname) do
|
||||||
|
info =
|
||||||
|
user.info
|
||||||
|
|> Map.put("locked", !!locked)
|
||||||
|
|
||||||
|
cng = User.info_changeset(user, %{info: info})
|
||||||
|
user = Repo.update!(cng)
|
||||||
|
|
||||||
|
IO.puts("locked status of #{nickname}: #{user.info["locked"]}")
|
||||||
|
else
|
||||||
|
_ ->
|
||||||
|
IO.puts("No local user #{nickname}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -197,6 +197,14 @@ def maybe_direct_follow(%User{} = follower, %User{info: info} = followed) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def maybe_follow(%User{} = follower, %User{info: info} = followed) do
|
||||||
|
if not following?(follower, followed) do
|
||||||
|
follow(follower, followed)
|
||||||
|
else
|
||||||
|
{:ok, follower}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def follow(%User{} = follower, %User{info: info} = followed) do
|
def follow(%User{} = follower, %User{info: info} = followed) do
|
||||||
ap_followers = followed.follower_address
|
ap_followers = followed.follower_address
|
||||||
|
|
||||||
|
@ -252,6 +260,10 @@ def following?(%User{} = follower, %User{} = followed) do
|
||||||
Enum.member?(follower.following, followed.follower_address)
|
Enum.member?(follower.following, followed.follower_address)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def locked?(%User{} = user) do
|
||||||
|
user.info["locked"] || false
|
||||||
|
end
|
||||||
|
|
||||||
def get_by_ap_id(ap_id) do
|
def get_by_ap_id(ap_id) do
|
||||||
Repo.get_by(User, ap_id: ap_id)
|
Repo.get_by(User, ap_id: ap_id)
|
||||||
end
|
end
|
||||||
|
@ -349,6 +361,40 @@ def get_friends(user) do
|
||||||
{:ok, Repo.all(q)}
|
{:ok, Repo.all(q)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_follow_requests_query(%User{} = user) do
|
||||||
|
from(
|
||||||
|
a in Activity,
|
||||||
|
where:
|
||||||
|
fragment(
|
||||||
|
"? ->> 'type' = 'Follow'",
|
||||||
|
a.data
|
||||||
|
),
|
||||||
|
where:
|
||||||
|
fragment(
|
||||||
|
"? ->> 'state' = 'pending'",
|
||||||
|
a.data
|
||||||
|
),
|
||||||
|
where:
|
||||||
|
fragment(
|
||||||
|
"? @> ?",
|
||||||
|
a.data,
|
||||||
|
^%{"object" => user.ap_id}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_follow_requests(%User{} = user) do
|
||||||
|
q = get_follow_requests_query(user)
|
||||||
|
reqs = Repo.all(q)
|
||||||
|
|
||||||
|
users =
|
||||||
|
Enum.map(reqs, fn req -> req.actor end)
|
||||||
|
|> Enum.uniq()
|
||||||
|
|> Enum.map(fn ap_id -> get_by_ap_id(ap_id) end)
|
||||||
|
|
||||||
|
{:ok, users}
|
||||||
|
end
|
||||||
|
|
||||||
def increase_note_count(%User{} = user) do
|
def increase_note_count(%User{} = user) do
|
||||||
note_count = (user.info["note_count"] || 0) + 1
|
note_count = (user.info["note_count"] || 0) + 1
|
||||||
new_info = Map.put(user.info, "note_count", note_count)
|
new_info = Map.put(user.info, "note_count", note_count)
|
||||||
|
|
|
@ -214,6 +214,7 @@ def follow(follower, followed, activity_id \\ nil, local \\ true) do
|
||||||
|
|
||||||
def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
|
def unfollow(follower, followed, activity_id \\ nil, local \\ true) do
|
||||||
with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
|
with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed),
|
||||||
|
{:ok, follow_activity} <- update_follow_state(follow_activity, "cancelled"),
|
||||||
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
|
unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id),
|
||||||
{:ok, activity} <- insert(unfollow_data, local),
|
{:ok, activity} <- insert(unfollow_data, local),
|
||||||
:ok <- maybe_federate(activity) do
|
:ok <- maybe_federate(activity) do
|
||||||
|
|
|
@ -137,9 +137,17 @@ def handle_incoming(
|
||||||
with %User{local: true} = followed <- User.get_cached_by_ap_id(followed),
|
with %User{local: true} = followed <- User.get_cached_by_ap_id(followed),
|
||||||
%User{} = follower <- User.get_or_fetch_by_ap_id(follower),
|
%User{} = follower <- User.get_or_fetch_by_ap_id(follower),
|
||||||
{:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do
|
{:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do
|
||||||
ActivityPub.accept(%{to: [follower.ap_id], actor: followed.ap_id, object: data, local: true})
|
if not User.locked?(followed) do
|
||||||
|
ActivityPub.accept(%{
|
||||||
|
to: [follower.ap_id],
|
||||||
|
actor: followed.ap_id,
|
||||||
|
object: data,
|
||||||
|
local: true
|
||||||
|
})
|
||||||
|
|
||||||
User.follow(follower, followed)
|
User.follow(follower, followed)
|
||||||
|
end
|
||||||
|
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
else
|
else
|
||||||
_e -> :error
|
_e -> :error
|
||||||
|
@ -252,7 +260,7 @@ def handle_incoming(
|
||||||
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
|
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
|
||||||
|
|
||||||
banner = new_user_data[:info]["banner"]
|
banner = new_user_data[:info]["banner"]
|
||||||
locked = new_user_data[:info]["locked"]
|
locked = new_user_data[:info]["locked"] || false
|
||||||
|
|
||||||
update_data =
|
update_data =
|
||||||
new_user_data
|
new_user_data
|
||||||
|
@ -432,6 +440,58 @@ def prepare_outgoing(%{"type" => "Create", "object" => %{"type" => "Note"} = obj
|
||||||
{:ok, data}
|
{:ok, data}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Mastodon Accept/Reject requires a non-normalized object containing the actor URIs,
|
||||||
|
# because of course it does.
|
||||||
|
def prepare_outgoing(%{"type" => "Accept"} = data) do
|
||||||
|
follow_activity_id =
|
||||||
|
if is_binary(data["object"]) do
|
||||||
|
data["object"]
|
||||||
|
else
|
||||||
|
data["object"]["id"]
|
||||||
|
end
|
||||||
|
|
||||||
|
with follow_activity <- Activity.get_by_ap_id(follow_activity_id) do
|
||||||
|
object = %{
|
||||||
|
"actor" => follow_activity.actor,
|
||||||
|
"object" => follow_activity.data["object"],
|
||||||
|
"id" => follow_activity.data["id"],
|
||||||
|
"type" => "Follow"
|
||||||
|
}
|
||||||
|
|
||||||
|
data =
|
||||||
|
data
|
||||||
|
|> Map.put("object", object)
|
||||||
|
|> Map.put("@context", "https://www.w3.org/ns/activitystreams")
|
||||||
|
|
||||||
|
{:ok, data}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_outgoing(%{"type" => "Reject"} = data) do
|
||||||
|
follow_activity_id =
|
||||||
|
if is_binary(data["object"]) do
|
||||||
|
data["object"]
|
||||||
|
else
|
||||||
|
data["object"]["id"]
|
||||||
|
end
|
||||||
|
|
||||||
|
with follow_activity <- Activity.get_by_ap_id(follow_activity_id) do
|
||||||
|
object = %{
|
||||||
|
"actor" => follow_activity.actor,
|
||||||
|
"object" => follow_activity.data["object"],
|
||||||
|
"id" => follow_activity.data["id"],
|
||||||
|
"type" => "Follow"
|
||||||
|
}
|
||||||
|
|
||||||
|
data =
|
||||||
|
data
|
||||||
|
|> Map.put("object", object)
|
||||||
|
|> Map.put("@context", "https://www.w3.org/ns/activitystreams")
|
||||||
|
|
||||||
|
{:ok, data}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def prepare_outgoing(%{"type" => _type} = data) do
|
def prepare_outgoing(%{"type" => _type} = data) do
|
||||||
data =
|
data =
|
||||||
data
|
data
|
||||||
|
|
|
@ -4,6 +4,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
||||||
alias Pleroma.Web.Endpoint
|
alias Pleroma.Web.Endpoint
|
||||||
alias Ecto.{Changeset, UUID}
|
alias Ecto.{Changeset, UUID}
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
require Logger
|
||||||
|
|
||||||
# Some implementations send the actor URI as the actor field, others send the entire actor object,
|
# Some implementations send the actor URI as the actor field, others send the entire actor object,
|
||||||
# so figure out what the actor's URI is based on what we have.
|
# so figure out what the actor's URI is based on what we have.
|
||||||
|
@ -216,10 +217,27 @@ def remove_like_from_object(%Activity{data: %{"actor" => actor}}, object) do
|
||||||
|
|
||||||
#### Follow-related helpers
|
#### Follow-related helpers
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Updates a follow activity's state (for locked accounts).
|
||||||
|
"""
|
||||||
|
def update_follow_state(%Activity{} = activity, state) do
|
||||||
|
with new_data <-
|
||||||
|
activity.data
|
||||||
|
|> Map.put("state", state),
|
||||||
|
changeset <- Changeset.change(activity, data: new_data),
|
||||||
|
{:ok, activity} <- Repo.update(changeset) do
|
||||||
|
{:ok, activity}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Makes a follow activity data for the given follower and followed
|
Makes a follow activity data for the given follower and followed
|
||||||
"""
|
"""
|
||||||
def make_follow_data(%User{ap_id: follower_id}, %User{ap_id: followed_id}, activity_id) do
|
def make_follow_data(
|
||||||
|
%User{ap_id: follower_id},
|
||||||
|
%User{ap_id: followed_id} = followed,
|
||||||
|
activity_id
|
||||||
|
) do
|
||||||
data = %{
|
data = %{
|
||||||
"type" => "Follow",
|
"type" => "Follow",
|
||||||
"actor" => follower_id,
|
"actor" => follower_id,
|
||||||
|
@ -228,7 +246,10 @@ def make_follow_data(%User{ap_id: follower_id}, %User{ap_id: followed_id}, activ
|
||||||
"object" => followed_id
|
"object" => followed_id
|
||||||
}
|
}
|
||||||
|
|
||||||
if activity_id, do: Map.put(data, "id", activity_id), else: data
|
data = if activity_id, do: Map.put(data, "id", activity_id), else: data
|
||||||
|
data = if User.locked?(followed), do: Map.put(data, "state", "pending"), else: data
|
||||||
|
|
||||||
|
data
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_latest_follow(%User{ap_id: follower_id}, %User{ap_id: followed_id}) do
|
def fetch_latest_follow(%User{ap_id: follower_id}, %User{ap_id: followed_id}) do
|
||||||
|
|
|
@ -4,6 +4,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
alias Pleroma.Web
|
alias Pleroma.Web
|
||||||
alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView, ListView}
|
alias Pleroma.Web.MastodonAPI.{StatusView, AccountView, MastodonView, ListView}
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.{CommonAPI, OStatus}
|
alias Pleroma.Web.{CommonAPI, OStatus}
|
||||||
alias Pleroma.Web.OAuth.{Authorization, Token, App}
|
alias Pleroma.Web.OAuth.{Authorization, Token, App}
|
||||||
alias Comeonin.Pbkdf2
|
alias Comeonin.Pbkdf2
|
||||||
|
@ -71,6 +72,20 @@ def update_credentials(%{assigns: %{user: user}} = conn, params) do
|
||||||
user
|
user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
user =
|
||||||
|
if locked = params["locked"] do
|
||||||
|
with locked <- locked == "true",
|
||||||
|
new_info <- Map.put(user.info, "locked", locked),
|
||||||
|
change <- User.info_changeset(user, %{info: new_info}),
|
||||||
|
{:ok, user} <- User.update_and_set_cache(change) do
|
||||||
|
user
|
||||||
|
else
|
||||||
|
_e -> user
|
||||||
|
end
|
||||||
|
else
|
||||||
|
user
|
||||||
|
end
|
||||||
|
|
||||||
with changeset <- User.update_changeset(user, params),
|
with changeset <- User.update_changeset(user, params),
|
||||||
{:ok, user} <- User.update_and_set_cache(changeset) do
|
{:ok, user} <- User.update_and_set_cache(changeset) do
|
||||||
if original_user != user do
|
if original_user != user do
|
||||||
|
@ -476,6 +491,53 @@ def following(conn, %{"id" => id}) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def follow_requests(%{assigns: %{user: followed}} = conn, _params) do
|
||||||
|
with {:ok, follow_requests} <- User.get_follow_requests(followed) do
|
||||||
|
render(conn, AccountView, "accounts.json", %{users: follow_requests, as: :user})
|
||||||
|
end
|
||||||
|
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.ap_id,
|
||||||
|
object: follow_activity.data["id"],
|
||||||
|
type: "Accept"
|
||||||
|
}) do
|
||||||
|
render(conn, AccountView, "relationship.json", %{user: followed, target: follower})
|
||||||
|
else
|
||||||
|
{:error, message} ->
|
||||||
|
conn
|
||||||
|
|> put_resp_content_type("application/json")
|
||||||
|
|> send_resp(403, Jason.encode!(%{"error" => message}))
|
||||||
|
end
|
||||||
|
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.ap_id,
|
||||||
|
object: follow_activity.data["id"],
|
||||||
|
type: "Reject"
|
||||||
|
}) do
|
||||||
|
render(conn, AccountView, "relationship.json", %{user: followed, target: follower})
|
||||||
|
else
|
||||||
|
{:error, message} ->
|
||||||
|
conn
|
||||||
|
|> put_resp_content_type("application/json")
|
||||||
|
|> send_resp(403, Jason.encode!(%{"error" => message}))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
|
def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
|
||||||
with %User{} = followed <- Repo.get(User, id),
|
with %User{} = followed <- Repo.get(User, id),
|
||||||
{:ok, follower} <- User.maybe_direct_follow(follower, followed),
|
{:ok, follower} <- User.maybe_direct_follow(follower, followed),
|
||||||
|
|
|
@ -97,11 +97,14 @@ def user_fetcher(username) do
|
||||||
post("/accounts/:id/mute", MastodonAPIController, :relationship_noop)
|
post("/accounts/:id/mute", MastodonAPIController, :relationship_noop)
|
||||||
post("/accounts/:id/unmute", MastodonAPIController, :relationship_noop)
|
post("/accounts/:id/unmute", MastodonAPIController, :relationship_noop)
|
||||||
|
|
||||||
|
get("/follow_requests", MastodonAPIController, :follow_requests)
|
||||||
|
post("/follow_requests/:id/authorize", MastodonAPIController, :authorize_follow_request)
|
||||||
|
post("/follow_requests/:id/reject", MastodonAPIController, :reject_follow_request)
|
||||||
|
|
||||||
post("/follows", MastodonAPIController, :follow)
|
post("/follows", MastodonAPIController, :follow)
|
||||||
|
|
||||||
get("/blocks", MastodonAPIController, :blocks)
|
get("/blocks", MastodonAPIController, :blocks)
|
||||||
|
|
||||||
get("/follow_requests", MastodonAPIController, :empty_array)
|
|
||||||
get("/mutes", MastodonAPIController, :empty_array)
|
get("/mutes", MastodonAPIController, :empty_array)
|
||||||
|
|
||||||
get("/timelines/home", MastodonAPIController, :home_timeline)
|
get("/timelines/home", MastodonAPIController, :home_timeline)
|
||||||
|
@ -243,6 +246,10 @@ def user_fetcher(username) do
|
||||||
post("/statuses/retweet/:id", TwitterAPI.Controller, :retweet)
|
post("/statuses/retweet/:id", TwitterAPI.Controller, :retweet)
|
||||||
post("/statuses/destroy/:id", TwitterAPI.Controller, :delete_post)
|
post("/statuses/destroy/:id", TwitterAPI.Controller, :delete_post)
|
||||||
|
|
||||||
|
get("/pleroma/friend_requests", TwitterAPI.Controller, :friend_requests)
|
||||||
|
post("/pleroma/friendships/approve", TwitterAPI.Controller, :approve_friend_request)
|
||||||
|
post("/pleroma/friendships/deny", TwitterAPI.Controller, :deny_friend_request)
|
||||||
|
|
||||||
post("/friendships/create", TwitterAPI.Controller, :follow)
|
post("/friendships/create", TwitterAPI.Controller, :follow)
|
||||||
post("/friendships/destroy", TwitterAPI.Controller, :unfollow)
|
post("/friendships/destroy", TwitterAPI.Controller, :unfollow)
|
||||||
post("/blocks/create", TwitterAPI.Controller, :block)
|
post("/blocks/create", TwitterAPI.Controller, :block)
|
||||||
|
|
|
@ -4,6 +4,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
alias Pleroma.{Repo, Activity, User, Notification}
|
alias Pleroma.{Repo, Activity, User, Notification}
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Ecto.Changeset
|
alias Ecto.Changeset
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
@ -331,6 +332,54 @@ def friends(conn, params) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def friend_requests(conn, params) do
|
||||||
|
with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),
|
||||||
|
{:ok, friend_requests} <- User.get_follow_requests(user) do
|
||||||
|
render(conn, UserView, "index.json", %{users: friend_requests, for: conn.assigns[:user]})
|
||||||
|
else
|
||||||
|
_e -> bad_request_reply(conn, "Can't get friend requests")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def approve_friend_request(conn, %{"user_id" => uid} = params) do
|
||||||
|
with followed <- conn.assigns[:user],
|
||||||
|
uid when is_number(uid) <- String.to_integer(uid),
|
||||||
|
%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.ap_id,
|
||||||
|
object: follow_activity.data["id"],
|
||||||
|
type: "Accept"
|
||||||
|
}) do
|
||||||
|
render(conn, UserView, "show.json", %{user: follower, for: followed})
|
||||||
|
else
|
||||||
|
e -> bad_request_reply(conn, "Can't approve user: #{inspect(e)}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def deny_friend_request(conn, %{"user_id" => uid} = params) do
|
||||||
|
with followed <- conn.assigns[:user],
|
||||||
|
uid when is_number(uid) <- String.to_integer(uid),
|
||||||
|
%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.ap_id,
|
||||||
|
object: follow_activity.data["id"],
|
||||||
|
type: "Reject"
|
||||||
|
}) do
|
||||||
|
render(conn, UserView, "show.json", %{user: follower, for: followed})
|
||||||
|
else
|
||||||
|
e -> bad_request_reply(conn, "Can't deny user: #{inspect(e)}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def friends_ids(%{assigns: %{user: user}} = conn, _params) do
|
def friends_ids(%{assigns: %{user: user}} = conn, _params) do
|
||||||
with {:ok, friends} <- User.get_friends(user) do
|
with {:ok, friends} <- User.get_friends(user) do
|
||||||
ids =
|
ids =
|
||||||
|
@ -357,6 +406,20 @@ def update_profile(%{assigns: %{user: user}} = conn, params) do
|
||||||
params
|
params
|
||||||
end
|
end
|
||||||
|
|
||||||
|
user =
|
||||||
|
if locked = params["locked"] do
|
||||||
|
with locked <- locked == "true",
|
||||||
|
new_info <- Map.put(user.info, "locked", locked),
|
||||||
|
change <- User.info_changeset(user, %{info: new_info}),
|
||||||
|
{:ok, user} <- User.update_and_set_cache(change) do
|
||||||
|
user
|
||||||
|
else
|
||||||
|
_e -> user
|
||||||
|
end
|
||||||
|
else
|
||||||
|
user
|
||||||
|
end
|
||||||
|
|
||||||
with changeset <- User.update_changeset(user, params),
|
with changeset <- User.update_changeset(user, params),
|
||||||
{:ok, user} <- User.update_and_set_cache(changeset) do
|
{:ok, user} <- User.update_and_set_cache(changeset) do
|
||||||
CommonAPI.update(user)
|
CommonAPI.update(user)
|
||||||
|
|
|
@ -51,7 +51,8 @@ def render("user.json", %{user: user = %User{}} = assigns) do
|
||||||
"statusnet_profile_url" => user.ap_id,
|
"statusnet_profile_url" => user.ap_id,
|
||||||
"cover_photo" => User.banner_url(user) |> MediaProxy.url(),
|
"cover_photo" => User.banner_url(user) |> MediaProxy.url(),
|
||||||
"background_image" => image_url(user.info["background"]) |> MediaProxy.url(),
|
"background_image" => image_url(user.info["background"]) |> MediaProxy.url(),
|
||||||
"is_local" => user.local
|
"is_local" => user.local,
|
||||||
|
"locked" => !!user.info["locked"]
|
||||||
}
|
}
|
||||||
|
|
||||||
if assigns[:token] do
|
if assigns[:token] do
|
||||||
|
|
|
@ -4,6 +4,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|
||||||
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||||
alias Pleroma.{Repo, User, Activity, Notification}
|
alias Pleroma.{Repo, User, Activity, Notification}
|
||||||
alias Pleroma.Web.{OStatus, CommonAPI}
|
alias Pleroma.Web.{OStatus, CommonAPI}
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
import ExUnit.CaptureLog
|
import ExUnit.CaptureLog
|
||||||
|
@ -644,6 +645,73 @@ test "returns the relationships for the current user", %{conn: conn} do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "locked accounts" do
|
||||||
|
test "/api/v1/follow_requests works" do
|
||||||
|
user = insert(:user, %{info: %{"locked" => true}})
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} = ActivityPub.follow(other_user, user)
|
||||||
|
|
||||||
|
user = Repo.get(User, user.id)
|
||||||
|
other_user = Repo.get(User, other_user.id)
|
||||||
|
|
||||||
|
assert User.following?(other_user, user) == false
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get("/api/v1/follow_requests")
|
||||||
|
|
||||||
|
assert [relationship] = json_response(conn, 200)
|
||||||
|
assert to_string(other_user.id) == relationship["id"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "/api/v1/follow_requests/:id/authorize works" do
|
||||||
|
user = insert(:user, %{info: %{"locked" => true}})
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} = ActivityPub.follow(other_user, user)
|
||||||
|
|
||||||
|
user = Repo.get(User, user.id)
|
||||||
|
other_user = Repo.get(User, other_user.id)
|
||||||
|
|
||||||
|
assert User.following?(other_user, user) == false
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> post("/api/v1/follow_requests/#{other_user.id}/authorize")
|
||||||
|
|
||||||
|
assert relationship = json_response(conn, 200)
|
||||||
|
assert to_string(other_user.id) == relationship["id"]
|
||||||
|
|
||||||
|
user = Repo.get(User, user.id)
|
||||||
|
other_user = Repo.get(User, other_user.id)
|
||||||
|
|
||||||
|
assert User.following?(other_user, user) == true
|
||||||
|
end
|
||||||
|
|
||||||
|
test "/api/v1/follow_requests/:id/reject works" do
|
||||||
|
user = insert(:user, %{info: %{"locked" => true}})
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} = ActivityPub.follow(other_user, user)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> post("/api/v1/follow_requests/#{other_user.id}/reject")
|
||||||
|
|
||||||
|
assert relationship = json_response(conn, 200)
|
||||||
|
assert to_string(other_user.id) == relationship["id"]
|
||||||
|
|
||||||
|
user = Repo.get(User, user.id)
|
||||||
|
other_user = Repo.get(User, other_user.id)
|
||||||
|
|
||||||
|
assert User.following?(other_user, user) == false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "account fetching", %{conn: conn} do
|
test "account fetching", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
|
|
|
@ -762,6 +762,38 @@ test "it updates a user's profile", %{conn: conn} do
|
||||||
|
|
||||||
assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
|
assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it locks an account", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> post("/api/account/update_profile.json", %{
|
||||||
|
"locked" => "true"
|
||||||
|
})
|
||||||
|
|
||||||
|
user = Repo.get!(User, user.id)
|
||||||
|
assert user.info["locked"] == true
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it unlocks an account", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> post("/api/account/update_profile.json", %{
|
||||||
|
"locked" => "false"
|
||||||
|
})
|
||||||
|
|
||||||
|
user = Repo.get!(User, user.id)
|
||||||
|
assert user.info["locked"] == false
|
||||||
|
|
||||||
|
assert json_response(conn, 200) == UserView.render("user.json", %{user: user, for: user})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp valid_user(_context) do
|
defp valid_user(_context) do
|
||||||
|
@ -926,4 +958,72 @@ test "with credentials and valid password", %{conn: conn, user: current_user} do
|
||||||
:timer.sleep(1000)
|
:timer.sleep(1000)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "GET /api/pleroma/friend_requests" do
|
||||||
|
test "it lists friend requests" do
|
||||||
|
user = insert(:user, %{info: %{"locked" => true}})
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} = ActivityPub.follow(other_user, user)
|
||||||
|
|
||||||
|
user = Repo.get(User, user.id)
|
||||||
|
other_user = Repo.get(User, other_user.id)
|
||||||
|
|
||||||
|
assert User.following?(other_user, user) == false
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get("/api/pleroma/friend_requests")
|
||||||
|
|
||||||
|
assert [relationship] = json_response(conn, 200)
|
||||||
|
assert other_user.id == relationship["id"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "POST /api/pleroma/friendships/approve" do
|
||||||
|
test "it approves a friend request" do
|
||||||
|
user = insert(:user, %{info: %{"locked" => true}})
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} = ActivityPub.follow(other_user, user)
|
||||||
|
|
||||||
|
user = Repo.get(User, user.id)
|
||||||
|
other_user = Repo.get(User, other_user.id)
|
||||||
|
|
||||||
|
assert User.following?(other_user, user) == false
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> post("/api/pleroma/friendships/approve", %{"user_id" => to_string(other_user.id)})
|
||||||
|
|
||||||
|
assert relationship = json_response(conn, 200)
|
||||||
|
assert other_user.id == relationship["id"]
|
||||||
|
assert relationship["follows_you"] == true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "POST /api/pleroma/friendships/deny" do
|
||||||
|
test "it denies a friend request" do
|
||||||
|
user = insert(:user, %{info: %{"locked" => true}})
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} = ActivityPub.follow(other_user, user)
|
||||||
|
|
||||||
|
user = Repo.get(User, user.id)
|
||||||
|
other_user = Repo.get(User, other_user.id)
|
||||||
|
|
||||||
|
assert User.following?(other_user, user) == false
|
||||||
|
|
||||||
|
conn =
|
||||||
|
build_conn()
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> post("/api/pleroma/friendships/deny", %{"user_id" => to_string(other_user.id)})
|
||||||
|
|
||||||
|
assert relationship = json_response(conn, 200)
|
||||||
|
assert other_user.id == relationship["id"]
|
||||||
|
assert relationship["follows_you"] == false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -59,7 +59,8 @@ test "A user" do
|
||||||
"statusnet_profile_url" => user.ap_id,
|
"statusnet_profile_url" => user.ap_id,
|
||||||
"cover_photo" => banner,
|
"cover_photo" => banner,
|
||||||
"background_image" => nil,
|
"background_image" => nil,
|
||||||
"is_local" => true
|
"is_local" => true,
|
||||||
|
"locked" => false
|
||||||
}
|
}
|
||||||
|
|
||||||
assert represented == UserView.render("show.json", %{user: user})
|
assert represented == UserView.render("show.json", %{user: user})
|
||||||
|
@ -94,7 +95,8 @@ test "A user for a given other follower", %{user: user} do
|
||||||
"statusnet_profile_url" => user.ap_id,
|
"statusnet_profile_url" => user.ap_id,
|
||||||
"cover_photo" => banner,
|
"cover_photo" => banner,
|
||||||
"background_image" => nil,
|
"background_image" => nil,
|
||||||
"is_local" => true
|
"is_local" => true,
|
||||||
|
"locked" => false
|
||||||
}
|
}
|
||||||
|
|
||||||
assert represented == UserView.render("show.json", %{user: user, for: follower})
|
assert represented == UserView.render("show.json", %{user: user, for: follower})
|
||||||
|
@ -130,7 +132,8 @@ test "A user that follows you", %{user: user} do
|
||||||
"statusnet_profile_url" => follower.ap_id,
|
"statusnet_profile_url" => follower.ap_id,
|
||||||
"cover_photo" => banner,
|
"cover_photo" => banner,
|
||||||
"background_image" => nil,
|
"background_image" => nil,
|
||||||
"is_local" => true
|
"is_local" => true,
|
||||||
|
"locked" => false
|
||||||
}
|
}
|
||||||
|
|
||||||
assert represented == UserView.render("show.json", %{user: follower, for: user})
|
assert represented == UserView.render("show.json", %{user: follower, for: user})
|
||||||
|
@ -173,7 +176,8 @@ test "A blocked user for the blocker" do
|
||||||
"statusnet_profile_url" => user.ap_id,
|
"statusnet_profile_url" => user.ap_id,
|
||||||
"cover_photo" => banner,
|
"cover_photo" => banner,
|
||||||
"background_image" => nil,
|
"background_image" => nil,
|
||||||
"is_local" => true
|
"is_local" => true,
|
||||||
|
"locked" => false
|
||||||
}
|
}
|
||||||
|
|
||||||
blocker = Repo.get(User, blocker.id)
|
blocker = Repo.get(User, blocker.id)
|
||||||
|
|
Loading…
Reference in a new issue