Merge branch 'develop' of https://git.pleroma.social/pleroma/pleroma into develop
commit
780ac9cedb
@ -0,0 +1,31 @@
|
||||
# Optimizing your PostgreSQL performance
|
||||
|
||||
Pleroma performance depends to a large extent on good database performance. The default PostgreSQL settings are mostly fine, but often you can get better performance by changing a few settings.
|
||||
|
||||
You can use [PGTune](https://pgtune.leopard.in.ua) to get recommendations for your setup. If you do, set the "Number of Connections" field to 20, as Pleroma will only use 10 concurrent connections anyway. If you don't, it will give you advice that might even hurt your performance.
|
||||
|
||||
We also recommend not using the "Network Storage" option.
|
||||
|
||||
## Example configurations
|
||||
|
||||
Here are some configuration suggestions for PostgreSQL 10+.
|
||||
|
||||
### 1GB RAM, 1 CPU
|
||||
```
|
||||
shared_buffers = 256MB
|
||||
effective_cache_size = 768MB
|
||||
maintenance_work_mem = 64MB
|
||||
work_mem = 13107kB
|
||||
```
|
||||
|
||||
### 2GB RAM, 2 CPU
|
||||
```
|
||||
shared_buffers = 512MB
|
||||
effective_cache_size = 1536MB
|
||||
maintenance_work_mem = 128MB
|
||||
work_mem = 26214kB
|
||||
max_worker_processes = 2
|
||||
max_parallel_workers_per_gather = 1
|
||||
max_parallel_workers = 2
|
||||
```
|
||||
|
@ -0,0 +1,38 @@
|
||||
# Storing Remote Media
|
||||
|
||||
Pleroma does not store remote/federated media by default. The best way to achieve this is to change Nginx to keep its reverse proxy cache
|
||||
for a year and to activate the `MediaProxyWarmingPolicy` MRF policy in Pleroma which will automatically fetch all media through the proxy
|
||||
as soon as the post is received by your instance.
|
||||
|
||||
## Nginx
|
||||
|
||||
```
|
||||
proxy_cache_path /long/term/storage/path/pleroma-media-cache levels=1:2
|
||||
keys_zone=pleroma_media_cache:10m inactive=1y use_temp_path=off;
|
||||
|
||||
location ~ ^/(media|proxy) {
|
||||
proxy_cache pleroma_media_cache;
|
||||
slice 1m;
|
||||
proxy_cache_key $host$uri$is_args$args$slice_range;
|
||||
proxy_set_header Range $slice_range;
|
||||
proxy_http_version 1.1;
|
||||
proxy_cache_valid 206 301 302 304 1h;
|
||||
proxy_cache_valid 200 1y;
|
||||
proxy_cache_use_stale error timeout invalid_header updating;
|
||||
proxy_ignore_client_abort on;
|
||||
proxy_buffering on;
|
||||
chunked_transfer_encoding on;
|
||||
proxy_ignore_headers Cache-Control Expires;
|
||||
proxy_hide_header Cache-Control Expires;
|
||||
proxy_pass http://127.0.0.1:4000;
|
||||
}
|
||||
```
|
||||
|
||||
## Pleroma
|
||||
|
||||
Add to your `prod.secret.exs`:
|
||||
|
||||
```
|
||||
config :pleroma, :instance,
|
||||
rewrite_policy: [Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy]
|
||||
```
|
@ -1,21 +1,45 @@
|
||||
#!/sbin/openrc-run
|
||||
|
||||
# Requires OpenRC >= 0.35
|
||||
directory=/opt/pleroma
|
||||
|
||||
command=/usr/bin/mix
|
||||
command_args="phx.server"
|
||||
supervisor=supervise-daemon
|
||||
command_user=pleroma:pleroma
|
||||
command_background=1
|
||||
|
||||
export PORT=4000
|
||||
export MIX_ENV=prod
|
||||
|
||||
# Ask process to terminate within 30 seconds, otherwise kill it
|
||||
retry="SIGTERM/30/SIGKILL/5"
|
||||
|
||||
pidfile="/var/run/pleroma.pid"
|
||||
directory=/opt/pleroma
|
||||
healthcheck_delay=60
|
||||
healthcheck_timer=30
|
||||
|
||||
: ${pleroma_port:-4000}
|
||||
|
||||
# Needs OpenRC >= 0.42
|
||||
#respawn_max=0
|
||||
#respawn_delay=5
|
||||
|
||||
# put pleroma_console=YES in /etc/conf.d/pleroma if you want to be able to
|
||||
# connect to pleroma via an elixir console
|
||||
if yesno "${pleroma_console}"; then
|
||||
command=elixir
|
||||
command_args="--name pleroma@127.0.0.1 --erl '-kernel inet_dist_listen_min 9001 inet_dist_listen_max 9001 inet_dist_use_interface {127,0,0,1}' -S mix phx.server"
|
||||
|
||||
start_post() {
|
||||
einfo "You can get a console by using this command as pleroma's user:"
|
||||
einfo "iex --name console@127.0.0.1 --remsh pleroma@127.0.0.1"
|
||||
}
|
||||
else
|
||||
command=/usr/bin/mix
|
||||
command_args="phx.server"
|
||||
fi
|
||||
|
||||
export MIX_ENV=prod
|
||||
|
||||
depend() {
|
||||
need nginx postgresql
|
||||
need nginx postgresql
|
||||
}
|
||||
|
||||
healthcheck() {
|
||||
# put pleroma_health=YES in /etc/conf.d/pleroma if you want healthchecking
|
||||
# and make sure you have curl installed
|
||||
yesno "$pleroma_health" || return 0
|
||||
|
||||
curl -q "localhost:${pleroma_port}/api/pleroma/healthcheck"
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
|
||||
# A simple shell script to delete a media from the Nginx cache.
|
||||
|
||||
SCRIPTNAME=${0##*/}
|
||||
|
||||
# NGINX cache directory
|
||||
CACHE_DIRECTORY="/tmp/pleroma-media-cache"
|
||||
|
||||
## Return the files where the items are cached.
|
||||
## $1 - the filename, can be a pattern .
|
||||
## $2 - the cache directory.
|
||||
## $3 - (optional) the number of parallel processes to run for grep.
|
||||
get_cache_files() {
|
||||
local max_parallel=${3-16}
|
||||
find $2 -maxdepth 2 -type d | xargs -P $max_parallel -n 1 grep -E Rl "^KEY:.*$1" | sort -u
|
||||
}
|
||||
|
||||
## Removes an item from the given cache zone.
|
||||
## $1 - the filename, can be a pattern .
|
||||
## $2 - the cache directory.
|
||||
purge_item() {
|
||||
for f in $(get_cache_files $1 $2); do
|
||||
echo "found file: $f"
|
||||
[ -f $f ] || continue
|
||||
echo "Deleting $f from $2."
|
||||
rm $f
|
||||
done
|
||||
} # purge_item
|
||||
|
||||
purge() {
|
||||
for url in "$@"
|
||||
do
|
||||
echo "$SCRIPTNAME delete \`$url\` from cache ($CACHE_DIRECTORY)"
|
||||
purge_item $url $CACHE_DIRECTORY
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
purge $1
|
@ -0,0 +1,37 @@
|
||||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Maintenance do
|
||||
alias Pleroma.Repo
|
||||
require Logger
|
||||
|
||||
def vacuum(args) do
|
||||
case args do
|
||||
"analyze" ->
|
||||
Logger.info("Runnning VACUUM ANALYZE.")
|
||||
|
||||
Repo.query!(
|
||||
"vacuum analyze;",
|
||||
[],
|
||||
timeout: :infinity
|
||||
)
|
||||
|
||||
"full" ->
|
||||
Logger.info("Runnning VACUUM FULL.")
|
||||
|
||||
Logger.warn(
|
||||
"Re-packing your entire database may take a while and will consume extra disk space during the process."
|
||||
)
|
||||
|
||||
Repo.query!(
|
||||
"vacuum full;",
|
||||
[],
|
||||
timeout: :infinity
|
||||
)
|
||||
|
||||
_ ->
|
||||
Logger.error("Error: invalid vacuum argument.")
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,15 @@
|
||||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Maps do
|
||||
def put_if_present(map, key, value, value_function \\ &{:ok, &1}) when is_map(map) do
|
||||
with false <- is_nil(key),
|
||||
false <- is_nil(value),
|
||||
{:ok, new_value} <- value_function.(value) do
|
||||
Map.put(map, key, new_value)
|
||||
else
|
||||
_ -> map
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,101 @@
|
||||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator do
|
||||
use Ecto.Schema
|
||||
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ObjectValidators.Types
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
|
||||
import Ecto.Changeset
|
||||
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||
|
||||
require Pleroma.Constants
|
||||
|
||||
@primary_key false
|
||||
|
||||
embedded_schema do
|
||||
field(:id, Types.ObjectID, primary_key: true)
|
||||
field(:type, :string)
|
||||
field(:object, Types.ObjectID)
|
||||
field(:actor, Types.ObjectID)
|
||||
field(:context, :string, autogenerate: {Utils, :generate_context_id, []})
|
||||
field(:to, Types.Recipients, default: [])
|
||||
field(:cc, Types.Recipients, default: [])
|
||||
field(:published, Types.DateTime)
|
||||
end
|
||||
|
||||
def cast_and_validate(data) do
|
||||
data
|
||||
|> cast_data()
|
||||
|> validate_data()
|
||||
end
|
||||
|
||||
def cast_data(data) do
|
||||
%__MODULE__{}
|
||||
|> changeset(data)
|
||||
end
|
||||
|
||||
def changeset(struct, data) do
|
||||
struct
|
||||
|> cast(data, __schema__(:fields))
|
||||
|> fix_after_cast()
|
||||
end
|
||||
|
||||
def fix_after_cast(cng) do
|
||||
cng
|
||||
end
|
||||
|
||||
def validate_data(data_cng) do
|
||||
data_cng
|
||||
|> validate_inclusion(:type, ["Announce"])
|
||||
|> validate_required([:id, :type, :object, :actor, :to, :cc])
|
||||
|> validate_actor_presence()
|
||||
|> validate_object_presence()
|
||||
|> validate_existing_announce()
|
||||
|> validate_announcable()
|
||||
end
|
||||
|
||||
def validate_announcable(cng) do
|
||||
with actor when is_binary(actor) <- get_field(cng, :actor),
|
||||
object when is_binary(object) <- get_field(cng, :object),
|
||||
%User{} = actor <- User.get_cached_by_ap_id(actor),
|
||||
%Object{} = object <- Object.get_cached_by_ap_id(object),
|
||||
false <- Visibility.is_public?(object) do
|
||||
same_actor = object.data["actor"] == actor.ap_id
|
||||
is_public = Pleroma.Constants.as_public() in (get_field(cng, :to) ++ get_field(cng, :cc))
|
||||
|
||||
cond do
|
||||
same_actor && is_public ->
|
||||
cng
|
||||
|> add_error(:actor, "can not announce this object publicly")
|
||||
|
||||
!same_actor ->
|
||||
cng
|
||||
|> add_error(:actor, "can not announce this object")
|
||||
|
||||
true ->
|
||||
cng
|
||||
end
|
||||
else
|
||||
_ -> cng
|
||||
end
|
||||
end
|
||||
|
||||
def validate_existing_announce(cng) do
|
||||
actor = get_field(cng, :actor)
|
||||
object = get_field(cng, :object)
|
||||
|
||||
if actor && object && Utils.get_existing_announce(actor, %{data: %{"id" => object}}) do
|
||||
cng
|
||||
|> add_error(:actor, "already announced this object")
|
||||
|> add_error(:object, "already announced by this actor")
|
||||
else
|
||||
cng
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,152 @@
|
||||
# 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.ConfigController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.ConfigDB
|
||||
alias Pleroma.Plugs.OAuthScopesPlug
|
||||
|
||||
@descriptions Pleroma.Docs.JSON.compile()
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
plug(OAuthScopesPlug, %{scopes: ["write"], admin: true} when action == :update)
|
||||
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
%{scopes: ["read"], admin: true}
|
||||
when action in [:show, :descriptions]
|
||||
)
|
||||
|
||||
action_fallback(Pleroma.Web.AdminAPI.FallbackController)
|
||||
|
||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.ConfigOperation
|
||||
|
||||
def descriptions(conn, _params) do
|
||||
descriptions = Enum.filter(@descriptions, &whitelisted_config?/1)
|
||||
|
||||
json(conn, descriptions)
|
||||
end
|
||||
|
||||
def show(conn, %{only_db: true}) do
|
||||
with :ok <- configurable_from_database() do
|
||||
configs = Pleroma.Repo.all(ConfigDB)
|
||||
render(conn, "index.json", %{configs: configs})
|
||||
end
|
||||
end
|
||||
|
||||
def show(conn, _params) do
|
||||
with :ok <- configurable_from_database() do
|
||||
configs = ConfigDB.get_all_as_keyword()
|
||||
|
||||
merged =
|
||||
Config.Holder.default_config()
|
||||
|> ConfigDB.merge(configs)
|
||||
|> Enum.map(fn {group, values} ->
|
||||
Enum.map(values, fn {key, value} ->
|
||||
db =
|
||||
if configs[group][key] do
|
||||
ConfigDB.get_db_keys(configs[group][key], key)
|
||||
end
|
||||
|
||||
db_value = configs[group][key]
|
||||
|
||||
merged_value =
|
||||
if not is_nil(db_value) and Keyword.keyword?(db_value) and
|
||||
ConfigDB.sub_key_full_update?(group, key, Keyword.keys(db_value)) do
|
||||
ConfigDB.merge_group(group, key, value, db_value)
|
||||
else
|
||||
value
|
||||
end
|
||||
|
||||
%{
|
||||
group: ConfigDB.convert(group),
|
||||
key: ConfigDB.convert(key),
|
||||
value: ConfigDB.convert(merged_value)
|
||||
}
|
||||
|> Pleroma.Maps.put_if_present(:db, db)
|
||||
end)
|
||||
end)
|
||||
|> List.flatten()
|
||||
|
||||
json(conn, %{configs: merged, need_reboot: Restarter.Pleroma.need_reboot?()})
|
||||
end
|
||||
end
|
||||
|
||||
def update(%{body_params: %{configs: configs}} = conn, _) do
|
||||
with :ok <- configurable_from_database() do
|
||||
results =
|
||||
configs
|
||||
|> Enum.filter(&whitelisted_config?/1)
|
||||
|> Enum.map(fn
|
||||
%{group: group, key: key, delete: true} = params ->
|
||||
ConfigDB.delete(%{group: group, key: key, subkeys: params[:subkeys]})
|
||||
|
||||
%{group: group, key: key, value: value} ->
|
||||
ConfigDB.update_or_create(%{group: group, key: key, value: value})
|
||||
end)
|
||||
|> Enum.reject(fn {result, _} -> result == :error end)
|
||||
|
||||
{deleted, updated} =
|
||||
results
|
||||
|> Enum.map(fn {:ok, config} ->
|
||||
Map.put(config, :db, ConfigDB.get_db_keys(config))
|
||||
end)
|
||||
|> Enum.split_with(fn config ->
|
||||
Ecto.get_meta(config, :state) == :deleted
|
||||
end)
|
||||
|
||||
Config.TransferTask.load_and_update_env(deleted, false)
|
||||
|
||||
if not Restarter.Pleroma.need_reboot?() do
|
||||
changed_reboot_settings? =
|
||||
(updated ++ deleted)
|
||||
|> Enum.any?(fn config ->
|
||||
group = ConfigDB.from_string(config.group)
|
||||
key = ConfigDB.from_string(config.key)
|
||||
value = ConfigDB.from_binary(config.value)
|
||||
Config.TransferTask.pleroma_need_restart?(group, key, value)
|
||||
end)
|
||||
|
||||
if changed_reboot_settings?, do: Restarter.Pleroma.need_reboot()
|
||||
end
|
||||
|
||||
render(conn, "index.json", %{
|
||||
configs: updated,
|
||||
need_reboot: Restarter.Pleroma.need_reboot?()
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
defp configurable_from_database do
|
||||
if Config.get(:configurable_from_database) do
|
||||
:ok
|
||||
else
|
||||
{:error, "To use this endpoint you need to enable configuration from database."}
|
||||
end
|
||||
end
|
||||
|
||||
defp whitelisted_config?(group, key) do
|
||||
if whitelisted_configs = Config.get(:database_config_whitelist) do
|
||||
Enum.any?(whitelisted_configs, fn
|
||||
{whitelisted_group} ->
|
||||
group == inspect(whitelisted_group)
|
||||
|
||||
{whitelisted_group, whitelisted_key} ->
|
||||
group == inspect(whitelisted_group) && key == inspect(whitelisted_key)
|
||||
end)
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
defp whitelisted_config?(%{group: group, key: key}) do
|
||||
whitelisted_config?(group, key)
|
||||
end
|
||||
|
||||
defp whitelisted_config?(%{group: group} = config) do
|
||||
whitelisted_config?(group, config[:key])
|
||||
end
|
||||
end
|
@ -0,0 +1,31 @@
|
||||
# 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.FallbackController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
def call(conn, {:error, :not_found}) do
|
||||
conn
|
||||
|> put_status(:not_found)
|
||||
|> json(%{error: dgettext("errors", "Not found")})
|
||||
end
|
||||
|
||||
def call(conn, {:error, reason}) do
|
||||
conn
|
||||
|> put_status(:bad_request)
|
||||
|> json(%{error: reason})
|
||||
end
|
||||
|
||||
def call(conn, {:param_cast, _}) do
|
||||
conn
|
||||
|> put_status(:bad_request)
|
||||
|> json(dgettext("errors", "Invalid parameters"))
|
||||
end
|
||||
|
||||
def call(conn, _) do
|
||||
conn
|
||||
|> put_status(:internal_server_error)
|
||||
|> json(%{error: dgettext("errors", "Something went wrong")})
|
||||
end
|
||||
end
|
@ -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
|
@ -0,0 +1,77 @@
|
||||
# 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.OAuthAppController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
|
||||
|
||||
alias Pleroma.Plugs.OAuthScopesPlug
|
||||
alias Pleroma.Web.OAuth.App
|
||||
|
||||
require Logger
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
plug(:put_view, Pleroma.Web.MastodonAPI.AppView)
|
||||
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
%{scopes: ["write"], admin: true}
|
||||
when action in [:create, :index, :update, :delete]
|
||||
)
|
||||
|
||||
action_fallback(Pleroma.Web.AdminAPI.FallbackController)
|
||||
|
||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.OAuthAppOperation
|
||||
|
||||
def index(conn, params) do
|
||||
search_params =
|
||||
params
|
||||
|> Map.take([:client_id, :page, :page_size, :trusted])
|
||||
|> Map.put(:client_name, params[:name])
|
||||
|
||||
with {:ok, apps, count} <- App.search(search_params) do
|
||||
render(conn, "index.json",
|
||||
apps: apps,
|
||||
count: count,
|
||||
page_size: params.page_size,
|
||||
admin: true
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def create(%{body_params: params} = conn, _) do
|
||||
params = Pleroma.Maps.put_if_present(params, :client_name, params[:name])
|
||||
|
||||
case App.create(params) do
|
||||
{:ok, app} ->
|
||||
render(conn, "show.json", app: app, admin: true)
|
||||
|
||||
{:error, changeset} ->
|
||||
json(conn, App.errors(changeset))
|
||||
end
|
||||
end
|
||||
|
||||
def update(%{body_params: params} = conn, %{id: id}) do
|
||||
params = Pleroma.Maps.put_if_present(params, :client_name, params[:name])
|
||||
|
||||
with {:ok, app} <- App.update(id, params) do
|
||||
render(conn, "show.json", app: app, admin: true)
|
||||
else
|
||||
{:error, changeset} ->
|
||||
json(conn, App.errors(changeset))
|
||||
|
||||
nil ->
|
||||
json_response(conn, :bad_request, "")
|
||||
end
|
||||
end
|
||||
|
||||
def delete(conn, params) do
|
||||
with {:ok, _app} <- App.destroy(params.id) do
|
||||
json_response(conn, :no_content, "")
|
||||
else
|
||||
_ -> json_response(conn, :bad_request, "")
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,107 @@
|
||||
# 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.ReportController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.ModerationLog
|
||||
alias Pleroma.Plugs.OAuthScopesPlug
|
||||
alias Pleroma.ReportNote
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
alias Pleroma.Web.AdminAPI
|
||||
alias Pleroma.Web.AdminAPI.Report
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
require Logger
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
plug(OAuthScopesPlug, %{scopes: ["read:reports"], admin: true} when action in [:index, :show])
|
||||
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
%{scopes: ["write:reports"], admin: true}
|
||||
when action in [:update, :notes_create, :notes_delete]
|
||||
)
|
||||
|
||||
action_fallback(AdminAPI.FallbackController)
|
||||
|
||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.ReportOperation
|
||||
|
||||
def index(conn, params) do
|
||||
reports = Utils.get_reports(params, params.page, params.page_size)
|
||||
|
||||
render(conn, "index.json", reports: reports)
|
||||
end
|
||||
|
||||
def show(conn, %{id: id}) do
|
||||
with %Activity{} = report <- Activity.get_by_id(id) do
|
||||
render(conn, "show.json", Report.extract_report_info(report))
|
||||
else
|
||||
_ -> {:error, :not_found}
|
||||
end
|
||||
end
|
||||
|
||||
def update(%{assigns: %{user: admin}, body_params: %{reports: reports}} = conn, _) do
|
||||
result =
|
||||
Enum.map(reports, fn report ->
|
||||
case CommonAPI.update_report_state(report.id, report.state) do
|
||||
{:ok, activity} ->
|
||||
ModerationLog.insert_log(%{
|
||||
action: "report_update",
|
||||
actor: admin,
|
||||
subject: activity
|
||||
})
|
||||
|
||||
activity
|
||||
|
||||
{:error, message} ->
|
||||
%{id: report.id, error: message}
|
||||
end
|
||||
end)
|
||||
|
||||
if Enum.any?(result, &Map.has_key?(&1, :error)) do
|
||||
json_response(conn, :bad_request, result)
|
||||
else
|
||||
json_response(conn, :no_content, "")
|
||||
end
|
||||
end
|
||||
|
||||
def notes_create(%{assigns: %{user: user}, body_params: %{content: content}} = conn, %{
|
||||
id: report_id
|
||||
}) do
|
||||
with {:ok, _} <- ReportNote.create(user.id, report_id, content) do
|
||||
ModerationLog.insert_log(%{
|
||||
action: "report_note",
|
||||
actor: user,
|
||||
subject: Activity.get_by_id(report_id),
|
||||
text: content
|
||||
})
|
||||
|
||||
json_response(conn, :no_content, "")
|
||||
else
|
||||
_ -> json_response(conn, :bad_request, "")
|
||||
end
|
||||
end
|
||||
|
||||
def notes_delete(%{assigns: %{user: user}} = conn, %{
|
||||
id: note_id,
|
||||
report_id: report_id
|
||||
}) do
|
||||
with {:ok, note} <- ReportNote.destroy(note_id) do
|
||||
ModerationLog.insert_log(%{
|
||||
action: "report_note_delete",
|
||||
actor: user,
|
||||
subject: Activity.get_by_id(report_id),
|
||||
text: note.content
|
||||
})
|
||||
|
||||
json_response(conn, :no_content, "")
|
||||
else
|
||||
_ -> json_response(conn, :bad_request, "")
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,77 @@
|
||||
# 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.StatusController do
|
||||
use Pleroma.Web, :controller
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.ModerationLog
|
||||
alias Pleroma.Plugs.OAuthScopesPlug
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.MastodonAPI
|
||||
|
||||
require Logger
|
||||
|
||||
plug(Pleroma.Web.ApiSpec.CastAndValidate)
|
||||
plug(OAuthScopesPlug, %{scopes: ["read:statuses"], admin: true} when action in [:index, :show])
|
||||
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
%{scopes: ["write:statuses"], admin: true} when action in [:update, :delete]
|
||||
)
|
||||
|
||||
action_fallback(Pleroma.Web.AdminAPI.FallbackController)
|
||||
|
||||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.StatusOperation
|
||||
|
||||
def index(%{assigns: %{user: _admin}} = conn, params) do
|
||||
activities =
|
||||
ActivityPub.fetch_statuses(nil, %{
|
||||
"godmode" => params.godmode,
|
||||
"local_only" => params.local_only,
|
||||
"limit" => params.page_size,
|
||||
"offset" => (params.page - 1) * params.page_size,
|
||||
"exclude_reblogs" => not params.with_reblogs
|
||||
})
|
||||
|
||||
render(conn, "index.json", activities: activities, as: :activity)
|
||||
end
|
||||
|
||||
def show(conn, %{id: id}) do
|
||||
with %Activity{} = activity <- Activity.get_by_id(id) do
|
||||
render(conn, "show.json", %{activity: activity})
|
||||
else
|
||||
nil -> {:error, :not_found}
|
||||
end
|
||||
end
|
||||
|
||||
def update(%{assigns: %{user: admin}, body_params: params} = conn, %{id: id}) do
|
||||
with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do
|
||||
ModerationLog.insert_log(%{
|
||||
action: "status_update",
|
||||
actor: admin,
|
||||
subject: activity,
|
||||
sensitive: params[:sensitive],
|
||||
visibility: params[:visibility]
|
||||
})
|
||||
|
||||
conn
|
||||
|> put_view(MastodonAPI.StatusView)
|
||||
|> render("show.json", %{activity: activity})
|
||||
end
|
||||
end
|
||||
|
||||
def delete(%{assigns: %{user: user}} = conn, %{id: id}) do
|
||||
with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
|
||||
ModerationLog.insert_log(%{
|
||||
action: "status_delete",
|
||||
actor: user,
|
||||
subject_id: id
|
||||
})
|
||||
|
||||
json(conn, %{})
|
||||
end
|
||||
end
|
||||
end
|
@ -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,142 @@
|
||||
# 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.ConfigOperation 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 show_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "Config"],
|
||||
summary: "Get list of merged default settings with saved in database",
|
||||
operationId: "AdminAPI.ConfigController.show",
|
||||
parameters: [
|
||||
Operation.parameter(
|
||||
:only_db,
|
||||
:query,
|
||||
%Schema{type: :boolean, default: false},
|
||||
"Get only saved in database settings"
|
||||
)
|
||||
],
|
||||
security: [%{"oAuth" => ["read"]}],
|
||||
responses: %{
|
||||
200 => Operation.response("Config", "application/json", config_response()),
|
||||
400 => Operation.response("Bad Request", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def update_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "Config"],
|
||||
summary: "Update config settings",
|
||||
operationId: "AdminAPI.ConfigController.update",
|
||||
security: [%{"oAuth" => ["write"]}],
|
||||
requestBody:
|
||||
request_body("Parameters", %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
configs: %Schema{
|
||||
type: :array,
|
||||
items: %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
group: %Schema{type: :string},
|
||||
key: %Schema{type: :string},
|
||||
value: any(),
|
||||
delete: %Schema{type: :boolean},
|
||||
subkeys: %Schema{type: :array, items: %Schema{type: :string}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
responses: %{
|
||||
200 => Operation.response("Config", "application/json", config_response()),
|
||||
400 => Operation.response("Bad Request", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def descriptions_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "Config"],
|
||||
summary: "Get JSON with config descriptions.",
|
||||
operationId: "AdminAPI.ConfigController.descriptions",
|
||||
security: [%{"oAuth" => ["read"]}],
|
||||
responses: %{
|
||||
200 =>
|
||||
Operation.response("Config Descriptions", "application/json", %Schema{
|
||||
type: :array,
|
||||
items: %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
group: %Schema{type: :string},
|
||||
key: %Schema{type: :string},
|
||||
type: %Schema{oneOf: [%Schema{type: :string}, %Schema{type: :array}]},
|
||||
description: %Schema{type: :string},
|
||||
children: %Schema{
|
||||
type: :array,
|
||||
items: %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
key: %Schema{type: :string},
|
||||
type: %Schema{oneOf: [%Schema{type: :string}, %Schema{type: :array}]},
|
||||
description: %Schema{type: :string},
|
||||
suggestions: %Schema{type: :array}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
400 => Operation.response("Bad Request", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp any do
|
||||
%Schema{
|
||||
oneOf: [
|
||||
%Schema{type: :array},
|
||||
%Schema{type: :object},
|
||||
%Schema{type: :string},
|
||||
%Schema{type: :integer},
|
||||
%Schema{type: :boolean}
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
defp config_response do
|
||||
%Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
configs: %Schema{
|
||||
type: :array,
|
||||
items: %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
group: %Schema{type: :string},
|
||||
key: %Schema{type: :string},
|
||||
value: any()
|
||||
}
|
||||
}
|
||||
},
|
||||
need_reboot: %Schema{
|
||||
type: :boolean,
|
||||
description:
|
||||
"If `need_reboot` is `true`, instance must be restarted, so reboot time settings can take effect"
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
@ -0,0 +1,215 @@
|
||||
# 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.OAuthAppOperation 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{
|
||||
summary: "List OAuth apps",
|
||||
tags: ["Admin", "oAuth Apps"],
|
||||
operationId: "AdminAPI.OAuthAppController.index",
|
||||
security: [%{"oAuth" => ["write"]}],
|
||||
parameters: [
|
||||
Operation.parameter(:name, :query, %Schema{type: :string}, "App name"),
|
||||
Operation.parameter(:client_id, :query, %Schema{type: :string}, "Client ID"),
|
||||
Operation.parameter(:page, :query, %Schema{type: :integer, default: 1}, "Page"),
|
||||
Operation.parameter(
|
||||
:trusted,
|
||||
:query,
|
||||
%Schema{type: :boolean, default: false},
|
||||
"Trusted apps"
|
||||
),
|
||||
Operation.parameter(
|
||||
:page_size,
|
||||
:query,
|
||||
%Schema{type: :integer, default: 50},
|
||||
"Number of apps to return"
|
||||
)
|
||||
],
|
||||
responses: %{
|
||||
200 =>
|
||||
Operation.response("List of apps", "application/json", %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
apps: %Schema{type: :array, items: oauth_app()},
|
||||
count: %Schema{type: :integer},
|
||||
page_size: %Schema{type: :integer}
|
||||
},
|
||||
example: %{
|
||||
"apps" => [
|
||||
%{
|
||||
"id" => 1,
|
||||
"name" => "App name",
|
||||
"client_id" => "yHoDSiWYp5mPV6AfsaVOWjdOyt5PhWRiafi6MRd1lSk",
|
||||
"client_secret" => "nLmis486Vqrv2o65eM9mLQx_m_4gH-Q6PcDpGIMl6FY",
|
||||
"redirect_uri" => "https://example.com/oauth-callback",
|
||||
"website" => "https://example.com",
|
||||
"trusted" => true
|
||||
}
|
||||
],
|
||||
"count" => 1,
|
||||
"page_size" => 50
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def create_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "oAuth Apps"],
|
||||
summary: "Create OAuth App",
|
||||
operationId: "AdminAPI.OAuthAppController.create",
|
||||
requestBody: request_body("Parameters", create_request()),
|
||||
security: [%{"oAuth" => ["write"]}],
|
||||
responses: %{
|
||||
200 => Operation.response("App", "application/json", oauth_app()),
|
||||
400 => Operation.response("Bad Request", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def update_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "oAuth Apps"],
|
||||
summary: "Update OAuth App",
|
||||
operationId: "AdminAPI.OAuthAppController.update",
|
||||
parameters: [id_param()],
|
||||
security: [%{"oAuth" => ["write"]}],
|
||||
requestBody: request_body("Parameters", update_request()),
|
||||
responses: %{
|
||||
200 => Operation.response("App", "application/json", oauth_app()),
|
||||
400 =>
|
||||
Operation.response("Bad Request", "application/json", %Schema{
|
||||
oneOf: [ApiError, %Schema{type: :string}]
|
||||
})
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def delete_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "oAuth Apps"],
|
||||
summary: "Delete OAuth App",
|
||||
operationId: "AdminAPI.OAuthAppController.delete",
|
||||
parameters: [id_param()],
|
||||
security: [%{"oAuth" => ["write"]}],
|
||||
responses: %{
|
||||
204 => no_content_response(),
|
||||
400 => no_content_response()
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp create_request do
|
||||
%Schema{
|
||||
title: "oAuthAppCreateRequest",
|
||||
type: :object,
|
||||
required: [:name, :redirect_uris],
|
||||
properties: %{
|
||||
name: %Schema{type: :string, description: "Application Name"},
|
||||
scopes: %Schema{type: :array, items: %Schema{type: :string}, description: "oAuth scopes"},
|
||||
redirect_uris: %Schema{
|
||||
type: :string,
|
||||
description:
|
||||
"Where the user should be redirected after authorization. To display the authorization code to the user instead of redirecting to a web page, use `urn:ietf:wg:oauth:2.0:oob` in this parameter."
|
||||
},
|
||||
website: %Schema{
|
||||
type: :string,
|
||||
nullable: true,
|
||||
description: "A URL to the homepage of the app"
|
||||
},
|
||||
trusted: %Schema{
|
||||
type: :boolean,
|
||||
nullable: true,
|
||||
default: false,
|
||||
description: "Is the app trusted?"
|
||||
}
|
||||
},
|
||||
example: %{
|
||||
"name" => "My App",
|
||||
"redirect_uris" => "https://myapp.com/auth/callback",
|
||||
"website" => "https://myapp.com/",
|
||||
"scopes" => ["read", "write"],
|
||||
"trusted" => true
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp update_request do
|
||||
%Schema{
|
||||
title: "oAuthAppUpdateRequest",
|
||||
type: :object,
|
||||
properties: %{
|
||||
name: %Schema{type: :string, description: "Application Name"},
|
||||
scopes: %Schema{type: :array, items: %Schema{type: :string}, description: "oAuth scopes"},
|
||||
redirect_uris: %Schema{
|
||||
type: :string,
|
||||
description:
|
||||
"Where the user should be redirected after authorization. To display the authorization code to the user instead of redirecting to a web page, use `urn:ietf:wg:oauth:2.0:oob` in this parameter."
|
||||
},
|
||||
website: %Schema{
|
||||
type: :string,
|
||||
nullable: true,
|
||||
description: "A URL to the homepage of the app"
|
||||
},
|
||||
trusted: %Schema{
|
||||
type: :boolean,
|
||||
nullable: true,
|
||||
default: false,
|
||||
description: "Is the app trusted?"
|
||||
}
|
||||
},
|
||||
example: %{
|
||||
"name" => "My App",
|
||||
"redirect_uris" => "https://myapp.com/auth/callback",
|
||||
"website" => "https://myapp.com/",
|
||||
"scopes" => ["read", "write"],
|
||||
"trusted" => true
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp oauth_app do
|
||||
%Schema{
|
||||
title: "oAuthApp",
|
||||
type: :object,
|
||||
properties: %{
|
||||
id: %Schema{type: :integer},
|
||||
name: %Schema{type: :string},
|
||||
client_id: %Schema{type: :string},
|
||||
client_secret: %Schema{type: :string},
|
||||
redirect_uri: %Schema{type: :string},
|
||||
website: %Schema{type: :string, nullable: true},
|
||||
trusted: %Schema{type: :boolean}
|
||||
},
|
||||
example: %{
|
||||
"id" => 123,
|
||||
"name" => "My App",
|
||||
"client_id" => "TWhM-tNSuncnqN7DBJmoyeLnk6K3iJJ71KKXxgL1hPM",
|
||||
"client_secret" => "ZEaFUFmF0umgBX1qKJDjaU99Q31lDkOU8NutzTOoliw",
|
||||
"redirect_uri" => "https://myapp.com/oauth-callback",
|
||||
"website" => "https://myapp.com/",
|
||||
"trusted" => false
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def id_param do
|
||||
Operation.parameter(:id, :path, :integer, "App ID",
|
||||
example: 1337,
|
||||
required: true
|
||||
)
|
||||
end
|
||||
end
|
@ -0,0 +1,237 @@
|
||||
# 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.ReportOperation do
|
||||
alias OpenApiSpex.Operation
|
||||
alias OpenApiSpex.Schema
|
||||
alias Pleroma.Web.ApiSpec.Schemas.Account
|
||||
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
||||
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
|
||||
alias Pleroma.Web.ApiSpec.Schemas.Status
|
||||
|
||||
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", "Reports"],
|
||||
summary: "Get a list of reports",
|
||||
operationId: "AdminAPI.ReportController.index",
|
||||
security: [%{"oAuth" => ["read:reports"]}],
|
||||
parameters: [
|
||||
Operation.parameter(
|
||||
:state,
|
||||
:query,
|
||||
report_state(),
|
||||
"Filter by report state"
|
||||
),
|
||||
Operation.parameter(
|
||||
:limit,
|
||||
:query,
|
||||
%Schema{type: :integer},
|
||||
"The number of records to retrieve"
|
||||
),
|
||||
Operation.parameter(
|
||||
:page,
|
||||
:query,
|
||||
%Schema{type: :integer, default: 1},
|
||||
"Page number"
|
||||
),
|
||||
Operation.parameter(
|
||||
:page_size,
|
||||
:query,
|
||||
%Schema{type: :integer, default: 50},
|
||||
"Number number of log entries per page"
|
||||
)
|
||||
],
|
||||
responses: %{
|
||||
200 =>
|
||||
Operation.response("Response", "application/json", %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
total: %Schema{type: :integer},
|
||||
reports: %Schema{
|
||||
type: :array,
|
||||
items: report()
|
||||
}
|
||||
}
|
||||
}),
|
||||
403 => Operation.response("Forbidden", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def show_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "Reports"],
|
||||
summary: "Get an individual report",
|
||||
operationId: "AdminAPI.ReportController.show",
|
||||
parameters: [id_param()],
|
||||
security: [%{"oAuth" => ["read:reports"]}],
|
||||
responses: %{
|
||||
200 => Operation.response("Report", "application/json", report()),
|
||||
404 => Operation.response("Not Found", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def update_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "Reports"],
|
||||
summary: "Change the state of one or multiple reports",
|
||||
operationId: "AdminAPI.ReportController.update",
|
||||
security: [%{"oAuth" => ["write:reports"]}],
|
||||
requestBody: request_body("Parameters", update_request(), required: true),
|
||||
responses: %{
|
||||
204 => no_content_response(),
|
||||
400 => Operation.response("Bad Request", "application/json", update_400_response()),
|
||||
403 => Operation.response("Forbidden", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def notes_create_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "Reports"],
|
||||
summary: "Create report note",
|
||||
operationId: "AdminAPI.ReportController.notes_create",
|
||||
parameters: [id_param()],
|
||||
requestBody:
|
||||
request_body("Parameters", %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
content: %Schema{type: :string, description: "The message"}
|
||||
}
|
||||
}),
|
||||
security: [%{"oAuth" => ["write:reports"]}],
|
||||
responses: %{
|
||||
204 => no_content_response(),
|
||||
404 => Operation.response("Not Found", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def notes_delete_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "Reports"],
|
||||
summary: "Delete report note",
|
||||
operationId: "AdminAPI.ReportController.notes_delete",
|
||||
parameters: [
|
||||
Operation.parameter(:report_id, :path, :string, "Report ID"),
|
||||
Operation.parameter(:id, :path, :string, "Note ID")
|
||||
],
|
||||
security: [%{"oAuth" => ["write:reports"]}],
|
||||
responses: %{
|
||||
204 => no_content_response(),
|
||||
404 => Operation.response("Not Found", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp report_state do
|
||||
%Schema{type: :string, enum: ["open", "closed", "resolved"]}
|
||||
end
|
||||
|
||||
defp id_param do
|
||||
Operation.parameter(:id, :path, FlakeID, "Report ID",
|
||||
example: "9umDrYheeY451cQnEe",
|
||||
required: true
|
||||
)
|
||||
end
|
||||
|
||||
defp report do
|
||||
%Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
id: FlakeID,
|
||||
state: report_state(),
|
||||
account: account_admin(),
|
||||
actor: account_admin(),
|
||||
content: %Schema{type: :string},
|
||||
created_at: %Schema{type: :string, format: :"date-time"},
|
||||
statuses: %Schema{type: :array, items: Status},
|
||||
notes: %Schema{
|
||||
type: :array,
|
||||
items: %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
id: %Schema{type: :integer},
|
||||
user_id: FlakeID,
|
||||
content: %Schema{type: :string},
|
||||
inserted_at: %Schema{type: :string, format: :"date-time"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp account_admin do
|
||||
%Schema{
|
||||
title: "Account",
|
||||
description: "Account view for admins",
|
||||
type: :object,
|
||||
properties:
|
||||
Map.merge(Account.schema().properties, %{
|
||||
nickname: %Schema{type: :string},
|
||||
deactivated: %Schema{type: :boolean},
|
||||
local: %Schema{type: :boolean},
|
||||
roles: %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
admin: %Schema{type: :boolean},
|
||||
moderator: %Schema{type: :boolean}
|
||||
}
|
||||
},
|
||||
confirmation_pending: %Schema{type: :boolean}
|
||||
})
|
||||
}
|
||||
end
|
||||
|
||||
defp update_request do
|
||||
%Schema{
|
||||
type: :object,
|
||||
required: [:reports],
|
||||
properties: %{
|
||||
reports: %Schema{
|
||||
type: :array,
|
||||
items: %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
id: %Schema{allOf: [FlakeID], description: "Required, report ID"},
|
||||
state: %Schema{
|
||||
type: :string,
|
||||
description:
|
||||
"Required, the new state. Valid values are `open`, `closed` and `resolved`"
|
||||
}
|
||||
}
|
||||
},
|
||||
example: %{
|
||||
"reports" => [
|
||||
%{"id" => "123", "state" => "closed"},
|
||||
%{"id" => "1337", "state" => "resolved"}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp update_400_response do
|
||||
%Schema{
|
||||
type: :array,
|
||||
items: %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
id: %Schema{allOf: [FlakeID], description: "Report ID"},
|
||||
error: %Schema{type: :string, description: "Error message"}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
@ -0,0 +1,165 @@
|
||||
# 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.StatusOperation do
|
||||
alias OpenApiSpex.Operation
|
||||
alias OpenApiSpex.Schema
|
||||
alias Pleroma.Web.ApiSpec.Schemas.Account
|
||||
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
||||
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
|
||||
alias Pleroma.Web.ApiSpec.Schemas.Status
|
||||
alias Pleroma.Web.ApiSpec.Schemas.VisibilityScope
|
||||
|
||||
import Pleroma.Web.ApiSpec.Helpers
|
||||
import Pleroma.Web.ApiSpec.StatusOperation, only: [id_param: 0]
|
||||
|
||||
def open_api_operation(action) do
|
||||
operation = String.to_existing_atom("#{action}_operation")
|
||||
apply(__MODULE__, operation, [])
|
||||
end
|
||||
|
||||
def index_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "Statuses"],
|
||||
operationId: "AdminAPI.StatusController.index",
|
||||
security: [%{"oAuth" => ["read:statuses"]}],
|
||||
parameters: [
|
||||
Operation.parameter(
|
||||
:godmode,
|
||||
:query,
|
||||
%Schema{type: :boolean, default: false},
|
||||
"Allows to see private statuses"
|
||||
),
|
||||
Operation.parameter(
|
||||
:local_only,
|
||||
:query,
|
||||
%Schema{type: :boolean, default: false},
|
||||
"Excludes remote statuses"
|
||||
),
|
||||
Operation.parameter(
|
||||
:with_reblogs,
|
||||
:query,
|
||||
%Schema{type: :boolean, default: false},
|
||||
"Allows to see reblogs"
|
||||
),
|
||||
Operation.parameter(
|
||||
:page,
|
||||
:query,
|
||||
%Schema{type: :integer, default: 1},
|
||||
"Page"
|
||||
),
|
||||
Operation.parameter(
|
||||
:page_size,
|
||||
:query,
|
||||
%Schema{type: :integer, default: 50},
|
||||
"Number of statuses to return"
|
||||
)
|
||||
],
|
||||
responses: %{
|
||||
200 =>
|
||||
Operation.response("Array of statuses", "application/json", %Schema{
|
||||
type: :array,
|
||||
items: status()
|
||||
})
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def show_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "Statuses"],
|
||||
summary: "Show Status",
|
||||
operationId: "AdminAPI.StatusController.show",
|
||||
parameters: [id_param()],
|
||||
security: [%{"oAuth" => ["read:statuses"]}],
|
||||
responses: %{
|
||||
200 => Operation.response("Status", "application/json", status()),
|
||||
404 => Operation.response("Not Found", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def update_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "Statuses"],
|
||||
summary: "Change the scope of an individual reported status",
|
||||
operationId: "AdminAPI.StatusController.update",
|
||||
parameters: [id_param()],
|
||||
security: [%{"oAuth" => ["write:statuses"]}],
|
||||
requestBody: request_body("Parameters", update_request(), required: true),
|
||||
responses: %{
|
||||
200 => Operation.response("Status", "application/json", Status),
|
||||
400 => Operation.response("Error", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def delete_operation do
|
||||
%Operation{
|
||||
tags: ["Admin", "Statuses"],
|
||||
summary: "Delete an individual reported status",
|
||||
operationId: "AdminAPI.StatusController.delete",
|
||||
parameters: [id_param()],
|
||||
security: [%{"oAuth" => ["write:statuses"]}],
|
||||
responses: %{
|
||||
200 => empty_object_response(),
|
||||
404 => Operation.response("Not Found", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp status do
|
||||
%Schema{
|
||||
anyOf: [
|
||||
Status,
|
||||
%Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
account: %Schema{allOf: [Account, admin_account()]}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
def admin_account do
|
||||
%Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
id: FlakeID,
|
||||
avatar: %Schema{type: :string},
|
||||
nickname: %Schema{type: :string},
|
||||
display_name: %Schema{type: :string},
|
||||
deactivated: %Schema{type: :boolean},
|
||||
local: %Schema{type: :boolean},
|
||||
roles: %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
admin: %Schema{type: :boolean},
|
||||
moderator: %Schema{type: :boolean}
|
||||
}
|
||||
},
|
||||
tags: %Schema{type: :string},
|
||||
confirmation_pending: %Schema{type: :string}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp update_request do
|
||||
%Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
sensitive: %Schema{
|
||||
type: :boolean,
|
||||
description: "Mark status and attached media as sensitive?"
|
||||
},
|
||||
visibility: VisibilityScope
|
||||
},
|
||||
example: %{
|
||||
"visibility" => "private",
|
||||
"sensitive" => "false"
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
@ -0,0 +1,104 @@
|
||||
# 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.EmojiReactionOperation do
|
||||
alias OpenApiSpex.Operation
|
||||
alias OpenApiSpex.Schema
|
||||
alias Pleroma.Web.ApiSpec.Schemas.Account
|
||||
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
||||
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
|
||||
alias Pleroma.Web.ApiSpec.Schemas.Status
|
||||
|
||||
def open_api_operation(action) do
|
||||
operation = String.to_existing_atom("#{action}_operation")
|
||||
apply(__MODULE__, operation, [])
|
||||
end
|
||||
|
||||
def index_operation do
|
||||
%Operation{
|
||||
tags: ["Emoji Reactions"],
|
||||
summary:
|
||||
"Get an object of emoji to account mappings with accounts that reacted to the post",
|
||||
parameters: [
|
||||
Operation.parameter(:id, :path, FlakeID, "Status ID", required: true),
|
||||
Operation.parameter(:emoji, :path, :string, "Filter by a single unicode emoji",
|
||||
required: false
|
||||
)
|
||||
],
|
||||
security: [%{"oAuth" => ["read:statuses"]}],
|
||||
operationId: "EmojiReactionController.index",
|
||||
responses: %{
|
||||
200 => array_of_reactions_response()
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def create_operation do
|
||||
%Operation{
|
||||
tags: ["Emoji Reactions"],
|
||||
summary: "React to a post with a unicode emoji",
|
||||
parameters: [
|
||||
Operation.parameter(:id, :path, FlakeID, "Status ID", required: true),
|
||||
Operation.parameter(:emoji, :path, :string, "A single character unicode emoji",
|
||||
required: true
|
||||
)
|
||||
],
|
||||
security: [%{"oAuth" => ["write:statuses"]}],
|
||||
operationId: "EmojiReactionController.create",
|
||||
responses: %{
|
||||
200 => Operation.response("Status", "application/json", Status),
|
||||
400 => Operation.response("Bad Request", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def delete_operation do
|
||||
%Operation{
|
||||
tags: ["Emoji Reactions"],
|
||||
summary: "Remove a reaction to a post with a unicode emoji",
|
||||
parameters: [
|
||||
Operation.parameter(:id, :path, FlakeID, "Status ID", required: true),
|
||||
Operation.parameter(:emoji, :path, :string, "A single character unicode emoji",
|
||||
required: true
|
||||
)
|
||||
],
|
||||
security: [%{"oAuth" => ["write:statuses"]}],
|
||||
operationId: "EmojiReactionController.delete",
|
||||
responses: %{
|
||||
200 => Operation.response("Status", "application/json", Status)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp array_of_reactions_response do
|
||||
Operation.response("Array of Emoji Reactions", "application/json", %Schema{
|
||||
type: :array,
|
||||
items: emoji_reaction(),
|
||||
example: [emoji_reaction().example]
|
||||
})
|
||||
end
|
||||
|
||||
defp emoji_reaction do
|
||||
%Schema{
|
||||
title: "EmojiReaction",
|
||||
type: :object,
|
||||
properties: %{
|
||||
name: %Schema{type: :string, description: "Emoji"},
|
||||
count: %Schema{type: :integer, description: "Count of reactions with this emoji"},
|
||||
me: %Schema{type: :boolean, description: "Did I react with this emoji?"},
|
||||
accounts: %Schema{
|
||||
type: :array,
|
||||
items: Account,
|
||||
description: "Array of accounts reacted with this emoji"
|
||||
}
|
||||
},
|
||||
example: %{
|
||||
"name" => "😱",
|
||||
"count" => 1,
|
||||
"me" => false,
|
||||
"accounts" => [Account.schema().example]
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
@ -0,0 +1,132 @@
|
||||
# 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.MediaOperation do
|
||||
alias OpenApiSpex.Operation
|
||||
alias OpenApiSpex.Schema
|
||||
alias Pleroma.Web.ApiSpec.Helpers
|
||||
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
||||
alias Pleroma.Web.ApiSpec.Schemas.Attachment
|
||||
|
||||
def open_api_operation(action) do
|
||||
operation = String.to_existing_atom("#{action}_operation")
|
||||
apply(__MODULE__, operation, [])
|
||||
end
|
||||
|
||||
def create_operation do
|
||||
%Operation{
|
||||
tags: ["media"],
|
||||
summary: "Upload media as attachment",
|
||||
description: "Creates an attachment to be used with a new status.",
|
||||
operationId: "MediaController.create",
|
||||
security: [%{"oAuth" => ["write:media"]}],
|
||||
requestBody: Helpers.request_body("Parameters", create_request()),
|
||||
responses: %{
|
||||
200 => Operation.response("Media", "application/json", Attachment),
|
||||
401 => Operation.response("Media", "application/json", ApiError),
|
||||
422 => Operation.response("Media", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp create_request do
|
||||
%Schema{
|
||||
title: "MediaCreateRequest",
|
||||
description: "POST body for creating an attachment",
|
||||
type: :object,
|
||||
required: [:file],
|
||||
properties: %{
|
||||
file: %Schema{
|
||||
type: :string,
|
||||
format: :binary,
|
||||
description: "The file to be attached, using multipart form data."
|
||||
},
|
||||
description: %Schema{
|
||||
type: :string,
|
||||
description: "A plain-text description of the media, for accessibility purposes."
|
||||
},
|
||||
focus: %Schema{
|
||||
type: :string,
|
||||
description: "Two floating points (x,y), comma-delimited, ranging from -1.0 to 1.0."
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def update_operation do
|
||||
%Operation{
|
||||
tags: ["media"],
|
||||
summary: "Upload media as attachment",
|
||||
description: "Creates an attachment to be used with a new status.",
|
||||
operationId: "MediaController.update",
|
||||
security: [%{"oAuth" => ["write:media"]}],
|
||||
parameters: [id_param()],
|
||||
requestBody: Helpers.request_body("Parameters", update_request()),
|
||||
responses: %{
|
||||
200 => Operation.response("Media", "application/json", Attachment),
|
||||
400 => Operation.response("Media", "application/json", ApiError),
|
||||
401 => Operation.response("Media", "application/json", ApiError),
|
||||
422 => Operation.response("Media", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp update_request do
|
||||
%Schema{
|
||||
title: "MediaUpdateRequest",
|
||||
description: "POST body for updating an attachment",
|
||||
type: :object,
|
||||
properties: %{
|
||||
file: %Schema{
|
||||
type: :string,
|
||||
format: :binary,
|
||||
description: "The file to be attached, using multipart form data."
|
||||
},
|
||||
description: %Schema{
|
||||
type: :string,
|
||||
description: "A plain-text description of the media, for accessibility purposes."
|
||||
},
|
||||
focus: %Schema{
|
||||
type: :string,
|
||||
description: "Two floating points (x,y), comma-delimited, ranging from -1.0 to 1.0."
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def show_operation do
|
||||
%Operation{
|
||||
tags: ["media"],
|
||||
summary: "Show Uploaded media attachment",
|
||||
operationId: "MediaController.show",
|
||||
parameters: [id_param()],
|
||||
security: [%{"oAuth" => ["read:media"]}],
|
||||
responses: %{
|
||||
200 => Operation.response("Media", "application/json", Attachment),
|
||||
401 => Operation.response("Media", "application/json", ApiError),
|
||||
422 => Operation.response("Media", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def create2_operation do
|
||||
%Operation{
|
||||
tags: ["media"],
|
||||
summary: "Upload media as attachment",
|
||||
description: "Creates an attachment to be used with a new status.",
|
||||
operationId: "MediaController.create2",
|
||||
security: [%{"oAuth" => ["write:media"]}],
|
||||
requestBody: Helpers.request_body("Parameters", create_request()),
|
||||
responses: %{
|
||||
202 => Operation.response("Media", "application/json", Attachment),
|
||||
422 => Operation.response("Media", "application/json", ApiError),
|
||||
500 => Operation.response("Media", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp id_param do
|
||||
Operation.parameter(:id, :path, :string, "The ID of the Attachment entity")
|
||||
end
|
||||
end
|
@ -0,0 +1,187 @@
|
||||
# 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.PleromaAccountOperation do
|
||||
alias OpenApiSpex.Operation
|
||||
alias OpenApiSpex.Schema
|
||||
alias Pleroma.Web.ApiSpec.Schemas.AccountRelationship
|
||||
alias Pleroma.Web.ApiSpec.Schemas.ApiError
|
||||
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
|
||||
alias Pleroma.Web.ApiSpec.StatusOperation
|
||||
|
||||
import Pleroma.Web.ApiSpec.Helpers
|
||||
|
||||
def open_api_operation(action) do
|
||||
operation = String.to_existing_atom("#{action}_operation")
|
||||
apply(__MODULE__, operation, [])
|
||||
end
|
||||
|
||||
def confirmation_resend_operation do
|
||||
%Operation{
|
||||
tags: ["Accounts"],
|
||||
summary: "Resend confirmation email. Expects `email` or `nickname`",
|
||||
operationId: "PleromaAPI.AccountController.confirmation_resend",
|
||||
parameters: [
|
||||
Operation.parameter(:email, :query, :string, "Email of that needs to be verified",
|
||||
example: "cofe@cofe.io"
|
||||
),
|
||||
Operation.parameter(
|
||||
:nickname,
|
||||
:query,
|
||||
:string,
|
||||
"Nickname of user that needs to be verified",
|
||||
example: "cofefe"
|
||||
)
|
||||
],
|
||||
responses: %{
|
||||
204 => no_content_response()
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def update_avatar_operation do
|
||||
%Operation{
|
||||
tags: ["Accounts"],
|
||||
summary: "Set/clear user avatar image",
|
||||
operationId: "PleromaAPI.AccountController.update_avatar",
|
||||
requestBody:
|
||||
request_body("Parameters", update_avatar_or_background_request(), required: true),
|
||||
security: [%{"oAuth" => ["write:accounts"]}],
|
||||
responses: %{
|
||||
200 => update_response(),
|
||||
403 => Operation.response("Forbidden", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def update_banner_operation do
|
||||
%Operation{
|
||||
tags: ["Accounts"],
|
||||
summary: "Set/clear user banner image",
|
||||
operationId: "PleromaAPI.AccountController.update_banner",
|
||||
requestBody: request_body("Parameters", update_banner_request(), required: true),
|
||||
security: [%{"oAuth" => ["write:accounts"]}],
|
||||
responses: %{
|
||||
200 => update_response()
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def update_background_operation do
|
||||
%Operation{
|
||||
tags: ["Accounts"],
|
||||
summary: "Set/clear user background image",
|
||||
operationId: "PleromaAPI.AccountController.update_background",
|
||||
security: [%{"oAuth" => ["write:accounts"]}],
|
||||
requestBody:
|
||||
request_body("Parameters", update_avatar_or_background_request(), required: true),
|
||||
responses: %{
|
||||
200 => update_response()
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def favourites_operation do
|
||||
%Operation{
|
||||
tags: ["Accounts"],
|
||||
summary: "Returns favorites timeline of any user",
|
||||
operationId: "PleromaAPI.AccountController.favourites",
|
||||
parameters: [id_param() | pagination_params()],
|
||||
security: [%{"oAuth" => ["read:favourites"]}],
|
||||
responses: %{
|
||||
200 =>
|
||||
Operation.response(
|
||||
"Array of Statuses",
|
||||
"application/json",
|
||||
StatusOperation.array_of_statuses()
|
||||
),
|
||||
403 => Operation.response("Forbidden", "application/json", ApiError),
|
||||
404 => Operation.response("Not Found", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def subscribe_operation do
|
||||
%Operation{
|
||||
tags: ["Accounts"],
|
||||
summary: "Subscribe to receive notifications for all statuses posted by a user",
|
||||
operationId: "PleromaAPI.AccountController.subscribe",
|
||||
parameters: [id_param()],
|
||||
security: [%{"oAuth" => ["follow", "write:follows"]}],
|
||||
responses: %{
|
||||
200 => Operation.response("Relationship", "application/json", AccountRelationship),
|
||||
404 => Operation.response("Not Found", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def unsubscribe_operation do
|
||||
%Operation{
|
||||
tags: ["Accounts"],
|
||||
summary: "Unsubscribe to stop receiving notifications from user statuses",
|
||||
operationId: "PleromaAPI.AccountController.unsubscribe",
|
||||
parameters: [id_param()],
|
||||
security: [%{"oAuth" => ["follow", "write:follows"]}],
|
||||
responses: %{
|
||||
200 => Operation.response("Relationship", "application/json", AccountRelationship),
|
||||
404 => Operation.response("Not Found", "application/json", ApiError)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp id_param do
|
||||
Operation.parameter(:id, :path, FlakeID, "Account ID",
|
||||
example: "9umDrYheeY451cQnEe",
|
||||
required: true
|
||||
)
|
||||
end
|
||||
|
||||
defp update_avatar_or_background_request do
|
||||
%Schema{
|
||||
title: "PleromaAccountUpdateAvatarOrBackgroundRequest",
|
||||
type: :object,
|
||||
properties: %{
|
||||
img: %Schema{
|
||||
nullable: true,
|
||||
type: :string,
|
||||
format: :binary,
|
||||
description: "Image encoded using `multipart/form-data` or an empty string to clear"
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp update_banner_request do
|
||||
%Schema{
|
||||
title: "PleromaAccountUpdateBannerRequest",
|
||||
type: :object,
|
||||
properties: %{
|
||||
banner: %Schema{
|
||||
type: :string,
|
||||
nullable: true,
|
||||
format: :binary,
|
||||
description: "Image encoded using `multipart/form-data` or an empty string to clear"
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
defp update_response do
|
||||
Operation.response("PleromaAccountUpdateResponse", "application/json", %Schema{
|
||||
type: :object,
|
||||
properties: %{
|
||||
url: %Schema{
|
||||
type: :string,
|
||||
format: :uri,
|
||||
nullable: true,
|
||||
description: "Image URL"
|
||||
}
|
||||
},
|
||||
example: %{
|
||||
"url" =>
|
||||
"https://cofe.party/media/9d0add56-bcb6-4c0f-8225-cbbd0b6dd773/13eadb6972c9ccd3f4ffa3b8196f0e0d38b4d2f27594457c52e52946c054cd9a.gif"
|
||||
}
|
||||
})
|
||||
end
|
||||
end
|
@ -0,0 +1,106 @@
|
||||
# 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.PleromaConversationOperation do
|
||||
alias OpenApiSpex.Operation
|
||||
alias OpenApiSpex.Schema
|
||||
alias Pleroma.Web.ApiSpec.Schemas.Conversation
|
||||
alias Pleroma.Web.ApiSpec.Schemas.FlakeID
|
||||
alias Pleroma.Web.ApiSpec.StatusOperation
|
||||
|
||||
import Pleroma.Web.ApiSpec.Helpers
|
||||
|
||||
def open_api_operation(action) do
|
||||
operation = String.to_existing_atom("#{action}_operation")
|
||||
apply(__MODULE__, operation, [])
|
||||
end
|
||||
|
||||
def show_operation do
|
||||
%Operation{
|
||||
tags: ["Conversations"],
|
||||
summary: "The conversation with the given ID",
|
||||
parameters: [
|
||||
Operation.parameter(:id, :path, :string, "Conversation ID",
|
||||
example: "123",
|
||||
required: true
|
||||
)
|
||||
],
|
||||
security: [%{"oAuth" => ["read:statuses"]}],
|
||||
operationId: "PleromaAPI.ConversationController.show",
|
||||
responses: %{
|
||||
200 => Operation.response("Conversation", "application/json", Conversation)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def statuses_operation do
|
||||
%Operation{
|
||||
tags: ["Conversations"],
|
||||
summary: "Timeline for a given conversation",
|
||||
parameters: [
|
||||
Operation.parameter(:id, :path, :string, "Conversation ID",
|
||||
example: "123",
|
||||
required: true
|
||||
)
|
||||
| pagination_params()
|
||||
],
|
||||
security: [%{"oAuth" => ["read:statuses"]}],
|
||||
operationId: "PleromaAPI.ConversationController.statuses",
|
||||
responses: %{
|
||||
200 =>
|
||||
Operation.response(
|
||||
"Array of Statuses",
|
||||
"application/json",
|
||||
StatusOperation.array_of_statuses()
|
||||
)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def update_operation do
|
||||
%Operation{
|
||||
tags: ["Conversations"],
|
||||
summary: "Update a conversation. Used to change the set of recipients.",
|
||||
parameters: [
|
||||
Operation.parameter(:id, :path, :string, "Conversation ID",
|
||||
example: "123",
|
||||
required: true
|
||||
),
|
||||
Operation.parameter(
|
||||
:recipients,
|
||||
:query,
|
||||
%Schema{type: :array, items: FlakeID},
|
||||
"A list of ids of users that should receive posts to this conversation. This will replace the current list of recipients, so submit the full list. The owner of owner of the conversation will always be part of the set of recipients, though.",
|
||||
required: true
|
||||
)
|
||||
],
|
||||
security: [%{"oAuth" => ["write:conversations"]}],
|
||||
operationId: "PleromaAPI.ConversationController.update",
|
||||
responses: %{
|
||||
200 => Operation.response("Conversation", "application/json", Conversation)
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def mark_as_read_operation do
|
||||
%Operation{
|
||||
tags: ["Conversations"],
|
||||
summary: "Marks all user's conversations as read",
|
||||
security: [%{"oAuth" => ["write:conversations"]}],
|
||||
operationId: "PleromaAPI.ConversationController.mark_as_read",
|
||||
responses: %{
|
||||
200 =>
|
||||
Operation.response(
|
||||
"Array of Conversations that were marked as read",
|
||||
"application/json",
|
||||
%Schema{
|
||||
type: :array,
|
||||
items: Conversation,
|
||||
example: [Conversation.schema().example]
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue