forked from AkkomaGang/akkoma
Merge branch 'develop' into issue/1383
This commit is contained in:
commit
bfc70fdf29
23 changed files with 401 additions and 245 deletions
|
@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- **Breaking:** Elixir >=1.8 is now required (was >= 1.7)
|
- **Breaking:** Elixir >=1.8 is now required (was >= 1.7)
|
||||||
- **Breaking:** attachment links (`config :pleroma, :instance, no_attachment_links` and `config :pleroma, Pleroma.Upload, link_name`) disabled by default
|
- **Breaking:** attachment links (`config :pleroma, :instance, no_attachment_links` and `config :pleroma, Pleroma.Upload, link_name`) disabled by default
|
||||||
- **Breaking:** OAuth: defaulted `[:auth, :enforce_oauth_admin_scope_usage]` setting to `true` which demands `admin` OAuth scope to perform admin actions (in addition to `is_admin` flag on User); make sure to use bundled or newer versions of AdminFE & PleromaFE to access admin / moderator features.
|
- **Breaking:** OAuth: defaulted `[:auth, :enforce_oauth_admin_scope_usage]` setting to `true` which demands `admin` OAuth scope to perform admin actions (in addition to `is_admin` flag on User); make sure to use bundled or newer versions of AdminFE & PleromaFE to access admin / moderator features.
|
||||||
|
- **Breaking:** Dynamic configuration has been rearchitected. The `:pleroma, :instance, dynamic_configuration` setting has been replaced with `config :pleroma, configurable_from_database`. Please backup your configuration to a file and run the migration task to ensure consistency with the new schema.
|
||||||
- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings)
|
- Replaced [pleroma_job_queue](https://git.pleroma.social/pleroma/pleroma_job_queue) and `Pleroma.Web.Federator.RetryQueue` with [Oban](https://github.com/sorentwo/oban) (see [`docs/config.md`](docs/config.md) on migrating customized worker / retry settings)
|
||||||
- Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler
|
- Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler
|
||||||
- Enabled `:instance, extended_nickname_format` in the default config
|
- Enabled `:instance, extended_nickname_format` in the default config
|
||||||
|
@ -26,6 +27,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Store status data inside Flag activity
|
- Store status data inside Flag activity
|
||||||
- Deprecated (reorganized as `UserRelationship` entity) User fields with user AP IDs (`blocks`, `mutes`, `muted_reblogs`, `muted_notifications`, `subscribers`).
|
- Deprecated (reorganized as `UserRelationship` entity) User fields with user AP IDs (`blocks`, `mutes`, `muted_reblogs`, `muted_notifications`, `subscribers`).
|
||||||
- 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.
|
||||||
<details>
|
<details>
|
||||||
<summary>API Changes</summary>
|
<summary>API Changes</summary>
|
||||||
|
|
||||||
|
@ -97,6 +99,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Mastodon API: Add `emoji_reactions` property to Statuses
|
- Mastodon API: Add `emoji_reactions` property to Statuses
|
||||||
- Mastodon API: Change emoji reaction reply format
|
- Mastodon API: Change emoji reaction reply format
|
||||||
- Notifications: Added `pleroma:emoji_reaction` notification type
|
- Notifications: Added `pleroma:emoji_reaction` notification type
|
||||||
|
- Mastodon API: Change emoji reaction reply format once more
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
key: :uploader,
|
key: :uploader,
|
||||||
type: :module,
|
type: :module,
|
||||||
description: "Module which will be used for uploads",
|
description: "Module which will be used for uploads",
|
||||||
suggestions: [Pleroma.Uploaders.Local, Pleroma.Uploaders.MDII, Pleroma.Uploaders.S3]
|
suggestions: [Pleroma.Uploaders.Local, Pleroma.Uploaders.S3]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :filters,
|
key: :filters,
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
key: :link_name,
|
key: :link_name,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description:
|
||||||
"If enabled, a name parameter will be added to the url of the upload. For example `https://instance.tld/media/imagehash.png?name=realname.png`"
|
"If enabled, a name parameter will be added to the url of the upload. For example `https://instance.tld/media/imagehash.png?name=realname.png`."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :base_url,
|
key: :base_url,
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
key: :proxy_remote,
|
key: :proxy_remote,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description:
|
||||||
"If enabled, requests to media stored using a remote uploader will be proxied instead of being redirected."
|
"If enabled, requests to media stored using a remote uploader will be proxied instead of being redirected"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :proxy_opts,
|
key: :proxy_opts,
|
||||||
|
@ -73,14 +73,14 @@
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description:
|
||||||
"Redirects the client to the real remote URL if there's any HTTP errors. " <>
|
"Redirects the client to the real remote URL if there's any HTTP errors. " <>
|
||||||
"Any error during body processing will not be redirected as the response is chunked"
|
"Any error during body processing will not be redirected as the response is chunked."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :max_body_length,
|
key: :max_body_length,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description:
|
description:
|
||||||
"limits the content length to be approximately the " <>
|
"Limits the content length to be approximately the " <>
|
||||||
"specified length. It is validated with the `content-length` header and also verified when proxying"
|
"specified length. It is validated with the `content-length` header and also verified when proxying."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :http,
|
key: :http,
|
||||||
|
@ -130,7 +130,7 @@
|
||||||
%{
|
%{
|
||||||
key: :uploads,
|
key: :uploads,
|
||||||
type: :string,
|
type: :string,
|
||||||
description: "Path where user uploads will be saved",
|
description: "Path where user's uploads will be saved",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
"uploads"
|
"uploads"
|
||||||
]
|
]
|
||||||
|
@ -207,7 +207,7 @@
|
||||||
type: :string,
|
type: :string,
|
||||||
description:
|
description:
|
||||||
"Text to replace filenames in links. If no setting, {random}.extension will be used. You can get the original" <>
|
"Text to replace filenames in links. If no setting, {random}.extension will be used. You can get the original" <>
|
||||||
" filename extension by using {extension}, for example custom-file-name.{extension}",
|
" filename extension by using {extension}, for example custom-file-name.{extension}.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
"custom-file-name.{extension}"
|
"custom-file-name.{extension}"
|
||||||
]
|
]
|
||||||
|
@ -515,6 +515,7 @@
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :email,
|
key: :email,
|
||||||
|
label: "Admin Email Address",
|
||||||
type: :string,
|
type: :string,
|
||||||
description: "Email used to reach an Administrator/Moderator of the instance",
|
description: "Email used to reach an Administrator/Moderator of the instance",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
|
@ -523,8 +524,9 @@
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :notify_email,
|
key: :notify_email,
|
||||||
|
label: "Sender Email Address",
|
||||||
type: :string,
|
type: :string,
|
||||||
description: "Email used for notifications",
|
description: "Envelope FROM address for mail sent via Pleroma",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
"notify@example.com"
|
"notify@example.com"
|
||||||
]
|
]
|
||||||
|
@ -635,12 +637,12 @@
|
||||||
%{
|
%{
|
||||||
key: :registrations_open,
|
key: :registrations_open,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Enable registrations for anyone, invitations can be enabled when false"
|
description: "Enable registrations for anyone, invitations can be enabled when `false`"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :invites_enabled,
|
key: :invites_enabled,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Enable user invitations for admins (depends on registrations_open: false)"
|
description: "Enable user invitations for admins (depends on `registrations_open: false`)"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :account_activation_required,
|
key: :account_activation_required,
|
||||||
|
@ -658,7 +660,7 @@
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description:
|
description:
|
||||||
"Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while" <>
|
"Max. depth of reply-to activities fetching on incoming federation, to prevent out-of-memory situations while" <>
|
||||||
" fetching very long threads. If set to nil, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes",
|
" fetching very long threads. If set to `nil`, threads of any depth will be fetched. Lower this value if you experience out-of-memory crashes.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
100
|
100
|
||||||
]
|
]
|
||||||
|
@ -668,7 +670,7 @@
|
||||||
label: "Fed. reachability timeout days",
|
label: "Fed. reachability timeout days",
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description:
|
description:
|
||||||
"Timeout (in days) of each external federation target being unreachable prior to pausing federating to it",
|
"Timeout (in days) of each external federation target being unreachable prior to pausing federating to it.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
7
|
7
|
||||||
]
|
]
|
||||||
|
@ -701,7 +703,7 @@
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description:
|
||||||
"Makes the client API in authentificated mode-only except for user-profiles." <>
|
"Makes the client API in authentificated mode-only except for user-profiles." <>
|
||||||
" Useful for disabling the Local Timeline and The Whole Known Network"
|
" Useful for disabling the Local Timeline and The Whole Known Network."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :quarantined_instances,
|
key: :quarantined_instances,
|
||||||
|
@ -750,7 +752,7 @@
|
||||||
label: "MRF transparency exclusions",
|
label: "MRF transparency exclusions",
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
description:
|
description:
|
||||||
"Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value",
|
"Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
"exclusion.com"
|
"exclusion.com"
|
||||||
]
|
]
|
||||||
|
@ -759,13 +761,13 @@
|
||||||
key: :extended_nickname_format,
|
key: :extended_nickname_format,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description:
|
||||||
"Set to true to use extended local nicknames format (allows underscores/dashes)." <>
|
"Set to `true` to use extended local nicknames format (allows underscores/dashes)." <>
|
||||||
" This will break federation with older software for theses nicknames"
|
" This will break federation with older software for theses nicknames."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :max_pinned_statuses,
|
key: :max_pinned_statuses,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description: "The maximum number of pinned statuses. 0 will disable the feature",
|
description: "The maximum number of pinned statuses. 0 will disable the feature.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
|
@ -788,13 +790,13 @@
|
||||||
key: :no_attachment_links,
|
key: :no_attachment_links,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description:
|
||||||
"Set to true to disable automatically adding attachment link text to statuses"
|
"Set to `true` to disable automatically adding attachment link text to statuses"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :welcome_message,
|
key: :welcome_message,
|
||||||
type: :string,
|
type: :string,
|
||||||
description:
|
description:
|
||||||
"A message that will be send to a newly registered users as a direct message",
|
"A message that will be sent to a newly registered users as a direct message",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
"Hi, @username! Welcome on board!"
|
"Hi, @username! Welcome on board!"
|
||||||
]
|
]
|
||||||
|
@ -810,7 +812,7 @@
|
||||||
%{
|
%{
|
||||||
key: :max_report_comment_size,
|
key: :max_report_comment_size,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description: "The maximum size of the report comment (Default: 1000)",
|
description: "The maximum size of the report comment. Default: 1000.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
1_000
|
1_000
|
||||||
]
|
]
|
||||||
|
@ -819,14 +821,14 @@
|
||||||
key: :safe_dm_mentions,
|
key: :safe_dm_mentions,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description:
|
||||||
"If set to true, only mentions at the beginning of a post will be used to address people in direct messages." <>
|
"If set to `true`, only mentions at the beginning of a post will be used to address people in direct messages." <>
|
||||||
" This is to prevent accidental mentioning of people when talking about them (e.g. \"@friend hey i really don't like @enemy\")." <>
|
" This is to prevent accidental mentioning of people when talking about them (e.g. \"@admin please keep an eye on @bad_actor\")." <>
|
||||||
" Default: false"
|
" Default: `false`"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :healthcheck,
|
key: :healthcheck,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "If set to true, system data will be shown on /api/pleroma/healthcheck"
|
description: "If set to `true`, system data will be shown on /api/pleroma/healthcheck"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :remote_post_retention_days,
|
key: :remote_post_retention_days,
|
||||||
|
@ -840,7 +842,7 @@
|
||||||
%{
|
%{
|
||||||
key: :user_bio_length,
|
key: :user_bio_length,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description: "A user bio maximum length (default: 5000)",
|
description: "A user bio maximum length. Default: 5000.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
5_000
|
5_000
|
||||||
]
|
]
|
||||||
|
@ -848,7 +850,7 @@
|
||||||
%{
|
%{
|
||||||
key: :user_name_length,
|
key: :user_name_length,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description: "A user name maximum length (default: 100)",
|
description: "A user name maximum length. Default: 100.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
100
|
100
|
||||||
]
|
]
|
||||||
|
@ -856,13 +858,13 @@
|
||||||
%{
|
%{
|
||||||
key: :skip_thread_containment,
|
key: :skip_thread_containment,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Skip filter out broken threads. The default is true"
|
description: "Skip filter out broken threads. Default: `true`"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :limit_to_local_content,
|
key: :limit_to_local_content,
|
||||||
type: [:atom, false],
|
type: [:atom, false],
|
||||||
description:
|
description:
|
||||||
"Limit unauthenticated users to search for local statutes and users only. The default is :unauthenticated ",
|
"Limit unauthenticated users to search for local statutes and users only. Default: `:unauthenticated`.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
:unauthenticated,
|
:unauthenticated,
|
||||||
:all,
|
:all,
|
||||||
|
@ -872,7 +874,7 @@
|
||||||
%{
|
%{
|
||||||
key: :max_account_fields,
|
key: :max_account_fields,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description: "The maximum number of custom fields in the user profile (default: 10)",
|
description: "The maximum number of custom fields in the user profile. Default: 10.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
10
|
10
|
||||||
]
|
]
|
||||||
|
@ -881,7 +883,7 @@
|
||||||
key: :max_remote_account_fields,
|
key: :max_remote_account_fields,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description:
|
description:
|
||||||
"The maximum number of custom fields in the remote user profile (default: 20)",
|
"The maximum number of custom fields in the remote user profile. Default: 20.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
20
|
20
|
||||||
]
|
]
|
||||||
|
@ -889,7 +891,7 @@
|
||||||
%{
|
%{
|
||||||
key: :account_field_name_length,
|
key: :account_field_name_length,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description: "An account field name maximum length (default: 512)",
|
description: "An account field name maximum length. Default: 512.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
512
|
512
|
||||||
]
|
]
|
||||||
|
@ -897,7 +899,7 @@
|
||||||
%{
|
%{
|
||||||
key: :account_field_value_length,
|
key: :account_field_value_length,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description: "An account field value maximum length (default: 2048)",
|
description: "An account field value maximum length. Default: 2048.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
2048
|
2048
|
||||||
]
|
]
|
||||||
|
@ -918,7 +920,7 @@
|
||||||
key: :backends,
|
key: :backends,
|
||||||
type: [:atom, :tuple, :module],
|
type: [:atom, :tuple, :module],
|
||||||
description:
|
description:
|
||||||
"Where logs will be send, :console - send logs to stdout, {ExSyslogger, :ex_syslogger} - to syslog, Quack.Logger - to Slack.",
|
"Where logs will be sent, :console - send logs to stdout, { ExSyslogger, :ex_syslogger } - to syslog, Quack.Logger - to Slack.",
|
||||||
suggestions: [:console, {ExSyslogger, :ex_syslogger}, Quack.Logger]
|
suggestions: [:console, {ExSyslogger, :ex_syslogger}, Quack.Logger]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -945,7 +947,7 @@
|
||||||
%{
|
%{
|
||||||
key: :format,
|
key: :format,
|
||||||
type: :string,
|
type: :string,
|
||||||
description: "It defaults to \"$date $time [$level] $levelpad$node $metadata $message\"",
|
description: "Default: \"$date $time [$level] $levelpad$node $metadata $message\".",
|
||||||
suggestions: ["$metadata[$level] $message"]
|
suggestions: ["$metadata[$level] $message"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -970,7 +972,7 @@
|
||||||
%{
|
%{
|
||||||
key: :format,
|
key: :format,
|
||||||
type: :string,
|
type: :string,
|
||||||
description: "It defaults to \"$date $time [$level] $levelpad$node $metadata $message\"",
|
description: "Default: \"$date $time [$level] $levelpad$node $metadata $message\".",
|
||||||
suggestions: ["$metadata[$level] $message"]
|
suggestions: ["$metadata[$level] $message"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -1024,7 +1026,7 @@
|
||||||
description:
|
description:
|
||||||
"This form can be used to configure a keyword list that keeps the configuration data for any " <>
|
"This form can be used to configure a keyword list that keeps the configuration data for any " <>
|
||||||
"kind of frontend. By default, settings for pleroma_fe and masto_fe are configured. If you want to " <>
|
"kind of frontend. By default, settings for pleroma_fe and masto_fe are configured. If you want to " <>
|
||||||
"add your own configuration your settings need to be complete as they will override the defaults.",
|
"add your own configuration your settings all fields must be complete.",
|
||||||
children: [
|
children: [
|
||||||
%{
|
%{
|
||||||
key: :pleroma_fe,
|
key: :pleroma_fe,
|
||||||
|
@ -1046,7 +1048,11 @@
|
||||||
hideUserStats: false,
|
hideUserStats: false,
|
||||||
scopeCopy: true,
|
scopeCopy: true,
|
||||||
subjectLineBehavior: "email",
|
subjectLineBehavior: "email",
|
||||||
alwaysShowSubjectInput: true
|
alwaysShowSubjectInput: true,
|
||||||
|
logoMask: false,
|
||||||
|
logoMargin: ".1em",
|
||||||
|
stickers: false,
|
||||||
|
enableEmojiPicker: false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
children: [
|
children: [
|
||||||
|
@ -1074,7 +1080,7 @@
|
||||||
label: "Redirect root no login",
|
label: "Redirect root no login",
|
||||||
type: :string,
|
type: :string,
|
||||||
description:
|
description:
|
||||||
"relative URL which indicates where to redirect when a user isn't logged in",
|
"Relative URL which indicates where to redirect when a user isn't logged in",
|
||||||
suggestions: ["/main/all"]
|
suggestions: ["/main/all"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -1082,7 +1088,7 @@
|
||||||
label: "Redirect root login",
|
label: "Redirect root login",
|
||||||
type: :string,
|
type: :string,
|
||||||
description:
|
description:
|
||||||
"relative URL which indicates where to redirect when a user is logged in",
|
"Relative URL which indicates where to redirect when a user is logged in",
|
||||||
suggestions: ["/main/friends"]
|
suggestions: ["/main/friends"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -1095,14 +1101,14 @@
|
||||||
key: :scopeOptionsEnabled,
|
key: :scopeOptionsEnabled,
|
||||||
label: "Scope options enabled",
|
label: "Scope options enabled",
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Enable setting an notice visibility and subject/CW when posting"
|
description: "Enable setting a notice visibility and subject/CW when posting"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :formattingOptionsEnabled,
|
key: :formattingOptionsEnabled,
|
||||||
label: "Formatting options enabled",
|
label: "Formatting options enabled",
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description:
|
||||||
"Enable setting a formatting different than plain-text (ie. HTML, Markdown) when posting, relates to :instance, allowed_post_formats"
|
"Enable setting a formatting different than plain-text (ie. HTML, Markdown) when posting, relates to `:instance`, `allowed_post_formats`"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :collapseMessageWithSubject,
|
key: :collapseMessageWithSubject,
|
||||||
|
@ -1135,16 +1141,46 @@
|
||||||
label: "Subject line behavior",
|
label: "Subject line behavior",
|
||||||
type: :string,
|
type: :string,
|
||||||
description: "Allows changing the default behaviour of subject lines in replies.
|
description: "Allows changing the default behaviour of subject lines in replies.
|
||||||
`email`: Copy and preprend re:, as in email,
|
`email`: copy and preprend re:, as in email,
|
||||||
`masto`: Copy verbatim, as in Mastodon,
|
`masto`: copy verbatim, as in Mastodon,
|
||||||
`noop`: Don't copy the subjec",
|
`noop`: don't copy the subject.",
|
||||||
suggestions: ["email", "masto", "noop"]
|
suggestions: ["email", "masto", "noop"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :alwaysShowSubjectInput,
|
key: :alwaysShowSubjectInput,
|
||||||
label: "Always show subject input",
|
label: "Always show subject input",
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "When set to false, auto-hide the subject field when it's empty"
|
description: "When set to `false`, auto-hide the subject field when it's empty"
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :logoMask,
|
||||||
|
label: "Logo mask",
|
||||||
|
type: :boolean,
|
||||||
|
description:
|
||||||
|
"By default it assumes logo used will be monochrome-with-alpha one, this is done to be compatible with both light and dark themes, " <>
|
||||||
|
"so that white logo designed with dark theme in mind won't be invisible over light theme, this is done via CSS3 Masking. " <>
|
||||||
|
"Basically - it will take alpha channel of the image and fill non-transparent areas of it with solid color. " <>
|
||||||
|
"If you really want colorful logo - it can be done by setting logoMask to false."
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :logoMargin,
|
||||||
|
label: "Logo margin",
|
||||||
|
type: :string,
|
||||||
|
description:
|
||||||
|
"allows you to adjust vertical margins between logo boundary and navbar borders. " <>
|
||||||
|
"The idea is that to have logo's image without any extra margins and instead adjust them to your need in layout.",
|
||||||
|
suggestions: [".1em"]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :stickers,
|
||||||
|
type: :boolean,
|
||||||
|
description: "Enables/disables stickers."
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
key: :enableEmojiPicker,
|
||||||
|
label: "Emoji picker",
|
||||||
|
type: :boolean,
|
||||||
|
description: "Enables/disables emoji picker."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1180,7 +1216,7 @@
|
||||||
key: :mascots,
|
key: :mascots,
|
||||||
type: {:keyword, :map},
|
type: {:keyword, :map},
|
||||||
description:
|
description:
|
||||||
"Keyword of mascots, each element MUST contain both a url and a mime_type key",
|
"Keyword of mascots, each element must contain both an url and a mime_type key",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
pleroma_fox_tan: %{
|
pleroma_fox_tan: %{
|
||||||
url: "/images/pleroma-fox-tan-smol.png",
|
url: "/images/pleroma-fox-tan-smol.png",
|
||||||
|
@ -1196,7 +1232,7 @@
|
||||||
key: :default_mascot,
|
key: :default_mascot,
|
||||||
type: :atom,
|
type: :atom,
|
||||||
description:
|
description:
|
||||||
"This will be used as the default mascot on MastoFE (default: :pleroma_fox_tan)",
|
"This will be used as the default mascot on MastoFE. Default: `:pleroma_fox_tan`",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
:pleroma_fox_tan
|
:pleroma_fox_tan
|
||||||
]
|
]
|
||||||
|
@ -1334,12 +1370,12 @@
|
||||||
key: :allow_followersonly,
|
key: :allow_followersonly,
|
||||||
label: "Allow followers-only",
|
label: "Allow followers-only",
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "whether to allow followers-only posts"
|
description: "Whether to allow followers-only posts"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :allow_direct,
|
key: :allow_direct,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "whether to allow direct messages"
|
description: "Whether to allow direct messages"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1355,14 +1391,14 @@
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description:
|
description:
|
||||||
"Number of mentioned users after which the message gets delisted (the message can still be seen, " <>
|
"Number of mentioned users after which the message gets delisted (the message can still be seen, " <>
|
||||||
" but it will not show up in public timelines and mentioned users won't get notifications about it). Set to 0 to disable",
|
" but it will not show up in public timelines and mentioned users won't get notifications about it). Set to 0 to disable.",
|
||||||
suggestions: [10]
|
suggestions: [10]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :reject_threshold,
|
key: :reject_threshold,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description:
|
description:
|
||||||
"Number of mentioned users after which the messaged gets rejected. Set to 0 to disable",
|
"Number of mentioned users after which the messaged gets rejected. Set to 0 to disable.",
|
||||||
suggestions: [20]
|
suggestions: [20]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1378,14 +1414,14 @@
|
||||||
key: :reject,
|
key: :reject,
|
||||||
type: [:string, :regex],
|
type: [:string, :regex],
|
||||||
description:
|
description:
|
||||||
"A list of patterns which result in message being rejected, each pattern can be a string or a regular expression",
|
"A list of patterns which result in message being rejected, each pattern can be a string or a regular expression.",
|
||||||
suggestions: ["foo", ~r/foo/iu]
|
suggestions: ["foo", ~r/foo/iu]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :federated_timeline_removal,
|
key: :federated_timeline_removal,
|
||||||
type: [:string, :regex],
|
type: [:string, :regex],
|
||||||
description:
|
description:
|
||||||
"A list of patterns which result in message being removed from federated timelines (a.k.a unlisted), each pattern can be a string or a regular expression",
|
"A list of patterns which result in message being removed from federated timelines (a.k.a unlisted), each pattern can be a string or a regular expression.",
|
||||||
suggestions: ["foo", ~r/foo/iu]
|
suggestions: ["foo", ~r/foo/iu]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -1464,7 +1500,7 @@
|
||||||
key: :base_url,
|
key: :base_url,
|
||||||
type: :string,
|
type: :string,
|
||||||
description:
|
description:
|
||||||
"The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts",
|
"The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts.",
|
||||||
suggestions: ["https://example.com"]
|
suggestions: ["https://example.com"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -1485,14 +1521,14 @@
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description:
|
||||||
"Redirects the client to the real remote URL if there's any HTTP errors. " <>
|
"Redirects the client to the real remote URL if there's any HTTP errors. " <>
|
||||||
"Any error during body processing will not be redirected as the response is chunked"
|
"Any error during body processing will not be redirected as the response is chunked."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :max_body_length,
|
key: :max_body_length,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description:
|
description:
|
||||||
"limits the content length to be approximately the " <>
|
"Limits the content length to be approximately the " <>
|
||||||
"specified length. It is validated with the `content-length` header and also verified when proxying"
|
"specified length. It is validated with the `content-length` header and also verified when proxying."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :http,
|
key: :http,
|
||||||
|
@ -1810,9 +1846,9 @@
|
||||||
key: :subject,
|
key: :subject,
|
||||||
type: :string,
|
type: :string,
|
||||||
description:
|
description:
|
||||||
"a mailto link for the administrative contact." <>
|
"A mailto link for the administrative contact." <>
|
||||||
" It's best if this email is not a personal email address, but rather a group email so that if a person leaves an organization," <>
|
" It's best if this email is not a personal email address, but rather a group email so that if a person leaves an organization," <>
|
||||||
" is unavailable for an extended period, or otherwise can't respond, someone else on the list can",
|
" is unavailable for an extended period, or otherwise can't respond, someone else on the list can.",
|
||||||
suggestions: ["Subject"]
|
suggestions: ["Subject"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -1860,12 +1896,12 @@
|
||||||
type: :group,
|
type: :group,
|
||||||
description:
|
description:
|
||||||
"Kocaptcha is a very simple captcha service with a single API endpoint, the source code is" <>
|
"Kocaptcha is a very simple captcha service with a single API endpoint, the source code is" <>
|
||||||
" here: https://github.com/koto-bank/kocaptcha. The default endpoint https://captcha.kotobank.ch is hosted by the developer",
|
" here: https://github.com/koto-bank/kocaptcha. The default endpoint (https://captcha.kotobank.ch) is hosted by the developer.",
|
||||||
children: [
|
children: [
|
||||||
%{
|
%{
|
||||||
key: :endpoint,
|
key: :endpoint,
|
||||||
type: :string,
|
type: :string,
|
||||||
description: "the kocaptcha endpoint to use",
|
description: "The kocaptcha endpoint to use",
|
||||||
suggestions: ["https://captcha.kotobank.ch"]
|
suggestions: ["https://captcha.kotobank.ch"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1874,7 +1910,7 @@
|
||||||
group: :pleroma,
|
group: :pleroma,
|
||||||
type: :group,
|
type: :group,
|
||||||
description:
|
description:
|
||||||
"Allows to set a token that can be used to authenticate with the admin api without using an actual user by giving it as the 'admin_token' parameter",
|
"Allows to set a token that can be used to authenticate with the admin api without using an actual user by giving it as the `admin_token` parameter",
|
||||||
children: [
|
children: [
|
||||||
%{
|
%{
|
||||||
key: :admin_token,
|
key: :admin_token,
|
||||||
|
@ -1924,8 +1960,9 @@
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :verbose,
|
key: :verbose,
|
||||||
type: :boolean,
|
type: :atom,
|
||||||
description: "Logs verbose mode"
|
description: "Logs verbose mode",
|
||||||
|
suggestions: [false, :error, :warn, :info, :debug]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :prune,
|
key: :prune,
|
||||||
|
@ -2040,7 +2077,7 @@
|
||||||
key: :unfurl_nsfw,
|
key: :unfurl_nsfw,
|
||||||
label: "Unfurl NSFW",
|
label: "Unfurl NSFW",
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "If set to true nsfw attachments will be shown in previews"
|
description: "If set to `true` NSFW attachments will be shown in previews"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2084,7 +2121,7 @@
|
||||||
key: :ttl_setters,
|
key: :ttl_setters,
|
||||||
label: "TTL setters",
|
label: "TTL setters",
|
||||||
type: {:list, :module},
|
type: {:list, :module},
|
||||||
description: "List of rich media ttl setters.",
|
description: "List of rich media TTL setters.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl
|
Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl
|
||||||
]
|
]
|
||||||
|
@ -2101,12 +2138,12 @@
|
||||||
key: :enabled,
|
key: :enabled,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description:
|
description:
|
||||||
"if enabled, when a new user is federated with, fetch some of their latest posts"
|
"If enabled, when a new user is federated with, fetch some of their latest posts"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :pages,
|
key: :pages,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description: "the amount of pages to fetch",
|
description: "The amount of pages to fetch",
|
||||||
suggestions: [5]
|
suggestions: [5]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -2120,24 +2157,24 @@
|
||||||
%{
|
%{
|
||||||
key: :class,
|
key: :class,
|
||||||
type: [:string, false],
|
type: [:string, false],
|
||||||
description: "specify the class to be added to the generated link. false to clear",
|
description: "Specify the class to be added to the generated link. `False` to clear",
|
||||||
suggestions: ["auto-linker", false]
|
suggestions: ["auto-linker", false]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :rel,
|
key: :rel,
|
||||||
type: [:string, false],
|
type: [:string, false],
|
||||||
description: "override the rel attribute. false to clear",
|
description: "Override the rel attribute. `False` to clear",
|
||||||
suggestions: ["ugc", "noopener noreferrer", false]
|
suggestions: ["ugc", "noopener noreferrer", false]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :new_window,
|
key: :new_window,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "set to false to remove target='_blank' attribute"
|
description: "Set to `false` to remove target='_blank' attribute"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :scheme,
|
key: :scheme,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Set to true to link urls with schema http://google.com"
|
description: "Set to `true` to link urls with schema http://google.com"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :truncate,
|
key: :truncate,
|
||||||
|
@ -2154,7 +2191,7 @@
|
||||||
%{
|
%{
|
||||||
key: :extra,
|
key: :extra,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "link urls with rarely used schemes (magnet, ipfs, irc, etc.)"
|
description: "Link urls with rarely used schemes (magnet, ipfs, irc, etc.)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2168,20 +2205,20 @@
|
||||||
key: :daily_user_limit,
|
key: :daily_user_limit,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description:
|
description:
|
||||||
"the number of scheduled activities a user is allowed to create in a single day (Default: 25)",
|
"The number of scheduled activities a user is allowed to create in a single day. Default: 25.",
|
||||||
suggestions: [25]
|
suggestions: [25]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :total_user_limit,
|
key: :total_user_limit,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description:
|
description:
|
||||||
"the number of scheduled activities a user is allowed to create in total (Default: 300)",
|
"The number of scheduled activities a user is allowed to create in total. Default: 300.",
|
||||||
suggestions: [300]
|
suggestions: [300]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :enabled,
|
key: :enabled,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "whether scheduled activities are sent to the job queue to be executed"
|
description: "Whether scheduled activities are sent to the job queue to be executed"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2194,7 +2231,7 @@
|
||||||
%{
|
%{
|
||||||
key: :enabled,
|
key: :enabled,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "whether expired activities will be sent to the job queue to be deleted"
|
description: "Whether expired activities will be sent to the job queue to be deleted"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2216,14 +2253,14 @@
|
||||||
type: :group,
|
type: :group,
|
||||||
description:
|
description:
|
||||||
"Use LDAP for user authentication. When a user logs in to the Pleroma instance, the name and password" <>
|
"Use LDAP for user authentication. When a user logs in to the Pleroma instance, the name and password" <>
|
||||||
" will be verified by trying to authenticate (bind) to an LDAP server." <>
|
" will be verified by trying to authenticate (bind) to a LDAP server." <>
|
||||||
" If a user exists in the LDAP directory but there is no account with the same name yet on the" <>
|
" If a user exists in the LDAP directory but there is no account with the same name yet on the" <>
|
||||||
" Pleroma instance then a new Pleroma account will be created with the same name as the LDAP user name.",
|
" Pleroma instance then a new Pleroma account will be created with the same name as the LDAP user name.",
|
||||||
children: [
|
children: [
|
||||||
%{
|
%{
|
||||||
key: :enabled,
|
key: :enabled,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "enables LDAP authentication"
|
description: "Enables LDAP authentication"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :host,
|
key: :host,
|
||||||
|
@ -2241,13 +2278,13 @@
|
||||||
key: :ssl,
|
key: :ssl,
|
||||||
label: "SSL",
|
label: "SSL",
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "true to use SSL, usually implies the port 636"
|
description: "`True` to use SSL, usually implies the port 636"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :sslopts,
|
key: :sslopts,
|
||||||
label: "SSL options",
|
label: "SSL options",
|
||||||
type: :keyword,
|
type: :keyword,
|
||||||
description: "additional SSL options",
|
description: "Additional SSL options",
|
||||||
suggestions: [cacertfile: "path/to/file/with/PEM/cacerts", verify: :verify_peer],
|
suggestions: [cacertfile: "path/to/file/with/PEM/cacerts", verify: :verify_peer],
|
||||||
children: [
|
children: [
|
||||||
%{
|
%{
|
||||||
|
@ -2268,13 +2305,13 @@
|
||||||
key: :tls,
|
key: :tls,
|
||||||
label: "TLS",
|
label: "TLS",
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "true to start TLS, usually implies the port 389"
|
description: "`True` to start TLS, usually implies the port 389"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :tlsopts,
|
key: :tlsopts,
|
||||||
label: "TLS options",
|
label: "TLS options",
|
||||||
type: :keyword,
|
type: :keyword,
|
||||||
description: "additional TLS options",
|
description: "Additional TLS options",
|
||||||
suggestions: [cacertfile: "path/to/file/with/PEM/cacerts", verify: :verify_peer],
|
suggestions: [cacertfile: "path/to/file/with/PEM/cacerts", verify: :verify_peer],
|
||||||
children: [
|
children: [
|
||||||
%{
|
%{
|
||||||
|
@ -2325,23 +2362,23 @@
|
||||||
key: :auth_template,
|
key: :auth_template,
|
||||||
type: :string,
|
type: :string,
|
||||||
description:
|
description:
|
||||||
"authentication form template. By default it's show.html which corresponds to lib/pleroma/web/templates/o_auth/o_auth/show.html.ee",
|
"Authentication form template. By default it's `show.html` which corresponds to `lib/pleroma/web/templates/o_auth/o_auth/show.html.ee`.",
|
||||||
suggestions: ["show.html"]
|
suggestions: ["show.html"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :oauth_consumer_template,
|
key: :oauth_consumer_template,
|
||||||
type: :string,
|
type: :string,
|
||||||
description:
|
description:
|
||||||
"OAuth consumer mode authentication form template. By default it's consumer.html which corresponds to" <>
|
"OAuth consumer mode authentication form template. By default it's `consumer.html` which corresponds to" <>
|
||||||
" lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex",
|
" `lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex`.",
|
||||||
suggestions: ["consumer.html"]
|
suggestions: ["consumer.html"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :oauth_consumer_strategies,
|
key: :oauth_consumer_strategies,
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
description:
|
description:
|
||||||
"the list of enabled OAuth consumer strategies; by default it's set by OAUTH_CONSUMER_STRATEGIES environment variable." <>
|
"The list of enabled OAuth consumer strategies; by default it's set by OAUTH_CONSUMER_STRATEGIES environment variable." <>
|
||||||
" Each entry in this space-delimited string should be of format <strategy> or <strategy>:<dependency>" <>
|
" Each entry in this space-delimited string should be of format \"strategy\" or \"strategy:dependency\"" <>
|
||||||
" (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is named differently than ueberauth_<strategy>).",
|
" (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is named differently than ueberauth_<strategy>).",
|
||||||
suggestions: ["twitter", "keycloak:ueberauth_keycloak_strategy"]
|
suggestions: ["twitter", "keycloak:ueberauth_keycloak_strategy"]
|
||||||
}
|
}
|
||||||
|
@ -2370,13 +2407,13 @@
|
||||||
%{
|
%{
|
||||||
key: :active,
|
key: :active,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "globally enable or disable digest emails"
|
description: "Globally enable or disable digest emails"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :schedule,
|
key: :schedule,
|
||||||
type: :string,
|
type: :string,
|
||||||
description:
|
description:
|
||||||
"When to send digest email, in crontab format. \"0 0 0\" is the default, meaning \"once a week at midnight on Sunday morning\"",
|
"When to send digest email, in crontab format. \"0 0 0\" is the default, meaning \"once a week at midnight on Sunday morning\".",
|
||||||
suggestions: ["0 0 * * 0"]
|
suggestions: ["0 0 * * 0"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -2404,7 +2441,7 @@
|
||||||
%{
|
%{
|
||||||
key: :logo,
|
key: :logo,
|
||||||
type: :string,
|
type: :string,
|
||||||
description: "a path to a custom logo. Set it to nil to use the default Pleroma logo",
|
description: "A path to a custom logo. Set it to `nil` to use the default Pleroma logo.",
|
||||||
suggestions: ["some/path/logo.png"]
|
suggestions: ["some/path/logo.png"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -2477,7 +2514,7 @@
|
||||||
%{
|
%{
|
||||||
key: :clean_expired_tokens,
|
key: :clean_expired_tokens,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Enable a background job to clean expired oauth tokens. Defaults to false"
|
description: "Enable a background job to clean expired oauth tokens. Default: `false`."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2489,7 +2526,7 @@
|
||||||
%{
|
%{
|
||||||
key: :shortcode_globs,
|
key: :shortcode_globs,
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
description: "Location of custom emoji files. * can be used as a wildcard",
|
description: "Location of custom emoji files. * can be used as a wildcard.",
|
||||||
suggestions: ["/emoji/custom/**/*.png"]
|
suggestions: ["/emoji/custom/**/*.png"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -2504,7 +2541,7 @@
|
||||||
type: {:keyword, :string, {:list, :string}},
|
type: {:keyword, :string, {:list, :string}},
|
||||||
description:
|
description:
|
||||||
"Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the group name" <>
|
"Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the group name" <>
|
||||||
" and the value the location or array of locations. * can be used as a wildcard",
|
" and the value is the location or array of locations. * can be used as a wildcard.",
|
||||||
suggestions: [
|
suggestions: [
|
||||||
Custom: ["/emoji/*.png", "/emoji/**/*.png"]
|
Custom: ["/emoji/*.png", "/emoji/**/*.png"]
|
||||||
]
|
]
|
||||||
|
@ -2514,7 +2551,7 @@
|
||||||
type: :string,
|
type: :string,
|
||||||
description:
|
description:
|
||||||
"Location of the JSON-manifest. This manifest contains information about the emoji-packs you can download." <>
|
"Location of the JSON-manifest. This manifest contains information about the emoji-packs you can download." <>
|
||||||
" Currently only one manifest can be added (no arrays)",
|
" Currently only one manifest can be added (no arrays).",
|
||||||
suggestions: ["https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json"]
|
suggestions: ["https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -2537,7 +2574,7 @@
|
||||||
%{
|
%{
|
||||||
key: :rum_enabled,
|
key: :rum_enabled,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "If RUM indexes should be used. Defaults to false"
|
description: "If RUM indexes should be used. Default: `false`"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -2551,45 +2588,45 @@
|
||||||
%{
|
%{
|
||||||
key: :search,
|
key: :search,
|
||||||
type: [:tuple, {:list, :tuple}],
|
type: [:tuple, {:list, :tuple}],
|
||||||
description: "for the search requests (account & status search etc.)",
|
description: "For the search requests (account & status search etc.)",
|
||||||
suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
|
suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :app_account_creation,
|
key: :app_account_creation,
|
||||||
type: [:tuple, {:list, :tuple}],
|
type: [:tuple, {:list, :tuple}],
|
||||||
description: "for registering user accounts from the same IP address",
|
description: "For registering user accounts from the same IP address",
|
||||||
suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
|
suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :relations_actions,
|
key: :relations_actions,
|
||||||
type: [:tuple, {:list, :tuple}],
|
type: [:tuple, {:list, :tuple}],
|
||||||
description: "for actions on relations with all users (follow, unfollow)",
|
description: "For actions on relations with all users (follow, unfollow)",
|
||||||
suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
|
suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :relation_id_action,
|
key: :relation_id_action,
|
||||||
type: [:tuple, {:list, :tuple}],
|
type: [:tuple, {:list, :tuple}],
|
||||||
description: "for actions on relation with a specific user (follow, unfollow)",
|
description: "For actions on relation with a specific user (follow, unfollow)",
|
||||||
suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
|
suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :statuses_actions,
|
key: :statuses_actions,
|
||||||
type: [:tuple, {:list, :tuple}],
|
type: [:tuple, {:list, :tuple}],
|
||||||
description:
|
description:
|
||||||
"for create / delete / fav / unfav / reblog / unreblog actions on any statuses",
|
"For create / delete / fav / unfav / reblog / unreblog actions on any statuses",
|
||||||
suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
|
suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :status_id_action,
|
key: :status_id_action,
|
||||||
type: [:tuple, {:list, :tuple}],
|
type: [:tuple, {:list, :tuple}],
|
||||||
description:
|
description:
|
||||||
"for fav / unfav or reblog / unreblog actions on the same status by the same user",
|
"For fav / unfav or reblog / unreblog actions on the same status by the same user",
|
||||||
suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
|
suggestions: [{1000, 10}, [{10_000, 10}, {10_000, 50}]]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :authentication,
|
key: :authentication,
|
||||||
type: [:tuple, {:list, :tuple}],
|
type: [:tuple, {:list, :tuple}],
|
||||||
description: "for authentication create / password check / user existence check requests",
|
description: "For authentication create / password check / user existence check requests",
|
||||||
suggestions: [{60_000, 15}]
|
suggestions: [{60_000, 15}]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -2604,12 +2641,12 @@
|
||||||
%{
|
%{
|
||||||
key: :enabled,
|
key: :enabled,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Enables ssh"
|
description: "Enables SSH"
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :priv_dir,
|
key: :priv_dir,
|
||||||
type: :string,
|
type: :string,
|
||||||
description: "Dir with ssh keys",
|
description: "Dir with SSH keys",
|
||||||
suggestions: ["/some/path/ssh_keys"]
|
suggestions: ["/some/path/ssh_keys"]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -2788,7 +2825,7 @@
|
||||||
key: :user_agent,
|
key: :user_agent,
|
||||||
type: [:string, :atom],
|
type: [:string, :atom],
|
||||||
description:
|
description:
|
||||||
"What user agent to use. Must be a string or an atom `:default`. Default value is `:default`",
|
"What user agent to use. Must be a string or an atom `:default`. Default value is `:default`.",
|
||||||
suggestions: ["Pleroma", :default]
|
suggestions: ["Pleroma", :default]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
|
@ -2960,19 +2997,19 @@
|
||||||
%{
|
%{
|
||||||
key: :enabled,
|
key: :enabled,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
description: "Enable/disable the plug. Defaults to `false`."
|
description: "Enable/disable the plug. Default: `false`."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :headers,
|
key: :headers,
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
description:
|
description:
|
||||||
"A list of strings naming the `req_headers` to use when deriving the `remote_ip`. Order does not matter. Defaults to `~w[forwarded x-forwarded-for x-client-ip x-real-ip]`."
|
"A list of strings naming the `req_headers` to use when deriving the `remote_ip`. Order does not matter. Default: `~w[forwarded x-forwarded-for x-client-ip x-real-ip]`."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :proxies,
|
key: :proxies,
|
||||||
type: {:list, :string},
|
type: {:list, :string},
|
||||||
description:
|
description:
|
||||||
"A list of strings in [CIDR](https://en.wikipedia.org/wiki/CIDR) notation specifying the IPs of known proxies. Defaults to `[]`."
|
"A list of strings in [CIDR](https://en.wikipedia.org/wiki/CIDR) notation specifying the IPs of known proxies. Default: `[]`."
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :reserved,
|
key: :reserved,
|
||||||
|
@ -2993,14 +3030,13 @@
|
||||||
key: :activity_pub,
|
key: :activity_pub,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description:
|
description:
|
||||||
"activity pub routes (except question activities). Defaults to `nil` (no expiration).",
|
"Activity pub routes (except question activities). Default: `nil` (no expiration).",
|
||||||
suggestions: [30_000]
|
suggestions: [30_000, nil]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
key: :activity_pub_question,
|
key: :activity_pub_question,
|
||||||
type: :integer,
|
type: :integer,
|
||||||
description:
|
description: "Activity pub routes (question activities). Default: `30_000` (30 seconds).",
|
||||||
"activity pub routes (question activities). Defaults to `30_000` (30 seconds).",
|
|
||||||
suggestions: [30_000]
|
suggestions: [30_000]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -29,7 +29,7 @@ Has these additional fields under the `pleroma` object:
|
||||||
- `spoiler_text`: a map consisting of alternate representations of the `spoiler_text` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`
|
- `spoiler_text`: a map consisting of alternate representations of the `spoiler_text` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`
|
||||||
- `expires_at`: a datetime (iso8601) that states when the post will expire (be deleted automatically), or empty if the post won't expire
|
- `expires_at`: a datetime (iso8601) that states when the post will expire (be deleted automatically), or empty if the post won't expire
|
||||||
- `thread_muted`: true if the thread the post belongs to is muted
|
- `thread_muted`: true if the thread the post belongs to is muted
|
||||||
- `emoji_reactions`: A list with emoji / reaction count tuples. Contains no information about the reacting users, for that use the `emoji_reactions_by` endpoint.
|
- `emoji_reactions`: A list with emoji / reaction maps. The format is {emoji: "☕", count: 1}. Contains no information about the reacting users, for that use the `emoji_reactions_by` endpoint.
|
||||||
|
|
||||||
## Attachments
|
## Attachments
|
||||||
|
|
||||||
|
|
|
@ -455,7 +455,7 @@ Emoji reactions work a lot like favourites do. They make it possible to react to
|
||||||
* Example Response:
|
* Example Response:
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
["😀", [{"id" => "xyz.."...}, {"id" => "zyx..."}]],
|
{"emoji": "😀", "count": 2, "accounts": [{"id" => "xyz.."...}, {"id" => "zyx..."}]},
|
||||||
["☕", [{"id" => "abc..."}]]
|
{"emoji": "☕", "count": 1, "accounts": [{"id" => "abc..."}]}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
|
@ -52,6 +52,9 @@ def migrate_to_db(file_path \\ nil) do
|
||||||
|
|
||||||
defp do_migrate_to_db(config_file) do
|
defp do_migrate_to_db(config_file) do
|
||||||
if File.exists?(config_file) do
|
if File.exists?(config_file) do
|
||||||
|
Ecto.Adapters.SQL.query!(Repo, "TRUNCATE config;")
|
||||||
|
Ecto.Adapters.SQL.query!(Repo, "ALTER SEQUENCE config_id_seq RESTART;")
|
||||||
|
|
||||||
custom_config =
|
custom_config =
|
||||||
config_file
|
config_file
|
||||||
|> read_file()
|
|> read_file()
|
||||||
|
|
|
@ -9,6 +9,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
|
||||||
@moduledoc File.read!("docs/administration/CLI_tasks/emoji.md")
|
@moduledoc File.read!("docs/administration/CLI_tasks/emoji.md")
|
||||||
|
|
||||||
def run(["ls-packs" | args]) do
|
def run(["ls-packs" | args]) do
|
||||||
|
Mix.Pleroma.start_pleroma()
|
||||||
Application.ensure_all_started(:hackney)
|
Application.ensure_all_started(:hackney)
|
||||||
|
|
||||||
{options, [], []} = parse_global_opts(args)
|
{options, [], []} = parse_global_opts(args)
|
||||||
|
@ -35,6 +36,7 @@ def run(["ls-packs" | args]) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def run(["get-packs" | args]) do
|
def run(["get-packs" | args]) do
|
||||||
|
Mix.Pleroma.start_pleroma()
|
||||||
Application.ensure_all_started(:hackney)
|
Application.ensure_all_started(:hackney)
|
||||||
|
|
||||||
{options, pack_names, []} = parse_global_opts(args)
|
{options, pack_names, []} = parse_global_opts(args)
|
||||||
|
|
|
@ -18,6 +18,7 @@ defmodule Mix.Tasks.Pleroma.RobotsTxt do
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def run(["disallow_all"]) do
|
def run(["disallow_all"]) do
|
||||||
|
Mix.Pleroma.start_pleroma()
|
||||||
static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/")
|
static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/")
|
||||||
|
|
||||||
if !File.exists?(static_dir) do
|
if !File.exists?(static_dir) do
|
||||||
|
|
|
@ -236,15 +236,7 @@ def from_binary_with_convert(binary) do
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec from_string(String.t()) :: atom() | no_return()
|
@spec from_string(String.t()) :: atom() | no_return()
|
||||||
def from_string(":" <> entity), do: String.to_existing_atom(entity)
|
def from_string(string), do: do_transform_string(string)
|
||||||
|
|
||||||
def from_string(entity) when is_binary(entity) do
|
|
||||||
if is_module_name?(entity) do
|
|
||||||
String.to_existing_atom("Elixir.#{entity}")
|
|
||||||
else
|
|
||||||
entity
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec convert(any()) :: any()
|
@spec convert(any()) :: any()
|
||||||
def convert(entity), do: do_convert(entity)
|
def convert(entity), do: do_convert(entity)
|
||||||
|
@ -416,7 +408,7 @@ defp do_transform_string(value) do
|
||||||
|
|
||||||
@spec is_module_name?(String.t()) :: boolean()
|
@spec is_module_name?(String.t()) :: boolean()
|
||||||
def is_module_name?(string) do
|
def is_module_name?(string) do
|
||||||
Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack|Ueberauth)\./, string) or
|
Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack|Ueberauth|Swoosh)\./, string) or
|
||||||
string in ["Oban", "Ueberauth", "ExSyslogger"]
|
string in ["Oban", "Ueberauth", "ExSyslogger"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,11 +11,9 @@ def init(options) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(%{assigns: %{user: %User{} = user}} = conn, _) do
|
def call(%{assigns: %{user: %User{} = user}} = conn, _) do
|
||||||
if User.auth_active?(user) do
|
case User.account_status(user) do
|
||||||
conn
|
:active -> conn
|
||||||
else
|
_ -> assign(conn, :user, nil)
|
||||||
conn
|
|
||||||
|> assign(:user, nil)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ defmodule Pleroma.User do
|
||||||
alias Comeonin.Pbkdf2
|
alias Comeonin.Pbkdf2
|
||||||
alias Ecto.Multi
|
alias Ecto.Multi
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.Config
|
||||||
alias Pleroma.Conversation.Participation
|
alias Pleroma.Conversation.Participation
|
||||||
alias Pleroma.Delivery
|
alias Pleroma.Delivery
|
||||||
alias Pleroma.FollowingRelationship
|
alias Pleroma.FollowingRelationship
|
||||||
|
@ -35,7 +36,7 @@ defmodule Pleroma.User do
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
@type t :: %__MODULE__{}
|
@type t :: %__MODULE__{}
|
||||||
|
@type account_status :: :active | :deactivated | :password_reset_pending | :confirmation_pending
|
||||||
@primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true}
|
@primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true}
|
||||||
|
|
||||||
# credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
|
# credo:disable-for-next-line Credo.Check.Readability.MaxLineLength
|
||||||
|
@ -216,14 +217,21 @@ def unquote(:"#{outgoing_relation_target}_ap_ids")(user, restrict_deactivated? \
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "Returns if the user should be allowed to authenticate"
|
@doc "Returns status account"
|
||||||
def auth_active?(%User{deactivated: true}), do: false
|
@spec account_status(User.t()) :: account_status()
|
||||||
|
def account_status(%User{deactivated: true}), do: :deactivated
|
||||||
|
def account_status(%User{password_reset_pending: true}), do: :password_reset_pending
|
||||||
|
|
||||||
def auth_active?(%User{confirmation_pending: true}),
|
def account_status(%User{confirmation_pending: true}) do
|
||||||
do: !Pleroma.Config.get([:instance, :account_activation_required])
|
case Config.get([:instance, :account_activation_required]) do
|
||||||
|
true -> :confirmation_pending
|
||||||
|
_ -> :active
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def auth_active?(%User{}), do: true
|
def account_status(%User{}), do: :active
|
||||||
|
|
||||||
|
@spec visible_for?(User.t(), User.t() | nil) :: boolean()
|
||||||
def visible_for?(user, for_user \\ nil)
|
def visible_for?(user, for_user \\ nil)
|
||||||
|
|
||||||
def visible_for?(%User{invisible: true}, _), do: false
|
def visible_for?(%User{invisible: true}, _), do: false
|
||||||
|
@ -231,15 +239,17 @@ def visible_for?(%User{invisible: true}, _), do: false
|
||||||
def visible_for?(%User{id: user_id}, %User{id: for_id}) when user_id == for_id, do: true
|
def visible_for?(%User{id: user_id}, %User{id: for_id}) when user_id == for_id, do: true
|
||||||
|
|
||||||
def visible_for?(%User{} = user, for_user) do
|
def visible_for?(%User{} = user, for_user) do
|
||||||
auth_active?(user) || superuser?(for_user)
|
account_status(user) == :active || superuser?(for_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def visible_for?(_, _), do: false
|
def visible_for?(_, _), do: false
|
||||||
|
|
||||||
|
@spec superuser?(User.t()) :: boolean()
|
||||||
def superuser?(%User{local: true, is_admin: true}), do: true
|
def superuser?(%User{local: true, is_admin: true}), do: true
|
||||||
def superuser?(%User{local: true, is_moderator: true}), do: true
|
def superuser?(%User{local: true, is_moderator: true}), do: true
|
||||||
def superuser?(_), do: false
|
def superuser?(_), do: false
|
||||||
|
|
||||||
|
@spec invisible?(User.t()) :: boolean()
|
||||||
def invisible?(%User{invisible: true}), do: true
|
def invisible?(%User{invisible: true}), do: true
|
||||||
def invisible?(_), do: false
|
def invisible?(_), do: false
|
||||||
|
|
||||||
|
|
|
@ -337,7 +337,7 @@ def add_emoji_reaction_to_object(
|
||||||
%Activity{data: %{"content" => emoji, "actor" => actor}},
|
%Activity{data: %{"content" => emoji, "actor" => actor}},
|
||||||
object
|
object
|
||||||
) do
|
) do
|
||||||
reactions = object.data["reactions"] || []
|
reactions = get_cached_emoji_reactions(object)
|
||||||
|
|
||||||
new_reactions =
|
new_reactions =
|
||||||
case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
|
case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
|
||||||
|
@ -365,7 +365,7 @@ def remove_emoji_reaction_from_object(
|
||||||
%Activity{data: %{"content" => emoji, "actor" => actor}},
|
%Activity{data: %{"content" => emoji, "actor" => actor}},
|
||||||
object
|
object
|
||||||
) do
|
) do
|
||||||
reactions = object.data["reactions"] || []
|
reactions = get_cached_emoji_reactions(object)
|
||||||
|
|
||||||
new_reactions =
|
new_reactions =
|
||||||
case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
|
case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
|
||||||
|
@ -385,6 +385,14 @@ def remove_emoji_reaction_from_object(
|
||||||
update_element_in_object("reaction", new_reactions, object, count)
|
update_element_in_object("reaction", new_reactions, object, count)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_cached_emoji_reactions(object) do
|
||||||
|
if is_list(object.data["reactions"]) do
|
||||||
|
object.data["reactions"]
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@spec add_like_to_object(Activity.t(), Object.t()) ::
|
@spec add_like_to_object(Activity.t(), Object.t()) ::
|
||||||
{:ok, Object.t()} | {:error, Ecto.Changeset.t()}
|
{:ok, Object.t()} | {:error, Ecto.Changeset.t()}
|
||||||
def add_like_to_object(%Activity{data: %{"actor" => actor}}, object) do
|
def add_like_to_object(%Activity{data: %{"actor" => actor}}, object) do
|
||||||
|
|
|
@ -7,10 +7,6 @@ defmodule Pleroma.Web.MastodonAPI.AppView do
|
||||||
|
|
||||||
alias Pleroma.Web.OAuth.App
|
alias Pleroma.Web.OAuth.App
|
||||||
|
|
||||||
@vapid_key :web_push_encryption
|
|
||||||
|> Application.get_env(:vapid_details, [])
|
|
||||||
|> Keyword.get(:public_key)
|
|
||||||
|
|
||||||
def render("show.json", %{app: %App{} = app}) do
|
def render("show.json", %{app: %App{} = app}) do
|
||||||
%{
|
%{
|
||||||
id: app.id |> to_string,
|
id: app.id |> to_string,
|
||||||
|
@ -32,8 +28,10 @@ def render("short.json", %{app: %App{website: webiste, client_name: name}}) do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp with_vapid_key(data) do
|
defp with_vapid_key(data) do
|
||||||
if @vapid_key do
|
vapid_key = Application.get_env(:web_push_encryption, :vapid_details, [])[:public_key]
|
||||||
Map.put(data, "vapid_key", @vapid_key)
|
|
||||||
|
if vapid_key do
|
||||||
|
Map.put(data, "vapid_key", vapid_key)
|
||||||
else
|
else
|
||||||
data
|
data
|
||||||
end
|
end
|
||||||
|
|
|
@ -256,7 +256,7 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity}
|
||||||
emoji_reactions =
|
emoji_reactions =
|
||||||
with %{data: %{"reactions" => emoji_reactions}} <- object do
|
with %{data: %{"reactions" => emoji_reactions}} <- object do
|
||||||
Enum.map(emoji_reactions, fn [emoji, users] ->
|
Enum.map(emoji_reactions, fn [emoji, users] ->
|
||||||
[emoji, length(users)]
|
%{emoji: emoji, count: length(users)}
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
_ -> []
|
_ -> []
|
||||||
|
|
|
@ -167,17 +167,37 @@ defp handle_create_authorization_error(
|
||||||
|
|
||||||
defp handle_create_authorization_error(
|
defp handle_create_authorization_error(
|
||||||
%Plug.Conn{} = conn,
|
%Plug.Conn{} = conn,
|
||||||
{:auth_active, false},
|
{:account_status, :confirmation_pending},
|
||||||
%{"authorization" => _} = params
|
%{"authorization" => _} = params
|
||||||
) do
|
) do
|
||||||
# Per https://github.com/tootsuite/mastodon/blob/
|
|
||||||
# 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76
|
|
||||||
conn
|
conn
|
||||||
|> put_flash(:error, dgettext("errors", "Your login is missing a confirmed e-mail address"))
|
|> put_flash(:error, dgettext("errors", "Your login is missing a confirmed e-mail address"))
|
||||||
|> put_status(:forbidden)
|
|> put_status(:forbidden)
|
||||||
|> authorize(params)
|
|> authorize(params)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp handle_create_authorization_error(
|
||||||
|
%Plug.Conn{} = conn,
|
||||||
|
{:account_status, :password_reset_pending},
|
||||||
|
%{"authorization" => _} = params
|
||||||
|
) do
|
||||||
|
conn
|
||||||
|
|> put_flash(:error, dgettext("errors", "Password reset is required"))
|
||||||
|
|> put_status(:forbidden)
|
||||||
|
|> authorize(params)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_create_authorization_error(
|
||||||
|
%Plug.Conn{} = conn,
|
||||||
|
{:account_status, :deactivated},
|
||||||
|
%{"authorization" => _} = params
|
||||||
|
) do
|
||||||
|
conn
|
||||||
|
|> put_flash(:error, dgettext("errors", "Your account is currently disabled"))
|
||||||
|
|> put_status(:forbidden)
|
||||||
|
|> authorize(params)
|
||||||
|
end
|
||||||
|
|
||||||
defp handle_create_authorization_error(%Plug.Conn{} = conn, error, %{"authorization" => _}) do
|
defp handle_create_authorization_error(%Plug.Conn{} = conn, error, %{"authorization" => _}) do
|
||||||
Authenticator.handle_error(conn, error)
|
Authenticator.handle_error(conn, error)
|
||||||
end
|
end
|
||||||
|
@ -218,46 +238,14 @@ def token_exchange(
|
||||||
) do
|
) do
|
||||||
with {:ok, %User{} = user} <- Authenticator.get_user(conn),
|
with {:ok, %User{} = user} <- Authenticator.get_user(conn),
|
||||||
{:ok, app} <- Token.Utils.fetch_app(conn),
|
{:ok, app} <- Token.Utils.fetch_app(conn),
|
||||||
{:auth_active, true} <- {:auth_active, User.auth_active?(user)},
|
{:account_status, :active} <- {:account_status, User.account_status(user)},
|
||||||
{:user_active, true} <- {:user_active, !user.deactivated},
|
|
||||||
{:password_reset_pending, false} <-
|
|
||||||
{:password_reset_pending, user.password_reset_pending},
|
|
||||||
{:ok, scopes} <- validate_scopes(app, params),
|
{:ok, scopes} <- validate_scopes(app, params),
|
||||||
{:ok, auth} <- Authorization.create_authorization(app, user, scopes),
|
{:ok, auth} <- Authorization.create_authorization(app, user, scopes),
|
||||||
{:ok, token} <- Token.exchange_token(app, auth) do
|
{:ok, token} <- Token.exchange_token(app, auth) do
|
||||||
json(conn, Token.Response.build(user, token))
|
json(conn, Token.Response.build(user, token))
|
||||||
else
|
else
|
||||||
{:auth_active, false} ->
|
error ->
|
||||||
# Per https://github.com/tootsuite/mastodon/blob/
|
handle_token_exchange_error(conn, error)
|
||||||
# 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76
|
|
||||||
render_error(
|
|
||||||
conn,
|
|
||||||
:forbidden,
|
|
||||||
"Your login is missing a confirmed e-mail address",
|
|
||||||
%{},
|
|
||||||
"missing_confirmed_email"
|
|
||||||
)
|
|
||||||
|
|
||||||
{:user_active, false} ->
|
|
||||||
render_error(
|
|
||||||
conn,
|
|
||||||
:forbidden,
|
|
||||||
"Your account is currently disabled",
|
|
||||||
%{},
|
|
||||||
"account_is_disabled"
|
|
||||||
)
|
|
||||||
|
|
||||||
{:password_reset_pending, true} ->
|
|
||||||
render_error(
|
|
||||||
conn,
|
|
||||||
:forbidden,
|
|
||||||
"Password reset is required",
|
|
||||||
%{},
|
|
||||||
"password_reset_required"
|
|
||||||
)
|
|
||||||
|
|
||||||
_error ->
|
|
||||||
render_invalid_credentials_error(conn)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -286,6 +274,43 @@ def token_exchange(%Plug.Conn{} = conn, %{"grant_type" => "client_credentials"}
|
||||||
# Bad request
|
# Bad request
|
||||||
def token_exchange(%Plug.Conn{} = conn, params), do: bad_request(conn, params)
|
def token_exchange(%Plug.Conn{} = conn, params), do: bad_request(conn, params)
|
||||||
|
|
||||||
|
defp handle_token_exchange_error(%Plug.Conn{} = conn, {:account_status, :deactivated}) do
|
||||||
|
render_error(
|
||||||
|
conn,
|
||||||
|
:forbidden,
|
||||||
|
"Your account is currently disabled",
|
||||||
|
%{},
|
||||||
|
"account_is_disabled"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_token_exchange_error(
|
||||||
|
%Plug.Conn{} = conn,
|
||||||
|
{:account_status, :password_reset_pending}
|
||||||
|
) do
|
||||||
|
render_error(
|
||||||
|
conn,
|
||||||
|
:forbidden,
|
||||||
|
"Password reset is required",
|
||||||
|
%{},
|
||||||
|
"password_reset_required"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_token_exchange_error(%Plug.Conn{} = conn, {:account_status, :confirmation_pending}) do
|
||||||
|
render_error(
|
||||||
|
conn,
|
||||||
|
:forbidden,
|
||||||
|
"Your login is missing a confirmed e-mail address",
|
||||||
|
%{},
|
||||||
|
"missing_confirmed_email"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp handle_token_exchange_error(%Plug.Conn{} = conn, _error) do
|
||||||
|
render_invalid_credentials_error(conn)
|
||||||
|
end
|
||||||
|
|
||||||
def token_revoke(%Plug.Conn{} = conn, %{"token" => _token} = params) do
|
def token_revoke(%Plug.Conn{} = conn, %{"token" => _token} = params) do
|
||||||
with {:ok, app} <- Token.Utils.fetch_app(conn),
|
with {:ok, app} <- Token.Utils.fetch_app(conn),
|
||||||
{:ok, _token} <- RevokeToken.revoke(app, params) do
|
{:ok, _token} <- RevokeToken.revoke(app, params) do
|
||||||
|
@ -472,7 +497,7 @@ defp do_create_authorization(
|
||||||
%App{} = app <- Repo.get_by(App, client_id: client_id),
|
%App{} = app <- Repo.get_by(App, client_id: client_id),
|
||||||
true <- redirect_uri in String.split(app.redirect_uris),
|
true <- redirect_uri in String.split(app.redirect_uris),
|
||||||
{:ok, scopes} <- validate_scopes(app, auth_attrs),
|
{:ok, scopes} <- validate_scopes(app, auth_attrs),
|
||||||
{:auth_active, true} <- {:auth_active, User.auth_active?(user)} do
|
{:account_status, :active} <- {:account_status, User.account_status(user)} do
|
||||||
Authorization.create_authorization(app, user, scopes)
|
Authorization.create_authorization(app, user, scopes)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -49,7 +49,12 @@ def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id})
|
||||||
emoji_reactions
|
emoji_reactions
|
||||||
|> Enum.map(fn [emoji, users] ->
|
|> Enum.map(fn [emoji, users] ->
|
||||||
users = Enum.map(users, &User.get_cached_by_ap_id/1)
|
users = Enum.map(users, &User.get_cached_by_ap_id/1)
|
||||||
{emoji, AccountView.render("index.json", %{users: users, for: user, as: :user})}
|
|
||||||
|
%{
|
||||||
|
emoji: emoji,
|
||||||
|
count: length(users),
|
||||||
|
accounts: AccountView.render("index.json", %{users: users, for: user, as: :user})
|
||||||
|
}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|
|
|
@ -307,6 +307,15 @@ test "Quack.Logger module" do
|
||||||
assert ConfigDB.from_binary(binary) == Quack.Logger
|
assert ConfigDB.from_binary(binary) == Quack.Logger
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "Swoosh.Adapters modules" do
|
||||||
|
binary = ConfigDB.transform("Swoosh.Adapters.SMTP")
|
||||||
|
assert binary == :erlang.term_to_binary(Swoosh.Adapters.SMTP)
|
||||||
|
assert ConfigDB.from_binary(binary) == Swoosh.Adapters.SMTP
|
||||||
|
binary = ConfigDB.transform("Swoosh.Adapters.AmazonSES")
|
||||||
|
assert binary == :erlang.term_to_binary(Swoosh.Adapters.AmazonSES)
|
||||||
|
assert ConfigDB.from_binary(binary) == Swoosh.Adapters.AmazonSES
|
||||||
|
end
|
||||||
|
|
||||||
test "sigil" do
|
test "sigil" do
|
||||||
binary = ConfigDB.transform("~r[comp[lL][aA][iI][nN]er]")
|
binary = ConfigDB.transform("~r[comp[lL][aA][iI][nN]er]")
|
||||||
assert binary == :erlang.term_to_binary(~r/comp[lL][aA][iI][nN]er/)
|
assert binary == :erlang.term_to_binary(~r/comp[lL][aA][iI][nN]er/)
|
||||||
|
|
|
@ -105,17 +105,4 @@ test "transfer config values with full subkey update" do
|
||||||
Application.put_env(:pleroma, :assets, assets)
|
Application.put_env(:pleroma, :assets, assets)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "non existing atom" do
|
|
||||||
ConfigDB.create(%{
|
|
||||||
group: ":pleroma",
|
|
||||||
key: ":undefined_atom_key",
|
|
||||||
value: [live: 2, com: 3]
|
|
||||||
})
|
|
||||||
|
|
||||||
assert ExUnit.CaptureLog.capture_log(fn ->
|
|
||||||
TransferTask.start_link([])
|
|
||||||
end) =~
|
|
||||||
"updating env causes error, group: \":pleroma\" key: \":undefined_atom_key\" value: [live: 2, com: 3] error: %ArgumentError{message: \"argument error\"}"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,18 +25,22 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "error if file with custom settings doesn't exist" do
|
test "error if file with custom settings doesn't exist" do
|
||||||
Mix.Tasks.Pleroma.Config.run(["migrate_to_db"])
|
Mix.Tasks.Pleroma.Config.migrate_to_db("config/not_existance_config_file.exs")
|
||||||
|
|
||||||
assert_receive {:mix_shell, :info,
|
assert_receive {:mix_shell, :info,
|
||||||
[
|
[
|
||||||
"To migrate settings, you must define custom settings in config/test.secret.exs."
|
"To migrate settings, you must define custom settings in config/not_existance_config_file.exs."
|
||||||
]},
|
]},
|
||||||
15
|
15
|
||||||
end
|
end
|
||||||
|
|
||||||
test "settings are migrated to db" do
|
describe "migrate_to_db/1" do
|
||||||
|
setup do
|
||||||
initial = Application.get_env(:quack, :level)
|
initial = Application.get_env(:quack, :level)
|
||||||
on_exit(fn -> Application.put_env(:quack, :level, initial) end)
|
on_exit(fn -> Application.put_env(:quack, :level, initial) end)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "settings are migrated to db" do
|
||||||
assert Repo.all(ConfigDB) == []
|
assert Repo.all(ConfigDB) == []
|
||||||
|
|
||||||
Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs")
|
Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs")
|
||||||
|
@ -51,6 +55,22 @@ test "settings are migrated to db" do
|
||||||
assert ConfigDB.from_binary(config3.value) == :info
|
assert ConfigDB.from_binary(config3.value) == :info
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "config table is truncated before migration" do
|
||||||
|
ConfigDB.create(%{
|
||||||
|
group: ":pleroma",
|
||||||
|
key: ":first_setting",
|
||||||
|
value: [key: "value", key2: ["Activity"]]
|
||||||
|
})
|
||||||
|
|
||||||
|
assert Repo.aggregate(ConfigDB, :count, :id) == 1
|
||||||
|
|
||||||
|
Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs")
|
||||||
|
|
||||||
|
config = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"})
|
||||||
|
assert ConfigDB.from_binary(config.value) == [key: "value", key2: [Repo]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "with deletion temp file" do
|
describe "with deletion temp file" do
|
||||||
setup do
|
setup do
|
||||||
temp_file = "config/temp.exported_from_db.secret.exs"
|
temp_file = "config/temp.exported_from_db.secret.exs"
|
||||||
|
|
|
@ -1286,23 +1286,35 @@ test "User.delete() plugs any possible zombie objects" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "auth_active?/1 works correctly" do
|
describe "account_status/1" do
|
||||||
|
clear_config([:instance, :account_activation_required])
|
||||||
|
|
||||||
|
test "return confirmation_pending for unconfirm user" do
|
||||||
Pleroma.Config.put([:instance, :account_activation_required], true)
|
Pleroma.Config.put([:instance, :account_activation_required], true)
|
||||||
|
user = insert(:user, confirmation_pending: true)
|
||||||
|
assert User.account_status(user) == :confirmation_pending
|
||||||
|
end
|
||||||
|
|
||||||
local_user = insert(:user, local: true, confirmation_pending: true)
|
test "return active for confirmed user" do
|
||||||
confirmed_user = insert(:user, local: true, confirmation_pending: false)
|
Pleroma.Config.put([:instance, :account_activation_required], true)
|
||||||
remote_user = insert(:user, local: false)
|
user = insert(:user, confirmation_pending: false)
|
||||||
|
assert User.account_status(user) == :active
|
||||||
|
end
|
||||||
|
|
||||||
refute User.auth_active?(local_user)
|
test "return active for remote user" do
|
||||||
assert User.auth_active?(confirmed_user)
|
user = insert(:user, local: false)
|
||||||
assert User.auth_active?(remote_user)
|
assert User.account_status(user) == :active
|
||||||
|
end
|
||||||
|
|
||||||
# also shows unactive for deactivated users
|
test "returns :password_reset_pending for user with reset password" do
|
||||||
|
user = insert(:user, password_reset_pending: true)
|
||||||
|
assert User.account_status(user) == :password_reset_pending
|
||||||
|
end
|
||||||
|
|
||||||
deactivated_but_confirmed =
|
test "returns :deactivated for deactivated user" do
|
||||||
insert(:user, local: true, confirmation_pending: false, deactivated: true)
|
user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
|
||||||
|
assert User.account_status(user) == :deactivated
|
||||||
refute User.auth_active?(deactivated_but_confirmed)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "superuser?/1" do
|
describe "superuser?/1" do
|
||||||
|
|
|
@ -636,4 +636,17 @@ test "removes actor from announcements" do
|
||||||
assert updated_object.data["announcement_count"] == 1
|
assert updated_object.data["announcement_count"] == 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "get_cached_emoji_reactions/1" do
|
||||||
|
test "returns the data or an emtpy list" do
|
||||||
|
object = insert(:note)
|
||||||
|
assert Utils.get_cached_emoji_reactions(object) == []
|
||||||
|
|
||||||
|
object = insert(:note, data: %{"reactions" => [["x", ["lain"]]]})
|
||||||
|
assert Utils.get_cached_emoji_reactions(object) == [["x", ["lain"]]]
|
||||||
|
|
||||||
|
object = insert(:note, data: %{"reactions" => %{}})
|
||||||
|
assert Utils.get_cached_emoji_reactions(object) == []
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,7 +36,10 @@ test "has an emoji reaction list" do
|
||||||
activity = Repo.get(Activity, activity.id)
|
activity = Repo.get(Activity, activity.id)
|
||||||
status = StatusView.render("show.json", activity: activity)
|
status = StatusView.render("show.json", activity: activity)
|
||||||
|
|
||||||
assert status[:pleroma][:emoji_reactions] == [["☕", 2], ["🍵", 1]]
|
assert status[:pleroma][:emoji_reactions] == [
|
||||||
|
%{emoji: "☕", count: 2},
|
||||||
|
%{emoji: "🍵", count: 1}
|
||||||
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do
|
test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do
|
||||||
|
|
|
@ -819,7 +819,7 @@ test "rejects token exchange for valid credentials belonging to unconfirmed user
|
||||||
|> User.confirmation_changeset(need_confirmation: true)
|
|> User.confirmation_changeset(need_confirmation: true)
|
||||||
|> User.update_and_set_cache()
|
|> User.update_and_set_cache()
|
||||||
|
|
||||||
refute Pleroma.User.auth_active?(user)
|
refute Pleroma.User.account_status(user) == :active
|
||||||
|
|
||||||
app = insert(:oauth_app)
|
app = insert(:oauth_app)
|
||||||
|
|
||||||
|
@ -849,7 +849,7 @@ test "rejects token exchange for valid credentials belonging to deactivated user
|
||||||
|
|
||||||
app = insert(:oauth_app)
|
app = insert(:oauth_app)
|
||||||
|
|
||||||
conn =
|
resp =
|
||||||
build_conn()
|
build_conn()
|
||||||
|> post("/oauth/token", %{
|
|> post("/oauth/token", %{
|
||||||
"grant_type" => "password",
|
"grant_type" => "password",
|
||||||
|
@ -858,10 +858,12 @@ test "rejects token exchange for valid credentials belonging to deactivated user
|
||||||
"client_id" => app.client_id,
|
"client_id" => app.client_id,
|
||||||
"client_secret" => app.client_secret
|
"client_secret" => app.client_secret
|
||||||
})
|
})
|
||||||
|
|> json_response(403)
|
||||||
|
|
||||||
assert resp = json_response(conn, 403)
|
assert resp == %{
|
||||||
assert %{"error" => _} = resp
|
"error" => "Your account is currently disabled",
|
||||||
refute Map.has_key?(resp, "access_token")
|
"identifier" => "account_is_disabled"
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "rejects token exchange for user with password_reset_pending set to true" do
|
test "rejects token exchange for user with password_reset_pending set to true" do
|
||||||
|
@ -875,7 +877,7 @@ test "rejects token exchange for user with password_reset_pending set to true" d
|
||||||
|
|
||||||
app = insert(:oauth_app, scopes: ["read", "write"])
|
app = insert(:oauth_app, scopes: ["read", "write"])
|
||||||
|
|
||||||
conn =
|
resp =
|
||||||
build_conn()
|
build_conn()
|
||||||
|> post("/oauth/token", %{
|
|> post("/oauth/token", %{
|
||||||
"grant_type" => "password",
|
"grant_type" => "password",
|
||||||
|
@ -884,12 +886,41 @@ test "rejects token exchange for user with password_reset_pending set to true" d
|
||||||
"client_id" => app.client_id,
|
"client_id" => app.client_id,
|
||||||
"client_secret" => app.client_secret
|
"client_secret" => app.client_secret
|
||||||
})
|
})
|
||||||
|
|> json_response(403)
|
||||||
|
|
||||||
assert resp = json_response(conn, 403)
|
assert resp == %{
|
||||||
|
"error" => "Password reset is required",
|
||||||
|
"identifier" => "password_reset_required"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
assert resp["error"] == "Password reset is required"
|
test "rejects token exchange for user with confirmation_pending set to true" do
|
||||||
assert resp["identifier"] == "password_reset_required"
|
Pleroma.Config.put([:instance, :account_activation_required], true)
|
||||||
refute Map.has_key?(resp, "access_token")
|
password = "testpassword"
|
||||||
|
|
||||||
|
user =
|
||||||
|
insert(:user,
|
||||||
|
password_hash: Comeonin.Pbkdf2.hashpwsalt(password),
|
||||||
|
confirmation_pending: true
|
||||||
|
)
|
||||||
|
|
||||||
|
app = insert(:oauth_app, scopes: ["read", "write"])
|
||||||
|
|
||||||
|
resp =
|
||||||
|
build_conn()
|
||||||
|
|> post("/oauth/token", %{
|
||||||
|
"grant_type" => "password",
|
||||||
|
"username" => user.nickname,
|
||||||
|
"password" => password,
|
||||||
|
"client_id" => app.client_id,
|
||||||
|
"client_secret" => app.client_secret
|
||||||
|
})
|
||||||
|
|> json_response(403)
|
||||||
|
|
||||||
|
assert resp == %{
|
||||||
|
"error" => "Your login is missing a confirmed e-mail address",
|
||||||
|
"identifier" => "missing_confirmed_email"
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "rejects an invalid authorization code" do
|
test "rejects an invalid authorization code" do
|
||||||
|
|
|
@ -71,7 +71,7 @@ test "GET /api/v1/pleroma/statuses/:id/emoji_reactions_by", %{conn: conn} do
|
||||||
|> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by")
|
|> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by")
|
||||||
|> json_response(200)
|
|> json_response(200)
|
||||||
|
|
||||||
[["🎅", [represented_user]]] = result
|
[%{"emoji" => "🎅", "count" => 1, "accounts" => [represented_user]}] = result
|
||||||
assert represented_user["id"] == other_user.id
|
assert represented_user["id"] == other_user.id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue