Add OpenAPI spec for AdminAPI.InviteController See merge request pleroma/pleroma!25851570-levenshtein-distance-user-search
@@ -16,7 +16,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do | |||||
alias Pleroma.ReportNote | alias Pleroma.ReportNote | ||||
alias Pleroma.Stats | alias Pleroma.Stats | ||||
alias Pleroma.User | alias Pleroma.User | ||||
alias Pleroma.UserInviteToken | |||||
alias Pleroma.Web.ActivityPub.ActivityPub | alias Pleroma.Web.ActivityPub.ActivityPub | ||||
alias Pleroma.Web.ActivityPub.Builder | alias Pleroma.Web.ActivityPub.Builder | ||||
alias Pleroma.Web.ActivityPub.Pipeline | alias Pleroma.Web.ActivityPub.Pipeline | ||||
@@ -69,14 +68,6 @@ 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( | plug( | ||||
OAuthScopesPlug, | OAuthScopesPlug, | ||||
%{scopes: ["write:follows"], admin: true} | %{scopes: ["write:follows"], admin: true} | ||||
@@ -575,69 +566,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do | |||||
end | end | ||||
end | end | ||||
@doc "Sends registration invite via email" | |||||
def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do | |||||
with {_, false} <- {:registrations_open, Config.get([:instance, :registrations_open])}, | |||||
{_, true} <- {:invites_enabled, Config.get([:instance, :invites_enabled])}, | |||||
{:ok, invite_token} <- UserInviteToken.create_invite(), | |||||
email <- | |||||
Pleroma.Emails.UserEmail.user_invitation_email( | |||||
user, | |||||
invite_token, | |||||
email, | |||||
params["name"] | |||||
), | |||||
{:ok, _} <- Pleroma.Emails.Mailer.deliver(email) do | |||||
json_response(conn, :no_content, "") | |||||
else | |||||
{:registrations_open, _} -> | |||||
{:error, "To send invites you need to set the `registrations_open` option to false."} | |||||
{:invites_enabled, _} -> | |||||
{:error, "To send invites you need to set the `invites_enabled` option to true."} | |||||
end | |||||
end | |||||
@doc "Create an account registration invite token" | |||||
def create_invite_token(conn, params) do | |||||
opts = %{} | |||||
opts = | |||||
if params["max_use"], | |||||
do: Map.put(opts, :max_use, params["max_use"]), | |||||
else: opts | |||||
opts = | |||||
if params["expires_at"], | |||||
do: Map.put(opts, :expires_at, params["expires_at"]), | |||||
else: opts | |||||
{:ok, invite} = UserInviteToken.create_invite(opts) | |||||
json(conn, AccountView.render("invite.json", %{invite: invite})) | |||||
end | |||||
@doc "Get list of created invites" | |||||
def invites(conn, _params) do | |||||
invites = UserInviteToken.list_invites() | |||||
conn | |||||
|> put_view(AccountView) | |||||
|> render("invites.json", %{invites: invites}) | |||||
end | |||||
@doc "Revokes invite by token" | |||||
def revoke_invite(conn, %{"token" => token}) do | |||||
with {:ok, invite} <- UserInviteToken.find_by_token(token), | |||||
{:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) do | |||||
conn | |||||
|> put_view(AccountView) | |||||
|> render("invite.json", %{invite: updated_invite}) | |||||
else | |||||
nil -> {:error, :not_found} | |||||
end | |||||
end | |||||
@doc "Get a password reset token (base64 string) for given nickname" | @doc "Get a password reset token (base64 string) for given nickname" | ||||
def get_password_reset(conn, %{"nickname" => nickname}) do | def get_password_reset(conn, %{"nickname" => nickname}) do | ||||
(%User{local: true} = user) = User.get_cached_by_nickname(nickname) | (%User{local: true} = user) = User.get_cached_by_nickname(nickname) | ||||
@@ -0,0 +1,78 @@ | |||||
# Pleroma: A lightweight social networking server | |||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> | |||||
# SPDX-License-Identifier: AGPL-3.0-only | |||||
defmodule Pleroma.Web.AdminAPI.InviteController do | |||||
use Pleroma.Web, :controller | |||||
import Pleroma.Web.ControllerHelper, only: [json_response: 3] | |||||
alias Pleroma.Config | |||||
alias Pleroma.Plugs.OAuthScopesPlug | |||||
alias Pleroma.UserInviteToken | |||||
require Logger | |||||
plug(Pleroma.Web.ApiSpec.CastAndValidate) | |||||
plug(OAuthScopesPlug, %{scopes: ["read:invites"], admin: true} when action == :index) | |||||
plug( | |||||
OAuthScopesPlug, | |||||
%{scopes: ["write:invites"], admin: true} when action in [:create, :revoke, :email] | |||||
) | |||||
action_fallback(Pleroma.Web.AdminAPI.FallbackController) | |||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.InviteOperation | |||||
@doc "Get list of created invites" | |||||
def index(conn, _params) do | |||||
invites = UserInviteToken.list_invites() | |||||
render(conn, "index.json", invites: invites) | |||||
end | |||||
@doc "Create an account registration invite token" | |||||
def create(%{body_params: params} = conn, _) do | |||||
{:ok, invite} = UserInviteToken.create_invite(params) | |||||
render(conn, "show.json", invite: invite) | |||||
end | |||||
@doc "Revokes invite by token" | |||||
def revoke(%{body_params: %{token: token}} = conn, _) do | |||||
with {:ok, invite} <- UserInviteToken.find_by_token(token), | |||||
{:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) do | |||||
render(conn, "show.json", invite: updated_invite) | |||||
else | |||||
nil -> {:error, :not_found} | |||||
error -> error | |||||
end | |||||
end | |||||
@doc "Sends registration invite via email" | |||||
def email(%{assigns: %{user: user}, body_params: %{email: email} = params} = conn, _) do | |||||
with {_, false} <- {:registrations_open, Config.get([:instance, :registrations_open])}, | |||||
{_, true} <- {:invites_enabled, Config.get([:instance, :invites_enabled])}, | |||||
{:ok, invite_token} <- UserInviteToken.create_invite(), | |||||
{:ok, _} <- | |||||
user | |||||
|> Pleroma.Emails.UserEmail.user_invitation_email( | |||||
invite_token, | |||||
email, | |||||
params[:name] | |||||
) | |||||
|> Pleroma.Emails.Mailer.deliver() do | |||||
json_response(conn, :no_content, "") | |||||
else | |||||
{:registrations_open, _} -> | |||||
{:error, "To send invites you need to set the `registrations_open` option to false."} | |||||
{:invites_enabled, _} -> | |||||
{:error, "To send invites you need to set the `invites_enabled` option to true."} | |||||
{:error, error} -> | |||||
{:error, error} | |||||
end | |||||
end | |||||
end |
@@ -80,24 +80,6 @@ defmodule Pleroma.Web.AdminAPI.AccountView do | |||||
} | } | ||||
end | end | ||||
def render("invite.json", %{invite: invite}) do | |||||
%{ | |||||
"id" => invite.id, | |||||
"token" => invite.token, | |||||
"used" => invite.used, | |||||
"expires_at" => invite.expires_at, | |||||
"uses" => invite.uses, | |||||
"max_use" => invite.max_use, | |||||
"invite_type" => invite.invite_type | |||||
} | |||||
end | |||||
def render("invites.json", %{invites: invites}) do | |||||
%{ | |||||
invites: render_many(invites, AccountView, "invite.json", as: :invite) | |||||
} | |||||
end | |||||
def render("created.json", %{user: user}) do | def render("created.json", %{user: user}) do | ||||
%{ | %{ | ||||
type: "success", | type: "success", | ||||
@@ -0,0 +1,25 @@ | |||||
# Pleroma: A lightweight social networking server | |||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> | |||||
# SPDX-License-Identifier: AGPL-3.0-only | |||||
defmodule Pleroma.Web.AdminAPI.InviteView do | |||||
use Pleroma.Web, :view | |||||
def render("index.json", %{invites: invites}) do | |||||
%{ | |||||
invites: render_many(invites, __MODULE__, "show.json", as: :invite) | |||||
} | |||||
end | |||||
def render("show.json", %{invite: invite}) do | |||||
%{ | |||||
"id" => invite.id, | |||||
"token" => invite.token, | |||||
"used" => invite.used, | |||||
"expires_at" => invite.expires_at, | |||||
"uses" => invite.uses, | |||||
"max_use" => invite.max_use, | |||||
"invite_type" => invite.invite_type | |||||
} | |||||
end | |||||
end |
@@ -0,0 +1,148 @@ | |||||
# Pleroma: A lightweight social networking server | |||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> | |||||
# SPDX-License-Identifier: AGPL-3.0-only | |||||
defmodule Pleroma.Web.ApiSpec.Admin.InviteOperation do | |||||
alias OpenApiSpex.Operation | |||||
alias OpenApiSpex.Schema | |||||
alias Pleroma.Web.ApiSpec.Schemas.ApiError | |||||
import Pleroma.Web.ApiSpec.Helpers | |||||
def open_api_operation(action) do | |||||
operation = String.to_existing_atom("#{action}_operation") | |||||
apply(__MODULE__, operation, []) | |||||
end | |||||
def index_operation do | |||||
%Operation{ | |||||
tags: ["Admin", "Invites"], | |||||
summary: "Get a list of generated invites", | |||||
operationId: "AdminAPI.InviteController.index", | |||||
security: [%{"oAuth" => ["read:invites"]}], | |||||
responses: %{ | |||||
200 => | |||||
Operation.response("Invites", "application/json", %Schema{ | |||||
type: :object, | |||||
properties: %{ | |||||
invites: %Schema{type: :array, items: invite()} | |||||
}, | |||||
example: %{ | |||||
"invites" => [ | |||||
%{ | |||||
"id" => 123, | |||||
"token" => "kSQtDj_GNy2NZsL9AQDFIsHN5qdbguB6qRg3WHw6K1U=", | |||||
"used" => true, | |||||
"expires_at" => nil, | |||||
"uses" => 0, | |||||
"max_use" => nil, | |||||
"invite_type" => "one_time" | |||||
} | |||||
] | |||||
} | |||||
}) | |||||
} | |||||
} | |||||
end | |||||
def create_operation do | |||||
%Operation{ | |||||
tags: ["Admin", "Invites"], | |||||
summary: "Create an account registration invite token", | |||||
operationId: "AdminAPI.InviteController.create", | |||||
security: [%{"oAuth" => ["write:invites"]}], | |||||
requestBody: | |||||
request_body("Parameters", %Schema{ | |||||
type: :object, | |||||
properties: %{ | |||||
max_use: %Schema{type: :integer}, | |||||
expires_at: %Schema{type: :string, format: :date, example: "2020-04-20"} | |||||
} | |||||
}), | |||||
responses: %{ | |||||
200 => Operation.response("Invite", "application/json", invite()) | |||||
} | |||||
} | |||||
end | |||||
def revoke_operation do | |||||
%Operation{ | |||||
tags: ["Admin", "Invites"], | |||||
summary: "Revoke invite by token", | |||||
operationId: "AdminAPI.InviteController.revoke", | |||||
security: [%{"oAuth" => ["write:invites"]}], | |||||
requestBody: | |||||
request_body( | |||||
"Parameters", | |||||
%Schema{ | |||||
type: :object, | |||||
required: [:token], | |||||
properties: %{ | |||||
token: %Schema{type: :string} | |||||
} | |||||
}, | |||||
required: true | |||||
), | |||||
responses: %{ | |||||
200 => Operation.response("Invite", "application/json", invite()), | |||||
400 => Operation.response("Bad Request", "application/json", ApiError), | |||||
404 => Operation.response("Not Found", "application/json", ApiError) | |||||
} | |||||
} | |||||
end | |||||
def email_operation do | |||||
%Operation{ | |||||
tags: ["Admin", "Invites"], | |||||
summary: "Sends registration invite via email", | |||||
operationId: "AdminAPI.InviteController.email", | |||||
security: [%{"oAuth" => ["write:invites"]}], | |||||
requestBody: | |||||
request_body( | |||||
"Parameters", | |||||
%Schema{ | |||||
type: :object, | |||||
required: [:email], | |||||
properties: %{ | |||||
email: %Schema{type: :string, format: :email}, | |||||
name: %Schema{type: :string} | |||||
} | |||||
}, | |||||
required: true | |||||
), | |||||
responses: %{ | |||||
204 => no_content_response(), | |||||
400 => Operation.response("Bad Request", "application/json", ApiError), | |||||
403 => Operation.response("Forbidden", "application/json", ApiError) | |||||
} | |||||
} | |||||
end | |||||
defp invite do | |||||
%Schema{ | |||||
title: "Invite", | |||||
type: :object, | |||||
properties: %{ | |||||
id: %Schema{type: :integer}, | |||||
token: %Schema{type: :string}, | |||||
used: %Schema{type: :boolean}, | |||||
expires_at: %Schema{type: :string, format: :date, nullable: true}, | |||||
uses: %Schema{type: :integer}, | |||||
max_use: %Schema{type: :integer, nullable: true}, | |||||
invite_type: %Schema{ | |||||
type: :string, | |||||
enum: ["one_time", "reusable", "date_limited", "reusable_date_limited"] | |||||
} | |||||
}, | |||||
example: %{ | |||||
"id" => 123, | |||||
"token" => "kSQtDj_GNy2NZsL9AQDFIsHN5qdbguB6qRg3WHw6K1U=", | |||||
"used" => true, | |||||
"expires_at" => nil, | |||||
"uses" => 0, | |||||
"max_use" => nil, | |||||
"invite_type" => "one_time" | |||||
} | |||||
} | |||||
end | |||||
end |
@@ -164,10 +164,10 @@ defmodule Pleroma.Web.Router do | |||||
post("/relay", AdminAPIController, :relay_follow) | post("/relay", AdminAPIController, :relay_follow) | ||||
delete("/relay", AdminAPIController, :relay_unfollow) | delete("/relay", AdminAPIController, :relay_unfollow) | ||||
post("/users/invite_token", AdminAPIController, :create_invite_token) | |||||
get("/users/invites", AdminAPIController, :invites) | |||||
post("/users/revoke_invite", AdminAPIController, :revoke_invite) | |||||
post("/users/email_invite", AdminAPIController, :email_invite) | |||||
post("/users/invite_token", InviteController, :create) | |||||
get("/users/invites", InviteController, :index) | |||||
post("/users/revoke_invite", InviteController, :revoke) | |||||
post("/users/email_invite", InviteController, :email) | |||||
get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) | get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) | ||||
patch("/users/force_password_reset", AdminAPIController, :force_password_reset) | patch("/users/force_password_reset", AdminAPIController, :force_password_reset) | ||||
@@ -20,7 +20,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do | |||||
alias Pleroma.ReportNote | alias Pleroma.ReportNote | ||||
alias Pleroma.Tests.ObanHelpers | alias Pleroma.Tests.ObanHelpers | ||||
alias Pleroma.User | alias Pleroma.User | ||||
alias Pleroma.UserInviteToken | |||||
alias Pleroma.Web | alias Pleroma.Web | ||||
alias Pleroma.Web.ActivityPub.Relay | alias Pleroma.Web.ActivityPub.Relay | ||||
alias Pleroma.Web.CommonAPI | alias Pleroma.Web.CommonAPI | ||||
@@ -588,122 +587,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do | |||||
end | end | ||||
end | end | ||||
describe "POST /api/pleroma/admin/email_invite, with valid config" do | |||||
setup do: clear_config([:instance, :registrations_open], false) | |||||
setup do: clear_config([:instance, :invites_enabled], true) | |||||
test "sends invitation and returns 204", %{admin: admin, conn: conn} do | |||||
recipient_email = "foo@bar.com" | |||||
recipient_name = "J. D." | |||||
conn = | |||||
post( | |||||
conn, | |||||
"/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}" | |||||
) | |||||
assert json_response(conn, :no_content) | |||||
token_record = List.last(Repo.all(Pleroma.UserInviteToken)) | |||||
assert token_record | |||||
refute token_record.used | |||||
notify_email = Config.get([:instance, :notify_email]) | |||||
instance_name = Config.get([:instance, :name]) | |||||
email = | |||||
Pleroma.Emails.UserEmail.user_invitation_email( | |||||
admin, | |||||
token_record, | |||||
recipient_email, | |||||
recipient_name | |||||
) | |||||
Swoosh.TestAssertions.assert_email_sent( | |||||
from: {instance_name, notify_email}, | |||||
to: {recipient_name, recipient_email}, | |||||
html_body: email.html_body | |||||
) | |||||
end | |||||
test "it returns 403 if requested by a non-admin" do | |||||
non_admin_user = insert(:user) | |||||
token = insert(:oauth_token, user: non_admin_user) | |||||
conn = | |||||
build_conn() | |||||
|> assign(:user, non_admin_user) | |||||
|> assign(:token, token) | |||||
|> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD") | |||||
assert json_response(conn, :forbidden) | |||||
end | |||||
test "email with +", %{conn: conn, admin: admin} do | |||||
recipient_email = "foo+bar@baz.com" | |||||
conn | |||||
|> put_req_header("content-type", "application/json;charset=utf-8") | |||||
|> post("/api/pleroma/admin/users/email_invite", %{email: recipient_email}) | |||||
|> json_response(:no_content) | |||||
token_record = | |||||
Pleroma.UserInviteToken | |||||
|> Repo.all() | |||||
|> List.last() | |||||
assert token_record | |||||
refute token_record.used | |||||
notify_email = Config.get([:instance, :notify_email]) | |||||
instance_name = Config.get([:instance, :name]) | |||||
email = | |||||
Pleroma.Emails.UserEmail.user_invitation_email( | |||||
admin, | |||||
token_record, | |||||
recipient_email | |||||
) | |||||
Swoosh.TestAssertions.assert_email_sent( | |||||
from: {instance_name, notify_email}, | |||||
to: recipient_email, | |||||
html_body: email.html_body | |||||
) | |||||
end | |||||
end | |||||
describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do | |||||
setup do: clear_config([:instance, :registrations_open]) | |||||
setup do: clear_config([:instance, :invites_enabled]) | |||||
test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do | |||||
Config.put([:instance, :registrations_open], false) | |||||
Config.put([:instance, :invites_enabled], false) | |||||
conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD") | |||||
assert json_response(conn, :bad_request) == | |||||
%{ | |||||
"error" => | |||||
"To send invites you need to set the `invites_enabled` option to true." | |||||
} | |||||
end | |||||
test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do | |||||
Config.put([:instance, :registrations_open], true) | |||||
Config.put([:instance, :invites_enabled], true) | |||||
conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD") | |||||
assert json_response(conn, :bad_request) == | |||||
%{ | |||||
"error" => | |||||
"To send invites you need to set the `registrations_open` option to false." | |||||
} | |||||
end | |||||
end | |||||
test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do | test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do | ||||
user = insert(:user) | user = insert(:user) | ||||
@@ -1315,112 +1198,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do | |||||
end | end | ||||
end | end | ||||
describe "POST /api/pleroma/admin/users/invite_token" do | |||||
test "without options", %{conn: conn} do | |||||
conn = post(conn, "/api/pleroma/admin/users/invite_token") | |||||
invite_json = json_response(conn, 200) | |||||
invite = UserInviteToken.find_by_token!(invite_json["token"]) | |||||
refute invite.used | |||||
refute invite.expires_at | |||||
refute invite.max_use | |||||
assert invite.invite_type == "one_time" | |||||
end | |||||
test "with expires_at", %{conn: conn} do | |||||
conn = | |||||
post(conn, "/api/pleroma/admin/users/invite_token", %{ | |||||
"expires_at" => Date.to_string(Date.utc_today()) | |||||
}) | |||||
invite_json = json_response(conn, 200) | |||||
invite = UserInviteToken.find_by_token!(invite_json["token"]) | |||||
refute invite.used | |||||
assert invite.expires_at == Date.utc_today() | |||||
refute invite.max_use | |||||
assert invite.invite_type == "date_limited" | |||||
end | |||||
test "with max_use", %{conn: conn} do | |||||
conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150}) | |||||
invite_json = json_response(conn, 200) | |||||
invite = UserInviteToken.find_by_token!(invite_json["token"]) | |||||
refute invite.used | |||||
refute invite.expires_at | |||||
assert invite.max_use == 150 | |||||
assert invite.invite_type == "reusable" | |||||
end | |||||
test "with max use and expires_at", %{conn: conn} do | |||||
conn = | |||||
post(conn, "/api/pleroma/admin/users/invite_token", %{ | |||||
"max_use" => 150, | |||||
"expires_at" => Date.to_string(Date.utc_today()) | |||||
}) | |||||
invite_json = json_response(conn, 200) | |||||
invite = UserInviteToken.find_by_token!(invite_json["token"]) | |||||
refute invite.used | |||||
assert invite.expires_at == Date.utc_today() | |||||
assert invite.max_use == 150 | |||||
assert invite.invite_type == "reusable_date_limited" | |||||
end | |||||
end | |||||
describe "GET /api/pleroma/admin/users/invites" do | |||||
test "no invites", %{conn: conn} do | |||||
conn = get(conn, "/api/pleroma/admin/users/invites") | |||||
assert json_response(conn, 200) == %{"invites" => []} | |||||
end | |||||
test "with invite", %{conn: conn} do | |||||
{:ok, invite} = UserInviteToken.create_invite() | |||||
conn = get(conn, "/api/pleroma/admin/users/invites") | |||||
assert json_response(conn, 200) == %{ | |||||
"invites" => [ | |||||
%{ | |||||
"expires_at" => nil, | |||||
"id" => invite.id, | |||||
"invite_type" => "one_time", | |||||
"max_use" => nil, | |||||
"token" => invite.token, | |||||
"used" => false, | |||||
"uses" => 0 | |||||
} | |||||
] | |||||
} | |||||
end | |||||
end | |||||
describe "POST /api/pleroma/admin/users/revoke_invite" do | |||||
test "with token", %{conn: conn} do | |||||
{:ok, invite} = UserInviteToken.create_invite() | |||||
conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token}) | |||||
assert json_response(conn, 200) == %{ | |||||
"expires_at" => nil, | |||||
"id" => invite.id, | |||||
"invite_type" => "one_time", | |||||
"max_use" => nil, | |||||
"token" => invite.token, | |||||
"used" => true, | |||||
"uses" => 0 | |||||
} | |||||
end | |||||
test "with invalid token", %{conn: conn} do | |||||
conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"}) | |||||
assert json_response(conn, :not_found) == %{"error" => "Not found"} | |||||
end | |||||
end | |||||
describe "GET /api/pleroma/admin/reports/:id" do | describe "GET /api/pleroma/admin/reports/:id" do | ||||
test "returns report by its id", %{conn: conn} do | test "returns report by its id", %{conn: conn} do | ||||
[reporter, target_user] = insert_pair(:user) | [reporter, target_user] = insert_pair(:user) | ||||
@@ -0,0 +1,281 @@ | |||||
# Pleroma: A lightweight social networking server | |||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> | |||||
# SPDX-License-Identifier: AGPL-3.0-only | |||||
defmodule Pleroma.Web.AdminAPI.InviteControllerTest do | |||||
use Pleroma.Web.ConnCase, async: true | |||||
import Pleroma.Factory | |||||
alias Pleroma.Config | |||||
alias Pleroma.Repo | |||||
alias Pleroma.UserInviteToken | |||||
setup do | |||||
admin = insert(:user, is_admin: true) | |||||
token = insert(:oauth_admin_token, user: admin) | |||||
conn = | |||||
build_conn() | |||||
|> assign(:user, admin) | |||||
|> assign(:token, token) | |||||
{:ok, %{admin: admin, token: token, conn: conn}} | |||||
end | |||||
describe "POST /api/pleroma/admin/users/email_invite, with valid config" do | |||||
setup do: clear_config([:instance, :registrations_open], false) | |||||
setup do: clear_config([:instance, :invites_enabled], true) | |||||
test "sends invitation and returns 204", %{admin: admin, conn: conn} do | |||||
recipient_email = "foo@bar.com" | |||||
recipient_name = "J. D." | |||||
conn = | |||||
conn | |||||
|> put_req_header("content-type", "application/json;charset=utf-8") | |||||
|> post("/api/pleroma/admin/users/email_invite", %{ | |||||
email: recipient_email, | |||||
name: recipient_name | |||||
}) | |||||
assert json_response_and_validate_schema(conn, :no_content) | |||||
token_record = List.last(Repo.all(Pleroma.UserInviteToken)) | |||||
assert token_record | |||||
refute token_record.used | |||||
notify_email = Config.get([:instance, :notify_email]) | |||||
instance_name = Config.get([:instance, :name]) | |||||
email = | |||||
Pleroma.Emails.UserEmail.user_invitation_email( | |||||
admin, | |||||
token_record, | |||||
recipient_email, | |||||
recipient_name | |||||
) | |||||
Swoosh.TestAssertions.assert_email_sent( | |||||
from: {instance_name, notify_email}, | |||||
to: {recipient_name, recipient_email}, | |||||
html_body: email.html_body | |||||
) | |||||
end | |||||
test "it returns 403 if requested by a non-admin" do | |||||
non_admin_user = insert(:user) | |||||
token = insert(:oauth_token, user: non_admin_user) | |||||
conn = | |||||
build_conn() | |||||
|> assign(:user, non_admin_user) | |||||
|> assign(:token, token) | |||||
|> put_req_header("content-type", "application/json;charset=utf-8") | |||||
|> post("/api/pleroma/admin/users/email_invite", %{ | |||||
email: "foo@bar.com", | |||||
name: "JD" | |||||
}) | |||||
assert json_response(conn, :forbidden) | |||||
end | |||||
test "email with +", %{conn: conn, admin: admin} do | |||||
recipient_email = "foo+bar@baz.com" | |||||
conn | |||||
|> put_req_header("content-type", "application/json;charset=utf-8") | |||||
|> post("/api/pleroma/admin/users/email_invite", %{email: recipient_email}) | |||||
|> json_response_and_validate_schema(:no_content) | |||||
token_record = | |||||
Pleroma.UserInviteToken | |||||
|> Repo.all() | |||||
|> List.last() | |||||
assert token_record | |||||
refute token_record.used | |||||
notify_email = Config.get([:instance, :notify_email]) | |||||
instance_name = Config.get([:instance, :name]) | |||||
email = | |||||
Pleroma.Emails.UserEmail.user_invitation_email( | |||||
admin, | |||||
token_record, | |||||
recipient_email | |||||
) | |||||
Swoosh.TestAssertions.assert_email_sent( | |||||
from: {instance_name, notify_email}, | |||||
to: recipient_email, | |||||
html_body: email.html_body | |||||
) | |||||
end | |||||
end | |||||
describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do | |||||
setup do: clear_config([:instance, :registrations_open]) | |||||
setup do: clear_config([:instance, :invites_enabled]) | |||||
test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do | |||||
Config.put([:instance, :registrations_open], false) | |||||
Config.put([:instance, :invites_enabled], false) | |||||
conn = | |||||
conn | |||||
|> put_req_header("content-type", "application/json") | |||||
|> post("/api/pleroma/admin/users/email_invite", %{ | |||||
email: "foo@bar.com", | |||||
name: "JD" | |||||
}) | |||||
assert json_response_and_validate_schema(conn, :bad_request) == | |||||
%{ | |||||
"error" => | |||||
"To send invites you need to set the `invites_enabled` option to true." | |||||
} | |||||
end | |||||
test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do | |||||
Config.put([:instance, :registrations_open], true) | |||||
Config.put([:instance, :invites_enabled], true) | |||||
conn = | |||||
conn | |||||
|> put_req_header("content-type", "application/json") | |||||
|> post("/api/pleroma/admin/users/email_invite", %{ | |||||
email: "foo@bar.com", | |||||
name: "JD" | |||||
}) | |||||
assert json_response_and_validate_schema(conn, :bad_request) == | |||||
%{ | |||||
"error" => | |||||
"To send invites you need to set the `registrations_open` option to false." | |||||
} | |||||
end | |||||
end | |||||
describe "POST /api/pleroma/admin/users/invite_token" do | |||||
test "without options", %{conn: conn} do | |||||
conn = | |||||
conn | |||||
|> put_req_header("content-type", "application/json") | |||||
|> post("/api/pleroma/admin/users/invite_token") | |||||
invite_json = json_response_and_validate_schema(conn, 200) | |||||
invite = UserInviteToken.find_by_token!(invite_json["token"]) | |||||
refute invite.used | |||||
refute invite.expires_at | |||||
refute invite.max_use | |||||
assert invite.invite_type == "one_time" | |||||
end | |||||
test "with expires_at", %{conn: conn} do | |||||
conn = | |||||
conn | |||||
|> put_req_header("content-type", "application/json") | |||||
|> post("/api/pleroma/admin/users/invite_token", %{ | |||||
"expires_at" => Date.to_string(Date.utc_today()) | |||||
}) | |||||
invite_json = json_response_and_validate_schema(conn, 200) | |||||
invite = UserInviteToken.find_by_token!(invite_json["token"]) | |||||
refute invite.used | |||||
assert invite.expires_at == Date.utc_today() | |||||
refute invite.max_use | |||||
assert invite.invite_type == "date_limited" | |||||
end | |||||
test "with max_use", %{conn: conn} do | |||||
conn = | |||||
conn | |||||
|> put_req_header("content-type", "application/json") | |||||
|> post("/api/pleroma/admin/users/invite_token", %{"max_use" => 150}) | |||||
invite_json = json_response_and_validate_schema(conn, 200) | |||||
invite = UserInviteToken.find_by_token!(invite_json["token"]) | |||||
refute invite.used | |||||
refute invite.expires_at | |||||
assert invite.max_use == 150 | |||||
assert invite.invite_type == "reusable" | |||||
end | |||||
test "with max use and expires_at", %{conn: conn} do | |||||
conn = | |||||
conn | |||||
|> put_req_header("content-type", "application/json") | |||||
|> post("/api/pleroma/admin/users/invite_token", %{ | |||||
"max_use" => 150, | |||||
"expires_at" => Date.to_string(Date.utc_today()) | |||||
}) | |||||
invite_json = json_response_and_validate_schema(conn, 200) | |||||
invite = UserInviteToken.find_by_token!(invite_json["token"]) | |||||
refute invite.used | |||||
assert invite.expires_at == Date.utc_today() | |||||
assert invite.max_use == 150 | |||||
assert invite.invite_type == "reusable_date_limited" | |||||
end | |||||
end | |||||
describe "GET /api/pleroma/admin/users/invites" do | |||||
test "no invites", %{conn: conn} do | |||||
conn = get(conn, "/api/pleroma/admin/users/invites") | |||||
assert json_response_and_validate_schema(conn, 200) == %{"invites" => []} | |||||
end | |||||
test "with invite", %{conn: conn} do | |||||
{:ok, invite} = UserInviteToken.create_invite() | |||||
conn = get(conn, "/api/pleroma/admin/users/invites") | |||||
assert json_response_and_validate_schema(conn, 200) == %{ | |||||
"invites" => [ | |||||
%{ | |||||
"expires_at" => nil, | |||||
"id" => invite.id, | |||||
"invite_type" => "one_time", | |||||
"max_use" => nil, | |||||
"token" => invite.token, | |||||
"used" => false, | |||||
"uses" => 0 | |||||
} | |||||
] | |||||
} | |||||
end | |||||
end | |||||
describe "POST /api/pleroma/admin/users/revoke_invite" do | |||||
test "with token", %{conn: conn} do | |||||
{:ok, invite} = UserInviteToken.create_invite() | |||||
conn = | |||||
conn | |||||
|> put_req_header("content-type", "application/json") | |||||
|> post("/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token}) | |||||
assert json_response_and_validate_schema(conn, 200) == %{ | |||||
"expires_at" => nil, | |||||
"id" => invite.id, | |||||
"invite_type" => "one_time", | |||||
"max_use" => nil, | |||||
"token" => invite.token, | |||||
"used" => true, | |||||
"uses" => 0 | |||||
} | |||||
end | |||||
test "with invalid token", %{conn: conn} do | |||||
conn = | |||||
conn | |||||
|> put_req_header("content-type", "application/json") | |||||
|> post("/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"}) | |||||
assert json_response_and_validate_schema(conn, :not_found) == %{"error" => "Not found"} | |||||
end | |||||
end | |||||
end |