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.Stats | |||
alias Pleroma.User | |||
alias Pleroma.UserInviteToken | |||
alias Pleroma.Web.ActivityPub.ActivityPub | |||
alias Pleroma.Web.ActivityPub.Builder | |||
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( | |||
OAuthScopesPlug, | |||
%{scopes: ["write:follows"], admin: true} | |||
@@ -575,69 +566,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do | |||
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" | |||
def get_password_reset(conn, %{"nickname" => nickname}) do | |||
(%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 | |||
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 | |||
%{ | |||
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) | |||
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) | |||
patch("/users/force_password_reset", AdminAPIController, :force_password_reset) | |||
@@ -20,7 +20,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do | |||
alias Pleroma.ReportNote | |||
alias Pleroma.Tests.ObanHelpers | |||
alias Pleroma.User | |||
alias Pleroma.UserInviteToken | |||
alias Pleroma.Web | |||
alias Pleroma.Web.ActivityPub.Relay | |||
alias Pleroma.Web.CommonAPI | |||
@@ -588,122 +587,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do | |||
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 | |||
user = insert(:user) | |||
@@ -1315,112 +1198,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do | |||
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 | |||
test "returns report by its id", %{conn: conn} do | |||
[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 |