Merge branch 'feature/admin-api' into 'develop'
Add a admin API See merge request pleroma/pleroma!366
This commit is contained in:
commit
675653ceb7
9 changed files with 412 additions and 14 deletions
|
@ -14,9 +14,11 @@ defmodule Mix.Tasks.RelayFollow do
|
|||
def run([target]) do
|
||||
Mix.Task.run("app.start")
|
||||
|
||||
:ok = Relay.follow(target)
|
||||
|
||||
# put this task to sleep to allow the genserver to push out the messages
|
||||
:timer.sleep(500)
|
||||
with {:ok, activity} <- Relay.follow(target) do
|
||||
# put this task to sleep to allow the genserver to push out the messages
|
||||
:timer.sleep(500)
|
||||
else
|
||||
{:error, e} -> Mix.shell().error("Error while following #{target}: #{inspect(e)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,9 +13,11 @@ defmodule Mix.Tasks.RelayUnfollow do
|
|||
def run([target]) do
|
||||
Mix.Task.run("app.start")
|
||||
|
||||
:ok = Relay.unfollow(target)
|
||||
|
||||
# put this task to sleep to allow the genserver to push out the messages
|
||||
:timer.sleep(500)
|
||||
with {:ok, activity} <- Relay.follow(target) do
|
||||
# put this task to sleep to allow the genserver to push out the messages
|
||||
:timer.sleep(500)
|
||||
else
|
||||
{:error, e} -> Mix.shell().error("Error while following #{target}: #{inspect(e)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
32
lib/mix/tasks/set_admin.ex
Normal file
32
lib/mix/tasks/set_admin.ex
Normal file
|
@ -0,0 +1,32 @@
|
|||
defmodule Mix.Tasks.SetAdmin do
|
||||
use Mix.Task
|
||||
alias Pleroma.User
|
||||
|
||||
@doc """
|
||||
Sets admin status
|
||||
Usage: set_admin nickname [true|false]
|
||||
"""
|
||||
def run([nickname | rest]) do
|
||||
Application.ensure_all_started(:pleroma)
|
||||
|
||||
status =
|
||||
case rest do
|
||||
[status] -> status == "true"
|
||||
_ -> true
|
||||
end
|
||||
|
||||
with %User{local: true} = user <- User.get_by_nickname(nickname) do
|
||||
info =
|
||||
user.info
|
||||
|> Map.put("is_admin", !!status)
|
||||
|
||||
cng = User.info_changeset(user, %{info: info})
|
||||
{:ok, user} = User.update_and_set_cache(cng)
|
||||
|
||||
IO.puts("Admin status of #{nickname}: #{user.info["is_admin"]}")
|
||||
else
|
||||
_ ->
|
||||
IO.puts("No local user #{nickname}")
|
||||
end
|
||||
end
|
||||
end
|
19
lib/pleroma/plugs/user_is_admin_plug.ex
Normal file
19
lib/pleroma/plugs/user_is_admin_plug.ex
Normal file
|
@ -0,0 +1,19 @@
|
|||
defmodule Pleroma.Plugs.UserIsAdminPlug do
|
||||
import Plug.Conn
|
||||
alias Pleroma.User
|
||||
|
||||
def init(options) do
|
||||
options
|
||||
end
|
||||
|
||||
def call(%{assigns: %{user: %User{info: %{"is_admin" => true}}}} = conn, _) do
|
||||
conn
|
||||
end
|
||||
|
||||
def call(conn, _) do
|
||||
conn
|
||||
|> put_resp_content_type("application/json")
|
||||
|> send_resp(403, Jason.encode!(%{error: "User is not admin."}))
|
||||
|> halt
|
||||
end
|
||||
end
|
|
@ -12,11 +12,12 @@ def follow(target_instance) do
|
|||
%User{} = target_user <- User.get_or_fetch_by_ap_id(target_instance),
|
||||
{:ok, activity} <- ActivityPub.follow(local_user, target_user) do
|
||||
Logger.info("relay: followed instance: #{target_instance}; id=#{activity.data["id"]}")
|
||||
{:ok, activity}
|
||||
else
|
||||
e -> Logger.error("error: #{inspect(e)}")
|
||||
e ->
|
||||
Logger.error("error: #{inspect(e)}")
|
||||
{:error, e}
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
def unfollow(target_instance) do
|
||||
|
@ -24,11 +25,12 @@ def unfollow(target_instance) do
|
|||
%User{} = target_user <- User.get_or_fetch_by_ap_id(target_instance),
|
||||
{:ok, activity} <- ActivityPub.unfollow(local_user, target_user) do
|
||||
Logger.info("relay: unfollowed instance: #{target_instance}: id=#{activity.data["id"]}")
|
||||
{:ok, activity}
|
||||
else
|
||||
e -> Logger.error("error: #{inspect(e)}")
|
||||
e ->
|
||||
Logger.error("error: #{inspect(e)}")
|
||||
{:error, e}
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
def publish(%Activity{data: %{"type" => "Create"}} = activity) do
|
||||
|
|
158
lib/pleroma/web/admin_api/admin_api_controller.ex
Normal file
158
lib/pleroma/web/admin_api/admin_api_controller.ex
Normal file
|
@ -0,0 +1,158 @@
|
|||
defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|
||||
use Pleroma.Web, :controller
|
||||
alias Pleroma.{User, Repo}
|
||||
alias Pleroma.Web.ActivityPub.Relay
|
||||
|
||||
require Logger
|
||||
|
||||
action_fallback(:errors)
|
||||
|
||||
def user_delete(conn, %{"nickname" => nickname}) do
|
||||
user = User.get_by_nickname(nickname)
|
||||
|
||||
if user.local == true do
|
||||
User.delete(user)
|
||||
else
|
||||
User.delete(user)
|
||||
end
|
||||
|
||||
conn
|
||||
|> json(nickname)
|
||||
end
|
||||
|
||||
def user_create(
|
||||
conn,
|
||||
%{"nickname" => nickname, "email" => email, "password" => password}
|
||||
) do
|
||||
new_user = %{
|
||||
nickname: nickname,
|
||||
name: nickname,
|
||||
email: email,
|
||||
password: password,
|
||||
password_confirmation: password,
|
||||
bio: "."
|
||||
}
|
||||
|
||||
User.register_changeset(%User{}, new_user)
|
||||
|> Repo.insert!()
|
||||
|
||||
conn
|
||||
|> json(new_user.nickname)
|
||||
end
|
||||
|
||||
def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
|
||||
when permission_group in ["moderator", "admin"] do
|
||||
user = User.get_by_nickname(nickname)
|
||||
|
||||
info =
|
||||
user.info
|
||||
|> Map.put("is_" <> permission_group, true)
|
||||
|
||||
cng = User.info_changeset(user, %{info: info})
|
||||
{:ok, user} = User.update_and_set_cache(cng)
|
||||
|
||||
conn
|
||||
|> json(user.info)
|
||||
end
|
||||
|
||||
def right_get(conn, %{"nickname" => nickname}) do
|
||||
user = User.get_by_nickname(nickname)
|
||||
|
||||
conn
|
||||
|> json(user.info)
|
||||
end
|
||||
|
||||
def right_add(conn, _) do
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "No such permission_group"})
|
||||
end
|
||||
|
||||
def right_delete(
|
||||
%{assigns: %{user: %User{:nickname => admin_nickname}}} = conn,
|
||||
%{
|
||||
"permission_group" => permission_group,
|
||||
"nickname" => nickname
|
||||
}
|
||||
)
|
||||
when permission_group in ["moderator", "admin"] do
|
||||
if admin_nickname == nickname do
|
||||
conn
|
||||
|> put_status(403)
|
||||
|> json(%{error: "You can't revoke your own admin status."})
|
||||
else
|
||||
user = User.get_by_nickname(nickname)
|
||||
|
||||
info =
|
||||
user.info
|
||||
|> Map.put("is_" <> permission_group, false)
|
||||
|
||||
cng = User.info_changeset(user, %{info: info})
|
||||
{:ok, user} = User.update_and_set_cache(cng)
|
||||
|
||||
conn
|
||||
|> json(user.info)
|
||||
end
|
||||
end
|
||||
|
||||
def right_delete(conn, _) do
|
||||
conn
|
||||
|> put_status(404)
|
||||
|> json(%{error: "No such permission_group"})
|
||||
end
|
||||
|
||||
def relay_follow(conn, %{"relay_url" => target}) do
|
||||
{status, message} = Relay.follow(target)
|
||||
|
||||
if status == :ok do
|
||||
conn
|
||||
|> json(target)
|
||||
else
|
||||
conn
|
||||
|> put_status(500)
|
||||
|> json(target)
|
||||
end
|
||||
end
|
||||
|
||||
def relay_unfollow(conn, %{"relay_url" => target}) do
|
||||
{status, message} = Relay.unfollow(target)
|
||||
|
||||
if status == :ok do
|
||||
conn
|
||||
|> json(target)
|
||||
else
|
||||
conn
|
||||
|> put_status(500)
|
||||
|> json(target)
|
||||
end
|
||||
end
|
||||
|
||||
@shortdoc "Get a account registeration invite token (base64 string)"
|
||||
def get_invite_token(conn, _params) do
|
||||
{:ok, token} = Pleroma.UserInviteToken.create_token()
|
||||
|
||||
conn
|
||||
|> json(token.token)
|
||||
end
|
||||
|
||||
@shortdoc "Get a password reset token (base64 string) for given nickname"
|
||||
def get_password_reset(conn, %{"nickname" => nickname}) do
|
||||
(%User{local: true} = user) = User.get_by_nickname(nickname)
|
||||
{:ok, token} = Pleroma.PasswordResetToken.create_token(user)
|
||||
|
||||
conn
|
||||
|> json(token.token)
|
||||
end
|
||||
|
||||
def errors(conn, {:param_cast, _}) do
|
||||
conn
|
||||
|> put_status(400)
|
||||
|> json("Invalid parameters")
|
||||
end
|
||||
|
||||
def errors(conn, _) do
|
||||
conn
|
||||
|> put_status(500)
|
||||
|> json("Something went wrong")
|
||||
end
|
||||
end
|
|
@ -31,6 +31,21 @@ defmodule Pleroma.Web.Router do
|
|||
plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
|
||||
end
|
||||
|
||||
pipeline :admin_api do
|
||||
plug(:accepts, ["json"])
|
||||
plug(:fetch_session)
|
||||
plug(Pleroma.Plugs.OAuthPlug)
|
||||
plug(Pleroma.Plugs.BasicAuthDecoderPlug)
|
||||
plug(Pleroma.Plugs.UserFetcherPlug)
|
||||
plug(Pleroma.Plugs.SessionAuthenticationPlug)
|
||||
plug(Pleroma.Plugs.LegacyAuthenticationPlug)
|
||||
plug(Pleroma.Plugs.AuthenticationPlug)
|
||||
plug(Pleroma.Plugs.UserEnabledPlug)
|
||||
plug(Pleroma.Plugs.SetUserSessionIdPlug)
|
||||
plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
|
||||
plug(Pleroma.Plugs.UserIsAdminPlug)
|
||||
end
|
||||
|
||||
pipeline :mastodon_html do
|
||||
plug(:accepts, ["html"])
|
||||
plug(:fetch_session)
|
||||
|
@ -79,6 +94,23 @@ defmodule Pleroma.Web.Router do
|
|||
get("/emoji", UtilController, :emoji)
|
||||
end
|
||||
|
||||
scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do
|
||||
pipe_through(:admin_api)
|
||||
delete("/user", AdminAPIController, :user_delete)
|
||||
post("/user", AdminAPIController, :user_create)
|
||||
|
||||
get("/permission_group/:nickname", AdminAPIController, :right_get)
|
||||
get("/permission_group/:nickname/:permission_group", AdminAPIController, :right_get)
|
||||
post("/permission_group/:nickname/:permission_group", AdminAPIController, :right_add)
|
||||
delete("/permission_group/:nickname/:permission_group", AdminAPIController, :right_delete)
|
||||
|
||||
post("/relay", AdminAPIController, :relay_follow)
|
||||
delete("/relay", AdminAPIController, :relay_unfollow)
|
||||
|
||||
get("/invite_token", AdminAPIController, :get_invite_token)
|
||||
get("/password_reset", AdminAPIController, :get_password_reset)
|
||||
end
|
||||
|
||||
scope "/", Pleroma.Web.TwitterAPI do
|
||||
pipe_through(:pleroma_html)
|
||||
get("/ostatus_subscribe", UtilController, :remote_follow)
|
||||
|
|
39
test/plugs/user_is_admin_plug_test.exs
Normal file
39
test/plugs/user_is_admin_plug_test.exs
Normal file
|
@ -0,0 +1,39 @@
|
|||
defmodule Pleroma.Plugs.UserIsAdminPlugTest do
|
||||
use Pleroma.Web.ConnCase, async: true
|
||||
|
||||
alias Pleroma.Plugs.UserIsAdminPlug
|
||||
import Pleroma.Factory
|
||||
|
||||
test "accepts a user that is admin", %{conn: conn} do
|
||||
user = insert(:user, info: %{"is_admin" => true})
|
||||
|
||||
conn =
|
||||
build_conn()
|
||||
|> assign(:user, user)
|
||||
|
||||
ret_conn =
|
||||
conn
|
||||
|> UserIsAdminPlug.call(%{})
|
||||
|
||||
assert conn == ret_conn
|
||||
end
|
||||
|
||||
test "denies a user that isn't admin", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
|
||||
conn =
|
||||
build_conn()
|
||||
|> assign(:user, user)
|
||||
|> UserIsAdminPlug.call(%{})
|
||||
|
||||
assert conn.status == 403
|
||||
end
|
||||
|
||||
test "denies when a user isn't set", %{conn: conn} do
|
||||
conn =
|
||||
build_conn()
|
||||
|> UserIsAdminPlug.call(%{})
|
||||
|
||||
assert conn.status == 403
|
||||
end
|
||||
end
|
112
test/web/admin_api/admin_api_controller_test.exs
Normal file
112
test/web/admin_api/admin_api_controller_test.exs
Normal file
|
@ -0,0 +1,112 @@
|
|||
defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
|
||||
use Pleroma.Web.ConnCase
|
||||
|
||||
alias Pleroma.{Repo, User}
|
||||
|
||||
import Pleroma.Factory
|
||||
import ExUnit.CaptureLog
|
||||
|
||||
describe "/api/pleroma/admin/user" do
|
||||
test "Delete" do
|
||||
admin = insert(:user, info: %{"is_admin" => true})
|
||||
user = insert(:user)
|
||||
|
||||
conn =
|
||||
build_conn()
|
||||
|> assign(:user, admin)
|
||||
|> put_req_header("accept", "application/json")
|
||||
|> delete("/api/pleroma/admin/user?nickname=#{user.nickname}")
|
||||
|
||||
assert json_response(conn, 200) == user.nickname
|
||||
end
|
||||
|
||||
test "Create" do
|
||||
admin = insert(:user, info: %{"is_admin" => true})
|
||||
|
||||
conn =
|
||||
build_conn()
|
||||
|> assign(:user, admin)
|
||||
|> put_req_header("accept", "application/json")
|
||||
|> post("/api/pleroma/admin/user", %{
|
||||
"nickname" => "lain",
|
||||
"email" => "lain@example.org",
|
||||
"password" => "test"
|
||||
})
|
||||
|
||||
assert json_response(conn, 200) == "lain"
|
||||
end
|
||||
end
|
||||
|
||||
describe "/api/pleroma/admin/permission_group" do
|
||||
test "GET is giving user_info" do
|
||||
admin = insert(:user, info: %{"is_admin" => true})
|
||||
|
||||
conn =
|
||||
build_conn()
|
||||
|> assign(:user, admin)
|
||||
|> put_req_header("accept", "application/json")
|
||||
|> get("/api/pleroma/admin/permission_group/#{admin.nickname}")
|
||||
|
||||
assert json_response(conn, 200) == admin.info
|
||||
end
|
||||
|
||||
test "/:right POST, can add to a permission group" do
|
||||
admin = insert(:user, info: %{"is_admin" => true})
|
||||
user = insert(:user)
|
||||
|
||||
user_info =
|
||||
user.info
|
||||
|> Map.put("is_admin", true)
|
||||
|
||||
conn =
|
||||
build_conn()
|
||||
|> assign(:user, admin)
|
||||
|> put_req_header("accept", "application/json")
|
||||
|> post("/api/pleroma/admin/permission_group/#{user.nickname}/admin")
|
||||
|
||||
assert json_response(conn, 200) == user_info
|
||||
end
|
||||
|
||||
test "/:right DELETE, can remove from a permission group" do
|
||||
admin = insert(:user, info: %{"is_admin" => true})
|
||||
user = insert(:user, info: %{"is_admin" => true})
|
||||
|
||||
user_info =
|
||||
user.info
|
||||
|> Map.put("is_admin", false)
|
||||
|
||||
conn =
|
||||
build_conn()
|
||||
|> assign(:user, admin)
|
||||
|> put_req_header("accept", "application/json")
|
||||
|> delete("/api/pleroma/admin/permission_group/#{user.nickname}/admin")
|
||||
|
||||
assert json_response(conn, 200) == user_info
|
||||
end
|
||||
end
|
||||
|
||||
test "/api/pleroma/admin/invite_token" do
|
||||
admin = insert(:user, info: %{"is_admin" => true})
|
||||
|
||||
conn =
|
||||
build_conn()
|
||||
|> assign(:user, admin)
|
||||
|> put_req_header("accept", "application/json")
|
||||
|> get("/api/pleroma/admin/invite_token")
|
||||
|
||||
assert conn.status == 200
|
||||
end
|
||||
|
||||
test "/api/pleroma/admin/password_reset" do
|
||||
admin = insert(:user, info: %{"is_admin" => true})
|
||||
user = insert(:user, info: %{"is_admin" => true})
|
||||
|
||||
conn =
|
||||
build_conn()
|
||||
|> assign(:user, admin)
|
||||
|> put_req_header("accept", "application/json")
|
||||
|> get("/api/pleroma/admin/password_reset?nickname=#{user.nickname}")
|
||||
|
||||
assert conn.status == 200
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue