Merge branch 'v2-suggestions' into 'develop'
V2 suggestions See merge request pleroma/pleroma!3547
This commit is contained in:
commit
bd853199d9
|
@ -261,6 +261,46 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## `PATCH /api/v1/pleroma/admin/users/suggest`
|
||||||
|
|
||||||
|
### Suggest a user
|
||||||
|
|
||||||
|
Adds the user(s) to follower recommendations.
|
||||||
|
|
||||||
|
- Params:
|
||||||
|
- `nicknames`: nicknames array
|
||||||
|
- Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
users: [
|
||||||
|
{
|
||||||
|
// user object
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `PATCH /api/v1/pleroma/admin/users/unsuggest`
|
||||||
|
|
||||||
|
### Unsuggest a user
|
||||||
|
|
||||||
|
Removes the user(s) from follower recommendations.
|
||||||
|
|
||||||
|
- Params:
|
||||||
|
- `nicknames`: nicknames array
|
||||||
|
- Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
users: [
|
||||||
|
{
|
||||||
|
// user object
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## `GET /api/v1/pleroma/admin/users/:nickname_or_id`
|
## `GET /api/v1/pleroma/admin/users/:nickname_or_id`
|
||||||
|
|
||||||
### Retrive the details of a user
|
### Retrive the details of a user
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
mute: 2,
|
mute: 2,
|
||||||
reblog_mute: 3,
|
reblog_mute: 3,
|
||||||
notification_mute: 4,
|
notification_mute: 4,
|
||||||
inverse_subscription: 5
|
inverse_subscription: 5,
|
||||||
|
suggestion_dismiss: 6
|
||||||
)
|
)
|
||||||
|
|
||||||
defenum(Pleroma.FollowingRelationship.State,
|
defenum(Pleroma.FollowingRelationship.State,
|
||||||
|
|
|
@ -338,6 +338,26 @@ def get_log_entry_message(%ModerationLog{
|
||||||
"@#{actor_nickname} approved users: #{users_to_nicknames_string(users)}"
|
"@#{actor_nickname} approved users: #{users_to_nicknames_string(users)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_log_entry_message(%ModerationLog{
|
||||||
|
data: %{
|
||||||
|
"actor" => %{"nickname" => actor_nickname},
|
||||||
|
"action" => "add_suggestion",
|
||||||
|
"subject" => users
|
||||||
|
}
|
||||||
|
}) do
|
||||||
|
"@#{actor_nickname} added suggested users: #{users_to_nicknames_string(users)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_log_entry_message(%ModerationLog{
|
||||||
|
data: %{
|
||||||
|
"actor" => %{"nickname" => actor_nickname},
|
||||||
|
"action" => "remove_suggestion",
|
||||||
|
"subject" => users
|
||||||
|
}
|
||||||
|
}) do
|
||||||
|
"@#{actor_nickname} removed suggested users: #{users_to_nicknames_string(users)}"
|
||||||
|
end
|
||||||
|
|
||||||
def get_log_entry_message(%ModerationLog{
|
def get_log_entry_message(%ModerationLog{
|
||||||
data: %{
|
data: %{
|
||||||
"actor" => %{"nickname" => actor_nickname},
|
"actor" => %{"nickname" => actor_nickname},
|
||||||
|
|
|
@ -148,6 +148,7 @@ defmodule Pleroma.User do
|
||||||
field(:last_active_at, :naive_datetime)
|
field(:last_active_at, :naive_datetime)
|
||||||
field(:disclose_client, :boolean, default: true)
|
field(:disclose_client, :boolean, default: true)
|
||||||
field(:pinned_objects, :map, default: %{})
|
field(:pinned_objects, :map, default: %{})
|
||||||
|
field(:is_suggested, :boolean, default: false)
|
||||||
|
|
||||||
embeds_one(
|
embeds_one(
|
||||||
:notification_settings,
|
:notification_settings,
|
||||||
|
@ -1676,6 +1677,22 @@ def confirm(%User{is_confirmed: false} = user) do
|
||||||
|
|
||||||
def confirm(%User{} = user), do: {:ok, user}
|
def confirm(%User{} = user), do: {:ok, user}
|
||||||
|
|
||||||
|
def set_suggestion(users, is_suggested) when is_list(users) do
|
||||||
|
Repo.transaction(fn ->
|
||||||
|
Enum.map(users, fn user ->
|
||||||
|
with {:ok, user} <- set_suggestion(user, is_suggested), do: user
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_suggestion(%User{is_suggested: is_suggested} = user, is_suggested), do: {:ok, user}
|
||||||
|
|
||||||
|
def set_suggestion(%User{} = user, is_suggested) when is_boolean(is_suggested) do
|
||||||
|
user
|
||||||
|
|> change(is_suggested: is_suggested)
|
||||||
|
|> update_and_set_cache()
|
||||||
|
end
|
||||||
|
|
||||||
def update_notification_settings(%User{} = user, settings) do
|
def update_notification_settings(%User{} = user, settings) do
|
||||||
user
|
user
|
||||||
|> cast(%{notification_settings: settings}, [])
|
|> cast(%{notification_settings: settings}, [])
|
||||||
|
|
|
@ -46,6 +46,7 @@ defmodule Pleroma.User.Query do
|
||||||
unconfirmed: boolean(),
|
unconfirmed: boolean(),
|
||||||
is_admin: boolean(),
|
is_admin: boolean(),
|
||||||
is_moderator: boolean(),
|
is_moderator: boolean(),
|
||||||
|
is_suggested: boolean(),
|
||||||
super_users: boolean(),
|
super_users: boolean(),
|
||||||
invisible: boolean(),
|
invisible: boolean(),
|
||||||
internal: boolean(),
|
internal: boolean(),
|
||||||
|
@ -167,6 +168,10 @@ defp compose_query({:unconfirmed, _}, query) do
|
||||||
where(query, [u], u.is_confirmed == false)
|
where(query, [u], u.is_confirmed == false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp compose_query({:is_suggested, bool}, query) do
|
||||||
|
where(query, [u], u.is_suggested == ^bool)
|
||||||
|
end
|
||||||
|
|
||||||
defp compose_query({:followers, %User{id: id}}, query) do
|
defp compose_query({:followers, %User{id: id}}, query) do
|
||||||
query
|
query
|
||||||
|> where([u], u.id != ^id)
|
|> where([u], u.id != ^id)
|
||||||
|
|
|
@ -35,7 +35,9 @@ defmodule Pleroma.Web.AdminAPI.UserController do
|
||||||
:toggle_activation,
|
:toggle_activation,
|
||||||
:activate,
|
:activate,
|
||||||
:deactivate,
|
:deactivate,
|
||||||
:approve
|
:approve,
|
||||||
|
:suggest,
|
||||||
|
:unsuggest
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -239,6 +241,32 @@ def approve(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = c
|
||||||
render(conn, "index.json", users: updated_users)
|
render(conn, "index.json", users: updated_users)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def suggest(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
|
||||||
|
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
|
||||||
|
{:ok, updated_users} = User.set_suggestion(users, true)
|
||||||
|
|
||||||
|
ModerationLog.insert_log(%{
|
||||||
|
actor: admin,
|
||||||
|
subject: users,
|
||||||
|
action: "add_suggestion"
|
||||||
|
})
|
||||||
|
|
||||||
|
render(conn, "index.json", users: updated_users)
|
||||||
|
end
|
||||||
|
|
||||||
|
def unsuggest(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
|
||||||
|
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
|
||||||
|
{:ok, updated_users} = User.set_suggestion(users, false)
|
||||||
|
|
||||||
|
ModerationLog.insert_log(%{
|
||||||
|
actor: admin,
|
||||||
|
subject: users,
|
||||||
|
action: "remove_suggestion"
|
||||||
|
})
|
||||||
|
|
||||||
|
render(conn, "index.json", users: updated_users)
|
||||||
|
end
|
||||||
|
|
||||||
def index(conn, params) do
|
def index(conn, params) do
|
||||||
{page, page_size} = page_params(params)
|
{page, page_size} = page_params(params)
|
||||||
filters = maybe_parse_filters(params[:filters])
|
filters = maybe_parse_filters(params[:filters])
|
||||||
|
|
|
@ -80,6 +80,7 @@ def render("show.json", %{user: user}) do
|
||||||
"tags" => user.tags || [],
|
"tags" => user.tags || [],
|
||||||
"is_confirmed" => user.is_confirmed,
|
"is_confirmed" => user.is_confirmed,
|
||||||
"is_approved" => user.is_approved,
|
"is_approved" => user.is_approved,
|
||||||
|
"is_suggested" => user.is_suggested,
|
||||||
"url" => user.uri || user.ap_id,
|
"url" => user.uri || user.ap_id,
|
||||||
"registration_reason" => user.registration_reason,
|
"registration_reason" => user.registration_reason,
|
||||||
"actor_type" => user.actor_type,
|
"actor_type" => user.actor_type,
|
||||||
|
|
|
@ -216,7 +216,71 @@ def approve_operation do
|
||||||
request_body(
|
request_body(
|
||||||
"Parameters",
|
"Parameters",
|
||||||
%Schema{
|
%Schema{
|
||||||
description: "POST body for deleting multiple users",
|
description: "POST body for approving multiple users",
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
nicknames: %Schema{
|
||||||
|
type: :array,
|
||||||
|
items: %Schema{type: :string}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
responses: %{
|
||||||
|
200 =>
|
||||||
|
Operation.response("Response", "application/json", %Schema{
|
||||||
|
type: :object,
|
||||||
|
properties: %{user: %Schema{type: :array, items: user()}}
|
||||||
|
}),
|
||||||
|
403 => Operation.response("Forbidden", "application/json", ApiError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def suggest_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["User administration"],
|
||||||
|
summary: "Suggest multiple users",
|
||||||
|
operationId: "AdminAPI.UserController.suggest",
|
||||||
|
security: [%{"oAuth" => ["admin:write:accounts"]}],
|
||||||
|
parameters: admin_api_params(),
|
||||||
|
requestBody:
|
||||||
|
request_body(
|
||||||
|
"Parameters",
|
||||||
|
%Schema{
|
||||||
|
description: "POST body for adding multiple suggested users",
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
nicknames: %Schema{
|
||||||
|
type: :array,
|
||||||
|
items: %Schema{type: :string}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
responses: %{
|
||||||
|
200 =>
|
||||||
|
Operation.response("Response", "application/json", %Schema{
|
||||||
|
type: :object,
|
||||||
|
properties: %{user: %Schema{type: :array, items: user()}}
|
||||||
|
}),
|
||||||
|
403 => Operation.response("Forbidden", "application/json", ApiError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def unsuggest_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["User administration"],
|
||||||
|
summary: "Unsuggest multiple users",
|
||||||
|
operationId: "AdminAPI.UserController.unsuggest",
|
||||||
|
security: [%{"oAuth" => ["admin:write:accounts"]}],
|
||||||
|
parameters: admin_api_params(),
|
||||||
|
requestBody:
|
||||||
|
request_body(
|
||||||
|
"Parameters",
|
||||||
|
%Schema{
|
||||||
|
description: "POST body for removing multiple suggested users",
|
||||||
type: :object,
|
type: :object,
|
||||||
properties: %{
|
properties: %{
|
||||||
nicknames: %Schema{
|
nicknames: %Schema{
|
||||||
|
|
|
@ -4,11 +4,16 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.MastodonAPI.SuggestionController do
|
defmodule Pleroma.Web.MastodonAPI.SuggestionController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
import Ecto.Query
|
||||||
|
alias Pleroma.FollowingRelationship
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.UserRelationship
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||||
plug(Pleroma.Web.Plugs.OAuthScopesPlug, %{scopes: ["read"]} when action == :index)
|
plug(Pleroma.Web.Plugs.OAuthScopesPlug, %{scopes: ["read"]} when action in [:index, :index2])
|
||||||
|
plug(Pleroma.Web.Plugs.OAuthScopesPlug, %{scopes: ["write"]} when action in [:dismiss])
|
||||||
|
|
||||||
def open_api_operation(action) do
|
def open_api_operation(action) do
|
||||||
operation = String.to_existing_atom("#{action}_operation")
|
operation = String.to_existing_atom("#{action}_operation")
|
||||||
|
@ -26,7 +31,90 @@ def index_operation do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def index2_operation do
|
||||||
|
%OpenApiSpex.Operation{
|
||||||
|
tags: ["Suggestions"],
|
||||||
|
summary: "Follow suggestions",
|
||||||
|
operationId: "SuggestionController.index2",
|
||||||
|
responses: %{
|
||||||
|
200 => Pleroma.Web.ApiSpec.Helpers.empty_array_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def dismiss_operation do
|
||||||
|
%OpenApiSpex.Operation{
|
||||||
|
tags: ["Suggestions"],
|
||||||
|
summary: "Remove a suggestion",
|
||||||
|
operationId: "SuggestionController.dismiss",
|
||||||
|
parameters: [
|
||||||
|
OpenApiSpex.Operation.parameter(
|
||||||
|
:account_id,
|
||||||
|
:path,
|
||||||
|
%OpenApiSpex.Schema{type: :string},
|
||||||
|
"Account to dismiss",
|
||||||
|
required: true
|
||||||
|
)
|
||||||
|
],
|
||||||
|
responses: %{
|
||||||
|
200 => Pleroma.Web.ApiSpec.Helpers.empty_object_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
@doc "GET /api/v1/suggestions"
|
@doc "GET /api/v1/suggestions"
|
||||||
def index(conn, params),
|
def index(conn, params),
|
||||||
do: Pleroma.Web.MastodonAPI.MastodonAPIController.empty_array(conn, params)
|
do: Pleroma.Web.MastodonAPI.MastodonAPIController.empty_array(conn, params)
|
||||||
|
|
||||||
|
@doc "GET /api/v2/suggestions"
|
||||||
|
def index2(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
limit = Map.get(params, :limit, 40) |> min(80)
|
||||||
|
|
||||||
|
users =
|
||||||
|
%{is_suggested: true, invisible: false, limit: limit}
|
||||||
|
|> User.Query.build()
|
||||||
|
|> exclude_user(user)
|
||||||
|
|> exclude_relationships(user, [:block, :mute, :suggestion_dismiss])
|
||||||
|
|> exclude_following(user)
|
||||||
|
|> Pleroma.Repo.all()
|
||||||
|
|
||||||
|
render(conn, "index.json", %{
|
||||||
|
users: users,
|
||||||
|
source: :staff,
|
||||||
|
for: user,
|
||||||
|
skip_visibility_check: true
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
defp exclude_user(query, %User{id: user_id}) do
|
||||||
|
where(query, [u], u.id != ^user_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp exclude_relationships(query, %User{id: user_id}, relationship_types) do
|
||||||
|
query
|
||||||
|
|> join(:left, [u], r in UserRelationship,
|
||||||
|
as: :user_relationships,
|
||||||
|
on:
|
||||||
|
r.target_id == u.id and r.source_id == ^user_id and
|
||||||
|
r.relationship_type in ^relationship_types
|
||||||
|
)
|
||||||
|
|> where([user_relationships: r], is_nil(r.target_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp exclude_following(query, %User{id: user_id}) do
|
||||||
|
query
|
||||||
|
|> join(:left, [u], r in FollowingRelationship,
|
||||||
|
as: :following_relationships,
|
||||||
|
on: r.following_id == u.id and r.follower_id == ^user_id and r.state == :follow_accept
|
||||||
|
)
|
||||||
|
|> where([following_relationships: r], is_nil(r.following_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc "DELETE /api/v1/suggestions/:account_id"
|
||||||
|
def dismiss(%{assigns: %{user: source}} = conn, %{account_id: user_id}) do
|
||||||
|
with %User{} = target <- User.get_cached_by_id(user_id),
|
||||||
|
{:ok, _} <- UserRelationship.create(:suggestion_dismiss, source, target) do
|
||||||
|
json(conn, %{})
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -269,6 +269,7 @@ defp do_render("show.json", %{user: user} = opts) do
|
||||||
ap_id: user.ap_id,
|
ap_id: user.ap_id,
|
||||||
also_known_as: user.also_known_as,
|
also_known_as: user.also_known_as,
|
||||||
is_confirmed: user.is_confirmed,
|
is_confirmed: user.is_confirmed,
|
||||||
|
is_suggested: user.is_suggested,
|
||||||
tags: user.tags,
|
tags: user.tags,
|
||||||
hide_followers_count: user.hide_followers_count,
|
hide_followers_count: user.hide_followers_count,
|
||||||
hide_follows_count: user.hide_follows_count,
|
hide_follows_count: user.hide_follows_count,
|
||||||
|
|
|
@ -59,6 +59,7 @@ def features do
|
||||||
"mastodon_api",
|
"mastodon_api",
|
||||||
"mastodon_api_streaming",
|
"mastodon_api_streaming",
|
||||||
"polls",
|
"polls",
|
||||||
|
"v2_suggestions",
|
||||||
"pleroma_explicit_addressing",
|
"pleroma_explicit_addressing",
|
||||||
"shareable_emoji_packs",
|
"shareable_emoji_packs",
|
||||||
"multifetch",
|
"multifetch",
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.MastodonAPI.SuggestionView do
|
||||||
|
use Pleroma.Web, :view
|
||||||
|
alias Pleroma.Web.MastodonAPI.AccountView
|
||||||
|
|
||||||
|
@source_types [:staff, :global, :past_interactions]
|
||||||
|
|
||||||
|
def render("index.json", %{users: users} = opts) do
|
||||||
|
Enum.map(users, fn user ->
|
||||||
|
opts =
|
||||||
|
opts
|
||||||
|
|> Map.put(:user, user)
|
||||||
|
|> Map.delete(:users)
|
||||||
|
|
||||||
|
render("show.json", opts)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def render("show.json", %{source: source, user: _user} = opts) when source in @source_types do
|
||||||
|
%{
|
||||||
|
source: source,
|
||||||
|
account: AccountView.render("show.json", opts)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -192,6 +192,9 @@ defmodule Pleroma.Web.Router do
|
||||||
patch("/users/deactivate", UserController, :deactivate)
|
patch("/users/deactivate", UserController, :deactivate)
|
||||||
patch("/users/approve", UserController, :approve)
|
patch("/users/approve", UserController, :approve)
|
||||||
|
|
||||||
|
patch("/users/suggest", UserController, :suggest)
|
||||||
|
patch("/users/unsuggest", UserController, :unsuggest)
|
||||||
|
|
||||||
get("/relay", RelayController, :index)
|
get("/relay", RelayController, :index)
|
||||||
post("/relay", RelayController, :follow)
|
post("/relay", RelayController, :follow)
|
||||||
delete("/relay", RelayController, :unfollow)
|
delete("/relay", RelayController, :unfollow)
|
||||||
|
@ -535,6 +538,7 @@ defmodule Pleroma.Web.Router do
|
||||||
delete("/push/subscription", SubscriptionController, :delete)
|
delete("/push/subscription", SubscriptionController, :delete)
|
||||||
|
|
||||||
get("/suggestions", SuggestionController, :index)
|
get("/suggestions", SuggestionController, :index)
|
||||||
|
delete("/suggestions/:account_id", SuggestionController, :dismiss)
|
||||||
|
|
||||||
get("/timelines/home", TimelineController, :home)
|
get("/timelines/home", TimelineController, :home)
|
||||||
get("/timelines/direct", TimelineController, :direct)
|
get("/timelines/direct", TimelineController, :direct)
|
||||||
|
@ -586,6 +590,8 @@ defmodule Pleroma.Web.Router do
|
||||||
get("/search", SearchController, :search2)
|
get("/search", SearchController, :search2)
|
||||||
|
|
||||||
post("/media", MediaController, :create2)
|
post("/media", MediaController, :create2)
|
||||||
|
|
||||||
|
get("/suggestions", SuggestionController, :index2)
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/api", Pleroma.Web do
|
scope "/api", Pleroma.Web do
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.AddSuggestions do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
alter table(:users) do
|
||||||
|
add(:is_suggested, :boolean, default: false, null: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
create_if_not_exists(index(:users, [:is_suggested]))
|
||||||
|
end
|
||||||
|
end
|
|
@ -34,4 +34,14 @@ test "it returns internal users when enabled" do
|
||||||
assert %{internal: true} |> Query.build() |> Repo.aggregate(:count) == 2
|
assert %{internal: true} |> Query.build() |> Repo.aggregate(:count) == 2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "is_suggested param" do
|
||||||
|
_user1 = insert(:user, is_suggested: false)
|
||||||
|
user2 = insert(:user, is_suggested: true)
|
||||||
|
|
||||||
|
assert [^user2] =
|
||||||
|
%{is_suggested: true}
|
||||||
|
|> User.Query.build()
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1718,6 +1718,38 @@ test "delete/1 purges a remote user" do
|
||||||
assert user.banner == %{}
|
assert user.banner == %{}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "set_suggestion" do
|
||||||
|
test "suggests a user" do
|
||||||
|
user = insert(:user, is_suggested: false)
|
||||||
|
refute user.is_suggested
|
||||||
|
{:ok, user} = User.set_suggestion(user, true)
|
||||||
|
assert user.is_suggested
|
||||||
|
end
|
||||||
|
|
||||||
|
test "suggests a list of users" do
|
||||||
|
unsuggested_users = [
|
||||||
|
insert(:user, is_suggested: false),
|
||||||
|
insert(:user, is_suggested: false),
|
||||||
|
insert(:user, is_suggested: false)
|
||||||
|
]
|
||||||
|
|
||||||
|
{:ok, users} = User.set_suggestion(unsuggested_users, true)
|
||||||
|
|
||||||
|
assert Enum.count(users) == 3
|
||||||
|
|
||||||
|
Enum.each(users, fn user ->
|
||||||
|
assert user.is_suggested
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "unsuggests a user" do
|
||||||
|
user = insert(:user, is_suggested: true)
|
||||||
|
assert user.is_suggested
|
||||||
|
{:ok, user} = User.set_suggestion(user, false)
|
||||||
|
refute user.is_suggested
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "get_public_key_for_ap_id fetches a user that's not in the db" do
|
test "get_public_key_for_ap_id fetches a user that's not in the db" do
|
||||||
assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
|
assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
|
||||||
end
|
end
|
||||||
|
|
|
@ -873,6 +873,56 @@ test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do
|
||||||
"@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}"
|
"@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "PATCH /api/pleroma/admin/users/suggest", %{admin: admin, conn: conn} do
|
||||||
|
user1 = insert(:user, is_suggested: false)
|
||||||
|
user2 = insert(:user, is_suggested: false)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> patch(
|
||||||
|
"/api/pleroma/admin/users/suggest",
|
||||||
|
%{nicknames: [user1.nickname, user2.nickname]}
|
||||||
|
)
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
assert Enum.map(response["users"], & &1["is_suggested"]) == [true, true]
|
||||||
|
[user1, user2] = Repo.reload!([user1, user2])
|
||||||
|
|
||||||
|
assert user1.is_suggested
|
||||||
|
assert user2.is_suggested
|
||||||
|
|
||||||
|
log_entry = Repo.one(ModerationLog)
|
||||||
|
|
||||||
|
assert ModerationLog.get_log_entry_message(log_entry) ==
|
||||||
|
"@#{admin.nickname} added suggested users: @#{user1.nickname}, @#{user2.nickname}"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "PATCH /api/pleroma/admin/users/unsuggest", %{admin: admin, conn: conn} do
|
||||||
|
user1 = insert(:user, is_suggested: true)
|
||||||
|
user2 = insert(:user, is_suggested: true)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> patch(
|
||||||
|
"/api/pleroma/admin/users/unsuggest",
|
||||||
|
%{nicknames: [user1.nickname, user2.nickname]}
|
||||||
|
)
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
assert Enum.map(response["users"], & &1["is_suggested"]) == [false, false]
|
||||||
|
[user1, user2] = Repo.reload!([user1, user2])
|
||||||
|
|
||||||
|
refute user1.is_suggested
|
||||||
|
refute user2.is_suggested
|
||||||
|
|
||||||
|
log_entry = Repo.one(ModerationLog)
|
||||||
|
|
||||||
|
assert ModerationLog.get_log_entry_message(log_entry) ==
|
||||||
|
"@#{admin.nickname} removed suggested users: @#{user1.nickname}, @#{user2.nickname}"
|
||||||
|
end
|
||||||
|
|
||||||
test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
|
test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
|
@ -906,6 +956,7 @@ defp user_response(user, attrs \\ %{}) do
|
||||||
"display_name" => HTML.strip_tags(user.name || user.nickname),
|
"display_name" => HTML.strip_tags(user.name || user.nickname),
|
||||||
"is_confirmed" => true,
|
"is_confirmed" => true,
|
||||||
"is_approved" => true,
|
"is_approved" => true,
|
||||||
|
"is_suggested" => false,
|
||||||
"url" => user.ap_id,
|
"url" => user.ap_id,
|
||||||
"registration_reason" => nil,
|
"registration_reason" => nil,
|
||||||
"actor_type" => "Person",
|
"actor_type" => "Person",
|
||||||
|
|
|
@ -4,8 +4,11 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.MastodonAPI.SuggestionControllerTest do
|
defmodule Pleroma.Web.MastodonAPI.SuggestionControllerTest do
|
||||||
use Pleroma.Web.ConnCase, async: true
|
use Pleroma.Web.ConnCase, async: true
|
||||||
|
alias Pleroma.UserRelationship
|
||||||
|
alias Pleroma.Web.CommonAPI
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
setup do: oauth_access(["read"])
|
setup do: oauth_access(["read", "write"])
|
||||||
|
|
||||||
test "returns empty result", %{conn: conn} do
|
test "returns empty result", %{conn: conn} do
|
||||||
res =
|
res =
|
||||||
|
@ -15,4 +18,66 @@ test "returns empty result", %{conn: conn} do
|
||||||
|
|
||||||
assert res == []
|
assert res == []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "returns v2 suggestions", %{conn: conn} do
|
||||||
|
%{id: user_id} = insert(:user, is_suggested: true)
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> get("/api/v2/suggestions")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
assert [%{"source" => "staff", "account" => %{"id" => ^user_id}}] = res
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns v2 suggestions excluding dismissed accounts", %{conn: conn} do
|
||||||
|
%{id: user_id} = insert(:user, is_suggested: true)
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> delete("/api/v1/suggestions/#{user_id}")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> get("/api/v2/suggestions")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
assert [] = res
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns v2 suggestions excluding blocked accounts", %{conn: conn, user: blocker} do
|
||||||
|
blocked = insert(:user, is_suggested: true)
|
||||||
|
{:ok, _} = CommonAPI.block(blocker, blocked)
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> get("/api/v2/suggestions")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
assert [] = res
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns v2 suggestions excluding followed accounts", %{conn: conn, user: follower} do
|
||||||
|
followed = insert(:user, is_suggested: true)
|
||||||
|
{:ok, _, _, _} = CommonAPI.follow(follower, followed)
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> get("/api/v2/suggestions")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
assert [] = res
|
||||||
|
end
|
||||||
|
|
||||||
|
test "dismiss suggestion", %{conn: conn, user: source} do
|
||||||
|
target = insert(:user, is_suggested: true)
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> delete("/api/v1/suggestions/#{target.id}")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
assert res == %{}
|
||||||
|
assert UserRelationship.exists?(:suggestion_dismiss, source, target)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -83,6 +83,7 @@ test "Represent a user account" do
|
||||||
tags: [],
|
tags: [],
|
||||||
is_admin: false,
|
is_admin: false,
|
||||||
is_moderator: false,
|
is_moderator: false,
|
||||||
|
is_suggested: false,
|
||||||
hide_favorites: true,
|
hide_favorites: true,
|
||||||
hide_followers: false,
|
hide_followers: false,
|
||||||
hide_follows: false,
|
hide_follows: false,
|
||||||
|
@ -183,6 +184,7 @@ test "Represent a Service(bot) account" do
|
||||||
tags: [],
|
tags: [],
|
||||||
is_admin: false,
|
is_admin: false,
|
||||||
is_moderator: false,
|
is_moderator: false,
|
||||||
|
is_suggested: false,
|
||||||
hide_favorites: true,
|
hide_favorites: true,
|
||||||
hide_followers: false,
|
hide_followers: false,
|
||||||
hide_follows: false,
|
hide_follows: false,
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.MastodonAPI.SuggestionViewTest do
|
||||||
|
use Pleroma.DataCase, async: true
|
||||||
|
import Pleroma.Factory
|
||||||
|
alias Pleroma.Web.MastodonAPI.SuggestionView, as: View
|
||||||
|
|
||||||
|
test "show.json" do
|
||||||
|
user = insert(:user, is_suggested: true)
|
||||||
|
json = View.render("show.json", %{user: user, source: :staff, skip_visibility_check: true})
|
||||||
|
|
||||||
|
assert json.source == :staff
|
||||||
|
assert json.account.id == user.id
|
||||||
|
end
|
||||||
|
|
||||||
|
test "index.json" do
|
||||||
|
user1 = insert(:user, is_suggested: true)
|
||||||
|
user2 = insert(:user, is_suggested: true)
|
||||||
|
user3 = insert(:user, is_suggested: true)
|
||||||
|
|
||||||
|
[suggestion1, suggestion2, suggestion3] =
|
||||||
|
View.render("index.json", %{
|
||||||
|
users: [user1, user2, user3],
|
||||||
|
source: :staff,
|
||||||
|
skip_visibility_check: true
|
||||||
|
})
|
||||||
|
|
||||||
|
assert suggestion1.source == :staff
|
||||||
|
assert suggestion2.account.id == user2.id
|
||||||
|
assert suggestion3.account.url == user3.ap_id
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue