Instance rules
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
4605efe272
commit
bd52e2aec7
|
@ -0,0 +1,56 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Rule do
|
||||||
|
use Ecto.Schema
|
||||||
|
|
||||||
|
import Ecto.Changeset
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.Rule
|
||||||
|
|
||||||
|
schema "rules" do
|
||||||
|
field(:priority, :integer, default: 0)
|
||||||
|
field(:text, :string)
|
||||||
|
|
||||||
|
timestamps()
|
||||||
|
end
|
||||||
|
|
||||||
|
def changeset(%Rule{} = rule, params \\ %{}) do
|
||||||
|
rule
|
||||||
|
|> cast(params, [:priority, :text])
|
||||||
|
|> validate_required([:text])
|
||||||
|
end
|
||||||
|
|
||||||
|
def query do
|
||||||
|
Rule
|
||||||
|
|> order_by(asc: :priority)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(id), do: Repo.get(__MODULE__, id)
|
||||||
|
|
||||||
|
def create(params) do
|
||||||
|
{:ok, rule} =
|
||||||
|
%Rule{}
|
||||||
|
|> changeset(params)
|
||||||
|
|> Repo.insert()
|
||||||
|
|
||||||
|
rule
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(params, id) do
|
||||||
|
{:ok, rule} =
|
||||||
|
get(id)
|
||||||
|
|> changeset(params)
|
||||||
|
|> Repo.update()
|
||||||
|
|
||||||
|
rule
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(id) do
|
||||||
|
get(id)
|
||||||
|
|> Repo.delete()
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,64 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.AdminAPI.RuleController do
|
||||||
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.Rule
|
||||||
|
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||||
|
|
||||||
|
import Pleroma.Web.ControllerHelper,
|
||||||
|
only: [
|
||||||
|
json_response: 3
|
||||||
|
]
|
||||||
|
|
||||||
|
require Logger
|
||||||
|
|
||||||
|
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||||
|
|
||||||
|
plug(
|
||||||
|
OAuthScopesPlug,
|
||||||
|
%{scopes: ["admin:write"]}
|
||||||
|
when action in [:create, :update, :delete]
|
||||||
|
)
|
||||||
|
|
||||||
|
plug(OAuthScopesPlug, %{scopes: ["admin:read"]} when action == :index)
|
||||||
|
|
||||||
|
action_fallback(AdminAPI.FallbackController)
|
||||||
|
|
||||||
|
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.RuleOperation
|
||||||
|
|
||||||
|
def index(conn, _) do
|
||||||
|
rules =
|
||||||
|
Rule.query()
|
||||||
|
|> Repo.all()
|
||||||
|
|
||||||
|
render(conn, "index.json", rules: rules)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create(%{body_params: params} = conn, _) do
|
||||||
|
rule =
|
||||||
|
params
|
||||||
|
|> Rule.create()
|
||||||
|
|
||||||
|
render(conn, "show.json", rule: rule)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(%{body_params: params} = conn, %{id: id}) do
|
||||||
|
rule =
|
||||||
|
params
|
||||||
|
|> Rule.update(id)
|
||||||
|
|
||||||
|
render(conn, "show.json", rule: rule)
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(conn, %{id: id}) do
|
||||||
|
with {:ok, _} <- Rule.delete(id) do
|
||||||
|
json(conn, %{})
|
||||||
|
else
|
||||||
|
_ -> json_response(conn, :bad_request, "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.AdminAPI.RuleView do
|
||||||
|
use Pleroma.Web, :view
|
||||||
|
|
||||||
|
require Pleroma.Constants
|
||||||
|
|
||||||
|
def render("index.json", %{rules: rules} = _opts) do
|
||||||
|
render_many(rules, __MODULE__, "show.json")
|
||||||
|
end
|
||||||
|
|
||||||
|
def render("show.json", %{rule: rule} = _opts) do
|
||||||
|
%{
|
||||||
|
id: rule.id,
|
||||||
|
priority: rule.priority,
|
||||||
|
text: rule.text
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,113 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ApiSpec.Admin.RuleOperation 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: ["Instance rule managment"],
|
||||||
|
summary: "Retrieve a list of instance rules",
|
||||||
|
operationId: "AdminAPI.RuleController.index",
|
||||||
|
security: [%{"oAuth" => ["admin:read"]}],
|
||||||
|
responses: %{
|
||||||
|
200 =>
|
||||||
|
Operation.response("Response", "application/json", %Schema{
|
||||||
|
type: :array,
|
||||||
|
items: rule()
|
||||||
|
}),
|
||||||
|
403 => Operation.response("Forbidden", "application/json", ApiError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["Instance rule managment"],
|
||||||
|
summary: "Create new rule",
|
||||||
|
operationId: "AdminAPI.RuleController.create",
|
||||||
|
security: [%{"oAuth" => ["admin:write"]}],
|
||||||
|
parameters: admin_api_params(),
|
||||||
|
requestBody: request_body("Parameters", create_request(), required: true),
|
||||||
|
responses: %{
|
||||||
|
200 => Operation.response("Response", "application/json", rule()),
|
||||||
|
400 => Operation.response("Bad Request", "application/json", ApiError),
|
||||||
|
403 => Operation.response("Forbidden", "application/json", ApiError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["Instance rule managment"],
|
||||||
|
summary: "Modify existing rule",
|
||||||
|
operationId: "AdminAPI.RuleController.update",
|
||||||
|
security: [%{"oAuth" => ["admin:write"]}],
|
||||||
|
parameters: [Operation.parameter(:id, :path, :string, "Rule ID")],
|
||||||
|
requestBody: request_body("Parameters", update_request(), required: true),
|
||||||
|
responses: %{
|
||||||
|
200 => Operation.response("Response", "application/json", rule()),
|
||||||
|
400 => Operation.response("Bad Request", "application/json", ApiError),
|
||||||
|
403 => Operation.response("Forbidden", "application/json", ApiError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_operation do
|
||||||
|
%Operation{
|
||||||
|
tags: ["Instance rule managment"],
|
||||||
|
summary: "Delete rule",
|
||||||
|
operationId: "AdminAPI.RuleController.delete",
|
||||||
|
parameters: [Operation.parameter(:id, :path, :string, "Rule ID")],
|
||||||
|
security: [%{"oAuth" => ["admin:write"]}],
|
||||||
|
responses: %{
|
||||||
|
200 => empty_object_response(),
|
||||||
|
404 => Operation.response("Not Found", "application/json", ApiError),
|
||||||
|
403 => Operation.response("Forbidden", "application/json", ApiError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp create_request do
|
||||||
|
%Schema{
|
||||||
|
type: :object,
|
||||||
|
required: [:text],
|
||||||
|
properties: %{
|
||||||
|
priority: %Schema{type: :integer},
|
||||||
|
text: %Schema{type: :string}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp update_request do
|
||||||
|
%Schema{
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
priority: %Schema{type: :integer},
|
||||||
|
text: %Schema{type: :string}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp rule do
|
||||||
|
%Schema{
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
id: %Schema{type: :integer},
|
||||||
|
priority: %Schema{type: :integer},
|
||||||
|
text: %Schema{type: :string},
|
||||||
|
created_at: %Schema{type: :string, format: :"date-time"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -40,6 +40,7 @@ def render("show.json", _) do
|
||||||
background_image: Pleroma.Web.Endpoint.url() <> Keyword.get(instance, :background_image),
|
background_image: Pleroma.Web.Endpoint.url() <> Keyword.get(instance, :background_image),
|
||||||
shout_limit: Config.get([:shout, :limit]),
|
shout_limit: Config.get([:shout, :limit]),
|
||||||
description_limit: Keyword.get(instance, :description_limit),
|
description_limit: Keyword.get(instance, :description_limit),
|
||||||
|
rules: rules(),
|
||||||
pleroma: %{
|
pleroma: %{
|
||||||
metadata: %{
|
metadata: %{
|
||||||
account_activation_required: Keyword.get(instance, :account_activation_required),
|
account_activation_required: Keyword.get(instance, :account_activation_required),
|
||||||
|
@ -137,4 +138,10 @@ def fields_limits do
|
||||||
value_length: Config.get([:instance, :account_field_value_length])
|
value_length: Config.get([:instance, :account_field_value_length])
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def rules do
|
||||||
|
Pleroma.Rule.query()
|
||||||
|
|> Pleroma.Repo.all()
|
||||||
|
|> Enum.map(&%{id: &1.id, text: &1.text})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -229,6 +229,11 @@ defmodule Pleroma.Web.Router do
|
||||||
post("/frontends/install", FrontendController, :install)
|
post("/frontends/install", FrontendController, :install)
|
||||||
|
|
||||||
post("/backups", AdminAPIController, :create_backup)
|
post("/backups", AdminAPIController, :create_backup)
|
||||||
|
|
||||||
|
get("/rules", RuleController, :index)
|
||||||
|
post("/rules", RuleController, :create)
|
||||||
|
patch("/rules/:id", RuleController, :update)
|
||||||
|
delete("/rules/:id", RuleController, :delete)
|
||||||
end
|
end
|
||||||
|
|
||||||
# AdminAPI: admins and mods (staff) can perform these actions (if enabled by config)
|
# AdminAPI: admins and mods (staff) can perform these actions (if enabled by config)
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.CreateRules do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
create_if_not_exists table(:rules) do
|
||||||
|
add(:priority, :integer, default: 0, null: false)
|
||||||
|
add(:text, :text, null: false)
|
||||||
|
|
||||||
|
timestamps()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,78 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.AdminAPI.RuleControllerTest do
|
||||||
|
use Pleroma.Web.ConnCase, async: true
|
||||||
|
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
alias Pleroma.Rule
|
||||||
|
|
||||||
|
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 "GET /api/pleroma/admin/rules" do
|
||||||
|
test "sorts rules by priority", %{conn: conn} do
|
||||||
|
%{id: id1} = Rule.create(%{text: "Example rule"})
|
||||||
|
%{id: id2} = Rule.create(%{text: "Second rule", priority: 2})
|
||||||
|
%{id: id3} = Rule.create(%{text: "Third rule", priority: 1})
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> get("/api/pleroma/admin/rules")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|
||||||
|
assert [%{"id" => ^id1}, %{"id" => ^id3}, %{"id" => ^id2}] = response
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "POST /api/pleroma/admin/rules" do
|
||||||
|
test "creates a rule", %{conn: conn} do
|
||||||
|
%{"id" => id} =
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> post("/api/pleroma/admin/rules", %{text: "Example rule"})
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|
||||||
|
assert %{text: "Example rule"} = Rule.get(id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "PATCH /api/pleroma/admin/rules" do
|
||||||
|
test "edits a rule", %{conn: conn} do
|
||||||
|
%{id: id} = Rule.create(%{text: "Example rule"})
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> patch("/api/pleroma/admin/rules/#{id}", %{text: "There are no rules", priority: 2})
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|
||||||
|
assert %{text: "There are no rules", priority: 2} = Rule.get(id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "DELETE /api/pleroma/admin/rules" do
|
||||||
|
test "deletes a rule", %{conn: conn} do
|
||||||
|
%{id: id} = Rule.create(%{text: "Example rule"})
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_req_header("content-type", "application/json")
|
||||||
|
|> delete("/api/pleroma/admin/rules/#{id}")
|
||||||
|
|> json_response_and_validate_schema(:ok)
|
||||||
|
|
||||||
|
assert [] =
|
||||||
|
Rule.query()
|
||||||
|
|> Pleroma.Repo.all()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,6 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do
|
||||||
# TODO: Should not need Cachex
|
# TODO: Should not need Cachex
|
||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
|
alias Pleroma.Rule
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
@ -39,7 +40,8 @@ test "get instance information", %{conn: conn} do
|
||||||
"banner_upload_limit" => _,
|
"banner_upload_limit" => _,
|
||||||
"background_image" => from_config_background,
|
"background_image" => from_config_background,
|
||||||
"shout_limit" => _,
|
"shout_limit" => _,
|
||||||
"description_limit" => _
|
"description_limit" => _,
|
||||||
|
"rules" => _
|
||||||
} = result
|
} = result
|
||||||
|
|
||||||
assert result["pleroma"]["metadata"]["account_activation_required"] != nil
|
assert result["pleroma"]["metadata"]["account_activation_required"] != nil
|
||||||
|
@ -91,4 +93,18 @@ test "get peers", %{conn: conn} do
|
||||||
|
|
||||||
assert ["peer1.com", "peer2.com"] == Enum.sort(result)
|
assert ["peer1.com", "peer2.com"] == Enum.sort(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "get instance rules", %{conn: conn} do
|
||||||
|
Rule.create(%{text: "Example rule"})
|
||||||
|
Rule.create(%{text: "Second rule"})
|
||||||
|
Rule.create(%{text: "Third rule"})
|
||||||
|
|
||||||
|
conn = get(conn, "/api/v1/instance")
|
||||||
|
|
||||||
|
assert result = json_response_and_validate_schema(conn, 200)
|
||||||
|
|
||||||
|
rules = result["rules"]
|
||||||
|
|
||||||
|
assert length(rules) == 3
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue