diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..c46415a5c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.ex diff=elixir +*.exs diff=elixir diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c6ad4fd9..4127e21f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - **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. +- **Breaking:** `:instance, no_attachment_links` has been replaced with `:instance, attachment_links` which still takes a boolean value but doesn't use double negative language. - 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 @@ -37,6 +38,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
API Changes +- **Breaking** EmojiReactions: Change endpoints and responses to align with Mastodon - **Breaking** Admin API: `PATCH /api/pleroma/admin/users/:nickname/force_password_reset` is now `PATCH /api/pleroma/admin/users/force_password_reset` (accepts `nicknames` array in the request body) - **Breaking:** Admin API: Return link alongside with token on password reset - **Breaking:** Admin API: `PUT /api/pleroma/admin/reports/:id` is now `PATCH /api/pleroma/admin/reports`, see admin_api.md for details @@ -70,7 +72,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - User notification settings: Add `privacy_option` option. - Support for custom Elixir modules (such as MRF policies) - User settings: Add _This account is a_ option. +- A new users admin digest email - OAuth: admin scopes support (relevant setting: `[:auth, :enforce_oauth_admin_scope_usage]`). +- Add an option `authorized_fetch_mode` to require HTTP signatures for AP fetches.
API Changes diff --git a/config/config.exs b/config/config.exs index fcda1653a..897475df2 100644 --- a/config/config.exs +++ b/config/config.exs @@ -51,20 +51,6 @@ telemetry_event: [Pleroma.Repo.Instrumenter], migration_lock: nil -scheduled_jobs = - with digest_config <- Application.get_env(:pleroma, :email_notifications)[:digest], - true <- digest_config[:active] do - [{digest_config[:schedule], {Pleroma.Daemons.DigestEmailDaemon, :perform, []}}] - else - _ -> [] - end - -config :pleroma, Pleroma.Scheduler, - global: true, - overlap: true, - timezone: :utc, - jobs: scheduled_jobs - config :pleroma, Pleroma.Captcha, enabled: true, seconds_valid: 300, @@ -256,7 +242,7 @@ staff_transparency: [], autofollowed_nicknames: [], max_pinned_statuses: 1, - no_attachment_links: true, + attachment_links: false, welcome_user_nickname: nil, welcome_message: nil, max_report_comment_size: 1000, @@ -341,7 +327,8 @@ unfollow_blocked: true, outgoing_blocks: true, follow_handshake_timeout: 500, - sign_object_fetches: true + sign_object_fetches: true, + authorized_fetch_mode: false config :pleroma, :streamer, workers: 3, @@ -495,7 +482,15 @@ transmogrifier: 20, scheduled_activities: 10, background: 5, - attachments_cleanup: 5 + attachments_cleanup: 5, + new_users_digest: 1 + ], + crontab: [ + {"0 0 * * *", Pleroma.Workers.Cron.ClearOauthTokenWorker}, + {"0 * * * *", Pleroma.Workers.Cron.StatsWorker}, + {"* * * * *", Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker}, + {"0 0 * * 0", Pleroma.Workers.Cron.DigestEmailsWorker}, + {"0 0 * * *", Pleroma.Workers.Cron.NewUsersDigestWorker} ] config :pleroma, :workers, @@ -569,6 +564,8 @@ text_muted_color: "#b9b9ba" } +config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: false + config :prometheus, Pleroma.Web.Endpoint.MetricsExporter, path: "/api/pleroma/app_metrics" config :pleroma, Pleroma.ScheduledActivity, @@ -579,7 +576,6 @@ config :pleroma, :email_notifications, digest: %{ active: false, - schedule: "0 0 * * 0", interval: 7, inactivity_threshold: 7 } @@ -587,8 +583,7 @@ config :pleroma, :oauth2, token_expires_in: 600, issue_new_refresh_token: true, - clean_expired_tokens: false, - clean_expired_tokens_interval: 86_400_000 + clean_expired_tokens: false config :pleroma, :database, rum_enabled: false @@ -623,7 +618,6 @@ config :pleroma, configurable_from_database: false -config :swarm, node_blacklist: [~r/myhtml_.*$/] # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{Mix.env()}.exs" diff --git a/config/description.exs b/config/description.exs index 6b912a07e..53d980c83 100644 --- a/config/description.exs +++ b/config/description.exs @@ -101,7 +101,7 @@ %{ key: :versions, type: {:list, :atom}, - description: "List of TLS version to use", + description: "List of TLS versions to use", suggestions: [:tlsv1, ":tlsv1.1", ":tlsv1.2"] } ] @@ -534,7 +534,8 @@ %{ key: :description, type: :string, - description: "The instance's description, can be seen in nodeinfo and /api/v1/instance", + description: + "The instance's description. It can be seen in nodeinfo and `/api/v1/instance`", suggestions: [ "Very cool instance" ] @@ -637,22 +638,24 @@ %{ key: :registrations_open, type: :boolean, - description: "Enable registrations for anyone, invitations can be enabled when `false`" + description: + "Enable registrations for anyone. Invitations require this setting to be disabled." }, %{ 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` being disabled)." }, %{ key: :account_activation_required, type: :boolean, - description: "Require users to confirm their emails before signing in" + description: "Require users to confirm their emails before signing in." }, %{ key: :federating, type: :boolean, - description: "Enable federation with other instances" + description: "Enable federation with other instances." }, %{ key: :federation_incoming_replies_max_depth, @@ -761,14 +764,14 @@ key: :extended_nickname_format, type: :boolean, description: - "Set to `true` to use extended local nicknames format (allows underscores/dashes)." <> + "Enable to use extended local nicknames format (allows underscores/dashes)." <> " This will break federation with older software for theses nicknames." }, %{ key: :cleanup_attachments, type: :boolean, description: """ - "Set to `true` to remove associated attachments when status is removed. + Enable to remove associated attachments when status is removed. This will not affect duplicates and attachments without status. Enabling this will increase load to database when deleting statuses on larger instances. """ @@ -796,10 +799,9 @@ ] }, %{ - key: :no_attachment_links, + key: :attachment_links, type: :boolean, - description: - "Set to `true` to disable automatically adding attachment link text to statuses" + description: "Enable to automatically add attachment link text to statuses" }, %{ key: :welcome_message, @@ -830,14 +832,14 @@ 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." <> + "If enabled, 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`" + " Default: disabled" }, %{ key: :healthcheck, type: :boolean, - description: "If set to `true`, system data will be shown on /api/pleroma/healthcheck" + description: "If enabled, system data will be shown on `/api/pleroma/healthcheck`" }, %{ key: :remote_post_retention_days, @@ -867,7 +869,7 @@ %{ key: :skip_thread_containment, type: :boolean, - description: "Skip filter out broken threads. Default: `true`" + description: "Skip filtering out broken threads. Default: enabled" }, %{ key: :limit_to_local_content, @@ -1159,17 +1161,15 @@ 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 disabled, auto-hide the subject field if 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." + "By default it assumes logo used will be monochrome with alpha channel to be compatible with both light and dark themes. " <> + "If you want a colorful logo you must disable logoMask." }, %{ key: :logoMargin, @@ -1183,13 +1183,13 @@ %{ key: :stickers, type: :boolean, - description: "Enables/disables stickers." + description: "Enables stickers." }, %{ key: :enableEmojiPicker, label: "Emoji picker", type: :boolean, - description: "Enables/disables emoji picker." + description: "Enables emoji picker." } ] }, @@ -1297,14 +1297,14 @@ %{ key: :media_removal, type: {:list, :string}, - description: "List of instances to remove medias from", + description: "List of instances to strip media attachments from", suggestions: ["example.com", "*.example.com"] }, %{ 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 tag all media as NSFW (sensitive) from", suggestions: ["example.com", "*.example.com"] }, %{ @@ -1423,21 +1423,21 @@ 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] }, %{ key: :replace, type: [{:tuple, :string, :string}, {:tuple, :regex, :string}], description: - "A list of tuples containing {pattern, replacement}, pattern can be a string or a regular expression.", + "A list of tuples containing {pattern, replacement}. Each pattern can be a string or a regular expression.", suggestions: [{"foo", "bar"}, {~r/foo/iu, "bar"}] } ] @@ -1452,7 +1452,7 @@ %{ key: :actors, type: {:list, :string}, - description: "A list of actors, for which to drop any posts mentioning", + description: "A list of actors for which any post mentioning them will be dropped.", suggestions: ["actor1", "actor2"] } ] @@ -1856,9 +1856,8 @@ type: :string, description: "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.", - suggestions: ["Subject"] + " It's best if this email is not a personal email address, but rather a group email to the instance moderation team.", + suggestions: ["mailto:moderators@pleroma.com"] }, %{ key: :public_key, @@ -1925,7 +1924,7 @@ key: :admin_token, type: :string, description: "Token", - suggestions: ["some_random_token"] + suggestions: ["We recommend a secure random string or UUID"] } ] }, @@ -1987,6 +1986,7 @@ "Background jobs queues (keys: queues, values: max numbers of concurrent jobs)", suggestions: [ activity_expiration: 10, + attachments_cleanup: 5, background: 5, federator_incoming: 50, federator_outgoing: 50, @@ -2002,6 +2002,12 @@ description: "Activity expiration queue", suggestions: [10] }, + %{ + key: :attachments_cleanup, + type: :integer, + description: "Attachment deletion queue", + suggestions: [5] + }, %{ key: :background, type: :integer, @@ -2086,7 +2092,7 @@ key: :unfurl_nsfw, label: "Unfurl NSFW", type: :boolean, - description: "If set to `true` NSFW attachments will be shown in previews" + description: "When enabled NSFW attachments will be shown in previews" } ] }, @@ -2100,7 +2106,7 @@ %{ key: :enabled, type: :boolean, - description: "Enables/disables RichMedia." + description: "Enables RichMedia parsing of URLs." }, %{ key: :ignore_hosts, @@ -2146,8 +2152,7 @@ %{ key: :enabled, type: :boolean, - description: - "If enabled, when a new user is federated with, fetch some of their latest posts" + description: "Fetch posts when a new user is federated with" }, %{ key: :pages, @@ -2166,13 +2171,13 @@ %{ 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. Disable to clear", suggestions: ["auto-linker", false] }, %{ key: :rel, type: [:string, false], - description: "Override the rel attribute. `False` to clear", + description: "Override the rel attribute. Disable to clear", suggestions: ["ugc", "noopener noreferrer", false] }, %{ @@ -2282,7 +2287,7 @@ key: :ssl, label: "SSL", type: :boolean, - description: "`True` to use SSL, usually implies the port 636" + description: "Enable to use SSL, usually implies the port 636" }, %{ key: :sslopts, @@ -2309,7 +2314,7 @@ key: :tls, label: "TLS", type: :boolean, - description: "`True` to start TLS, usually implies the port 389" + description: "Enable to use STARTTLS, usually implies the port 389" }, %{ key: :tlsopts, @@ -2358,8 +2363,8 @@ type: :boolean, description: "OAuth admin scope requirement toggle. " <> - "If `true`, admin actions explicitly demand admin OAuth scope(s) presence in OAuth token " <> - "(client app must support admin scopes). If `false` and token doesn't have admin scope(s)," <> + "If enabled, admin actions explicitly demand admin OAuth scope(s) presence in OAuth token " <> + "(client app must support admin scopes). If disabled and token doesn't have admin scope(s)," <> "`is_admin` user flag grants access to admin-specific actions." }, %{ @@ -2381,7 +2386,7 @@ 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." <> + "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"] @@ -2497,6 +2502,20 @@ } ] }, + %{ + group: :pleroma, + key: Pleroma.Emails.NewUsersDigestEmail, + type: :group, + description: "New users admin email digest", + children: [ + %{ + key: :enabled, + type: :boolean, + description: "enables new users admin digest email when `true`", + suggestions: [false] + } + ] + }, %{ group: :pleroma, key: :oauth2, @@ -2518,14 +2537,7 @@ %{ key: :clean_expired_tokens, type: :boolean, - description: "Enable a background job to clean expired oauth tokens. Default: `false`." - }, - %{ - key: :clean_expired_tokens_interval, - type: :integer, - description: - "Interval to run the job to clean expired tokens. Default: 86_400_000 (24 hours).", - suggestions: [86_400_000] + description: "Enable a background job to clean expired oauth tokens. Default: disabled." } ] }, @@ -2585,7 +2597,7 @@ %{ key: :rum_enabled, type: :boolean, - description: "If RUM indexes should be used. Default: `false`" + description: "If RUM indexes should be used. Default: disabled" } ] }, @@ -2971,7 +2983,7 @@ %{ key: :enabled, type: :boolean, - description: "Enable/disable the plug. Default: `false`." + description: "Enable/disable the plug. Default: disabled." }, %{ key: :headers, @@ -3025,7 +3037,7 @@ %{ key: :enabled, type: :boolean, - description: "Enables the rendering of static HTML. Defaults to `false`." + description: "Enables the rendering of static HTML. Default: disabled." } ] }, @@ -3101,7 +3113,7 @@ key: :configurable_from_database, type: :boolean, description: - "Allow transferring configuration to DB with the subsequent customization from Admin api. Defaults to `false`" + "Allow transferring configuration to DB with the subsequent customization from Admin api. Default: disabled" } ] } diff --git a/config/test.exs b/config/test.exs index 5c66a36f1..6bea09380 100644 --- a/config/test.exs +++ b/config/test.exs @@ -66,11 +66,8 @@ config :pleroma, Oban, queues: false, - prune: :disabled - -config :pleroma, Pleroma.Scheduler, - jobs: [], - global: false + prune: :disabled, + crontab: false config :pleroma, Pleroma.ScheduledActivity, daily_user_limit: 2, @@ -97,6 +94,8 @@ config :pleroma, :modules, runtime_dir: "test/fixtures/modules" +config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: true + if File.exists?("./config/test.secret.exs") do import_config "test.secret.exs" else diff --git a/docs/API/admin_api.md b/docs/API/admin_api.md index fb6dfcb08..47acd240e 100644 --- a/docs/API/admin_api.md +++ b/docs/API/admin_api.md @@ -682,6 +682,8 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret ### Get list of merged default settings with saved in database. +*If `need_reboot` flag exists in response, instance must be restarted, so reboot time settings can take effect.* + **Only works when configuration from database is enabled.** - Params: @@ -692,20 +694,24 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret ```json { - configs: [ + "configs": [ { "group": ":pleroma", "key": "Pleroma.Upload", "value": [] } - ] + ], + "need_reboot": true } ``` + need_reboot - *optional*, if were changed reboot time settings. ## `POST /api/pleroma/admin/config` ### Update config settings +*If `need_reboot` flag exists in response, instance must be restarted, so reboot time settings can take effect.* + **Only works when configuration from database is enabled.** Some modifications are necessary to save the config settings correctly: @@ -793,7 +799,7 @@ config :quack, ``` ```json { - configs: [ + "configs": [ {"group": ":quack", "key": ":level", "value": ":debug"}, {"group": ":quack", "key": ":meta", "value": [":all"]}, ... @@ -804,7 +810,7 @@ config :quack, ```json { - configs: [ + "configs": [ { "group": ":pleroma", "key": "Pleroma.Upload", @@ -836,15 +842,17 @@ config :quack, - 400 Bad Request `"To use this endpoint you need to enable configuration from database."` ```json { - configs: [ + "configs": [ { "group": ":pleroma", "key": "Pleroma.Upload", "value": [...] } - ] + ], + "need_reboot": true } ``` +need_reboot - *optional*, if were changed reboot time settings. ## ` GET /api/pleroma/admin/config/descriptions` diff --git a/docs/API/differences_in_mastoapi_responses.md b/docs/API/differences_in_mastoapi_responses.md index 89245261c..06de90f71 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 maps. The format is `{emoji: "☕", count: 1, reacted: true}`. 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 `{name: "☕", count: 1, me: true}`. Contains no information about the reacting users, for that use the `/statuses/:id/reactions` endpoint. ## Attachments @@ -88,6 +88,9 @@ Behavior has changed: - `/api/v1/accounts/search`: Does not require authentication +## Search (global) + +Unlisted posts are available in search results, they are considered to be public posts that shouldn't be shown in local/federated timeline. ## Notifications diff --git a/docs/API/pleroma_api.md b/docs/API/pleroma_api.md index c7125c1cd..07e0af5e5 100644 --- a/docs/API/pleroma_api.md +++ b/docs/API/pleroma_api.md @@ -432,21 +432,21 @@ The status posting endpoint takes an additional parameter, `in_reply_to_conversa Emoji reactions work a lot like favourites do. They make it possible to react to a post with a single emoji character. -## `POST /api/v1/pleroma/statuses/:id/react_with_emoji` +## `PUT /api/v1/pleroma/statuses/:id/reactions/:emoji` ### React to a post with a unicode emoji -* Method: `POST` +* Method: `PUT` * Authentication: required * Params: `emoji`: A single character unicode emoji * Response: JSON, the status. -## `POST /api/v1/pleroma/statuses/:id/unreact_with_emoji` +## `DELETE /api/v1/pleroma/statuses/:id/reactions/:emoji` ### Remove a reaction to a post with a unicode emoji -* Method: `POST` +* Method: `DELETE` * Authentication: required * Params: `emoji`: A single character unicode emoji * Response: JSON, the status. -## `GET /api/v1/pleroma/statuses/:id/emoji_reactions_by` +## `GET /api/v1/pleroma/statuses/:id/reactions` ### Get an object of emoji to account mappings with accounts that reacted to the post * Method: `GET` * Authentication: optional @@ -455,7 +455,7 @@ Emoji reactions work a lot like favourites do. They make it possible to react to * Example Response: ```json [ - {"emoji": "😀", "count": 2, "reacted": true, "accounts": [{"id" => "xyz.."...}, {"id" => "zyx..."}]}, - {"emoji": "☕", "count": 1, "reacted": false, "accounts": [{"id" => "abc..."}]} + {"name": "😀", "count": 2, "me": true, "accounts": [{"id" => "xyz.."...}, {"id" => "zyx..."}]}, + {"name": "☕", "count": 1, "me": false, "accounts": [{"id" => "abc..."}]} ] ``` diff --git a/docs/administration/backup.md b/docs/administration/backup.md index 2c70e7bf8..685c45128 100644 --- a/docs/administration/backup.md +++ b/docs/administration/backup.md @@ -1,17 +1,35 @@ -# Backup/Restore your instance +# Backup/Restore/Move/Remove your instance ## Backup 1. Stop the Pleroma service. 2. Go to the working directory of Pleroma (default is `/opt/pleroma`) -3. Run `sudo -Hu postgres pg_dump -d --format=custom -f ` +3. Run `sudo -Hu postgres pg_dump -d --format=custom -f ` (make sure the postgres user has write access to the destination file) 4. Copy `pleroma.pgdump`, `config/prod.secret.exs` and the `uploads` folder to your backup destination. If you have other modifications, copy those changes too. 5. Restart the Pleroma service. -## Restore +## Restore/Move -1. Stop the Pleroma service. -2. Go to the working directory of Pleroma (default is `/opt/pleroma`) -3. Copy the above mentioned files back to their original position. -4. Run `sudo -Hu postgres pg_restore -d -v -1 ` -5. Restart the Pleroma service. +1. Optionally reinstall Pleroma (either on the same server or on another server if you want to move servers). Try to use the same database name. +2. Stop the Pleroma service. +3. Go to the working directory of Pleroma (default is `/opt/pleroma`) +4. Copy the above mentioned files back to their original position. +5. Drop the existing database and recreate an empty one `sudo -Hu postgres psql -c 'DROP DATABASE ;';` `sudo -Hu postgres psql -c 'CREATE DATABASE ;';` +6. Run `sudo -Hu postgres pg_restore -d -v -1 ` +7. If you installed a newer Pleroma version, you should run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any. +8. Restart the Pleroma service. + +[^1]: Prefix with `MIX_ENV=prod` to run it using the production config file. + +## Remove + +1. Optionally you can remove the users of your instance. This will trigger delete requests for their accounts and posts. Note that this is 'best effort' and doesn't mean that all traces of your instance will be gone from the fediverse. + * You can do this from the admin-FE where you can select all local users and delete the accounts using the *Moderate multiple users* dropdown. + * You can also list local users and delete them individualy using the CLI tasks for [Managing users](./CLI_tasks/user.md). +2. Stop the Pleroma service `systemctl stop pleroma` +3. Disable pleroma from systemd `systemctl disable pleroma` +4. Remove the files and folders you created during installation (see installation guide). This includes the pleroma, nginx and systemd files and folders. +5. Reload nginx now that the configuration is removed `systemctl reload nginx` +6. Remove the database and database user `sudo -Hu postgres psql -c 'DROP DATABASE ;';` `sudo -Hu postgres psql -c 'DROP USER ;';` +7. Remove the system user `userdel pleroma` +8. Remove the dependencies that you don't need anymore (see installation guide). Make sure you don't remove packages that are still needed for other software that you have running! diff --git a/docs/administration/updating.md b/docs/administration/updating.md index 84e6ef18d..2a08dac1f 100644 --- a/docs/administration/updating.md +++ b/docs/administration/updating.md @@ -1,4 +1,21 @@ # Updating your instance + +You should **always check the release notes/changelog** in case there are config deprecations, special update special update steps, etc. + +Besides that, doing the following is generally enough: + +## For OTP installations + +```sh +# Download the new release +su pleroma -s $SHELL -lc "./bin/pleroma_ctl update" + +# Migrate the database, you are advised to stop the instance before doing that +su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate" +``` + +## For from source installations (using git) + 1. Go to the working directory of Pleroma (default is `/opt/pleroma`) 2. Run `git pull`. This pulls the latest changes from upstream. 3. Run `mix deps.get`. This pulls in any new dependencies. diff --git a/docs/clients.md b/docs/clients.md index 6c6180f7a..8ac9ad3de 100644 --- a/docs/clients.md +++ b/docs/clients.md @@ -37,6 +37,11 @@ Feel free to contact us to be added to this list! - Platforms: Android - Features: Streaming Ready, Moderation, Text Formatting +### Kyclos +- Source Code: +- Platforms: SailfishOS +- Features: No Streaming + ### Nekonium - Homepage: [F-Droid Repository](https://repo.gdgd.jp.net/), [Google Play](https://play.google.com/store/apps/details?id=com.apps.nekonium), [Amazon](https://www.amazon.co.jp/dp/B076FXPRBC/) - Source: diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index f30aedc01..ac55a0b32 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -143,10 +143,11 @@ config :pleroma, :mrf_user_allowlist, * `:reject` rejects the message entirely ### :activitypub -* ``unfollow_blocked``: Whether blocks result in people getting unfollowed -* ``outgoing_blocks``: Whether to federate blocks to other instances -* ``deny_follow_blocked``: Whether to disallow following an account that has blocked the user in question -* ``sign_object_fetches``: Sign object fetches with HTTP signatures +* `unfollow_blocked`: Whether blocks result in people getting unfollowed +* `outgoing_blocks`: Whether to federate blocks to other instances +* `deny_follow_blocked`: Whether to disallow following an account that has blocked the user in question +* `sign_object_fetches`: Sign object fetches with HTTP signatures +* `authorized_fetch_mode`: Require HTTP signatures for AP fetches ### :fetch_initial_posts * `enabled`: if enabled, when a new user is federated with, fetch some of their latest posts @@ -501,6 +502,10 @@ Email notifications settings. - `:logo` - a path to a custom logo. Set it to `nil` to use the default Pleroma logo. - `:styling` - a map with color settings for email templates. +### Pleroma.Emails.NewUsersDigestEmail + +- `:enabled` - a boolean, enables new users admin digest email when `true`. Defaults to `false`. + ## Background jobs ### Oban @@ -513,6 +518,7 @@ Configuration options described in [Oban readme](https://github.com/sorentwo/oba * `verbose` - logs verbosity * `prune` - non-retryable jobs [pruning settings](https://github.com/sorentwo/oban#pruning) (`:disabled` / `{:maxlen, value}` / `{:maxage, value}`) * `queues` - job queues (see below) +* `crontab` - periodic jobs, see [`Oban.Cron`](#obancron) Pleroma has the following queues: @@ -524,6 +530,12 @@ Pleroma has the following queues: * `web_push` - Web push notifications * `scheduled_activities` - Scheduled activities, see [`Pleroma.ScheduledActivity`](#pleromascheduledactivity) +#### Oban.Cron + +Pleroma has these periodic job workers: + +`Pleroma.Workers.Cron.ClearOauthTokenWorker` - a job worker to cleanup expired oauth tokens. + Example: ```elixir @@ -534,6 +546,9 @@ config :pleroma, Oban, queues: [ federator_incoming: 50, federator_outgoing: 50 + ], + crontab: [ + {"0 0 * * *", Pleroma.Workers.Cron.ClearOauthTokenWorker} ] ``` @@ -816,8 +831,7 @@ Configure OAuth 2 provider capabilities: * `token_expires_in` - The lifetime in seconds of the access token. * `issue_new_refresh_token` - Keeps old refresh token or generate new refresh token when to obtain an access token. -* `clean_expired_tokens` - Enable a background job to clean expired oauth tokens. Defaults to `false`. -* `clean_expired_tokens_interval` - Interval to run the job to clean expired tokens. Defaults to `86_400_000` (24 hours). +* `clean_expired_tokens` - Enable a background job to clean expired oauth tokens. Defaults to `false`. Interval settings sets in configuration periodic jobs [`Oban.Cron`](#obancron) ## Link parsing diff --git a/docs/configuration/mrf.md b/docs/configuration/mrf.md index 45be18fc5..c3957c255 100644 --- a/docs/configuration/mrf.md +++ b/docs/configuration/mrf.md @@ -1,4 +1,5 @@ # Message Rewrite Facility + The Message Rewrite Facility (MRF) is a subsystem that is implemented as a series of hooks that allows the administrator to rewrite or discard messages. Possible uses include: @@ -10,7 +11,8 @@ Possible uses include: * removing media from messages * sending only public messages to a specific instance -The MRF provides user-configurable policies. The default policy is `NoOpPolicy`, which disables the MRF functionality. Pleroma also includes an easy to use policy called `SimplePolicy` which maps messages matching certain pre-defined criterion to actions built into the policy module. +The MRF provides user-configurable policies. The default policy is `NoOpPolicy`, which disables the MRF functionality. Pleroma also includes an easy to use policy called `SimplePolicy` which maps messages matching certain pre-defined criterion to actions built into the policy module. + It is possible to use multiple, active MRF policies at the same time. ## Quarantine Instances @@ -18,7 +20,8 @@ It is possible to use multiple, active MRF policies at the same time. You have the ability to prevent from private / followers-only messages from federating with specific instances. Which means they will only get the public or unlisted messages from your instance. If, for example, you're using `MIX_ENV=prod` aka using production mode, you would open your configuration file located in `config/prod.secret.exs` and edit or add the option under your `:instance` config object. Then you would specify the instance within quotes. -``` + +```elixir config :pleroma, :instance, [...] quarantined_instances: ["instance.example", "other.example"] @@ -28,15 +31,15 @@ config :pleroma, :instance, `SimplePolicy` is capable of handling most common admin tasks. -To use `SimplePolicy`, you must enable it. Do so by adding the following to your `:instance` config object, so that it looks like this: +To use `SimplePolicy`, you must enable it. Do so by adding the following to your `:instance` config object, so that it looks like this: -``` +```elixir config :pleroma, :instance, [...] rewrite_policy: Pleroma.Web.ActivityPub.MRF.SimplePolicy ``` -Once `SimplePolicy` is enabled, you can configure various groups in the `:mrf_simple` config object. These groups are: +Once `SimplePolicy` is enabled, you can configure various groups in the `:mrf_simple` config object. These groups are: * `media_removal`: Servers in this group will have media stripped from incoming messages. * `media_nsfw`: Servers in this group will have the #nsfw tag and sensitive setting injected into incoming messages which contain media. @@ -50,7 +53,7 @@ Servers should be configured as lists. This example will enable `SimplePolicy`, block media from `illegalporn.biz`, mark media as NSFW from `porn.biz` and `porn.business`, reject messages from `spam.com`, remove messages from `spam.university` from the federated timeline and block reports (flags) from `whiny.whiner`: -``` +```elixir config :pleroma, :instance, rewrite_policy: [Pleroma.Web.ActivityPub.MRF.SimplePolicy] @@ -60,30 +63,31 @@ config :pleroma, :mrf_simple, reject: ["spam.com"], federated_timeline_removal: ["spam.university"], report_removal: ["whiny.whiner"] - ``` ### Use with Care -The effects of MRF policies can be very drastic. It is important to use this functionality carefully. Always try to talk to an admin before writing an MRF policy concerning their instance. +The effects of MRF policies can be very drastic. It is important to use this functionality carefully. Always try to talk to an admin before writing an MRF policy concerning their instance. ## Writing your own MRF Policy -As discussed above, the MRF system is a modular system that supports pluggable policies. This means that an admin may write a custom MRF policy in Elixir or any other language that runs on the Erlang VM, by specifying the module name in the `rewrite_policy` config setting. +As discussed above, the MRF system is a modular system that supports pluggable policies. This means that an admin may write a custom MRF policy in Elixir or any other language that runs on the Erlang VM, by specifying the module name in the `rewrite_policy` config setting. For example, here is a sample policy module which rewrites all messages to "new message content": ```elixir -# This is a sample MRF policy which rewrites all Notes to have "new message -# content." -defmodule Site.RewritePolicy do - @behavior Pleroma.Web.ActivityPub.MRF +defmodule Pleroma.Web.ActivityPub.MRF.RewritePolicy do + @moduledoc "MRF policy which rewrites all Notes to have 'new message content'." + @behaviour Pleroma.Web.ActivityPub.MRF # Catch messages which contain Note objects with actual data to filter. # Capture the object as `object`, the message content as `content` and the # message itself as `message`. @impl true - def filter(%{"type" => Create", "object" => {"type" => "Note", "content" => content} = object} = message) + def filter( + %{"type" => "Create", "object" => %{"type" => "Note", "content" => content} = object} = + message + ) when is_binary(content) do # Subject / CW is stored as summary instead of `name` like other AS2 objects # because of Mastodon doing it that way. @@ -106,17 +110,22 @@ defmodule Site.RewritePolicy do # Let all other messages through without modifying them. @impl true def filter(message), do: {:ok, message} + + @impl true + def describe do + {:ok, %{mrf_sample: %{content: "new message content"}}}` + end end ``` -If you save this file as `lib/site/mrf/rewrite_policy.ex`, it will be included when you next rebuild Pleroma. You can enable it in the configuration like so: +If you save this file as `lib/pleroma/web/activity_pub/mrf/rewrite_policy.ex`, it will be included when you next rebuild Pleroma. You can enable it in the configuration like so: -``` +```elixir config :pleroma, :instance, rewrite_policy: [ Pleroma.Web.ActivityPub.MRF.SimplePolicy, - Site.RewritePolicy + Pleroma.Web.ActivityPub.MRF.RewritePolicy ] ``` -Please note that the Pleroma developers consider custom MRF policy modules to fall under the purview of the AGPL. As such, you are obligated to release the sources to your custom MRF policy modules upon request. +Please note that the Pleroma developers consider custom MRF policy modules to fall under the purview of the AGPL. As such, you are obligated to release the sources to your custom MRF policy modules upon request. diff --git a/docs/installation/otp_en.md b/docs/installation/otp_en.md index 93230806c..aab5197a2 100644 --- a/docs/installation/otp_en.md +++ b/docs/installation/otp_en.md @@ -259,19 +259,14 @@ su pleroma -s $SHELL -lc "./bin/pleroma_ctl user new joeuser joeuser@sld.tld --a ``` This will create an account withe the username of 'joeuser' with the email address of joeuser@sld.tld, and set that user's account as an admin. This will result in a link that you can paste into the browser, which logs you in and enables you to set the password. -### Updating -Generally, doing the following is enough: -```sh -# Download the new release -su pleroma -s $SHELL -lc "./bin/pleroma_ctl update" - -# Migrate the database, you are advised to stop the instance before doing that -su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate" -``` -But you should **always check the release notes/changelog** in case there are config deprecations, special update steps, etc. - ## Further reading * [Backup your instance](../administration/backup.md) * [Hardening your instance](../configuration/hardening.md) * [How to activate mediaproxy](../configuration/howto_mediaproxy.md) +* [Updating your instance](../administration/updating.md) + +## Questions + +Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**. + diff --git a/lib/pleroma/activity_expiration.ex b/lib/pleroma/activity_expiration.ex index 7ea5c48ca..a58a493f7 100644 --- a/lib/pleroma/activity_expiration.ex +++ b/lib/pleroma/activity_expiration.ex @@ -62,6 +62,6 @@ def validate_scheduled_at(changeset) do def expires_late_enough?(scheduled_at) do now = NaiveDateTime.utc_now() diff = NaiveDateTime.diff(scheduled_at, now, :millisecond) - diff >= @min_activity_lifetime + diff > @min_activity_lifetime end end diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 2c8889ce5..27758cf94 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -42,12 +42,9 @@ def start(_type, _args) do children = [ Pleroma.Repo, - Pleroma.Scheduler, Pleroma.Config.TransferTask, Pleroma.Emoji, Pleroma.Captcha, - Pleroma.Daemons.ScheduledActivityDaemon, - Pleroma.Daemons.ActivityExpirationDaemon, Pleroma.Plugs.RateLimiter.Supervisor ] ++ cachex_children() ++ @@ -58,7 +55,6 @@ def start(_type, _args) do {Oban, Pleroma.Config.get(Oban)} ] ++ task_children(@env) ++ - oauth_cleanup_child(oauth_cleanup_enabled?()) ++ streamer_child(@env) ++ chat_child(@env, chat_enabled?()) ++ [ @@ -160,20 +156,12 @@ defp build_cachex(type, opts), defp chat_enabled?, do: Pleroma.Config.get([:chat, :enabled]) - defp oauth_cleanup_enabled?, - do: Pleroma.Config.get([:oauth2, :clean_expired_tokens], false) - defp streamer_child(:test), do: [] defp streamer_child(_) do [Pleroma.Web.Streamer.supervisor()] end - defp oauth_cleanup_child(true), - do: [Pleroma.Web.OAuth.Token.CleanWorker] - - defp oauth_cleanup_child(_), do: [] - defp chat_child(_env, true) do [Pleroma.Web.ChatChannel.ChatChannelState] end diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex index 6c5ba1f95..f037ce8a5 100644 --- a/lib/pleroma/config/transfer_task.ex +++ b/lib/pleroma/config/transfer_task.ex @@ -146,9 +146,7 @@ defp group_and_subkey_need_reboot?(group, key, value) do defp update_env(group, key, nil), do: Application.delete_env(group, key) defp update_env(group, key, value), do: Application.put_env(group, key, value) - defp restart(_, :pleroma, :test), do: Logger.warn("pleroma restarted") - - defp restart(_, :pleroma, _), do: send(Restarter.Pleroma, :after_boot) + defp restart(_, :pleroma, env), do: Restarter.Pleroma.restart_after_boot(env) defp restart(started_applications, app, _) do with {^app, _, _} <- List.keyfind(started_applications, app, 0), diff --git a/lib/pleroma/daemons/activity_expiration_daemon.ex b/lib/pleroma/daemons/activity_expiration_daemon.ex deleted file mode 100644 index cab7628c4..000000000 --- a/lib/pleroma/daemons/activity_expiration_daemon.ex +++ /dev/null @@ -1,66 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Daemons.ActivityExpirationDaemon do - alias Pleroma.Activity - alias Pleroma.ActivityExpiration - alias Pleroma.Config - alias Pleroma.Repo - alias Pleroma.User - alias Pleroma.Web.CommonAPI - - require Logger - use GenServer - import Ecto.Query - - @schedule_interval :timer.minutes(1) - - def start_link(_) do - GenServer.start_link(__MODULE__, nil) - end - - @impl true - def init(_) do - if Config.get([ActivityExpiration, :enabled]) do - schedule_next() - {:ok, nil} - else - :ignore - end - end - - def perform(:execute, expiration_id) do - try do - expiration = - ActivityExpiration - |> where([e], e.id == ^expiration_id) - |> Repo.one!() - - activity = Activity.get_by_id_with_object(expiration.activity_id) - user = User.get_by_ap_id(activity.object.data["actor"]) - CommonAPI.delete(activity.id, user) - rescue - error -> - Logger.error("#{__MODULE__} Couldn't delete expired activity: #{inspect(error)}") - end - end - - @impl true - def handle_info(:perform, state) do - ActivityExpiration.due_expirations(@schedule_interval) - |> Enum.each(fn expiration -> - Pleroma.Workers.ActivityExpirationWorker.enqueue( - "activity_expiration", - %{"activity_expiration_id" => expiration.id} - ) - end) - - schedule_next() - {:noreply, state} - end - - defp schedule_next do - Process.send_after(self(), :perform, @schedule_interval) - end -end diff --git a/lib/pleroma/daemons/digest_email_daemon.ex b/lib/pleroma/daemons/digest_email_daemon.ex deleted file mode 100644 index b4c8eaad9..000000000 --- a/lib/pleroma/daemons/digest_email_daemon.ex +++ /dev/null @@ -1,42 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Daemons.DigestEmailDaemon do - alias Pleroma.Repo - alias Pleroma.Workers.DigestEmailsWorker - - import Ecto.Query - - def perform do - config = Pleroma.Config.get([:email_notifications, :digest]) - negative_interval = -Map.fetch!(config, :interval) - inactivity_threshold = Map.fetch!(config, :inactivity_threshold) - inactive_users_query = Pleroma.User.list_inactive_users_query(inactivity_threshold) - - now = NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second) - - from(u in inactive_users_query, - where: fragment(~s(? ->'digest' @> 'true'), u.email_notifications), - where: u.last_digest_emailed_at < datetime_add(^now, ^negative_interval, "day"), - select: u - ) - |> Repo.all() - |> Enum.each(fn user -> - DigestEmailsWorker.enqueue("digest_email", %{"user_id" => user.id}) - end) - end - - @doc """ - Send digest email to the given user. - Updates `last_digest_emailed_at` field for the user and returns the updated user. - """ - @spec perform(Pleroma.User.t()) :: Pleroma.User.t() - def perform(user) do - with %Swoosh.Email{} = email <- Pleroma.Emails.UserEmail.digest_email(user) do - Pleroma.Emails.Mailer.deliver_async(email) - end - - Pleroma.User.touch_last_digest_emailed_at(user) - end -end diff --git a/lib/pleroma/daemons/scheduled_activity_daemon.ex b/lib/pleroma/daemons/scheduled_activity_daemon.ex deleted file mode 100644 index aee5f723a..000000000 --- a/lib/pleroma/daemons/scheduled_activity_daemon.ex +++ /dev/null @@ -1,62 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Daemons.ScheduledActivityDaemon do - @moduledoc """ - Sends scheduled activities to the job queue. - """ - - alias Pleroma.Config - alias Pleroma.ScheduledActivity - alias Pleroma.User - alias Pleroma.Web.CommonAPI - - use GenServer - require Logger - - @schedule_interval :timer.minutes(1) - - def start_link(_) do - GenServer.start_link(__MODULE__, nil) - end - - def init(_) do - if Config.get([ScheduledActivity, :enabled]) do - schedule_next() - {:ok, nil} - else - :ignore - end - end - - def perform(:execute, scheduled_activity_id) do - try do - {:ok, scheduled_activity} = ScheduledActivity.delete(scheduled_activity_id) - %User{} = user = User.get_cached_by_id(scheduled_activity.user_id) - {:ok, _result} = CommonAPI.post(user, scheduled_activity.params) - rescue - error -> - Logger.error( - "#{__MODULE__} Couldn't create a status from the scheduled activity: #{inspect(error)}" - ) - end - end - - def handle_info(:perform, state) do - ScheduledActivity.due_activities(@schedule_interval) - |> Enum.each(fn scheduled_activity -> - Pleroma.Workers.ScheduledActivityWorker.enqueue( - "execute", - %{"activity_id" => scheduled_activity.id} - ) - end) - - schedule_next() - {:noreply, state} - end - - defp schedule_next do - Process.send_after(self(), :perform, @schedule_interval) - end -end diff --git a/lib/pleroma/docs/generator.ex b/lib/pleroma/docs/generator.ex index 6b12dcdd9..e0fc8cd02 100644 --- a/lib/pleroma/docs/generator.ex +++ b/lib/pleroma/docs/generator.ex @@ -13,7 +13,7 @@ def list_modules_in_dir(dir, start) do |> Enum.filter(&String.ends_with?(&1, ".ex")) |> Enum.map(fn filename -> module = filename |> String.trim_trailing(".ex") |> Macro.camelize() - String.to_existing_atom(start <> module) + String.to_atom(start <> module) end) end end diff --git a/lib/pleroma/emails/new_users_digest_email.ex b/lib/pleroma/emails/new_users_digest_email.ex new file mode 100644 index 000000000..7d16b807f --- /dev/null +++ b/lib/pleroma/emails/new_users_digest_email.ex @@ -0,0 +1,32 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Emails.NewUsersDigestEmail do + use Phoenix.Swoosh, view: Pleroma.Web.EmailView, layout: {Pleroma.Web.LayoutView, :email_styled} + + defp instance_notify_email do + Pleroma.Config.get([:instance, :notify_email]) || Pleroma.Config.get([:instance, :email]) + end + + def new_users(to, users_and_statuses) do + instance_name = Pleroma.Config.get([:instance, :name]) + styling = Pleroma.Config.get([Pleroma.Emails.UserEmail, :styling]) + + logo_url = + Pleroma.Web.Endpoint.url() <> + Pleroma.Config.get([:frontend_configurations, :pleroma_fe, :logo]) + + new() + |> to({to.name, to.email}) + |> from({instance_name, instance_notify_email()}) + |> subject("#{instance_name} New Users") + |> render_body("new_users_digest.html", %{ + title: "New Users", + users_and_statuses: users_and_statuses, + instance: instance_name, + styling: styling, + logo_url: logo_url + }) + end +end diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 11513106e..05946aa96 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -108,6 +108,7 @@ def extract_first_external_url(object, content) do Cachex.fetch!(:scrubber_cache, key, fn _key -> result = content + |> Floki.parse_fragment!() |> Floki.filter_out("a.mention,a.hashtag,a[rel~=\"tag\"]") |> Floki.attribute("a", "href") |> Enum.at(0) diff --git a/lib/pleroma/plugs/http_signature.ex b/lib/pleroma/plugs/http_signature.ex index 23d22a712..477a5b578 100644 --- a/lib/pleroma/plugs/http_signature.ex +++ b/lib/pleroma/plugs/http_signature.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do import Plug.Conn + import Phoenix.Controller, only: [get_format: 1, text: 2] require Logger def init(options) do @@ -15,25 +16,27 @@ def call(%{assigns: %{valid_signature: true}} = conn, _opts) do end def call(conn, _opts) do - headers = get_req_header(conn, "signature") - signature = Enum.at(headers, 0) + if get_format(conn) == "activity+json" do + conn + |> maybe_assign_valid_signature() + |> maybe_require_signature() + else + conn + end + end - if signature do + defp maybe_assign_valid_signature(conn) do + if has_signature_header?(conn) do # set (request-target) header to the appropriate value # we also replace the digest header with the one we computed - conn = - conn - |> put_req_header( - "(request-target)", - String.downcase("#{conn.method}") <> " #{conn.request_path}" - ) + request_target = String.downcase("#{conn.method}") <> " #{conn.request_path}" conn = - if conn.assigns[:digest] do - conn - |> put_req_header("digest", conn.assigns[:digest]) - else - conn + conn + |> put_req_header("(request-target)", request_target) + |> case do + %{assigns: %{digest: digest}} = conn -> put_req_header(conn, "digest", digest) + conn -> conn end assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn)) @@ -42,4 +45,21 @@ def call(conn, _opts) do conn end end + + defp has_signature_header?(conn) do + conn |> get_req_header("signature") |> Enum.at(0, false) + end + + defp maybe_require_signature(%{assigns: %{valid_signature: true}} = conn), do: conn + + defp maybe_require_signature(conn) do + if Pleroma.Config.get([:activitypub, :authorized_fetch_mode], false) do + conn + |> put_status(:unauthorized) + |> text("Request not signed") + |> halt() + else + conn + end + end end diff --git a/lib/pleroma/scheduled_activity.ex b/lib/pleroma/scheduled_activity.ex index fea2cf3ff..e81bfcd7d 100644 --- a/lib/pleroma/scheduled_activity.ex +++ b/lib/pleroma/scheduled_activity.ex @@ -5,15 +5,19 @@ defmodule Pleroma.ScheduledActivity do use Ecto.Schema + alias Ecto.Multi alias Pleroma.Config alias Pleroma.Repo alias Pleroma.ScheduledActivity alias Pleroma.User alias Pleroma.Web.CommonAPI.Utils + alias Pleroma.Workers.ScheduledActivityWorker import Ecto.Query import Ecto.Changeset + @type t :: %__MODULE__{} + @min_offset :timer.minutes(5) schema "scheduled_activities" do @@ -105,16 +109,32 @@ def far_enough?(scheduled_at) do end def new(%User{} = user, attrs) do - %ScheduledActivity{user_id: user.id} - |> changeset(attrs) + changeset(%ScheduledActivity{user_id: user.id}, attrs) end + @doc """ + Creates ScheduledActivity and add to queue to perform at scheduled_at date + """ + @spec create(User.t(), map()) :: {:ok, ScheduledActivity.t()} | {:error, Ecto.Changeset.t()} def create(%User{} = user, attrs) do - user - |> new(attrs) - |> Repo.insert() + Multi.new() + |> Multi.insert(:scheduled_activity, new(user, attrs)) + |> maybe_add_jobs(Config.get([ScheduledActivity, :enabled])) + |> Repo.transaction() + |> transaction_response end + defp maybe_add_jobs(multi, true) do + multi + |> Multi.run(:scheduled_activity_job, fn _repo, %{scheduled_activity: activity} -> + %{activity_id: activity.id} + |> ScheduledActivityWorker.new(scheduled_at: activity.scheduled_at) + |> Oban.insert() + end) + end + + defp maybe_add_jobs(multi, _), do: multi + def get(%User{} = user, scheduled_activity_id) do ScheduledActivity |> where(user_id: ^user.id) @@ -122,25 +142,43 @@ def get(%User{} = user, scheduled_activity_id) do |> Repo.one() end - def update(%ScheduledActivity{} = scheduled_activity, attrs) do - scheduled_activity - |> update_changeset(attrs) - |> Repo.update() + @spec update(ScheduledActivity.t(), map()) :: + {:ok, ScheduledActivity.t()} | {:error, Ecto.Changeset.t()} + def update(%ScheduledActivity{id: id} = scheduled_activity, attrs) do + with {:error, %Ecto.Changeset{valid?: true} = changeset} <- + {:error, update_changeset(scheduled_activity, attrs)} do + Multi.new() + |> Multi.update(:scheduled_activity, changeset) + |> Multi.update_all(:scheduled_job, job_query(id), + set: [scheduled_at: get_field(changeset, :scheduled_at)] + ) + |> Repo.transaction() + |> transaction_response + end end - def delete(%ScheduledActivity{} = scheduled_activity) do - scheduled_activity - |> Repo.delete() + @doc "Deletes a ScheduledActivity and linked jobs." + @spec delete(ScheduledActivity.t() | binary() | integer) :: + {:ok, ScheduledActivity.t()} | {:error, Ecto.Changeset.t()} + def delete(%ScheduledActivity{id: id} = scheduled_activity) do + Multi.new() + |> Multi.delete(:scheduled_activity, scheduled_activity, stale_error_field: :id) + |> Multi.delete_all(:jobs, job_query(id)) + |> Repo.transaction() + |> transaction_response end def delete(id) when is_binary(id) or is_integer(id) do - ScheduledActivity - |> where(id: ^id) - |> select([sa], sa) - |> Repo.delete_all() - |> case do - {1, [scheduled_activity]} -> {:ok, scheduled_activity} - _ -> :error + delete(%__MODULE__{id: id}) + end + + defp transaction_response(result) do + case result do + {:ok, %{scheduled_activity: scheduled_activity}} -> + {:ok, scheduled_activity} + + {:error, _, changeset, _} -> + {:error, changeset} end end @@ -158,4 +196,11 @@ def due_activities(offset \\ 0) do |> where([sa], sa.scheduled_at < ^naive_datetime) |> Repo.all() end + + def job_query(scheduled_activity_id) do + from(j in Oban.Job, + where: j.queue == "scheduled_activities", + where: fragment("args ->> 'activity_id' = ?::text", ^to_string(scheduled_activity_id)) + ) + end end diff --git a/lib/pleroma/scheduler.ex b/lib/pleroma/scheduler.ex deleted file mode 100644 index d84cd99ad..000000000 --- a/lib/pleroma/scheduler.ex +++ /dev/null @@ -1,7 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Scheduler do - use Quantum.Scheduler, otp_app: :pleroma -end diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex index 8154a09b7..cf590fb01 100644 --- a/lib/pleroma/stats.ex +++ b/lib/pleroma/stats.ex @@ -9,22 +9,43 @@ defmodule Pleroma.Stats do use GenServer - @interval 1000 * 60 * 60 + @init_state %{ + peers: [], + stats: %{ + domain_count: 0, + status_count: 0, + user_count: 0 + } + } def start_link(_) do - GenServer.start_link(__MODULE__, initial_data(), name: __MODULE__) + GenServer.start_link( + __MODULE__, + @init_state, + name: __MODULE__ + ) end + @doc "Performs update stats" def force_update do GenServer.call(__MODULE__, :force_update) end + @doc "Performs collect stats" + def do_collect do + GenServer.cast(__MODULE__, :run_update) + end + + @doc "Returns stats data" + @spec get_stats() :: %{domain_count: integer(), status_count: integer(), user_count: integer()} def get_stats do %{stats: stats} = GenServer.call(__MODULE__, :get_state) stats end + @doc "Returns list peers" + @spec get_peers() :: list(String.t()) def get_peers do %{peers: peers} = GenServer.call(__MODULE__, :get_state) @@ -32,7 +53,6 @@ def get_peers do end def init(args) do - Process.send(self(), :run_update, []) {:ok, args} end @@ -45,17 +65,12 @@ def handle_call(:get_state, _from, state) do {:reply, state, state} end - def handle_info(:run_update, _state) do + def handle_cast(:run_update, _state) do new_stats = get_stat_data() - Process.send_after(self(), :run_update, @interval) {:noreply, new_stats} end - defp initial_data do - %{peers: [], stats: %{}} - end - defp get_stat_data do peers = from( @@ -74,7 +89,11 @@ defp get_stat_data do %{ peers: peers, - stats: %{domain_count: domain_count, status_count: status_count, user_count: user_count} + stats: %{ + domain_count: domain_count, + status_count: status_count, + user_count: user_count + } } end end diff --git a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex index 8abe18e29..802d10edc 100644 --- a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex @@ -17,6 +17,7 @@ defp old_user?(%User{} = u) do # does the post contain links? defp contains_links?(%{"content" => content} = _object) do content + |> Floki.parse_fragment!() |> Floki.filter_out("a.mention,a.hashtag,a[rel~=\"tag\"],a.zrl") |> Floki.attribute("a", "href") |> length() > 0 diff --git a/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex b/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex index 8b36c1021..788508349 100644 --- a/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex @@ -5,12 +5,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do alias Pleroma.Config alias Pleroma.User - alias Pleroma.Web.ActivityPub.MRF require Pleroma.Constants @moduledoc "Filter activities depending on their age" - @behaviour MRF + @behaviour Pleroma.Web.ActivityPub.MRF defp check_date(%{"published" => published} = message) do with %DateTime{} = now <- DateTime.utc_now(), diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index 8e53296e7..b94c3c78a 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do alias Pleroma.User alias Pleroma.Web.ActivityPub.MRF @moduledoc "Filter activities depending on their origin instance" - @behaviour MRF + @behaviour Pleroma.Web.ActivityPub.MRF require Pleroma.Constants diff --git a/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex b/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex index 566c1e191..77ffd1bb9 100644 --- a/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex @@ -8,7 +8,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicy do require Logger - @behaviour MRF + @behaviour Pleroma.Web.ActivityPub.MRF defp lookup_subchain(actor) do with matches <- Config.get([:mrf_subchain, :match_actor]), diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index c95cd182d..67222ebae 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do import Pleroma.Web.ControllerHelper, only: [json_response: 3] alias Pleroma.Activity + alias Pleroma.Config alias Pleroma.ConfigDB alias Pleroma.ModerationLog alias Pleroma.Plugs.OAuthScopesPlug @@ -570,8 +571,8 @@ def relay_unfollow(%{assigns: %{user: admin}} = conn, %{"relay_url" => target}) @doc "Sends registration invite via email" def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do with true <- - Pleroma.Config.get([:instance, :invites_enabled]) && - !Pleroma.Config.get([:instance, :registrations_open]), + Config.get([:instance, :invites_enabled]) && + !Config.get([:instance, :registrations_open]), {:ok, invite_token} <- UserInviteToken.create_invite(), email <- Pleroma.Emails.UserEmail.user_invitation_email( @@ -808,7 +809,7 @@ def config_show(conn, _params) do configs = ConfigDB.get_all_as_keyword() merged = - Pleroma.Config.Holder.config() + Config.Holder.config() |> ConfigDB.merge(configs) |> Enum.map(fn {group, values} -> Enum.map(values, fn {key, value} -> @@ -838,7 +839,16 @@ def config_show(conn, _params) do end) |> List.flatten() - json(conn, %{configs: merged}) + response = %{configs: merged} + + response = + if Restarter.Pleroma.need_reboot?() do + Map.put(response, :need_reboot, true) + else + response + end + + json(conn, response) end end @@ -863,20 +873,26 @@ def config_update(conn, %{"configs" => configs}) do Ecto.get_meta(config, :state) == :deleted end) - Pleroma.Config.TransferTask.load_and_update_env(deleted, false) + Config.TransferTask.load_and_update_env(deleted, false) need_reboot? = - Enum.any?(updated, fn config -> - group = ConfigDB.from_string(config.group) - key = ConfigDB.from_string(config.key) - value = ConfigDB.from_binary(config.value) - Pleroma.Config.TransferTask.pleroma_need_restart?(group, key, value) - end) + Restarter.Pleroma.need_reboot?() || + Enum.any?(updated, fn config -> + group = ConfigDB.from_string(config.group) + key = ConfigDB.from_string(config.key) + value = ConfigDB.from_binary(config.value) + Config.TransferTask.pleroma_need_restart?(group, key, value) + end) response = %{configs: updated} response = - if need_reboot?, do: Map.put(response, :need_reboot, need_reboot?), else: response + if need_reboot? do + Restarter.Pleroma.need_reboot() + Map.put(response, :need_reboot, need_reboot?) + else + response + end conn |> put_view(ConfigView) @@ -886,18 +902,14 @@ def config_update(conn, %{"configs" => configs}) do def restart(conn, _params) do with :ok <- configurable_from_database(conn) do - if Pleroma.Config.get(:env) == :test do - Logger.warn("pleroma restarted") - else - send(Restarter.Pleroma, {:restart, 50}) - end + Restarter.Pleroma.restart(Config.get(:env), 50) json(conn, %{}) end end defp configurable_from_database(conn) do - if Pleroma.Config.get(:configurable_from_database) do + if Config.get(:configurable_from_database) do :ok else errors( diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index ca6c93862..4445894b0 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -228,9 +228,9 @@ def make_content_html( data, visibility ) do - no_attachment_links = + attachment_links = data - |> Map.get("no_attachment_links", Config.get([:instance, :no_attachment_links])) + |> Map.get("attachment_links", Config.get([:instance, :attachment_links])) |> truthy_param?() content_type = get_content_type(data["content_type"]) @@ -244,7 +244,7 @@ def make_content_html( status |> format_input(content_type, options) - |> maybe_add_attachments(attachments, no_attachment_links) + |> maybe_add_attachments(attachments, attachment_links) |> maybe_add_nsfw_tag(data) end @@ -270,7 +270,7 @@ def make_context(_, %Participation{} = participation) do def make_context(%Activity{data: %{"context" => context}}, _), do: context def make_context(_, _), do: Utils.generate_context_id() - def maybe_add_attachments(parsed, _attachments, true = _no_links), do: parsed + def maybe_add_attachments(parsed, _attachments, false = _no_links), do: parsed def maybe_add_attachments({text, mentions, tags}, attachments, _no_links) do text = add_attachments(text, attachments) diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index 1149fb469..287d1631c 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -124,15 +124,18 @@ def create( ) do params = Map.put(params, "in_reply_to_status_id", params["in_reply_to_id"]) - if ScheduledActivity.far_enough?(scheduled_at) do - with {:ok, scheduled_activity} <- - ScheduledActivity.create(user, %{"params" => params, "scheduled_at" => scheduled_at}) do - conn - |> put_view(ScheduledActivityView) - |> render("show.json", scheduled_activity: scheduled_activity) - end + with {:far_enough, true} <- {:far_enough, ScheduledActivity.far_enough?(scheduled_at)}, + attrs <- %{"params" => params, "scheduled_at" => scheduled_at}, + {:ok, scheduled_activity} <- ScheduledActivity.create(user, attrs) do + conn + |> put_view(ScheduledActivityView) + |> render("show.json", scheduled_activity: scheduled_activity) else - create(conn, Map.drop(params, ["scheduled_at"])) + {:far_enough, _} -> + create(conn, Map.drop(params, ["scheduled_at"])) + + error -> + error end end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 6cb158bbf..6b0fe9215 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -175,9 +175,11 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} expires_at = with true <- client_posted_this_activity, - expiration when not is_nil(expiration) <- + %ActivityExpiration{scheduled_at: scheduled_at} <- ActivityExpiration.get_by_activity_id(activity.id) do - expiration.scheduled_at + scheduled_at + else + _ -> nil end thread_muted? = @@ -242,9 +244,9 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} with %{data: %{"reactions" => emoji_reactions}} <- object do Enum.map(emoji_reactions, fn [emoji, users] -> %{ - emoji: emoji, + name: emoji, count: length(users), - reacted: !!(opts[:for] && opts[:for].ap_id in users) + me: !!(opts[:for] && opts[:for].ap_id in users) } end) else @@ -321,11 +323,9 @@ def render("card.json", %{rich_media: rich_media, page_url: page_url}) do nil end - site_name = rich_media[:site_name] || page_url_data.host - %{ type: "link", - provider_name: site_name, + provider_name: page_url_data.host, provider_url: page_url_data.scheme <> "://" <> page_url_data.host, url: page_url, image: image_url |> MediaProxy.url(), diff --git a/lib/pleroma/web/metadata/rel_me.ex b/lib/pleroma/web/metadata/rel_me.ex index f87fc1973..86dcc1a3b 100644 --- a/lib/pleroma/web/metadata/rel_me.ex +++ b/lib/pleroma/web/metadata/rel_me.ex @@ -8,8 +8,10 @@ defmodule Pleroma.Web.Metadata.Providers.RelMe do @impl Provider def build_tags(%{user: user}) do - (Floki.attribute(user.bio, "link[rel~=me]", "href") ++ - Floki.attribute(user.bio, "a[rel~=me]", "href")) + bio_tree = Floki.parse_fragment!(user.bio) + + (Floki.attribute(bio_tree, "link[rel~=me]", "href") ++ + Floki.attribute(bio_tree, "a[rel~=me]", "href")) |> Enum.map(fn link -> {:link, [rel: "me", href: link], []} end) diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index 5cd4806b1..012bf560b 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -50,10 +50,10 @@ def raw_nodeinfo do data |> Map.merge(%{quarantined_instances: quarantined}) - |> Map.put(:enabled, Config.get([:instance, :federating])) else %{} end + |> Map.put(:enabled, Config.get([:instance, :federating])) features = [ diff --git a/lib/pleroma/web/oauth/token/clean_worker.ex b/lib/pleroma/web/oauth/token/clean_worker.ex deleted file mode 100644 index 3c9c580d5..000000000 --- a/lib/pleroma/web/oauth/token/clean_worker.ex +++ /dev/null @@ -1,34 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.OAuth.Token.CleanWorker do - @moduledoc """ - The module represents functions to clean an expired oauth tokens. - """ - use GenServer - - @ten_seconds 10_000 - @one_day 86_400_000 - - alias Pleroma.Web.OAuth.Token - alias Pleroma.Workers.BackgroundWorker - - def start_link(_), do: GenServer.start_link(__MODULE__, %{}) - - def init(_) do - Process.send_after(self(), :perform, @ten_seconds) - {:ok, nil} - end - - @doc false - def handle_info(:perform, state) do - BackgroundWorker.enqueue("clean_expired_tokens", %{}) - interval = Pleroma.Config.get([:oauth2, :clean_expired_tokens_interval], @one_day) - - Process.send_after(self(), :perform, interval) - {:noreply, state} - end - - def perform(:clean), do: Token.delete_expired_tokens() -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 d76e39795..108e48438 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -53,10 +53,10 @@ def emoji_reactions_by(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) |> Enum.filter(& &1) %{ - emoji: emoji, + name: emoji, count: length(users), accounts: AccountView.render("index.json", %{users: users, for: user, as: :user}), - reacted: !!(user && user.ap_id in user_ap_ids) + me: !!(user && user.ap_id in user_ap_ids) } end) diff --git a/lib/pleroma/web/rel_me.ex b/lib/pleroma/web/rel_me.ex index 16b1a53d2..540fa65df 100644 --- a/lib/pleroma/web/rel_me.ex +++ b/lib/pleroma/web/rel_me.ex @@ -27,9 +27,10 @@ def parse(_), do: {:error, "No URL provided"} defp parse_url(url) do with {:ok, %Tesla.Env{body: html, status: status}} when status in 200..299 <- Pleroma.HTTP.get(url, [], adapter: @hackney_options), + {:ok, html_tree} <- Floki.parse_document(html), data <- - Floki.attribute(html, "link[rel~=me]", "href") ++ - Floki.attribute(html, "a[rel~=me]", "href") do + Floki.attribute(html_tree, "link[rel~=me]", "href") ++ + Floki.attribute(html_tree, "a[rel~=me]", "href") do {:ok, data} end rescue diff --git a/lib/pleroma/web/rich_media/parser.ex b/lib/pleroma/web/rich_media/parser.ex index c06b0a0f2..9702e90f1 100644 --- a/lib/pleroma/web/rich_media/parser.ex +++ b/lib/pleroma/web/rich_media/parser.ex @@ -81,18 +81,18 @@ defp parse_url(url) do {:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: @hackney_options) html - |> parse_html + |> parse_html() |> maybe_parse() |> Map.put(:url, url) |> clean_parsed_data() |> check_parsed_data() rescue e -> - {:error, "Parsing error: #{inspect(e)}"} + {:error, "Parsing error: #{inspect(e)} #{inspect(__STACKTRACE__)}"} end end - defp parse_html(html), do: Floki.parse(html) + defp parse_html(html), do: Floki.parse_document!(html) defp maybe_parse(html) do Enum.reduce_while(parsers(), %{}, fn parser, acc -> diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index e86bc3cc3..897215698 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -271,7 +271,7 @@ defmodule Pleroma.Web.Router do scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do pipe_through(:api) - get("/statuses/:id/emoji_reactions_by", PleromaAPIController, :emoji_reactions_by) + get("/statuses/:id/reactions", PleromaAPIController, :emoji_reactions_by) end scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do @@ -287,8 +287,8 @@ defmodule Pleroma.Web.Router do pipe_through(:authenticated_api) patch("/conversations/:id", PleromaAPIController, :update_conversation) - post("/statuses/:id/react_with_emoji", PleromaAPIController, :react_with_emoji) - post("/statuses/:id/unreact_with_emoji", PleromaAPIController, :unreact_with_emoji) + put("/statuses/:id/reactions/:emoji", PleromaAPIController, :react_with_emoji) + delete("/statuses/:id/reactions/:emoji", PleromaAPIController, :unreact_with_emoji) post("/notifications/read", PleromaAPIController, :read_notification) patch("/accounts/update_avatar", AccountController, :update_avatar) diff --git a/lib/pleroma/web/templates/email/new_users_digest.html.eex b/lib/pleroma/web/templates/email/new_users_digest.html.eex new file mode 100644 index 000000000..40d9b8381 --- /dev/null +++ b/lib/pleroma/web/templates/email/new_users_digest.html.eex @@ -0,0 +1,158 @@ +<%= for {user, total_statuses, latest_status} <- @users_and_statuses do %> + <%# user card START %> +
+
+
+ + +
+
+ +
+ +
+ <%= user.name %> + +
+ +
+ +
+
+ + + +
+
+ +
+ + +
+
+

<%= user.name %>

+

<%= link "@" <> user.nickname, style: "color: #{@styling.link_color};text-decoration: none;", to: admin_user_url(user) %>

+

Total: <%= total_statuses %>

+
+
+ + +
+ +
+
+ + +
+
+
+ <%# user card END %> + + <%= if latest_status do %> +
+
+
+ + +
+
+ +
+ + +
+
+ <%= raw latest_status.object.data["content"] %>
+
+ + +
+
+

<%= format_date latest_status.object.data["published"] %>

+
+
+ + +
+ +
+
+ + +
+
+
+ <% end %> + <%# divider start %> +
+
+
+ + +
+
+ +
+ + + + + + + + + +
+ +
+
+ + +
+
+
+ + <%# divider end %> + <%# user card END %> +<% end %> diff --git a/lib/pleroma/web/templates/layout/email_styled.html.eex b/lib/pleroma/web/templates/layout/email_styled.html.eex new file mode 100644 index 000000000..ca2caaf4d --- /dev/null +++ b/lib/pleroma/web/templates/layout/email_styled.html.eex @@ -0,0 +1,193 @@ + + + + + + + + + + + + <%= @email.subject %> + + + + + + + + + + + + + + + + + + + diff --git a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex index e0d4d5632..fbf31c7eb 100644 --- a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors +# Copyright © 2017-2020 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do @@ -69,7 +69,7 @@ defp is_status?(acct) do def do_follow(%{assigns: %{user: %User{} = user}} = conn, %{"user" => %{"id" => id}}) do with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)}, {:ok, _, _, _} <- CommonAPI.follow(user, followee) do - render(conn, "followed.html", %{error: false}) + redirect(conn, to: "/users/#{followee.id}") else error -> handle_follow_error(conn, error) @@ -80,7 +80,7 @@ def do_follow(conn, %{"authorization" => %{"name" => _, "password" => _, "id" => with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)}, {_, {:ok, user}, _} <- {:auth, Authenticator.get_user(conn), followee}, {:ok, _, _, _} <- CommonAPI.follow(user, followee) do - render(conn, "followed.html", %{error: false}) + redirect(conn, to: "/users/#{followee.id}") else error -> handle_follow_error(conn, error) diff --git a/lib/pleroma/web/views/email_view.ex b/lib/pleroma/web/views/email_view.ex index b506a234b..6b0fbe61e 100644 --- a/lib/pleroma/web/views/email_view.ex +++ b/lib/pleroma/web/views/email_view.ex @@ -12,4 +12,8 @@ def format_date(date) when is_binary(date) do |> Timex.parse!("{ISO:Extended:Z}") |> Timex.format!("{Mshort} {D}, {YYYY} {h24}:{m}") end + + def admin_user_url(%{id: id}) do + Pleroma.Web.Endpoint.url() <> "/pleroma/admin/#/users/" <> id + end end diff --git a/lib/pleroma/workers/activity_expiration_worker.ex b/lib/pleroma/workers/activity_expiration_worker.ex deleted file mode 100644 index 4e3e4195f..000000000 --- a/lib/pleroma/workers/activity_expiration_worker.ex +++ /dev/null @@ -1,18 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Workers.ActivityExpirationWorker do - use Pleroma.Workers.WorkerHelper, queue: "activity_expiration" - - @impl Oban.Worker - def perform( - %{ - "op" => "activity_expiration", - "activity_expiration_id" => activity_expiration_id - }, - _job - ) do - Pleroma.Daemons.ActivityExpirationDaemon.perform(:execute, activity_expiration_id) - end -end diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex index 323a4da1e..ac2fe6946 100644 --- a/lib/pleroma/workers/background_worker.ex +++ b/lib/pleroma/workers/background_worker.ex @@ -6,7 +6,6 @@ defmodule Pleroma.Workers.BackgroundWorker do alias Pleroma.Activity alias Pleroma.User alias Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy - alias Pleroma.Web.OAuth.Token.CleanWorker use Pleroma.Workers.WorkerHelper, queue: "background" @@ -55,10 +54,6 @@ def perform( User.perform(:follow_import, follower, followed_identifiers) end - def perform(%{"op" => "clean_expired_tokens"}, _job) do - CleanWorker.perform(:clean) - end - def perform(%{"op" => "media_proxy_preload", "message" => message}, _job) do MediaProxyWarmingPolicy.perform(:preload, message) end diff --git a/lib/pleroma/workers/cron/clear_oauth_token_worker.ex b/lib/pleroma/workers/cron/clear_oauth_token_worker.ex new file mode 100644 index 000000000..a24407874 --- /dev/null +++ b/lib/pleroma/workers/cron/clear_oauth_token_worker.ex @@ -0,0 +1,21 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Cron.ClearOauthTokenWorker do + @moduledoc """ + The worker to cleanup expired oAuth tokens. + """ + + use Oban.Worker, queue: "background" + + alias Pleroma.Config + alias Pleroma.Web.OAuth.Token + + @impl Oban.Worker + def perform(_opts, _job) do + if Config.get([:oauth2, :clean_expired_tokens], false) do + Token.delete_expired_tokens() + end + end +end diff --git a/lib/pleroma/workers/cron/digest_emails_worker.ex b/lib/pleroma/workers/cron/digest_emails_worker.ex new file mode 100644 index 000000000..0a00129df --- /dev/null +++ b/lib/pleroma/workers/cron/digest_emails_worker.ex @@ -0,0 +1,58 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Cron.DigestEmailsWorker do + @moduledoc """ + The worker to send digest emails. + """ + + use Oban.Worker, queue: "digest_emails" + + alias Pleroma.Config + alias Pleroma.Emails + alias Pleroma.Repo + alias Pleroma.User + + import Ecto.Query + + require Logger + + @impl Oban.Worker + def perform(_opts, _job) do + config = Config.get([:email_notifications, :digest]) + + if config[:active] do + negative_interval = -Map.fetch!(config, :interval) + inactivity_threshold = Map.fetch!(config, :inactivity_threshold) + inactive_users_query = User.list_inactive_users_query(inactivity_threshold) + + now = NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second) + + from(u in inactive_users_query, + where: fragment(~s(? ->'digest' @> 'true'), u.email_notifications), + where: u.last_digest_emailed_at < datetime_add(^now, ^negative_interval, "day"), + select: u + ) + |> Repo.all() + |> send_emails + end + end + + def send_emails(users) do + Enum.each(users, &send_email/1) + end + + @doc """ + Send digest email to the given user. + Updates `last_digest_emailed_at` field for the user and returns the updated user. + """ + @spec send_email(User.t()) :: User.t() + def send_email(user) do + with %Swoosh.Email{} = email <- Emails.UserEmail.digest_email(user) do + Emails.Mailer.deliver_async(email) + end + + User.touch_last_digest_emailed_at(user) + end +end diff --git a/lib/pleroma/workers/cron/new_users_digest_worker.ex b/lib/pleroma/workers/cron/new_users_digest_worker.ex new file mode 100644 index 000000000..951c2c054 --- /dev/null +++ b/lib/pleroma/workers/cron/new_users_digest_worker.ex @@ -0,0 +1,60 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Cron.NewUsersDigestWorker do + alias Pleroma.Activity + alias Pleroma.Repo + alias Pleroma.User + + import Ecto.Query + + use Pleroma.Workers.WorkerHelper, queue: "new_users_digest" + + @impl Oban.Worker + def perform(_args, _job) do + if Pleroma.Config.get([Pleroma.Emails.NewUsersDigestEmail, :enabled]) do + today = NaiveDateTime.utc_now() |> Timex.beginning_of_day() + + a_day_ago = + today + |> Timex.shift(days: -1) + |> Timex.beginning_of_day() + + users_and_statuses = + %{ + local: true, + order_by: :inserted_at + } + |> User.Query.build() + |> where([u], u.inserted_at >= ^a_day_ago and u.inserted_at < ^today) + |> Repo.all() + |> Enum.map(fn user -> + latest_status = + Activity + |> Activity.Queries.by_actor(user.ap_id) + |> Activity.Queries.by_type("Create") + |> Activity.with_preloaded_object() + |> order_by(desc: :inserted_at) + |> limit(1) + |> Repo.one() + + total_statuses = + Activity + |> Activity.Queries.by_actor(user.ap_id) + |> Activity.Queries.by_type("Create") + |> Repo.aggregate(:count, :id) + + {user, total_statuses, latest_status} + end) + + if users_and_statuses != [] do + %{is_admin: true} + |> User.Query.build() + |> Repo.all() + |> Enum.map(&Pleroma.Emails.NewUsersDigestEmail.new_users(&1, users_and_statuses)) + |> Enum.each(&Pleroma.Emails.Mailer.deliver/1) + end + end + end +end diff --git a/lib/pleroma/workers/cron/purge_expired_activities_worker.ex b/lib/pleroma/workers/cron/purge_expired_activities_worker.ex new file mode 100644 index 000000000..7a52860a9 --- /dev/null +++ b/lib/pleroma/workers/cron/purge_expired_activities_worker.ex @@ -0,0 +1,46 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker do + @moduledoc """ + The worker to purge expired activities. + """ + + use Oban.Worker, queue: "activity_expiration" + + alias Pleroma.Activity + alias Pleroma.ActivityExpiration + alias Pleroma.Config + alias Pleroma.User + alias Pleroma.Web.CommonAPI + + require Logger + + @interval :timer.minutes(1) + + @impl Oban.Worker + def perform(_opts, _job) do + if Config.get([ActivityExpiration, :enabled]) do + Enum.each(ActivityExpiration.due_expirations(@interval), &delete_activity/1) + end + end + + def delete_activity(%ActivityExpiration{activity_id: activity_id}) do + with {:activity, %Activity{} = activity} <- + {:activity, Activity.get_by_id_with_object(activity_id)}, + {:user, %User{} = user} <- {:user, User.get_by_ap_id(activity.object.data["actor"])} do + CommonAPI.delete(activity.id, user) + else + {:activity, _} -> + Logger.error( + "#{__MODULE__} Couldn't delete expired activity: not found activity ##{activity_id}" + ) + + {:user, _} -> + Logger.error( + "#{__MODULE__} Couldn't delete expired activity: not found actorof ##{activity_id}" + ) + end + end +end diff --git a/lib/pleroma/workers/cron/stats_worker.ex b/lib/pleroma/workers/cron/stats_worker.ex new file mode 100644 index 000000000..425ad41ca --- /dev/null +++ b/lib/pleroma/workers/cron/stats_worker.ex @@ -0,0 +1,16 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Cron.StatsWorker do + @moduledoc """ + The worker to update peers statistics. + """ + + use Oban.Worker, queue: "background" + + @impl Oban.Worker + def perform(_opts, _job) do + Pleroma.Stats.do_collect() + end +end diff --git a/lib/pleroma/workers/digest_emails_worker.ex b/lib/pleroma/workers/digest_emails_worker.ex deleted file mode 100644 index 3e5a836d0..000000000 --- a/lib/pleroma/workers/digest_emails_worker.ex +++ /dev/null @@ -1,16 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Workers.DigestEmailsWorker do - alias Pleroma.User - - use Pleroma.Workers.WorkerHelper, queue: "digest_emails" - - @impl Oban.Worker - def perform(%{"op" => "digest_email", "user_id" => user_id}, _job) do - user_id - |> User.get_cached_by_id() - |> Pleroma.Daemons.DigestEmailDaemon.perform() - end -end diff --git a/lib/pleroma/workers/scheduled_activity_worker.ex b/lib/pleroma/workers/scheduled_activity_worker.ex index ca7d53af1..bd41ab4ce 100644 --- a/lib/pleroma/workers/scheduled_activity_worker.ex +++ b/lib/pleroma/workers/scheduled_activity_worker.ex @@ -3,10 +3,42 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Workers.ScheduledActivityWorker do + @moduledoc """ + The worker to post scheduled activity. + """ + use Pleroma.Workers.WorkerHelper, queue: "scheduled_activities" + alias Pleroma.Config + alias Pleroma.ScheduledActivity + alias Pleroma.User + alias Pleroma.Web.CommonAPI + + require Logger + @impl Oban.Worker - def perform(%{"op" => "execute", "activity_id" => activity_id}, _job) do - Pleroma.Daemons.ScheduledActivityDaemon.perform(:execute, activity_id) + def perform(%{"activity_id" => activity_id}, _job) do + if Config.get([ScheduledActivity, :enabled]) do + case Pleroma.Repo.get(ScheduledActivity, activity_id) do + %ScheduledActivity{} = scheduled_activity -> + post_activity(scheduled_activity) + + _ -> + Logger.error("#{__MODULE__} Couldn't find scheduled activity: #{activity_id}") + end + end + end + + defp post_activity(%ScheduledActivity{user_id: user_id, params: params} = scheduled_activity) do + with {:delete, {:ok, _}} <- {:delete, ScheduledActivity.delete(scheduled_activity)}, + {:user, %User{} = user} <- {:user, User.get_cached_by_id(user_id)}, + {:post, {:ok, _}} <- {:post, CommonAPI.post(user, params)} do + :ok + else + error -> + Logger.error( + "#{__MODULE__} Couldn't create a status from the scheduled activity: #{inspect(error)}" + ) + end end end diff --git a/mix.exs b/mix.exs index f6794f126..24f183472 100644 --- a/mix.exs +++ b/mix.exs @@ -63,7 +63,7 @@ def copy_nginx_config(%{path: target_path} = release) do def application do [ mod: {Pleroma.Application, []}, - extra_applications: [:logger, :runtime_tools, :comeonin, :quack, :fast_sanitize, :swarm], + extra_applications: [:logger, :runtime_tools, :comeonin, :quack, :fast_sanitize], included_applications: [:ex_syslogger] ] end @@ -108,8 +108,7 @@ defp deps do {:ecto_enum, "~> 1.4"}, {:ecto_sql, "~> 3.3.2"}, {:postgrex, ">= 0.13.5"}, - {:oban, "~> 0.12.0"}, - {:quantum, "~> 2.3"}, + {:oban, "~> 0.12.1"}, {:gettext, "~> 0.15"}, {:comeonin, "~> 4.1.1"}, {:pbkdf2_elixir, "~> 0.12.3"}, @@ -140,8 +139,8 @@ defp deps do {:phoenix_swoosh, "~> 0.2"}, {:gen_smtp, "~> 0.13"}, {:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test}, - {:floki, "~> 0.23.0"}, - {:ex_syslogger, github: "slashmili/ex_syslogger", tag: "1.4.0"}, + {:ex_syslogger, "~> 1.4"}, + {:floki, "~> 0.25"}, {:timex, "~> 3.5"}, {:ueberauth, "~> 0.4"}, {:auto_linker, @@ -156,14 +155,14 @@ defp deps do {:prometheus_plugs, "~> 1.1"}, {:prometheus_phoenix, "~> 1.3"}, {:prometheus_ecto, "~> 1.4"}, - {:recon, github: "ferd/recon", tag: "2.4.0"}, + {:recon, "~> 2.5"}, {:quack, "~> 0.1.1"}, {:joken, "~> 2.0"}, {:benchee, "~> 1.0"}, {:esshd, "~> 0.1.0", runtime: Application.get_env(:esshd, :enabled, false)}, {:ex_const, "~> 0.2"}, {:plug_static_index_html, "~> 1.0.0"}, - {:excoveralls, "~> 0.11.1", only: :test}, + {:excoveralls, "~> 0.12.1", only: :test}, {:flake_id, "~> 0.1.0"}, {:remote_ip, git: "https://git.pleroma.social/pleroma/remote_ip.git", diff --git a/mix.lock b/mix.lock index 6ef9d5c33..5a667055f 100644 --- a/mix.lock +++ b/mix.lock @@ -1,113 +1,110 @@ %{ - "accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm"}, + "accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm", "11b18c220bcc2eab63b5470c038ef10eb6783bcb1fcdb11aa4137defa5ac1bb8"}, "auto_linker": {:git, "https://git.pleroma.social/pleroma/auto_linker.git", "95e8188490e97505c56636c1379ffdf036c1fdde", [ref: "95e8188490e97505c56636c1379ffdf036c1fdde"]}, - "base62": {:hex, :base62, "1.2.1", "4866763e08555a7b3917064e9eef9194c41667276c51b59de2bc42c6ea65f806", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm"}, + "base62": {:hex, :base62, "1.2.1", "4866763e08555a7b3917064e9eef9194c41667276c51b59de2bc42c6ea65f806", [:mix], [{:custom_base, "~> 0.2.1", [hex: :custom_base, repo: "hexpm", optional: false]}], "hexpm", "3b29948de2013d3f93aa898c884a9dff847e7aec75d9d6d8c1dc4c61c2716c42"}, "base64url": {:hex, :base64url, "0.0.1", "36a90125f5948e3afd7be97662a1504b934dd5dac78451ca6e9abf85a10286be", [:rebar], [], "hexpm"}, - "bbcode": {:hex, :bbcode, "0.1.1", "0023e2c7814119b2e620b7add67182e3f6019f92bfec9a22da7e99821aceba70", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, - "benchee": {:hex, :benchee, "1.0.1", "66b211f9bfd84bd97e6d1beaddf8fc2312aaabe192f776e8931cb0c16f53a521", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}], "hexpm"}, - "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"}, - "cachex": {:hex, :cachex, "3.0.3", "4e2d3e05814a5738f5ff3903151d5c25636d72a3527251b753f501ad9c657967", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm"}, - "calendar": {:hex, :calendar, "0.17.6", "ec291cb2e4ba499c2e8c0ef5f4ace974e2f9d02ae9e807e711a9b0c7850b9aee", [:mix], [{:tzdata, "~> 0.5.20 or ~> 0.1.201603 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, + "bbcode": {:hex, :bbcode, "0.1.1", "0023e2c7814119b2e620b7add67182e3f6019f92bfec9a22da7e99821aceba70", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5a981b98ac7d366a9b6bf40eac389aaf4d6e623c631e6b6f8a6b571efaafd338"}, + "benchee": {:hex, :benchee, "1.0.1", "66b211f9bfd84bd97e6d1beaddf8fc2312aaabe192f776e8931cb0c16f53a521", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}], "hexpm", "3ad58ae787e9c7c94dd7ceda3b587ec2c64604563e049b2a0e8baafae832addb"}, + "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, + "cachex": {:hex, :cachex, "3.0.3", "4e2d3e05814a5738f5ff3903151d5c25636d72a3527251b753f501ad9c657967", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "3aadb1e605747122f60aa7b0b121cca23c14868558157563b3f3e19ea929f7d0"}, + "calendar": {:hex, :calendar, "0.17.6", "ec291cb2e4ba499c2e8c0ef5f4ace974e2f9d02ae9e807e711a9b0c7850b9aee", [:mix], [{:tzdata, "~> 0.5.20 or ~> 0.1.201603 or ~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "738d0e17a93c2ccfe4ddc707bdc8e672e9074c8569498483feb1c4530fb91b2b"}, "captcha": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/elixir-captcha.git", "e0f16822d578866e186a0974d65ad58cddc1e2ab", [ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"]}, - "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, - "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"}, - "comeonin": {:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm"}, - "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"}, - "cors_plug": {:hex, :cors_plug, "1.5.2", "72df63c87e4f94112f458ce9d25800900cc88608c1078f0e4faddf20933eda6e", [:mix], [{:plug, "~> 1.3 or ~> 1.4 or ~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"}, - "cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm"}, - "credo": {:hex, :credo, "1.1.5", "caec7a3cadd2e58609d7ee25b3931b129e739e070539ad1a0cd7efeeb47014f4", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, + "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "805abd97539caf89ec6d4732c91e62ba9da0cda51ac462380bbd28ee697a8c42"}, + "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, + "comeonin": {:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm", "d8700a0ca4dbb616c22c9b3f6dd539d88deaafec3efe66869d6370c9a559b3e9"}, + "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"}, + "cors_plug": {:hex, :cors_plug, "1.5.2", "72df63c87e4f94112f458ce9d25800900cc88608c1078f0e4faddf20933eda6e", [:mix], [{:plug, "~> 1.3 or ~> 1.4 or ~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "9af027d20dc12dd0c4345a6b87247e0c62965871feea0bfecf9764648b02cc69"}, + "cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "04fd8c6a39edc6aaa9c26123009200fc61f92a3a94f3178c527b70b767c6e605"}, + "cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm", "79f954a7021b302186a950a32869dbc185523d99d3e44ce430cd1f3289f41ed4"}, + "credo": {:hex, :credo, "1.1.5", "caec7a3cadd2e58609d7ee25b3931b129e739e070539ad1a0cd7efeeb47014f4", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d0bbd3222607ccaaac5c0340f7f525c627ae4d7aee6c8c8c108922620c5b6446"}, "crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, "crypt": {:git, "https://github.com/msantos/crypt", "1f2b58927ab57e72910191a7ebaeff984382a1d3", [ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"]}, - "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm"}, - "db_connection": {:hex, :db_connection, "2.2.0", "e923e88887cd60f9891fd324ac5e0290954511d090553c415fbf54be4c57ee63", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"}, - "decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm"}, - "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm"}, - "earmark": {:hex, :earmark, "1.4.2", "3aa0bd23bc4c61cf2f1e5d752d1bb470560a6f8539974f767a38923bb20e1d7f", [:mix], [], "hexpm"}, - "ecto": {:hex, :ecto, "3.3.1", "82ab74298065bf0c64ca299f6c6785e68ea5d6b980883ee80b044499df35aba1", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, - "ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm"}, - "ecto_sql": {:hex, :ecto_sql, "3.3.2", "92804e0de69bb63e621273c3492252cb08a29475c05d40eeb6f41ad2d483cfd3", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, - "esshd": {:hex, :esshd, "0.1.0", "6f93a2062adb43637edad0ea7357db2702a4b80dd9683482fe00f5134e97f4c1", [:mix], [], "hexpm"}, - "eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm"}, + "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"}, + "db_connection": {:hex, :db_connection, "2.2.1", "caee17725495f5129cb7faebde001dc4406796f12a62b8949f4ac69315080566", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"}, + "decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"}, + "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, + "earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm"}, + "ecto": {:hex, :ecto, "3.3.3", "0830bf3aebcbf3d8c1a1811cd581773b6866886c012f52c0f027031fa96a0b53", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, + "ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"}, + "ecto_sql": {:hex, :ecto_sql, "3.3.4", "aa18af12eb875fbcda2f75e608b3bd534ebf020fc4f6448e4672fcdcbb081244", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4 or ~> 3.3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, + "esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm"}, + "eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"}, "ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"}, - "ex_aws": {:hex, :ex_aws, "2.1.1", "1e4de2106cfbf4e837de41be41cd15813eabc722315e388f0d6bb3732cec47cd", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1 or 1.8.6 or ~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"}, - "ex_aws_s3": {:hex, :ex_aws_s3, "2.0.2", "c0258bbdfea55de4f98f0b2f0ca61fe402cc696f573815134beb1866e778f47b", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"}, - "ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm"}, - "ex_doc": {:hex, :ex_doc, "0.21.2", "caca5bc28ed7b3bdc0b662f8afe2bee1eedb5c3cf7b322feeeb7c6ebbde089d6", [:mix], [{:earmark, "~> 1.3.3 or ~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, - "ex_machina": {:hex, :ex_machina, "2.3.0", "92a5ad0a8b10ea6314b876a99c8c9e3f25f4dde71a2a835845b136b9adaf199a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"}, - "ex_syslogger": {:git, "https://github.com/slashmili/ex_syslogger.git", "f3963399047af17e038897c69e20d552e6899e1d", [tag: "1.4.0"]}, - "excoveralls": {:hex, :excoveralls, "0.11.2", "0c6f2c8db7683b0caa9d490fb8125709c54580b4255ffa7ad35f3264b075a643", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, - "fast_html": {:hex, :fast_html, "1.0.1", "5bc7df4dc4607ec2c314c16414e4111d79a209956c4f5df96602d194c61197f9", [:make, :mix], [], "hexpm"}, - "fast_sanitize": {:hex, :fast_sanitize, "0.1.6", "60a5ae96879956dea409a91a77f5dd2994c24cc10f80eefd8f9892ee4c0c7b25", [:mix], [{:fast_html, "~> 1.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"}, - "floki": {:hex, :floki, "0.23.1", "e100306ce7d8841d70a559748e5091542e2cfc67ffb3ade92b89a8435034dab1", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm"}, - "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm"}, + "ex_aws": {:hex, :ex_aws, "2.1.1", "1e4de2106cfbf4e837de41be41cd15813eabc722315e388f0d6bb3732cec47cd", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1 or 1.8.6 or ~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "06b6fde12b33bb6d65d5d3493e903ba5a56d57a72350c15285a4298338089e10"}, + "ex_aws_s3": {:hex, :ex_aws_s3, "2.0.2", "c0258bbdfea55de4f98f0b2f0ca61fe402cc696f573815134beb1866e778f47b", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "0569f5b211b1a3b12b705fe2a9d0e237eb1360b9d76298028df2346cad13097a"}, + "ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm", "96fd346610cc992b8f896ed26a98be82ac4efb065a0578f334a32d60a3ba9767"}, + "ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, + "ex_machina": {:hex, :ex_machina, "2.3.0", "92a5ad0a8b10ea6314b876a99c8c9e3f25f4dde71a2a835845b136b9adaf199a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "b84f6af156264530b312a8ab98ac6088f6b77ae5fe2058305c81434aa01fbaf9"}, + "ex_syslogger": {:hex, :ex_syslogger, "1.5.0", "bc936ee3fd13d9e592cb4c3a1e8a55fccd33b05e3aa7b185f211f3ed263ff8f0", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.0.5", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm"}, + "excoveralls": {:hex, :excoveralls, "0.12.2", "a513defac45c59e310ac42fcf2b8ae96f1f85746410f30b1ff2b710a4b6cd44b", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, + "fast_html": {:hex, :fast_html, "1.0.3", "2cc0d4b68496266a1530e0c852cafeaede0bd10cfdee26fda50dc696c203162f", [:make, :mix], [], "hexpm", "ab3d782b639d3c4655fbaec0f9d032c91f8cab8dd791ac7469c2381bc7c32f85"}, + "fast_sanitize": {:hex, :fast_sanitize, "0.1.7", "2a7cd8734c88a2de6de55022104f8a3b87f1fdbe8bbf131d9049764b53d50d0d", [:mix], [{:fast_html, "~> 1.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f39fe8ea08fbac17487c30bf09b7d9f3e12472e51fb07a88ffeb8fd17da8ab67"}, + "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"}, + "floki": {:hex, :floki, "0.25.0", "b1c9ddf5f32a3a90b43b76f3386ca054325dc2478af020e87b5111c19f2284ac", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm"}, + "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"}, "gen_stage": {:hex, :gen_stage, "0.14.3", "d0c66f1c87faa301c1a85a809a3ee9097a4264b2edf7644bf5c123237ef732bf", [:mix], [], "hexpm"}, "gen_state_machine": {:hex, :gen_state_machine, "2.0.5", "9ac15ec6e66acac994cc442dcc2c6f9796cf380ec4b08267223014be1c728a95", [:mix], [], "hexpm"}, - "gettext": {:hex, :gettext, "0.17.1", "8baab33482df4907b3eae22f719da492cee3981a26e649b9c2be1c0192616962", [:mix], [], "hexpm"}, - "hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, - "html_entities": {:hex, :html_entities, "0.5.0", "40f5c5b9cbe23073b48a4e69c67b6c11974f623a76165e2b92d098c0e88ccb1d", [:mix], [], "hexpm"}, + "gettext": {:hex, :gettext, "0.17.4", "f13088e1ec10ce01665cf25f5ff779e7df3f2dc71b37084976cf89d1aa124d5c", [:mix], [], "hexpm"}, + "hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "e0100f8ef7d1124222c11ad362c857d3df7cb5f4204054f9f0f4a728666591fc"}, + "html_entities": {:hex, :html_entities, "0.5.1", "1c9715058b42c35a2ab65edc5b36d0ea66dd083767bef6e3edb57870ef556549", [:mix], [], "hexpm"}, "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"}, "http_signatures": {:git, "https://git.pleroma.social/pleroma/http_signatures.git", "293d77bb6f4a67ac8bde1428735c3b42f22cbb30", [ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"]}, - "httpoison": {:hex, :httpoison, "1.6.1", "2ce5bf6e535cd0ab02e905ba8c276580bab80052c5c549f53ddea52d72e81f33", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, - "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, - "inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm"}, - "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, - "joken": {:hex, :joken, "2.1.0", "bf21a73105d82649f617c5e59a7f8919aa47013d2519ebcc39d998d8d12adda9", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm"}, - "jose": {:hex, :jose, "1.9.0", "4167c5f6d06ffaebffd15cdb8da61a108445ef5e85ab8f5a7ad926fdf3ada154", [:mix, :rebar3], [{:base64url, "~> 0.0.1", [hex: :base64url, repo: "hexpm", optional: false]}], "hexpm"}, + "httpoison": {:hex, :httpoison, "1.6.2", "ace7c8d3a361cebccbed19c283c349b3d26991eff73a1eaaa8abae2e3c8089b6", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, + "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"}, + "inet_cidr": {:hex, :inet_cidr, "1.0.4", "a05744ab7c221ca8e395c926c3919a821eb512e8f36547c062f62c4ca0cf3d6e", [:mix], [], "hexpm", "64a2d30189704ae41ca7dbdd587f5291db5d1dda1414e0774c29ffc81088c1bc"}, + "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fdf843bca858203ae1de16da2ee206f53416bbda5dc8c9e78f43243de4bc3afe"}, + "joken": {:hex, :joken, "2.2.0", "2daa1b12be05184aff7b5ace1d43ca1f81345962285fff3f88db74927c954d3a", [:mix], [{:jose, "~> 1.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm"}, + "jose": {:hex, :jose, "1.10.1", "16d8e460dae7203c6d1efa3f277e25b5af8b659febfc2f2eb4bacf87f128b80a", [:mix, :rebar3], [], "hexpm"}, "libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"}, - "makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, - "meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm"}, - "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"}, - "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"}, - "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"}, + "makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "a10c6eb62cca416019663129699769f0c2ccf39428b3bb3c0cb38c718a0c186d"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"}, + "meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm", "d34f013c156db51ad57cc556891b9720e6a1c1df5fe2e15af999c84d6cebeb1a"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, + "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm", "6cbe761d6a0ca5a31a0931bf4c63204bceb64538e664a8ecf784a9a6f3b875f1"}, + "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"}, - "mock": {:hex, :mock, "0.3.4", "c5862eb3b8c64237f45f586cf00c9d892ba07bb48305a43319d428ce3c2897dd", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"}, - "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm"}, - "mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm"}, - "mrfcontrib": {:git, "https://github.com/FloatingGhost/pleroma-mrf-contrib.git", "8cecf964b6f9686ab11687e8267bc238a19bd3b6", [tag: "v0.0.5"]}, + "mock": {:hex, :mock, "0.3.4", "c5862eb3b8c64237f45f586cf00c9d892ba07bb48305a43319d428ce3c2897dd", [:mix], [{:meck, "~> 0.8.13", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "e6d886252f1a41f4ba06ecf2b4c8d38760b34b1c08a11c28f7397b2e03995964"}, + "mogrify": {:hex, :mogrify, "0.6.1", "de1b527514f2d95a7bbe9642eb556061afb337e220cf97adbf3a4e6438ed70af", [:mix], [], "hexpm", "3bc928d817974fa10cc11e6c89b9a9361e37e96dbbf3d868c41094ec05745dcd"}, + "mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm", "052346cf322311c49a0f22789f3698eea030eec09b8c47367f0686ef2634ae14"}, "myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]}, - "nimble_parsec": {:hex, :nimble_parsec, "0.5.1", "c90796ecee0289dbb5ad16d3ad06f957b0cd1199769641c961cfe0b97db190e0", [:mix], [], "hexpm"}, + "nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm"}, "nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]}, - "oban": {:hex, :oban, "0.12.1", "695e9490c6e0edfca616d80639528e448bd29b3bff7b7dd10a56c79b00a5d7fb", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, - "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, - "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm"}, - "phoenix": {:hex, :phoenix, "1.4.10", "619e4a545505f562cd294df52294372d012823f4fd9d34a6657a8b242898c255", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, - "phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "phoenix_html": {:hex, :phoenix_html, "2.13.3", "850e292ff6e204257f5f9c4c54a8cb1f6fbc16ed53d360c2b780a3d0ba333867", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"}, - "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.2.0", "a7e0b32077cd6d2323ae15198839b05d9caddfa20663fd85787479e81f89520e", [:mix], [{:phoenix, "~> 1.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.2", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 0.1", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm"}, - "plug": {:hex, :plug, "1.9.0", "8d7c4e26962283ff9f8f3347bd73838e2413fbc38b7bb5467d5924f68f3a5a4a", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.1.0", "b75768153c3a8a9e8039d4b25bb9b14efbc58e9c4a6e6a270abff1cd30cbe320", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, - "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, - "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm"}, - "postgrex": {:hex, :postgrex, "0.15.3", "5806baa8a19a68c4d07c7a624ccdb9b57e89cbc573f1b98099e3741214746ae4", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, - "prometheus": {:hex, :prometheus, "4.4.1", "1e96073b3ed7788053768fea779cbc896ddc3bdd9ba60687f2ad50b252ac87d6", [:mix, :rebar3], [], "hexpm"}, - "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, - "prometheus_ex": {:hex, :prometheus_ex, "3.0.5", "fa58cfd983487fc5ead331e9a3e0aa622c67232b3ec71710ced122c4c453a02f", [:mix], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm"}, - "prometheus_phoenix": {:hex, :prometheus_phoenix, "1.3.0", "c4b527e0b3a9ef1af26bdcfbfad3998f37795b9185d475ca610fe4388fdd3bb5", [:mix], [{:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm"}, - "prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm"}, - "quack": {:hex, :quack, "0.1.1", "cca7b4da1a233757fdb44b3334fce80c94785b3ad5a602053b7a002b5a8967bf", [:mix], [{:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: false]}, {:tesla, "~> 1.2.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm"}, - "quantum": {:hex, :quantum, "2.3.4", "72a0e8855e2adc101459eac8454787cb74ab4169de6ca50f670e72142d4960e9", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}], "hexpm"}, - "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, - "recon": {:git, "https://github.com/ferd/recon.git", "75d70c7c08926d2f24f1ee6de14ee50fe8a52763", [tag: "2.4.0"]}, + "oban": {:hex, :oban, "0.12.1", "695e9490c6e0edfca616d80639528e448bd29b3bff7b7dd10a56c79b00a5d7fb", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c1d58d69b8b5a86e7167abbb8cc92764a66f25f12f6172052595067fc6a30a17"}, + "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"}, + "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "0.12.4", "8dd29ed783f2e12195d7e0a4640effc0a7c37e6537da491f1db01839eee6d053", [:mix], [], "hexpm", "595d09db74cb093b1903381c9de423276a931a2480a46a1a5dc7f932a2a6375b"}, + "phoenix": {:hex, :phoenix, "1.4.13", "67271ad69b51f3719354604f4a3f968f83aa61c19199343656c9caee057ff3b8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, + "phoenix_ecto": {:hex, :phoenix_ecto, "4.1.0", "a044d0756d0464c5a541b4a0bf4bcaf89bffcaf92468862408290682c73ae50d", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, + "phoenix_html": {:hex, :phoenix_html, "2.14.0", "d8c6bc28acc8e65f8ea0080ee05aa13d912c8758699283b8d3427b655aabe284", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm", "1f13f9f0f3e769a667a6b6828d29dec37497a082d195cc52dbef401a9b69bf38"}, + "phoenix_swoosh": {:hex, :phoenix_swoosh, "0.2.0", "a7e0b32077cd6d2323ae15198839b05d9caddfa20663fd85787479e81f89520e", [:mix], [{:phoenix, "~> 1.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.2", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:swoosh, "~> 0.1", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "ebf1bfa7b3c1c850c04929afe02e2e0d7ab135e0706332c865de03e761676b1f"}, + "plug": {:hex, :plug, "1.9.0", "8d7c4e26962283ff9f8f3347bd73838e2413fbc38b7bb5467d5924f68f3a5a4a", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "9902eda2c52ada2a096434682e99a2493f5d06a94d6ac6bcfff9805f952350f1"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.1.2", "8b0addb5908c5238fac38e442e81b6fcd32788eaa03246b4d55d147c47c5805e", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, + "plug_crypto": {:hex, :plug_crypto, "1.1.2", "bdd187572cc26dbd95b87136290425f2b580a116d3fb1f564216918c9730d227", [:mix], [], "hexpm"}, + "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"}, + "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"}, + "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"}, + "postgrex": {:hex, :postgrex, "0.15.3", "5806baa8a19a68c4d07c7a624ccdb9b57e89cbc573f1b98099e3741214746ae4", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "4737ce62a31747b4c63c12b20c62307e51bb4fcd730ca0c32c280991e0606c90"}, + "prometheus": {:hex, :prometheus, "4.5.0", "8f4a2246fe0beb50af0f77c5e0a5bb78fe575c34a9655d7f8bc743aad1c6bf76", [:mix, :rebar3], [], "hexpm"}, + "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "8d66289f77f913b37eda81fd287340c17e61a447549deb28efc254532b2bed82"}, + "prometheus_ex": {:hex, :prometheus_ex, "3.0.5", "fa58cfd983487fc5ead331e9a3e0aa622c67232b3ec71710ced122c4c453a02f", [:mix], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm", "9fd13404a48437e044b288b41f76e64acd9735fb8b0e3809f494811dfa66d0fb"}, + "prometheus_phoenix": {:hex, :prometheus_phoenix, "1.3.0", "c4b527e0b3a9ef1af26bdcfbfad3998f37795b9185d475ca610fe4388fdd3bb5", [:mix], [{:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "c4d1404ac4e9d3d963da601db2a7d8ea31194f0017057fabf0cfb9bf5a6c8c75"}, + "prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm", "0273a6483ccb936d79ca19b0ab629aef0dba958697c94782bb728b920dfc6a79"}, + "quack": {:hex, :quack, "0.1.1", "cca7b4da1a233757fdb44b3334fce80c94785b3ad5a602053b7a002b5a8967bf", [:mix], [{:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: false]}, {:tesla, "~> 1.2.0", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "d736bfa7444112eb840027bb887832a0e403a4a3437f48028c3b29a2dbbd2543"}, + "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"}, + "recon": {:hex, :recon, "2.5.0", "2f7fcbec2c35034bade2f9717f77059dc54eb4e929a3049ca7ba6775c0bd66cd", [:mix, :rebar3], [], "hexpm"}, "remote_ip": {:git, "https://git.pleroma.social/pleroma/remote_ip.git", "825dc00aaba5a1b7c4202a532b696b595dd3bcb3", [ref: "825dc00aaba5a1b7c4202a532b696b595dd3bcb3"]}, - "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"}, - "swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm"}, - "sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm"}, - "swoosh": {:hex, :swoosh, "0.23.5", "bfd9404bbf5069b1be2ffd317923ce57e58b332e25dbca2a35dedd7820dfee5a", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"}, - "syslog": {:git, "https://github.com/Vagabond/erlang-syslog.git", "4a6c6f2c996483e86c1320e9553f91d337bcb6aa", [tag: "1.0.5"]}, - "telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm"}, - "tesla": {:hex, :tesla, "1.3.0", "f35d72f029e608f9cdc6f6d6fcc7c66cf6d6512a70cfef9206b21b8bd0203a30", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 0.4", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"}, - "timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, - "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "tzdata": {:hex, :tzdata, "0.5.22", "f2ba9105117ee0360eae2eca389783ef7db36d533899b2e84559404dbc77ebb8", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, - "ueberauth": {:hex, :ueberauth, "0.6.2", "25a31111249d60bad8b65438b2306a4dc91f3208faa62f5a8c33e8713989b2e8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"}, - "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm"}, - "web_push_encryption": {:hex, :web_push_encryption, "0.2.3", "a0ceab85a805a30852f143d22d71c434046fbdbafbc7292e7887cec500826a80", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:poison, "~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"}, + "sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm", "2e1ec458f892ffa81f9f8386e3f35a1af6db7a7a37748a64478f13163a1f3573"}, + "swoosh": {:hex, :swoosh, "0.23.5", "bfd9404bbf5069b1be2ffd317923ce57e58b332e25dbca2a35dedd7820dfee5a", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "e3928e1d2889a308aaf3e42755809ac21cffd77cb58eef01cbfdab4ce2fd1e21"}, + "syslog": {:hex, :syslog, "1.0.6", "995970c9aa7feb380ac493302138e308d6e04fd57da95b439a6df5bb3bf75076", [:rebar3], [], "hexpm"}, + "telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm", "4738382e36a0a9a2b6e25d67c960e40e1a2c95560b9f936d8e29de8cd858480f"}, + "tesla": {:hex, :tesla, "1.3.2", "deb92c5c9ce35e747a395ba413ca78593a4f75bf0e1545630ee2e3d34264021e", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"}, + "timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "f354efb2400dd7a80fd9eb6c8419068c4f632da4ac47f3d8822d6e33f08bc852"}, + "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"}, + "tzdata": {:hex, :tzdata, "0.5.22", "f2ba9105117ee0360eae2eca389783ef7db36d533899b2e84559404dbc77ebb8", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "cd66c8a1e6a9e121d1f538b01bef459334bb4029a1ffb4eeeb5e4eae0337e7b6"}, + "ueberauth": {:hex, :ueberauth, "0.6.2", "25a31111249d60bad8b65438b2306a4dc91f3208faa62f5a8c33e8713989b2e8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "db9fbfb5ac707bc4f85a297758406340bf0358b4af737a88113c1a9eee120ac7"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"}, + "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"}, + "web_push_encryption": {:hex, :web_push_encryption, "0.2.3", "a0ceab85a805a30852f143d22d71c434046fbdbafbc7292e7887cec500826a80", [:mix], [{:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:poison, "~> 3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm", "9315c8f37c108835cf3f8e9157d7a9b8f420a34f402d1b1620a31aed5b93ecdf"}, "websocket_client": {:git, "https://github.com/jeremyong/websocket_client.git", "9a6f65d05ebf2725d62fb19262b21f1805a59fbf", []}, } diff --git a/priv/static/adminfe/app.fdd73ce4.css b/priv/static/adminfe/app.c836e084.css similarity index 100% rename from priv/static/adminfe/app.fdd73ce4.css rename to priv/static/adminfe/app.c836e084.css diff --git a/priv/static/adminfe/chunk-06de.3abb5de7.css b/priv/static/adminfe/chunk-06de.3abb5de7.css new file mode 100644 index 000000000..4fb60b648 Binary files /dev/null and b/priv/static/adminfe/chunk-06de.3abb5de7.css differ diff --git a/priv/static/adminfe/chunk-0cc4.571d0025.css b/priv/static/adminfe/chunk-0cc4.571d0025.css deleted file mode 100644 index 8bd6a2e50..000000000 Binary files a/priv/static/adminfe/chunk-0cc4.571d0025.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-15fa.5a5f973d.css b/priv/static/adminfe/chunk-15fa.5a5f973d.css deleted file mode 100644 index 30bf7de23..000000000 Binary files a/priv/static/adminfe/chunk-15fa.5a5f973d.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-15fa.2246593e.css b/priv/static/adminfe/chunk-15fa.86ad6a40.css similarity index 100% rename from priv/static/adminfe/chunk-15fa.2246593e.css rename to priv/static/adminfe/chunk-15fa.86ad6a40.css diff --git a/priv/static/adminfe/chunk-18e1.ed715f8d.css b/priv/static/adminfe/chunk-18e1.ed715f8d.css deleted file mode 100644 index da819ca09..000000000 Binary files a/priv/static/adminfe/chunk-18e1.ed715f8d.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-20e0.ee636d82.css b/priv/static/adminfe/chunk-20e0.ee636d82.css new file mode 100644 index 000000000..567079fed Binary files /dev/null and b/priv/static/adminfe/chunk-20e0.ee636d82.css differ diff --git a/priv/static/adminfe/chunk-2aa6.8ce63ac0.css b/priv/static/adminfe/chunk-2aa6.8ce63ac0.css deleted file mode 100644 index 8bd6a2e50..000000000 Binary files a/priv/static/adminfe/chunk-2aa6.8ce63ac0.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-3d8e.48523459.css b/priv/static/adminfe/chunk-3d8e.48523459.css deleted file mode 100644 index 8eefd9493..000000000 Binary files a/priv/static/adminfe/chunk-3d8e.48523459.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-1c46.f36071a4.css b/priv/static/adminfe/chunk-48a4.1bb1db91.css similarity index 100% rename from priv/static/adminfe/chunk-1c46.f36071a4.css rename to priv/static/adminfe/chunk-48a4.1bb1db91.css diff --git a/priv/static/adminfe/chunk-4dc2.25d3bcab.css b/priv/static/adminfe/chunk-4dc2.25d3bcab.css deleted file mode 100644 index 48784b9d2..000000000 Binary files a/priv/static/adminfe/chunk-4dc2.25d3bcab.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-18e1.dd09fe2e.css b/priv/static/adminfe/chunk-51b0.55057987.css similarity index 100% rename from priv/static/adminfe/chunk-18e1.dd09fe2e.css rename to priv/static/adminfe/chunk-51b0.55057987.css diff --git a/priv/static/adminfe/chunk-645e.8bb40e00.css b/priv/static/adminfe/chunk-645e.8bb40e00.css new file mode 100644 index 000000000..0591e4930 Binary files /dev/null and b/priv/static/adminfe/chunk-645e.8bb40e00.css differ diff --git a/priv/static/adminfe/chunk-1ada.90dffac4.css b/priv/static/adminfe/chunk-6aa3.fb02ac69.css similarity index 100% rename from priv/static/adminfe/chunk-1ada.90dffac4.css rename to priv/static/adminfe/chunk-6aa3.fb02ac69.css diff --git a/priv/static/adminfe/chunk-6b7b.1ab4da3b.css b/priv/static/adminfe/chunk-6b7b.1ab4da3b.css deleted file mode 100644 index 7124c9690..000000000 Binary files a/priv/static/adminfe/chunk-6b7b.1ab4da3b.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-6e77.57276c93.css b/priv/static/adminfe/chunk-6e77.57276c93.css deleted file mode 100644 index f0b3bf144..000000000 Binary files a/priv/static/adminfe/chunk-6e77.57276c93.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-7de9.889d1da1.css b/priv/static/adminfe/chunk-7de9.889d1da1.css deleted file mode 100644 index 29f7b475d..000000000 Binary files a/priv/static/adminfe/chunk-7de9.889d1da1.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-7f83.f9f73c8e.css b/priv/static/adminfe/chunk-7f83.f9f73c8e.css deleted file mode 100644 index 29f7b475d..000000000 Binary files a/priv/static/adminfe/chunk-7f83.f9f73c8e.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-7f8e.d508c376.css b/priv/static/adminfe/chunk-7f8e.d508c376.css deleted file mode 100644 index 6cd674a28..000000000 Binary files a/priv/static/adminfe/chunk-7f8e.d508c376.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-7f8e.1d10e1c7.css b/priv/static/adminfe/chunk-7f8e.f03bd164.css similarity index 100% rename from priv/static/adminfe/chunk-7f8e.1d10e1c7.css rename to priv/static/adminfe/chunk-7f8e.f03bd164.css diff --git a/priv/static/adminfe/chunk-9bb0.2a82c722.css b/priv/static/adminfe/chunk-9bb0.2a82c722.css deleted file mode 100644 index c0074e6f7..000000000 Binary files a/priv/static/adminfe/chunk-9bb0.2a82c722.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-a601.62c86eea.css b/priv/static/adminfe/chunk-a601.62c86eea.css deleted file mode 100644 index a036b0253..000000000 Binary files a/priv/static/adminfe/chunk-a601.62c86eea.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-b4ba.e55f897a.css b/priv/static/adminfe/chunk-b4ba.e55f897a.css new file mode 100644 index 000000000..dadc5cbda Binary files /dev/null and b/priv/static/adminfe/chunk-b4ba.e55f897a.css differ diff --git a/priv/static/adminfe/chunk-bb29.61e9e8f2.css b/priv/static/adminfe/chunk-bb29.61e9e8f2.css new file mode 100644 index 000000000..bbab1c2ac Binary files /dev/null and b/priv/static/adminfe/chunk-bb29.61e9e8f2.css differ diff --git a/priv/static/adminfe/chunk-cf58.6bdb954d.css b/priv/static/adminfe/chunk-cf58.6bdb954d.css new file mode 100644 index 000000000..69fc0072a Binary files /dev/null and b/priv/static/adminfe/chunk-cf58.6bdb954d.css differ diff --git a/priv/static/adminfe/chunk-d01a.03fe0a3f.css b/priv/static/adminfe/chunk-d01a.03fe0a3f.css deleted file mode 100644 index f0b3bf144..000000000 Binary files a/priv/static/adminfe/chunk-d01a.03fe0a3f.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-f3c9.155bfc51.css b/priv/static/adminfe/chunk-f3c9.155bfc51.css deleted file mode 100644 index 1cb3e5949..000000000 Binary files a/priv/static/adminfe/chunk-f3c9.155bfc51.css and /dev/null differ diff --git a/priv/static/adminfe/chunk-libs.57fe98a3.css b/priv/static/adminfe/chunk-libs.686b5876.css similarity index 100% rename from priv/static/adminfe/chunk-libs.57fe98a3.css rename to priv/static/adminfe/chunk-libs.686b5876.css diff --git a/priv/static/adminfe/index.html b/priv/static/adminfe/index.html index e28125b5e..0b08c3290 100644 --- a/priv/static/adminfe/index.html +++ b/priv/static/adminfe/index.html @@ -1 +1 @@ -Admin FE
\ No newline at end of file +Admin FE
\ No newline at end of file diff --git a/priv/static/adminfe/static/js/app.3da0f475.js b/priv/static/adminfe/static/js/app.3da0f475.js deleted file mode 100644 index c6bd005d2..000000000 Binary files a/priv/static/adminfe/static/js/app.3da0f475.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/app.3da0f475.js.map b/priv/static/adminfe/static/js/app.3da0f475.js.map deleted file mode 100644 index 999df6709..000000000 Binary files a/priv/static/adminfe/static/js/app.3da0f475.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/app.5f0094e3.js b/priv/static/adminfe/static/js/app.5f0094e3.js new file mode 100644 index 000000000..e65b2f09c Binary files /dev/null and b/priv/static/adminfe/static/js/app.5f0094e3.js differ diff --git a/priv/static/adminfe/static/js/app.5f0094e3.js.map b/priv/static/adminfe/static/js/app.5f0094e3.js.map new file mode 100644 index 000000000..edb94a554 Binary files /dev/null and b/priv/static/adminfe/static/js/app.5f0094e3.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-06de.ff4586ab.js b/priv/static/adminfe/static/js/chunk-06de.ff4586ab.js new file mode 100644 index 000000000..c989bed18 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-06de.ff4586ab.js differ diff --git a/priv/static/adminfe/static/js/chunk-06de.ff4586ab.js.map b/priv/static/adminfe/static/js/chunk-06de.ff4586ab.js.map new file mode 100644 index 000000000..5652f3192 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-06de.ff4586ab.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-15fa.34070731.js b/priv/static/adminfe/static/js/chunk-15fa.99004e49.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-15fa.34070731.js rename to priv/static/adminfe/static/js/chunk-15fa.99004e49.js index 937908d00..5ab46f8b9 100644 Binary files a/priv/static/adminfe/static/js/chunk-15fa.34070731.js and b/priv/static/adminfe/static/js/chunk-15fa.99004e49.js differ diff --git a/priv/static/adminfe/static/js/chunk-15fa.34070731.js.map b/priv/static/adminfe/static/js/chunk-15fa.99004e49.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-15fa.34070731.js.map rename to priv/static/adminfe/static/js/chunk-15fa.99004e49.js.map index d3830be7c..f4b92260a 100644 Binary files a/priv/static/adminfe/static/js/chunk-15fa.34070731.js.map and b/priv/static/adminfe/static/js/chunk-15fa.99004e49.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-20e0.dc3e8a45.js b/priv/static/adminfe/static/js/chunk-20e0.dc3e8a45.js new file mode 100644 index 000000000..5fa5107f4 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-20e0.dc3e8a45.js differ diff --git a/priv/static/adminfe/static/js/chunk-20e0.dc3e8a45.js.map b/priv/static/adminfe/static/js/chunk-20e0.dc3e8a45.js.map new file mode 100644 index 000000000..2186ce225 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-20e0.dc3e8a45.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-2aa6.be23b313.js b/priv/static/adminfe/static/js/chunk-2aa6.be23b313.js deleted file mode 100644 index 21a0fde72..000000000 Binary files a/priv/static/adminfe/static/js/chunk-2aa6.be23b313.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-2aa6.be23b313.js.map b/priv/static/adminfe/static/js/chunk-2aa6.be23b313.js.map deleted file mode 100644 index 64ac03193..000000000 Binary files a/priv/static/adminfe/static/js/chunk-2aa6.be23b313.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-3d8e.916ea1c1.js b/priv/static/adminfe/static/js/chunk-3d8e.916ea1c1.js deleted file mode 100644 index 57831d50d..000000000 Binary files a/priv/static/adminfe/static/js/chunk-3d8e.916ea1c1.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-3d8e.916ea1c1.js.map b/priv/static/adminfe/static/js/chunk-3d8e.916ea1c1.js.map deleted file mode 100644 index a66a5fc00..000000000 Binary files a/priv/static/adminfe/static/js/chunk-3d8e.916ea1c1.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-4dc2.ec296292.js b/priv/static/adminfe/static/js/chunk-48a4.e3d2c4b6.js similarity index 98% rename from priv/static/adminfe/static/js/chunk-4dc2.ec296292.js rename to priv/static/adminfe/static/js/chunk-48a4.e3d2c4b6.js index f7cbe90c4..596384cab 100644 Binary files a/priv/static/adminfe/static/js/chunk-4dc2.ec296292.js and b/priv/static/adminfe/static/js/chunk-48a4.e3d2c4b6.js differ diff --git a/priv/static/adminfe/static/js/chunk-4dc2.ec296292.js.map b/priv/static/adminfe/static/js/chunk-48a4.e3d2c4b6.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-4dc2.ec296292.js.map rename to priv/static/adminfe/static/js/chunk-48a4.e3d2c4b6.js.map index 898961dd6..f3d7fd870 100644 Binary files a/priv/static/adminfe/static/js/chunk-4dc2.ec296292.js.map and b/priv/static/adminfe/static/js/chunk-48a4.e3d2c4b6.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-18e1.c5abe3f2.js b/priv/static/adminfe/static/js/chunk-51b0.7d1554b1.js similarity index 85% rename from priv/static/adminfe/static/js/chunk-18e1.c5abe3f2.js rename to priv/static/adminfe/static/js/chunk-51b0.7d1554b1.js index e0561aa1a..a770215ae 100644 Binary files a/priv/static/adminfe/static/js/chunk-18e1.c5abe3f2.js and b/priv/static/adminfe/static/js/chunk-51b0.7d1554b1.js differ diff --git a/priv/static/adminfe/static/js/chunk-18e1.c5abe3f2.js.map b/priv/static/adminfe/static/js/chunk-51b0.7d1554b1.js.map similarity index 98% rename from priv/static/adminfe/static/js/chunk-18e1.c5abe3f2.js.map rename to priv/static/adminfe/static/js/chunk-51b0.7d1554b1.js.map index 27f79dceb..9b8014486 100644 Binary files a/priv/static/adminfe/static/js/chunk-18e1.c5abe3f2.js.map and b/priv/static/adminfe/static/js/chunk-51b0.7d1554b1.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-645e.ad5c2109.js b/priv/static/adminfe/static/js/chunk-645e.ad5c2109.js new file mode 100644 index 000000000..1ffacd027 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-645e.ad5c2109.js differ diff --git a/priv/static/adminfe/static/js/chunk-645e.ad5c2109.js.map b/priv/static/adminfe/static/js/chunk-645e.ad5c2109.js.map new file mode 100644 index 000000000..47f9e1213 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-645e.ad5c2109.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-1ada.b41cb585.js b/priv/static/adminfe/static/js/chunk-6aa3.95b2c0b4.js similarity index 97% rename from priv/static/adminfe/static/js/chunk-1ada.b41cb585.js rename to priv/static/adminfe/static/js/chunk-6aa3.95b2c0b4.js index b7bc3b278..1d44bee16 100644 Binary files a/priv/static/adminfe/static/js/chunk-1ada.b41cb585.js and b/priv/static/adminfe/static/js/chunk-6aa3.95b2c0b4.js differ diff --git a/priv/static/adminfe/static/js/chunk-1ada.b41cb585.js.map b/priv/static/adminfe/static/js/chunk-6aa3.95b2c0b4.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-1ada.b41cb585.js.map rename to priv/static/adminfe/static/js/chunk-6aa3.95b2c0b4.js.map index 27a2f8e5c..aa3fa8ee1 100644 Binary files a/priv/static/adminfe/static/js/chunk-1ada.b41cb585.js.map and b/priv/static/adminfe/static/js/chunk-6aa3.95b2c0b4.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-6b7b.e7ed7973.js b/priv/static/adminfe/static/js/chunk-6b7b.e7ed7973.js deleted file mode 100644 index 3a2a7694b..000000000 Binary files a/priv/static/adminfe/static/js/chunk-6b7b.e7ed7973.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-6b7b.e7ed7973.js.map b/priv/static/adminfe/static/js/chunk-6b7b.e7ed7973.js.map deleted file mode 100644 index 570df08e6..000000000 Binary files a/priv/static/adminfe/static/js/chunk-6b7b.e7ed7973.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-6e77.d1988eaf.js b/priv/static/adminfe/static/js/chunk-6e77.d1988eaf.js deleted file mode 100644 index 9fef6e5dc..000000000 Binary files a/priv/static/adminfe/static/js/chunk-6e77.d1988eaf.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-6e77.d1988eaf.js.map b/priv/static/adminfe/static/js/chunk-6e77.d1988eaf.js.map deleted file mode 100644 index 4b756b70a..000000000 Binary files a/priv/static/adminfe/static/js/chunk-6e77.d1988eaf.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-7f83.1321eab8.js b/priv/static/adminfe/static/js/chunk-7f83.1321eab8.js deleted file mode 100644 index 52c9efc2d..000000000 Binary files a/priv/static/adminfe/static/js/chunk-7f83.1321eab8.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-7f83.1321eab8.js.map b/priv/static/adminfe/static/js/chunk-7f83.1321eab8.js.map deleted file mode 100644 index 5a7d9d6a2..000000000 Binary files a/priv/static/adminfe/static/js/chunk-7f83.1321eab8.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/chunk-7f8e.0505d295.js b/priv/static/adminfe/static/js/chunk-7f8e.a4876ede.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-7f8e.0505d295.js rename to priv/static/adminfe/static/js/chunk-7f8e.a4876ede.js index 43d8a02d8..e3025b00f 100644 Binary files a/priv/static/adminfe/static/js/chunk-7f8e.0505d295.js and b/priv/static/adminfe/static/js/chunk-7f8e.a4876ede.js differ diff --git a/priv/static/adminfe/static/js/chunk-7f8e.0505d295.js.map b/priv/static/adminfe/static/js/chunk-7f8e.a4876ede.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-7f8e.0505d295.js.map rename to priv/static/adminfe/static/js/chunk-7f8e.a4876ede.js.map index d1100abb0..c34b1dc46 100644 Binary files a/priv/static/adminfe/static/js/chunk-7f8e.0505d295.js.map and b/priv/static/adminfe/static/js/chunk-7f8e.a4876ede.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-7f9e.c49aa694.js b/priv/static/adminfe/static/js/chunk-7f9e.c49aa694.js new file mode 100644 index 000000000..9fb60af23 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-7f9e.c49aa694.js differ diff --git a/priv/static/adminfe/static/js/chunk-7f9e.c49aa694.js.map b/priv/static/adminfe/static/js/chunk-7f9e.c49aa694.js.map new file mode 100644 index 000000000..241c6cc21 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-7f9e.c49aa694.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-b4ba.f717f3b2.js b/priv/static/adminfe/static/js/chunk-b4ba.f717f3b2.js new file mode 100644 index 000000000..b748c0739 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-b4ba.f717f3b2.js differ diff --git a/priv/static/adminfe/static/js/chunk-b4ba.f717f3b2.js.map b/priv/static/adminfe/static/js/chunk-b4ba.f717f3b2.js.map new file mode 100644 index 000000000..2871c747d Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-b4ba.f717f3b2.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-bb29.6468c7fe.js b/priv/static/adminfe/static/js/chunk-bb29.6468c7fe.js new file mode 100644 index 000000000..866a07448 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-bb29.6468c7fe.js differ diff --git a/priv/static/adminfe/static/js/chunk-bb29.6468c7fe.js.map b/priv/static/adminfe/static/js/chunk-bb29.6468c7fe.js.map new file mode 100644 index 000000000..27274eaec Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-bb29.6468c7fe.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-cf58.438233c4.js b/priv/static/adminfe/static/js/chunk-cf58.438233c4.js new file mode 100644 index 000000000..5c22b4ba4 Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-cf58.438233c4.js differ diff --git a/priv/static/adminfe/static/js/chunk-cf58.438233c4.js.map b/priv/static/adminfe/static/js/chunk-cf58.438233c4.js.map new file mode 100644 index 000000000..dd70f756c Binary files /dev/null and b/priv/static/adminfe/static/js/chunk-cf58.438233c4.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js b/priv/static/adminfe/static/js/chunk-elementUI.fba0efec.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js rename to priv/static/adminfe/static/js/chunk-elementUI.fba0efec.js index c76b0430b..f106931f5 100644 Binary files a/priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js and b/priv/static/adminfe/static/js/chunk-elementUI.fba0efec.js differ diff --git a/priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js.map b/priv/static/adminfe/static/js/chunk-elementUI.fba0efec.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js.map rename to priv/static/adminfe/static/js/chunk-elementUI.fba0efec.js.map index fa9dc12f0..a1f726fde 100644 Binary files a/priv/static/adminfe/static/js/chunk-elementUI.2de79b84.js.map and b/priv/static/adminfe/static/js/chunk-elementUI.fba0efec.js.map differ diff --git a/priv/static/adminfe/static/js/chunk-libs.680db3fc.js b/priv/static/adminfe/static/js/chunk-libs.b8c453ab.js similarity index 99% rename from priv/static/adminfe/static/js/chunk-libs.680db3fc.js rename to priv/static/adminfe/static/js/chunk-libs.b8c453ab.js index 478edf880..2af35eb62 100644 Binary files a/priv/static/adminfe/static/js/chunk-libs.680db3fc.js and b/priv/static/adminfe/static/js/chunk-libs.b8c453ab.js differ diff --git a/priv/static/adminfe/static/js/chunk-libs.680db3fc.js.map b/priv/static/adminfe/static/js/chunk-libs.b8c453ab.js.map similarity index 99% rename from priv/static/adminfe/static/js/chunk-libs.680db3fc.js.map rename to priv/static/adminfe/static/js/chunk-libs.b8c453ab.js.map index f8c92c2fa..9c9d9acde 100644 Binary files a/priv/static/adminfe/static/js/chunk-libs.680db3fc.js.map and b/priv/static/adminfe/static/js/chunk-libs.b8c453ab.js.map differ diff --git a/priv/static/adminfe/static/js/runtime.cab03b3e.js b/priv/static/adminfe/static/js/runtime.cab03b3e.js deleted file mode 100644 index f700f7ccc..000000000 Binary files a/priv/static/adminfe/static/js/runtime.cab03b3e.js and /dev/null differ diff --git a/priv/static/adminfe/static/js/runtime.cab03b3e.js.map b/priv/static/adminfe/static/js/runtime.cab03b3e.js.map deleted file mode 100644 index eca2ddd29..000000000 Binary files a/priv/static/adminfe/static/js/runtime.cab03b3e.js.map and /dev/null differ diff --git a/priv/static/adminfe/static/js/runtime.dfdeb6eb.js b/priv/static/adminfe/static/js/runtime.dfdeb6eb.js new file mode 100644 index 000000000..418b2c4de Binary files /dev/null and b/priv/static/adminfe/static/js/runtime.dfdeb6eb.js differ diff --git a/priv/static/adminfe/static/js/runtime.dfdeb6eb.js.map b/priv/static/adminfe/static/js/runtime.dfdeb6eb.js.map new file mode 100644 index 000000000..6728ad670 Binary files /dev/null and b/priv/static/adminfe/static/js/runtime.dfdeb6eb.js.map differ diff --git a/priv/static/index.html b/priv/static/index.html index 4d25be810..62a188adc 100644 --- a/priv/static/index.html +++ b/priv/static/index.html @@ -1 +1 @@ -Pleroma
\ No newline at end of file +Pleroma
\ No newline at end of file diff --git a/priv/static/static/css/app.ae04505b31bb0ee2765e.css b/priv/static/static/css/app.1055039ce3f2fe4dd110.css similarity index 90% rename from priv/static/static/css/app.ae04505b31bb0ee2765e.css rename to priv/static/static/css/app.1055039ce3f2fe4dd110.css index 05e3f2087..1867ca81a 100644 Binary files a/priv/static/static/css/app.ae04505b31bb0ee2765e.css and b/priv/static/static/css/app.1055039ce3f2fe4dd110.css differ diff --git a/priv/static/static/css/app.1055039ce3f2fe4dd110.css.map b/priv/static/static/css/app.1055039ce3f2fe4dd110.css.map new file mode 100644 index 000000000..861ee8313 --- /dev/null +++ b/priv/static/static/css/app.1055039ce3f2fe4dd110.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///./src/hocs/with_load_more/with_load_more.scss","webpack:///./src/components/tab_switcher/tab_switcher.scss","webpack:///./src/hocs/with_subscription/with_subscription.scss"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,C;ACTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,C;ACxFA;AACA;AACA;AACA;AACA;AACA;AACA,C","file":"static/css/app.1055039ce3f2fe4dd110.css","sourcesContent":[".with-load-more-footer {\n padding: 10px;\n text-align: center;\n border-top: 1px solid;\n border-top-color: #222;\n border-top-color: var(--border, #222);\n}\n.with-load-more-footer .error {\n font-size: 14px;\n}",".tab-switcher {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n}\n.tab-switcher .contents {\n -ms-flex: 1 0 auto;\n flex: 1 0 auto;\n min-height: 0px;\n}\n.tab-switcher .contents .hidden {\n display: none;\n}\n.tab-switcher .contents.scrollable-tabs {\n -ms-flex-preferred-size: 0;\n flex-basis: 0;\n overflow-y: auto;\n}\n.tab-switcher .tabs {\n display: -ms-flexbox;\n display: flex;\n position: relative;\n width: 100%;\n overflow-y: hidden;\n overflow-x: auto;\n padding-top: 5px;\n box-sizing: border-box;\n}\n.tab-switcher .tabs::after, .tab-switcher .tabs::before {\n display: block;\n content: \"\";\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n border-bottom: 1px solid;\n border-bottom-color: #222;\n border-bottom-color: var(--border, #222);\n}\n.tab-switcher .tabs .tab-wrapper {\n height: 28px;\n position: relative;\n display: -ms-flexbox;\n display: flex;\n -ms-flex: 0 0 auto;\n flex: 0 0 auto;\n}\n.tab-switcher .tabs .tab-wrapper .tab {\n width: 100%;\n min-width: 1px;\n position: relative;\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n padding: 6px 1em;\n padding-bottom: 99px;\n margin-bottom: -93px;\n white-space: nowrap;\n color: #b9b9ba;\n color: var(--tabText, #b9b9ba);\n background-color: #182230;\n background-color: var(--tab, #182230);\n}\n.tab-switcher .tabs .tab-wrapper .tab:not(.active) {\n z-index: 4;\n}\n.tab-switcher .tabs .tab-wrapper .tab:not(.active):hover {\n z-index: 6;\n}\n.tab-switcher .tabs .tab-wrapper .tab.active {\n background: transparent;\n z-index: 5;\n color: #b9b9ba;\n color: var(--tabActiveText, #b9b9ba);\n}\n.tab-switcher .tabs .tab-wrapper .tab img {\n max-height: 26px;\n vertical-align: top;\n margin-top: -5px;\n}\n.tab-switcher .tabs .tab-wrapper:not(.active)::after {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 7;\n border-bottom: 1px solid;\n border-bottom-color: #222;\n border-bottom-color: var(--border, #222);\n}",".with-subscription-loading {\n padding: 10px;\n text-align: center;\n}\n.with-subscription-loading .error {\n font-size: 14px;\n}"],"sourceRoot":""} \ No newline at end of file diff --git a/priv/static/static/css/app.ae04505b31bb0ee2765e.css.map b/priv/static/static/css/app.ae04505b31bb0ee2765e.css.map deleted file mode 100644 index 72f33316e..000000000 --- a/priv/static/static/css/app.ae04505b31bb0ee2765e.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["webpack:///./src/hocs/with_load_more/with_load_more.scss","webpack:///./src/components/tab_switcher/tab_switcher.scss","webpack:///./src/hocs/with_subscription/with_subscription.scss"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,C;ACTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,C;AClFA;AACA;AACA;AACA;AACA;AACA;AACA,C","file":"static/css/app.ae04505b31bb0ee2765e.css","sourcesContent":[".with-load-more-footer {\n padding: 10px;\n text-align: center;\n border-top: 1px solid;\n border-top-color: #222;\n border-top-color: var(--border, #222);\n}\n.with-load-more-footer .error {\n font-size: 14px;\n}",".tab-switcher {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: column;\n flex-direction: column;\n}\n.tab-switcher .contents {\n -ms-flex: 1 0 auto;\n flex: 1 0 auto;\n min-height: 0px;\n}\n.tab-switcher .contents .hidden {\n display: none;\n}\n.tab-switcher .contents.scrollable-tabs {\n -ms-flex-preferred-size: 0;\n flex-basis: 0;\n overflow-y: auto;\n}\n.tab-switcher .tabs {\n display: -ms-flexbox;\n display: flex;\n position: relative;\n width: 100%;\n overflow-y: hidden;\n overflow-x: auto;\n padding-top: 5px;\n box-sizing: border-box;\n}\n.tab-switcher .tabs::after, .tab-switcher .tabs::before {\n display: block;\n content: \"\";\n -ms-flex: 1 1 auto;\n flex: 1 1 auto;\n border-bottom: 1px solid;\n border-bottom-color: #222;\n border-bottom-color: var(--border, #222);\n}\n.tab-switcher .tabs .tab-wrapper {\n height: 28px;\n position: relative;\n display: -ms-flexbox;\n display: flex;\n -ms-flex: 0 0 auto;\n flex: 0 0 auto;\n}\n.tab-switcher .tabs .tab-wrapper .tab {\n width: 100%;\n min-width: 1px;\n position: relative;\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n padding: 6px 1em;\n padding-bottom: 99px;\n margin-bottom: -93px;\n white-space: nowrap;\n}\n.tab-switcher .tabs .tab-wrapper .tab:not(.active) {\n z-index: 4;\n}\n.tab-switcher .tabs .tab-wrapper .tab:not(.active):hover {\n z-index: 6;\n}\n.tab-switcher .tabs .tab-wrapper .tab.active {\n background: transparent;\n z-index: 5;\n}\n.tab-switcher .tabs .tab-wrapper .tab img {\n max-height: 26px;\n vertical-align: top;\n margin-top: -5px;\n}\n.tab-switcher .tabs .tab-wrapper:not(.active)::after {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 7;\n border-bottom: 1px solid;\n border-bottom-color: #222;\n border-bottom-color: var(--border, #222);\n}",".with-subscription-loading {\n padding: 10px;\n text-align: center;\n}\n.with-subscription-loading .error {\n font-size: 14px;\n}"],"sourceRoot":""} \ No newline at end of file diff --git a/priv/static/static/css/base16-3024.css b/priv/static/static/css/base16-3024.css deleted file mode 100644 index 91859e272..000000000 Binary files a/priv/static/static/css/base16-3024.css and /dev/null differ diff --git a/priv/static/static/css/base16-apathy.css b/priv/static/static/css/base16-apathy.css deleted file mode 100644 index 2e99ba1f0..000000000 Binary files a/priv/static/static/css/base16-apathy.css and /dev/null differ diff --git a/priv/static/static/css/base16-ashes.css b/priv/static/static/css/base16-ashes.css deleted file mode 100644 index d10e1918e..000000000 Binary files a/priv/static/static/css/base16-ashes.css and /dev/null differ diff --git a/priv/static/static/css/base16-atelier-cave.css b/priv/static/static/css/base16-atelier-cave.css deleted file mode 100644 index 5ac17f97e..000000000 Binary files a/priv/static/static/css/base16-atelier-cave.css and /dev/null differ diff --git a/priv/static/static/css/base16-atelier-dune.css b/priv/static/static/css/base16-atelier-dune.css deleted file mode 100644 index cfb2d9a1e..000000000 Binary files a/priv/static/static/css/base16-atelier-dune.css and /dev/null differ diff --git a/priv/static/static/css/base16-atelier-estuary.css b/priv/static/static/css/base16-atelier-estuary.css deleted file mode 100644 index 76d82c754..000000000 Binary files a/priv/static/static/css/base16-atelier-estuary.css and /dev/null differ diff --git a/priv/static/static/css/base16-atelier-forest.css b/priv/static/static/css/base16-atelier-forest.css deleted file mode 100644 index 8108ed8f6..000000000 Binary files a/priv/static/static/css/base16-atelier-forest.css and /dev/null differ diff --git a/priv/static/static/css/base16-atelier-heath.css b/priv/static/static/css/base16-atelier-heath.css deleted file mode 100644 index 8858cb807..000000000 Binary files a/priv/static/static/css/base16-atelier-heath.css and /dev/null differ diff --git a/priv/static/static/css/base16-atelier-lakeside.css b/priv/static/static/css/base16-atelier-lakeside.css deleted file mode 100644 index 77d44c5fa..000000000 Binary files a/priv/static/static/css/base16-atelier-lakeside.css and /dev/null differ diff --git a/priv/static/static/css/base16-atelier-plateau.css b/priv/static/static/css/base16-atelier-plateau.css deleted file mode 100644 index a7445030b..000000000 Binary files a/priv/static/static/css/base16-atelier-plateau.css and /dev/null differ diff --git a/priv/static/static/css/base16-atelier-savanna.css b/priv/static/static/css/base16-atelier-savanna.css deleted file mode 100644 index be728d07d..000000000 Binary files a/priv/static/static/css/base16-atelier-savanna.css and /dev/null differ diff --git a/priv/static/static/css/base16-atelier-seaside.css b/priv/static/static/css/base16-atelier-seaside.css deleted file mode 100644 index 8b3914669..000000000 Binary files a/priv/static/static/css/base16-atelier-seaside.css and /dev/null differ diff --git a/priv/static/static/css/base16-atelier-sulphurpool.css b/priv/static/static/css/base16-atelier-sulphurpool.css deleted file mode 100644 index fb44d6e0f..000000000 Binary files a/priv/static/static/css/base16-atelier-sulphurpool.css and /dev/null differ diff --git a/priv/static/static/css/base16-bespin.css b/priv/static/static/css/base16-bespin.css deleted file mode 100644 index 48a9dcf76..000000000 Binary files a/priv/static/static/css/base16-bespin.css and /dev/null differ diff --git a/priv/static/static/css/base16-brewer.css b/priv/static/static/css/base16-brewer.css deleted file mode 100644 index c88f219b7..000000000 Binary files a/priv/static/static/css/base16-brewer.css and /dev/null differ diff --git a/priv/static/static/css/base16-bright.css b/priv/static/static/css/base16-bright.css deleted file mode 100644 index c2333b8d1..000000000 Binary files a/priv/static/static/css/base16-bright.css and /dev/null differ diff --git a/priv/static/static/css/base16-chalk.css b/priv/static/static/css/base16-chalk.css deleted file mode 100644 index e3cb3c20c..000000000 Binary files a/priv/static/static/css/base16-chalk.css and /dev/null differ diff --git a/priv/static/static/css/base16-codeschool.css b/priv/static/static/css/base16-codeschool.css deleted file mode 100644 index 00194bbfc..000000000 Binary files a/priv/static/static/css/base16-codeschool.css and /dev/null differ diff --git a/priv/static/static/css/base16-darktooth.css b/priv/static/static/css/base16-darktooth.css deleted file mode 100644 index 534487064..000000000 Binary files a/priv/static/static/css/base16-darktooth.css and /dev/null differ diff --git a/priv/static/static/css/base16-default-dark.css b/priv/static/static/css/base16-default-dark.css deleted file mode 100644 index 3cd7e860c..000000000 Binary files a/priv/static/static/css/base16-default-dark.css and /dev/null differ diff --git a/priv/static/static/css/base16-default-light.css b/priv/static/static/css/base16-default-light.css deleted file mode 100644 index 7e660c302..000000000 Binary files a/priv/static/static/css/base16-default-light.css and /dev/null differ diff --git a/priv/static/static/css/base16-eighties.css b/priv/static/static/css/base16-eighties.css deleted file mode 100644 index 8ffcf04d9..000000000 Binary files a/priv/static/static/css/base16-eighties.css and /dev/null differ diff --git a/priv/static/static/css/base16-embers.css b/priv/static/static/css/base16-embers.css deleted file mode 100644 index 74e9b7693..000000000 Binary files a/priv/static/static/css/base16-embers.css and /dev/null differ diff --git a/priv/static/static/css/base16-flat.css b/priv/static/static/css/base16-flat.css deleted file mode 100644 index 72918a5df..000000000 Binary files a/priv/static/static/css/base16-flat.css and /dev/null differ diff --git a/priv/static/static/css/base16-github.css b/priv/static/static/css/base16-github.css deleted file mode 100644 index 080ed34ce..000000000 Binary files a/priv/static/static/css/base16-github.css and /dev/null differ diff --git a/priv/static/static/css/base16-google-dark.css b/priv/static/static/css/base16-google-dark.css deleted file mode 100644 index 988eac51d..000000000 Binary files a/priv/static/static/css/base16-google-dark.css and /dev/null differ diff --git a/priv/static/static/css/base16-google-light.css b/priv/static/static/css/base16-google-light.css deleted file mode 100644 index 2ee2a6069..000000000 Binary files a/priv/static/static/css/base16-google-light.css and /dev/null differ diff --git a/priv/static/static/css/base16-grayscale-dark.css b/priv/static/static/css/base16-grayscale-dark.css deleted file mode 100644 index dc0dd03a0..000000000 Binary files a/priv/static/static/css/base16-grayscale-dark.css and /dev/null differ diff --git a/priv/static/static/css/base16-grayscale-light.css b/priv/static/static/css/base16-grayscale-light.css deleted file mode 100644 index f9fd213ae..000000000 Binary files a/priv/static/static/css/base16-grayscale-light.css and /dev/null differ diff --git a/priv/static/static/css/base16-green-screen.css b/priv/static/static/css/base16-green-screen.css deleted file mode 100644 index 205efeaec..000000000 Binary files a/priv/static/static/css/base16-green-screen.css and /dev/null differ diff --git a/priv/static/static/css/base16-harmonic16-dark.css b/priv/static/static/css/base16-harmonic16-dark.css deleted file mode 100644 index 0c2c7ce42..000000000 Binary files a/priv/static/static/css/base16-harmonic16-dark.css and /dev/null differ diff --git a/priv/static/static/css/base16-harmonic16-light.css b/priv/static/static/css/base16-harmonic16-light.css deleted file mode 100644 index 37bb7679a..000000000 Binary files a/priv/static/static/css/base16-harmonic16-light.css and /dev/null differ diff --git a/priv/static/static/css/base16-hopscotch.css b/priv/static/static/css/base16-hopscotch.css deleted file mode 100644 index f2ad232c5..000000000 Binary files a/priv/static/static/css/base16-hopscotch.css and /dev/null differ diff --git a/priv/static/static/css/base16-ir-black.css b/priv/static/static/css/base16-ir-black.css deleted file mode 100644 index 8d14ab9b8..000000000 Binary files a/priv/static/static/css/base16-ir-black.css and /dev/null differ diff --git a/priv/static/static/css/base16-isotope.css b/priv/static/static/css/base16-isotope.css deleted file mode 100644 index f7a4a0b4b..000000000 Binary files a/priv/static/static/css/base16-isotope.css and /dev/null differ diff --git a/priv/static/static/css/base16-london-tube.css b/priv/static/static/css/base16-london-tube.css deleted file mode 100644 index 0537d1ad5..000000000 Binary files a/priv/static/static/css/base16-london-tube.css and /dev/null differ diff --git a/priv/static/static/css/base16-macintosh.css b/priv/static/static/css/base16-macintosh.css deleted file mode 100644 index d5969fec2..000000000 Binary files a/priv/static/static/css/base16-macintosh.css and /dev/null differ diff --git a/priv/static/static/css/base16-marrakesh.css b/priv/static/static/css/base16-marrakesh.css deleted file mode 100644 index 91f0471fc..000000000 Binary files a/priv/static/static/css/base16-marrakesh.css and /dev/null differ diff --git a/priv/static/static/css/base16-materia.css b/priv/static/static/css/base16-materia.css deleted file mode 100644 index 41d935dd1..000000000 Binary files a/priv/static/static/css/base16-materia.css and /dev/null differ diff --git a/priv/static/static/css/base16-mexico-light.css b/priv/static/static/css/base16-mexico-light.css deleted file mode 100644 index 1916c67bc..000000000 Binary files a/priv/static/static/css/base16-mexico-light.css and /dev/null differ diff --git a/priv/static/static/css/base16-mocha.css b/priv/static/static/css/base16-mocha.css deleted file mode 100644 index 6cb2fb580..000000000 Binary files a/priv/static/static/css/base16-mocha.css and /dev/null differ diff --git a/priv/static/static/css/base16-monokai.css b/priv/static/static/css/base16-monokai.css deleted file mode 100644 index fc7ccf471..000000000 Binary files a/priv/static/static/css/base16-monokai.css and /dev/null differ diff --git a/priv/static/static/css/base16-ocean.css b/priv/static/static/css/base16-ocean.css deleted file mode 100644 index 8622d17e0..000000000 Binary files a/priv/static/static/css/base16-ocean.css and /dev/null differ diff --git a/priv/static/static/css/base16-oceanicnext.css b/priv/static/static/css/base16-oceanicnext.css deleted file mode 100644 index df4d9ef5e..000000000 Binary files a/priv/static/static/css/base16-oceanicnext.css and /dev/null differ diff --git a/priv/static/static/css/base16-paraiso.css b/priv/static/static/css/base16-paraiso.css deleted file mode 100644 index b68c94071..000000000 Binary files a/priv/static/static/css/base16-paraiso.css and /dev/null differ diff --git a/priv/static/static/css/base16-phd.css b/priv/static/static/css/base16-phd.css deleted file mode 100644 index 54276ab11..000000000 Binary files a/priv/static/static/css/base16-phd.css and /dev/null differ diff --git a/priv/static/static/css/base16-pico.css b/priv/static/static/css/base16-pico.css deleted file mode 100644 index 86482b72d..000000000 Binary files a/priv/static/static/css/base16-pico.css and /dev/null differ diff --git a/priv/static/static/css/base16-pleroma-dark.css b/priv/static/static/css/base16-pleroma-dark.css deleted file mode 100644 index e1d46f927..000000000 Binary files a/priv/static/static/css/base16-pleroma-dark.css and /dev/null differ diff --git a/priv/static/static/css/base16-pleroma-light.css b/priv/static/static/css/base16-pleroma-light.css deleted file mode 100644 index 1a85689aa..000000000 Binary files a/priv/static/static/css/base16-pleroma-light.css and /dev/null differ diff --git a/priv/static/static/css/base16-pop.css b/priv/static/static/css/base16-pop.css deleted file mode 100644 index 14acac171..000000000 Binary files a/priv/static/static/css/base16-pop.css and /dev/null differ diff --git a/priv/static/static/css/base16-railscasts.css b/priv/static/static/css/base16-railscasts.css deleted file mode 100644 index 18f43bfd6..000000000 Binary files a/priv/static/static/css/base16-railscasts.css and /dev/null differ diff --git a/priv/static/static/css/base16-seti-ui.css b/priv/static/static/css/base16-seti-ui.css deleted file mode 100644 index bd4f9cc42..000000000 Binary files a/priv/static/static/css/base16-seti-ui.css and /dev/null differ diff --git a/priv/static/static/css/base16-shapeshifter.css b/priv/static/static/css/base16-shapeshifter.css deleted file mode 100644 index ded180691..000000000 Binary files a/priv/static/static/css/base16-shapeshifter.css and /dev/null differ diff --git a/priv/static/static/css/base16-solar-flare.css b/priv/static/static/css/base16-solar-flare.css deleted file mode 100644 index 7d1d38624..000000000 Binary files a/priv/static/static/css/base16-solar-flare.css and /dev/null differ diff --git a/priv/static/static/css/base16-solarized-dark.css b/priv/static/static/css/base16-solarized-dark.css deleted file mode 100644 index ac16f12c9..000000000 Binary files a/priv/static/static/css/base16-solarized-dark.css and /dev/null differ diff --git a/priv/static/static/css/base16-solarized-light.css b/priv/static/static/css/base16-solarized-light.css deleted file mode 100644 index 7164cb046..000000000 Binary files a/priv/static/static/css/base16-solarized-light.css and /dev/null differ diff --git a/priv/static/static/css/base16-spacemacs.css b/priv/static/static/css/base16-spacemacs.css deleted file mode 100644 index 487376500..000000000 Binary files a/priv/static/static/css/base16-spacemacs.css and /dev/null differ diff --git a/priv/static/static/css/base16-summerfruit-dark.css b/priv/static/static/css/base16-summerfruit-dark.css deleted file mode 100644 index 1c8f2332e..000000000 Binary files a/priv/static/static/css/base16-summerfruit-dark.css and /dev/null differ diff --git a/priv/static/static/css/base16-summerfruit-light.css b/priv/static/static/css/base16-summerfruit-light.css deleted file mode 100644 index cb54d4c54..000000000 Binary files a/priv/static/static/css/base16-summerfruit-light.css and /dev/null differ diff --git a/priv/static/static/css/base16-tomorrow-night.css b/priv/static/static/css/base16-tomorrow-night.css deleted file mode 100644 index 09ecf08ef..000000000 Binary files a/priv/static/static/css/base16-tomorrow-night.css and /dev/null differ diff --git a/priv/static/static/css/base16-tomorrow.css b/priv/static/static/css/base16-tomorrow.css deleted file mode 100644 index f14868230..000000000 Binary files a/priv/static/static/css/base16-tomorrow.css and /dev/null differ diff --git a/priv/static/static/css/base16-twilight.css b/priv/static/static/css/base16-twilight.css deleted file mode 100644 index c8dfda3f8..000000000 Binary files a/priv/static/static/css/base16-twilight.css and /dev/null differ diff --git a/priv/static/static/css/base16-unikitty-dark.css b/priv/static/static/css/base16-unikitty-dark.css deleted file mode 100644 index e6ef32e33..000000000 Binary files a/priv/static/static/css/base16-unikitty-dark.css and /dev/null differ diff --git a/priv/static/static/css/base16-unikitty-light.css b/priv/static/static/css/base16-unikitty-light.css deleted file mode 100644 index 7e4c51b7a..000000000 Binary files a/priv/static/static/css/base16-unikitty-light.css and /dev/null differ diff --git a/priv/static/static/css/themes.json b/priv/static/static/css/themes.json deleted file mode 100644 index ea8e5a0c4..000000000 --- a/priv/static/static/css/themes.json +++ /dev/null @@ -1,66 +0,0 @@ -[ -"base16-pleroma-dark.css", -"base16-pleroma-light.css", -"base16-3024.css", -"base16-apathy.css", -"base16-ashes.css", -"base16-atelier-cave.css", -"base16-atelier-dune.css", -"base16-atelier-estuary.css", -"base16-atelier-forest.css", -"base16-atelier-heath.css", -"base16-atelier-lakeside.css", -"base16-atelier-plateau.css", -"base16-atelier-savanna.css", -"base16-atelier-seaside.css", -"base16-atelier-sulphurpool.css", -"base16-bespin.css", -"base16-brewer.css", -"base16-bright.css", -"base16-chalk.css", -"base16-codeschool.css", -"base16-darktooth.css", -"base16-default-dark.css", -"base16-default-light.css", -"base16-eighties.css", -"base16-embers.css", -"base16-flat.css", -"base16-github.css", -"base16-google-dark.css", -"base16-google-light.css", -"base16-grayscale-dark.css", -"base16-grayscale-light.css", -"base16-green-screen.css", -"base16-harmonic16-dark.css", -"base16-harmonic16-light.css", -"base16-hopscotch.css", -"base16-ir-black.css", -"base16-isotope.css", -"base16-london-tube.css", -"base16-macintosh.css", -"base16-marrakesh.css", -"base16-materia.css", -"base16-mexico-light.css", -"base16-mocha.css", -"base16-monokai.css", -"base16-ocean.css", -"base16-oceanicnext.css", -"base16-paraiso.css", -"base16-phd.css", -"base16-pico.css", -"base16-pop.css", -"base16-railscasts.css", -"base16-seti-ui.css", -"base16-shapeshifter.css", -"base16-solar-flare.css", -"base16-solarized-dark.css", -"base16-solarized-light.css", -"base16-spacemacs.css", -"base16-summerfruit-dark.css", -"base16-summerfruit-light.css", -"base16-tomorrow-night.css", -"base16-tomorrow.css", -"base16-twilight.css", -"base16-unikitty-dark.css", -"base16-unikitty-light.css" -] diff --git a/priv/static/static/font/fontello.1581272100487.woff b/priv/static/static/font/fontello.1581272100487.woff deleted file mode 100644 index 62f9a5931..000000000 Binary files a/priv/static/static/font/fontello.1581272100487.woff and /dev/null differ diff --git a/priv/static/static/font/fontello.1581272100487.woff2 b/priv/static/static/font/fontello.1581272100487.woff2 deleted file mode 100644 index 3001c5997..000000000 Binary files a/priv/static/static/font/fontello.1581272100487.woff2 and /dev/null differ diff --git a/priv/static/static/font/fontello.1581272100487.eot b/priv/static/static/font/fontello.1582206587591.eot similarity index 86% rename from priv/static/static/font/fontello.1581272100487.eot rename to priv/static/static/font/fontello.1582206587591.eot index 0fc4f848a..7101b3104 100644 Binary files a/priv/static/static/font/fontello.1581272100487.eot and b/priv/static/static/font/fontello.1582206587591.eot differ diff --git a/priv/static/static/font/fontello.1581272100487.svg b/priv/static/static/font/fontello.1582206587591.svg similarity index 97% rename from priv/static/static/font/fontello.1581272100487.svg rename to priv/static/static/font/fontello.1582206587591.svg index 44beba9a2..b905a0f6c 100644 --- a/priv/static/static/font/fontello.1581272100487.svg +++ b/priv/static/static/font/fontello.1582206587591.svg @@ -76,6 +76,8 @@ + + diff --git a/priv/static/static/font/fontello.1581272100487.ttf b/priv/static/static/font/fontello.1582206587591.ttf similarity index 86% rename from priv/static/static/font/fontello.1581272100487.ttf rename to priv/static/static/font/fontello.1582206587591.ttf index 7d614ac8d..8f0e51a13 100644 Binary files a/priv/static/static/font/fontello.1581272100487.ttf and b/priv/static/static/font/fontello.1582206587591.ttf differ diff --git a/priv/static/static/font/fontello.1582206587591.woff b/priv/static/static/font/fontello.1582206587591.woff new file mode 100644 index 000000000..74cd6c05b Binary files /dev/null and b/priv/static/static/font/fontello.1582206587591.woff differ diff --git a/priv/static/static/font/fontello.1582206587591.woff2 b/priv/static/static/font/fontello.1582206587591.woff2 new file mode 100644 index 000000000..2f548b653 Binary files /dev/null and b/priv/static/static/font/fontello.1582206587591.woff2 differ diff --git a/priv/static/static/fontello.1581272100487.css b/priv/static/static/fontello.1582206587591.css similarity index 87% rename from priv/static/static/fontello.1581272100487.css rename to priv/static/static/fontello.1582206587591.css index f89a6a156..7e3acd49e 100644 Binary files a/priv/static/static/fontello.1581272100487.css and b/priv/static/static/fontello.1582206587591.css differ diff --git a/priv/static/static/fontello.json b/priv/static/static/fontello.json index 829241b55..5a7086a23 100755 --- a/priv/static/static/fontello.json +++ b/priv/static/static/fontello.json @@ -339,6 +339,12 @@ "css": "arrow-curved", "code": 59426, "src": "iconic" + }, + { + "uid": "0ddd3e8201ccc7d41f7b7c9d27eca6c1", + "css": "link", + "code": 59427, + "src": "fontawesome" } ] -} \ No newline at end of file +} diff --git a/priv/static/static/js/2.9be9f9ec29f7536c73c3.js b/priv/static/static/js/2.9be9f9ec29f7536c73c3.js deleted file mode 100644 index d464dbf74..000000000 Binary files a/priv/static/static/js/2.9be9f9ec29f7536c73c3.js and /dev/null differ diff --git a/priv/static/static/js/2.e44dd0959c37a28ce531.js b/priv/static/static/js/2.e44dd0959c37a28ce531.js new file mode 100644 index 000000000..c93165f91 Binary files /dev/null and b/priv/static/static/js/2.e44dd0959c37a28ce531.js differ diff --git a/priv/static/static/js/2.9be9f9ec29f7536c73c3.js.map b/priv/static/static/js/2.e44dd0959c37a28ce531.js.map similarity index 50% rename from priv/static/static/js/2.9be9f9ec29f7536c73c3.js.map rename to priv/static/static/js/2.e44dd0959c37a28ce531.js.map index 21efd7ec8..c468d679d 100644 Binary files a/priv/static/static/js/2.9be9f9ec29f7536c73c3.js.map and b/priv/static/static/js/2.e44dd0959c37a28ce531.js.map differ diff --git a/priv/static/static/js/app.1bb1c4f9614d2ee4144e.js b/priv/static/static/js/app.1bb1c4f9614d2ee4144e.js deleted file mode 100644 index ddca136fb..000000000 Binary files a/priv/static/static/js/app.1bb1c4f9614d2ee4144e.js and /dev/null differ diff --git a/priv/static/static/js/app.1bb1c4f9614d2ee4144e.js.map b/priv/static/static/js/app.1bb1c4f9614d2ee4144e.js.map deleted file mode 100644 index 0d73bab99..000000000 Binary files a/priv/static/static/js/app.1bb1c4f9614d2ee4144e.js.map and /dev/null differ diff --git a/priv/static/static/js/app.6a317a7bca161d1a49d2.js b/priv/static/static/js/app.6a317a7bca161d1a49d2.js new file mode 100644 index 000000000..40d6e292d Binary files /dev/null and b/priv/static/static/js/app.6a317a7bca161d1a49d2.js differ diff --git a/priv/static/static/js/app.6a317a7bca161d1a49d2.js.map b/priv/static/static/js/app.6a317a7bca161d1a49d2.js.map new file mode 100644 index 000000000..b29cc2cec Binary files /dev/null and b/priv/static/static/js/app.6a317a7bca161d1a49d2.js.map differ diff --git a/priv/static/static/js/vendors~app.c26cf2fc57e9c1975e8d.js b/priv/static/static/js/vendors~app.3030a9fca79d649e2964.js similarity index 74% rename from priv/static/static/js/vendors~app.c26cf2fc57e9c1975e8d.js rename to priv/static/static/js/vendors~app.3030a9fca79d649e2964.js index bffb28fa7..36b1d0ee5 100644 Binary files a/priv/static/static/js/vendors~app.c26cf2fc57e9c1975e8d.js and b/priv/static/static/js/vendors~app.3030a9fca79d649e2964.js differ diff --git a/priv/static/static/js/vendors~app.3030a9fca79d649e2964.js.map b/priv/static/static/js/vendors~app.3030a9fca79d649e2964.js.map new file mode 100644 index 000000000..02edf97fa Binary files /dev/null and b/priv/static/static/js/vendors~app.3030a9fca79d649e2964.js.map differ diff --git a/priv/static/static/js/vendors~app.c26cf2fc57e9c1975e8d.js.map b/priv/static/static/js/vendors~app.c26cf2fc57e9c1975e8d.js.map deleted file mode 100644 index 044d577a6..000000000 Binary files a/priv/static/static/js/vendors~app.c26cf2fc57e9c1975e8d.js.map and /dev/null differ diff --git a/priv/static/static/styles.json b/priv/static/static/styles.json index f85c72f9d..ee94fda8a 100644 --- a/priv/static/static/styles.json +++ b/priv/static/static/styles.json @@ -13,5 +13,6 @@ "breezy-dark": "/static/themes/breezy-dark.json", "breezy-light": "/static/themes/breezy-light.json", "ihatebeingalive": "/static/themes/ihatebeingalive.json", - "mammal": "/static/themes/mammal.json" + "mammal": "/static/themes/mammal.json", + "paper": "/static/themes/paper.json" } diff --git a/priv/static/static/terms-of-service.html b/priv/static/static/terms-of-service.html index e3823b032..4d91f9b08 100644 --- a/priv/static/static/terms-of-service.html +++ b/priv/static/static/terms-of-service.html @@ -42,4 +42,4 @@

So I guess yeah, that's about it. Try to be nice, eh? We're probably all sad here.


- + diff --git a/priv/static/static/themes/breezy-dark.json b/priv/static/static/themes/breezy-dark.json index 6119bf887..76b962c56 100644 --- a/priv/static/static/themes/breezy-dark.json +++ b/priv/static/static/themes/breezy-dark.json @@ -1,7 +1,9 @@ { "_pleroma_theme_version": 2, "name": "Breezy Dark (beta)", - "theme": { + "source": { + "themeEngineVersion": 3, + "fonts": {}, "shadows": { "panel": [ { @@ -19,7 +21,7 @@ "y": "0", "blur": "0", "spread": "1", - "color": "#ffffff", + "color": "--btn,900", "alpha": "0.15", "inset": true }, @@ -40,7 +42,7 @@ "blur": "40", "spread": "-40", "inset": true, - "color": "#ffffff", + "color": "--panel,900", "alpha": "0.1" } ], @@ -50,8 +52,8 @@ "y": "0", "blur": 0, "spread": "1", - "color": "--link", - "alpha": "0.3", + "color": "--accent", + "alpha": "1", "inset": true }, { @@ -65,21 +67,12 @@ } ], "buttonPressed": [ - { - "x": 0, - "y": 0, - "blur": "0", - "spread": "50", - "color": "--faint", - "alpha": 1, - "inset": true - }, { "x": 0, "y": "0", "blur": 0, "spread": "1", - "color": "#ffffff", + "color": "--btn,900", "alpha": 0.2, "inset": true }, @@ -99,31 +92,30 @@ "y": "0", "blur": 0, "spread": "1", - "color": "#FFFFFF", + "color": "--input,900", "alpha": "0.2", "inset": true } ] }, - "fonts": {}, - "opacity": { - "input": "1", - "panel": "0" - }, + "opacity": {}, "colors": { "bg": "#31363b", "text": "#eff0f1", "link": "#3daee9", "fg": "#31363b", - "panel": "#31363b", - "input": "#232629", - "topBarLink": "#eff0f1", - "btn": "#31363b", + "panel": "transparent", + "input": "--bg,-6.47", + "topBarLink": "--topBarText", + "btn": "--bg", "border": "#4c545b", "cRed": "#da4453", "cBlue": "#3daee9", "cGreen": "#27ae60", - "cOrange": "#f67400" + "cOrange": "#f67400", + "btnPressed": "--accent", + "selectedMenu": "--accent", + "selectedMenuPopover": "--accent" }, "radii": { "btn": "2", diff --git a/priv/static/static/themes/breezy-light.json b/priv/static/static/themes/breezy-light.json index becf704fc..0968fff0c 100644 --- a/priv/static/static/themes/breezy-light.json +++ b/priv/static/static/themes/breezy-light.json @@ -1,7 +1,9 @@ { "_pleroma_theme_version": 2, "name": "Breezy Light (beta)", - "theme": { + "source": { + "themeEngineVersion": 3, + "fonts": {}, "shadows": { "panel": [ { @@ -19,7 +21,7 @@ "y": "0", "blur": "0", "spread": "1", - "color": "#000000", + "color": "--btn,900", "alpha": "0.3", "inset": true }, @@ -40,7 +42,7 @@ "blur": "40", "spread": "-40", "inset": true, - "color": "#ffffff", + "color": "--panel,900", "alpha": "0.1" } ], @@ -50,8 +52,8 @@ "y": "0", "blur": 0, "spread": "1", - "color": "--link", - "alpha": "0.3", + "color": "--accent", + "alpha": "1", "inset": true }, { @@ -65,21 +67,12 @@ } ], "buttonPressed": [ - { - "x": 0, - "y": 0, - "blur": "0", - "spread": "50", - "color": "--faint", - "alpha": 1, - "inset": true - }, { "x": 0, "y": "0", "blur": 0, "spread": "1", - "color": "#ffffff", + "color": "--btn,900", "alpha": 0.2, "inset": true }, @@ -99,31 +92,30 @@ "y": "0", "blur": 0, "spread": "1", - "color": "#000000", + "color": "--input,900", "alpha": "0.2", "inset": true } ] }, - "fonts": {}, "opacity": { "input": "1" }, "colors": { "bg": "#eff0f1", "text": "#232627", - "link": "#2980b9", - "fg": "#bcc2c7", - "panel": "#475057", - "panelText": "#fcfcfc", - "input": "#fcfcfc", - "topBar": "#475057", - "topBarLink": "#eff0f1", - "btn": "#eff0f1", + "fg": "#475057", + "accent": "#2980b9", + "input": "--bg,-6.47", + "topBarLink": "--topBarText", + "btn": "--bg", "cRed": "#da4453", "cBlue": "#2980b9", "cGreen": "#27ae60", - "cOrange": "#f67400" + "cOrange": "#f67400", + "btnPressed": "--accent", + "selectedMenu": "--accent", + "selectedMenuPopover": "--accent" }, "radii": { "btn": "2", diff --git a/priv/static/static/themes/paper.json b/priv/static/static/themes/paper.json new file mode 100644 index 000000000..a3b90a0a1 --- /dev/null +++ b/priv/static/static/themes/paper.json @@ -0,0 +1,172 @@ +{ + "_pleroma_theme_version": 2, + "name": "Paper", + "source": { + "themeEngineVersion": 3, + "fonts": {}, + "shadows": { + "panel": [ + { + "x": "0", + "y": "2", + "blur": "9", + "spread": 0, + "inset": false, + "color": "#668bb2", + "alpha": "0.1" + }, + { + "x": "0", + "y": "1", + "blur": "2", + "spread": "-1", + "inset": false, + "color": "#668bb2", + "alpha": "0.1" + } + ], + "topBar": [ + { + "x": 0, + "y": "3", + "blur": "8", + "spread": 0, + "inset": false, + "color": "#3e618e", + "alpha": "0.1" + }, + { + "x": 0, + "y": "1", + "blur": "4", + "spread": 0, + "inset": false, + "color": "#3e618e", + "alpha": "0.1" + } + ], + "button": [ + { + "x": 0, + "y": "2", + "blur": "5", + "spread": 0, + "color": "#463f78", + "alpha": "0.1", + "inset": false + } + ], + "input": [ + { + "x": 0, + "y": "1", + "blur": "2", + "spread": 0, + "inset": true, + "color": "#6277b7", + "alpha": "0.1" + } + ], + "buttonHover": [ + { + "x": 0, + "y": "2", + "blur": "5", + "spread": 0, + "color": "#494949", + "alpha": "0.1" + }, + { + "x": 0, + "y": "2", + "blur": "0", + "spread": "20", + "color": "#ffffff", + "alpha": "1", + "inset": true + } + ], + "buttonPressed": [ + { + "x": 0, + "y": 0, + "blur": "4", + "spread": "0", + "color": "#494949", + "alpha": "0.8", + "inset": false + } + ], + "avatarStatus": [ + { + "x": "0", + "y": "2", + "blur": "4", + "spread": "0", + "inset": false, + "color": "#3e618e", + "alpha": "0.1" + } + ], + "avatar": [ + { + "x": 0, + "y": "2", + "blur": "5", + "spread": "0", + "color": "#3e618e", + "alpha": "0.9" + } + ], + "popup": [ + { + "x": "0", + "y": "3", + "blur": "11", + "spread": 0, + "color": "#668bb2", + "alpha": "0.2" + }, + { + "x": "0", + "y": "2", + "blur": "3", + "spread": "-1", + "color": "#668bb2", + "alpha": "0.2" + } + ] + }, + "opacity": { + "underlay": "1", + "border": "0" + }, + "colors": { + "bg": "#ffffff", + "fg": "#f6f6f6", + "text": "#494949", + "underlay": "#ffffff", + "link": "#788ca1", + "accent": "#97a0aa", + "cBlue": "#788ca1", + "cRed": "#eed7ce", + "cGreen": "#788ca1", + "cOrange": "#788ca1", + "postLink": "#788ca1", + "border": "#ffffff", + "icon": "#b6c9c4", + "panel": "#ffffff", + "topBarText": "#4b4b4b" + }, + "radii": { + "btn": "0", + "input": "0", + "checkbox": "0", + "panel": "0", + "avatar": "2", + "avatarAlt": "2", + "tooltip": "0", + "attachment": "0" + } + } +} diff --git a/priv/static/static/themes/redmond-xx-se.json b/priv/static/static/themes/redmond-xx-se.json index 70ee89d1b..7a4a29da3 100644 --- a/priv/static/static/themes/redmond-xx-se.json +++ b/priv/static/static/themes/redmond-xx-se.json @@ -1,7 +1,8 @@ { "_pleroma_theme_version": 2, "name": "Redmond XX SE", - "theme": { + "source": { + "themeEngineVersion": 3, "shadows": { "panel": [ { @@ -268,6 +269,7 @@ "bg": "#c0c0c0", "text": "#000000", "link": "#0000ff", + "accent": "#000080", "fg": "#c0c0c0", "panel": "#000080", "panelFaint": "#c0c0c0", @@ -275,13 +277,16 @@ "topBar": "#000080", "topBarLink": "#ffffff", "btn": "#c0c0c0", + "btnToggled": "--btn", "faint": "#3f3f3f", "faintLink": "#404080", "border": "#808080", "cRed": "#FF0000", "cBlue": "#008080", "cGreen": "#008000", - "cOrange": "#808000" + "cOrange": "#808000", + "highlight": "--accent", + "selectedPost": "--bg,-10" }, "radii": { "btn": "0", diff --git a/priv/static/static/themes/redmond-xx.json b/priv/static/static/themes/redmond-xx.json index 4fd6a3691..ff95b1e06 100644 --- a/priv/static/static/themes/redmond-xx.json +++ b/priv/static/static/themes/redmond-xx.json @@ -1,7 +1,8 @@ { "_pleroma_theme_version": 2, "name": "Redmond XX", - "theme": { + "source": { + "themeEngineVersion": 3, "shadows": { "panel": [ { @@ -259,6 +260,7 @@ "bg": "#c0c0c0", "text": "#000000", "link": "#0000ff", + "accent": "#000080", "fg": "#c0c0c0", "panel": "#000080", "panelFaint": "#c0c0c0", @@ -266,13 +268,16 @@ "topBar": "#000080", "topBarLink": "#ffffff", "btn": "#c0c0c0", + "btnToggled": "--btn", "faint": "#3f3f3f", "faintLink": "#404080", "border": "#808080", "cRed": "#FF0000", "cBlue": "#008080", "cGreen": "#008000", - "cOrange": "#808000" + "cOrange": "#808000", + "highlight": "--accent", + "selectedPost": "--bg,-10" }, "radii": { "btn": "0", diff --git a/priv/static/static/themes/redmond-xxi.json b/priv/static/static/themes/redmond-xxi.json index d10bf138f..f788bdb83 100644 --- a/priv/static/static/themes/redmond-xxi.json +++ b/priv/static/static/themes/redmond-xxi.json @@ -1,7 +1,8 @@ { "_pleroma_theme_version": 2, "name": "Redmond XXI", - "theme": { + "source": { + "themeEngineVersion": 3, "shadows": { "panel": [ { @@ -241,6 +242,7 @@ "bg": "#d6d6ce", "text": "#000000", "link": "#0000ff", + "accent": "#0a246a", "fg": "#d6d6ce", "panel": "#042967", "panelFaint": "#FFFFFF", @@ -248,13 +250,16 @@ "topBar": "#042967", "topBarLink": "#ffffff", "btn": "#d6d6ce", + "btnToggled": "--btn", "faint": "#3f3f3f", "faintLink": "#404080", "border": "#808080", "cRed": "#c42726", "cBlue": "#6699cc", "cGreen": "#669966", - "cOrange": "#cc6633" + "cOrange": "#cc6633", + "highlight": "--accent", + "selectedPost": "--bg,-10" }, "radii": { "btn": "0", diff --git a/priv/static/sw-pleroma.js b/priv/static/sw-pleroma.js index b65e603e4..efef7b76e 100644 Binary files a/priv/static/sw-pleroma.js and b/priv/static/sw-pleroma.js differ diff --git a/restarter/lib/pleroma.ex b/restarter/lib/pleroma.ex index da714654c..d7817909d 100644 --- a/restarter/lib/pleroma.ex +++ b/restarter/lib/pleroma.ex @@ -1,26 +1,72 @@ defmodule Restarter.Pleroma do use GenServer + require Logger + def start_link(_) do GenServer.start_link(__MODULE__, [], name: __MODULE__) end - def init(_), do: {:ok, %{}} + def init(_), do: {:ok, %{need_reboot?: false}} - def handle_info(:after_boot, %{after_boot: true} = state), do: {:noreply, state} + def need_reboot? do + GenServer.call(__MODULE__, :need_reboot?) + end - def handle_info(:after_boot, state) do - restart(:pleroma) + def need_reboot do + GenServer.cast(__MODULE__, :need_reboot) + end + + def refresh do + GenServer.cast(__MODULE__, :refresh) + end + + def restart(env, delay) do + GenServer.cast(__MODULE__, {:restart, env, delay}) + end + + def restart_after_boot(env) do + GenServer.cast(__MODULE__, {:after_boot, env}) + end + + def handle_call(:need_reboot?, _from, state) do + {:reply, state[:need_reboot?], state} + end + + def handle_cast(:refresh, _state) do + {:noreply, %{need_reboot?: false}} + end + + def handle_cast(:need_reboot, %{need_reboot?: true} = state), do: {:noreply, state} + + def handle_cast(:need_reboot, state) do + {:noreply, Map.put(state, :need_reboot?, true)} + end + + def handle_cast({:restart, :test, _}, state) do + Logger.warn("pleroma restarted") + {:noreply, Map.put(state, :need_reboot?, false)} + end + + def handle_cast({:restart, _, delay}, state) do + Process.sleep(delay) + do_restart(:pleroma) + {:noreply, Map.put(state, :need_reboot?, false)} + end + + def handle_cast({:after_boot, _}, %{after_boot: true} = state), do: {:noreply, state} + + def handle_cast({:after_boot, :test}, state) do + Logger.warn("pleroma restarted") {:noreply, Map.put(state, :after_boot, true)} end - def handle_info({:restart, delay}, state) do - Process.sleep(delay) - restart(:pleroma) - {:noreply, state} + def handle_cast({:after_boot, _}, state) do + do_restart(:pleroma) + {:noreply, Map.put(state, :after_boot, true)} end - defp restart(app) do + defp do_restart(app) do :ok = Application.ensure_started(app) :ok = Application.stop(app) :ok = Application.start(app) diff --git a/test/activity_expiration_test.exs b/test/activity_expiration_test.exs index 4948fae16..2fc593b8c 100644 --- a/test/activity_expiration_test.exs +++ b/test/activity_expiration_test.exs @@ -7,6 +7,8 @@ defmodule Pleroma.ActivityExpirationTest do alias Pleroma.ActivityExpiration import Pleroma.Factory + clear_config([ActivityExpiration, :enabled]) + test "finds activities due to be deleted only" do activity = insert(:note_activity) expiration_due = insert(:expiration_in_the_past, %{activity_id: activity.id}) @@ -24,4 +26,27 @@ test "denies expirations that don't live long enough" do now = NaiveDateTime.utc_now() assert {:error, _} = ActivityExpiration.create(activity, now) end + + test "deletes an expiration activity" do + Pleroma.Config.put([ActivityExpiration, :enabled], true) + activity = insert(:note_activity) + + naive_datetime = + NaiveDateTime.add( + NaiveDateTime.utc_now(), + -:timer.minutes(2), + :millisecond + ) + + expiration = + insert( + :expiration_in_the_past, + %{activity_id: activity.id, scheduled_at: naive_datetime} + ) + + Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker.perform(:ops, :pid) + + refute Pleroma.Repo.get(Pleroma.Activity, activity.id) + refute Pleroma.Repo.get(Pleroma.ActivityExpiration, expiration.id) + end end diff --git a/test/activity_test.exs b/test/activity_test.exs index e7ea2bd5e..8aeece96d 100644 --- a/test/activity_test.exs +++ b/test/activity_test.exs @@ -138,6 +138,8 @@ test "when association is not loaded" do } end + clear_config([:instance, :limit_to_local_content]) + test "finds utf8 text in statuses", %{ japanese_activity: japanese_activity, user: user @@ -165,7 +167,6 @@ test "find only local statuses for unauthenticated users when `limit_to_local_c %{local_activity: local_activity} do Pleroma.Config.put([:instance, :limit_to_local_content], :all) assert [^local_activity] = Activity.search(nil, "find me") - Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) end test "find all statuses for unauthenticated users when `limit_to_local_content` is `false`", @@ -178,8 +179,6 @@ test "find all statuses for unauthenticated users when `limit_to_local_content` activities = Enum.sort_by(Activity.search(nil, "find me"), & &1.id) assert [^local_activity, ^remote_activity] = activities - - Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) end end diff --git a/test/config/transfer_task_test.exs b/test/config/transfer_task_test.exs index ebdc951cf..3d7218dde 100644 --- a/test/config/transfer_task_test.exs +++ b/test/config/transfer_task_test.exs @@ -109,6 +109,10 @@ test "transfer config values with full subkey update" do end describe "pleroma restart" do + setup do + on_exit(fn -> Restarter.Pleroma.refresh() end) + end + test "don't restart if no reboot time settings were changed" do emoji = Application.get_env(:pleroma, :emoji) on_exit(fn -> Application.put_env(:pleroma, :emoji, emoji) end) @@ -125,7 +129,7 @@ test "don't restart if no reboot time settings were changed" do ) end - test "restart pleroma on reboot time key" do + test "on reboot time key" do chat = Application.get_env(:pleroma, :chat) on_exit(fn -> Application.put_env(:pleroma, :chat, chat) end) @@ -138,7 +142,7 @@ test "restart pleroma on reboot time key" do assert capture_log(fn -> TransferTask.start_link([]) end) =~ "pleroma restarted" end - test "restart pleroma on reboot time subkey" do + test "on reboot time subkey" do captcha = Application.get_env(:pleroma, Pleroma.Captcha) on_exit(fn -> Application.put_env(:pleroma, Pleroma.Captcha, captcha) end) diff --git a/test/daemons/activity_expiration_daemon_test.exs b/test/daemons/activity_expiration_daemon_test.exs deleted file mode 100644 index b51132fb0..000000000 --- a/test/daemons/activity_expiration_daemon_test.exs +++ /dev/null @@ -1,17 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.ActivityExpirationWorkerTest do - use Pleroma.DataCase - alias Pleroma.Activity - import Pleroma.Factory - - test "deletes an activity" do - activity = insert(:note_activity) - expiration = insert(:expiration_in_the_past, %{activity_id: activity.id}) - Pleroma.Daemons.ActivityExpirationDaemon.perform(:execute, expiration.id) - - refute Repo.get(Activity, activity.id) - end -end diff --git a/test/daemons/scheduled_activity_daemon_test.exs b/test/daemons/scheduled_activity_daemon_test.exs deleted file mode 100644 index c8e464491..000000000 --- a/test/daemons/scheduled_activity_daemon_test.exs +++ /dev/null @@ -1,19 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.ScheduledActivityDaemonTest do - use Pleroma.DataCase - alias Pleroma.ScheduledActivity - import Pleroma.Factory - - test "creates a status from the scheduled activity" do - user = insert(:user) - scheduled_activity = insert(:scheduled_activity, user: user, params: %{status: "hi"}) - Pleroma.Daemons.ScheduledActivityDaemon.perform(:execute, scheduled_activity.id) - - refute Repo.get(ScheduledActivity, scheduled_activity.id) - activity = Repo.all(Pleroma.Activity) |> Enum.find(&(&1.actor == user.ap_id)) - assert Pleroma.Object.normalize(activity).data["content"] == "hi" - end -end diff --git a/test/http/request_builder_test.exs b/test/http/request_builder_test.exs index 80ef25d7b..113158c9f 100644 --- a/test/http/request_builder_test.exs +++ b/test/http/request_builder_test.exs @@ -9,6 +9,7 @@ defmodule Pleroma.HTTP.RequestBuilderTest do describe "headers/2" do clear_config([:http, :send_user_agent]) + clear_config([:http, :user_agent]) test "don't send pleroma user agent" do assert RequestBuilder.headers(%{}, []) == %{headers: []} diff --git a/test/object_test.exs b/test/object_test.exs index 5690bedec..75f192da2 100644 --- a/test/object_test.exs +++ b/test/object_test.exs @@ -75,6 +75,7 @@ test "ensures cache is cleared for the object" do describe "delete attachments" do clear_config([Pleroma.Upload]) + clear_config([:instance, :cleanup_attachments]) test "Disabled via config" do Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local) diff --git a/test/plugs/admin_secret_authentication_plug_test.exs b/test/plugs/admin_secret_authentication_plug_test.exs index 506b1f609..e41ce1825 100644 --- a/test/plugs/admin_secret_authentication_plug_test.exs +++ b/test/plugs/admin_secret_authentication_plug_test.exs @@ -23,6 +23,8 @@ test "does nothing if a user is assigned", %{conn: conn} do end describe "when secret set it assigns an admin user" do + clear_config([:admin_token]) + test "with `admin_token` query parameter", %{conn: conn} do Pleroma.Config.put(:admin_token, "password123") diff --git a/test/plugs/http_security_plug_test.exs b/test/plugs/http_security_plug_test.exs index 9c1c20541..aa285d827 100644 --- a/test/plugs/http_security_plug_test.exs +++ b/test/plugs/http_security_plug_test.exs @@ -9,6 +9,7 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do clear_config([:http_securiy, :enabled]) clear_config([:http_security, :sts]) + clear_config([:http_security, :referrer_policy]) describe "http security enabled" do setup do diff --git a/test/plugs/http_signature_plug_test.exs b/test/plugs/http_signature_plug_test.exs index d8ace36da..55e8bafc0 100644 --- a/test/plugs/http_signature_plug_test.exs +++ b/test/plugs/http_signature_plug_test.exs @@ -7,6 +7,7 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do alias Pleroma.Web.Plugs.HTTPSignaturePlug import Plug.Conn + import Phoenix.Controller, only: [put_format: 2] import Mock test "it call HTTPSignatures to check validity if the actor sighed it" do @@ -20,10 +21,69 @@ test "it call HTTPSignatures to check validity if the actor sighed it" do "signature", "keyId=\"http://mastodon.example.org/users/admin#main-key" ) + |> put_format("activity+json") |> HTTPSignaturePlug.call(%{}) assert conn.assigns.valid_signature == true + assert conn.halted == false assert called(HTTPSignatures.validate_conn(:_)) end end + + describe "requires a signature when `authorized_fetch_mode` is enabled" do + setup do + Pleroma.Config.put([:activitypub, :authorized_fetch_mode], true) + + on_exit(fn -> + Pleroma.Config.put([:activitypub, :authorized_fetch_mode], false) + end) + + params = %{"actor" => "http://mastodon.example.org/users/admin"} + conn = build_conn(:get, "/doesntmattter", params) |> put_format("activity+json") + + [conn: conn] + end + + test "when signature header is present", %{conn: conn} do + with_mock HTTPSignatures, validate_conn: fn _ -> false end do + conn = + conn + |> put_req_header( + "signature", + "keyId=\"http://mastodon.example.org/users/admin#main-key" + ) + |> HTTPSignaturePlug.call(%{}) + + assert conn.assigns.valid_signature == false + assert conn.halted == true + assert conn.status == 401 + assert conn.state == :sent + assert conn.resp_body == "Request not signed" + assert called(HTTPSignatures.validate_conn(:_)) + end + + with_mock HTTPSignatures, validate_conn: fn _ -> true end do + conn = + conn + |> put_req_header( + "signature", + "keyId=\"http://mastodon.example.org/users/admin#main-key" + ) + |> HTTPSignaturePlug.call(%{}) + + assert conn.assigns.valid_signature == true + assert conn.halted == false + assert called(HTTPSignatures.validate_conn(:_)) + end + end + + test "halts the connection when `signature` header is not present", %{conn: conn} do + conn = HTTPSignaturePlug.call(conn, %{}) + assert conn.assigns[:valid_signature] == nil + assert conn.halted == true + assert conn.status == 401 + assert conn.state == :sent + assert conn.resp_body == "Request not signed" + end + end end diff --git a/test/plugs/remote_ip_test.exs b/test/plugs/remote_ip_test.exs index d120c588b..93e276454 100644 --- a/test/plugs/remote_ip_test.exs +++ b/test/plugs/remote_ip_test.exs @@ -8,6 +8,10 @@ defmodule Pleroma.Plugs.RemoteIpTest do alias Pleroma.Plugs.RemoteIp + import Pleroma.Tests.Helpers, only: [clear_config: 1, clear_config: 2] + + clear_config(RemoteIp) + test "disabled" do Pleroma.Config.put(RemoteIp, enabled: false) diff --git a/test/plugs/user_enabled_plug_test.exs b/test/plugs/user_enabled_plug_test.exs index a4035bf0e..b6f297552 100644 --- a/test/plugs/user_enabled_plug_test.exs +++ b/test/plugs/user_enabled_plug_test.exs @@ -8,6 +8,8 @@ defmodule Pleroma.Plugs.UserEnabledPlugTest do alias Pleroma.Plugs.UserEnabledPlug import Pleroma.Factory + clear_config([:instance, :account_activation_required]) + test "doesn't do anything if the user isn't set", %{conn: conn} do ret_conn = conn @@ -18,7 +20,6 @@ test "doesn't do anything if the user isn't set", %{conn: conn} do test "with a user that's not confirmed and a config requiring confirmation, it removes that user", %{conn: conn} do - old = Pleroma.Config.get([:instance, :account_activation_required]) Pleroma.Config.put([:instance, :account_activation_required], true) user = insert(:user, confirmation_pending: true) @@ -29,8 +30,6 @@ test "with a user that's not confirmed and a config requiring confirmation, it r |> UserEnabledPlug.call(%{}) assert conn.assigns.user == nil - - Pleroma.Config.put([:instance, :account_activation_required], old) end test "with a user that is deactivated, it removes that user", %{conn: conn} do diff --git a/test/repo_test.exs b/test/repo_test.exs index 5526b0327..2224a6b2b 100644 --- a/test/repo_test.exs +++ b/test/repo_test.exs @@ -67,6 +67,8 @@ test "return error if has not assoc " do :ok end + clear_config([:i_am_aware_this_may_cause_data_loss, :disable_migration_check]) + test "raises if it detects unapplied migrations" do assert_raise Pleroma.Repo.UnappliedMigrationsError, fn -> capture_log(&Repo.check_migrations_applied!/0) @@ -74,18 +76,8 @@ test "raises if it detects unapplied migrations" do end test "doesn't do anything if disabled" do - disable_migration_check = - Pleroma.Config.get([:i_am_aware_this_may_cause_data_loss, :disable_migration_check]) - Pleroma.Config.put([:i_am_aware_this_may_cause_data_loss, :disable_migration_check], true) - on_exit(fn -> - Pleroma.Config.put( - [:i_am_aware_this_may_cause_data_loss, :disable_migration_check], - disable_migration_check - ) - end) - assert :ok == Repo.check_migrations_applied!() end end diff --git a/test/scheduled_activity_test.exs b/test/scheduled_activity_test.exs index dcf12fb49..6c13d300a 100644 --- a/test/scheduled_activity_test.exs +++ b/test/scheduled_activity_test.exs @@ -8,11 +8,51 @@ defmodule Pleroma.ScheduledActivityTest do alias Pleroma.ScheduledActivity import Pleroma.Factory + clear_config([ScheduledActivity, :enabled]) + setup context do DataCase.ensure_local_uploader(context) end describe "creation" do + test "scheduled activities with jobs when ScheduledActivity enabled" do + Pleroma.Config.put([ScheduledActivity, :enabled], true) + user = insert(:user) + + today = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(:timer.minutes(6), :millisecond) + |> NaiveDateTime.to_iso8601() + + attrs = %{params: %{}, scheduled_at: today} + {:ok, sa1} = ScheduledActivity.create(user, attrs) + {:ok, sa2} = ScheduledActivity.create(user, attrs) + + jobs = + Repo.all(from(j in Oban.Job, where: j.queue == "scheduled_activities", select: j.args)) + + assert jobs == [%{"activity_id" => sa1.id}, %{"activity_id" => sa2.id}] + end + + test "scheduled activities without jobs when ScheduledActivity disabled" do + Pleroma.Config.put([ScheduledActivity, :enabled], false) + user = insert(:user) + + today = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(:timer.minutes(6), :millisecond) + |> NaiveDateTime.to_iso8601() + + attrs = %{params: %{}, scheduled_at: today} + {:ok, _sa1} = ScheduledActivity.create(user, attrs) + {:ok, _sa2} = ScheduledActivity.create(user, attrs) + + jobs = + Repo.all(from(j in Oban.Job, where: j.queue == "scheduled_activities", select: j.args)) + + assert jobs == [] + end + test "when daily user limit is exceeded" do user = insert(:user) @@ -24,6 +64,7 @@ test "when daily user limit is exceeded" do attrs = %{params: %{}, scheduled_at: today} {:ok, _} = ScheduledActivity.create(user, attrs) {:ok, _} = ScheduledActivity.create(user, attrs) + {:error, changeset} = ScheduledActivity.create(user, attrs) assert changeset.errors == [scheduled_at: {"daily limit exceeded", []}] end diff --git a/test/support/helpers.ex b/test/support/helpers.ex index 9f817622d..db2f08c81 100644 --- a/test/support/helpers.ex +++ b/test/support/helpers.ex @@ -26,6 +26,7 @@ defmacro clear_config(config_path, do: yield) do end end + @doc "Stores initial config value and restores it after *all* test examples are executed." defmacro clear_config_all(config_path) do quote do clear_config_all(unquote(config_path)) do @@ -33,6 +34,11 @@ defmacro clear_config_all(config_path) do end end + @doc """ + Stores initial config value and restores it after *all* test examples are executed. + Only use if *all* test examples should work with the same stubbed value + (*no* examples set a different value). + """ defmacro clear_config_all(config_path, do: yield) do quote do setup_all do @@ -54,6 +60,12 @@ defmacro __using__(_opts) do clear_config_all: 2 ] + def to_datetime(naive_datetime) do + naive_datetime + |> DateTime.from_naive!("Etc/UTC") + |> DateTime.truncate(:second) + end + def collect_ids(collection) do collection |> Enum.map(& &1.id) diff --git a/test/tasks/config_test.exs b/test/tasks/config_test.exs index d79d34276..2f9405550 100644 --- a/test/tasks/config_test.exs +++ b/test/tasks/config_test.exs @@ -145,7 +145,7 @@ test "load a settings with large values and pass to file", %{temp_file: temp_fil mrf_transparency_exclusions: [], autofollowed_nicknames: [], max_pinned_statuses: 1, - no_attachment_links: true, + attachment_links: false, welcome_user_nickname: nil, welcome_message: nil, max_report_comment_size: 1000, @@ -190,7 +190,7 @@ test "load a settings with large values and pass to file", %{temp_file: temp_fil end assert file == - "#{header}\n\nconfig :pleroma, :instance,\n name: \"Pleroma\",\n email: \"example@example.com\",\n notify_email: \"noreply@example.com\",\n description: \"A Pleroma instance, an alternative fediverse server\",\n limit: 5000,\n chat_limit: 5000,\n remote_limit: 100_000,\n upload_limit: 16_000_000,\n avatar_upload_limit: 2_000_000,\n background_upload_limit: 4_000_000,\n banner_upload_limit: 4_000_000,\n poll_limits: %{\n max_expiration: 31_536_000,\n max_option_chars: 200,\n max_options: 20,\n min_expiration: 0\n },\n registrations_open: true,\n federating: true,\n federation_incoming_replies_max_depth: 100,\n federation_reachability_timeout_days: 7,\n federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n allow_relay: true,\n rewrite_policy: Pleroma.Web.ActivityPub.MRF.NoOpPolicy,\n public: true,\n quarantined_instances: [],\n managed_config: true,\n static_dir: \"instance/static/\",\n allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n mrf_transparency: true,\n mrf_transparency_exclusions: [],\n autofollowed_nicknames: [],\n max_pinned_statuses: 1,\n no_attachment_links: true,\n welcome_user_nickname: nil,\n welcome_message: nil,\n max_report_comment_size: 1000,\n safe_dm_mentions: false,\n healthcheck: false,\n remote_post_retention_days: 90,\n skip_thread_containment: true,\n limit_to_local_content: :unauthenticated,\n user_bio_length: 5000,\n user_name_length: 100,\n max_account_fields: 10,\n max_remote_account_fields: 20,\n account_field_name_length: 512,\n account_field_value_length: 2048,\n external_user_synchronization: true,\n extended_nickname_format: true,\n multi_factor_authentication: [\n totp: [digits: 6, period: 30],\n backup_codes: [number: 2, length: 6]\n ]\n" + "#{header}\n\nconfig :pleroma, :instance,\n name: \"Pleroma\",\n email: \"example@example.com\",\n notify_email: \"noreply@example.com\",\n description: \"A Pleroma instance, an alternative fediverse server\",\n limit: 5000,\n chat_limit: 5000,\n remote_limit: 100_000,\n upload_limit: 16_000_000,\n avatar_upload_limit: 2_000_000,\n background_upload_limit: 4_000_000,\n banner_upload_limit: 4_000_000,\n poll_limits: %{\n max_expiration: 31_536_000,\n max_option_chars: 200,\n max_options: 20,\n min_expiration: 0\n },\n registrations_open: true,\n federating: true,\n federation_incoming_replies_max_depth: 100,\n federation_reachability_timeout_days: 7,\n federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n allow_relay: true,\n rewrite_policy: Pleroma.Web.ActivityPub.MRF.NoOpPolicy,\n public: true,\n quarantined_instances: [],\n managed_config: true,\n static_dir: \"instance/static/\",\n allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n mrf_transparency: true,\n mrf_transparency_exclusions: [],\n autofollowed_nicknames: [],\n max_pinned_statuses: 1,\n attachment_links: false,\n welcome_user_nickname: nil,\n welcome_message: nil,\n max_report_comment_size: 1000,\n safe_dm_mentions: false,\n healthcheck: false,\n remote_post_retention_days: 90,\n skip_thread_containment: true,\n limit_to_local_content: :unauthenticated,\n user_bio_length: 5000,\n user_name_length: 100,\n max_account_fields: 10,\n max_remote_account_fields: 20,\n account_field_name_length: 512,\n account_field_value_length: 2048,\n external_user_synchronization: true,\n extended_nickname_format: true,\n multi_factor_authentication: [\n totp: [digits: 6, period: 30],\n backup_codes: [number: 2, length: 6]\n ]\n" end end end diff --git a/test/user_search_test.exs b/test/user_search_test.exs index 821858476..fe52cc7a1 100644 --- a/test/user_search_test.exs +++ b/test/user_search_test.exs @@ -15,6 +15,8 @@ defmodule Pleroma.UserSearchTest do end describe "User.search" do + clear_config([:instance, :limit_to_local_content]) + test "excluded invisible users from results" do user = insert(:user, %{nickname: "john t1000"}) insert(:user, %{invisible: true, nickname: "john t800"}) @@ -127,8 +129,6 @@ test "find only local users for authenticated users when `limit_to_local_content insert(:user, %{nickname: "lain@pleroma.soykaf.com", local: false}) assert [%{id: ^id}] = User.search("lain") - - Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) end test "find all users for unauthenticated users when `limit_to_local_content` is `false`" do @@ -145,8 +145,6 @@ test "find all users for unauthenticated users when `limit_to_local_content` is |> Enum.sort() assert [u1.id, u2.id, u3.id] == results - - Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) end test "does not yield false-positive matches" do diff --git a/test/user_test.exs b/test/user_test.exs index 1b5e63bd4..2fc42a90d 100644 --- a/test/user_test.exs +++ b/test/user_test.exs @@ -297,15 +297,7 @@ test "local users do not automatically follow local locked accounts" do end describe "unfollow/2" do - setup do - setting = Pleroma.Config.get([:instance, :external_user_synchronization]) - - on_exit(fn -> - Pleroma.Config.put([:instance, :external_user_synchronization], setting) - end) - - :ok - end + clear_config([:instance, :external_user_synchronization]) test "unfollow with syncronizes external user" do Pleroma.Config.put([:instance, :external_user_synchronization], true) @@ -383,6 +375,7 @@ test "fetches correct profile for nickname beginning with number" do password_confirmation: "test", email: "email@example.com" } + clear_config([:instance, :autofollowed_nicknames]) clear_config([:instance, :welcome_message]) clear_config([:instance, :welcome_user_nickname]) @@ -1754,17 +1747,14 @@ test "changes email", %{user: user} do describe "get_cached_by_nickname_or_id" do setup do - limit_to_local_content = Pleroma.Config.get([:instance, :limit_to_local_content]) local_user = insert(:user) remote_user = insert(:user, nickname: "nickname@example.com", local: false) - on_exit(fn -> - Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local_content) - end) - [local_user: local_user, remote_user: remote_user] end + clear_config([:instance, :limit_to_local_content]) + test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{ remote_user: remote_user } do diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index ce68e7d0e..9b7cfee63 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -1224,6 +1224,8 @@ test "creates an undo activity for the last block" do end describe "deletion" do + clear_config([:instance, :rewrite_policy]) + test "it creates a delete activity and deletes the original object" do note = insert(:note_activity) object = Object.normalize(note) @@ -1327,11 +1329,8 @@ test "decreases reply count" do end test "it passes delete activity through MRF before deleting the object" do - rewrite_policy = Pleroma.Config.get([:instance, :rewrite_policy]) Pleroma.Config.put([:instance, :rewrite_policy], Pleroma.Web.ActivityPub.MRF.DropPolicy) - on_exit(fn -> Pleroma.Config.put([:instance, :rewrite_policy], rewrite_policy) end) - note = insert(:note_activity) object = Object.normalize(note) @@ -1396,6 +1395,8 @@ test "it filters broken threads" do end describe "update" do + clear_config([:instance, :max_pinned_statuses]) + test "it creates an update activity with the new user data" do user = insert(:user) {:ok, user} = User.ensure_keys_present(user) diff --git a/test/web/activity_pub/mrf/hellthread_policy_test.exs b/test/web/activity_pub/mrf/hellthread_policy_test.exs index eb6ee4d04..a78752a12 100644 --- a/test/web/activity_pub/mrf/hellthread_policy_test.exs +++ b/test/web/activity_pub/mrf/hellthread_policy_test.exs @@ -26,6 +26,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do [user: user, message: message] end + clear_config(:mrf_hellthread) + describe "reject" do test "rejects the message if the recipient count is above reject_threshold", %{ message: message diff --git a/test/web/activity_pub/mrf/keyword_policy_test.exs b/test/web/activity_pub/mrf/keyword_policy_test.exs index 602892a37..d950ddd56 100644 --- a/test/web/activity_pub/mrf/keyword_policy_test.exs +++ b/test/web/activity_pub/mrf/keyword_policy_test.exs @@ -7,6 +7,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do alias Pleroma.Web.ActivityPub.MRF.KeywordPolicy + clear_config(:mrf_keyword) + setup do Pleroma.Config.put([:mrf_keyword], %{reject: [], federated_timeline_removal: [], replace: []}) end diff --git a/test/web/activity_pub/mrf/mention_policy_test.exs b/test/web/activity_pub/mrf/mention_policy_test.exs index 9fd9c31df..93a55850f 100644 --- a/test/web/activity_pub/mrf/mention_policy_test.exs +++ b/test/web/activity_pub/mrf/mention_policy_test.exs @@ -7,6 +7,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do alias Pleroma.Web.ActivityPub.MRF.MentionPolicy + clear_config(:mrf_mention) + test "pass filter if allow list is empty" do Pleroma.Config.delete([:mrf_mention]) diff --git a/test/web/activity_pub/mrf/subchain_policy_test.exs b/test/web/activity_pub/mrf/subchain_policy_test.exs index f7cbcad48..29065f612 100644 --- a/test/web/activity_pub/mrf/subchain_policy_test.exs +++ b/test/web/activity_pub/mrf/subchain_policy_test.exs @@ -14,6 +14,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicyTest do "object" => %{"content" => "hi"} } + clear_config([:mrf_subchain, :match_actor]) + test "it matches and processes subchains when the actor matches a configured target" do Pleroma.Config.put([:mrf_subchain, :match_actor], %{ ~r/^https:\/\/banned.com/s => [DropPolicy] diff --git a/test/web/activity_pub/transmogrifier/follow_handling_test.exs b/test/web/activity_pub/transmogrifier/follow_handling_test.exs index 1c88b05c2..fd771ac54 100644 --- a/test/web/activity_pub/transmogrifier/follow_handling_test.exs +++ b/test/web/activity_pub/transmogrifier/follow_handling_test.exs @@ -19,6 +19,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do end describe "handle_incoming" do + clear_config([:user, :deny_follow_blocked]) + test "it works for osada follow request" do user = insert(:user) diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs index 5fbdf96f6..908ef4d37 100644 --- a/test/web/admin_api/admin_api_controller_test.exs +++ b/test/web/admin_api/admin_api_controller_test.exs @@ -6,7 +6,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do use Pleroma.Web.ConnCase use Oban.Testing, repo: Pleroma.Repo + import Pleroma.Factory + import ExUnit.CaptureLog + alias Pleroma.Activity + alias Pleroma.Config alias Pleroma.ConfigDB alias Pleroma.HTML alias Pleroma.ModerationLog @@ -19,7 +23,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MediaProxy - import Pleroma.Factory setup_all do Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) @@ -41,7 +44,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do describe "with [:auth, :enforce_oauth_admin_scope_usage]," do clear_config([:auth, :enforce_oauth_admin_scope_usage]) do - Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], true) + Config.put([:auth, :enforce_oauth_admin_scope_usage], true) end test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope", @@ -91,7 +94,7 @@ test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or bro describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do clear_config([:auth, :enforce_oauth_admin_scope_usage]) do - Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], false) + Config.put([:auth, :enforce_oauth_admin_scope_usage], false) end test "GET /api/pleroma/admin/users/:nickname requires " <> @@ -579,11 +582,11 @@ test "/:right DELETE, can remove from a permission group (multiple)", %{ describe "POST /api/pleroma/admin/email_invite, with valid config" do clear_config([:instance, :registrations_open]) do - Pleroma.Config.put([:instance, :registrations_open], false) + Config.put([:instance, :registrations_open], false) end clear_config([:instance, :invites_enabled]) do - Pleroma.Config.put([:instance, :invites_enabled], true) + Config.put([:instance, :invites_enabled], true) end test "sends invitation and returns 204", %{admin: admin, conn: conn} do @@ -602,8 +605,8 @@ test "sends invitation and returns 204", %{admin: admin, conn: conn} do assert token_record refute token_record.used - notify_email = Pleroma.Config.get([:instance, :notify_email]) - instance_name = Pleroma.Config.get([:instance, :name]) + notify_email = Config.get([:instance, :notify_email]) + instance_name = Config.get([:instance, :name]) email = Pleroma.Emails.UserEmail.user_invitation_email( @@ -639,8 +642,8 @@ test "it returns 403 if requested by a non-admin" do clear_config([:instance, :invites_enabled]) test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do - Pleroma.Config.put([:instance, :registrations_open], false) - Pleroma.Config.put([:instance, :invites_enabled], false) + Config.put([:instance, :registrations_open], false) + Config.put([:instance, :invites_enabled], false) conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD") @@ -648,8 +651,8 @@ test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do end test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do - Pleroma.Config.put([:instance, :registrations_open], true) - Pleroma.Config.put([:instance, :invites_enabled], true) + Config.put([:instance, :registrations_open], true) + Config.put([:instance, :invites_enabled], true) conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD") @@ -1886,13 +1889,11 @@ test "returns error when status is not exist", %{conn: conn} do describe "GET /api/pleroma/admin/config" do clear_config(:configurable_from_database) do - Pleroma.Config.put(:configurable_from_database, true) + Config.put(:configurable_from_database, true) end test "when configuration from database is off", %{conn: conn} do - initial = Pleroma.Config.get(:configurable_from_database) - Pleroma.Config.put(:configurable_from_database, false) - on_exit(fn -> Pleroma.Config.put(:configurable_from_database, initial) end) + Config.put(:configurable_from_database, false) conn = get(conn, "/api/pleroma/admin/config") assert json_response(conn, 400) == @@ -2036,11 +2037,12 @@ test "POST /api/pleroma/admin/config error", %{conn: conn} do Application.delete_env(:pleroma, Pleroma.Captcha.NotReal) Application.put_env(:pleroma, :http, http) Application.put_env(:tesla, :adapter, Tesla.Mock) + Restarter.Pleroma.refresh() end) end clear_config(:configurable_from_database) do - Pleroma.Config.put(:configurable_from_database, true) + Config.put(:configurable_from_database, true) end @tag capture_log: true @@ -2249,21 +2251,19 @@ test "saving config with partial update", %{conn: conn} do end test "saving config which need pleroma reboot", %{conn: conn} do - chat = Pleroma.Config.get(:chat) - on_exit(fn -> Pleroma.Config.put(:chat, chat) end) + chat = Config.get(:chat) + on_exit(fn -> Config.put(:chat, chat) end) - conn = - post( - conn, - "/api/pleroma/admin/config", - %{ - configs: [ - %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} - ] - } - ) - - assert json_response(conn, 200) == %{ + assert post( + conn, + "/api/pleroma/admin/config", + %{ + configs: [ + %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} + ] + } + ) + |> json_response(200) == %{ "configs" => [ %{ "db" => [":enabled"], @@ -2274,6 +2274,80 @@ test "saving config which need pleroma reboot", %{conn: conn} do ], "need_reboot" => true } + + configs = + conn + |> get("/api/pleroma/admin/config") + |> json_response(200) + + assert configs["need_reboot"] + + capture_log(fn -> + assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} + end) =~ "pleroma restarted" + + configs = + conn + |> get("/api/pleroma/admin/config") + |> json_response(200) + + refute Map.has_key?(configs, "need_reboot") + end + + test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do + chat = Config.get(:chat) + on_exit(fn -> Config.put(:chat, chat) end) + + assert post( + conn, + "/api/pleroma/admin/config", + %{ + configs: [ + %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]} + ] + } + ) + |> json_response(200) == %{ + "configs" => [ + %{ + "db" => [":enabled"], + "group" => ":pleroma", + "key" => ":chat", + "value" => [%{"tuple" => [":enabled", true]}] + } + ], + "need_reboot" => true + } + + assert post(conn, "/api/pleroma/admin/config", %{ + configs: [ + %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]} + ] + }) + |> json_response(200) == %{ + "configs" => [ + %{ + "group" => ":pleroma", + "key" => ":key1", + "value" => [ + %{"tuple" => [":key3", 3]} + ], + "db" => [":key3"] + } + ], + "need_reboot" => true + } + + capture_log(fn -> + assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} + end) =~ "pleroma restarted" + + configs = + conn + |> get("/api/pleroma/admin/config") + |> json_response(200) + + refute Map.has_key?(configs, "need_reboot") end test "saving config with nested merge", %{conn: conn} do @@ -2410,7 +2484,7 @@ test "saving full setting if value is in full_key_update list", %{conn: conn} do {ExSyslogger, :ex_syslogger} ] - ExUnit.CaptureLog.capture_log(fn -> + capture_log(fn -> require Logger Logger.warn("Ooops...") end) =~ "Ooops..." @@ -2543,7 +2617,7 @@ test "common config example", %{conn: conn} do }) assert Application.get_env(:tesla, :adapter) == Tesla.Adapter.Httpc - assert Pleroma.Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma" + assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma" assert json_response(conn, 200) == %{ "configs" => [ @@ -2979,13 +3053,15 @@ test "proxy tuple ip", %{conn: conn} do describe "GET /api/pleroma/admin/restart" do clear_config(:configurable_from_database) do - Pleroma.Config.put(:configurable_from_database, true) + Config.put(:configurable_from_database, true) end test "pleroma restarts", %{conn: conn} do - ExUnit.CaptureLog.capture_log(fn -> + capture_log(fn -> assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{} end) =~ "pleroma restarted" + + refute Restarter.Pleroma.need_reboot?() end end diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs index 11f7c068f..601c32954 100644 --- a/test/web/common_api/common_api_test.exs +++ b/test/web/common_api/common_api_test.exs @@ -68,6 +68,7 @@ test "with the safe_dm_mention option set, it does not mention people beyond the har = insert(:user) jafnhar = insert(:user) tridi = insert(:user) + Pleroma.Config.put([:instance, :safe_dm_mentions], true) {:ok, activity} = diff --git a/test/web/common_api/common_api_utils_test.exs b/test/web/common_api/common_api_utils_test.exs index 4b761e039..848300ef3 100644 --- a/test/web/common_api/common_api_utils_test.exs +++ b/test/web/common_api/common_api_utils_test.exs @@ -575,11 +575,11 @@ test "returns note data" do end describe "maybe_add_attachments/3" do - test "returns parsed results when no_links is true" do + test "returns parsed results when attachment_links is false" do assert Utils.maybe_add_attachments( {"test", [], ["tags"]}, [], - true + false ) == {"test", [], ["tags"]} end @@ -589,7 +589,7 @@ test "adds attachments to parsed results" do assert Utils.maybe_add_attachments( {"test", [], ["tags"]}, [attachment], - false + true ) == { "test
SakuraPM.png", [], diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/web/mastodon_api/controllers/account_controller_test.exs index e2abcd7c5..8625bb9cf 100644 --- a/test/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/web/mastodon_api/controllers/account_controller_test.exs @@ -15,6 +15,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do import Pleroma.Factory describe "account fetching" do + clear_config([:instance, :limit_to_local_content]) + test "works by id" do user = insert(:user) @@ -44,7 +46,6 @@ test "works by nickname" do end test "works by nickname for remote users" do - limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content]) Pleroma.Config.put([:instance, :limit_to_local_content], false) user = insert(:user, nickname: "user@example.com", local: false) @@ -52,13 +53,11 @@ test "works by nickname for remote users" do build_conn() |> get("/api/v1/accounts/#{user.nickname}") - Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local) assert %{"id" => id} = json_response(conn, 200) assert id == user.id end test "respects limit_to_local_content == :all for remote user nicknames" do - limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content]) Pleroma.Config.put([:instance, :limit_to_local_content], :all) user = insert(:user, nickname: "user@example.com", local: false) @@ -67,12 +66,10 @@ test "respects limit_to_local_content == :all for remote user nicknames" do build_conn() |> get("/api/v1/accounts/#{user.nickname}") - Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local) assert json_response(conn, 404) end test "respects limit_to_local_content == :unauthenticated for remote user nicknames" do - limit_to_local = Pleroma.Config.get([:instance, :limit_to_local_content]) Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated) user = insert(:user, nickname: "user@example.com", local: false) @@ -90,7 +87,6 @@ test "respects limit_to_local_content == :unauthenticated for remote user nickna |> assign(:token, insert(:oauth_token, user: reading_user, scopes: ["read:accounts"])) |> get("/api/v1/accounts/#{user.nickname}") - Pleroma.Config.put([:instance, :limit_to_local_content], limit_to_local) assert %{"id" => id} = json_response(conn, 200) assert id == user.id end @@ -677,6 +673,8 @@ test "returns error when user already registred", %{conn: conn, valid_params: va assert json_response(res, 400) == %{"error" => "{\"email\":[\"has already been taken\"]}"} end + clear_config([Pleroma.Plugs.RemoteIp, :enabled]) + test "rate limit", %{conn: conn} do Pleroma.Config.put([Pleroma.Plugs.RemoteIp, :enabled], true) app_token = insert(:oauth_token, user: nil) diff --git a/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs b/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs index 9666a7f2e..6317d1b47 100644 --- a/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs +++ b/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs @@ -9,6 +9,9 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do alias Pleroma.ScheduledActivity import Pleroma.Factory + import Ecto.Query + + clear_config([ScheduledActivity, :enabled]) test "shows scheduled activities" do %{user: user, conn: conn} = oauth_access(["read:statuses"]) @@ -52,11 +55,26 @@ test "shows a scheduled activity" do end test "updates a scheduled activity" do + Pleroma.Config.put([ScheduledActivity, :enabled], true) %{user: user, conn: conn} = oauth_access(["write:statuses"]) - scheduled_activity = insert(:scheduled_activity, user: user) - new_scheduled_at = - NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond) + scheduled_at = Timex.shift(NaiveDateTime.utc_now(), minutes: 60) + + {:ok, scheduled_activity} = + ScheduledActivity.create( + user, + %{ + scheduled_at: scheduled_at, + params: build(:note).data + } + ) + + job = Repo.one(from(j in Oban.Job, where: j.queue == "scheduled_activities")) + + assert job.args == %{"activity_id" => scheduled_activity.id} + assert DateTime.truncate(job.scheduled_at, :second) == to_datetime(scheduled_at) + + new_scheduled_at = Timex.shift(NaiveDateTime.utc_now(), minutes: 120) res_conn = put(conn, "/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{ @@ -65,6 +83,9 @@ test "updates a scheduled activity" do assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200) assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at) + job = refresh_record(job) + + assert DateTime.truncate(job.scheduled_at, :second) == to_datetime(new_scheduled_at) res_conn = put(conn, "/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at}) @@ -72,8 +93,22 @@ test "updates a scheduled activity" do end test "deletes a scheduled activity" do + Pleroma.Config.put([ScheduledActivity, :enabled], true) %{user: user, conn: conn} = oauth_access(["write:statuses"]) - scheduled_activity = insert(:scheduled_activity, user: user) + scheduled_at = Timex.shift(NaiveDateTime.utc_now(), minutes: 60) + + {:ok, scheduled_activity} = + ScheduledActivity.create( + user, + %{ + scheduled_at: scheduled_at, + params: build(:note).data + } + ) + + job = Repo.one(from(j in Oban.Job, where: j.queue == "scheduled_activities")) + + assert job.args == %{"activity_id" => scheduled_activity.id} res_conn = conn @@ -81,7 +116,8 @@ test "deletes a scheduled activity" do |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}") assert %{} = json_response(res_conn, 200) - assert nil == Repo.get(ScheduledActivity, scheduled_activity.id) + refute Repo.get(ScheduledActivity, scheduled_activity.id) + refute Repo.get(Oban.Job, job.id) res_conn = conn diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs index 83138d7ef..781c3f7dc 100644 --- a/test/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/web/mastodon_api/controllers/status_controller_test.exs @@ -21,6 +21,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do clear_config([:instance, :federating]) clear_config([:instance, :allow_relay]) + clear_config([:rich_media, :enabled]) describe "posting statuses" do setup do: oauth_access(["write:statuses"]) @@ -121,6 +122,32 @@ test "posting a status", %{conn: conn} do NaiveDateTime.to_iso8601(expiration.scheduled_at) end + test "it fails to create a status if `expires_in` is less or equal than an hour", %{ + conn: conn + } do + # 1 hour + expires_in = 60 * 60 + + assert %{"error" => "Expiry date is too soon"} = + conn + |> post("api/v1/statuses", %{ + "status" => "oolong", + "expires_in" => expires_in + }) + |> json_response(422) + + # 30 minutes + expires_in = 30 * 60 + + assert %{"error" => "Expiry date is too soon"} = + conn + |> post("api/v1/statuses", %{ + "status" => "oolong", + "expires_in" => expires_in + }) + |> json_response(422) + end + test "posting an undefined status with an attachment", %{user: user, conn: conn} do file = %Plug.Upload{ content_type: "image/jpg", @@ -1228,4 +1255,23 @@ test "returns the favorites of a user" do assert [] = json_response(third_conn, 200) end + + test "expires_at is nil for another user" do + %{conn: conn, user: user} = oauth_access(["read:statuses"]) + {:ok, activity} = CommonAPI.post(user, %{"status" => "foobar", "expires_in" => 1_000_000}) + + expires_at = + activity.id + |> ActivityExpiration.get_by_activity_id() + |> Map.get(:scheduled_at) + |> NaiveDateTime.to_iso8601() + + assert %{"pleroma" => %{"expires_at" => ^expires_at}} = + conn |> get("/api/v1/statuses/#{activity.id}") |> json_response(:ok) + + %{conn: conn} = oauth_access(["read:statuses"]) + + assert %{"pleroma" => %{"expires_at" => nil}} = + conn |> get("/api/v1/statuses/#{activity.id}") |> json_response(:ok) + 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 fc110417c..560f8179f 100644 --- a/test/web/mastodon_api/views/status_view_test.exs +++ b/test/web/mastodon_api/views/status_view_test.exs @@ -37,15 +37,15 @@ test "has an emoji reaction list" do status = StatusView.render("show.json", activity: activity) assert status[:pleroma][:emoji_reactions] == [ - %{emoji: "☕", count: 2, reacted: false}, - %{emoji: "🍵", count: 1, reacted: false} + %{name: "☕", count: 2, me: false}, + %{name: "🍵", count: 1, me: false} ] status = StatusView.render("show.json", activity: activity, for: user) assert status[:pleroma][:emoji_reactions] == [ - %{emoji: "☕", count: 2, reacted: true}, - %{emoji: "🍵", count: 1, reacted: false} + %{name: "☕", count: 2, me: true}, + %{name: "🍵", count: 1, me: false} ] end @@ -491,7 +491,7 @@ test "a rich media card without an image renders correctly" do title: "Example website" } - %{provider_name: "Example site name"} = + %{provider_name: "example.com"} = StatusView.render("card.json", %{page_url: page_url, rich_media: card}) end @@ -506,7 +506,7 @@ test "a rich media card with all relevant data renders correctly" do description: "Example description" } - %{provider_name: "Example site name"} = + %{provider_name: "example.com"} = StatusView.render("card.json", %{page_url: page_url, rich_media: card}) end end diff --git a/test/web/media_proxy/media_proxy_controller_test.exs b/test/web/media_proxy/media_proxy_controller_test.exs index fdfdb5ec6..8c0c2a0e2 100644 --- a/test/web/media_proxy/media_proxy_controller_test.exs +++ b/test/web/media_proxy/media_proxy_controller_test.exs @@ -7,11 +7,8 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do import Mock alias Pleroma.Config - setup do - media_proxy_config = Config.get([:media_proxy]) || [] - on_exit(fn -> Config.put([:media_proxy], media_proxy_config) end) - :ok - end + clear_config(:media_proxy) + clear_config([Pleroma.Web.Endpoint, :secret_key_base]) test "it returns 404 when MediaProxy disabled", %{conn: conn} do Config.put([:media_proxy, :enabled], false) diff --git a/test/web/media_proxy/media_proxy_test.exs b/test/web/media_proxy/media_proxy_test.exs index 96bdde219..2be5c9de0 100644 --- a/test/web/media_proxy/media_proxy_test.exs +++ b/test/web/media_proxy/media_proxy_test.exs @@ -9,6 +9,7 @@ defmodule Pleroma.Web.MediaProxyTest do alias Pleroma.Web.MediaProxy.MediaProxyController clear_config([:media_proxy, :enabled]) + clear_config(Pleroma.Upload) describe "when enabled" do setup do @@ -224,7 +225,6 @@ test "does not change whitelisted urls" do end test "ensure Pleroma.Upload base_url is always whitelisted" do - upload_config = Pleroma.Config.get([Pleroma.Upload]) media_url = "https://media.pleroma.social" Pleroma.Config.put([Pleroma.Upload, :base_url], media_url) @@ -232,8 +232,6 @@ test "ensure Pleroma.Upload base_url is always whitelisted" do encoded = url(url) assert String.starts_with?(encoded, media_url) - - Pleroma.Config.put([Pleroma.Upload], upload_config) end end end diff --git a/test/web/metadata/opengraph_test.exs b/test/web/metadata/opengraph_test.exs index 4283f72cd..0d47b1cb8 100644 --- a/test/web/metadata/opengraph_test.exs +++ b/test/web/metadata/opengraph_test.exs @@ -7,6 +7,8 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraphTest do import Pleroma.Factory alias Pleroma.Web.Metadata.Providers.OpenGraph + clear_config([Pleroma.Web.Metadata, :unfurl_nsfw]) + test "it renders all supported types of attachments and skips unknown types" do user = insert(:user) diff --git a/test/web/metadata/twitter_card_test.exs b/test/web/metadata/twitter_card_test.exs index 85a654f52..faf347cc6 100644 --- a/test/web/metadata/twitter_card_test.exs +++ b/test/web/metadata/twitter_card_test.exs @@ -13,6 +13,8 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do alias Pleroma.Web.Metadata.Utils alias Pleroma.Web.Router + clear_config([Pleroma.Web.Metadata, :unfurl_nsfw]) + test "it renders twitter card for user info" do user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994") avatar_url = Utils.attachment_url(User.avatar_url(user)) diff --git a/test/web/node_info_test.exs b/test/web/node_info_test.exs index 9a574a38d..d1d7a3ce8 100644 --- a/test/web/node_info_test.exs +++ b/test/web/node_info_test.exs @@ -7,6 +7,9 @@ defmodule Pleroma.Web.NodeInfoTest do import Pleroma.Factory + clear_config([:mrf_simple]) + clear_config(:instance) + test "GET /.well-known/nodeinfo", %{conn: conn} do links = conn @@ -62,11 +65,6 @@ test "returns software.repository field in nodeinfo 2.1", %{conn: conn} do end test "returns fieldsLimits field", %{conn: conn} do - max_account_fields = Pleroma.Config.get([:instance, :max_account_fields]) - max_remote_account_fields = Pleroma.Config.get([:instance, :max_remote_account_fields]) - account_field_name_length = Pleroma.Config.get([:instance, :account_field_name_length]) - account_field_value_length = Pleroma.Config.get([:instance, :account_field_value_length]) - Pleroma.Config.put([:instance, :max_account_fields], 10) Pleroma.Config.put([:instance, :max_remote_account_fields], 15) Pleroma.Config.put([:instance, :account_field_name_length], 255) @@ -81,11 +79,6 @@ test "returns fieldsLimits field", %{conn: conn} do assert response["metadata"]["fieldsLimits"]["maxRemoteFields"] == 15 assert response["metadata"]["fieldsLimits"]["nameLength"] == 255 assert response["metadata"]["fieldsLimits"]["valueLength"] == 2048 - - Pleroma.Config.put([:instance, :max_account_fields], max_account_fields) - Pleroma.Config.put([:instance, :max_remote_account_fields], max_remote_account_fields) - Pleroma.Config.put([:instance, :account_field_name_length], account_field_name_length) - Pleroma.Config.put([:instance, :account_field_value_length], account_field_value_length) end test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do @@ -111,28 +104,28 @@ test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do Pleroma.Config.put([:instance, :safe_dm_mentions], option) end - test "it shows if federation is enabled/disabled", %{conn: conn} do - original = Pleroma.Config.get([:instance, :federating]) + describe "`metadata/federation/enabled`" do + clear_config([:instance, :federating]) - Pleroma.Config.put([:instance, :federating], true) + test "it shows if federation is enabled/disabled", %{conn: conn} do + Pleroma.Config.put([:instance, :federating], true) - response = - conn - |> get("/nodeinfo/2.1.json") - |> json_response(:ok) + response = + conn + |> get("/nodeinfo/2.1.json") + |> json_response(:ok) - assert response["metadata"]["federation"]["enabled"] == true + assert response["metadata"]["federation"]["enabled"] == true - Pleroma.Config.put([:instance, :federating], false) + Pleroma.Config.put([:instance, :federating], false) - response = - conn - |> get("/nodeinfo/2.1.json") - |> json_response(:ok) + response = + conn + |> get("/nodeinfo/2.1.json") + |> json_response(:ok) - assert response["metadata"]["federation"]["enabled"] == false - - Pleroma.Config.put([:instance, :federating], original) + assert response["metadata"]["federation"]["enabled"] == false + end end test "it shows MRF transparency data if enabled", %{conn: conn} do diff --git a/test/web/oauth/oauth_controller_test.exs b/test/web/oauth/oauth_controller_test.exs index adeff8e25..89fcf8c36 100644 --- a/test/web/oauth/oauth_controller_test.exs +++ b/test/web/oauth/oauth_controller_test.exs @@ -17,7 +17,8 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do key: "_test", signing_salt: "cooldude" ] - clear_config_all([:instance, :account_activation_required]) + + clear_config([:instance, :account_activation_required]) describe "in OAuth consumer mode, " do setup 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 be5007de5..36868db38 100644 --- a/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs +++ b/test/web/pleroma_api/controllers/pleroma_api_controller_test.exs @@ -14,7 +14,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIControllerTest do import Pleroma.Factory - test "POST /api/v1/pleroma/statuses/:id/react_with_emoji", %{conn: conn} do + test "PUT /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do user = insert(:user) other_user = insert(:user) @@ -24,18 +24,19 @@ test "POST /api/v1/pleroma/statuses/:id/react_with_emoji", %{conn: conn} do conn |> assign(:user, other_user) |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"])) - |> post("/api/v1/pleroma/statuses/#{activity.id}/react_with_emoji", %{"emoji" => "☕"}) + |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/☕") |> json_response(200) + # We return the status, but this our implementation detail. assert %{"id" => id} = result assert to_string(activity.id) == id assert result["pleroma"]["emoji_reactions"] == [ - %{"emoji" => "☕", "count" => 1, "reacted" => true} + %{"name" => "☕", "count" => 1, "me" => true} ] end - test "POST /api/v1/pleroma/statuses/:id/unreact_with_emoji", %{conn: conn} do + test "DELETE /api/v1/pleroma/statuses/:id/reactions/:emoji", %{conn: conn} do user = insert(:user) other_user = insert(:user) @@ -46,7 +47,7 @@ test "POST /api/v1/pleroma/statuses/:id/unreact_with_emoji", %{conn: conn} do conn |> assign(:user, other_user) |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"])) - |> post("/api/v1/pleroma/statuses/#{activity.id}/unreact_with_emoji", %{"emoji" => "☕"}) + |> delete("/api/v1/pleroma/statuses/#{activity.id}/reactions/☕") assert %{"id" => id} = json_response(result, 200) assert to_string(activity.id) == id @@ -56,7 +57,7 @@ test "POST /api/v1/pleroma/statuses/:id/unreact_with_emoji", %{conn: conn} do assert object.data["reaction_count"] == 0 end - test "GET /api/v1/pleroma/statuses/:id/emoji_reactions_by", %{conn: conn} do + test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do user = insert(:user) other_user = insert(:user) doomed_user = insert(:user) @@ -65,7 +66,7 @@ test "GET /api/v1/pleroma/statuses/:id/emoji_reactions_by", %{conn: conn} do result = conn - |> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by") + |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") |> json_response(200) assert result == [] @@ -77,11 +78,10 @@ test "GET /api/v1/pleroma/statuses/:id/emoji_reactions_by", %{conn: conn} do result = conn - |> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by") + |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") |> json_response(200) - [%{"emoji" => "🎅", "count" => 1, "accounts" => [represented_user], "reacted" => false}] = - result + [%{"name" => "🎅", "count" => 1, "accounts" => [represented_user], "me" => false}] = result assert represented_user["id"] == other_user.id @@ -89,10 +89,10 @@ test "GET /api/v1/pleroma/statuses/:id/emoji_reactions_by", %{conn: conn} do conn |> assign(:user, other_user) |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["read:statuses"])) - |> get("/api/v1/pleroma/statuses/#{activity.id}/emoji_reactions_by") + |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions") |> json_response(200) - assert [%{"emoji" => "🎅", "count" => 1, "accounts" => [_represented_user], "reacted" => true}] = + assert [%{"name" => "🎅", "count" => 1, "accounts" => [_represented_user], "me" => true}] = result end diff --git a/test/web/plugs/federating_plug_test.exs b/test/web/plugs/federating_plug_test.exs index 9dcab93da..c26b487d9 100644 --- a/test/web/plugs/federating_plug_test.exs +++ b/test/web/plugs/federating_plug_test.exs @@ -4,7 +4,8 @@ defmodule Pleroma.Web.FederatingPlugTest do use Pleroma.Web.ConnCase - clear_config_all([:instance, :federating]) + + clear_config([:instance, :federating]) test "returns and halt the conn when federating is disabled" do Pleroma.Config.put([:instance, :federating], false) diff --git a/test/web/rich_media/parsers/twitter_card_test.exs b/test/web/rich_media/parsers/twitter_card_test.exs index 751ca614c..f2ebbde7e 100644 --- a/test/web/rich_media/parsers/twitter_card_test.exs +++ b/test/web/rich_media/parsers/twitter_card_test.exs @@ -7,11 +7,14 @@ defmodule Pleroma.Web.RichMedia.Parsers.TwitterCardTest do alias Pleroma.Web.RichMedia.Parsers.TwitterCard test "returns error when html not contains twitter card" do - assert TwitterCard.parse("", %{}) == {:error, "No twitter card metadata found"} + assert TwitterCard.parse([{"html", [], [{"head", [], []}, {"body", [], []}]}], %{}) == + {:error, "No twitter card metadata found"} end test "parses twitter card with only name attributes" do - html = File.read!("test/fixtures/nypd-facial-recognition-children-teenagers3.html") + html = + File.read!("test/fixtures/nypd-facial-recognition-children-teenagers3.html") + |> Floki.parse_document!() assert TwitterCard.parse(html, %{}) == {:ok, @@ -26,7 +29,9 @@ test "parses twitter card with only name attributes" do end test "parses twitter card with only property attributes" do - html = File.read!("test/fixtures/nypd-facial-recognition-children-teenagers2.html") + html = + File.read!("test/fixtures/nypd-facial-recognition-children-teenagers2.html") + |> Floki.parse_document!() assert TwitterCard.parse(html, %{}) == {:ok, @@ -45,7 +50,9 @@ test "parses twitter card with only property attributes" do end test "parses twitter card with name & property attributes" do - html = File.read!("test/fixtures/nypd-facial-recognition-children-teenagers.html") + html = + File.read!("test/fixtures/nypd-facial-recognition-children-teenagers.html") + |> Floki.parse_document!() assert TwitterCard.parse(html, %{}) == {:ok, @@ -73,7 +80,8 @@ test "respect only first title tag on the page" do "YTQ5MF9EQVIgZXhodW1hdGlvbiBvZiBNYXJnYXJldCBDb3JiaW4gZ3JhdmUgMTkyNi5qcGciXSxbInAiLCJjb252ZXJ0IiwiIl0sWyJwIiwiY29udmVydCIsIi1xdWFsaXR5IDgxIC1hdXRvLW9" <> "yaWVudCJdLFsicCIsInRodW1iIiwiNjAweD4iXV0/DAR%20exhumation%20of%20Margaret%20Corbin%20grave%201926.jpg" - html = File.read!("test/fixtures/margaret-corbin-grave-west-point.html") + html = + File.read!("test/fixtures/margaret-corbin-grave-west-point.html") |> Floki.parse_document!() assert TwitterCard.parse(html, %{}) == {:ok, @@ -87,7 +95,9 @@ test "respect only first title tag on the page" do end test "takes first founded title in html head if there is html markup error" do - html = File.read!("test/fixtures/nypd-facial-recognition-children-teenagers4.html") + html = + File.read!("test/fixtures/nypd-facial-recognition-children-teenagers4.html") + |> Floki.parse_document!() assert TwitterCard.parse(html, %{}) == {:ok, diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs index 2a7550551..1cf20f1c2 100644 --- a/test/web/streamer/streamer_test.exs +++ b/test/web/streamer/streamer_test.exs @@ -20,7 +20,7 @@ defmodule Pleroma.Web.StreamerTest do @streamer_timeout 150 @streamer_start_wait 10 - clear_config_all([:instance, :skip_thread_containment]) + clear_config([:instance, :skip_thread_containment]) describe "user streams" do setup do diff --git a/test/web/twitter_api/remote_follow_controller_test.exs b/test/web/twitter_api/remote_follow_controller_test.exs index 444949375..80a42989d 100644 --- a/test/web/twitter_api/remote_follow_controller_test.exs +++ b/test/web/twitter_api/remote_follow_controller_test.exs @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors +# Copyright © 2017-2020 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do @@ -92,15 +92,13 @@ test "follows user", %{conn: conn} do user = insert(:user) user2 = insert(:user) - response = + conn = conn |> assign(:user, user) |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"])) |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) - |> response(200) - assert response =~ "Account followed!" - assert user2.follower_address in User.following(user) + assert redirected_to(conn) == "/users/#{user2.id}" end test "returns error when user is deactivated", %{conn: conn} do @@ -149,14 +147,13 @@ test "returns success result when user already in followers", %{conn: conn} do user2 = insert(:user) {:ok, _, _, _} = CommonAPI.follow(user, user2) - response = + conn = conn |> assign(:user, refresh_record(user)) |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:follows"])) |> post(remote_follow_path(conn, :do_follow), %{"user" => %{"id" => user2.id}}) - |> response(200) - assert response =~ "Account followed!" + assert redirected_to(conn) == "/users/#{user2.id}" end end @@ -165,14 +162,13 @@ test "follows", %{conn: conn} do user = insert(:user) user2 = insert(:user) - response = + conn = conn |> post(remote_follow_path(conn, :do_follow), %{ "authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id} }) - |> response(200) - assert response =~ "Account followed!" + assert redirected_to(conn) == "/users/#{user2.id}" assert user2.follower_address in User.following(user) end diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/web/twitter_api/twitter_api_controller_test.exs new file mode 100644 index 000000000..ab0a2c3df --- /dev/null +++ b/test/web/twitter_api/twitter_api_controller_test.exs @@ -0,0 +1,142 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.TwitterAPI.ControllerTest do + use Pleroma.Web.ConnCase + + alias Pleroma.Builders.ActivityBuilder + alias Pleroma.Repo + alias Pleroma.User + alias Pleroma.Web.OAuth.Token + + import Pleroma.Factory + + describe "POST /api/qvitter/statuses/notifications/read" do + test "without valid credentials", %{conn: conn} do + conn = post(conn, "/api/qvitter/statuses/notifications/read", %{"latest_id" => 1_234_567}) + assert json_response(conn, 403) == %{"error" => "Invalid credentials."} + end + + test "with credentials, without any params" do + %{user: current_user, conn: conn} = + oauth_access(["read:notifications", "write:notifications"]) + + conn = + conn + |> assign(:user, current_user) + |> post("/api/qvitter/statuses/notifications/read") + + assert json_response(conn, 400) == %{ + "error" => "You need to specify latest_id", + "request" => "/api/qvitter/statuses/notifications/read" + } + end + + test "with credentials, with params" do + %{user: current_user, conn: conn} = + oauth_access(["read:notifications", "write:notifications"]) + + other_user = insert(:user) + + {:ok, _activity} = + ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user}) + + response_conn = + conn + |> assign(:user, current_user) + |> get("/api/v1/notifications") + + [notification] = response = json_response(response_conn, 200) + + assert length(response) == 1 + + assert notification["pleroma"]["is_seen"] == false + + response_conn = + conn + |> assign(:user, current_user) + |> post("/api/qvitter/statuses/notifications/read", %{"latest_id" => notification["id"]}) + + [notification] = response = json_response(response_conn, 200) + + assert length(response) == 1 + + assert notification["pleroma"]["is_seen"] == true + end + end + + describe "GET /api/account/confirm_email/:id/:token" do + setup do + {:ok, user} = + insert(:user) + |> User.confirmation_changeset(need_confirmation: true) + |> Repo.update() + + assert user.confirmation_pending + + [user: user] + end + + test "it redirects to root url", %{conn: conn, user: user} do + conn = get(conn, "/api/account/confirm_email/#{user.id}/#{user.confirmation_token}") + + assert 302 == conn.status + end + + test "it confirms the user account", %{conn: conn, user: user} do + get(conn, "/api/account/confirm_email/#{user.id}/#{user.confirmation_token}") + + user = User.get_cached_by_id(user.id) + + refute user.confirmation_pending + refute user.confirmation_token + end + + test "it returns 500 if user cannot be found by id", %{conn: conn, user: user} do + conn = get(conn, "/api/account/confirm_email/0/#{user.confirmation_token}") + + assert 500 == conn.status + end + + test "it returns 500 if token is invalid", %{conn: conn, user: user} do + conn = get(conn, "/api/account/confirm_email/#{user.id}/wrong_token") + + assert 500 == conn.status + end + end + + describe "GET /api/oauth_tokens" do + setup do + token = insert(:oauth_token) |> Repo.preload(:user) + + %{token: token} + end + + test "renders list", %{token: token} do + response = + build_conn() + |> assign(:user, token.user) + |> get("/api/oauth_tokens") + + keys = + json_response(response, 200) + |> hd() + |> Map.keys() + + assert keys -- ["id", "app_name", "valid_until"] == [] + end + + test "revoke token", %{token: token} do + response = + build_conn() + |> assign(:user, token.user) + |> delete("/api/oauth_tokens/#{token.id}") + + tokens = Token.get_user_tokens(token.user) + + assert tokens == [] + assert response.status == 201 + end + end +end diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/web/twitter_api/twitter_api_test.exs index 85a9be3e0..7650238f2 100644 --- a/test/web/twitter_api/twitter_api_test.exs +++ b/test/web/twitter_api/twitter_api_test.exs @@ -117,15 +117,8 @@ test "it registers a new user and parses mentions in the bio" do end describe "register with one time token" do - setup do - setting = Pleroma.Config.get([:instance, :registrations_open]) - - if setting do - Pleroma.Config.put([:instance, :registrations_open], false) - on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end) - end - - :ok + clear_config([:instance, :registrations_open]) do + Pleroma.Config.put([:instance, :registrations_open], false) end test "returns user on success" do @@ -191,14 +184,11 @@ test "returns error on expired token" do end describe "registers with date limited token" do + clear_config([:instance, :registrations_open]) do + Pleroma.Config.put([:instance, :registrations_open], false) + end + setup do - setting = Pleroma.Config.get([:instance, :registrations_open]) - - if setting do - Pleroma.Config.put([:instance, :registrations_open], false) - on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end) - end - data = %{ "nickname" => "vinny", "email" => "pasta@pizza.vs", @@ -256,15 +246,8 @@ test "returns an error on overdue date", %{data: data} do end describe "registers with reusable token" do - setup do - setting = Pleroma.Config.get([:instance, :registrations_open]) - - if setting do - Pleroma.Config.put([:instance, :registrations_open], false) - on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end) - end - - :ok + clear_config([:instance, :registrations_open]) do + Pleroma.Config.put([:instance, :registrations_open], false) end test "returns user on success, after him registration fails" do @@ -309,15 +292,8 @@ test "returns user on success, after him registration fails" do end describe "registers with reusable date limited token" do - setup do - setting = Pleroma.Config.get([:instance, :registrations_open]) - - if setting do - Pleroma.Config.put([:instance, :registrations_open], false) - on_exit(fn -> Pleroma.Config.put([:instance, :registrations_open], setting) end) - end - - :ok + clear_config([:instance, :registrations_open]) do + Pleroma.Config.put([:instance, :registrations_open], false) end test "returns user on success" do diff --git a/test/web/twitter_api/util_controller_test.exs b/test/web/twitter_api/util_controller_test.exs index 5d60c0d51..56633ffce 100644 --- a/test/web/twitter_api/util_controller_test.exs +++ b/test/web/twitter_api/util_controller_test.exs @@ -19,7 +19,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do clear_config([:instance]) clear_config([:frontend_configurations, :pleroma_fe]) - clear_config([:user, :deny_follow_blocked]) describe "POST /api/pleroma/follow_import" do setup do: oauth_access(["follow"]) diff --git a/test/workers/cron/clear_oauth_token_worker_test.exs b/test/workers/cron/clear_oauth_token_worker_test.exs new file mode 100644 index 000000000..adea47326 --- /dev/null +++ b/test/workers/cron/clear_oauth_token_worker_test.exs @@ -0,0 +1,22 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Cron.ClearOauthTokenWorkerTest do + use Pleroma.DataCase + + import Pleroma.Factory + alias Pleroma.Workers.Cron.ClearOauthTokenWorker + + clear_config([:oauth2, :clean_expired_tokens]) + + test "deletes expired tokens" do + insert(:oauth_token, + valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), -60 * 10) + ) + + Pleroma.Config.put([:oauth2, :clean_expired_tokens], true) + ClearOauthTokenWorker.perform(:opts, :job) + assert Pleroma.Repo.all(Pleroma.Web.OAuth.Token) == [] + end +end diff --git a/test/daemons/digest_email_daemon_test.exs b/test/workers/cron/digest_emails_worker_test.exs similarity index 74% rename from test/daemons/digest_email_daemon_test.exs rename to test/workers/cron/digest_emails_worker_test.exs index faf592d5f..073615d9e 100644 --- a/test/daemons/digest_email_daemon_test.exs +++ b/test/workers/cron/digest_emails_worker_test.exs @@ -2,16 +2,24 @@ # Copyright © 2017-2019 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only -defmodule Pleroma.DigestEmailDaemonTest do +defmodule Pleroma.Workers.Cron.DigestEmailsWorkerTest do use Pleroma.DataCase + import Pleroma.Factory - alias Pleroma.Daemons.DigestEmailDaemon alias Pleroma.Tests.ObanHelpers alias Pleroma.User alias Pleroma.Web.CommonAPI + clear_config([:email_notifications, :digest]) + test "it sends digest emails" do + Pleroma.Config.put([:email_notifications, :digest], %{ + active: true, + inactivity_threshold: 7, + interval: 7 + }) + user = insert(:user) date = @@ -23,8 +31,7 @@ test "it sends digest emails" do {:ok, _} = User.switch_email_notifications(user2, "digest", true) CommonAPI.post(user, %{"status" => "hey @#{user2.nickname}!"}) - DigestEmailDaemon.perform() - ObanHelpers.perform_all() + Pleroma.Workers.Cron.DigestEmailsWorker.perform(:opts, :pid) # Performing job(s) enqueued at previous step ObanHelpers.perform_all() diff --git a/test/workers/cron/new_users_digest_worker_test.exs b/test/workers/cron/new_users_digest_worker_test.exs new file mode 100644 index 000000000..2f439c1fe --- /dev/null +++ b/test/workers/cron/new_users_digest_worker_test.exs @@ -0,0 +1,32 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Cron.NewUsersDigestWorkerTest do + use Pleroma.DataCase + import Pleroma.Factory + + alias Pleroma.Tests.ObanHelpers + alias Pleroma.Web.CommonAPI + alias Pleroma.Workers.Cron.NewUsersDigestWorker + + test "it sends new users digest emails" do + yesterday = NaiveDateTime.utc_now() |> Timex.shift(days: -1) + admin = insert(:user, %{is_admin: true}) + user = insert(:user, %{inserted_at: yesterday}) + user2 = insert(:user, %{inserted_at: yesterday}) + CommonAPI.post(user, %{"status" => "cofe"}) + + NewUsersDigestWorker.perform(nil, nil) + ObanHelpers.perform_all() + + assert_received {:email, email} + assert email.to == [{admin.name, admin.email}] + assert email.subject == "#{Pleroma.Config.get([:instance, :name])} New Users" + + refute email.html_body =~ admin.nickname + assert email.html_body =~ user.nickname + assert email.html_body =~ user2.nickname + assert email.html_body =~ "cofe" + end +end diff --git a/test/workers/cron/purge_expired_activities_worker_test.exs b/test/workers/cron/purge_expired_activities_worker_test.exs new file mode 100644 index 000000000..c2561683e --- /dev/null +++ b/test/workers/cron/purge_expired_activities_worker_test.exs @@ -0,0 +1,56 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.Cron.PurgeExpiredActivitiesWorkerTest do + use Pleroma.DataCase + + alias Pleroma.ActivityExpiration + alias Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker + + import Pleroma.Factory + import ExUnit.CaptureLog + + clear_config([ActivityExpiration, :enabled]) + + test "deletes an expiration activity" do + Pleroma.Config.put([ActivityExpiration, :enabled], true) + activity = insert(:note_activity) + + naive_datetime = + NaiveDateTime.add( + NaiveDateTime.utc_now(), + -:timer.minutes(2), + :millisecond + ) + + expiration = + insert( + :expiration_in_the_past, + %{activity_id: activity.id, scheduled_at: naive_datetime} + ) + + Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker.perform(:ops, :pid) + + refute Pleroma.Repo.get(Pleroma.Activity, activity.id) + refute Pleroma.Repo.get(Pleroma.ActivityExpiration, expiration.id) + end + + describe "delete_activity/1" do + test "adds log message if activity isn't find" do + assert capture_log([level: :error], fn -> + PurgeExpiredActivitiesWorker.delete_activity(%ActivityExpiration{ + activity_id: "test-activity" + }) + end) =~ "Couldn't delete expired activity: not found activity" + end + + test "adds log message if actor isn't find" do + assert capture_log([level: :error], fn -> + PurgeExpiredActivitiesWorker.delete_activity(%ActivityExpiration{ + activity_id: "test-activity" + }) + end) =~ "Couldn't delete expired activity: not found activity" + end + end +end diff --git a/test/workers/scheduled_activity_worker_test.exs b/test/workers/scheduled_activity_worker_test.exs new file mode 100644 index 000000000..1405d7142 --- /dev/null +++ b/test/workers/scheduled_activity_worker_test.exs @@ -0,0 +1,52 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Workers.ScheduledActivityWorkerTest do + use Pleroma.DataCase + + alias Pleroma.ScheduledActivity + alias Pleroma.Workers.ScheduledActivityWorker + + import Pleroma.Factory + import ExUnit.CaptureLog + + clear_config([ScheduledActivity, :enabled]) + + test "creates a status from the scheduled activity" do + Pleroma.Config.put([ScheduledActivity, :enabled], true) + user = insert(:user) + + naive_datetime = + NaiveDateTime.add( + NaiveDateTime.utc_now(), + -:timer.minutes(2), + :millisecond + ) + + scheduled_activity = + insert( + :scheduled_activity, + scheduled_at: naive_datetime, + user: user, + params: %{status: "hi"} + ) + + ScheduledActivityWorker.perform( + %{"activity_id" => scheduled_activity.id}, + :pid + ) + + refute Repo.get(ScheduledActivity, scheduled_activity.id) + activity = Repo.all(Pleroma.Activity) |> Enum.find(&(&1.actor == user.ap_id)) + assert Pleroma.Object.normalize(activity).data["content"] == "hi" + end + + test "adds log message if ScheduledActivity isn't find" do + Pleroma.Config.put([ScheduledActivity, :enabled], true) + + assert capture_log([level: :error], fn -> + ScheduledActivityWorker.perform(%{"activity_id" => 42}, :pid) + end) =~ "Couldn't find scheduled activity" + end +end