Account endorsements
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
c97f99ccf2
commit
a9b0027071
9 changed files with 179 additions and 18 deletions
|
@ -9,7 +9,8 @@
|
|||
mute: 2,
|
||||
reblog_mute: 3,
|
||||
notification_mute: 4,
|
||||
inverse_subscription: 5
|
||||
inverse_subscription: 5,
|
||||
endorsement: 6
|
||||
)
|
||||
|
||||
defenum(Pleroma.FollowingRelationship.State,
|
||||
|
|
|
@ -78,7 +78,11 @@ defmodule Pleroma.User do
|
|||
inverse_subscription: [
|
||||
subscribee_subscriptions: :subscriber_users,
|
||||
subscriber_subscriptions: :subscribee_users
|
||||
]
|
||||
],
|
||||
endorsement: [
|
||||
endorser_endorsements: :endorsed_users,
|
||||
endorsee_endorsements: :endorser_users
|
||||
],
|
||||
]
|
||||
|
||||
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
|
||||
|
@ -168,25 +172,25 @@ defmodule Pleroma.User do
|
|||
{incoming_relation, incoming_relation_source}
|
||||
]} <- @user_relationships_config do
|
||||
# Definitions of `has_many` relations: :blocker_blocks, :muter_mutes, :reblog_muter_mutes,
|
||||
# :notification_muter_mutes, :subscribee_subscriptions
|
||||
# :notification_muter_mutes, :subscribee_subscriptions, :endorser_endorsements
|
||||
has_many(outgoing_relation, UserRelationship,
|
||||
foreign_key: :source_id,
|
||||
where: [relationship_type: relationship_type]
|
||||
)
|
||||
|
||||
# Definitions of `has_many` relations: :blockee_blocks, :mutee_mutes, :reblog_mutee_mutes,
|
||||
# :notification_mutee_mutes, :subscriber_subscriptions
|
||||
# :notification_mutee_mutes, :subscriber_subscriptions, :endorsee_endorsements
|
||||
has_many(incoming_relation, UserRelationship,
|
||||
foreign_key: :target_id,
|
||||
where: [relationship_type: relationship_type]
|
||||
)
|
||||
|
||||
# Definitions of `has_many` relations: :blocked_users, :muted_users, :reblog_muted_users,
|
||||
# :notification_muted_users, :subscriber_users
|
||||
# :notification_muted_users, :subscriber_users, :endorsed_users
|
||||
has_many(outgoing_relation_target, through: [outgoing_relation, :target])
|
||||
|
||||
# Definitions of `has_many` relations: :blocker_users, :muter_users, :reblog_muter_users,
|
||||
# :notification_muter_users, :subscribee_users
|
||||
# :notification_muter_users, :subscribee_users, :endorser_users
|
||||
has_many(incoming_relation_source, through: [incoming_relation, :source])
|
||||
end
|
||||
|
||||
|
@ -214,7 +218,7 @@ defmodule Pleroma.User do
|
|||
@user_relationships_config do
|
||||
# `def blocked_users_relation/2`, `def muted_users_relation/2`,
|
||||
# `def reblog_muted_users_relation/2`, `def notification_muted_users/2`,
|
||||
# `def subscriber_users/2`
|
||||
# `def subscriber_users/2`, `def endorsed_users_relation/2`
|
||||
def unquote(:"#{outgoing_relation_target}_relation")(user, restrict_deactivated? \\ false) do
|
||||
target_users_query = assoc(user, unquote(outgoing_relation_target))
|
||||
|
||||
|
@ -227,7 +231,7 @@ def unquote(:"#{outgoing_relation_target}_relation")(user, restrict_deactivated?
|
|||
end
|
||||
|
||||
# `def blocked_users/2`, `def muted_users/2`, `def reblog_muted_users/2`,
|
||||
# `def notification_muted_users/2`, `def subscriber_users/2`
|
||||
# `def notification_muted_users/2`, `def subscriber_users/2`, `def endorsed_users/2`
|
||||
def unquote(outgoing_relation_target)(user, restrict_deactivated? \\ false) do
|
||||
__MODULE__
|
||||
|> apply(unquote(:"#{outgoing_relation_target}_relation"), [
|
||||
|
@ -238,7 +242,8 @@ def unquote(outgoing_relation_target)(user, restrict_deactivated? \\ false) do
|
|||
end
|
||||
|
||||
# `def blocked_users_ap_ids/2`, `def muted_users_ap_ids/2`, `def reblog_muted_users_ap_ids/2`,
|
||||
# `def notification_muted_users_ap_ids/2`, `def subscriber_users_ap_ids/2`
|
||||
# `def notification_muted_users_ap_ids/2`, `def subscriber_users_ap_ids/2`,
|
||||
# `def endorsed_users_ap_ids/2`
|
||||
def unquote(:"#{outgoing_relation_target}_ap_ids")(user, restrict_deactivated? \\ false) do
|
||||
__MODULE__
|
||||
|> apply(unquote(:"#{outgoing_relation_target}_relation"), [
|
||||
|
@ -1514,6 +1519,30 @@ def unblock(%User{} = blocker, %{ap_id: ap_id}) do
|
|||
unblock(blocker, get_cached_by_ap_id(ap_id))
|
||||
end
|
||||
|
||||
def endorse(%User{} = endorser, %User{} = target) do
|
||||
if not following?(endorser, target) do
|
||||
{:error, "Could not endorse: You are not following #{target.nickname}"}
|
||||
else
|
||||
UserRelationship.create_endorsement(endorser, target)
|
||||
end
|
||||
end
|
||||
|
||||
def endorse(%User{} = endorser, %{ap_id: ap_id}) do
|
||||
with %User{} = endorsed <- get_cached_by_ap_id(ap_id) do
|
||||
endorse(endorser, endorsed)
|
||||
end
|
||||
end
|
||||
|
||||
def unendorse(%User{} = unendorser, %User{} = target) do
|
||||
UserRelationship.delete_endorsement(unendorser, target)
|
||||
end
|
||||
|
||||
def unendorse(%User{} = unendorser, %{ap_id: ap_id}) do
|
||||
with %User{} = user <- get_cached_by_ap_id(ap_id) do
|
||||
unendorse(unendorser, user)
|
||||
end
|
||||
end
|
||||
|
||||
def mutes?(nil, _), do: false
|
||||
def mutes?(%User{} = user, %User{} = target), do: mutes_user?(user, target)
|
||||
|
||||
|
@ -1559,6 +1588,10 @@ def subscribed_to?(%User{} = user, %{ap_id: ap_id}) do
|
|||
end
|
||||
end
|
||||
|
||||
def endorses?(%User{} = user, %User{} = target) do
|
||||
UserRelationship.endorsement_exists?(user, target)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns map of outgoing (blocked, muted etc.) relationships' user AP IDs by relation type.
|
||||
E.g. `outgoing_relationships_ap_ids(user, [:block])` -> `%{block: ["https://some.site/users/userapid"]}`
|
||||
|
|
|
@ -24,17 +24,20 @@ defmodule Pleroma.UserRelationship do
|
|||
|
||||
for relationship_type <- Keyword.keys(Pleroma.UserRelationship.Type.__enum_map__()) do
|
||||
# `def create_block/2`, `def create_mute/2`, `def create_reblog_mute/2`,
|
||||
# `def create_notification_mute/2`, `def create_inverse_subscription/2`
|
||||
# `def create_notification_mute/2`, `def create_inverse_subscription/2`,
|
||||
# `def endorsement/2`
|
||||
def unquote(:"create_#{relationship_type}")(source, target),
|
||||
do: create(unquote(relationship_type), source, target)
|
||||
|
||||
# `def delete_block/2`, `def delete_mute/2`, `def delete_reblog_mute/2`,
|
||||
# `def delete_notification_mute/2`, `def delete_inverse_subscription/2`
|
||||
# `def delete_notification_mute/2`, `def delete_inverse_subscription/2`,
|
||||
# `def delete_endorsement/2`
|
||||
def unquote(:"delete_#{relationship_type}")(source, target),
|
||||
do: delete(unquote(relationship_type), source, target)
|
||||
|
||||
# `def block_exists?/2`, `def mute_exists?/2`, `def reblog_mute_exists?/2`,
|
||||
# `def notification_mute_exists?/2`, `def inverse_subscription_exists?/2`
|
||||
# `def notification_mute_exists?/2`, `def inverse_subscription_exists?/2`,
|
||||
# `def inverse_endorsement?/2`
|
||||
def unquote(:"#{relationship_type}_exists?")(source, target),
|
||||
do: exists?(unquote(relationship_type), source, target)
|
||||
end
|
||||
|
|
|
@ -328,6 +328,35 @@ def unblock_operation do
|
|||
}
|
||||
end
|
||||
|
||||
def endorse_operation do
|
||||
%Operation{
|
||||
tags: ["Account actions"],
|
||||
summary: "Endorse",
|
||||
operationId: "AccountController.endorse",
|
||||
security: [%{"oAuth" => ["follow", "write:accounts"]}],
|
||||
description:
|
||||
"Addds the given account to endorsed accounts list.",
|
||||
parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
|
||||
responses: %{
|
||||
200 => Operation.response("Relationship", "application/json", AccountRelationship)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def unendorse_operation do
|
||||
%Operation{
|
||||
tags: ["Account actions"],
|
||||
summary: "Unendorse",
|
||||
operationId: "AccountController.unendorse",
|
||||
security: [%{"oAuth" => ["follow", "write:accounts"]}],
|
||||
description: "Removes the given account from endorsed accounts list.",
|
||||
parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
|
||||
responses: %{
|
||||
200 => Operation.response("Relationship", "application/json", AccountRelationship)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def follow_by_uri_operation do
|
||||
%Operation{
|
||||
tags: ["Account actions"],
|
||||
|
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do
|
|||
alias Pleroma.Web.ApiSpec.Schemas.AccountRelationship
|
||||
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
||||
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
|
||||
alias Pleroma.Web.ApiSpec.AccountOperation
|
||||
alias Pleroma.Web.ApiSpec.StatusOperation
|
||||
|
||||
import Pleroma.Web.ApiSpec.Helpers
|
||||
|
@ -62,6 +63,27 @@ def favourites_operation do
|
|||
}
|
||||
end
|
||||
|
||||
def endorsements_operation do
|
||||
%Operation{
|
||||
tags: ["Retrieve account information"],
|
||||
summary: "Endorsements",
|
||||
description: "Returns endorsed accounts",
|
||||
operationId: "PleromaAPI.AccountController.endorsements",
|
||||
parameters: [id_param() | pagination_params()],
|
||||
security: [%{"oAuth" => ["read:account"]}],
|
||||
responses: %{
|
||||
200 =>
|
||||
Operation.response(
|
||||
"Array of Accounts",
|
||||
"application/json",
|
||||
AccountOperation.array_of_accounts()
|
||||
),
|
||||
403 => Operation.response("Forbidden", "application/json", ApiError),
|
||||
404 => Operation.response("Not Found", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def subscribe_operation do
|
||||
%Operation{
|
||||
tags: ["Account actions"],
|
||||
|
|
|
@ -53,7 +53,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
|||
when action in [:verify_credentials, :endorsements, :identity_proofs]
|
||||
)
|
||||
|
||||
plug(OAuthScopesPlug, %{scopes: ["write:accounts"]} when action == :update_credentials)
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
%{scopes: ["write:accounts"]} when action in [:update_credentials, :endorse, :unendorse]
|
||||
)
|
||||
|
||||
plug(OAuthScopesPlug, %{scopes: ["read:lists"]} when action == :lists)
|
||||
|
||||
|
@ -79,7 +82,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
|||
plug(OAuthScopesPlug, %{scopes: ["follow", "write:mutes"]} when action in [:mute, :unmute])
|
||||
|
||||
@relationship_actions [:follow, :unfollow]
|
||||
@needs_account ~W(followers following lists follow unfollow mute unmute block unblock)a
|
||||
@needs_account ~W(followers following lists follow unfollow mute unmute block unblock endorse unendorse)a
|
||||
|
||||
plug(
|
||||
RateLimiter,
|
||||
|
@ -435,6 +438,24 @@ def unblock(%{assigns: %{user: blocker, account: blocked}} = conn, _params) do
|
|||
end
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/accounts/:id/mute"
|
||||
def endorse(%{assigns: %{user: endorser, account: endorsed}} = conn, _params) do
|
||||
with {:ok, _user_relationships} <- User.endorse(endorser, endorsed) do
|
||||
render(conn, "relationship.json", user: endorser, target: endorsed)
|
||||
else
|
||||
{:error, message} -> json_response(conn, :forbidden, %{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/accounts/:id/unmute"
|
||||
def unendorse(%{assigns: %{user: endorser, account: endorsed}} = conn, _params) do
|
||||
with {:ok, _user_relationships} <- User.unendorse(endorser, endorsed) do
|
||||
render(conn, "relationship.json", user: endorser, target: endorsed)
|
||||
else
|
||||
{:error, message} -> json_response(conn, :forbidden, %{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/follows"
|
||||
def follow_by_uri(%{body_params: %{uri: uri}} = conn, _) do
|
||||
case User.get_cached_by_nickname(uri) do
|
||||
|
@ -478,7 +499,21 @@ def blocks(%{assigns: %{user: user}} = conn, params) do
|
|||
end
|
||||
|
||||
@doc "GET /api/v1/endorsements"
|
||||
def endorsements(conn, params), do: MastodonAPIController.empty_array(conn, params)
|
||||
def endorsements(%{assigns: %{user: user}} = conn, params) do
|
||||
users =
|
||||
user
|
||||
|> User.endorsed_users_relation(_restrict_deactivated = true)
|
||||
|> Pleroma.Pagination.fetch_paginated(Map.put(params, :skip_order, true))
|
||||
|
||||
conn
|
||||
|> add_link_headers(users)
|
||||
|> render("index.json",
|
||||
users: users,
|
||||
for: user,
|
||||
as: :user,
|
||||
embed_relationships: embed_relationships?(params)
|
||||
)
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/identity_proofs"
|
||||
def identity_proofs(conn, params), do: MastodonAPIController.empty_array(conn, params)
|
||||
|
|
|
@ -156,7 +156,14 @@ def render(
|
|||
target,
|
||||
&User.muting_reblogs?(&1, &2)
|
||||
),
|
||||
endorsed: false
|
||||
endorsed:
|
||||
UserRelationship.exists?(
|
||||
user_relationships,
|
||||
:endorsement,
|
||||
target,
|
||||
reading_user,
|
||||
&User.endorses?(&2, &1)
|
||||
),
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -6,7 +6,12 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
|
|||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper,
|
||||
only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2]
|
||||
only: [
|
||||
json_response: 3,
|
||||
add_link_headers: 2,
|
||||
embed_relationships?: 1,
|
||||
assign_account_by_id: 2
|
||||
]
|
||||
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
|
@ -40,9 +45,15 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
|
|||
%{scopes: ["read:favourites"], fallback: :proceed_unauthenticated} when action == :favourites
|
||||
)
|
||||
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
%{fallback: :proceed_unauthenticated, scopes: ["read:accounts"]}
|
||||
when action == :endorsements
|
||||
)
|
||||
|
||||
plug(RateLimiter, [name: :account_confirmation_resend] when action == :confirmation_resend)
|
||||
|
||||
plug(:assign_account_by_id when action in [:favourites, :subscribe, :unsubscribe])
|
||||
plug(:assign_account_by_id when action in [:favourites, :endorsements, :subscribe, :unsubscribe])
|
||||
|
||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PleromaAccountOperation
|
||||
|
||||
|
@ -90,6 +101,23 @@ def favourites(%{assigns: %{user: for_user, account: user}} = conn, params) do
|
|||
)
|
||||
end
|
||||
|
||||
@doc "GET /api/v1/pleroma/accounts/:id/endorsements"
|
||||
def endorsements(%{assigns: %{user: for_user, account: user}} = conn, params) do
|
||||
users =
|
||||
user
|
||||
|> User.endorsed_users_relation(_restrict_deactivated = true)
|
||||
|> Pleroma.Pagination.fetch_paginated(Map.put(params, :skip_order, true))
|
||||
|
||||
conn
|
||||
|> add_link_headers(users)
|
||||
|> render("index.json",
|
||||
for: for_user,
|
||||
users: users,
|
||||
as: :user,
|
||||
embed_relationships: embed_relationships?(params)
|
||||
)
|
||||
end
|
||||
|
||||
@doc "POST /api/v1/pleroma/accounts/:id/subscribe"
|
||||
def subscribe(%{assigns: %{user: user, account: subscription_target}} = conn, _params) do
|
||||
with {:ok, _subscription} <- User.subscribe(user, subscription_target) do
|
||||
|
|
|
@ -411,6 +411,7 @@ defmodule Pleroma.Web.Router do
|
|||
scope [] do
|
||||
pipe_through(:api)
|
||||
get("/accounts/:id/favourites", AccountController, :favourites)
|
||||
get("/accounts/:id/endorsements", AccountController, :endorsements)
|
||||
end
|
||||
|
||||
scope [] do
|
||||
|
@ -456,6 +457,8 @@ defmodule Pleroma.Web.Router do
|
|||
post("/accounts/:id/unblock", AccountController, :unblock)
|
||||
post("/accounts/:id/mute", AccountController, :mute)
|
||||
post("/accounts/:id/unmute", AccountController, :unmute)
|
||||
post("/accounts/:id/pin", AccountController, :endorse)
|
||||
post("/accounts/:id/unpin", AccountController, :unendorse)
|
||||
|
||||
get("/conversations", ConversationController, :index)
|
||||
post("/conversations/:id/read", ConversationController, :mark_as_read)
|
||||
|
|
Loading…
Reference in a new issue