diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f6914638..4d626a683 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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:** 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:** 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) - Introduced [quantum](https://github.com/quantum-elixir/quantum-core) job scheduler - 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 - 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`. +- Config mix task `migrate_to_db` truncates `config` table before migrating the config file.
API Changes @@ -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: Change emoji reaction reply format - Notifications: Added `pleroma:emoji_reaction` notification type +- Mastodon API: Change emoji reaction reply format once more
### Fixed diff --git a/config/description.exs b/config/description.exs index 3dba9b121..7829497fe 100644 --- a/config/description.exs +++ b/config/description.exs @@ -23,7 +23,7 @@ config :pleroma, :config_description, [ key: :uploader, type: :module, 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, @@ -39,7 +39,7 @@ config :pleroma, :config_description, [ key: :link_name, type: :boolean, 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, @@ -53,7 +53,7 @@ config :pleroma, :config_description, [ key: :proxy_remote, type: :boolean, 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, @@ -73,14 +73,14 @@ config :pleroma, :config_description, [ type: :boolean, description: "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, type: :integer, description: - "limits the content length to be approximately the " <> - "specified length. It is validated with the `content-length` header and also verified when proxying" + "Limits the content length to be approximately the " <> + "specified length. It is validated with the `content-length` header and also verified when proxying." }, %{ key: :http, @@ -130,7 +130,7 @@ config :pleroma, :config_description, [ %{ key: :uploads, type: :string, - description: "Path where user uploads will be saved", + description: "Path where user's uploads will be saved", suggestions: [ "uploads" ] @@ -207,7 +207,7 @@ config :pleroma, :config_description, [ type: :string, description: "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: [ "custom-file-name.{extension}" ] @@ -515,6 +515,7 @@ config :pleroma, :config_description, [ }, %{ key: :email, + label: "Admin Email Address", type: :string, description: "Email used to reach an Administrator/Moderator of the instance", suggestions: [ @@ -523,8 +524,9 @@ config :pleroma, :config_description, [ }, %{ key: :notify_email, + label: "Sender Email Address", type: :string, - description: "Email used for notifications", + description: "Envelope FROM address for mail sent via Pleroma", suggestions: [ "notify@example.com" ] @@ -635,12 +637,12 @@ config :pleroma, :config_description, [ %{ key: :registrations_open, 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, 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, @@ -658,7 +660,7 @@ config :pleroma, :config_description, [ type: :integer, description: "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: [ 100 ] @@ -668,7 +670,7 @@ config :pleroma, :config_description, [ label: "Fed. reachability timeout days", type: :integer, 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: [ 7 ] @@ -701,13 +703,13 @@ config :pleroma, :config_description, [ type: :boolean, description: "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, type: {:list, :string}, description: - "List of ActivityPub instances where private(DMs, followers-only) activities will not be send", + "List of ActivityPub instances where private (DMs, followers-only) activities will not be send", suggestions: [ "quarantined.com", "*.quarantined.com" @@ -750,7 +752,7 @@ config :pleroma, :config_description, [ label: "MRF transparency exclusions", type: {:list, :string}, 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: [ "exclusion.com" ] @@ -759,13 +761,13 @@ config :pleroma, :config_description, [ key: :extended_nickname_format, type: :boolean, description: - "Set to true to use extended local nicknames format (allows underscores/dashes)." <> - " This will break federation with older software for theses nicknames" + "Set to `true` to use extended local nicknames format (allows underscores/dashes)." <> + " This will break federation with older software for theses nicknames." }, %{ key: :max_pinned_statuses, 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: [ 0, 1, @@ -788,13 +790,13 @@ config :pleroma, :config_description, [ key: :no_attachment_links, type: :boolean, 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, type: :string, 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: [ "Hi, @username! Welcome on board!" ] @@ -810,7 +812,7 @@ config :pleroma, :config_description, [ %{ key: :max_report_comment_size, type: :integer, - description: "The maximum size of the report comment (Default: 1000)", + description: "The maximum size of the report comment. Default: 1000.", suggestions: [ 1_000 ] @@ -819,14 +821,14 @@ config :pleroma, :config_description, [ key: :safe_dm_mentions, type: :boolean, description: - "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\")." <> - " Default: false" + "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. \"@admin please keep an eye on @bad_actor\")." <> + " Default: `false`" }, %{ key: :healthcheck, 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, @@ -840,7 +842,7 @@ config :pleroma, :config_description, [ %{ key: :user_bio_length, type: :integer, - description: "A user bio maximum length (default: 5000)", + description: "A user bio maximum length. Default: 5000.", suggestions: [ 5_000 ] @@ -848,7 +850,7 @@ config :pleroma, :config_description, [ %{ key: :user_name_length, type: :integer, - description: "A user name maximum length (default: 100)", + description: "A user name maximum length. Default: 100.", suggestions: [ 100 ] @@ -856,13 +858,13 @@ config :pleroma, :config_description, [ %{ key: :skip_thread_containment, 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, type: [:atom, false], 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: [ :unauthenticated, :all, @@ -872,7 +874,7 @@ config :pleroma, :config_description, [ %{ key: :max_account_fields, 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: [ 10 ] @@ -881,7 +883,7 @@ config :pleroma, :config_description, [ key: :max_remote_account_fields, type: :integer, 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: [ 20 ] @@ -889,7 +891,7 @@ config :pleroma, :config_description, [ %{ key: :account_field_name_length, type: :integer, - description: "An account field name maximum length (default: 512)", + description: "An account field name maximum length. Default: 512.", suggestions: [ 512 ] @@ -897,7 +899,7 @@ config :pleroma, :config_description, [ %{ key: :account_field_value_length, type: :integer, - description: "An account field value maximum length (default: 2048)", + description: "An account field value maximum length. Default: 2048.", suggestions: [ 2048 ] @@ -918,7 +920,7 @@ config :pleroma, :config_description, [ key: :backends, type: [:atom, :tuple, :module], 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] } ] @@ -945,7 +947,7 @@ config :pleroma, :config_description, [ %{ key: :format, 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"] }, %{ @@ -970,7 +972,7 @@ config :pleroma, :config_description, [ %{ key: :format, 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"] }, %{ @@ -1024,7 +1026,7 @@ config :pleroma, :config_description, [ description: "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 " <> - "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: [ %{ key: :pleroma_fe, @@ -1046,7 +1048,11 @@ config :pleroma, :config_description, [ hideUserStats: false, scopeCopy: true, subjectLineBehavior: "email", - alwaysShowSubjectInput: true + alwaysShowSubjectInput: true, + logoMask: false, + logoMargin: ".1em", + stickers: false, + enableEmojiPicker: false } ], children: [ @@ -1074,7 +1080,7 @@ config :pleroma, :config_description, [ label: "Redirect root no login", type: :string, 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"] }, %{ @@ -1082,7 +1088,7 @@ config :pleroma, :config_description, [ label: "Redirect root login", type: :string, 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"] }, %{ @@ -1095,34 +1101,34 @@ config :pleroma, :config_description, [ key: :scopeOptionsEnabled, label: "Scope options enabled", 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, label: "Formatting options enabled", type: :boolean, 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, label: "Collapse message with subject", type: :boolean, description: - "When a message has a subject(aka Content Warning), collapse it by default" + "When a message has a subject (aka Content Warning), collapse it by default" }, %{ key: :hidePostStats, label: "Hide post stats", type: :boolean, - description: "Hide notices statistics(repeats, favorites, ...)" + description: "Hide notices statistics (repeats, favorites, ...)" }, %{ key: :hideUserStats, label: "Hide user stats", type: :boolean, description: - "Hide profile statistics(posts, posts per day, followers, followings, ...)" + "Hide profile statistics (posts, posts per day, followers, followings, ...)" }, %{ key: :scopeCopy, @@ -1135,16 +1141,46 @@ config :pleroma, :config_description, [ label: "Subject line behavior", type: :string, description: "Allows changing the default behaviour of subject lines in replies. - `email`: Copy and preprend re:, as in email, - `masto`: Copy verbatim, as in Mastodon, - `noop`: Don't copy the subjec", + `email`: copy and preprend re:, as in email, + `masto`: copy verbatim, as in Mastodon, + `noop`: don't copy the subject.", suggestions: ["email", "masto", "noop"] }, %{ key: :alwaysShowSubjectInput, label: "Always show subject input", 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 @@ config :pleroma, :config_description, [ key: :mascots, type: {:keyword, :map}, 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: [ pleroma_fox_tan: %{ url: "/images/pleroma-fox-tan-smol.png", @@ -1196,7 +1232,7 @@ config :pleroma, :config_description, [ key: :default_mascot, type: :atom, 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: [ :pleroma_fox_tan ] @@ -1259,7 +1295,7 @@ config :pleroma, :config_description, [ key: :media_nsfw, label: "Media NSFW", type: {:list, :string}, - description: "List of instances to put medias as NSFW(sensitive) from", + description: "List of instances to put medias as NSFW (sensitive) from", suggestions: ["example.com", "*.example.com"] }, %{ @@ -1334,12 +1370,12 @@ config :pleroma, :config_description, [ key: :allow_followersonly, label: "Allow followers-only", type: :boolean, - description: "whether to allow followers-only posts" + description: "Whether to allow followers-only posts" }, %{ key: :allow_direct, type: :boolean, - description: "whether to allow direct messages" + description: "Whether to allow direct messages" } ] }, @@ -1355,14 +1391,14 @@ config :pleroma, :config_description, [ type: :integer, description: "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] }, %{ key: :reject_threshold, type: :integer, 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] } ] @@ -1378,14 +1414,14 @@ config :pleroma, :config_description, [ key: :reject, type: [:string, :regex], 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] }, %{ key: :federated_timeline_removal, type: [:string, :regex], 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] }, %{ @@ -1464,7 +1500,7 @@ config :pleroma, :config_description, [ key: :base_url, type: :string, 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"] }, %{ @@ -1485,14 +1521,14 @@ config :pleroma, :config_description, [ type: :boolean, description: "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, type: :integer, description: - "limits the content length to be approximately the " <> - "specified length. It is validated with the `content-length` header and also verified when proxying" + "Limits the content length to be approximately the " <> + "specified length. It is validated with the `content-length` header and also verified when proxying." }, %{ key: :http, @@ -1810,9 +1846,9 @@ config :pleroma, :config_description, [ key: :subject, type: :string, 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," <> - " 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"] }, %{ @@ -1860,12 +1896,12 @@ config :pleroma, :config_description, [ type: :group, description: "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: [ %{ key: :endpoint, type: :string, - description: "the kocaptcha endpoint to use", + description: "The kocaptcha endpoint to use", suggestions: ["https://captcha.kotobank.ch"] } ] @@ -1874,7 +1910,7 @@ config :pleroma, :config_description, [ group: :pleroma, type: :group, 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: [ %{ key: :admin_token, @@ -1924,8 +1960,9 @@ config :pleroma, :config_description, [ }, %{ key: :verbose, - type: :boolean, - description: "Logs verbose mode" + type: :atom, + description: "Logs verbose mode", + suggestions: [false, :error, :warn, :info, :debug] }, %{ key: :prune, @@ -2040,7 +2077,7 @@ config :pleroma, :config_description, [ key: :unfurl_nsfw, label: "Unfurl NSFW", 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 @@ config :pleroma, :config_description, [ key: :ttl_setters, label: "TTL setters", type: {:list, :module}, - description: "List of rich media ttl setters.", + description: "List of rich media TTL setters.", suggestions: [ Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl ] @@ -2101,12 +2138,12 @@ config :pleroma, :config_description, [ key: :enabled, type: :boolean, 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, type: :integer, - description: "the amount of pages to fetch", + description: "The amount of pages to fetch", suggestions: [5] } ] @@ -2120,24 +2157,24 @@ config :pleroma, :config_description, [ %{ key: :class, 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] }, %{ key: :rel, type: [:string, false], - description: "override the rel attribute. false to clear", + description: "Override the rel attribute. `False` to clear", suggestions: ["ugc", "noopener noreferrer", false] }, %{ key: :new_window, type: :boolean, - description: "set to false to remove target='_blank' attribute" + description: "Set to `false` to remove target='_blank' attribute" }, %{ key: :scheme, 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, @@ -2154,7 +2191,7 @@ config :pleroma, :config_description, [ %{ key: :extra, 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 @@ config :pleroma, :config_description, [ key: :daily_user_limit, type: :integer, 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] }, %{ key: :total_user_limit, type: :integer, 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] }, %{ key: :enabled, 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 @@ config :pleroma, :config_description, [ %{ key: :enabled, 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 @@ config :pleroma, :config_description, [ type: :group, description: "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" <> " Pleroma instance then a new Pleroma account will be created with the same name as the LDAP user name.", children: [ %{ key: :enabled, type: :boolean, - description: "enables LDAP authentication" + description: "Enables LDAP authentication" }, %{ key: :host, @@ -2241,13 +2278,13 @@ config :pleroma, :config_description, [ key: :ssl, label: "SSL", type: :boolean, - description: "true to use SSL, usually implies the port 636" + description: "`True` to use SSL, usually implies the port 636" }, %{ key: :sslopts, label: "SSL options", type: :keyword, - description: "additional SSL options", + description: "Additional SSL options", suggestions: [cacertfile: "path/to/file/with/PEM/cacerts", verify: :verify_peer], children: [ %{ @@ -2268,13 +2305,13 @@ config :pleroma, :config_description, [ key: :tls, label: "TLS", type: :boolean, - description: "true to start TLS, usually implies the port 389" + description: "`True` to start TLS, usually implies the port 389" }, %{ key: :tlsopts, label: "TLS options", type: :keyword, - description: "additional TLS options", + description: "Additional TLS options", suggestions: [cacertfile: "path/to/file/with/PEM/cacerts", verify: :verify_peer], children: [ %{ @@ -2325,23 +2362,23 @@ config :pleroma, :config_description, [ key: :auth_template, type: :string, 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"] }, %{ key: :oauth_consumer_template, type: :string, description: - "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", + "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`.", suggestions: ["consumer.html"] }, %{ key: :oauth_consumer_strategies, type: {:list, :string}, description: - "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 or :" <> + "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\"" <> " (e.g. twitter or keycloak:ueberauth_keycloak_strategy in case dependency is named differently than ueberauth_).", suggestions: ["twitter", "keycloak:ueberauth_keycloak_strategy"] } @@ -2370,13 +2407,13 @@ config :pleroma, :config_description, [ %{ key: :active, type: :boolean, - description: "globally enable or disable digest emails" + description: "Globally enable or disable digest emails" }, %{ key: :schedule, type: :string, 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"] }, %{ @@ -2404,7 +2441,7 @@ config :pleroma, :config_description, [ %{ key: :logo, 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"] }, %{ @@ -2477,7 +2514,7 @@ config :pleroma, :config_description, [ %{ key: :clean_expired_tokens, 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 @@ config :pleroma, :config_description, [ %{ key: :shortcode_globs, 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"] }, %{ @@ -2503,8 +2540,8 @@ config :pleroma, :config_description, [ key: :groups, type: {:keyword, :string, {:list, :string}}, description: - "Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the groupname" <> - " and the value the location or array of locations. * can be used as a wildcard", + "Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the group name" <> + " and the value is the location or array of locations. * can be used as a wildcard.", suggestions: [ Custom: ["/emoji/*.png", "/emoji/**/*.png"] ] @@ -2514,7 +2551,7 @@ config :pleroma, :config_description, [ type: :string, description: "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"] }, %{ @@ -2537,7 +2574,7 @@ config :pleroma, :config_description, [ %{ key: :rum_enabled, 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 @@ config :pleroma, :config_description, [ %{ key: :search, 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}]] }, %{ key: :app_account_creation, 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}]] }, %{ key: :relations_actions, 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}]] }, %{ key: :relation_id_action, 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}]] }, %{ key: :statuses_actions, type: [:tuple, {:list, :tuple}], 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}]] }, %{ key: :status_id_action, type: [:tuple, {:list, :tuple}], 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}]] }, %{ key: :authentication, 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}] } ] @@ -2604,12 +2641,12 @@ config :pleroma, :config_description, [ %{ key: :enabled, type: :boolean, - description: "Enables ssh" + description: "Enables SSH" }, %{ key: :priv_dir, type: :string, - description: "Dir with ssh keys", + description: "Dir with SSH keys", suggestions: ["/some/path/ssh_keys"] }, %{ @@ -2788,7 +2825,7 @@ config :pleroma, :config_description, [ key: :user_agent, type: [:string, :atom], 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] }, %{ @@ -2960,19 +2997,19 @@ config :pleroma, :config_description, [ %{ key: :enabled, type: :boolean, - description: "Enable/disable the plug. Defaults to `false`." + description: "Enable/disable the plug. Default: `false`." }, %{ key: :headers, type: {:list, :string}, 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, type: {:list, :string}, 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, @@ -2993,14 +3030,13 @@ config :pleroma, :config_description, [ key: :activity_pub, type: :integer, description: - "activity pub routes (except question activities). Defaults to `nil` (no expiration).", - suggestions: [30_000] + "Activity pub routes (except question activities). Default: `nil` (no expiration).", + suggestions: [30_000, nil] }, %{ key: :activity_pub_question, type: :integer, - description: - "activity pub routes (question activities). Defaults to `30_000` (30 seconds).", + description: "Activity pub routes (question activities). Default: `30_000` (30 seconds).", suggestions: [30_000] } ] diff --git a/docs/API/differences_in_mastoapi_responses.md b/docs/API/differences_in_mastoapi_responses.md index 2236870c7..030660b34 100644 --- a/docs/API/differences_in_mastoapi_responses.md +++ b/docs/API/differences_in_mastoapi_responses.md @@ -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` - `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 -- `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 diff --git a/docs/API/pleroma_api.md b/docs/API/pleroma_api.md index 9ca8a5af0..9f5cafe5a 100644 --- a/docs/API/pleroma_api.md +++ b/docs/API/pleroma_api.md @@ -455,7 +455,7 @@ Emoji reactions work a lot like favourites do. They make it possible to react to * Example Response: ```json [ - ["😀", [{"id" => "xyz.."...}, {"id" => "zyx..."}]], - ["☕", [{"id" => "abc..."}]] + {"emoji": "😀", "count": 2, "accounts": [{"id" => "xyz.."...}, {"id" => "zyx..."}]}, + {"emoji": "☕", "count": 1, "accounts": [{"id" => "abc..."}]} ] ``` diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 861832451..3e76d2c97 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -52,6 +52,9 @@ defmodule Mix.Tasks.Pleroma.Config do defp do_migrate_to_db(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 = config_file |> read_file() diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex index 35669af27..24d999707 100644 --- a/lib/mix/tasks/pleroma/emoji.ex +++ b/lib/mix/tasks/pleroma/emoji.ex @@ -9,6 +9,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do @moduledoc File.read!("docs/administration/CLI_tasks/emoji.md") def run(["ls-packs" | args]) do + Mix.Pleroma.start_pleroma() Application.ensure_all_started(:hackney) {options, [], []} = parse_global_opts(args) @@ -35,6 +36,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do end def run(["get-packs" | args]) do + Mix.Pleroma.start_pleroma() Application.ensure_all_started(:hackney) {options, pack_names, []} = parse_global_opts(args) diff --git a/lib/mix/tasks/pleroma/robotstxt.ex b/lib/mix/tasks/pleroma/robotstxt.ex index 2128e1cd6..e99dd8502 100644 --- a/lib/mix/tasks/pleroma/robotstxt.ex +++ b/lib/mix/tasks/pleroma/robotstxt.ex @@ -18,6 +18,7 @@ defmodule Mix.Tasks.Pleroma.RobotsTxt do """ def run(["disallow_all"]) do + Mix.Pleroma.start_pleroma() static_dir = Pleroma.Config.get([:instance, :static_dir], "instance/static/") if !File.exists?(static_dir) do diff --git a/lib/pleroma/config/config_db.ex b/lib/pleroma/config/config_db.ex index 91a1aa0cc..119251bee 100644 --- a/lib/pleroma/config/config_db.ex +++ b/lib/pleroma/config/config_db.ex @@ -236,15 +236,7 @@ defmodule Pleroma.ConfigDB do end @spec from_string(String.t()) :: atom() | no_return() - def from_string(":" <> entity), do: String.to_existing_atom(entity) - - 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 + def from_string(string), do: do_transform_string(string) @spec convert(any()) :: any() def convert(entity), do: do_convert(entity) @@ -416,7 +408,7 @@ defmodule Pleroma.ConfigDB do @spec is_module_name?(String.t()) :: boolean() 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"] end end diff --git a/lib/pleroma/plugs/user_enabled_plug.ex b/lib/pleroma/plugs/user_enabled_plug.ex index 8d102ee5b..7b304eebc 100644 --- a/lib/pleroma/plugs/user_enabled_plug.ex +++ b/lib/pleroma/plugs/user_enabled_plug.ex @@ -11,11 +11,9 @@ defmodule Pleroma.Plugs.UserEnabledPlug do end def call(%{assigns: %{user: %User{} = user}} = conn, _) do - if User.auth_active?(user) do - conn - else - conn - |> assign(:user, nil) + case User.account_status(user) do + :active -> conn + _ -> assign(conn, :user, nil) end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 430f04ae9..3899c34c2 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -12,6 +12,7 @@ defmodule Pleroma.User do alias Comeonin.Pbkdf2 alias Ecto.Multi alias Pleroma.Activity + alias Pleroma.Config alias Pleroma.Conversation.Participation alias Pleroma.Delivery alias Pleroma.FollowingRelationship @@ -35,7 +36,7 @@ defmodule Pleroma.User do require Logger @type t :: %__MODULE__{} - + @type account_status :: :active | :deactivated | :password_reset_pending | :confirmation_pending @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true} # credo:disable-for-next-line Credo.Check.Readability.MaxLineLength @@ -216,14 +217,21 @@ defmodule Pleroma.User do end end - @doc "Returns if the user should be allowed to authenticate" - def auth_active?(%User{deactivated: true}), do: false + @doc "Returns status account" + @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}), - do: !Pleroma.Config.get([:instance, :account_activation_required]) + def account_status(%User{confirmation_pending: true}) do + 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{invisible: true}, _), do: false @@ -231,15 +239,17 @@ defmodule Pleroma.User do 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 - auth_active?(user) || superuser?(for_user) + account_status(user) == :active || superuser?(for_user) end 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_moderator: true}), do: true def superuser?(_), do: false + @spec invisible?(User.t()) :: boolean() def invisible?(%User{invisible: true}), do: true def invisible?(_), do: false diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 4def431f1..4f7fdaf38 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -337,7 +337,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do %Activity{data: %{"content" => emoji, "actor" => actor}}, object ) do - reactions = object.data["reactions"] || [] + reactions = get_cached_emoji_reactions(object) new_reactions = case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do @@ -365,7 +365,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do %Activity{data: %{"content" => emoji, "actor" => actor}}, object ) do - reactions = object.data["reactions"] || [] + reactions = get_cached_emoji_reactions(object) new_reactions = case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do @@ -385,6 +385,14 @@ defmodule Pleroma.Web.ActivityPub.Utils do update_element_in_object("reaction", new_reactions, object, count) 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()) :: {:ok, Object.t()} | {:error, Ecto.Changeset.t()} def add_like_to_object(%Activity{data: %{"actor" => actor}}, object) do diff --git a/lib/pleroma/web/mastodon_api/views/app_view.ex b/lib/pleroma/web/mastodon_api/views/app_view.ex index f52b693a6..beba89edb 100644 --- a/lib/pleroma/web/mastodon_api/views/app_view.ex +++ b/lib/pleroma/web/mastodon_api/views/app_view.ex @@ -7,10 +7,6 @@ defmodule Pleroma.Web.MastodonAPI.AppView do 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 %{ id: app.id |> to_string, @@ -32,8 +28,10 @@ defmodule Pleroma.Web.MastodonAPI.AppView do end defp with_vapid_key(data) do - if @vapid_key do - Map.put(data, "vapid_key", @vapid_key) + vapid_key = Application.get_env(:web_push_encryption, :vapid_details, [])[:public_key] + + if vapid_key do + Map.put(data, "vapid_key", vapid_key) else data end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 64a97896a..e60ef709b 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -256,7 +256,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do emoji_reactions = with %{data: %{"reactions" => emoji_reactions}} <- object do Enum.map(emoji_reactions, fn [emoji, users] -> - [emoji, length(users)] + %{emoji: emoji, count: length(users)} end) else _ -> [] diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 5292aedf2..528f08574 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -167,17 +167,37 @@ defmodule Pleroma.Web.OAuth.OAuthController do defp handle_create_authorization_error( %Plug.Conn{} = conn, - {:auth_active, false}, + {:account_status, :confirmation_pending}, %{"authorization" => _} = params ) do - # Per https://github.com/tootsuite/mastodon/blob/ - # 51e154f5e87968d6bb115e053689767ab33e80cd/app/controllers/api/base_controller.rb#L76 conn |> put_flash(:error, dgettext("errors", "Your login is missing a confirmed e-mail address")) |> put_status(:forbidden) |> authorize(params) 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 Authenticator.handle_error(conn, error) end @@ -218,46 +238,14 @@ defmodule Pleroma.Web.OAuth.OAuthController do ) do with {:ok, %User{} = user} <- Authenticator.get_user(conn), {:ok, app} <- Token.Utils.fetch_app(conn), - {:auth_active, true} <- {:auth_active, User.auth_active?(user)}, - {:user_active, true} <- {:user_active, !user.deactivated}, - {:password_reset_pending, false} <- - {:password_reset_pending, user.password_reset_pending}, + {:account_status, :active} <- {:account_status, User.account_status(user)}, {:ok, scopes} <- validate_scopes(app, params), {:ok, auth} <- Authorization.create_authorization(app, user, scopes), {:ok, token} <- Token.exchange_token(app, auth) do json(conn, Token.Response.build(user, token)) else - {:auth_active, false} -> - # Per https://github.com/tootsuite/mastodon/blob/ - # 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) + error -> + handle_token_exchange_error(conn, error) end end @@ -286,6 +274,43 @@ defmodule Pleroma.Web.OAuth.OAuthController do # Bad request 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 with {:ok, app} <- Token.Utils.fetch_app(conn), {:ok, _token} <- RevokeToken.revoke(app, params) do @@ -472,7 +497,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do %App{} = app <- Repo.get_by(App, client_id: client_id), true <- redirect_uri in String.split(app.redirect_uris), {: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) end end diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index bb19836ae..cd1c0764f 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -49,7 +49,12 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do emoji_reactions |> Enum.map(fn [emoji, users] -> 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) conn diff --git a/test/config/config_db_test.exs b/test/config/config_db_test.exs index 61a0b1d5d..812709fd8 100644 --- a/test/config/config_db_test.exs +++ b/test/config/config_db_test.exs @@ -307,6 +307,15 @@ defmodule Pleroma.ConfigDBTest do assert ConfigDB.from_binary(binary) == Quack.Logger 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 binary = ConfigDB.transform("~r[comp[lL][aA][iI][nN]er]") assert binary == :erlang.term_to_binary(~r/comp[lL][aA][iI][nN]er/) diff --git a/test/config/transfer_task_test.exs b/test/config/transfer_task_test.exs index b9072e0fc..53e8703fd 100644 --- a/test/config/transfer_task_test.exs +++ b/test/config/transfer_task_test.exs @@ -105,17 +105,4 @@ defmodule Pleroma.Config.TransferTaskTest do Application.put_env(:pleroma, :assets, assets) 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 diff --git a/test/tasks/config_test.exs b/test/tasks/config_test.exs index 2e56e6cfe..d79d34276 100644 --- a/test/tasks/config_test.exs +++ b/test/tasks/config_test.exs @@ -25,30 +25,50 @@ defmodule Mix.Tasks.Pleroma.ConfigTest do end 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, [ - "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 end - test "settings are migrated to db" do - initial = Application.get_env(:quack, :level) - on_exit(fn -> Application.put_env(:quack, :level, initial) end) - assert Repo.all(ConfigDB) == [] + describe "migrate_to_db/1" do + setup do + initial = Application.get_env(:quack, :level) + on_exit(fn -> Application.put_env(:quack, :level, initial) end) + end - Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs") + test "settings are migrated to db" do + assert Repo.all(ConfigDB) == [] - config1 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"}) - config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"}) - config3 = ConfigDB.get_by_params(%{group: ":quack", key: ":level"}) - refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"}) + Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs") - assert ConfigDB.from_binary(config1.value) == [key: "value", key2: [Repo]] - assert ConfigDB.from_binary(config2.value) == [key: "value2", key2: ["Activity"]] - assert ConfigDB.from_binary(config3.value) == :info + config1 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"}) + config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"}) + config3 = ConfigDB.get_by_params(%{group: ":quack", key: ":level"}) + refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"}) + + assert ConfigDB.from_binary(config1.value) == [key: "value", key2: [Repo]] + assert ConfigDB.from_binary(config2.value) == [key: "value2", key2: ["Activity"]] + assert ConfigDB.from_binary(config3.value) == :info + 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 diff --git a/test/user_test.exs b/test/user_test.exs index 9da1e02a9..158f98e66 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -1286,23 +1286,35 @@ defmodule Pleroma.UserTest do end end - test "auth_active?/1 works correctly" do - Pleroma.Config.put([:instance, :account_activation_required], true) + describe "account_status/1" do + clear_config([:instance, :account_activation_required]) - local_user = insert(:user, local: true, confirmation_pending: true) - confirmed_user = insert(:user, local: true, confirmation_pending: false) - remote_user = insert(:user, local: false) + test "return confirmation_pending for unconfirm user" do + Pleroma.Config.put([:instance, :account_activation_required], true) + user = insert(:user, confirmation_pending: true) + assert User.account_status(user) == :confirmation_pending + end - refute User.auth_active?(local_user) - assert User.auth_active?(confirmed_user) - assert User.auth_active?(remote_user) + test "return active for confirmed user" do + Pleroma.Config.put([:instance, :account_activation_required], true) + user = insert(:user, confirmation_pending: false) + assert User.account_status(user) == :active + end - # also shows unactive for deactivated users + test "return active for remote user" do + user = insert(:user, local: false) + assert User.account_status(user) == :active + end - deactivated_but_confirmed = - insert(:user, local: true, confirmation_pending: false, deactivated: true) + 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 - refute User.auth_active?(deactivated_but_confirmed) + test "returns :deactivated for deactivated user" do + user = insert(:user, local: true, confirmation_pending: false, deactivated: true) + assert User.account_status(user) == :deactivated + end end describe "superuser?/1" do diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index 586eb1d2f..211fa6c95 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -636,4 +636,17 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do assert updated_object.data["announcement_count"] == 1 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 diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/web/mastodon_api/views/status_view_test.exs index 069bb8eac..25777b011 100644 --- a/test/web/mastodon_api/views/status_view_test.exs +++ b/test/web/mastodon_api/views/status_view_test.exs @@ -36,7 +36,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do activity = Repo.get(Activity, activity.id) 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 test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs index 59f4674eb..adeff8e25 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/web/oauth/oauth_controller_test.exs @@ -819,7 +819,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do |> User.confirmation_changeset(need_confirmation: true) |> User.update_and_set_cache() - refute Pleroma.User.auth_active?(user) + refute Pleroma.User.account_status(user) == :active app = insert(:oauth_app) @@ -849,7 +849,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do app = insert(:oauth_app) - conn = + resp = build_conn() |> post("/oauth/token", %{ "grant_type" => "password", @@ -858,10 +858,12 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do "client_id" => app.client_id, "client_secret" => app.client_secret }) + |> json_response(403) - assert resp = json_response(conn, 403) - assert %{"error" => _} = resp - refute Map.has_key?(resp, "access_token") + assert resp == %{ + "error" => "Your account is currently disabled", + "identifier" => "account_is_disabled" + } end test "rejects token exchange for user with password_reset_pending set to true" do @@ -875,7 +877,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do app = insert(:oauth_app, scopes: ["read", "write"]) - conn = + resp = build_conn() |> post("/oauth/token", %{ "grant_type" => "password", @@ -884,12 +886,41 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do "client_id" => app.client_id, "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" - assert resp["identifier"] == "password_reset_required" - refute Map.has_key?(resp, "access_token") + test "rejects token exchange for user with confirmation_pending set to true" do + Pleroma.Config.put([:instance, :account_activation_required], true) + 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 test "rejects an invalid authorization code" do diff --git a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs index a79ecd05b..3978c2ec5 100644 --- a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs +++ b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs @@ -71,7 +71,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do |> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by") |> json_response(200) - [["🎅", [represented_user]]] = result + [%{"emoji" => "🎅", "count" => 1, "accounts" => [represented_user]}] = result assert represented_user["id"] == other_user.id end