forked from AkkomaGang/akkoma
Merge branch 'develop' into gun
This commit is contained in:
commit
39ed608b13
34 changed files with 281 additions and 90 deletions
|
@ -38,6 +38,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Rate limiter is now disabled for localhost/socket (unless remoteip plug is enabled)
|
- Rate limiter is now disabled for localhost/socket (unless remoteip plug is enabled)
|
||||||
- Logger: default log level changed from `warn` to `info`.
|
- Logger: default log level changed from `warn` to `info`.
|
||||||
- Config mix task `migrate_to_db` truncates `config` table before migrating the config file.
|
- Config mix task `migrate_to_db` truncates `config` table before migrating the config file.
|
||||||
|
- Allow account registration without an email
|
||||||
- Default to `prepare: :unnamed` in the database configuration.
|
- Default to `prepare: :unnamed` in the database configuration.
|
||||||
- Instance stats are now loaded on startup instead of being empty until next hourly job.
|
- Instance stats are now loaded on startup instead of being empty until next hourly job.
|
||||||
<details>
|
<details>
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
Replaces embedded objects with references to them in the `objects` table. Only needs to be ran once if the instance was created before Pleroma 1.0.5. The reason why this is not a migration is because it could significantly increase the database size after being ran, however after this `VACUUM FULL` will be able to reclaim about 20% (really depends on what is in the database, your mileage may vary) of the db size before the migration.
|
Replaces embedded objects with references to them in the `objects` table. Only needs to be ran once if the instance was created before Pleroma 1.0.5. The reason why this is not a migration is because it could significantly increase the database size after being ran, however after this `VACUUM FULL` will be able to reclaim about 20% (really depends on what is in the database, your mileage may vary) of the db size before the migration.
|
||||||
|
|
||||||
```sh tab="OTP"
|
```sh tab="OTP"
|
||||||
./bin/pleroma_ctl database remove_embedded_objects [<options>]
|
./bin/pleroma_ctl database remove_embedded_objects [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh tab="From Source"
|
```sh tab="From Source"
|
||||||
mix pleroma.database remove_embedded_objects [<options>]
|
mix pleroma.database remove_embedded_objects [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
@ -28,11 +28,11 @@ This will prune remote posts older than 90 days (configurable with [`config :ple
|
||||||
The disk space will only be reclaimed after `VACUUM FULL`. You may run out of disk space during the execution of the task or vacuuming if you don't have about 1/3rds of the database size free.
|
The disk space will only be reclaimed after `VACUUM FULL`. You may run out of disk space during the execution of the task or vacuuming if you don't have about 1/3rds of the database size free.
|
||||||
|
|
||||||
```sh tab="OTP"
|
```sh tab="OTP"
|
||||||
./bin/pleroma_ctl database prune_objects [<options>]
|
./bin/pleroma_ctl database prune_objects [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh tab="From Source"
|
```sh tab="From Source"
|
||||||
mix pleroma.database prune_objects [<options>]
|
mix pleroma.database prune_objects [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
## Send digest email since given date (user registration date by default) ignoring user activity status.
|
## Send digest email since given date (user registration date by default) ignoring user activity status.
|
||||||
|
|
||||||
```sh tab="OTP"
|
```sh tab="OTP"
|
||||||
./bin/pleroma_ctl digest test <nickname> [<since_date>]
|
./bin/pleroma_ctl digest test <nickname> [since_date]
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh tab="From Source"
|
```sh tab="From Source"
|
||||||
mix pleroma.digest test <nickname> [<since_date>]
|
mix pleroma.digest test <nickname> [since_date]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
## Lists emoji packs and metadata specified in the manifest
|
## Lists emoji packs and metadata specified in the manifest
|
||||||
|
|
||||||
```sh tab="OTP"
|
```sh tab="OTP"
|
||||||
./bin/pleroma_ctl emoji ls-packs [<options>]
|
./bin/pleroma_ctl emoji ls-packs [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh tab="From Source"
|
```sh tab="From Source"
|
||||||
mix pleroma.emoji ls-packs [<options>]
|
mix pleroma.emoji ls-packs [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,11 +19,11 @@ mix pleroma.emoji ls-packs [<options>]
|
||||||
## Fetch, verify and install the specified packs from the manifest into `STATIC-DIR/emoji/PACK-NAME`
|
## Fetch, verify and install the specified packs from the manifest into `STATIC-DIR/emoji/PACK-NAME`
|
||||||
|
|
||||||
```sh tab="OTP"
|
```sh tab="OTP"
|
||||||
./bin/pleroma_ctl emoji get-packs [<options>] <packs>
|
./bin/pleroma_ctl emoji get-packs [option ...] <pack ...>
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh tab="From Source"
|
```sh tab="From Source"
|
||||||
mix pleroma.emoji get-packs [<options>] <packs>
|
mix pleroma.emoji get-packs [option ...] <pack ...>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
|
|
||||||
## Generate a new configuration file
|
## Generate a new configuration file
|
||||||
```sh tab="OTP"
|
```sh tab="OTP"
|
||||||
./bin/pleroma_ctl instance gen [<options>]
|
./bin/pleroma_ctl instance gen [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh tab="From Source"
|
```sh tab="From Source"
|
||||||
mix pleroma.instance gen [<options>]
|
mix pleroma.instance gen [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
|
|
||||||
## Migrate uploads from local to remote storage
|
## Migrate uploads from local to remote storage
|
||||||
```sh tab="OTP"
|
```sh tab="OTP"
|
||||||
./bin/pleroma_ctl uploads migrate_local <target_uploader> [<options>]
|
./bin/pleroma_ctl uploads migrate_local <target_uploader> [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh tab="From Source"
|
```sh tab="From Source"
|
||||||
mix pleroma.uploads migrate_local <target_uploader> [<options>]
|
mix pleroma.uploads migrate_local <target_uploader> [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
## Create a user
|
## Create a user
|
||||||
|
|
||||||
```sh tab="OTP"
|
```sh tab="OTP"
|
||||||
./bin/pleroma_ctl user new <email> [<options>]
|
./bin/pleroma_ctl user new <nickname> <email> [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh tab="From Source"
|
```sh tab="From Source"
|
||||||
mix pleroma.user new <email> [<options>]
|
mix pleroma.user new <nickname> <email> [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,11 +33,11 @@ mix pleroma.user list
|
||||||
|
|
||||||
## Generate an invite link
|
## Generate an invite link
|
||||||
```sh tab="OTP"
|
```sh tab="OTP"
|
||||||
./bin/pleroma_ctl user invite [<options>]
|
./bin/pleroma_ctl user invite [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh tab="From Source"
|
```sh tab="From Source"
|
||||||
mix pleroma.user invite [<options>]
|
mix pleroma.user invite [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,11 +137,11 @@ mix pleroma.user reset_password <nickname>
|
||||||
|
|
||||||
## Set the value of the given user's settings
|
## Set the value of the given user's settings
|
||||||
```sh tab="OTP"
|
```sh tab="OTP"
|
||||||
./bin/pleroma_ctl user set <nickname> [<options>]
|
./bin/pleroma_ctl user set <nickname> [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh tab="From Source"
|
```sh tab="From Source"
|
||||||
mix pleroma.user set <nickname> [<options>]
|
mix pleroma.user set <nickname> [option ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
|
@ -18,9 +18,8 @@
|
||||||
6. Run `sudo -Hu postgres pg_restore -d <pleroma_db> -v -1 </path/to/backup_location/pleroma.pgdump>`
|
6. Run `sudo -Hu postgres pg_restore -d <pleroma_db> -v -1 </path/to/backup_location/pleroma.pgdump>`
|
||||||
7. If you installed a newer Pleroma version, you should run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any.
|
7. If you installed a newer Pleroma version, you should run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any.
|
||||||
8. Restart the Pleroma service.
|
8. Restart the Pleroma service.
|
||||||
9. After you've restarted Pleroma, you will notice that postgres will take up more cpu resources than usual. A lot in fact. To fix this you must do a VACUUM ANLAYZE. This can also be done while the instance is still running like so:
|
9. Run `sudo -Hu postgres vacuumdb --all --analyze-in-stages`. This will quickly generate the statistics so that postgres can properly plan queries.
|
||||||
$ sudo -u postgres psql pleroma_database_name
|
|
||||||
pleroma=# VACUUM ANALYZE;
|
|
||||||
[^1]: Prefix with `MIX_ENV=prod` to run it using the production config file.
|
[^1]: Prefix with `MIX_ENV=prod` to run it using the production config file.
|
||||||
|
|
||||||
## Remove
|
## Remove
|
||||||
|
|
|
@ -156,8 +156,8 @@ cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/conf.d/pleroma.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh tab="Debian/Ubuntu"
|
```sh tab="Debian/Ubuntu"
|
||||||
cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/sites-available/pleroma.nginx
|
cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/sites-available/pleroma.conf
|
||||||
ln -s /etc/nginx/sites-available/pleroma.nginx /etc/nginx/sites-enabled/pleroma.nginx
|
ln -s /etc/nginx/sites-available/pleroma.conf /etc/nginx/sites-enabled/pleroma.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
If your distro does not have either of those you can append `include /etc/nginx/pleroma.conf` to the end of the http section in /etc/nginx/nginx.conf and
|
If your distro does not have either of those you can append `include /etc/nginx/pleroma.conf` to the end of the http section in /etc/nginx/nginx.conf and
|
||||||
|
|
|
@ -28,7 +28,7 @@ def run(_) do
|
||||||
defp do_run(implementation) do
|
defp do_run(implementation) do
|
||||||
start_pleroma()
|
start_pleroma()
|
||||||
|
|
||||||
with descriptions <- Pleroma.Config.Loader.load("config/description.exs"),
|
with descriptions <- Pleroma.Config.Loader.read("config/description.exs"),
|
||||||
{:ok, file_path} <-
|
{:ok, file_path} <-
|
||||||
Pleroma.Docs.Generator.process(
|
Pleroma.Docs.Generator.process(
|
||||||
implementation,
|
implementation,
|
||||||
|
|
|
@ -35,7 +35,7 @@ def run(["unfollow", target]) do
|
||||||
def run(["list"]) do
|
def run(["list"]) do
|
||||||
start_pleroma()
|
start_pleroma()
|
||||||
|
|
||||||
with {:ok, list} <- Relay.list() do
|
with {:ok, list} <- Relay.list(true) do
|
||||||
list |> Enum.each(&shell_info(&1))
|
list |> Enum.each(&shell_info(&1))
|
||||||
else
|
else
|
||||||
{:error, e} -> shell_error("Error while fetching relay subscription list: #{inspect(e)}")
|
{:error, e} -> shell_error("Error while fetching relay subscription list: #{inspect(e)}")
|
||||||
|
|
|
@ -308,6 +308,13 @@ def follow_requests_for_actor(%Pleroma.User{ap_id: ap_id}) do
|
||||||
|> where([a], fragment("? ->> 'state' = 'pending'", a.data))
|
|> where([a], fragment("? ->> 'state' = 'pending'", a.data))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def following_requests_for_actor(%Pleroma.User{ap_id: ap_id}) do
|
||||||
|
Queries.by_type("Follow")
|
||||||
|
|> where([a], fragment("?->>'state' = 'pending'", a.data))
|
||||||
|
|> where([a], a.actor == ^ap_id)
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
|
|
||||||
def restrict_deactivated_users(query) do
|
def restrict_deactivated_users(query) do
|
||||||
deactivated_users =
|
deactivated_users =
|
||||||
from(u in User.Query.build(%{deactivated: true}), select: u.ap_id)
|
from(u in User.Query.build(%{deactivated: true}), select: u.ap_id)
|
||||||
|
|
|
@ -35,6 +35,7 @@ def user_agent do
|
||||||
# See http://elixir-lang.org/docs/stable/elixir/Application.html
|
# See http://elixir-lang.org/docs/stable/elixir/Application.html
|
||||||
# for more information on OTP Applications
|
# for more information on OTP Applications
|
||||||
def start(_type, _args) do
|
def start(_type, _args) do
|
||||||
|
Pleroma.Config.Holder.save_default()
|
||||||
Pleroma.HTML.compile_scrubbers()
|
Pleroma.HTML.compile_scrubbers()
|
||||||
Config.DeprecationWarnings.warn()
|
Config.DeprecationWarnings.warn()
|
||||||
Pleroma.Plugs.HTTPSecurityPlug.warn_if_disabled()
|
Pleroma.Plugs.HTTPSecurityPlug.warn_if_disabled()
|
||||||
|
|
|
@ -3,14 +3,33 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Config.Holder do
|
defmodule Pleroma.Config.Holder do
|
||||||
@config Pleroma.Config.Loader.load_and_merge()
|
@config Pleroma.Config.Loader.default_config()
|
||||||
|
|
||||||
@spec config() :: keyword()
|
@spec save_default() :: :ok
|
||||||
def config, do: @config
|
def save_default do
|
||||||
|
default_config =
|
||||||
|
if System.get_env("RELEASE_NAME") do
|
||||||
|
release_config =
|
||||||
|
[:code.root_dir(), "releases", System.get_env("RELEASE_VSN"), "releases.exs"]
|
||||||
|
|> Path.join()
|
||||||
|
|> Pleroma.Config.Loader.read()
|
||||||
|
|
||||||
@spec config(atom()) :: any()
|
Pleroma.Config.Loader.merge(@config, release_config)
|
||||||
def config(group), do: @config[group]
|
else
|
||||||
|
@config
|
||||||
@spec config(atom(), atom()) :: any()
|
end
|
||||||
def config(group, key), do: @config[group][key]
|
|
||||||
|
Pleroma.Config.put(:default_config, default_config)
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec default_config() :: keyword()
|
||||||
|
def default_config, do: get_default()
|
||||||
|
|
||||||
|
@spec default_config(atom()) :: keyword()
|
||||||
|
def default_config(group), do: Keyword.get(get_default(), group)
|
||||||
|
|
||||||
|
@spec default_config(atom(), atom()) :: keyword()
|
||||||
|
def default_config(group, key), do: get_in(get_default(), [group, key])
|
||||||
|
|
||||||
|
defp get_default, do: Pleroma.Config.get(:default_config)
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,32 +13,28 @@ defmodule Pleroma.Config.Loader do
|
||||||
]
|
]
|
||||||
|
|
||||||
if Code.ensure_loaded?(Config.Reader) do
|
if Code.ensure_loaded?(Config.Reader) do
|
||||||
@spec load(Path.t()) :: keyword()
|
@reader Config.Reader
|
||||||
def load(path), do: Config.Reader.read!(path)
|
|
||||||
|
|
||||||
defp do_merge(conf1, conf2), do: Config.Reader.merge(conf1, conf2)
|
def read(path), do: @reader.read!(path)
|
||||||
else
|
else
|
||||||
# support for Elixir less than 1.9
|
# support for Elixir less than 1.9
|
||||||
@spec load(Path.t()) :: keyword()
|
@reader Mix.Config
|
||||||
def load(path) do
|
def read(path) do
|
||||||
path
|
path
|
||||||
|> Mix.Config.eval!()
|
|> @reader.eval!()
|
||||||
|> elem(0)
|
|> elem(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp do_merge(conf1, conf2), do: Mix.Config.merge(conf1, conf2)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec load_and_merge() :: keyword()
|
@spec read(Path.t()) :: keyword()
|
||||||
def load_and_merge do
|
|
||||||
all_paths =
|
|
||||||
if Pleroma.Config.get(:release),
|
|
||||||
do: ["config/config.exs", "config/releases.exs"],
|
|
||||||
else: ["config/config.exs"]
|
|
||||||
|
|
||||||
all_paths
|
@spec merge(keyword(), keyword()) :: keyword()
|
||||||
|> Enum.map(&load(&1))
|
def merge(c1, c2), do: @reader.merge(c1, c2)
|
||||||
|> Enum.reduce([], &do_merge(&2, &1))
|
|
||||||
|
@spec default_config() :: keyword()
|
||||||
|
def default_config do
|
||||||
|
"config/config.exs"
|
||||||
|
|> read()
|
||||||
|> filter()
|
|> filter()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ defp merge_and_update(setting) do
|
||||||
key = ConfigDB.from_string(setting.key)
|
key = ConfigDB.from_string(setting.key)
|
||||||
group = ConfigDB.from_string(setting.group)
|
group = ConfigDB.from_string(setting.group)
|
||||||
|
|
||||||
default = Config.Holder.config(group, key)
|
default = Config.Holder.default_config(group, key)
|
||||||
value = ConfigDB.from_binary(setting.value)
|
value = ConfigDB.from_binary(setting.value)
|
||||||
|
|
||||||
merged_value =
|
merged_value =
|
||||||
|
|
|
@ -15,7 +15,7 @@ def process(descriptions) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def compile do
|
def compile do
|
||||||
with config <- Pleroma.Config.Loader.load("config/description.exs") do
|
with config <- Pleroma.Config.Loader.read("config/description.exs") do
|
||||||
config[:pleroma][:config_description]
|
config[:pleroma][:config_description]
|
||||||
|> Pleroma.Docs.Generator.convert_to_strings()
|
|> Pleroma.Docs.Generator.convert_to_strings()
|
||||||
|> Jason.encode!()
|
|> Jason.encode!()
|
||||||
|
|
|
@ -530,7 +530,14 @@ def register_changeset(struct, params \\ %{}, opts \\ []) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def maybe_validate_required_email(changeset, true), do: changeset
|
def maybe_validate_required_email(changeset, true), do: changeset
|
||||||
def maybe_validate_required_email(changeset, _), do: validate_required(changeset, [:email])
|
|
||||||
|
def maybe_validate_required_email(changeset, _) do
|
||||||
|
if Pleroma.Config.get([:instance, :account_activation_required]) do
|
||||||
|
validate_required(changeset, [:email])
|
||||||
|
else
|
||||||
|
changeset
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp put_ap_id(changeset) do
|
defp put_ap_id(changeset) do
|
||||||
ap_id = ap_id(%User{nickname: get_field(changeset, :nickname)})
|
ap_id = ap_id(%User{nickname: get_field(changeset, :nickname)})
|
||||||
|
|
|
@ -60,15 +60,28 @@ def publish(%Activity{data: %{"type" => "Create"}} = activity) do
|
||||||
|
|
||||||
def publish(_), do: {:error, "Not implemented"}
|
def publish(_), do: {:error, "Not implemented"}
|
||||||
|
|
||||||
@spec list() :: {:ok, [String.t()]} | {:error, any()}
|
@spec list(boolean()) :: {:ok, [String.t()]} | {:error, any()}
|
||||||
def list do
|
def list(with_not_accepted \\ false) do
|
||||||
with %User{} = user <- get_actor() do
|
with %User{} = user <- get_actor() do
|
||||||
list =
|
accepted =
|
||||||
user
|
user
|
||||||
|> User.following()
|
|> User.following()
|
||||||
|> Enum.map(fn entry -> URI.parse(entry).host end)
|
|> Enum.map(fn entry -> URI.parse(entry).host end)
|
||||||
|> Enum.uniq()
|
|> Enum.uniq()
|
||||||
|
|
||||||
|
list =
|
||||||
|
if with_not_accepted do
|
||||||
|
without_accept =
|
||||||
|
user
|
||||||
|
|> Pleroma.Activity.following_requests_for_actor()
|
||||||
|
|> Enum.map(fn a -> URI.parse(a.data["object"]).host <> " (no Accept received)" end)
|
||||||
|
|> Enum.uniq()
|
||||||
|
|
||||||
|
accepted ++ without_accept
|
||||||
|
else
|
||||||
|
accepted
|
||||||
|
end
|
||||||
|
|
||||||
{:ok, list}
|
{:ok, list}
|
||||||
else
|
else
|
||||||
error -> format_error(error)
|
error -> format_error(error)
|
||||||
|
|
|
@ -834,7 +834,7 @@ def config_show(conn, _params) do
|
||||||
configs = ConfigDB.get_all_as_keyword()
|
configs = ConfigDB.get_all_as_keyword()
|
||||||
|
|
||||||
merged =
|
merged =
|
||||||
Config.Holder.config()
|
Config.Holder.default_config()
|
||||||
|> ConfigDB.merge(configs)
|
|> ConfigDB.merge(configs)
|
||||||
|> Enum.map(fn {group, values} ->
|
|> Enum.map(fn {group, values} ->
|
||||||
Enum.map(values, fn {key, value} ->
|
Enum.map(values, fn {key, value} ->
|
||||||
|
|
|
@ -591,7 +591,7 @@ def validate_character_limit(full_payload, _attachments) do
|
||||||
limit = Pleroma.Config.get([:instance, :limit])
|
limit = Pleroma.Config.get([:instance, :limit])
|
||||||
length = String.length(full_payload)
|
length = String.length(full_payload)
|
||||||
|
|
||||||
if length < limit do
|
if length <= limit do
|
||||||
:ok
|
:ok
|
||||||
else
|
else
|
||||||
{:error, dgettext("errors", "The status is over the character limit")}
|
{:error, dgettext("errors", "The status is over the character limit")}
|
||||||
|
|
|
@ -76,7 +76,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||||
@doc "POST /api/v1/accounts"
|
@doc "POST /api/v1/accounts"
|
||||||
def create(
|
def create(
|
||||||
%{assigns: %{app: app}} = conn,
|
%{assigns: %{app: app}} = conn,
|
||||||
%{"username" => nickname, "email" => _, "password" => _, "agreement" => true} = params
|
%{"username" => nickname, "password" => _, "agreement" => true} = params
|
||||||
) do
|
) do
|
||||||
params =
|
params =
|
||||||
params
|
params
|
||||||
|
@ -93,7 +93,8 @@ def create(
|
||||||
|> Map.put("bio", params["bio"] || "")
|
|> Map.put("bio", params["bio"] || "")
|
||||||
|> Map.put("confirm", params["password"])
|
|> Map.put("confirm", params["password"])
|
||||||
|
|
||||||
with {:ok, user} <- TwitterAPI.register_user(params, need_confirmation: true),
|
with :ok <- validate_email_param(params),
|
||||||
|
{:ok, user} <- TwitterAPI.register_user(params, need_confirmation: true),
|
||||||
{:ok, token} <- Token.create_token(app, user, %{scopes: app.scopes}) do
|
{:ok, token} <- Token.create_token(app, user, %{scopes: app.scopes}) do
|
||||||
json(conn, %{
|
json(conn, %{
|
||||||
token_type: "Bearer",
|
token_type: "Bearer",
|
||||||
|
@ -114,6 +115,15 @@ def create(conn, _) do
|
||||||
render_error(conn, :forbidden, "Invalid credentials")
|
render_error(conn, :forbidden, "Invalid credentials")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp validate_email_param(%{"email" => _}), do: :ok
|
||||||
|
|
||||||
|
defp validate_email_param(_) do
|
||||||
|
case Pleroma.Config.get([:instance, :account_activation_required]) do
|
||||||
|
true -> {:error, %{"error" => "Missing parameters"}}
|
||||||
|
_ -> :ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@doc "GET /api/v1/accounts/verify_credentials"
|
@doc "GET /api/v1/accounts/verify_credentials"
|
||||||
def verify_credentials(%{assigns: %{user: user}} = conn, _) do
|
def verify_credentials(%{assigns: %{user: user}} = conn, _) do
|
||||||
chat_token = Phoenix.Token.sign(conn, "user socket", user.id)
|
chat_token = Phoenix.Token.sign(conn, "user socket", user.id)
|
||||||
|
|
BIN
priv/static/static/static-fe.css
Normal file
BIN
priv/static/static/static-fe.css
Normal file
Binary file not shown.
|
@ -7,8 +7,8 @@ defmodule Pleroma.Config.HolderTest do
|
||||||
|
|
||||||
alias Pleroma.Config.Holder
|
alias Pleroma.Config.Holder
|
||||||
|
|
||||||
test "config/0" do
|
test "default_config/0" do
|
||||||
config = Holder.config()
|
config = Holder.default_config()
|
||||||
assert config[:pleroma][Pleroma.Uploaders.Local][:uploads] == "test/uploads"
|
assert config[:pleroma][Pleroma.Uploaders.Local][:uploads] == "test/uploads"
|
||||||
assert config[:tesla][:adapter] == Tesla.Mock
|
assert config[:tesla][:adapter] == Tesla.Mock
|
||||||
|
|
||||||
|
@ -20,15 +20,15 @@ test "config/0" do
|
||||||
refute config[:phoenix][:serve_endpoints]
|
refute config[:phoenix][:serve_endpoints]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "config/1" do
|
test "default_config/1" do
|
||||||
pleroma_config = Holder.config(:pleroma)
|
pleroma_config = Holder.default_config(:pleroma)
|
||||||
assert pleroma_config[Pleroma.Uploaders.Local][:uploads] == "test/uploads"
|
assert pleroma_config[Pleroma.Uploaders.Local][:uploads] == "test/uploads"
|
||||||
tesla_config = Holder.config(:tesla)
|
tesla_config = Holder.default_config(:tesla)
|
||||||
assert tesla_config[:adapter] == Tesla.Mock
|
assert tesla_config[:adapter] == Tesla.Mock
|
||||||
end
|
end
|
||||||
|
|
||||||
test "config/2" do
|
test "default_config/2" do
|
||||||
assert Holder.config(:pleroma, Pleroma.Uploaders.Local) == [uploads: "test/uploads"]
|
assert Holder.default_config(:pleroma, Pleroma.Uploaders.Local) == [uploads: "test/uploads"]
|
||||||
assert Holder.config(:tesla, :adapter) == Tesla.Mock
|
assert Holder.default_config(:tesla, :adapter) == Tesla.Mock
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,28 +7,13 @@ defmodule Pleroma.Config.LoaderTest do
|
||||||
|
|
||||||
alias Pleroma.Config.Loader
|
alias Pleroma.Config.Loader
|
||||||
|
|
||||||
test "load/1" do
|
test "read/1" do
|
||||||
config = Loader.load("test/fixtures/config/temp.secret.exs")
|
config = Loader.read("test/fixtures/config/temp.secret.exs")
|
||||||
assert config[:pleroma][:first_setting][:key] == "value"
|
assert config[:pleroma][:first_setting][:key] == "value"
|
||||||
assert config[:pleroma][:first_setting][:key2] == [Pleroma.Repo]
|
assert config[:pleroma][:first_setting][:key2] == [Pleroma.Repo]
|
||||||
assert config[:quack][:level] == :info
|
assert config[:quack][:level] == :info
|
||||||
end
|
end
|
||||||
|
|
||||||
test "load_and_merge/0" do
|
|
||||||
config = Loader.load_and_merge()
|
|
||||||
|
|
||||||
refute config[:pleroma][Pleroma.Repo]
|
|
||||||
refute config[:pleroma][Pleroma.Web.Endpoint]
|
|
||||||
refute config[:pleroma][:env]
|
|
||||||
refute config[:pleroma][:configurable_from_database]
|
|
||||||
refute config[:pleroma][:database]
|
|
||||||
refute config[:phoenix][:serve_endpoints]
|
|
||||||
|
|
||||||
assert config[:pleroma][:ecto_repos] == [Pleroma.Repo]
|
|
||||||
assert config[:pleroma][Pleroma.Uploaders.Local][:uploads] == "test/uploads"
|
|
||||||
assert config[:tesla][:adapter] == Tesla.Mock
|
|
||||||
end
|
|
||||||
|
|
||||||
test "filter_group/2" do
|
test "filter_group/2" do
|
||||||
assert Loader.filter_group(:pleroma,
|
assert Loader.filter_group(:pleroma,
|
||||||
pleroma: [
|
pleroma: [
|
||||||
|
|
|
@ -70,7 +70,7 @@ test "transfer config values for 1 group and some keys" do
|
||||||
|
|
||||||
assert Application.get_env(:quack, :level) == :info
|
assert Application.get_env(:quack, :level) == :info
|
||||||
assert Application.get_env(:quack, :meta) == [:none]
|
assert Application.get_env(:quack, :meta) == [:none]
|
||||||
default = Pleroma.Config.Holder.config(:quack, :webhook_url)
|
default = Pleroma.Config.Holder.default_config(:quack, :webhook_url)
|
||||||
assert Application.get_env(:quack, :webhook_url) == default
|
assert Application.get_env(:quack, :webhook_url) == default
|
||||||
|
|
||||||
on_exit(fn ->
|
on_exit(fn ->
|
||||||
|
|
15
test/fixtures/relay/accept-follow.json
vendored
Normal file
15
test/fixtures/relay/accept-follow.json
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"actor": "https://relay.mastodon.host/actor",
|
||||||
|
"id": "https://relay.mastodon.host/activities/ec477b69-db26-4019-923e-cf809de516ab",
|
||||||
|
"object": {
|
||||||
|
"actor": "{{ap_id}}",
|
||||||
|
"id": "{{activity_id}}",
|
||||||
|
"object": "https://relay.mastodon.host/actor",
|
||||||
|
"type": "Follow"
|
||||||
|
},
|
||||||
|
"to": [
|
||||||
|
"{{ap_id}}"
|
||||||
|
],
|
||||||
|
"type": "Accept"
|
||||||
|
}
|
20
test/fixtures/relay/relay.json
vendored
Normal file
20
test/fixtures/relay/relay.json
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"endpoints": {
|
||||||
|
"sharedInbox": "https://relay.mastodon.host/inbox"
|
||||||
|
},
|
||||||
|
"followers": "https://relay.mastodon.host/followers",
|
||||||
|
"following": "https://relay.mastodon.host/following",
|
||||||
|
"inbox": "https://relay.mastodon.host/inbox",
|
||||||
|
"name": "ActivityRelay",
|
||||||
|
"type": "Application",
|
||||||
|
"id": "https://relay.mastodon.host/actor",
|
||||||
|
"publicKey": {
|
||||||
|
"id": "https://relay.mastodon.host/actor#main-key",
|
||||||
|
"owner": "https://relay.mastodon.host/actor",
|
||||||
|
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuNYHNYETdsZFsdcTTEQo\nlsTP9yz4ZjOGrQ1EjoBA7NkjBUxxUAPxZbBjWPT9F+L3IbCX1IwI2OrBM/KwDlug\nV41xnjNmxSCUNpxX5IMZtFaAz9/hWu6xkRTs9Bh6XWZxi+db905aOqszb9Mo3H2g\nQJiAYemXwTh2kBO7XlBDbsMhO11Tu8FxcWTMdR54vlGv4RoiVh8dJRa06yyiTs+m\njbj/OJwR06mHHwlKYTVT/587NUb+e9QtCK6t/dqpyZ1o7vKSK5PSldZVjwHt292E\nXVxFOQVXi7JazTwpdPww79ECSe8ThCykOYCNkm3RjsKuLuokp7Vzq1hXIoeBJ7z2\ndU8vbgg/JyazsOsTxkVs2nd2i9/QW2SH+sX9X3357+XLSCh/A8p8fv/GeoN7UCXe\n4DWHFJZDlItNFfymiPbQH+omuju8qrfW9ngk1gFeI2mahXFQVu7x0qsaZYioCIrZ\nwq0zPnUGl9u0tLUXQz+ZkInRrEz+JepDVauy5/3QdzMLG420zCj/ygDrFzpBQIrc\n62Z6URueUBJox0UK71K+usxqOrepgw8haFGMvg3STFo34pNYjoK4oKO+h5qZEDFD\nb1n57t6JWUaBocZbJns9RGASq5gih+iMk2+zPLWp1x64yvuLsYVLPLBHxjCxS6lA\ndWcopZHi7R/OsRz+vTT7420CAwEAAQ==\n-----END PUBLIC KEY-----"
|
||||||
|
},
|
||||||
|
"summary": "ActivityRelay bot",
|
||||||
|
"preferredUsername": "relay",
|
||||||
|
"url": "https://relay.mastodon.host/actor"
|
||||||
|
}
|
|
@ -1287,6 +1287,10 @@ def get("http://example.com/rel_me/error", _, _, _) do
|
||||||
{:ok, %Tesla.Env{status: 404, body: ""}}
|
{:ok, %Tesla.Env{status: 404, body: ""}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get("https://relay.mastodon.host/actor", _, _, _) do
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/relay/relay.json")}}
|
||||||
|
end
|
||||||
|
|
||||||
def get(url, query, body, headers) do
|
def get(url, query, body, headers) do
|
||||||
{:error,
|
{:error,
|
||||||
"Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{
|
"Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{
|
||||||
|
@ -1299,6 +1303,10 @@ def get(url, query, body, headers) do
|
||||||
|
|
||||||
def post(url, query \\ [], body \\ [], headers \\ [])
|
def post(url, query \\ [], body \\ [], headers \\ [])
|
||||||
|
|
||||||
|
def post("https://relay.mastodon.host/inbox", _, _, _) do
|
||||||
|
{:ok, %Tesla.Env{status: 200, body: ""}}
|
||||||
|
end
|
||||||
|
|
||||||
def post("http://example.org/needs_refresh", _, _, _) do
|
def post("http://example.org/needs_refresh", _, _, _) do
|
||||||
{:ok,
|
{:ok,
|
||||||
%Tesla.Env{
|
%Tesla.Env{
|
||||||
|
|
|
@ -38,6 +38,9 @@ test "relay is followed" do
|
||||||
assert activity.data["type"] == "Follow"
|
assert activity.data["type"] == "Follow"
|
||||||
assert activity.data["actor"] == local_user.ap_id
|
assert activity.data["actor"] == local_user.ap_id
|
||||||
assert activity.data["object"] == target_user.ap_id
|
assert activity.data["object"] == target_user.ap_id
|
||||||
|
|
||||||
|
:ok = Mix.Tasks.Pleroma.Relay.run(["list"])
|
||||||
|
assert_receive {:mix_shell, :info, ["mastodon.example.org (no Accept received)"]}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -412,7 +412,11 @@ test "it sends a welcome message if it is set" do
|
||||||
assert activity.actor == welcome_user.ap_id
|
assert activity.actor == welcome_user.ap_id
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it requires an email, name, nickname and password, bio is optional" do
|
clear_config([:instance, :account_activation_required])
|
||||||
|
|
||||||
|
test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
|
||||||
|
Pleroma.Config.put([:instance, :account_activation_required], true)
|
||||||
|
|
||||||
@full_user_data
|
@full_user_data
|
||||||
|> Map.keys()
|
|> Map.keys()
|
||||||
|> Enum.each(fn key ->
|
|> Enum.each(fn key ->
|
||||||
|
@ -423,6 +427,19 @@ test "it requires an email, name, nickname and password, bio is optional" do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
|
||||||
|
Pleroma.Config.put([:instance, :account_activation_required], false)
|
||||||
|
|
||||||
|
@full_user_data
|
||||||
|
|> Map.keys()
|
||||||
|
|> Enum.each(fn key ->
|
||||||
|
params = Map.delete(@full_user_data, key)
|
||||||
|
changeset = User.register_changeset(%User{}, params)
|
||||||
|
|
||||||
|
assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
test "it restricts certain nicknames" do
|
test "it restricts certain nicknames" do
|
||||||
[restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
|
[restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
|
||||||
|
|
||||||
|
|
|
@ -341,6 +341,44 @@ test "it clears `unreachable` federation status of the sender", %{conn: conn} do
|
||||||
assert "ok" == json_response(conn, 200)
|
assert "ok" == json_response(conn, 200)
|
||||||
assert Instances.reachable?(sender_url)
|
assert Instances.reachable?(sender_url)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "accept follow activity", %{conn: conn} do
|
||||||
|
Pleroma.Config.put([:instance, :federating], true)
|
||||||
|
relay = Relay.get_actor()
|
||||||
|
|
||||||
|
assert {:ok, %Activity{} = activity} = Relay.follow("https://relay.mastodon.host/actor")
|
||||||
|
|
||||||
|
followed_relay = Pleroma.User.get_by_ap_id("https://relay.mastodon.host/actor")
|
||||||
|
relay = refresh_record(relay)
|
||||||
|
|
||||||
|
accept =
|
||||||
|
File.read!("test/fixtures/relay/accept-follow.json")
|
||||||
|
|> String.replace("{{ap_id}}", relay.ap_id)
|
||||||
|
|> String.replace("{{activity_id}}", activity.data["id"])
|
||||||
|
|
||||||
|
assert "ok" ==
|
||||||
|
conn
|
||||||
|
|> assign(:valid_signature, true)
|
||||||
|
|> put_req_header("content-type", "application/activity+json")
|
||||||
|
|> post("/inbox", accept)
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
|
||||||
|
|
||||||
|
assert Pleroma.FollowingRelationship.following?(
|
||||||
|
relay,
|
||||||
|
followed_relay
|
||||||
|
)
|
||||||
|
|
||||||
|
Mix.shell(Mix.Shell.Process)
|
||||||
|
|
||||||
|
on_exit(fn ->
|
||||||
|
Mix.shell(Mix.Shell.IO)
|
||||||
|
end)
|
||||||
|
|
||||||
|
:ok = Mix.Tasks.Pleroma.Relay.run(["list"])
|
||||||
|
assert_receive {:mix_shell, :info, ["relay.mastodon.host"]}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "/users/:nickname/inbox" do
|
describe "/users/:nickname/inbox" do
|
||||||
|
|
|
@ -202,13 +202,15 @@ test "it returns error when status is empty and no attachments" do
|
||||||
CommonAPI.post(user, %{"status" => ""})
|
CommonAPI.post(user, %{"status" => ""})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it returns error when character limit is exceeded" do
|
test "it validates character limits are correctly enforced" do
|
||||||
Pleroma.Config.put([:instance, :limit], 5)
|
Pleroma.Config.put([:instance, :limit], 5)
|
||||||
|
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
assert {:error, "The status is over the character limit"} =
|
assert {:error, "The status is over the character limit"} =
|
||||||
CommonAPI.post(user, %{"status" => "foobar"})
|
CommonAPI.post(user, %{"status" => "foobar"})
|
||||||
|
|
||||||
|
assert {:ok, activity} = CommonAPI.post(user, %{"status" => "12345"})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it can handle activities that expire" do
|
test "it can handle activities that expire" do
|
||||||
|
|
|
@ -601,6 +601,8 @@ test "blocking / unblocking a user" do
|
||||||
[valid_params: valid_params]
|
[valid_params: valid_params]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
clear_config([:instance, :account_activation_required])
|
||||||
|
|
||||||
test "Account registration via Application", %{conn: conn} do
|
test "Account registration via Application", %{conn: conn} do
|
||||||
conn =
|
conn =
|
||||||
post(conn, "/api/v1/apps", %{
|
post(conn, "/api/v1/apps", %{
|
||||||
|
@ -685,7 +687,7 @@ test "returns bad_request if missing required params", %{
|
||||||
assert json_response(res, 200)
|
assert json_response(res, 200)
|
||||||
|
|
||||||
[{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
|
[{127, 0, 0, 1}, {127, 0, 0, 2}, {127, 0, 0, 3}, {127, 0, 0, 4}]
|
||||||
|> Stream.zip(valid_params)
|
|> Stream.zip(Map.delete(valid_params, :email))
|
||||||
|> Enum.each(fn {ip, {attr, _}} ->
|
|> Enum.each(fn {ip, {attr, _}} ->
|
||||||
res =
|
res =
|
||||||
conn
|
conn
|
||||||
|
@ -697,6 +699,54 @@ test "returns bad_request if missing required params", %{
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
clear_config([:instance, :account_activation_required])
|
||||||
|
|
||||||
|
test "returns bad_request if missing email params when :account_activation_required is enabled",
|
||||||
|
%{conn: conn, valid_params: valid_params} do
|
||||||
|
Pleroma.Config.put([:instance, :account_activation_required], true)
|
||||||
|
|
||||||
|
app_token = insert(:oauth_token, user: nil)
|
||||||
|
conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> Map.put(:remote_ip, {127, 0, 0, 5})
|
||||||
|
|> post("/api/v1/accounts", Map.delete(valid_params, :email))
|
||||||
|
|
||||||
|
assert json_response(res, 400) == %{"error" => "Missing parameters"}
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> Map.put(:remote_ip, {127, 0, 0, 6})
|
||||||
|
|> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
|
||||||
|
|
||||||
|
assert json_response(res, 400) == %{"error" => "{\"email\":[\"can't be blank\"]}"}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "allow registration without an email", %{conn: conn, valid_params: valid_params} do
|
||||||
|
app_token = insert(:oauth_token, user: nil)
|
||||||
|
conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> Map.put(:remote_ip, {127, 0, 0, 7})
|
||||||
|
|> post("/api/v1/accounts", Map.delete(valid_params, :email))
|
||||||
|
|
||||||
|
assert json_response(res, 200)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "allow registration with an empty email", %{conn: conn, valid_params: valid_params} do
|
||||||
|
app_token = insert(:oauth_token, user: nil)
|
||||||
|
conn = put_req_header(conn, "authorization", "Bearer " <> app_token.token)
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> Map.put(:remote_ip, {127, 0, 0, 8})
|
||||||
|
|> post("/api/v1/accounts", Map.put(valid_params, :email, ""))
|
||||||
|
|
||||||
|
assert json_response(res, 200)
|
||||||
|
end
|
||||||
|
|
||||||
test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
|
test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
|
||||||
conn = put_req_header(conn, "authorization", "Bearer " <> "invalid-token")
|
conn = put_req_header(conn, "authorization", "Bearer " <> "invalid-token")
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue