From 0ba6ab88a9f5c28e629d196c671f89ce15f23a6b Mon Sep 17 00:00:00 2001 From: tobi Date: Sun, 15 Dec 2024 17:19:57 +0100 Subject: [PATCH] weeeeeeeee --- .devcontainer/Dockerfile | 20 - .devcontainer/codespaces/devcontainer.json | 49 - .devcontainer/devcontainer.json | 40 - .devcontainer/docker-compose.yml | 90 -- .devcontainer/post-create.sh | 26 - .devcontainer/welcome-message.txt | 8 - .dockerignore | 21 - .env.production.sample | 303 ---- .env.vagrant | 8 - .github/FUNDING.yml | 3 - .github/renovate.json5 | 124 -- .github/stale.yml | 10 - .github/stylelint-matcher.json | 21 - .github/workflows/build-container-image.yml | 99 -- .github/workflows/build-nightly.yml | 41 - .github/workflows/build-push-pr.yml | 41 - .github/workflows/build-releases.yml | 28 - .github/workflows/bundler-audit.yml | 40 - .github/workflows/check-i18n.yml | 62 - .github/workflows/codeql.yml | 62 - .github/workflows/crowdin-download.yml | 77 - .github/workflows/crowdin-upload.yml | 36 - .../workflows/haml-lint-problem-matcher.json | 17 - .github/workflows/lint-css.yml | 52 - .github/workflows/lint-haml.yml | 47 - .github/workflows/lint-js.yml | 55 - .github/workflows/lint-json.yml | 44 - .github/workflows/lint-md.yml | 44 - .github/workflows/lint-ruby.yml | 51 - .github/workflows/lint-yml.yml | 46 - .github/workflows/rebase-needed.yml | 27 - .github/workflows/test-image-build.yml | 21 - .github/workflows/test-js.yml | 48 - .../workflows/test-migrations-one-step.yml | 111 -- .../workflows/test-migrations-two-step.yml | 119 -- .github/workflows/test-ruby.yml | 370 ----- .haml-lint.yml | 14 - .haml-lint_todo.yml | 41 - CODE_OF_CONDUCT.md | 46 - CONTRIBUTING.md | 87 -- Dockerfile | 107 +- FEDERATION.md | 31 - Gemfile | 201 --- Gemfile.lock | 929 ----------- Procfile | 14 - Rakefile | 8 - SECURITY.md | 22 - Vagrantfile | 190 --- app/chewy/accounts_index.rb | 68 - app/chewy/instances_index.rb | 12 - app/chewy/public_statuses_index.rb | 67 - app/chewy/statuses_index.rb | 65 - app/chewy/tags_index.rb | 47 - app/controllers/about_controller.rb | 11 - app/controllers/accounts_controller.rb | 112 -- .../activitypub/base_controller.rb | 13 - .../activitypub/claims_controller.rb | 21 - .../activitypub/collections_controller.rb | 75 - .../followers_synchronizations_controller.rb | 37 - .../activitypub/inboxes_controller.rb | 76 - .../activitypub/outboxes_controller.rb | 85 - .../activitypub/replies_controller.rb | 95 -- .../admin/account_actions_controller.rb | 40 - .../account_moderation_notes_controller.rb | 42 - app/controllers/admin/accounts_controller.rb | 174 --- .../admin/action_logs_controller.rb | 22 - .../admin/announcements_controller.rb | 88 -- app/controllers/admin/base_controller.rb | 34 - .../admin/change_emails_controller.rb | 49 - .../admin/confirmations_controller.rb | 35 - .../admin/custom_emojis_controller.rb | 83 - app/controllers/admin/dashboard_controller.rb | 18 - .../admin/disputes/appeals_controller.rb | 40 - .../admin/domain_allows_controller.rb | 40 - .../admin/domain_blocks_controller.rb | 110 -- .../admin/email_domain_blocks_controller.rb | 83 - .../admin/export_domain_allows_controller.rb | 58 - .../admin/export_domain_blocks_controller.rb | 77 - .../follow_recommendations_controller.rb | 55 - app/controllers/admin/instances_controller.rb | 75 - app/controllers/admin/invites_controller.rb | 53 - app/controllers/admin/ip_blocks_controller.rb | 58 - .../admin/relationships_controller.rb | 26 - app/controllers/admin/relays_controller.rb | 63 - .../admin/report_notes_controller.rb | 60 - .../admin/reports/actions_controller.rb | 63 - app/controllers/admin/reports_controller.rb | 64 - app/controllers/admin/resets_controller.rb | 14 - app/controllers/admin/roles_controller.rb | 67 - app/controllers/admin/rules_controller.rb | 59 - .../admin/settings/about_controller.rb | 9 - .../admin/settings/appearance_controller.rb | 9 - .../admin/settings/branding_controller.rb | 9 - .../settings/content_retention_controller.rb | 9 - .../admin/settings/discovery_controller.rb | 9 - .../admin/settings/other_controller.rb | 9 - .../settings/registrations_controller.rb | 9 - app/controllers/admin/settings_controller.rb | 34 - .../admin/site_uploads_controller.rb | 21 - .../admin/software_updates_controller.rb | 18 - app/controllers/admin/statuses_controller.rb | 78 - app/controllers/admin/tags_controller.rb | 35 - .../preview_card_providers_controller.rb | 43 - .../admin/trends/links_controller.rb | 48 - .../admin/trends/statuses_controller.rb | 48 - .../admin/trends/tags_controller.rb | 43 - .../admin/users/roles_controller.rb | 34 - .../two_factor_authentications_controller.rb | 21 - .../admin/warning_presets_controller.rb | 58 - .../admin/webhooks/secrets_controller.rb | 19 - app/controllers/admin/webhooks_controller.rb | 80 - app/controllers/api/base_controller.rb | 161 -- app/controllers/api/oembed_controller.rb | 34 - .../api/v1/accounts/credentials_controller.rb | 51 - .../accounts/familiar_followers_controller.rb | 25 - .../v1/accounts/featured_tags_controller.rb | 22 - .../accounts/follower_accounts_controller.rb | 71 - .../accounts/following_accounts_controller.rb | 71 - .../v1/accounts/identity_proofs_controller.rb | 16 - .../api/v1/accounts/lists_controller.rb | 18 - .../api/v1/accounts/lookup_controller.rb | 19 - .../api/v1/accounts/notes_controller.rb | 30 - .../api/v1/accounts/pins_controller.rb | 30 - .../v1/accounts/relationships_controller.rb | 24 - .../api/v1/accounts/search_controller.rb | 24 - .../api/v1/accounts/statuses_controller.rb | 61 - app/controllers/api/v1/accounts_controller.rb | 107 -- .../v1/admin/account_actions_controller.rb | 37 - .../api/v1/admin/accounts_controller.rb | 159 -- .../canonical_email_blocks_controller.rb | 95 -- .../api/v1/admin/dimensions_controller.rb | 27 - .../api/v1/admin/domain_allows_controller.rb | 95 -- .../api/v1/admin/domain_blocks_controller.rb | 106 -- .../admin/email_domain_blocks_controller.rb | 88 -- .../api/v1/admin/ip_blocks_controller.rb | 93 -- .../api/v1/admin/measures_controller.rb | 26 - .../api/v1/admin/reports_controller.rb | 118 -- .../api/v1/admin/retention_controller.rb | 25 - .../api/v1/admin/tags_controller.rb | 74 - .../preview_card_providers_controller.rb | 72 - .../api/v1/admin/trends/links_controller.rb | 48 - .../v1/admin/trends/statuses_controller.rb | 48 - .../api/v1/admin/trends/tags_controller.rb | 48 - .../v1/announcements/reactions_controller.rb | 29 - .../api/v1/announcements_controller.rb | 27 - .../api/v1/apps/credentials_controller.rb | 9 - app/controllers/api/v1/apps_controller.rb | 29 - app/controllers/api/v1/blocks_controller.rb | 58 - .../api/v1/bookmarks_controller.rb | 61 - .../api/v1/conversations_controller.rb | 83 - .../api/v1/crypto/deliveries_controller.rb | 30 - .../crypto/encrypted_messages_controller.rb | 59 - .../api/v1/crypto/keys/claims_controller.rb | 25 - .../api/v1/crypto/keys/counts_controller.rb | 17 - .../api/v1/crypto/keys/queries_controller.rb | 26 - .../api/v1/crypto/keys/uploads_controller.rb | 29 - .../api/v1/custom_emojis_controller.rb | 10 - .../api/v1/directories_controller.rb | 57 - .../api/v1/domain_blocks_controller.rb | 72 - .../api/v1/emails/confirmations_controller.rb | 30 - .../api/v1/endorsements_controller.rb | 66 - .../api/v1/favourites_controller.rb | 61 - .../featured_tags/suggestions_controller.rb | 17 - .../api/v1/featured_tags_controller.rb | 34 - app/controllers/api/v1/filters_controller.rb | 65 - .../api/v1/follow_requests_controller.rb | 78 - .../api/v1/followed_tags_controller.rb | 52 - .../api/v1/instances/activity_controller.rb | 38 - .../v1/instances/domain_blocks_controller.rb | 30 - .../extended_descriptions_controller.rb | 26 - .../api/v1/instances/languages_controller.rb | 21 - .../api/v1/instances/peers_controller.rb | 26 - .../instances/privacy_policies_controller.rb | 20 - .../api/v1/instances/rules_controller.rb | 26 - .../translation_languages_controller.rb | 25 - .../api/v1/instances_controller.rb | 18 - .../api/v1/lists/accounts_controller.rb | 93 -- app/controllers/api/v1/lists_controller.rb | 47 - app/controllers/api/v1/markers_controller.rb | 47 - app/controllers/api/v1/media_controller.rb | 57 - app/controllers/api/v1/mutes_controller.rb | 58 - .../api/v1/notifications_controller.rb | 96 -- .../api/v1/peers/search_controller.rb | 47 - .../api/v1/polls/votes_controller.rb | 27 - app/controllers/api/v1/polls_controller.rb | 27 - .../api/v1/preferences_controller.rb | 10 - .../api/v1/profile/avatars_controller.rb | 13 - .../api/v1/profile/headers_controller.rb | 13 - .../api/v1/push/subscriptions_controller.rb | 57 - app/controllers/api/v1/reports_controller.rb | 28 - .../api/v1/scheduled_statuses_controller.rb | 73 - .../api/v1/statuses/bookmarks_controller.rb | 40 - .../favourited_by_accounts_controller.rb | 74 - .../api/v1/statuses/favourites_controller.rb | 42 - .../api/v1/statuses/histories_controller.rb | 26 - .../api/v1/statuses/mutes_controller.rb | 38 - .../api/v1/statuses/pins_controller.rb | 52 - .../reblogged_by_accounts_controller.rb | 70 - .../api/v1/statuses/reblogs_controller.rb | 55 - .../api/v1/statuses/sources_controller.rb | 21 - .../v1/statuses/translations_controller.rb | 37 - app/controllers/api/v1/statuses_controller.rb | 164 -- .../api/v1/streaming_controller.rb | 19 - .../api/v1/suggestions_controller.rb | 24 - app/controllers/api/v1/tags_controller.rb | 33 - .../api/v1/timelines/direct_controller.rb | 65 - .../api/v1/timelines/home_controller.rb | 66 - .../api/v1/timelines/list_controller.rb | 67 - .../api/v1/timelines/public_controller.rb | 71 - .../api/v1/timelines/tag_controller.rb | 77 - .../api/v1/trends/links_controller.rb | 60 - .../api/v1/trends/statuses_controller.rb | 58 - .../api/v1/trends/tags_controller.rb | 56 - .../api/v2/admin/accounts_controller.rb | 48 - .../api/v2/filters/keywords_controller.rb | 50 - .../api/v2/filters/statuses_controller.rb | 44 - app/controllers/api/v2/filters_controller.rb | 48 - .../api/v2/instances_controller.rb | 8 - app/controllers/api/v2/media_controller.rb | 13 - app/controllers/api/v2/search_controller.rb | 44 - .../api/v2/suggestions_controller.rb | 19 - app/controllers/api/web/base_controller.rb | 9 - app/controllers/api/web/embeds_controller.rb | 36 - .../api/web/push_subscriptions_controller.rb | 57 - .../api/web/settings_controller.rb | 17 - app/controllers/application_controller.rb | 175 --- app/controllers/auth/challenges_controller.rb | 29 - .../auth/confirmations_controller.rb | 97 -- .../auth/omniauth_callbacks_controller.rb | 58 - app/controllers/auth/passwords_controller.rb | 40 - .../auth/registrations_controller.rb | 157 -- app/controllers/auth/sessions_controller.rb | 171 -- app/controllers/auth/setup_controller.rb | 50 - .../authorize_interactions_controller.rb | 51 - app/controllers/backups_controller.rb | 31 - .../concerns/access_token_tracking_concern.rb | 21 - .../concerns/account_controller_concern.rb | 43 - .../concerns/account_owned_concern.rb | 57 - .../concerns/accountable_concern.rb | 13 - .../admin_export_controller_concern.rb | 29 - .../concerns/api_caching_concern.rb | 13 - app/controllers/concerns/authorization.rb | 23 - app/controllers/concerns/cache_concern.rb | 231 --- app/controllers/concerns/captcha_concern.rb | 66 - .../concerns/challengable_concern.rb | 64 - .../concerns/export_controller_concern.rb | 32 - app/controllers/concerns/localized.rb | 34 - .../concerns/rate_limit_headers.rb | 70 - .../concerns/registration_spam_concern.rb | 9 - .../concerns/session_tracking_concern.rb | 23 - .../concerns/signature_authentication.rb | 11 - .../concerns/signature_verification.rb | 280 ---- app/controllers/concerns/theming_concern.rb | 89 -- .../two_factor_authentication_concern.rb | 92 -- .../concerns/user_tracking_concern.rb | 21 - .../concerns/web_app_controller_concern.rb | 35 - app/controllers/custom_css_controller.rb | 8 - .../disputes/appeals_controller.rb | 26 - app/controllers/disputes/base_controller.rb | 28 - .../disputes/strikes_controller.rb | 21 - app/controllers/emojis_controller.rb | 18 - .../filters/statuses_controller.rb | 57 - app/controllers/filters_controller.rb | 67 - .../follower_accounts_controller.rb | 88 -- .../following_accounts_controller.rb | 91 -- app/controllers/health_controller.rb | 7 - app/controllers/home_controller.rb | 9 - app/controllers/instance_actors_controller.rb | 26 - app/controllers/intents_controller.rb | 34 - app/controllers/invites_controller.rb | 62 - .../mail_subscriptions_controller.rb | 44 - app/controllers/manifests_controller.rb | 12 - app/controllers/media_controller.rb | 55 - app/controllers/media_proxy_controller.rb | 47 - .../oauth/authorizations_controller.rb | 44 - .../authorized_applications_controller.rb | 55 - app/controllers/oauth/tokens_controller.rb | 15 - app/controllers/privacy_controller.rb | 11 - app/controllers/relationships_controller.rb | 83 - .../remote_interaction_helper_controller.rb | 43 - .../settings/aliases_controller.rb | 43 - .../settings/applications_controller.rb | 75 - app/controllers/settings/base_controller.rb | 28 - .../settings/deletes_controller.rb | 44 - .../exports/blocked_accounts_controller.rb | 19 - .../exports/blocked_domains_controller.rb | 19 - .../settings/exports/bookmarks_controller.rb | 19 - .../exports/following_accounts_controller.rb | 19 - .../settings/exports/lists_controller.rb | 19 - .../exports/muted_accounts_controller.rb | 19 - .../settings/exports_controller.rb | 27 - .../settings/featured_tags_controller.rb | 47 - .../settings/flavours_controller.rb | 26 - .../settings/imports_controller.rb | 101 -- .../settings/login_activities_controller.rb | 13 - .../migration/redirects_controller.rb | 38 - .../settings/migrations_controller.rb | 44 - .../settings/pictures_controller.rb | 35 - .../preferences/appearance_controller.rb | 9 - .../settings/preferences/base_controller.rb | 24 - .../preferences/notifications_controller.rb | 9 - .../settings/preferences/other_controller.rb | 9 - .../settings/privacy_controller.rb | 27 - .../settings/profiles_controller.rb | 29 - .../settings/sessions_controller.rb | 20 - .../confirmations_controller.rb | 58 - .../otp_authentication_controller.rb | 30 - .../recovery_codes_controller.rb | 23 - .../webauthn_credentials_controller.rb | 106 -- ...actor_authentication_methods_controller.rb | 27 - .../settings/verifications_controller.rb | 15 - app/controllers/shares_controller.rb | 21 - .../statuses_cleanup_controller.rb | 49 - app/controllers/statuses_controller.rb | 73 - app/controllers/tags_controller.rb | 61 - .../well_known/host_meta_controller.rb | 13 - .../well_known/nodeinfo_controller.rb | 21 - .../well_known/webfinger_controller.rb | 63 - app/helpers/accounts_helper.rb | 56 - .../admin/account_moderation_notes_helper.rb | 30 - app/helpers/admin/action_logs_helper.rb | 38 - app/helpers/admin/announcements_helper.rb | 11 - app/helpers/admin/dashboard_helper.rb | 39 - app/helpers/admin/filter_helper.rb | 53 - app/helpers/admin/settings_helper.rb | 7 - app/helpers/admin/trends/statuses_helper.rb | 15 - app/helpers/application_helper.rb | 241 --- app/helpers/authorized_fetch_helper.rb | 11 - app/helpers/branding_helper.rb | 35 - app/helpers/context_helper.rb | 64 - app/helpers/database_helper.rb | 24 - app/helpers/domain_control_helper.rb | 23 - app/helpers/email_helper.rb | 18 - app/helpers/flashes_helper.rb | 7 - app/helpers/formatting_helper.rb | 63 - app/helpers/home_helper.rb | 69 - app/helpers/instance_helper.rb | 25 - app/helpers/invites_helper.rb | 11 - app/helpers/jsonld_helper.rb | 229 --- app/helpers/languages_helper.rb | 302 ---- app/helpers/mascot_helper.rb | 11 - app/helpers/media_component_helper.rb | 112 -- app/helpers/react_component_helper.rb | 23 - app/helpers/routing_helper.rb | 34 - app/helpers/settings_helper.rb | 31 - app/helpers/statuses_helper.rb | 88 -- app/helpers/webfinger_helper.rb | 7 - .../flavours/glitch/features/about/index.jsx | 2 +- .../compose/components/navigation_bar.jsx | 2 +- .../mastodon/features/about/index.jsx | 2 +- app/javascript/mastodon/locales/af.json | 2 +- app/javascript/mastodon/locales/an.json | 2 +- app/javascript/mastodon/locales/ar.json | 2 +- app/javascript/mastodon/locales/ast.json | 2 +- app/javascript/mastodon/locales/be.json | 2 +- app/javascript/mastodon/locales/bg.json | 2 +- app/javascript/mastodon/locales/bn.json | 2 +- app/javascript/mastodon/locales/br.json | 2 +- app/javascript/mastodon/locales/ca.json | 2 +- app/javascript/mastodon/locales/ckb.json | 2 +- app/javascript/mastodon/locales/cs.json | 2 +- app/javascript/mastodon/locales/cy.json | 2 +- app/javascript/mastodon/locales/da.json | 2 +- app/javascript/mastodon/locales/de.json | 2 +- app/javascript/mastodon/locales/el.json | 2 +- app/javascript/mastodon/locales/en-GB.json | 2 +- app/javascript/mastodon/locales/en.json | 2 +- app/javascript/mastodon/locales/eo.json | 2 +- app/javascript/mastodon/locales/es-AR.json | 2 +- app/javascript/mastodon/locales/es-MX.json | 2 +- app/javascript/mastodon/locales/es.json | 2 +- app/javascript/mastodon/locales/et.json | 2 +- app/javascript/mastodon/locales/eu.json | 2 +- app/javascript/mastodon/locales/fa.json | 2 +- app/javascript/mastodon/locales/fi.json | 2 +- app/javascript/mastodon/locales/fo.json | 2 +- app/javascript/mastodon/locales/fr-QC.json | 2 +- app/javascript/mastodon/locales/fr.json | 2 +- app/javascript/mastodon/locales/fy.json | 2 +- app/javascript/mastodon/locales/ga.json | 2 +- app/javascript/mastodon/locales/gd.json | 2 +- app/javascript/mastodon/locales/gl.json | 2 +- app/javascript/mastodon/locales/he.json | 2 +- app/javascript/mastodon/locales/hi.json | 2 +- app/javascript/mastodon/locales/hu.json | 2 +- app/javascript/mastodon/locales/hy.json | 2 +- app/javascript/mastodon/locales/id.json | 2 +- app/javascript/mastodon/locales/io.json | 2 +- app/javascript/mastodon/locales/is.json | 2 +- app/javascript/mastodon/locales/it.json | 2 +- app/javascript/mastodon/locales/ja.json | 2 +- app/javascript/mastodon/locales/kk.json | 2 +- app/javascript/mastodon/locales/ko.json | 2 +- app/javascript/mastodon/locales/ku.json | 2 +- app/javascript/mastodon/locales/lv.json | 2 +- app/javascript/mastodon/locales/mk.json | 2 +- app/javascript/mastodon/locales/mr.json | 2 +- app/javascript/mastodon/locales/ms.json | 2 +- app/javascript/mastodon/locales/my.json | 2 +- app/javascript/mastodon/locales/nl.json | 2 +- app/javascript/mastodon/locales/nn.json | 2 +- app/javascript/mastodon/locales/no.json | 2 +- app/javascript/mastodon/locales/oc.json | 2 +- app/javascript/mastodon/locales/pl.json | 2 +- app/javascript/mastodon/locales/pt-BR.json | 2 +- app/javascript/mastodon/locales/pt-PT.json | 2 +- app/javascript/mastodon/locales/ro.json | 2 +- app/javascript/mastodon/locales/ru.json | 2 +- app/javascript/mastodon/locales/sa.json | 2 +- app/javascript/mastodon/locales/sco.json | 2 +- app/javascript/mastodon/locales/sk.json | 2 +- app/javascript/mastodon/locales/sl.json | 2 +- app/javascript/mastodon/locales/sq.json | 2 +- app/javascript/mastodon/locales/sr-Latn.json | 2 +- app/javascript/mastodon/locales/sr.json | 2 +- app/javascript/mastodon/locales/sv.json | 2 +- app/javascript/mastodon/locales/th.json | 2 +- app/javascript/mastodon/locales/tr.json | 2 +- app/javascript/mastodon/locales/tt.json | 2 +- app/javascript/mastodon/locales/uk.json | 2 +- app/javascript/mastodon/locales/uz.json | 2 +- app/javascript/mastodon/locales/vi.json | 2 +- app/javascript/mastodon/locales/zh-CN.json | 2 +- app/javascript/mastodon/locales/zh-HK.json | 2 +- app/javascript/mastodon/locales/zh-TW.json | 2 +- app/lib/access_token_extension.rb | 23 - app/lib/account_reach_finder.rb | 32 - app/lib/account_statuses_filter.rb | 145 -- app/lib/activity_tracker.rb | 71 - app/lib/activitypub/activity.rb | 179 --- app/lib/activitypub/activity/accept.rb | 49 - app/lib/activitypub/activity/add.rb | 33 - app/lib/activitypub/activity/announce.rb | 87 -- app/lib/activitypub/activity/block.rb | 23 - app/lib/activitypub/activity/create.rb | 429 ----- app/lib/activitypub/activity/delete.rb | 52 - app/lib/activitypub/activity/flag.rb | 43 - app/lib/activitypub/activity/follow.rb | 45 - app/lib/activitypub/activity/like.rb | 14 - app/lib/activitypub/activity/move.rb | 44 - app/lib/activitypub/activity/reject.rb | 43 - app/lib/activitypub/activity/remove.rb | 37 - app/lib/activitypub/activity/undo.rb | 131 -- app/lib/activitypub/activity/update.rb | 35 - app/lib/activitypub/adapter.rb | 25 - app/lib/activitypub/case_transform.rb | 26 - app/lib/activitypub/dereferencer.rb | 60 - app/lib/activitypub/forwarder.rb | 63 - app/lib/activitypub/linked_data_signature.rb | 55 - .../activitypub/parser/custom_emoji_parser.rb | 27 - .../parser/media_attachment_parser.rb | 58 - app/lib/activitypub/parser/poll_parser.rb | 53 - app/lib/activitypub/parser/status_parser.rb | 124 -- app/lib/activitypub/serializer.rb | 38 - app/lib/activitypub/tag_manager.rb | 190 --- app/lib/admin/account_statuses_filter.rb | 9 - app/lib/admin/metrics/dimension.rb | 22 - .../admin/metrics/dimension/base_dimension.rb | 68 - .../dimension/instance_accounts_dimension.rb | 40 - .../dimension/instance_languages_dimension.rb | 50 - .../metrics/dimension/languages_dimension.rb | 32 - .../admin/metrics/dimension/query_helper.rb | 13 - .../metrics/dimension/servers_dimension.rb | 39 - .../dimension/software_versions_dimension.rb | 84 - .../metrics/dimension/sources_dimension.rb | 31 - .../dimension/space_usage_dimension.rb | 86 - .../dimension/tag_languages_dimension.rb | 53 - .../dimension/tag_servers_dimension.rb | 53 - app/lib/admin/metrics/measure.rb | 27 - .../metrics/measure/active_users_measure.rb | 33 - app/lib/admin/metrics/measure/base_measure.rb | 107 -- .../measure/instance_accounts_measure.rb | 62 - .../measure/instance_followers_measure.rb | 63 - .../measure/instance_follows_measure.rb | 63 - .../instance_media_attachments_measure.rb | 72 - .../measure/instance_reports_measure.rb | 63 - .../measure/instance_statuses_measure.rb | 72 - .../metrics/measure/interactions_measure.rb | 33 - .../metrics/measure/new_users_measure.rb | 39 - .../metrics/measure/opened_reports_measure.rb | 39 - app/lib/admin/metrics/measure/query_helper.rb | 25 - .../measure/resolved_reports_measure.rb | 39 - .../metrics/measure/tag_accounts_measure.rb | 41 - .../metrics/measure/tag_servers_measure.rb | 60 - .../admin/metrics/measure/tag_uses_measure.rb | 41 - app/lib/admin/metrics/retention.rb | 103 -- app/lib/admin/system_check.rb | 24 - app/lib/admin/system_check/base_check.rb | 21 - .../system_check/database_schema_check.rb | 15 - .../admin/system_check/elasticsearch_check.rb | 130 -- .../admin/system_check/media_privacy_check.rb | 105 -- app/lib/admin/system_check/message.rb | 12 - app/lib/admin/system_check/rules_check.rb | 17 - .../system_check/sidekiq_process_check.rb | 30 - .../system_check/software_version_check.rb | 27 - app/lib/advanced_text_formatter.rb | 134 -- app/lib/application_extension.rb | 17 - app/lib/ascii_folding.rb | 10 - app/lib/attachment_batch.rb | 114 -- app/lib/cache_buster.rb | 35 - .../connection_pool/shared_connection_pool.rb | 73 - app/lib/connection_pool/shared_timed_stack.rb | 95 -- app/lib/delivery_failure_tracker.rb | 97 -- app/lib/emoji_formatter.rb | 113 -- app/lib/entity_cache.rb | 40 - app/lib/extractor.rb | 118 -- app/lib/fast_geometry_parser.rb | 11 - app/lib/fast_ip_map.rb | 32 - app/lib/feed_manager.rb | 640 -------- app/lib/hashtag_normalizer.rb | 25 - app/lib/html_aware_formatter.rb | 44 - app/lib/importer/accounts_index_importer.rb | 30 - app/lib/importer/base_importer.rb | 100 -- app/lib/importer/instances_index_importer.rb | 26 - .../public_statuses_index_importer.rb | 32 - app/lib/importer/statuses_index_importer.rb | 80 - app/lib/importer/tags_index_importer.rb | 26 - app/lib/inline_renderer.rb | 52 - app/lib/link_details_extractor.rb | 285 ---- app/lib/nodeinfo/adapter.rb | 7 - app/lib/ostatus/tag_manager.rb | 73 - app/lib/permalink_redirector.rb | 77 - app/lib/plain_text_formatter.rb | 31 - app/lib/potential_friendship_tracker.rb | 31 - app/lib/rate_limiter.rb | 64 - app/lib/redis_configuration.rb | 50 - app/lib/request.rb | 346 ----- app/lib/request_pool.rb | 115 -- app/lib/response_with_limit.rb | 10 - app/lib/rss/builder.rb | 41 - app/lib/rss/channel.rb | 49 - app/lib/rss/element.rb | 24 - app/lib/rss/item.rb | 45 - app/lib/rss/media_content.rb | 35 - app/lib/scope_parser.rb | 10 - app/lib/scope_transformer.rb | 40 - app/lib/search_query_parser.rb | 15 - app/lib/search_query_transformer.rb | 250 --- app/lib/settings/scoped_settings.rb | 80 - app/lib/status_cache_hydrator.rb | 99 -- app/lib/status_filter.rb | 59 - app/lib/status_finder.rb | 32 - app/lib/status_reach_finder.rb | 96 -- app/lib/suspicious_sign_in_detector.rb | 42 - app/lib/tag_manager.rb | 35 - app/lib/text_formatter.rb | 166 -- app/lib/themes.rb | 87 -- app/lib/translation_service.rb | 31 - app/lib/translation_service/deepl.rb | 84 - .../translation_service/libre_translate.rb | 61 - app/lib/translation_service/translation.rb | 5 - app/lib/user_settings_serializer.rb | 19 - app/lib/vacuum.rb | 3 - app/lib/vacuum/access_tokens_vacuum.rb | 20 - app/lib/vacuum/applications_vacuum.rb | 10 - app/lib/vacuum/backups_vacuum.rb | 25 - app/lib/vacuum/feeds_vacuum.rb | 41 - app/lib/vacuum/imports_vacuum.rb | 18 - app/lib/vacuum/media_attachments_vacuum.rb | 40 - app/lib/vacuum/preview_cards_vacuum.rb | 30 - app/lib/vacuum/statuses_vacuum.rb | 47 - app/lib/vacuum/system_keys_vacuum.rb | 13 - app/lib/validation_error_formatter.rb | 32 - app/lib/video_metadata_extractor.rb | 58 - app/lib/webfinger.rb | 117 -- app/lib/webfinger_resource.rb | 83 - app/lib/webhooks/payload_renderer.rb | 67 - app/mailers/admin_mailer.rb | 73 - app/mailers/application_mailer.rb | 23 - app/mailers/notification_mailer.rb | 90 -- app/mailers/user_mailer.rb | 213 --- app/models/account.rb | 536 ------- app/models/account/field.rb | 87 -- app/models/account_alias.rb | 60 - app/models/account_conversation.rb | 132 -- app/models/account_deletion_request.rb | 20 - app/models/account_domain_block.rb | 33 - app/models/account_filter.rb | 140 -- app/models/account_migration.rb | 83 - app/models/account_moderation_note.rb | 22 - app/models/account_note.rb | 22 - app/models/account_pin.rb | 28 - app/models/account_stat.rb | 36 - app/models/account_statuses_cleanup_policy.rb | 177 --- app/models/account_suggestions.rb | 28 - .../account_suggestions/global_source.rb | 39 - .../past_interactions_source.rb | 36 - .../account_suggestions/setting_source.rb | 68 - app/models/account_suggestions/source.rb | 34 - app/models/account_suggestions/suggestion.rb | 7 - app/models/account_summary.rb | 26 - app/models/account_warning.rb | 59 - app/models/account_warning_preset.rb | 18 - app/models/admin.rb | 7 - app/models/admin/account_action.rb | 184 --- app/models/admin/action_log.rb | 50 - app/models/admin/action_log_filter.rb | 101 -- app/models/admin/appeal_filter.rb | 51 - app/models/admin/import.rb | 64 - app/models/admin/status_batch_action.rb | 145 -- app/models/admin/status_filter.rb | 40 - app/models/announcement.rb | 95 -- app/models/announcement_filter.rb | 39 - app/models/announcement_mute.rb | 19 - app/models/announcement_reaction.rb | 36 - app/models/appeal.rb | 68 - app/models/application_record.rb | 25 - app/models/backup.rb | 23 - app/models/block.rb | 41 - app/models/bookmark.rb | 35 - app/models/bulk_import.rb | 54 - app/models/bulk_import_row.rb | 15 - app/models/canonical_email_block.rb | 35 - app/models/concerns/account_associations.rb | 75 - app/models/concerns/account_avatar.rb | 34 - app/models/concerns/account_counters.rb | 87 -- app/models/concerns/account_finder_concern.rb | 66 - app/models/concerns/account_header.rb | 35 - app/models/concerns/account_interactions.rb | 322 ---- app/models/concerns/account_merging.rb | 56 - app/models/concerns/account_search.rb | 151 -- .../concerns/account_statuses_search.rb | 44 - app/models/concerns/attachmentable.rb | 83 - app/models/concerns/cacheable.rb | 21 - app/models/concerns/domain_materializable.rb | 26 - app/models/concerns/domain_normalizable.rb | 17 - app/models/concerns/expireable.rb | 36 - app/models/concerns/follow_limitable.rb | 17 - app/models/concerns/has_user_settings.rb | 169 -- app/models/concerns/ldap_authenticable.rb | 60 - app/models/concerns/lockable.rb | 19 - app/models/concerns/omniauthable.rb | 101 -- app/models/concerns/paginable.rb | 32 - app/models/concerns/pam_authenticable.rb | 67 - app/models/concerns/rate_limitable.rb | 36 - app/models/concerns/redisable.rb | 11 - app/models/concerns/relationship_cacheable.rb | 16 - app/models/concerns/remotable.rb | 52 - .../concerns/status_safe_reblog_insert.rb | 72 - app/models/concerns/status_search_concern.rb | 48 - .../concerns/status_snapshot_concern.rb | 36 - .../concerns/status_threading_concern.rb | 111 -- app/models/content_retention_policy.rb | 25 - app/models/context.rb | 5 - app/models/conversation.rb | 21 - app/models/conversation_mute.rb | 15 - app/models/custom_emoji.rb | 105 -- app/models/custom_emoji_category.rb | 17 - app/models/custom_emoji_filter.rb | 45 - app/models/custom_filter.rb | 133 -- app/models/custom_filter_keyword.rb | 35 - app/models/custom_filter_status.rb | 38 - app/models/device.rb | 36 - app/models/direct_feed.rb | 32 - app/models/domain_allow.rb | 43 - app/models/domain_block.rb | 111 -- app/models/email_domain_block.rb | 89 -- app/models/encrypted_message.rb | 49 - app/models/export.rb | 107 -- app/models/extended_description.rb | 15 - app/models/favourite.rb | 51 - app/models/featured_tag.rb | 75 - app/models/feed.rb | 37 - app/models/follow.rb | 77 - app/models/follow_recommendation.rb | 28 - app/models/follow_recommendation_filter.rb | 28 - .../follow_recommendation_suppression.rb | 29 - app/models/follow_request.rb | 54 - app/models/form/account_batch.rb | 149 -- app/models/form/admin_settings.rb | 176 --- app/models/form/challenge.rb | 8 - app/models/form/custom_emoji_batch.rb | 104 -- app/models/form/delete_confirmation.rb | 7 - app/models/form/domain_block_batch.rb | 35 - app/models/form/email_domain_block_batch.rb | 30 - app/models/form/import.rb | 164 -- app/models/form/ip_block_batch.rb | 31 - app/models/form/redirect.rb | 47 - app/models/form/status_filter_batch_action.rb | 34 - app/models/form/two_factor_confirmation.rb | 7 - app/models/home_feed.rb | 12 - app/models/identity.rb | 23 - app/models/import.rb | 46 - app/models/instance.rb | 69 - app/models/instance_filter.rb | 53 - app/models/invite.rb | 43 - app/models/invite_filter.rb | 37 - app/models/ip_block.rb | 49 - app/models/list.rb | 41 - app/models/list_account.rb | 42 - app/models/list_feed.rb | 7 - app/models/login_activity.rb | 36 - app/models/marker.rb | 23 - app/models/media_attachment.rb | 412 ----- app/models/mention.rb | 36 - app/models/message_franking.rb | 19 - app/models/mute.rb | 33 - app/models/notification.rb | 161 -- app/models/one_time_key.rb | 22 - app/models/poll.rb | 125 -- app/models/poll_vote.rb | 41 - app/models/preview_card.rb | 152 -- app/models/preview_card_provider.rb | 59 - app/models/preview_card_trend.rb | 17 - app/models/privacy_policy.rb | 77 - app/models/public_feed.rb | 110 -- app/models/relationship_filter.rb | 122 -- app/models/relay.rb | 83 - app/models/remote_follow.rb | 77 - app/models/report.rb | 169 -- app/models/report_filter.rb | 55 - app/models/report_note.rb | 22 - app/models/rule.rb | 22 - app/models/scheduled_status.rb | 39 - app/models/search.rb | 5 - app/models/session_activation.rb | 87 -- app/models/setting.rb | 61 - app/models/site_upload.rb | 71 - app/models/software_update.rb | 40 - app/models/status.rb | 552 ------- app/models/status_edit.rb | 72 - app/models/status_pin.rb | 27 - app/models/status_stat.rb | 30 - app/models/status_trend.rb | 21 - app/models/system_key.rb | 41 - app/models/tag.rb | 173 --- app/models/tag_feed.rb | 57 - app/models/tag_follow.rb | 24 - app/models/tombstone.rb | 17 - app/models/translation.rb | 14 - app/models/trends.rb | 56 - app/models/trends/base.rb | 105 -- app/models/trends/history.rb | 100 -- app/models/trends/links.rb | 160 -- app/models/trends/preview_card_batch.rb | 65 - app/models/trends/preview_card_filter.rb | 57 - .../trends/preview_card_provider_batch.rb | 33 - .../trends/preview_card_provider_filter.rb | 49 - app/models/trends/query.rb | 121 -- app/models/trends/status_batch.rb | 65 - app/models/trends/status_filter.rb | 57 - app/models/trends/statuses.rb | 138 -- app/models/trends/tag_batch.rb | 37 - app/models/trends/tag_filter.rb | 58 - app/models/trends/tags.rb | 97 -- app/models/unavailable_domain.rb | 29 - app/models/user.rb | 505 ------ app/models/user_invite_request.rb | 17 - app/models/user_ip.rb | 20 - app/models/user_role.rb | 192 --- app/models/user_settings.rb | 107 -- app/models/user_settings/dsl.rb | 41 - app/models/user_settings/glue.rb | 23 - app/models/user_settings/namespace.rb | 21 - app/models/user_settings/setting.rb | 70 - app/models/web.rb | 7 - app/models/web/push_subscription.rb | 121 -- app/models/web/setting.rb | 18 - app/models/webauthn_credential.rb | 23 - app/models/webhook.rb | 98 -- .../account_moderation_note_policy.rb | 17 - app/policies/account_policy.rb | 67 - app/policies/account_warning_policy.rb | 17 - app/policies/account_warning_preset_policy.rb | 19 - app/policies/admin/status_policy.rb | 35 - app/policies/announcement_policy.rb | 19 - app/policies/appeal_policy.rb | 15 - app/policies/application_policy.rb | 24 - app/policies/audit_log_policy.rb | 7 - app/policies/backup_policy.rb | 9 - app/policies/canonical_email_block_policy.rb | 23 - app/policies/custom_emoji_policy.rb | 31 - app/policies/dashboard_policy.rb | 7 - app/policies/delivery_policy.rb | 15 - app/policies/domain_allow_policy.rb | 19 - app/policies/domain_block_policy.rb | 23 - app/policies/email_domain_block_policy.rb | 19 - app/policies/follow_recommendation_policy.rb | 15 - app/policies/instance_policy.rb | 15 - app/policies/invite_policy.rb | 25 - app/policies/ip_block_policy.rb | 23 - app/policies/poll_policy.rb | 7 - app/policies/preview_card_policy.rb | 11 - app/policies/preview_card_provider_policy.rb | 11 - app/policies/relay_policy.rb | 7 - app/policies/report_note_policy.rb | 17 - app/policies/report_policy.rb | 15 - app/policies/rule_policy.rb | 19 - app/policies/settings_policy.rb | 15 - app/policies/software_update_policy.rb | 7 - app/policies/status_policy.rb | 96 -- app/policies/tag_policy.rb | 19 - app/policies/user_policy.rb | 39 - app/policies/user_role_policy.rb | 19 - app/policies/webhook_policy.rb | 35 - .../account_relationships_presenter.rb | 88 -- .../activitypub/activity_presenter.rb | 41 - .../activitypub/collection_presenter.rb | 5 - .../familiar_followers_presenter.rb | 17 - app/presenters/filter_result_presenter.rb | 5 - app/presenters/initial_state_presenter.rb | 15 - app/presenters/instance_presenter.rb | 84 - app/presenters/language_presenter.rb | 20 - .../status_relationships_presenter.rb | 47 - app/presenters/tag_relationships_presenter.rb | 13 - app/presenters/webhooks/event_presenter.rb | 13 - .../activitypub/accept_follow_serializer.rb | 19 - .../activitypub/activity_serializer.rb | 22 - .../activitypub/actor_serializer.rb | 226 --- app/serializers/activitypub/add_serializer.rb | 43 - .../activitypub/block_serializer.rb | 22 - .../activitypub/collection_serializer.rb | 63 - .../activitypub/delete_actor_serializer.rb | 26 - .../activitypub/delete_serializer.rb | 41 - .../activitypub/device_serializer.rb | 52 - .../activitypub/emoji_serializer.rb | 31 - .../encrypted_message_serializer.rb | 61 - .../activitypub/flag_serializer.rb | 26 - .../activitypub/follow_serializer.rb | 22 - .../activitypub/hashtag_serializer.rb | 25 - .../activitypub/image_serializer.rb | 30 - .../activitypub/like_serializer.rb | 22 - .../activitypub/move_serializer.rb | 26 - .../activitypub/note_serializer.rb | 320 ---- .../activitypub/one_time_key_serializer.rb | 35 - .../activitypub/outbox_serializer.rb | 15 - .../activitypub/public_key_serializer.rb | 19 - .../activitypub/reject_follow_serializer.rb | 19 - .../activitypub/remove_serializer.rb | 43 - .../activitypub/undo_announce_serializer.rb | 27 - .../activitypub/undo_block_serializer.rb | 19 - .../activitypub/undo_follow_serializer.rb | 19 - .../activitypub/undo_like_serializer.rb | 19 - .../activitypub/update_poll_serializer.rb | 27 - .../activitypub/update_serializer.rb | 23 - .../activitypub/vote_serializer.rb | 52 - app/serializers/initial_state_serializer.rb | 135 -- app/serializers/manifest_serializer.rb | 93 -- .../nodeinfo/discovery_serializer.rb | 11 - app/serializers/nodeinfo/serializer.rb | 49 - app/serializers/oembed_serializer.rb | 59 - app/serializers/rest/account_serializer.rb | 160 -- .../rest/admin/account_serializer.rb | 87 -- .../admin/canonical_email_block_serializer.rb | 9 - .../rest/admin/cohort_serializer.rb | 19 - .../rest/admin/dimension_serializer.rb | 5 - .../rest/admin/domain_allow_serializer.rb | 9 - .../rest/admin/domain_block_serializer.rb | 11 - .../admin/email_domain_block_serializer.rb | 9 - .../existing_domain_block_error_serializer.rb | 15 - .../rest/admin/ip_block_serializer.rb | 14 - app/serializers/rest/admin/ip_serializer.rb | 5 - .../rest/admin/measure_serializer.rb | 21 - .../rest/admin/report_serializer.rb | 22 - app/serializers/rest/admin/tag_serializer.rb | 13 - .../rest/admin/trends/link_serializer.rb | 9 - .../links/preview_card_provider_serializer.rb | 10 - .../rest/admin/trends/status_serializer.rb | 9 - .../rest/admin/webhook_event_serializer.rb | 28 - .../rest/announcement_serializer.rb | 64 - .../rest/application_serializer.rb | 26 - app/serializers/rest/context_serializer.rb | 6 - .../rest/conversation_serializer.rb | 12 - .../rest/credential_account_serializer.rb | 27 - .../rest/custom_emoji_serializer.rb | 27 - .../rest/domain_block_serializer.rb | 17 - .../rest/encrypted_message_serializer.rb | 19 - .../rest/extended_description_serializer.rb | 23 - .../rest/familiar_followers_serializer.rb | 11 - .../rest/featured_tag_serializer.rb | 27 - .../rest/filter_keyword_serializer.rb | 9 - .../rest/filter_result_serializer.rb | 11 - app/serializers/rest/filter_serializer.rb | 15 - .../rest/filter_status_serializer.rb | 13 - app/serializers/rest/instance_serializer.rb | 106 -- .../rest/keys/claim_result_serializer.rb | 9 - .../rest/keys/device_serializer.rb | 6 - .../rest/keys/query_result_serializer.rb | 11 - app/serializers/rest/language_serializer.rb | 5 - app/serializers/rest/list_serializer.rb | 9 - app/serializers/rest/marker_serializer.rb | 13 - .../rest/media_attachment_serializer.rb | 49 - app/serializers/rest/mute_serializer.rb | 15 - .../rest/muted_account_serializer.rb | 10 - .../rest/notification_serializer.rb | 21 - app/serializers/rest/poll_serializer.rb | 36 - .../rest/preferences_serializer.rb | 35 - .../rest/preview_card_serializer.rb | 18 - .../rest/privacy_policy_serializer.rb | 19 - app/serializers/rest/reaction_serializer.rb | 31 - .../rest/relationship_serializer.rb | 74 - app/serializers/rest/report_serializer.rb | 20 - app/serializers/rest/role_serializer.rb | 13 - app/serializers/rest/rule_serializer.rb | 9 - .../rest/scheduled_status_serializer.rb | 15 - app/serializers/rest/search_serializer.rb | 7 - .../rest/status_edit_serializer.rb | 22 - app/serializers/rest/status_serializer.rb | 202 --- .../rest/status_source_serializer.rb | 9 - app/serializers/rest/suggestion_serializer.rb | 7 - app/serializers/rest/tag_serializer.rb | 29 - .../rest/translation_serializer.rb | 38 - .../rest/trends/link_serializer.rb | 5 - app/serializers/rest/v1/filter_serializer.rb | 26 - .../rest/v1/instance_serializer.rb | 120 -- .../rest/web_push_subscription_serializer.rb | 17 - .../web/notification_serializer.rb | 39 - app/serializers/webfinger_serializer.rb | 48 - app/services/account_search_service.rb | 273 ---- .../account_statuses_cleanup_service.rb | 27 - .../fetch_featured_collection_service.rb | 103 -- .../fetch_featured_tags_collection_service.rb | 72 - .../fetch_remote_account_service.rb | 12 - .../activitypub/fetch_remote_actor_service.rb | 80 - .../activitypub/fetch_remote_key_service.rb | 76 - .../activitypub/fetch_remote_poll_service.rb | 13 - .../fetch_remote_status_service.rb | 83 - .../activitypub/fetch_replies_service.rb | 50 - ...epare_followers_synchronization_service.rb | 13 - .../activitypub/process_account_service.rb | 342 ---- .../activitypub/process_collection_service.rb | 80 - .../process_status_update_service.rb | 312 ---- .../synchronize_followers_service.rb | 74 - ...after_block_domain_from_account_service.rb | 50 - app/services/after_block_service.rb | 31 - app/services/after_unallow_domain_service.rb | 9 - app/services/app_sign_up_service.rb | 68 - app/services/appeal_service.rb | 29 - app/services/approve_appeal_service.rb | 83 - app/services/authorize_follow_service.rb | 27 - app/services/backup_service.rb | 198 --- app/services/base_service.rb | 12 - app/services/batched_remove_status_service.rb | 109 -- app/services/block_domain_service.rb | 51 - app/services/block_service.rb | 29 - app/services/bootstrap_timeline_service.rb | 24 - app/services/bulk_import_row_service.rb | 66 - app/services/bulk_import_service.rb | 185 --- app/services/clear_domain_media_service.rb | 52 - app/services/concerns/payloadable.rb | 30 - app/services/create_featured_tag_service.rb | 25 - app/services/delete_account_service.rb | 308 ---- app/services/deliver_to_device_service.rb | 78 - app/services/fan_out_on_write_service.rb | 169 -- app/services/favourite_service.rb | 50 - app/services/fetch_link_card_service.rb | 155 -- app/services/fetch_oembed_service.rb | 113 -- app/services/fetch_remote_status_service.rb | 14 - app/services/fetch_resource_service.rb | 83 - app/services/follow_migration_service.rb | 62 - app/services/follow_service.rb | 96 -- app/services/import_service.rb | 144 -- app/services/keys/claim_service.rb | 79 - app/services/keys/query_service.rb | 79 - app/services/move_service.rb | 32 - app/services/mute_service.rb | 19 - app/services/notify_service.rb | 189 --- app/services/post_status_service.rb | 242 --- app/services/precompute_feed_service.rb | 12 - app/services/process_hashtags_service.rb | 40 - app/services/process_mentions_service.rb | 95 -- app/services/purge_domain_service.rb | 11 - app/services/reblog_service.rb | 64 - app/services/reject_follow_service.rb | 22 - .../remove_domains_from_followers_service.rb | 23 - app/services/remove_featured_tag_service.rb | 18 - app/services/remove_from_followers_service.rb | 23 - app/services/remove_status_service.rb | 170 -- app/services/report_service.rb | 99 -- app/services/resolve_account_service.rb | 143 -- app/services/resolve_url_service.rb | 125 -- app/services/search_service.rb | 107 -- app/services/software_update_check_service.rb | 84 - app/services/statuses_search_service.rb | 53 - app/services/suspend_account_service.rb | 107 -- app/services/tag_search_service.rb | 103 -- app/services/translate_status_service.rb | 114 -- app/services/unallow_domain_service.rb | 18 - app/services/unblock_domain_service.rb | 18 - app/services/unblock_service.rb | 23 - app/services/unfavourite_service.rb | 23 - app/services/unfollow_service.rb | 66 - app/services/unmute_service.rb | 11 - app/services/unsuspend_account_service.rb | 103 -- app/services/update_account_service.rb | 37 - app/services/update_status_service.rb | 171 -- app/services/verify_link_service.rb | 49 - app/services/vote_service.rb | 80 - app/services/webhook_service.rb | 22 - app/validators/blacklisted_email_validator.rb | 42 - .../disallowed_hashtags_validator.rb | 10 - app/validators/domain_validator.rb | 23 - app/validators/ed25519_key_validator.rb | 19 - app/validators/ed25519_signature_validator.rb | 29 - app/validators/email_mx_validator.rb | 63 - app/validators/existing_username_validator.rb | 26 - app/validators/follow_limit_validator.rb | 28 - app/validators/language_validator.rb | 23 - app/validators/note_length_validator.rb | 22 - app/validators/poll_validator.rb | 19 - app/validators/reaction_validator.rb | 28 - .../registration_form_time_validator.rb | 9 - app/validators/status_length_validator.rb | 59 - app/validators/status_pin_validator.rb | 12 - app/validators/unique_username_validator.rb | 17 - .../unreserved_username_validator.rb | 26 - app/validators/url_validator.rb | 31 - app/validators/vote_validator.rb | 53 - app/views/about/show.html.haml | 7 - app/views/accounts/_og.html.haml | 13 - app/views/accounts/show.html.haml | 17 - app/views/accounts/show.rss.ruby | 37 - app/views/admin/account_actions/new.html.haml | 30 - .../_account_warning.html.haml | 25 - app/views/admin/accounts/_account.html.haml | 35 - app/views/admin/accounts/index.html.haml | 67 - app/views/admin/accounts/show.html.haml | 284 ---- .../admin/action_logs/_action_log.html.haml | 9 - app/views/admin/action_logs/index.html.haml | 25 - .../announcements/_announcement.html.haml | 19 - app/views/admin/announcements/edit.html.haml | 22 - app/views/admin/announcements/index.html.haml | 21 - app/views/admin/announcements/new.html.haml | 21 - app/views/admin/change_emails/show.html.haml | 12 - .../custom_emojis/_custom_emoji.html.haml | 35 - app/views/admin/custom_emojis/index.html.haml | 84 - app/views/admin/custom_emojis/new.html.haml | 13 - app/views/admin/dashboard/index.html.haml | 68 - .../admin/disputes/appeals/_appeal.html.haml | 21 - .../admin/disputes/appeals/index.html.haml | 19 - app/views/admin/domain_allows/new.html.haml | 11 - .../confirm_suspension.html.haml | 22 - app/views/admin/domain_blocks/edit.html.haml | 30 - app/views/admin/domain_blocks/new.html.haml | 30 - .../_email_domain_block.html.haml | 14 - .../admin/email_domain_blocks/index.html.haml | 22 - .../admin/email_domain_blocks/new.html.haml | 35 - .../admin/export_domain_allows/new.html.haml | 10 - .../_domain_block.html.haml | 27 - .../export_domain_blocks/import.html.haml | 21 - .../admin/export_domain_blocks/new.html.haml | 10 - .../follow_recommendations/_account.html.haml | 20 - .../follow_recommendations/show.html.haml | 40 - app/views/admin/instances/_instance.html.haml | 15 - app/views/admin/instances/index.html.haml | 52 - app/views/admin/instances/show.html.haml | 94 -- app/views/admin/invites/_invite.html.haml | 30 - app/views/admin/invites/index.html.haml | 37 - app/views/admin/ip_blocks/_ip_block.html.haml | 11 - app/views/admin/ip_blocks/index.html.haml | 24 - app/views/admin/ip_blocks/new.html.haml | 20 - app/views/admin/relationships/index.html.haml | 40 - app/views/admin/relays/_relay.html.haml | 25 - app/views/admin/relays/index.html.haml | 19 - app/views/admin/relays/new.html.haml | 13 - .../admin/report_notes/_report_note.html.haml | 18 - app/views/admin/reports/_actions.html.haml | 33 - .../reports/_media_attachments.html.haml | 7 - app/views/admin/reports/_status.html.haml | 39 - .../admin/reports/actions/preview.html.haml | 78 - app/views/admin/reports/index.html.haml | 77 - app/views/admin/reports/show.html.haml | 212 --- app/views/admin/roles/_form.html.haml | 36 - app/views/admin/roles/_role.html.haml | 30 - app/views/admin/roles/edit.html.haml | 10 - app/views/admin/roles/index.html.haml | 17 - app/views/admin/roles/new.html.haml | 7 - app/views/admin/rules/_rule.html.haml | 11 - app/views/admin/rules/edit.html.haml | 11 - app/views/admin/rules/index.html.haml | 25 - app/views/admin/settings/about/show.html.haml | 33 - .../admin/settings/appearance/show.html.haml | 31 - .../admin/settings/branding/show.html.haml | 36 - .../settings/content_retention/show.html.haml | 19 - .../admin/settings/discovery/show.html.haml | 61 - app/views/admin/settings/other/show.html.haml | 26 - .../settings/registrations/show.html.haml | 28 - .../admin/settings/shared/_links.html.haml | 10 - .../admin/software_updates/index.html.haml | 29 - .../admin/status_edits/_status_edit.html.haml | 20 - app/views/admin/statuses/index.html.haml | 43 - app/views/admin/statuses/show.html.haml | 61 - app/views/admin/tags/show.html.haml | 61 - .../trends/links/_preview_card.html.haml | 30 - app/views/admin/trends/links/index.html.haml | 48 - .../_preview_card_provider.html.haml | 16 - .../preview_card_providers/index.html.haml | 43 - .../admin/trends/statuses/_status.html.haml | 33 - .../admin/trends/statuses/index.html.haml | 44 - app/views/admin/trends/tags/_tag.html.haml | 25 - app/views/admin/trends/tags/index.html.haml | 37 - app/views/admin/users/roles/show.html.haml | 9 - .../warning_presets/_warning_preset.html.haml | 10 - .../admin/warning_presets/edit.html.haml | 14 - .../admin/warning_presets/index.html.haml | 24 - app/views/admin/webhooks/_form.html.haml | 10 - app/views/admin/webhooks/_webhook.html.haml | 19 - app/views/admin/webhooks/edit.html.haml | 7 - app/views/admin/webhooks/index.html.haml | 18 - app/views/admin/webhooks/new.html.haml | 7 - app/views/admin/webhooks/show.html.haml | 34 - .../admin_mailer/_new_trending_links.text.erb | 8 - .../_new_trending_statuses.text.erb | 8 - .../admin_mailer/_new_trending_tags.text.erb | 14 - app/views/admin_mailer/new_appeal.text.erb | 9 - .../new_critical_software_updates.text.erb | 5 - .../admin_mailer/new_pending_account.text.erb | 12 - app/views/admin_mailer/new_report.text.erb | 5 - .../new_software_updates.text.erb | 5 - app/views/admin_mailer/new_trends.text.erb | 13 - app/views/application/_card.html.haml | 18 - app/views/application/_flashes.html.haml | 3 - app/views/auth/challenges/new.html.haml | 15 - .../auth/confirmations/captcha.html.haml | 18 - app/views/auth/confirmations/new.html.haml | 13 - app/views/auth/passwords/edit.html.haml | 20 - app/views/auth/passwords/new.html.haml | 13 - .../registrations/_account_warning.html.haml | 20 - .../auth/registrations/_session.html.haml | 16 - .../auth/registrations/_sessions.html.haml | 17 - .../auth/registrations/_status.html.haml | 33 - app/views/auth/registrations/edit.html.haml | 49 - app/views/auth/registrations/new.html.haml | 46 - app/views/auth/registrations/rules.html.haml | 29 - app/views/auth/sessions/new.html.haml | 30 - app/views/auth/sessions/two_factor.html.haml | 7 - .../_otp_authentication_form.html.haml | 18 - .../two_factor/_webauthn_form.html.haml | 17 - app/views/auth/setup/show.html.haml | 22 - app/views/auth/shared/_links.html.haml | 18 - app/views/auth/shared/_progress.html.haml | 25 - app/views/custom_css/show.css.erb | 10 - app/views/disputes/strikes/index.html.haml | 6 - app/views/disputes/strikes/show.html.haml | 126 -- app/views/errors/400.html.haml | 5 - app/views/errors/403.html.haml | 5 - app/views/errors/404.html.haml | 5 - app/views/errors/406.html.haml | 5 - app/views/errors/410.html.haml | 5 - app/views/errors/422.html.haml | 5 - app/views/errors/429.html.haml | 5 - app/views/errors/500.html.haml | 5 - app/views/errors/503.html.haml | 5 - app/views/filters/_filter.html.haml | 41 - app/views/filters/_filter_fields.html.haml | 40 - app/views/filters/_keyword_fields.html.haml | 8 - app/views/filters/edit.html.haml | 8 - app/views/filters/index.html.haml | 11 - app/views/filters/new.html.haml | 8 - .../filters/statuses/_status_filter.html.haml | 37 - app/views/filters/statuses/index.html.haml | 35 - app/views/follower_accounts/index.html.haml | 6 - app/views/following_accounts/index.html.haml | 6 - app/views/home/index.html.haml | 7 - app/views/invites/_form.html.haml | 13 - app/views/invites/_invite.html.haml | 25 - app/views/invites/index.html.haml | 21 - app/views/kaminari/_gap.html.haml | 9 - app/views/kaminari/_next_page.html.haml | 11 - app/views/kaminari/_paginator.html.haml | 17 - app/views/kaminari/_prev_page.html.haml | 10 - app/views/layouts/_theme.html.haml | 13 - app/views/layouts/admin.html.haml | 42 - app/views/layouts/application.html.haml | 53 - app/views/layouts/auth.html.haml | 13 - app/views/layouts/embedded.html.haml | 28 - app/views/layouts/error.html.haml | 16 - app/views/layouts/helper_frame.html.haml | 8 - app/views/layouts/mailer.html.haml | 54 - app/views/layouts/mailer.text.erb | 5 - app/views/layouts/modal.html.haml | 17 - app/views/layouts/plain_mailer.html.haml | 1 - app/views/mail_subscriptions/create.html.haml | 9 - app/views/mail_subscriptions/show.html.haml | 12 - app/views/media/player.html.haml | 26 - .../notification_mailer/_status.html.haml | 45 - .../notification_mailer/_status.text.erb | 8 - .../notification_mailer/favourite.html.haml | 45 - .../notification_mailer/favourite.text.erb | 5 - .../notification_mailer/follow.html.haml | 43 - app/views/notification_mailer/follow.text.erb | 5 - .../follow_request.html.haml | 43 - .../follow_request.text.erb | 5 - .../notification_mailer/mention.html.haml | 45 - .../notification_mailer/mention.text.erb | 5 - .../notification_mailer/reblog.html.haml | 45 - app/views/notification_mailer/reblog.text.erb | 5 - .../oauth/authorizations/error.html.haml | 3 - app/views/oauth/authorizations/new.html.haml | 38 - app/views/oauth/authorizations/show.html.haml | 7 - .../authorized_applications/index.html.haml | 44 - app/views/privacy/show.html.haml | 7 - app/views/relationships/_account.html.haml | 22 - app/views/relationships/show.html.haml | 55 - .../remote_interaction_helper/index.html.haml | 4 - app/views/settings/aliases/index.html.haml | 33 - .../settings/applications/_fields.html.haml | 18 - .../settings/applications/index.html.haml | 25 - app/views/settings/applications/new.html.haml | 8 - .../settings/applications/show.html.haml | 30 - app/views/settings/deletes/show.html.haml | 29 - app/views/settings/exports/show.html.haml | 69 - .../settings/featured_tags/index.html.haml | 33 - app/views/settings/flavours/show.html.haml | 20 - app/views/settings/imports/index.html.haml | 49 - app/views/settings/imports/show.html.haml | 15 - .../_login_activity.html.haml | 18 - .../settings/login_activities/index.html.haml | 15 - .../migration/redirects/new.html.haml | 27 - app/views/settings/migrations/show.html.haml | 89 -- .../preferences/appearance/show.html.haml | 64 - .../preferences/notifications/show.html.haml | 46 - .../settings/preferences/other/show.html.haml | 35 - app/views/settings/privacy/show.html.haml | 50 - app/views/settings/profiles/show.html.haml | 65 - .../shared/_profile_navigation.html.haml | 7 - .../confirmations/new.html.haml | 18 - .../otp_authentication/show.html.haml | 9 - .../recovery_codes/index.html.haml | 9 - .../webauthn_credentials/index.html.haml | 17 - .../webauthn_credentials/new.html.haml | 14 - .../index.html.haml | 41 - .../settings/verifications/show.html.haml | 30 - app/views/shared/_error_messages.html.haml | 6 - app/views/shared/_og.html.haml | 14 - app/views/shared/_web_app.html.haml | 17 - app/views/shares/show.html.haml | 4 - app/views/statuses/_attachment_list.html.haml | 8 - app/views/statuses/_detailed_status.html.haml | 80 - app/views/statuses/_og_description.html.haml | 4 - app/views/statuses/_og_image.html.haml | 48 - app/views/statuses/_poll.html.haml | 40 - app/views/statuses/_simple_status.html.haml | 70 - app/views/statuses/_status.html.haml | 2 - app/views/statuses/embed.html.haml | 2 - app/views/statuses/show.html.haml | 21 - app/views/statuses_cleanup/show.html.haml | 45 - app/views/tags/show.html.haml | 5 - app/views/tags/show.rss.ruby | 35 - .../user_mailer/appeal_approved.html.haml | 59 - .../user_mailer/appeal_approved.text.erb | 7 - .../user_mailer/appeal_rejected.html.haml | 59 - .../user_mailer/appeal_rejected.text.erb | 7 - app/views/user_mailer/backup_ready.html.haml | 59 - app/views/user_mailer/backup_ready.text.erb | 7 - .../confirmation_instructions.html.haml | 80 - .../confirmation_instructions.text.erb | 12 - app/views/user_mailer/email_changed.html.haml | 58 - app/views/user_mailer/email_changed.text.erb | 9 - .../user_mailer/password_change.html.haml | 40 - .../user_mailer/password_change.text.erb | 7 - .../reconfirmation_instructions.html.haml | 60 - .../reconfirmation_instructions.text.erb | 9 - .../reset_password_instructions.html.haml | 60 - .../reset_password_instructions.text.erb | 9 - .../user_mailer/suspicious_sign_in.html.haml | 67 - .../user_mailer/suspicious_sign_in.text.erb | 15 - .../user_mailer/two_factor_disabled.html.haml | 43 - .../user_mailer/two_factor_disabled.text.erb | 7 - .../user_mailer/two_factor_enabled.html.haml | 43 - .../user_mailer/two_factor_enabled.text.erb | 7 - ...wo_factor_recovery_codes_changed.html.haml | 43 - ...two_factor_recovery_codes_changed.text.erb | 7 - app/views/user_mailer/warning.html.haml | 98 -- app/views/user_mailer/warning.text.erb | 36 - .../webauthn_credential_added.html.haml | 44 - .../webauthn_credential_added.text.erb | 7 - .../webauthn_credential_deleted.html.haml | 44 - .../webauthn_credential_deleted.text.erb | 7 - .../user_mailer/webauthn_disabled.html.haml | 43 - .../user_mailer/webauthn_disabled.text.erb | 7 - .../user_mailer/webauthn_enabled.html.haml | 43 - .../user_mailer/webauthn_enabled.text.erb | 7 - app/views/user_mailer/welcome.html.haml | 99 -- app/views/user_mailer/welcome.text.erb | 16 - app/views/well_known/host_meta/show.xml.ruby | 21 - app/workers/account_deletion_worker.rb | 18 - app/workers/account_merging_worker.rb | 18 - app/workers/account_refresh_worker.rb | 14 - .../account_raw_distribution_worker.rb | 9 - app/workers/activitypub/delivery_worker.rb | 83 - .../distribute_poll_update_worker.rb | 54 - .../activitypub/distribution_worker.rb | 32 - .../activitypub/fetch_replies_worker.rb | 14 - .../followers_synchronization_worker.rb | 14 - .../low_priority_delivery_worker.rb | 5 - .../migrated_follow_delivery_worker.rb | 17 - .../activitypub/move_distribution_worker.rb | 33 - .../activitypub/post_upgrade_worker.rb | 15 - app/workers/activitypub/processing_worker.rb | 20 - .../activitypub/raw_distribution_worker.rb | 48 - .../status_update_distribution_worker.rb | 29 - .../synchronize_featured_collection_worker.rb | 15 - ...hronize_featured_tags_collection_worker.rb | 13 - .../activitypub/update_distribution_worker.rb | 26 - .../add_to_public_statuses_index_worker.rb | 22 - app/workers/admin/account_deletion_worker.rb | 13 - app/workers/admin/domain_purge_worker.rb | 11 - app/workers/admin/suspension_worker.rb | 13 - app/workers/admin/unsuspension_worker.rb | 13 - .../after_account_domain_block_worker.rb | 11 - app/workers/after_unallow_domain_worker.rb | 9 - app/workers/authorize_follow_worker.rb | 14 - app/workers/backup_worker.rb | 28 - app/workers/block_worker.rb | 12 - app/workers/bootstrap_timeline_worker.rb | 9 - app/workers/bulk_import_worker.rb | 13 - app/workers/cache_buster_worker.rb | 18 - app/workers/concerns/exponential_backoff.rb | 11 - app/workers/delete_mute_worker.rb | 10 - app/workers/distribution_worker.rb | 15 - app/workers/domain_block_worker.rb | 12 - app/workers/domain_clear_media_worker.rb | 14 - app/workers/feed_insert_worker.rb | 90 -- app/workers/fetch_reply_worker.rb | 12 - app/workers/import/relationship_worker.rb | 58 - app/workers/import/row_worker.rb | 33 - app/workers/import_worker.rb | 17 - app/workers/link_crawl_worker.rb | 13 - app/workers/local_notification_worker.rb | 28 - app/workers/merge_worker.rb | 22 - app/workers/move_worker.rb | 133 -- app/workers/mute_worker.rb | 11 - app/workers/poll_expiration_notify_worker.rb | 51 - app/workers/post_process_media_worker.rb | 38 - .../publish_announcement_reaction_worker.rb | 22 - .../publish_scheduled_announcement_worker.rb | 28 - .../publish_scheduled_status_worker.rb | 26 - app/workers/push_conversation_worker.rb | 16 - app/workers/push_encrypted_message_worker.rb | 16 - app/workers/push_update_worker.rb | 39 - app/workers/redownload_avatar_worker.rb | 29 - app/workers/redownload_header_worker.rb | 29 - app/workers/redownload_media_worker.rb | 29 - app/workers/refollow_worker.rb | 29 - app/workers/regeneration_worker.rb | 20 - app/workers/remote_account_refresh_worker.rb | 24 - app/workers/removal_worker.rb | 11 - app/workers/remove_featured_tag_worker.rb | 11 - ...emove_from_public_statuses_index_worker.rb | 15 - app/workers/resolve_account_worker.rb | 11 - .../accounts_statuses_cleanup_scheduler.rb | 131 -- .../follow_recommendations_scheduler.rb | 62 - app/workers/scheduler/indexing_scheduler.rb | 30 - .../scheduler/instance_refresh_scheduler.rb | 12 - app/workers/scheduler/ip_cleanup_scheduler.rb | 29 - app/workers/scheduler/pghero_scheduler.rb | 11 - .../scheduler/scheduled_statuses_scheduler.rb | 43 - .../software_update_check_scheduler.rb | 11 - .../suspended_user_cleanup_scheduler.rb | 38 - .../scheduler/trends/refresh_scheduler.rb | 11 - .../trends/review_notifications_scheduler.rb | 11 - .../scheduler/user_cleanup_scheduler.rb | 31 - app/workers/scheduler/vacuum_scheduler.rb | 66 - app/workers/tag_unmerge_worker.rb | 21 - app/workers/thread_resolve_worker.rb | 20 - app/workers/trigger_webhook_worker.rb | 12 - app/workers/unfavourite_worker.rb | 11 - app/workers/unfollow_follow_worker.rb | 17 - app/workers/unmerge_worker.rb | 21 - app/workers/unpublish_announcement_worker.rb | 14 - app/workers/verify_account_links_worker.rb | 19 - app/workers/web/push_notification_worker.rb | 69 - app/workers/webhooks/delivery_worker.rb | 37 - chart/README.md | 3 - config.ru | 6 - config/application.rb | 217 --- config/boot.rb | 11 - config/deploy.rb | 35 - config/environment.rb | 9 - config/environments/development.rb | 103 -- config/environments/production.rb | 160 -- config/environments/test.rb | 94 -- config/i18n-tasks.yml | 82 - config/imagemagick/policy.xml | 27 - config/initializers/0_duplicate_migrations.rb | 56 - .../0_post_deployment_migrations.rb | 17 - config/initializers/1_hosts.rb | 36 - .../initializers/2_limited_federation_mode.rb | 7 - config/initializers/3_omniauth.rb | 110 -- .../initializers/active_model_serializers.rb | 7 - .../application_controller_renderer.rb | 9 - config/initializers/assets.rb | 16 - config/initializers/backtrace_silencers.rb | 10 - config/initializers/blacklists.rb | 6 - config/initializers/cache_buster.rb | 11 - config/initializers/cache_logging.rb | 5 - config/initializers/chewy.rb | 35 - .../initializers/content_security_policy.rb | 107 -- config/initializers/cookie_rotator.rb | 27 - config/initializers/cookies_serializer.rb | 7 - config/initializers/cors.rb | 26 - config/initializers/devise.rb | 417 ----- config/initializers/doorkeeper.rb | 178 --- config/initializers/fast_blank.rb | 7 - config/initializers/ffmpeg.rb | 5 - .../initializers/filter_parameter_logging.rb | 10 - config/initializers/http_client_proxy.rb | 41 - config/initializers/httplog.rb | 7 - config/initializers/inflections.rb | 34 - config/initializers/json_ld.rb | 4 - config/initializers/kaminari_config.rb | 7 - config/initializers/locale.rb | 9 - config/initializers/mail_delivery_job.rb | 5 - config/initializers/mime_types.rb | 7 - .../new_framework_defaults_7_0.rb | 10 - config/initializers/oj.rb | 3 - config/initializers/open_uri_redirection.rb | 10 - config/initializers/paperclip.rb | 186 --- config/initializers/permissions_policy.rb | 12 - config/initializers/pghero.rb | 3 - config/initializers/preload_link_headers.rb | 10 - config/initializers/premailer_rails.rb | 8 - config/initializers/rack_attack.rb | 153 -- config/initializers/rack_attack_logging.rb | 9 - config/initializers/redis.rb | 3 - config/initializers/session_activations.rb | 5 - config/initializers/session_store.rb | 11 - config/initializers/sidekiq.rb | 39 - config/initializers/simple_form.rb | 243 --- config/initializers/single_user_mode.rb | 5 - config/initializers/statsd.rb | 15 - config/initializers/stoplight.rb | 8 - config/initializers/strong_migrations.rb | 4 - config/initializers/suppress_csrf_warnings.rb | 5 - config/initializers/trusted_proxies.rb | 13 - config/initializers/twitter_regex.rb | 82 - config/initializers/vapid.rb | 16 - config/initializers/webauthn.rb | 26 - config/initializers/wrap_parameters.rb | 16 - config/navigation.rb | 73 - config/pghero.yml | 41 - config/puma.rb | 28 - config/routes.rb | 192 --- config/routes/admin.rb | 207 --- config/routes/api.rb | 320 ---- config/routes/settings.rb | 76 - config/secrets.yml | 22 - config/sidekiq.yml | 64 - config/storage.yml | 0 crowdin-glitch.yml | 14 - crowdin.yml | 20 - db/migrate/20160220174730_create_accounts.rb | 27 - db/migrate/20160220211917_create_statuses.rb | 15 - db/migrate/20160221003140_create_users.rb | 14 - db/migrate/20160221003621_create_follows.rb | 14 - .../20160222122600_create_stream_entries.rb | 13 - ...22143943_add_profile_fields_to_accounts.rb | 9 - ...20160223162837_add_metadata_to_statuses.rb | 8 - ...23164502_make_uris_nullable_in_statuses.rb | 7 - .../20160223165723_add_url_to_statuses.rb | 7 - .../20160223165855_add_url_to_accounts.rb | 7 - .../20160223171800_create_favourites.rb | 14 - db/migrate/20160224223247_create_mentions.rb | 14 - ...30233_add_attachment_avatar_to_accounts.rb | 13 - .../20160305115639_add_devise_to_users.rb | 40 - ...20160306172223_create_doorkeeper_tables.rb | 52 - ...93225_add_attachment_header_to_accounts.rb | 13 - ...20160314164231_add_owner_to_application.rb | 9 - .../20160316103650_add_missing_indices.rb | 12 - ...93748_add_avatar_remote_url_to_accounts.rb | 7 - .../20160325130944_add_admin_to_users.rb | 7 - ...5805_add_superapp_to_oauth_applications.rb | 7 - ...20160905150353_create_media_attachments.rb | 16 - ...add_subscription_expires_at_to_accounts.rb | 7 - ...03904_remove_verify_token_from_accounts.rb | 7 - ...926213048_remove_owner_from_application.rb | 9 - ...20161003142332_add_confirmable_to_users.rb | 11 - db/migrate/20161003145426_create_blocks.rb | 14 - ...20161006213403_rails_settings_migration.rb | 23 - .../20161009120834_create_domain_blocks.rb | 12 - ...20161027172456_add_silenced_to_accounts.rb | 7 - db/migrate/20161104173623_create_tags.rb | 13 - ...5130633_create_statuses_tags_join_table.rb | 10 - .../20161116162355_add_locale_to_users.rb | 7 - .../20161119211120_create_notifications.rb | 16 - .../20161122163057_remove_unneeded_indexes.rb | 9 - ...0161123093447_add_sensitive_to_statuses.rb | 7 - .../20161128103007_create_subscriptions.rb | 17 - ...successful_delivery_at_to_subscriptions.rb | 7 - ...161130185319_add_visibility_to_statuses.rb | 7 - ..._add_in_reply_to_account_id_to_statuses.rb | 20 - ...20_add_from_account_id_to_notifications.rb | 45 - ...0161205214545_add_suspended_to_accounts.rb | 7 - ...1221152630_add_hidden_to_stream_entries.rb | 7 - .../20161222201034_add_locked_to_accounts.rb | 7 - .../20161222204147_create_follow_requests.rb | 14 - ...4407_add_shortcode_to_media_attachments.rb | 23 - .../20170109120109_create_web_settings.rb | 14 - db/migrate/20170112154826_migrate_settings.rb | 21 - ...70114194937_add_application_to_statuses.rb | 7 - ...203041_add_website_to_oauth_application.rb | 7 - .../20170119214911_create_preview_cards.rb | 19 - ...123162658_add_severity_to_domain_blocks.rb | 7 - ...03248_add_reject_media_to_domain_blocks.rb | 7 - ...0125145934_add_spoiler_text_to_statuses.rb | 7 - ...27165745_add_devise_two_factor_to_users.rb | 11 - db/migrate/20170205175257_remove_devices.rb | 7 - .../20170209184350_add_reply_to_statuses.rb | 12 - db/migrate/20170214110202_create_reports.rb | 15 - ...dd_reblog_of_id_foreign_key_to_statuses.rb | 7 - db/migrate/20170301222600_create_mutes.rb | 13 - ...0303212857_add_last_emailed_at_to_users.rb | 7 - ...304202101_add_type_to_media_attachments.rb | 27 - ...0317193015_add_search_index_to_accounts.rb | 11 - ...14217_add_header_remote_url_to_accounts.rb | 7 - ...2021028_add_lowercase_index_to_accounts.rb | 11 - ...hange_primary_key_to_bigint_on_statuses.rb | 17 - ...20170322162804_add_search_index_to_tags.rb | 11 - .../20170330021336_add_counter_caches.rb | 15 - db/migrate/20170330163835_create_imports.rb | 13 - ...30164118_add_attachment_data_to_imports.rb | 13 - ...d_action_taken_by_account_id_to_reports.rb | 7 - ...5112956_add_index_on_mentions_status_id.rb | 7 - ...dd_notifications_and_favourites_indices.rb | 9 - ...753_add_last_webfingered_at_to_accounts.rb | 7 - ...d_devise_two_factor_backupable_to_users.rb | 7 - ...20170414132105_add_language_to_statuses.rb | 7 - ...728_add_indexes_to_reports_for_accounts.rb | 8 - ...423005413_add_allowed_languages_to_user.rb | 8 - ...0424003227_create_account_domain_blocks.rb | 14 - ...22_add_status_id_index_to_statuses_tags.rb | 7 - ...0170425131920_add_media_attachment_meta.rb | 7 - ...70425202925_add_oembed_to_preview_cards.rb | 14 - ...70427011934_re_add_owner_to_application.rb | 10 - .../20170506235850_create_conversations.rb | 12 - ...7000211_add_conversation_id_to_statuses.rb | 8 - ...0507141759_optimize_index_subscriptions.rb | 13 - ...0170508230434_create_conversation_mutes.rb | 12 - ...0170516072309_add_index_accounts_on_uri.rb | 7 - ...45338_change_language_filter_to_opt_out.rb | 11 - ...d_index_on_media_attachments_account_id.rb | 7 - ...604144747_add_foreign_keys_for_accounts.rb | 43 - ...113804_change_tag_search_index_to_btree.rb | 13 - ...6_remove_default_language_from_statuses.rb | 7 - ...000_add_statuses_index_on_account_id_id.rb | 15 - ...170623152212_create_session_activations.rb | 15 - ..._add_description_to_session_activations.rb | 9 - ..._access_token_id_to_session_activations.rb | 8 - .../20170711225116_fix_null_booleans.rb | 21 - ...112503_make_tag_search_case_insensitive.rb | 13 - ...713175513_create_web_push_subscriptions.rb | 14 - ...ush_subscription_to_session_activations.rb | 7 - ...70714184731_add_domain_to_subscriptions.rb | 7 - ...16191202_add_hide_notifications_to_mute.rb | 17 - ...70718211102_add_activitypub_to_accounts.rb | 11 - ...d_index_favourites_on_account_id_and_id.rb | 8 - .../20170823162448_create_status_pins.rb | 12 - ...824103029_add_timestamps_to_status_pins.rb | 7 - ...215220_remove_status_pins_account_index.rb | 8 - .../20170901141119_truncate_preview_cards.rb | 32 - ...reate_join_table_preview_cards_statuses.rb | 9 - ...count_id_activity_type_on_notifications.rb | 7 - .../20170905165803_add_local_to_statuses.rb | 7 - .../20170913000752_create_site_uploads.rb | 12 - ..._existing_mutes_to_hiding_notifications.rb | 13 - .../20170917153509_create_custom_emojis.rb | 15 - db/migrate/20170918125918_ids_to_bigints.rb | 113 -- ...70920024819_status_ids_to_timestamp_ids.rb | 34 - .../20170920032311_fix_reblogs_in_feeds.rb | 79 - db/migrate/20170924022025_ids_to_bigints2.rb | 11 - ...09_add_description_to_media_attachments.rb | 7 - ...170928082043_create_email_domain_blocks.rb | 11 - ...5102658_create_account_moderation_notes.rb | 15 - ...005171936_add_disabled_to_custom_emojis.rb | 17 - ...20171006142024_add_uri_to_custom_emojis.rb | 8 - .../20171009222537_create_keyword_mutes.rb | 14 - ...foreign_key_to_account_moderation_notes.rb | 7 - ...nonnullable_in_account_moderation_notes.rb | 10 - ...8_add_visible_in_picker_to_custom_emoji.rb | 9 - ...ove_keyword_mutes_into_glitch_namespace.rb | 9 - .../20171028221157_add_reblogs_to_follows.rb | 21 - ...20171107143332_add_memorial_to_accounts.rb | 17 - .../20171107143624_add_disabled_to_users.rb | 17 - ...0171109012327_add_moderator_to_accounts.rb | 17 - ...add_index_domain_to_email_domain_blocks.rb | 10 - db/migrate/20171114231651_create_lists.rb | 12 - .../20171116161857_create_list_accounts.rb | 14 - ...443_add_moved_to_account_id_to_accounts.rb | 8 - ...20171119172437_create_admin_action_logs.rb | 14 - ...ex_account_and_reblog_of_id_to_statuses.rb | 14 - db/migrate/20171125024930_create_invites.rb | 17 - .../20171125031751_add_invite_id_to_users.rb | 7 - ...ex_reblog_of_id_and_account_to_statuses.rb | 9 - ...735_remove_old_reblog_index_on_statuses.rb | 16 - ...71129172043_add_index_on_stream_entries.rb | 10 - ...30000000_add_embed_url_to_preview_cards.rb | 20 - ..._change_account_id_nonnullable_in_lists.rb | 9 - ...0213213_add_local_only_flag_to_statuses.rb | 7 - ...95226_remove_duplicate_indexes_in_lists.rb | 8 - ...4803_more_faster_index_on_notifications.rb | 10 - ...for_api_v1_accounts_account_id_statuses.rb | 12 - ...80109143959_add_remember_token_to_users.rb | 7 - .../20180204034416_create_identities.rb | 13 - ...180206000000_change_user_id_nonnullable.rb | 10 - db/migrate/20180211015820_create_backups.rb | 13 - ...add_featured_collection_url_to_accounts.rb | 7 - ...ge_columns_in_notifications_nonnullable.rb | 12 - ...1200_add_assigned_account_id_to_reports.rb | 7 - .../20180402040909_create_report_notes.rb | 16 - .../20180410204633_add_fields_to_accounts.rb | 7 - db/migrate/20180410220657_create_bookmarks.rb | 22 - ...20180416210259_add_uri_to_relationships.rb | 9 - ...180506221944_add_actor_type_to_accounts.rb | 7 - ...cess_token_id_to_web_push_subscriptions.rb | 10 - ...10230049_migrate_web_push_subscriptions.rb | 15 - ...for_api_v1_accounts_account_id_statuses.rb | 12 - ...for_api_v1_accounts_account_id_statuses.rb | 15 - ...0180528141303_fix_accounts_unique_index.rb | 118 -- ...apply_to_mentions_flag_to_keyword_mutes.rb | 19 - ...08213548_reject_following_blocked_users.rb | 42 - ...9104432_migrate_web_push_subscriptions2.rb | 19 - ...0180615122121_add_autofollow_to_invites.rb | 19 - ...616192031_add_chosen_languages_to_users.rb | 7 - .../20180617162849_remove_unused_indexes.rb | 9 - .../20180628181026_create_custom_filters.rb | 15 - ...7154237_add_whole_word_to_custom_filter.rb | 19 - db/migrate/20180707193142_migrate_filters.rb | 58 - db/migrate/20180711152640_create_relays.rb | 14 - .../20180808175627_create_account_pins.rb | 14 - .../20180812123222_change_relays_enabled.rb | 21 - .../20180812162710_create_status_stats.rb | 14 - .../20180812173710_copy_status_stats.rb | 54 - ..._confidential_to_doorkeeper_application.rb | 25 - .../20180820232245_add_foreign_key_indices.rb | 16 - db/migrate/20180831171112_create_bookmarks.rb | 22 - ...0929222014_create_account_conversations.rb | 16 - ...0181007025445_create_pghero_space_stats.rb | 15 - .../20181010141500_add_silent_to_mentions.rb | 25 - ...937_add_reject_reports_to_domain_blocks.rb | 19 - ...649_add_unread_to_account_conversations.rb | 25 - ...024224956_migrate_account_conversations.rb | 134 -- ...3_remove_faux_remote_account_duplicates.rb | 58 - .../20181116165755_create_account_stats.rb | 14 - .../20181116173541_copy_account_stats.rb | 58 - .../20181127130500_identity_id_to_bigint.rb | 29 - ...0181127165847_add_show_replies_to_lists.rb | 25 - ...3003808_create_accounts_tags_join_table.rb | 10 - ...1203021853_add_discoverable_to_accounts.rb | 7 - ...439_add_last_status_at_to_account_stats.rb | 7 - ...20181204215309_create_account_tag_stats.rb | 13 - ...207011115_downcase_custom_emoji_domains.rb | 17 - .../20181213184704_create_account_warnings.rb | 14 - ...13185533_create_account_warning_presets.rb | 11 - ..._add_created_by_application_id_to_users.rb | 10 - ...226021420_add_also_known_as_to_accounts.rb | 7 - ...0190103124649_create_scheduled_statuses.rb | 11 - ...cheduled_status_id_to_media_attachments.rb | 10 - .../20190117114553_create_tombstones.rb | 14 - ...20190201012802_add_overwrite_to_imports.rb | 19 - .../20190203180359_create_featured_tags.rb | 14 - db/migrate/20190225031541_create_polls.rb | 19 - .../20190225031625_create_poll_votes.rb | 13 - .../20190226003449_add_poll_id_to_statuses.rb | 7 - .../20190304152020_add_uri_to_poll_votes.rb | 7 - ...0190306145741_add_lock_version_to_polls.rb | 25 - .../20190307234537_add_approved_to_users.rb | 25 - ...1829_migrate_open_registrations_setting.rb | 19 - ...16190352_create_account_identity_proofs.rb | 18 - .../20190317135723_add_uri_to_reports.rb | 7 - .../20190403141604_add_comment_to_invites.rb | 7 - ...90409054914_create_user_invite_requests.rb | 12 - ...25523_add_blurhash_to_media_attachments.rb | 7 - ...509164208_add_by_moderator_to_tombstone.rb | 7 - ...dd_silenced_at_suspended_at_to_accounts.rb | 43 - ...0512200918_add_content_type_to_statuses.rb | 7 - ..._preserve_old_layout_for_existing_users.rb | 19 - ...27222225_create_custom_emoji_categories.rb | 11 - ...222826_add_category_id_to_custom_emojis.rb | 7 - ...90701022101_add_trust_level_to_accounts.rb | 7 - .../20190705002136_create_domain_allows.rb | 11 - .../20190715164535_add_instance_actor.rb | 24 - ...5042_add_case_insensitive_index_to_tags.rb | 36 - .../20190729185330_add_score_to_tags.rb | 7 - ...20190805123746_add_capabilities_to_tags.rb | 11 - ...807135426_add_comments_to_domain_blocks.rb | 8 - ...190815225426_add_last_status_at_to_tags.rb | 8 - ...190819134503_add_deleted_at_to_statuses.rb | 7 - .../20190820003045_update_statuses_index.rb | 15 - ...90823221802_add_local_index_to_statuses.rb | 13 - .../20190901035623_add_max_score_to_tags.rb | 8 - db/migrate/20190904222339_create_markers.rb | 16 - ...0190914202517_create_account_migrations.rb | 14 - .../20190915194355_create_account_aliases.rb | 13 - ...20190917213523_add_remember_token_index.rb | 9 - ...0190927232842_add_voters_count_to_polls.rb | 7 - ...13028_add_lock_version_to_account_stats.rb | 17 - .../20191007013357_update_pt_locales.rb | 17 - ...205_change_list_account_follow_nullable.rb | 9 - .../20191212003415_increase_backup_size.rb | 23 - ...163405_add_hide_collections_to_accounts.rb | 7 - .../20191218153258_create_announcements.rb | 18 - ...0200113125135_create_announcement_mutes.rb | 14 - ...114113335_create_announcement_reactions.rb | 17 - ...0119112504_add_public_index_to_statuses.rb | 13 - ...03551_add_published_at_to_announcements.rb | 7 - ...625_add_processing_to_media_attachments.rb | 7 - ...20200309150742_add_forwarded_to_reports.rb | 7 - ...58_add_title_to_account_warning_presets.rb | 17 - ...2162302_add_status_ids_to_announcements.rb | 7 - ...43_add_parent_id_to_email_domain_blocks.rb | 7 - .../20200317021758_add_expires_at_to_mutes.rb | 7 - ...200407201300_create_unavailable_domains.rb | 11 - ...00407202420_migrate_unavailable_inboxes.rb | 24 - ...200417125749_add_storage_schema_version.rb | 11 - .../20200508212852_reset_unique_jobs_locks.rb | 14 - .../20200510110808_reset_web_app_secret.rb | 16 - ...181721_remove_duplicated_indexes_pghero.rb | 23 - db/migrate/20200516180352_create_devices.rb | 16 - .../20200516183822_create_one_time_keys.rb | 14 - ...0200518083523_create_encrypted_messages.rb | 17 - ..._encrypted_message_ids_to_timestamp_ids.rb | 15 - ...00529214050_add_devices_url_to_accounts.rb | 7 - .../20200601222558_create_system_keys.rb | 11 - ...605155027_add_blurhash_to_preview_cards.rb | 7 - ...200608113046_add_sign_in_token_to_users.rb | 8 - ...200614002136_add_sensitized_to_accounts.rb | 7 - ...3_add_fixed_lowercase_index_to_accounts.rb | 32 - ...5_media_attachment_ids_to_timestamp_ids.rb | 19 - ..._thumbnail_columns_to_media_attachments.rb | 13 - .../20200628133322_create_account_notes.rb | 14 - ...00630190240_create_webauthn_credentials.rb | 18 - ...20200630190544_add_webauthn_id_to_users.rb | 7 - ...193330_create_account_deletion_requests.rb | 10 - .../20200917192924_add_notify_to_follows.rb | 21 - ...0200917193034_add_type_to_notifications.rb | 7 - ...7222316_add_index_notifications_on_type.rb | 9 - db/migrate/20201008202037_create_ip_blocks.rb | 14 - .../20201008220312_add_sign_up_ip_to_users.rb | 7 - ...33919_add_suspension_origin_to_accounts.rb | 7 - db/migrate/20201206004238_create_instances.rb | 11 - ...18054746_add_obfuscate_to_domain_blocks.rb | 17 - db/migrate/20210221045109_create_rules.rb | 13 - ...0306164523_account_ids_to_timestamp_ids.rb | 19 - ...20210322164601_create_account_summaries.rb | 11 - ...323114347_create_follow_recommendations.rb | 7 - ...eate_follow_recommendation_suppressions.rb | 11 - ...416200740_create_canonical_email_blocks.rb | 12 - ...dd_case_insensitive_btree_index_to_tags.rb | 27 - ..._media_attachments_account_id_status_id.rb | 15 - ...ate_follow_recommendations_to_version_2.rb | 20 - .../20210609202149_create_login_activities.rb | 16 - db/migrate/20210616214526_create_user_ips.rb | 7 - ...1221010_add_skip_sign_in_token_to_users.rb | 7 - ..._fix_canonical_email_blocks_foreign_key.rb | 15 - ...reate_account_statuses_cleanup_policies.rb | 21 - ...0210904215403_add_edited_at_to_statuses.rb | 7 - .../20210908220918_create_status_edits.rb | 15 - ...031031021_create_preview_card_providers.rb | 14 - ...112011713_add_language_to_preview_cards.rb | 9 - ...15032527_add_trendable_to_preview_cards.rb | 7 - ...23212714_add_link_type_to_preview_cards.rb | 7 - ...6_update_account_summaries_to_version_2.rb | 26 - .../20211231080958_add_category_to_reports.rb | 23 - ...5163928_remove_mentions_status_id_index.rb | 11 - ...25126_add_report_id_to_account_warnings.rb | 8 - ...20115125341_fix_account_warning_actions.rb | 23 - ...202951_add_deleted_at_index_on_statuses.rb | 9 - db/migrate/20220124141035_create_appeals.rb | 16 - ...0220202200743_add_trendable_to_accounts.rb | 9 - ...0220202200926_add_trendable_to_statuses.rb | 7 - ...175231_add_content_type_to_status_edits.rb | 7 - ...19_add_overruled_at_to_account_warnings.rb | 7 - ...24010024_add_ips_to_email_domain_blocks.rb | 8 - ...add_last_used_at_to_oauth_access_tokens.rb | 8 - ...rdered_media_attachment_ids_to_statuses.rb | 7 - ...ed_media_attachment_ids_to_status_edits.rb | 10 - ...4195405_migrate_hide_network_preference.rb | 39 - ...307094650_fix_featured_tags_constraints.rb | 19 - .../20220309213005_fix_reblog_deleted_at.rb | 11 - .../20220316233212_update_kurdish_locales.rb | 19 - ...112511_add_index_statuses_on_account_id.rb | 9 - ...27_add_index_statuses_pins_on_status_id.rb | 9 - ...dd_index_reports_on_assigned_account_id.rb | 9 - ...x_reports_on_action_taken_by_account_id.rb | 9 - db/migrate/20220606044941_create_webhooks.rb | 14 - .../20220611210335_create_user_roles.rb | 15 - .../20220611212541_add_role_id_to_users.rb | 10 - ...613110628_create_custom_filter_keywords.rb | 13 - .../20220613110711_migrate_custom_filters.rb | 34 - ...0613110834_add_action_to_custom_filters.rb | 21 - ...20220710102457_add_display_name_to_tags.rb | 7 - .../20220714171049_create_tag_follows.rb | 14 - ...808101323_create_custom_filter_statuses.rb | 12 - ...d_human_identifier_to_admin_action_logs.rb | 9 - .../20220824233535_create_status_trends.rb | 14 - ..._change_canonical_email_blocks_nullable.rb | 7 - ...20220829192633_add_languages_to_follows.rb | 7 - ...192658_add_languages_to_follow_requests.rb | 7 - ...221006061337_create_preview_card_trends.rb | 13 - ...1012181003_add_blurhash_to_site_uploads.rb | 7 - ..._featured_tags_on_account_id_and_tag_id.rb | 21 - ...0221025171544_add_index_ip_blocks_on_ip.rb | 19 - ...0221104133904_add_name_to_featured_tags.rb | 7 - ...20230129023109_add_template_to_webhooks.rb | 7 - .../20230215074327_add_settings_to_users.rb | 7 - .../20230215074423_move_user_settings.rb | 89 -- ...0230215074424_move_glitch_user_settings.rb | 62 - .../20230330135507_create_bulk_imports.rb | 22 - .../20230330140036_create_bulk_import_rows.rb | 12 - ..._add_follow_request_id_to_list_accounts.rb | 10 - ...515_add_index_accounts_on_domain_and_id.rb | 9 - ...0230524192812_fix_account_domain_casing.rb | 13 - ...5_add_index_instances_on_reverse_domain.rb | 9 - ...primary_key_to_accounts_tags_join_table.rb | 24 - ...primary_key_to_statuses_tags_join_table.rb | 24 - .../20230605085710_add_exclusive_to_lists.rb | 17 - .../20230605085711_add_time_zone_to_users.rb | 7 - ...0630145300_add_index_backups_on_user_id.rb | 9 - ...1023_add_superapp_index_to_applications.rb | 9 - ...753_add_index_user_on_unconfirmed_email.rb | 9 - ...60715_add_published_at_to_preview_cards.rb | 7 - ..._add_image_description_to_preview_cards.rb | 17 - ...0230814223300_add_indexable_to_accounts.rb | 17 - ...56_create_global_follow_recommendations.rb | 8 - .../20230822081029_create_software_updates.rb | 16 - ..._stats_on_last_status_at_and_account_id.rb | 9 - db/post_migrate/.gitkeep | 0 ...0180813113448_copy_status_stats_cleanup.rb | 12 - .../20180813160548_post_migrate_filters.rb | 11 - ...181116184611_copy_account_stats_cleanup.rb | 13 - ...emove_suspended_silenced_account_fields.rb | 46 - ...9130537_remove_boosts_widening_audience.rb | 25 - .../20190706233204_drop_stream_entries.rb | 13 - .../20190715031050_drop_subscriptions.rb | 11 - .../20190901040524_remove_score_from_tags.rb | 12 - ...42_remove_invalid_web_push_subscription.rb | 18 - ...200917193528_migrate_notifications_type.rb | 22 - ...index_notifications_on_account_activity.rb | 15 - ...17234926_fill_account_suspension_origin.rb | 18 - ...e_subscription_expires_at_from_accounts.rb | 9 - .../20210502233513_drop_account_tag_stats.rb | 13 - ...0507001928_remove_hub_url_from_accounts.rb | 12 - ..._remove_lock_version_from_account_stats.rb | 9 - ...35_remove_current_sign_in_ip_from_users.rb | 12 - ...0808071221_clear_orphaned_account_notes.rb | 21 - ...1126000907_drop_account_identity_proofs.rb | 13 - ...213908_remove_action_taken_from_reports.rb | 9 - ...10_remove_index_users_on_remember_token.rb | 13 - ...18183123_remove_rememberable_from_users.rb | 10 - ...201015_remove_trust_level_from_accounts.rb | 9 - ...a_attachments_changed_from_status_edits.rb | 7 - ...3_optimize_null_index_conversations_uri.rb | 17 - ...l_index_statuses_in_reply_to_account_id.rb | 17 - ...mize_null_index_statuses_in_reply_to_id.rb | 17 - ...x_media_attachments_scheduled_status_id.rb | 17 - ..._null_index_media_attachments_shortcode.rb | 17 - ...e_null_index_users_reset_password_token.rb | 17 - ...l_index_users_created_by_application_id.rb | 17 - ...060706_optimize_null_index_statuses_uri.rb | 17 - ...null_index_accounts_moved_to_account_id.rb | 17 - ...index_oauth_access_tokens_refresh_token.rb | 17 - ...060750_optimize_null_index_accounts_url.rb | 17 - ...x_oauth_access_tokens_resource_owner_id.rb | 17 - ..._announcement_reactions_custom_emoji_id.rb | 17 - ...ll_index_appeals_approved_by_account_id.rb | 17 - ...ex_account_migrations_target_account_id.rb | 17 - ...ll_index_appeals_rejected_by_account_id.rb | 17 - ...mize_null_index_list_accounts_follow_id.rb | 17 - ..._web_push_subscriptions_access_token_id.rb | 17 - ...025_remove_ips_from_email_domain_blocks.rb | 12 - ...0220429101850_clear_email_domain_blocks.rb | 14 - ...23_remove_filtered_languages_from_users.rb | 11 - ...2_remove_whole_word_from_custom_filters.rb | 21 - ...remove_irreversible_from_custom_filters.rb | 21 - .../20220617202502_migrate_roles.rb | 27 - ...04024901_migrate_settings_to_user_roles.rb | 41 - ...71123_fix_custom_filter_keywords_id_seq.rb | 20 - ...recorded_changes_from_admin_action_logs.rb | 9 - ...221101190723_backfill_admin_action_logs.rb | 166 -- ...114142_backfill_admin_action_logs_again.rb | 166 -- ..._unique_index_on_preview_cards_statuses.rb | 51 - ...ey_to_preview_cards_statuses_join_table.rb | 20 - ...atuses_on_status_id_and_preview_card_id.rb | 9 - ...30818142253_drop_follow_recommendations.rb | 12 - .../20230904134623_fix_kmr_locale_settings.rb | 27 - db/schema.rb | 1380 ----------------- db/seeds.rb | 7 - db/seeds/01_web_app.rb | 3 - db/seeds/02_instance_actor.rb | 3 - db/seeds/03_roles.rb | 11 - db/seeds/04_admin.rb | 11 - db/views/account_summaries_v01.sql | 22 - db/views/account_summaries_v02.sql | 23 - db/views/follow_recommendations_v01.sql | 38 - db/views/follow_recommendations_v02.sql | 34 - .../global_follow_recommendations_v01.sql | 32 - db/views/instances_v01.sql | 17 - db/views/user_ips_v01.sql | 26 - dist/mastodon-sidekiq.service | 53 - dist/mastodon-streaming.service | 12 - dist/mastodon-streaming@.service | 54 - dist/mastodon-web.service | 53 - dist/nginx.conf | 173 --- docker-compose.yml | 133 -- lib/active_record/batches.rb | 44 - .../database_tasks_extensions.rb | 20 - lib/chewy/index_extensions.rb | 18 - lib/chewy/settings_extensions.rb | 11 - lib/chewy/strategy/bypass_with_warning.rb | 12 - lib/chewy/strategy/mastodon.rb | 27 - lib/devise/two_factor_ldap_authenticatable.rb | 32 - lib/devise/two_factor_pam_authenticatable.rb | 31 - lib/exceptions.rb | 38 - .../post_deployment_migration/USAGE | 10 - .../post_deployment_migration_generator.rb | 17 - .../templates/migration.erb | 8 - lib/http_extensions.rb | 8 - lib/json_ld/identity.rb | 86 - lib/json_ld/security.rb | 50 - lib/linter/haml_middle_dot.rb | 26 - lib/linter/rubocop_middle_dot.rb | 31 - lib/mastodon/cli/accounts.rb | 674 -------- lib/mastodon/cli/base.rb | 42 - lib/mastodon/cli/cache.rb | 72 - lib/mastodon/cli/canonical_email_blocks.rb | 43 - lib/mastodon/cli/domains.rb | 216 --- lib/mastodon/cli/email_domain_blocks.rb | 123 -- lib/mastodon/cli/emoji.rb | 140 -- lib/mastodon/cli/feeds.rb | 57 - lib/mastodon/cli/ip_blocks.rb | 143 -- lib/mastodon/cli/main.rb | 155 -- lib/mastodon/cli/maintenance.rb | 690 --------- lib/mastodon/cli/media.rb | 376 ----- lib/mastodon/cli/preview_cards.rb | 51 - lib/mastodon/cli/progress_helper.rb | 87 -- lib/mastodon/cli/search.rb | 120 -- lib/mastodon/cli/settings.rb | 38 - lib/mastodon/cli/statuses.rb | 219 --- lib/mastodon/cli/upgrade.rb | 167 -- lib/mastodon/migration_helpers.rb | 990 ------------ lib/mastodon/migration_warning.rb | 55 - lib/mastodon/premailer_webpack_strategy.rb | 23 - lib/mastodon/rack_middleware.rb | 30 - lib/mastodon/redis_config.rb | 49 - lib/mastodon/sidekiq_middleware.rb | 37 - lib/mastodon/snowflake.rb | 176 --- lib/mastodon/version.rb | 71 - lib/paperclip/attachment_extensions.rb | 98 -- lib/paperclip/blurhash_transcoder.rb | 16 - lib/paperclip/color_extractor.rb | 189 --- lib/paperclip/gif_transcoder.rb | 126 -- lib/paperclip/image_extractor.rb | 50 - lib/paperclip/lazy_thumbnail.rb | 39 - .../media_type_spoof_detector_extensions.rb | 24 - lib/paperclip/response_with_limit_adapter.rb | 55 - lib/paperclip/transcoder.rb | 125 -- lib/paperclip/type_corrector.rb | 21 - lib/paperclip/url_generator_extensions.rb | 11 - lib/public_file_server_middleware.rb | 48 - lib/rails/engine_extensions.rb | 13 - lib/redis/namespace_extensions.rb | 12 - lib/sanitize_ext/sanitize_config.rb | 175 --- lib/simple_navigation/item_extensions.rb | 15 - lib/tasks/assets.rake | 26 - lib/tasks/auto_annotate_models.rake | 46 - lib/tasks/branding.rake | 79 - lib/tasks/db.rake | 24 - lib/tasks/emojis.rake | 106 -- lib/tasks/glitchsoc.rake | 12 - lib/tasks/mastodon.rake | 608 -------- lib/tasks/repo.rake | 136 -- lib/tasks/spec.rake | 21 - lib/tasks/statistics.rake | 19 - lib/tasks/tests.rake | 392 ----- lib/templates/haml/scaffold/_form.html.haml | 10 - lib/terrapin/multi_pipe_extensions.rb | 66 - lib/webpacker/helper_extensions.rb | 27 - lib/webpacker/manifest_extensions.rb | 17 - log/.keep | 0 nginx.conf | 42 + package.json | 3 +- public/auth.js | 26 +- public/favicon.ico | Bin 15086 -> 15406 bytes public/images/mascot.svg | 205 ++- scalingo.json | 101 -- spec/chewy/accounts_index_spec.rb | 31 - spec/chewy/public_statuses_index_spec.rb | 31 - spec/chewy/statuses_index_spec.rb | 31 - spec/chewy/tags_index_spec.rb | 31 - spec/config/initializers/rack_attack_spec.rb | 106 -- spec/controllers/.rubocop.yml | 6 - spec/controllers/about_controller_spec.rb | 17 - spec/controllers/accounts_controller_spec.rb | 474 ------ .../activitypub/claims_controller_spec.rb | 19 - .../collections_controller_spec.rb | 187 --- ...lowers_synchronizations_controller_spec.rb | 83 - .../activitypub/inboxes_controller_spec.rb | 112 -- .../activitypub/outboxes_controller_spec.rb | 236 --- .../activitypub/replies_controller_spec.rb | 213 --- .../admin/account_actions_controller_spec.rb | 35 - ...ccount_moderation_notes_controller_spec.rb | 48 - .../admin/accounts_controller_spec.rb | 436 ------ .../admin/action_logs_controller_spec.rb | 27 - .../admin/announcements_controller_spec.rb | 102 -- .../controllers/admin/base_controller_spec.rb | 42 - .../admin/change_emails_controller_spec.rb | 48 - .../admin/confirmations_controller_spec.rb | 64 - .../admin/custom_emojis_controller_spec.rb | 57 - .../admin/dashboard_controller_spec.rb | 24 - .../admin/disputes/appeals_controller_spec.rb | 57 - .../admin/domain_allows_controller_spec.rb | 50 - .../admin/domain_blocks_controller_spec.rb | 227 --- .../email_domain_blocks_controller_spec.rb | 59 - .../export_domain_allows_controller_spec.rb | 44 - .../export_domain_blocks_controller_spec.rb | 59 - .../follow_recommendations_controller_spec.rb | 21 - .../admin/instances_controller_spec.rb | 59 - .../admin/invites_controller_spec.rb | 59 - .../admin/ip_blocks_controller_spec.rb | 54 - .../admin/relationships_controller_spec.rb | 23 - .../admin/relays_controller_spec.rb | 100 -- .../admin/report_notes_controller_spec.rb | 92 -- .../admin/reports/actions_controller_spec.rb | 155 -- .../admin/reports_controller_spec.rb | 97 -- .../admin/resets_controller_spec.rb | 25 - .../admin/roles_controller_spec.rb | 251 --- .../admin/rules_controller_spec.rb | 85 - .../admin/settings/about_controller_spec.rb | 21 - .../settings/appearance_controller_spec.rb | 21 - .../settings/branding_controller_spec.rb | 53 - .../content_retention_controller_spec.rb | 21 - .../settings/discovery_controller_spec.rb | 21 - .../settings/registrations_controller_spec.rb | 21 - .../admin/site_uploads_controller_spec.rb | 23 - .../admin/statuses_controller_spec.rb | 87 -- .../controllers/admin/tags_controller_spec.rb | 23 - .../preview_card_providers_controller_spec.rb | 21 - .../admin/trends/links_controller_spec.rb | 21 - .../admin/trends/statuses_controller_spec.rb | 21 - .../admin/trends/tags_controller_spec.rb | 21 - .../admin/users/roles_controller_spec.rb | 83 - ..._factor_authentications_controller_spec.rb | 54 - .../admin/warning_presets_controller_spec.rb | 85 - .../admin/webhooks/secrets_controller_spec.rb | 23 - .../admin/webhooks_controller_spec.rb | 99 -- spec/controllers/api/base_controller_spec.rb | 99 -- .../controllers/api/oembed_controller_spec.rb | 25 - .../accounts/credentials_controller_spec.rb | 111 -- .../familiar_followers_controller_spec.rb | 23 - .../accounts/featured_tags_controller_spec.rb | 23 - .../follower_accounts_controller_spec.rb | 65 - .../following_accounts_controller_spec.rb | 65 - .../identity_proofs_controller_spec.rb | 23 - .../api/v1/accounts/lists_controller_spec.rb | 25 - .../api/v1/accounts/lookup_controller_spec.rb | 23 - .../api/v1/accounts/notes_controller_spec.rb | 50 - .../api/v1/accounts/pins_controller_spec.rb | 46 - .../accounts/relationships_controller_spec.rb | 102 -- .../api/v1/accounts/search_controller_spec.rb | 22 - .../v1/accounts/statuses_controller_spec.rb | 107 -- .../api/v1/accounts_controller_spec.rb | 329 ---- .../api/v1/admin/accounts_controller_spec.rb | 198 --- .../v1/admin/dimensions_controller_spec.rb | 23 - .../api/v1/admin/measures_controller_spec.rb | 23 - .../api/v1/admin/retention_controller_spec.rb | 23 - .../preview_card_providers_controller_spec.rb | 52 - .../v1/admin/trends/links_controller_spec.rb | 52 - .../admin/trends/statuses_controller_spec.rb | 52 - .../v1/admin/trends/tags_controller_spec.rb | 52 - .../reactions_controller_spec.rb | 65 - .../api/v1/announcements_controller_spec.rb | 59 - .../api/v1/blocks_controller_spec.rb | 65 - .../api/v1/conversations_controller_spec.rb | 59 - .../api/v1/custom_emojis_controller_spec.rb | 18 - .../api/v1/directories_controller_spec.rb | 135 -- .../api/v1/endorsements_controller_spec.rb | 17 - .../api/v1/favourites_controller_spec.rb | 80 - .../suggestions_controller_spec.rb | 23 - .../api/v1/filters_controller_spec.rb | 112 -- .../api/v1/followed_tags_controller_spec.rb | 25 - .../v1/instances/activity_controller_spec.rb | 21 - .../domain_blocks_controller_spec.rb | 16 - .../extended_descriptions_controller_spec.rb | 15 - .../api/v1/instances/peers_controller_spec.rb | 21 - .../privacy_policies_controller_spec.rb | 15 - .../api/v1/instances/rules_controller_spec.rb | 15 - .../translation_languages_controller_spec.rb | 30 - .../api/v1/instances_controller_spec.rb | 22 - .../api/v1/lists/accounts_controller_spec.rb | 92 -- .../api/v1/markers_controller_spec.rb | 67 - .../api/v1/media_controller_spec.rb | 132 -- .../api/v1/notifications_controller_spec.rb | 137 -- .../api/v1/polls/votes_controller_spec.rb | 36 - .../api/v1/preferences_controller_spec.rb | 23 - .../v1/push/subscriptions_controller_spec.rb | 99 -- .../api/v1/reports_controller_spec.rb | 75 - .../v1/scheduled_statuses_controller_spec.rb | 23 - .../favourited_by_accounts_controller_spec.rb | 83 - .../v1/statuses/histories_controller_spec.rb | 30 - .../api/v1/statuses/mutes_controller_spec.rb | 50 - .../reblogged_by_accounts_controller_spec.rb | 83 - .../v1/statuses/reblogs_controller_spec.rb | 134 -- .../v1/statuses/sources_controller_spec.rb | 29 - .../statuses/translations_controller_spec.rb | 33 - .../api/v1/statuses_controller_spec.rb | 271 ---- .../api/v1/streaming_controller_spec.rb | 45 - .../v1/timelines/direct_controller_spec.rb | 17 - .../api/v1/timelines/list_controller_spec.rb | 56 - .../api/v1/timelines/tag_controller_spec.rb | 75 - .../api/v1/trends/links_controller_spec.rb | 15 - .../api/v1/trends/statuses_controller_spec.rb | 15 - .../api/v1/trends/tags_controller_spec.rb | 21 - .../api/v2/admin/accounts_controller_spec.rb | 67 - .../v2/filters/keywords_controller_spec.rb | 144 -- .../v2/filters/statuses_controller_spec.rb | 118 -- .../api/v2/instances_controller_spec.rb | 22 - .../api/v2/search_controller_spec.rb | 95 -- .../api/v2/suggestions_controller_spec.rb | 22 - .../web/push_subscriptions_controller_spec.rb | 97 -- .../api/web/settings_controller_spec.rb | 24 - .../application_controller_spec.rb | 266 ---- .../auth/challenges_controller_spec.rb | 46 - .../auth/confirmations_controller_spec.rb | 99 -- .../auth/passwords_controller_spec.rb | 99 -- .../auth/registrations_controller_spec.rb | 291 ---- .../auth/sessions_controller_spec.rb | 430 ----- .../controllers/auth/setup_controller_spec.rb | 25 - .../authorize_interactions_controller_spec.rb | 66 - .../account_controller_concern_spec.rb | 76 - .../concerns/accountable_concern_spec.rb | 28 - .../concerns/cache_concern_spec.rb | 60 - .../concerns/challengable_concern_spec.rb | 114 -- .../export_controller_concern_spec.rb | 35 - spec/controllers/concerns/localized_spec.rb | 68 - .../concerns/rate_limit_headers_spec.rb | 56 - .../concerns/signature_verification_spec.rb | 305 ---- .../concerns/user_tracking_concern_spec.rb | 91 -- .../controllers/custom_css_controller_spec.rb | 30 - .../disputes/appeals_controller_spec.rb | 28 - .../disputes/strikes_controller_spec.rb | 32 - spec/controllers/emojis_controller_spec.rb | 20 - .../filters/statuses_controller_spec.rb | 47 - spec/controllers/filters_controller_spec.rb | 34 - .../follower_accounts_controller_spec.rb | 126 -- .../following_accounts_controller_spec.rb | 126 -- spec/controllers/health_controller_spec.rb | 14 - spec/controllers/home_controller_spec.rb | 30 - .../instance_actors_controller_spec.rb | 59 - spec/controllers/intents_controller_spec.rb | 53 - spec/controllers/invites_controller_spec.rb | 87 -- spec/controllers/manifests_controller_spec.rb | 30 - spec/controllers/media_controller_spec.rb | 65 - .../media_proxy_controller_spec.rb | 42 - .../oauth/authorizations_controller_spec.rb | 78 - ...authorized_applications_controller_spec.rb | 67 - .../oauth/tokens_controller_spec.rb | 24 - spec/controllers/privacy_controller_spec.rb | 14 - .../relationships_controller_spec.rb | 91 -- .../settings/aliases_controller_spec.rb | 74 - .../settings/applications_controller_spec.rb | 192 --- .../settings/deletes_controller_spec.rb | 102 -- .../blocked_accounts_controller_spec.rb | 19 - .../blocked_domains_controller_spec.rb | 20 - .../exports/bookmarks_controller_spec.rb | 24 - .../following_accounts_controller_spec.rb | 19 - .../settings/exports/lists_controller_spec.rb | 21 - .../exports/muted_accounts_controller_spec.rb | 19 - .../settings/exports_controller_spec.rb | 52 - .../settings/featured_tags_controller_spec.rb | 64 - .../settings/flavours_controller_spec.rb | 39 - .../settings/imports_controller_spec.rb | 319 ---- .../login_activities_controller_spec.rb | 27 - .../migration/redirects_controller_spec.rb | 70 - .../settings/migrations_controller_spec.rb | 113 -- .../settings/pictures_controller_spec.rb | 52 - .../preferences/appearance_controller_spec.rb | 41 - .../preferences/base_controller_spec.rb | 11 - .../notifications_controller_spec.rb | 48 - .../preferences/other_controller_spec.rb | 57 - .../settings/profiles_controller_spec.rb | 54 - .../settings/sessions_controller_spec.rb | 33 - .../confirmations_controller_spec.rb | 127 -- .../otp_authentication_controller_spec.rb | 99 -- .../recovery_codes_controller_spec.rb | 31 - .../webauthn_credentials_controller_spec.rb | 374 ----- ..._authentication_methods_controller_spec.rb | 82 - spec/controllers/shares_controller_spec.rb | 22 - .../statuses_cleanup_controller_spec.rb | 42 - spec/controllers/statuses_controller_spec.rb | 787 ---------- spec/controllers/tags_controller_spec.rb | 57 - .../well_known/host_meta_controller_spec.rb | 22 - .../well_known/nodeinfo_controller_spec.rb | 41 - .../well_known/webfinger_controller_spec.rb | 235 --- spec/fabrication/fabricators_spec.rb | 14 - spec/fabricators/access_grant_fabricator.rb | 8 - spec/fabricators/access_token_fabricator.rb | 4 - .../accessible_access_token_fabricator.rb | 6 - .../account_domain_block_fabricator.rb | 6 - spec/fabricators/account_fabricator.rb | 18 - .../account_migration_fabricator.rb | 9 - .../account_moderation_note_fabricator.rb | 7 - spec/fabricators/account_note_fabricator.rb | 7 - spec/fabricators/account_pin_fabricator.rb | 7 - spec/fabricators/account_stat_fabricator.rb | 8 - ...ount_statuses_cleanup_policy_fabricator.rb | 5 - .../fabricators/account_warning_fabricator.rb | 8 - .../account_warning_preset_fabricator.rb | 5 - .../admin_action_log_fabricator.rb | 7 - spec/fabricators/announcement_fabricator.rb | 8 - spec/fabricators/appeal_fabricator.rb | 7 - spec/fabricators/application_fabricator.rb | 7 - spec/fabricators/assets/TEAPOT | 6 - spec/fabricators/assets/utah_teapot.png | Bin 195600 -> 0 bytes spec/fabricators/backup_fabricator.rb | 5 - spec/fabricators/block_fabricator.rb | 6 - spec/fabricators/bookmark_fabricator.rb | 6 - spec/fabricators/bulk_import_fabricator.rb | 12 - .../fabricators/bulk_import_row_fabricator.rb | 6 - .../canonical_email_block_fabricator.rb | 6 - spec/fabricators/conversation_fabricator.rb | 4 - spec/fabricators/custom_emoji_fabricator.rb | 7 - spec/fabricators/custom_filter_fabricator.rb | 8 - .../custom_filter_keyword_fabricator.rb | 6 - .../custom_filter_status_fabricator.rb | 6 - spec/fabricators/device_fabricator.rb | 10 - spec/fabricators/domain_allow_fabricator.rb | 5 - spec/fabricators/domain_block_fabricator.rb | 5 - .../email_domain_block_fabricator.rb | 5 - .../encrypted_message_fabricator.rb | 7 - spec/fabricators/favourite_fabricator.rb | 6 - spec/fabricators/featured_tag_fabricator.rb | 7 - spec/fabricators/follow_fabricator.rb | 6 - spec/fabricators/follow_request_fabricator.rb | 6 - spec/fabricators/identity_fabricator.rb | 7 - spec/fabricators/invite_fabricator.rb | 8 - spec/fabricators/list_account_fabricator.rb | 7 - spec/fabricators/list_fabricator.rb | 6 - spec/fabricators/login_activity_fabricator.rb | 10 - spec/fabricators/marker_fabricator.rb | 8 - .../media_attachment_fabricator.rb | 14 - spec/fabricators/mention_fabricator.rb | 6 - spec/fabricators/mute_fabricator.rb | 6 - spec/fabricators/notification_fabricator.rb | 6 - spec/fabricators/one_time_key_fabricator.rb | 13 - spec/fabricators/poll_fabricator.rb | 10 - spec/fabricators/poll_vote_fabricator.rb | 7 - spec/fabricators/preview_card_fabricator.rb | 9 - .../preview_card_provider_fabricator.rb | 5 - spec/fabricators/relay_fabricator.rb | 6 - spec/fabricators/report_fabricator.rb | 8 - spec/fabricators/report_note_fabricator.rb | 7 - spec/fabricators/rule_fabricator.rb | 7 - .../scheduled_status_fabricator.rb | 6 - .../session_activation_fabricator.rb | 6 - spec/fabricators/setting_fabricator.rb | 5 - spec/fabricators/site_upload_fabricator.rb | 6 - .../fabricators/software_update_fabricator.rb | 7 - spec/fabricators/status_fabricator.rb | 10 - spec/fabricators/status_pin_fabricator.rb | 6 - spec/fabricators/status_stat_fabricator.rb | 8 - spec/fabricators/system_key_fabricator.rb | 4 - spec/fabricators/tag_fabricator.rb | 5 - spec/fabricators/tag_follow_fabricator.rb | 6 - .../unavailable_domain_fabricator.rb | 5 - spec/fabricators/user_fabricator.rb | 10 - spec/fabricators/user_role_fabricator.rb | 7 - .../web_push_subscription_fabricator.rb | 7 - .../webauthn_credential_fabricator.rb | 9 - spec/fabricators/webhook_fabricator.rb | 7 - spec/features/admin/domain_blocks_spec.rb | 102 -- spec/features/admin/software_updates_spec.rb | 23 - spec/features/captcha_spec.rb | 35 - spec/features/log_in_spec.rb | 51 - spec/features/oauth_spec.rb | 190 --- spec/features/profile_spec.rb | 33 - spec/fixtures/files/4096x4097.png | Bin 58859 -> 0 bytes spec/fixtures/files/600x400.avif | Bin 7742 -> 0 bytes spec/fixtures/files/600x400.heic | Bin 9671 -> 0 bytes spec/fixtures/files/600x400.jpeg | Bin 21442 -> 0 bytes spec/fixtures/files/600x400.png | Bin 14127 -> 0 bytes spec/fixtures/files/600x400.webp | Bin 9026 -> 0 bytes .../fixtures/files/attachment-jpg.123456_abcd | Bin 61022 -> 0 bytes spec/fixtures/files/attachment.gif | Bin 30184 -> 0 bytes spec/fixtures/files/attachment.jpg | Bin 61022 -> 0 bytes spec/fixtures/files/attachment.webm | Bin 43777 -> 0 bytes spec/fixtures/files/avatar.gif | Bin 85810 -> 0 bytes spec/fixtures/files/bookmark-imports.txt | 4 - spec/fixtures/files/boop.mp3 | Bin 7841601 -> 0 bytes spec/fixtures/files/boop.ogg | Bin 11379 -> 0 bytes spec/fixtures/files/domain_allows.csv | 3 - spec/fixtures/files/domain_blocks.csv | 4 - spec/fixtures/files/domain_blocks_list.txt | 3 - spec/fixtures/files/emojo.png | Bin 29283 -> 0 bytes spec/fixtures/files/empty.csv | 0 spec/fixtures/files/following_accounts.csv | 5 - spec/fixtures/files/imports.txt | 3 - spec/fixtures/files/lists.csv | 3 - spec/fixtures/files/mini-static.gif | Bin 1188 -> 0 bytes spec/fixtures/files/mute-imports.txt | 4 - spec/fixtures/files/muted_accounts.csv | 5 - spec/fixtures/files/new-following-imports.txt | 4 - spec/fixtures/files/new-mute-imports.txt | 4 - spec/fixtures/files/utf8-followers.txt | 1 - spec/fixtures/push/feed.atom | 424 ----- spec/fixtures/push/reblog.atom | 92 -- spec/fixtures/requests/.host-meta.txt | 19 - .../requests/activitypub-actor-individual.txt | 9 - .../requests/activitypub-actor-noinbox.txt | 9 - spec/fixtures/requests/activitypub-actor.txt | 9 - spec/fixtures/requests/activitypub-feed.txt | 47 - .../requests/activitypub-webfinger.txt | 7 - spec/fixtures/requests/attachment1.txt | Bin 192052 -> 0 bytes spec/fixtures/requests/attachment2.txt | Bin 109077 -> 0 bytes spec/fixtures/requests/avatar.txt | Bin 109961 -> 0 bytes spec/fixtures/requests/feed.txt | 440 ------ .../requests/json-ld.activitystreams.txt | 391 ----- spec/fixtures/requests/json-ld.identity.txt | 100 -- spec/fixtures/requests/json-ld.security.txt | 61 - spec/fixtures/requests/koi8-r.txt | 20 - spec/fixtures/requests/localdomain-feed.txt | 57 - .../requests/localdomain-hostmeta.txt | 14 - .../requests/localdomain-webfinger.txt | 20 - .../fixtures/requests/oembed_invalid_xml.html | 7 - spec/fixtures/requests/oembed_json.html | 7 - spec/fixtures/requests/oembed_json_empty.html | 7 - spec/fixtures/requests/oembed_json_xml.html | 14 - .../requests/oembed_undiscoverable.html | 5 - spec/fixtures/requests/oembed_xml.html | 13 - spec/fixtures/requests/oembed_youtube.html | 7 - .../requests/redirected.host-meta.txt | 15 - spec/fixtures/requests/sjis.txt | 20 - .../requests/sjis_with_wrong_charset.txt | 20 - spec/fixtures/requests/webfinger-hacker1.txt | 11 - spec/fixtures/requests/webfinger-hacker2.txt | 11 - spec/fixtures/requests/webfinger-hacker3.txt | 11 - spec/fixtures/requests/webfinger.txt | 11 - spec/fixtures/requests/windows-1251.txt | 17 - spec/fixtures/salmon/mention.xml | 2 - ...ost_deployment_migration_generator_spec.rb | 27 - spec/helpers/accounts_helper_spec.rb | 69 - .../account_moderation_notes_helper_spec.rb | 53 - spec/helpers/admin/dashboard_helper_spec.rb | 69 - spec/helpers/admin/filter_helper_spec.rb | 21 - .../admin/trends/statuses_helper_spec.rb | 54 - spec/helpers/application_helper_spec.rb | 300 ---- spec/helpers/flashes_helper_spec.rb | 19 - spec/helpers/formatting_helper_spec.rb | 24 - spec/helpers/home_helper_spec.rb | 119 -- spec/helpers/instance_helper_spec.rb | 33 - spec/helpers/jsonld_helper_spec.rb | 174 --- spec/helpers/languages_helper_spec.rb | 89 -- spec/helpers/media_component_helper_spec.rb | 86 - spec/helpers/react_component_helper_spec.rb | 45 - spec/helpers/routing_helper_spec.rb | 43 - spec/helpers/settings_helper_spec.rb | 37 - spec/helpers/statuses_helper_spec.rb | 117 -- spec/lib/account_reach_finder_spec.rb | 53 - spec/lib/account_statuses_filter_spec.rb | 257 --- spec/lib/activitypub/activity/accept_spec.rb | 71 - spec/lib/activitypub/activity/add_spec.rb | 80 - .../lib/activitypub/activity/announce_spec.rb | 174 --- spec/lib/activitypub/activity/block_spec.rb | 109 -- spec/lib/activitypub/activity/create_spec.rb | 976 ------------ spec/lib/activitypub/activity/delete_spec.rb | 76 - spec/lib/activitypub/activity/flag_spec.rb | 191 --- spec/lib/activitypub/activity/follow_spec.rb | 190 --- spec/lib/activitypub/activity/like_spec.rb | 31 - spec/lib/activitypub/activity/move_spec.rb | 107 -- spec/lib/activitypub/activity/reject_spec.rb | 150 -- spec/lib/activitypub/activity/remove_spec.rb | 32 - spec/lib/activitypub/activity/undo_spec.rb | 180 --- spec/lib/activitypub/activity/update_spec.rb | 119 -- spec/lib/activitypub/adapter_spec.rb | 98 -- spec/lib/activitypub/dereferencer_spec.rb | 75 - .../activitypub/linked_data_signature_spec.rb | 88 -- spec/lib/activitypub/tag_manager_spec.rb | 161 -- .../instance_accounts_dimension_spec.rb | 18 - .../instance_languages_dimension_spec.rb | 18 - .../dimension/languages_dimension_spec.rb | 18 - .../dimension/servers_dimension_spec.rb | 18 - .../software_versions_dimension_spec.rb | 18 - .../dimension/sources_dimension_spec.rb | 18 - .../dimension/space_usage_dimension_spec.rb | 18 - .../dimension/tag_languages_dimension_spec.rb | 18 - .../dimension/tag_servers_dimension_spec.rb | 18 - .../measure/active_users_measure_spec.rb | 17 - .../measure/instance_accounts_measure_spec.rb | 46 - .../instance_followers_measure_spec.rb | 48 - .../measure/instance_follows_measure_spec.rb | 48 - ...instance_media_attachments_measure_spec.rb | 49 - .../measure/instance_reports_measure_spec.rb | 45 - .../measure/instance_statuses_measure_spec.rb | 45 - .../measure/interactions_measure_spec.rb | 17 - .../metrics/measure/new_users_measure_spec.rb | 17 - .../measure/opened_reports_measure_spec.rb | 17 - .../measure/resolved_reports_measure_spec.rb | 17 - .../measure/tag_accounts_measure_spec.rb | 19 - .../measure/tag_servers_measure_spec.rb | 19 - .../metrics/measure/tag_uses_measure_spec.rb | 19 - .../lib/admin/system_check/base_check_spec.rb | 27 - .../database_schema_check_spec.rb | 45 - .../system_check/elasticsearch_check_spec.rb | 134 -- .../system_check/media_privacy_check_spec.rb | 33 - spec/lib/admin/system_check/message_spec.rb | 14 - .../admin/system_check/rules_check_spec.rb | 53 - .../sidekiq_process_check_spec.rb | 45 - .../software_version_check_spec.rb | 133 -- spec/lib/admin/system_check_spec.rb | 15 - spec/lib/advanced_text_formatter_spec.rb | 300 ---- spec/lib/cache_buster_spec.rb | 64 - .../shared_connection_pool_spec.rb | 30 - .../shared_timed_stack_spec.rb | 63 - spec/lib/delivery_failure_tracker_spec.rb | 63 - spec/lib/emoji_formatter_spec.rb | 57 - spec/lib/entity_cache_spec.rb | 21 - spec/lib/extractor_spec.rb | 79 - spec/lib/fast_ip_map_spec.rb | 21 - spec/lib/feed_manager_spec.rb | 565 ------- spec/lib/hashtag_normalizer_spec.rb | 29 - spec/lib/html_aware_formatter_spec.rb | 46 - .../importer/accounts_index_importer_spec.rb | 16 - spec/lib/importer/base_importer_spec.rb | 14 - .../public_statuses_index_importer_spec.rb | 16 - .../importer/statuses_index_importer_spec.rb | 16 - spec/lib/importer/tags_index_importer_spec.rb | 16 - spec/lib/link_details_extractor_spec.rb | 292 ---- spec/lib/mastodon/cli/accounts_spec.rb | 1364 ---------------- spec/lib/mastodon/cli/cache_spec.rb | 71 - .../cli/canonical_email_blocks_spec.rb | 60 - spec/lib/mastodon/cli/domains_spec.rb | 12 - .../mastodon/cli/email_domain_blocks_spec.rb | 12 - spec/lib/mastodon/cli/emoji_spec.rb | 12 - spec/lib/mastodon/cli/feeds_spec.rb | 68 - spec/lib/mastodon/cli/ip_blocks_spec.rb | 298 ---- spec/lib/mastodon/cli/main_spec.rb | 20 - spec/lib/mastodon/cli/maintenance_spec.rb | 12 - spec/lib/mastodon/cli/media_spec.rb | 12 - spec/lib/mastodon/cli/preview_cards_spec.rb | 12 - spec/lib/mastodon/cli/search_spec.rb | 12 - spec/lib/mastodon/cli/settings_spec.rb | 70 - spec/lib/mastodon/cli/statuses_spec.rb | 12 - spec/lib/mastodon/cli/upgrade_spec.rb | 12 - spec/lib/mastodon/migration_warning_spec.rb | 34 - spec/lib/ostatus/tag_manager_spec.rb | 70 - spec/lib/permalink_redirector_spec.rb | 33 - spec/lib/plain_text_formatter_spec.rb | 77 - spec/lib/request_pool_spec.rb | 72 - spec/lib/request_spec.rb | 143 -- spec/lib/sanitize_config_spec.rb | 76 - spec/lib/scope_transformer_spec.rb | 89 -- spec/lib/search_query_parser_spec.rb | 98 -- spec/lib/search_query_transformer_spec.rb | 80 - spec/lib/status_cache_hydrator_spec.rb | 147 -- spec/lib/status_filter_spec.rb | 84 - spec/lib/status_finder_spec.rb | 56 - spec/lib/status_reach_finder_spec.rb | 105 -- spec/lib/suspicious_sign_in_detector_spec.rb | 59 - spec/lib/tag_manager_spec.rb | 88 -- spec/lib/text_formatter_spec.rb | 315 ---- spec/lib/translation_service/deepl_spec.rb | 100 -- .../libre_translate_spec.rb | 72 - spec/lib/vacuum/access_tokens_vacuum_spec.rb | 45 - spec/lib/vacuum/applications_vacuum_spec.rb | 48 - spec/lib/vacuum/backups_vacuum_spec.rb | 26 - spec/lib/vacuum/feeds_vacuum_spec.rb | 32 - spec/lib/vacuum/imports_vacuum_spec.rb | 19 - .../vacuum/media_attachments_vacuum_spec.rb | 48 - spec/lib/vacuum/preview_cards_vacuum_spec.rb | 34 - spec/lib/vacuum/statuses_vacuum_spec.rb | 38 - spec/lib/vacuum/system_keys_vacuum_spec.rb | 24 - spec/lib/webfinger_resource_spec.rb | 140 -- spec/lib/webhooks/payload_renderer_spec.rb | 30 - spec/locales/i18n_spec.rb | 35 - spec/mailers/admin_mailer_spec.rb | 130 -- spec/mailers/notification_mailer_spec.rb | 125 -- spec/mailers/previews/admin_mailer_preview.rb | 20 - .../previews/notification_mailer_preview.rb | 44 - spec/mailers/previews/user_mailer_preview.rb | 96 -- spec/mailers/user_mailer_spec.rb | 187 --- spec/models/account/field_spec.rb | 164 -- spec/models/account_conversation_spec.rb | 74 - spec/models/account_domain_block_spec.rb | 24 - spec/models/account_filter_spec.rb | 66 - spec/models/account_migration_spec.rb | 50 - spec/models/account_spec.rb | 1001 ------------ .../account_statuses_cleanup_policy_spec.rb | 547 ------- spec/models/account_warning_preset_spec.rb | 17 - spec/models/admin/account_action_spec.rb | 150 -- spec/models/admin/action_log_spec.rb | 12 - spec/models/admin/appeal_filter_spec.rb | 16 - spec/models/appeal_spec.rb | 38 - spec/models/block_spec.rb | 44 - spec/models/canonical_email_block_spec.rb | 49 - spec/models/concerns/account_counters_spec.rb | 62 - .../concerns/account_finder_concern_spec.rb | 109 -- .../concerns/account_interactions_spec.rb | 721 --------- .../concerns/account_statuses_search_spec.rb | 66 - spec/models/concerns/remotable_spec.rb | 205 --- .../concerns/status_threading_concern_spec.rb | 132 -- spec/models/conversation_spec.rb | 15 - spec/models/custom_emoji_category_spec.rb | 14 - spec/models/custom_emoji_filter_spec.rb | 70 - spec/models/custom_emoji_spec.rb | 89 -- spec/models/domain_allow_spec.rb | 18 - spec/models/domain_block_spec.rb | 112 -- spec/models/email_domain_block_spec.rb | 45 - spec/models/export_spec.rb | 68 - spec/models/extended_description_spec.rb | 29 - spec/models/favourite_spec.rb | 31 - spec/models/follow_request_spec.rb | 71 - spec/models/follow_spec.rb | 67 - spec/models/form/account_batch_spec.rb | 63 - spec/models/form/admin_settings_spec.rb | 36 - spec/models/form/import_spec.rb | 318 ---- .../form/status_filter_batch_action_spec.rb | 13 - spec/models/home_feed_spec.rb | 46 - spec/models/identity_spec.rb | 18 - spec/models/import_spec.rb | 26 - spec/models/invite_spec.rb | 38 - spec/models/ip_block_spec.rb | 15 - spec/models/marker_spec.rb | 16 - spec/models/media_attachment_spec.rb | 264 ---- spec/models/mention_spec.rb | 19 - spec/models/notification_spec.rb | 186 --- spec/models/one_time_key_spec.rb | 23 - spec/models/poll_spec.rb | 32 - spec/models/poll_vote_spec.rb | 62 - spec/models/preview_card_provider_spec.rb | 42 - spec/models/privacy_policy_spec.rb | 28 - spec/models/public_feed_spec.rb | 274 ---- spec/models/relationship_filter_spec.rb | 65 - spec/models/remote_follow_spec.rb | 67 - spec/models/report_filter_spec.rb | 33 - spec/models/report_spec.rb | 137 -- spec/models/rule_spec.rb | 19 - spec/models/session_activation_spec.rb | 127 -- spec/models/setting_spec.rb | 188 --- spec/models/site_upload_spec.rb | 13 - spec/models/software_update_spec.rb | 87 -- spec/models/status_edit_spec.rb | 13 - spec/models/status_pin_spec.rb | 74 - spec/models/status_spec.rb | 467 ------ spec/models/tag_feed_spec.rb | 84 - spec/models/tag_spec.rb | 173 --- spec/models/trends/statuses_spec.rb | 115 -- spec/models/trends/tags_spec.rb | 71 - spec/models/user_role_spec.rb | 189 --- spec/models/user_settings/namespace_spec.rb | 25 - spec/models/user_settings/setting_spec.rb | 106 -- spec/models/user_settings_spec.rb | 120 -- spec/models/user_spec.rb | 554 ------- spec/models/web/push_subscription_spec.rb | 96 -- spec/models/webauthn_credentials_spec.rb | 82 - spec/models/webhook_spec.rb | 34 - .../account_moderation_note_policy_spec.rb | 53 - spec/policies/account_policy_spec.rb | 160 -- .../account_warning_preset_policy_spec.rb | 24 - spec/policies/admin/status_policy_spec.rb | 62 - spec/policies/announcement_policy_spec.rb | 24 - spec/policies/appeal_policy_spec.rb | 51 - spec/policies/backup_policy_spec.rb | 46 - .../canonical_email_block_policy_spec.rb | 24 - spec/policies/custom_emoji_policy_spec.rb | 39 - spec/policies/delivery_policy_spec.rb | 24 - spec/policies/domain_block_policy_spec.rb | 25 - .../email_domain_block_policy_spec.rb | 25 - .../follow_recommendation_policy_spec.rb | 24 - spec/policies/instance_policy_spec.rb | 25 - spec/policies/invite_policy_spec.rb | 77 - spec/policies/ip_block_policy_spec.rb | 24 - spec/policies/preview_card_policy_spec.rb | 24 - .../preview_card_provider_policy_spec.rb | 24 - spec/policies/relay_policy_spec.rb | 25 - spec/policies/report_note_policy_spec.rb | 48 - spec/policies/report_policy_spec.rb | 25 - spec/policies/rule_policy_spec.rb | 24 - spec/policies/settings_policy_spec.rb | 25 - spec/policies/software_update_policy_spec.rb | 25 - spec/policies/status_policy_spec.rb | 161 -- spec/policies/tag_policy_spec.rb | 25 - spec/policies/user_policy_spec.rb | 115 -- spec/policies/webhook_policy_spec.rb | 40 - .../account_relationships_presenter_spec.rb | 91 -- .../familiar_followers_presenter_spec.rb | 58 - spec/presenters/instance_presenter_spec.rb | 130 -- .../status_relationships_presenter_spec.rb | 125 -- spec/rails_helper.rb | 220 --- spec/requests/account_show_page_spec.rb | 25 - spec/requests/anonymous_cookies_spec.rb | 44 - .../api/v1/accounts/credentials_spec.rb | 64 - spec/requests/api/v1/accounts_show_spec.rb | 53 - .../api/v1/admin/account_actions_spec.rb | 154 -- .../v1/admin/canonical_email_blocks_spec.rb | 285 ---- .../api/v1/admin/domain_allows_spec.rb | 194 --- .../api/v1/admin/domain_blocks_spec.rb | 264 ---- .../api/v1/admin/email_domain_blocks_spec.rb | 211 --- spec/requests/api/v1/admin/ip_blocks_spec.rb | 255 --- spec/requests/api/v1/admin/reports_spec.rb | 272 ---- spec/requests/api/v1/admin/tags_spec.rb | 141 -- spec/requests/api/v1/apps/credentials_spec.rb | 44 - spec/requests/api/v1/apps_spec.rb | 115 -- spec/requests/api/v1/bookmarks_spec.rb | 61 - spec/requests/api/v1/domain_blocks_spec.rb | 125 -- .../api/v1/emails/confirmations_spec.rb | 168 -- spec/requests/api/v1/featured_tags_spec.rb | 193 --- spec/requests/api/v1/follow_requests_spec.rb | 119 -- .../api/v1/instances/languages_spec.rb | 19 - spec/requests/api/v1/lists_spec.rb | 247 --- spec/requests/api/v1/mutes_spec.rb | 90 -- spec/requests/api/v1/polls_spec.rb | 47 - spec/requests/api/v1/profiles_spec.rb | 98 -- .../api/v1/statuses/bookmarks_spec.rb | 155 -- .../api/v1/statuses/favourites_spec.rb | 155 -- spec/requests/api/v1/statuses/pins_spec.rb | 131 -- spec/requests/api/v1/suggestions_spec.rb | 103 -- spec/requests/api/v1/tags_spec.rb | 169 -- spec/requests/api/v1/timelines/home_spec.rb | 101 -- spec/requests/api/v1/timelines/public_spec.rb | 120 -- spec/requests/api/v2/filters/filters_spec.rb | 248 --- spec/requests/api/v2/media_spec.rb | 18 - spec/requests/api/web/embeds_spec.rb | 161 -- spec/requests/backups_spec.rb | 26 - spec/requests/cache_spec.rb | 686 -------- spec/requests/catch_all_route_request_spec.rb | 23 - spec/requests/content_security_policy_spec.rb | 27 - spec/requests/follower_accounts_spec.rb | 13 - spec/requests/following_accounts_spec.rb | 13 - spec/requests/host_meta_request_spec.rb | 14 - spec/requests/link_headers_spec.rb | 33 - spec/requests/localization_spec.rb | 41 - spec/requests/mail_subscriptions_spec.rb | 103 -- spec/requests/omniauth_callbacks_spec.rb | 124 -- spec/requests/webfinger_request_spec.rb | 33 - spec/routing/accounts_routing_spec.rb | 85 - spec/routing/api_routing_spec.rb | 103 -- spec/routing/well_known_routes_spec.rb | 19 - .../models/concerns/account_search_spec.rb | 51 - .../concerns/account_statuses_search_spec.rb | 53 - .../activitypub/device_serializer_spec.rb | 20 - .../activitypub/note_serializer_spec.rb | 51 - .../one_time_key_serializer_spec.rb | 20 - .../activitypub/undo_like_serializer_spec.rb | 20 - .../update_poll_serializer_spec.rb | 27 - .../activitypub/vote_serializer_spec.rb | 20 - .../rest/account_serializer_spec.rb | 47 - .../rest/encrypted_message_serializer_spec.rb | 20 - .../rest/instance_serializer_spec.rb | 20 - .../rest/keys/claim_result_serializer_spec.rb | 20 - .../rest/keys/device_serializer_spec.rb | 20 - .../rest/keys/query_result_serializer_spec.rb | 20 - .../rest/suggestion_serializer_spec.rb | 26 - spec/services/account_search_service_spec.rb | 89 -- .../account_statuses_cleanup_service_spec.rb | 103 -- .../fetch_featured_collection_service_spec.rb | 129 -- ...h_featured_tags_collection_service_spec.rb | 97 -- .../fetch_remote_account_service_spec.rb | 182 --- .../fetch_remote_actor_service_spec.rb | 182 --- .../fetch_remote_key_service_spec.rb | 95 -- .../fetch_remote_status_service_spec.rb | 322 ---- .../activitypub/fetch_replies_service_spec.rb | 118 -- .../process_account_service_spec.rb | 206 --- .../process_collection_service_spec.rb | 255 --- .../process_status_update_service_spec.rb | 466 ------ .../synchronize_followers_service_spec.rb | 107 -- ..._block_domain_from_account_service_spec.rb | 27 - spec/services/after_block_service_spec.rb | 51 - spec/services/app_sign_up_service_spec.rb | 55 - .../services/authorize_follow_service_spec.rb | 48 - spec/services/backup_service_spec.rb | 101 -- .../batched_remove_status_service_spec.rb | 55 - spec/services/block_domain_service_spec.rb | 78 - spec/services/block_service_spec.rb | 38 - .../bootstrap_timeline_service_spec.rb | 38 - spec/services/bulk_import_row_service_spec.rb | 173 --- spec/services/bulk_import_service_spec.rb | 417 ----- .../clear_domain_media_service_spec.rb | 25 - spec/services/delete_account_service_spec.rb | 121 -- .../services/fan_out_on_write_service_spec.rb | 113 -- spec/services/favourite_service_spec.rb | 40 - spec/services/fetch_link_card_service_spec.rb | 257 --- spec/services/fetch_oembed_service_spec.rb | 201 --- .../fetch_remote_status_service_spec.rb | 35 - spec/services/fetch_resource_service_spec.rb | 110 -- spec/services/follow_service_spec.rb | 157 -- spec/services/import_service_spec.rb | 242 --- spec/services/mute_service_spec.rb | 63 - spec/services/notify_service_spec.rb | 179 --- spec/services/post_status_service_spec.rb | 277 ---- spec/services/precompute_feed_service_spec.rb | 37 - .../services/process_mentions_service_spec.rb | 106 -- spec/services/purge_domain_service_spec.rb | 29 - spec/services/reblog_service_spec.rb | 94 -- spec/services/reject_follow_service_spec.rb | 48 - .../remove_from_followers_service_spec.rb | 40 - spec/services/remove_status_service_spec.rb | 113 -- spec/services/report_service_spec.rb | 171 -- spec/services/resolve_account_service_spec.rb | 232 --- spec/services/resolve_url_service_spec.rb | 179 --- spec/services/search_service_spec.rb | 93 -- .../software_update_check_service_spec.rb | 158 -- spec/services/suspend_account_service_spec.rb | 86 - .../services/translate_status_service_spec.rb | 234 --- spec/services/unallow_domain_service_spec.rb | 66 - spec/services/unblock_domain_service_spec.rb | 43 - spec/services/unblock_service_spec.rb | 40 - spec/services/unfollow_service_spec.rb | 58 - .../unsuspend_account_service_spec.rb | 134 -- spec/services/update_account_service_spec.rb | 40 - spec/services/update_status_service_spec.rb | 188 --- spec/services/verify_link_service_spec.rb | 178 --- spec/spec_helper.rb | 173 --- spec/support/examples/api.rb | 23 - spec/support/examples/lib/admin/checks.rb | 21 - spec/support/examples/mailers.rb | 14 - .../models/concerns/account_avatar.rb | 39 - .../models/concerns/account_header.rb | 23 - .../matchers/json/match_json_schema.rb | 8 - .../model/model_have_error_on_field.rb | 15 - spec/support/omniauth_mocks.rb | 7 - spec/support/schema/nodeinfo_2.0.json | 170 -- spec/support/stories/profile_stories.rb | 51 - spec/system/new_statuses_spec.rb | 45 - .../blacklisted_email_validator_spec.rb | 48 - .../disallowed_hashtags_validator_spec.rb | 48 - spec/validators/email_mx_validator_spec.rb | 122 -- .../validators/follow_limit_validator_spec.rb | 51 - spec/validators/language_validator_spec.rb | 60 - spec/validators/note_length_validator_spec.rb | 39 - spec/validators/poll_validator_spec.rb | 29 - spec/validators/reaction_validator_spec.rb | 42 - .../status_length_validator_spec.rb | 89 -- spec/validators/status_pin_validator_spec.rb | 57 - .../unique_username_validator_spec.rb | 74 - .../unreserved_username_validator_spec.rb | 44 - spec/validators/url_validator_spec.rb | 66 - spec/views/statuses/show.html.haml_spec.rb | 48 - .../activitypub/delivery_worker_spec.rb | 29 - .../distribute_poll_update_worker_spec.rb | 23 - .../activitypub/distribution_worker_spec.rb | 52 - .../activitypub/fetch_replies_worker_spec.rb | 40 - .../move_distribution_worker_spec.rb | 26 - .../activitypub/processing_worker_spec.rb | 18 - .../status_update_distribution_worker_spec.rb | 46 - .../update_distribution_worker_spec.rb | 21 - ...dd_to_public_statuses_index_worker_spec.rb | 42 - .../admin/account_deletion_worker_spec.rb | 19 - .../workers/admin/domain_purge_worker_spec.rb | 18 - spec/workers/bulk_import_worker_spec.rb | 26 - spec/workers/cache_buster_worker_spec.rb | 19 - spec/workers/domain_block_worker_spec.rb | 26 - .../workers/domain_clear_media_worker_spec.rb | 26 - spec/workers/feed_insert_worker_spec.rb | 52 - spec/workers/import/row_worker_spec.rb | 127 -- spec/workers/move_worker_spec.rb | 197 --- .../poll_expiration_notify_worker_spec.rb | 72 - .../workers/post_process_media_worker_spec.rb | 13 - ...lish_scheduled_announcement_worker_spec.rb | 26 - .../publish_scheduled_status_worker_spec.rb | 23 - spec/workers/push_conversation_worker_spec.rb | 13 - .../push_encrypted_message_worker_spec.rb | 13 - spec/workers/push_update_worker_spec.rb | 16 - spec/workers/redownload_avatar_worker_spec.rb | 13 - spec/workers/redownload_header_worker_spec.rb | 13 - spec/workers/refollow_worker_spec.rb | 31 - spec/workers/regeneration_worker_spec.rb | 26 - .../remove_featured_tag_worker_spec.rb | 15 - ..._from_public_statuses_index_worker_spec.rb | 42 - spec/workers/resolve_account_worker_spec.rb | 13 - ...ccounts_statuses_cleanup_scheduler_spec.rb | 171 -- .../follow_recommendations_scheduler_spec.rb | 43 - .../scheduler/indexing_scheduler_spec.rb | 13 - .../instance_refresh_scheduler_spec.rb | 13 - .../scheduler/ip_cleanup_scheduler_spec.rb | 13 - .../scheduler/pghero_scheduler_spec.rb | 13 - .../scheduled_statuses_scheduler_spec.rb | 13 - .../software_update_check_scheduler_spec.rb | 20 - .../suspended_user_cleanup_scheduler_spec.rb | 13 - .../trends/refresh_scheduler_spec.rb | 13 - .../review_notifications_scheduler_spec.rb | 13 - .../scheduler/user_cleanup_scheduler_spec.rb | 41 - .../scheduler/vacuum_scheduler_spec.rb | 13 - spec/workers/tag_unmerge_worker_spec.rb | 39 - spec/workers/unfollow_follow_worker_spec.rb | 50 - .../unpublish_announcement_worker_spec.rb | 13 - .../verify_account_links_worker_spec.rb | 13 - .../web/push_notification_worker_spec.rb | 48 - spec/workers/webhooks/delivery_worker_spec.rb | 13 - vendor/.keep | 0 yarn.lock | 21 +- 2780 files changed, 345 insertions(+), 142681 deletions(-) delete mode 100644 .devcontainer/Dockerfile delete mode 100644 .devcontainer/codespaces/devcontainer.json delete mode 100644 .devcontainer/devcontainer.json delete mode 100644 .devcontainer/docker-compose.yml delete mode 100755 .devcontainer/post-create.sh delete mode 100644 .devcontainer/welcome-message.txt delete mode 100644 .env.production.sample delete mode 100644 .env.vagrant delete mode 100644 .github/FUNDING.yml delete mode 100644 .github/renovate.json5 delete mode 100644 .github/stale.yml delete mode 100644 .github/stylelint-matcher.json delete mode 100644 .github/workflows/build-container-image.yml delete mode 100644 .github/workflows/build-nightly.yml delete mode 100644 .github/workflows/build-push-pr.yml delete mode 100644 .github/workflows/build-releases.yml delete mode 100644 .github/workflows/bundler-audit.yml delete mode 100644 .github/workflows/check-i18n.yml delete mode 100644 .github/workflows/codeql.yml delete mode 100644 .github/workflows/crowdin-download.yml delete mode 100644 .github/workflows/crowdin-upload.yml delete mode 100644 .github/workflows/haml-lint-problem-matcher.json delete mode 100644 .github/workflows/lint-css.yml delete mode 100644 .github/workflows/lint-haml.yml delete mode 100644 .github/workflows/lint-js.yml delete mode 100644 .github/workflows/lint-json.yml delete mode 100644 .github/workflows/lint-md.yml delete mode 100644 .github/workflows/lint-ruby.yml delete mode 100644 .github/workflows/lint-yml.yml delete mode 100644 .github/workflows/rebase-needed.yml delete mode 100644 .github/workflows/test-image-build.yml delete mode 100644 .github/workflows/test-js.yml delete mode 100644 .github/workflows/test-migrations-one-step.yml delete mode 100644 .github/workflows/test-migrations-two-step.yml delete mode 100644 .github/workflows/test-ruby.yml delete mode 100644 .haml-lint.yml delete mode 100644 .haml-lint_todo.yml delete mode 100644 CODE_OF_CONDUCT.md delete mode 100644 CONTRIBUTING.md delete mode 100644 FEDERATION.md delete mode 100644 Gemfile delete mode 100644 Gemfile.lock delete mode 100644 Procfile delete mode 100644 Rakefile delete mode 100644 SECURITY.md delete mode 100644 Vagrantfile delete mode 100644 app/chewy/accounts_index.rb delete mode 100644 app/chewy/instances_index.rb delete mode 100644 app/chewy/public_statuses_index.rb delete mode 100644 app/chewy/statuses_index.rb delete mode 100644 app/chewy/tags_index.rb delete mode 100644 app/controllers/about_controller.rb delete mode 100644 app/controllers/accounts_controller.rb delete mode 100644 app/controllers/activitypub/base_controller.rb delete mode 100644 app/controllers/activitypub/claims_controller.rb delete mode 100644 app/controllers/activitypub/collections_controller.rb delete mode 100644 app/controllers/activitypub/followers_synchronizations_controller.rb delete mode 100644 app/controllers/activitypub/inboxes_controller.rb delete mode 100644 app/controllers/activitypub/outboxes_controller.rb delete mode 100644 app/controllers/activitypub/replies_controller.rb delete mode 100644 app/controllers/admin/account_actions_controller.rb delete mode 100644 app/controllers/admin/account_moderation_notes_controller.rb delete mode 100644 app/controllers/admin/accounts_controller.rb delete mode 100644 app/controllers/admin/action_logs_controller.rb delete mode 100644 app/controllers/admin/announcements_controller.rb delete mode 100644 app/controllers/admin/base_controller.rb delete mode 100644 app/controllers/admin/change_emails_controller.rb delete mode 100644 app/controllers/admin/confirmations_controller.rb delete mode 100644 app/controllers/admin/custom_emojis_controller.rb delete mode 100644 app/controllers/admin/dashboard_controller.rb delete mode 100644 app/controllers/admin/disputes/appeals_controller.rb delete mode 100644 app/controllers/admin/domain_allows_controller.rb delete mode 100644 app/controllers/admin/domain_blocks_controller.rb delete mode 100644 app/controllers/admin/email_domain_blocks_controller.rb delete mode 100644 app/controllers/admin/export_domain_allows_controller.rb delete mode 100644 app/controllers/admin/export_domain_blocks_controller.rb delete mode 100644 app/controllers/admin/follow_recommendations_controller.rb delete mode 100644 app/controllers/admin/instances_controller.rb delete mode 100644 app/controllers/admin/invites_controller.rb delete mode 100644 app/controllers/admin/ip_blocks_controller.rb delete mode 100644 app/controllers/admin/relationships_controller.rb delete mode 100644 app/controllers/admin/relays_controller.rb delete mode 100644 app/controllers/admin/report_notes_controller.rb delete mode 100644 app/controllers/admin/reports/actions_controller.rb delete mode 100644 app/controllers/admin/reports_controller.rb delete mode 100644 app/controllers/admin/resets_controller.rb delete mode 100644 app/controllers/admin/roles_controller.rb delete mode 100644 app/controllers/admin/rules_controller.rb delete mode 100644 app/controllers/admin/settings/about_controller.rb delete mode 100644 app/controllers/admin/settings/appearance_controller.rb delete mode 100644 app/controllers/admin/settings/branding_controller.rb delete mode 100644 app/controllers/admin/settings/content_retention_controller.rb delete mode 100644 app/controllers/admin/settings/discovery_controller.rb delete mode 100644 app/controllers/admin/settings/other_controller.rb delete mode 100644 app/controllers/admin/settings/registrations_controller.rb delete mode 100644 app/controllers/admin/settings_controller.rb delete mode 100644 app/controllers/admin/site_uploads_controller.rb delete mode 100644 app/controllers/admin/software_updates_controller.rb delete mode 100644 app/controllers/admin/statuses_controller.rb delete mode 100644 app/controllers/admin/tags_controller.rb delete mode 100644 app/controllers/admin/trends/links/preview_card_providers_controller.rb delete mode 100644 app/controllers/admin/trends/links_controller.rb delete mode 100644 app/controllers/admin/trends/statuses_controller.rb delete mode 100644 app/controllers/admin/trends/tags_controller.rb delete mode 100644 app/controllers/admin/users/roles_controller.rb delete mode 100644 app/controllers/admin/users/two_factor_authentications_controller.rb delete mode 100644 app/controllers/admin/warning_presets_controller.rb delete mode 100644 app/controllers/admin/webhooks/secrets_controller.rb delete mode 100644 app/controllers/admin/webhooks_controller.rb delete mode 100644 app/controllers/api/base_controller.rb delete mode 100644 app/controllers/api/oembed_controller.rb delete mode 100644 app/controllers/api/v1/accounts/credentials_controller.rb delete mode 100644 app/controllers/api/v1/accounts/familiar_followers_controller.rb delete mode 100644 app/controllers/api/v1/accounts/featured_tags_controller.rb delete mode 100644 app/controllers/api/v1/accounts/follower_accounts_controller.rb delete mode 100644 app/controllers/api/v1/accounts/following_accounts_controller.rb delete mode 100644 app/controllers/api/v1/accounts/identity_proofs_controller.rb delete mode 100644 app/controllers/api/v1/accounts/lists_controller.rb delete mode 100644 app/controllers/api/v1/accounts/lookup_controller.rb delete mode 100644 app/controllers/api/v1/accounts/notes_controller.rb delete mode 100644 app/controllers/api/v1/accounts/pins_controller.rb delete mode 100644 app/controllers/api/v1/accounts/relationships_controller.rb delete mode 100644 app/controllers/api/v1/accounts/search_controller.rb delete mode 100644 app/controllers/api/v1/accounts/statuses_controller.rb delete mode 100644 app/controllers/api/v1/accounts_controller.rb delete mode 100644 app/controllers/api/v1/admin/account_actions_controller.rb delete mode 100644 app/controllers/api/v1/admin/accounts_controller.rb delete mode 100644 app/controllers/api/v1/admin/canonical_email_blocks_controller.rb delete mode 100644 app/controllers/api/v1/admin/dimensions_controller.rb delete mode 100644 app/controllers/api/v1/admin/domain_allows_controller.rb delete mode 100644 app/controllers/api/v1/admin/domain_blocks_controller.rb delete mode 100644 app/controllers/api/v1/admin/email_domain_blocks_controller.rb delete mode 100644 app/controllers/api/v1/admin/ip_blocks_controller.rb delete mode 100644 app/controllers/api/v1/admin/measures_controller.rb delete mode 100644 app/controllers/api/v1/admin/reports_controller.rb delete mode 100644 app/controllers/api/v1/admin/retention_controller.rb delete mode 100644 app/controllers/api/v1/admin/tags_controller.rb delete mode 100644 app/controllers/api/v1/admin/trends/links/preview_card_providers_controller.rb delete mode 100644 app/controllers/api/v1/admin/trends/links_controller.rb delete mode 100644 app/controllers/api/v1/admin/trends/statuses_controller.rb delete mode 100644 app/controllers/api/v1/admin/trends/tags_controller.rb delete mode 100644 app/controllers/api/v1/announcements/reactions_controller.rb delete mode 100644 app/controllers/api/v1/announcements_controller.rb delete mode 100644 app/controllers/api/v1/apps/credentials_controller.rb delete mode 100644 app/controllers/api/v1/apps_controller.rb delete mode 100644 app/controllers/api/v1/blocks_controller.rb delete mode 100644 app/controllers/api/v1/bookmarks_controller.rb delete mode 100644 app/controllers/api/v1/conversations_controller.rb delete mode 100644 app/controllers/api/v1/crypto/deliveries_controller.rb delete mode 100644 app/controllers/api/v1/crypto/encrypted_messages_controller.rb delete mode 100644 app/controllers/api/v1/crypto/keys/claims_controller.rb delete mode 100644 app/controllers/api/v1/crypto/keys/counts_controller.rb delete mode 100644 app/controllers/api/v1/crypto/keys/queries_controller.rb delete mode 100644 app/controllers/api/v1/crypto/keys/uploads_controller.rb delete mode 100644 app/controllers/api/v1/custom_emojis_controller.rb delete mode 100644 app/controllers/api/v1/directories_controller.rb delete mode 100644 app/controllers/api/v1/domain_blocks_controller.rb delete mode 100644 app/controllers/api/v1/emails/confirmations_controller.rb delete mode 100644 app/controllers/api/v1/endorsements_controller.rb delete mode 100644 app/controllers/api/v1/favourites_controller.rb delete mode 100644 app/controllers/api/v1/featured_tags/suggestions_controller.rb delete mode 100644 app/controllers/api/v1/featured_tags_controller.rb delete mode 100644 app/controllers/api/v1/filters_controller.rb delete mode 100644 app/controllers/api/v1/follow_requests_controller.rb delete mode 100644 app/controllers/api/v1/followed_tags_controller.rb delete mode 100644 app/controllers/api/v1/instances/activity_controller.rb delete mode 100644 app/controllers/api/v1/instances/domain_blocks_controller.rb delete mode 100644 app/controllers/api/v1/instances/extended_descriptions_controller.rb delete mode 100644 app/controllers/api/v1/instances/languages_controller.rb delete mode 100644 app/controllers/api/v1/instances/peers_controller.rb delete mode 100644 app/controllers/api/v1/instances/privacy_policies_controller.rb delete mode 100644 app/controllers/api/v1/instances/rules_controller.rb delete mode 100644 app/controllers/api/v1/instances/translation_languages_controller.rb delete mode 100644 app/controllers/api/v1/instances_controller.rb delete mode 100644 app/controllers/api/v1/lists/accounts_controller.rb delete mode 100644 app/controllers/api/v1/lists_controller.rb delete mode 100644 app/controllers/api/v1/markers_controller.rb delete mode 100644 app/controllers/api/v1/media_controller.rb delete mode 100644 app/controllers/api/v1/mutes_controller.rb delete mode 100644 app/controllers/api/v1/notifications_controller.rb delete mode 100644 app/controllers/api/v1/peers/search_controller.rb delete mode 100644 app/controllers/api/v1/polls/votes_controller.rb delete mode 100644 app/controllers/api/v1/polls_controller.rb delete mode 100644 app/controllers/api/v1/preferences_controller.rb delete mode 100644 app/controllers/api/v1/profile/avatars_controller.rb delete mode 100644 app/controllers/api/v1/profile/headers_controller.rb delete mode 100644 app/controllers/api/v1/push/subscriptions_controller.rb delete mode 100644 app/controllers/api/v1/reports_controller.rb delete mode 100644 app/controllers/api/v1/scheduled_statuses_controller.rb delete mode 100644 app/controllers/api/v1/statuses/bookmarks_controller.rb delete mode 100644 app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb delete mode 100644 app/controllers/api/v1/statuses/favourites_controller.rb delete mode 100644 app/controllers/api/v1/statuses/histories_controller.rb delete mode 100644 app/controllers/api/v1/statuses/mutes_controller.rb delete mode 100644 app/controllers/api/v1/statuses/pins_controller.rb delete mode 100644 app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb delete mode 100644 app/controllers/api/v1/statuses/reblogs_controller.rb delete mode 100644 app/controllers/api/v1/statuses/sources_controller.rb delete mode 100644 app/controllers/api/v1/statuses/translations_controller.rb delete mode 100644 app/controllers/api/v1/statuses_controller.rb delete mode 100644 app/controllers/api/v1/streaming_controller.rb delete mode 100644 app/controllers/api/v1/suggestions_controller.rb delete mode 100644 app/controllers/api/v1/tags_controller.rb delete mode 100644 app/controllers/api/v1/timelines/direct_controller.rb delete mode 100644 app/controllers/api/v1/timelines/home_controller.rb delete mode 100644 app/controllers/api/v1/timelines/list_controller.rb delete mode 100644 app/controllers/api/v1/timelines/public_controller.rb delete mode 100644 app/controllers/api/v1/timelines/tag_controller.rb delete mode 100644 app/controllers/api/v1/trends/links_controller.rb delete mode 100644 app/controllers/api/v1/trends/statuses_controller.rb delete mode 100644 app/controllers/api/v1/trends/tags_controller.rb delete mode 100644 app/controllers/api/v2/admin/accounts_controller.rb delete mode 100644 app/controllers/api/v2/filters/keywords_controller.rb delete mode 100644 app/controllers/api/v2/filters/statuses_controller.rb delete mode 100644 app/controllers/api/v2/filters_controller.rb delete mode 100644 app/controllers/api/v2/instances_controller.rb delete mode 100644 app/controllers/api/v2/media_controller.rb delete mode 100644 app/controllers/api/v2/search_controller.rb delete mode 100644 app/controllers/api/v2/suggestions_controller.rb delete mode 100644 app/controllers/api/web/base_controller.rb delete mode 100644 app/controllers/api/web/embeds_controller.rb delete mode 100644 app/controllers/api/web/push_subscriptions_controller.rb delete mode 100644 app/controllers/api/web/settings_controller.rb delete mode 100644 app/controllers/application_controller.rb delete mode 100644 app/controllers/auth/challenges_controller.rb delete mode 100644 app/controllers/auth/confirmations_controller.rb delete mode 100644 app/controllers/auth/omniauth_callbacks_controller.rb delete mode 100644 app/controllers/auth/passwords_controller.rb delete mode 100644 app/controllers/auth/registrations_controller.rb delete mode 100644 app/controllers/auth/sessions_controller.rb delete mode 100644 app/controllers/auth/setup_controller.rb delete mode 100644 app/controllers/authorize_interactions_controller.rb delete mode 100644 app/controllers/backups_controller.rb delete mode 100644 app/controllers/concerns/access_token_tracking_concern.rb delete mode 100644 app/controllers/concerns/account_controller_concern.rb delete mode 100644 app/controllers/concerns/account_owned_concern.rb delete mode 100644 app/controllers/concerns/accountable_concern.rb delete mode 100644 app/controllers/concerns/admin_export_controller_concern.rb delete mode 100644 app/controllers/concerns/api_caching_concern.rb delete mode 100644 app/controllers/concerns/authorization.rb delete mode 100644 app/controllers/concerns/cache_concern.rb delete mode 100644 app/controllers/concerns/captcha_concern.rb delete mode 100644 app/controllers/concerns/challengable_concern.rb delete mode 100644 app/controllers/concerns/export_controller_concern.rb delete mode 100644 app/controllers/concerns/localized.rb delete mode 100644 app/controllers/concerns/rate_limit_headers.rb delete mode 100644 app/controllers/concerns/registration_spam_concern.rb delete mode 100644 app/controllers/concerns/session_tracking_concern.rb delete mode 100644 app/controllers/concerns/signature_authentication.rb delete mode 100644 app/controllers/concerns/signature_verification.rb delete mode 100644 app/controllers/concerns/theming_concern.rb delete mode 100644 app/controllers/concerns/two_factor_authentication_concern.rb delete mode 100644 app/controllers/concerns/user_tracking_concern.rb delete mode 100644 app/controllers/concerns/web_app_controller_concern.rb delete mode 100644 app/controllers/custom_css_controller.rb delete mode 100644 app/controllers/disputes/appeals_controller.rb delete mode 100644 app/controllers/disputes/base_controller.rb delete mode 100644 app/controllers/disputes/strikes_controller.rb delete mode 100644 app/controllers/emojis_controller.rb delete mode 100644 app/controllers/filters/statuses_controller.rb delete mode 100644 app/controllers/filters_controller.rb delete mode 100644 app/controllers/follower_accounts_controller.rb delete mode 100644 app/controllers/following_accounts_controller.rb delete mode 100644 app/controllers/health_controller.rb delete mode 100644 app/controllers/home_controller.rb delete mode 100644 app/controllers/instance_actors_controller.rb delete mode 100644 app/controllers/intents_controller.rb delete mode 100644 app/controllers/invites_controller.rb delete mode 100644 app/controllers/mail_subscriptions_controller.rb delete mode 100644 app/controllers/manifests_controller.rb delete mode 100644 app/controllers/media_controller.rb delete mode 100644 app/controllers/media_proxy_controller.rb delete mode 100644 app/controllers/oauth/authorizations_controller.rb delete mode 100644 app/controllers/oauth/authorized_applications_controller.rb delete mode 100644 app/controllers/oauth/tokens_controller.rb delete mode 100644 app/controllers/privacy_controller.rb delete mode 100644 app/controllers/relationships_controller.rb delete mode 100644 app/controllers/remote_interaction_helper_controller.rb delete mode 100644 app/controllers/settings/aliases_controller.rb delete mode 100644 app/controllers/settings/applications_controller.rb delete mode 100644 app/controllers/settings/base_controller.rb delete mode 100644 app/controllers/settings/deletes_controller.rb delete mode 100644 app/controllers/settings/exports/blocked_accounts_controller.rb delete mode 100644 app/controllers/settings/exports/blocked_domains_controller.rb delete mode 100644 app/controllers/settings/exports/bookmarks_controller.rb delete mode 100644 app/controllers/settings/exports/following_accounts_controller.rb delete mode 100644 app/controllers/settings/exports/lists_controller.rb delete mode 100644 app/controllers/settings/exports/muted_accounts_controller.rb delete mode 100644 app/controllers/settings/exports_controller.rb delete mode 100644 app/controllers/settings/featured_tags_controller.rb delete mode 100644 app/controllers/settings/flavours_controller.rb delete mode 100644 app/controllers/settings/imports_controller.rb delete mode 100644 app/controllers/settings/login_activities_controller.rb delete mode 100644 app/controllers/settings/migration/redirects_controller.rb delete mode 100644 app/controllers/settings/migrations_controller.rb delete mode 100644 app/controllers/settings/pictures_controller.rb delete mode 100644 app/controllers/settings/preferences/appearance_controller.rb delete mode 100644 app/controllers/settings/preferences/base_controller.rb delete mode 100644 app/controllers/settings/preferences/notifications_controller.rb delete mode 100644 app/controllers/settings/preferences/other_controller.rb delete mode 100644 app/controllers/settings/privacy_controller.rb delete mode 100644 app/controllers/settings/profiles_controller.rb delete mode 100644 app/controllers/settings/sessions_controller.rb delete mode 100644 app/controllers/settings/two_factor_authentication/confirmations_controller.rb delete mode 100644 app/controllers/settings/two_factor_authentication/otp_authentication_controller.rb delete mode 100644 app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb delete mode 100644 app/controllers/settings/two_factor_authentication/webauthn_credentials_controller.rb delete mode 100644 app/controllers/settings/two_factor_authentication_methods_controller.rb delete mode 100644 app/controllers/settings/verifications_controller.rb delete mode 100644 app/controllers/shares_controller.rb delete mode 100644 app/controllers/statuses_cleanup_controller.rb delete mode 100644 app/controllers/statuses_controller.rb delete mode 100644 app/controllers/tags_controller.rb delete mode 100644 app/controllers/well_known/host_meta_controller.rb delete mode 100644 app/controllers/well_known/nodeinfo_controller.rb delete mode 100644 app/controllers/well_known/webfinger_controller.rb delete mode 100644 app/helpers/accounts_helper.rb delete mode 100644 app/helpers/admin/account_moderation_notes_helper.rb delete mode 100644 app/helpers/admin/action_logs_helper.rb delete mode 100644 app/helpers/admin/announcements_helper.rb delete mode 100644 app/helpers/admin/dashboard_helper.rb delete mode 100644 app/helpers/admin/filter_helper.rb delete mode 100644 app/helpers/admin/settings_helper.rb delete mode 100644 app/helpers/admin/trends/statuses_helper.rb delete mode 100644 app/helpers/application_helper.rb delete mode 100644 app/helpers/authorized_fetch_helper.rb delete mode 100644 app/helpers/branding_helper.rb delete mode 100644 app/helpers/context_helper.rb delete mode 100644 app/helpers/database_helper.rb delete mode 100644 app/helpers/domain_control_helper.rb delete mode 100644 app/helpers/email_helper.rb delete mode 100644 app/helpers/flashes_helper.rb delete mode 100644 app/helpers/formatting_helper.rb delete mode 100644 app/helpers/home_helper.rb delete mode 100644 app/helpers/instance_helper.rb delete mode 100644 app/helpers/invites_helper.rb delete mode 100644 app/helpers/jsonld_helper.rb delete mode 100644 app/helpers/languages_helper.rb delete mode 100644 app/helpers/mascot_helper.rb delete mode 100644 app/helpers/media_component_helper.rb delete mode 100644 app/helpers/react_component_helper.rb delete mode 100644 app/helpers/routing_helper.rb delete mode 100644 app/helpers/settings_helper.rb delete mode 100644 app/helpers/statuses_helper.rb delete mode 100644 app/helpers/webfinger_helper.rb delete mode 100644 app/lib/access_token_extension.rb delete mode 100644 app/lib/account_reach_finder.rb delete mode 100644 app/lib/account_statuses_filter.rb delete mode 100644 app/lib/activity_tracker.rb delete mode 100644 app/lib/activitypub/activity.rb delete mode 100644 app/lib/activitypub/activity/accept.rb delete mode 100644 app/lib/activitypub/activity/add.rb delete mode 100644 app/lib/activitypub/activity/announce.rb delete mode 100644 app/lib/activitypub/activity/block.rb delete mode 100644 app/lib/activitypub/activity/create.rb delete mode 100644 app/lib/activitypub/activity/delete.rb delete mode 100644 app/lib/activitypub/activity/flag.rb delete mode 100644 app/lib/activitypub/activity/follow.rb delete mode 100644 app/lib/activitypub/activity/like.rb delete mode 100644 app/lib/activitypub/activity/move.rb delete mode 100644 app/lib/activitypub/activity/reject.rb delete mode 100644 app/lib/activitypub/activity/remove.rb delete mode 100644 app/lib/activitypub/activity/undo.rb delete mode 100644 app/lib/activitypub/activity/update.rb delete mode 100644 app/lib/activitypub/adapter.rb delete mode 100644 app/lib/activitypub/case_transform.rb delete mode 100644 app/lib/activitypub/dereferencer.rb delete mode 100644 app/lib/activitypub/forwarder.rb delete mode 100644 app/lib/activitypub/linked_data_signature.rb delete mode 100644 app/lib/activitypub/parser/custom_emoji_parser.rb delete mode 100644 app/lib/activitypub/parser/media_attachment_parser.rb delete mode 100644 app/lib/activitypub/parser/poll_parser.rb delete mode 100644 app/lib/activitypub/parser/status_parser.rb delete mode 100644 app/lib/activitypub/serializer.rb delete mode 100644 app/lib/activitypub/tag_manager.rb delete mode 100644 app/lib/admin/account_statuses_filter.rb delete mode 100644 app/lib/admin/metrics/dimension.rb delete mode 100644 app/lib/admin/metrics/dimension/base_dimension.rb delete mode 100644 app/lib/admin/metrics/dimension/instance_accounts_dimension.rb delete mode 100644 app/lib/admin/metrics/dimension/instance_languages_dimension.rb delete mode 100644 app/lib/admin/metrics/dimension/languages_dimension.rb delete mode 100644 app/lib/admin/metrics/dimension/query_helper.rb delete mode 100644 app/lib/admin/metrics/dimension/servers_dimension.rb delete mode 100644 app/lib/admin/metrics/dimension/software_versions_dimension.rb delete mode 100644 app/lib/admin/metrics/dimension/sources_dimension.rb delete mode 100644 app/lib/admin/metrics/dimension/space_usage_dimension.rb delete mode 100644 app/lib/admin/metrics/dimension/tag_languages_dimension.rb delete mode 100644 app/lib/admin/metrics/dimension/tag_servers_dimension.rb delete mode 100644 app/lib/admin/metrics/measure.rb delete mode 100644 app/lib/admin/metrics/measure/active_users_measure.rb delete mode 100644 app/lib/admin/metrics/measure/base_measure.rb delete mode 100644 app/lib/admin/metrics/measure/instance_accounts_measure.rb delete mode 100644 app/lib/admin/metrics/measure/instance_followers_measure.rb delete mode 100644 app/lib/admin/metrics/measure/instance_follows_measure.rb delete mode 100644 app/lib/admin/metrics/measure/instance_media_attachments_measure.rb delete mode 100644 app/lib/admin/metrics/measure/instance_reports_measure.rb delete mode 100644 app/lib/admin/metrics/measure/instance_statuses_measure.rb delete mode 100644 app/lib/admin/metrics/measure/interactions_measure.rb delete mode 100644 app/lib/admin/metrics/measure/new_users_measure.rb delete mode 100644 app/lib/admin/metrics/measure/opened_reports_measure.rb delete mode 100644 app/lib/admin/metrics/measure/query_helper.rb delete mode 100644 app/lib/admin/metrics/measure/resolved_reports_measure.rb delete mode 100644 app/lib/admin/metrics/measure/tag_accounts_measure.rb delete mode 100644 app/lib/admin/metrics/measure/tag_servers_measure.rb delete mode 100644 app/lib/admin/metrics/measure/tag_uses_measure.rb delete mode 100644 app/lib/admin/metrics/retention.rb delete mode 100644 app/lib/admin/system_check.rb delete mode 100644 app/lib/admin/system_check/base_check.rb delete mode 100644 app/lib/admin/system_check/database_schema_check.rb delete mode 100644 app/lib/admin/system_check/elasticsearch_check.rb delete mode 100644 app/lib/admin/system_check/media_privacy_check.rb delete mode 100644 app/lib/admin/system_check/message.rb delete mode 100644 app/lib/admin/system_check/rules_check.rb delete mode 100644 app/lib/admin/system_check/sidekiq_process_check.rb delete mode 100644 app/lib/admin/system_check/software_version_check.rb delete mode 100644 app/lib/advanced_text_formatter.rb delete mode 100644 app/lib/application_extension.rb delete mode 100644 app/lib/ascii_folding.rb delete mode 100644 app/lib/attachment_batch.rb delete mode 100644 app/lib/cache_buster.rb delete mode 100644 app/lib/connection_pool/shared_connection_pool.rb delete mode 100644 app/lib/connection_pool/shared_timed_stack.rb delete mode 100644 app/lib/delivery_failure_tracker.rb delete mode 100644 app/lib/emoji_formatter.rb delete mode 100644 app/lib/entity_cache.rb delete mode 100644 app/lib/extractor.rb delete mode 100644 app/lib/fast_geometry_parser.rb delete mode 100644 app/lib/fast_ip_map.rb delete mode 100644 app/lib/feed_manager.rb delete mode 100644 app/lib/hashtag_normalizer.rb delete mode 100644 app/lib/html_aware_formatter.rb delete mode 100644 app/lib/importer/accounts_index_importer.rb delete mode 100644 app/lib/importer/base_importer.rb delete mode 100644 app/lib/importer/instances_index_importer.rb delete mode 100644 app/lib/importer/public_statuses_index_importer.rb delete mode 100644 app/lib/importer/statuses_index_importer.rb delete mode 100644 app/lib/importer/tags_index_importer.rb delete mode 100644 app/lib/inline_renderer.rb delete mode 100644 app/lib/link_details_extractor.rb delete mode 100644 app/lib/nodeinfo/adapter.rb delete mode 100644 app/lib/ostatus/tag_manager.rb delete mode 100644 app/lib/permalink_redirector.rb delete mode 100644 app/lib/plain_text_formatter.rb delete mode 100644 app/lib/potential_friendship_tracker.rb delete mode 100644 app/lib/rate_limiter.rb delete mode 100644 app/lib/redis_configuration.rb delete mode 100644 app/lib/request.rb delete mode 100644 app/lib/request_pool.rb delete mode 100644 app/lib/response_with_limit.rb delete mode 100644 app/lib/rss/builder.rb delete mode 100644 app/lib/rss/channel.rb delete mode 100644 app/lib/rss/element.rb delete mode 100644 app/lib/rss/item.rb delete mode 100644 app/lib/rss/media_content.rb delete mode 100644 app/lib/scope_parser.rb delete mode 100644 app/lib/scope_transformer.rb delete mode 100644 app/lib/search_query_parser.rb delete mode 100644 app/lib/search_query_transformer.rb delete mode 100644 app/lib/settings/scoped_settings.rb delete mode 100644 app/lib/status_cache_hydrator.rb delete mode 100644 app/lib/status_filter.rb delete mode 100644 app/lib/status_finder.rb delete mode 100644 app/lib/status_reach_finder.rb delete mode 100644 app/lib/suspicious_sign_in_detector.rb delete mode 100644 app/lib/tag_manager.rb delete mode 100644 app/lib/text_formatter.rb delete mode 100644 app/lib/themes.rb delete mode 100644 app/lib/translation_service.rb delete mode 100644 app/lib/translation_service/deepl.rb delete mode 100644 app/lib/translation_service/libre_translate.rb delete mode 100644 app/lib/translation_service/translation.rb delete mode 100644 app/lib/user_settings_serializer.rb delete mode 100644 app/lib/vacuum.rb delete mode 100644 app/lib/vacuum/access_tokens_vacuum.rb delete mode 100644 app/lib/vacuum/applications_vacuum.rb delete mode 100644 app/lib/vacuum/backups_vacuum.rb delete mode 100644 app/lib/vacuum/feeds_vacuum.rb delete mode 100644 app/lib/vacuum/imports_vacuum.rb delete mode 100644 app/lib/vacuum/media_attachments_vacuum.rb delete mode 100644 app/lib/vacuum/preview_cards_vacuum.rb delete mode 100644 app/lib/vacuum/statuses_vacuum.rb delete mode 100644 app/lib/vacuum/system_keys_vacuum.rb delete mode 100644 app/lib/validation_error_formatter.rb delete mode 100644 app/lib/video_metadata_extractor.rb delete mode 100644 app/lib/webfinger.rb delete mode 100644 app/lib/webfinger_resource.rb delete mode 100644 app/lib/webhooks/payload_renderer.rb delete mode 100644 app/mailers/admin_mailer.rb delete mode 100644 app/mailers/application_mailer.rb delete mode 100644 app/mailers/notification_mailer.rb delete mode 100644 app/mailers/user_mailer.rb delete mode 100644 app/models/account.rb delete mode 100644 app/models/account/field.rb delete mode 100644 app/models/account_alias.rb delete mode 100644 app/models/account_conversation.rb delete mode 100644 app/models/account_deletion_request.rb delete mode 100644 app/models/account_domain_block.rb delete mode 100644 app/models/account_filter.rb delete mode 100644 app/models/account_migration.rb delete mode 100644 app/models/account_moderation_note.rb delete mode 100644 app/models/account_note.rb delete mode 100644 app/models/account_pin.rb delete mode 100644 app/models/account_stat.rb delete mode 100644 app/models/account_statuses_cleanup_policy.rb delete mode 100644 app/models/account_suggestions.rb delete mode 100644 app/models/account_suggestions/global_source.rb delete mode 100644 app/models/account_suggestions/past_interactions_source.rb delete mode 100644 app/models/account_suggestions/setting_source.rb delete mode 100644 app/models/account_suggestions/source.rb delete mode 100644 app/models/account_suggestions/suggestion.rb delete mode 100644 app/models/account_summary.rb delete mode 100644 app/models/account_warning.rb delete mode 100644 app/models/account_warning_preset.rb delete mode 100644 app/models/admin.rb delete mode 100644 app/models/admin/account_action.rb delete mode 100644 app/models/admin/action_log.rb delete mode 100644 app/models/admin/action_log_filter.rb delete mode 100644 app/models/admin/appeal_filter.rb delete mode 100644 app/models/admin/import.rb delete mode 100644 app/models/admin/status_batch_action.rb delete mode 100644 app/models/admin/status_filter.rb delete mode 100644 app/models/announcement.rb delete mode 100644 app/models/announcement_filter.rb delete mode 100644 app/models/announcement_mute.rb delete mode 100644 app/models/announcement_reaction.rb delete mode 100644 app/models/appeal.rb delete mode 100644 app/models/application_record.rb delete mode 100644 app/models/backup.rb delete mode 100644 app/models/block.rb delete mode 100644 app/models/bookmark.rb delete mode 100644 app/models/bulk_import.rb delete mode 100644 app/models/bulk_import_row.rb delete mode 100644 app/models/canonical_email_block.rb delete mode 100644 app/models/concerns/account_associations.rb delete mode 100644 app/models/concerns/account_avatar.rb delete mode 100644 app/models/concerns/account_counters.rb delete mode 100644 app/models/concerns/account_finder_concern.rb delete mode 100644 app/models/concerns/account_header.rb delete mode 100644 app/models/concerns/account_interactions.rb delete mode 100644 app/models/concerns/account_merging.rb delete mode 100644 app/models/concerns/account_search.rb delete mode 100644 app/models/concerns/account_statuses_search.rb delete mode 100644 app/models/concerns/attachmentable.rb delete mode 100644 app/models/concerns/cacheable.rb delete mode 100644 app/models/concerns/domain_materializable.rb delete mode 100644 app/models/concerns/domain_normalizable.rb delete mode 100644 app/models/concerns/expireable.rb delete mode 100644 app/models/concerns/follow_limitable.rb delete mode 100644 app/models/concerns/has_user_settings.rb delete mode 100644 app/models/concerns/ldap_authenticable.rb delete mode 100644 app/models/concerns/lockable.rb delete mode 100644 app/models/concerns/omniauthable.rb delete mode 100644 app/models/concerns/paginable.rb delete mode 100644 app/models/concerns/pam_authenticable.rb delete mode 100644 app/models/concerns/rate_limitable.rb delete mode 100644 app/models/concerns/redisable.rb delete mode 100644 app/models/concerns/relationship_cacheable.rb delete mode 100644 app/models/concerns/remotable.rb delete mode 100644 app/models/concerns/status_safe_reblog_insert.rb delete mode 100644 app/models/concerns/status_search_concern.rb delete mode 100644 app/models/concerns/status_snapshot_concern.rb delete mode 100644 app/models/concerns/status_threading_concern.rb delete mode 100644 app/models/content_retention_policy.rb delete mode 100644 app/models/context.rb delete mode 100644 app/models/conversation.rb delete mode 100644 app/models/conversation_mute.rb delete mode 100644 app/models/custom_emoji.rb delete mode 100644 app/models/custom_emoji_category.rb delete mode 100644 app/models/custom_emoji_filter.rb delete mode 100644 app/models/custom_filter.rb delete mode 100644 app/models/custom_filter_keyword.rb delete mode 100644 app/models/custom_filter_status.rb delete mode 100644 app/models/device.rb delete mode 100644 app/models/direct_feed.rb delete mode 100644 app/models/domain_allow.rb delete mode 100644 app/models/domain_block.rb delete mode 100644 app/models/email_domain_block.rb delete mode 100644 app/models/encrypted_message.rb delete mode 100644 app/models/export.rb delete mode 100644 app/models/extended_description.rb delete mode 100644 app/models/favourite.rb delete mode 100644 app/models/featured_tag.rb delete mode 100644 app/models/feed.rb delete mode 100644 app/models/follow.rb delete mode 100644 app/models/follow_recommendation.rb delete mode 100644 app/models/follow_recommendation_filter.rb delete mode 100644 app/models/follow_recommendation_suppression.rb delete mode 100644 app/models/follow_request.rb delete mode 100644 app/models/form/account_batch.rb delete mode 100644 app/models/form/admin_settings.rb delete mode 100644 app/models/form/challenge.rb delete mode 100644 app/models/form/custom_emoji_batch.rb delete mode 100644 app/models/form/delete_confirmation.rb delete mode 100644 app/models/form/domain_block_batch.rb delete mode 100644 app/models/form/email_domain_block_batch.rb delete mode 100644 app/models/form/import.rb delete mode 100644 app/models/form/ip_block_batch.rb delete mode 100644 app/models/form/redirect.rb delete mode 100644 app/models/form/status_filter_batch_action.rb delete mode 100644 app/models/form/two_factor_confirmation.rb delete mode 100644 app/models/home_feed.rb delete mode 100644 app/models/identity.rb delete mode 100644 app/models/import.rb delete mode 100644 app/models/instance.rb delete mode 100644 app/models/instance_filter.rb delete mode 100644 app/models/invite.rb delete mode 100644 app/models/invite_filter.rb delete mode 100644 app/models/ip_block.rb delete mode 100644 app/models/list.rb delete mode 100644 app/models/list_account.rb delete mode 100644 app/models/list_feed.rb delete mode 100644 app/models/login_activity.rb delete mode 100644 app/models/marker.rb delete mode 100644 app/models/media_attachment.rb delete mode 100644 app/models/mention.rb delete mode 100644 app/models/message_franking.rb delete mode 100644 app/models/mute.rb delete mode 100644 app/models/notification.rb delete mode 100644 app/models/one_time_key.rb delete mode 100644 app/models/poll.rb delete mode 100644 app/models/poll_vote.rb delete mode 100644 app/models/preview_card.rb delete mode 100644 app/models/preview_card_provider.rb delete mode 100644 app/models/preview_card_trend.rb delete mode 100644 app/models/privacy_policy.rb delete mode 100644 app/models/public_feed.rb delete mode 100644 app/models/relationship_filter.rb delete mode 100644 app/models/relay.rb delete mode 100644 app/models/remote_follow.rb delete mode 100644 app/models/report.rb delete mode 100644 app/models/report_filter.rb delete mode 100644 app/models/report_note.rb delete mode 100644 app/models/rule.rb delete mode 100644 app/models/scheduled_status.rb delete mode 100644 app/models/search.rb delete mode 100644 app/models/session_activation.rb delete mode 100644 app/models/setting.rb delete mode 100644 app/models/site_upload.rb delete mode 100644 app/models/software_update.rb delete mode 100644 app/models/status.rb delete mode 100644 app/models/status_edit.rb delete mode 100644 app/models/status_pin.rb delete mode 100644 app/models/status_stat.rb delete mode 100644 app/models/status_trend.rb delete mode 100644 app/models/system_key.rb delete mode 100644 app/models/tag.rb delete mode 100644 app/models/tag_feed.rb delete mode 100644 app/models/tag_follow.rb delete mode 100644 app/models/tombstone.rb delete mode 100644 app/models/translation.rb delete mode 100644 app/models/trends.rb delete mode 100644 app/models/trends/base.rb delete mode 100644 app/models/trends/history.rb delete mode 100644 app/models/trends/links.rb delete mode 100644 app/models/trends/preview_card_batch.rb delete mode 100644 app/models/trends/preview_card_filter.rb delete mode 100644 app/models/trends/preview_card_provider_batch.rb delete mode 100644 app/models/trends/preview_card_provider_filter.rb delete mode 100644 app/models/trends/query.rb delete mode 100644 app/models/trends/status_batch.rb delete mode 100644 app/models/trends/status_filter.rb delete mode 100644 app/models/trends/statuses.rb delete mode 100644 app/models/trends/tag_batch.rb delete mode 100644 app/models/trends/tag_filter.rb delete mode 100644 app/models/trends/tags.rb delete mode 100644 app/models/unavailable_domain.rb delete mode 100644 app/models/user.rb delete mode 100644 app/models/user_invite_request.rb delete mode 100644 app/models/user_ip.rb delete mode 100644 app/models/user_role.rb delete mode 100644 app/models/user_settings.rb delete mode 100644 app/models/user_settings/dsl.rb delete mode 100644 app/models/user_settings/glue.rb delete mode 100644 app/models/user_settings/namespace.rb delete mode 100644 app/models/user_settings/setting.rb delete mode 100644 app/models/web.rb delete mode 100644 app/models/web/push_subscription.rb delete mode 100644 app/models/web/setting.rb delete mode 100644 app/models/webauthn_credential.rb delete mode 100644 app/models/webhook.rb delete mode 100644 app/policies/account_moderation_note_policy.rb delete mode 100644 app/policies/account_policy.rb delete mode 100644 app/policies/account_warning_policy.rb delete mode 100644 app/policies/account_warning_preset_policy.rb delete mode 100644 app/policies/admin/status_policy.rb delete mode 100644 app/policies/announcement_policy.rb delete mode 100644 app/policies/appeal_policy.rb delete mode 100644 app/policies/application_policy.rb delete mode 100644 app/policies/audit_log_policy.rb delete mode 100644 app/policies/backup_policy.rb delete mode 100644 app/policies/canonical_email_block_policy.rb delete mode 100644 app/policies/custom_emoji_policy.rb delete mode 100644 app/policies/dashboard_policy.rb delete mode 100644 app/policies/delivery_policy.rb delete mode 100644 app/policies/domain_allow_policy.rb delete mode 100644 app/policies/domain_block_policy.rb delete mode 100644 app/policies/email_domain_block_policy.rb delete mode 100644 app/policies/follow_recommendation_policy.rb delete mode 100644 app/policies/instance_policy.rb delete mode 100644 app/policies/invite_policy.rb delete mode 100644 app/policies/ip_block_policy.rb delete mode 100644 app/policies/poll_policy.rb delete mode 100644 app/policies/preview_card_policy.rb delete mode 100644 app/policies/preview_card_provider_policy.rb delete mode 100644 app/policies/relay_policy.rb delete mode 100644 app/policies/report_note_policy.rb delete mode 100644 app/policies/report_policy.rb delete mode 100644 app/policies/rule_policy.rb delete mode 100644 app/policies/settings_policy.rb delete mode 100644 app/policies/software_update_policy.rb delete mode 100644 app/policies/status_policy.rb delete mode 100644 app/policies/tag_policy.rb delete mode 100644 app/policies/user_policy.rb delete mode 100644 app/policies/user_role_policy.rb delete mode 100644 app/policies/webhook_policy.rb delete mode 100644 app/presenters/account_relationships_presenter.rb delete mode 100644 app/presenters/activitypub/activity_presenter.rb delete mode 100644 app/presenters/activitypub/collection_presenter.rb delete mode 100644 app/presenters/familiar_followers_presenter.rb delete mode 100644 app/presenters/filter_result_presenter.rb delete mode 100644 app/presenters/initial_state_presenter.rb delete mode 100644 app/presenters/instance_presenter.rb delete mode 100644 app/presenters/language_presenter.rb delete mode 100644 app/presenters/status_relationships_presenter.rb delete mode 100644 app/presenters/tag_relationships_presenter.rb delete mode 100644 app/presenters/webhooks/event_presenter.rb delete mode 100644 app/serializers/activitypub/accept_follow_serializer.rb delete mode 100644 app/serializers/activitypub/activity_serializer.rb delete mode 100644 app/serializers/activitypub/actor_serializer.rb delete mode 100644 app/serializers/activitypub/add_serializer.rb delete mode 100644 app/serializers/activitypub/block_serializer.rb delete mode 100644 app/serializers/activitypub/collection_serializer.rb delete mode 100644 app/serializers/activitypub/delete_actor_serializer.rb delete mode 100644 app/serializers/activitypub/delete_serializer.rb delete mode 100644 app/serializers/activitypub/device_serializer.rb delete mode 100644 app/serializers/activitypub/emoji_serializer.rb delete mode 100644 app/serializers/activitypub/encrypted_message_serializer.rb delete mode 100644 app/serializers/activitypub/flag_serializer.rb delete mode 100644 app/serializers/activitypub/follow_serializer.rb delete mode 100644 app/serializers/activitypub/hashtag_serializer.rb delete mode 100644 app/serializers/activitypub/image_serializer.rb delete mode 100644 app/serializers/activitypub/like_serializer.rb delete mode 100644 app/serializers/activitypub/move_serializer.rb delete mode 100644 app/serializers/activitypub/note_serializer.rb delete mode 100644 app/serializers/activitypub/one_time_key_serializer.rb delete mode 100644 app/serializers/activitypub/outbox_serializer.rb delete mode 100644 app/serializers/activitypub/public_key_serializer.rb delete mode 100644 app/serializers/activitypub/reject_follow_serializer.rb delete mode 100644 app/serializers/activitypub/remove_serializer.rb delete mode 100644 app/serializers/activitypub/undo_announce_serializer.rb delete mode 100644 app/serializers/activitypub/undo_block_serializer.rb delete mode 100644 app/serializers/activitypub/undo_follow_serializer.rb delete mode 100644 app/serializers/activitypub/undo_like_serializer.rb delete mode 100644 app/serializers/activitypub/update_poll_serializer.rb delete mode 100644 app/serializers/activitypub/update_serializer.rb delete mode 100644 app/serializers/activitypub/vote_serializer.rb delete mode 100644 app/serializers/initial_state_serializer.rb delete mode 100644 app/serializers/manifest_serializer.rb delete mode 100644 app/serializers/nodeinfo/discovery_serializer.rb delete mode 100644 app/serializers/nodeinfo/serializer.rb delete mode 100644 app/serializers/oembed_serializer.rb delete mode 100644 app/serializers/rest/account_serializer.rb delete mode 100644 app/serializers/rest/admin/account_serializer.rb delete mode 100644 app/serializers/rest/admin/canonical_email_block_serializer.rb delete mode 100644 app/serializers/rest/admin/cohort_serializer.rb delete mode 100644 app/serializers/rest/admin/dimension_serializer.rb delete mode 100644 app/serializers/rest/admin/domain_allow_serializer.rb delete mode 100644 app/serializers/rest/admin/domain_block_serializer.rb delete mode 100644 app/serializers/rest/admin/email_domain_block_serializer.rb delete mode 100644 app/serializers/rest/admin/existing_domain_block_error_serializer.rb delete mode 100644 app/serializers/rest/admin/ip_block_serializer.rb delete mode 100644 app/serializers/rest/admin/ip_serializer.rb delete mode 100644 app/serializers/rest/admin/measure_serializer.rb delete mode 100644 app/serializers/rest/admin/report_serializer.rb delete mode 100644 app/serializers/rest/admin/tag_serializer.rb delete mode 100644 app/serializers/rest/admin/trends/link_serializer.rb delete mode 100644 app/serializers/rest/admin/trends/links/preview_card_provider_serializer.rb delete mode 100644 app/serializers/rest/admin/trends/status_serializer.rb delete mode 100644 app/serializers/rest/admin/webhook_event_serializer.rb delete mode 100644 app/serializers/rest/announcement_serializer.rb delete mode 100644 app/serializers/rest/application_serializer.rb delete mode 100644 app/serializers/rest/context_serializer.rb delete mode 100644 app/serializers/rest/conversation_serializer.rb delete mode 100644 app/serializers/rest/credential_account_serializer.rb delete mode 100644 app/serializers/rest/custom_emoji_serializer.rb delete mode 100644 app/serializers/rest/domain_block_serializer.rb delete mode 100644 app/serializers/rest/encrypted_message_serializer.rb delete mode 100644 app/serializers/rest/extended_description_serializer.rb delete mode 100644 app/serializers/rest/familiar_followers_serializer.rb delete mode 100644 app/serializers/rest/featured_tag_serializer.rb delete mode 100644 app/serializers/rest/filter_keyword_serializer.rb delete mode 100644 app/serializers/rest/filter_result_serializer.rb delete mode 100644 app/serializers/rest/filter_serializer.rb delete mode 100644 app/serializers/rest/filter_status_serializer.rb delete mode 100644 app/serializers/rest/instance_serializer.rb delete mode 100644 app/serializers/rest/keys/claim_result_serializer.rb delete mode 100644 app/serializers/rest/keys/device_serializer.rb delete mode 100644 app/serializers/rest/keys/query_result_serializer.rb delete mode 100644 app/serializers/rest/language_serializer.rb delete mode 100644 app/serializers/rest/list_serializer.rb delete mode 100644 app/serializers/rest/marker_serializer.rb delete mode 100644 app/serializers/rest/media_attachment_serializer.rb delete mode 100644 app/serializers/rest/mute_serializer.rb delete mode 100644 app/serializers/rest/muted_account_serializer.rb delete mode 100644 app/serializers/rest/notification_serializer.rb delete mode 100644 app/serializers/rest/poll_serializer.rb delete mode 100644 app/serializers/rest/preferences_serializer.rb delete mode 100644 app/serializers/rest/preview_card_serializer.rb delete mode 100644 app/serializers/rest/privacy_policy_serializer.rb delete mode 100644 app/serializers/rest/reaction_serializer.rb delete mode 100644 app/serializers/rest/relationship_serializer.rb delete mode 100644 app/serializers/rest/report_serializer.rb delete mode 100644 app/serializers/rest/role_serializer.rb delete mode 100644 app/serializers/rest/rule_serializer.rb delete mode 100644 app/serializers/rest/scheduled_status_serializer.rb delete mode 100644 app/serializers/rest/search_serializer.rb delete mode 100644 app/serializers/rest/status_edit_serializer.rb delete mode 100644 app/serializers/rest/status_serializer.rb delete mode 100644 app/serializers/rest/status_source_serializer.rb delete mode 100644 app/serializers/rest/suggestion_serializer.rb delete mode 100644 app/serializers/rest/tag_serializer.rb delete mode 100644 app/serializers/rest/translation_serializer.rb delete mode 100644 app/serializers/rest/trends/link_serializer.rb delete mode 100644 app/serializers/rest/v1/filter_serializer.rb delete mode 100644 app/serializers/rest/v1/instance_serializer.rb delete mode 100644 app/serializers/rest/web_push_subscription_serializer.rb delete mode 100644 app/serializers/web/notification_serializer.rb delete mode 100644 app/serializers/webfinger_serializer.rb delete mode 100644 app/services/account_search_service.rb delete mode 100644 app/services/account_statuses_cleanup_service.rb delete mode 100644 app/services/activitypub/fetch_featured_collection_service.rb delete mode 100644 app/services/activitypub/fetch_featured_tags_collection_service.rb delete mode 100644 app/services/activitypub/fetch_remote_account_service.rb delete mode 100644 app/services/activitypub/fetch_remote_actor_service.rb delete mode 100644 app/services/activitypub/fetch_remote_key_service.rb delete mode 100644 app/services/activitypub/fetch_remote_poll_service.rb delete mode 100644 app/services/activitypub/fetch_remote_status_service.rb delete mode 100644 app/services/activitypub/fetch_replies_service.rb delete mode 100644 app/services/activitypub/prepare_followers_synchronization_service.rb delete mode 100644 app/services/activitypub/process_account_service.rb delete mode 100644 app/services/activitypub/process_collection_service.rb delete mode 100644 app/services/activitypub/process_status_update_service.rb delete mode 100644 app/services/activitypub/synchronize_followers_service.rb delete mode 100644 app/services/after_block_domain_from_account_service.rb delete mode 100644 app/services/after_block_service.rb delete mode 100644 app/services/after_unallow_domain_service.rb delete mode 100644 app/services/app_sign_up_service.rb delete mode 100644 app/services/appeal_service.rb delete mode 100644 app/services/approve_appeal_service.rb delete mode 100644 app/services/authorize_follow_service.rb delete mode 100644 app/services/backup_service.rb delete mode 100644 app/services/base_service.rb delete mode 100644 app/services/batched_remove_status_service.rb delete mode 100644 app/services/block_domain_service.rb delete mode 100644 app/services/block_service.rb delete mode 100644 app/services/bootstrap_timeline_service.rb delete mode 100644 app/services/bulk_import_row_service.rb delete mode 100644 app/services/bulk_import_service.rb delete mode 100644 app/services/clear_domain_media_service.rb delete mode 100644 app/services/concerns/payloadable.rb delete mode 100644 app/services/create_featured_tag_service.rb delete mode 100644 app/services/delete_account_service.rb delete mode 100644 app/services/deliver_to_device_service.rb delete mode 100644 app/services/fan_out_on_write_service.rb delete mode 100644 app/services/favourite_service.rb delete mode 100644 app/services/fetch_link_card_service.rb delete mode 100644 app/services/fetch_oembed_service.rb delete mode 100644 app/services/fetch_remote_status_service.rb delete mode 100644 app/services/fetch_resource_service.rb delete mode 100644 app/services/follow_migration_service.rb delete mode 100644 app/services/follow_service.rb delete mode 100644 app/services/import_service.rb delete mode 100644 app/services/keys/claim_service.rb delete mode 100644 app/services/keys/query_service.rb delete mode 100644 app/services/move_service.rb delete mode 100644 app/services/mute_service.rb delete mode 100644 app/services/notify_service.rb delete mode 100644 app/services/post_status_service.rb delete mode 100644 app/services/precompute_feed_service.rb delete mode 100644 app/services/process_hashtags_service.rb delete mode 100644 app/services/process_mentions_service.rb delete mode 100644 app/services/purge_domain_service.rb delete mode 100644 app/services/reblog_service.rb delete mode 100644 app/services/reject_follow_service.rb delete mode 100644 app/services/remove_domains_from_followers_service.rb delete mode 100644 app/services/remove_featured_tag_service.rb delete mode 100644 app/services/remove_from_followers_service.rb delete mode 100644 app/services/remove_status_service.rb delete mode 100644 app/services/report_service.rb delete mode 100644 app/services/resolve_account_service.rb delete mode 100644 app/services/resolve_url_service.rb delete mode 100644 app/services/search_service.rb delete mode 100644 app/services/software_update_check_service.rb delete mode 100644 app/services/statuses_search_service.rb delete mode 100644 app/services/suspend_account_service.rb delete mode 100644 app/services/tag_search_service.rb delete mode 100644 app/services/translate_status_service.rb delete mode 100644 app/services/unallow_domain_service.rb delete mode 100644 app/services/unblock_domain_service.rb delete mode 100644 app/services/unblock_service.rb delete mode 100644 app/services/unfavourite_service.rb delete mode 100644 app/services/unfollow_service.rb delete mode 100644 app/services/unmute_service.rb delete mode 100644 app/services/unsuspend_account_service.rb delete mode 100644 app/services/update_account_service.rb delete mode 100644 app/services/update_status_service.rb delete mode 100644 app/services/verify_link_service.rb delete mode 100644 app/services/vote_service.rb delete mode 100644 app/services/webhook_service.rb delete mode 100644 app/validators/blacklisted_email_validator.rb delete mode 100644 app/validators/disallowed_hashtags_validator.rb delete mode 100644 app/validators/domain_validator.rb delete mode 100644 app/validators/ed25519_key_validator.rb delete mode 100644 app/validators/ed25519_signature_validator.rb delete mode 100644 app/validators/email_mx_validator.rb delete mode 100644 app/validators/existing_username_validator.rb delete mode 100644 app/validators/follow_limit_validator.rb delete mode 100644 app/validators/language_validator.rb delete mode 100644 app/validators/note_length_validator.rb delete mode 100644 app/validators/poll_validator.rb delete mode 100644 app/validators/reaction_validator.rb delete mode 100644 app/validators/registration_form_time_validator.rb delete mode 100644 app/validators/status_length_validator.rb delete mode 100644 app/validators/status_pin_validator.rb delete mode 100644 app/validators/unique_username_validator.rb delete mode 100644 app/validators/unreserved_username_validator.rb delete mode 100644 app/validators/url_validator.rb delete mode 100644 app/validators/vote_validator.rb delete mode 100644 app/views/about/show.html.haml delete mode 100644 app/views/accounts/_og.html.haml delete mode 100644 app/views/accounts/show.html.haml delete mode 100644 app/views/accounts/show.rss.ruby delete mode 100644 app/views/admin/account_actions/new.html.haml delete mode 100644 app/views/admin/account_warnings/_account_warning.html.haml delete mode 100644 app/views/admin/accounts/_account.html.haml delete mode 100644 app/views/admin/accounts/index.html.haml delete mode 100644 app/views/admin/accounts/show.html.haml delete mode 100644 app/views/admin/action_logs/_action_log.html.haml delete mode 100644 app/views/admin/action_logs/index.html.haml delete mode 100644 app/views/admin/announcements/_announcement.html.haml delete mode 100644 app/views/admin/announcements/edit.html.haml delete mode 100644 app/views/admin/announcements/index.html.haml delete mode 100644 app/views/admin/announcements/new.html.haml delete mode 100644 app/views/admin/change_emails/show.html.haml delete mode 100644 app/views/admin/custom_emojis/_custom_emoji.html.haml delete mode 100644 app/views/admin/custom_emojis/index.html.haml delete mode 100644 app/views/admin/custom_emojis/new.html.haml delete mode 100644 app/views/admin/dashboard/index.html.haml delete mode 100644 app/views/admin/disputes/appeals/_appeal.html.haml delete mode 100644 app/views/admin/disputes/appeals/index.html.haml delete mode 100644 app/views/admin/domain_allows/new.html.haml delete mode 100644 app/views/admin/domain_blocks/confirm_suspension.html.haml delete mode 100644 app/views/admin/domain_blocks/edit.html.haml delete mode 100644 app/views/admin/domain_blocks/new.html.haml delete mode 100644 app/views/admin/email_domain_blocks/_email_domain_block.html.haml delete mode 100644 app/views/admin/email_domain_blocks/index.html.haml delete mode 100644 app/views/admin/email_domain_blocks/new.html.haml delete mode 100644 app/views/admin/export_domain_allows/new.html.haml delete mode 100644 app/views/admin/export_domain_blocks/_domain_block.html.haml delete mode 100644 app/views/admin/export_domain_blocks/import.html.haml delete mode 100644 app/views/admin/export_domain_blocks/new.html.haml delete mode 100644 app/views/admin/follow_recommendations/_account.html.haml delete mode 100644 app/views/admin/follow_recommendations/show.html.haml delete mode 100644 app/views/admin/instances/_instance.html.haml delete mode 100644 app/views/admin/instances/index.html.haml delete mode 100644 app/views/admin/instances/show.html.haml delete mode 100644 app/views/admin/invites/_invite.html.haml delete mode 100644 app/views/admin/invites/index.html.haml delete mode 100644 app/views/admin/ip_blocks/_ip_block.html.haml delete mode 100644 app/views/admin/ip_blocks/index.html.haml delete mode 100644 app/views/admin/ip_blocks/new.html.haml delete mode 100644 app/views/admin/relationships/index.html.haml delete mode 100644 app/views/admin/relays/_relay.html.haml delete mode 100644 app/views/admin/relays/index.html.haml delete mode 100644 app/views/admin/relays/new.html.haml delete mode 100644 app/views/admin/report_notes/_report_note.html.haml delete mode 100644 app/views/admin/reports/_actions.html.haml delete mode 100644 app/views/admin/reports/_media_attachments.html.haml delete mode 100644 app/views/admin/reports/_status.html.haml delete mode 100644 app/views/admin/reports/actions/preview.html.haml delete mode 100644 app/views/admin/reports/index.html.haml delete mode 100644 app/views/admin/reports/show.html.haml delete mode 100644 app/views/admin/roles/_form.html.haml delete mode 100644 app/views/admin/roles/_role.html.haml delete mode 100644 app/views/admin/roles/edit.html.haml delete mode 100644 app/views/admin/roles/index.html.haml delete mode 100644 app/views/admin/roles/new.html.haml delete mode 100644 app/views/admin/rules/_rule.html.haml delete mode 100644 app/views/admin/rules/edit.html.haml delete mode 100644 app/views/admin/rules/index.html.haml delete mode 100644 app/views/admin/settings/about/show.html.haml delete mode 100644 app/views/admin/settings/appearance/show.html.haml delete mode 100644 app/views/admin/settings/branding/show.html.haml delete mode 100644 app/views/admin/settings/content_retention/show.html.haml delete mode 100644 app/views/admin/settings/discovery/show.html.haml delete mode 100644 app/views/admin/settings/other/show.html.haml delete mode 100644 app/views/admin/settings/registrations/show.html.haml delete mode 100644 app/views/admin/settings/shared/_links.html.haml delete mode 100644 app/views/admin/software_updates/index.html.haml delete mode 100644 app/views/admin/status_edits/_status_edit.html.haml delete mode 100644 app/views/admin/statuses/index.html.haml delete mode 100644 app/views/admin/statuses/show.html.haml delete mode 100644 app/views/admin/tags/show.html.haml delete mode 100644 app/views/admin/trends/links/_preview_card.html.haml delete mode 100644 app/views/admin/trends/links/index.html.haml delete mode 100644 app/views/admin/trends/links/preview_card_providers/_preview_card_provider.html.haml delete mode 100644 app/views/admin/trends/links/preview_card_providers/index.html.haml delete mode 100644 app/views/admin/trends/statuses/_status.html.haml delete mode 100644 app/views/admin/trends/statuses/index.html.haml delete mode 100644 app/views/admin/trends/tags/_tag.html.haml delete mode 100644 app/views/admin/trends/tags/index.html.haml delete mode 100644 app/views/admin/users/roles/show.html.haml delete mode 100644 app/views/admin/warning_presets/_warning_preset.html.haml delete mode 100644 app/views/admin/warning_presets/edit.html.haml delete mode 100644 app/views/admin/warning_presets/index.html.haml delete mode 100644 app/views/admin/webhooks/_form.html.haml delete mode 100644 app/views/admin/webhooks/_webhook.html.haml delete mode 100644 app/views/admin/webhooks/edit.html.haml delete mode 100644 app/views/admin/webhooks/index.html.haml delete mode 100644 app/views/admin/webhooks/new.html.haml delete mode 100644 app/views/admin/webhooks/show.html.haml delete mode 100644 app/views/admin_mailer/_new_trending_links.text.erb delete mode 100644 app/views/admin_mailer/_new_trending_statuses.text.erb delete mode 100644 app/views/admin_mailer/_new_trending_tags.text.erb delete mode 100644 app/views/admin_mailer/new_appeal.text.erb delete mode 100644 app/views/admin_mailer/new_critical_software_updates.text.erb delete mode 100644 app/views/admin_mailer/new_pending_account.text.erb delete mode 100644 app/views/admin_mailer/new_report.text.erb delete mode 100644 app/views/admin_mailer/new_software_updates.text.erb delete mode 100644 app/views/admin_mailer/new_trends.text.erb delete mode 100644 app/views/application/_card.html.haml delete mode 100644 app/views/application/_flashes.html.haml delete mode 100644 app/views/auth/challenges/new.html.haml delete mode 100644 app/views/auth/confirmations/captcha.html.haml delete mode 100644 app/views/auth/confirmations/new.html.haml delete mode 100644 app/views/auth/passwords/edit.html.haml delete mode 100644 app/views/auth/passwords/new.html.haml delete mode 100644 app/views/auth/registrations/_account_warning.html.haml delete mode 100644 app/views/auth/registrations/_session.html.haml delete mode 100644 app/views/auth/registrations/_sessions.html.haml delete mode 100644 app/views/auth/registrations/_status.html.haml delete mode 100644 app/views/auth/registrations/edit.html.haml delete mode 100644 app/views/auth/registrations/new.html.haml delete mode 100644 app/views/auth/registrations/rules.html.haml delete mode 100644 app/views/auth/sessions/new.html.haml delete mode 100644 app/views/auth/sessions/two_factor.html.haml delete mode 100644 app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml delete mode 100644 app/views/auth/sessions/two_factor/_webauthn_form.html.haml delete mode 100644 app/views/auth/setup/show.html.haml delete mode 100644 app/views/auth/shared/_links.html.haml delete mode 100644 app/views/auth/shared/_progress.html.haml delete mode 100644 app/views/custom_css/show.css.erb delete mode 100644 app/views/disputes/strikes/index.html.haml delete mode 100644 app/views/disputes/strikes/show.html.haml delete mode 100644 app/views/errors/400.html.haml delete mode 100644 app/views/errors/403.html.haml delete mode 100644 app/views/errors/404.html.haml delete mode 100644 app/views/errors/406.html.haml delete mode 100644 app/views/errors/410.html.haml delete mode 100644 app/views/errors/422.html.haml delete mode 100644 app/views/errors/429.html.haml delete mode 100644 app/views/errors/500.html.haml delete mode 100644 app/views/errors/503.html.haml delete mode 100644 app/views/filters/_filter.html.haml delete mode 100644 app/views/filters/_filter_fields.html.haml delete mode 100644 app/views/filters/_keyword_fields.html.haml delete mode 100644 app/views/filters/edit.html.haml delete mode 100644 app/views/filters/index.html.haml delete mode 100644 app/views/filters/new.html.haml delete mode 100644 app/views/filters/statuses/_status_filter.html.haml delete mode 100644 app/views/filters/statuses/index.html.haml delete mode 100644 app/views/follower_accounts/index.html.haml delete mode 100644 app/views/following_accounts/index.html.haml delete mode 100644 app/views/home/index.html.haml delete mode 100644 app/views/invites/_form.html.haml delete mode 100644 app/views/invites/_invite.html.haml delete mode 100644 app/views/invites/index.html.haml delete mode 100644 app/views/kaminari/_gap.html.haml delete mode 100644 app/views/kaminari/_next_page.html.haml delete mode 100644 app/views/kaminari/_paginator.html.haml delete mode 100644 app/views/kaminari/_prev_page.html.haml delete mode 100644 app/views/layouts/_theme.html.haml delete mode 100644 app/views/layouts/admin.html.haml delete mode 100755 app/views/layouts/application.html.haml delete mode 100644 app/views/layouts/auth.html.haml delete mode 100644 app/views/layouts/embedded.html.haml delete mode 100644 app/views/layouts/error.html.haml delete mode 100644 app/views/layouts/helper_frame.html.haml delete mode 100644 app/views/layouts/mailer.html.haml delete mode 100644 app/views/layouts/mailer.text.erb delete mode 100644 app/views/layouts/modal.html.haml delete mode 100644 app/views/layouts/plain_mailer.html.haml delete mode 100644 app/views/mail_subscriptions/create.html.haml delete mode 100644 app/views/mail_subscriptions/show.html.haml delete mode 100644 app/views/media/player.html.haml delete mode 100644 app/views/notification_mailer/_status.html.haml delete mode 100644 app/views/notification_mailer/_status.text.erb delete mode 100644 app/views/notification_mailer/favourite.html.haml delete mode 100644 app/views/notification_mailer/favourite.text.erb delete mode 100644 app/views/notification_mailer/follow.html.haml delete mode 100644 app/views/notification_mailer/follow.text.erb delete mode 100644 app/views/notification_mailer/follow_request.html.haml delete mode 100644 app/views/notification_mailer/follow_request.text.erb delete mode 100644 app/views/notification_mailer/mention.html.haml delete mode 100644 app/views/notification_mailer/mention.text.erb delete mode 100644 app/views/notification_mailer/reblog.html.haml delete mode 100644 app/views/notification_mailer/reblog.text.erb delete mode 100644 app/views/oauth/authorizations/error.html.haml delete mode 100644 app/views/oauth/authorizations/new.html.haml delete mode 100644 app/views/oauth/authorizations/show.html.haml delete mode 100644 app/views/oauth/authorized_applications/index.html.haml delete mode 100644 app/views/privacy/show.html.haml delete mode 100644 app/views/relationships/_account.html.haml delete mode 100644 app/views/relationships/show.html.haml delete mode 100644 app/views/remote_interaction_helper/index.html.haml delete mode 100644 app/views/settings/aliases/index.html.haml delete mode 100644 app/views/settings/applications/_fields.html.haml delete mode 100644 app/views/settings/applications/index.html.haml delete mode 100644 app/views/settings/applications/new.html.haml delete mode 100644 app/views/settings/applications/show.html.haml delete mode 100644 app/views/settings/deletes/show.html.haml delete mode 100644 app/views/settings/exports/show.html.haml delete mode 100644 app/views/settings/featured_tags/index.html.haml delete mode 100644 app/views/settings/flavours/show.html.haml delete mode 100644 app/views/settings/imports/index.html.haml delete mode 100644 app/views/settings/imports/show.html.haml delete mode 100644 app/views/settings/login_activities/_login_activity.html.haml delete mode 100644 app/views/settings/login_activities/index.html.haml delete mode 100644 app/views/settings/migration/redirects/new.html.haml delete mode 100644 app/views/settings/migrations/show.html.haml delete mode 100644 app/views/settings/preferences/appearance/show.html.haml delete mode 100644 app/views/settings/preferences/notifications/show.html.haml delete mode 100644 app/views/settings/preferences/other/show.html.haml delete mode 100644 app/views/settings/privacy/show.html.haml delete mode 100644 app/views/settings/profiles/show.html.haml delete mode 100644 app/views/settings/shared/_profile_navigation.html.haml delete mode 100644 app/views/settings/two_factor_authentication/confirmations/new.html.haml delete mode 100644 app/views/settings/two_factor_authentication/otp_authentication/show.html.haml delete mode 100644 app/views/settings/two_factor_authentication/recovery_codes/index.html.haml delete mode 100644 app/views/settings/two_factor_authentication/webauthn_credentials/index.html.haml delete mode 100644 app/views/settings/two_factor_authentication/webauthn_credentials/new.html.haml delete mode 100644 app/views/settings/two_factor_authentication_methods/index.html.haml delete mode 100644 app/views/settings/verifications/show.html.haml delete mode 100644 app/views/shared/_error_messages.html.haml delete mode 100644 app/views/shared/_og.html.haml delete mode 100644 app/views/shared/_web_app.html.haml delete mode 100644 app/views/shares/show.html.haml delete mode 100644 app/views/statuses/_attachment_list.html.haml delete mode 100644 app/views/statuses/_detailed_status.html.haml delete mode 100644 app/views/statuses/_og_description.html.haml delete mode 100644 app/views/statuses/_og_image.html.haml delete mode 100644 app/views/statuses/_poll.html.haml delete mode 100644 app/views/statuses/_simple_status.html.haml delete mode 100644 app/views/statuses/_status.html.haml delete mode 100644 app/views/statuses/embed.html.haml delete mode 100644 app/views/statuses/show.html.haml delete mode 100644 app/views/statuses_cleanup/show.html.haml delete mode 100644 app/views/tags/show.html.haml delete mode 100644 app/views/tags/show.rss.ruby delete mode 100644 app/views/user_mailer/appeal_approved.html.haml delete mode 100644 app/views/user_mailer/appeal_approved.text.erb delete mode 100644 app/views/user_mailer/appeal_rejected.html.haml delete mode 100644 app/views/user_mailer/appeal_rejected.text.erb delete mode 100644 app/views/user_mailer/backup_ready.html.haml delete mode 100644 app/views/user_mailer/backup_ready.text.erb delete mode 100644 app/views/user_mailer/confirmation_instructions.html.haml delete mode 100644 app/views/user_mailer/confirmation_instructions.text.erb delete mode 100644 app/views/user_mailer/email_changed.html.haml delete mode 100644 app/views/user_mailer/email_changed.text.erb delete mode 100644 app/views/user_mailer/password_change.html.haml delete mode 100644 app/views/user_mailer/password_change.text.erb delete mode 100644 app/views/user_mailer/reconfirmation_instructions.html.haml delete mode 100644 app/views/user_mailer/reconfirmation_instructions.text.erb delete mode 100644 app/views/user_mailer/reset_password_instructions.html.haml delete mode 100644 app/views/user_mailer/reset_password_instructions.text.erb delete mode 100644 app/views/user_mailer/suspicious_sign_in.html.haml delete mode 100644 app/views/user_mailer/suspicious_sign_in.text.erb delete mode 100644 app/views/user_mailer/two_factor_disabled.html.haml delete mode 100644 app/views/user_mailer/two_factor_disabled.text.erb delete mode 100644 app/views/user_mailer/two_factor_enabled.html.haml delete mode 100644 app/views/user_mailer/two_factor_enabled.text.erb delete mode 100644 app/views/user_mailer/two_factor_recovery_codes_changed.html.haml delete mode 100644 app/views/user_mailer/two_factor_recovery_codes_changed.text.erb delete mode 100644 app/views/user_mailer/warning.html.haml delete mode 100644 app/views/user_mailer/warning.text.erb delete mode 100644 app/views/user_mailer/webauthn_credential_added.html.haml delete mode 100644 app/views/user_mailer/webauthn_credential_added.text.erb delete mode 100644 app/views/user_mailer/webauthn_credential_deleted.html.haml delete mode 100644 app/views/user_mailer/webauthn_credential_deleted.text.erb delete mode 100644 app/views/user_mailer/webauthn_disabled.html.haml delete mode 100644 app/views/user_mailer/webauthn_disabled.text.erb delete mode 100644 app/views/user_mailer/webauthn_enabled.html.haml delete mode 100644 app/views/user_mailer/webauthn_enabled.text.erb delete mode 100644 app/views/user_mailer/welcome.html.haml delete mode 100644 app/views/user_mailer/welcome.text.erb delete mode 100644 app/views/well_known/host_meta/show.xml.ruby delete mode 100644 app/workers/account_deletion_worker.rb delete mode 100644 app/workers/account_merging_worker.rb delete mode 100644 app/workers/account_refresh_worker.rb delete mode 100644 app/workers/activitypub/account_raw_distribution_worker.rb delete mode 100644 app/workers/activitypub/delivery_worker.rb delete mode 100644 app/workers/activitypub/distribute_poll_update_worker.rb delete mode 100644 app/workers/activitypub/distribution_worker.rb delete mode 100644 app/workers/activitypub/fetch_replies_worker.rb delete mode 100644 app/workers/activitypub/followers_synchronization_worker.rb delete mode 100644 app/workers/activitypub/low_priority_delivery_worker.rb delete mode 100644 app/workers/activitypub/migrated_follow_delivery_worker.rb delete mode 100644 app/workers/activitypub/move_distribution_worker.rb delete mode 100644 app/workers/activitypub/post_upgrade_worker.rb delete mode 100644 app/workers/activitypub/processing_worker.rb delete mode 100644 app/workers/activitypub/raw_distribution_worker.rb delete mode 100644 app/workers/activitypub/status_update_distribution_worker.rb delete mode 100644 app/workers/activitypub/synchronize_featured_collection_worker.rb delete mode 100644 app/workers/activitypub/synchronize_featured_tags_collection_worker.rb delete mode 100644 app/workers/activitypub/update_distribution_worker.rb delete mode 100644 app/workers/add_to_public_statuses_index_worker.rb delete mode 100644 app/workers/admin/account_deletion_worker.rb delete mode 100644 app/workers/admin/domain_purge_worker.rb delete mode 100644 app/workers/admin/suspension_worker.rb delete mode 100644 app/workers/admin/unsuspension_worker.rb delete mode 100644 app/workers/after_account_domain_block_worker.rb delete mode 100644 app/workers/after_unallow_domain_worker.rb delete mode 100644 app/workers/authorize_follow_worker.rb delete mode 100644 app/workers/backup_worker.rb delete mode 100644 app/workers/block_worker.rb delete mode 100644 app/workers/bootstrap_timeline_worker.rb delete mode 100644 app/workers/bulk_import_worker.rb delete mode 100644 app/workers/cache_buster_worker.rb delete mode 100644 app/workers/concerns/exponential_backoff.rb delete mode 100644 app/workers/delete_mute_worker.rb delete mode 100644 app/workers/distribution_worker.rb delete mode 100644 app/workers/domain_block_worker.rb delete mode 100644 app/workers/domain_clear_media_worker.rb delete mode 100644 app/workers/feed_insert_worker.rb delete mode 100644 app/workers/fetch_reply_worker.rb delete mode 100644 app/workers/import/relationship_worker.rb delete mode 100644 app/workers/import/row_worker.rb delete mode 100644 app/workers/import_worker.rb delete mode 100644 app/workers/link_crawl_worker.rb delete mode 100644 app/workers/local_notification_worker.rb delete mode 100644 app/workers/merge_worker.rb delete mode 100644 app/workers/move_worker.rb delete mode 100644 app/workers/mute_worker.rb delete mode 100644 app/workers/poll_expiration_notify_worker.rb delete mode 100644 app/workers/post_process_media_worker.rb delete mode 100644 app/workers/publish_announcement_reaction_worker.rb delete mode 100644 app/workers/publish_scheduled_announcement_worker.rb delete mode 100644 app/workers/publish_scheduled_status_worker.rb delete mode 100644 app/workers/push_conversation_worker.rb delete mode 100644 app/workers/push_encrypted_message_worker.rb delete mode 100644 app/workers/push_update_worker.rb delete mode 100644 app/workers/redownload_avatar_worker.rb delete mode 100644 app/workers/redownload_header_worker.rb delete mode 100644 app/workers/redownload_media_worker.rb delete mode 100644 app/workers/refollow_worker.rb delete mode 100644 app/workers/regeneration_worker.rb delete mode 100644 app/workers/remote_account_refresh_worker.rb delete mode 100644 app/workers/removal_worker.rb delete mode 100644 app/workers/remove_featured_tag_worker.rb delete mode 100644 app/workers/remove_from_public_statuses_index_worker.rb delete mode 100644 app/workers/resolve_account_worker.rb delete mode 100644 app/workers/scheduler/accounts_statuses_cleanup_scheduler.rb delete mode 100644 app/workers/scheduler/follow_recommendations_scheduler.rb delete mode 100644 app/workers/scheduler/indexing_scheduler.rb delete mode 100644 app/workers/scheduler/instance_refresh_scheduler.rb delete mode 100644 app/workers/scheduler/ip_cleanup_scheduler.rb delete mode 100644 app/workers/scheduler/pghero_scheduler.rb delete mode 100644 app/workers/scheduler/scheduled_statuses_scheduler.rb delete mode 100644 app/workers/scheduler/software_update_check_scheduler.rb delete mode 100644 app/workers/scheduler/suspended_user_cleanup_scheduler.rb delete mode 100644 app/workers/scheduler/trends/refresh_scheduler.rb delete mode 100644 app/workers/scheduler/trends/review_notifications_scheduler.rb delete mode 100644 app/workers/scheduler/user_cleanup_scheduler.rb delete mode 100644 app/workers/scheduler/vacuum_scheduler.rb delete mode 100644 app/workers/tag_unmerge_worker.rb delete mode 100644 app/workers/thread_resolve_worker.rb delete mode 100644 app/workers/trigger_webhook_worker.rb delete mode 100644 app/workers/unfavourite_worker.rb delete mode 100644 app/workers/unfollow_follow_worker.rb delete mode 100644 app/workers/unmerge_worker.rb delete mode 100644 app/workers/unpublish_announcement_worker.rb delete mode 100644 app/workers/verify_account_links_worker.rb delete mode 100644 app/workers/web/push_notification_worker.rb delete mode 100644 app/workers/webhooks/delivery_worker.rb delete mode 100644 chart/README.md delete mode 100644 config.ru delete mode 100644 config/application.rb delete mode 100644 config/boot.rb delete mode 100644 config/deploy.rb delete mode 100644 config/environment.rb delete mode 100644 config/environments/development.rb delete mode 100644 config/environments/production.rb delete mode 100644 config/environments/test.rb delete mode 100644 config/i18n-tasks.yml delete mode 100644 config/imagemagick/policy.xml delete mode 100644 config/initializers/0_duplicate_migrations.rb delete mode 100644 config/initializers/0_post_deployment_migrations.rb delete mode 100644 config/initializers/1_hosts.rb delete mode 100644 config/initializers/2_limited_federation_mode.rb delete mode 100644 config/initializers/3_omniauth.rb delete mode 100644 config/initializers/active_model_serializers.rb delete mode 100644 config/initializers/application_controller_renderer.rb delete mode 100644 config/initializers/assets.rb delete mode 100644 config/initializers/backtrace_silencers.rb delete mode 100644 config/initializers/blacklists.rb delete mode 100644 config/initializers/cache_buster.rb delete mode 100644 config/initializers/cache_logging.rb delete mode 100644 config/initializers/chewy.rb delete mode 100644 config/initializers/content_security_policy.rb delete mode 100644 config/initializers/cookie_rotator.rb delete mode 100644 config/initializers/cookies_serializer.rb delete mode 100644 config/initializers/cors.rb delete mode 100644 config/initializers/devise.rb delete mode 100644 config/initializers/doorkeeper.rb delete mode 100644 config/initializers/fast_blank.rb delete mode 100644 config/initializers/ffmpeg.rb delete mode 100644 config/initializers/filter_parameter_logging.rb delete mode 100644 config/initializers/http_client_proxy.rb delete mode 100644 config/initializers/httplog.rb delete mode 100644 config/initializers/inflections.rb delete mode 100644 config/initializers/json_ld.rb delete mode 100644 config/initializers/kaminari_config.rb delete mode 100644 config/initializers/locale.rb delete mode 100644 config/initializers/mail_delivery_job.rb delete mode 100644 config/initializers/mime_types.rb delete mode 100644 config/initializers/new_framework_defaults_7_0.rb delete mode 100644 config/initializers/oj.rb delete mode 100644 config/initializers/open_uri_redirection.rb delete mode 100644 config/initializers/paperclip.rb delete mode 100644 config/initializers/permissions_policy.rb delete mode 100644 config/initializers/pghero.rb delete mode 100644 config/initializers/preload_link_headers.rb delete mode 100644 config/initializers/premailer_rails.rb delete mode 100644 config/initializers/rack_attack.rb delete mode 100644 config/initializers/rack_attack_logging.rb delete mode 100644 config/initializers/redis.rb delete mode 100644 config/initializers/session_activations.rb delete mode 100644 config/initializers/session_store.rb delete mode 100644 config/initializers/sidekiq.rb delete mode 100644 config/initializers/simple_form.rb delete mode 100644 config/initializers/single_user_mode.rb delete mode 100644 config/initializers/statsd.rb delete mode 100644 config/initializers/stoplight.rb delete mode 100644 config/initializers/strong_migrations.rb delete mode 100644 config/initializers/suppress_csrf_warnings.rb delete mode 100644 config/initializers/trusted_proxies.rb delete mode 100644 config/initializers/twitter_regex.rb delete mode 100644 config/initializers/vapid.rb delete mode 100644 config/initializers/webauthn.rb delete mode 100644 config/initializers/wrap_parameters.rb delete mode 100644 config/navigation.rb delete mode 100644 config/pghero.yml delete mode 100644 config/puma.rb delete mode 100644 config/routes.rb delete mode 100644 config/routes/admin.rb delete mode 100644 config/routes/api.rb delete mode 100644 config/routes/settings.rb delete mode 100644 config/secrets.yml delete mode 100644 config/sidekiq.yml delete mode 100644 config/storage.yml delete mode 100644 crowdin-glitch.yml delete mode 100644 crowdin.yml delete mode 100644 db/migrate/20160220174730_create_accounts.rb delete mode 100644 db/migrate/20160220211917_create_statuses.rb delete mode 100644 db/migrate/20160221003140_create_users.rb delete mode 100644 db/migrate/20160221003621_create_follows.rb delete mode 100644 db/migrate/20160222122600_create_stream_entries.rb delete mode 100644 db/migrate/20160222143943_add_profile_fields_to_accounts.rb delete mode 100644 db/migrate/20160223162837_add_metadata_to_statuses.rb delete mode 100644 db/migrate/20160223164502_make_uris_nullable_in_statuses.rb delete mode 100644 db/migrate/20160223165723_add_url_to_statuses.rb delete mode 100644 db/migrate/20160223165855_add_url_to_accounts.rb delete mode 100644 db/migrate/20160223171800_create_favourites.rb delete mode 100644 db/migrate/20160224223247_create_mentions.rb delete mode 100644 db/migrate/20160227230233_add_attachment_avatar_to_accounts.rb delete mode 100644 db/migrate/20160305115639_add_devise_to_users.rb delete mode 100644 db/migrate/20160306172223_create_doorkeeper_tables.rb delete mode 100644 db/migrate/20160312193225_add_attachment_header_to_accounts.rb delete mode 100644 db/migrate/20160314164231_add_owner_to_application.rb delete mode 100644 db/migrate/20160316103650_add_missing_indices.rb delete mode 100644 db/migrate/20160322193748_add_avatar_remote_url_to_accounts.rb delete mode 100644 db/migrate/20160325130944_add_admin_to_users.rb delete mode 100644 db/migrate/20160826155805_add_superapp_to_oauth_applications.rb delete mode 100644 db/migrate/20160905150353_create_media_attachments.rb delete mode 100644 db/migrate/20160919221059_add_subscription_expires_at_to_accounts.rb delete mode 100644 db/migrate/20160920003904_remove_verify_token_from_accounts.rb delete mode 100644 db/migrate/20160926213048_remove_owner_from_application.rb delete mode 100644 db/migrate/20161003142332_add_confirmable_to_users.rb delete mode 100644 db/migrate/20161003145426_create_blocks.rb delete mode 100644 db/migrate/20161006213403_rails_settings_migration.rb delete mode 100644 db/migrate/20161009120834_create_domain_blocks.rb delete mode 100644 db/migrate/20161027172456_add_silenced_to_accounts.rb delete mode 100644 db/migrate/20161104173623_create_tags.rb delete mode 100644 db/migrate/20161105130633_create_statuses_tags_join_table.rb delete mode 100644 db/migrate/20161116162355_add_locale_to_users.rb delete mode 100644 db/migrate/20161119211120_create_notifications.rb delete mode 100644 db/migrate/20161122163057_remove_unneeded_indexes.rb delete mode 100644 db/migrate/20161123093447_add_sensitive_to_statuses.rb delete mode 100644 db/migrate/20161128103007_create_subscriptions.rb delete mode 100644 db/migrate/20161130142058_add_last_successful_delivery_at_to_subscriptions.rb delete mode 100644 db/migrate/20161130185319_add_visibility_to_statuses.rb delete mode 100644 db/migrate/20161202132159_add_in_reply_to_account_id_to_statuses.rb delete mode 100644 db/migrate/20161203164520_add_from_account_id_to_notifications.rb delete mode 100644 db/migrate/20161205214545_add_suspended_to_accounts.rb delete mode 100644 db/migrate/20161221152630_add_hidden_to_stream_entries.rb delete mode 100644 db/migrate/20161222201034_add_locked_to_accounts.rb delete mode 100644 db/migrate/20161222204147_create_follow_requests.rb delete mode 100644 db/migrate/20170105224407_add_shortcode_to_media_attachments.rb delete mode 100644 db/migrate/20170109120109_create_web_settings.rb delete mode 100644 db/migrate/20170112154826_migrate_settings.rb delete mode 100644 db/migrate/20170114194937_add_application_to_statuses.rb delete mode 100644 db/migrate/20170114203041_add_website_to_oauth_application.rb delete mode 100644 db/migrate/20170119214911_create_preview_cards.rb delete mode 100644 db/migrate/20170123162658_add_severity_to_domain_blocks.rb delete mode 100644 db/migrate/20170123203248_add_reject_media_to_domain_blocks.rb delete mode 100644 db/migrate/20170125145934_add_spoiler_text_to_statuses.rb delete mode 100644 db/migrate/20170127165745_add_devise_two_factor_to_users.rb delete mode 100644 db/migrate/20170205175257_remove_devices.rb delete mode 100644 db/migrate/20170209184350_add_reply_to_statuses.rb delete mode 100644 db/migrate/20170214110202_create_reports.rb delete mode 100644 db/migrate/20170217012631_add_reblog_of_id_foreign_key_to_statuses.rb delete mode 100644 db/migrate/20170301222600_create_mutes.rb delete mode 100644 db/migrate/20170303212857_add_last_emailed_at_to_users.rb delete mode 100644 db/migrate/20170304202101_add_type_to_media_attachments.rb delete mode 100644 db/migrate/20170317193015_add_search_index_to_accounts.rb delete mode 100644 db/migrate/20170318214217_add_header_remote_url_to_accounts.rb delete mode 100644 db/migrate/20170322021028_add_lowercase_index_to_accounts.rb delete mode 100644 db/migrate/20170322143850_change_primary_key_to_bigint_on_statuses.rb delete mode 100644 db/migrate/20170322162804_add_search_index_to_tags.rb delete mode 100644 db/migrate/20170330021336_add_counter_caches.rb delete mode 100644 db/migrate/20170330163835_create_imports.rb delete mode 100644 db/migrate/20170330164118_add_attachment_data_to_imports.rb delete mode 100644 db/migrate/20170403172249_add_action_taken_by_account_id_to_reports.rb delete mode 100644 db/migrate/20170405112956_add_index_on_mentions_status_id.rb delete mode 100644 db/migrate/20170406215816_add_notifications_and_favourites_indices.rb delete mode 100644 db/migrate/20170409170753_add_last_webfingered_at_to_accounts.rb delete mode 100644 db/migrate/20170414080609_add_devise_two_factor_backupable_to_users.rb delete mode 100644 db/migrate/20170414132105_add_language_to_statuses.rb delete mode 100644 db/migrate/20170418160728_add_indexes_to_reports_for_accounts.rb delete mode 100644 db/migrate/20170423005413_add_allowed_languages_to_user.rb delete mode 100644 db/migrate/20170424003227_create_account_domain_blocks.rb delete mode 100644 db/migrate/20170424112722_add_status_id_index_to_statuses_tags.rb delete mode 100644 db/migrate/20170425131920_add_media_attachment_meta.rb delete mode 100644 db/migrate/20170425202925_add_oembed_to_preview_cards.rb delete mode 100644 db/migrate/20170427011934_re_add_owner_to_application.rb delete mode 100644 db/migrate/20170506235850_create_conversations.rb delete mode 100644 db/migrate/20170507000211_add_conversation_id_to_statuses.rb delete mode 100644 db/migrate/20170507141759_optimize_index_subscriptions.rb delete mode 100644 db/migrate/20170508230434_create_conversation_mutes.rb delete mode 100644 db/migrate/20170516072309_add_index_accounts_on_uri.rb delete mode 100644 db/migrate/20170520145338_change_language_filter_to_opt_out.rb delete mode 100644 db/migrate/20170601210557_add_index_on_media_attachments_account_id.rb delete mode 100644 db/migrate/20170604144747_add_foreign_keys_for_accounts.rb delete mode 100644 db/migrate/20170606113804_change_tag_search_index_to_btree.rb delete mode 100644 db/migrate/20170609145826_remove_default_language_from_statuses.rb delete mode 100644 db/migrate/20170610000000_add_statuses_index_on_account_id_id.rb delete mode 100644 db/migrate/20170623152212_create_session_activations.rb delete mode 100644 db/migrate/20170624134742_add_description_to_session_activations.rb delete mode 100644 db/migrate/20170625140443_add_access_token_id_to_session_activations.rb delete mode 100644 db/migrate/20170711225116_fix_null_booleans.rb delete mode 100644 db/migrate/20170713112503_make_tag_search_case_insensitive.rb delete mode 100644 db/migrate/20170713175513_create_web_push_subscriptions.rb delete mode 100644 db/migrate/20170713190709_add_web_push_subscription_to_session_activations.rb delete mode 100644 db/migrate/20170714184731_add_domain_to_subscriptions.rb delete mode 100644 db/migrate/20170716191202_add_hide_notifications_to_mute.rb delete mode 100644 db/migrate/20170718211102_add_activitypub_to_accounts.rb delete mode 100644 db/migrate/20170720000000_add_index_favourites_on_account_id_and_id.rb delete mode 100644 db/migrate/20170823162448_create_status_pins.rb delete mode 100644 db/migrate/20170824103029_add_timestamps_to_status_pins.rb delete mode 100644 db/migrate/20170829215220_remove_status_pins_account_index.rb delete mode 100644 db/migrate/20170901141119_truncate_preview_cards.rb delete mode 100644 db/migrate/20170901142658_create_join_table_preview_cards_statuses.rb delete mode 100644 db/migrate/20170905044538_add_index_id_account_id_activity_type_on_notifications.rb delete mode 100644 db/migrate/20170905165803_add_local_to_statuses.rb delete mode 100644 db/migrate/20170913000752_create_site_uploads.rb delete mode 100644 db/migrate/20170914032032_default_existing_mutes_to_hiding_notifications.rb delete mode 100644 db/migrate/20170917153509_create_custom_emojis.rb delete mode 100644 db/migrate/20170918125918_ids_to_bigints.rb delete mode 100644 db/migrate/20170920024819_status_ids_to_timestamp_ids.rb delete mode 100644 db/migrate/20170920032311_fix_reblogs_in_feeds.rb delete mode 100644 db/migrate/20170924022025_ids_to_bigints2.rb delete mode 100644 db/migrate/20170927215609_add_description_to_media_attachments.rb delete mode 100644 db/migrate/20170928082043_create_email_domain_blocks.rb delete mode 100644 db/migrate/20171005102658_create_account_moderation_notes.rb delete mode 100644 db/migrate/20171005171936_add_disabled_to_custom_emojis.rb delete mode 100644 db/migrate/20171006142024_add_uri_to_custom_emojis.rb delete mode 100644 db/migrate/20171009222537_create_keyword_mutes.rb delete mode 100644 db/migrate/20171010023049_add_foreign_key_to_account_moderation_notes.rb delete mode 100644 db/migrate/20171010025614_change_accounts_nonnullable_in_account_moderation_notes.rb delete mode 100644 db/migrate/20171020084748_add_visible_in_picker_to_custom_emoji.rb delete mode 100644 db/migrate/20171021191900_move_keyword_mutes_into_glitch_namespace.rb delete mode 100644 db/migrate/20171028221157_add_reblogs_to_follows.rb delete mode 100644 db/migrate/20171107143332_add_memorial_to_accounts.rb delete mode 100644 db/migrate/20171107143624_add_disabled_to_users.rb delete mode 100644 db/migrate/20171109012327_add_moderator_to_accounts.rb delete mode 100644 db/migrate/20171114080328_add_index_domain_to_email_domain_blocks.rb delete mode 100644 db/migrate/20171114231651_create_lists.rb delete mode 100644 db/migrate/20171116161857_create_list_accounts.rb delete mode 100644 db/migrate/20171118012443_add_moved_to_account_id_to_accounts.rb delete mode 100644 db/migrate/20171119172437_create_admin_action_logs.rb delete mode 100644 db/migrate/20171122120436_add_index_account_and_reblog_of_id_to_statuses.rb delete mode 100644 db/migrate/20171125024930_create_invites.rb delete mode 100644 db/migrate/20171125031751_add_invite_id_to_users.rb delete mode 100644 db/migrate/20171125185353_add_index_reblog_of_id_and_account_to_statuses.rb delete mode 100644 db/migrate/20171125190735_remove_old_reblog_index_on_statuses.rb delete mode 100644 db/migrate/20171129172043_add_index_on_stream_entries.rb delete mode 100644 db/migrate/20171130000000_add_embed_url_to_preview_cards.rb delete mode 100644 db/migrate/20171201000000_change_account_id_nonnullable_in_lists.rb delete mode 100644 db/migrate/20171210213213_add_local_only_flag_to_statuses.rb delete mode 100644 db/migrate/20171212195226_remove_duplicate_indexes_in_lists.rb delete mode 100644 db/migrate/20171226094803_more_faster_index_on_notifications.rb delete mode 100644 db/migrate/20180106000232_add_index_on_statuses_for_api_v1_accounts_account_id_statuses.rb delete mode 100644 db/migrate/20180109143959_add_remember_token_to_users.rb delete mode 100644 db/migrate/20180204034416_create_identities.rb delete mode 100644 db/migrate/20180206000000_change_user_id_nonnullable.rb delete mode 100644 db/migrate/20180211015820_create_backups.rb delete mode 100644 db/migrate/20180304013859_add_featured_collection_url_to_accounts.rb delete mode 100644 db/migrate/20180310000000_change_columns_in_notifications_nonnullable.rb delete mode 100644 db/migrate/20180402031200_add_assigned_account_id_to_reports.rb delete mode 100644 db/migrate/20180402040909_create_report_notes.rb delete mode 100644 db/migrate/20180410204633_add_fields_to_accounts.rb delete mode 100644 db/migrate/20180410220657_create_bookmarks.rb delete mode 100644 db/migrate/20180416210259_add_uri_to_relationships.rb delete mode 100644 db/migrate/20180506221944_add_actor_type_to_accounts.rb delete mode 100644 db/migrate/20180510214435_add_access_token_id_to_web_push_subscriptions.rb delete mode 100644 db/migrate/20180510230049_migrate_web_push_subscriptions.rb delete mode 100644 db/migrate/20180514130000_improve_index_on_statuses_for_api_v1_accounts_account_id_statuses.rb delete mode 100644 db/migrate/20180514140000_revert_index_change_on_statuses_for_api_v1_accounts_account_id_statuses.rb delete mode 100644 db/migrate/20180528141303_fix_accounts_unique_index.rb delete mode 100644 db/migrate/20180604000556_add_apply_to_mentions_flag_to_keyword_mutes.rb delete mode 100644 db/migrate/20180608213548_reject_following_blocked_users.rb delete mode 100644 db/migrate/20180609104432_migrate_web_push_subscriptions2.rb delete mode 100644 db/migrate/20180615122121_add_autofollow_to_invites.rb delete mode 100644 db/migrate/20180616192031_add_chosen_languages_to_users.rb delete mode 100644 db/migrate/20180617162849_remove_unused_indexes.rb delete mode 100644 db/migrate/20180628181026_create_custom_filters.rb delete mode 100644 db/migrate/20180707154237_add_whole_word_to_custom_filter.rb delete mode 100644 db/migrate/20180707193142_migrate_filters.rb delete mode 100644 db/migrate/20180711152640_create_relays.rb delete mode 100644 db/migrate/20180808175627_create_account_pins.rb delete mode 100644 db/migrate/20180812123222_change_relays_enabled.rb delete mode 100644 db/migrate/20180812162710_create_status_stats.rb delete mode 100644 db/migrate/20180812173710_copy_status_stats.rb delete mode 100644 db/migrate/20180814171349_add_confidential_to_doorkeeper_application.rb delete mode 100644 db/migrate/20180820232245_add_foreign_key_indices.rb delete mode 100644 db/migrate/20180831171112_create_bookmarks.rb delete mode 100644 db/migrate/20180929222014_create_account_conversations.rb delete mode 100644 db/migrate/20181007025445_create_pghero_space_stats.rb delete mode 100644 db/migrate/20181010141500_add_silent_to_mentions.rb delete mode 100644 db/migrate/20181017170937_add_reject_reports_to_domain_blocks.rb delete mode 100644 db/migrate/20181018205649_add_unread_to_account_conversations.rb delete mode 100644 db/migrate/20181024224956_migrate_account_conversations.rb delete mode 100644 db/migrate/20181026034033_remove_faux_remote_account_duplicates.rb delete mode 100644 db/migrate/20181116165755_create_account_stats.rb delete mode 100644 db/migrate/20181116173541_copy_account_stats.rb delete mode 100644 db/migrate/20181127130500_identity_id_to_bigint.rb delete mode 100644 db/migrate/20181127165847_add_show_replies_to_lists.rb delete mode 100644 db/migrate/20181203003808_create_accounts_tags_join_table.rb delete mode 100644 db/migrate/20181203021853_add_discoverable_to_accounts.rb delete mode 100644 db/migrate/20181204193439_add_last_status_at_to_account_stats.rb delete mode 100644 db/migrate/20181204215309_create_account_tag_stats.rb delete mode 100644 db/migrate/20181207011115_downcase_custom_emoji_domains.rb delete mode 100644 db/migrate/20181213184704_create_account_warnings.rb delete mode 100644 db/migrate/20181213185533_create_account_warning_presets.rb delete mode 100644 db/migrate/20181219235220_add_created_by_application_id_to_users.rb delete mode 100644 db/migrate/20181226021420_add_also_known_as_to_accounts.rb delete mode 100644 db/migrate/20190103124649_create_scheduled_statuses.rb delete mode 100644 db/migrate/20190103124754_add_scheduled_status_id_to_media_attachments.rb delete mode 100644 db/migrate/20190117114553_create_tombstones.rb delete mode 100644 db/migrate/20190201012802_add_overwrite_to_imports.rb delete mode 100644 db/migrate/20190203180359_create_featured_tags.rb delete mode 100644 db/migrate/20190225031541_create_polls.rb delete mode 100644 db/migrate/20190225031625_create_poll_votes.rb delete mode 100644 db/migrate/20190226003449_add_poll_id_to_statuses.rb delete mode 100644 db/migrate/20190304152020_add_uri_to_poll_votes.rb delete mode 100644 db/migrate/20190306145741_add_lock_version_to_polls.rb delete mode 100644 db/migrate/20190307234537_add_approved_to_users.rb delete mode 100644 db/migrate/20190314181829_migrate_open_registrations_setting.rb delete mode 100644 db/migrate/20190316190352_create_account_identity_proofs.rb delete mode 100644 db/migrate/20190317135723_add_uri_to_reports.rb delete mode 100644 db/migrate/20190403141604_add_comment_to_invites.rb delete mode 100644 db/migrate/20190409054914_create_user_invite_requests.rb delete mode 100644 db/migrate/20190420025523_add_blurhash_to_media_attachments.rb delete mode 100644 db/migrate/20190509164208_add_by_moderator_to_tombstone.rb delete mode 100644 db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb delete mode 100644 db/migrate/20190512200918_add_content_type_to_statuses.rb delete mode 100644 db/migrate/20190529143559_preserve_old_layout_for_existing_users.rb delete mode 100644 db/migrate/20190627222225_create_custom_emoji_categories.rb delete mode 100644 db/migrate/20190627222826_add_category_id_to_custom_emojis.rb delete mode 100644 db/migrate/20190701022101_add_trust_level_to_accounts.rb delete mode 100644 db/migrate/20190705002136_create_domain_allows.rb delete mode 100644 db/migrate/20190715164535_add_instance_actor.rb delete mode 100644 db/migrate/20190726175042_add_case_insensitive_index_to_tags.rb delete mode 100644 db/migrate/20190729185330_add_score_to_tags.rb delete mode 100644 db/migrate/20190805123746_add_capabilities_to_tags.rb delete mode 100644 db/migrate/20190807135426_add_comments_to_domain_blocks.rb delete mode 100644 db/migrate/20190815225426_add_last_status_at_to_tags.rb delete mode 100644 db/migrate/20190819134503_add_deleted_at_to_statuses.rb delete mode 100644 db/migrate/20190820003045_update_statuses_index.rb delete mode 100644 db/migrate/20190823221802_add_local_index_to_statuses.rb delete mode 100644 db/migrate/20190901035623_add_max_score_to_tags.rb delete mode 100644 db/migrate/20190904222339_create_markers.rb delete mode 100644 db/migrate/20190914202517_create_account_migrations.rb delete mode 100644 db/migrate/20190915194355_create_account_aliases.rb delete mode 100644 db/migrate/20190917213523_add_remember_token_index.rb delete mode 100644 db/migrate/20190927232842_add_voters_count_to_polls.rb delete mode 100644 db/migrate/20191001213028_add_lock_version_to_account_stats.rb delete mode 100644 db/migrate/20191007013357_update_pt_locales.rb delete mode 100644 db/migrate/20191031163205_change_list_account_follow_nullable.rb delete mode 100644 db/migrate/20191212003415_increase_backup_size.rb delete mode 100644 db/migrate/20191212163405_add_hide_collections_to_accounts.rb delete mode 100644 db/migrate/20191218153258_create_announcements.rb delete mode 100644 db/migrate/20200113125135_create_announcement_mutes.rb delete mode 100644 db/migrate/20200114113335_create_announcement_reactions.rb delete mode 100644 db/migrate/20200119112504_add_public_index_to_statuses.rb delete mode 100644 db/migrate/20200126203551_add_published_at_to_announcements.rb delete mode 100644 db/migrate/20200306035625_add_processing_to_media_attachments.rb delete mode 100644 db/migrate/20200309150742_add_forwarded_to_reports.rb delete mode 100644 db/migrate/20200312144258_add_title_to_account_warning_presets.rb delete mode 100644 db/migrate/20200312162302_add_status_ids_to_announcements.rb delete mode 100644 db/migrate/20200312185443_add_parent_id_to_email_domain_blocks.rb delete mode 100644 db/migrate/20200317021758_add_expires_at_to_mutes.rb delete mode 100644 db/migrate/20200407201300_create_unavailable_domains.rb delete mode 100644 db/migrate/20200407202420_migrate_unavailable_inboxes.rb delete mode 100644 db/migrate/20200417125749_add_storage_schema_version.rb delete mode 100644 db/migrate/20200508212852_reset_unique_jobs_locks.rb delete mode 100644 db/migrate/20200510110808_reset_web_app_secret.rb delete mode 100644 db/migrate/20200510181721_remove_duplicated_indexes_pghero.rb delete mode 100644 db/migrate/20200516180352_create_devices.rb delete mode 100644 db/migrate/20200516183822_create_one_time_keys.rb delete mode 100644 db/migrate/20200518083523_create_encrypted_messages.rb delete mode 100644 db/migrate/20200521180606_encrypted_message_ids_to_timestamp_ids.rb delete mode 100644 db/migrate/20200529214050_add_devices_url_to_accounts.rb delete mode 100644 db/migrate/20200601222558_create_system_keys.rb delete mode 100644 db/migrate/20200605155027_add_blurhash_to_preview_cards.rb delete mode 100644 db/migrate/20200608113046_add_sign_in_token_to_users.rb delete mode 100644 db/migrate/20200614002136_add_sensitized_to_accounts.rb delete mode 100644 db/migrate/20200620164023_add_fixed_lowercase_index_to_accounts.rb delete mode 100644 db/migrate/20200622213645_media_attachment_ids_to_timestamp_ids.rb delete mode 100644 db/migrate/20200627125810_add_thumbnail_columns_to_media_attachments.rb delete mode 100644 db/migrate/20200628133322_create_account_notes.rb delete mode 100644 db/migrate/20200630190240_create_webauthn_credentials.rb delete mode 100644 db/migrate/20200630190544_add_webauthn_id_to_users.rb delete mode 100644 db/migrate/20200908193330_create_account_deletion_requests.rb delete mode 100644 db/migrate/20200917192924_add_notify_to_follows.rb delete mode 100644 db/migrate/20200917193034_add_type_to_notifications.rb delete mode 100644 db/migrate/20200917222316_add_index_notifications_on_type.rb delete mode 100644 db/migrate/20201008202037_create_ip_blocks.rb delete mode 100644 db/migrate/20201008220312_add_sign_up_ip_to_users.rb delete mode 100644 db/migrate/20201017233919_add_suspension_origin_to_accounts.rb delete mode 100644 db/migrate/20201206004238_create_instances.rb delete mode 100644 db/migrate/20201218054746_add_obfuscate_to_domain_blocks.rb delete mode 100644 db/migrate/20210221045109_create_rules.rb delete mode 100644 db/migrate/20210306164523_account_ids_to_timestamp_ids.rb delete mode 100644 db/migrate/20210322164601_create_account_summaries.rb delete mode 100644 db/migrate/20210323114347_create_follow_recommendations.rb delete mode 100644 db/migrate/20210324171613_create_follow_recommendation_suppressions.rb delete mode 100644 db/migrate/20210416200740_create_canonical_email_blocks.rb delete mode 100644 db/migrate/20210421121431_add_case_insensitive_btree_index_to_tags.rb delete mode 100644 db/migrate/20210425135952_add_index_on_media_attachments_account_id_status_id.rb delete mode 100644 db/migrate/20210505174616_update_follow_recommendations_to_version_2.rb delete mode 100644 db/migrate/20210609202149_create_login_activities.rb delete mode 100644 db/migrate/20210616214526_create_user_ips.rb delete mode 100644 db/migrate/20210621221010_add_skip_sign_in_token_to_users.rb delete mode 100644 db/migrate/20210630000137_fix_canonical_email_blocks_foreign_key.rb delete mode 100644 db/migrate/20210722120340_create_account_statuses_cleanup_policies.rb delete mode 100644 db/migrate/20210904215403_add_edited_at_to_statuses.rb delete mode 100644 db/migrate/20210908220918_create_status_edits.rb delete mode 100644 db/migrate/20211031031021_create_preview_card_providers.rb delete mode 100644 db/migrate/20211112011713_add_language_to_preview_cards.rb delete mode 100644 db/migrate/20211115032527_add_trendable_to_preview_cards.rb delete mode 100644 db/migrate/20211123212714_add_link_type_to_preview_cards.rb delete mode 100644 db/migrate/20211213040746_update_account_summaries_to_version_2.rb delete mode 100644 db/migrate/20211231080958_add_category_to_reports.rb delete mode 100644 db/migrate/20220105163928_remove_mentions_status_id_index.rb delete mode 100644 db/migrate/20220115125126_add_report_id_to_account_warnings.rb delete mode 100644 db/migrate/20220115125341_fix_account_warning_actions.rb delete mode 100644 db/migrate/20220116202951_add_deleted_at_index_on_statuses.rb delete mode 100644 db/migrate/20220124141035_create_appeals.rb delete mode 100644 db/migrate/20220202200743_add_trendable_to_accounts.rb delete mode 100644 db/migrate/20220202200926_add_trendable_to_statuses.rb delete mode 100644 db/migrate/20220209175231_add_content_type_to_status_edits.rb delete mode 100644 db/migrate/20220210153119_add_overruled_at_to_account_warnings.rb delete mode 100644 db/migrate/20220224010024_add_ips_to_email_domain_blocks.rb delete mode 100644 db/migrate/20220227041951_add_last_used_at_to_oauth_access_tokens.rb delete mode 100644 db/migrate/20220302232632_add_ordered_media_attachment_ids_to_statuses.rb delete mode 100644 db/migrate/20220303000827_add_ordered_media_attachment_ids_to_status_edits.rb delete mode 100644 db/migrate/20220304195405_migrate_hide_network_preference.rb delete mode 100644 db/migrate/20220307094650_fix_featured_tags_constraints.rb delete mode 100644 db/migrate/20220309213005_fix_reblog_deleted_at.rb delete mode 100644 db/migrate/20220316233212_update_kurdish_locales.rb delete mode 100644 db/migrate/20220428112511_add_index_statuses_on_account_id.rb delete mode 100644 db/migrate/20220428112727_add_index_statuses_pins_on_status_id.rb delete mode 100644 db/migrate/20220428114454_add_index_reports_on_assigned_account_id.rb delete mode 100644 db/migrate/20220428114902_add_index_reports_on_action_taken_by_account_id.rb delete mode 100644 db/migrate/20220606044941_create_webhooks.rb delete mode 100644 db/migrate/20220611210335_create_user_roles.rb delete mode 100644 db/migrate/20220611212541_add_role_id_to_users.rb delete mode 100644 db/migrate/20220613110628_create_custom_filter_keywords.rb delete mode 100644 db/migrate/20220613110711_migrate_custom_filters.rb delete mode 100644 db/migrate/20220613110834_add_action_to_custom_filters.rb delete mode 100644 db/migrate/20220710102457_add_display_name_to_tags.rb delete mode 100644 db/migrate/20220714171049_create_tag_follows.rb delete mode 100644 db/migrate/20220808101323_create_custom_filter_statuses.rb delete mode 100644 db/migrate/20220824164433_add_human_identifier_to_admin_action_logs.rb delete mode 100644 db/migrate/20220824233535_create_status_trends.rb delete mode 100644 db/migrate/20220827195229_change_canonical_email_blocks_nullable.rb delete mode 100644 db/migrate/20220829192633_add_languages_to_follows.rb delete mode 100644 db/migrate/20220829192658_add_languages_to_follow_requests.rb delete mode 100644 db/migrate/20221006061337_create_preview_card_trends.rb delete mode 100644 db/migrate/20221012181003_add_blurhash_to_site_uploads.rb delete mode 100644 db/migrate/20221021055441_add_index_featured_tags_on_account_id_and_tag_id.rb delete mode 100644 db/migrate/20221025171544_add_index_ip_blocks_on_ip.rb delete mode 100644 db/migrate/20221104133904_add_name_to_featured_tags.rb delete mode 100644 db/migrate/20230129023109_add_template_to_webhooks.rb delete mode 100644 db/migrate/20230215074327_add_settings_to_users.rb delete mode 100644 db/migrate/20230215074423_move_user_settings.rb delete mode 100644 db/migrate/20230215074424_move_glitch_user_settings.rb delete mode 100644 db/migrate/20230330135507_create_bulk_imports.rb delete mode 100644 db/migrate/20230330140036_create_bulk_import_rows.rb delete mode 100644 db/migrate/20230330155710_add_follow_request_id_to_list_accounts.rb delete mode 100644 db/migrate/20230524190515_add_index_accounts_on_domain_and_id.rb delete mode 100644 db/migrate/20230524192812_fix_account_domain_casing.rb delete mode 100644 db/migrate/20230524194155_add_index_instances_on_reverse_domain.rb delete mode 100644 db/migrate/20230531153942_add_primary_key_to_accounts_tags_join_table.rb delete mode 100644 db/migrate/20230531154811_add_primary_key_to_statuses_tags_join_table.rb delete mode 100644 db/migrate/20230605085710_add_exclusive_to_lists.rb delete mode 100644 db/migrate/20230605085711_add_time_zone_to_users.rb delete mode 100644 db/migrate/20230630145300_add_index_backups_on_user_id.rb delete mode 100644 db/migrate/20230702131023_add_superapp_index_to_applications.rb delete mode 100644 db/migrate/20230702151753_add_index_user_on_unconfirmed_email.rb delete mode 100644 db/migrate/20230724160715_add_published_at_to_preview_cards.rb delete mode 100644 db/migrate/20230725213448_add_image_description_to_preview_cards.rb delete mode 100644 db/migrate/20230814223300_add_indexable_to_accounts.rb delete mode 100644 db/migrate/20230818141056_create_global_follow_recommendations.rb delete mode 100644 db/migrate/20230822081029_create_software_updates.rb delete mode 100644 db/migrate/20230907150100_add_index_account_stats_on_last_status_at_and_account_id.rb delete mode 100644 db/post_migrate/.gitkeep delete mode 100644 db/post_migrate/20180813113448_copy_status_stats_cleanup.rb delete mode 100644 db/post_migrate/20180813160548_post_migrate_filters.rb delete mode 100644 db/post_migrate/20181116184611_copy_account_stats_cleanup.rb delete mode 100644 db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb delete mode 100644 db/post_migrate/20190519130537_remove_boosts_widening_audience.rb delete mode 100644 db/post_migrate/20190706233204_drop_stream_entries.rb delete mode 100644 db/post_migrate/20190715031050_drop_subscriptions.rb delete mode 100644 db/post_migrate/20190901040524_remove_score_from_tags.rb delete mode 100644 db/post_migrate/20190927124642_remove_invalid_web_push_subscription.rb delete mode 100644 db/post_migrate/20200917193528_migrate_notifications_type.rb delete mode 100644 db/post_migrate/20200917222734_remove_index_notifications_on_account_activity.rb delete mode 100644 db/post_migrate/20201017234926_fill_account_suspension_origin.rb delete mode 100644 db/post_migrate/20210308133107_remove_subscription_expires_at_from_accounts.rb delete mode 100644 db/post_migrate/20210502233513_drop_account_tag_stats.rb delete mode 100644 db/post_migrate/20210507001928_remove_hub_url_from_accounts.rb delete mode 100644 db/post_migrate/20210526193025_remove_lock_version_from_account_stats.rb delete mode 100644 db/post_migrate/20210616214135_remove_current_sign_in_ip_from_users.rb delete mode 100644 db/post_migrate/20210808071221_clear_orphaned_account_notes.rb delete mode 100644 db/post_migrate/20211126000907_drop_account_identity_proofs.rb delete mode 100644 db/post_migrate/20220109213908_remove_action_taken_from_reports.rb delete mode 100644 db/post_migrate/20220118183010_remove_index_users_on_remember_token.rb delete mode 100644 db/post_migrate/20220118183123_remove_rememberable_from_users.rb delete mode 100644 db/post_migrate/20220202201015_remove_trust_level_from_accounts.rb delete mode 100644 db/post_migrate/20220303203437_remove_media_attachments_changed_from_status_edits.rb delete mode 100644 db/post_migrate/20220307083603_optimize_null_index_conversations_uri.rb delete mode 100644 db/post_migrate/20220310060545_optimize_null_index_statuses_in_reply_to_account_id.rb delete mode 100644 db/post_migrate/20220310060556_optimize_null_index_statuses_in_reply_to_id.rb delete mode 100644 db/post_migrate/20220310060614_optimize_null_index_media_attachments_scheduled_status_id.rb delete mode 100644 db/post_migrate/20220310060626_optimize_null_index_media_attachments_shortcode.rb delete mode 100644 db/post_migrate/20220310060641_optimize_null_index_users_reset_password_token.rb delete mode 100644 db/post_migrate/20220310060653_optimize_null_index_users_created_by_application_id.rb delete mode 100644 db/post_migrate/20220310060706_optimize_null_index_statuses_uri.rb delete mode 100644 db/post_migrate/20220310060722_optimize_null_index_accounts_moved_to_account_id.rb delete mode 100644 db/post_migrate/20220310060740_optimize_null_index_oauth_access_tokens_refresh_token.rb delete mode 100644 db/post_migrate/20220310060750_optimize_null_index_accounts_url.rb delete mode 100644 db/post_migrate/20220310060809_optimize_null_index_oauth_access_tokens_resource_owner_id.rb delete mode 100644 db/post_migrate/20220310060833_optimize_null_index_announcement_reactions_custom_emoji_id.rb delete mode 100644 db/post_migrate/20220310060854_optimize_null_index_appeals_approved_by_account_id.rb delete mode 100644 db/post_migrate/20220310060913_optimize_null_index_account_migrations_target_account_id.rb delete mode 100644 db/post_migrate/20220310060926_optimize_null_index_appeals_rejected_by_account_id.rb delete mode 100644 db/post_migrate/20220310060939_optimize_null_index_list_accounts_follow_id.rb delete mode 100644 db/post_migrate/20220310060959_optimize_null_index_web_push_subscriptions_access_token_id.rb delete mode 100644 db/post_migrate/20220429101025_remove_ips_from_email_domain_blocks.rb delete mode 100644 db/post_migrate/20220429101850_clear_email_domain_blocks.rb delete mode 100644 db/post_migrate/20220527114923_remove_filtered_languages_from_users.rb delete mode 100644 db/post_migrate/20220613110802_remove_whole_word_from_custom_filters.rb delete mode 100644 db/post_migrate/20220613110903_remove_irreversible_from_custom_filters.rb delete mode 100644 db/post_migrate/20220617202502_migrate_roles.rb delete mode 100644 db/post_migrate/20220704024901_migrate_settings_to_user_roles.rb delete mode 100644 db/post_migrate/20220729171123_fix_custom_filter_keywords_id_seq.rb delete mode 100644 db/post_migrate/20220824164532_remove_recorded_changes_from_admin_action_logs.rb delete mode 100644 db/post_migrate/20221101190723_backfill_admin_action_logs.rb delete mode 100644 db/post_migrate/20221206114142_backfill_admin_action_logs_again.rb delete mode 100644 db/post_migrate/20230803082451_add_unique_index_on_preview_cards_statuses.rb delete mode 100644 db/post_migrate/20230803112520_add_primary_key_to_preview_cards_statuses_join_table.rb delete mode 100644 db/post_migrate/20230811103651_remove_index_preview_cards_statuses_on_status_id_and_preview_card_id.rb delete mode 100644 db/post_migrate/20230818142253_drop_follow_recommendations.rb delete mode 100644 db/post_migrate/20230904134623_fix_kmr_locale_settings.rb delete mode 100644 db/schema.rb delete mode 100644 db/seeds.rb delete mode 100644 db/seeds/01_web_app.rb delete mode 100644 db/seeds/02_instance_actor.rb delete mode 100644 db/seeds/03_roles.rb delete mode 100644 db/seeds/04_admin.rb delete mode 100644 db/views/account_summaries_v01.sql delete mode 100644 db/views/account_summaries_v02.sql delete mode 100644 db/views/follow_recommendations_v01.sql delete mode 100644 db/views/follow_recommendations_v02.sql delete mode 100644 db/views/global_follow_recommendations_v01.sql delete mode 100644 db/views/instances_v01.sql delete mode 100644 db/views/user_ips_v01.sql delete mode 100644 dist/mastodon-sidekiq.service delete mode 100644 dist/mastodon-streaming.service delete mode 100644 dist/mastodon-streaming@.service delete mode 100644 dist/mastodon-web.service delete mode 100644 dist/nginx.conf delete mode 100644 docker-compose.yml delete mode 100644 lib/active_record/batches.rb delete mode 100644 lib/active_record/database_tasks_extensions.rb delete mode 100644 lib/chewy/index_extensions.rb delete mode 100644 lib/chewy/settings_extensions.rb delete mode 100644 lib/chewy/strategy/bypass_with_warning.rb delete mode 100644 lib/chewy/strategy/mastodon.rb delete mode 100644 lib/devise/two_factor_ldap_authenticatable.rb delete mode 100644 lib/devise/two_factor_pam_authenticatable.rb delete mode 100644 lib/exceptions.rb delete mode 100644 lib/generators/post_deployment_migration/USAGE delete mode 100644 lib/generators/post_deployment_migration/post_deployment_migration_generator.rb delete mode 100644 lib/generators/post_deployment_migration/templates/migration.erb delete mode 100644 lib/http_extensions.rb delete mode 100644 lib/json_ld/identity.rb delete mode 100644 lib/json_ld/security.rb delete mode 100644 lib/linter/haml_middle_dot.rb delete mode 100644 lib/linter/rubocop_middle_dot.rb delete mode 100644 lib/mastodon/cli/accounts.rb delete mode 100644 lib/mastodon/cli/base.rb delete mode 100644 lib/mastodon/cli/cache.rb delete mode 100644 lib/mastodon/cli/canonical_email_blocks.rb delete mode 100644 lib/mastodon/cli/domains.rb delete mode 100644 lib/mastodon/cli/email_domain_blocks.rb delete mode 100644 lib/mastodon/cli/emoji.rb delete mode 100644 lib/mastodon/cli/feeds.rb delete mode 100644 lib/mastodon/cli/ip_blocks.rb delete mode 100644 lib/mastodon/cli/main.rb delete mode 100644 lib/mastodon/cli/maintenance.rb delete mode 100644 lib/mastodon/cli/media.rb delete mode 100644 lib/mastodon/cli/preview_cards.rb delete mode 100644 lib/mastodon/cli/progress_helper.rb delete mode 100644 lib/mastodon/cli/search.rb delete mode 100644 lib/mastodon/cli/settings.rb delete mode 100644 lib/mastodon/cli/statuses.rb delete mode 100644 lib/mastodon/cli/upgrade.rb delete mode 100644 lib/mastodon/migration_helpers.rb delete mode 100644 lib/mastodon/migration_warning.rb delete mode 100644 lib/mastodon/premailer_webpack_strategy.rb delete mode 100644 lib/mastodon/rack_middleware.rb delete mode 100644 lib/mastodon/redis_config.rb delete mode 100644 lib/mastodon/sidekiq_middleware.rb delete mode 100644 lib/mastodon/snowflake.rb delete mode 100644 lib/mastodon/version.rb delete mode 100644 lib/paperclip/attachment_extensions.rb delete mode 100644 lib/paperclip/blurhash_transcoder.rb delete mode 100644 lib/paperclip/color_extractor.rb delete mode 100644 lib/paperclip/gif_transcoder.rb delete mode 100644 lib/paperclip/image_extractor.rb delete mode 100644 lib/paperclip/lazy_thumbnail.rb delete mode 100644 lib/paperclip/media_type_spoof_detector_extensions.rb delete mode 100644 lib/paperclip/response_with_limit_adapter.rb delete mode 100644 lib/paperclip/transcoder.rb delete mode 100644 lib/paperclip/type_corrector.rb delete mode 100644 lib/paperclip/url_generator_extensions.rb delete mode 100644 lib/public_file_server_middleware.rb delete mode 100644 lib/rails/engine_extensions.rb delete mode 100644 lib/redis/namespace_extensions.rb delete mode 100644 lib/sanitize_ext/sanitize_config.rb delete mode 100644 lib/simple_navigation/item_extensions.rb delete mode 100644 lib/tasks/assets.rake delete mode 100644 lib/tasks/auto_annotate_models.rake delete mode 100644 lib/tasks/branding.rake delete mode 100644 lib/tasks/db.rake delete mode 100644 lib/tasks/emojis.rake delete mode 100644 lib/tasks/glitchsoc.rake delete mode 100644 lib/tasks/mastodon.rake delete mode 100644 lib/tasks/repo.rake delete mode 100644 lib/tasks/spec.rake delete mode 100644 lib/tasks/statistics.rake delete mode 100644 lib/tasks/tests.rake delete mode 100644 lib/templates/haml/scaffold/_form.html.haml delete mode 100644 lib/terrapin/multi_pipe_extensions.rb delete mode 100644 lib/webpacker/helper_extensions.rb delete mode 100644 lib/webpacker/manifest_extensions.rb delete mode 100644 log/.keep create mode 100644 nginx.conf delete mode 100644 scalingo.json delete mode 100644 spec/chewy/accounts_index_spec.rb delete mode 100644 spec/chewy/public_statuses_index_spec.rb delete mode 100644 spec/chewy/statuses_index_spec.rb delete mode 100644 spec/chewy/tags_index_spec.rb delete mode 100644 spec/config/initializers/rack_attack_spec.rb delete mode 100644 spec/controllers/.rubocop.yml delete mode 100644 spec/controllers/about_controller_spec.rb delete mode 100644 spec/controllers/accounts_controller_spec.rb delete mode 100644 spec/controllers/activitypub/claims_controller_spec.rb delete mode 100644 spec/controllers/activitypub/collections_controller_spec.rb delete mode 100644 spec/controllers/activitypub/followers_synchronizations_controller_spec.rb delete mode 100644 spec/controllers/activitypub/inboxes_controller_spec.rb delete mode 100644 spec/controllers/activitypub/outboxes_controller_spec.rb delete mode 100644 spec/controllers/activitypub/replies_controller_spec.rb delete mode 100644 spec/controllers/admin/account_actions_controller_spec.rb delete mode 100644 spec/controllers/admin/account_moderation_notes_controller_spec.rb delete mode 100644 spec/controllers/admin/accounts_controller_spec.rb delete mode 100644 spec/controllers/admin/action_logs_controller_spec.rb delete mode 100644 spec/controllers/admin/announcements_controller_spec.rb delete mode 100644 spec/controllers/admin/base_controller_spec.rb delete mode 100644 spec/controllers/admin/change_emails_controller_spec.rb delete mode 100644 spec/controllers/admin/confirmations_controller_spec.rb delete mode 100644 spec/controllers/admin/custom_emojis_controller_spec.rb delete mode 100644 spec/controllers/admin/dashboard_controller_spec.rb delete mode 100644 spec/controllers/admin/disputes/appeals_controller_spec.rb delete mode 100644 spec/controllers/admin/domain_allows_controller_spec.rb delete mode 100644 spec/controllers/admin/domain_blocks_controller_spec.rb delete mode 100644 spec/controllers/admin/email_domain_blocks_controller_spec.rb delete mode 100644 spec/controllers/admin/export_domain_allows_controller_spec.rb delete mode 100644 spec/controllers/admin/export_domain_blocks_controller_spec.rb delete mode 100644 spec/controllers/admin/follow_recommendations_controller_spec.rb delete mode 100644 spec/controllers/admin/instances_controller_spec.rb delete mode 100644 spec/controllers/admin/invites_controller_spec.rb delete mode 100644 spec/controllers/admin/ip_blocks_controller_spec.rb delete mode 100644 spec/controllers/admin/relationships_controller_spec.rb delete mode 100644 spec/controllers/admin/relays_controller_spec.rb delete mode 100644 spec/controllers/admin/report_notes_controller_spec.rb delete mode 100644 spec/controllers/admin/reports/actions_controller_spec.rb delete mode 100644 spec/controllers/admin/reports_controller_spec.rb delete mode 100644 spec/controllers/admin/resets_controller_spec.rb delete mode 100644 spec/controllers/admin/roles_controller_spec.rb delete mode 100644 spec/controllers/admin/rules_controller_spec.rb delete mode 100644 spec/controllers/admin/settings/about_controller_spec.rb delete mode 100644 spec/controllers/admin/settings/appearance_controller_spec.rb delete mode 100644 spec/controllers/admin/settings/branding_controller_spec.rb delete mode 100644 spec/controllers/admin/settings/content_retention_controller_spec.rb delete mode 100644 spec/controllers/admin/settings/discovery_controller_spec.rb delete mode 100644 spec/controllers/admin/settings/registrations_controller_spec.rb delete mode 100644 spec/controllers/admin/site_uploads_controller_spec.rb delete mode 100644 spec/controllers/admin/statuses_controller_spec.rb delete mode 100644 spec/controllers/admin/tags_controller_spec.rb delete mode 100644 spec/controllers/admin/trends/links/preview_card_providers_controller_spec.rb delete mode 100644 spec/controllers/admin/trends/links_controller_spec.rb delete mode 100644 spec/controllers/admin/trends/statuses_controller_spec.rb delete mode 100644 spec/controllers/admin/trends/tags_controller_spec.rb delete mode 100644 spec/controllers/admin/users/roles_controller_spec.rb delete mode 100644 spec/controllers/admin/users/two_factor_authentications_controller_spec.rb delete mode 100644 spec/controllers/admin/warning_presets_controller_spec.rb delete mode 100644 spec/controllers/admin/webhooks/secrets_controller_spec.rb delete mode 100644 spec/controllers/admin/webhooks_controller_spec.rb delete mode 100644 spec/controllers/api/base_controller_spec.rb delete mode 100644 spec/controllers/api/oembed_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts/credentials_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts/familiar_followers_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts/featured_tags_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts/identity_proofs_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts/lists_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts/lookup_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts/notes_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts/pins_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts/relationships_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts/search_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts/statuses_controller_spec.rb delete mode 100644 spec/controllers/api/v1/accounts_controller_spec.rb delete mode 100644 spec/controllers/api/v1/admin/accounts_controller_spec.rb delete mode 100644 spec/controllers/api/v1/admin/dimensions_controller_spec.rb delete mode 100644 spec/controllers/api/v1/admin/measures_controller_spec.rb delete mode 100644 spec/controllers/api/v1/admin/retention_controller_spec.rb delete mode 100644 spec/controllers/api/v1/admin/trends/links/preview_card_providers_controller_spec.rb delete mode 100644 spec/controllers/api/v1/admin/trends/links_controller_spec.rb delete mode 100644 spec/controllers/api/v1/admin/trends/statuses_controller_spec.rb delete mode 100644 spec/controllers/api/v1/admin/trends/tags_controller_spec.rb delete mode 100644 spec/controllers/api/v1/announcements/reactions_controller_spec.rb delete mode 100644 spec/controllers/api/v1/announcements_controller_spec.rb delete mode 100644 spec/controllers/api/v1/blocks_controller_spec.rb delete mode 100644 spec/controllers/api/v1/conversations_controller_spec.rb delete mode 100644 spec/controllers/api/v1/custom_emojis_controller_spec.rb delete mode 100644 spec/controllers/api/v1/directories_controller_spec.rb delete mode 100644 spec/controllers/api/v1/endorsements_controller_spec.rb delete mode 100644 spec/controllers/api/v1/favourites_controller_spec.rb delete mode 100644 spec/controllers/api/v1/featured_tags/suggestions_controller_spec.rb delete mode 100644 spec/controllers/api/v1/filters_controller_spec.rb delete mode 100644 spec/controllers/api/v1/followed_tags_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances/activity_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances/domain_blocks_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances/extended_descriptions_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances/peers_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances/privacy_policies_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances/rules_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances/translation_languages_controller_spec.rb delete mode 100644 spec/controllers/api/v1/instances_controller_spec.rb delete mode 100644 spec/controllers/api/v1/lists/accounts_controller_spec.rb delete mode 100644 spec/controllers/api/v1/markers_controller_spec.rb delete mode 100644 spec/controllers/api/v1/media_controller_spec.rb delete mode 100644 spec/controllers/api/v1/notifications_controller_spec.rb delete mode 100644 spec/controllers/api/v1/polls/votes_controller_spec.rb delete mode 100644 spec/controllers/api/v1/preferences_controller_spec.rb delete mode 100644 spec/controllers/api/v1/push/subscriptions_controller_spec.rb delete mode 100644 spec/controllers/api/v1/reports_controller_spec.rb delete mode 100644 spec/controllers/api/v1/scheduled_statuses_controller_spec.rb delete mode 100644 spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb delete mode 100644 spec/controllers/api/v1/statuses/histories_controller_spec.rb delete mode 100644 spec/controllers/api/v1/statuses/mutes_controller_spec.rb delete mode 100644 spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb delete mode 100644 spec/controllers/api/v1/statuses/reblogs_controller_spec.rb delete mode 100644 spec/controllers/api/v1/statuses/sources_controller_spec.rb delete mode 100644 spec/controllers/api/v1/statuses/translations_controller_spec.rb delete mode 100644 spec/controllers/api/v1/statuses_controller_spec.rb delete mode 100644 spec/controllers/api/v1/streaming_controller_spec.rb delete mode 100644 spec/controllers/api/v1/timelines/direct_controller_spec.rb delete mode 100644 spec/controllers/api/v1/timelines/list_controller_spec.rb delete mode 100644 spec/controllers/api/v1/timelines/tag_controller_spec.rb delete mode 100644 spec/controllers/api/v1/trends/links_controller_spec.rb delete mode 100644 spec/controllers/api/v1/trends/statuses_controller_spec.rb delete mode 100644 spec/controllers/api/v1/trends/tags_controller_spec.rb delete mode 100644 spec/controllers/api/v2/admin/accounts_controller_spec.rb delete mode 100644 spec/controllers/api/v2/filters/keywords_controller_spec.rb delete mode 100644 spec/controllers/api/v2/filters/statuses_controller_spec.rb delete mode 100644 spec/controllers/api/v2/instances_controller_spec.rb delete mode 100644 spec/controllers/api/v2/search_controller_spec.rb delete mode 100644 spec/controllers/api/v2/suggestions_controller_spec.rb delete mode 100644 spec/controllers/api/web/push_subscriptions_controller_spec.rb delete mode 100644 spec/controllers/api/web/settings_controller_spec.rb delete mode 100644 spec/controllers/application_controller_spec.rb delete mode 100644 spec/controllers/auth/challenges_controller_spec.rb delete mode 100644 spec/controllers/auth/confirmations_controller_spec.rb delete mode 100644 spec/controllers/auth/passwords_controller_spec.rb delete mode 100644 spec/controllers/auth/registrations_controller_spec.rb delete mode 100644 spec/controllers/auth/sessions_controller_spec.rb delete mode 100644 spec/controllers/auth/setup_controller_spec.rb delete mode 100644 spec/controllers/authorize_interactions_controller_spec.rb delete mode 100644 spec/controllers/concerns/account_controller_concern_spec.rb delete mode 100644 spec/controllers/concerns/accountable_concern_spec.rb delete mode 100644 spec/controllers/concerns/cache_concern_spec.rb delete mode 100644 spec/controllers/concerns/challengable_concern_spec.rb delete mode 100644 spec/controllers/concerns/export_controller_concern_spec.rb delete mode 100644 spec/controllers/concerns/localized_spec.rb delete mode 100644 spec/controllers/concerns/rate_limit_headers_spec.rb delete mode 100644 spec/controllers/concerns/signature_verification_spec.rb delete mode 100644 spec/controllers/concerns/user_tracking_concern_spec.rb delete mode 100644 spec/controllers/custom_css_controller_spec.rb delete mode 100644 spec/controllers/disputes/appeals_controller_spec.rb delete mode 100644 spec/controllers/disputes/strikes_controller_spec.rb delete mode 100644 spec/controllers/emojis_controller_spec.rb delete mode 100644 spec/controllers/filters/statuses_controller_spec.rb delete mode 100644 spec/controllers/filters_controller_spec.rb delete mode 100644 spec/controllers/follower_accounts_controller_spec.rb delete mode 100644 spec/controllers/following_accounts_controller_spec.rb delete mode 100644 spec/controllers/health_controller_spec.rb delete mode 100644 spec/controllers/home_controller_spec.rb delete mode 100644 spec/controllers/instance_actors_controller_spec.rb delete mode 100644 spec/controllers/intents_controller_spec.rb delete mode 100644 spec/controllers/invites_controller_spec.rb delete mode 100644 spec/controllers/manifests_controller_spec.rb delete mode 100644 spec/controllers/media_controller_spec.rb delete mode 100644 spec/controllers/media_proxy_controller_spec.rb delete mode 100644 spec/controllers/oauth/authorizations_controller_spec.rb delete mode 100644 spec/controllers/oauth/authorized_applications_controller_spec.rb delete mode 100644 spec/controllers/oauth/tokens_controller_spec.rb delete mode 100644 spec/controllers/privacy_controller_spec.rb delete mode 100644 spec/controllers/relationships_controller_spec.rb delete mode 100644 spec/controllers/settings/aliases_controller_spec.rb delete mode 100644 spec/controllers/settings/applications_controller_spec.rb delete mode 100644 spec/controllers/settings/deletes_controller_spec.rb delete mode 100644 spec/controllers/settings/exports/blocked_accounts_controller_spec.rb delete mode 100644 spec/controllers/settings/exports/blocked_domains_controller_spec.rb delete mode 100644 spec/controllers/settings/exports/bookmarks_controller_spec.rb delete mode 100644 spec/controllers/settings/exports/following_accounts_controller_spec.rb delete mode 100644 spec/controllers/settings/exports/lists_controller_spec.rb delete mode 100644 spec/controllers/settings/exports/muted_accounts_controller_spec.rb delete mode 100644 spec/controllers/settings/exports_controller_spec.rb delete mode 100644 spec/controllers/settings/featured_tags_controller_spec.rb delete mode 100644 spec/controllers/settings/flavours_controller_spec.rb delete mode 100644 spec/controllers/settings/imports_controller_spec.rb delete mode 100644 spec/controllers/settings/login_activities_controller_spec.rb delete mode 100644 spec/controllers/settings/migration/redirects_controller_spec.rb delete mode 100644 spec/controllers/settings/migrations_controller_spec.rb delete mode 100644 spec/controllers/settings/pictures_controller_spec.rb delete mode 100644 spec/controllers/settings/preferences/appearance_controller_spec.rb delete mode 100644 spec/controllers/settings/preferences/base_controller_spec.rb delete mode 100644 spec/controllers/settings/preferences/notifications_controller_spec.rb delete mode 100644 spec/controllers/settings/preferences/other_controller_spec.rb delete mode 100644 spec/controllers/settings/profiles_controller_spec.rb delete mode 100644 spec/controllers/settings/sessions_controller_spec.rb delete mode 100644 spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb delete mode 100644 spec/controllers/settings/two_factor_authentication/otp_authentication_controller_spec.rb delete mode 100644 spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb delete mode 100644 spec/controllers/settings/two_factor_authentication/webauthn_credentials_controller_spec.rb delete mode 100644 spec/controllers/settings/two_factor_authentication_methods_controller_spec.rb delete mode 100644 spec/controllers/shares_controller_spec.rb delete mode 100644 spec/controllers/statuses_cleanup_controller_spec.rb delete mode 100644 spec/controllers/statuses_controller_spec.rb delete mode 100644 spec/controllers/tags_controller_spec.rb delete mode 100644 spec/controllers/well_known/host_meta_controller_spec.rb delete mode 100644 spec/controllers/well_known/nodeinfo_controller_spec.rb delete mode 100644 spec/controllers/well_known/webfinger_controller_spec.rb delete mode 100644 spec/fabrication/fabricators_spec.rb delete mode 100644 spec/fabricators/access_grant_fabricator.rb delete mode 100644 spec/fabricators/access_token_fabricator.rb delete mode 100644 spec/fabricators/accessible_access_token_fabricator.rb delete mode 100644 spec/fabricators/account_domain_block_fabricator.rb delete mode 100644 spec/fabricators/account_fabricator.rb delete mode 100644 spec/fabricators/account_migration_fabricator.rb delete mode 100644 spec/fabricators/account_moderation_note_fabricator.rb delete mode 100644 spec/fabricators/account_note_fabricator.rb delete mode 100644 spec/fabricators/account_pin_fabricator.rb delete mode 100644 spec/fabricators/account_stat_fabricator.rb delete mode 100644 spec/fabricators/account_statuses_cleanup_policy_fabricator.rb delete mode 100644 spec/fabricators/account_warning_fabricator.rb delete mode 100644 spec/fabricators/account_warning_preset_fabricator.rb delete mode 100644 spec/fabricators/admin_action_log_fabricator.rb delete mode 100644 spec/fabricators/announcement_fabricator.rb delete mode 100644 spec/fabricators/appeal_fabricator.rb delete mode 100644 spec/fabricators/application_fabricator.rb delete mode 100644 spec/fabricators/assets/TEAPOT delete mode 100644 spec/fabricators/assets/utah_teapot.png delete mode 100644 spec/fabricators/backup_fabricator.rb delete mode 100644 spec/fabricators/block_fabricator.rb delete mode 100644 spec/fabricators/bookmark_fabricator.rb delete mode 100644 spec/fabricators/bulk_import_fabricator.rb delete mode 100644 spec/fabricators/bulk_import_row_fabricator.rb delete mode 100644 spec/fabricators/canonical_email_block_fabricator.rb delete mode 100644 spec/fabricators/conversation_fabricator.rb delete mode 100644 spec/fabricators/custom_emoji_fabricator.rb delete mode 100644 spec/fabricators/custom_filter_fabricator.rb delete mode 100644 spec/fabricators/custom_filter_keyword_fabricator.rb delete mode 100644 spec/fabricators/custom_filter_status_fabricator.rb delete mode 100644 spec/fabricators/device_fabricator.rb delete mode 100644 spec/fabricators/domain_allow_fabricator.rb delete mode 100644 spec/fabricators/domain_block_fabricator.rb delete mode 100644 spec/fabricators/email_domain_block_fabricator.rb delete mode 100644 spec/fabricators/encrypted_message_fabricator.rb delete mode 100644 spec/fabricators/favourite_fabricator.rb delete mode 100644 spec/fabricators/featured_tag_fabricator.rb delete mode 100644 spec/fabricators/follow_fabricator.rb delete mode 100644 spec/fabricators/follow_request_fabricator.rb delete mode 100644 spec/fabricators/identity_fabricator.rb delete mode 100644 spec/fabricators/invite_fabricator.rb delete mode 100644 spec/fabricators/list_account_fabricator.rb delete mode 100644 spec/fabricators/list_fabricator.rb delete mode 100644 spec/fabricators/login_activity_fabricator.rb delete mode 100644 spec/fabricators/marker_fabricator.rb delete mode 100644 spec/fabricators/media_attachment_fabricator.rb delete mode 100644 spec/fabricators/mention_fabricator.rb delete mode 100644 spec/fabricators/mute_fabricator.rb delete mode 100644 spec/fabricators/notification_fabricator.rb delete mode 100644 spec/fabricators/one_time_key_fabricator.rb delete mode 100644 spec/fabricators/poll_fabricator.rb delete mode 100644 spec/fabricators/poll_vote_fabricator.rb delete mode 100644 spec/fabricators/preview_card_fabricator.rb delete mode 100644 spec/fabricators/preview_card_provider_fabricator.rb delete mode 100644 spec/fabricators/relay_fabricator.rb delete mode 100644 spec/fabricators/report_fabricator.rb delete mode 100644 spec/fabricators/report_note_fabricator.rb delete mode 100644 spec/fabricators/rule_fabricator.rb delete mode 100644 spec/fabricators/scheduled_status_fabricator.rb delete mode 100644 spec/fabricators/session_activation_fabricator.rb delete mode 100644 spec/fabricators/setting_fabricator.rb delete mode 100644 spec/fabricators/site_upload_fabricator.rb delete mode 100644 spec/fabricators/software_update_fabricator.rb delete mode 100644 spec/fabricators/status_fabricator.rb delete mode 100644 spec/fabricators/status_pin_fabricator.rb delete mode 100644 spec/fabricators/status_stat_fabricator.rb delete mode 100644 spec/fabricators/system_key_fabricator.rb delete mode 100644 spec/fabricators/tag_fabricator.rb delete mode 100644 spec/fabricators/tag_follow_fabricator.rb delete mode 100644 spec/fabricators/unavailable_domain_fabricator.rb delete mode 100644 spec/fabricators/user_fabricator.rb delete mode 100644 spec/fabricators/user_role_fabricator.rb delete mode 100644 spec/fabricators/web_push_subscription_fabricator.rb delete mode 100644 spec/fabricators/webauthn_credential_fabricator.rb delete mode 100644 spec/fabricators/webhook_fabricator.rb delete mode 100644 spec/features/admin/domain_blocks_spec.rb delete mode 100644 spec/features/admin/software_updates_spec.rb delete mode 100644 spec/features/captcha_spec.rb delete mode 100644 spec/features/log_in_spec.rb delete mode 100644 spec/features/oauth_spec.rb delete mode 100644 spec/features/profile_spec.rb delete mode 100644 spec/fixtures/files/4096x4097.png delete mode 100644 spec/fixtures/files/600x400.avif delete mode 100644 spec/fixtures/files/600x400.heic delete mode 100644 spec/fixtures/files/600x400.jpeg delete mode 100644 spec/fixtures/files/600x400.png delete mode 100644 spec/fixtures/files/600x400.webp delete mode 100644 spec/fixtures/files/attachment-jpg.123456_abcd delete mode 100644 spec/fixtures/files/attachment.gif delete mode 100644 spec/fixtures/files/attachment.jpg delete mode 100644 spec/fixtures/files/attachment.webm delete mode 100644 spec/fixtures/files/avatar.gif delete mode 100644 spec/fixtures/files/bookmark-imports.txt delete mode 100644 spec/fixtures/files/boop.mp3 delete mode 100644 spec/fixtures/files/boop.ogg delete mode 100644 spec/fixtures/files/domain_allows.csv delete mode 100644 spec/fixtures/files/domain_blocks.csv delete mode 100644 spec/fixtures/files/domain_blocks_list.txt delete mode 100644 spec/fixtures/files/emojo.png delete mode 100644 spec/fixtures/files/empty.csv delete mode 100644 spec/fixtures/files/following_accounts.csv delete mode 100644 spec/fixtures/files/imports.txt delete mode 100644 spec/fixtures/files/lists.csv delete mode 100644 spec/fixtures/files/mini-static.gif delete mode 100644 spec/fixtures/files/mute-imports.txt delete mode 100644 spec/fixtures/files/muted_accounts.csv delete mode 100644 spec/fixtures/files/new-following-imports.txt delete mode 100644 spec/fixtures/files/new-mute-imports.txt delete mode 100644 spec/fixtures/files/utf8-followers.txt delete mode 100644 spec/fixtures/push/feed.atom delete mode 100644 spec/fixtures/push/reblog.atom delete mode 100644 spec/fixtures/requests/.host-meta.txt delete mode 100644 spec/fixtures/requests/activitypub-actor-individual.txt delete mode 100644 spec/fixtures/requests/activitypub-actor-noinbox.txt delete mode 100644 spec/fixtures/requests/activitypub-actor.txt delete mode 100644 spec/fixtures/requests/activitypub-feed.txt delete mode 100644 spec/fixtures/requests/activitypub-webfinger.txt delete mode 100644 spec/fixtures/requests/attachment1.txt delete mode 100644 spec/fixtures/requests/attachment2.txt delete mode 100644 spec/fixtures/requests/avatar.txt delete mode 100644 spec/fixtures/requests/feed.txt delete mode 100644 spec/fixtures/requests/json-ld.activitystreams.txt delete mode 100644 spec/fixtures/requests/json-ld.identity.txt delete mode 100644 spec/fixtures/requests/json-ld.security.txt delete mode 100644 spec/fixtures/requests/koi8-r.txt delete mode 100644 spec/fixtures/requests/localdomain-feed.txt delete mode 100644 spec/fixtures/requests/localdomain-hostmeta.txt delete mode 100644 spec/fixtures/requests/localdomain-webfinger.txt delete mode 100644 spec/fixtures/requests/oembed_invalid_xml.html delete mode 100644 spec/fixtures/requests/oembed_json.html delete mode 100644 spec/fixtures/requests/oembed_json_empty.html delete mode 100644 spec/fixtures/requests/oembed_json_xml.html delete mode 100644 spec/fixtures/requests/oembed_undiscoverable.html delete mode 100644 spec/fixtures/requests/oembed_xml.html delete mode 100644 spec/fixtures/requests/oembed_youtube.html delete mode 100644 spec/fixtures/requests/redirected.host-meta.txt delete mode 100644 spec/fixtures/requests/sjis.txt delete mode 100644 spec/fixtures/requests/sjis_with_wrong_charset.txt delete mode 100644 spec/fixtures/requests/webfinger-hacker1.txt delete mode 100644 spec/fixtures/requests/webfinger-hacker2.txt delete mode 100644 spec/fixtures/requests/webfinger-hacker3.txt delete mode 100644 spec/fixtures/requests/webfinger.txt delete mode 100644 spec/fixtures/requests/windows-1251.txt delete mode 100644 spec/fixtures/salmon/mention.xml delete mode 100644 spec/generators/post_deployment_migration_generator_spec.rb delete mode 100644 spec/helpers/accounts_helper_spec.rb delete mode 100644 spec/helpers/admin/account_moderation_notes_helper_spec.rb delete mode 100644 spec/helpers/admin/dashboard_helper_spec.rb delete mode 100644 spec/helpers/admin/filter_helper_spec.rb delete mode 100644 spec/helpers/admin/trends/statuses_helper_spec.rb delete mode 100644 spec/helpers/application_helper_spec.rb delete mode 100644 spec/helpers/flashes_helper_spec.rb delete mode 100644 spec/helpers/formatting_helper_spec.rb delete mode 100644 spec/helpers/home_helper_spec.rb delete mode 100644 spec/helpers/instance_helper_spec.rb delete mode 100644 spec/helpers/jsonld_helper_spec.rb delete mode 100644 spec/helpers/languages_helper_spec.rb delete mode 100644 spec/helpers/media_component_helper_spec.rb delete mode 100644 spec/helpers/react_component_helper_spec.rb delete mode 100644 spec/helpers/routing_helper_spec.rb delete mode 100644 spec/helpers/settings_helper_spec.rb delete mode 100644 spec/helpers/statuses_helper_spec.rb delete mode 100644 spec/lib/account_reach_finder_spec.rb delete mode 100644 spec/lib/account_statuses_filter_spec.rb delete mode 100644 spec/lib/activitypub/activity/accept_spec.rb delete mode 100644 spec/lib/activitypub/activity/add_spec.rb delete mode 100644 spec/lib/activitypub/activity/announce_spec.rb delete mode 100644 spec/lib/activitypub/activity/block_spec.rb delete mode 100644 spec/lib/activitypub/activity/create_spec.rb delete mode 100644 spec/lib/activitypub/activity/delete_spec.rb delete mode 100644 spec/lib/activitypub/activity/flag_spec.rb delete mode 100644 spec/lib/activitypub/activity/follow_spec.rb delete mode 100644 spec/lib/activitypub/activity/like_spec.rb delete mode 100644 spec/lib/activitypub/activity/move_spec.rb delete mode 100644 spec/lib/activitypub/activity/reject_spec.rb delete mode 100644 spec/lib/activitypub/activity/remove_spec.rb delete mode 100644 spec/lib/activitypub/activity/undo_spec.rb delete mode 100644 spec/lib/activitypub/activity/update_spec.rb delete mode 100644 spec/lib/activitypub/adapter_spec.rb delete mode 100644 spec/lib/activitypub/dereferencer_spec.rb delete mode 100644 spec/lib/activitypub/linked_data_signature_spec.rb delete mode 100644 spec/lib/activitypub/tag_manager_spec.rb delete mode 100644 spec/lib/admin/metrics/dimension/instance_accounts_dimension_spec.rb delete mode 100644 spec/lib/admin/metrics/dimension/instance_languages_dimension_spec.rb delete mode 100644 spec/lib/admin/metrics/dimension/languages_dimension_spec.rb delete mode 100644 spec/lib/admin/metrics/dimension/servers_dimension_spec.rb delete mode 100644 spec/lib/admin/metrics/dimension/software_versions_dimension_spec.rb delete mode 100644 spec/lib/admin/metrics/dimension/sources_dimension_spec.rb delete mode 100644 spec/lib/admin/metrics/dimension/space_usage_dimension_spec.rb delete mode 100644 spec/lib/admin/metrics/dimension/tag_languages_dimension_spec.rb delete mode 100644 spec/lib/admin/metrics/dimension/tag_servers_dimension_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/active_users_measure_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/instance_accounts_measure_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/instance_followers_measure_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/instance_follows_measure_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/instance_media_attachments_measure_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/instance_reports_measure_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/instance_statuses_measure_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/interactions_measure_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/new_users_measure_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/opened_reports_measure_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/resolved_reports_measure_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/tag_accounts_measure_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/tag_servers_measure_spec.rb delete mode 100644 spec/lib/admin/metrics/measure/tag_uses_measure_spec.rb delete mode 100644 spec/lib/admin/system_check/base_check_spec.rb delete mode 100644 spec/lib/admin/system_check/database_schema_check_spec.rb delete mode 100644 spec/lib/admin/system_check/elasticsearch_check_spec.rb delete mode 100644 spec/lib/admin/system_check/media_privacy_check_spec.rb delete mode 100644 spec/lib/admin/system_check/message_spec.rb delete mode 100644 spec/lib/admin/system_check/rules_check_spec.rb delete mode 100644 spec/lib/admin/system_check/sidekiq_process_check_spec.rb delete mode 100644 spec/lib/admin/system_check/software_version_check_spec.rb delete mode 100644 spec/lib/admin/system_check_spec.rb delete mode 100644 spec/lib/advanced_text_formatter_spec.rb delete mode 100644 spec/lib/cache_buster_spec.rb delete mode 100644 spec/lib/connection_pool/shared_connection_pool_spec.rb delete mode 100644 spec/lib/connection_pool/shared_timed_stack_spec.rb delete mode 100644 spec/lib/delivery_failure_tracker_spec.rb delete mode 100644 spec/lib/emoji_formatter_spec.rb delete mode 100644 spec/lib/entity_cache_spec.rb delete mode 100644 spec/lib/extractor_spec.rb delete mode 100644 spec/lib/fast_ip_map_spec.rb delete mode 100644 spec/lib/feed_manager_spec.rb delete mode 100644 spec/lib/hashtag_normalizer_spec.rb delete mode 100644 spec/lib/html_aware_formatter_spec.rb delete mode 100644 spec/lib/importer/accounts_index_importer_spec.rb delete mode 100644 spec/lib/importer/base_importer_spec.rb delete mode 100644 spec/lib/importer/public_statuses_index_importer_spec.rb delete mode 100644 spec/lib/importer/statuses_index_importer_spec.rb delete mode 100644 spec/lib/importer/tags_index_importer_spec.rb delete mode 100644 spec/lib/link_details_extractor_spec.rb delete mode 100644 spec/lib/mastodon/cli/accounts_spec.rb delete mode 100644 spec/lib/mastodon/cli/cache_spec.rb delete mode 100644 spec/lib/mastodon/cli/canonical_email_blocks_spec.rb delete mode 100644 spec/lib/mastodon/cli/domains_spec.rb delete mode 100644 spec/lib/mastodon/cli/email_domain_blocks_spec.rb delete mode 100644 spec/lib/mastodon/cli/emoji_spec.rb delete mode 100644 spec/lib/mastodon/cli/feeds_spec.rb delete mode 100644 spec/lib/mastodon/cli/ip_blocks_spec.rb delete mode 100644 spec/lib/mastodon/cli/main_spec.rb delete mode 100644 spec/lib/mastodon/cli/maintenance_spec.rb delete mode 100644 spec/lib/mastodon/cli/media_spec.rb delete mode 100644 spec/lib/mastodon/cli/preview_cards_spec.rb delete mode 100644 spec/lib/mastodon/cli/search_spec.rb delete mode 100644 spec/lib/mastodon/cli/settings_spec.rb delete mode 100644 spec/lib/mastodon/cli/statuses_spec.rb delete mode 100644 spec/lib/mastodon/cli/upgrade_spec.rb delete mode 100644 spec/lib/mastodon/migration_warning_spec.rb delete mode 100644 spec/lib/ostatus/tag_manager_spec.rb delete mode 100644 spec/lib/permalink_redirector_spec.rb delete mode 100644 spec/lib/plain_text_formatter_spec.rb delete mode 100644 spec/lib/request_pool_spec.rb delete mode 100644 spec/lib/request_spec.rb delete mode 100644 spec/lib/sanitize_config_spec.rb delete mode 100644 spec/lib/scope_transformer_spec.rb delete mode 100644 spec/lib/search_query_parser_spec.rb delete mode 100644 spec/lib/search_query_transformer_spec.rb delete mode 100644 spec/lib/status_cache_hydrator_spec.rb delete mode 100644 spec/lib/status_filter_spec.rb delete mode 100644 spec/lib/status_finder_spec.rb delete mode 100644 spec/lib/status_reach_finder_spec.rb delete mode 100644 spec/lib/suspicious_sign_in_detector_spec.rb delete mode 100644 spec/lib/tag_manager_spec.rb delete mode 100644 spec/lib/text_formatter_spec.rb delete mode 100644 spec/lib/translation_service/deepl_spec.rb delete mode 100644 spec/lib/translation_service/libre_translate_spec.rb delete mode 100644 spec/lib/vacuum/access_tokens_vacuum_spec.rb delete mode 100644 spec/lib/vacuum/applications_vacuum_spec.rb delete mode 100644 spec/lib/vacuum/backups_vacuum_spec.rb delete mode 100644 spec/lib/vacuum/feeds_vacuum_spec.rb delete mode 100644 spec/lib/vacuum/imports_vacuum_spec.rb delete mode 100644 spec/lib/vacuum/media_attachments_vacuum_spec.rb delete mode 100644 spec/lib/vacuum/preview_cards_vacuum_spec.rb delete mode 100644 spec/lib/vacuum/statuses_vacuum_spec.rb delete mode 100644 spec/lib/vacuum/system_keys_vacuum_spec.rb delete mode 100644 spec/lib/webfinger_resource_spec.rb delete mode 100644 spec/lib/webhooks/payload_renderer_spec.rb delete mode 100644 spec/locales/i18n_spec.rb delete mode 100644 spec/mailers/admin_mailer_spec.rb delete mode 100644 spec/mailers/notification_mailer_spec.rb delete mode 100644 spec/mailers/previews/admin_mailer_preview.rb delete mode 100644 spec/mailers/previews/notification_mailer_preview.rb delete mode 100644 spec/mailers/previews/user_mailer_preview.rb delete mode 100644 spec/mailers/user_mailer_spec.rb delete mode 100644 spec/models/account/field_spec.rb delete mode 100644 spec/models/account_conversation_spec.rb delete mode 100644 spec/models/account_domain_block_spec.rb delete mode 100644 spec/models/account_filter_spec.rb delete mode 100644 spec/models/account_migration_spec.rb delete mode 100644 spec/models/account_spec.rb delete mode 100644 spec/models/account_statuses_cleanup_policy_spec.rb delete mode 100644 spec/models/account_warning_preset_spec.rb delete mode 100644 spec/models/admin/account_action_spec.rb delete mode 100644 spec/models/admin/action_log_spec.rb delete mode 100644 spec/models/admin/appeal_filter_spec.rb delete mode 100644 spec/models/appeal_spec.rb delete mode 100644 spec/models/block_spec.rb delete mode 100644 spec/models/canonical_email_block_spec.rb delete mode 100644 spec/models/concerns/account_counters_spec.rb delete mode 100644 spec/models/concerns/account_finder_concern_spec.rb delete mode 100644 spec/models/concerns/account_interactions_spec.rb delete mode 100644 spec/models/concerns/account_statuses_search_spec.rb delete mode 100644 spec/models/concerns/remotable_spec.rb delete mode 100644 spec/models/concerns/status_threading_concern_spec.rb delete mode 100644 spec/models/conversation_spec.rb delete mode 100644 spec/models/custom_emoji_category_spec.rb delete mode 100644 spec/models/custom_emoji_filter_spec.rb delete mode 100644 spec/models/custom_emoji_spec.rb delete mode 100644 spec/models/domain_allow_spec.rb delete mode 100644 spec/models/domain_block_spec.rb delete mode 100644 spec/models/email_domain_block_spec.rb delete mode 100644 spec/models/export_spec.rb delete mode 100644 spec/models/extended_description_spec.rb delete mode 100644 spec/models/favourite_spec.rb delete mode 100644 spec/models/follow_request_spec.rb delete mode 100644 spec/models/follow_spec.rb delete mode 100644 spec/models/form/account_batch_spec.rb delete mode 100644 spec/models/form/admin_settings_spec.rb delete mode 100644 spec/models/form/import_spec.rb delete mode 100644 spec/models/form/status_filter_batch_action_spec.rb delete mode 100644 spec/models/home_feed_spec.rb delete mode 100644 spec/models/identity_spec.rb delete mode 100644 spec/models/import_spec.rb delete mode 100644 spec/models/invite_spec.rb delete mode 100644 spec/models/ip_block_spec.rb delete mode 100644 spec/models/marker_spec.rb delete mode 100644 spec/models/media_attachment_spec.rb delete mode 100644 spec/models/mention_spec.rb delete mode 100644 spec/models/notification_spec.rb delete mode 100644 spec/models/one_time_key_spec.rb delete mode 100644 spec/models/poll_spec.rb delete mode 100644 spec/models/poll_vote_spec.rb delete mode 100644 spec/models/preview_card_provider_spec.rb delete mode 100644 spec/models/privacy_policy_spec.rb delete mode 100644 spec/models/public_feed_spec.rb delete mode 100644 spec/models/relationship_filter_spec.rb delete mode 100644 spec/models/remote_follow_spec.rb delete mode 100644 spec/models/report_filter_spec.rb delete mode 100644 spec/models/report_spec.rb delete mode 100644 spec/models/rule_spec.rb delete mode 100644 spec/models/session_activation_spec.rb delete mode 100644 spec/models/setting_spec.rb delete mode 100644 spec/models/site_upload_spec.rb delete mode 100644 spec/models/software_update_spec.rb delete mode 100644 spec/models/status_edit_spec.rb delete mode 100644 spec/models/status_pin_spec.rb delete mode 100644 spec/models/status_spec.rb delete mode 100644 spec/models/tag_feed_spec.rb delete mode 100644 spec/models/tag_spec.rb delete mode 100644 spec/models/trends/statuses_spec.rb delete mode 100644 spec/models/trends/tags_spec.rb delete mode 100644 spec/models/user_role_spec.rb delete mode 100644 spec/models/user_settings/namespace_spec.rb delete mode 100644 spec/models/user_settings/setting_spec.rb delete mode 100644 spec/models/user_settings_spec.rb delete mode 100644 spec/models/user_spec.rb delete mode 100644 spec/models/web/push_subscription_spec.rb delete mode 100644 spec/models/webauthn_credentials_spec.rb delete mode 100644 spec/models/webhook_spec.rb delete mode 100644 spec/policies/account_moderation_note_policy_spec.rb delete mode 100644 spec/policies/account_policy_spec.rb delete mode 100644 spec/policies/account_warning_preset_policy_spec.rb delete mode 100644 spec/policies/admin/status_policy_spec.rb delete mode 100644 spec/policies/announcement_policy_spec.rb delete mode 100644 spec/policies/appeal_policy_spec.rb delete mode 100644 spec/policies/backup_policy_spec.rb delete mode 100644 spec/policies/canonical_email_block_policy_spec.rb delete mode 100644 spec/policies/custom_emoji_policy_spec.rb delete mode 100644 spec/policies/delivery_policy_spec.rb delete mode 100644 spec/policies/domain_block_policy_spec.rb delete mode 100644 spec/policies/email_domain_block_policy_spec.rb delete mode 100644 spec/policies/follow_recommendation_policy_spec.rb delete mode 100644 spec/policies/instance_policy_spec.rb delete mode 100644 spec/policies/invite_policy_spec.rb delete mode 100644 spec/policies/ip_block_policy_spec.rb delete mode 100644 spec/policies/preview_card_policy_spec.rb delete mode 100644 spec/policies/preview_card_provider_policy_spec.rb delete mode 100644 spec/policies/relay_policy_spec.rb delete mode 100644 spec/policies/report_note_policy_spec.rb delete mode 100644 spec/policies/report_policy_spec.rb delete mode 100644 spec/policies/rule_policy_spec.rb delete mode 100644 spec/policies/settings_policy_spec.rb delete mode 100644 spec/policies/software_update_policy_spec.rb delete mode 100644 spec/policies/status_policy_spec.rb delete mode 100644 spec/policies/tag_policy_spec.rb delete mode 100644 spec/policies/user_policy_spec.rb delete mode 100644 spec/policies/webhook_policy_spec.rb delete mode 100644 spec/presenters/account_relationships_presenter_spec.rb delete mode 100644 spec/presenters/familiar_followers_presenter_spec.rb delete mode 100644 spec/presenters/instance_presenter_spec.rb delete mode 100644 spec/presenters/status_relationships_presenter_spec.rb delete mode 100644 spec/rails_helper.rb delete mode 100644 spec/requests/account_show_page_spec.rb delete mode 100644 spec/requests/anonymous_cookies_spec.rb delete mode 100644 spec/requests/api/v1/accounts/credentials_spec.rb delete mode 100644 spec/requests/api/v1/accounts_show_spec.rb delete mode 100644 spec/requests/api/v1/admin/account_actions_spec.rb delete mode 100644 spec/requests/api/v1/admin/canonical_email_blocks_spec.rb delete mode 100644 spec/requests/api/v1/admin/domain_allows_spec.rb delete mode 100644 spec/requests/api/v1/admin/domain_blocks_spec.rb delete mode 100644 spec/requests/api/v1/admin/email_domain_blocks_spec.rb delete mode 100644 spec/requests/api/v1/admin/ip_blocks_spec.rb delete mode 100644 spec/requests/api/v1/admin/reports_spec.rb delete mode 100644 spec/requests/api/v1/admin/tags_spec.rb delete mode 100644 spec/requests/api/v1/apps/credentials_spec.rb delete mode 100644 spec/requests/api/v1/apps_spec.rb delete mode 100644 spec/requests/api/v1/bookmarks_spec.rb delete mode 100644 spec/requests/api/v1/domain_blocks_spec.rb delete mode 100644 spec/requests/api/v1/emails/confirmations_spec.rb delete mode 100644 spec/requests/api/v1/featured_tags_spec.rb delete mode 100644 spec/requests/api/v1/follow_requests_spec.rb delete mode 100644 spec/requests/api/v1/instances/languages_spec.rb delete mode 100644 spec/requests/api/v1/lists_spec.rb delete mode 100644 spec/requests/api/v1/mutes_spec.rb delete mode 100644 spec/requests/api/v1/polls_spec.rb delete mode 100644 spec/requests/api/v1/profiles_spec.rb delete mode 100644 spec/requests/api/v1/statuses/bookmarks_spec.rb delete mode 100644 spec/requests/api/v1/statuses/favourites_spec.rb delete mode 100644 spec/requests/api/v1/statuses/pins_spec.rb delete mode 100644 spec/requests/api/v1/suggestions_spec.rb delete mode 100644 spec/requests/api/v1/tags_spec.rb delete mode 100644 spec/requests/api/v1/timelines/home_spec.rb delete mode 100644 spec/requests/api/v1/timelines/public_spec.rb delete mode 100644 spec/requests/api/v2/filters/filters_spec.rb delete mode 100644 spec/requests/api/v2/media_spec.rb delete mode 100644 spec/requests/api/web/embeds_spec.rb delete mode 100644 spec/requests/backups_spec.rb delete mode 100644 spec/requests/cache_spec.rb delete mode 100644 spec/requests/catch_all_route_request_spec.rb delete mode 100644 spec/requests/content_security_policy_spec.rb delete mode 100644 spec/requests/follower_accounts_spec.rb delete mode 100644 spec/requests/following_accounts_spec.rb delete mode 100644 spec/requests/host_meta_request_spec.rb delete mode 100644 spec/requests/link_headers_spec.rb delete mode 100644 spec/requests/localization_spec.rb delete mode 100644 spec/requests/mail_subscriptions_spec.rb delete mode 100644 spec/requests/omniauth_callbacks_spec.rb delete mode 100644 spec/requests/webfinger_request_spec.rb delete mode 100644 spec/routing/accounts_routing_spec.rb delete mode 100644 spec/routing/api_routing_spec.rb delete mode 100644 spec/routing/well_known_routes_spec.rb delete mode 100644 spec/search/models/concerns/account_search_spec.rb delete mode 100644 spec/search/models/concerns/account_statuses_search_spec.rb delete mode 100644 spec/serializers/activitypub/device_serializer_spec.rb delete mode 100644 spec/serializers/activitypub/note_serializer_spec.rb delete mode 100644 spec/serializers/activitypub/one_time_key_serializer_spec.rb delete mode 100644 spec/serializers/activitypub/undo_like_serializer_spec.rb delete mode 100644 spec/serializers/activitypub/update_poll_serializer_spec.rb delete mode 100644 spec/serializers/activitypub/vote_serializer_spec.rb delete mode 100644 spec/serializers/rest/account_serializer_spec.rb delete mode 100644 spec/serializers/rest/encrypted_message_serializer_spec.rb delete mode 100644 spec/serializers/rest/instance_serializer_spec.rb delete mode 100644 spec/serializers/rest/keys/claim_result_serializer_spec.rb delete mode 100644 spec/serializers/rest/keys/device_serializer_spec.rb delete mode 100644 spec/serializers/rest/keys/query_result_serializer_spec.rb delete mode 100644 spec/serializers/rest/suggestion_serializer_spec.rb delete mode 100644 spec/services/account_search_service_spec.rb delete mode 100644 spec/services/account_statuses_cleanup_service_spec.rb delete mode 100644 spec/services/activitypub/fetch_featured_collection_service_spec.rb delete mode 100644 spec/services/activitypub/fetch_featured_tags_collection_service_spec.rb delete mode 100644 spec/services/activitypub/fetch_remote_account_service_spec.rb delete mode 100644 spec/services/activitypub/fetch_remote_actor_service_spec.rb delete mode 100644 spec/services/activitypub/fetch_remote_key_service_spec.rb delete mode 100644 spec/services/activitypub/fetch_remote_status_service_spec.rb delete mode 100644 spec/services/activitypub/fetch_replies_service_spec.rb delete mode 100644 spec/services/activitypub/process_account_service_spec.rb delete mode 100644 spec/services/activitypub/process_collection_service_spec.rb delete mode 100644 spec/services/activitypub/process_status_update_service_spec.rb delete mode 100644 spec/services/activitypub/synchronize_followers_service_spec.rb delete mode 100644 spec/services/after_block_domain_from_account_service_spec.rb delete mode 100644 spec/services/after_block_service_spec.rb delete mode 100644 spec/services/app_sign_up_service_spec.rb delete mode 100644 spec/services/authorize_follow_service_spec.rb delete mode 100644 spec/services/backup_service_spec.rb delete mode 100644 spec/services/batched_remove_status_service_spec.rb delete mode 100644 spec/services/block_domain_service_spec.rb delete mode 100644 spec/services/block_service_spec.rb delete mode 100644 spec/services/bootstrap_timeline_service_spec.rb delete mode 100644 spec/services/bulk_import_row_service_spec.rb delete mode 100644 spec/services/bulk_import_service_spec.rb delete mode 100644 spec/services/clear_domain_media_service_spec.rb delete mode 100644 spec/services/delete_account_service_spec.rb delete mode 100644 spec/services/fan_out_on_write_service_spec.rb delete mode 100644 spec/services/favourite_service_spec.rb delete mode 100644 spec/services/fetch_link_card_service_spec.rb delete mode 100644 spec/services/fetch_oembed_service_spec.rb delete mode 100644 spec/services/fetch_remote_status_service_spec.rb delete mode 100644 spec/services/fetch_resource_service_spec.rb delete mode 100644 spec/services/follow_service_spec.rb delete mode 100644 spec/services/import_service_spec.rb delete mode 100644 spec/services/mute_service_spec.rb delete mode 100644 spec/services/notify_service_spec.rb delete mode 100644 spec/services/post_status_service_spec.rb delete mode 100644 spec/services/precompute_feed_service_spec.rb delete mode 100644 spec/services/process_mentions_service_spec.rb delete mode 100644 spec/services/purge_domain_service_spec.rb delete mode 100644 spec/services/reblog_service_spec.rb delete mode 100644 spec/services/reject_follow_service_spec.rb delete mode 100644 spec/services/remove_from_followers_service_spec.rb delete mode 100644 spec/services/remove_status_service_spec.rb delete mode 100644 spec/services/report_service_spec.rb delete mode 100644 spec/services/resolve_account_service_spec.rb delete mode 100644 spec/services/resolve_url_service_spec.rb delete mode 100644 spec/services/search_service_spec.rb delete mode 100644 spec/services/software_update_check_service_spec.rb delete mode 100644 spec/services/suspend_account_service_spec.rb delete mode 100644 spec/services/translate_status_service_spec.rb delete mode 100644 spec/services/unallow_domain_service_spec.rb delete mode 100644 spec/services/unblock_domain_service_spec.rb delete mode 100644 spec/services/unblock_service_spec.rb delete mode 100644 spec/services/unfollow_service_spec.rb delete mode 100644 spec/services/unsuspend_account_service_spec.rb delete mode 100644 spec/services/update_account_service_spec.rb delete mode 100644 spec/services/update_status_service_spec.rb delete mode 100644 spec/services/verify_link_service_spec.rb delete mode 100644 spec/spec_helper.rb delete mode 100644 spec/support/examples/api.rb delete mode 100644 spec/support/examples/lib/admin/checks.rb delete mode 100644 spec/support/examples/mailers.rb delete mode 100644 spec/support/examples/models/concerns/account_avatar.rb delete mode 100644 spec/support/examples/models/concerns/account_header.rb delete mode 100644 spec/support/matchers/json/match_json_schema.rb delete mode 100644 spec/support/matchers/model/model_have_error_on_field.rb delete mode 100644 spec/support/omniauth_mocks.rb delete mode 100644 spec/support/schema/nodeinfo_2.0.json delete mode 100644 spec/support/stories/profile_stories.rb delete mode 100644 spec/system/new_statuses_spec.rb delete mode 100644 spec/validators/blacklisted_email_validator_spec.rb delete mode 100644 spec/validators/disallowed_hashtags_validator_spec.rb delete mode 100644 spec/validators/email_mx_validator_spec.rb delete mode 100644 spec/validators/follow_limit_validator_spec.rb delete mode 100644 spec/validators/language_validator_spec.rb delete mode 100644 spec/validators/note_length_validator_spec.rb delete mode 100644 spec/validators/poll_validator_spec.rb delete mode 100644 spec/validators/reaction_validator_spec.rb delete mode 100644 spec/validators/status_length_validator_spec.rb delete mode 100644 spec/validators/status_pin_validator_spec.rb delete mode 100644 spec/validators/unique_username_validator_spec.rb delete mode 100644 spec/validators/unreserved_username_validator_spec.rb delete mode 100644 spec/validators/url_validator_spec.rb delete mode 100644 spec/views/statuses/show.html.haml_spec.rb delete mode 100644 spec/workers/activitypub/delivery_worker_spec.rb delete mode 100644 spec/workers/activitypub/distribute_poll_update_worker_spec.rb delete mode 100644 spec/workers/activitypub/distribution_worker_spec.rb delete mode 100644 spec/workers/activitypub/fetch_replies_worker_spec.rb delete mode 100644 spec/workers/activitypub/move_distribution_worker_spec.rb delete mode 100644 spec/workers/activitypub/processing_worker_spec.rb delete mode 100644 spec/workers/activitypub/status_update_distribution_worker_spec.rb delete mode 100644 spec/workers/activitypub/update_distribution_worker_spec.rb delete mode 100644 spec/workers/add_to_public_statuses_index_worker_spec.rb delete mode 100644 spec/workers/admin/account_deletion_worker_spec.rb delete mode 100644 spec/workers/admin/domain_purge_worker_spec.rb delete mode 100644 spec/workers/bulk_import_worker_spec.rb delete mode 100644 spec/workers/cache_buster_worker_spec.rb delete mode 100644 spec/workers/domain_block_worker_spec.rb delete mode 100644 spec/workers/domain_clear_media_worker_spec.rb delete mode 100644 spec/workers/feed_insert_worker_spec.rb delete mode 100644 spec/workers/import/row_worker_spec.rb delete mode 100644 spec/workers/move_worker_spec.rb delete mode 100644 spec/workers/poll_expiration_notify_worker_spec.rb delete mode 100644 spec/workers/post_process_media_worker_spec.rb delete mode 100644 spec/workers/publish_scheduled_announcement_worker_spec.rb delete mode 100644 spec/workers/publish_scheduled_status_worker_spec.rb delete mode 100644 spec/workers/push_conversation_worker_spec.rb delete mode 100644 spec/workers/push_encrypted_message_worker_spec.rb delete mode 100644 spec/workers/push_update_worker_spec.rb delete mode 100644 spec/workers/redownload_avatar_worker_spec.rb delete mode 100644 spec/workers/redownload_header_worker_spec.rb delete mode 100644 spec/workers/refollow_worker_spec.rb delete mode 100644 spec/workers/regeneration_worker_spec.rb delete mode 100644 spec/workers/remove_featured_tag_worker_spec.rb delete mode 100644 spec/workers/remove_from_public_statuses_index_worker_spec.rb delete mode 100644 spec/workers/resolve_account_worker_spec.rb delete mode 100644 spec/workers/scheduler/accounts_statuses_cleanup_scheduler_spec.rb delete mode 100644 spec/workers/scheduler/follow_recommendations_scheduler_spec.rb delete mode 100644 spec/workers/scheduler/indexing_scheduler_spec.rb delete mode 100644 spec/workers/scheduler/instance_refresh_scheduler_spec.rb delete mode 100644 spec/workers/scheduler/ip_cleanup_scheduler_spec.rb delete mode 100644 spec/workers/scheduler/pghero_scheduler_spec.rb delete mode 100644 spec/workers/scheduler/scheduled_statuses_scheduler_spec.rb delete mode 100644 spec/workers/scheduler/software_update_check_scheduler_spec.rb delete mode 100644 spec/workers/scheduler/suspended_user_cleanup_scheduler_spec.rb delete mode 100644 spec/workers/scheduler/trends/refresh_scheduler_spec.rb delete mode 100644 spec/workers/scheduler/trends/review_notifications_scheduler_spec.rb delete mode 100644 spec/workers/scheduler/user_cleanup_scheduler_spec.rb delete mode 100644 spec/workers/scheduler/vacuum_scheduler_spec.rb delete mode 100644 spec/workers/tag_unmerge_worker_spec.rb delete mode 100644 spec/workers/unfollow_follow_worker_spec.rb delete mode 100644 spec/workers/unpublish_announcement_worker_spec.rb delete mode 100644 spec/workers/verify_account_links_worker_spec.rb delete mode 100644 spec/workers/web/push_notification_worker_spec.rb delete mode 100644 spec/workers/webhooks/delivery_worker_spec.rb delete mode 100644 vendor/.keep diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index b3b1d97a2..000000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -# For details, see https://github.com/devcontainers/images/tree/main/src/ruby -FROM mcr.microsoft.com/devcontainers/ruby:1-3.2-bullseye - -# Install Rails -# RUN gem install rails webdrivers - -ARG NODE_VERSION="16" -RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1" - -# [Optional] Uncomment this section to install additional OS packages. -RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends libicu-dev libidn11-dev ffmpeg imagemagick libpam-dev - -# [Optional] Uncomment this line to install additional gems. -RUN gem install foreman - -# [Optional] Uncomment this line to install global node packages. -RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g yarn" 2>&1 - -COPY welcome-message.txt /usr/local/etc/vscode-dev-containers/first-run-notice.txt diff --git a/.devcontainer/codespaces/devcontainer.json b/.devcontainer/codespaces/devcontainer.json deleted file mode 100644 index ca9156fda..000000000 --- a/.devcontainer/codespaces/devcontainer.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "Mastodon on GitHub Codespaces", - "dockerComposeFile": "../docker-compose.yml", - "service": "app", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", - - "features": { - "ghcr.io/devcontainers/features/sshd:1": {} - }, - - "runServices": ["app", "db", "redis"], - - "forwardPorts": [3000, 4000], - - "portsAttributes": { - "3000": { - "label": "web", - "onAutoForward": "notify" - }, - "4000": { - "label": "stream", - "onAutoForward": "silent" - } - }, - - "otherPortsAttributes": { - "onAutoForward": "silent" - }, - - "remoteEnv": { - "LOCAL_DOMAIN": "${localEnv:CODESPACE_NAME}-3000.app.github.dev", - "LOCAL_HTTPS": "true", - "STREAMING_API_BASE_URL": "https://${localEnv:CODESPACE_NAME}-4000.app.github.dev", - "DISABLE_FORGERY_REQUEST_PROTECTION": "true", - "ES_ENABLED": "", - "LIBRE_TRANSLATE_ENDPOINT": "" - }, - - "onCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}", - "postCreateCommand": ".devcontainer/post-create.sh", - "waitFor": "postCreateCommand", - - "customizations": { - "vscode": { - "settings": {}, - "extensions": ["EditorConfig.EditorConfig", "webben.browserslist"] - } - } -} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index fa8d6542c..000000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "Mastodon on local machine", - "dockerComposeFile": "docker-compose.yml", - "service": "app", - "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", - - "features": { - "ghcr.io/devcontainers/features/sshd:1": {} - }, - - "forwardPorts": [3000, 4000], - - "portsAttributes": { - "3000": { - "label": "web", - "onAutoForward": "notify", - "requireLocalPort": true - }, - "4000": { - "label": "stream", - "onAutoForward": "silent", - "requireLocalPort": true - } - }, - - "otherPortsAttributes": { - "onAutoForward": "silent" - }, - - "onCreateCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}", - "postCreateCommand": ".devcontainer/post-create.sh", - "waitFor": "postCreateCommand", - - "customizations": { - "vscode": { - "settings": {}, - "extensions": ["EditorConfig.EditorConfig", "webben.browserslist"] - } - } -} diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml deleted file mode 100644 index 036952196..000000000 --- a/.devcontainer/docker-compose.yml +++ /dev/null @@ -1,90 +0,0 @@ -version: '3' - -services: - app: - build: - context: . - dockerfile: Dockerfile - volumes: - - ../..:/workspaces:cached - environment: - RAILS_ENV: development - NODE_ENV: development - BIND: 0.0.0.0 - REDIS_HOST: redis - REDIS_PORT: '6379' - DB_HOST: db - DB_USER: postgres - DB_PASS: postgres - DB_PORT: '5432' - ES_ENABLED: 'true' - ES_HOST: es - ES_PORT: '9200' - LIBRE_TRANSLATE_ENDPOINT: http://libretranslate:5000 - # Overrides default command so things don't shut down after the process ends. - command: sleep infinity - ports: - - '127.0.0.1:3000:3000' - - '127.0.0.1:3035:3035' - - '127.0.0.1:4000:4000' - networks: - - external_network - - internal_network - - db: - image: postgres:14-alpine - restart: unless-stopped - volumes: - - postgres-data:/var/lib/postgresql/data - environment: - POSTGRES_USER: postgres - POSTGRES_DB: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_HOST_AUTH_METHOD: trust - networks: - - internal_network - - redis: - image: redis:7-alpine - restart: unless-stopped - volumes: - - redis-data:/data - networks: - - internal_network - - es: - image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2 - restart: unless-stopped - environment: - ES_JAVA_OPTS: -Xms512m -Xmx512m - cluster.name: es-mastodon - discovery.type: single-node - bootstrap.memory_lock: 'true' - volumes: - - es-data:/usr/share/elasticsearch/data - networks: - - internal_network - ulimits: - memlock: - soft: -1 - hard: -1 - - libretranslate: - image: libretranslate/libretranslate:v1.3.12 - restart: unless-stopped - volumes: - - lt-data:/home/libretranslate/.local - networks: - - external_network - - internal_network - -volumes: - postgres-data: - redis-data: - es-data: - lt-data: - -networks: - external_network: - internal_network: - internal: true diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh deleted file mode 100755 index a075cc7b3..000000000 --- a/.devcontainer/post-create.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -set -e # Fail the whole script on first error - -# Fetch Ruby gem dependencies -bundle config path 'vendor/bundle' -bundle config with 'development test' -bundle install - -# Make Gemfile.lock pristine again -git checkout -- Gemfile.lock - -# Fetch Javascript dependencies -yarn --frozen-lockfile - -# [re]create, migrate, and seed the test database -RAILS_ENV=test ./bin/rails db:setup - -# [re]create, migrate, and seed the development database -RAILS_ENV=development ./bin/rails db:setup - -# Precompile assets for development -RAILS_ENV=development ./bin/rails assets:precompile - -# Precompile assets for test -RAILS_ENV=test NODE_ENV=tests ./bin/rails assets:precompile diff --git a/.devcontainer/welcome-message.txt b/.devcontainer/welcome-message.txt deleted file mode 100644 index 488cf9285..000000000 --- a/.devcontainer/welcome-message.txt +++ /dev/null @@ -1,8 +0,0 @@ -👋 Welcome to "Mastodon" in GitHub Codespaces! - -🛠️ Your environment is fully setup with all the required software. - -🔍 To explore VS Code to its fullest, search using the Command Palette (Cmd/Ctrl + Shift + P or F1). - -📝 Edit away, run your app as usual, and we'll automatically make it available for you to access. - diff --git a/.dockerignore b/.dockerignore index fedbea236..e69de29bb 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,21 +0,0 @@ -.bundle -.env -.env.* -.git -.gitattributes -.gitignore -.github -public/system -public/assets -public/packs -node_modules -neo4j -vendor/bundle -.DS_Store -*.swp -*~ -postgres -postgres14 -redis -elasticsearch -chart diff --git a/.env.production.sample b/.env.production.sample deleted file mode 100644 index 7bcce0f7e..000000000 --- a/.env.production.sample +++ /dev/null @@ -1,303 +0,0 @@ -# This is a sample configuration file. You can generate your configuration -# with the `rake mastodon:setup` interactive setup wizard, but to customize -# your setup even further, you'll need to edit it manually. This sample does -# not demonstrate all available configuration options. Please look at -# https://docs.joinmastodon.org/admin/config/ for the full documentation. - -# Note that this file accepts slightly different syntax depending on whether -# you are using `docker-compose` or not. In particular, if you use -# `docker-compose`, the value of each declared variable will be taken verbatim, -# including surrounding quotes. -# See: https://github.com/mastodon/mastodon/issues/16895 - -# Federation -# ---------- -# This identifies your server and cannot be changed safely later -# ---------- -LOCAL_DOMAIN=example.com - -# Use this only if you need to run mastodon on a different domain than the one used for federation. -# You can read more about this option on https://docs.joinmastodon.org/admin/config/#web-domain -# DO *NOT* USE THIS UNLESS YOU KNOW *EXACTLY* WHAT YOU ARE DOING. -# WEB_DOMAIN=mastodon.example.com - -# Use this if you want to have several aliases handler@example1.com -# handler@example2.com etc. for the same user. LOCAL_DOMAIN should not -# be added. Comma separated values -# ALTERNATE_DOMAINS=example1.com,example2.com - -# Use HTTP proxy for outgoing request (optional) -# http_proxy=http://gateway.local:8118 -# Access control for hidden service. -# ALLOW_ACCESS_TO_HIDDEN_SERVICE=true - -# Authorized fetch mode (optional) -# Require remote servers to authentify when fetching toots, see -# https://docs.joinmastodon.org/admin/config/#authorized_fetch -# AUTHORIZED_FETCH=true - -# Limited federation mode (optional) -# Only allow federation with specific domains, see -# https://docs.joinmastodon.org/admin/config/#whitelist_mode -# LIMITED_FEDERATION_MODE=true - -# Redis -# ----- -REDIS_HOST=localhost -REDIS_PORT=6379 - - -# PostgreSQL -# ---------- -DB_HOST=/var/run/postgresql -DB_USER=mastodon -DB_NAME=mastodon_production -DB_PASS= -DB_PORT=5432 - - -# Elasticsearch (optional) -# ------------------------ -#ES_ENABLED=true -#ES_HOST=localhost -#ES_PORT=9200 -# Authentication for ES (optional) -#ES_USER=elastic -#ES_PASS=password - - -# Secrets -# ------- -# Generate each with the `RAILS_ENV=production bundle exec rake secret` task (`docker-compose run --rm web bundle exec rake secret` if you use docker compose) -# ------- -SECRET_KEY_BASE= -OTP_SECRET= - - -# Web Push -# -------- -# Generate with `rake mastodon:webpush:generate_vapid_key` (first is the private key, second is the public one) -# You should only generate this once per instance. If you later decide to change it, all push subscription will -# be invalidated, requiring the users to access the website again to resubscribe. -# -------- -VAPID_PRIVATE_KEY= -VAPID_PUBLIC_KEY= - - -# Registrations -# ------------- - -# Single user mode will disable registrations and redirect frontpage to the first profile -# SINGLE_USER_MODE=true - -# Prevent registrations with following e-mail domains -# EMAIL_DOMAIN_DENYLIST=example1.com|example2.de|etc - -# Only allow registrations with the following e-mail domains -# EMAIL_DOMAIN_ALLOWLIST=example1.com|example2.de|etc - -#TODO move this -# Optionally change default language -# DEFAULT_LOCALE=de - - -# Sending mail -# ------------ -SMTP_SERVER= -SMTP_PORT=587 -SMTP_LOGIN= -SMTP_PASSWORD= -SMTP_FROM_ADDRESS=notifications@example.com - - -# File storage (optional) -# ----------------------- -# The attachment host must allow cross origin request from WEB_DOMAIN or -# LOCAL_DOMAIN if WEB_DOMAIN is not set. For example, the server may have the -# following header field: -# Access-Control-Allow-Origin: https://192.168.1.123:9000/ -# ----------------------- -#S3_ENABLED=true -#S3_BUCKET=files.example.com -#AWS_ACCESS_KEY_ID= -#AWS_SECRET_ACCESS_KEY= -#S3_ALIAS_HOST=files.example.com - -# Swift (optional) -# The attachment host must allow cross origin request - see the description -# above. -# SWIFT_ENABLED=true -# SWIFT_USERNAME= -# For Keystone V3, the value for SWIFT_TENANT should be the project name -# SWIFT_TENANT= -# SWIFT_PASSWORD= -# Some OpenStack V3 providers require PROJECT_ID (optional) -# SWIFT_PROJECT_ID= -# Keystone V2 and V3 URLs are supported. Use a V3 URL if possible to avoid -# issues with token rate-limiting during high load. -# SWIFT_AUTH_URL= -# SWIFT_CONTAINER= -# SWIFT_OBJECT_URL= -# SWIFT_REGION= -# Defaults to 'default' -# SWIFT_DOMAIN_NAME= -# Defaults to 60 seconds. Set to 0 to disable -# SWIFT_CACHE_TTL= - -# Optional asset host for multi-server setups -# The asset host must allow cross origin request from WEB_DOMAIN or LOCAL_DOMAIN -# if WEB_DOMAIN is not set. For example, the server may have the -# following header field: -# Access-Control-Allow-Origin: https://example.com/ -# CDN_HOST=https://assets.example.com - -# Optional list of hosts that are allowed to serve media for your instance -# This is useful if you include external media in your custom CSS or about page, -# or if your data storage provider makes use of redirects to other domains. -# EXTRA_DATA_HOSTS=https://data.example1.com|https://data.example2.com - -# Optional alias for S3 (e.g. to serve files on a custom domain, possibly using Cloudfront or Cloudflare) -# S3_ALIAS_HOST= - -# Streaming API integration -# STREAMING_API_BASE_URL= - - -# External authentication (optional) -# ---------------------------------- -# LDAP authentication (optional) -# LDAP_ENABLED=true -# LDAP_HOST=localhost -# LDAP_PORT=389 -# LDAP_METHOD=simple_tls -# LDAP_BASE= -# LDAP_BIND_DN= -# LDAP_PASSWORD= -# LDAP_UID=cn -# LDAP_MAIL=mail -# LDAP_SEARCH_FILTER=(|(%{uid}=%{email})(%{mail}=%{email})) -# LDAP_UID_CONVERSION_ENABLED=true -# LDAP_UID_CONVERSION_SEARCH=., - -# LDAP_UID_CONVERSION_REPLACE=_ - -# PAM authentication (optional) -# PAM authentication uses for the email generation the "email" pam variable -# and optional as fallback PAM_DEFAULT_SUFFIX -# The pam environment variable "email" is provided by: -# https://github.com/devkral/pam_email_extractor -# PAM_ENABLED=true -# Fallback email domain for email address generation (LOCAL_DOMAIN by default) -# PAM_EMAIL_DOMAIN=example.com -# Name of the pam service (pam "auth" section is evaluated) -# PAM_DEFAULT_SERVICE=rpam -# Name of the pam service used for checking if an user can register (pam "account" section is evaluated) (nil (disabled) by default) -# PAM_CONTROLLED_SERVICE=rpam - -# Global OAuth settings (optional) : -# If you have only one strategy, you may want to enable this -# OAUTH_REDIRECT_AT_SIGN_IN=true - -# Optional CAS authentication (cf. omniauth-cas) : -# CAS_ENABLED=true -# CAS_URL=https://sso.myserver.com/ -# CAS_HOST=sso.myserver.com/ -# CAS_PORT=443 -# CAS_SSL=true -# CAS_VALIDATE_URL= -# CAS_CALLBACK_URL= -# CAS_LOGOUT_URL= -# CAS_LOGIN_URL= -# CAS_UID_FIELD='user' -# CAS_CA_PATH= -# CAS_DISABLE_SSL_VERIFICATION=false -# CAS_UID_KEY='user' -# CAS_NAME_KEY='name' -# CAS_EMAIL_KEY='email' -# CAS_NICKNAME_KEY='nickname' -# CAS_FIRST_NAME_KEY='firstname' -# CAS_LAST_NAME_KEY='lastname' -# CAS_LOCATION_KEY='location' -# CAS_IMAGE_KEY='image' -# CAS_PHONE_KEY='phone' - -# Optional SAML authentication (cf. omniauth-saml) -# SAML_ENABLED=true -# SAML_ACS_URL=http://localhost:3000/auth/auth/saml/callback -# SAML_ISSUER=https://example.com -# SAML_IDP_SSO_TARGET_URL=https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO -# SAML_IDP_CERT= -# SAML_IDP_CERT_FINGERPRINT= -# SAML_NAME_IDENTIFIER_FORMAT= -# SAML_CERT= -# SAML_PRIVATE_KEY= -# SAML_SECURITY_WANT_ASSERTION_SIGNED=true -# SAML_SECURITY_WANT_ASSERTION_ENCRYPTED=true -# SAML_SECURITY_ASSUME_EMAIL_IS_VERIFIED=true -# SAML_ATTRIBUTES_STATEMENTS_UID="urn:oid:0.9.2342.19200300.100.1.1" -# SAML_ATTRIBUTES_STATEMENTS_EMAIL="urn:oid:1.3.6.1.4.1.5923.1.1.1.6" -# SAML_ATTRIBUTES_STATEMENTS_FULL_NAME="urn:oid:2.16.840.1.113730.3.1.241" -# SAML_ATTRIBUTES_STATEMENTS_FIRST_NAME="urn:oid:2.5.4.42" -# SAML_ATTRIBUTES_STATEMENTS_LAST_NAME="urn:oid:2.5.4.4" -# SAML_UID_ATTRIBUTE="urn:oid:0.9.2342.19200300.100.1.1" -# SAML_ATTRIBUTES_STATEMENTS_VERIFIED= -# SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL= - - -# Custom settings -# --------------- -# Various ways to customize Mastodon's behavior -# --------------- - -# Maximum allowed character count -MAX_TOOT_CHARS=500 - -# Maximum number of pinned posts -MAX_PINNED_TOOTS=5 - -# Maximum allowed bio characters -MAX_BIO_CHARS=500 - -# Maximim number of profile fields allowed -MAX_PROFILE_FIELDS=4 - -# Maximum allowed display name characters -MAX_DISPLAY_NAME_CHARS=30 - -# Maximum allowed poll options -MAX_POLL_OPTIONS=5 - -# Maximum allowed poll option characters -MAX_POLL_OPTION_CHARS=100 - -# Maximum image and video/audio upload sizes -# Units are in bytes -# 1048576 bytes equals 1 megabyte -# MAX_IMAGE_SIZE=8388608 -# MAX_VIDEO_SIZE=41943040 - -# Maximum search results to display -# Only relevant when elasticsearch is installed -# MAX_SEARCH_RESULTS=20 - -# Maximum hashtags to display -# Customize the number of hashtags shown in 'Explore' -# MAX_TRENDING_TAGS=10 - -# Maximum custom emoji file sizes -# If undefined or smaller than MAX_EMOJI_SIZE, the value -# of MAX_EMOJI_SIZE will be used for MAX_REMOTE_EMOJI_SIZE -# Units are in bytes -# MAX_EMOJI_SIZE=262144 -# MAX_REMOTE_EMOJI_SIZE=262144 - -# Optional hCaptcha support -# HCAPTCHA_SECRET_KEY= -# HCAPTCHA_SITE_KEY= - -# IP and session retention -# ----------------------- -# Make sure to modify the scheduling of ip_cleanup_scheduler in config/sidekiq.yml -# to be less than daily if you lower IP_RETENTION_PERIOD below two days (172800). -# ----------------------- -IP_RETENTION_PERIOD=31556952 -SESSION_RETENTION_PERIOD=31556952 diff --git a/.env.vagrant b/.env.vagrant deleted file mode 100644 index 69c1bf1fb..000000000 --- a/.env.vagrant +++ /dev/null @@ -1,8 +0,0 @@ -VAGRANT=true -LOCAL_DOMAIN=mastodon.local -BIND=0.0.0.0 -DB_HOST=/var/run/postgresql/ - -ES_ENABLED=true -ES_HOST=localhost -ES_PORT=9200 \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index be750a5e4..000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,3 +0,0 @@ -patreon: mastodon -open_collective: mastodon -custom: https://sponsor.joinmastodon.org diff --git a/.github/renovate.json5 b/.github/renovate.json5 deleted file mode 100644 index 879a564e1..000000000 --- a/.github/renovate.json5 +++ /dev/null @@ -1,124 +0,0 @@ -{ - $schema: 'https://docs.renovatebot.com/renovate-schema.json', - extends: [ - 'config:recommended', - ':labels(dependencies)', - ':maintainLockFilesMonthly', // update non-direct dependencies monthly - ':prConcurrentLimitNone', // Remove limit for open PRs at any time. - ':prHourlyLimit2', // Rate limit PR creation to a maximum of two per hour. - ], - minimumReleaseAge: '3', // Wait 3 days after the package has been published before upgrading it - // packageRules order is important, they are applied from top to bottom and are merged, - // meaning the most important ones must be at the bottom, for example grouping rules - // If we do not want a package to be grouped with others, we need to set its groupName - // to `null` after any other rule set it to something. - dependencyDashboardHeader: 'This issue lists Renovate updates and detected dependencies. Read the [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) docs to learn more. Before approving any upgrade: read the description and comments in the [`renovate.json5` file](https://github.com/mastodon/mastodon/blob/main/.github/renovate.json5).', - packageRules: [ - { - // Require Dependency Dashboard Approval for major version bumps of these node packages - matchManagers: ['npm'], - matchPackageNames: [ - 'tesseract.js', // Requires code changes - 'react-hotkeys', // Requires code changes - - // Requires Webpacker upgrade or replacement - '@types/webpack', - 'babel-loader', - 'compression-webpack-plugin', - 'css-loader', - 'imports-loader', - 'mini-css-extract-plugin', - 'postcss-loader', - 'sass-loader', - 'terser-webpack-plugin', - 'webpack', - 'webpack-assets-manifest', - 'webpack-bundle-analyzer', - 'webpack-dev-server', - 'webpack-cli', - - // react-router: Requires manual upgrade - 'history', - 'react-router-dom', - ], - matchUpdateTypes: ['major'], - dependencyDashboardApproval: true, - }, - { - // Require Dependency Dashboard Approval for major version bumps of these Ruby packages - matchManagers: ['bundler'], - matchPackageNames: [ - 'rack', // Needs to be synced with Rails version - 'sprockets', // Requires manual upgrade https://github.com/rails/sprockets/blob/master/UPGRADING.md#guide-to-upgrading-from-sprockets-3x-to-4x - 'strong_migrations', // Requires manual upgrade - 'sidekiq', // Requires manual upgrade - 'sidekiq-unique-jobs', // Requires manual upgrades and sync with Sidekiq version - 'redis', // Requires manual upgrade and sync with Sidekiq version - ], - matchUpdateTypes: ['major'], - dependencyDashboardApproval: true, - }, - { - // Update Github Actions and Docker images weekly - matchManagers: ['github-actions', 'dockerfile', 'docker-compose'], - extends: ['schedule:weekly'], - }, - { - // Require Dependency Dashboard Approval for major & minor bumps for the ruby image, this needs to be synced with .ruby-version - matchManagers: ['dockerfile'], - matchPackageNames: ['moritzheiber/ruby-jemalloc'], - matchUpdateTypes: ['minor', 'major'], - dependencyDashboardApproval: true, - }, - { - // Require Dependency Dashboard Approval for major bumps for the node image, this needs to be synced with .nvmrc - matchManagers: ['dockerfile'], - matchPackageNames: ['node'], - matchUpdateTypes: ['major'], - dependencyDashboardApproval: true, - }, - { - // Require Dependency Dashboard Approval for major postgres bumps in the docker-compose file, as those break dev environments - matchManagers: ['docker-compose'], - matchPackageNames: ['postgres'], - matchUpdateTypes: ['major'], - dependencyDashboardApproval: true, - }, - { - // Update devDependencies every week, with one grouped PR - matchDepTypes: 'devDependencies', - matchUpdateTypes: ['patch', 'minor'], - groupName: 'devDependencies (non-major)', - extends: ['schedule:weekly'], - }, - { - // Group all eslint-related packages with `eslint` in the same PR - matchManagers: ['npm'], - matchPackageNames: ['eslint'], - matchPackagePrefixes: ['eslint-', '@typescript-eslint/'], - matchUpdateTypes: ['patch', 'minor'], - groupName: 'eslint (non-major)', - }, - { - // Update @types/* packages every week, with one grouped PR - matchPackagePrefixes: '@types/', - matchUpdateTypes: ['patch', 'minor'], - groupName: 'DefinitelyTyped types (non-major)', - extends: ['schedule:weekly'], - addLabels: ['typescript'], - }, - { - // We want those packages to always have their own PR - matchManagers: ['npm'], - matchPackageNames: [ - 'typescript', // Typescript has code-impacting changes in minor versions - ], - groupName: null, // We dont want them to belong to any group - }, - // Add labels depending on package manager - { matchManagers: ['npm', 'nvm'], addLabels: ['javascript'] }, - { matchManagers: ['bundler', 'ruby-version'], addLabels: ['ruby'] }, - { matchManagers: ['docker-compose', 'dockerfile'], addLabels: ['docker'] }, - { matchManagers: ['github-actions'], addLabels: ['github_actions'] }, - ], -} diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index 6601ef8c0..000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,10 +0,0 @@ -daysUntilStale: 120 -daysUntilClose: 7 -exemptLabels: - - security -staleLabel: wontfix -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. -only: pulls diff --git a/.github/stylelint-matcher.json b/.github/stylelint-matcher.json deleted file mode 100644 index cdfd4086b..000000000 --- a/.github/stylelint-matcher.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "problemMatcher": [ - { - "owner": "stylelint", - "pattern": [ - { - "regexp": "^([^\\s].*)$", - "file": 1 - }, - { - "regexp": "^\\s+((\\d+):(\\d+))?\\s+(✖|×)\\s+(.*)\\s{2,}(.*)$", - "line": 2, - "column": 3, - "message": 5, - "code": 6, - "loop": true - } - ] - } - ] -} diff --git a/.github/workflows/build-container-image.yml b/.github/workflows/build-container-image.yml deleted file mode 100644 index 29868c72f..000000000 --- a/.github/workflows/build-container-image.yml +++ /dev/null @@ -1,99 +0,0 @@ -on: - workflow_call: - inputs: - platforms: - required: true - type: string - cache: - type: boolean - default: true - use_native_arm64_builder: - type: boolean - push_to_images: - type: string - version_prerelease: - type: string - version_metadata: - type: string - flavor: - type: string - tags: - type: string - labels: - type: string - -jobs: - build-image: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - uses: docker/setup-qemu-action@v3 - if: contains(inputs.platforms, 'linux/arm64') && !inputs.use_native_arm64_builder - - - uses: docker/setup-buildx-action@v3 - id: buildx - if: ${{ !(inputs.use_native_arm64_builder && contains(inputs.platforms, 'linux/arm64')) }} - - - name: Start a local Docker Builder - if: inputs.use_native_arm64_builder && contains(inputs.platforms, 'linux/arm64') - run: | - docker run --rm -d --name buildkitd -p 1234:1234 --privileged moby/buildkit:latest --addr tcp://0.0.0.0:1234 - - - uses: docker/setup-buildx-action@v3 - id: buildx-native - if: inputs.use_native_arm64_builder && contains(inputs.platforms, 'linux/arm64') - with: - driver: remote - endpoint: tcp://localhost:1234 - platforms: linux/amd64 - append: | - - endpoint: tcp://${{ vars.DOCKER_BUILDER_HETZNER_ARM64_01_HOST }}:13865 - platforms: linux/arm64 - name: mastodon-docker-builder-arm64-01 - driver-opts: - - servername=mastodon-docker-builder-arm64-01 - env: - BUILDER_NODE_1_AUTH_TLS_CACERT: ${{ secrets.DOCKER_BUILDER_HETZNER_ARM64_01_CACERT }} - BUILDER_NODE_1_AUTH_TLS_CERT: ${{ secrets.DOCKER_BUILDER_HETZNER_ARM64_01_CERT }} - BUILDER_NODE_1_AUTH_TLS_KEY: ${{ secrets.DOCKER_BUILDER_HETZNER_ARM64_01_KEY }} - - - name: Log in to Docker Hub - if: contains(inputs.push_to_images, 'tootsuite') - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Log in to the Github Container registry - if: contains(inputs.push_to_images, 'ghcr.io') - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - uses: docker/metadata-action@v5 - id: meta - if: ${{ inputs.push_to_images != '' }} - with: - images: ${{ inputs.push_to_images }} - flavor: ${{ inputs.flavor }} - tags: ${{ inputs.tags }} - labels: ${{ inputs.labels }} - - - uses: docker/build-push-action@v5 - with: - context: . - build-args: | - MASTODON_VERSION_PRERELEASE=${{ inputs.version_prerelease }} - MASTODON_VERSION_METADATA=${{ inputs.version_metadata }} - platforms: ${{ inputs.platforms }} - provenance: false - builder: ${{ steps.buildx.outputs.name || steps.buildx-native.outputs.name }} - push: ${{ inputs.push_to_images != '' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: ${{ inputs.cache && 'type=gha' || '' }} - cache-to: ${{ inputs.cache && 'type=gha,mode=max' || '' }} diff --git a/.github/workflows/build-nightly.yml b/.github/workflows/build-nightly.yml deleted file mode 100644 index d2c3eea19..000000000 --- a/.github/workflows/build-nightly.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Build nightly container image -on: - workflow_dispatch: - schedule: - - cron: '0 2 * * *' # run at 2 AM UTC - -permissions: - contents: read - packages: write - -jobs: - compute-suffix: - runs-on: ubuntu-latest - steps: - - id: version_vars - env: - TZ: Etc/UTC - run: | - echo mastodon_version_prerelease=nightly.$(date +'%Y-%m-%d')>> $GITHUB_OUTPUT - outputs: - prerelease: ${{ steps.version_vars.outputs.mastodon_version_prerelease }} - - build-image: - needs: compute-suffix - uses: ./.github/workflows/build-container-image.yml - with: - platforms: linux/amd64,linux/arm64 - use_native_arm64_builder: false - cache: false - push_to_images: | - ghcr.io/${{ github.repository_owner }}/mastodon - version_prerelease: ${{ needs.compute-suffix.outputs.prerelease }} - labels: | - org.opencontainers.image.description=Nightly build image used for testing purposes - flavor: | - latest=true - tags: | - type=raw,value=edge - type=raw,value=nightly - type=schedule,pattern=${{ needs.compute-suffix.outputs.prerelease }} - secrets: inherit diff --git a/.github/workflows/build-push-pr.yml b/.github/workflows/build-push-pr.yml deleted file mode 100644 index b5f6cbc74..000000000 --- a/.github/workflows/build-push-pr.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Build container image for PR -on: - pull_request: - types: [labeled, synchronize, reopened, ready_for_review, opened] - -permissions: - contents: read - packages: write - -jobs: - compute-suffix: - runs-on: ubuntu-latest - # This is only allowed to run if: - # - the PR branch is in the `mastodon/mastodon` repository - # - the PR is not a draft - # - the PR has the "build-image" label - if: ${{ github.event.pull_request.head.repo.full_name == github.repository && !github.event.pull_request.draft && contains(github.event.pull_request.labels.*.name, 'build-image') }} - steps: - # Repository needs to be cloned so `git rev-parse` below works - - name: Clone repository - uses: actions/checkout@v4 - - id: version_vars - run: | - echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT - outputs: - metadata: ${{ steps.version_vars.outputs.mastodon_version_metadata }} - - build-image: - needs: compute-suffix - uses: ./.github/workflows/build-container-image.yml - with: - platforms: linux/amd64,linux/arm64 - use_native_arm64_builder: false - push_to_images: | - ghcr.io/${{ github.repository_owner }}/mastodon - version_metadata: ${{ needs.compute-suffix.outputs.metadata }} - flavor: | - latest=auto - tags: | - type=ref,event=pr - secrets: inherit diff --git a/.github/workflows/build-releases.yml b/.github/workflows/build-releases.yml deleted file mode 100644 index 2b7e7aaa4..000000000 --- a/.github/workflows/build-releases.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Build container release images -on: - push: - tags: - - '*' - -permissions: - contents: read - packages: write - -jobs: - build-image: - uses: ./.github/workflows/build-container-image.yml - with: - platforms: linux/amd64,linux/arm64 - use_native_arm64_builder: false - push_to_images: | - ghcr.io/${{ github.repository_owner }}/mastodon - # Do not use cache when building releases, so apt update is always ran and the release always contain the latest packages - cache: false - # Only tag with latest when ran against the latest stable branch - # This needs to be updated after each minor version release - flavor: | - latest=${{ startsWith(github.ref, 'refs/tags/v4.2.') }} - tags: | - type=pep440,pattern={{raw}} - type=pep440,pattern=v{{major}}.{{minor}} - secrets: inherit diff --git a/.github/workflows/bundler-audit.yml b/.github/workflows/bundler-audit.yml deleted file mode 100644 index bfb93a36c..000000000 --- a/.github/workflows/bundler-audit.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Bundler Audit -on: - push: - branches-ignore: - - 'dependabot/**' - paths: - - 'Gemfile*' - - '.ruby-version' - - '.bundler-audit.yml' - - '.github/workflows/bundler-audit.yml' - - pull_request: - paths: - - 'Gemfile*' - - '.ruby-version' - - '.bundler-audit.yml' - - '.github/workflows/bundler-audit.yml' - - schedule: - - cron: '0 5 * * 1' - -jobs: - security: - runs-on: ubuntu-latest - - steps: - - name: Clone repository - uses: actions/checkout@v4 - - - name: Install native Ruby dependencies - run: sudo apt-get install -y libicu-dev libidn11-dev - - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: .ruby-version - bundler-cache: true - - - name: Run bundler-audit - run: bundle exec bundler-audit diff --git a/.github/workflows/check-i18n.yml b/.github/workflows/check-i18n.yml deleted file mode 100644 index 39cf32ddc..000000000 --- a/.github/workflows/check-i18n.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Check i18n - -on: - push: - branches: [main] - pull_request: - branches: [main] - -env: - RAILS_ENV: test - -permissions: - contents: read - -jobs: - check-i18n: - runs-on: ubuntu-22.04 - - steps: - - uses: actions/checkout@v4 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libicu-dev libidn11-dev - - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: .ruby-version - bundler-cache: true - - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - cache: yarn - node-version-file: '.nvmrc' - - - name: Install all yarn packages - run: yarn --frozen-lockfile - - - name: Check for missing strings in English JSON - run: | - yarn i18n:extract --throws - git diff --exit-code - - - name: Check locale file normalization - run: bundle exec i18n-tasks check-normalized - - - name: Check for unused strings - run: bundle exec i18n-tasks unused - - - name: Check for missing strings in English YML - run: | - bundle exec i18n-tasks add-missing -l en - git diff --exit-code - - - name: Check for wrong string interpolations - run: bundle exec i18n-tasks check-consistent-interpolations - - - name: Check that all required locale files exist - run: bundle exec rake repo:check_locales_files diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 3b40c3fd0..000000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: 'CodeQL' - -on: - push: - branches: ['main'] - pull_request: - # The branches below must be a subset of the branches above - branches: ['main'] - schedule: - - cron: '22 6 * * 1' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: ['javascript', 'ruby'] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - with: - category: '/language:${{matrix.language}}' diff --git a/.github/workflows/crowdin-download.yml b/.github/workflows/crowdin-download.yml deleted file mode 100644 index dc6fd874d..000000000 --- a/.github/workflows/crowdin-download.yml +++ /dev/null @@ -1,77 +0,0 @@ -name: Crowdin / Download translations -on: - schedule: - - cron: '17 4 * * *' # Every day - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -jobs: - download-translations: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Increase Git http.postBuffer - # This is needed due to a bug in Ubuntu's cURL version? - # See https://github.com/orgs/community/discussions/55820 - run: | - git config --global http.version HTTP/1.1 - git config --global http.postBuffer 157286400 - - # Download the translation files from Crowdin - - name: crowdin action - uses: crowdin/github-action@v1 - with: - config: crowdin-glitch.yml - upload_sources: false - upload_translations: false - download_translations: true - crowdin_branch_name: main - push_translations: false - create_pull_request: false - env: - CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - - # As the files are extracted from a Docker container, they belong to root:root - # We need to fix this before the next steps - - name: Fix file permissions - run: sudo chown -R runner:docker . - - # This is needed to run the normalize step - - name: Install native Ruby dependencies - run: sudo apt-get install -y libicu-dev libidn11-dev - - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: .ruby-version - bundler-cache: true - - - name: Run i18n normalize task - run: bundle exec i18n-tasks normalize - - # Create or update the pull request - - name: Create Pull Request - uses: peter-evans/create-pull-request@v5.0.2 - with: - commit-message: 'New Crowdin translations' - title: 'New Crowdin Translations (automated)' - author: 'GitHub Actions ' - body: | - New Crowdin translations, automated with Github Actions - - See `.github/workflows/crowdin-download.yml` - - This PR will be updated every day with new translations. - - Due to a limitation in Github Actions, checks are not running on this PR without manual action. - If you want to run the checks, then close and re-open it. - branch: i18n/crowdin/translations - base: main - labels: i18n diff --git a/.github/workflows/crowdin-upload.yml b/.github/workflows/crowdin-upload.yml deleted file mode 100644 index 75d66c2a6..000000000 --- a/.github/workflows/crowdin-upload.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Crowdin / Upload translations - -on: - push: - branches: - - main - paths: - - crowdin.yml - - app/javascript/mastodon/locales/en.json - - config/locales/en.yml - - config/locales/simple_form.en.yml - - config/locales/activerecord.en.yml - - config/locales/devise.en.yml - - config/locales/doorkeeper.en.yml - - .github/workflows/crowdin-upload.yml - -jobs: - upload-translations: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: crowdin action - uses: crowdin/github-action@v1 - with: - config: crowdin-glitch.yml - upload_sources: true - upload_translations: false - download_translations: false - crowdin_branch_name: main - - env: - CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} diff --git a/.github/workflows/haml-lint-problem-matcher.json b/.github/workflows/haml-lint-problem-matcher.json deleted file mode 100644 index 3523ea295..000000000 --- a/.github/workflows/haml-lint-problem-matcher.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "problemMatcher": [ - { - "owner": "haml-lint", - "severity": "warning", - "pattern": [ - { - "regexp": "^(.*):(\\d+)\\s\\[W]\\s(.*):\\s(.*)$", - "file": 1, - "line": 2, - "code": 3, - "message": 4 - } - ] - } - ] -} diff --git a/.github/workflows/lint-css.yml b/.github/workflows/lint-css.yml deleted file mode 100644 index bd775dba2..000000000 --- a/.github/workflows/lint-css.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: CSS Linting -on: - push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' - paths: - - 'package.json' - - 'yarn.lock' - - '.nvmrc' - - '.prettier*' - - 'stylelint.config.js' - - '**/*.css' - - '**/*.scss' - - '.github/workflows/lint-css.yml' - - '.github/stylelint-matcher.json' - - pull_request: - paths: - - 'package.json' - - 'yarn.lock' - - '.nvmrc' - - '.prettier*' - - 'stylelint.config.js' - - '**/*.css' - - '**/*.scss' - - '.github/workflows/lint-css.yml' - - '.github/stylelint-matcher.json' - -jobs: - lint: - runs-on: ubuntu-latest - - steps: - - name: Clone repository - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - cache: yarn - node-version-file: '.nvmrc' - - - name: Install all yarn packages - run: yarn --frozen-lockfile - - - uses: xt0rted/stylelint-problem-matcher@v1 - - - run: echo "::add-matcher::.github/stylelint-matcher.json" - - - name: Stylelint - run: yarn lint:sass diff --git a/.github/workflows/lint-haml.yml b/.github/workflows/lint-haml.yml deleted file mode 100644 index ca9bd66a4..000000000 --- a/.github/workflows/lint-haml.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Haml Linting -on: - push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' - paths: - - '.github/workflows/haml-lint-problem-matcher.json' - - '.github/workflows/lint-haml.yml' - - '.haml-lint*.yml' - - '.rubocop*.yml' - - '.ruby-version' - - '**/*.haml' - - 'Gemfile*' - - pull_request: - paths: - - '.github/workflows/haml-lint-problem-matcher.json' - - '.github/workflows/lint-haml.yml' - - '.haml-lint*.yml' - - '.rubocop*.yml' - - '.ruby-version' - - '**/*.haml' - - 'Gemfile*' - -jobs: - lint: - runs-on: ubuntu-latest - steps: - - name: Clone repository - uses: actions/checkout@v4 - - - name: Install native Ruby dependencies - run: | - sudo apt-get update - sudo apt-get install -y libicu-dev libidn11-dev - - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: .ruby-version - bundler-cache: true - - - name: Run haml-lint - run: | - echo "::add-matcher::.github/workflows/haml-lint-problem-matcher.json" - bundle exec haml-lint diff --git a/.github/workflows/lint-js.yml b/.github/workflows/lint-js.yml deleted file mode 100644 index 67d28589c..000000000 --- a/.github/workflows/lint-js.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: JavaScript Linting -on: - push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' - paths: - - 'package.json' - - 'yarn.lock' - - 'tsconfig.json' - - '.nvmrc' - - '.prettier*' - - '.eslint*' - - '**/*.js' - - '**/*.jsx' - - '**/*.ts' - - '**/*.tsx' - - '.github/workflows/lint-js.yml' - - pull_request: - paths: - - 'package.json' - - 'yarn.lock' - - 'tsconfig.json' - - '.nvmrc' - - '.prettier*' - - '.eslint*' - - '**/*.js' - - '**/*.jsx' - - '**/*.ts' - - '**/*.tsx' - - '.github/workflows/lint-js.yml' - -jobs: - lint: - runs-on: ubuntu-latest - - steps: - - name: Clone repository - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - cache: yarn - node-version-file: '.nvmrc' - - - name: Install all yarn packages - run: yarn --frozen-lockfile - - - name: ESLint - run: yarn lint:js --max-warnings 0 - - - name: Typecheck - run: yarn typecheck diff --git a/.github/workflows/lint-json.yml b/.github/workflows/lint-json.yml deleted file mode 100644 index 1d98c5267..000000000 --- a/.github/workflows/lint-json.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: JSON Linting -on: - push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' - paths: - - 'package.json' - - 'yarn.lock' - - '.nvmrc' - - '.prettier*' - - '**/*.json' - - '.github/workflows/lint-json.yml' - - '!app/javascript/mastodon/locales/*.json' - - pull_request: - paths: - - 'package.json' - - 'yarn.lock' - - '.nvmrc' - - '.prettier*' - - '**/*.json' - - '.github/workflows/lint-json.yml' - - '!app/javascript/mastodon/locales/*.json' - -jobs: - lint: - runs-on: ubuntu-latest - - steps: - - name: Clone repository - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - cache: yarn - node-version-file: '.nvmrc' - - - name: Install all yarn packages - run: yarn --frozen-lockfile - - - name: Prettier - run: yarn lint:json diff --git a/.github/workflows/lint-md.yml b/.github/workflows/lint-md.yml deleted file mode 100644 index 1b3f92c97..000000000 --- a/.github/workflows/lint-md.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Markdown Linting -on: - push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' - paths: - - '.github/workflows/lint-md.yml' - - '.nvmrc' - - '.prettier*' - - '**/*.md' - - '!AUTHORS.md' - - 'package.json' - - 'yarn.lock' - - pull_request: - paths: - - '.github/workflows/lint-md.yml' - - '.nvmrc' - - '.prettier*' - - '**/*.md' - - '!AUTHORS.md' - - 'package.json' - - 'yarn.lock' - -jobs: - lint: - runs-on: ubuntu-latest - - steps: - - name: Clone repository - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - cache: yarn - node-version-file: '.nvmrc' - - - name: Install all yarn packages - run: yarn --frozen-lockfile - - - name: Prettier - run: yarn lint:md diff --git a/.github/workflows/lint-ruby.yml b/.github/workflows/lint-ruby.yml deleted file mode 100644 index 92882a084..000000000 --- a/.github/workflows/lint-ruby.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Ruby Linting -on: - push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' - paths: - - 'Gemfile*' - - '.rubocop*.yml' - - '.ruby-version' - - 'config/brakeman.ignore' - - '**/*.rb' - - '**/*.rake' - - '.github/workflows/lint-ruby.yml' - - pull_request: - paths: - - 'Gemfile*' - - '.rubocop*.yml' - - '.ruby-version' - - 'config/brakeman.ignore' - - '**/*.rb' - - '**/*.rake' - - '.github/workflows/lint-ruby.yml' - -jobs: - lint: - runs-on: ubuntu-latest - - steps: - - name: Clone repository - uses: actions/checkout@v4 - - - name: Install native Ruby dependencies - run: sudo apt-get install -y libicu-dev libidn11-dev - - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: .ruby-version - bundler-cache: true - - - name: Set-up RuboCop Problem Matcher - uses: r7kamura/rubocop-problem-matchers-action@v1 - - - name: Run rubocop - run: bundle exec rubocop - - - name: Run brakeman - if: always() # Run both checks, even if the first failed - run: bundle exec brakeman diff --git a/.github/workflows/lint-yml.yml b/.github/workflows/lint-yml.yml deleted file mode 100644 index e77cc9889..000000000 --- a/.github/workflows/lint-yml.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: YML Linting -on: - push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' - paths: - - 'package.json' - - 'yarn.lock' - - '.nvmrc' - - '.prettier*' - - '**/*.yaml' - - '**/*.yml' - - '.github/workflows/lint-yml.yml' - - '!config/locales/*.yml' - - pull_request: - paths: - - 'package.json' - - 'yarn.lock' - - '.nvmrc' - - '.prettier*' - - '**/*.yaml' - - '**/*.yml' - - '.github/workflows/lint-yml.yml' - - '!config/locales/*.yml' - -jobs: - lint: - runs-on: ubuntu-latest - - steps: - - name: Clone repository - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - cache: yarn - node-version-file: '.nvmrc' - - - name: Install all yarn packages - run: yarn --frozen-lockfile - - - name: Prettier - run: yarn lint:yml diff --git a/.github/workflows/rebase-needed.yml b/.github/workflows/rebase-needed.yml deleted file mode 100644 index 06d835c09..000000000 --- a/.github/workflows/rebase-needed.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: PR Needs Rebase - -on: - schedule: - - cron: '0 * * * *' - -permissions: - pull-requests: write - -jobs: - label-rebase-needed: - runs-on: ubuntu-latest - - concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - - steps: - - name: Check for merge conflicts - uses: eps1lon/actions-label-merge-conflict@releases/2.x - with: - dirtyLabel: 'rebase needed :construction:' - repoToken: '${{ secrets.GITHUB_TOKEN }}' - commentOnClean: This pull request has resolved merge conflicts and is ready for review. - commentOnDirty: This pull request has merge conflicts that must be resolved before it can be merged. - retryMax: 30 - continueOnMissingPermissions: false diff --git a/.github/workflows/test-image-build.yml b/.github/workflows/test-image-build.yml deleted file mode 100644 index 778e34177..000000000 --- a/.github/workflows/test-image-build.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Test container image build -on: - pull_request: - paths: - - .github/workflows/build-nightly.yml - - .github/workflows/build-push-pr.yml - - .github/workflows/build-releases.yml - - .github/workflows/test-image-build.yml - - Dockerfile -permissions: - contents: read - -jobs: - build-image: - concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - - uses: ./.github/workflows/build-container-image.yml - with: - platforms: linux/amd64 # Testing only on native platform so it is performant diff --git a/.github/workflows/test-js.yml b/.github/workflows/test-js.yml deleted file mode 100644 index 0ef1d9b7c..000000000 --- a/.github/workflows/test-js.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: JavaScript Testing -on: - push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' - paths: - - 'package.json' - - 'yarn.lock' - - '.nvmrc' - - '**/*.js' - - '**/*.jsx' - - '**/*.ts' - - '**/*.tsx' - - '**/*.snap' - - '.github/workflows/test-js.yml' - - pull_request: - paths: - - 'package.json' - - 'yarn.lock' - - '.nvmrc' - - '**/*.js' - - '**/*.jsx' - - '**/*.ts' - - '**/*.tsx' - - '**/*.snap' - - '.github/workflows/test-js.yml' - -jobs: - test: - runs-on: ubuntu-latest - - steps: - - name: Clone repository - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - cache: yarn - node-version-file: '.nvmrc' - - - name: Install all yarn packages - run: yarn --frozen-lockfile - - - name: Jest testing - run: yarn jest --reporters github-actions summary diff --git a/.github/workflows/test-migrations-one-step.yml b/.github/workflows/test-migrations-one-step.yml deleted file mode 100644 index 59287e88c..000000000 --- a/.github/workflows/test-migrations-one-step.yml +++ /dev/null @@ -1,111 +0,0 @@ -name: Test one step migrations -on: - push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' - pull_request: - -jobs: - pre_job: - runs-on: ubuntu-latest - - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - paths: '["Gemfile*", ".ruby-version", "**/*.rb", ".github/workflows/test-migrations-one-step.yml", "lib/tasks/tests.rake"]' - - test: - runs-on: ubuntu-latest - needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' - - strategy: - fail-fast: false - - matrix: - postgres: - - 14-alpine - - 15-alpine - - services: - postgres: - image: postgres:${{ matrix.postgres}} - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - - redis: - image: redis:7-alpine - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 6379:6379 - - env: - CONTINUOUS_INTEGRATION: true - DB_HOST: localhost - DB_USER: postgres - DB_PASS: postgres - DISABLE_SIMPLECOV: true - RAILS_ENV: test - BUNDLE_CLEAN: true - BUNDLE_FROZEN: true - BUNDLE_WITHOUT: 'development production' - BUNDLE_JOBS: 3 - BUNDLE_RETRY: 3 - - steps: - - uses: actions/checkout@v4 - - - name: Install native Ruby dependencies - run: | - sudo apt-get update - sudo apt-get install -y libicu-dev libidn11-dev - - - name: Set up bundler cache - uses: ruby/setup-ruby@v1 - with: - ruby-version: .ruby-version - bundler-cache: true - - - name: Create database - run: './bin/rails db:create' - - - name: Run migrations up to v2.0.0 - run: './bin/rails db:migrate VERSION=20171010025614' - - - name: Populate database with test data - run: './bin/rails tests:migrations:populate_v2' - - - name: Run migrations up to v2.4.0 - run: './bin/rails db:migrate VERSION=20180514140000' - - - name: Populate database with test data - run: './bin/rails tests:migrations:populate_v2_4' - - - name: Run migrations up to v2.4.3 - run: './bin/rails db:migrate VERSION=20180707154237' - - - name: Populate database with test data - run: './bin/rails tests:migrations:populate_v2_4_3' - - - name: Run all remaining migrations - run: './bin/rails db:migrate' - - - name: Check migration result - run: './bin/rails tests:migrations:check_database' diff --git a/.github/workflows/test-migrations-two-step.yml b/.github/workflows/test-migrations-two-step.yml deleted file mode 100644 index 8f3c84d8f..000000000 --- a/.github/workflows/test-migrations-two-step.yml +++ /dev/null @@ -1,119 +0,0 @@ -name: Test two step migrations -on: - push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' - pull_request: - -jobs: - pre_job: - runs-on: ubuntu-latest - - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - paths: '["Gemfile*", ".ruby-version", "**/*.rb", ".github/workflows/test-migrations-two-step.yml", "lib/tasks/tests.rake"]' - - test: - runs-on: ubuntu-latest - needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' - - strategy: - fail-fast: false - - matrix: - postgres: - - 14-alpine - - 15-alpine - - services: - postgres: - image: postgres:${{ matrix.postgres}} - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - redis: - image: redis:7-alpine - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 6379:6379 - - env: - CONTINUOUS_INTEGRATION: true - DB_HOST: localhost - DB_USER: postgres - DB_PASS: postgres - DISABLE_SIMPLECOV: true - RAILS_ENV: test - BUNDLE_CLEAN: true - BUNDLE_FROZEN: true - BUNDLE_WITHOUT: 'development production' - BUNDLE_JOBS: 3 - BUNDLE_RETRY: 3 - - steps: - - uses: actions/checkout@v4 - - - name: Install native Ruby dependencies - run: | - sudo apt-get update - sudo apt-get install -y libicu-dev libidn11-dev - - - name: Set up bundler cache - uses: ruby/setup-ruby@v1 - with: - ruby-version: .ruby-version - bundler-cache: true - - - name: Create database - run: './bin/rails db:create' - - - name: Run migrations up to v2.0.0 - run: './bin/rails db:migrate VERSION=20171010025614' - - - name: Populate database with test data - run: './bin/rails tests:migrations:populate_v2' - - - name: Run pre-deployment migrations up to v2.4.0 - run: './bin/rails db:migrate VERSION=20180514140000' - env: - SKIP_POST_DEPLOYMENT_MIGRATIONS: true - - - name: Populate database with test data - run: './bin/rails tests:migrations:populate_v2_4' - - - name: Run migrations up to v2.4.3 - run: './bin/rails db:migrate VERSION=20180707154237' - env: - SKIP_POST_DEPLOYMENT_MIGRATIONS: true - - - name: Populate database with test data - run: './bin/rails tests:migrations:populate_v2_4_3' - - - name: Run all remaining pre-deployment migrations - run: './bin/rails db:migrate' - env: - SKIP_POST_DEPLOYMENT_MIGRATIONS: true - - - name: Run all post-deployment migrations - run: './bin/rails db:migrate' - - - name: Check migration result - run: './bin/rails tests:migrations:check_database' diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml deleted file mode 100644 index 0d0215bc0..000000000 --- a/.github/workflows/test-ruby.yml +++ /dev/null @@ -1,370 +0,0 @@ -name: Ruby Testing - -on: - push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' - pull_request: - -env: - BUNDLE_CLEAN: true - BUNDLE_FROZEN: true - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - build: - runs-on: ubuntu-latest - - strategy: - fail-fast: true - matrix: - mode: - - production - - test - env: - RAILS_ENV: ${{ matrix.mode }} - BUNDLE_WITH: ${{ matrix.mode }} - OTP_SECRET: precompile_placeholder - SECRET_KEY_BASE: precompile_placeholder - - steps: - - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - cache: yarn - node-version-file: '.nvmrc' - - - name: Install native Ruby dependencies - run: | - sudo apt-get update - sudo apt-get install -y libicu-dev libidn11-dev - - - name: Set up bundler cache - uses: ruby/setup-ruby@v1 - with: - ruby-version: .ruby-version - bundler-cache: true - - - run: yarn --frozen-lockfile --production - - name: Precompile assets - # Previously had set this, but it's not supported - # export NODE_OPTIONS=--openssl-legacy-provider - run: |- - ./bin/rails assets:precompile - - - uses: actions/upload-artifact@v3 - if: matrix.mode == 'test' - with: - path: |- - ./public/assets - ./public/packs-test - name: ${{ github.sha }} - retention-days: 0 - - test: - runs-on: ubuntu-latest - - needs: - - build - - services: - postgres: - image: postgres:14-alpine - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - - redis: - image: redis:7-alpine - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 6379:6379 - - env: - DB_HOST: localhost - DB_USER: postgres - DB_PASS: postgres - DISABLE_SIMPLECOV: true - RAILS_ENV: test - ALLOW_NOPAM: true - PAM_ENABLED: true - PAM_DEFAULT_SERVICE: pam_test - PAM_CONTROLLED_SERVICE: pam_test_controlled - OIDC_ENABLED: true - OIDC_SCOPE: read - SAML_ENABLED: true - CAS_ENABLED: true - BUNDLE_WITH: 'pam_authentication test' - CI_JOBS: ${{ matrix.ci_job }}/4 - - strategy: - fail-fast: false - matrix: - ruby-version: - - '3.0' - - '3.1' - - '.ruby-version' - ci_job: - - 1 - - 2 - - 3 - - 4 - steps: - - uses: actions/checkout@v4 - - - uses: actions/download-artifact@v3 - with: - path: './public' - name: ${{ github.sha }} - - - name: Update package index - run: sudo apt-get update - - - name: Install native Ruby dependencies - run: sudo apt-get install -y libicu-dev libidn11-dev - - - name: Install additional system dependencies - run: sudo apt-get install -y ffmpeg imagemagick libpam-dev - - - name: Set up bundler cache - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby-version}} - bundler-cache: true - - - name: Load database schema - run: './bin/rails db:create db:schema:load db:seed' - - - run: bundle exec rake rspec_chunked - - test-e2e: - name: End to End testing - runs-on: ubuntu-latest - - needs: - - build - - services: - postgres: - image: postgres:14-alpine - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - - redis: - image: redis:7-alpine - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 6379:6379 - - env: - DB_HOST: localhost - DB_USER: postgres - DB_PASS: postgres - DISABLE_SIMPLECOV: true - RAILS_ENV: test - BUNDLE_WITH: test - - strategy: - fail-fast: false - matrix: - ruby-version: - - '3.0' - - '3.1' - - '.ruby-version' - - steps: - - uses: actions/checkout@v4 - - - uses: actions/download-artifact@v3 - with: - path: './public' - name: ${{ github.sha }} - - - name: Update package index - run: sudo apt-get update - - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - cache: yarn - node-version-file: '.nvmrc' - - - name: Install native Ruby dependencies - run: sudo apt-get install -y libicu-dev libidn11-dev - - - name: Install additional system dependencies - run: sudo apt-get install -y ffmpeg imagemagick - - - name: Set up bundler cache - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby-version}} - bundler-cache: true - - - run: yarn --frozen-lockfile - - - name: Load database schema - run: './bin/rails db:create db:schema:load db:seed' - - - run: bundle exec rake spec:system - - - name: Archive logs - uses: actions/upload-artifact@v3 - if: failure() - with: - name: e2e-logs-${{ matrix.ruby-version }} - path: log/ - - - name: Archive test screenshots - uses: actions/upload-artifact@v3 - if: failure() - with: - name: e2e-screenshots - path: tmp/screenshots/ - - test-search: - name: Testing search - runs-on: ubuntu-latest - - needs: - - build - - services: - postgres: - image: postgres:14-alpine - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 - - redis: - image: redis:7-alpine - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 6379:6379 - - search: - image: ${{ matrix.search-image }} - env: - discovery.type: single-node - xpack.security.enabled: false - options: >- - --health-cmd "curl http://localhost:9200/_cluster/health" - --health-interval 10s - --health-timeout 5s - --health-retries 10 - ports: - - 9200:9200 - - env: - DB_HOST: localhost - DB_USER: postgres - DB_PASS: postgres - DISABLE_SIMPLECOV: true - RAILS_ENV: test - BUNDLE_WITH: test - ES_ENABLED: true - ES_HOST: localhost - ES_PORT: 9200 - - strategy: - fail-fast: false - matrix: - ruby-version: - - '3.0' - - '3.1' - - '.ruby-version' - search-image: - - docker.elastic.co/elasticsearch/elasticsearch:7.17.13 - include: - - ruby-version: '.ruby-version' - search-image: docker.elastic.co/elasticsearch/elasticsearch:8.10.2 - - steps: - - uses: actions/checkout@v4 - - - uses: actions/download-artifact@v3 - with: - path: './public' - name: ${{ github.sha }} - - - name: Update package index - run: sudo apt-get update - - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - cache: yarn - node-version-file: '.nvmrc' - - - name: Install native Ruby dependencies - run: sudo apt-get install -y libicu-dev libidn11-dev - - - name: Install additional system dependencies - run: sudo apt-get install -y ffmpeg imagemagick - - - name: Set up bundler cache - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby-version}} - bundler-cache: true - - - run: yarn --frozen-lockfile - - - name: Load database schema - run: './bin/rails db:create db:schema:load db:seed' - - - run: bundle exec rake spec:search - - - name: Archive logs - uses: actions/upload-artifact@v3 - if: failure() - with: - name: test-search-logs-${{ matrix.ruby-version }} - path: log/ - - - name: Archive test screenshots - uses: actions/upload-artifact@v3 - if: failure() - with: - name: test-search-screenshots - path: tmp/screenshots/ diff --git a/.haml-lint.yml b/.haml-lint.yml deleted file mode 100644 index d1ed30b26..000000000 --- a/.haml-lint.yml +++ /dev/null @@ -1,14 +0,0 @@ -inherits_from: .haml-lint_todo.yml - -exclude: - - 'vendor/**/*' - - lib/templates/haml/scaffold/_form.html.haml - -require: - - ./lib/linter/haml_middle_dot.rb - -linters: - AltText: - enabled: true - MiddleDot: - enabled: true diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml deleted file mode 100644 index 69937c4c4..000000000 --- a/.haml-lint_todo.yml +++ /dev/null @@ -1,41 +0,0 @@ -# This configuration was generated by -# `haml-lint --auto-gen-config` -# on 2023-10-03 08:32:28 -0400 using Haml-Lint version 0.51.0. -# The point is for the user to remove these configuration records -# one by one as the lints are removed from the code base. -# Note that changes in the inspected code, or installation of new -# versions of Haml-Lint, may require this file to be generated again. - -linters: - # Offense count: 944 - LineLength: - enabled: false - - # Offense count: 22 - UnnecessaryStringOutput: - enabled: false - - # Offense count: 44 - RuboCop: - enabled: false - - # Offense count: 3 - ViewLength: - exclude: - - 'app/views/admin/accounts/show.html.haml' - - 'app/views/admin/reports/show.html.haml' - - 'app/views/disputes/strikes/show.html.haml' - - # Offense count: 15 - InstanceVariables: - exclude: - - 'app/views/admin/reports/_actions.html.haml' - - 'app/views/auth/registrations/_status.html.haml' - - 'app/views/auth/sessions/two_factor/_otp_authentication_form.html.haml' - - 'app/views/relationships/_account.html.haml' - - # Offense count: 2 - IdNames: - exclude: - - 'app/views/oauth/authorizations/error.html.haml' - - 'app/views/shared/_error_messages.html.haml' diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 2ee2e538b..000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,46 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual attention or advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at glitch-abuse@sitedethib.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version] - -[homepage]: https://contributor-covenant.org -[version]: https://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index a232915b6..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,87 +0,0 @@ -# Contributing to Mastodon Glitch Edition - -Thank you for your interest in contributing to the `glitch-soc` project! -Here are some guidelines, and ways you can help. - -> (This document is a bit of a work-in-progress, so please bear with us. -> If you don't see what you're looking for here, please don't hesitate to reach out!) - -## Translations - -You can submit glitch-soc-specific translations via [Crowdin](https://crowdin.com/project/glitch-soc). They are periodically merged into the codebase. - -[![Crowdin](https://badges.crowdin.net/glitch-soc/localized.svg)](https://crowdin.com/project/glitch-soc) - -## Planning - -Right now a lot of the planning for this project takes place in our development Discord, or through GitHub Issues and Projects. -We're working on ways to improve the planning structure and better solicit feedback, and if you feel like you can help in this respect, feel free to give us a holler. - -## Documentation - -The documentation for this repository is available at [`glitch-soc/docs`](https://github.com/glitch-soc/docs) (online at [glitch-soc.github.io/docs/](https://glitch-soc.github.io/docs/)). -Right now, we've mostly focused on the features that make this fork different from upstream in some manner. -Adding screenshots, improving descriptions, and so forth are all ways to help contribute to the project even if you don't know any code. - -## Frontend Development - -Check out [the documentation here](https://glitch-soc.github.io/docs/contributing/frontend/) for more information. - -## Backend Development - -See the guidelines below. - ---- - -You should also try to follow the guidelines set out in the original `CONTRIBUTING.md` from `mastodon/mastodon`, reproduced below. - -
- -# Contributing - -Thank you for considering contributing to Mastodon 🐘 - -You can contribute in the following ways: - -- Finding and reporting bugs -- Translating the Mastodon interface into various languages -- Contributing code to Mastodon by fixing bugs or implementing features -- Improving the documentation - -If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon). - -## Bug reports - -Bug reports and feature suggestions must use descriptive and concise titles and be submitted to [GitHub Issues](https://github.com/mastodon/mastodon/issues). Please use the search function to make sure that you are not submitting duplicates, and that a similar report or request has not already been resolved or rejected. - -## Translations - -You can submit translations via [Crowdin](https://crowdin.com/project/mastodon). They are periodically merged into the codebase. - -[![Crowdin](https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg)](https://crowdin.com/project/mastodon) - -## Pull requests - -**Please use clean, concise titles for your pull requests.** Unless the pull request is about refactoring code, updating dependencies or other internal tasks, assume that the person reading the pull request title is not a programmer or Mastodon developer, but instead a Mastodon user or server administrator, and **try to describe your change or fix from their perspective**. We use commit squashing, so the final commit in the main branch will carry the title of the pull request, and commits from the main branch are fed into the changelog. The changelog is separated into [keepachangelog.com categories](https://keepachangelog.com/en/1.0.0/), and while that spec does not prescribe how the entries ought to be named, for easier sorting, start your pull request titles using one of the verbs "Add", "Change", "Deprecate", "Remove", or "Fix" (present tense). - -Example: - -| Not ideal | Better | -| ------------------------------------ | ------------------------------------------------------------- | -| Fixed NoMethodError in RemovalWorker | Fix nil error when removing statuses caused by race condition | - -It is not always possible to phrase every change in such a manner, but it is desired. - -**The smaller the set of changes in the pull request is, the quicker it can be reviewed and merged.** Splitting tasks into multiple smaller pull requests is often preferable. - -**Pull requests that do not pass automated checks may not be reviewed**. In particular, you need to keep in mind: - -- Unit and integration tests (rspec, jest) -- Code style rules (rubocop, eslint) -- Normalization of locale files (i18n-tasks) - -## Documentation - -The [Mastodon documentation](https://docs.joinmastodon.org) is a statically generated site. You can [submit merge requests to mastodon/documentation](https://github.com/mastodon/documentation). - -
diff --git a/Dockerfile b/Dockerfile index 8e40091ad..9f05bffce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,105 +1,4 @@ -# syntax=docker/dockerfile:1.4 -# This needs to be bookworm-slim because the Ruby image is built on bookworm-slim -ARG NODE_VERSION="20.8-bookworm-slim" +FROM nginx:alpine -FROM ghcr.io/moritzheiber/ruby-jemalloc:3.2.2-slim as ruby -FROM node:${NODE_VERSION} as build - -COPY --link --from=ruby /opt/ruby /opt/ruby - -ENV DEBIAN_FRONTEND="noninteractive" \ - PATH="${PATH}:/opt/ruby/bin" - -SHELL ["/bin/bash", "-o", "pipefail", "-c"] - -WORKDIR /opt/mastodon -COPY Gemfile* package.json yarn.lock /opt/mastodon/ - -# hadolint ignore=DL3008 -RUN apt-get update && \ - apt-get -yq dist-upgrade && \ - apt-get install -y --no-install-recommends build-essential \ - git \ - libicu-dev \ - libidn-dev \ - libpq-dev \ - libjemalloc-dev \ - zlib1g-dev \ - libgdbm-dev \ - libgmp-dev \ - libssl-dev \ - libyaml-0-2 \ - ca-certificates \ - libreadline8 \ - python3 \ - shared-mime-info && \ - bundle config set --local deployment 'true' && \ - bundle config set --local without 'development test' && \ - bundle config set silence_root_warning true && \ - bundle install -j"$(nproc)" && \ - yarn install --pure-lockfile --production --network-timeout 600000 && \ - yarn cache clean - -FROM node:${NODE_VERSION} - -# Use those args to specify your own version flags & suffixes -ARG MASTODON_VERSION_PRERELEASE="" -ARG MASTODON_VERSION_METADATA="" - -ARG UID="991" -ARG GID="991" - -COPY --link --from=ruby /opt/ruby /opt/ruby - -SHELL ["/bin/bash", "-o", "pipefail", "-c"] - -ENV DEBIAN_FRONTEND="noninteractive" \ - PATH="${PATH}:/opt/ruby/bin:/opt/mastodon/bin" - -# Ignoring these here since we don't want to pin any versions and the Debian image removes apt-get content after use -# hadolint ignore=DL3008,DL3009 -RUN apt-get update && \ - echo "Etc/UTC" > /etc/localtime && \ - groupadd -g "${GID}" mastodon && \ - useradd -l -u "$UID" -g "${GID}" -m -d /opt/mastodon mastodon && \ - apt-get -y --no-install-recommends install whois \ - wget \ - procps \ - libssl3 \ - libpq5 \ - imagemagick \ - ffmpeg \ - libjemalloc2 \ - libicu72 \ - libidn12 \ - libyaml-0-2 \ - file \ - ca-certificates \ - tzdata \ - libreadline8 \ - tini && \ - ln -s /opt/mastodon /mastodon - -# Note: no, cleaning here since Debian does this automatically -# See the file /etc/apt/apt.conf.d/docker-clean within the Docker image's filesystem - -COPY --chown=mastodon:mastodon . /opt/mastodon -COPY --chown=mastodon:mastodon --from=build /opt/mastodon /opt/mastodon - -ENV RAILS_ENV="production" \ - NODE_ENV="production" \ - RAILS_SERVE_STATIC_FILES="true" \ - BIND="0.0.0.0" \ - MASTODON_VERSION_PRERELEASE="${MASTODON_VERSION_PRERELEASE}" \ - MASTODON_VERSION_METADATA="${MASTODON_VERSION_METADATA}" - -# Set the run user -USER mastodon -WORKDIR /opt/mastodon - -# Precompile assets -RUN OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder rails assets:precompile - -# Set the work dir and the container entry point -ENTRYPOINT ["/usr/bin/tini", "--"] -EXPOSE 3000 4000 +COPY public /usr/share/nginx/html/ +COPY nginx.conf /etc/nginx/nginx.conf diff --git a/FEDERATION.md b/FEDERATION.md deleted file mode 100644 index e3721d724..000000000 --- a/FEDERATION.md +++ /dev/null @@ -1,31 +0,0 @@ -## ActivityPub federation in Mastodon - -Mastodon largely follows the ActivityPub server-to-server specification but it makes uses of some non-standard extensions, some of which are required for interacting with Mastodon at all. - -Supported vocabulary: https://docs.joinmastodon.org/spec/activitypub/ - -### Required extensions - -#### Webfinger - -In Mastodon, users are identified by a `username` and `domain` pair (e.g., `Gargron@mastodon.social`). -This is used both for discovery and for unambiguously mentioning users across the fediverse. Furthermore, this is part of Mastodon's database design from its very beginnings. - -As a result, Mastodon requires that each ActivityPub actor uniquely maps back to an `acct:` URI that can be resolved via WebFinger. - -More information and examples are available at: https://docs.joinmastodon.org/spec/webfinger/ - -#### HTTP Signatures - -In order to authenticate activities, Mastodon relies on HTTP Signatures, signing every `POST` and `GET` request to other ActivityPub implementations on behalf of the user authoring an activity (for `POST` requests) or an actor representing the Mastodon server itself (for most `GET` requests). - -Mastodon requires all `POST` requests to be signed, and MAY require `GET` requests to be signed, depending on the configuration of the Mastodon server. - -More information on HTTP Signatures, as well as examples, can be found here: https://docs.joinmastodon.org/spec/security/#http - -### Optional extensions - -- Linked-Data Signatures: https://docs.joinmastodon.org/spec/security/#ld -- Bearcaps: https://docs.joinmastodon.org/spec/bearcaps/ -- Followers collection synchronization: https://codeberg.org/fediverse/fep/src/branch/main/fep/8fcf/fep-8fcf.md -- Search indexing consent for actors: https://codeberg.org/fediverse/fep/src/branch/main/fep/5feb/fep-5feb.md diff --git a/Gemfile b/Gemfile deleted file mode 100644 index 449b0a920..000000000 --- a/Gemfile +++ /dev/null @@ -1,201 +0,0 @@ -# frozen_string_literal: true - -source 'https://rubygems.org' -ruby '>= 3.0.0' - -gem 'puma', '~> 6.3' -gem 'rails', '~> 7.0' -gem 'sprockets', '~> 3.7.2' -gem 'thor', '~> 1.2' -gem 'rack', '~> 2.2.7' - -gem 'haml-rails', '~>2.0' -gem 'pg', '~> 1.5' -gem 'pghero' -gem 'dotenv-rails', '~> 2.8' - -gem 'aws-sdk-s3', '~> 1.123', require: false -gem 'fog-core', '<= 2.4.0' -gem 'fog-openstack', '~> 0.3', require: false -gem 'kt-paperclip', '~> 7.2' -gem 'md-paperclip-azure', '~> 2.2', require: false -gem 'blurhash', '~> 0.1' - -gem 'active_model_serializers', '~> 0.10' -gem 'addressable', '~> 2.8' -gem 'bootsnap', '~> 1.16.0', require: false -gem 'browser' -gem 'charlock_holmes', '~> 0.7.7' -gem 'chewy', '~> 7.3' -gem 'devise', '~> 4.9' -gem 'devise-two-factor', '~> 4.1' - -group :pam_authentication, optional: true do - gem 'devise_pam_authenticatable2', '~> 9.2' -end - -gem 'net-ldap', '~> 0.18' - -# TODO: Point back at released omniauth-cas gem when PR merged -# https://github.com/dlindahl/omniauth-cas/pull/68 -gem 'omniauth-cas', github: 'stanhu/omniauth-cas', ref: '4211e6d05941b4a981f9a36b49ec166cecd0e271' -gem 'omniauth-saml', '~> 2.0' -gem 'omniauth_openid_connect', '~> 0.6.1' -gem 'omniauth', '~> 2.0' -gem 'omniauth-rails_csrf_protection', '~> 1.0' - -gem 'color_diff', '~> 0.1' -gem 'discard', '~> 1.2' -gem 'doorkeeper', '~> 5.6' -gem 'ed25519', '~> 1.3' -gem 'fast_blank', '~> 1.0' -gem 'fastimage' -gem 'hiredis', '~> 0.6' -gem 'redis-namespace', '~> 1.10' -gem 'htmlentities', '~> 4.3' -gem 'http', '~> 5.1' -gem 'http_accept_language', '~> 2.1' -gem 'httplog', '~> 1.6.2' -gem 'idn-ruby', require: 'idn' -gem 'kaminari', '~> 1.2' -gem 'link_header', '~> 0.0' -gem 'mime-types', '~> 3.5.0', require: 'mime/types/columnar' -gem 'nokogiri', '~> 1.15' -gem 'nsa', github: 'jhawthorn/nsa', ref: 'e020fcc3a54d993ab45b7194d89ab720296c111b' -gem 'oj', '~> 3.14' -gem 'ox', '~> 2.14' -gem 'parslet' -gem 'posix-spawn' -gem 'public_suffix', '~> 5.0' -gem 'pundit', '~> 2.3' -gem 'premailer-rails' -gem 'rack-attack', '~> 6.6' -gem 'rack-cors', '~> 2.0', require: 'rack/cors' -gem 'rails-i18n', '~> 7.0' -gem 'rails-settings-cached', '~> 0.6', git: 'https://github.com/mastodon/rails-settings-cached.git', branch: 'v0.6.6-aliases-true' -gem 'redcarpet', '~> 3.6' -gem 'redis', '~> 4.5', require: ['redis', 'redis/connection/hiredis'] -gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock' -gem 'rqrcode', '~> 2.2' -gem 'ruby-progressbar', '~> 1.13' -gem 'sanitize', '~> 6.0' -gem 'scenic', '~> 1.7' -gem 'sidekiq', '~> 6.5' -gem 'sidekiq-scheduler', '~> 5.0' -gem 'sidekiq-unique-jobs', '~> 7.1' -gem 'sidekiq-bulk', '~> 0.2.0' -gem 'simple-navigation', '~> 4.4' -gem 'simple_form', '~> 5.2' -gem 'sprockets-rails', '~> 3.4', require: 'sprockets/railtie' -gem 'stoplight', '~> 3.0.1' -gem 'strong_migrations', '~> 0.8' -gem 'tty-prompt', '~> 0.23', require: false -gem 'twitter-text', '~> 3.1.0' -gem 'tzinfo-data', '~> 1.2023' -gem 'webpacker', '~> 5.4' -gem 'webpush', github: 'ClearlyClaire/webpush', ref: 'f14a4d52e201128b1b00245d11b6de80d6cfdcd9' -gem 'webauthn', '~> 3.0' - -gem 'json-ld' -gem 'json-ld-preloaded', '~> 3.2' -gem 'rdf-normalize', '~> 0.5' - -gem 'private_address_check', '~> 0.5' - -group :test do - # Used to split testing into chunks in CI - gem 'rspec_chunked', '~> 0.6' - - # RSpec progress bar formatter - gem 'fuubar', '~> 2.5' - - # Extra RSpec extenion methods and helpers for sidekiq - gem 'rspec-sidekiq', '~> 4.0' - - # Browser integration testing - gem 'capybara', '~> 3.39' - gem 'selenium-webdriver' - - # Used to reset the database between system tests - gem 'database_cleaner-active_record' - - # Used to mock environment variables - gem 'climate_control', '~> 0.2' - - # Generating fake data for specs - gem 'faker', '~> 3.2' - - # Generate test objects for specs - gem 'fabrication', '~> 2.30' - - # Add back helpers functions removed in Rails 5.1 - gem 'rails-controller-testing', '~> 1.0' - - # Validate schemas in specs - gem 'json-schema', '~> 4.0' - - # Test harness fo rack components - gem 'rack-test', '~> 2.1' - - # Coverage formatter for RSpec test if DISABLE_SIMPLECOV is false - gem 'simplecov', '~> 0.22', require: false - - # Stub web requests for specs - gem 'webmock', '~> 3.18' -end - -group :development do - # Code linting CLI and plugins - gem 'rubocop', require: false - gem 'rubocop-capybara', require: false - gem 'rubocop-performance', require: false - gem 'rubocop-rails', require: false - gem 'rubocop-rspec', require: false - - # Annotates modules with schema - gem 'annotate', '~> 3.2' - - # Enhanced error message pages for development - gem 'better_errors', '~> 2.9' - gem 'binding_of_caller', '~> 1.0' - - # Preview mail in the browser - gem 'letter_opener', '~> 1.8' - gem 'letter_opener_web', '~> 2.0' - - # Security analysis CLI tools - gem 'brakeman', '~> 6.0', require: false - gem 'bundler-audit', '~> 0.9', require: false - - # Linter CLI for HAML files - gem 'haml_lint', require: false - - # Validate missing i18n keys - gem 'i18n-tasks', '~> 1.0', require: false -end - -group :development, :test do - # Profiling tools - gem 'memory_profiler', require: false - gem 'ruby-prof', require: false - gem 'stackprof', require: false - gem 'test-prof' - - # RSpec runner for rails - gem 'rspec-rails', '~> 6.0' -end - -group :production do - gem 'lograge', '~> 0.12' -end - -gem 'concurrent-ruby', require: false -gem 'connection_pool', require: false -gem 'xorcist', '~> 1.1' - -gem 'cocoon', '~> 1.2' - -gem 'net-http', '~> 0.3.2' -gem 'rubyzip', '~> 2.3' - -gem 'hcaptcha', '~> 7.1' diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index affe1bf7f..000000000 --- a/Gemfile.lock +++ /dev/null @@ -1,929 +0,0 @@ -GIT - remote: https://github.com/ClearlyClaire/webpush.git - revision: f14a4d52e201128b1b00245d11b6de80d6cfdcd9 - ref: f14a4d52e201128b1b00245d11b6de80d6cfdcd9 - specs: - webpush (0.3.8) - hkdf (~> 0.2) - jwt (~> 2.0) - -GIT - remote: https://github.com/jhawthorn/nsa.git - revision: e020fcc3a54d993ab45b7194d89ab720296c111b - ref: e020fcc3a54d993ab45b7194d89ab720296c111b - specs: - nsa (0.2.8) - activesupport (>= 4.2, < 7.2) - concurrent-ruby (~> 1.0, >= 1.0.2) - sidekiq (>= 3.5) - statsd-ruby (~> 1.4, >= 1.4.0) - -GIT - remote: https://github.com/mastodon/rails-settings-cached.git - revision: 86328ef0bd04ce21cc0504ff5e334591e8c2ccab - branch: v0.6.6-aliases-true - specs: - rails-settings-cached (0.6.6) - rails (>= 4.2.0) - -GIT - remote: https://github.com/stanhu/omniauth-cas.git - revision: 4211e6d05941b4a981f9a36b49ec166cecd0e271 - ref: 4211e6d05941b4a981f9a36b49ec166cecd0e271 - specs: - omniauth-cas (2.0.0) - addressable (~> 2.3) - nokogiri (~> 1.5) - omniauth (>= 1.2, < 3) - -GEM - remote: https://rubygems.org/ - specs: - actioncable (7.0.8) - actionpack (= 7.0.8) - activesupport (= 7.0.8) - nio4r (~> 2.0) - websocket-driver (>= 0.6.1) - actionmailbox (7.0.8) - actionpack (= 7.0.8) - activejob (= 7.0.8) - activerecord (= 7.0.8) - activestorage (= 7.0.8) - activesupport (= 7.0.8) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.0.8) - actionpack (= 7.0.8) - actionview (= 7.0.8) - activejob (= 7.0.8) - activesupport (= 7.0.8) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp - rails-dom-testing (~> 2.0) - actionpack (7.0.8) - actionview (= 7.0.8) - activesupport (= 7.0.8) - rack (~> 2.0, >= 2.2.4) - rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.8) - actionpack (= 7.0.8) - activerecord (= 7.0.8) - activestorage (= 7.0.8) - activesupport (= 7.0.8) - globalid (>= 0.6.0) - nokogiri (>= 1.8.5) - actionview (7.0.8) - activesupport (= 7.0.8) - builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - active_model_serializers (0.10.14) - actionpack (>= 4.1) - activemodel (>= 4.1) - case_transform (>= 0.2) - jsonapi-renderer (>= 0.1.1.beta1, < 0.3) - activejob (7.0.8) - activesupport (= 7.0.8) - globalid (>= 0.3.6) - activemodel (7.0.8) - activesupport (= 7.0.8) - activerecord (7.0.8) - activemodel (= 7.0.8) - activesupport (= 7.0.8) - activestorage (7.0.8) - actionpack (= 7.0.8) - activejob (= 7.0.8) - activerecord (= 7.0.8) - activesupport (= 7.0.8) - marcel (~> 1.0) - mini_mime (>= 1.1.0) - activesupport (7.0.8) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 1.6, < 2) - minitest (>= 5.1) - tzinfo (~> 2.0) - addressable (2.8.5) - public_suffix (>= 2.0.2, < 6.0) - aes_key_wrap (1.1.0) - android_key_attestation (0.3.0) - annotate (3.2.0) - activerecord (>= 3.2, < 8.0) - rake (>= 10.4, < 14.0) - ast (2.4.2) - attr_encrypted (4.0.0) - encryptor (~> 3.0.0) - attr_required (1.0.1) - awrence (1.2.1) - aws-eventstream (1.2.0) - aws-partitions (1.809.0) - aws-sdk-core (3.181.0) - aws-eventstream (~> 1, >= 1.0.2) - aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.5) - jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.71.0) - aws-sdk-core (~> 3, >= 3.177.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.133.0) - aws-sdk-core (~> 3, >= 3.181.0) - aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.6) - aws-sigv4 (1.6.0) - aws-eventstream (~> 1, >= 1.0.2) - azure-storage-blob (2.0.3) - azure-storage-common (~> 2.0) - nokogiri (~> 1, >= 1.10.8) - azure-storage-common (2.0.4) - faraday (~> 1.0) - faraday_middleware (~> 1.0, >= 1.0.0.rc1) - net-http-persistent (~> 4.0) - nokogiri (~> 1, >= 1.10.8) - base64 (0.1.1) - bcrypt (3.1.18) - better_errors (2.10.1) - erubi (>= 1.0.0) - rack (>= 0.9.0) - rouge (>= 1.0.0) - better_html (2.0.1) - actionview (>= 6.0) - activesupport (>= 6.0) - ast (~> 2.0) - erubi (~> 1.4) - parser (>= 2.4) - smart_properties - bindata (2.4.15) - binding_of_caller (1.0.0) - debug_inspector (>= 0.0.1) - blurhash (0.1.7) - bootsnap (1.16.0) - msgpack (~> 1.2) - brakeman (6.0.1) - browser (5.3.1) - brpoplpush-redis_script (0.1.3) - concurrent-ruby (~> 1.0, >= 1.0.5) - redis (>= 1.0, < 6) - builder (3.2.4) - bundler-audit (0.9.1) - bundler (>= 1.2.0, < 3) - thor (~> 1.0) - capybara (3.39.2) - addressable - matrix - mini_mime (>= 0.1.3) - nokogiri (~> 1.8) - rack (>= 1.6.0) - rack-test (>= 0.6.3) - regexp_parser (>= 1.5, < 3.0) - xpath (~> 3.2) - case_transform (0.2) - activesupport - cbor (0.5.9.6) - charlock_holmes (0.7.7) - chewy (7.3.4) - activesupport (>= 5.2) - elasticsearch (>= 7.12.0, < 7.14.0) - elasticsearch-dsl - chunky_png (1.4.0) - climate_control (0.2.0) - cocoon (1.2.15) - color_diff (0.1) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - cose (1.3.0) - cbor (~> 0.5.9) - openssl-signature_algorithm (~> 1.0) - crack (0.4.5) - rexml - crass (1.0.6) - css_parser (1.14.0) - addressable - database_cleaner-active_record (2.1.0) - activerecord (>= 5.a) - database_cleaner-core (~> 2.0.0) - database_cleaner-core (2.0.1) - date (3.3.3) - debug_inspector (1.1.0) - devise (4.9.2) - bcrypt (~> 3.0) - orm_adapter (~> 0.1) - railties (>= 4.1.0) - responders - warden (~> 1.2.3) - devise-two-factor (4.1.0) - activesupport (< 7.1) - attr_encrypted (>= 1.3, < 5, != 2) - devise (~> 4.0) - railties (< 7.1) - rotp (~> 6.0) - devise_pam_authenticatable2 (9.2.0) - devise (>= 4.0.0) - rpam2 (~> 4.0) - diff-lcs (1.5.0) - discard (1.2.1) - activerecord (>= 4.2, < 8) - docile (1.4.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) - doorkeeper (5.6.6) - railties (>= 5) - dotenv (2.8.1) - dotenv-rails (2.8.1) - dotenv (= 2.8.1) - railties (>= 3.2) - ed25519 (1.3.0) - elasticsearch (7.13.3) - elasticsearch-api (= 7.13.3) - elasticsearch-transport (= 7.13.3) - elasticsearch-api (7.13.3) - multi_json - elasticsearch-dsl (0.1.10) - elasticsearch-transport (7.13.3) - faraday (~> 1) - multi_json - encryptor (3.0.0) - erubi (1.12.0) - et-orbi (1.2.7) - tzinfo - excon (0.100.0) - fabrication (2.30.0) - faker (3.2.1) - i18n (>= 1.8.11, < 2) - faraday (1.10.3) - faraday-em_http (~> 1.0) - faraday-em_synchrony (~> 1.0) - faraday-excon (~> 1.1) - faraday-httpclient (~> 1.0) - faraday-multipart (~> 1.0) - faraday-net_http (~> 1.0) - faraday-net_http_persistent (~> 1.0) - faraday-patron (~> 1.0) - faraday-rack (~> 1.0) - faraday-retry (~> 1.0) - ruby2_keywords (>= 0.0.4) - faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) - faraday-excon (1.1.0) - faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) - faraday-net_http (1.0.1) - faraday-net_http_persistent (1.2.0) - faraday-patron (1.0.0) - faraday-rack (1.0.0) - faraday-retry (1.0.3) - faraday_middleware (1.2.0) - faraday (~> 1.0) - fast_blank (1.0.1) - fastimage (2.2.7) - ffi (1.15.5) - ffi-compiler (1.0.1) - ffi (>= 1.0.0) - rake - fog-core (2.1.0) - builder - excon (~> 0.58) - formatador (~> 0.2) - mime-types - fog-json (1.2.0) - fog-core - multi_json (~> 1.10) - fog-openstack (0.3.10) - fog-core (>= 1.45, <= 2.1.0) - fog-json (>= 1.0) - ipaddress (>= 0.8) - formatador (0.3.0) - fugit (1.8.1) - et-orbi (~> 1, >= 1.2.7) - raabro (~> 1.4) - fuubar (2.5.1) - rspec-core (~> 3.0) - ruby-progressbar (~> 1.4) - globalid (1.1.0) - activesupport (>= 5.0) - haml (6.2.0) - temple (>= 0.8.2) - thor - tilt - haml-rails (2.1.0) - actionpack (>= 5.1) - activesupport (>= 5.1) - haml (>= 4.0.6) - railties (>= 5.1) - haml_lint (0.51.0) - haml (>= 4.0) - parallel (~> 1.10) - rainbow - rubocop (>= 1.0) - sysexits (~> 1.1) - hashdiff (1.0.1) - hashie (5.0.0) - hcaptcha (7.1.0) - json - highline (2.1.0) - hiredis (0.6.3) - hkdf (0.3.0) - htmlentities (4.3.4) - http (5.1.1) - addressable (~> 2.8) - http-cookie (~> 1.0) - http-form_data (~> 2.2) - llhttp-ffi (~> 0.4.0) - http-cookie (1.0.5) - domain_name (~> 0.5) - http-form_data (2.3.0) - http_accept_language (2.1.1) - httpclient (2.8.3) - httplog (1.6.2) - rack (>= 2.0) - rainbow (>= 2.0.0) - i18n (1.14.1) - concurrent-ruby (~> 1.0) - i18n-tasks (1.0.12) - activesupport (>= 4.0.2) - ast (>= 2.1.0) - better_html (>= 1.0, < 3.0) - erubi - highline (>= 2.0.0) - i18n - parser (>= 2.2.3.0) - rails-i18n - rainbow (>= 2.2.2, < 4.0) - terminal-table (>= 1.5.1) - idn-ruby (0.1.5) - ipaddress (0.8.3) - jmespath (1.6.2) - json (2.6.3) - json-canonicalization (0.3.2) - json-jwt (1.15.3) - activesupport (>= 4.2) - aes_key_wrap - bindata - httpclient - json-ld (3.2.5) - htmlentities (~> 4.3) - json-canonicalization (~> 0.3, >= 0.3.2) - link_header (~> 0.0, >= 0.0.8) - multi_json (~> 1.15) - rack (>= 2.2, < 4) - rdf (~> 3.2, >= 3.2.10) - json-ld-preloaded (3.2.2) - json-ld (~> 3.2) - rdf (~> 3.2) - json-schema (4.0.0) - addressable (>= 2.8) - jsonapi-renderer (0.2.2) - jwt (2.7.1) - kaminari (1.2.2) - activesupport (>= 4.1.0) - kaminari-actionview (= 1.2.2) - kaminari-activerecord (= 1.2.2) - kaminari-core (= 1.2.2) - kaminari-actionview (1.2.2) - actionview - kaminari-core (= 1.2.2) - kaminari-activerecord (1.2.2) - activerecord - kaminari-core (= 1.2.2) - kaminari-core (1.2.2) - kt-paperclip (7.2.1) - activemodel (>= 4.2.0) - activesupport (>= 4.2.0) - marcel (~> 1.0.1) - mime-types - terrapin (~> 0.6.0) - language_server-protocol (3.17.0.3) - launchy (2.5.2) - addressable (~> 2.8) - letter_opener (1.8.1) - launchy (>= 2.2, < 3) - letter_opener_web (2.0.0) - actionmailer (>= 5.2) - letter_opener (~> 1.7) - railties (>= 5.2) - rexml - link_header (0.0.8) - llhttp-ffi (0.4.0) - ffi-compiler (~> 1.0) - rake (~> 13.0) - lograge (0.13.0) - actionpack (>= 4) - activesupport (>= 4) - railties (>= 4) - request_store (~> 1.0) - loofah (2.21.3) - crass (~> 1.0.2) - nokogiri (>= 1.12.0) - mail (2.8.1) - mini_mime (>= 0.1.1) - net-imap - net-pop - net-smtp - marcel (1.0.2) - mario-redis-lock (1.2.1) - redis (>= 3.0.5) - matrix (0.4.2) - md-paperclip-azure (2.2.0) - addressable (~> 2.5) - azure-storage-blob (~> 2.0.1) - hashie (~> 5.0) - memory_profiler (1.0.1) - method_source (1.0.0) - mime-types (3.5.1) - mime-types-data (~> 3.2015) - mime-types-data (3.2023.0808) - mini_mime (1.1.5) - mini_portile2 (2.8.4) - minitest (5.19.0) - msgpack (1.7.1) - multi_json (1.15.0) - multipart-post (2.3.0) - net-http (0.3.2) - uri - net-http-persistent (4.0.2) - connection_pool (~> 2.2) - net-imap (0.3.7) - date - net-protocol - net-ldap (0.18.0) - net-pop (0.1.2) - net-protocol - net-protocol (0.2.1) - timeout - net-smtp (0.3.3) - net-protocol - nio4r (2.5.9) - nokogiri (1.15.4) - mini_portile2 (~> 2.8.2) - racc (~> 1.4) - oj (3.16.1) - omniauth (2.1.1) - hashie (>= 3.4.6) - rack (>= 2.2.3) - rack-protection - omniauth-rails_csrf_protection (1.0.1) - actionpack (>= 4.2) - omniauth (~> 2.0) - omniauth-saml (2.1.0) - omniauth (~> 2.0) - ruby-saml (~> 1.12) - omniauth_openid_connect (0.6.1) - omniauth (>= 1.9, < 3) - openid_connect (~> 1.1) - openid_connect (1.4.2) - activemodel - attr_required (>= 1.0.0) - json-jwt (>= 1.15.0) - net-smtp - rack-oauth2 (~> 1.21) - swd (~> 1.3) - tzinfo - validate_email - validate_url - webfinger (~> 1.2) - openssl (3.1.0) - openssl-signature_algorithm (1.3.0) - openssl (> 2.0) - orm_adapter (0.5.0) - ox (2.14.17) - parallel (1.23.0) - parser (3.2.2.3) - ast (~> 2.4.1) - racc - parslet (2.0.0) - pastel (0.8.0) - tty-color (~> 0.5) - pg (1.5.4) - pghero (3.3.4) - activerecord (>= 6) - posix-spawn (0.3.15) - premailer (1.21.0) - addressable - css_parser (>= 1.12.0) - htmlentities (>= 4.0.0) - premailer-rails (1.12.0) - actionmailer (>= 3) - net-smtp - premailer (~> 1.7, >= 1.7.9) - private_address_check (0.5.0) - public_suffix (5.0.3) - puma (6.3.1) - nio4r (~> 2.0) - pundit (2.3.0) - activesupport (>= 3.0.0) - raabro (1.4.0) - racc (1.7.1) - rack (2.2.8) - rack-attack (6.7.0) - rack (>= 1.0, < 4) - rack-cors (2.0.1) - rack (>= 2.0.0) - rack-oauth2 (1.21.3) - activesupport - attr_required - httpclient - json-jwt (>= 1.11.0) - rack (>= 2.1.0) - rack-protection (3.0.5) - rack - rack-proxy (0.7.6) - rack - rack-test (2.1.0) - rack (>= 1.3) - rails (7.0.8) - actioncable (= 7.0.8) - actionmailbox (= 7.0.8) - actionmailer (= 7.0.8) - actionpack (= 7.0.8) - actiontext (= 7.0.8) - actionview (= 7.0.8) - activejob (= 7.0.8) - activemodel (= 7.0.8) - activerecord (= 7.0.8) - activestorage (= 7.0.8) - activesupport (= 7.0.8) - bundler (>= 1.15.0) - railties (= 7.0.8) - rails-controller-testing (1.0.5) - actionpack (>= 5.0.1.rc1) - actionview (>= 5.0.1.rc1) - activesupport (>= 5.0.1.rc1) - rails-dom-testing (2.1.1) - activesupport (>= 5.0.0) - minitest - nokogiri (>= 1.6) - rails-html-sanitizer (1.6.0) - loofah (~> 2.21) - nokogiri (~> 1.14) - rails-i18n (7.0.7) - i18n (>= 0.7, < 2) - railties (>= 6.0.0, < 8) - railties (7.0.8) - actionpack (= 7.0.8) - activesupport (= 7.0.8) - method_source - rake (>= 12.2) - thor (~> 1.0) - zeitwerk (~> 2.5) - rainbow (3.1.1) - rake (13.0.6) - rdf (3.2.11) - link_header (~> 0.0, >= 0.0.8) - rdf-normalize (0.6.1) - rdf (~> 3.2) - redcarpet (3.6.0) - redis (4.8.1) - redis-namespace (1.11.0) - redis (>= 4) - redlock (1.3.2) - redis (>= 3.0.0, < 6.0) - regexp_parser (2.8.1) - request_store (1.5.1) - rack (>= 1.4) - responders (3.1.0) - actionpack (>= 5.2) - railties (>= 5.2) - rexml (3.2.6) - rotp (6.2.2) - rouge (4.1.2) - rpam2 (4.0.2) - rqrcode (2.2.0) - chunky_png (~> 1.0) - rqrcode_core (~> 1.0) - rqrcode_core (1.2.0) - rspec-core (3.12.2) - rspec-support (~> 3.12.0) - rspec-expectations (3.12.3) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.12.0) - rspec-mocks (3.12.5) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.12.0) - rspec-rails (6.0.3) - actionpack (>= 6.1) - activesupport (>= 6.1) - railties (>= 6.1) - rspec-core (~> 3.12) - rspec-expectations (~> 3.12) - rspec-mocks (~> 3.12) - rspec-support (~> 3.12) - rspec-sidekiq (4.0.1) - rspec-core (~> 3.0) - rspec-expectations (~> 3.0) - rspec-mocks (~> 3.0) - sidekiq (>= 5, < 8) - rspec-support (3.12.1) - rspec_chunked (0.6) - rubocop (1.56.4) - base64 (~> 0.1.1) - json (~> 2.3) - language_server-protocol (>= 3.17.0) - parallel (~> 1.10) - parser (>= 3.2.2.3) - rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.28.1, < 2.0) - ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.29.0) - parser (>= 3.2.1.0) - rubocop-capybara (2.18.0) - rubocop (~> 1.41) - rubocop-factory_bot (2.23.1) - rubocop (~> 1.33) - rubocop-performance (1.19.0) - rubocop (>= 1.7.0, < 2.0) - rubocop-ast (>= 0.4.0) - rubocop-rails (2.20.2) - activesupport (>= 4.2.0) - rack (>= 1.1) - rubocop (>= 1.33.0, < 2.0) - rubocop-rspec (2.23.2) - rubocop (~> 1.33) - rubocop-capybara (~> 2.17) - rubocop-factory_bot (~> 2.22) - ruby-prof (1.6.3) - ruby-progressbar (1.13.0) - ruby-saml (1.15.0) - nokogiri (>= 1.13.10) - rexml - ruby2_keywords (0.0.5) - rubyzip (2.3.2) - rufus-scheduler (3.9.1) - fugit (~> 1.1, >= 1.1.6) - safety_net_attestation (0.4.0) - jwt (~> 2.0) - sanitize (6.0.2) - crass (~> 1.0.2) - nokogiri (>= 1.12.0) - scenic (1.7.0) - activerecord (>= 4.0.0) - railties (>= 4.0.0) - selenium-webdriver (4.13.1) - rexml (~> 3.2, >= 3.2.5) - rubyzip (>= 1.2.2, < 3.0) - websocket (~> 1.0) - semantic_range (3.0.0) - sidekiq (6.5.11) - connection_pool (>= 2.2.5, < 3) - rack (~> 2.0) - redis (>= 4.5.0, < 5) - sidekiq-bulk (0.2.0) - sidekiq - sidekiq-scheduler (5.0.3) - rufus-scheduler (~> 3.2) - sidekiq (>= 6, < 8) - tilt (>= 1.4.0) - sidekiq-unique-jobs (7.1.29) - brpoplpush-redis_script (> 0.1.1, <= 2.0.0) - concurrent-ruby (~> 1.0, >= 1.0.5) - redis (< 5.0) - sidekiq (>= 5.0, < 7.0) - thor (>= 0.20, < 3.0) - simple-navigation (4.4.0) - activesupport (>= 2.3.2) - simple_form (5.2.0) - actionpack (>= 5.2) - activemodel (>= 5.2) - simplecov (0.22.0) - docile (~> 1.1) - simplecov-html (~> 0.11) - simplecov_json_formatter (~> 0.1) - simplecov-html (0.12.3) - simplecov_json_formatter (0.1.4) - smart_properties (1.17.0) - sprockets (3.7.2) - concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) - sprockets (>= 3.0.0) - stackprof (0.2.25) - statsd-ruby (1.5.0) - stoplight (3.0.2) - redlock (~> 1.0) - strong_migrations (0.8.0) - activerecord (>= 5.2) - swd (1.3.0) - activesupport (>= 3) - attr_required (>= 0.0.5) - httpclient (>= 2.4) - sysexits (1.2.0) - temple (0.10.2) - terminal-table (3.0.2) - unicode-display_width (>= 1.1.1, < 3) - terrapin (0.6.0) - climate_control (>= 0.0.3, < 1.0) - test-prof (1.2.3) - thor (1.2.2) - tilt (2.3.0) - timeout (0.4.0) - tpm-key_attestation (0.12.0) - bindata (~> 2.4) - openssl (> 2.0) - openssl-signature_algorithm (~> 1.0) - tty-color (0.6.0) - tty-cursor (0.7.1) - tty-prompt (0.23.1) - pastel (~> 0.8) - tty-reader (~> 0.8) - tty-reader (0.9.0) - tty-cursor (~> 0.7) - tty-screen (~> 0.8) - wisper (~> 2.0) - tty-screen (0.8.1) - twitter-text (3.1.0) - idn-ruby - unf (~> 0.1.0) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - tzinfo-data (1.2023.3) - tzinfo (>= 1.0.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) - unicode-display_width (2.5.0) - uri (0.12.2) - validate_email (0.1.6) - activemodel (>= 3.0) - mail (>= 2.2.5) - validate_url (1.0.15) - activemodel (>= 3.0.0) - public_suffix - warden (1.2.9) - rack (>= 2.0.9) - webauthn (3.0.0) - android_key_attestation (~> 0.3.0) - awrence (~> 1.1) - bindata (~> 2.4) - cbor (~> 0.5.9) - cose (~> 1.1) - openssl (>= 2.2) - safety_net_attestation (~> 0.4.0) - tpm-key_attestation (~> 0.12.0) - webfinger (1.2.0) - activesupport - httpclient (>= 2.4) - webmock (3.19.1) - addressable (>= 2.8.0) - crack (>= 0.3.2) - hashdiff (>= 0.4.0, < 2.0.0) - webpacker (5.4.4) - activesupport (>= 5.2) - rack-proxy (>= 0.6.1) - railties (>= 5.2) - semantic_range (>= 2.3.0) - websocket (1.2.10) - websocket-driver (0.7.6) - websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.5) - wisper (2.0.1) - xorcist (1.1.3) - xpath (3.2.0) - nokogiri (~> 1.8) - zeitwerk (2.6.11) - -PLATFORMS - ruby - -DEPENDENCIES - active_model_serializers (~> 0.10) - addressable (~> 2.8) - annotate (~> 3.2) - aws-sdk-s3 (~> 1.123) - better_errors (~> 2.9) - binding_of_caller (~> 1.0) - blurhash (~> 0.1) - bootsnap (~> 1.16.0) - brakeman (~> 6.0) - browser - bundler-audit (~> 0.9) - capybara (~> 3.39) - charlock_holmes (~> 0.7.7) - chewy (~> 7.3) - climate_control (~> 0.2) - cocoon (~> 1.2) - color_diff (~> 0.1) - concurrent-ruby - connection_pool - database_cleaner-active_record - devise (~> 4.9) - devise-two-factor (~> 4.1) - devise_pam_authenticatable2 (~> 9.2) - discard (~> 1.2) - doorkeeper (~> 5.6) - dotenv-rails (~> 2.8) - ed25519 (~> 1.3) - fabrication (~> 2.30) - faker (~> 3.2) - fast_blank (~> 1.0) - fastimage - fog-core (<= 2.4.0) - fog-openstack (~> 0.3) - fuubar (~> 2.5) - haml-rails (~> 2.0) - haml_lint - hcaptcha (~> 7.1) - hiredis (~> 0.6) - htmlentities (~> 4.3) - http (~> 5.1) - http_accept_language (~> 2.1) - httplog (~> 1.6.2) - i18n-tasks (~> 1.0) - idn-ruby - json-ld - json-ld-preloaded (~> 3.2) - json-schema (~> 4.0) - kaminari (~> 1.2) - kt-paperclip (~> 7.2) - letter_opener (~> 1.8) - letter_opener_web (~> 2.0) - link_header (~> 0.0) - lograge (~> 0.12) - mario-redis-lock (~> 1.2) - md-paperclip-azure (~> 2.2) - memory_profiler - mime-types (~> 3.5.0) - net-http (~> 0.3.2) - net-ldap (~> 0.18) - nokogiri (~> 1.15) - nsa! - oj (~> 3.14) - omniauth (~> 2.0) - omniauth-cas! - omniauth-rails_csrf_protection (~> 1.0) - omniauth-saml (~> 2.0) - omniauth_openid_connect (~> 0.6.1) - ox (~> 2.14) - parslet - pg (~> 1.5) - pghero - posix-spawn - premailer-rails - private_address_check (~> 0.5) - public_suffix (~> 5.0) - puma (~> 6.3) - pundit (~> 2.3) - rack (~> 2.2.7) - rack-attack (~> 6.6) - rack-cors (~> 2.0) - rack-test (~> 2.1) - rails (~> 7.0) - rails-controller-testing (~> 1.0) - rails-i18n (~> 7.0) - rails-settings-cached (~> 0.6)! - rdf-normalize (~> 0.5) - redcarpet (~> 3.6) - redis (~> 4.5) - redis-namespace (~> 1.10) - rqrcode (~> 2.2) - rspec-rails (~> 6.0) - rspec-sidekiq (~> 4.0) - rspec_chunked (~> 0.6) - rubocop - rubocop-capybara - rubocop-performance - rubocop-rails - rubocop-rspec - ruby-prof - ruby-progressbar (~> 1.13) - rubyzip (~> 2.3) - sanitize (~> 6.0) - scenic (~> 1.7) - selenium-webdriver - sidekiq (~> 6.5) - sidekiq-bulk (~> 0.2.0) - sidekiq-scheduler (~> 5.0) - sidekiq-unique-jobs (~> 7.1) - simple-navigation (~> 4.4) - simple_form (~> 5.2) - simplecov (~> 0.22) - sprockets (~> 3.7.2) - sprockets-rails (~> 3.4) - stackprof - stoplight (~> 3.0.1) - strong_migrations (~> 0.8) - test-prof - thor (~> 1.2) - tty-prompt (~> 0.23) - twitter-text (~> 3.1.0) - tzinfo-data (~> 1.2023) - webauthn (~> 3.0) - webmock (~> 3.18) - webpacker (~> 5.4) - webpush! - xorcist (~> 1.1) - -RUBY VERSION - ruby 3.2.2p53 - -BUNDLED WITH - 2.4.13 diff --git a/Procfile b/Procfile deleted file mode 100644 index d15c835b8..000000000 --- a/Procfile +++ /dev/null @@ -1,14 +0,0 @@ -web: bin/heroku-web -worker: bundle exec sidekiq - -# For the streaming API, you need a separate app that shares Postgres and Redis: -# -# heroku create -# heroku buildpacks:add heroku/nodejs -# heroku config:set RUN_STREAMING=true -# heroku addons:attach ::DATABASE -# heroku addons:attach ::REDIS -# -# and let the main app use the separate app: -# -# heroku config:set STREAMING_API_BASE_URL=wss://.herokuapp.com -a diff --git a/Rakefile b/Rakefile deleted file mode 100644 index e51cf0e17..000000000 --- a/Rakefile +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -# Add your own tasks in files placed in lib/tasks ending in .rake, -# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. - -require File.expand_path('config/application', __dir__) - -Rails.application.load_tasks diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 3e13377db..000000000 --- a/SECURITY.md +++ /dev/null @@ -1,22 +0,0 @@ -# Security Policy - -If you believe you've identified a security vulnerability in Mastodon (a bug that allows something to happen that shouldn't be possible), you can either: - -- open a [Github security issue on the Mastodon project](https://github.com/mastodon/mastodon/security/advisories/new) -- reach us at - -You should _not_ report such issues on public GitHub issues or in other public spaces to give us time to publish a fix for the issue without exposing Mastodon's users to increased risk. - -## Scope - -A "vulnerability in Mastodon" is a vulnerability in the code distributed through our main source code repository on GitHub. Vulnerabilities that are specific to a given installation (e.g. misconfiguration) should be reported to the owner of that installation and not us. - -## Supported Versions - -| Version | Supported | -| ------- | ---------------- | -| 4.2.x | Yes | -| 4.1.x | Yes | -| 4.0.x | Until 2023-10-31 | -| 3.5.x | Until 2023-12-31 | -| < 3.5 | No | diff --git a/Vagrantfile b/Vagrantfile deleted file mode 100644 index 4303f8e06..000000000 --- a/Vagrantfile +++ /dev/null @@ -1,190 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -ENV["PORT"] ||= "3000" - -$provisionA = <' } - - it 'does not include the HTML in the URL' do - expect(subject).to include '"http://example.com/blahblahblahblah/a"' - end - - it 'does not include a script tag' do - expect(subject).to_not include '' } - - it 'does not include a script tag' do - expect(subject).to_not include '' } - - it 'strips the scripts' do - expect(subject).to_not include '' - end - end - - context 'when given text containing malicious classes' do - let(:text) { 'Show more' } - - it 'strips the malicious classes' do - expect(subject).to_not include 'status__content__spoiler-link' - end - end - end - end -end diff --git a/spec/lib/importer/accounts_index_importer_spec.rb b/spec/lib/importer/accounts_index_importer_spec.rb deleted file mode 100644 index 73f9bce39..000000000 --- a/spec/lib/importer/accounts_index_importer_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Importer::AccountsIndexImporter do - describe 'import!' do - let(:pool) { Concurrent::FixedThreadPool.new(5) } - let(:importer) { described_class.new(batch_size: 123, executor: pool) } - - before { Fabricate(:account) } - - it 'indexes relevant accounts' do - expect { importer.import! }.to update_index(AccountsIndex) - end - end -end diff --git a/spec/lib/importer/base_importer_spec.rb b/spec/lib/importer/base_importer_spec.rb deleted file mode 100644 index 78e9a869b..000000000 --- a/spec/lib/importer/base_importer_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Importer::BaseImporter do - describe 'import!' do - let(:pool) { Concurrent::FixedThreadPool.new(5) } - let(:importer) { described_class.new(batch_size: 123, executor: pool) } - - it 'raises an error' do - expect { importer.import! }.to raise_error(NotImplementedError) - end - end -end diff --git a/spec/lib/importer/public_statuses_index_importer_spec.rb b/spec/lib/importer/public_statuses_index_importer_spec.rb deleted file mode 100644 index bc7c038a9..000000000 --- a/spec/lib/importer/public_statuses_index_importer_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Importer::PublicStatusesIndexImporter do - describe 'import!' do - let(:pool) { Concurrent::FixedThreadPool.new(5) } - let(:importer) { described_class.new(batch_size: 123, executor: pool) } - - before { Fabricate(:status, account: Fabricate(:account, indexable: true)) } - - it 'indexes relevant statuses' do - expect { importer.import! }.to update_index(PublicStatusesIndex) - end - end -end diff --git a/spec/lib/importer/statuses_index_importer_spec.rb b/spec/lib/importer/statuses_index_importer_spec.rb deleted file mode 100644 index d5e1c9f2c..000000000 --- a/spec/lib/importer/statuses_index_importer_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Importer::StatusesIndexImporter do - describe 'import!' do - let(:pool) { Concurrent::FixedThreadPool.new(5) } - let(:importer) { described_class.new(batch_size: 123, executor: pool) } - - before { Fabricate(:status) } - - it 'indexes relevant statuses' do - expect { importer.import! }.to update_index(StatusesIndex) - end - end -end diff --git a/spec/lib/importer/tags_index_importer_spec.rb b/spec/lib/importer/tags_index_importer_spec.rb deleted file mode 100644 index 348990c01..000000000 --- a/spec/lib/importer/tags_index_importer_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Importer::TagsIndexImporter do - describe 'import!' do - let(:pool) { Concurrent::FixedThreadPool.new(5) } - let(:importer) { described_class.new(batch_size: 123, executor: pool) } - - before { Fabricate(:tag) } - - it 'indexes relevant tags' do - expect { importer.import! }.to update_index(TagsIndex) - end - end -end diff --git a/spec/lib/link_details_extractor_spec.rb b/spec/lib/link_details_extractor_spec.rb deleted file mode 100644 index 599bc4e6d..000000000 --- a/spec/lib/link_details_extractor_spec.rb +++ /dev/null @@ -1,292 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe LinkDetailsExtractor do - subject { described_class.new(original_url, html, nil) } - - let(:original_url) { 'https://example.com/dog.html?tracking=123' } - - describe '#canonical_url' do - let(:html) { "" } - - context 'when canonical URL points to the same host' do - let(:url) { 'https://example.com/dog.html' } - - it 'ignores the canonical URLs' do - expect(subject.canonical_url).to eq 'https://example.com/dog.html' - end - end - - context 'when canonical URL points to another host' do - let(:url) { 'https://different.example.net/dog.html' } - - it 'ignores the canonical URLs' do - expect(subject.canonical_url).to eq original_url - end - end - - context 'when canonical URL is set to "null"' do - let(:url) { 'null' } - - it 'ignores the canonical URLs' do - expect(subject.canonical_url).to eq original_url - end - end - end - - context 'when only basic metadata is present' do - let(:html) { <<~HTML } - - - - Man bites dog - - - - HTML - - describe '#title' do - it 'returns the title from title tag' do - expect(subject.title).to eq 'Man bites dog' - end - end - - describe '#description' do - it 'returns the description from meta tag' do - expect(subject.description).to eq "A dog's tale" - end - end - - describe '#language' do - it 'returns the language from lang attribute' do - expect(subject.language).to eq 'en' - end - end - end - - context 'when structured data is present' do - let(:ld_json) do - { - '@context' => 'https://schema.org', - '@type' => 'NewsArticle', - 'headline' => 'Man bites dog', - 'description' => "A dog's tale", - 'datePublished' => '2022-01-31T19:53:00+00:00', - 'author' => { - '@type' => 'Organization', - 'name' => 'Charlie Brown', - }, - 'publisher' => { - '@type' => 'NewsMediaOrganization', - 'name' => 'Pet News', - 'url' => 'https://example.com', - }, - }.to_json - end - - shared_examples 'structured data' do - describe '#title' do - it 'returns the title from structured data' do - expect(subject.title).to eq 'Man bites dog' - end - end - - describe '#description' do - it 'returns the description from structured data' do - expect(subject.description).to eq "A dog's tale" - end - end - - describe '#published_at' do - it 'returns the publicaton time from structured data' do - expect(subject.published_at).to eq '2022-01-31T19:53:00+00:00' - end - end - - describe '#author_name' do - it 'returns the author name from structured data' do - expect(subject.author_name).to eq 'Charlie Brown' - end - end - - describe '#provider_name' do - it 'returns the provider name from structured data' do - expect(subject.provider_name).to eq 'Pet News' - end - end - end - - context 'when is wrapped in CDATA tags' do - let(:html) { <<~HTML } - - - - - - - HTML - - include_examples 'structured data' - end - - context 'with the first tag is invalid JSON' do - let(:html) { <<~HTML } - - - - - - - - HTML - - include_examples 'structured data' - end - - context 'with preceding block of unsupported LD+JSON' do - let(:html) { <<~HTML } - - - - - - - - HTML - - include_examples 'structured data' - end - - context 'with unsupported in same block LD+JSON' do - let(:html) { <<~HTML } - - - - - - - HTML - - include_examples 'structured data' - end - end - - context 'when Open Graph protocol data is present' do - let(:html) { <<~HTML } - - - - - - - - - - - - - - - HTML - - describe '#canonical_url' do - it 'returns the URL from Open Graph protocol data' do - expect(subject.canonical_url).to eq 'https://example.com/dog.html' - end - end - - describe '#title' do - it 'returns the title from Open Graph protocol data' do - expect(subject.title).to eq 'Man bites dog' - end - end - - describe '#description' do - it 'returns the description from Open Graph protocol data' do - expect(subject.description).to eq "A dog's tale" - end - end - - describe '#published_at' do - it 'returns the publicaton time from Open Graph protocol data' do - expect(subject.published_at).to eq '2022-01-31T19:53:00+00:00' - end - end - - describe '#author_name' do - it 'returns the author name from Open Graph protocol data' do - expect(subject.author_name).to eq 'Charlie Brown' - end - end - - describe '#language' do - it 'returns the language from Open Graph protocol data' do - expect(subject.language).to eq 'en' - end - end - - describe '#image' do - it 'returns the image from Open Graph protocol data' do - expect(subject.image).to eq 'https://example.com/snoopy.jpg' - end - end - - describe '#image:alt' do - it 'returns the image description from Open Graph protocol data' do - expect(subject.image_alt).to eq 'A good boy' - end - end - - describe '#provider_name' do - it 'returns the provider name from Open Graph protocol data' do - expect(subject.provider_name).to eq 'Pet News' - end - end - end -end diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb deleted file mode 100644 index a263d673d..000000000 --- a/spec/lib/mastodon/cli/accounts_spec.rb +++ /dev/null @@ -1,1364 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/accounts' - -describe Mastodon::CLI::Accounts do - let(:cli) { described_class.new } - - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end - - describe '#create' do - shared_examples 'a new user with given email address and username' do - it 'creates a new user with the specified email address' do - cli.invoke(:create, arguments, options) - - expect(User.find_by(email: options[:email])).to be_present - end - - it 'creates a new local account with the specified username' do - cli.invoke(:create, arguments, options) - - expect(Account.find_local('tootctl_username')).to be_present - end - - it 'returns "OK" and newly generated password' do - allow(SecureRandom).to receive(:hex).and_return('test_password') - - expect { cli.invoke(:create, arguments, options) }.to output( - a_string_including("OK\nNew password: test_password") - ).to_stdout - end - end - - context 'when required USERNAME and --email are provided' do - let(:arguments) { ['tootctl_username'] } - - context 'with USERNAME and --email only' do - let(:options) { { email: 'tootctl@example.com' } } - - it_behaves_like 'a new user with given email address and username' - - context 'with invalid --email value' do - let(:options) { { email: 'invalid' } } - - it 'exits with an error message' do - expect { cli.invoke(:create, arguments, options) }.to output( - a_string_including('Failure/Error: email') - ).to_stdout - .and raise_error(SystemExit) - end - end - end - - context 'with --confirmed option' do - let(:options) { { email: 'tootctl@example.com', confirmed: true } } - - it_behaves_like 'a new user with given email address and username' - - it 'creates a new user with confirmed status' do - cli.invoke(:create, arguments, options) - - user = User.find_by(email: options[:email]) - - expect(user.confirmed?).to be(true) - end - end - - context 'with --approve option' do - let(:options) { { email: 'tootctl@example.com', approve: true } } - - before do - Form::AdminSettings.new(registrations_mode: 'approved').save - end - - it_behaves_like 'a new user with given email address and username' - - it 'creates a new user with approved status' do - cli.invoke(:create, arguments, options) - - user = User.find_by(email: options[:email]) - - expect(user.approved?).to be(true) - end - end - - context 'with --role option' do - context 'when role exists' do - let(:default_role) { Fabricate(:user_role) } - let(:options) { { email: 'tootctl@example.com', role: default_role.name } } - - it_behaves_like 'a new user with given email address and username' - - it 'creates a new user and assigns the specified role' do - cli.invoke(:create, arguments, options) - - role = User.find_by(email: options[:email])&.role - - expect(role.name).to eq(default_role.name) - end - end - - context 'when role does not exist' do - let(:options) { { email: 'tootctl@example.com', role: '404' } } - - it 'exits with an error message indicating the role name was not found' do - expect { cli.invoke(:create, arguments, options) }.to output( - a_string_including('Cannot find user role with that name') - ).to_stdout - .and raise_error(SystemExit) - end - end - end - - context 'with --reattach option' do - context "when account's user is present" do - let(:options) { { email: 'tootctl_new@example.com', reattach: true } } - let(:user) { Fabricate.build(:user, email: 'tootctl@example.com') } - - before do - Fabricate(:account, username: 'tootctl_username', user: user) - end - - it 'returns an error message indicating the username is already taken' do - expect { cli.invoke(:create, arguments, options) }.to output( - a_string_including("The chosen username is currently in use\nUse --force to reattach it anyway and delete the other user") - ).to_stdout - end - - context 'with --force option' do - let(:options) { { email: 'tootctl_new@example.com', reattach: true, force: true } } - - it 'reattaches the account to the new user and deletes the previous user' do - cli.invoke(:create, arguments, options) - - user = Account.find_local('tootctl_username')&.user - - expect(user.email).to eq(options[:email]) - end - end - end - - context "when account's user is not present" do - let(:options) { { email: 'tootctl@example.com', reattach: true } } - - before do - Fabricate(:account, username: 'tootctl_username', user: nil) - end - - it_behaves_like 'a new user with given email address and username' - end - end - end - - context 'when required --email option is not provided' do - let(:arguments) { ['tootctl_username'] } - - it 'raises a required argument missing error (Thor::RequiredArgumentMissingError)' do - expect { cli.invoke(:create, arguments) } - .to raise_error(Thor::RequiredArgumentMissingError) - end - end - end - - describe '#modify' do - context 'when the given username is not found' do - let(:arguments) { ['non_existent_username'] } - - it 'exits with an error message indicating the user was not found' do - expect { cli.invoke(:modify, arguments) }.to output( - a_string_including('No user with such username') - ).to_stdout - .and raise_error(SystemExit) - end - end - - context 'when the given username is found' do - let(:user) { Fabricate(:user) } - let(:arguments) { [user.account.username] } - - context 'when no option is provided' do - it 'returns a successful message' do - expect { cli.invoke(:modify, arguments) }.to output( - a_string_including('OK') - ).to_stdout - end - - it 'does not modify the user' do - cli.invoke(:modify, arguments) - - expect(user).to eq(user.reload) - end - end - - context 'with --role option' do - context 'when the given role is not found' do - let(:options) { { role: '404' } } - - it 'exits with an error message indicating the role was not found' do - expect { cli.invoke(:modify, arguments, options) }.to output( - a_string_including('Cannot find user role with that name') - ).to_stdout - .and raise_error(SystemExit) - end - end - - context 'when the given role is found' do - let(:default_role) { Fabricate(:user_role) } - let(:options) { { role: default_role.name } } - - it "updates the user's role to the specified role" do - cli.invoke(:modify, arguments, options) - - role = user.reload.role - - expect(role.name).to eq(default_role.name) - end - end - end - - context 'with --remove-role option' do - let(:options) { { remove_role: true } } - let(:role) { Fabricate(:user_role) } - let(:user) { Fabricate(:user, role: role) } - - it "removes the user's role successfully" do - cli.invoke(:modify, arguments, options) - - role = user.reload.role - - expect(role.name).to be_empty - end - end - - context 'with --email option' do - let(:user) { Fabricate(:user, email: 'old_email@email.com') } - let(:options) { { email: 'new_email@email.com' } } - - it "sets the user's unconfirmed email to the provided email address" do - cli.invoke(:modify, arguments, options) - - expect(user.reload.unconfirmed_email).to eq(options[:email]) - end - - it "does not update the user's original email address" do - cli.invoke(:modify, arguments, options) - - expect(user.reload.email).to eq('old_email@email.com') - end - - context 'with --confirm option' do - let(:user) { Fabricate(:user, email: 'old_email@email.com', confirmed_at: nil) } - let(:options) { { email: 'new_email@email.com', confirm: true } } - - it "updates the user's email address to the provided email" do - cli.invoke(:modify, arguments, options) - - expect(user.reload.email).to eq(options[:email]) - end - - it "sets the user's email address as confirmed" do - cli.invoke(:modify, arguments, options) - - expect(user.reload.confirmed?).to be(true) - end - end - end - - context 'with --confirm option' do - let(:user) { Fabricate(:user, confirmed_at: nil) } - let(:options) { { confirm: true } } - - it "confirms the user's email address" do - cli.invoke(:modify, arguments, options) - - expect(user.reload.confirmed?).to be(true) - end - end - - context 'with --approve option' do - let(:user) { Fabricate(:user, approved: false) } - let(:options) { { approve: true } } - - before do - Form::AdminSettings.new(registrations_mode: 'approved').save - end - - it 'approves the user' do - expect { cli.invoke(:modify, arguments, options) }.to change { user.reload.approved }.from(false).to(true) - end - end - - context 'with --disable option' do - let(:user) { Fabricate(:user, disabled: false) } - let(:options) { { disable: true } } - - it 'disables the user' do - expect { cli.invoke(:modify, arguments, options) }.to change { user.reload.disabled }.from(false).to(true) - end - end - - context 'with --enable option' do - let(:user) { Fabricate(:user, disabled: true) } - let(:options) { { enable: true } } - - it 'enables the user' do - expect { cli.invoke(:modify, arguments, options) }.to change { user.reload.disabled }.from(true).to(false) - end - end - - context 'with --reset-password option' do - let(:options) { { reset_password: true } } - - it 'returns a new password for the user' do - allow(SecureRandom).to receive(:hex).and_return('new_password') - - expect { cli.invoke(:modify, arguments, options) }.to output( - a_string_including('new_password') - ).to_stdout - end - end - - context 'with --disable-2fa option' do - let(:user) { Fabricate(:user, otp_required_for_login: true) } - let(:options) { { disable_2fa: true } } - - it 'disables the two-factor authentication for the user' do - expect { cli.invoke(:modify, arguments, options) }.to change { user.reload.otp_required_for_login }.from(true).to(false) - end - end - - context 'when provided data is invalid' do - let(:user) { Fabricate(:user) } - let(:options) { { email: 'invalid' } } - - it 'exits with an error message' do - expect { cli.invoke(:modify, arguments, options) }.to output( - a_string_including('Failure/Error: email') - ).to_stdout - .and raise_error(SystemExit) - end - end - end - end - - describe '#delete' do - let(:account) { Fabricate(:account) } - let(:arguments) { [account.username] } - let(:options) { { email: account.user.email } } - let(:delete_account_service) { instance_double(DeleteAccountService) } - - before do - allow(DeleteAccountService).to receive(:new).and_return(delete_account_service) - allow(delete_account_service).to receive(:call) - end - - context 'when both username and --email are provided' do - it 'exits with an error message indicating that only one should be used' do - expect { cli.invoke(:delete, arguments, options) }.to output( - a_string_including('Use username or --email, not both') - ).to_stdout - .and raise_error(SystemExit) - end - end - - context 'when neither username nor --email are provided' do - it 'exits with an error message indicating that no username was provided' do - expect { cli.invoke(:delete) }.to output( - a_string_including('No username provided') - ).to_stdout - .and raise_error(SystemExit) - end - end - - context 'when username is provided' do - it 'deletes the specified user successfully' do - cli.invoke(:delete, arguments) - - expect(delete_account_service).to have_received(:call).with(account, reserve_email: false).once - end - - context 'with --dry-run option' do - let(:options) { { dry_run: true } } - - it 'does not delete the specified user' do - cli.invoke(:delete, arguments, options) - - expect(delete_account_service).to_not have_received(:call).with(account, reserve_email: false) - end - - it 'outputs a successful message in dry run mode' do - expect { cli.invoke(:delete, arguments, options) }.to output( - a_string_including('OK (DRY RUN)') - ).to_stdout - end - end - - context 'when the given username is not found' do - let(:arguments) { ['non_existent_username'] } - - it 'exits with an error message indicating that no user was found' do - expect { cli.invoke(:delete, arguments) }.to output( - a_string_including('No user with such username') - ).to_stdout - .and raise_error(SystemExit) - end - end - end - - context 'when --email is provided' do - it 'deletes the specified user successfully' do - cli.invoke(:delete, nil, options) - - expect(delete_account_service).to have_received(:call).with(account, reserve_email: false).once - end - - context 'with --dry-run option' do - let(:options) { { email: account.user.email, dry_run: true } } - - it 'does not delete the user' do - cli.invoke(:delete, nil, options) - - expect(delete_account_service).to_not have_received(:call).with(account, reserve_email: false) - end - - it 'outputs a successful message in dry run mode' do - expect { cli.invoke(:delete, nil, options) }.to output( - a_string_including('OK (DRY RUN)') - ).to_stdout - end - end - - context 'when the given email address is not found' do - let(:options) { { email: '404@example.com' } } - - it 'exits with an error message indicating that no user was found' do - expect { cli.invoke(:delete, nil, options) }.to output( - a_string_including('No user with such email') - ).to_stdout - .and raise_error(SystemExit) - end - end - end - end - - describe '#approve' do - let(:total_users) { 10 } - - before do - Form::AdminSettings.new(registrations_mode: 'approved').save - Fabricate.times(total_users, :user) - end - - context 'with --all option' do - it 'approves all pending registrations' do - cli.invoke(:approve, nil, all: true) - - expect(User.pluck(:approved).all?(true)).to be(true) - end - end - - context 'with --number option' do - context 'when the number is positive' do - let(:options) { { number: 3 } } - - it 'approves the earliest n pending registrations' do - cli.invoke(:approve, nil, options) - - n_earliest_pending_registrations = User.order(created_at: :asc).first(options[:number]) - - expect(n_earliest_pending_registrations.all?(&:approved?)).to be(true) - end - - it 'does not approve the remaining pending registrations' do - cli.invoke(:approve, nil, options) - - pending_registrations = User.order(created_at: :asc).last(total_users - options[:number]) - - expect(pending_registrations.all?(&:approved?)).to be(false) - end - end - - context 'when the number is negative' do - it 'exits with an error message indicating that the number must be positive' do - expect { cli.invoke(:approve, nil, number: -1) }.to output( - a_string_including('Number must be positive') - ).to_stdout - .and raise_error(SystemExit) - end - end - - context 'when the given number is greater than the number of users' do - let(:options) { { number: total_users * 2 } } - - it 'approves all users' do - cli.invoke(:approve, nil, options) - - expect(User.pluck(:approved).all?(true)).to be(true) - end - - it 'does not raise any error' do - expect { cli.invoke(:approve, nil, options) } - .to_not raise_error - end - end - end - - context 'with username argument' do - context 'when the given username is found' do - let(:user) { User.last } - let(:arguments) { [user.account.username] } - - it 'approves the specified user successfully' do - cli.invoke(:approve, arguments) - - expect(user.reload.approved?).to be(true) - end - end - - context 'when the given username is not found' do - let(:arguments) { ['non_existent_username'] } - - it 'exits with an error message indicating that no such account was found' do - expect { cli.invoke(:approve, arguments) }.to output( - a_string_including('No such account') - ).to_stdout - .and raise_error(SystemExit) - end - end - end - end - - describe '#follow' do - context 'when the given username is not found' do - let(:arguments) { ['non_existent_username'] } - - it 'exits with an error message indicating that no account with the given username was found' do - expect { cli.invoke(:follow, arguments) }.to output( - a_string_including('No such account') - ).to_stdout - .and raise_error(SystemExit) - end - end - - context 'when the given username is found' do - let!(:target_account) { Fabricate(:account) } - let!(:follower_bob) { Fabricate(:account, username: 'bob') } - let!(:follower_rony) { Fabricate(:account, username: 'rony') } - let!(:follower_charles) { Fabricate(:account, username: 'charles') } - let(:follow_service) { instance_double(FollowService, call: nil) } - let(:scope) { Account.local.without_suspended } - - before do - allow(cli).to receive(:parallelize_with_progress).and_yield(follower_bob) - .and_yield(follower_rony) - .and_yield(follower_charles) - .and_return([3, nil]) - allow(FollowService).to receive(:new).and_return(follow_service) - end - - it 'makes all local accounts follow the target account' do - cli.follow(target_account.username) - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(follow_service).to have_received(:call).with(follower_bob, target_account, any_args).once - expect(follow_service).to have_received(:call).with(follower_rony, target_account, any_args).once - expect(follow_service).to have_received(:call).with(follower_charles, target_account, any_args).once - end - - it 'displays a successful message' do - expect { cli.follow(target_account.username) }.to output( - a_string_including('OK, followed target from 3 accounts') - ).to_stdout - end - end - end - - describe '#unfollow' do - context 'when the given username is not found' do - let(:arguments) { ['non_existent_username'] } - - it 'exits with an error message indicating that no account with the given username was found' do - expect { cli.invoke(:unfollow, arguments) }.to output( - a_string_including('No such account') - ).to_stdout - .and raise_error(SystemExit) - end - end - - context 'when the given username is found' do - let!(:target_account) { Fabricate(:account) } - let!(:follower_chris) { Fabricate(:account, username: 'chris') } - let!(:follower_rambo) { Fabricate(:account, username: 'rambo') } - let!(:follower_ana) { Fabricate(:account, username: 'ana') } - let(:unfollow_service) { instance_double(UnfollowService, call: nil) } - let(:scope) { target_account.followers.local } - - before do - accounts = [follower_chris, follower_rambo, follower_ana] - accounts.each { |account| target_account.follow!(account) } - allow(cli).to receive(:parallelize_with_progress).and_yield(follower_chris) - .and_yield(follower_rambo) - .and_yield(follower_ana) - .and_return([3, nil]) - allow(UnfollowService).to receive(:new).and_return(unfollow_service) - end - - it 'makes all local accounts unfollow the target account' do - cli.unfollow(target_account.username) - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(unfollow_service).to have_received(:call).with(follower_chris, target_account).once - expect(unfollow_service).to have_received(:call).with(follower_rambo, target_account).once - expect(unfollow_service).to have_received(:call).with(follower_ana, target_account).once - end - - it 'displays a successful message' do - expect { cli.unfollow(target_account.username) }.to output( - a_string_including('OK, unfollowed target from 3 accounts') - ).to_stdout - end - end - end - - describe '#backup' do - context 'when the given username is not found' do - let(:arguments) { ['non_existent_username'] } - - it 'exits with an error message indicating that there is no such account' do - expect { cli.invoke(:backup, arguments) }.to output( - a_string_including('No user with such username') - ).to_stdout - .and raise_error(SystemExit) - end - end - - context 'when the given username is found' do - let(:account) { Fabricate(:account) } - let(:user) { account.user } - let(:arguments) { [account.username] } - - it 'creates a new backup for the specified user' do - expect { cli.invoke(:backup, arguments) }.to change { user.backups.count }.by(1) - end - - it 'creates a backup job' do - allow(BackupWorker).to receive(:perform_async) - - cli.invoke(:backup, arguments) - latest_backup = user.backups.last - - expect(BackupWorker).to have_received(:perform_async).with(latest_backup.id).once - end - - it 'displays a successful message' do - expect { cli.invoke(:backup, arguments) }.to output( - a_string_including('OK') - ).to_stdout - end - end - end - - describe '#refresh' do - context 'with --all option' do - let!(:local_account) { Fabricate(:account, domain: nil) } - let!(:remote_account_example_com) { Fabricate(:account, domain: 'example.com') } - let!(:account_example_net) { Fabricate(:account, domain: 'example.net') } - let(:scope) { Account.remote } - - before do - allow(cli).to receive(:parallelize_with_progress).and_yield(remote_account_example_com) - .and_yield(account_example_net) - .and_return([2, nil]) - cli.options = { all: true } - end - - it 'refreshes the avatar for all remote accounts' do - allow(remote_account_example_com).to receive(:reset_avatar!) - allow(account_example_net).to receive(:reset_avatar!) - - cli.refresh - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(remote_account_example_com).to have_received(:reset_avatar!).once - expect(account_example_net).to have_received(:reset_avatar!).once - end - - it 'does not refresh avatar for local accounts' do - allow(local_account).to receive(:reset_avatar!) - - cli.refresh - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(local_account).to_not have_received(:reset_avatar!) - end - - it 'refreshes the header for all remote accounts' do - allow(remote_account_example_com).to receive(:reset_header!) - allow(account_example_net).to receive(:reset_header!) - - cli.refresh - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(remote_account_example_com).to have_received(:reset_header!).once - expect(account_example_net).to have_received(:reset_header!).once - end - - it 'does not refresh the header for local accounts' do - allow(local_account).to receive(:reset_header!) - - cli.refresh - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(local_account).to_not have_received(:reset_header!) - end - - it 'displays a successful message' do - expect { cli.refresh }.to output( - a_string_including('Refreshed 2 accounts') - ).to_stdout - end - - context 'with --dry-run option' do - before do - cli.options = { all: true, dry_run: true } - end - - it 'does not refresh the avatar for any account' do - allow(local_account).to receive(:reset_avatar!) - allow(remote_account_example_com).to receive(:reset_avatar!) - allow(account_example_net).to receive(:reset_avatar!) - - cli.refresh - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(local_account).to_not have_received(:reset_avatar!) - expect(remote_account_example_com).to_not have_received(:reset_avatar!) - expect(account_example_net).to_not have_received(:reset_avatar!) - end - - it 'does not refresh the header for any account' do - allow(local_account).to receive(:reset_header!) - allow(remote_account_example_com).to receive(:reset_header!) - allow(account_example_net).to receive(:reset_header!) - - cli.refresh - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(local_account).to_not have_received(:reset_header!) - expect(remote_account_example_com).to_not have_received(:reset_header!) - expect(account_example_net).to_not have_received(:reset_header!) - end - - it 'displays a successful message with (DRY RUN)' do - expect { cli.refresh }.to output( - a_string_including('Refreshed 2 accounts (DRY RUN)') - ).to_stdout - end - end - end - - context 'with a list of accts' do - let!(:account_example_com_a) { Fabricate(:account, domain: 'example.com') } - let!(:account_example_com_b) { Fabricate(:account, domain: 'example.com') } - let!(:account_example_net) { Fabricate(:account, domain: 'example.net') } - let(:arguments) { [account_example_com_a.acct, account_example_com_b.acct] } - - before do - allow(Account).to receive(:find_remote).with(account_example_com_a.username, account_example_com_a.domain).and_return(account_example_com_a) - allow(Account).to receive(:find_remote).with(account_example_com_b.username, account_example_com_b.domain).and_return(account_example_com_b) - allow(Account).to receive(:find_remote).with(account_example_net.username, account_example_net.domain).and_return(account_example_net) - end - - it 'resets the avatar for the specified accounts' do - allow(account_example_com_a).to receive(:reset_avatar!) - allow(account_example_com_b).to receive(:reset_avatar!) - - cli.refresh(*arguments) - - expect(account_example_com_a).to have_received(:reset_avatar!).once - expect(account_example_com_b).to have_received(:reset_avatar!).once - end - - it 'does not reset the avatar for unspecified accounts' do - allow(account_example_net).to receive(:reset_avatar!) - - cli.refresh(*arguments) - - expect(account_example_net).to_not have_received(:reset_avatar!) - end - - it 'resets the header for the specified accounts' do - allow(account_example_com_a).to receive(:reset_header!) - allow(account_example_com_b).to receive(:reset_header!) - - cli.refresh(*arguments) - - expect(account_example_com_a).to have_received(:reset_header!).once - expect(account_example_com_b).to have_received(:reset_header!).once - end - - it 'does not reset the header for unspecified accounts' do - allow(account_example_net).to receive(:reset_header!) - - cli.refresh(*arguments) - - expect(account_example_net).to_not have_received(:reset_header!) - end - - context 'when an UnexpectedResponseError is raised' do - it 'displays a failure message' do - allow(account_example_com_a).to receive(:reset_avatar!).and_raise(Mastodon::UnexpectedResponseError) - - expect { cli.refresh(*arguments) } - .to output( - a_string_including("Account failed: #{account_example_com_a.username}@#{account_example_com_a.domain}") - ).to_stdout - end - end - - context 'when a specified account is not found' do - it 'exits with an error message' do - allow(Account).to receive(:find_remote).with(account_example_com_b.username, account_example_com_b.domain).and_return(nil) - - expect { cli.refresh(*arguments) }.to output( - a_string_including('No such account') - ).to_stdout - .and raise_error(SystemExit) - end - end - - context 'with --dry-run option' do - before do - cli.options = { dry_run: true } - end - - it 'does not refresh the avatar for any account' do - allow(account_example_com_a).to receive(:reset_avatar!) - allow(account_example_com_b).to receive(:reset_avatar!) - - cli.refresh(*arguments) - - expect(account_example_com_a).to_not have_received(:reset_avatar!) - expect(account_example_com_b).to_not have_received(:reset_avatar!) - end - - it 'does not refresh the header for any account' do - allow(account_example_com_a).to receive(:reset_header!) - allow(account_example_com_b).to receive(:reset_header!) - - cli.refresh(*arguments) - - expect(account_example_com_a).to_not have_received(:reset_header!) - expect(account_example_com_b).to_not have_received(:reset_header!) - end - end - end - - context 'with --domain option' do - let!(:account_example_com_a) { Fabricate(:account, domain: 'example.com') } - let!(:account_example_com_b) { Fabricate(:account, domain: 'example.com') } - let!(:account_example_net) { Fabricate(:account, domain: 'example.net') } - let(:domain) { 'example.com' } - let(:scope) { Account.remote.where(domain: domain) } - - before do - allow(cli).to receive(:parallelize_with_progress).and_yield(account_example_com_a) - .and_yield(account_example_com_b) - .and_return([2, nil]) - - cli.options = { domain: domain } - end - - it 'refreshes the avatar for all accounts on specified domain' do - allow(account_example_com_a).to receive(:reset_avatar!) - allow(account_example_com_b).to receive(:reset_avatar!) - - cli.refresh - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(account_example_com_a).to have_received(:reset_avatar!).once - expect(account_example_com_b).to have_received(:reset_avatar!).once - end - - it 'does not refresh the avatar for accounts outside specified domain' do - allow(account_example_net).to receive(:reset_avatar!) - - cli.refresh - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(account_example_net).to_not have_received(:reset_avatar!) - end - - it 'refreshes the header for all accounts on specified domain' do - allow(account_example_com_a).to receive(:reset_header!) - allow(account_example_com_b).to receive(:reset_header!) - - cli.refresh - - expect(cli).to have_received(:parallelize_with_progress).with(scope) - expect(account_example_com_a).to have_received(:reset_header!).once - expect(account_example_com_b).to have_received(:reset_header!).once - end - - it 'does not refresh the header for accounts outside specified domain' do - allow(account_example_net).to receive(:reset_header!) - - cli.refresh - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(account_example_net).to_not have_received(:reset_header!) - end - end - - context 'when neither a list of accts nor options are provided' do - it 'exits with an error message' do - expect { cli.refresh }.to output( - a_string_including('No account(s) given') - ).to_stdout - .and raise_error(SystemExit) - end - end - end - - describe '#rotate' do - context 'when neither username nor --all option are given' do - it 'exits with an error message' do - expect { cli.rotate }.to output( - a_string_including('No account(s) given') - ).to_stdout - .and raise_error(SystemExit) - end - end - - context 'when a username is given' do - let(:account) { Fabricate(:account) } - - it 'correctly rotates keys for the specified account' do - old_private_key = account.private_key - old_public_key = account.public_key - - cli.rotate(account.username) - account.reload - - expect(account.private_key).to_not eq(old_private_key) - expect(account.public_key).to_not eq(old_public_key) - end - - it 'broadcasts the new keys for the specified account' do - allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_in) - - cli.rotate(account.username) - - expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_in).with(anything, account.id, anything).once - end - - context 'when the given username is not found' do - it 'exits with an error message when the specified username is not found' do - expect { cli.rotate('non_existent_username') }.to output( - a_string_including('No such account') - ).to_stdout - .and raise_error(SystemExit) - end - end - end - - context 'when --all option is provided' do - let(:accounts) { Fabricate.times(3, :account) } - let(:options) { { all: true } } - - before do - allow(Account).to receive(:local).and_return(Account.where(id: accounts.map(&:id))) - cli.options = { all: true } - end - - it 'correctly rotates keys for all local accounts' do - old_private_keys = accounts.map(&:private_key) - old_public_keys = accounts.map(&:public_key) - - cli.rotate - accounts.each(&:reload) - - expect(accounts.map(&:private_key)).to_not eq(old_private_keys) - expect(accounts.map(&:public_key)).to_not eq(old_public_keys) - end - - it 'broadcasts the new keys for each account' do - allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_in) - - cli.rotate - - accounts.each do |account| - expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_in).with(anything, account.id, anything).once - end - end - end - end - - describe '#merge' do - shared_examples 'an account not found' do |acct| - it 'exits with an error message indicating that there is no such account' do - expect { cli.invoke(:merge, arguments) }.to output( - a_string_including("No such account (#{acct})") - ).to_stdout - .and raise_error(SystemExit) - end - end - - context 'when "from_account" is not found' do - let(:to_account) { Fabricate(:account, domain: 'example.com') } - let(:arguments) { ['non_existent_username@domain.com', "#{to_account.username}@#{to_account.domain}"] } - - it_behaves_like 'an account not found', 'non_existent_username@domain.com' - end - - context 'when "from_account" is a local account' do - let(:from_account) { Fabricate(:account, domain: nil, username: 'bob') } - let(:to_account) { Fabricate(:account, domain: 'example.com') } - let(:arguments) { [from_account.username, "#{to_account.username}@#{to_account.domain}"] } - - it_behaves_like 'an account not found', 'bob' - end - - context 'when "to_account" is not found' do - let(:from_account) { Fabricate(:account, domain: 'example.com') } - let(:arguments) { ["#{from_account.username}@#{from_account.domain}", 'non_existent_username'] } - - it_behaves_like 'an account not found', 'non_existent_username' - end - - context 'when "to_account" is local' do - let(:from_account) { Fabricate(:account, domain: 'example.com') } - let(:to_account) { Fabricate(:account, domain: nil, username: 'bob') } - let(:arguments) do - ["#{from_account.username}@#{from_account.domain}", "#{to_account.username}@#{to_account.domain}"] - end - - it_behaves_like 'an account not found', 'bob@' - end - - context 'when "from_account" and "to_account" public keys do not match' do - let(:from_account) { instance_double(Account, username: 'bob', domain: 'example1.com', local?: false, public_key: 'from_account') } - let(:to_account) { instance_double(Account, username: 'bob', domain: 'example2.com', local?: false, public_key: 'to_account') } - let(:arguments) do - ["#{from_account.username}@#{from_account.domain}", "#{to_account.username}@#{to_account.domain}"] - end - - before do - allow(Account).to receive(:find_remote).with(from_account.username, from_account.domain).and_return(from_account) - allow(Account).to receive(:find_remote).with(to_account.username, to_account.domain).and_return(to_account) - end - - it 'exits with an error message indicating that the accounts do not have the same pub key' do - expect { cli.invoke(:merge, arguments) }.to output( - a_string_including("Accounts don't have the same public key, might not be duplicates!\nOverride with --force") - ).to_stdout - .and raise_error(SystemExit) - end - - context 'with --force option' do - let(:options) { { force: true } } - - before do - allow(to_account).to receive(:merge_with!) - allow(from_account).to receive(:destroy) - end - - it 'merges "from_account" into "to_account"' do - cli.invoke(:merge, arguments, options) - - expect(to_account).to have_received(:merge_with!).with(from_account).once - end - - it 'deletes "from_account"' do - cli.invoke(:merge, arguments, options) - - expect(from_account).to have_received(:destroy).once - end - end - end - - context 'when "from_account" and "to_account" public keys match' do - let(:from_account) { instance_double(Account, username: 'bob', domain: 'example1.com', local?: false, public_key: 'pub_key') } - let(:to_account) { instance_double(Account, username: 'bob', domain: 'example2.com', local?: false, public_key: 'pub_key') } - let(:arguments) do - ["#{from_account.username}@#{from_account.domain}", "#{to_account.username}@#{to_account.domain}"] - end - - before do - allow(Account).to receive(:find_remote).with(from_account.username, from_account.domain).and_return(from_account) - allow(Account).to receive(:find_remote).with(to_account.username, to_account.domain).and_return(to_account) - allow(to_account).to receive(:merge_with!) - allow(from_account).to receive(:destroy) - end - - it 'merges "from_account" into "to_account"' do - cli.invoke(:merge, arguments) - - expect(to_account).to have_received(:merge_with!).with(from_account).once - end - - it 'deletes "from_account"' do - cli.invoke(:merge, arguments) - - expect(from_account).to have_received(:destroy) - end - end - end - - describe '#cull' do - let(:delete_account_service) { instance_double(DeleteAccountService, call: nil) } - let!(:tom) { Fabricate(:account, updated_at: 30.days.ago, username: 'tom', uri: 'https://example.com/users/tom', domain: 'example.com') } - let!(:bob) { Fabricate(:account, updated_at: 30.days.ago, last_webfingered_at: nil, username: 'bob', uri: 'https://example.org/users/bob', domain: 'example.org') } - let!(:gon) { Fabricate(:account, updated_at: 15.days.ago, last_webfingered_at: 15.days.ago, username: 'gon', uri: 'https://example.net/users/gon', domain: 'example.net') } - let!(:ana) { Fabricate(:account, username: 'ana', uri: 'https://example.com/users/ana', domain: 'example.com') } - let!(:tales) { Fabricate(:account, updated_at: 10.days.ago, last_webfingered_at: nil, username: 'tales', uri: 'https://example.net/users/tales', domain: 'example.net') } - - before do - allow(DeleteAccountService).to receive(:new).and_return(delete_account_service) - end - - context 'when no domain is specified' do - let(:scope) { Account.remote.where(protocol: :activitypub).partitioned } - - before do - allow(cli).to receive(:parallelize_with_progress).and_yield(tom) - .and_yield(bob) - .and_yield(gon) - .and_yield(ana) - .and_yield(tales) - .and_return([5, 3]) - stub_request(:head, 'https://example.org/users/bob').to_return(status: 404) - stub_request(:head, 'https://example.net/users/gon').to_return(status: 410) - stub_request(:head, 'https://example.net/users/tales').to_return(status: 200) - end - - it 'deletes all inactive remote accounts that longer exist in the origin server' do - cli.cull - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(delete_account_service).to have_received(:call).with(bob, reserve_username: false).once - expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once - end - - it 'does not delete any active remote account that still exists in the origin server' do - cli.cull - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(delete_account_service).to_not have_received(:call).with(tom, reserve_username: false) - expect(delete_account_service).to_not have_received(:call).with(ana, reserve_username: false) - expect(delete_account_service).to_not have_received(:call).with(tales, reserve_username: false) - end - - it 'touches inactive remote accounts that have not been deleted' do - allow(tales).to receive(:touch) - - cli.cull - - expect(tales).to have_received(:touch).once - end - - it 'displays the summary correctly' do - expect { cli.cull }.to output( - a_string_including('Visited 5 accounts, removed 3') - ).to_stdout - end - end - - context 'when a domain is specified' do - let(:domain) { 'example.net' } - let(:scope) { Account.remote.where(protocol: :activitypub, domain: domain).partitioned } - - before do - allow(cli).to receive(:parallelize_with_progress).and_yield(gon) - .and_yield(tales) - .and_return([2, 2]) - stub_request(:head, 'https://example.net/users/gon').to_return(status: 410) - stub_request(:head, 'https://example.net/users/tales').to_return(status: 404) - end - - it 'deletes inactive remote accounts that longer exist in the specified domain' do - cli.cull(domain) - - expect(cli).to have_received(:parallelize_with_progress).with(scope).once - expect(delete_account_service).to have_received(:call).with(gon, reserve_username: false).once - expect(delete_account_service).to have_received(:call).with(tales, reserve_username: false).once - end - - it 'displays the summary correctly' do - expect { cli.cull }.to output( - a_string_including('Visited 2 accounts, removed 2') - ).to_stdout - end - end - - context 'when a domain is unavailable' do - shared_examples 'an unavailable domain' do - before do - allow(cli).to receive(:parallelize_with_progress).and_yield(tales).and_return([1, 0]) - end - - it 'skips accounts from the unavailable domain' do - cli.cull - - expect(delete_account_service).to_not have_received(:call).with(tales, reserve_username: false) - end - - it 'displays the summary correctly' do - expect { cli.cull }.to output( - a_string_including("Visited 1 accounts, removed 0\nThe following domains were not available during the check:\n example.net") - ).to_stdout - end - end - - context 'when a connection timeout occurs' do - before do - stub_request(:head, 'https://example.net/users/tales').to_timeout - end - - it_behaves_like 'an unavailable domain' - end - - context 'when a connection error occurs' do - before do - stub_request(:head, 'https://example.net/users/tales').to_raise(HTTP::ConnectionError) - end - - it_behaves_like 'an unavailable domain' - end - - context 'when an ssl error occurs' do - before do - stub_request(:head, 'https://example.net/users/tales').to_raise(OpenSSL::SSL::SSLError) - end - - it_behaves_like 'an unavailable domain' - end - - context 'when a private network address error occurs' do - before do - stub_request(:head, 'https://example.net/users/tales').to_raise(Mastodon::PrivateNetworkAddressError) - end - - it_behaves_like 'an unavailable domain' - end - end - end - - describe '#reset_relationships' do - let(:target_account) { Fabricate(:account) } - let(:arguments) { [target_account.username] } - - context 'when no option is given' do - it 'exits with an error message indicating that at least one option is required' do - expect { cli.invoke(:reset_relationships, arguments) }.to output( - a_string_including('Please specify either --follows or --followers, or both') - ).to_stdout - .and raise_error(SystemExit) - end - end - - context 'when the given username is not found' do - let(:arguments) { ['non_existent_username'] } - - it 'exits with an error message indicating that there is no such account' do - expect { cli.invoke(:reset_relationships, arguments, follows: true) }.to output( - a_string_including('No such account') - ).to_stdout - .and raise_error(SystemExit) - end - end - - context 'when the given username is found' do - let(:total_relationships) { 10 } - let!(:accounts) { Fabricate.times(total_relationships, :account) } - - context 'with --follows option' do - let(:options) { { follows: true } } - - before do - accounts.each { |account| target_account.follow!(account) } - end - - it 'resets all "following" relationships from the target account' do - cli.invoke(:reset_relationships, arguments, options) - - expect(target_account.reload.following).to be_empty - end - - it 'calls BootstrapTimelineWorker once to rebuild the timeline' do - allow(BootstrapTimelineWorker).to receive(:perform_async) - - cli.invoke(:reset_relationships, arguments, options) - - expect(BootstrapTimelineWorker).to have_received(:perform_async).with(target_account.id).once - end - - it 'displays a successful message' do - expect { cli.invoke(:reset_relationships, arguments, options) }.to output( - a_string_including("Processed #{total_relationships} relationships") - ).to_stdout - end - end - - context 'with --followers option' do - let(:options) { { followers: true } } - - before do - accounts.each { |account| account.follow!(target_account) } - end - - it 'resets all "followers" relationships from the target account' do - cli.invoke(:reset_relationships, arguments, options) - - expect(target_account.reload.followers).to be_empty - end - - it 'displays a successful message' do - expect { cli.invoke(:reset_relationships, arguments, options) }.to output( - a_string_including("Processed #{total_relationships} relationships") - ).to_stdout - end - end - - context 'with --follows and --followers options' do - let(:options) { { followers: true, follows: true } } - - before do - accounts.first(6).each { |account| account.follow!(target_account) } - accounts.last(4).each { |account| target_account.follow!(account) } - end - - it 'resets all "followers" relationships from the target account' do - cli.invoke(:reset_relationships, arguments, options) - - expect(target_account.reload.followers).to be_empty - end - - it 'resets all "following" relationships from the target account' do - cli.invoke(:reset_relationships, arguments, options) - - expect(target_account.reload.following).to be_empty - end - - it 'calls BootstrapTimelineWorker once to rebuild the timeline' do - allow(BootstrapTimelineWorker).to receive(:perform_async) - - cli.invoke(:reset_relationships, arguments, options) - - expect(BootstrapTimelineWorker).to have_received(:perform_async).with(target_account.id).once - end - - it 'displays a successful message' do - expect { cli.invoke(:reset_relationships, arguments, options) }.to output( - a_string_including("Processed #{total_relationships} relationships") - ).to_stdout - end - end - end - end -end diff --git a/spec/lib/mastodon/cli/cache_spec.rb b/spec/lib/mastodon/cli/cache_spec.rb deleted file mode 100644 index 3ab42dc8c..000000000 --- a/spec/lib/mastodon/cli/cache_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/cache' - -describe Mastodon::CLI::Cache do - let(:cli) { described_class.new } - - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end - - describe '#clear' do - before { allow(Rails.cache).to receive(:clear) } - - it 'clears the Rails cache' do - expect { cli.invoke(:clear) }.to output( - a_string_including('OK') - ).to_stdout - expect(Rails.cache).to have_received(:clear) - end - end - - describe '#recount' do - context 'with the `accounts` argument' do - let(:arguments) { ['accounts'] } - let(:account_stat) { Fabricate(:account_stat) } - - before do - account_stat.update(statuses_count: 123) - end - - it 're-calculates account records in the cache' do - expect { cli.invoke(:recount, arguments) }.to output( - a_string_including('OK') - ).to_stdout - - expect(account_stat.reload.statuses_count).to be_zero - end - end - - context 'with the `statuses` argument' do - let(:arguments) { ['statuses'] } - let(:status_stat) { Fabricate(:status_stat) } - - before do - status_stat.update(replies_count: 123) - end - - it 're-calculates account records in the cache' do - expect { cli.invoke(:recount, arguments) }.to output( - a_string_including('OK') - ).to_stdout - - expect(status_stat.reload.replies_count).to be_zero - end - end - - context 'with an unknown type' do - let(:arguments) { ['other-type'] } - - it 'Exits with an error message' do - expect { cli.invoke(:recount, arguments) }.to output( - a_string_including('Unknown') - ).to_stdout.and raise_error(SystemExit) - end - end - end -end diff --git a/spec/lib/mastodon/cli/canonical_email_blocks_spec.rb b/spec/lib/mastodon/cli/canonical_email_blocks_spec.rb deleted file mode 100644 index eb57a3cd1..000000000 --- a/spec/lib/mastodon/cli/canonical_email_blocks_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/canonical_email_blocks' - -describe Mastodon::CLI::CanonicalEmailBlocks do - let(:cli) { described_class.new } - - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end - - describe '#find' do - let(:arguments) { ['user@example.com'] } - - context 'when a block is present' do - before { Fabricate(:canonical_email_block, email: 'user@example.com') } - - it 'announces the presence of the block' do - expect { cli.invoke(:find, arguments) }.to output( - a_string_including('user@example.com is blocked') - ).to_stdout - end - end - - context 'when a block is not present' do - it 'announces the absence of the block' do - expect { cli.invoke(:find, arguments) }.to output( - a_string_including('user@example.com is not blocked') - ).to_stdout - end - end - end - - describe '#remove' do - let(:arguments) { ['user@example.com'] } - - context 'when a block is present' do - before { Fabricate(:canonical_email_block, email: 'user@example.com') } - - it 'removes the block' do - expect { cli.invoke(:remove, arguments) }.to output( - a_string_including('Unblocked user@example.com') - ).to_stdout - - expect(CanonicalEmailBlock.matching_email('user@example.com')).to be_empty - end - end - - context 'when a block is not present' do - it 'announces the absence of the block' do - expect { cli.invoke(:remove, arguments) }.to output( - a_string_including('user@example.com is not blocked') - ).to_stdout - end - end - end -end diff --git a/spec/lib/mastodon/cli/domains_spec.rb b/spec/lib/mastodon/cli/domains_spec.rb deleted file mode 100644 index ea58845c0..000000000 --- a/spec/lib/mastodon/cli/domains_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/domains' - -describe Mastodon::CLI::Domains do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end -end diff --git a/spec/lib/mastodon/cli/email_domain_blocks_spec.rb b/spec/lib/mastodon/cli/email_domain_blocks_spec.rb deleted file mode 100644 index 333ae3f2b..000000000 --- a/spec/lib/mastodon/cli/email_domain_blocks_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/email_domain_blocks' - -describe Mastodon::CLI::EmailDomainBlocks do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end -end diff --git a/spec/lib/mastodon/cli/emoji_spec.rb b/spec/lib/mastodon/cli/emoji_spec.rb deleted file mode 100644 index 9b5865372..000000000 --- a/spec/lib/mastodon/cli/emoji_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/emoji' - -describe Mastodon::CLI::Emoji do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end -end diff --git a/spec/lib/mastodon/cli/feeds_spec.rb b/spec/lib/mastodon/cli/feeds_spec.rb deleted file mode 100644 index 030f08721..000000000 --- a/spec/lib/mastodon/cli/feeds_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/feeds' - -describe Mastodon::CLI::Feeds do - let(:cli) { described_class.new } - - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end - - describe '#build' do - before { Fabricate(:account) } - - context 'with --all option' do - let(:options) { { all: true } } - - it 'regenerates feeds for all accounts' do - expect { cli.invoke(:build, [], options) }.to output( - a_string_including('Regenerated feeds') - ).to_stdout - end - end - - context 'with a username' do - before { Fabricate(:account, username: 'alice') } - - let(:arguments) { ['alice'] } - - it 'regenerates feeds for the account' do - expect { cli.invoke(:build, arguments) }.to output( - a_string_including('OK') - ).to_stdout - end - end - - context 'with invalid username' do - let(:arguments) { ['invalid-username'] } - - it 'displays an error and exits' do - expect { cli.invoke(:build, arguments) }.to output( - a_string_including('No such account') - ).to_stdout.and raise_error(SystemExit) - end - end - end - - describe '#clear' do - before do - allow(redis).to receive(:del).with(key_namespace) - end - - it 'clears the redis `feed:*` namespace' do - expect { cli.invoke(:clear) }.to output( - a_string_including('OK') - ).to_stdout - - expect(redis).to have_received(:del).with(key_namespace).once - end - - def key_namespace - redis.keys('feed:*') - end - end -end diff --git a/spec/lib/mastodon/cli/ip_blocks_spec.rb b/spec/lib/mastodon/cli/ip_blocks_spec.rb deleted file mode 100644 index 030d9fcb1..000000000 --- a/spec/lib/mastodon/cli/ip_blocks_spec.rb +++ /dev/null @@ -1,298 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/ip_blocks' - -describe Mastodon::CLI::IpBlocks do - let(:cli) { described_class.new } - - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end - - describe '#add' do - let(:ip_list) do - [ - '192.0.2.1', - '172.16.0.1', - '192.0.2.0/24', - '172.16.0.0/16', - '10.0.0.0/8', - '2001:0db8:85a3:0000:0000:8a2e:0370:7334', - 'fe80::1', - '::1', - '2001:0db8::/32', - 'fe80::/10', - '::/128', - ] - end - let(:options) { { severity: 'no_access' } } - - shared_examples 'ip address blocking' do - it 'blocks all specified IP addresses' do - cli.invoke(:add, ip_list, options) - - blocked_ip_addresses = IpBlock.where(ip: ip_list).pluck(:ip) - expected_ip_addresses = ip_list.map { |ip| IPAddr.new(ip) } - - expect(blocked_ip_addresses).to match_array(expected_ip_addresses) - end - - it 'sets the severity for all blocked IP addresses' do - cli.invoke(:add, ip_list, options) - - blocked_ips_severity = IpBlock.where(ip: ip_list).pluck(:severity).all?(options[:severity]) - - expect(blocked_ips_severity).to be(true) - end - - it 'displays a success message with a summary' do - expect { cli.invoke(:add, ip_list, options) }.to output( - a_string_including("Added #{ip_list.size}, skipped 0, failed 0") - ).to_stdout - end - end - - context 'with valid IP addresses' do - include_examples 'ip address blocking' - end - - context 'when a specified IP address is already blocked' do - let!(:blocked_ip) { IpBlock.create(ip: ip_list.last, severity: options[:severity]) } - - it 'skips the already blocked IP address' do - allow(IpBlock).to receive(:new).and_call_original - - cli.invoke(:add, ip_list, options) - - expect(IpBlock).to_not have_received(:new).with(ip: ip_list.last) - end - - it 'displays the correct summary' do - expect { cli.invoke(:add, ip_list, options) }.to output( - a_string_including("#{ip_list.last} is already blocked\nAdded #{ip_list.size - 1}, skipped 1, failed 0") - ).to_stdout - end - - context 'with --force option' do - let!(:blocked_ip) { IpBlock.create(ip: ip_list.last, severity: 'no_access') } - let(:options) { { severity: 'sign_up_requires_approval', force: true } } - - it 'overwrites the existing IP block record' do - expect { cli.invoke(:add, ip_list, options) } - .to change { blocked_ip.reload.severity } - .from('no_access') - .to('sign_up_requires_approval') - end - - include_examples 'ip address blocking' - end - end - - context 'when a specified IP address is invalid' do - let(:ip_list) { ['320.15.175.0', '9.5.105.255', '0.0.0.0'] } - - it 'displays the correct summary' do - expect { cli.invoke(:add, ip_list, options) }.to output( - a_string_including("#{ip_list.first} is invalid\nAdded #{ip_list.size - 1}, skipped 0, failed 1") - ).to_stdout - end - end - - context 'with --comment option' do - let(:options) { { severity: 'no_access', comment: 'Spam' } } - - include_examples 'ip address blocking' - end - - context 'with --duration option' do - let(:options) { { severity: 'no_access', duration: 10.days } } - - include_examples 'ip address blocking' - end - - context 'with "sign_up_requires_approval" severity' do - let(:options) { { severity: 'sign_up_requires_approval' } } - - include_examples 'ip address blocking' - end - - context 'with "sign_up_block" severity' do - let(:options) { { severity: 'sign_up_block' } } - - include_examples 'ip address blocking' - end - - context 'when a specified IP address fails to be blocked' do - let(:ip_address) { '127.0.0.1' } - let(:ip_block) { instance_double(IpBlock, ip: ip_address, save: false) } - - before do - allow(IpBlock).to receive(:new).and_return(ip_block) - allow(ip_block).to receive(:severity=) - allow(ip_block).to receive(:expires_in=) - end - - it 'displays an error message' do - expect { cli.invoke(:add, [ip_address], options) } - .to output( - a_string_including("#{ip_address} could not be saved") - ).to_stdout - end - end - - context 'when no IP address is provided' do - it 'exits with an error message' do - expect { cli.add }.to output( - a_string_including('No IP(s) given') - ).to_stdout - .and raise_error(SystemExit) - end - end - end - - describe '#remove' do - context 'when removing exact matches' do - let(:ip_list) do - [ - '192.0.2.1', - '172.16.0.1', - '192.0.2.0/24', - '172.16.0.0/16', - '10.0.0.0/8', - '2001:0db8:85a3:0000:0000:8a2e:0370:7334', - 'fe80::1', - '::1', - '2001:0db8::/32', - 'fe80::/10', - '::/128', - ] - end - - before do - ip_list.each { |ip| IpBlock.create(ip: ip, severity: :no_access) } - end - - it 'removes exact IP blocks' do - cli.invoke(:remove, ip_list) - - expect(IpBlock.where(ip: ip_list)).to_not exist - end - - it 'displays success message with a summary' do - expect { cli.invoke(:remove, ip_list) }.to output( - a_string_including("Removed #{ip_list.size}, skipped 0") - ).to_stdout - end - end - - context 'with --force option' do - let!(:first_ip_range_block) { IpBlock.create(ip: '192.168.0.0/24', severity: :no_access) } - let!(:second_ip_range_block) { IpBlock.create(ip: '10.0.0.0/16', severity: :no_access) } - let!(:third_ip_range_block) { IpBlock.create(ip: '172.16.0.0/20', severity: :no_access) } - let(:arguments) { ['192.168.0.5', '10.0.1.50'] } - let(:options) { { force: true } } - - it 'removes blocks for IP ranges that cover given IP(s)' do - cli.invoke(:remove, arguments, options) - - expect(IpBlock.where(id: [first_ip_range_block.id, second_ip_range_block.id])).to_not exist - end - - it 'does not remove other IP ranges' do - cli.invoke(:remove, arguments, options) - - expect(IpBlock.where(id: third_ip_range_block.id)).to exist - end - end - - context 'when a specified IP address is not blocked' do - let(:unblocked_ip) { '192.0.2.1' } - - it 'skips the IP address' do - expect { cli.invoke(:remove, [unblocked_ip]) }.to output( - a_string_including("#{unblocked_ip} is not yet blocked") - ).to_stdout - end - - it 'displays the summary correctly' do - expect { cli.invoke(:remove, [unblocked_ip]) }.to output( - a_string_including('Removed 0, skipped 1') - ).to_stdout - end - end - - context 'when a specified IP address is invalid' do - let(:invalid_ip) { '320.15.175.0' } - - it 'skips the invalid IP address' do - expect { cli.invoke(:remove, [invalid_ip]) }.to output( - a_string_including("#{invalid_ip} is invalid") - ).to_stdout - end - - it 'displays the summary correctly' do - expect { cli.invoke(:remove, [invalid_ip]) }.to output( - a_string_including('Removed 0, skipped 1') - ).to_stdout - end - end - - context 'when no IP address is provided' do - it 'exits with an error message' do - expect { cli.remove }.to output( - a_string_including('No IP(s) given') - ).to_stdout - .and raise_error(SystemExit) - end - end - end - - describe '#export' do - let(:first_ip_range_block) { IpBlock.create(ip: '192.168.0.0/24', severity: :no_access) } - let(:second_ip_range_block) { IpBlock.create(ip: '10.0.0.0/16', severity: :no_access) } - let(:third_ip_range_block) { IpBlock.create(ip: '127.0.0.1', severity: :sign_up_block) } - - context 'when --format option is set to "plain"' do - let(:options) { { format: 'plain' } } - - it 'exports blocked IPs with "no_access" severity in plain format' do - expect { cli.invoke(:export, nil, options) }.to output( - a_string_including("#{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}\n#{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix}") - ).to_stdout - end - - it 'does not export bloked IPs with different severities' do - expect { cli.invoke(:export, nil, options) }.to_not output( - a_string_including("#{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}") - ).to_stdout - end - end - - context 'when --format option is set to "nginx"' do - let(:options) { { format: 'nginx' } } - - it 'exports blocked IPs with "no_access" severity in plain format' do - expect { cli.invoke(:export, nil, options) }.to output( - a_string_including("deny #{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};\ndeny #{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix};") - ).to_stdout - end - - it 'does not export bloked IPs with different severities' do - expect { cli.invoke(:export, nil, options) }.to_not output( - a_string_including("deny #{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};") - ).to_stdout - end - end - - context 'when --format option is not provided' do - it 'exports blocked IPs in plain format by default' do - expect { cli.export }.to output( - a_string_including("#{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}\n#{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix}") - ).to_stdout - end - end - end -end diff --git a/spec/lib/mastodon/cli/main_spec.rb b/spec/lib/mastodon/cli/main_spec.rb deleted file mode 100644 index e3709afe3..000000000 --- a/spec/lib/mastodon/cli/main_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/main' - -describe Mastodon::CLI::Main do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end - - describe 'version' do - it 'returns the Mastodon version' do - expect { described_class.new.invoke(:version) }.to output( - a_string_including(Mastodon::Version.to_s) - ).to_stdout - end - end -end diff --git a/spec/lib/mastodon/cli/maintenance_spec.rb b/spec/lib/mastodon/cli/maintenance_spec.rb deleted file mode 100644 index 12cd9ca8a..000000000 --- a/spec/lib/mastodon/cli/maintenance_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/maintenance' - -describe Mastodon::CLI::Maintenance do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end -end diff --git a/spec/lib/mastodon/cli/media_spec.rb b/spec/lib/mastodon/cli/media_spec.rb deleted file mode 100644 index 29f7d424a..000000000 --- a/spec/lib/mastodon/cli/media_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/media' - -describe Mastodon::CLI::Media do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end -end diff --git a/spec/lib/mastodon/cli/preview_cards_spec.rb b/spec/lib/mastodon/cli/preview_cards_spec.rb deleted file mode 100644 index b4b018b3b..000000000 --- a/spec/lib/mastodon/cli/preview_cards_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/preview_cards' - -describe Mastodon::CLI::PreviewCards do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end -end diff --git a/spec/lib/mastodon/cli/search_spec.rb b/spec/lib/mastodon/cli/search_spec.rb deleted file mode 100644 index d5cae5bf4..000000000 --- a/spec/lib/mastodon/cli/search_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/search' - -describe Mastodon::CLI::Search do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end -end diff --git a/spec/lib/mastodon/cli/settings_spec.rb b/spec/lib/mastodon/cli/settings_spec.rb deleted file mode 100644 index ae58e74e5..000000000 --- a/spec/lib/mastodon/cli/settings_spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/settings' - -describe Mastodon::CLI::Settings do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end - - describe 'subcommand "registrations"' do - let(:cli) { Mastodon::CLI::Registrations.new } - - before do - Setting.registrations_mode = nil - end - - describe '#open' do - it 'changes "registrations_mode" to "open"' do - expect { cli.open }.to change(Setting, :registrations_mode).from(nil).to('open') - end - - it 'displays success message' do - expect { cli.open }.to output( - a_string_including('OK') - ).to_stdout - end - end - - describe '#approved' do - it 'changes "registrations_mode" to "approved"' do - expect { cli.approved }.to change(Setting, :registrations_mode).from(nil).to('approved') - end - - it 'displays success message' do - expect { cli.approved }.to output( - a_string_including('OK') - ).to_stdout - end - - context 'with --require-reason' do - before do - cli.options = { require_reason: true } - end - - it 'changes "registrations_mode" to "approved"' do - expect { cli.approved }.to change(Setting, :registrations_mode).from(nil).to('approved') - end - - it 'sets "require_invite_text" to "true"' do - expect { cli.approved }.to change(Setting, :require_invite_text).from(false).to(true) - end - end - end - - describe '#close' do - it 'changes "registrations_mode" to "none"' do - expect { cli.close }.to change(Setting, :registrations_mode).from(nil).to('none') - end - - it 'displays success message' do - expect { cli.close }.to output( - a_string_including('OK') - ).to_stdout - end - end - end -end diff --git a/spec/lib/mastodon/cli/statuses_spec.rb b/spec/lib/mastodon/cli/statuses_spec.rb deleted file mode 100644 index 2430a8841..000000000 --- a/spec/lib/mastodon/cli/statuses_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/statuses' - -describe Mastodon::CLI::Statuses do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end -end diff --git a/spec/lib/mastodon/cli/upgrade_spec.rb b/spec/lib/mastodon/cli/upgrade_spec.rb deleted file mode 100644 index 9e0ab9d06..000000000 --- a/spec/lib/mastodon/cli/upgrade_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/cli/upgrade' - -describe Mastodon::CLI::Upgrade do - describe '.exit_on_failure?' do - it 'returns true' do - expect(described_class.exit_on_failure?).to be true - end - end -end diff --git a/spec/lib/mastodon/migration_warning_spec.rb b/spec/lib/mastodon/migration_warning_spec.rb deleted file mode 100644 index 4adf0837a..000000000 --- a/spec/lib/mastodon/migration_warning_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'mastodon/migration_warning' - -describe Mastodon::MigrationWarning do - describe 'migration_duration_warning' do - before do - allow(migration).to receive(:valid_environment?).and_return(true) - allow(migration).to receive(:sleep).with(1) - end - - let(:migration) { Class.new(ActiveRecord::Migration[6.1]).extend(described_class) } - - context 'with the default message' do - it 'warns about long migrations' do - expectation = expect { migration.migration_duration_warning } - - expectation.to output(/interrupt this migration/).to_stdout - expectation.to output(/Continuing in 5/).to_stdout - end - end - - context 'with an additional message' do - it 'warns about long migrations' do - expectation = expect { migration.migration_duration_warning('Get ready for it') } - - expectation.to output(/interrupt this migration/).to_stdout - expectation.to output(/Get ready for it/).to_stdout - expectation.to output(/Continuing in 5/).to_stdout - end - end - end -end diff --git a/spec/lib/ostatus/tag_manager_spec.rb b/spec/lib/ostatus/tag_manager_spec.rb deleted file mode 100644 index 0e20f26c7..000000000 --- a/spec/lib/ostatus/tag_manager_spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe OStatus::TagManager do - describe '#unique_tag' do - it 'returns a unique tag' do - expect(described_class.instance.unique_tag(Time.utc(2000), 12, 'Status')).to eq 'tag:cb6e6126.ngrok.io,2000-01-01:objectId=12:objectType=Status' - end - end - - describe '#unique_tag_to_local_id' do - it 'returns the ID part' do - expect(described_class.instance.unique_tag_to_local_id('tag:cb6e6126.ngrok.io,2000-01-01:objectId=12:objectType=Status', 'Status')).to eql '12' - end - - it 'returns nil if it is not local id' do - expect(described_class.instance.unique_tag_to_local_id('tag:remote,2000-01-01:objectId=12:objectType=Status', 'Status')).to be_nil - end - - it 'returns nil if it is not expected type' do - expect(described_class.instance.unique_tag_to_local_id('tag:cb6e6126.ngrok.io,2000-01-01:objectId=12:objectType=Block', 'Status')).to be_nil - end - - it 'returns nil if it does not have object ID' do - expect(described_class.instance.unique_tag_to_local_id('tag:cb6e6126.ngrok.io,2000-01-01:objectType=Status', 'Status')).to be_nil - end - end - - describe '#local_id?' do - it 'returns true for a local ID' do - expect(described_class.instance.local_id?('tag:cb6e6126.ngrok.io;objectId=12:objectType=Status')).to be true - end - - it 'returns false for a foreign ID' do - expect(described_class.instance.local_id?('tag:foreign.tld;objectId=12:objectType=Status')).to be false - end - end - - describe '#uri_for' do - subject { described_class.instance.uri_for(target) } - - context 'with comment object' do - let(:target) { Fabricate(:status, created_at: '2000-01-01T00:00:00Z', reply: true) } - - it 'returns the unique tag for status' do - expect(target.object_type).to eq :comment - expect(subject).to eq target.uri - end - end - - context 'with note object' do - let(:target) { Fabricate(:status, created_at: '2000-01-01T00:00:00Z', reply: false, thread: nil) } - - it 'returns the unique tag for status' do - expect(target.object_type).to eq :note - expect(subject).to eq target.uri - end - end - - context 'when person object' do - let(:target) { Fabricate(:account, username: 'alice') } - - it 'returns the URL for account' do - expect(target.object_type).to eq :person - expect(subject).to eq 'https://cb6e6126.ngrok.io/users/alice' - end - end - end -end diff --git a/spec/lib/permalink_redirector_spec.rb b/spec/lib/permalink_redirector_spec.rb deleted file mode 100644 index a00913656..000000000 --- a/spec/lib/permalink_redirector_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe PermalinkRedirector do - let(:remote_account) { Fabricate(:account, username: 'alice', domain: 'example.com', url: 'https://example.com/@alice', id: 2) } - - describe '#redirect_url' do - before do - Fabricate(:status, account: remote_account, id: 123, url: 'https://example.com/status-123') - end - - it 'returns path for legacy account links' do - redirector = described_class.new('accounts/2') - expect(redirector.redirect_path).to eq 'https://example.com/@alice' - end - - it 'returns path for legacy status links' do - redirector = described_class.new('statuses/123') - expect(redirector.redirect_path).to eq 'https://example.com/status-123' - end - - it 'returns path for pretty account links' do - redirector = described_class.new('@alice@example.com') - expect(redirector.redirect_path).to eq 'https://example.com/@alice' - end - - it 'returns path for pretty status links' do - redirector = described_class.new('@alice/123') - expect(redirector.redirect_path).to eq 'https://example.com/status-123' - end - end -end diff --git a/spec/lib/plain_text_formatter_spec.rb b/spec/lib/plain_text_formatter_spec.rb deleted file mode 100644 index 80b3c331a..000000000 --- a/spec/lib/plain_text_formatter_spec.rb +++ /dev/null @@ -1,77 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe PlainTextFormatter do - describe '#to_s' do - subject { described_class.new(status.text, status.local?).to_s } - - context 'when status is local' do - let(:status) { Fabricate(:status, text: '

a text by a nerd who uses an HTML tag in text

', uri: nil) } - - it 'returns the raw text' do - expect(subject).to eq '

a text by a nerd who uses an HTML tag in text

' - end - end - - context 'when status is remote' do - let(:remote_account) { Fabricate(:account, domain: 'remote.test', username: 'bob', url: 'https://remote.test/') } - - context 'when text contains inline HTML tags' do - let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem ipsum') } - - it 'strips the tags' do - expect(subject).to eq 'Lorem ipsum' - end - end - - context 'when text contains

tags' do - let(:status) { Fabricate(:status, account: remote_account, text: '

Lorem

ipsum

') } - - it 'inserts a newline' do - expect(subject).to eq "Lorem\nipsum" - end - end - - context 'when text contains a single
tag' do - let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem
ipsum') } - - it 'inserts a newline' do - expect(subject).to eq "Lorem\nipsum" - end - end - - context 'when text contains consecutive
tag' do - let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem


ipsum') } - - it 'inserts a single newline' do - expect(subject).to eq "Lorem\nipsum" - end - end - - context 'when text contains HTML entity' do - let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem & ipsum ❤') } - - it 'unescapes the entity' do - expect(subject).to eq 'Lorem & ipsum ❤' - end - end - - context 'when text contains ipsum') } - - it 'strips the tag and its contents' do - expect(subject).to eq 'Lorem ipsum' - end - end - - context 'when text contains an HTML comment tags' do - let(:status) { Fabricate(:status, account: remote_account, text: 'Lorem ipsum') } - - it 'strips the comment' do - expect(subject).to eq 'Lorem ipsum' - end - end - end - end -end diff --git a/spec/lib/request_pool_spec.rb b/spec/lib/request_pool_spec.rb deleted file mode 100644 index f179e6ca9..000000000 --- a/spec/lib/request_pool_spec.rb +++ /dev/null @@ -1,72 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe RequestPool do - subject { described_class.new } - - describe '#with' do - it 'returns a HTTP client for a host' do - subject.with('http://example.com') do |http_client| - expect(http_client).to be_a HTTP::Client - end - end - - it 'returns the same instance of HTTP client within the same thread for the same host' do - test_client = nil - - subject.with('http://example.com') { |http_client| test_client = http_client } - expect(test_client).to_not be_nil - subject.with('http://example.com') { |http_client| expect(http_client).to be test_client } - end - - it 'returns different HTTP clients for different hosts' do - test_client = nil - - subject.with('http://example.com') { |http_client| test_client = http_client } - expect(test_client).to_not be_nil - subject.with('http://example.org') { |http_client| expect(http_client).to_not be test_client } - end - - it 'grows to the number of threads accessing it' do - stub_request(:get, 'http://example.com/').to_return(status: 200, body: 'Hello!') - - subject - - threads = Array.new(20) do |_i| - Thread.new do - 20.times do - subject.with('http://example.com') do |http_client| - http_client.get('/').flush - end - end - end - end - - threads.map(&:join) - - expect(subject.size).to be > 1 - end - - context 'with an idle connection' do - before do - stub_const('RequestPool::MAX_IDLE_TIME', 1) # Lower idle time limit to 1 seconds - stub_const('RequestPool::REAPER_FREQUENCY', 0.1) # Run reaper every 0.1 seconds - stub_request(:get, 'http://example.com/').to_return(status: 200, body: 'Hello!') - end - - it 'closes the connections' do - subject.with('http://example.com') do |http_client| - http_client.get('/').flush - end - - expect { reaper_observes_idle_timeout }.to change(subject, :size).from(1).to(0) - end - - def reaper_observes_idle_timeout - # One full idle period and 2 reaper cycles more - sleep RequestPool::MAX_IDLE_TIME + (RequestPool::REAPER_FREQUENCY * 2) - end - end - end -end diff --git a/spec/lib/request_spec.rb b/spec/lib/request_spec.rb deleted file mode 100644 index f0861376b..000000000 --- a/spec/lib/request_spec.rb +++ /dev/null @@ -1,143 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'securerandom' - -describe Request do - subject { described_class.new(:get, 'http://example.com') } - - describe '#headers' do - it 'returns user agent' do - expect(subject.headers['User-Agent']).to be_present - end - - it 'returns the date header' do - expect(subject.headers['Date']).to be_present - end - - it 'returns the host header' do - expect(subject.headers['Host']).to be_present - end - - it 'does not return virtual request-target header' do - expect(subject.headers['(request-target)']).to be_nil - end - end - - describe '#on_behalf_of' do - it 'when used, adds signature header' do - subject.on_behalf_of(Fabricate(:account)) - expect(subject.headers['Signature']).to be_present - end - end - - describe '#add_headers' do - it 'adds headers to the request' do - subject.add_headers('Test' => 'Foo') - expect(subject.headers['Test']).to eq 'Foo' - end - end - - describe '#perform' do - context 'with valid host' do - before { stub_request(:get, 'http://example.com') } - - it 'executes a HTTP request' do - expect { |block| subject.perform(&block) }.to yield_control - expect(a_request(:get, 'http://example.com')).to have_been_made.once - end - - it 'executes a HTTP request when the first address is private' do - resolver = instance_double(Resolv::DNS) - - allow(resolver).to receive(:getaddresses).with('example.com').and_return(%w(0.0.0.0 2001:4860:4860::8844)) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) - - expect { |block| subject.perform(&block) }.to yield_control - expect(a_request(:get, 'http://example.com')).to have_been_made.once - end - - it 'sets headers' do - expect { |block| subject.perform(&block) }.to yield_control - expect(a_request(:get, 'http://example.com').with(headers: subject.headers)).to have_been_made - end - - it 'closes underlying connection' do - expect_any_instance_of(HTTP::Client).to receive(:close) - expect { |block| subject.perform(&block) }.to yield_control - end - - it 'returns response which implements body_with_limit' do - subject.perform do |response| - expect(response).to respond_to :body_with_limit - end - end - end - - context 'with private host' do - around do |example| - WebMock.disable! - example.run - WebMock.enable! - end - - it 'raises Mastodon::ValidationError' do - resolver = instance_double(Resolv::DNS) - - allow(resolver).to receive(:getaddresses).with('example.com').and_return(%w(0.0.0.0 2001:db8::face)) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) - - expect { subject.perform }.to raise_error Mastodon::ValidationError - end - end - end - - describe "response's body_with_limit method" do - it 'rejects body more than 1 megabyte by default' do - stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes)) - expect { subject.perform(&:body_with_limit) }.to raise_error Mastodon::LengthValidationError - end - - it 'accepts body less than 1 megabyte by default' do - stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.kilobytes)) - expect { subject.perform(&:body_with_limit) }.to_not raise_error - end - - it 'rejects body by given size' do - stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.kilobytes)) - expect { subject.perform { |response| response.body_with_limit(1.kilobyte) } }.to raise_error Mastodon::LengthValidationError - end - - it 'rejects too large chunked body' do - stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes), headers: { 'Transfer-Encoding' => 'chunked' }) - expect { subject.perform(&:body_with_limit) }.to raise_error Mastodon::LengthValidationError - end - - it 'rejects too large monolithic body' do - stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes), headers: { 'Content-Length' => 2.megabytes }) - expect { subject.perform(&:body_with_limit) }.to raise_error Mastodon::LengthValidationError - end - - it 'truncates large monolithic body' do - stub_request(:any, 'http://example.com').to_return(body: SecureRandom.random_bytes(2.megabytes), headers: { 'Content-Length' => 2.megabytes }) - expect(subject.perform { |response| response.truncated_body.bytesize }).to be < 2.megabytes - end - - it 'uses binary encoding if Content-Type does not tell encoding' do - stub_request(:any, 'http://example.com').to_return(body: '', headers: { 'Content-Type' => 'text/html' }) - expect(subject.perform { |response| response.body_with_limit.encoding }).to eq Encoding::BINARY - end - - it 'uses binary encoding if Content-Type tells unknown encoding' do - stub_request(:any, 'http://example.com').to_return(body: '', headers: { 'Content-Type' => 'text/html; charset=unknown' }) - expect(subject.perform { |response| response.body_with_limit.encoding }).to eq Encoding::BINARY - end - - it 'uses encoding specified by Content-Type' do - stub_request(:any, 'http://example.com').to_return(body: '', headers: { 'Content-Type' => 'text/html; charset=UTF-8' }) - expect(subject.perform { |response| response.body_with_limit.encoding }).to eq Encoding::UTF_8 - end - end -end diff --git a/spec/lib/sanitize_config_spec.rb b/spec/lib/sanitize_config_spec.rb deleted file mode 100644 index cc9916bfd..000000000 --- a/spec/lib/sanitize_config_spec.rb +++ /dev/null @@ -1,76 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Sanitize::Config do - shared_examples 'common HTML sanitization' do - it 'keeps h1' do - expect(Sanitize.fragment('

Foo

', subject)).to eq '

Foo

' - end - - it 'keeps ul' do - expect(Sanitize.fragment('

Check out:

  • Foo
  • Bar
', subject)).to eq '

Check out:

  • Foo
  • Bar
' - end - - it 'keeps start and reversed attributes of ol' do - expect(Sanitize.fragment('

Check out:

  1. Foo
  2. Bar
', subject)).to eq '

Check out:

  1. Foo
  2. Bar
' - end - - it 'removes a without href' do - expect(Sanitize.fragment('Test', subject)).to eq 'Test' - end - - it 'removes a without href and only keeps text content' do - expect(Sanitize.fragment('Test', subject)).to eq 'foo&Test' - end - - it 'removes a with unsupported scheme in href' do - expect(Sanitize.fragment('Test', subject)).to eq 'Test' - end - - it 'does not re-interpret HTML when removing unsupported links' do - expect(Sanitize.fragment('Test<a href="https://example.com">test</a>', subject)).to eq 'Test<a href="https://example.com">test</a>' - end - - it 'keeps a with href' do - expect(Sanitize.fragment('Test', subject)).to eq 'Test' - end - - it 'keeps a with translate="no"' do - expect(Sanitize.fragment('Test', subject)).to eq 'Test' - end - - it 'removes "translate" attribute with invalid value' do - expect(Sanitize.fragment('Test', subject)).to eq 'Test' - end - - it 'removes a with unparsable href' do - expect(Sanitize.fragment('Test', subject)).to eq 'Test' - end - - it 'keeps a with supported scheme and no host' do - expect(Sanitize.fragment('Test', subject)).to eq 'Test' - end - - it 'keeps title in abbr' do - expect(Sanitize.fragment('HTML', subject)).to eq 'HTML' - end - end - - describe '::MASTODON_OUTGOING' do - subject { Sanitize::Config::MASTODON_OUTGOING } - - around do |example| - original_web_domain = Rails.configuration.x.web_domain - example.run - Rails.configuration.x.web_domain = original_web_domain - end - - it_behaves_like 'common HTML sanitization' - - it 'keeps a with href and rel tag, not adding to rel or target if url is local' do - Rails.configuration.x.web_domain = 'domain.test' - expect(Sanitize.fragment('', subject)).to eq '' - end - end -end diff --git a/spec/lib/scope_transformer_spec.rb b/spec/lib/scope_transformer_spec.rb deleted file mode 100644 index 8a9c7cf96..000000000 --- a/spec/lib/scope_transformer_spec.rb +++ /dev/null @@ -1,89 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ScopeTransformer do - describe '#apply' do - subject { described_class.new.apply(ScopeParser.new.parse(input)) } - - shared_examples 'a scope' do |namespace, term, access| - it 'parses the term' do - expect(subject.term).to eq term - end - - it 'parses the namespace' do - expect(subject.namespace).to eq namespace - end - - it 'parses the access' do - expect(subject.access).to eq access - end - end - - context 'with scope "read"' do - let(:input) { 'read' } - - it_behaves_like 'a scope', nil, 'all', 'read' - end - - context 'with scope "write"' do - let(:input) { 'write' } - - it_behaves_like 'a scope', nil, 'all', 'write' - end - - context 'with scope "follow"' do - let(:input) { 'follow' } - - it_behaves_like 'a scope', nil, 'follow', 'read/write' - end - - context 'with scope "crypto"' do - let(:input) { 'crypto' } - - it_behaves_like 'a scope', nil, 'crypto', 'read/write' - end - - context 'with scope "push"' do - let(:input) { 'push' } - - it_behaves_like 'a scope', nil, 'push', 'read/write' - end - - context 'with scope "admin:read"' do - let(:input) { 'admin:read' } - - it_behaves_like 'a scope', 'admin', 'all', 'read' - end - - context 'with scope "admin:write"' do - let(:input) { 'admin:write' } - - it_behaves_like 'a scope', 'admin', 'all', 'write' - end - - context 'with scope "admin:read:accounts"' do - let(:input) { 'admin:read:accounts' } - - it_behaves_like 'a scope', 'admin', 'accounts', 'read' - end - - context 'with scope "admin:write:accounts"' do - let(:input) { 'admin:write:accounts' } - - it_behaves_like 'a scope', 'admin', 'accounts', 'write' - end - - context 'with scope "read:accounts"' do - let(:input) { 'read:accounts' } - - it_behaves_like 'a scope', nil, 'accounts', 'read' - end - - context 'with scope "write:accounts"' do - let(:input) { 'write:accounts' } - - it_behaves_like 'a scope', nil, 'accounts', 'write' - end - end -end diff --git a/spec/lib/search_query_parser_spec.rb b/spec/lib/search_query_parser_spec.rb deleted file mode 100644 index 66b0e8f9e..000000000 --- a/spec/lib/search_query_parser_spec.rb +++ /dev/null @@ -1,98 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'parslet/rig/rspec' - -describe SearchQueryParser do - let(:parser) { described_class.new } - - context 'with term' do - it 'consumes "hello"' do - expect(parser.term).to parse('hello') - end - end - - context 'with prefix' do - it 'consumes "foo:"' do - expect(parser.prefix).to parse('foo:') - end - end - - context 'with operator' do - it 'consumes "+"' do - expect(parser.operator).to parse('+') - end - - it 'consumes "-"' do - expect(parser.operator).to parse('-') - end - end - - context 'with shortcode' do - it 'consumes ":foo:"' do - expect(parser.shortcode).to parse(':foo:') - end - end - - context 'with phrase' do - it 'consumes "hello world"' do - expect(parser.phrase).to parse('"hello world"') - end - end - - context 'with clause' do - it 'consumes "foo"' do - expect(parser.clause).to parse('foo') - end - - it 'consumes "-foo"' do - expect(parser.clause).to parse('-foo') - end - - it 'consumes "foo:bar"' do - expect(parser.clause).to parse('foo:bar') - end - - it 'consumes "-foo:bar"' do - expect(parser.clause).to parse('-foo:bar') - end - - it 'consumes \'foo:"hello world"\'' do - expect(parser.clause).to parse('foo:"hello world"') - end - - it 'consumes \'-foo:"hello world"\'' do - expect(parser.clause).to parse('-foo:"hello world"') - end - - it 'consumes "foo:"' do - expect(parser.clause).to parse('foo:') - end - - it 'consumes \'"\'' do - expect(parser.clause).to parse('"') - end - end - - context 'with query' do - it 'consumes "hello -world"' do - expect(parser.query).to parse('hello -world') - end - - it 'consumes \'foo "hello world"\'' do - expect(parser.query).to parse('foo "hello world"') - end - - it 'consumes "foo:bar hello"' do - expect(parser.query).to parse('foo:bar hello') - end - - it 'consumes \'"hello" world "\'' do - expect(parser.query).to parse('"hello" world "') - end - - it 'consumes "foo:bar bar: hello"' do - expect(parser.query).to parse('foo:bar bar: hello') - end - end -end diff --git a/spec/lib/search_query_transformer_spec.rb b/spec/lib/search_query_transformer_spec.rb deleted file mode 100644 index 5817e3d1d..000000000 --- a/spec/lib/search_query_transformer_spec.rb +++ /dev/null @@ -1,80 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe SearchQueryTransformer do - subject { described_class.new.apply(parser, current_account: account) } - - let(:account) { Fabricate(:account) } - let(:parser) { SearchQueryParser.new.parse(query) } - - context 'with "hello world"' do - let(:query) { 'hello world' } - - it 'transforms clauses' do - expect(subject.send(:must_clauses).map(&:term)).to match_array %w(hello world) - expect(subject.send(:must_not_clauses)).to be_empty - expect(subject.send(:filter_clauses)).to be_empty - end - end - - context 'with "hello -world"' do - let(:query) { 'hello -world' } - - it 'transforms clauses' do - expect(subject.send(:must_clauses).map(&:term)).to match_array %w(hello) - expect(subject.send(:must_not_clauses).map(&:term)).to match_array %w(world) - expect(subject.send(:filter_clauses)).to be_empty - end - end - - context 'with "hello is:reply"' do - let(:query) { 'hello is:reply' } - - it 'transforms clauses' do - expect(subject.send(:must_clauses).map(&:term)).to match_array %w(hello) - expect(subject.send(:must_not_clauses)).to be_empty - expect(subject.send(:filter_clauses).map(&:term)).to match_array %w(reply) - end - end - - context 'with "foo: bar"' do - let(:query) { 'foo: bar' } - - it 'transforms clauses' do - expect(subject.send(:must_clauses).map(&:term)).to match_array %w(foo bar) - expect(subject.send(:must_not_clauses)).to be_empty - expect(subject.send(:filter_clauses)).to be_empty - end - end - - context 'with "foo:bar"' do - let(:query) { 'foo:bar' } - - it 'transforms clauses' do - expect(subject.send(:must_clauses).map(&:term)).to contain_exactly('foo bar') - expect(subject.send(:must_not_clauses)).to be_empty - expect(subject.send(:filter_clauses)).to be_empty - end - end - - context 'with \'"hello world"\'' do - let(:query) { '"hello world"' } - - it 'transforms clauses' do - expect(subject.send(:must_clauses).map(&:phrase)).to contain_exactly('hello world') - expect(subject.send(:must_not_clauses)).to be_empty - expect(subject.send(:filter_clauses)).to be_empty - end - end - - context 'with \'before:"2022-01-01 23:00"\'' do - let(:query) { 'before:"2022-01-01 23:00"' } - - it 'transforms clauses' do - expect(subject.send(:must_clauses)).to be_empty - expect(subject.send(:must_not_clauses)).to be_empty - expect(subject.send(:filter_clauses).map(&:term)).to contain_exactly(lt: '2022-01-01 23:00', time_zone: 'UTC') - end - end -end diff --git a/spec/lib/status_cache_hydrator_spec.rb b/spec/lib/status_cache_hydrator_spec.rb deleted file mode 100644 index 5b80ccb97..000000000 --- a/spec/lib/status_cache_hydrator_spec.rb +++ /dev/null @@ -1,147 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe StatusCacheHydrator do - let(:status) { Fabricate(:status) } - let(:account) { Fabricate(:account) } - - describe '#hydrate' do - let(:compare_to_hash) { InlineRenderer.render(status, account, :status) } - - shared_examples 'shared behavior' do - context 'when handling a new status' do - let(:poll) { Fabricate(:poll) } - let(:status) { Fabricate(:status, poll: poll) } - - it 'renders the same attributes as a full render' do - expect(subject).to eql(compare_to_hash) - end - end - - context 'when handling a new status with own poll' do - let(:poll) { Fabricate(:poll, account: account) } - let(:status) { Fabricate(:status, poll: poll, account: account) } - - it 'renders the same attributes as a full render' do - expect(subject).to eql(compare_to_hash) - end - end - - context 'when handling a filtered status' do - let(:status) { Fabricate(:status, text: 'this toot is about that banned word') } - - before do - account.custom_filters.create!(phrase: 'filter1', context: %w(home), action: :hide, keywords_attributes: [{ keyword: 'banned' }, { keyword: 'irrelevant' }]) - end - - it 'renders the same attributes as a full render' do - expect(subject).to eql(compare_to_hash) - end - end - - context 'when handling a reblog' do - let(:reblog) { Fabricate(:status) } - let(:status) { Fabricate(:status, reblog: reblog) } - - context 'when it has been favourited' do - before do - FavouriteService.new.call(account, reblog) - end - - it 'renders the same attributes as a full render' do - expect(subject).to eql(compare_to_hash) - end - end - - context 'when it has been reblogged' do - before do - ReblogService.new.call(account, reblog) - end - - it 'renders the same attributes as a full render' do - expect(subject).to eql(compare_to_hash) - end - end - - context 'when it has been pinned' do - let(:reblog) { Fabricate(:status, account: account) } - - before do - StatusPin.create!(account: account, status: reblog) - end - - it 'renders the same attributes as a full render' do - expect(subject).to eql(compare_to_hash) - end - end - - context 'when it has been followed tags' do - let(:followed_tag) { Fabricate(:tag) } - - before do - reblog.tags << Fabricate(:tag) - reblog.tags << followed_tag - TagFollow.create!(tag: followed_tag, account: account, rate_limit: false) - end - - it 'renders the same attributes as a full render' do - expect(subject).to eql(compare_to_hash) - end - end - - context 'when it has a poll authored by the user' do - let(:poll) { Fabricate(:poll, account: account) } - let(:reblog) { Fabricate(:status, poll: poll, account: account) } - - it 'renders the same attributes as a full render' do - expect(subject).to eql(compare_to_hash) - end - end - - context 'when it has been voted in' do - let(:poll) { Fabricate(:poll, options: %w(Yellow Blue)) } - let(:reblog) { Fabricate(:status, poll: poll) } - - before do - VoteService.new.call(account, poll, [0]) - end - - it 'renders the same attributes as a full render' do - expect(subject).to eql(compare_to_hash) - end - end - - context 'when it matches account filters' do - let(:reblog) { Fabricate(:status, text: 'this toot is about that banned word') } - - before do - account.custom_filters.create!(phrase: 'filter1', context: %w(home), action: :hide, keywords_attributes: [{ keyword: 'banned' }, { keyword: 'irrelevant' }]) - end - - it 'renders the same attributes as a full render' do - expect(subject).to eql(compare_to_hash) - end - end - end - end - - context 'when cache is warm' do - subject do - Rails.cache.write("fan-out/#{status.id}", InlineRenderer.render(status, nil, :status)) - described_class.new(status).hydrate(account.id) - end - - it_behaves_like 'shared behavior' - end - - context 'when cache is cold' do - subject do - Rails.cache.delete("fan-out/#{status.id}") - described_class.new(status).hydrate(account.id) - end - - it_behaves_like 'shared behavior' - end - end -end diff --git a/spec/lib/status_filter_spec.rb b/spec/lib/status_filter_spec.rb deleted file mode 100644 index c994ad419..000000000 --- a/spec/lib/status_filter_spec.rb +++ /dev/null @@ -1,84 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe StatusFilter do - describe '#filtered?' do - let(:status) { Fabricate(:status) } - - context 'without an account' do - subject(:filter) { described_class.new(status, nil) } - - context 'when there are no connections' do - it { is_expected.to_not be_filtered } - end - - context 'when status account is silenced' do - before do - status.account.silence! - end - - it { is_expected.to be_filtered } - end - - context 'when status policy does not allow show' do - it 'filters the status' do - allow_any_instance_of(StatusPolicy).to receive(:show?).and_return(false) - - expect(filter).to be_filtered - end - end - end - - context 'with real account' do - subject(:filter) { described_class.new(status, account) } - - let(:account) { Fabricate(:account) } - - context 'when there are no connections' do - it { is_expected.to_not be_filtered } - end - - context 'when status account is blocked' do - before do - Fabricate(:block, account: account, target_account: status.account) - end - - it { is_expected.to be_filtered } - end - - context 'when status account domain is blocked' do - before do - status.account.update(domain: 'example.com') - Fabricate(:account_domain_block, account: account, domain: status.account_domain) - end - - it { is_expected.to be_filtered } - end - - context 'when status account is muted' do - before do - Fabricate(:mute, account: account, target_account: status.account) - end - - it { is_expected.to be_filtered } - end - - context 'when status account is silenced' do - before do - status.account.silence! - end - - it { is_expected.to be_filtered } - end - - context 'when status policy does not allow show' do - it 'filters the status' do - allow_any_instance_of(StatusPolicy).to receive(:show?).and_return(false) - - expect(filter).to be_filtered - end - end - end - end -end diff --git a/spec/lib/status_finder_spec.rb b/spec/lib/status_finder_spec.rb deleted file mode 100644 index 53f5039af..000000000 --- a/spec/lib/status_finder_spec.rb +++ /dev/null @@ -1,56 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe StatusFinder do - include RoutingHelper - - describe '#status' do - subject { described_class.new(url) } - - context 'with a status url' do - let(:status) { Fabricate(:status) } - let(:url) { short_account_status_url(account_username: status.account.username, id: status.id) } - - it 'finds the stream entry' do - expect(subject.status).to eq(status) - end - - it 'raises an error if action is not :show' do - recognized = Rails.application.routes.recognize_path(url) - allow(recognized).to receive(:[]).with(:action).and_return(:create) - allow(Rails.application.routes).to receive(:recognize_path).with(url).and_return(recognized) - - expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound) - - expect(Rails.application.routes).to have_received(:recognize_path) - expect(recognized).to have_received(:[]) - end - end - - context 'with a remote url even if id exists on local' do - let(:status) { Fabricate(:status) } - let(:url) { "https://example.com/users/test/statuses/#{status.id}" } - - it 'raises an error' do - expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound) - end - end - - context 'with a plausible url' do - let(:url) { 'https://example.com/users/test/updates/123/embed' } - - it 'raises an error' do - expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound) - end - end - - context 'with an unrecognized url' do - let(:url) { 'https://example.com/about' } - - it 'raises an error' do - expect { subject.status }.to raise_error(ActiveRecord::RecordNotFound) - end - end - end -end diff --git a/spec/lib/status_reach_finder_spec.rb b/spec/lib/status_reach_finder_spec.rb deleted file mode 100644 index 7181717dc..000000000 --- a/spec/lib/status_reach_finder_spec.rb +++ /dev/null @@ -1,105 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe StatusReachFinder do - describe '#inboxes' do - context 'with a local status' do - subject { described_class.new(status) } - - let(:parent_status) { nil } - let(:visibility) { :public } - let(:alice) { Fabricate(:account, username: 'alice') } - let(:status) { Fabricate(:status, account: alice, thread: parent_status, visibility: visibility) } - - context 'when it contains mentions of remote accounts' do - let(:bob) { Fabricate(:account, username: 'bob', domain: 'foo.bar', protocol: :activitypub, inbox_url: 'https://foo.bar/inbox') } - - before do - status.mentions.create!(account: bob) - end - - it 'includes the inbox of the mentioned account' do - expect(subject.inboxes).to include 'https://foo.bar/inbox' - end - end - - context 'when it has been reblogged by a remote account' do - let(:bob) { Fabricate(:account, username: 'bob', domain: 'foo.bar', protocol: :activitypub, inbox_url: 'https://foo.bar/inbox') } - - before do - bob.statuses.create!(reblog: status) - end - - it 'includes the inbox of the reblogger' do - expect(subject.inboxes).to include 'https://foo.bar/inbox' - end - - context 'when status is not public' do - let(:visibility) { :private } - - it 'does not include the inbox of the reblogger' do - expect(subject.inboxes).to_not include 'https://foo.bar/inbox' - end - end - end - - context 'when it has been favourited by a remote account' do - let(:bob) { Fabricate(:account, username: 'bob', domain: 'foo.bar', protocol: :activitypub, inbox_url: 'https://foo.bar/inbox') } - - before do - bob.favourites.create!(status: status) - end - - it 'includes the inbox of the favouriter' do - expect(subject.inboxes).to include 'https://foo.bar/inbox' - end - - context 'when status is not public' do - let(:visibility) { :private } - - it 'does not include the inbox of the favouriter' do - expect(subject.inboxes).to_not include 'https://foo.bar/inbox' - end - end - end - - context 'when it has been replied to by a remote account' do - let(:bob) { Fabricate(:account, username: 'bob', domain: 'foo.bar', protocol: :activitypub, inbox_url: 'https://foo.bar/inbox') } - - before do - bob.statuses.create!(thread: status, text: 'Hoge') - end - - it 'includes the inbox of the replier' do - expect(subject.inboxes).to include 'https://foo.bar/inbox' - end - - context 'when status is not public' do - let(:visibility) { :private } - - it 'does not include the inbox of the replier' do - expect(subject.inboxes).to_not include 'https://foo.bar/inbox' - end - end - end - - context 'when it is a reply to a remote account' do - let(:bob) { Fabricate(:account, username: 'bob', domain: 'foo.bar', protocol: :activitypub, inbox_url: 'https://foo.bar/inbox') } - let(:parent_status) { Fabricate(:status, account: bob) } - - it 'includes the inbox of the replied-to account' do - expect(subject.inboxes).to include 'https://foo.bar/inbox' - end - - context 'when status is not public and replied-to account is not mentioned' do - let(:visibility) { :private } - - it 'does not include the inbox of the replied-to account' do - expect(subject.inboxes).to_not include 'https://foo.bar/inbox' - end - end - end - end - end -end diff --git a/spec/lib/suspicious_sign_in_detector_spec.rb b/spec/lib/suspicious_sign_in_detector_spec.rb deleted file mode 100644 index 9e64aff08..000000000 --- a/spec/lib/suspicious_sign_in_detector_spec.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe SuspiciousSignInDetector do - describe '#suspicious?' do - subject { described_class.new(user).suspicious?(request) } - - let(:user) { Fabricate(:user, current_sign_in_at: 1.day.ago) } - let(:request) { instance_double(ActionDispatch::Request, remote_ip: remote_ip) } - let(:remote_ip) { nil } - - context 'when user has 2FA enabled' do - before do - user.update!(otp_required_for_login: true) - end - - it 'returns false' do - expect(subject).to be false - end - end - - context 'when exact IP has been used before' do - let(:remote_ip) { '1.1.1.1' } - - before do - user.update!(sign_up_ip: remote_ip) - end - - it 'returns false' do - expect(subject).to be false - end - end - - context 'when similar IP has been used before' do - let(:remote_ip) { '1.1.2.2' } - - before do - user.update!(sign_up_ip: '1.1.1.1') - end - - it 'returns false' do - expect(subject).to be false - end - end - - context 'when IP is completely unfamiliar' do - let(:remote_ip) { '2.2.2.2' } - - before do - user.update!(sign_up_ip: '1.1.1.1') - end - - it 'returns true' do - expect(subject).to be true - end - end - end -end diff --git a/spec/lib/tag_manager_spec.rb b/spec/lib/tag_manager_spec.rb deleted file mode 100644 index 38203a55f..000000000 --- a/spec/lib/tag_manager_spec.rb +++ /dev/null @@ -1,88 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe TagManager do - describe '#local_domain?' do - # The following comparisons MUST be case-insensitive. - - around do |example| - original_local_domain = Rails.configuration.x.local_domain - Rails.configuration.x.local_domain = 'domain.example.com' - - example.run - - Rails.configuration.x.local_domain = original_local_domain - end - - it 'returns true for nil' do - expect(described_class.instance.local_domain?(nil)).to be true - end - - it 'returns true if the slash-stripped string equals to local domain' do - expect(described_class.instance.local_domain?('DoMaIn.Example.com/')).to be true - end - - it 'returns false for irrelevant string' do - expect(described_class.instance.local_domain?('DoMaIn.Example.com!')).to be false - end - end - - describe '#web_domain?' do - # The following comparisons MUST be case-insensitive. - - around do |example| - original_web_domain = Rails.configuration.x.web_domain - Rails.configuration.x.web_domain = 'domain.example.com' - - example.run - - Rails.configuration.x.web_domain = original_web_domain - end - - it 'returns true for nil' do - expect(described_class.instance.web_domain?(nil)).to be true - end - - it 'returns true if the slash-stripped string equals to web domain' do - expect(described_class.instance.web_domain?('DoMaIn.Example.com/')).to be true - end - - it 'returns false for string with irrelevant characters' do - expect(described_class.instance.web_domain?('DoMaIn.Example.com!')).to be false - end - end - - describe '#normalize_domain' do - it 'returns nil if the given parameter is nil' do - expect(described_class.instance.normalize_domain(nil)).to be_nil - end - - it 'returns normalized domain' do - expect(described_class.instance.normalize_domain('DoMaIn.Example.com/')).to eq 'domain.example.com' - end - end - - describe '#local_url?' do - around do |example| - original_web_domain = Rails.configuration.x.web_domain - example.run - Rails.configuration.x.web_domain = original_web_domain - end - - it 'returns true if the normalized string with port is local URL' do - Rails.configuration.x.web_domain = 'domain.example.com:42' - expect(described_class.instance.local_url?('https://DoMaIn.Example.com:42/')).to be true - end - - it 'returns true if the normalized string without port is local URL' do - Rails.configuration.x.web_domain = 'domain.example.com' - expect(described_class.instance.local_url?('https://DoMaIn.Example.com/')).to be true - end - - it 'returns false for string with irrelevant characters' do - Rails.configuration.x.web_domain = 'domain.example.com' - expect(described_class.instance.local_url?('https://domain.example.net/')).to be false - end - end -end diff --git a/spec/lib/text_formatter_spec.rb b/spec/lib/text_formatter_spec.rb deleted file mode 100644 index 8b922c018..000000000 --- a/spec/lib/text_formatter_spec.rb +++ /dev/null @@ -1,315 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe TextFormatter do - describe '#to_s' do - subject { described_class.new(text, preloaded_accounts: preloaded_accounts).to_s } - - let(:preloaded_accounts) { nil } - - context 'when given text containing plain text' do - let(:text) { 'text' } - - it 'paragraphizes the text' do - expect(subject).to eq '

text

' - end - end - - context 'when given text containing line feeds' do - let(:text) { "line\nfeed" } - - it 'removes line feeds' do - expect(subject).to_not include "\n" - end - end - - context 'when given text containing linkable mentions' do - let(:preloaded_accounts) { [Fabricate(:account, username: 'alice')] } - let(:text) { '@alice' } - - it 'creates a mention link' do - expect(subject).to include '@alice' - end - end - - context 'when given text containing unlinkable mentions' do - let(:preloaded_accounts) { [] } - let(:text) { '@alice' } - - it 'does not create a mention link' do - expect(subject).to include '@alice' - end - end - - context 'when given a stand-alone medium URL' do - let(:text) { 'https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4' } - - it 'matches the full URL' do - expect(subject).to include 'href="https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4"' - end - end - - context 'when given a stand-alone google URL' do - let(:text) { 'http://google.com' } - - it 'matches the full URL' do - expect(subject).to include 'href="http://google.com"' - end - end - - context 'when given a stand-alone URL with a newer TLD' do - let(:text) { 'http://example.gay' } - - it 'matches the full URL' do - expect(subject).to include 'href="http://example.gay"' - end - end - - context 'when given a stand-alone IDN URL' do - let(:text) { 'https://nic.みんな/' } - - it 'matches the full URL' do - expect(subject).to include 'href="https://nic.みんな/"' - end - - it 'has display URL' do - expect(subject).to include 'nic.みんな/' - end - end - - context 'when given a URL with a trailing period' do - let(:text) { 'http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona. ' } - - it 'matches the full URL but not the period' do - expect(subject).to include 'href="http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona"' - end - end - - context 'when given a URL enclosed with parentheses' do - let(:text) { '(http://google.com/)' } - - it 'matches the full URL but not the parentheses' do - expect(subject).to include 'href="http://google.com/"' - end - end - - context 'when given a URL with a trailing exclamation point' do - let(:text) { 'http://www.google.com!' } - - it 'matches the full URL but not the exclamation point' do - expect(subject).to include 'href="http://www.google.com"' - end - end - - context 'when given a URL with a trailing single quote' do - let(:text) { "http://www.google.com'" } - - it 'matches the full URL but not the single quote' do - expect(subject).to include 'href="http://www.google.com"' - end - end - - context 'when given a URL with a trailing angle bracket' do - let(:text) { 'http://www.google.com>' } - - it 'matches the full URL but not the angle bracket' do - expect(subject).to include 'href="http://www.google.com"' - end - end - - context 'when given a URL with a query string' do - context 'with escaped unicode character' do - let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink' } - - it 'matches the full URL' do - expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink"' - end - end - - context 'with unicode character' do - let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓&q=autolink' } - - it 'matches the full URL' do - expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=✓&q=autolink"' - end - end - - context 'with unicode character at the end' do - let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓' } - - it 'matches the full URL' do - expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=✓"' - end - end - - context 'with escaped and not escaped unicode characters' do - let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink' } - - it 'preserves escaped unicode characters' do - expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink"' - end - end - end - - context 'when given a URL with parentheses in it' do - let(:text) { 'https://en.wikipedia.org/wiki/Diaspora_(software)' } - - it 'matches the full URL' do - expect(subject).to include 'href="https://en.wikipedia.org/wiki/Diaspora_(software)"' - end - end - - context 'when given a URL in quotation marks' do - let(:text) { '"https://example.com/"' } - - it 'does not match the quotation marks' do - expect(subject).to include 'href="https://example.com/"' - end - end - - context 'when given a URL in angle brackets' do - let(:text) { '' } - - it 'does not match the angle brackets' do - expect(subject).to include 'href="https://example.com/"' - end - end - - context 'when given a URL with Japanese path string' do - let(:text) { 'https://ja.wikipedia.org/wiki/日本' } - - it 'matches the full URL' do - expect(subject).to include 'href="https://ja.wikipedia.org/wiki/日本"' - end - end - - context 'when given a URL with Korean path string' do - let(:text) { 'https://ko.wikipedia.org/wiki/대한민국' } - - it 'matches the full URL' do - expect(subject).to include 'href="https://ko.wikipedia.org/wiki/대한민국"' - end - end - - context 'when given a URL with a full-width space' do - let(:text) { 'https://example.com/ abc123' } - - it 'does not match the full-width space' do - expect(subject).to include 'href="https://example.com/"' - end - end - - context 'when given a URL in Japanese quotation marks' do - let(:text) { '「[https://example.org/」' } - - it 'does not match the quotation marks' do - expect(subject).to include 'href="https://example.org/"' - end - end - - context 'when given a URL with Simplified Chinese path string' do - let(:text) { 'https://baike.baidu.com/item/中华人民共和国' } - - it 'matches the full URL' do - expect(subject).to include 'href="https://baike.baidu.com/item/中华人民共和国"' - end - end - - context 'when given a URL with Traditional Chinese path string' do - let(:text) { 'https://zh.wikipedia.org/wiki/臺灣' } - - it 'matches the full URL' do - expect(subject).to include 'href="https://zh.wikipedia.org/wiki/臺灣"' - end - end - - context 'when given a URL containing unsafe code (XSS attack, visible part)' do - let(:text) { 'http://example.com/bb' } - - it 'does not include the HTML in the URL' do - expect(subject).to include '"http://example.com/b"' - end - - it 'escapes the HTML' do - expect(subject).to include '<del>b</del>' - end - end - - context 'when given a URL containing unsafe code (XSS attack, invisible part)' do - let(:text) { 'http://example.com/blahblahblahblah/a' } - - it 'does not include the HTML in the URL' do - expect(subject).to include '"http://example.com/blahblahblahblah/a"' - end - - it 'escapes the HTML' do - expect(subject).to include '<script>alert("Hello")</script>' - end - end - - context 'when given text containing HTML code (script tag)' do - let(:text) { '' } - - it 'escapes the HTML' do - expect(subject).to include '

<script>alert("Hello")</script>

' - end - end - - context 'when given text containing HTML (XSS attack)' do - let(:text) { %q{} } - - it 'escapes the HTML' do - expect(subject).to include '

<img src="javascript:alert('XSS');">

' - end - end - - context 'when given an invalid URL' do - let(:text) { 'http://www\.google\.com' } - - it 'outputs the raw URL' do - expect(subject).to eq '

http://www\.google\.com

' - end - end - - context 'when given text containing a hashtag' do - let(:text) { '#hashtag' } - - it 'creates a hashtag link' do - expect(subject).to include '/tags/hashtag" class="mention hashtag" rel="tag">#hashtag' - end - end - - context 'when given text containing a hashtag with Unicode chars' do - let(:text) { '#hashtagタグ' } - - it 'creates a hashtag link' do - expect(subject).to include '/tags/hashtag%E3%82%BF%E3%82%B0" class="mention hashtag" rel="tag">#hashtagタグ' - end - end - - context 'when given text with a stand-alone xmpp: URI' do - let(:text) { 'xmpp:user@instance.com' } - - it 'matches the full URI' do - expect(subject).to include 'href="xmpp:user@instance.com"' - end - end - - context 'when given text with an xmpp: URI with a query-string' do - let(:text) { 'please join xmpp:muc@instance.com?join right now' } - - it 'matches the full URI' do - expect(subject).to include 'href="xmpp:muc@instance.com?join"' - end - end - - context 'when given text containing a magnet: URI' do - let(:text) { 'wikipedia gives this example of a magnet uri: magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a' } - - it 'matches the full URI' do - expect(subject).to include 'href="magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a"' - end - end - end -end diff --git a/spec/lib/translation_service/deepl_spec.rb b/spec/lib/translation_service/deepl_spec.rb deleted file mode 100644 index 5a1d0f094..000000000 --- a/spec/lib/translation_service/deepl_spec.rb +++ /dev/null @@ -1,100 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe TranslationService::DeepL do - subject(:service) { described_class.new(plan, 'my-api-key') } - - let(:plan) { 'advanced' } - - before do - stub_request(:get, 'https://api.deepl.com/v2/languages?type=source').to_return( - body: '[{"language":"EN","name":"English"},{"language":"UK","name":"Ukrainian"}]' - ) - stub_request(:get, 'https://api.deepl.com/v2/languages?type=target').to_return( - body: '[{"language":"EN-GB","name":"English (British)"},{"language":"ZH","name":"Chinese"}]' - ) - end - - describe '#translate' do - it 'returns translation with specified source language' do - stub_request(:post, 'https://api.deepl.com/v2/translate') - .with(body: 'text=Hasta+la+vista&source_lang=ES&target_lang=en&tag_handling=html') - .to_return(body: '{"translations":[{"detected_source_language":"ES","text":"See you soon"}]}') - - translations = service.translate(['Hasta la vista'], 'es', 'en') - expect(translations.size).to eq 1 - - translation = translations.first - expect(translation.detected_source_language).to eq 'es' - expect(translation.provider).to eq 'DeepL.com' - expect(translation.text).to eq 'See you soon' - end - - it 'returns translation with auto-detected source language' do - stub_request(:post, 'https://api.deepl.com/v2/translate') - .with(body: 'text=Guten+Tag&source_lang&target_lang=en&tag_handling=html') - .to_return(body: '{"translations":[{"detected_source_language":"DE","text":"Good morning"}]}') - - translations = service.translate(['Guten Tag'], nil, 'en') - expect(translations.size).to eq 1 - - translation = translations.first - expect(translation.detected_source_language).to eq 'de' - expect(translation.provider).to eq 'DeepL.com' - expect(translation.text).to eq 'Good morning' - end - - it 'returns translation of multiple texts' do - stub_request(:post, 'https://api.deepl.com/v2/translate') - .with(body: 'text=Guten+Morgen&text=Gute+Nacht&source_lang=DE&target_lang=en&tag_handling=html') - .to_return(body: '{"translations":[{"detected_source_language":"DE","text":"Good morning"},{"detected_source_language":"DE","text":"Good night"}]}') - - translations = service.translate(['Guten Morgen', 'Gute Nacht'], 'de', 'en') - expect(translations.size).to eq 2 - - expect(translations.first.text).to eq 'Good morning' - expect(translations.last.text).to eq 'Good night' - end - end - - describe '#languages' do - it 'returns source languages' do - expect(service.languages.keys).to eq [nil, 'en', 'uk'] - end - - it 'returns target languages for each source language' do - expect(service.languages['en']).to eq %w(pt en-GB zh) - expect(service.languages['uk']).to eq %w(en pt en-GB zh) - end - - it 'returns target languages for auto-detection' do - expect(service.languages[nil]).to eq %w(en pt en-GB zh) - end - end - - describe '#request' do - before do - stub_request(:any, //) - # rubocop:disable Lint/EmptyBlock - service.send(:request, :get, '/v2/languages') { |res| } - # rubocop:enable Lint/EmptyBlock - end - - it 'uses paid plan base URL' do - expect(a_request(:get, 'https://api.deepl.com/v2/languages')).to have_been_made.once - end - - context 'with free plan' do - let(:plan) { 'free' } - - it 'uses free plan base URL' do - expect(a_request(:get, 'https://api-free.deepl.com/v2/languages')).to have_been_made.once - end - end - - it 'sends API key' do - expect(a_request(:get, 'https://api.deepl.com/v2/languages').with(headers: { Authorization: 'DeepL-Auth-Key my-api-key' })).to have_been_made.once - end - end -end diff --git a/spec/lib/translation_service/libre_translate_spec.rb b/spec/lib/translation_service/libre_translate_spec.rb deleted file mode 100644 index 90966a8eb..000000000 --- a/spec/lib/translation_service/libre_translate_spec.rb +++ /dev/null @@ -1,72 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe TranslationService::LibreTranslate do - subject(:service) { described_class.new('https://libretranslate.example.com', 'my-api-key') } - - before do - stub_request(:get, 'https://libretranslate.example.com/languages').to_return( - body: '[{"code": "en","name": "English","targets": ["de","en","es"]},{"code": "da","name": "Danish","targets": ["en","pt"]}]' - ) - end - - describe '#languages' do - subject(:languages) { service.languages } - - it 'returns source languages' do - expect(languages.keys).to eq ['en', 'da', nil] - end - - it 'returns target languages for each source language' do - expect(languages['en']).to eq %w(de es) - expect(languages['da']).to eq %w(en pt) - end - - it 'returns target languages for auto-detected language' do - expect(languages[nil]).to eq %w(de en es pt) - end - end - - describe '#translate' do - it 'returns translation with specified source language' do - stub_request(:post, 'https://libretranslate.example.com/translate') - .with(body: '{"q":["Hasta la vista"],"source":"es","target":"en","format":"html","api_key":"my-api-key"}') - .to_return(body: '{"translatedText": ["See you"]}') - - translations = service.translate(['Hasta la vista'], 'es', 'en') - expect(translations.size).to eq 1 - - translation = translations.first - expect(translation.detected_source_language).to be 'es' - expect(translation.provider).to eq 'LibreTranslate' - expect(translation.text).to eq 'See you' - end - - it 'returns translation with auto-detected source language' do - stub_request(:post, 'https://libretranslate.example.com/translate') - .with(body: '{"q":["Guten Morgen"],"source":"auto","target":"en","format":"html","api_key":"my-api-key"}') - .to_return(body: '{"detectedLanguage": [{"confidence": 92, "language": "de"}], "translatedText": ["Good morning"]}') - - translations = service.translate(['Guten Morgen'], nil, 'en') - expect(translations.size).to eq 1 - - translation = translations.first - expect(translation.detected_source_language).to eq 'de' - expect(translation.provider).to eq 'LibreTranslate' - expect(translation.text).to eq 'Good morning' - end - - it 'returns translation of multiple texts' do - stub_request(:post, 'https://libretranslate.example.com/translate') - .with(body: '{"q":["Guten Morgen","Gute Nacht"],"source":"de","target":"en","format":"html","api_key":"my-api-key"}') - .to_return(body: '{"translatedText": ["Good morning", "Good night"]}') - - translations = service.translate(['Guten Morgen', 'Gute Nacht'], 'de', 'en') - expect(translations.size).to eq 2 - - expect(translations.first.text).to eq 'Good morning' - expect(translations.last.text).to eq 'Good night' - end - end -end diff --git a/spec/lib/vacuum/access_tokens_vacuum_spec.rb b/spec/lib/vacuum/access_tokens_vacuum_spec.rb deleted file mode 100644 index 54760c41b..000000000 --- a/spec/lib/vacuum/access_tokens_vacuum_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Vacuum::AccessTokensVacuum do - subject { described_class.new } - - describe '#perform' do - let!(:revoked_access_token) { Fabricate(:access_token, revoked_at: 1.minute.ago) } - let!(:expired_access_token) { Fabricate(:access_token, expires_in: 59.minutes.to_i, created_at: 1.hour.ago) } - let!(:active_access_token) { Fabricate(:access_token) } - - let!(:revoked_access_grant) { Fabricate(:access_grant, revoked_at: 1.minute.ago) } - let!(:expired_access_grant) { Fabricate(:access_grant, expires_in: 59.minutes.to_i, created_at: 1.hour.ago) } - let!(:active_access_grant) { Fabricate(:access_grant) } - - before do - subject.perform - end - - it 'deletes revoked access tokens' do - expect { revoked_access_token.reload }.to raise_error ActiveRecord::RecordNotFound - end - - it 'deletes expired access tokens' do - expect { expired_access_token.reload }.to raise_error ActiveRecord::RecordNotFound - end - - it 'deletes revoked access grants' do - expect { revoked_access_grant.reload }.to raise_error ActiveRecord::RecordNotFound - end - - it 'deletes expired access grants' do - expect { expired_access_grant.reload }.to raise_error ActiveRecord::RecordNotFound - end - - it 'does not delete active access tokens' do - expect { active_access_token.reload }.to_not raise_error - end - - it 'does not delete active access grants' do - expect { active_access_grant.reload }.to_not raise_error - end - end -end diff --git a/spec/lib/vacuum/applications_vacuum_spec.rb b/spec/lib/vacuum/applications_vacuum_spec.rb deleted file mode 100644 index 57a222aaf..000000000 --- a/spec/lib/vacuum/applications_vacuum_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Vacuum::ApplicationsVacuum do - subject { described_class.new } - - describe '#perform' do - let!(:app_with_token) { Fabricate(:application, created_at: 1.month.ago) } - let!(:app_with_grant) { Fabricate(:application, created_at: 1.month.ago) } - let!(:app_with_signup) { Fabricate(:application, created_at: 1.month.ago) } - let!(:app_with_owner) { Fabricate(:application, created_at: 1.month.ago, owner: Fabricate(:user)) } - let!(:unused_app) { Fabricate(:application, created_at: 1.month.ago) } - let!(:recent_app) { Fabricate(:application, created_at: 1.hour.ago) } - - let!(:active_access_token) { Fabricate(:access_token, application: app_with_token) } - let!(:active_access_grant) { Fabricate(:access_grant, application: app_with_grant) } - let!(:user) { Fabricate(:user, created_by_application: app_with_signup) } - - before do - subject.perform - end - - it 'does not delete applications with valid access tokens' do - expect { app_with_token.reload }.to_not raise_error - end - - it 'does not delete applications with valid access grants' do - expect { app_with_grant.reload }.to_not raise_error - end - - it 'does not delete applications that were used to create users' do - expect { app_with_signup.reload }.to_not raise_error - end - - it 'does not delete owned applications' do - expect { app_with_owner.reload }.to_not raise_error - end - - it 'does not delete applications registered less than a day ago' do - expect { recent_app.reload }.to_not raise_error - end - - it 'deletes unused applications' do - expect { unused_app.reload }.to raise_error ActiveRecord::RecordNotFound - end - end -end diff --git a/spec/lib/vacuum/backups_vacuum_spec.rb b/spec/lib/vacuum/backups_vacuum_spec.rb deleted file mode 100644 index 867dbe402..000000000 --- a/spec/lib/vacuum/backups_vacuum_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Vacuum::BackupsVacuum do - subject { described_class.new(retention_period) } - - let(:retention_period) { 7.days } - - describe '#perform' do - let!(:expired_backup) { Fabricate(:backup, created_at: (retention_period + 1.day).ago) } - let!(:current_backup) { Fabricate(:backup) } - - before do - subject.perform - end - - it 'deletes backups past the retention period' do - expect { expired_backup.reload }.to raise_error ActiveRecord::RecordNotFound - end - - it 'does not delete backups within the retention period' do - expect { current_backup.reload }.to_not raise_error - end - end -end diff --git a/spec/lib/vacuum/feeds_vacuum_spec.rb b/spec/lib/vacuum/feeds_vacuum_spec.rb deleted file mode 100644 index ede1e3c36..000000000 --- a/spec/lib/vacuum/feeds_vacuum_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Vacuum::FeedsVacuum do - subject { described_class.new } - - describe '#perform' do - let!(:active_user) { Fabricate(:user, current_sign_in_at: 2.days.ago) } - let!(:inactive_user) { Fabricate(:user, current_sign_in_at: 22.days.ago) } - - before do - redis.zadd(feed_key_for(inactive_user), 1, 1) - redis.zadd(feed_key_for(active_user), 1, 1) - redis.zadd(feed_key_for(inactive_user, 'reblogs'), 2, 2) - redis.sadd(feed_key_for(inactive_user, 'reblogs:2'), 3) - - subject.perform - end - - it 'clears feeds of inactive users and lists' do - expect(redis.zcard(feed_key_for(inactive_user))).to eq 0 - expect(redis.zcard(feed_key_for(active_user))).to eq 1 - expect(redis.exists?(feed_key_for(inactive_user, 'reblogs'))).to be false - expect(redis.exists?(feed_key_for(inactive_user, 'reblogs:2'))).to be false - end - end - - def feed_key_for(user, subtype = nil) - FeedManager.instance.key(:home, user.account_id, subtype) - end -end diff --git a/spec/lib/vacuum/imports_vacuum_spec.rb b/spec/lib/vacuum/imports_vacuum_spec.rb deleted file mode 100644 index 1e0abc5e0..000000000 --- a/spec/lib/vacuum/imports_vacuum_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Vacuum::ImportsVacuum do - subject { described_class.new } - - let!(:old_unconfirmed) { Fabricate(:bulk_import, state: :unconfirmed, created_at: 2.days.ago) } - let!(:new_unconfirmed) { Fabricate(:bulk_import, state: :unconfirmed, created_at: 10.seconds.ago) } - let!(:recent_ongoing) { Fabricate(:bulk_import, state: :in_progress, created_at: 20.minutes.ago) } - let!(:recent_finished) { Fabricate(:bulk_import, state: :finished, created_at: 1.day.ago) } - let!(:old_finished) { Fabricate(:bulk_import, state: :finished, created_at: 2.months.ago) } - - describe '#perform' do - it 'cleans up the expected imports' do - expect { subject.perform }.to change { BulkImport.all.pluck(:id) }.from([old_unconfirmed, new_unconfirmed, recent_ongoing, recent_finished, old_finished].map(&:id)).to([new_unconfirmed, recent_ongoing, recent_finished].map(&:id)) - end - end -end diff --git a/spec/lib/vacuum/media_attachments_vacuum_spec.rb b/spec/lib/vacuum/media_attachments_vacuum_spec.rb deleted file mode 100644 index 3c17ecb00..000000000 --- a/spec/lib/vacuum/media_attachments_vacuum_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Vacuum::MediaAttachmentsVacuum do - subject { described_class.new(retention_period) } - - let(:retention_period) { 7.days } - let(:remote_status) { Fabricate(:status, account: Fabricate(:account, domain: 'example.com')) } - let(:local_status) { Fabricate(:status) } - - describe '#perform' do - let!(:old_remote_media) { Fabricate(:media_attachment, remote_url: 'https://example.com/foo.png', status: remote_status, created_at: (retention_period + 1.day).ago, updated_at: (retention_period + 1.day).ago) } - let!(:old_local_media) { Fabricate(:media_attachment, status: local_status, created_at: (retention_period + 1.day).ago, updated_at: (retention_period + 1.day).ago) } - let!(:new_remote_media) { Fabricate(:media_attachment, remote_url: 'https://example.com/foo.png', status: remote_status) } - let!(:new_local_media) { Fabricate(:media_attachment, status: local_status) } - let!(:old_unattached_media) { Fabricate(:media_attachment, account_id: nil, created_at: 10.days.ago) } - let!(:new_unattached_media) { Fabricate(:media_attachment, account_id: nil, created_at: 1.hour.ago) } - - before do - subject.perform - end - - it 'deletes cache of remote media attachments past the retention period' do - expect(old_remote_media.reload.file).to be_blank - end - - it 'does not touch local media attachments past the retention period' do - expect(old_local_media.reload.file).to_not be_blank - end - - it 'does not delete cache of remote media attachments within the retention period' do - expect(new_remote_media.reload.file).to_not be_blank - end - - it 'does not touch local media attachments within the retention period' do - expect(new_local_media.reload.file).to_not be_blank - end - - it 'deletes unattached media attachments past TTL' do - expect { old_unattached_media.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'does not delete unattached media attachments within TTL' do - expect(new_unattached_media.reload).to be_persisted - end - end -end diff --git a/spec/lib/vacuum/preview_cards_vacuum_spec.rb b/spec/lib/vacuum/preview_cards_vacuum_spec.rb deleted file mode 100644 index c1b7f7e9c..000000000 --- a/spec/lib/vacuum/preview_cards_vacuum_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Vacuum::PreviewCardsVacuum do - subject { described_class.new(retention_period) } - - let(:retention_period) { 7.days } - - describe '#perform' do - let!(:orphaned_preview_card) { Fabricate(:preview_card, created_at: 2.days.ago) } - let!(:old_preview_card) { Fabricate(:preview_card, updated_at: (retention_period + 1.day).ago) } - let!(:new_preview_card) { Fabricate(:preview_card) } - - before do - old_preview_card.statuses << Fabricate(:status) - new_preview_card.statuses << Fabricate(:status) - - subject.perform - end - - it 'deletes cache of preview cards last updated before the retention period' do - expect(old_preview_card.reload.image).to be_blank - end - - it 'does not delete cache of preview cards last updated within the retention period' do - expect(new_preview_card.reload.image).to_not be_blank - end - - it 'does not delete attached preview cards' do - expect(new_preview_card.reload).to be_persisted - end - end -end diff --git a/spec/lib/vacuum/statuses_vacuum_spec.rb b/spec/lib/vacuum/statuses_vacuum_spec.rb deleted file mode 100644 index d5c013950..000000000 --- a/spec/lib/vacuum/statuses_vacuum_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Vacuum::StatusesVacuum do - subject { described_class.new(retention_period) } - - let(:retention_period) { 7.days } - - let(:remote_account) { Fabricate(:account, domain: 'example.com') } - - describe '#perform' do - let!(:remote_status_old) { Fabricate(:status, account: remote_account, created_at: (retention_period + 2.days).ago) } - let!(:remote_status_recent) { Fabricate(:status, account: remote_account, created_at: (retention_period - 2.days).ago) } - let!(:local_status_old) { Fabricate(:status, created_at: (retention_period + 2.days).ago) } - let!(:local_status_recent) { Fabricate(:status, created_at: (retention_period - 2.days).ago) } - - before do - subject.perform - end - - it 'deletes remote statuses past the retention period' do - expect { remote_status_old.reload }.to raise_error ActiveRecord::RecordNotFound - end - - it 'does not delete local statuses past the retention period' do - expect { local_status_old.reload }.to_not raise_error - end - - it 'does not delete remote statuses within the retention period' do - expect { remote_status_recent.reload }.to_not raise_error - end - - it 'does not delete local statuses within the retention period' do - expect { local_status_recent.reload }.to_not raise_error - end - end -end diff --git a/spec/lib/vacuum/system_keys_vacuum_spec.rb b/spec/lib/vacuum/system_keys_vacuum_spec.rb deleted file mode 100644 index 84cae3041..000000000 --- a/spec/lib/vacuum/system_keys_vacuum_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Vacuum::SystemKeysVacuum do - subject { described_class.new } - - describe '#perform' do - let!(:expired_system_key) { Fabricate(:system_key, created_at: (SystemKey::ROTATION_PERIOD * 4).ago) } - let!(:current_system_key) { Fabricate(:system_key) } - - before do - subject.perform - end - - it 'deletes the expired key' do - expect { expired_system_key.reload }.to raise_error ActiveRecord::RecordNotFound - end - - it 'does not delete the current key' do - expect { current_system_key.reload }.to_not raise_error - end - end -end diff --git a/spec/lib/webfinger_resource_spec.rb b/spec/lib/webfinger_resource_spec.rb deleted file mode 100644 index 558a31892..000000000 --- a/spec/lib/webfinger_resource_spec.rb +++ /dev/null @@ -1,140 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe WebfingerResource do - around do |example| - before_local = Rails.configuration.x.local_domain - before_web = Rails.configuration.x.web_domain - example.run - Rails.configuration.x.local_domain = before_local - Rails.configuration.x.web_domain = before_web - end - - describe '#username' do - describe 'with a URL value' do - it 'raises with a route whose controller is not AccountsController' do - resource = 'https://example.com/users/alice/other' - - expect do - described_class.new(resource).username - end.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'raises with a route whose action is not show' do - resource = 'https://example.com/users/alice' - - recognized = Rails.application.routes.recognize_path(resource) - allow(recognized).to receive(:[]).with(:controller).and_return('accounts') - allow(recognized).to receive(:[]).with(:username).and_return('alice') - allow(recognized).to receive(:[]).with(:action).and_return('create') - - expect(Rails.application.routes).to receive(:recognize_path).with(resource).and_return(recognized).at_least(:once) - - expect do - described_class.new(resource).username - end.to raise_error(ActiveRecord::RecordNotFound) - expect(recognized).to have_received(:[]).exactly(3).times - end - - it 'raises with a string that doesnt start with URL' do - resource = 'website for http://example.com/users/alice/other' - - expect do - described_class.new(resource).username - end.to raise_error(WebfingerResource::InvalidRequest) - end - - it 'finds the username in a valid https route' do - resource = 'https://example.com/users/alice' - - result = described_class.new(resource).username - expect(result).to eq 'alice' - end - - it 'finds the username in a mixed case http route' do - resource = 'HTTp://exAMPLe.com/users/alice' - - result = described_class.new(resource).username - expect(result).to eq 'alice' - end - - it 'finds the username in a valid http route' do - resource = 'http://example.com/users/alice' - - result = described_class.new(resource).username - expect(result).to eq 'alice' - end - end - - describe 'with a username and hostname value' do - it 'raises on a non-local domain' do - resource = 'user@remote-host.com' - - expect do - described_class.new(resource).username - end.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'finds username for a local domain' do - Rails.configuration.x.local_domain = 'example.com' - resource = 'alice@example.com' - - result = described_class.new(resource).username - expect(result).to eq 'alice' - end - - it 'finds username for a web domain' do - Rails.configuration.x.web_domain = 'example.com' - resource = 'alice@example.com' - - result = described_class.new(resource).username - expect(result).to eq 'alice' - end - end - - describe 'with an acct value' do - it 'raises on a non-local domain' do - resource = 'acct:user@remote-host.com' - - expect do - described_class.new(resource).username - end.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'raises on a nonsense domain' do - resource = 'acct:user@remote-host@remote-hostess.remote.local@remote' - - expect do - described_class.new(resource).username - end.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'finds the username for a local account if the domain is the local one' do - Rails.configuration.x.local_domain = 'example.com' - resource = 'acct:alice@example.com' - - result = described_class.new(resource).username - expect(result).to eq 'alice' - end - - it 'finds the username for a local account if the domain is the Web one' do - Rails.configuration.x.web_domain = 'example.com' - resource = 'acct:alice@example.com' - - result = described_class.new(resource).username - expect(result).to eq 'alice' - end - end - - describe 'with a nonsense resource' do - it 'raises InvalidRequest' do - resource = 'df/:dfkj' - - expect do - described_class.new(resource).username - end.to raise_error(WebfingerResource::InvalidRequest) - end - end - end -end diff --git a/spec/lib/webhooks/payload_renderer_spec.rb b/spec/lib/webhooks/payload_renderer_spec.rb deleted file mode 100644 index 074847c74..000000000 --- a/spec/lib/webhooks/payload_renderer_spec.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Webhooks::PayloadRenderer do - subject(:renderer) { described_class.new(json) } - - let(:event) { Webhooks::EventPresenter.new(type, object) } - let(:payload) { ActiveModelSerializers::SerializableResource.new(event, serializer: REST::Admin::WebhookEventSerializer, scope: nil, scope_name: :current_user).as_json } - let(:json) { Oj.dump(payload) } - - describe '#render' do - context 'when event is account.approved' do - let(:type) { 'account.approved' } - let(:object) { Fabricate(:account, display_name: 'Foo"') } - - it 'renders event-related variables into template' do - expect(renderer.render('foo={{event}}')).to eq 'foo=account.approved' - end - - it 'renders event-specific variables into template' do - expect(renderer.render('foo={{object.username}}')).to eq "foo=#{object.username}" - end - - it 'escapes values for use in JSON' do - expect(renderer.render('foo={{object.account.display_name}}')).to eq 'foo=Foo\\"' - end - end - end -end diff --git a/spec/locales/i18n_spec.rb b/spec/locales/i18n_spec.rb deleted file mode 100644 index cfce8e223..000000000 --- a/spec/locales/i18n_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'I18n' do - describe 'Pluralizing locale translations' do - subject { I18n.t('generic.validation_errors', count: 1) } - - context 'with the `en` locale which has `one` and `other` plural values' do - around do |example| - I18n.with_locale(:en) do - example.run - end - end - - it 'translates to `en` correctly and without error' do - expect { subject }.to_not raise_error - expect(subject).to match(/the error below/) - end - end - - context 'with the `my` locale which has only `other` plural value' do - around do |example| - I18n.with_locale(:my) do - example.run - end - end - - it 'translates to `my` correctly and without error' do - expect { subject }.to_not raise_error - expect(subject).to match(/1/) - end - end - end -end diff --git a/spec/mailers/admin_mailer_spec.rb b/spec/mailers/admin_mailer_spec.rb deleted file mode 100644 index 423dce88a..000000000 --- a/spec/mailers/admin_mailer_spec.rb +++ /dev/null @@ -1,130 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe AdminMailer do - describe '.new_report' do - let(:sender) { Fabricate(:account, username: 'John') } - let(:recipient) { Fabricate(:account, username: 'Mike') } - let(:report) { Fabricate(:report, account: sender, target_account: recipient) } - let(:mail) { described_class.with(recipient: recipient).new_report(report) } - - before do - recipient.user.update(locale: :en) - end - - it 'renders the headers' do - expect(mail.subject).to eq("New report for cb6e6126.ngrok.io (##{report.id})") - expect(mail.to).to eq [recipient.user_email] - expect(mail.from).to eq ['notifications@localhost'] - end - - it 'renders the body' do - expect(mail.body.encoded).to eq("Mike,\r\n\r\nJohn has reported Mike\r\n\r\nView: https://cb6e6126.ngrok.io/admin/reports/#{report.id}\r\n") - end - end - - describe '.new_appeal' do - let(:appeal) { Fabricate(:appeal) } - let(:recipient) { Fabricate(:account, username: 'Kurt') } - let(:mail) { described_class.with(recipient: recipient).new_appeal(appeal) } - - before do - recipient.user.update(locale: :en) - end - - it 'renders the headers' do - expect(mail.subject).to eq("#{appeal.account.username} is appealing a moderation decision on cb6e6126.ngrok.io") - expect(mail.to).to eq [recipient.user_email] - expect(mail.from).to eq ['notifications@localhost'] - end - - it 'renders the body' do - expect(mail.body.encoded).to match "#{appeal.account.username} is appealing a moderation decision by #{appeal.strike.account.username}" - end - end - - describe '.new_pending_account' do - let(:recipient) { Fabricate(:account, username: 'Barklums') } - let(:user) { Fabricate(:user) } - let(:mail) { described_class.with(recipient: recipient).new_pending_account(user) } - - before do - recipient.user.update(locale: :en) - end - - it 'renders the headers' do - expect(mail.subject).to eq("New account up for review on cb6e6126.ngrok.io (#{user.account.username})") - expect(mail.to).to eq [recipient.user_email] - expect(mail.from).to eq ['notifications@localhost'] - end - - it 'renders the body' do - expect(mail.body.encoded).to match 'The details of the new account are below. You can approve or reject this application.' - end - end - - describe '.new_trends' do - let(:recipient) { Fabricate(:account, username: 'Snurf') } - let(:links) { [] } - let(:statuses) { [] } - let(:tags) { [] } - let(:mail) { described_class.with(recipient: recipient).new_trends(links, tags, statuses) } - - before do - recipient.user.update(locale: :en) - end - - it 'renders the headers' do - expect(mail.subject).to eq('New trends up for review on cb6e6126.ngrok.io') - expect(mail.to).to eq [recipient.user_email] - expect(mail.from).to eq ['notifications@localhost'] - end - - it 'renders the body' do - expect(mail.body.encoded).to match 'The following items need a review before they can be displayed publicly' - end - end - - describe '.new_software_updates' do - let(:recipient) { Fabricate(:account, username: 'Bob') } - let(:mail) { described_class.with(recipient: recipient).new_software_updates } - - before do - recipient.user.update(locale: :en) - end - - it 'renders the headers' do - expect(mail.subject).to eq('New Mastodon versions are available for cb6e6126.ngrok.io!') - expect(mail.to).to eq [recipient.user_email] - expect(mail.from).to eq ['notifications@localhost'] - end - - it 'renders the body' do - expect(mail.body.encoded).to match 'New Mastodon versions have been released, you may want to update!' - end - end - - describe '.new_critical_software_updates' do - let(:recipient) { Fabricate(:account, username: 'Bob') } - let(:mail) { described_class.with(recipient: recipient).new_critical_software_updates } - - before do - recipient.user.update(locale: :en) - end - - it 'renders the headers', :aggregate_failures do - expect(mail.subject).to eq('Critical Mastodon updates are available for cb6e6126.ngrok.io!') - expect(mail.to).to eq [recipient.user_email] - expect(mail.from).to eq ['notifications@localhost'] - - expect(mail['Importance'].value).to eq 'high' - expect(mail['Priority'].value).to eq 'urgent' - expect(mail['X-Priority'].value).to eq '1' - end - - it 'renders the body' do - expect(mail.body.encoded).to match 'New critical versions of Mastodon have been released, you may want to update as soon as possible!' - end - end -end diff --git a/spec/mailers/notification_mailer_spec.rb b/spec/mailers/notification_mailer_spec.rb deleted file mode 100644 index 78a497c06..000000000 --- a/spec/mailers/notification_mailer_spec.rb +++ /dev/null @@ -1,125 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe NotificationMailer do - let(:receiver) { Fabricate(:user, account_attributes: { username: 'alice' }) } - let(:sender) { Fabricate(:account, username: 'bob') } - let(:foreign_status) { Fabricate(:status, account: sender, text: 'The body of the foreign status') } - let(:own_status) { Fabricate(:status, account: receiver.account, text: 'The body of the own status') } - - shared_examples 'headers' do |type, thread| - it 'renders the to and from headers' do - expect(mail[:to].value).to eq "#{receiver.account.username} <#{receiver.email}>" - expect(mail.from).to eq ['notifications@localhost'] - end - - it 'renders the list headers' do - expect(mail['List-ID'].value).to eq "<#{type}.alice.cb6e6126.ngrok.io>" - expect(mail['List-Unsubscribe'].value).to match(%r{}) - expect(mail['List-Unsubscribe'].value).to match("&type=#{type}") - expect(mail['List-Unsubscribe-Post'].value).to eq 'List-Unsubscribe=One-Click' - end - - if thread - it 'renders the thread headers' do - expect(mail['In-Reply-To'].value).to match(//) - expect(mail['References'].value).to match(//) - end - end - end - - describe 'mention' do - let(:mention) { Mention.create!(account: receiver.account, status: foreign_status) } - let(:notification) { Notification.create!(account: receiver.account, activity: mention) } - let(:mail) { prepared_mailer_for(receiver.account).mention } - - include_examples 'localized subject', 'notification_mailer.mention.subject', name: 'bob' - include_examples 'headers', 'mention', true - - it 'renders the subject' do - expect(mail.subject).to eq('You were mentioned by bob') - end - - it 'renders the body' do - expect(mail.body.encoded).to match('You were mentioned by bob') - expect(mail.body.encoded).to include 'The body of the foreign status' - end - end - - describe 'follow' do - let(:follow) { sender.follow!(receiver.account) } - let(:notification) { Notification.create!(account: receiver.account, activity: follow) } - let(:mail) { prepared_mailer_for(receiver.account).follow } - - include_examples 'localized subject', 'notification_mailer.follow.subject', name: 'bob' - include_examples 'headers', 'follow', false - - it 'renders the subject' do - expect(mail.subject).to eq('bob is now following you') - end - - it 'renders the body' do - expect(mail.body.encoded).to match('bob is now following you') - end - end - - describe 'favourite' do - let(:favourite) { Favourite.create!(account: sender, status: own_status) } - let(:notification) { Notification.create!(account: receiver.account, activity: favourite) } - let(:mail) { prepared_mailer_for(own_status.account).favourite } - - include_examples 'localized subject', 'notification_mailer.favourite.subject', name: 'bob' - include_examples 'headers', 'favourite', true - - it 'renders the subject' do - expect(mail.subject).to eq('bob favorited your post') - end - - it 'renders the body' do - expect(mail.body.encoded).to match('Your post was favorited by bob') - expect(mail.body.encoded).to include 'The body of the own status' - end - end - - describe 'reblog' do - let(:reblog) { Status.create!(account: sender, reblog: own_status) } - let(:notification) { Notification.create!(account: receiver.account, activity: reblog) } - let(:mail) { prepared_mailer_for(own_status.account).reblog } - - include_examples 'localized subject', 'notification_mailer.reblog.subject', name: 'bob' - include_examples 'headers', 'reblog', true - - it 'renders the subject' do - expect(mail.subject).to eq('bob boosted your post') - end - - it 'renders the body' do - expect(mail.body.encoded).to match('Your post was boosted by bob') - expect(mail.body.encoded).to include 'The body of the own status' - end - end - - describe 'follow_request' do - let(:follow_request) { Fabricate(:follow_request, account: sender, target_account: receiver.account) } - let(:notification) { Notification.create!(account: receiver.account, activity: follow_request) } - let(:mail) { prepared_mailer_for(receiver.account).follow_request } - - include_examples 'localized subject', 'notification_mailer.follow_request.subject', name: 'bob' - include_examples 'headers', 'follow_request', false - - it 'renders the subject' do - expect(mail.subject).to eq('Pending follower: bob') - end - - it 'renders the body' do - expect(mail.body.encoded).to match('bob has requested to follow you') - end - end - - private - - def prepared_mailer_for(recipient) - described_class.with(recipient: recipient, notification: notification) - end -end diff --git a/spec/mailers/previews/admin_mailer_preview.rb b/spec/mailers/previews/admin_mailer_preview.rb deleted file mode 100644 index bc8f0193b..000000000 --- a/spec/mailers/previews/admin_mailer_preview.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -# Preview all emails at http://localhost:3000/rails/mailers/admin_mailer - -class AdminMailerPreview < ActionMailer::Preview - # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_pending_account - def new_pending_account - AdminMailer.with(recipient: Account.first).new_pending_account(User.pending.first) - end - - # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_trends - def new_trends - AdminMailer.with(recipient: Account.first).new_trends(PreviewCard.joins(:trend).limit(3), Tag.limit(3), Status.joins(:trend).where(reblog_of_id: nil).limit(3)) - end - - # Preview this email at http://localhost:3000/rails/mailers/admin_mailer/new_appeal - def new_appeal - AdminMailer.with(recipient: Account.first).new_appeal(Appeal.first) - end -end diff --git a/spec/mailers/previews/notification_mailer_preview.rb b/spec/mailers/previews/notification_mailer_preview.rb deleted file mode 100644 index a63c20c27..000000000 --- a/spec/mailers/previews/notification_mailer_preview.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -# Preview all emails at http://localhost:3000/rails/mailers/notification_mailer - -class NotificationMailerPreview < ActionMailer::Preview - # Preview this email at http://localhost:3000/rails/mailers/notification_mailer/mention - def mention - activity = Mention.last - mailer_for(activity.account, activity).mention - end - - # Preview this email at http://localhost:3000/rails/mailers/notification_mailer/follow - def follow - activity = Follow.last - mailer_for(activity.target_account, activity).follow - end - - # Preview this email at http://localhost:3000/rails/mailers/notification_mailer/follow_request - def follow_request - activity = Follow.last - mailer_for(activity.target_account, activity).follow_request - end - - # Preview this email at http://localhost:3000/rails/mailers/notification_mailer/favourite - def favourite - activity = Favourite.last - mailer_for(activity.status.account, activity).favourite - end - - # Preview this email at http://localhost:3000/rails/mailers/notification_mailer/reblog - def reblog - activity = Status.where.not(reblog_of_id: nil).first - mailer_for(activity.reblog.account, activity).reblog - end - - private - - def mailer_for(account, activity) - NotificationMailer.with( - recipient: account, - notification: Notification.find_by(activity: activity) - ) - end -end diff --git a/spec/mailers/previews/user_mailer_preview.rb b/spec/mailers/previews/user_mailer_preview.rb deleted file mode 100644 index 098c9cd90..000000000 --- a/spec/mailers/previews/user_mailer_preview.rb +++ /dev/null @@ -1,96 +0,0 @@ -# frozen_string_literal: true - -# Preview all emails at http://localhost:3000/rails/mailers/user_mailer - -class UserMailerPreview < ActionMailer::Preview - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/confirmation_instructions - def confirmation_instructions - UserMailer.confirmation_instructions(User.first, 'spec') - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/email_changed - def email_changed - user = User.first - user.unconfirmed_email = 'foo@bar.com' - UserMailer.email_changed(user) - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/password_change - def password_change - UserMailer.password_change(User.first) - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/two_factor_disabled - def two_factor_disabled - UserMailer.two_factor_disabled(User.first) - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/two_factor_enabled - def two_factor_enabled - UserMailer.two_factor_enabled(User.first) - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/two_factor_recovery_codes_changed - def two_factor_recovery_codes_changed - UserMailer.two_factor_recovery_codes_changed(User.first) - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/webauthn_enabled - def webauthn_enabled - UserMailer.webauthn_enabled(User.first) - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/webauthn_disabled - def webauthn_disabled - UserMailer.webauthn_disabled(User.first) - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/webauthn_credential_added - def webauthn_credential_added - webauthn_credential = WebauthnCredential.new(nickname: 'USB Key') - UserMailer.webauthn_credential_added(User.first, webauthn_credential) - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/webauthn_credential_deleted - def webauthn_credential_deleted - webauthn_credential = WebauthnCredential.new(nickname: 'USB Key') - UserMailer.webauthn_credential_deleted(User.first, webauthn_credential) - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/reconfirmation_instructions - def reconfirmation_instructions - user = User.first - user.unconfirmed_email = 'foo@bar.com' - UserMailer.confirmation_instructions(user, 'spec') - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/reset_password_instructions - def reset_password_instructions - UserMailer.reset_password_instructions(User.first, 'spec') - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/welcome - def welcome - UserMailer.welcome(User.first) - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/backup_ready - def backup_ready - UserMailer.backup_ready(User.first, Backup.first) - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/warning - def warning - UserMailer.warning(User.first, AccountWarning.last) - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/appeal_approved - def appeal_approved - UserMailer.appeal_approved(User.first, Appeal.last) - end - - # Preview this email at http://localhost:3000/rails/mailers/user_mailer/suspicious_sign_in - def suspicious_sign_in - UserMailer.suspicious_sign_in(User.first, '127.0.0.1', 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:75.0) Gecko/20100101 Firefox/75.0', Time.now.utc) - end -end diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb deleted file mode 100644 index 5affa66e0..000000000 --- a/spec/mailers/user_mailer_spec.rb +++ /dev/null @@ -1,187 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe UserMailer do - let(:receiver) { Fabricate(:user) } - - describe 'confirmation_instructions' do - let(:mail) { described_class.confirmation_instructions(receiver, 'spec') } - - it 'renders confirmation instructions' do - receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('devise.mailer.confirmation_instructions.title') - expect(mail.body.encoded).to include 'spec' - expect(mail.body.encoded).to include Rails.configuration.x.local_domain - end - - include_examples 'localized subject', - 'devise.mailer.confirmation_instructions.subject', - instance: Rails.configuration.x.local_domain - end - - describe 'reconfirmation_instructions' do - let(:mail) { described_class.confirmation_instructions(receiver, 'spec') } - - it 'renders reconfirmation instructions' do - receiver.update!(email: 'new-email@example.com', locale: nil) - expect(mail.body.encoded).to include I18n.t('devise.mailer.reconfirmation_instructions.title') - expect(mail.body.encoded).to include 'spec' - expect(mail.body.encoded).to include Rails.configuration.x.local_domain - expect(mail.subject).to eq I18n.t('devise.mailer.reconfirmation_instructions.subject', - instance: Rails.configuration.x.local_domain, - locale: I18n.default_locale) - end - end - - describe 'reset_password_instructions' do - let(:mail) { described_class.reset_password_instructions(receiver, 'spec') } - - it 'renders reset password instructions' do - receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('devise.mailer.reset_password_instructions.title') - expect(mail.body.encoded).to include 'spec' - end - - include_examples 'localized subject', - 'devise.mailer.reset_password_instructions.subject' - end - - describe 'password_change' do - let(:mail) { described_class.password_change(receiver) } - - it 'renders password change notification' do - receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('devise.mailer.password_change.title') - end - - include_examples 'localized subject', - 'devise.mailer.password_change.subject' - end - - describe 'email_changed' do - let(:mail) { described_class.email_changed(receiver) } - - it 'renders email change notification' do - receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('devise.mailer.email_changed.title') - end - - include_examples 'localized subject', - 'devise.mailer.email_changed.subject' - end - - describe 'warning' do - let(:strike) { Fabricate(:account_warning, target_account: receiver.account, text: 'dont worry its just the testsuite', action: 'suspend') } - let(:mail) { described_class.warning(receiver, strike) } - - it 'renders warning notification' do - receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('user_mailer.warning.title.suspend', acct: receiver.account.acct) - expect(mail.body.encoded).to include strike.text - end - end - - describe 'webauthn_credential_deleted' do - let(:credential) { Fabricate(:webauthn_credential, user_id: receiver.id) } - let(:mail) { described_class.webauthn_credential_deleted(receiver, credential) } - - it 'renders webauthn credential deleted notification' do - receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_credential.deleted.title') - end - - include_examples 'localized subject', - 'devise.mailer.webauthn_credential.deleted.subject' - end - - describe 'suspicious_sign_in' do - let(:ip) { '192.168.0.1' } - let(:agent) { 'NCSA_Mosaic/2.0 (Windows 3.1)' } - let(:timestamp) { Time.now.utc } - let(:mail) { described_class.suspicious_sign_in(receiver, ip, agent, timestamp) } - - it 'renders suspicious sign in notification' do - receiver.update!(locale: nil) - expect(mail.body.encoded).to include I18n.t('user_mailer.suspicious_sign_in.explanation') - end - - include_examples 'localized subject', - 'user_mailer.suspicious_sign_in.subject' - end - - describe 'appeal_approved' do - let(:appeal) { Fabricate(:appeal, account: receiver.account, approved_at: Time.now.utc) } - let(:mail) { described_class.appeal_approved(receiver, appeal) } - - it 'renders appeal_approved notification' do - expect(mail.subject).to eq I18n.t('user_mailer.appeal_approved.subject', date: I18n.l(appeal.created_at)) - expect(mail.body.encoded).to include I18n.t('user_mailer.appeal_approved.title') - end - end - - describe 'appeal_rejected' do - let(:appeal) { Fabricate(:appeal, account: receiver.account, rejected_at: Time.now.utc) } - let(:mail) { described_class.appeal_rejected(receiver, appeal) } - - it 'renders appeal_rejected notification' do - expect(mail.subject).to eq I18n.t('user_mailer.appeal_rejected.subject', date: I18n.l(appeal.created_at)) - expect(mail.body.encoded).to include I18n.t('user_mailer.appeal_rejected.title') - end - end - - describe 'two_factor_enabled' do - let(:mail) { described_class.two_factor_enabled(receiver) } - - it 'renders two_factor_enabled mail' do - expect(mail.subject).to eq I18n.t('devise.mailer.two_factor_enabled.subject') - expect(mail.body.encoded).to include I18n.t('devise.mailer.two_factor_enabled.explanation') - end - end - - describe 'two_factor_disabled' do - let(:mail) { described_class.two_factor_disabled(receiver) } - - it 'renders two_factor_disabled mail' do - expect(mail.subject).to eq I18n.t('devise.mailer.two_factor_disabled.subject') - expect(mail.body.encoded).to include I18n.t('devise.mailer.two_factor_disabled.explanation') - end - end - - describe 'webauthn_enabled' do - let(:mail) { described_class.webauthn_enabled(receiver) } - - it 'renders webauthn_enabled mail' do - expect(mail.subject).to eq I18n.t('devise.mailer.webauthn_enabled.subject') - expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_enabled.explanation') - end - end - - describe 'webauthn_disabled' do - let(:mail) { described_class.webauthn_disabled(receiver) } - - it 'renders webauthn_disabled mail' do - expect(mail.subject).to eq I18n.t('devise.mailer.webauthn_disabled.subject') - expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_disabled.explanation') - end - end - - describe 'two_factor_recovery_codes_changed' do - let(:mail) { described_class.two_factor_recovery_codes_changed(receiver) } - - it 'renders two_factor_recovery_codes_changed mail' do - expect(mail.subject).to eq I18n.t('devise.mailer.two_factor_recovery_codes_changed.subject') - expect(mail.body.encoded).to include I18n.t('devise.mailer.two_factor_recovery_codes_changed.explanation') - end - end - - describe 'webauthn_credential_added' do - let(:credential) { Fabricate.build(:webauthn_credential) } - let(:mail) { described_class.webauthn_credential_added(receiver, credential) } - - it 'renders webauthn_credential_added mail' do - expect(mail.subject).to eq I18n.t('devise.mailer.webauthn_credential.added.subject') - expect(mail.body.encoded).to include I18n.t('devise.mailer.webauthn_credential.added.explanation') - end - end -end diff --git a/spec/models/account/field_spec.rb b/spec/models/account/field_spec.rb deleted file mode 100644 index 22593bb21..000000000 --- a/spec/models/account/field_spec.rb +++ /dev/null @@ -1,164 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Account::Field do - describe '#verified?' do - subject { described_class.new(account, 'name' => 'Foo', 'value' => 'Bar', 'verified_at' => verified_at) } - - let(:account) { instance_double(Account, local?: true) } - - context 'when verified_at is set' do - let(:verified_at) { Time.now.utc.iso8601 } - - it 'returns true' do - expect(subject.verified?).to be true - end - end - - context 'when verified_at is not set' do - let(:verified_at) { nil } - - it 'returns false' do - expect(subject.verified?).to be false - end - end - end - - describe '#mark_verified!' do - subject { described_class.new(account, original_hash) } - - let(:account) { instance_double(Account, local?: true) } - let(:original_hash) { { 'name' => 'Foo', 'value' => 'Bar' } } - - before do - subject.mark_verified! - end - - it 'updates verified_at' do - expect(subject.verified_at).to_not be_nil - end - - it 'updates original hash' do - expect(original_hash['verified_at']).to_not be_nil - end - end - - describe '#verifiable?' do - subject { described_class.new(account, 'name' => 'Foo', 'value' => value) } - - let(:account) { instance_double(Account, local?: local) } - - context 'with local accounts' do - let(:local) { true } - - context 'with a URL with misleading authentication' do - let(:value) { 'https://spacex.com @h.43z.one' } - - it 'returns false' do - expect(subject.verifiable?).to be false - end - end - - context 'with a URL' do - let(:value) { 'https://example.com' } - - it 'returns true' do - expect(subject.verifiable?).to be true - end - end - - context 'with an IDN URL' do - let(:value) { 'https://twitter.com∕dougallj∕status∕1590357240443437057.ê.cc/twitter.html' } - - it 'returns false' do - expect(subject.verifiable?).to be false - end - end - - context 'with a URL with a non-normalized path' do - let(:value) { 'https://github.com/octocatxxxxxxxx/../mastodon' } - - it 'returns false' do - expect(subject.verifiable?).to be false - end - end - - context 'with text that is not a URL' do - let(:value) { 'Hello world' } - - it 'returns false' do - expect(subject.verifiable?).to be false - end - end - - context 'with text that contains a URL' do - let(:value) { 'Hello https://example.com world' } - - it 'returns false' do - expect(subject.verifiable?).to be false - end - end - - context 'with text which is blank' do - let(:value) { '' } - - it 'returns false' do - expect(subject.verifiable?).to be false - end - end - end - - context 'with remote accounts' do - let(:local) { false } - - context 'with a link' do - let(:value) { 'patreon.com/mastodon' } - - it 'returns true' do - expect(subject.verifiable?).to be true - end - end - - context 'with a link with misleading authentication' do - let(:value) { 'google.com' } - - it 'returns false' do - expect(subject.verifiable?).to be false - end - end - - context 'with HTML that has more than just a link' do - let(:value) { 'google.com @h.43z.one' } - - it 'returns false' do - expect(subject.verifiable?).to be false - end - end - - context 'with a link with different visible text' do - let(:value) { 'https://example.com/foo' } - - it 'returns false' do - expect(subject.verifiable?).to be false - end - end - - context 'with text that is a URL but is not linked' do - let(:value) { 'https://example.com/foo' } - - it 'returns false' do - expect(subject.verifiable?).to be false - end - end - - context 'with text which is blank' do - let(:value) { '' } - - it 'returns false' do - expect(subject.verifiable?).to be false - end - end - end - end -end diff --git a/spec/models/account_conversation_spec.rb b/spec/models/account_conversation_spec.rb deleted file mode 100644 index 4e8727ca3..000000000 --- a/spec/models/account_conversation_spec.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe AccountConversation do - let!(:alice) { Fabricate(:account, username: 'alice') } - let!(:bob) { Fabricate(:account, username: 'bob') } - let!(:mark) { Fabricate(:account, username: 'mark') } - - describe '.add_status' do - it 'creates new record when no others exist' do - status = Fabricate(:status, account: alice, visibility: :direct) - status.mentions.create(account: bob) - - conversation = described_class.add_status(alice, status) - - expect(conversation.participant_accounts).to include(bob) - expect(conversation.last_status).to eq status - expect(conversation.status_ids).to eq [status.id] - end - - it 'appends to old record when there is a match' do - last_status = Fabricate(:status, account: alice, visibility: :direct) - conversation = described_class.create!(account: alice, conversation: last_status.conversation, participant_account_ids: [bob.id], status_ids: [last_status.id]) - - status = Fabricate(:status, account: bob, visibility: :direct, thread: last_status) - status.mentions.create(account: alice) - - new_conversation = described_class.add_status(alice, status) - - expect(new_conversation.id).to eq conversation.id - expect(new_conversation.participant_accounts).to include(bob) - expect(new_conversation.last_status).to eq status - expect(new_conversation.status_ids).to eq [last_status.id, status.id] - end - - it 'creates new record when new participants are added' do - last_status = Fabricate(:status, account: alice, visibility: :direct) - conversation = described_class.create!(account: alice, conversation: last_status.conversation, participant_account_ids: [bob.id], status_ids: [last_status.id]) - - status = Fabricate(:status, account: bob, visibility: :direct, thread: last_status) - status.mentions.create(account: alice) - status.mentions.create(account: mark) - - new_conversation = described_class.add_status(alice, status) - - expect(new_conversation.id).to_not eq conversation.id - expect(new_conversation.participant_accounts).to include(bob, mark) - expect(new_conversation.last_status).to eq status - expect(new_conversation.status_ids).to eq [status.id] - end - end - - describe '.remove_status' do - it 'updates last status to a previous value' do - last_status = Fabricate(:status, account: alice, visibility: :direct) - status = Fabricate(:status, account: alice, visibility: :direct) - conversation = described_class.create!(account: alice, conversation: last_status.conversation, participant_account_ids: [bob.id], status_ids: [status.id, last_status.id]) - last_status.mentions.create(account: bob) - last_status.destroy! - conversation.reload - expect(conversation.last_status).to eq status - expect(conversation.status_ids).to eq [status.id] - end - - it 'removes the record if no other statuses are referenced' do - last_status = Fabricate(:status, account: alice, visibility: :direct) - conversation = described_class.create!(account: alice, conversation: last_status.conversation, participant_account_ids: [bob.id], status_ids: [last_status.id]) - last_status.mentions.create(account: bob) - last_status.destroy! - expect(described_class.where(id: conversation.id).count).to eq 0 - end - end -end diff --git a/spec/models/account_domain_block_spec.rb b/spec/models/account_domain_block_spec.rb deleted file mode 100644 index 10bd57936..000000000 --- a/spec/models/account_domain_block_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe AccountDomainBlock do - it 'removes blocking cache after creation' do - account = Fabricate(:account) - Rails.cache.write("exclude_domains_for:#{account.id}", 'a.domain.already.blocked') - - described_class.create!(account: account, domain: 'a.domain.blocked.later') - - expect(Rails.cache.exist?("exclude_domains_for:#{account.id}")).to be false - end - - it 'removes blocking cache after destruction' do - account = Fabricate(:account) - block = described_class.create!(account: account, domain: 'domain') - Rails.cache.write("exclude_domains_for:#{account.id}", 'domain') - - block.destroy! - - expect(Rails.cache.exist?("exclude_domains_for:#{account.id}")).to be false - end -end diff --git a/spec/models/account_filter_spec.rb b/spec/models/account_filter_spec.rb deleted file mode 100644 index fa47b5954..000000000 --- a/spec/models/account_filter_spec.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe AccountFilter do - describe 'with empty params' do - it 'excludes instance actor by default' do - filter = described_class.new({}) - - expect(filter.results).to eq Account.without_instance_actor - end - end - - describe 'with invalid params' do - it 'raises with key error' do - filter = described_class.new(wrong: true) - - expect { filter.results }.to raise_error(/wrong/) - end - end - - describe 'with origin and by_domain interacting' do - let!(:local_account) { Fabricate(:account, domain: nil) } - let!(:remote_account_one) { Fabricate(:account, domain: 'example.org') } - let(:remote_account_two) { Fabricate(:account, domain: 'other.domain') } - - it 'works with domain first and origin remote' do - filter = described_class.new(by_domain: 'example.org', origin: 'remote') - expect(filter.results).to contain_exactly(remote_account_one) - end - - it 'works with domain last and origin remote' do - filter = described_class.new(origin: 'remote', by_domain: 'example.org') - expect(filter.results).to contain_exactly(remote_account_one) - end - - it 'works with domain first and origin local' do - filter = described_class.new(by_domain: 'example.org', origin: 'local') - expect(filter.results).to contain_exactly(local_account) - end - - it 'works with domain last and origin local' do - filter = described_class.new(origin: 'local', by_domain: 'example.org') - expect(filter.results).to contain_exactly(remote_account_one) - end - end - - describe 'with username' do - let!(:local_account) { Fabricate(:account, domain: nil, username: 'validUserName') } - - it 'works with @ at the beginning of the username' do - filter = described_class.new(username: '@validUserName') - expect(filter.results).to contain_exactly(local_account) - end - - it 'does not work with more than one @ at the beginning of the username' do - filter = described_class.new(username: '@@validUserName') - expect(filter.results).to_not contain_exactly(local_account) - end - - it 'does not work with @ outside the beginning of the username' do - filter = described_class.new(username: 'validUserName@') - expect(filter.results).to_not contain_exactly(local_account) - end - end -end diff --git a/spec/models/account_migration_spec.rb b/spec/models/account_migration_spec.rb deleted file mode 100644 index 1f32c6082..000000000 --- a/spec/models/account_migration_spec.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe AccountMigration do - describe 'validations' do - subject { described_class.new(account: source_account, acct: target_acct) } - - let(:source_account) { Fabricate(:account) } - let(:target_acct) { target_account.acct } - - context 'with valid properties' do - let(:target_account) { Fabricate(:account, username: 'target', domain: 'remote.org') } - - before do - target_account.aliases.create!(acct: source_account.acct) - - service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(service_double) - allow(service_double).to receive(:call).with(target_acct, anything).and_return(target_account) - end - - it 'passes validations' do - expect(subject).to be_valid - end - end - - context 'with unresolvable account' do - let(:target_acct) { 'target@remote' } - - before do - service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(service_double) - allow(service_double).to receive(:call).with(target_acct, anything).and_return(nil) - end - - it 'has errors on acct field' do - expect(subject).to model_have_error_on_field(:acct) - end - end - - context 'with a space in the domain part' do - let(:target_acct) { 'target@remote. org' } - - it 'has errors on acct field' do - expect(subject).to model_have_error_on_field(:acct) - end - end - end -end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb deleted file mode 100644 index fc7a43110..000000000 --- a/spec/models/account_spec.rb +++ /dev/null @@ -1,1001 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Account do - context 'with an account record' do - subject { Fabricate(:account) } - - let(:bob) { Fabricate(:account, username: 'bob') } - - describe '#suspend!' do - it 'marks the account as suspended' do - subject.suspend! - expect(subject.suspended?).to be true - end - - it 'creates a deletion request' do - subject.suspend! - expect(AccountDeletionRequest.where(account: subject).exists?).to be true - end - - context 'when the account is of a local user' do - subject { local_user_account } - - let!(:local_user_account) { Fabricate(:user, email: 'foo+bar@domain.org').account } - - it 'creates a canonical domain block' do - subject.suspend! - expect(CanonicalEmailBlock.block?(subject.user_email)).to be true - end - - context 'when a canonical domain block already exists for that email' do - before do - Fabricate(:canonical_email_block, email: subject.user_email) - end - - it 'does not raise an error' do - expect { subject.suspend! }.to_not raise_error - end - end - end - end - - describe '#follow!' do - it 'creates a follow' do - follow = subject.follow!(bob) - - expect(follow).to be_instance_of Follow - expect(follow.account).to eq subject - expect(follow.target_account).to eq bob - end - end - - describe '#unfollow!' do - before do - subject.follow!(bob) - end - - it 'destroys a follow' do - unfollow = subject.unfollow!(bob) - - expect(unfollow).to be_instance_of Follow - expect(unfollow.account).to eq subject - expect(unfollow.target_account).to eq bob - expect(unfollow.destroyed?).to be true - end - end - - describe '#following?' do - it 'returns true when the target is followed' do - subject.follow!(bob) - expect(subject.following?(bob)).to be true - end - - it 'returns false if the target is not followed' do - expect(subject.following?(bob)).to be false - end - end - end - - describe '#local?' do - it 'returns true when the account is local' do - account = Fabricate(:account, domain: nil) - expect(account.local?).to be true - end - - it 'returns false when the account is on a different domain' do - account = Fabricate(:account, domain: 'foreign.tld') - expect(account.local?).to be false - end - end - - describe 'Local domain user methods' do - subject { Fabricate(:account, domain: nil, username: 'alice') } - - around do |example| - before = Rails.configuration.x.local_domain - example.run - Rails.configuration.x.local_domain = before - end - - describe '#to_webfinger_s' do - it 'returns a webfinger string for the account' do - Rails.configuration.x.local_domain = 'example.com' - - expect(subject.to_webfinger_s).to eq 'acct:alice@example.com' - end - end - - describe '#local_username_and_domain' do - it 'returns the username and local domain for the account' do - Rails.configuration.x.local_domain = 'example.com' - - expect(subject.local_username_and_domain).to eq 'alice@example.com' - end - end - end - - describe '#acct' do - it 'returns username for local users' do - account = Fabricate(:account, domain: nil, username: 'alice') - expect(account.acct).to eql 'alice' - end - - it 'returns username@domain for foreign users' do - account = Fabricate(:account, domain: 'foreign.tld', username: 'alice') - expect(account.acct).to eql 'alice@foreign.tld' - end - end - - describe '#save_with_optional_media!' do - before do - stub_request(:get, 'https://remote.test/valid_avatar').to_return(request_fixture('avatar.txt')) - stub_request(:get, 'https://remote.test/invalid_avatar').to_return(request_fixture('feed.txt')) - end - - let(:account) do - Fabricate(:account, - avatar_remote_url: 'https://remote.test/valid_avatar', - header_remote_url: 'https://remote.test/valid_avatar') - end - - let!(:expectation) { account.dup } - - context 'with valid properties' do - before do - account.save_with_optional_media! - end - - it 'unchanges avatar, header, avatar_remote_url, and header_remote_url' do - expect(account.avatar_remote_url).to eq expectation.avatar_remote_url - expect(account.header_remote_url).to eq expectation.header_remote_url - expect(account.avatar_file_name).to eq expectation.avatar_file_name - expect(account.header_file_name).to eq expectation.header_file_name - end - end - - context 'with invalid properties' do - before do - account.avatar_remote_url = 'https://remote.test/invalid_avatar' - account.save_with_optional_media! - end - - it 'sets default avatar, header, avatar_remote_url, and header_remote_url' do - expect(account.avatar_remote_url).to eq 'https://remote.test/invalid_avatar' - expect(account.header_remote_url).to eq expectation.header_remote_url - expect(account.avatar_file_name).to be_nil - expect(account.header_file_name).to eq expectation.header_file_name - end - end - end - - describe '#possibly_stale?' do - let(:account) { Fabricate(:account, last_webfingered_at: last_webfingered_at) } - - context 'when last_webfingered_at is nil' do - let(:last_webfingered_at) { nil } - - it 'returns true' do - expect(account.possibly_stale?).to be true - end - end - - context 'when last_webfingered_at is more than 24 hours before' do - let(:last_webfingered_at) { 25.hours.ago } - - it 'returns true' do - expect(account.possibly_stale?).to be true - end - end - - context 'when last_webfingered_at is less than 24 hours before' do - let(:last_webfingered_at) { 23.hours.ago } - - it 'returns false' do - expect(account.possibly_stale?).to be false - end - end - end - - describe '#refresh!' do - let(:account) { Fabricate(:account, domain: domain) } - let(:acct) { account.acct } - - context 'when domain is nil' do - let(:domain) { nil } - - it 'returns nil' do - expect(account.refresh!).to be_nil - end - - it 'calls not ResolveAccountService#call' do - expect_any_instance_of(ResolveAccountService).to_not receive(:call).with(acct) - account.refresh! - end - end - - context 'when domain is present' do - let(:domain) { 'example.com' } - - it 'calls ResolveAccountService#call' do - expect_any_instance_of(ResolveAccountService).to receive(:call).with(acct).once - account.refresh! - end - end - end - - describe '#to_param' do - it 'returns username' do - account = Fabricate(:account, username: 'alice') - expect(account.to_param).to eq 'alice' - end - end - - describe '#keypair' do - it 'returns an RSA key pair' do - account = Fabricate(:account) - expect(account.keypair).to be_instance_of OpenSSL::PKey::RSA - end - end - - describe '#object_type' do - it 'is always a person' do - account = Fabricate(:account) - expect(account.object_type).to be :person - end - end - - describe '#favourited?' do - subject { Fabricate(:account) } - - let(:original_status) do - author = Fabricate(:account, username: 'original') - Fabricate(:status, account: author) - end - - context 'when the status is a reblog of another status' do - let(:original_reblog) do - author = Fabricate(:account, username: 'original_reblogger') - Fabricate(:status, reblog: original_status, account: author) - end - - it 'is true when this account has favourited it' do - Fabricate(:favourite, status: original_reblog, account: subject) - - expect(subject.favourited?(original_status)).to be true - end - - it 'is false when this account has not favourited it' do - expect(subject.favourited?(original_status)).to be false - end - end - - context 'when the status is an original status' do - it 'is true when this account has favourited it' do - Fabricate(:favourite, status: original_status, account: subject) - - expect(subject.favourited?(original_status)).to be true - end - - it 'is false when this account has not favourited it' do - expect(subject.favourited?(original_status)).to be false - end - end - end - - describe '#reblogged?' do - subject { Fabricate(:account) } - - let(:original_status) do - author = Fabricate(:account, username: 'original') - Fabricate(:status, account: author) - end - - context 'when the status is a reblog of another status' do - let(:original_reblog) do - author = Fabricate(:account, username: 'original_reblogger') - Fabricate(:status, reblog: original_status, account: author) - end - - it 'is true when this account has reblogged it' do - Fabricate(:status, reblog: original_reblog, account: subject) - - expect(subject.reblogged?(original_reblog)).to be true - end - - it 'is false when this account has not reblogged it' do - expect(subject.reblogged?(original_reblog)).to be false - end - end - - context 'when the status is an original status' do - it 'is true when this account has reblogged it' do - Fabricate(:status, reblog: original_status, account: subject) - - expect(subject.reblogged?(original_status)).to be true - end - - it 'is false when this account has not reblogged it' do - expect(subject.reblogged?(original_status)).to be false - end - end - end - - describe '#excluded_from_timeline_account_ids' do - it 'includes account ids of blockings, blocked_bys and mutes' do - account = Fabricate(:account) - block = Fabricate(:block, account: account) - mute = Fabricate(:mute, account: account) - block_by = Fabricate(:block, target_account: account) - - results = account.excluded_from_timeline_account_ids - expect(results.size).to eq 3 - expect(results).to include(block.target_account.id) - expect(results).to include(mute.target_account.id) - expect(results).to include(block_by.account.id) - end - end - - describe '#excluded_from_timeline_domains' do - it 'returns the domains blocked by the account' do - account = Fabricate(:account) - account.block_domain!('domain') - expect(account.excluded_from_timeline_domains).to contain_exactly('domain') - end - end - - describe '.search_for' do - before do - _missing = Fabricate( - :account, - display_name: 'Missing', - username: 'missing', - domain: 'missing.com' - ) - end - - it 'does not return suspended users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username', - domain: 'example.com', - suspended: true - ) - - results = described_class.search_for('username') - expect(results).to eq [] - end - - it 'does not return unapproved users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username' - ) - - match.user.update(approved: false) - - results = described_class.search_for('username') - expect(results).to eq [] - end - - it 'does not return unconfirmed users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username' - ) - - match.user.update(confirmed_at: nil) - - results = described_class.search_for('username') - expect(results).to eq [] - end - - it 'accepts ?, \, : and space as delimiter' do - match = Fabricate( - :account, - display_name: 'A & l & i & c & e', - username: 'username', - domain: 'example.com' - ) - - results = described_class.search_for('A?l\i:c e') - expect(results).to eq [match] - end - - it 'finds accounts with matching display_name' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username', - domain: 'example.com' - ) - - results = described_class.search_for('display') - expect(results).to eq [match] - end - - it 'finds accounts with matching username' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username', - domain: 'example.com' - ) - - results = described_class.search_for('username') - expect(results).to eq [match] - end - - it 'finds accounts with matching domain' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username', - domain: 'example.com' - ) - - results = described_class.search_for('example') - expect(results).to eq [match] - end - - it 'limits by 10 by default' do - 11.times.each { Fabricate(:account, display_name: 'Display Name') } - results = described_class.search_for('display') - expect(results.size).to eq 10 - end - - it 'accepts arbitrary limits' do - 2.times.each { Fabricate(:account, display_name: 'Display Name') } - results = described_class.search_for('display', limit: 1) - expect(results.size).to eq 1 - end - - it 'ranks multiple matches higher' do - matches = [ - { username: 'username', display_name: 'username' }, - { display_name: 'Display Name', username: 'username', domain: 'example.com' }, - ].map(&method(:Fabricate).curry(2).call(:account)) - - results = described_class.search_for('username') - expect(results).to eq matches - end - end - - describe '.advanced_search_for' do - let(:account) { Fabricate(:account) } - - context 'when limiting search to followed accounts' do - it 'accepts ?, \, : and space as delimiter' do - match = Fabricate( - :account, - display_name: 'A & l & i & c & e', - username: 'username', - domain: 'example.com' - ) - account.follow!(match) - - results = described_class.advanced_search_for('A?l\i:c e', account, limit: 10, following: true) - expect(results).to eq [match] - end - - it 'does not return non-followed accounts' do - match = Fabricate( - :account, - display_name: 'A & l & i & c & e', - username: 'username', - domain: 'example.com' - ) - - results = described_class.advanced_search_for('A?l\i:c e', account, limit: 10, following: true) - expect(results).to eq [] - end - - it 'does not return suspended users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username', - domain: 'example.com', - suspended: true - ) - - results = described_class.advanced_search_for('username', account, limit: 10, following: true) - expect(results).to eq [] - end - - it 'does not return unapproved users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username' - ) - - match.user.update(approved: false) - - results = described_class.advanced_search_for('username', account, limit: 10, following: true) - expect(results).to eq [] - end - - it 'does not return unconfirmed users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username' - ) - - match.user.update(confirmed_at: nil) - - results = described_class.advanced_search_for('username', account, limit: 10, following: true) - expect(results).to eq [] - end - end - - it 'does not return suspended users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username', - domain: 'example.com', - suspended: true - ) - - results = described_class.advanced_search_for('username', account) - expect(results).to eq [] - end - - it 'does not return unapproved users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username' - ) - - match.user.update(approved: false) - - results = described_class.advanced_search_for('username', account) - expect(results).to eq [] - end - - it 'does not return unconfirmed users' do - match = Fabricate( - :account, - display_name: 'Display Name', - username: 'username' - ) - - match.user.update(confirmed_at: nil) - - results = described_class.advanced_search_for('username', account) - expect(results).to eq [] - end - - it 'accepts ?, \, : and space as delimiter' do - match = Fabricate( - :account, - display_name: 'A & l & i & c & e', - username: 'username', - domain: 'example.com' - ) - - results = described_class.advanced_search_for('A?l\i:c e', account) - expect(results).to eq [match] - end - - it 'limits by 10 by default' do - 11.times { Fabricate(:account, display_name: 'Display Name') } - results = described_class.advanced_search_for('display', account) - expect(results.size).to eq 10 - end - - it 'accepts arbitrary limits' do - 2.times { Fabricate(:account, display_name: 'Display Name') } - results = described_class.advanced_search_for('display', account, limit: 1) - expect(results.size).to eq 1 - end - - it 'ranks followed accounts higher' do - match = Fabricate(:account, username: 'Matching') - followed_match = Fabricate(:account, username: 'Matcher') - Fabricate(:follow, account: account, target_account: followed_match) - - results = described_class.advanced_search_for('match', account) - expect(results).to eq [followed_match, match] - expect(results.first.rank).to be > results.last.rank - end - end - - describe '#statuses_count' do - subject { Fabricate(:account) } - - it 'counts statuses' do - Fabricate(:status, account: subject) - Fabricate(:status, account: subject) - expect(subject.statuses_count).to eq 2 - end - - it 'does not count direct statuses' do - Fabricate(:status, account: subject, visibility: :direct) - expect(subject.statuses_count).to eq 0 - end - - it 'is decremented when status is removed' do - status = Fabricate(:status, account: subject) - expect(subject.statuses_count).to eq 1 - status.destroy - expect(subject.statuses_count).to eq 0 - end - - it 'is decremented when status is removed when account is not preloaded' do - status = Fabricate(:status, account: subject) - expect(subject.reload.statuses_count).to eq 1 - clean_status = Status.find(status.id) - expect(clean_status.association(:account).loaded?).to be false - clean_status.destroy - expect(subject.reload.statuses_count).to eq 0 - end - end - - describe '.following_map' do - it 'returns an hash' do - expect(described_class.following_map([], 1)).to be_a Hash - end - end - - describe '.followed_by_map' do - it 'returns an hash' do - expect(described_class.followed_by_map([], 1)).to be_a Hash - end - end - - describe '.blocking_map' do - it 'returns an hash' do - expect(described_class.blocking_map([], 1)).to be_a Hash - end - end - - describe '.requested_map' do - it 'returns an hash' do - expect(described_class.requested_map([], 1)).to be_a Hash - end - end - - describe '.requested_by_map' do - it 'returns an hash' do - expect(described_class.requested_by_map([], 1)).to be_a Hash - end - end - - describe 'MENTION_RE' do - subject { Account::MENTION_RE } - - it 'matches usernames in the middle of a sentence' do - expect(subject.match('Hello to @alice from me')[1]).to eq 'alice' - end - - it 'matches usernames in the beginning of status' do - expect(subject.match('@alice Hey how are you?')[1]).to eq 'alice' - end - - it 'matches full usernames' do - expect(subject.match('@alice@example.com')[1]).to eq 'alice@example.com' - end - - it 'matches full usernames with a dot at the end' do - expect(subject.match('Hello @alice@example.com.')[1]).to eq 'alice@example.com' - end - - it 'matches dot-prepended usernames' do - expect(subject.match('.@alice I want everybody to see this')[1]).to eq 'alice' - end - - it 'does not match e-mails' do - expect(subject.match('Drop me an e-mail at alice@example.com')).to be_nil - end - - it 'does not match URLs' do - expect(subject.match('Check this out https://medium.com/@alice/some-article#.abcdef123')).to be_nil - end - - it 'does not match URL query string' do - expect(subject.match('https://example.com/?x=@alice')).to be_nil - end - end - - describe 'validations' do - it 'is invalid without a username' do - account = Fabricate.build(:account, username: nil) - account.valid? - expect(account).to model_have_error_on_field(:username) - end - - it 'squishes the username before validation' do - account = Fabricate(:account, domain: nil, username: " \u3000bob \t \u00a0 \n ") - expect(account.username).to eq 'bob' - end - - context 'when is local' do - it 'is invalid if the username is not unique in case-insensitive comparison among local accounts' do - account_1 = Fabricate(:account, username: 'the_doctor') - account_2 = Fabricate.build(:account, username: 'the_Doctor') - account_2.valid? - expect(account_2).to model_have_error_on_field(:username) - end - - it 'is invalid if the username is reserved' do - account = Fabricate.build(:account, username: 'support') - account.valid? - expect(account).to model_have_error_on_field(:username) - end - - it 'is valid when username is reserved but record has already been created' do - account = Fabricate.build(:account, username: 'support') - account.save(validate: false) - expect(account.valid?).to be true - end - - it 'is valid if we are creating an instance actor account with a period' do - account = Fabricate.build(:account, id: -99, actor_type: 'Application', locked: true, username: 'example.com') - expect(account.valid?).to be true - end - - it 'is valid if we are creating a possibly-conflicting instance actor account' do - account_1 = Fabricate(:account, username: 'examplecom') - account_2 = Fabricate.build(:account, id: -99, actor_type: 'Application', locked: true, username: 'example.com') - expect(account_2.valid?).to be true - end - - it 'is invalid if the username doesn\'t only contains letters, numbers and underscores' do - account = Fabricate.build(:account, username: 'the-doctor') - account.valid? - expect(account).to model_have_error_on_field(:username) - end - - it 'is invalid if the username contains a period' do - account = Fabricate.build(:account, username: 'the.doctor') - account.valid? - expect(account).to model_have_error_on_field(:username) - end - - it 'is invalid if the username is longer than 30 characters' do - account = Fabricate.build(:account, username: Faker::Lorem.characters(number: 31)) - account.valid? - expect(account).to model_have_error_on_field(:username) - end - - it 'is invalid if the display name is longer than 30 characters' do - account = Fabricate.build(:account, display_name: Faker::Lorem.characters(number: 31)) - account.valid? - expect(account).to model_have_error_on_field(:display_name) - end - - it 'is invalid if the note is longer than 500 characters' do - account = Fabricate.build(:account, note: Faker::Lorem.characters(number: 501)) - account.valid? - expect(account).to model_have_error_on_field(:note) - end - end - - context 'when is remote' do - it 'is invalid if the username is same among accounts in the same normalized domain' do - Fabricate(:account, domain: 'にゃん', username: 'username') - account = Fabricate.build(:account, domain: 'xn--r9j5b5b', username: 'username') - account.valid? - expect(account).to model_have_error_on_field(:username) - end - - it 'is invalid if the username is not unique in case-insensitive comparison among accounts in the same normalized domain' do - Fabricate(:account, domain: 'にゃん', username: 'username') - account = Fabricate.build(:account, domain: 'xn--r9j5b5b', username: 'Username') - account.valid? - expect(account).to model_have_error_on_field(:username) - end - - it 'is valid even if the username contains hyphens' do - account = Fabricate.build(:account, domain: 'domain', username: 'the-doctor') - account.valid? - expect(account).to_not model_have_error_on_field(:username) - end - - it 'is invalid if the username doesn\'t only contains letters, numbers, underscores and hyphens' do - account = Fabricate.build(:account, domain: 'domain', username: 'the doctor') - account.valid? - expect(account).to model_have_error_on_field(:username) - end - - it 'is valid even if the username is longer than 30 characters' do - account = Fabricate.build(:account, domain: 'domain', username: Faker::Lorem.characters(number: 31)) - account.valid? - expect(account).to_not model_have_error_on_field(:username) - end - - it 'is valid even if the display name is longer than 30 characters' do - account = Fabricate.build(:account, domain: 'domain', display_name: Faker::Lorem.characters(number: 31)) - account.valid? - expect(account).to_not model_have_error_on_field(:display_name) - end - - it 'is valid even if the note is longer than 500 characters' do - account = Fabricate.build(:account, domain: 'domain', note: Faker::Lorem.characters(number: 501)) - account.valid? - expect(account).to_not model_have_error_on_field(:note) - end - end - end - - describe 'scopes' do - describe 'alphabetic' do - it 'sorts by alphabetic order of domain and username' do - matches = [ - { username: 'a', domain: 'a' }, - { username: 'b', domain: 'a' }, - { username: 'a', domain: 'b' }, - { username: 'b', domain: 'b' }, - ].map(&method(:Fabricate).curry(2).call(:account)) - - expect(described_class.where('id > 0').alphabetic).to eq matches - end - end - - describe 'matches_display_name' do - it 'matches display name which starts with the given string' do - match = Fabricate(:account, display_name: 'pattern and suffix') - Fabricate(:account, display_name: 'prefix and pattern') - - expect(described_class.matches_display_name('pattern')).to eq [match] - end - end - - describe 'matches_username' do - it 'matches display name which starts with the given string' do - match = Fabricate(:account, username: 'pattern_and_suffix') - Fabricate(:account, username: 'prefix_and_pattern') - - expect(described_class.matches_username('pattern')).to eq [match] - end - end - - describe 'by_domain_and_subdomains' do - it 'returns exact domain matches' do - account = Fabricate(:account, domain: 'example.com') - expect(described_class.by_domain_and_subdomains('example.com')).to eq [account] - end - - it 'returns subdomains' do - account = Fabricate(:account, domain: 'foo.example.com') - expect(described_class.by_domain_and_subdomains('example.com')).to eq [account] - end - - it 'does not return partially matching domains' do - account = Fabricate(:account, domain: 'grexample.com') - expect(described_class.by_domain_and_subdomains('example.com')).to_not eq [account] - end - end - - describe 'remote' do - it 'returns an array of accounts who have a domain' do - account_1 = Fabricate(:account, domain: nil) - account_2 = Fabricate(:account, domain: 'example.com') - expect(described_class.remote).to contain_exactly(account_2) - end - end - - describe 'local' do - it 'returns an array of accounts who do not have a domain' do - account_1 = Fabricate(:account, domain: nil) - account_2 = Fabricate(:account, domain: 'example.com') - expect(described_class.where('id > 0').local).to contain_exactly(account_1) - end - end - - describe 'partitioned' do - it 'returns a relation of accounts partitioned by domain' do - matches = %w(a b a b) - matches.size.times.to_a.shuffle.each do |index| - matches[index] = Fabricate(:account, domain: matches[index]) - end - - expect(described_class.where('id > 0').partitioned).to match_array(matches) - end - end - - describe 'recent' do - it 'returns a relation of accounts sorted by recent creation' do - matches = Array.new(2) { Fabricate(:account) } - expect(described_class.where('id > 0').recent).to match_array(matches) - end - end - - describe 'silenced' do - it 'returns an array of accounts who are silenced' do - account_1 = Fabricate(:account, silenced: true) - account_2 = Fabricate(:account, silenced: false) - expect(described_class.silenced).to contain_exactly(account_1) - end - end - - describe 'suspended' do - it 'returns an array of accounts who are suspended' do - account_1 = Fabricate(:account, suspended: true) - account_2 = Fabricate(:account, suspended: false) - expect(described_class.suspended).to contain_exactly(account_1) - end - end - - describe 'searchable' do - let!(:suspended_local) { Fabricate(:account, suspended: true, username: 'suspended_local') } - let!(:suspended_remote) { Fabricate(:account, suspended: true, domain: 'example.org', username: 'suspended_remote') } - let!(:silenced_local) { Fabricate(:account, silenced: true, username: 'silenced_local') } - let!(:silenced_remote) { Fabricate(:account, silenced: true, domain: 'example.org', username: 'silenced_remote') } - let!(:unconfirmed) { Fabricate(:user, confirmed_at: nil).account } - let!(:unapproved) { Fabricate(:user, approved: false).account } - let!(:unconfirmed_unapproved) { Fabricate(:user, confirmed_at: nil, approved: false).account } - let!(:local_account) { Fabricate(:account, username: 'local_account') } - let!(:remote_account) { Fabricate(:account, domain: 'example.org', username: 'remote_account') } - - before do - # Accounts get automatically-approved depending on settings, so ensure they aren't approved - unapproved.user.update(approved: false) - unconfirmed_unapproved.user.update(approved: false) - end - - it 'returns every usable non-suspended account' do - expect(described_class.searchable).to contain_exactly(silenced_local, silenced_remote, local_account, remote_account) - end - - it 'does not mess with previously-applied scopes' do - expect(described_class.where.not(id: remote_account.id).searchable).to contain_exactly(silenced_local, silenced_remote, local_account) - end - end - end - - context 'when is local' do - it 'generates keys' do - account = described_class.create!(domain: nil, username: Faker::Internet.user_name(separators: ['_'])) - expect(account.keypair).to be_private - expect(account.keypair).to be_public - end - end - - context 'when is remote' do - it 'does not generate keys' do - key = OpenSSL::PKey::RSA.new(1024).public_key - account = described_class.create!(domain: 'remote', uri: 'https://remote/actor', username: Faker::Internet.user_name(separators: ['_']), public_key: key.to_pem) - expect(account.keypair.params).to eq key.params - end - - it 'normalizes domain' do - account = described_class.create!(domain: 'にゃん', uri: 'https://xn--r9j5b5b/actor', username: Faker::Internet.user_name(separators: ['_'])) - expect(account.domain).to eq 'xn--r9j5b5b' - end - end - - include_examples 'AccountAvatar', :account - include_examples 'AccountHeader', :account - - describe '#increment_count!' do - subject { Fabricate(:account) } - - it 'increments the count in multi-threaded an environment when account_stat is not yet initialized' do - subject - - increment_by = 15 - wait_for_start = true - - threads = Array.new(increment_by) do - Thread.new do - true while wait_for_start - described_class.find(subject.id).increment_count!(:followers_count) - end - end - - wait_for_start = false - threads.each(&:join) - - expect(subject.reload.followers_count).to eq 15 - end - end -end diff --git a/spec/models/account_statuses_cleanup_policy_spec.rb b/spec/models/account_statuses_cleanup_policy_spec.rb deleted file mode 100644 index 7405bdfa2..000000000 --- a/spec/models/account_statuses_cleanup_policy_spec.rb +++ /dev/null @@ -1,547 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe AccountStatusesCleanupPolicy do - let(:account) { Fabricate(:account, username: 'alice', domain: nil) } - - describe 'validation' do - it 'disallow remote accounts' do - account.update(domain: 'example.com') - account_statuses_cleanup_policy = Fabricate.build(:account_statuses_cleanup_policy, account: account) - account_statuses_cleanup_policy.valid? - expect(account_statuses_cleanup_policy).to model_have_error_on_field(:account) - end - end - - describe 'save hooks' do - context 'when widening a policy' do - let!(:account_statuses_cleanup_policy) do - Fabricate(:account_statuses_cleanup_policy, - account: account, - keep_direct: true, - keep_pinned: true, - keep_polls: true, - keep_media: true, - keep_self_fav: true, - keep_self_bookmark: true, - min_favs: 1, - min_reblogs: 1) - end - - before do - account_statuses_cleanup_policy.record_last_inspected(42) - end - - it 'invalidates last_inspected when widened because of keep_direct' do - account_statuses_cleanup_policy.keep_direct = false - account_statuses_cleanup_policy.save - expect(account_statuses_cleanup_policy.last_inspected).to be_nil - end - - it 'invalidates last_inspected when widened because of keep_pinned' do - account_statuses_cleanup_policy.keep_pinned = false - account_statuses_cleanup_policy.save - expect(account_statuses_cleanup_policy.last_inspected).to be_nil - end - - it 'invalidates last_inspected when widened because of keep_polls' do - account_statuses_cleanup_policy.keep_polls = false - account_statuses_cleanup_policy.save - expect(account_statuses_cleanup_policy.last_inspected).to be_nil - end - - it 'invalidates last_inspected when widened because of keep_media' do - account_statuses_cleanup_policy.keep_media = false - account_statuses_cleanup_policy.save - expect(account_statuses_cleanup_policy.last_inspected).to be_nil - end - - it 'invalidates last_inspected when widened because of keep_self_fav' do - account_statuses_cleanup_policy.keep_self_fav = false - account_statuses_cleanup_policy.save - expect(account_statuses_cleanup_policy.last_inspected).to be_nil - end - - it 'invalidates last_inspected when widened because of keep_self_bookmark' do - account_statuses_cleanup_policy.keep_self_bookmark = false - account_statuses_cleanup_policy.save - expect(account_statuses_cleanup_policy.last_inspected).to be_nil - end - - it 'invalidates last_inspected when widened because of higher min_favs' do - account_statuses_cleanup_policy.min_favs = 5 - account_statuses_cleanup_policy.save - expect(account_statuses_cleanup_policy.last_inspected).to be_nil - end - - it 'invalidates last_inspected when widened because of disabled min_favs' do - account_statuses_cleanup_policy.min_favs = nil - account_statuses_cleanup_policy.save - expect(account_statuses_cleanup_policy.last_inspected).to be_nil - end - - it 'invalidates last_inspected when widened because of higher min_reblogs' do - account_statuses_cleanup_policy.min_reblogs = 5 - account_statuses_cleanup_policy.save - expect(account_statuses_cleanup_policy.last_inspected).to be_nil - end - - it 'invalidates last_inspected when widened because of disable min_reblogs' do - account_statuses_cleanup_policy.min_reblogs = nil - account_statuses_cleanup_policy.save - expect(account_statuses_cleanup_policy.last_inspected).to be_nil - end - end - - context 'when narrowing a policy' do - let!(:account_statuses_cleanup_policy) do - Fabricate(:account_statuses_cleanup_policy, - account: account, - keep_direct: false, - keep_pinned: false, - keep_polls: false, - keep_media: false, - keep_self_fav: false, - keep_self_bookmark: false, - min_favs: nil, - min_reblogs: nil) - end - - it 'does not unnecessarily invalidate last_inspected' do - account_statuses_cleanup_policy.record_last_inspected(42) - account_statuses_cleanup_policy.keep_direct = true - account_statuses_cleanup_policy.keep_pinned = true - account_statuses_cleanup_policy.keep_polls = true - account_statuses_cleanup_policy.keep_media = true - account_statuses_cleanup_policy.keep_self_fav = true - account_statuses_cleanup_policy.keep_self_bookmark = true - account_statuses_cleanup_policy.min_favs = 5 - account_statuses_cleanup_policy.min_reblogs = 5 - account_statuses_cleanup_policy.save - expect(account_statuses_cleanup_policy.last_inspected).to eq 42 - end - end - end - - describe '#record_last_inspected' do - let(:account_statuses_cleanup_policy) { Fabricate(:account_statuses_cleanup_policy, account: account) } - - it 'records the given id' do - account_statuses_cleanup_policy.record_last_inspected(42) - expect(account_statuses_cleanup_policy.last_inspected).to eq 42 - end - end - - describe '#invalidate_last_inspected' do - subject { account_statuses_cleanup_policy.invalidate_last_inspected(status, action) } - - let(:account_statuses_cleanup_policy) { Fabricate(:account_statuses_cleanup_policy, account: account) } - let(:status) { Fabricate(:status, id: 10, account: account) } - - before do - account_statuses_cleanup_policy.record_last_inspected(42) - end - - context 'when the action is :unbookmark' do - let(:action) { :unbookmark } - - context 'when the policy is not to keep self-bookmarked toots' do - before do - account_statuses_cleanup_policy.keep_self_bookmark = false - end - - it 'does not change the recorded id' do - subject - expect(account_statuses_cleanup_policy.last_inspected).to eq 42 - end - end - - context 'when the policy is to keep self-bookmarked toots' do - before do - account_statuses_cleanup_policy.keep_self_bookmark = true - end - - it 'records the older id' do - subject - expect(account_statuses_cleanup_policy.last_inspected).to eq 10 - end - end - end - - context 'when the action is :unfav' do - let(:action) { :unfav } - - context 'when the policy is not to keep self-favourited toots' do - before do - account_statuses_cleanup_policy.keep_self_fav = false - end - - it 'does not change the recorded id' do - subject - expect(account_statuses_cleanup_policy.last_inspected).to eq 42 - end - end - - context 'when the policy is to keep self-favourited toots' do - before do - account_statuses_cleanup_policy.keep_self_fav = true - end - - it 'records the older id' do - subject - expect(account_statuses_cleanup_policy.last_inspected).to eq 10 - end - end - end - - context 'when the action is :unpin' do - let(:action) { :unpin } - - context 'when the policy is not to keep pinned toots' do - before do - account_statuses_cleanup_policy.keep_pinned = false - end - - it 'does not change the recorded id' do - subject - expect(account_statuses_cleanup_policy.last_inspected).to eq 42 - end - end - - context 'when the policy is to keep pinned toots' do - before do - account_statuses_cleanup_policy.keep_pinned = true - end - - it 'records the older id' do - subject - expect(account_statuses_cleanup_policy.last_inspected).to eq 10 - end - end - end - - context 'when the status is more recent than the recorded inspected id' do - let(:action) { :unfav } - let(:status) { Fabricate(:status, account: account) } - - it 'does not change the recorded id' do - subject - expect(account_statuses_cleanup_policy.last_inspected).to eq 42 - end - end - end - - describe '#compute_cutoff_id' do - subject { account_statuses_cleanup_policy.compute_cutoff_id } - - let!(:unrelated_status) { Fabricate(:status, created_at: 3.years.ago) } - let(:account_statuses_cleanup_policy) { Fabricate(:account_statuses_cleanup_policy, account: account) } - - context 'when the account has posted multiple toots' do - let!(:very_old_status) { Fabricate(:status, created_at: 3.years.ago, account: account) } - let!(:old_status) { Fabricate(:status, created_at: 3.weeks.ago, account: account) } - let!(:recent_status) { Fabricate(:status, created_at: 2.days.ago, account: account) } - - it 'returns the most recent id that is still below policy age' do - expect(subject).to eq old_status.id - end - end - - context 'when the account has not posted anything' do - it 'returns nil' do - expect(subject).to be_nil - end - end - end - - describe '#statuses_to_delete' do - subject { account_statuses_cleanup_policy.statuses_to_delete } - - let!(:unrelated_status) { Fabricate(:status, created_at: 3.years.ago) } - let!(:very_old_status) { Fabricate(:status, created_at: 3.years.ago, account: account) } - let!(:pinned_status) { Fabricate(:status, created_at: 1.year.ago, account: account) } - let!(:direct_message) { Fabricate(:status, created_at: 1.year.ago, account: account, visibility: :direct) } - let!(:self_faved) { Fabricate(:status, created_at: 1.year.ago, account: account) } - let!(:self_bookmarked) { Fabricate(:status, created_at: 1.year.ago, account: account) } - let!(:status_with_poll) { Fabricate(:status, created_at: 1.year.ago, account: account, poll_attributes: { account: account, voters_count: 0, options: %w(a b), expires_in: 2.days }) } - let!(:status_with_media) { Fabricate(:status, created_at: 1.year.ago, account: account) } - let!(:faved_primary) { Fabricate(:status, created_at: 1.year.ago, account: account) } - let!(:faved_secondary) { Fabricate(:status, created_at: 1.year.ago, account: account) } - let!(:reblogged_primary) { Fabricate(:status, created_at: 1.year.ago, account: account) } - let!(:reblogged_secondary) { Fabricate(:status, created_at: 1.year.ago, account: account) } - let!(:recent_status) { Fabricate(:status, created_at: 2.days.ago, account: account) } - - let!(:media_attachment) { Fabricate(:media_attachment, account: account, status: status_with_media) } - let!(:status_pin) { Fabricate(:status_pin, account: account, status: pinned_status) } - let!(:favourite) { Fabricate(:favourite, account: account, status: self_faved) } - let!(:bookmark) { Fabricate(:bookmark, account: account, status: self_bookmarked) } - - let(:account_statuses_cleanup_policy) { Fabricate(:account_statuses_cleanup_policy, account: account) } - - before do - 4.times { faved_primary.increment_count!(:favourites_count) } - 5.times { faved_secondary.increment_count!(:favourites_count) } - 4.times { reblogged_primary.increment_count!(:reblogs_count) } - 5.times { reblogged_secondary.increment_count!(:reblogs_count) } - end - - context 'when passed a max_id' do - subject { account_statuses_cleanup_policy.statuses_to_delete(50, old_status.id).pluck(:id) } - - let!(:old_status) { Fabricate(:status, created_at: 1.year.ago, account: account) } - let!(:slightly_less_old_status) { Fabricate(:status, created_at: 6.months.ago, account: account) } - - it 'returns statuses including max_id' do - expect(subject).to include(old_status.id) - end - - it 'returns statuses including older than max_id' do - expect(subject).to include(very_old_status.id) - end - - it 'does not return statuses newer than max_id' do - expect(subject).to_not include(slightly_less_old_status.id) - end - end - - context 'when passed a min_id' do - subject { account_statuses_cleanup_policy.statuses_to_delete(50, recent_status.id, old_status.id).pluck(:id) } - - let!(:old_status) { Fabricate(:status, created_at: 1.year.ago, account: account) } - let!(:slightly_less_old_status) { Fabricate(:status, created_at: 6.months.ago, account: account) } - - it 'returns statuses including min_id' do - expect(subject).to include(old_status.id) - end - - it 'returns statuses including newer than max_id' do - expect(subject).to include(slightly_less_old_status.id) - end - - it 'does not return statuses older than min_id' do - expect(subject).to_not include(very_old_status.id) - end - end - - context 'when passed a low limit' do - it 'only returns the limited number of items' do - expect(account_statuses_cleanup_policy.statuses_to_delete(1).count).to eq 1 - end - end - - context 'when policy is set to keep statuses more recent than 2 years' do - before do - account_statuses_cleanup_policy.min_status_age = 2.years.seconds - end - - it 'does not return unrelated old status' do - expect(subject.pluck(:id)).to_not include(unrelated_status.id) - end - - it 'returns only oldest status for deletion' do - expect(subject.pluck(:id)).to eq [very_old_status.id] - end - end - - context 'when policy is set to keep DMs and reject everything else' do - before do - account_statuses_cleanup_policy.keep_direct = true - account_statuses_cleanup_policy.keep_pinned = false - account_statuses_cleanup_policy.keep_polls = false - account_statuses_cleanup_policy.keep_media = false - account_statuses_cleanup_policy.keep_self_fav = false - account_statuses_cleanup_policy.keep_self_bookmark = false - end - - it 'does not return the old direct message for deletion' do - expect(subject.pluck(:id)).to_not include(direct_message.id) - end - - it 'returns every other old status for deletion' do - expect(subject.pluck(:id)).to include(very_old_status.id, pinned_status.id, self_faved.id, self_bookmarked.id, status_with_poll.id, status_with_media.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id) - end - end - - context 'when policy is set to keep self-bookmarked toots and reject everything else' do - before do - account_statuses_cleanup_policy.keep_direct = false - account_statuses_cleanup_policy.keep_pinned = false - account_statuses_cleanup_policy.keep_polls = false - account_statuses_cleanup_policy.keep_media = false - account_statuses_cleanup_policy.keep_self_fav = false - account_statuses_cleanup_policy.keep_self_bookmark = true - end - - it 'does not return the old self-bookmarked message for deletion' do - expect(subject.pluck(:id)).to_not include(self_bookmarked.id) - end - - it 'returns every other old status for deletion' do - expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_faved.id, status_with_poll.id, status_with_media.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id) - end - end - - context 'when policy is set to keep self-faved toots and reject everything else' do - before do - account_statuses_cleanup_policy.keep_direct = false - account_statuses_cleanup_policy.keep_pinned = false - account_statuses_cleanup_policy.keep_polls = false - account_statuses_cleanup_policy.keep_media = false - account_statuses_cleanup_policy.keep_self_fav = true - account_statuses_cleanup_policy.keep_self_bookmark = false - end - - it 'does not return the old self-bookmarked message for deletion' do - expect(subject.pluck(:id)).to_not include(self_faved.id) - end - - it 'returns every other old status for deletion' do - expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_bookmarked.id, status_with_poll.id, status_with_media.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id) - end - end - - context 'when policy is set to keep toots with media and reject everything else' do - before do - account_statuses_cleanup_policy.keep_direct = false - account_statuses_cleanup_policy.keep_pinned = false - account_statuses_cleanup_policy.keep_polls = false - account_statuses_cleanup_policy.keep_media = true - account_statuses_cleanup_policy.keep_self_fav = false - account_statuses_cleanup_policy.keep_self_bookmark = false - end - - it 'does not return the old message with media for deletion' do - expect(subject.pluck(:id)).to_not include(status_with_media.id) - end - - it 'returns every other old status for deletion' do - expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_faved.id, self_bookmarked.id, status_with_poll.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id) - end - end - - context 'when policy is set to keep toots with polls and reject everything else' do - before do - account_statuses_cleanup_policy.keep_direct = false - account_statuses_cleanup_policy.keep_pinned = false - account_statuses_cleanup_policy.keep_polls = true - account_statuses_cleanup_policy.keep_media = false - account_statuses_cleanup_policy.keep_self_fav = false - account_statuses_cleanup_policy.keep_self_bookmark = false - end - - it 'does not return the old poll message for deletion' do - expect(subject.pluck(:id)).to_not include(status_with_poll.id) - end - - it 'returns every other old status for deletion' do - expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_faved.id, self_bookmarked.id, status_with_media.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id) - end - end - - context 'when policy is set to keep pinned toots and reject everything else' do - before do - account_statuses_cleanup_policy.keep_direct = false - account_statuses_cleanup_policy.keep_pinned = true - account_statuses_cleanup_policy.keep_polls = false - account_statuses_cleanup_policy.keep_media = false - account_statuses_cleanup_policy.keep_self_fav = false - account_statuses_cleanup_policy.keep_self_bookmark = false - end - - it 'does not return the old pinned message for deletion' do - expect(subject.pluck(:id)).to_not include(pinned_status.id) - end - - it 'returns every other old status for deletion' do - expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, self_faved.id, self_bookmarked.id, status_with_poll.id, status_with_media.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id) - end - end - - context 'when policy is to not keep any special messages' do - before do - account_statuses_cleanup_policy.keep_direct = false - account_statuses_cleanup_policy.keep_pinned = false - account_statuses_cleanup_policy.keep_polls = false - account_statuses_cleanup_policy.keep_media = false - account_statuses_cleanup_policy.keep_self_fav = false - account_statuses_cleanup_policy.keep_self_bookmark = false - end - - it 'does not return the recent toot' do - expect(subject.pluck(:id)).to_not include(recent_status.id) - end - - it 'does not return the unrelated toot' do - expect(subject.pluck(:id)).to_not include(unrelated_status.id) - end - - it 'returns every other old status for deletion' do - expect(subject.pluck(:id)).to include(direct_message.id, very_old_status.id, pinned_status.id, self_faved.id, self_bookmarked.id, status_with_poll.id, status_with_media.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id) - end - end - - context 'when policy is set to keep every category of toots' do - before do - account_statuses_cleanup_policy.keep_direct = true - account_statuses_cleanup_policy.keep_pinned = true - account_statuses_cleanup_policy.keep_polls = true - account_statuses_cleanup_policy.keep_media = true - account_statuses_cleanup_policy.keep_self_fav = true - account_statuses_cleanup_policy.keep_self_bookmark = true - end - - it 'does not return unrelated old status' do - expect(subject.pluck(:id)).to_not include(unrelated_status.id) - end - - it 'returns only normal statuses for deletion' do - expect(subject.pluck(:id)).to contain_exactly(very_old_status.id, faved_primary.id, faved_secondary.id, reblogged_primary.id, reblogged_secondary.id) - end - end - - context 'when policy is to keep statuses with at least 5 boosts' do - before do - account_statuses_cleanup_policy.min_reblogs = 5 - end - - it 'does not return the recent toot' do - expect(subject.pluck(:id)).to_not include(recent_status.id) - end - - it 'does not return the toot reblogged 5 times' do - expect(subject.pluck(:id)).to_not include(reblogged_secondary.id) - end - - it 'does not return the unrelated toot' do - expect(subject.pluck(:id)).to_not include(unrelated_status.id) - end - - it 'returns old statuses not reblogged as much' do - expect(subject.pluck(:id)).to include(very_old_status.id, faved_primary.id, faved_secondary.id, reblogged_primary.id) - end - end - - context 'when policy is to keep statuses with at least 5 favs' do - before do - account_statuses_cleanup_policy.min_favs = 5 - end - - it 'does not return the recent toot' do - expect(subject.pluck(:id)).to_not include(recent_status.id) - end - - it 'does not return the toot faved 5 times' do - expect(subject.pluck(:id)).to_not include(faved_secondary.id) - end - - it 'does not return the unrelated toot' do - expect(subject.pluck(:id)).to_not include(unrelated_status.id) - end - - it 'returns old statuses not faved as much' do - expect(subject.pluck(:id)).to include(very_old_status.id, faved_primary.id, reblogged_primary.id, reblogged_secondary.id) - end - end - end -end diff --git a/spec/models/account_warning_preset_spec.rb b/spec/models/account_warning_preset_spec.rb deleted file mode 100644 index f171df7c9..000000000 --- a/spec/models/account_warning_preset_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe AccountWarningPreset do - describe 'alphabetical' do - let(:first) { Fabricate(:account_warning_preset, title: 'aaa', text: 'aaa') } - let(:second) { Fabricate(:account_warning_preset, title: 'bbb', text: 'aaa') } - let(:third) { Fabricate(:account_warning_preset, title: 'bbb', text: 'bbb') } - - it 'returns records in order of title and text' do - results = described_class.alphabetic - - expect(results).to eq([first, second, third]) - end - end -end diff --git a/spec/models/admin/account_action_spec.rb b/spec/models/admin/account_action_spec.rb deleted file mode 100644 index b47561dd4..000000000 --- a/spec/models/admin/account_action_spec.rb +++ /dev/null @@ -1,150 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Admin::AccountAction do - let(:account_action) { described_class.new } - - describe '#save!' do - subject { account_action.save! } - - let(:account) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:target_account) { Fabricate(:account) } - let(:type) { 'disable' } - - before do - account_action.assign_attributes( - type: type, - current_account: account, - target_account: target_account - ) - end - - context 'when type is "disable"' do - let(:type) { 'disable' } - - it 'disable user' do - subject - expect(target_account.user).to be_disabled - end - end - - context 'when type is "silence"' do - let(:type) { 'silence' } - - it 'silences account' do - subject - expect(target_account).to be_silenced - end - end - - context 'when type is "suspend"' do - let(:type) { 'suspend' } - - it 'suspends account' do - subject - expect(target_account).to be_suspended - end - - it 'queues Admin::SuspensionWorker by 1' do - Sidekiq::Testing.fake! do - expect do - subject - end.to change { Admin::SuspensionWorker.jobs.size }.by 1 - end - end - end - - context 'when type is invalid' do - let(:type) { 'whatever' } - - it 'raises an invalid record error' do - expect { subject }.to raise_error(ActiveRecord::RecordInvalid) - end - end - - context 'when type is not given' do - let(:type) { '' } - - it 'raises an invalid record error' do - expect { subject }.to raise_error(ActiveRecord::RecordInvalid) - end - end - - it 'creates Admin::ActionLog' do - expect do - subject - end.to change(Admin::ActionLog, :count).by 1 - end - - it 'calls process_email!' do - expect(account_action).to receive(:process_email!) - subject - end - - it 'calls process_reports!' do - expect(account_action).to receive(:process_reports!) - subject - end - end - - describe '#report' do - subject { account_action.report } - - context 'with report_id.present?' do - before do - account_action.report_id = Fabricate(:report).id - end - - it 'returns Report' do - expect(subject).to be_instance_of Report - end - end - - context 'with !report_id.present?' do - it 'returns nil' do - expect(subject).to be_nil - end - end - end - - describe '#with_report?' do - subject { account_action.with_report? } - - context 'with !report.nil?' do - before do - account_action.report_id = Fabricate(:report).id - end - - it 'returns true' do - expect(subject).to be true - end - end - - context 'with !(!report.nil?)' do - it 'returns false' do - expect(subject).to be false - end - end - end - - describe '.types_for_account' do - subject { described_class.types_for_account(account) } - - context 'when Account.local?' do - let(:account) { Fabricate(:account, domain: nil) } - - it 'returns ["none", "disable", "sensitive", "silence", "suspend"]' do - expect(subject).to eq %w(none disable sensitive silence suspend) - end - end - - context 'with !account.local?' do - let(:account) { Fabricate(:account, domain: 'hoge.com') } - - it 'returns ["sensitive", "silence", "suspend"]' do - expect(subject).to eq %w(sensitive silence suspend) - end - end - end -end diff --git a/spec/models/admin/action_log_spec.rb b/spec/models/admin/action_log_spec.rb deleted file mode 100644 index 1e3649b83..000000000 --- a/spec/models/admin/action_log_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Admin::ActionLog do - describe '#action' do - it 'returns action' do - action_log = described_class.new(action: 'hoge') - expect(action_log.action).to be :hoge - end - end -end diff --git a/spec/models/admin/appeal_filter_spec.rb b/spec/models/admin/appeal_filter_spec.rb deleted file mode 100644 index e840bc3bc..000000000 --- a/spec/models/admin/appeal_filter_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Admin::AppealFilter do - describe '#results' do - let(:approved_appeal) { Fabricate(:appeal, approved_at: 10.days.ago) } - let(:not_approved_appeal) { Fabricate(:appeal, approved_at: nil) } - - it 'returns filtered appeals' do - filter = described_class.new(status: 'approved') - - expect(filter.results).to eq([approved_appeal]) - end - end -end diff --git a/spec/models/appeal_spec.rb b/spec/models/appeal_spec.rb deleted file mode 100644 index 12373a949..000000000 --- a/spec/models/appeal_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Appeal do - describe 'scopes' do - describe 'approved' do - let(:approved_appeal) { Fabricate(:appeal, approved_at: 10.days.ago) } - let(:not_approved_appeal) { Fabricate(:appeal, approved_at: nil) } - - it 'finds the correct records' do - results = described_class.approved - expect(results).to eq([approved_appeal]) - end - end - - describe 'rejected' do - let(:rejected_appeal) { Fabricate(:appeal, rejected_at: 10.days.ago) } - let(:not_rejected_appeal) { Fabricate(:appeal, rejected_at: nil) } - - it 'finds the correct records' do - results = described_class.rejected - expect(results).to eq([rejected_appeal]) - end - end - - describe 'pending' do - let(:approved_appeal) { Fabricate(:appeal, approved_at: 10.days.ago) } - let(:rejected_appeal) { Fabricate(:appeal, rejected_at: 10.days.ago) } - let(:pending_appeal) { Fabricate(:appeal, rejected_at: nil, approved_at: nil) } - - it 'finds the correct records' do - results = described_class.pending - expect(results).to eq([pending_appeal]) - end - end - end -end diff --git a/spec/models/block_spec.rb b/spec/models/block_spec.rb deleted file mode 100644 index 8249503c5..000000000 --- a/spec/models/block_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Block do - describe 'validations' do - it 'is invalid without an account' do - block = Fabricate.build(:block, account: nil) - block.valid? - expect(block).to model_have_error_on_field(:account) - end - - it 'is invalid without a target_account' do - block = Fabricate.build(:block, target_account: nil) - block.valid? - expect(block).to model_have_error_on_field(:target_account) - end - end - - it 'removes blocking cache after creation' do - account = Fabricate(:account) - target_account = Fabricate(:account) - Rails.cache.write("exclude_account_ids_for:#{account.id}", []) - Rails.cache.write("exclude_account_ids_for:#{target_account.id}", []) - - described_class.create!(account: account, target_account: target_account) - - expect(Rails.cache.exist?("exclude_account_ids_for:#{account.id}")).to be false - expect(Rails.cache.exist?("exclude_account_ids_for:#{target_account.id}")).to be false - end - - it 'removes blocking cache after destruction' do - account = Fabricate(:account) - target_account = Fabricate(:account) - block = described_class.create!(account: account, target_account: target_account) - Rails.cache.write("exclude_account_ids_for:#{account.id}", [target_account.id]) - Rails.cache.write("exclude_account_ids_for:#{target_account.id}", [account.id]) - - block.destroy! - - expect(Rails.cache.exist?("exclude_account_ids_for:#{account.id}")).to be false - expect(Rails.cache.exist?("exclude_account_ids_for:#{target_account.id}")).to be false - end -end diff --git a/spec/models/canonical_email_block_spec.rb b/spec/models/canonical_email_block_spec.rb deleted file mode 100644 index 0acff8237..000000000 --- a/spec/models/canonical_email_block_spec.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe CanonicalEmailBlock do - describe '#email=' do - let(:target_hash) { '973dfe463ec85785f5f95af5ba3906eedb2d931c24e69824a89ea65dba4e813b' } - - it 'sets canonical_email_hash' do - subject.email = 'test@example.com' - expect(subject.canonical_email_hash).to eq target_hash - end - - it 'sets the same hash even with dot permutations' do - subject.email = 't.e.s.t@example.com' - expect(subject.canonical_email_hash).to eq target_hash - end - - it 'sets the same hash even with extensions' do - subject.email = 'test+mastodon1@example.com' - expect(subject.canonical_email_hash).to eq target_hash - end - - it 'sets the same hash with different casing' do - subject.email = 'Test@EXAMPLE.com' - expect(subject.canonical_email_hash).to eq target_hash - end - end - - describe '.block?' do - let!(:canonical_email_block) { Fabricate(:canonical_email_block, email: 'foo@bar.com') } - - it 'returns true for the same email' do - expect(described_class.block?('foo@bar.com')).to be true - end - - it 'returns true for the same email with dots' do - expect(described_class.block?('f.oo@bar.com')).to be true - end - - it 'returns true for the same email with extensions' do - expect(described_class.block?('foo+spam@bar.com')).to be true - end - - it 'returns false for different email' do - expect(described_class.block?('hoge@bar.com')).to be false - end - end -end diff --git a/spec/models/concerns/account_counters_spec.rb b/spec/models/concerns/account_counters_spec.rb deleted file mode 100644 index fb02d79f1..000000000 --- a/spec/models/concerns/account_counters_spec.rb +++ /dev/null @@ -1,62 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe AccountCounters do - let!(:account) { Fabricate(:account) } - - describe '#increment_count!' do - it 'increments the count' do - expect(account.followers_count).to eq 0 - account.increment_count!(:followers_count) - expect(account.followers_count).to eq 1 - end - - it 'increments the count in multi-threaded an environment' do - increment_by = 15 - wait_for_start = true - - threads = Array.new(increment_by) do - Thread.new do - true while wait_for_start - account.increment_count!(:statuses_count) - end - end - - wait_for_start = false - threads.each(&:join) - - expect(account.statuses_count).to eq increment_by - end - end - - describe '#decrement_count!' do - it 'decrements the count' do - account.followers_count = 15 - account.save! - expect(account.followers_count).to eq 15 - account.decrement_count!(:followers_count) - expect(account.followers_count).to eq 14 - end - - it 'decrements the count in multi-threaded an environment' do - decrement_by = 10 - wait_for_start = true - - account.statuses_count = 15 - account.save! - - threads = Array.new(decrement_by) do - Thread.new do - true while wait_for_start - account.decrement_count!(:statuses_count) - end - end - - wait_for_start = false - threads.each(&:join) - - expect(account.statuses_count).to eq 5 - end - end -end diff --git a/spec/models/concerns/account_finder_concern_spec.rb b/spec/models/concerns/account_finder_concern_spec.rb deleted file mode 100644 index 25f4fdec4..000000000 --- a/spec/models/concerns/account_finder_concern_spec.rb +++ /dev/null @@ -1,109 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe AccountFinderConcern do - describe 'local finders' do - before do - @account = Fabricate(:account, username: 'Alice') - end - - describe '.find_local' do - it 'returns case-insensitive result' do - expect(Account.find_local('alice')).to eq(@account) - end - - it 'returns correctly cased result' do - expect(Account.find_local('Alice')).to eq(@account) - end - - it 'returns nil without a match' do - expect(Account.find_local('a_ice')).to be_nil - end - - it 'returns nil for regex style username value' do - expect(Account.find_local('al%')).to be_nil - end - - it 'returns nil for nil username value' do - expect(Account.find_local(nil)).to be_nil - end - - it 'returns nil for blank username value' do - expect(Account.find_local('')).to be_nil - end - end - - describe '.find_local!' do - it 'returns matching result' do - expect(Account.find_local!('alice')).to eq(@account) - end - - it 'raises on non-matching result' do - expect { Account.find_local!('missing') }.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'raises with blank username' do - expect { Account.find_local!('') }.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'raises with nil username' do - expect { Account.find_local!(nil) }.to raise_error(ActiveRecord::RecordNotFound) - end - end - end - - describe 'remote finders' do - before do - @account = Fabricate(:account, username: 'Alice', domain: 'mastodon.social') - end - - describe '.find_remote' do - it 'returns exact match result' do - expect(Account.find_remote('alice', 'mastodon.social')).to eq(@account) - end - - it 'returns case-insensitive result' do - expect(Account.find_remote('ALICE', 'MASTODON.SOCIAL')).to eq(@account) - end - - it 'returns nil when username does not match' do - expect(Account.find_remote('a_ice', 'mastodon.social')).to be_nil - end - - it 'returns nil when domain does not match' do - expect(Account.find_remote('alice', 'm_stodon.social')).to be_nil - end - - it 'returns nil for regex style domain value' do - expect(Account.find_remote('alice', 'm%')).to be_nil - end - - it 'returns nil for nil username value' do - expect(Account.find_remote(nil, 'domain')).to be_nil - end - - it 'returns nil for blank username value' do - expect(Account.find_remote('', 'domain')).to be_nil - end - end - - describe '.find_remote!' do - it 'returns matching result' do - expect(Account.find_remote!('alice', 'mastodon.social')).to eq(@account) - end - - it 'raises on non-matching result' do - expect { Account.find_remote!('missing', 'mastodon.host') }.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'raises with blank username' do - expect { Account.find_remote!('', '') }.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'raises with nil username' do - expect { Account.find_remote!(nil, nil) }.to raise_error(ActiveRecord::RecordNotFound) - end - end - end -end diff --git a/spec/models/concerns/account_interactions_spec.rb b/spec/models/concerns/account_interactions_spec.rb deleted file mode 100644 index 41aedd18b..000000000 --- a/spec/models/concerns/account_interactions_spec.rb +++ /dev/null @@ -1,721 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe AccountInteractions do - let(:account) { Fabricate(:account, username: 'account') } - let(:account_id) { account.id } - let(:account_ids) { [account_id] } - let(:target_account) { Fabricate(:account, username: 'target') } - let(:target_account_id) { target_account.id } - let(:target_account_ids) { [target_account_id] } - - describe '.following_map' do - subject { Account.following_map(target_account_ids, account_id) } - - context 'when Account with Follow' do - it 'returns { target_account_id => true }' do - Fabricate(:follow, account: account, target_account: target_account) - expect(subject).to eq(target_account_id => { reblogs: true, notify: false, languages: nil }) - end - end - - context 'when Account with Follow but with reblogs disabled' do - it 'returns { target_account_id => { reblogs: false } }' do - Fabricate(:follow, account: account, target_account: target_account, show_reblogs: false) - expect(subject).to eq(target_account_id => { reblogs: false, notify: false, languages: nil }) - end - end - - context 'when Account without Follow' do - it 'returns {}' do - expect(subject).to eq({}) - end - end - end - - describe '.followed_by_map' do - subject { Account.followed_by_map(target_account_ids, account_id) } - - context 'when Account with Follow' do - it 'returns { target_account_id => true }' do - Fabricate(:follow, account: target_account, target_account: account) - expect(subject).to eq(target_account_id => true) - end - end - - context 'when Account without Follow' do - it 'returns {}' do - expect(subject).to eq({}) - end - end - end - - describe '.blocking_map' do - subject { Account.blocking_map(target_account_ids, account_id) } - - context 'when Account with Block' do - it 'returns { target_account_id => true }' do - Fabricate(:block, account: account, target_account: target_account) - expect(subject).to eq(target_account_id => true) - end - end - - context 'when Account without Block' do - it 'returns {}' do - expect(subject).to eq({}) - end - end - end - - describe '.muting_map' do - subject { Account.muting_map(target_account_ids, account_id) } - - context 'when Account with Mute' do - before do - Fabricate(:mute, target_account: target_account, account: account, hide_notifications: hide) - end - - context 'when Mute#hide_notifications?' do - let(:hide) { true } - - it 'returns { target_account_id => { notifications: true } }' do - expect(subject).to eq(target_account_id => { notifications: true }) - end - end - - context 'when not Mute#hide_notifications?' do - let(:hide) { false } - - it 'returns { target_account_id => { notifications: false } }' do - expect(subject).to eq(target_account_id => { notifications: false }) - end - end - end - - context 'when Account without Mute' do - it 'returns {}' do - expect(subject).to eq({}) - end - end - end - - describe '#follow!' do - it 'creates and returns Follow' do - expect do - expect(account.follow!(target_account)).to be_a Follow - end.to change { account.following.count }.by 1 - end - end - - describe '#block' do - it 'creates and returns Block' do - expect do - expect(account.block!(target_account)).to be_a Block - end.to change { account.block_relationships.count }.by 1 - end - end - - describe '#mute!' do - subject { account.mute!(target_account, notifications: arg_notifications) } - - context 'when Mute does not exist yet' do - context 'when arg :notifications is nil' do - let(:arg_notifications) { nil } - - it 'creates Mute, and returns Mute' do - expect do - expect(subject).to be_a Mute - end.to change { account.mute_relationships.count }.by 1 - end - end - - context 'when arg :notifications is false' do - let(:arg_notifications) { false } - - it 'creates Mute, and returns Mute' do - expect do - expect(subject).to be_a Mute - end.to change { account.mute_relationships.count }.by 1 - end - end - - context 'when arg :notifications is true' do - let(:arg_notifications) { true } - - it 'creates Mute, and returns Mute' do - expect do - expect(subject).to be_a Mute - end.to change { account.mute_relationships.count }.by 1 - end - end - end - - context 'when Mute already exists' do - before do - account.mute_relationships << mute - end - - let(:mute) do - Fabricate(:mute, - account: account, - target_account: target_account, - hide_notifications: hide_notifications) - end - - context 'when mute.hide_notifications is true' do - let(:hide_notifications) { true } - - context 'when arg :notifications is nil' do - let(:arg_notifications) { nil } - - it 'returns Mute without updating mute.hide_notifications' do - expect do - expect(subject).to be_a Mute - end.to_not change { mute.reload.hide_notifications? }.from(true) - end - end - - context 'when arg :notifications is false' do - let(:arg_notifications) { false } - - it 'returns Mute, and updates mute.hide_notifications false' do - expect do - expect(subject).to be_a Mute - end.to change { mute.reload.hide_notifications? }.from(true).to(false) - end - end - - context 'when arg :notifications is true' do - let(:arg_notifications) { true } - - it 'returns Mute without updating mute.hide_notifications' do - expect do - expect(subject).to be_a Mute - end.to_not change { mute.reload.hide_notifications? }.from(true) - end - end - end - - context 'when mute.hide_notifications is false' do - let(:hide_notifications) { false } - - context 'when arg :notifications is nil' do - let(:arg_notifications) { nil } - - it 'returns Mute, and updates mute.hide_notifications true' do - expect do - expect(subject).to be_a Mute - end.to change { mute.reload.hide_notifications? }.from(false).to(true) - end - end - - context 'when arg :notifications is false' do - let(:arg_notifications) { false } - - it 'returns Mute without updating mute.hide_notifications' do - expect do - expect(subject).to be_a Mute - end.to_not change { mute.reload.hide_notifications? }.from(false) - end - end - - context 'when arg :notifications is true' do - let(:arg_notifications) { true } - - it 'returns Mute, and updates mute.hide_notifications true' do - expect do - expect(subject).to be_a Mute - end.to change { mute.reload.hide_notifications? }.from(false).to(true) - end - end - end - end - end - - describe '#mute_conversation!' do - subject { account.mute_conversation!(conversation) } - - let(:conversation) { Fabricate(:conversation) } - - it 'creates and returns ConversationMute' do - expect do - expect(subject).to be_a ConversationMute - end.to change { account.conversation_mutes.count }.by 1 - end - end - - describe '#block_domain!' do - subject { account.block_domain!(domain) } - - let(:domain) { 'example.com' } - - it 'creates and returns AccountDomainBlock' do - expect do - expect(subject).to be_a AccountDomainBlock - end.to change { account.domain_blocks.count }.by 1 - end - end - - describe '#unfollow!' do - subject { account.unfollow!(target_account) } - - context 'when following target_account' do - it 'returns destroyed Follow' do - account.active_relationships.create(target_account: target_account) - expect(subject).to be_a Follow - expect(subject).to be_destroyed - end - end - - context 'when not following target_account' do - it 'returns nil' do - expect(subject).to be_nil - end - end - end - - describe '#unblock!' do - subject { account.unblock!(target_account) } - - context 'when blocking target_account' do - it 'returns destroyed Block' do - account.block_relationships.create(target_account: target_account) - expect(subject).to be_a Block - expect(subject).to be_destroyed - end - end - - context 'when not blocking target_account' do - it 'returns nil' do - expect(subject).to be_nil - end - end - end - - describe '#unmute!' do - subject { account.unmute!(target_account) } - - context 'when muting target_account' do - it 'returns destroyed Mute' do - account.mute_relationships.create(target_account: target_account) - expect(subject).to be_a Mute - expect(subject).to be_destroyed - end - end - - context 'when not muting target_account' do - it 'returns nil' do - expect(subject).to be_nil - end - end - end - - describe '#unmute_conversation!' do - subject { account.unmute_conversation!(conversation) } - - let(:conversation) { Fabricate(:conversation) } - - context 'when muting the conversation' do - it 'returns destroyed ConversationMute' do - account.conversation_mutes.create(conversation: conversation) - expect(subject).to be_a ConversationMute - expect(subject).to be_destroyed - end - end - - context 'when not muting the conversation' do - it 'returns nil' do - expect(subject).to be_nil - end - end - end - - describe '#unblock_domain!' do - subject { account.unblock_domain!(domain) } - - let(:domain) { 'example.com' } - - context 'when blocking the domain' do - it 'returns destroyed AccountDomainBlock' do - account_domain_block = Fabricate(:account_domain_block, domain: domain) - account.domain_blocks << account_domain_block - expect(subject).to be_a AccountDomainBlock - expect(subject).to be_destroyed - end - end - - context 'when unblocking the domain' do - it 'returns nil' do - expect(subject).to be_nil - end - end - end - - describe '#following?' do - subject { account.following?(target_account) } - - context 'when following target_account' do - it 'returns true' do - account.active_relationships.create(target_account: target_account) - expect(subject).to be true - end - end - - context 'when not following target_account' do - it 'returns false' do - expect(subject).to be false - end - end - end - - describe '#followed_by?' do - subject { account.followed_by?(target_account) } - - context 'when followed by target_account' do - it 'returns true' do - account.passive_relationships.create(account: target_account) - expect(subject).to be true - end - end - - context 'when not followed by target_account' do - it 'returns false' do - expect(subject).to be false - end - end - end - - describe '#blocking?' do - subject { account.blocking?(target_account) } - - context 'when blocking target_account' do - it 'returns true' do - account.block_relationships.create(target_account: target_account) - expect(subject).to be true - end - end - - context 'when not blocking target_account' do - it 'returns false' do - expect(subject).to be false - end - end - end - - describe '#domain_blocking?' do - subject { account.domain_blocking?(domain) } - - let(:domain) { 'example.com' } - - context 'when blocking the domain' do - it 'returns true' do - account_domain_block = Fabricate(:account_domain_block, domain: domain) - account.domain_blocks << account_domain_block - expect(subject).to be true - end - end - - context 'when not blocking the domain' do - it 'returns false' do - expect(subject).to be false - end - end - end - - describe '#muting?' do - subject { account.muting?(target_account) } - - context 'when muting target_account' do - it 'returns true' do - mute = Fabricate(:mute, account: account, target_account: target_account) - account.mute_relationships << mute - expect(subject).to be true - end - end - - context 'when not muting target_account' do - it 'returns false' do - expect(subject).to be false - end - end - end - - describe '#muting_conversation?' do - subject { account.muting_conversation?(conversation) } - - let(:conversation) { Fabricate(:conversation) } - - context 'when muting the conversation' do - it 'returns true' do - account.conversation_mutes.create(conversation: conversation) - expect(subject).to be true - end - end - - context 'when not muting the conversation' do - it 'returns false' do - expect(subject).to be false - end - end - end - - describe '#muting_notifications?' do - subject { account.muting_notifications?(target_account) } - - before do - mute = Fabricate(:mute, target_account: target_account, account: account, hide_notifications: hide) - account.mute_relationships << mute - end - - context 'when muting notifications of target_account' do - let(:hide) { true } - - it 'returns true' do - expect(subject).to be true - end - end - - context 'when not muting notifications of target_account' do - let(:hide) { false } - - it 'returns false' do - expect(subject).to be false - end - end - end - - describe '#requested?' do - subject { account.requested?(target_account) } - - context 'with requested by target_account' do - it 'returns true' do - Fabricate(:follow_request, account: account, target_account: target_account) - expect(subject).to be true - end - end - - context 'when not requested by target_account' do - it 'returns false' do - expect(subject).to be false - end - end - end - - describe '#favourited?' do - subject { account.favourited?(status) } - - let(:status) { Fabricate(:status, account: account, favourites: favourites) } - - context 'when favorited' do - let(:favourites) { [Fabricate(:favourite, account: account)] } - - it 'returns true' do - expect(subject).to be true - end - end - - context 'when not favorited' do - let(:favourites) { [] } - - it 'returns false' do - expect(subject).to be false - end - end - end - - describe '#reblogged?' do - subject { account.reblogged?(status) } - - let(:status) { Fabricate(:status, account: account, reblogs: reblogs) } - - context 'with reblogged' do - let(:reblogs) { [Fabricate(:status, account: account)] } - - it 'returns true' do - expect(subject).to be true - end - end - - context 'when not reblogged' do - let(:reblogs) { [] } - - it 'returns false' do - expect(subject).to be false - end - end - end - - describe '#pinned?' do - subject { account.pinned?(status) } - - let(:status) { Fabricate(:status, account: account) } - - context 'when pinned' do - it 'returns true' do - Fabricate(:status_pin, account: account, status: status) - expect(subject).to be true - end - end - - context 'when not pinned' do - it 'returns false' do - expect(subject).to be false - end - end - end - - describe '#remote_followers_hash' do - let(:me) { Fabricate(:account, username: 'Me') } - let(:remote_alice) { Fabricate(:account, username: 'alice', domain: 'example.org', uri: 'https://example.org/users/alice') } - let(:remote_bob) { Fabricate(:account, username: 'bob', domain: 'example.org', uri: 'https://example.org/users/bob') } - let(:remote_instance_actor) { Fabricate(:account, username: 'instance-actor', domain: 'example.org', uri: 'https://example.org') } - let(:remote_eve) { Fabricate(:account, username: 'eve', domain: 'foo.org', uri: 'https://foo.org/users/eve') } - - before do - remote_alice.follow!(me) - remote_bob.follow!(me) - remote_instance_actor.follow!(me) - remote_eve.follow!(me) - me.follow!(remote_alice) - end - - it 'returns correct hash for remote domains' do - expect(me.remote_followers_hash('https://example.org/')).to eq '20aecbe774b3d61c25094370baf370012b9271c5b172ecedb05caff8d79ef0c7' - expect(me.remote_followers_hash('https://foo.org/')).to eq 'ccb9c18a67134cfff9d62c7f7e7eb88e6b803446c244b84265565f4eba29df0e' - expect(me.remote_followers_hash('https://foo.org.evil.com/')).to eq '0000000000000000000000000000000000000000000000000000000000000000' - expect(me.remote_followers_hash('https://foo')).to eq '0000000000000000000000000000000000000000000000000000000000000000' - end - - it 'invalidates cache as needed when removing or adding followers' do - expect(me.remote_followers_hash('https://example.org/')).to eq '20aecbe774b3d61c25094370baf370012b9271c5b172ecedb05caff8d79ef0c7' - remote_instance_actor.unfollow!(me) - expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec' - remote_alice.unfollow!(me) - expect(me.remote_followers_hash('https://example.org/')).to eq '241b00794ce9b46aa864f3220afadef128318da2659782985bac5ed5bd436bff' - remote_alice.follow!(me) - expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec' - end - end - - describe '#local_followers_hash' do - let(:me) { Fabricate(:account, username: 'Me') } - let(:remote_alice) { Fabricate(:account, username: 'alice', domain: 'example.org', uri: 'https://example.org/users/alice') } - - before do - me.follow!(remote_alice) - end - - it 'returns correct hash for local users' do - expect(remote_alice.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me)) - end - - it 'invalidates cache as needed when removing or adding followers' do - expect(remote_alice.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me)) - me.unfollow!(remote_alice) - expect(remote_alice.local_followers_hash).to eq '0000000000000000000000000000000000000000000000000000000000000000' - me.follow!(remote_alice) - expect(remote_alice.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me)) - end - end - - describe 'muting an account' do - let(:me) { Fabricate(:account, username: 'Me') } - let(:you) { Fabricate(:account, username: 'You') } - - context 'with the notifications option unspecified' do - before do - me.mute!(you) - end - - it 'defaults to muting notifications' do - expect(me.muting_notifications?(you)).to be true - end - end - - context 'with the notifications option set to false' do - before do - me.mute!(you, notifications: false) - end - - it 'does not mute notifications' do - expect(me.muting_notifications?(you)).to be false - end - end - - context 'with the notifications option set to true' do - before do - me.mute!(you, notifications: true) - end - - it 'does mute notifications' do - expect(me.muting_notifications?(you)).to be true - end - end - end - - describe 'ignoring reblogs from an account' do - before do - @me = Fabricate(:account, username: 'Me') - @you = Fabricate(:account, username: 'You') - end - - context 'with the reblogs option unspecified' do - before do - @me.follow!(@you) - end - - it 'defaults to showing reblogs' do - expect(@me.muting_reblogs?(@you)).to be(false) - end - end - - context 'with the reblogs option set to false' do - before do - @me.follow!(@you, reblogs: false) - end - - it 'does mute reblogs' do - expect(@me.muting_reblogs?(@you)).to be(true) - end - end - - context 'with the reblogs option set to true' do - before do - @me.follow!(@you, reblogs: true) - end - - it 'does not mute reblogs' do - expect(@me.muting_reblogs?(@you)).to be(false) - end - end - end - - describe '#lists_for_local_distribution' do - let(:account) { Fabricate(:user, current_sign_in_at: Time.now.utc).account } - let!(:inactive_follower_user) { Fabricate(:user, current_sign_in_at: 5.years.ago) } - let!(:follower_user) { Fabricate(:user, current_sign_in_at: Time.now.utc) } - let!(:follow_request_user) { Fabricate(:user, current_sign_in_at: Time.now.utc) } - - let!(:inactive_follower_list) { Fabricate(:list, account: inactive_follower_user.account) } - let!(:follower_list) { Fabricate(:list, account: follower_user.account) } - let!(:follow_request_list) { Fabricate(:list, account: follow_request_user.account) } - - let!(:self_list) { Fabricate(:list, account: account) } - - before do - inactive_follower_user.account.follow!(account) - follower_user.account.follow!(account) - follow_request_user.account.follow_requests.create!(target_account: account) - - inactive_follower_list.accounts << account - follower_list.accounts << account - follow_request_list.accounts << account - self_list.accounts << account - end - - it 'includes only the list from the active follower and from oneself' do - expect(account.lists_for_local_distribution.to_a).to contain_exactly(follower_list, self_list) - end - end -end diff --git a/spec/models/concerns/account_statuses_search_spec.rb b/spec/models/concerns/account_statuses_search_spec.rb deleted file mode 100644 index 46362936f..000000000 --- a/spec/models/concerns/account_statuses_search_spec.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe AccountStatusesSearch do - let(:account) { Fabricate(:account, indexable: indexable) } - - before do - allow(Chewy).to receive(:enabled?).and_return(true) - end - - describe '#enqueue_update_public_statuses_index' do - before do - allow(account).to receive(:enqueue_add_to_public_statuses_index) - allow(account).to receive(:enqueue_remove_from_public_statuses_index) - end - - context 'when account is indexable' do - let(:indexable) { true } - - it 'enqueues add_to_public_statuses_index and not to remove_from_public_statuses_index' do - account.enqueue_update_public_statuses_index - expect(account).to have_received(:enqueue_add_to_public_statuses_index) - expect(account).to_not have_received(:enqueue_remove_from_public_statuses_index) - end - end - - context 'when account is not indexable' do - let(:indexable) { false } - - it 'enqueues remove_from_public_statuses_index and not to add_to_public_statuses_index' do - account.enqueue_update_public_statuses_index - expect(account).to have_received(:enqueue_remove_from_public_statuses_index) - expect(account).to_not have_received(:enqueue_add_to_public_statuses_index) - end - end - end - - describe '#enqueue_add_to_public_statuses_index' do - let(:indexable) { true } - let(:worker) { AddToPublicStatusesIndexWorker } - - before do - allow(worker).to receive(:perform_async) - end - - it 'enqueues AddToPublicStatusesIndexWorker' do - account.enqueue_add_to_public_statuses_index - expect(worker).to have_received(:perform_async).with(account.id) - end - end - - describe '#enqueue_remove_from_public_statuses_index' do - let(:indexable) { false } - let(:worker) { RemoveFromPublicStatusesIndexWorker } - - before do - allow(worker).to receive(:perform_async) - end - - it 'enqueues RemoveFromPublicStatusesIndexWorker' do - account.enqueue_remove_from_public_statuses_index - expect(worker).to have_received(:perform_async).with(account.id) - end - end -end diff --git a/spec/models/concerns/remotable_spec.rb b/spec/models/concerns/remotable_spec.rb deleted file mode 100644 index b2aa56a70..000000000 --- a/spec/models/concerns/remotable_spec.rb +++ /dev/null @@ -1,205 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Remotable do - let(:foo_class) do - Class.new do - def initialize - @attrs = {} - end - - def [](arg) - @attrs[arg] - end - - def []=(arg1, arg2) - @attrs[arg1] = arg2 - end - - def hoge=(arg); end - - def hoge_file_name; end - - def hoge_file_name=(arg); end - - def has_attribute?(arg); end - - def self.attachment_definitions - { hoge: nil } - end - end - end - - let(:attribute_name) { "#{hoge}_remote_url".to_sym } - let(:code) { 200 } - let(:file) { 'filename="foo.txt"' } - let(:foo) { foo_class.new } - let(:headers) { { 'content-disposition' => file } } - let(:hoge) { :hoge } - let(:url) { 'https://google.com' } - - before do - foo_class.include described_class - foo_class.remotable_attachment :hoge, 1.kilobyte - end - - it 'defines a method #hoge_remote_url=' do - expect(foo).to respond_to(:hoge_remote_url=) - end - - it 'defines a method #reset_hoge!' do - expect(foo).to respond_to(:reset_hoge!) - end - - it 'defines a method #download_hoge!' do - expect(foo).to respond_to(:download_hoge!) - end - - describe '#hoge_remote_url=' do - before do - stub_request(:get, url).to_return(status: code, headers: headers) - end - - it 'always returns its argument' do - [nil, '', [], {}].each do |arg| - expect(foo.hoge_remote_url = arg).to be arg - end - end - - context 'with an invalid URL' do - before do - allow(Addressable::URI).to receive_message_chain(:parse, :normalize).with(url).with(no_args).and_raise(Addressable::URI::InvalidURIError) - end - - it 'makes no request' do - foo.hoge_remote_url = url - expect(a_request(:get, url)).to_not have_been_made - end - end - - context 'with scheme that is neither http nor https' do - let(:url) { 'ftp://google.com' } - - it 'makes no request' do - foo.hoge_remote_url = url - expect(a_request(:get, url)).to_not have_been_made - end - end - - context 'with relative URL' do - let(:url) { 'https:///path' } - - it 'makes no request' do - foo.hoge_remote_url = url - expect(a_request(:get, url)).to_not have_been_made - end - end - - context 'when URL has not changed' do - it 'makes no request if file is already saved' do - allow(foo).to receive(:[]).with(attribute_name).and_return(url) - allow(foo).to receive(:hoge_file_name).and_return('foo.jpg') - - foo.hoge_remote_url = url - expect(a_request(:get, url)).to_not have_been_made - end - - it 'makes request if file is not already saved' do - allow(foo).to receive(:[]).with(attribute_name).and_return(url) - allow(foo).to receive(:hoge_file_name).and_return(nil) - - foo.hoge_remote_url = url - expect(a_request(:get, url)).to have_been_made - end - end - - context 'when instance has no attribute for URL' do - before do - allow(foo).to receive(:has_attribute?).with(attribute_name).and_return(false) - end - - it 'does not try to write attribute' do - expect(foo).to_not receive('[]=').with(attribute_name, url) - foo.hoge_remote_url = url - end - end - - context 'when instance has an attribute for URL' do - before do - allow(foo).to receive(:has_attribute?).with(attribute_name).and_return(true) - end - - it 'does not try to write attribute' do - expect(foo).to receive('[]=').with(attribute_name, url) - foo.hoge_remote_url = url - end - end - - context 'with a valid URL' do - it 'makes a request' do - foo.hoge_remote_url = url - expect(a_request(:get, url)).to have_been_made - end - - context 'when the response is not successful' do - let(:code) { 500 } - - it 'does not assign file' do - expect(foo).to_not receive(:public_send).with("#{hoge}=", any_args) - expect(foo).to_not receive(:public_send).with("#{hoge}_file_name=", any_args) - - foo.hoge_remote_url = url - end - end - - context 'when the response is successful' do - let(:code) { 200 } - - context 'when contains Content-Disposition header' do - let(:file) { 'filename="foo.txt"' } - let(:headers) { { 'content-disposition' => file } } - - it 'assigns file' do - response_with_limit = ResponseWithLimit.new(nil, 0) - - allow(ResponseWithLimit).to receive(:new).with(anything, anything).and_return(response_with_limit) - - expect(foo).to receive(:public_send).with("download_#{hoge}!", url) - - foo.hoge_remote_url = url - - expect(foo).to receive(:public_send).with("#{hoge}=", response_with_limit) - - foo.download_hoge!(url) - end - end - end - - context 'when an error is raised during the request' do - before do - stub_request(:get, url).to_raise(error_class) - end - - error_classes = [ - HTTP::TimeoutError, - HTTP::ConnectionError, - OpenSSL::SSL::SSLError, - Paperclip::Errors::NotIdentifiedByImageMagickError, - Addressable::URI::InvalidURIError, - ] - - error_classes.each do |error_class| - let(:error_class) { error_class } - - it 'calls Rails.logger.debug' do - expect(Rails.logger).to receive(:debug) do |&block| - expect(block.call).to match(/^Error fetching remote #{hoge}: /) - end - foo.hoge_remote_url = url - end - end - end - end - end -end diff --git a/spec/models/concerns/status_threading_concern_spec.rb b/spec/models/concerns/status_threading_concern_spec.rb deleted file mode 100644 index 2eac1ca6e..000000000 --- a/spec/models/concerns/status_threading_concern_spec.rb +++ /dev/null @@ -1,132 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe StatusThreadingConcern do - describe '#ancestors' do - let!(:alice) { Fabricate(:account, username: 'alice') } - let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com') } - let!(:jeff) { Fabricate(:account, username: 'jeff') } - let!(:status) { Fabricate(:status, account: alice) } - let!(:reply_to_status) { Fabricate(:status, thread: status, account: jeff) } - let!(:reply_to_first_reply) { Fabricate(:status, thread: reply_to_status, account: bob) } - let!(:reply_to_second_reply) { Fabricate(:status, thread: reply_to_first_reply, account: alice) } - let!(:viewer) { Fabricate(:account, username: 'viewer') } - - it 'returns conversation history' do - expect(reply_to_second_reply.ancestors(4)).to include(status, reply_to_status, reply_to_first_reply) - end - - it 'does not return conversation history user is not allowed to see' do - reply_to_status.update(visibility: :private) - status.update(visibility: :direct) - - expect(reply_to_second_reply.ancestors(4, viewer)).to_not include(reply_to_status, status) - end - - it 'does not return conversation history from blocked users' do - viewer.block!(jeff) - expect(reply_to_second_reply.ancestors(4, viewer)).to_not include(reply_to_status) - end - - it 'does not return conversation history from muted users' do - viewer.mute!(jeff) - expect(reply_to_second_reply.ancestors(4, viewer)).to_not include(reply_to_status) - end - - it 'does not return conversation history from silenced and not followed users' do - jeff.silence! - expect(reply_to_second_reply.ancestors(4, viewer)).to_not include(reply_to_status) - end - - it 'does not return conversation history from blocked domains' do - viewer.block_domain!('example.com') - expect(reply_to_second_reply.ancestors(4, viewer)).to_not include(reply_to_first_reply) - end - - it 'ignores deleted records' do - first_status = Fabricate(:status, account: bob) - second_status = Fabricate(:status, thread: first_status, account: alice) - - # Create cache and delete cached record - second_status.ancestors(4) - first_status.destroy - - expect(second_status.ancestors(4)).to eq([]) - end - - it 'can return more records than previously requested' do - first_status = Fabricate(:status, account: bob) - second_status = Fabricate(:status, thread: first_status, account: alice) - third_status = Fabricate(:status, thread: second_status, account: alice) - - # Create cache - second_status.ancestors(1) - - expect(third_status.ancestors(2)).to eq([first_status, second_status]) - end - - it 'can return fewer records than previously requested' do - first_status = Fabricate(:status, account: bob) - second_status = Fabricate(:status, thread: first_status, account: alice) - third_status = Fabricate(:status, thread: second_status, account: alice) - - # Create cache - second_status.ancestors(2) - - expect(third_status.ancestors(1)).to eq([second_status]) - end - end - - describe '#descendants' do - let!(:alice) { Fabricate(:account, username: 'alice') } - let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com') } - let!(:jeff) { Fabricate(:account, username: 'jeff') } - let!(:status) { Fabricate(:status, account: alice) } - let!(:reply_to_status_from_alice) { Fabricate(:status, thread: status, account: alice) } - let!(:reply_to_status_from_bob) { Fabricate(:status, thread: status, account: bob) } - let!(:reply_to_alice_reply_from_jeff) { Fabricate(:status, thread: reply_to_status_from_alice, account: jeff) } - let!(:viewer) { Fabricate(:account, username: 'viewer') } - - it 'returns replies' do - expect(status.descendants(4)).to include(reply_to_status_from_alice, reply_to_status_from_bob, reply_to_alice_reply_from_jeff) - end - - it 'does not return replies user is not allowed to see' do - reply_to_status_from_alice.update(visibility: :private) - reply_to_alice_reply_from_jeff.update(visibility: :direct) - - expect(status.descendants(4, viewer)).to_not include(reply_to_status_from_alice, reply_to_alice_reply_from_jeff) - end - - it 'does not return replies from blocked users' do - viewer.block!(jeff) - expect(status.descendants(4, viewer)).to_not include(reply_to_alice_reply_from_jeff) - end - - it 'does not return replies from muted users' do - viewer.mute!(jeff) - expect(status.descendants(4, viewer)).to_not include(reply_to_alice_reply_from_jeff) - end - - it 'does not return replies from silenced and not followed users' do - jeff.silence! - expect(status.descendants(4, viewer)).to_not include(reply_to_alice_reply_from_jeff) - end - - it 'does not return replies from blocked domains' do - viewer.block_domain!('example.com') - expect(status.descendants(4, viewer)).to_not include(reply_to_status_from_bob) - end - - it 'promotes self-replies to the top while leaving the rest in order' do - a = Fabricate(:status, account: alice) - d = Fabricate(:status, account: jeff, thread: a) - e = Fabricate(:status, account: bob, thread: d) - c = Fabricate(:status, account: alice, thread: a) - f = Fabricate(:status, account: bob, thread: c) - - expect(a.descendants(20)).to eq [c, d, e, f] - end - end -end diff --git a/spec/models/conversation_spec.rb b/spec/models/conversation_spec.rb deleted file mode 100644 index c1d6659aa..000000000 --- a/spec/models/conversation_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Conversation do - describe '#local?' do - it 'returns true when URI is nil' do - expect(Fabricate(:conversation).local?).to be true - end - - it 'returns false when URI is not nil' do - expect(Fabricate(:conversation, uri: 'abc').local?).to be false - end - end -end diff --git a/spec/models/custom_emoji_category_spec.rb b/spec/models/custom_emoji_category_spec.rb deleted file mode 100644 index 30de07bd8..000000000 --- a/spec/models/custom_emoji_category_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe CustomEmojiCategory do - describe 'validations' do - it 'validates name presence' do - record = described_class.new(name: nil) - - expect(record).to_not be_valid - expect(record).to model_have_error_on_field(:name) - end - end -end diff --git a/spec/models/custom_emoji_filter_spec.rb b/spec/models/custom_emoji_filter_spec.rb deleted file mode 100644 index c36fecd60..000000000 --- a/spec/models/custom_emoji_filter_spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe CustomEmojiFilter do - describe '#results' do - subject { described_class.new(params).results } - - let!(:custom_emoji_domain_a) { Fabricate(:custom_emoji, domain: 'a') } - let!(:custom_emoji_domain_b) { Fabricate(:custom_emoji, domain: 'b') } - let!(:custom_emoji_domain_nil) { Fabricate(:custom_emoji, domain: nil, shortcode: 'hoge') } - - context 'when params have values' do - context 'when local' do - let(:params) { { local: true } } - - it 'returns ActiveRecord::Relation' do - expect(subject).to be_a(ActiveRecord::Relation) - expect(subject).to contain_exactly(custom_emoji_domain_nil) - end - end - - context 'when remote' do - let(:params) { { remote: true } } - - it 'returns ActiveRecord::Relation' do - expect(subject).to be_a(ActiveRecord::Relation) - expect(subject).to contain_exactly(custom_emoji_domain_a, custom_emoji_domain_b) - end - end - - context 'with by_domain' do - let(:params) { { by_domain: 'a' } } - - it 'returns ActiveRecord::Relation' do - expect(subject).to be_a(ActiveRecord::Relation) - expect(subject).to contain_exactly(custom_emoji_domain_a) - end - end - - context 'when shortcode' do - let(:params) { { shortcode: 'hoge' } } - - it 'returns ActiveRecord::Relation' do - expect(subject).to be_a(ActiveRecord::Relation) - expect(subject).to contain_exactly(custom_emoji_domain_nil) - end - end - - context 'when some other case' do - let(:params) { { else: 'else' } } - - it 'raises Mastodon::InvalidParameterError' do - expect do - subject - end.to raise_error(Mastodon::InvalidParameterError, /Unknown filter: else/) - end - end - end - - context 'when params without value' do - let(:params) { { hoge: nil } } - - it 'returns ActiveRecord::Relation' do - expect(subject).to be_a(ActiveRecord::Relation) - expect(subject).to contain_exactly(custom_emoji_domain_a, custom_emoji_domain_b, custom_emoji_domain_nil) - end - end - end -end diff --git a/spec/models/custom_emoji_spec.rb b/spec/models/custom_emoji_spec.rb deleted file mode 100644 index 8a6487c32..000000000 --- a/spec/models/custom_emoji_spec.rb +++ /dev/null @@ -1,89 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe CustomEmoji do - describe '#search' do - subject { described_class.search(search_term) } - - let(:custom_emoji) { Fabricate(:custom_emoji, shortcode: shortcode) } - - context 'when shortcode is exact' do - let(:shortcode) { 'blobpats' } - let(:search_term) { 'blobpats' } - - it 'finds emoji' do - expect(subject).to include(custom_emoji) - end - end - - context 'when shortcode is partial' do - let(:shortcode) { 'blobpats' } - let(:search_term) { 'blob' } - - it 'finds emoji' do - expect(subject).to include(custom_emoji) - end - end - end - - describe '#local?' do - subject { custom_emoji.local? } - - let(:custom_emoji) { Fabricate(:custom_emoji, domain: domain) } - - context 'when domain is nil' do - let(:domain) { nil } - - it 'returns true' do - expect(subject).to be true - end - end - - context 'when domain is present' do - let(:domain) { 'example.com' } - - it 'returns false' do - expect(subject).to be false - end - end - end - - describe '#object_type' do - it 'returns :emoji' do - custom_emoji = Fabricate(:custom_emoji) - expect(custom_emoji.object_type).to be :emoji - end - end - - describe '.from_text' do - subject { described_class.from_text(text, nil) } - - let!(:emojo) { Fabricate(:custom_emoji) } - - context 'with plain text' do - let(:text) { 'Hello :coolcat:' } - - it 'returns records used via shortcodes in text' do - expect(subject).to include(emojo) - end - end - - context 'with html' do - let(:text) { '

Hello :coolcat:

' } - - it 'returns records used via shortcodes in text' do - expect(subject).to include(emojo) - end - end - end - - describe 'pre_validation' do - let(:custom_emoji) { Fabricate(:custom_emoji, domain: 'wWw.MaStOdOn.CoM') } - - it 'downcases' do - custom_emoji.valid? - expect(custom_emoji.domain).to eq('www.mastodon.com') - end - end -end diff --git a/spec/models/domain_allow_spec.rb b/spec/models/domain_allow_spec.rb deleted file mode 100644 index 49e16376e..000000000 --- a/spec/models/domain_allow_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe DomainAllow do - describe 'scopes' do - describe 'matches_domain' do - let(:domain) { Fabricate(:domain_allow, domain: 'example.com') } - let(:other_domain) { Fabricate(:domain_allow, domain: 'example.biz') } - - it 'returns the correct records' do - results = described_class.matches_domain('example.com') - - expect(results).to eq([domain]) - end - end - end -end diff --git a/spec/models/domain_block_spec.rb b/spec/models/domain_block_spec.rb deleted file mode 100644 index 67f53fa78..000000000 --- a/spec/models/domain_block_spec.rb +++ /dev/null @@ -1,112 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe DomainBlock do - describe 'validations' do - it 'is invalid without a domain' do - domain_block = Fabricate.build(:domain_block, domain: nil) - domain_block.valid? - expect(domain_block).to model_have_error_on_field(:domain) - end - - it 'is invalid if the same normalized domain already exists' do - domain_block_1 = Fabricate(:domain_block, domain: 'にゃん') - domain_block_2 = Fabricate.build(:domain_block, domain: 'xn--r9j5b5b') - domain_block_2.valid? - expect(domain_block_2).to model_have_error_on_field(:domain) - end - end - - describe '.blocked?' do - it 'returns true if the domain is suspended' do - Fabricate(:domain_block, domain: 'example.com', severity: :suspend) - expect(described_class.blocked?('example.com')).to be true - end - - it 'returns false even if the domain is silenced' do - Fabricate(:domain_block, domain: 'example.com', severity: :silence) - expect(described_class.blocked?('example.com')).to be false - end - - it 'returns false if the domain is not suspended nor silenced' do - expect(described_class.blocked?('example.com')).to be false - end - end - - describe '.rule_for' do - it 'returns rule matching a blocked domain' do - block = Fabricate(:domain_block, domain: 'example.com') - expect(described_class.rule_for('example.com')).to eq block - end - - it 'returns a rule matching a subdomain of a blocked domain' do - block = Fabricate(:domain_block, domain: 'example.com') - expect(described_class.rule_for('sub.example.com')).to eq block - end - - it 'returns a rule matching a blocked subdomain' do - block = Fabricate(:domain_block, domain: 'sub.example.com') - expect(described_class.rule_for('sub.example.com')).to eq block - end - - it 'returns a rule matching a blocked TLD' do - block = Fabricate(:domain_block, domain: 'google') - expect(described_class.rule_for('google')).to eq block - end - - it 'returns a rule matching a subdomain of a blocked TLD' do - block = Fabricate(:domain_block, domain: 'google') - expect(described_class.rule_for('maps.google')).to eq block - end - end - - describe '#stricter_than?' do - it 'returns true if the new block has suspend severity while the old has lower severity' do - suspend = described_class.new(domain: 'domain', severity: :suspend) - silence = described_class.new(domain: 'domain', severity: :silence) - noop = described_class.new(domain: 'domain', severity: :noop) - expect(suspend.stricter_than?(silence)).to be true - expect(suspend.stricter_than?(noop)).to be true - end - - it 'returns false if the new block has lower severity than the old one' do - suspend = described_class.new(domain: 'domain', severity: :suspend) - silence = described_class.new(domain: 'domain', severity: :silence) - noop = described_class.new(domain: 'domain', severity: :noop) - expect(silence.stricter_than?(suspend)).to be false - expect(noop.stricter_than?(suspend)).to be false - expect(noop.stricter_than?(silence)).to be false - end - - it 'returns false if the new block does is less strict regarding reports' do - older = described_class.new(domain: 'domain', severity: :silence, reject_reports: true) - newer = described_class.new(domain: 'domain', severity: :silence, reject_reports: false) - expect(newer.stricter_than?(older)).to be false - end - - it 'returns false if the new block does is less strict regarding media' do - older = described_class.new(domain: 'domain', severity: :silence, reject_media: true) - newer = described_class.new(domain: 'domain', severity: :silence, reject_media: false) - expect(newer.stricter_than?(older)).to be false - end - end - - describe '#public_domain' do - context 'with a domain block that is obfuscated' do - let(:domain_block) { Fabricate(:domain_block, domain: 'hostname.example.com', obfuscate: true) } - - it 'garbles the domain' do - expect(domain_block.public_domain).to eq 'hostna**.******e.com' - end - end - - context 'with a domain block that is not obfuscated' do - let(:domain_block) { Fabricate(:domain_block, domain: 'example.com', obfuscate: false) } - - it 'returns the domain value' do - expect(domain_block.public_domain).to eq 'example.com' - end - end - end -end diff --git a/spec/models/email_domain_block_spec.rb b/spec/models/email_domain_block_spec.rb deleted file mode 100644 index 5874c5e53..000000000 --- a/spec/models/email_domain_block_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe EmailDomainBlock do - describe 'block?' do - let(:input) { nil } - - context 'when given an e-mail address' do - let(:input) { "foo@#{domain}" } - - context 'with a top level domain' do - let(:domain) { 'example.com' } - - it 'returns true if the domain is blocked' do - Fabricate(:email_domain_block, domain: 'example.com') - expect(described_class.block?(input)).to be true - end - - it 'returns false if the domain is not blocked' do - Fabricate(:email_domain_block, domain: 'other-example.com') - expect(described_class.block?(input)).to be false - end - end - - context 'with a subdomain' do - let(:domain) { 'mail.example.com' } - - it 'returns true if it is a subdomain of a blocked domain' do - Fabricate(:email_domain_block, domain: 'example.com') - expect(described_class.block?(input)).to be true - end - end - end - - context 'when given an array of domains' do - let(:input) { %w(foo.com mail.foo.com) } - - it 'returns true if the domain is blocked' do - Fabricate(:email_domain_block, domain: 'mail.foo.com') - expect(described_class.block?(input)).to be true - end - end - end -end diff --git a/spec/models/export_spec.rb b/spec/models/export_spec.rb deleted file mode 100644 index 75468898d..000000000 --- a/spec/models/export_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Export do - let(:account) { Fabricate(:account) } - let(:target_accounts) do - [{}, { username: 'one', domain: 'local.host' }].map(&method(:Fabricate).curry(2).call(:account)) - end - - describe 'to_csv' do - it 'returns a csv of the blocked accounts' do - target_accounts.each { |target_account| account.block!(target_account) } - - export = described_class.new(account).to_blocked_accounts_csv - results = export.strip.split - - expect(results.size).to eq 2 - expect(results.first).to eq 'one@local.host' - end - - it 'returns a csv of the muted accounts' do - target_accounts.each { |target_account| account.mute!(target_account) } - - export = described_class.new(account).to_muted_accounts_csv - results = export.strip.split("\n") - - expect(results.size).to eq 3 - expect(results.first).to eq 'Account address,Hide notifications' - expect(results.second).to eq 'one@local.host,true' - end - - it 'returns a csv of the following accounts' do - target_accounts.each { |target_account| account.follow!(target_account) } - - export = described_class.new(account).to_following_accounts_csv - results = export.strip.split("\n") - - expect(results.size).to eq 3 - expect(results.first).to eq 'Account address,Show boosts,Notify on new posts,Languages' - expect(results.second).to eq 'one@local.host,true,false,' - end - end - - describe 'total_storage' do - it 'returns the total size of the media attachments' do - media_attachment = Fabricate(:media_attachment, account: account) - expect(described_class.new(account).total_storage).to eq media_attachment.file_file_size || 0 - end - end - - describe 'total_follows' do - it 'returns the total number of the followed accounts' do - target_accounts.each { |target_account| account.follow!(target_account) } - expect(described_class.new(account.reload).total_follows).to eq 2 - end - - it 'returns the total number of the blocked accounts' do - target_accounts.each { |target_account| account.block!(target_account) } - expect(described_class.new(account.reload).total_blocks).to eq 2 - end - - it 'returns the total number of the muted accounts' do - target_accounts.each { |target_account| account.mute!(target_account) } - expect(described_class.new(account.reload).total_mutes).to eq 2 - end - end -end diff --git a/spec/models/extended_description_spec.rb b/spec/models/extended_description_spec.rb deleted file mode 100644 index ecc27c0f6..000000000 --- a/spec/models/extended_description_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ExtendedDescription do - describe '.current' do - context 'with the default values' do - it 'makes a new instance' do - record = described_class.current - - expect(record.text).to be_nil - expect(record.updated_at).to be_nil - end - end - - context 'with a custom setting value' do - before do - setting = instance_double(Setting, value: 'Extended text', updated_at: 10.days.ago) - allow(Setting).to receive(:find_by).with(var: 'site_extended_description').and_return(setting) - end - - it 'has the privacy text' do - record = described_class.current - - expect(record.text).to eq('Extended text') - end - end - end -end diff --git a/spec/models/favourite_spec.rb b/spec/models/favourite_spec.rb deleted file mode 100644 index ef7fbdefc..000000000 --- a/spec/models/favourite_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Favourite do - let(:account) { Fabricate(:account) } - - context 'when status is a reblog' do - let(:reblog) { Fabricate(:status, reblog: nil) } - let(:status) { Fabricate(:status, reblog: reblog) } - - it 'invalidates if the reblogged status is already a favourite' do - described_class.create!(account: account, status: reblog) - expect(described_class.new(account: account, status: status).valid?).to be false - end - - it 'replaces status with the reblogged one if it is a reblog' do - favourite = described_class.create!(account: account, status: status) - expect(favourite.status).to eq reblog - end - end - - context 'when status is not a reblog' do - let(:status) { Fabricate(:status, reblog: nil) } - - it 'saves with the specified status' do - favourite = described_class.create!(account: account, status: status) - expect(favourite.status).to eq status - end - end -end diff --git a/spec/models/follow_request_spec.rb b/spec/models/follow_request_spec.rb deleted file mode 100644 index 01faec0e7..000000000 --- a/spec/models/follow_request_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe FollowRequest do - describe '#authorize!' do - let!(:follow_request) { Fabricate(:follow_request, account: account, target_account: target_account) } - let(:account) { Fabricate(:account) } - let(:target_account) { Fabricate(:account) } - - context 'when the to-be-followed person has been added to a list' do - let!(:list) { Fabricate(:list, account: account) } - - before do - list.accounts << target_account - end - - it 'updates the ListAccount' do - expect { follow_request.authorize! }.to change { [list.list_accounts.first.follow_request_id, list.list_accounts.first.follow_id] }.from([follow_request.id, nil]).to([nil, anything]) - end - end - - it 'calls Account#follow!, MergeWorker.perform_async, and #destroy!' do - expect(account).to receive(:follow!).with(target_account, reblogs: true, notify: false, uri: follow_request.uri, languages: nil, bypass_limit: true) do - account.active_relationships.create!(target_account: target_account) - end - expect(MergeWorker).to receive(:perform_async).with(target_account.id, account.id) - expect(follow_request).to receive(:destroy!) - follow_request.authorize! - end - - it 'generates a Follow' do - follow_request = Fabricate.create(:follow_request) - follow_request.authorize! - target = follow_request.target_account - expect(follow_request.account.following?(target)).to be true - end - - it 'correctly passes show_reblogs when true' do - follow_request = Fabricate.create(:follow_request, show_reblogs: true) - follow_request.authorize! - target = follow_request.target_account - expect(follow_request.account.muting_reblogs?(target)).to be false - end - - it 'correctly passes show_reblogs when false' do - follow_request = Fabricate.create(:follow_request, show_reblogs: false) - follow_request.authorize! - target = follow_request.target_account - expect(follow_request.account.muting_reblogs?(target)).to be true - end - end - - describe '#reject!' do - let!(:follow_request) { Fabricate(:follow_request, account: account, target_account: target_account) } - let(:account) { Fabricate(:account) } - let(:target_account) { Fabricate(:account) } - - context 'when the to-be-followed person has been added to a list' do - let!(:list) { Fabricate(:list, account: account) } - - before do - list.accounts << target_account - end - - it 'deletes the ListAccount record' do - expect { follow_request.reject! }.to change { list.accounts.count }.from(1).to(0) - end - end - end -end diff --git a/spec/models/follow_spec.rb b/spec/models/follow_spec.rb deleted file mode 100644 index c7743183c..000000000 --- a/spec/models/follow_spec.rb +++ /dev/null @@ -1,67 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Follow do - let(:alice) { Fabricate(:account, username: 'alice') } - let(:bob) { Fabricate(:account, username: 'bob') } - - describe 'validations' do - subject { described_class.new(account: alice, target_account: bob, rate_limit: true) } - - it 'is invalid without an account' do - follow = Fabricate.build(:follow, account: nil) - follow.valid? - expect(follow).to model_have_error_on_field(:account) - end - - it 'is invalid without a target_account' do - follow = Fabricate.build(:follow, target_account: nil) - follow.valid? - expect(follow).to model_have_error_on_field(:target_account) - end - - it 'is invalid if account already follows too many people' do - alice.update(following_count: FollowLimitValidator::LIMIT) - - expect(subject).to_not be_valid - expect(subject).to model_have_error_on_field(:base) - end - - it 'is valid if account is only on the brink of following too many people' do - alice.update(following_count: FollowLimitValidator::LIMIT - 1) - - expect(subject).to be_valid - expect(subject).to_not model_have_error_on_field(:base) - end - end - - describe 'recent' do - it 'sorts so that more recent follows comes earlier' do - follow0 = described_class.create!(account: alice, target_account: bob) - follow1 = described_class.create!(account: bob, target_account: alice) - - a = described_class.recent.to_a - - expect(a.size).to eq 2 - expect(a[0]).to eq follow1 - expect(a[1]).to eq follow0 - end - end - - describe 'revoke_request!' do - let(:follow) { Fabricate(:follow, account: account, target_account: target_account) } - let(:account) { Fabricate(:account) } - let(:target_account) { Fabricate(:account) } - - it 'revokes the follow relation' do - follow.revoke_request! - expect(account.following?(target_account)).to be false - end - - it 'creates a follow request' do - follow.revoke_request! - expect(account.requested?(target_account)).to be true - end - end -end diff --git a/spec/models/form/account_batch_spec.rb b/spec/models/form/account_batch_spec.rb deleted file mode 100644 index fd8e90901..000000000 --- a/spec/models/form/account_batch_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Form::AccountBatch do - let(:account_batch) { described_class.new } - - describe '#save' do - subject { account_batch.save } - - let(:account) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:account_ids) { [] } - let(:query) { Account.none } - - before do - account_batch.assign_attributes( - action: action, - current_account: account, - account_ids: account_ids, - query: query, - select_all_matching: select_all_matching - ) - end - - context 'when action is "suspend"' do - let(:action) { 'suspend' } - - let(:target_account) { Fabricate(:account) } - let(:target_account2) { Fabricate(:account) } - - before do - Fabricate(:report, target_account: target_account) - Fabricate(:report, target_account: target_account2) - end - - context 'when accounts are passed as account_ids' do - let(:select_all_matching) { '0' } - let(:account_ids) { [target_account.id, target_account2.id] } - - it 'suspends the expected users' do - expect { subject }.to change { [target_account.reload.suspended?, target_account2.reload.suspended?] }.from([false, false]).to([true, true]) - end - - it 'closes open reports targeting the suspended users' do - expect { subject }.to change { Report.unresolved.where(target_account: [target_account, target_account2]).count }.from(2).to(0) - end - end - - context 'when accounts are passed as a query' do - let(:select_all_matching) { '1' } - let(:query) { Account.where(id: [target_account.id, target_account2.id]) } - - it 'suspends the expected users' do - expect { subject }.to change { [target_account.reload.suspended?, target_account2.reload.suspended?] }.from([false, false]).to([true, true]) - end - - it 'closes open reports targeting the suspended users' do - expect { subject }.to change { Report.unresolved.where(target_account: [target_account, target_account2]).count }.from(2).to(0) - end - end - end - end -end diff --git a/spec/models/form/admin_settings_spec.rb b/spec/models/form/admin_settings_spec.rb deleted file mode 100644 index 0dc2d881a..000000000 --- a/spec/models/form/admin_settings_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Form::AdminSettings do - describe 'validations' do - describe 'site_contact_username' do - context 'with no accounts' do - it 'is not valid' do - setting = described_class.new(site_contact_username: 'Test') - setting.valid? - - expect(setting).to model_have_error_on_field(:site_contact_username) - end - end - - context 'with an account' do - before { Fabricate(:account, username: 'Glorp') } - - it 'is not valid when account doesnt match' do - setting = described_class.new(site_contact_username: 'Test') - setting.valid? - - expect(setting).to model_have_error_on_field(:site_contact_username) - end - - it 'is valid when account matches' do - setting = described_class.new(site_contact_username: 'Glorp') - setting.valid? - - expect(setting).to_not model_have_error_on_field(:site_contact_username) - end - end - end - end -end diff --git a/spec/models/form/import_spec.rb b/spec/models/form/import_spec.rb deleted file mode 100644 index 2b70e396b..000000000 --- a/spec/models/form/import_spec.rb +++ /dev/null @@ -1,318 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Form::Import do - subject { described_class.new(current_account: account, type: import_type, mode: import_mode, data: data) } - - let(:account) { Fabricate(:account) } - let(:data) { fixture_file_upload(import_file) } - let(:import_mode) { 'merge' } - - describe 'validations' do - shared_examples 'incompatible import type' do |type, file| - let(:import_file) { file } - let(:import_type) { type } - - it 'has errors' do - subject.validate - expect(subject.errors[:data]).to include(I18n.t('imports.errors.incompatible_type')) - end - end - - shared_examples 'too many CSV rows' do |type, file, allowed_rows| - let(:import_file) { file } - let(:import_type) { type } - - before do - stub_const 'Form::Import::ROWS_PROCESSING_LIMIT', allowed_rows - end - - it 'has errors' do - subject.validate - expect(subject.errors[:data]).to include(I18n.t('imports.errors.over_rows_processing_limit', count: Form::Import::ROWS_PROCESSING_LIMIT)) - end - end - - shared_examples 'valid import' do |type, file| - let(:import_file) { file } - let(:import_type) { type } - - it 'passes validation' do - expect(subject).to be_valid - end - end - - context 'when the file too large' do - let(:import_type) { 'following' } - let(:import_file) { 'imports.txt' } - - before do - stub_const 'Form::Import::FILE_SIZE_LIMIT', 5 - end - - it 'has errors' do - subject.validate - expect(subject.errors[:data]).to include(I18n.t('imports.errors.too_large')) - end - end - - context 'when the CSV file is malformed CSV' do - let(:import_type) { 'following' } - let(:import_file) { 'boop.ogg' } - - it 'has errors' do - # NOTE: not testing more specific error because we don't know the string to match - expect(subject).to model_have_error_on_field(:data) - end - end - - context 'when importing more follows than allowed' do - let(:import_type) { 'following' } - let(:import_file) { 'imports.txt' } - - before do - allow(FollowLimitValidator).to receive(:limit_for_account).with(account).and_return(1) - end - - it 'has errors' do - subject.validate - expect(subject.errors[:data]).to include(I18n.t('users.follow_limit_reached', limit: 1)) - end - end - - it_behaves_like 'too many CSV rows', 'following', 'imports.txt', 1 - it_behaves_like 'too many CSV rows', 'blocking', 'imports.txt', 1 - it_behaves_like 'too many CSV rows', 'muting', 'imports.txt', 1 - it_behaves_like 'too many CSV rows', 'domain_blocking', 'domain_blocks.csv', 2 - it_behaves_like 'too many CSV rows', 'bookmarks', 'bookmark-imports.txt', 3 - it_behaves_like 'too many CSV rows', 'lists', 'lists.csv', 2 - - # Importing list of addresses with no headers into various types - it_behaves_like 'valid import', 'following', 'imports.txt' - it_behaves_like 'valid import', 'blocking', 'imports.txt' - it_behaves_like 'valid import', 'muting', 'imports.txt' - - # Importing domain blocks with headers into expected type - it_behaves_like 'valid import', 'domain_blocking', 'domain_blocks.csv' - - # Importing bookmarks list with no headers into expected type - it_behaves_like 'valid import', 'bookmarks', 'bookmark-imports.txt' - - # Importing lists with no headers into expected type - it_behaves_like 'valid import', 'lists', 'lists.csv' - - # Importing followed accounts with headers into various compatible types - it_behaves_like 'valid import', 'following', 'following_accounts.csv' - it_behaves_like 'valid import', 'blocking', 'following_accounts.csv' - it_behaves_like 'valid import', 'muting', 'following_accounts.csv' - - # Importing domain blocks with headers into incompatible types - it_behaves_like 'incompatible import type', 'following', 'domain_blocks.csv' - it_behaves_like 'incompatible import type', 'blocking', 'domain_blocks.csv' - it_behaves_like 'incompatible import type', 'muting', 'domain_blocks.csv' - it_behaves_like 'incompatible import type', 'bookmarks', 'domain_blocks.csv' - - # Importing followed accounts with headers into incompatible types - it_behaves_like 'incompatible import type', 'domain_blocking', 'following_accounts.csv' - it_behaves_like 'incompatible import type', 'bookmarks', 'following_accounts.csv' - end - - describe '#guessed_type' do - shared_examples 'with enough information' do |type, file, original_filename, expected_guess| - let(:import_file) { file } - let(:import_type) { type } - - before do - allow(data).to receive(:original_filename).and_return(original_filename) - end - - it 'guesses the expected type' do - expect(subject.guessed_type).to eq expected_guess - end - end - - context 'when the headers are enough to disambiguate' do - it_behaves_like 'with enough information', 'following', 'following_accounts.csv', 'import.csv', :following - it_behaves_like 'with enough information', 'blocking', 'following_accounts.csv', 'import.csv', :following - it_behaves_like 'with enough information', 'muting', 'following_accounts.csv', 'import.csv', :following - - it_behaves_like 'with enough information', 'following', 'muted_accounts.csv', 'imports.csv', :muting - it_behaves_like 'with enough information', 'blocking', 'muted_accounts.csv', 'imports.csv', :muting - it_behaves_like 'with enough information', 'muting', 'muted_accounts.csv', 'imports.csv', :muting - end - - context 'when the file name is enough to disambiguate' do - it_behaves_like 'with enough information', 'following', 'imports.txt', 'following_accounts.csv', :following - it_behaves_like 'with enough information', 'blocking', 'imports.txt', 'following_accounts.csv', :following - it_behaves_like 'with enough information', 'muting', 'imports.txt', 'following_accounts.csv', :following - - it_behaves_like 'with enough information', 'following', 'imports.txt', 'follows.csv', :following - it_behaves_like 'with enough information', 'blocking', 'imports.txt', 'follows.csv', :following - it_behaves_like 'with enough information', 'muting', 'imports.txt', 'follows.csv', :following - - it_behaves_like 'with enough information', 'following', 'imports.txt', 'blocked_accounts.csv', :blocking - it_behaves_like 'with enough information', 'blocking', 'imports.txt', 'blocked_accounts.csv', :blocking - it_behaves_like 'with enough information', 'muting', 'imports.txt', 'blocked_accounts.csv', :blocking - - it_behaves_like 'with enough information', 'following', 'imports.txt', 'blocks.csv', :blocking - it_behaves_like 'with enough information', 'blocking', 'imports.txt', 'blocks.csv', :blocking - it_behaves_like 'with enough information', 'muting', 'imports.txt', 'blocks.csv', :blocking - - it_behaves_like 'with enough information', 'following', 'imports.txt', 'muted_accounts.csv', :muting - it_behaves_like 'with enough information', 'blocking', 'imports.txt', 'muted_accounts.csv', :muting - it_behaves_like 'with enough information', 'muting', 'imports.txt', 'muted_accounts.csv', :muting - - it_behaves_like 'with enough information', 'following', 'imports.txt', 'mutes.csv', :muting - it_behaves_like 'with enough information', 'blocking', 'imports.txt', 'mutes.csv', :muting - it_behaves_like 'with enough information', 'muting', 'imports.txt', 'mutes.csv', :muting - end - end - - describe '#likely_mismatched?' do - shared_examples 'with matching types' do |type, file, original_filename = nil| - let(:import_file) { file } - let(:import_type) { type } - - before do - allow(data).to receive(:original_filename).and_return(original_filename) if original_filename.present? - end - - it 'returns false' do - expect(subject.likely_mismatched?).to be false - end - end - - shared_examples 'with mismatching types' do |type, file, original_filename = nil| - let(:import_file) { file } - let(:import_type) { type } - - before do - allow(data).to receive(:original_filename).and_return(original_filename) if original_filename.present? - end - - it 'returns true' do - expect(subject.likely_mismatched?).to be true - end - end - - it_behaves_like 'with matching types', 'following', 'following_accounts.csv' - it_behaves_like 'with matching types', 'following', 'following_accounts.csv', 'imports.txt' - it_behaves_like 'with matching types', 'following', 'imports.txt' - it_behaves_like 'with matching types', 'blocking', 'imports.txt', 'blocks.csv' - it_behaves_like 'with matching types', 'blocking', 'imports.txt' - it_behaves_like 'with matching types', 'muting', 'muted_accounts.csv' - it_behaves_like 'with matching types', 'muting', 'muted_accounts.csv', 'imports.txt' - it_behaves_like 'with matching types', 'muting', 'imports.txt' - it_behaves_like 'with matching types', 'domain_blocking', 'domain_blocks.csv' - it_behaves_like 'with matching types', 'domain_blocking', 'domain_blocks.csv', 'imports.txt' - it_behaves_like 'with matching types', 'bookmarks', 'bookmark-imports.txt' - it_behaves_like 'with matching types', 'bookmarks', 'bookmark-imports.txt', 'imports.txt' - - it_behaves_like 'with mismatching types', 'following', 'imports.txt', 'blocks.csv' - it_behaves_like 'with mismatching types', 'following', 'imports.txt', 'blocked_accounts.csv' - it_behaves_like 'with mismatching types', 'following', 'imports.txt', 'mutes.csv' - it_behaves_like 'with mismatching types', 'following', 'imports.txt', 'muted_accounts.csv' - it_behaves_like 'with mismatching types', 'following', 'muted_accounts.csv' - it_behaves_like 'with mismatching types', 'following', 'muted_accounts.csv', 'imports.txt' - it_behaves_like 'with mismatching types', 'blocking', 'following_accounts.csv' - it_behaves_like 'with mismatching types', 'blocking', 'following_accounts.csv', 'imports.txt' - it_behaves_like 'with mismatching types', 'blocking', 'muted_accounts.csv' - it_behaves_like 'with mismatching types', 'blocking', 'muted_accounts.csv', 'imports.txt' - it_behaves_like 'with mismatching types', 'blocking', 'imports.txt', 'follows.csv' - it_behaves_like 'with mismatching types', 'blocking', 'imports.txt', 'following_accounts.csv' - it_behaves_like 'with mismatching types', 'blocking', 'imports.txt', 'mutes.csv' - it_behaves_like 'with mismatching types', 'blocking', 'imports.txt', 'muted_accounts.csv' - it_behaves_like 'with mismatching types', 'muting', 'following_accounts.csv' - it_behaves_like 'with mismatching types', 'muting', 'following_accounts.csv', 'imports.txt' - it_behaves_like 'with mismatching types', 'muting', 'imports.txt', 'follows.csv' - it_behaves_like 'with mismatching types', 'muting', 'imports.txt', 'following_accounts.csv' - it_behaves_like 'with mismatching types', 'muting', 'imports.txt', 'blocks.csv' - it_behaves_like 'with mismatching types', 'muting', 'imports.txt', 'blocked_accounts.csv' - end - - describe 'save' do - shared_examples 'on successful import' do |type, mode, file, expected_rows| - let(:import_type) { type } - let(:import_file) { file } - let(:import_mode) { mode } - - before do - subject.save - end - - it 'creates the expected rows' do - expect(account.bulk_imports.first.rows.pluck(:data)).to match_array(expected_rows) - end - - context 'with a BulkImport' do - let(:bulk_import) { account.bulk_imports.first } - - it 'creates a non-nil bulk import' do - expect(bulk_import).to_not be_nil - end - - it 'matches the subjects type' do - expect(bulk_import.type.to_sym).to eq subject.type.to_sym - end - - it 'matches the subjects original filename' do - expect(bulk_import.original_filename).to eq subject.data.original_filename - end - - it 'matches the subjects likely_mismatched? value' do - expect(bulk_import.likely_mismatched?).to eq subject.likely_mismatched? - end - - it 'matches the subject overwrite value' do - expect(bulk_import.overwrite?).to eq !!subject.overwrite # rubocop:disable Style/DoubleNegation - end - - it 'has zero processed items' do - expect(bulk_import.processed_items).to eq 0 - end - - it 'has zero imported items' do - expect(bulk_import.imported_items).to eq 0 - end - - it 'has a correct total_items value' do - expect(bulk_import.total_items).to eq bulk_import.rows.count - end - - it 'defaults to unconfirmed true' do - expect(bulk_import.unconfirmed?).to be true - end - end - end - - it_behaves_like 'on successful import', 'following', 'merge', 'imports.txt', (%w(user@example.com user@test.com).map { |acct| { 'acct' => acct } }) - it_behaves_like 'on successful import', 'following', 'overwrite', 'imports.txt', (%w(user@example.com user@test.com).map { |acct| { 'acct' => acct } }) - it_behaves_like 'on successful import', 'blocking', 'merge', 'imports.txt', (%w(user@example.com user@test.com).map { |acct| { 'acct' => acct } }) - it_behaves_like 'on successful import', 'blocking', 'overwrite', 'imports.txt', (%w(user@example.com user@test.com).map { |acct| { 'acct' => acct } }) - it_behaves_like 'on successful import', 'muting', 'merge', 'imports.txt', (%w(user@example.com user@test.com).map { |acct| { 'acct' => acct } }) - it_behaves_like 'on successful import', 'domain_blocking', 'merge', 'domain_blocks.csv', (%w(bad.domain worse.domain reject.media).map { |domain| { 'domain' => domain } }) - it_behaves_like 'on successful import', 'bookmarks', 'merge', 'bookmark-imports.txt', (%w(https://example.com/statuses/1312 https://local.com/users/foo/statuses/42 https://unknown-remote.com/users/bar/statuses/1 https://example.com/statuses/direct).map { |uri| { 'uri' => uri } }) - - it_behaves_like 'on successful import', 'following', 'merge', 'following_accounts.csv', [ - { 'acct' => 'user@example.com', 'show_reblogs' => true, 'notify' => false, 'languages' => nil }, - { 'acct' => 'user@test.com', 'show_reblogs' => true, 'notify' => true, 'languages' => ['en', 'fr'] }, - ] - - it_behaves_like 'on successful import', 'muting', 'merge', 'muted_accounts.csv', [ - { 'acct' => 'user@example.com', 'hide_notifications' => true }, - { 'acct' => 'user@test.com', 'hide_notifications' => false }, - ] - - it_behaves_like 'on successful import', 'lists', 'merge', 'lists.csv', [ - { 'acct' => 'gargron@example.com', 'list_name' => 'Mastodon project' }, - { 'acct' => 'mastodon@example.com', 'list_name' => 'Mastodon project' }, - { 'acct' => 'foo@example.com', 'list_name' => 'test' }, - ] - - # Based on the bug report 20571 where UTF-8 encoded domains were rejecting import of their users - # - # https://github.com/mastodon/mastodon/issues/20571 - it_behaves_like 'on successful import', 'following', 'merge', 'utf8-followers.txt', [{ 'acct' => 'nare@թութ.հայ' }] - end -end diff --git a/spec/models/form/status_filter_batch_action_spec.rb b/spec/models/form/status_filter_batch_action_spec.rb deleted file mode 100644 index f06a11cc8..000000000 --- a/spec/models/form/status_filter_batch_action_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Form::StatusFilterBatchAction do - describe '#save!' do - it 'does nothing if status_filter_ids is empty' do - batch_action = described_class.new(status_filter_ids: []) - - expect(batch_action.save!).to be_nil - end - end -end diff --git a/spec/models/home_feed_spec.rb b/spec/models/home_feed_spec.rb deleted file mode 100644 index bd649d826..000000000 --- a/spec/models/home_feed_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe HomeFeed do - subject { described_class.new(account) } - - let(:account) { Fabricate(:account) } - - describe '#get' do - before do - Fabricate(:status, account: account, id: 1) - Fabricate(:status, account: account, id: 2) - Fabricate(:status, account: account, id: 3) - Fabricate(:status, account: account, id: 10) - end - - context 'when feed is generated' do - before do - redis.zadd( - FeedManager.instance.key(:home, account.id), - [[4, 4], [3, 3], [2, 2], [1, 1]] - ) - end - - it 'gets statuses with ids in the range from redis' do - results = subject.get(3) - - expect(results.map(&:id)).to eq [3, 2] - expect(results.first.attributes.keys).to eq %w(id updated_at) - end - end - - context 'when feed is being generated' do - before do - redis.set("account:#{account.id}:regeneration", true) - end - - it 'returns nothing' do - results = subject.get(3) - - expect(results.map(&:id)).to eq [] - end - end - end -end diff --git a/spec/models/identity_spec.rb b/spec/models/identity_spec.rb deleted file mode 100644 index 2fca1e1c1..000000000 --- a/spec/models/identity_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Identity do - describe '.find_for_oauth' do - let(:auth) { Fabricate(:identity, user: Fabricate(:user)) } - - it 'calls .find_or_create_by' do - expect(described_class).to receive(:find_or_create_by).with(uid: auth.uid, provider: auth.provider) - described_class.find_for_oauth(auth) - end - - it 'returns an instance of Identity' do - expect(described_class.find_for_oauth(auth)).to be_instance_of described_class - end - end -end diff --git a/spec/models/import_spec.rb b/spec/models/import_spec.rb deleted file mode 100644 index 3605f0b9b..000000000 --- a/spec/models/import_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Import do - let(:account) { Fabricate(:account) } - let(:type) { 'following' } - let(:data) { attachment_fixture('imports.txt') } - - describe 'validations' do - it 'has a valid parameters' do - import = described_class.create(account: account, type: type, data: data) - expect(import).to be_valid - end - - it 'is invalid without an type' do - import = described_class.create(account: account, data: data) - expect(import).to model_have_error_on_field(:type) - end - - it 'is invalid without a data' do - import = described_class.create(account: account, type: type) - expect(import).to model_have_error_on_field(:data) - end - end -end diff --git a/spec/models/invite_spec.rb b/spec/models/invite_spec.rb deleted file mode 100644 index 4ad589f2c..000000000 --- a/spec/models/invite_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Invite do - describe '#valid_for_use?' do - it 'returns true when there are no limitations' do - invite = Fabricate(:invite, max_uses: nil, expires_at: nil) - expect(invite.valid_for_use?).to be true - end - - it 'returns true when not expired' do - invite = Fabricate(:invite, max_uses: nil, expires_at: 1.hour.from_now) - expect(invite.valid_for_use?).to be true - end - - it 'returns false when expired' do - invite = Fabricate(:invite, max_uses: nil, expires_at: 1.hour.ago) - expect(invite.valid_for_use?).to be false - end - - it 'returns true when uses still available' do - invite = Fabricate(:invite, max_uses: 250, uses: 249, expires_at: nil) - expect(invite.valid_for_use?).to be true - end - - it 'returns false when maximum uses reached' do - invite = Fabricate(:invite, max_uses: 250, uses: 250, expires_at: nil) - expect(invite.valid_for_use?).to be false - end - - it 'returns false when invite creator has been disabled' do - invite = Fabricate(:invite, max_uses: nil, expires_at: nil) - invite.user.account.suspend! - expect(invite.valid_for_use?).to be false - end - end -end diff --git a/spec/models/ip_block_spec.rb b/spec/models/ip_block_spec.rb deleted file mode 100644 index ed5882667..000000000 --- a/spec/models/ip_block_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe IpBlock do - describe 'to_log_human_identifier' do - let(:ip_block) { described_class.new(ip: '192.168.0.1') } - - it 'combines the IP and prefix into a string' do - result = ip_block.to_log_human_identifier - - expect(result).to eq('192.168.0.1/32') - end - end -end diff --git a/spec/models/marker_spec.rb b/spec/models/marker_spec.rb deleted file mode 100644 index 51dd58438..000000000 --- a/spec/models/marker_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Marker do - describe 'validations' do - describe 'timeline' do - it 'must be included in valid list' do - record = described_class.new(timeline: 'not real timeline') - - expect(record).to_not be_valid - expect(record).to model_have_error_on_field(:timeline) - end - end - end -end diff --git a/spec/models/media_attachment_spec.rb b/spec/models/media_attachment_spec.rb deleted file mode 100644 index 6a82c8135..000000000 --- a/spec/models/media_attachment_spec.rb +++ /dev/null @@ -1,264 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe MediaAttachment, paperclip_processing: true do - describe 'local?' do - subject { media_attachment.local? } - - let(:media_attachment) { described_class.new(remote_url: remote_url) } - - context 'when remote_url is blank' do - let(:remote_url) { '' } - - it 'returns true' do - expect(subject).to be true - end - end - - context 'when remote_url is present' do - let(:remote_url) { 'remote_url' } - - it 'returns false' do - expect(subject).to be false - end - end - end - - describe 'needs_redownload?' do - subject { media_attachment.needs_redownload? } - - let(:media_attachment) { described_class.new(remote_url: remote_url, file: file) } - - context 'when file is blank' do - let(:file) { nil } - - context 'when remote_url is present' do - let(:remote_url) { 'remote_url' } - - it 'returns true' do - expect(subject).to be true - end - end - end - - context 'when file is present' do - let(:file) { attachment_fixture('avatar.gif') } - - context 'when remote_url is blank' do - let(:remote_url) { '' } - - it 'returns false' do - expect(subject).to be false - end - end - - context 'when remote_url is present' do - let(:remote_url) { 'remote_url' } - - it 'returns true' do - expect(subject).to be false - end - end - end - end - - describe '#to_param' do - let(:media_attachment) { Fabricate.build(:media_attachment, shortcode: shortcode, id: id) } - - context 'when media attachment has a shortcode' do - let(:shortcode) { 'foo' } - let(:id) { 123 } - - it 'returns shortcode' do - expect(media_attachment.to_param).to eq shortcode - end - end - - context 'when media attachment does not have a shortcode' do - let(:shortcode) { nil } - let(:id) { 123 } - - it 'returns string representation of id' do - expect(media_attachment.to_param).to eq id.to_s - end - end - end - - shared_examples 'static 600x400 image' do |content_type, extension| - after do - media.destroy - end - - it 'saves media attachment with correct file metadata' do - expect(media.persisted?).to be true - expect(media.file).to_not be_nil - - # completes processing - expect(media.processing_complete?).to be true - - # sets type - expect(media.type).to eq 'image' - - # sets content type - expect(media.file_content_type).to eq content_type - - # sets file extension - expect(media.file_file_name).to end_with extension - - # Rack::Mime (used by PublicFileServerMiddleware) recognizes file extension - expect(Rack::Mime.mime_type(extension, nil)).to eq content_type - end - - it 'saves media attachment with correct size metadata' do - # strips original file name - expect(media.file_file_name).to_not start_with '600x400' - - # sets meta for original - expect(media.file.meta['original']['width']).to eq 600 - expect(media.file.meta['original']['height']).to eq 400 - expect(media.file.meta['original']['aspect']).to eq 1.5 - - # sets meta for thumbnail - expect(media.file.meta['small']['width']).to eq 588 - expect(media.file.meta['small']['height']).to eq 392 - expect(media.file.meta['small']['aspect']).to eq 1.5 - end - end - - describe 'jpeg' do - let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400.jpeg')) } - - it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg' - end - - describe 'png' do - let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400.png')) } - - it_behaves_like 'static 600x400 image', 'image/png', '.png' - end - - describe 'webp' do - let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400.webp')) } - - it_behaves_like 'static 600x400 image', 'image/webp', '.webp' - end - - describe 'avif' do - let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400.avif')) } - - it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg' - end - - describe 'heic' do - let(:media) { Fabricate(:media_attachment, file: attachment_fixture('600x400.heic')) } - - it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg' - end - - describe 'base64-encoded image' do - let(:base64_attachment) { "data:image/jpeg;base64,#{Base64.encode64(attachment_fixture('600x400.jpeg').read)}" } - let(:media) { Fabricate(:media_attachment, file: base64_attachment) } - - it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg' - end - - describe 'animated gif' do - let(:media) { Fabricate(:media_attachment, file: attachment_fixture('avatar.gif')) } - - it 'sets correct file metadata' do - expect(media.type).to eq 'gifv' - expect(media.file_content_type).to eq 'video/mp4' - expect(media.file.meta['original']['width']).to eq 128 - expect(media.file.meta['original']['height']).to eq 128 - end - end - - describe 'static gif' do - fixtures = [ - { filename: 'attachment.gif', width: 600, height: 400, aspect: 1.5 }, - { filename: 'mini-static.gif', width: 32, height: 32, aspect: 1.0 }, - ] - - fixtures.each do |fixture| - context fixture[:filename] do - let(:media) { Fabricate(:media_attachment, file: attachment_fixture(fixture[:filename])) } - - it 'sets correct file metadata' do - expect(media.type).to eq 'image' - expect(media.file_content_type).to eq 'image/gif' - expect(media.file.meta['original']['width']).to eq fixture[:width] - expect(media.file.meta['original']['height']).to eq fixture[:height] - expect(media.file.meta['original']['aspect']).to eq fixture[:aspect] - end - end - end - end - - describe 'ogg with cover art' do - let(:media) { Fabricate(:media_attachment, file: attachment_fixture('boop.ogg')) } - - it 'sets correct file metadata' do - expect(media.type).to eq 'audio' - expect(media.file.meta['original']['duration']).to be_within(0.05).of(0.235102) - expect(media.thumbnail.present?).to be true - expect(media.file.meta['colors']['background']).to eq '#3088d4' - expect(media.file_file_name).to_not eq 'boop.ogg' - end - end - - describe 'mp3 with large cover art' do - let(:media) { Fabricate(:media_attachment, file: attachment_fixture('boop.mp3')) } - - it 'detects it as an audio file' do - expect(media.type).to eq 'audio' - end - - it 'sets meta for the duration' do - expect(media.file.meta['original']['duration']).to be_within(0.05).of(0.235102) - end - - it 'extracts thumbnail' do - expect(media.thumbnail.present?).to be true - end - - it 'gives the file a random name' do - expect(media.file_file_name).to_not eq 'boop.mp3' - end - end - - it 'is invalid without file' do - media = described_class.new - - expect(media.valid?).to be false - expect(media).to model_have_error_on_field(:file) - end - - describe 'size limit validation' do - it 'rejects video files that are too large' do - stub_const 'MediaAttachment::IMAGE_LIMIT', 100.megabytes - stub_const 'MediaAttachment::VIDEO_LIMIT', 1.kilobyte - expect { Fabricate(:media_attachment, file: attachment_fixture('attachment.webm')) }.to raise_error(ActiveRecord::RecordInvalid) - end - - it 'accepts video files that are small enough' do - stub_const 'MediaAttachment::IMAGE_LIMIT', 1.kilobyte - stub_const 'MediaAttachment::VIDEO_LIMIT', 100.megabytes - media = Fabricate(:media_attachment, file: attachment_fixture('attachment.webm')) - expect(media.valid?).to be true - end - - it 'rejects image files that are too large' do - stub_const 'MediaAttachment::IMAGE_LIMIT', 1.kilobyte - stub_const 'MediaAttachment::VIDEO_LIMIT', 100.megabytes - expect { Fabricate(:media_attachment, file: attachment_fixture('attachment.jpg')) }.to raise_error(ActiveRecord::RecordInvalid) - end - - it 'accepts image files that are small enough' do - stub_const 'MediaAttachment::IMAGE_LIMIT', 100.megabytes - stub_const 'MediaAttachment::VIDEO_LIMIT', 1.kilobyte - media = Fabricate(:media_attachment, file: attachment_fixture('attachment.jpg')) - expect(media.valid?).to be true - end - end -end diff --git a/spec/models/mention_spec.rb b/spec/models/mention_spec.rb deleted file mode 100644 index b241049a5..000000000 --- a/spec/models/mention_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Mention do - describe 'validations' do - it 'is invalid without an account' do - mention = Fabricate.build(:mention, account: nil) - mention.valid? - expect(mention).to model_have_error_on_field(:account) - end - - it 'is invalid without a status' do - mention = Fabricate.build(:mention, status: nil) - mention.valid? - expect(mention).to model_have_error_on_field(:status) - end - end -end diff --git a/spec/models/notification_spec.rb b/spec/models/notification_spec.rb deleted file mode 100644 index d6e228202..000000000 --- a/spec/models/notification_spec.rb +++ /dev/null @@ -1,186 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Notification do - describe '#target_status' do - let(:notification) { Fabricate(:notification, activity: activity) } - let(:status) { Fabricate(:status) } - let(:reblog) { Fabricate(:status, reblog: status) } - let(:favourite) { Fabricate(:favourite, status: status) } - let(:mention) { Fabricate(:mention, status: status) } - - context 'when Activity is reblog' do - let(:activity) { reblog } - - it 'returns status' do - expect(notification.target_status).to eq status - end - end - - context 'when Activity is favourite' do - let(:type) { :favourite } - let(:activity) { favourite } - - it 'returns status' do - expect(notification.target_status).to eq status - end - end - - context 'when Activity is mention' do - let(:activity) { mention } - - it 'returns status' do - expect(notification.target_status).to eq status - end - end - end - - describe '#type' do - it 'returns :reblog for a Status' do - notification = described_class.new(activity: Status.new) - expect(notification.type).to eq :reblog - end - - it 'returns :mention for a Mention' do - notification = described_class.new(activity: Mention.new) - expect(notification.type).to eq :mention - end - - it 'returns :favourite for a Favourite' do - notification = described_class.new(activity: Favourite.new) - expect(notification.type).to eq :favourite - end - - it 'returns :follow for a Follow' do - notification = described_class.new(activity: Follow.new) - expect(notification.type).to eq :follow - end - end - - describe '.preload_cache_collection_target_statuses' do - subject do - described_class.preload_cache_collection_target_statuses(notifications) do |target_statuses| - # preload account for testing instead of using cache_collection - Status.preload(:account).where(id: target_statuses.map(&:id)) - end - end - - context 'when notifications are empty' do - let(:notifications) { [] } - - it 'returns []' do - expect(subject).to eq [] - end - end - - context 'when notifications are present' do - before do - notifications.each(&:reload) - end - - let(:mention) { Fabricate(:mention) } - let(:status) { Fabricate(:status) } - let(:reblog) { Fabricate(:status, reblog: Fabricate(:status)) } - let(:follow) { Fabricate(:follow) } - let(:follow_request) { Fabricate(:follow_request) } - let(:favourite) { Fabricate(:favourite) } - let(:poll) { Fabricate(:poll) } - - let(:notifications) do - [ - Fabricate(:notification, type: :mention, activity: mention), - Fabricate(:notification, type: :status, activity: status), - Fabricate(:notification, type: :reblog, activity: reblog), - Fabricate(:notification, type: :follow, activity: follow), - Fabricate(:notification, type: :follow_request, activity: follow_request), - Fabricate(:notification, type: :favourite, activity: favourite), - Fabricate(:notification, type: :poll, activity: poll), - ] - end - - context 'with a preloaded target status' do - it 'preloads mention' do - expect(subject[0].type).to eq :mention - expect(subject[0].association(:mention)).to be_loaded - expect(subject[0].mention.association(:status)).to be_loaded - end - - it 'preloads status' do - expect(subject[1].type).to eq :status - expect(subject[1].association(:status)).to be_loaded - end - - it 'preloads reblog' do - expect(subject[2].type).to eq :reblog - expect(subject[2].association(:status)).to be_loaded - expect(subject[2].status.association(:reblog)).to be_loaded - end - - it 'preloads follow as nil' do - expect(subject[3].type).to eq :follow - expect(subject[3].target_status).to be_nil - end - - it 'preloads follow_request as nill' do - expect(subject[4].type).to eq :follow_request - expect(subject[4].target_status).to be_nil - end - - it 'preloads favourite' do - expect(subject[5].type).to eq :favourite - expect(subject[5].association(:favourite)).to be_loaded - expect(subject[5].favourite.association(:status)).to be_loaded - end - - it 'preloads poll' do - expect(subject[6].type).to eq :poll - expect(subject[6].association(:poll)).to be_loaded - expect(subject[6].poll.association(:status)).to be_loaded - end - end - - context 'with a cached status' do - it 'replaces mention' do - expect(subject[0].type).to eq :mention - expect(subject[0].target_status.association(:account)).to be_loaded - expect(subject[0].target_status).to eq mention.status - end - - it 'replaces status' do - expect(subject[1].type).to eq :status - expect(subject[1].target_status.association(:account)).to be_loaded - expect(subject[1].target_status).to eq status - end - - it 'replaces reblog' do - expect(subject[2].type).to eq :reblog - expect(subject[2].target_status.association(:account)).to be_loaded - expect(subject[2].target_status).to eq reblog.reblog - end - - it 'replaces follow' do - expect(subject[3].type).to eq :follow - expect(subject[3].target_status).to be_nil - end - - it 'replaces follow_request' do - expect(subject[4].type).to eq :follow_request - expect(subject[4].target_status).to be_nil - end - - it 'replaces favourite' do - expect(subject[5].type).to eq :favourite - expect(subject[5].target_status.association(:account)).to be_loaded - expect(subject[5].target_status).to eq favourite.status - end - - it 'replaces poll' do - expect(subject[6].type).to eq :poll - expect(subject[6].target_status.association(:account)).to be_loaded - expect(subject[6].target_status).to eq poll.status - end - end - end - end -end diff --git a/spec/models/one_time_key_spec.rb b/spec/models/one_time_key_spec.rb deleted file mode 100644 index 6ff7ffc5c..000000000 --- a/spec/models/one_time_key_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe OneTimeKey do - describe 'validations' do - context 'with an invalid signature' do - let(:one_time_key) { Fabricate.build(:one_time_key, signature: 'wrong!') } - - it 'is invalid' do - expect(one_time_key).to_not be_valid - end - end - - context 'with an invalid key' do - let(:one_time_key) { Fabricate.build(:one_time_key, key: 'wrong!') } - - it 'is invalid' do - expect(one_time_key).to_not be_valid - end - end - end -end diff --git a/spec/models/poll_spec.rb b/spec/models/poll_spec.rb deleted file mode 100644 index 8ae04ca41..000000000 --- a/spec/models/poll_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Poll do - describe 'scopes' do - let(:status) { Fabricate(:status) } - let(:attached_poll) { Fabricate(:poll, status: status) } - let(:not_attached_poll) do - Fabricate(:poll).tap do |poll| - poll.status = nil - poll.save(validate: false) - end - end - - describe 'attached' do - it 'finds the correct records' do - results = described_class.attached - - expect(results).to eq([attached_poll]) - end - end - - describe 'unattached' do - it 'finds the correct records' do - results = described_class.unattached - - expect(results).to eq([not_attached_poll]) - end - end - end -end diff --git a/spec/models/poll_vote_spec.rb b/spec/models/poll_vote_spec.rb deleted file mode 100644 index b017ea527..000000000 --- a/spec/models/poll_vote_spec.rb +++ /dev/null @@ -1,62 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe PollVote do - describe '#object_type' do - let(:poll_vote) { Fabricate.build(:poll_vote) } - - it 'returns :vote' do - expect(poll_vote.object_type).to eq :vote - end - end - - describe 'validations' do - context 'with a vote on an expired poll' do - it 'marks the vote invalid' do - poll = Fabricate.build(:poll, expires_at: 30.days.ago) - - vote = Fabricate.build(:poll_vote, poll: poll) - expect(vote).to_not be_valid - end - end - - context 'with invalid choices' do - it 'marks vote invalid with negative choice' do - poll = Fabricate.build(:poll) - - vote = Fabricate.build(:poll_vote, poll: poll, choice: -100) - expect(vote).to_not be_valid - end - - it 'marks vote invalid with choice in excess of options' do - poll = Fabricate.build(:poll, options: %w(a b c)) - - vote = Fabricate.build(:poll_vote, poll: poll, choice: 10) - expect(vote).to_not be_valid - end - end - - context 'with a poll where multiple is true' do - it 'does not allow a second vote on same choice from same account' do - poll = Fabricate(:poll, multiple: true, options: %w(a b c)) - first_vote = Fabricate(:poll_vote, poll: poll, choice: 1) - expect(first_vote).to be_valid - - second_vote = Fabricate.build(:poll_vote, account: first_vote.account, poll: poll, choice: 1) - expect(second_vote).to_not be_valid - end - end - - context 'with a poll where multiple is false' do - it 'does not allow a second vote from same account' do - poll = Fabricate(:poll, multiple: false, options: %w(a b c)) - first_vote = Fabricate(:poll_vote, poll: poll) - expect(first_vote).to be_valid - - second_vote = Fabricate.build(:poll_vote, account: first_vote.account, poll: poll) - expect(second_vote).to_not be_valid - end - end - end -end diff --git a/spec/models/preview_card_provider_spec.rb b/spec/models/preview_card_provider_spec.rb deleted file mode 100644 index 7425b9394..000000000 --- a/spec/models/preview_card_provider_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe PreviewCardProvider do - describe 'scopes' do - let(:trendable_and_reviewed) { Fabricate(:preview_card_provider, trendable: true, reviewed_at: 5.days.ago) } - let(:not_trendable_and_not_reviewed) { Fabricate(:preview_card_provider, trendable: false, reviewed_at: nil) } - - describe 'trendable' do - it 'returns the relevant records' do - results = described_class.trendable - - expect(results).to eq([trendable_and_reviewed]) - end - end - - describe 'not_trendable' do - it 'returns the relevant records' do - results = described_class.not_trendable - - expect(results).to eq([not_trendable_and_not_reviewed]) - end - end - - describe 'reviewed' do - it 'returns the relevant records' do - results = described_class.reviewed - - expect(results).to eq([trendable_and_reviewed]) - end - end - - describe 'pending_review' do - it 'returns the relevant records' do - results = described_class.pending_review - - expect(results).to eq([not_trendable_and_not_reviewed]) - end - end - end -end diff --git a/spec/models/privacy_policy_spec.rb b/spec/models/privacy_policy_spec.rb deleted file mode 100644 index 0d7471375..000000000 --- a/spec/models/privacy_policy_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe PrivacyPolicy do - describe '.current' do - context 'with the default values' do - it 'has the privacy text' do - policy = described_class.current - - expect(policy.text).to eq(PrivacyPolicy::DEFAULT_PRIVACY_POLICY) - end - end - - context 'with a custom setting value' do - before do - terms_setting = instance_double(Setting, value: 'Terms text', updated_at: 10.days.ago) - allow(Setting).to receive(:find_by).with(var: 'site_terms').and_return(terms_setting) - end - - it 'has the privacy text' do - policy = described_class.current - - expect(policy.text).to eq('Terms text') - end - end - end -end diff --git a/spec/models/public_feed_spec.rb b/spec/models/public_feed_spec.rb deleted file mode 100644 index fbbdf6258..000000000 --- a/spec/models/public_feed_spec.rb +++ /dev/null @@ -1,274 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe PublicFeed do - let(:account) { Fabricate(:account) } - - describe '#get' do - subject { described_class.new(nil).get(20).map(&:id) } - - it 'only includes statuses with public visibility' do - public_status = Fabricate(:status, visibility: :public) - private_status = Fabricate(:status, visibility: :private) - - expect(subject).to include(public_status.id) - expect(subject).to_not include(private_status.id) - end - - it 'does not include replies' do - status = Fabricate(:status) - reply = Fabricate(:status, in_reply_to_id: status.id) - - expect(subject).to include(status.id) - expect(subject).to_not include(reply.id) - end - - it 'does not include boosts' do - status = Fabricate(:status) - boost = Fabricate(:status, reblog_of_id: status.id) - - expect(subject).to include(status.id) - expect(subject).to_not include(boost.id) - end - - it 'filters out silenced accounts' do - silenced_account = Fabricate(:account, silenced: true) - status = Fabricate(:status, account: account) - silenced_status = Fabricate(:status, account: silenced_account) - - expect(subject).to include(status.id) - expect(subject).to_not include(silenced_status.id) - end - - context 'without local_only option' do - subject { described_class.new(viewer).get(20).map(&:id) } - - let(:viewer) { nil } - - let!(:local_account) { Fabricate(:account, domain: nil) } - let!(:remote_account) { Fabricate(:account, domain: 'test.com') } - let!(:local_status) { Fabricate(:status, account: local_account) } - let!(:remote_status) { Fabricate(:status, account: remote_account) } - let!(:local_only_status) { Fabricate(:status, account: local_account, local_only: true) } - - context 'without a viewer' do - let(:viewer) { nil } - - it 'includes remote instances statuses' do - expect(subject).to include(remote_status.id) - end - - it 'includes local statuses' do - expect(subject).to include(local_status.id) - end - - it 'does not include local-only statuses' do - expect(subject).to_not include(local_only_status.id) - end - end - - context 'with a viewer' do - let(:viewer) { Fabricate(:account, username: 'viewer') } - - it 'includes remote instances statuses' do - expect(subject).to include(remote_status.id) - end - - it 'includes local statuses' do - expect(subject).to include(local_status.id) - end - - it 'does not include local-only statuses' do - expect(subject).to_not include(local_only_status.id) - end - end - end - - context 'without local_only option but allow_local_only' do - subject { described_class.new(viewer, allow_local_only: true).get(20).map(&:id) } - - let(:viewer) { nil } - - let!(:local_account) { Fabricate(:account, domain: nil) } - let!(:remote_account) { Fabricate(:account, domain: 'test.com') } - let!(:local_status) { Fabricate(:status, account: local_account) } - let!(:remote_status) { Fabricate(:status, account: remote_account) } - let!(:local_only_status) { Fabricate(:status, account: local_account, local_only: true) } - - context 'without a viewer' do - let(:viewer) { nil } - - it 'includes remote instances statuses' do - expect(subject).to include(remote_status.id) - end - - it 'includes local statuses' do - expect(subject).to include(local_status.id) - end - - it 'does not include local-only statuses' do - expect(subject).to_not include(local_only_status.id) - end - end - - context 'with a viewer' do - let(:viewer) { Fabricate(:account, username: 'viewer') } - - it 'includes remote instances statuses' do - expect(subject).to include(remote_status.id) - end - - it 'includes local statuses' do - expect(subject).to include(local_status.id) - end - - it 'includes local-only statuses' do - expect(subject).to include(local_only_status.id) - end - end - end - - context 'with a local_only option set' do - subject { described_class.new(viewer, local: true).get(20).map(&:id) } - - let!(:local_account) { Fabricate(:account, domain: nil) } - let!(:remote_account) { Fabricate(:account, domain: 'test.com') } - let!(:local_status) { Fabricate(:status, account: local_account) } - let!(:remote_status) { Fabricate(:status, account: remote_account) } - let!(:local_only_status) { Fabricate(:status, account: local_account, local_only: true) } - - context 'without a viewer' do - let(:viewer) { nil } - - it 'does not include remote instances statuses' do - expect(subject).to include(local_status.id) - expect(subject).to_not include(remote_status.id) - end - - it 'does not include local-only statuses' do - expect(subject).to_not include(local_only_status.id) - end - end - - context 'with a viewer' do - let(:viewer) { Fabricate(:account, username: 'viewer') } - - it 'does not include remote instances statuses' do - expect(subject).to include(local_status.id) - expect(subject).to_not include(remote_status.id) - end - - it 'is not affected by personal domain blocks' do - viewer.block_domain!('test.com') - expect(subject).to include(local_status.id) - expect(subject).to_not include(remote_status.id) - end - - it 'includes local-only statuses' do - expect(subject).to include(local_only_status.id) - end - end - end - - context 'with a remote_only option set' do - subject { described_class.new(viewer, remote: true).get(20).map(&:id) } - - let!(:local_account) { Fabricate(:account, domain: nil) } - let!(:remote_account) { Fabricate(:account, domain: 'test.com') } - let!(:local_status) { Fabricate(:status, account: local_account) } - let!(:remote_status) { Fabricate(:status, account: remote_account) } - - context 'without a viewer' do - let(:viewer) { nil } - - it 'does not include local instances statuses' do - expect(subject).to_not include(local_status.id) - expect(subject).to include(remote_status.id) - end - end - - context 'with a viewer' do - let(:viewer) { Fabricate(:account, username: 'viewer') } - - it 'does not include local instances statuses' do - expect(subject).to_not include(local_status.id) - expect(subject).to include(remote_status.id) - end - end - end - - describe 'with an account passed in' do - subject { described_class.new(@account).get(20).map(&:id) } - - before do - @account = Fabricate(:account) - end - - it 'excludes statuses from accounts blocked by the account' do - blocked = Fabricate(:account) - @account.block!(blocked) - blocked_status = Fabricate(:status, account: blocked) - - expect(subject).to_not include(blocked_status.id) - end - - it 'excludes statuses from accounts who have blocked the account' do - blocker = Fabricate(:account) - blocker.block!(@account) - blocked_status = Fabricate(:status, account: blocker) - - expect(subject).to_not include(blocked_status.id) - end - - it 'excludes statuses from accounts muted by the account' do - muted = Fabricate(:account) - @account.mute!(muted) - muted_status = Fabricate(:status, account: muted) - - expect(subject).to_not include(muted_status.id) - end - - it 'excludes statuses from accounts from personally blocked domains' do - blocked = Fabricate(:account, domain: 'example.com') - @account.block_domain!(blocked.domain) - blocked_status = Fabricate(:status, account: blocked) - - expect(subject).to_not include(blocked_status.id) - end - - context 'with language preferences' do - it 'excludes statuses in languages not allowed by the account user' do - @account.user.update(chosen_languages: [:en, :es]) - en_status = Fabricate(:status, language: 'en') - es_status = Fabricate(:status, language: 'es') - fr_status = Fabricate(:status, language: 'fr') - - expect(subject).to include(en_status.id) - expect(subject).to include(es_status.id) - expect(subject).to_not include(fr_status.id) - end - - it 'includes all languages when user does not have a setting' do - @account.user.update(chosen_languages: nil) - - en_status = Fabricate(:status, language: 'en') - es_status = Fabricate(:status, language: 'es') - - expect(subject).to include(en_status.id) - expect(subject).to include(es_status.id) - end - - it 'includes all languages when account does not have a user' do - @account.update(user: nil) - - en_status = Fabricate(:status, language: 'en') - es_status = Fabricate(:status, language: 'es') - - expect(subject).to include(en_status.id) - expect(subject).to include(es_status.id) - end - end - end - end -end diff --git a/spec/models/relationship_filter_spec.rb b/spec/models/relationship_filter_spec.rb deleted file mode 100644 index fccd42aaa..000000000 --- a/spec/models/relationship_filter_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe RelationshipFilter do - let(:account) { Fabricate(:account) } - - describe '#results' do - let(:account_of_7_months) { Fabricate(:account_stat, statuses_count: 1, last_status_at: 7.months.ago).account } - let(:account_of_1_day) { Fabricate(:account_stat, statuses_count: 1, last_status_at: 1.day.ago).account } - let(:account_of_3_days) { Fabricate(:account_stat, statuses_count: 1, last_status_at: 3.days.ago).account } - let(:silent_account) { Fabricate(:account_stat, statuses_count: 0, last_status_at: nil).account } - - before do - account.follow!(account_of_7_months) - account.follow!(account_of_1_day) - account.follow!(account_of_3_days) - account.follow!(silent_account) - end - - context 'when ordering by last activity' do - context 'when not filtering' do - subject do - described_class.new(account, 'order' => 'active').results - end - - it 'returns followings ordered by last activity' do - expect(subject).to eq [account_of_1_day, account_of_3_days, account_of_7_months, silent_account] - end - end - - context 'when filtering for dormant accounts' do - subject do - described_class.new(account, 'order' => 'active', 'activity' => 'dormant').results - end - - it 'returns dormant followings ordered by last activity' do - expect(subject).to eq [account_of_7_months, silent_account] - end - end - end - - context 'when ordering by account creation' do - context 'when not filtering' do - subject do - described_class.new(account, 'order' => 'recent').results - end - - it 'returns followings ordered by last account creation' do - expect(subject).to eq [silent_account, account_of_3_days, account_of_1_day, account_of_7_months] - end - end - - context 'when filtering for dormant accounts' do - subject do - described_class.new(account, 'order' => 'recent', 'activity' => 'dormant').results - end - - it 'returns dormant followings ordered by last activity' do - expect(subject).to eq [silent_account, account_of_7_months] - end - end - end - end -end diff --git a/spec/models/remote_follow_spec.rb b/spec/models/remote_follow_spec.rb deleted file mode 100644 index 81c726a40..000000000 --- a/spec/models/remote_follow_spec.rb +++ /dev/null @@ -1,67 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe RemoteFollow do - before do - stub_request(:get, 'https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no').to_return(request_fixture('webfinger.txt')) - end - - let(:attrs) { nil } - let(:remote_follow) { described_class.new(attrs) } - - describe '.initialize' do - subject { remote_follow.acct } - - context 'when attrs with acct' do - let(:attrs) { { acct: 'gargron@quitter.no' } } - - it 'returns acct' do - expect(subject).to eq 'gargron@quitter.no' - end - end - - context 'when attrs without acct' do - let(:attrs) { {} } - - it do - expect(subject).to be_nil - end - end - end - - describe '#valid?' do - subject { remote_follow.valid? } - - context 'when attrs with acct' do - let(:attrs) { { acct: 'gargron@quitter.no' } } - - it do - expect(subject).to be true - end - end - - context 'when attrs without acct' do - let(:attrs) { {} } - - it do - expect(subject).to be false - end - end - end - - describe '#subscribe_address_for' do - subject { remote_follow.subscribe_address_for(account) } - - before do - remote_follow.valid? - end - - let(:attrs) { { acct: 'gargron@quitter.no' } } - let(:account) { Fabricate(:account, username: 'alice') } - - it 'returns subscribe address' do - expect(subject).to eq 'https://quitter.no/main/ostatussub?profile=https%3A%2F%2Fcb6e6126.ngrok.io%2Fusers%2Falice' - end - end -end diff --git a/spec/models/report_filter_spec.rb b/spec/models/report_filter_spec.rb deleted file mode 100644 index 6baf0ea42..000000000 --- a/spec/models/report_filter_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ReportFilter do - describe 'with empty params' do - it 'defaults to unresolved reports list' do - filter = described_class.new({}) - - expect(filter.results).to eq Report.unresolved - end - end - - describe 'with invalid params' do - it 'raises with key error' do - filter = described_class.new(wrong: true) - - expect { filter.results }.to raise_error(/wrong/) - end - end - - describe 'with valid params' do - it 'combines filters on Report' do - filter = described_class.new(account_id: '123', resolved: true, target_account_id: '456') - - allow(Report).to receive_messages(where: Report.none, resolved: Report.none) - filter.results - expect(Report).to have_received(:where).with(account_id: '123') - expect(Report).to have_received(:where).with(target_account_id: '456') - expect(Report).to have_received(:resolved) - end - end -end diff --git a/spec/models/report_spec.rb b/spec/models/report_spec.rb deleted file mode 100644 index 0093dcd8d..000000000 --- a/spec/models/report_spec.rb +++ /dev/null @@ -1,137 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Report do - describe 'statuses' do - it 'returns the statuses for the report' do - status = Fabricate(:status) - _other = Fabricate(:status) - report = Fabricate(:report, status_ids: [status.id]) - - expect(report.statuses).to eq [status] - end - end - - describe 'media_attachments_count' do - it 'returns count of media attachments in statuses' do - status1 = Fabricate(:status, ordered_media_attachment_ids: [1, 2]) - status2 = Fabricate(:status, ordered_media_attachment_ids: [5]) - report = Fabricate(:report, status_ids: [status1.id, status2.id]) - - expect(report.media_attachments_count).to eq 3 - end - end - - describe 'assign_to_self!' do - subject { report.assigned_account_id } - - let(:report) { Fabricate(:report, assigned_account_id: original_account) } - let(:original_account) { Fabricate(:account) } - let(:current_account) { Fabricate(:account) } - - before do - report.assign_to_self!(current_account) - end - - it 'assigns to a given account' do - expect(subject).to eq current_account.id - end - end - - describe 'unassign!' do - subject { report.assigned_account_id } - - let(:report) { Fabricate(:report, assigned_account_id: account.id) } - let(:account) { Fabricate(:account) } - - before do - report.unassign! - end - - it 'unassigns' do - expect(subject).to be_nil - end - end - - describe 'resolve!' do - subject(:report) { Fabricate(:report, action_taken_at: nil, action_taken_by_account_id: nil) } - - let(:acting_account) { Fabricate(:account) } - - before do - report.resolve!(acting_account) - end - - it 'records action taken' do - expect(report.action_taken?).to be true - expect(report.action_taken_by_account_id).to eq acting_account.id - end - end - - describe 'unresolve!' do - subject(:report) { Fabricate(:report, action_taken_at: Time.now.utc, action_taken_by_account_id: acting_account.id) } - - let(:acting_account) { Fabricate(:account) } - - before do - report.unresolve! - end - - it 'unresolves' do - expect(report.action_taken?).to be false - expect(report.action_taken_by_account_id).to be_nil - end - end - - describe 'unresolved?' do - subject { report.unresolved? } - - let(:report) { Fabricate(:report, action_taken_at: action_taken) } - - context 'when action is taken' do - let(:action_taken) { Time.now.utc } - - it { is_expected.to be false } - end - - context 'when action not is taken' do - let(:action_taken) { nil } - - it { is_expected.to be true } - end - end - - describe 'history' do - subject(:action_logs) { report.history } - - let(:report) { Fabricate(:report, target_account_id: target_account.id, status_ids: [status.id], created_at: 3.days.ago, updated_at: 1.day.ago) } - let(:target_account) { Fabricate(:account) } - let(:status) { Fabricate(:status) } - - before do - Fabricate('Admin::ActionLog', target_type: 'Report', account_id: target_account.id, target_id: report.id, created_at: 2.days.ago) - Fabricate('Admin::ActionLog', target_type: 'Account', account_id: target_account.id, target_id: report.target_account_id, created_at: 2.days.ago) - Fabricate('Admin::ActionLog', target_type: 'Status', account_id: target_account.id, target_id: status.id, created_at: 2.days.ago) - end - - it 'returns right logs' do - expect(action_logs.count).to eq 3 - end - end - - describe 'validations' do - let(:remote_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') } - - it 'is invalid if comment is longer than 1000 characters only if reporter is local' do - report = Fabricate.build(:report, comment: Faker::Lorem.characters(number: 1001)) - expect(report.valid?).to be false - expect(report).to model_have_error_on_field(:comment) - end - - it 'is valid if comment is longer than 1000 characters and reporter is not local' do - report = Fabricate.build(:report, account: remote_account, comment: Faker::Lorem.characters(number: 1001)) - expect(report.valid?).to be true - end - end -end diff --git a/spec/models/rule_spec.rb b/spec/models/rule_spec.rb deleted file mode 100644 index c9b9c5502..000000000 --- a/spec/models/rule_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Rule do - describe 'scopes' do - describe 'ordered' do - let(:deleted_rule) { Fabricate(:rule, deleted_at: 10.days.ago) } - let(:first_rule) { Fabricate(:rule, deleted_at: nil, priority: 1) } - let(:last_rule) { Fabricate(:rule, deleted_at: nil, priority: 10) } - - it 'finds the correct records' do - results = described_class.ordered - - expect(results).to eq([first_rule, last_rule]) - end - end - end -end diff --git a/spec/models/session_activation_spec.rb b/spec/models/session_activation_spec.rb deleted file mode 100644 index 75842e25b..000000000 --- a/spec/models/session_activation_spec.rb +++ /dev/null @@ -1,127 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe SessionActivation do - describe '#detection' do - let(:session_activation) { Fabricate(:session_activation, user_agent: 'Chrome/62.0.3202.89') } - - it 'sets a Browser instance as detection' do - expect(session_activation.detection).to be_a Browser::Chrome - end - end - - describe '#browser' do - before do - allow(session_activation).to receive(:detection).and_return(detection) - end - - let(:detection) { instance_double(Browser::Chrome, id: 1) } - let(:session_activation) { Fabricate(:session_activation) } - - it 'returns detection.id' do - expect(session_activation.browser).to be 1 - end - end - - describe '#platform' do - before do - allow(session_activation).to receive(:detection).and_return(detection) - end - - let(:session_activation) { Fabricate(:session_activation) } - let(:detection) { instance_double(Browser::Chrome, platform: instance_double(Browser::Platform, id: 1)) } - - it 'returns detection.platform.id' do - expect(session_activation.platform).to be 1 - end - end - - describe '.active?' do - subject { described_class.active?(id) } - - context 'when id is absent' do - let(:id) { nil } - - it 'returns nil' do - expect(subject).to be_nil - end - end - - context 'when id is present' do - let(:id) { '1' } - let!(:session_activation) { Fabricate(:session_activation, session_id: id) } - - context 'when id exists as session_id' do - it 'returns true' do - expect(subject).to be true - end - end - - context 'when id does not exist as session_id' do - before do - session_activation.update!(session_id: '2') - end - - it 'returns false' do - expect(subject).to be false - end - end - end - end - - describe '.activate' do - let(:options) { { user: Fabricate(:user), session_id: '1' } } - - it 'calls create! and purge_old' do - expect(described_class).to receive(:create!).with(**options) - expect(described_class).to receive(:purge_old) - described_class.activate(**options) - end - - it 'returns an instance of SessionActivation' do - expect(described_class.activate(**options)).to be_a described_class - end - end - - describe '.deactivate' do - context 'when id is absent' do - let(:id) { nil } - - it 'returns nil' do - expect(described_class.deactivate(id)).to be_nil - end - end - - context 'when id exists' do - let(:id) { '1' } - - it 'calls where.destroy_all' do - expect(described_class).to receive_message_chain(:where, :destroy_all) - .with(session_id: id).with(no_args) - - described_class.deactivate(id) - end - end - end - - describe '.purge_old' do - it 'calls order.offset.destroy_all' do - expect(described_class).to receive_message_chain(:order, :offset, :destroy_all) - .with('created_at desc').with(Rails.configuration.x.max_session_activations).with(no_args) - - described_class.purge_old - end - end - - describe '.exclusive' do - let(:id) { '1' } - - it 'calls where.destroy_all' do - expect(described_class).to receive_message_chain(:where, :not, :destroy_all) - .with(session_id: id).with(no_args) - - described_class.exclusive(id) - end - end -end diff --git a/spec/models/setting_spec.rb b/spec/models/setting_spec.rb deleted file mode 100644 index 5ed5c5d76..000000000 --- a/spec/models/setting_spec.rb +++ /dev/null @@ -1,188 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Setting do - describe '#to_param' do - let(:setting) { Fabricate(:setting, var: var) } - let(:var) { 'var' } - - it 'returns setting.var' do - expect(setting.to_param).to eq var - end - end - - describe '.[]' do - before do - allow(described_class).to receive(:rails_initialized?).and_return(rails_initialized) - end - - let(:key) { 'key' } - - context 'when rails_initialized? is falsey' do - let(:rails_initialized) { false } - - it 'calls RailsSettings::Base#[]' do - expect(RailsSettings::Base).to receive(:[]).with(key) - described_class[key] - end - end - - context 'when rails_initialized? is truthy' do - before do - allow(RailsSettings::Base).to receive(:cache_key).with(key, nil).and_return(cache_key) - end - - let(:rails_initialized) { true } - let(:cache_key) { 'cache-key' } - let(:cache_value) { 'cache-value' } - - it 'calls not RailsSettings::Base#[]' do - expect(RailsSettings::Base).to_not receive(:[]).with(key) - described_class[key] - end - - context 'when Rails.cache does not exists' do - before do - allow(RailsSettings::Settings).to receive(:object).with(key).and_return(object) - allow(described_class).to receive(:default_settings).and_return(default_settings) - allow_any_instance_of(Settings::ScopedSettings).to receive(:thing_scoped).and_return(records) - Rails.cache.delete(cache_key) - end - - let(:object) { nil } - let(:default_value) { 'default_value' } - let(:default_settings) { { key => default_value } } - let(:records) { [Fabricate(:setting, var: key, value: nil)] } - - it 'calls RailsSettings::Settings.object' do - expect(RailsSettings::Settings).to receive(:object).with(key) - described_class[key] - end - - context 'when RailsSettings::Settings.object returns truthy' do - let(:object) { db_val } - let(:db_val) { instance_double(described_class, value: 'db_val') } - - context 'when default_value is a Hash' do - let(:default_value) { { default_value: 'default_value' } } - - it 'calls default_value.with_indifferent_access.merge!' do - expect(default_value).to receive_message_chain(:with_indifferent_access, :merge!) - .with(db_val.value) - - described_class[key] - end - end - - context 'when default_value is not a Hash' do - let(:default_value) { 'default_value' } - - it 'returns db_val.value' do - expect(described_class[key]).to be db_val.value - end - end - end - - context 'when RailsSettings::Settings.object returns falsey' do - let(:object) { nil } - - it 'returns default_settings[key]' do - expect(described_class[key]).to be default_settings[key] - end - end - end - - context 'when Rails.cache exists' do - before do - Rails.cache.write(cache_key, cache_value) - end - - it 'does not query the database' do - callback = double - allow(callback).to receive(:call) - ActiveSupport::Notifications.subscribed callback, 'sql.active_record' do - described_class[key] - end - expect(callback).to_not have_received(:call) - end - - it 'returns the cached value' do - expect(described_class[key]).to eq cache_value - end - end - end - end - - describe '.all_as_records' do - before do - allow_any_instance_of(Settings::ScopedSettings).to receive(:thing_scoped).and_return(records) - allow(described_class).to receive(:default_settings).and_return(default_settings) - end - - let(:key) { 'key' } - let(:default_value) { 'default_value' } - let(:default_settings) { { key => default_value } } - let(:original_setting) { Fabricate(:setting, var: key, value: nil) } - let(:records) { [original_setting] } - - it 'returns a Hash' do - expect(described_class.all_as_records).to be_a Hash - end - - context 'when records includes Setting with var as the key' do - let(:records) { [original_setting] } - - it 'includes the original Setting' do - setting = described_class.all_as_records[key] - expect(setting).to eq original_setting - end - end - - context 'when records includes nothing' do - let(:records) { [] } - - context 'when default_value is not a Hash' do - it 'includes Setting with value of default_value' do - setting = described_class.all_as_records[key] - - expect(setting).to be_a described_class - expect(setting).to have_attributes(var: key) - expect(setting).to have_attributes(value: 'default_value') - end - end - - context 'when default_value is a Hash' do - let(:default_value) { { 'foo' => 'fuga' } } - - it 'returns {}' do - expect(described_class.all_as_records).to eq({}) - end - end - end - end - - describe '.default_settings' do - subject { described_class.default_settings } - - before do - allow(RailsSettings::Default).to receive(:enabled?).and_return(enabled) - end - - context 'when RailsSettings::Default.enabled? is false' do - let(:enabled) { false } - - it 'returns {}' do - expect(subject).to eq({}) - end - end - - context 'when RailsSettings::Settings.enabled? is true' do - let(:enabled) { true } - - it 'returns instance of RailsSettings::Default' do - expect(subject).to be_a RailsSettings::Default - end - end - end -end diff --git a/spec/models/site_upload_spec.rb b/spec/models/site_upload_spec.rb deleted file mode 100644 index 9689bce9e..000000000 --- a/spec/models/site_upload_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe SiteUpload do - describe '#cache_key' do - let(:site_upload) { described_class.new(var: 'var') } - - it 'returns cache_key' do - expect(site_upload.cache_key).to eq 'site_uploads/var' - end - end -end diff --git a/spec/models/software_update_spec.rb b/spec/models/software_update_spec.rb deleted file mode 100644 index 0a494b0c4..000000000 --- a/spec/models/software_update_spec.rb +++ /dev/null @@ -1,87 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe SoftwareUpdate do - describe '.pending_to_a' do - before do - allow(Mastodon::Version).to receive(:gem_version).and_return(Gem::Version.new(mastodon_version)) - - Fabricate(:software_update, version: '3.4.42', type: 'patch', urgent: true) - Fabricate(:software_update, version: '3.5.0', type: 'minor', urgent: false) - Fabricate(:software_update, version: '4.2.0', type: 'major', urgent: false) - end - - context 'when the Mastodon version is an outdated release' do - let(:mastodon_version) { '3.4.0' } - - it 'returns the expected versions' do - expect(described_class.pending_to_a.pluck(:version)).to contain_exactly('3.4.42', '3.5.0', '4.2.0') - end - end - - context 'when the Mastodon version is more recent than anything last returned by the server' do - let(:mastodon_version) { '5.0.0' } - - it 'returns the expected versions' do - expect(described_class.pending_to_a.pluck(:version)).to eq [] - end - end - - context 'when the Mastodon version is an outdated nightly' do - let(:mastodon_version) { '4.3.0-nightly.2023-09-10' } - - before do - Fabricate(:software_update, version: '4.3.0-nightly.2023-09-12', type: 'major', urgent: true) - end - - it 'returns the expected versions' do - expect(described_class.pending_to_a.pluck(:version)).to contain_exactly('4.3.0-nightly.2023-09-12') - end - end - - context 'when the Mastodon version is a very outdated nightly' do - let(:mastodon_version) { '4.2.0-nightly.2023-07-10' } - - it 'returns the expected versions' do - expect(described_class.pending_to_a.pluck(:version)).to contain_exactly('4.2.0') - end - end - - context 'when the Mastodon version is an outdated dev version' do - let(:mastodon_version) { '4.3.0-0.dev.0' } - - before do - Fabricate(:software_update, version: '4.3.0-0.dev.2', type: 'major', urgent: true) - end - - it 'returns the expected versions' do - expect(described_class.pending_to_a.pluck(:version)).to contain_exactly('4.3.0-0.dev.2') - end - end - - context 'when the Mastodon version is an outdated beta version' do - let(:mastodon_version) { '4.3.0-beta1' } - - before do - Fabricate(:software_update, version: '4.3.0-beta2', type: 'major', urgent: true) - end - - it 'returns the expected versions' do - expect(described_class.pending_to_a.pluck(:version)).to contain_exactly('4.3.0-beta2') - end - end - - context 'when the Mastodon version is an outdated beta version and there is a rc' do - let(:mastodon_version) { '4.3.0-beta1' } - - before do - Fabricate(:software_update, version: '4.3.0-rc1', type: 'major', urgent: true) - end - - it 'returns the expected versions' do - expect(described_class.pending_to_a.pluck(:version)).to contain_exactly('4.3.0-rc1') - end - end - end -end diff --git a/spec/models/status_edit_spec.rb b/spec/models/status_edit_spec.rb deleted file mode 100644 index 2d3351452..000000000 --- a/spec/models/status_edit_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe StatusEdit do - describe '#reblog?' do - it 'returns false' do - record = described_class.new - - expect(record).to_not be_a_reblog - end - end -end diff --git a/spec/models/status_pin_spec.rb b/spec/models/status_pin_spec.rb deleted file mode 100644 index 660b2e92a..000000000 --- a/spec/models/status_pin_spec.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe StatusPin do - describe 'validations' do - it 'allows pins of own statuses' do - account = Fabricate(:account) - status = Fabricate(:status, account: account) - - expect(described_class.new(account: account, status: status).save).to be true - end - - it 'does not allow pins of statuses by someone else' do - account = Fabricate(:account) - status = Fabricate(:status) - - expect(described_class.new(account: account, status: status).save).to be false - end - - it 'does not allow pins of reblogs' do - account = Fabricate(:account) - status = Fabricate(:status, account: account) - reblog = Fabricate(:status, reblog: status) - - expect(described_class.new(account: account, status: reblog).save).to be false - end - - it 'does allow pins of direct statuses' do - account = Fabricate(:account) - status = Fabricate(:status, account: account, visibility: :private) - - expect(described_class.new(account: account, status: status).save).to be true - end - - it 'does not allow pins of direct statuses' do - account = Fabricate(:account) - status = Fabricate(:status, account: account, visibility: :direct) - - expect(described_class.new(account: account, status: status).save).to be false - end - - max_pins = 5 - it 'does not allow pins above the max' do - account = Fabricate(:account) - status = [] - - (max_pins + 1).times do |i| - status[i] = Fabricate(:status, account: account) - end - - max_pins.times do |i| - expect(described_class.new(account: account, status: status[i]).save).to be true - end - - expect(described_class.new(account: account, status: status[max_pins]).save).to be false - end - - it 'allows pins above the max for remote accounts' do - account = Fabricate(:account, domain: 'remote.test', username: 'bob', url: 'https://remote.test/') - status = [] - - (max_pins + 1).times do |i| - status[i] = Fabricate(:status, account: account) - end - - max_pins.times do |i| - expect(described_class.new(account: account, status: status[i]).save).to be true - end - - expect(described_class.new(account: account, status: status[max_pins]).save).to be true - end - end -end diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb deleted file mode 100644 index f38e7c237..000000000 --- a/spec/models/status_spec.rb +++ /dev/null @@ -1,467 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Status do - subject { Fabricate(:status, account: alice) } - - let(:alice) { Fabricate(:account, username: 'alice') } - let(:bob) { Fabricate(:account, username: 'bob') } - let(:other) { Fabricate(:status, account: bob, text: 'Skulls for the skull god! The enemy\'s gates are sideways!') } - - describe '#local?' do - it 'returns true when no remote URI is set' do - expect(subject.local?).to be true - end - - it 'returns false if a remote URI is set' do - alice.update(domain: 'example.com') - subject.save - expect(subject.local?).to be false - end - - it 'returns true if a URI is set and `local` is true' do - subject.update(uri: 'example.com', local: true) - expect(subject.local?).to be true - end - end - - describe '#reblog?' do - it 'returns true when the status reblogs another status' do - subject.reblog = other - expect(subject.reblog?).to be true - end - - it 'returns false if the status is self-contained' do - expect(subject.reblog?).to be false - end - end - - describe '#reply?' do - it 'returns true if the status references another' do - subject.thread = other - expect(subject.reply?).to be true - end - - it 'returns false if the status is self-contained' do - expect(subject.reply?).to be false - end - end - - describe '#verb' do - context 'when destroyed?' do - it 'returns :delete' do - subject.destroy! - expect(subject.verb).to be :delete - end - end - - context 'when not destroyed?' do - context 'when reblog?' do - it 'returns :share' do - subject.reblog = other - expect(subject.verb).to be :share - end - end - - context 'when not reblog?' do - it 'returns :post' do - subject.reblog = nil - expect(subject.verb).to be :post - end - end - end - end - - describe '#object_type' do - it 'is note when the status is self-contained' do - expect(subject.object_type).to be :note - end - - it 'is comment when the status replies to another' do - subject.thread = other - expect(subject.object_type).to be :comment - end - end - - describe '#hidden?' do - context 'when private_visibility?' do - it 'returns true' do - subject.visibility = :private - expect(subject.hidden?).to be true - end - end - - context 'when direct_visibility?' do - it 'returns true' do - subject.visibility = :direct - expect(subject.hidden?).to be true - end - end - - context 'when public_visibility?' do - it 'returns false' do - subject.visibility = :public - expect(subject.hidden?).to be false - end - end - - context 'when unlisted_visibility?' do - it 'returns false' do - subject.visibility = :unlisted - expect(subject.hidden?).to be false - end - end - end - - describe '#content' do - it 'returns the text of the status if it is not a reblog' do - expect(subject.content).to eql subject.text - end - - it 'returns the text of the reblogged status' do - subject.reblog = other - expect(subject.content).to eql other.text - end - end - - describe '#target' do - it 'returns nil if the status is self-contained' do - expect(subject.target).to be_nil - end - - it 'returns nil if the status is a reply' do - subject.thread = other - expect(subject.target).to be_nil - end - - it 'returns the reblogged status' do - subject.reblog = other - expect(subject.target).to eq other - end - end - - describe '#reblogs_count' do - it 'is the number of reblogs' do - Fabricate(:status, account: bob, reblog: subject) - Fabricate(:status, account: alice, reblog: subject) - - expect(subject.reblogs_count).to eq 2 - end - - it 'is decremented when reblog is removed' do - reblog = Fabricate(:status, account: bob, reblog: subject) - expect(subject.reblogs_count).to eq 1 - reblog.destroy - expect(subject.reblogs_count).to eq 0 - end - - it 'does not fail when original is deleted before reblog' do - reblog = Fabricate(:status, account: bob, reblog: subject) - expect(subject.reblogs_count).to eq 1 - expect { subject.destroy }.to_not raise_error - expect(described_class.find_by(id: reblog.id)).to be_nil - end - end - - describe '#replies_count' do - it 'is the number of replies' do - reply = Fabricate(:status, account: bob, thread: subject) - expect(subject.replies_count).to eq 1 - end - - it 'is decremented when reply is removed' do - reply = Fabricate(:status, account: bob, thread: subject) - expect(subject.replies_count).to eq 1 - reply.destroy - expect(subject.replies_count).to eq 0 - end - end - - describe '#favourites_count' do - it 'is the number of favorites' do - Fabricate(:favourite, account: bob, status: subject) - Fabricate(:favourite, account: alice, status: subject) - - expect(subject.favourites_count).to eq 2 - end - - it 'is decremented when favourite is removed' do - favourite = Fabricate(:favourite, account: bob, status: subject) - expect(subject.favourites_count).to eq 1 - favourite.destroy - expect(subject.favourites_count).to eq 0 - end - end - - describe '#proper' do - it 'is itself for original statuses' do - expect(subject.proper).to eq subject - end - - it 'is the source status for reblogs' do - subject.reblog = other - expect(subject.proper).to eq other - end - end - - describe 'on create' do - subject { described_class.new } - - let(:local_account) { Fabricate(:account, username: 'local', domain: nil) } - let(:remote_account) { Fabricate(:account, username: 'remote', domain: 'example.com') } - - describe 'on a status that ends with the local-only emoji' do - before do - subject.text = "A toot #{subject.local_only_emoji}" - end - - context 'when the status originates from this instance' do - before do - subject.account = local_account - end - - it 'is marked local-only' do - subject.save! - - expect(subject).to be_local_only - end - end - - context 'when the status is remote' do - before do - subject.account = remote_account - end - - it 'is not marked local-only' do - subject.save! - - expect(subject).to_not be_local_only - end - end - end - end - - describe '.mutes_map' do - subject { described_class.mutes_map([status.conversation.id], account) } - - let(:status) { Fabricate(:status) } - let(:account) { Fabricate(:account) } - - it 'returns a hash' do - expect(subject).to be_a Hash - end - - it 'contains true value' do - account.mute_conversation!(status.conversation) - expect(subject[status.conversation.id]).to be true - end - end - - describe '.favourites_map' do - subject { described_class.favourites_map([status], account) } - - let(:status) { Fabricate(:status) } - let(:account) { Fabricate(:account) } - - it 'returns a hash' do - expect(subject).to be_a Hash - end - - it 'contains true value' do - Fabricate(:favourite, status: status, account: account) - expect(subject[status.id]).to be true - end - end - - describe '.reblogs_map' do - subject { described_class.reblogs_map([status], account) } - - let(:status) { Fabricate(:status) } - let(:account) { Fabricate(:account) } - - it 'returns a hash' do - expect(subject).to be_a Hash - end - - it 'contains true value' do - Fabricate(:status, account: account, reblog: status) - expect(subject[status.id]).to be true - end - end - - describe '.as_direct_timeline' do - subject(:results) { described_class.as_direct_timeline(account) } - - let(:account) { Fabricate(:account) } - let(:followed) { Fabricate(:account) } - let(:not_followed) { Fabricate(:account) } - - let!(:self_public_status) { Fabricate(:status, account: account, visibility: :public) } - let!(:self_direct_status) { Fabricate(:status, account: account, visibility: :direct) } - let!(:followed_public_status) { Fabricate(:status, account: followed, visibility: :public) } - let!(:followed_direct_status) { Fabricate(:status, account: followed, visibility: :direct) } - let!(:not_followed_direct_status) { Fabricate(:status, account: not_followed, visibility: :direct) } - - before do - account.follow!(followed) - end - - it 'does not include public statuses from self' do - expect(results).to_not include(self_public_status) - end - - it 'includes direct statuses from self' do - expect(results).to include(self_direct_status) - end - - it 'does not include public statuses from followed' do - expect(results).to_not include(followed_public_status) - end - - it 'does not include direct statuses not mentioning recipient from followed' do - expect(results).to_not include(followed_direct_status) - end - - it 'does not include direct statuses not mentioning recipient from non-followed' do - expect(results).to_not include(not_followed_direct_status) - end - - it 'includes direct statuses mentioning recipient from followed' do - Fabricate(:mention, account: account, status: followed_direct_status) - results2 = described_class.as_direct_timeline(account) - expect(results2).to include(followed_direct_status) - end - - it 'includes direct statuses mentioning recipient from non-followed' do - Fabricate(:mention, account: account, status: not_followed_direct_status) - results2 = described_class.as_direct_timeline(account) - expect(results2).to include(not_followed_direct_status) - end - end - - describe '.tagged_with' do - let(:tag_cats) { Fabricate(:tag, name: 'cats') } - let(:tag_dogs) { Fabricate(:tag, name: 'dogs') } - let(:tag_zebras) { Fabricate(:tag, name: 'zebras') } - let!(:status_with_tag_cats) { Fabricate(:status, tags: [tag_cats]) } - let!(:status_with_tag_dogs) { Fabricate(:status, tags: [tag_dogs]) } - let!(:status_tagged_with_zebras) { Fabricate(:status, tags: [tag_zebras]) } - let!(:status_without_tags) { Fabricate(:status, tags: []) } - let!(:status_with_all_tags) { Fabricate(:status, tags: [tag_cats, tag_dogs, tag_zebras]) } - - context 'when given one tag' do - it 'returns the expected statuses' do - expect(described_class.tagged_with([tag_cats.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_with_all_tags.id) - expect(described_class.tagged_with([tag_dogs.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_dogs.id, status_with_all_tags.id) - expect(described_class.tagged_with([tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_tagged_with_zebras.id, status_with_all_tags.id) - end - end - - context 'when given multiple tags' do - it 'returns the expected statuses' do - expect(described_class.tagged_with([tag_cats.id, tag_dogs.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_with_tag_dogs.id, status_with_all_tags.id) - expect(described_class.tagged_with([tag_cats.id, tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_tagged_with_zebras.id, status_with_all_tags.id) - expect(described_class.tagged_with([tag_dogs.id, tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_dogs.id, status_tagged_with_zebras.id, status_with_all_tags.id) - end - end - end - - describe '.tagged_with_all' do - let(:tag_cats) { Fabricate(:tag, name: 'cats') } - let(:tag_dogs) { Fabricate(:tag, name: 'dogs') } - let(:tag_zebras) { Fabricate(:tag, name: 'zebras') } - let!(:status_with_tag_cats) { Fabricate(:status, tags: [tag_cats]) } - let!(:status_with_tag_dogs) { Fabricate(:status, tags: [tag_dogs]) } - let!(:status_tagged_with_zebras) { Fabricate(:status, tags: [tag_zebras]) } - let!(:status_without_tags) { Fabricate(:status, tags: []) } - let!(:status_with_all_tags) { Fabricate(:status, tags: [tag_cats, tag_dogs]) } - - context 'when given one tag' do - it 'returns the expected statuses' do - expect(described_class.tagged_with_all([tag_cats.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_with_all_tags.id) - expect(described_class.tagged_with_all([tag_dogs.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_dogs.id, status_with_all_tags.id) - expect(described_class.tagged_with_all([tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_tagged_with_zebras.id) - end - end - - context 'when given multiple tags' do - it 'returns the expected statuses' do - expect(described_class.tagged_with_all([tag_cats.id, tag_dogs.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_all_tags.id) - expect(described_class.tagged_with_all([tag_cats.id, tag_zebras.id]).reorder(:id).pluck(:id).uniq).to eq [] - expect(described_class.tagged_with_all([tag_dogs.id, tag_zebras.id]).reorder(:id).pluck(:id).uniq).to eq [] - end - end - end - - describe '.tagged_with_none' do - let(:tag_cats) { Fabricate(:tag, name: 'cats') } - let(:tag_dogs) { Fabricate(:tag, name: 'dogs') } - let(:tag_zebras) { Fabricate(:tag, name: 'zebras') } - let!(:status_with_tag_cats) { Fabricate(:status, tags: [tag_cats]) } - let!(:status_with_tag_dogs) { Fabricate(:status, tags: [tag_dogs]) } - let!(:status_tagged_with_zebras) { Fabricate(:status, tags: [tag_zebras]) } - let!(:status_without_tags) { Fabricate(:status, tags: []) } - let!(:status_with_all_tags) { Fabricate(:status, tags: [tag_cats, tag_dogs, tag_zebras]) } - - context 'when given one tag' do - it 'returns the expected statuses' do - expect(described_class.tagged_with_none([tag_cats.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_dogs.id, status_tagged_with_zebras.id, status_without_tags.id) - expect(described_class.tagged_with_none([tag_dogs.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_tagged_with_zebras.id, status_without_tags.id) - expect(described_class.tagged_with_none([tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_with_tag_dogs.id, status_without_tags.id) - end - end - - context 'when given multiple tags' do - it 'returns the expected statuses' do - expect(described_class.tagged_with_none([tag_cats.id, tag_dogs.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_tagged_with_zebras.id, status_without_tags.id) - expect(described_class.tagged_with_none([tag_cats.id, tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_dogs.id, status_without_tags.id) - expect(described_class.tagged_with_none([tag_dogs.id, tag_zebras.id]).reorder(:id).pluck(:id).uniq).to contain_exactly(status_with_tag_cats.id, status_without_tags.id) - end - end - end - - describe 'before_validation' do - it 'sets account being replied to correctly over intermediary nodes' do - first_status = Fabricate(:status, account: bob) - intermediary = Fabricate(:status, thread: first_status, account: alice) - final = Fabricate(:status, thread: intermediary, account: alice) - - expect(final.in_reply_to_account_id).to eq bob.id - end - - it 'creates new conversation for stand-alone status' do - expect(described_class.create(account: alice, text: 'First').conversation_id).to_not be_nil - end - - it 'keeps conversation of parent node' do - parent = Fabricate(:status, text: 'First') - expect(described_class.create(account: alice, thread: parent, text: 'Response').conversation_id).to eq parent.conversation_id - end - - it 'sets `local` to true for status by local account' do - expect(described_class.create(account: alice, text: 'foo').local).to be true - end - - it 'sets `local` to false for status by remote account' do - alice.update(domain: 'example.com') - expect(described_class.create(account: alice, text: 'foo').local).to be false - end - end - - describe 'validation' do - it 'disallow empty uri for remote status' do - alice.update(domain: 'example.com') - status = Fabricate.build(:status, uri: '', account: alice) - expect(status).to model_have_error_on_field(:uri) - end - end - - describe 'after_create' do - it 'saves ActivityPub uri as uri for local status' do - status = described_class.create(account: alice, text: 'foo') - status.reload - expect(status.uri).to start_with('https://') - end - end -end diff --git a/spec/models/tag_feed_spec.rb b/spec/models/tag_feed_spec.rb deleted file mode 100644 index e836144f0..000000000 --- a/spec/models/tag_feed_spec.rb +++ /dev/null @@ -1,84 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe TagFeed, type: :service do - describe '#get' do - let(:account) { Fabricate(:account) } - let(:tag_cats) { Fabricate(:tag, name: 'cats') } - let(:tag_dogs) { Fabricate(:tag, name: 'dogs') } - let!(:status_tagged_with_cats) { Fabricate(:status, tags: [tag_cats]) } - let!(:status_tagged_with_dogs) { Fabricate(:status, tags: [tag_dogs]) } - let!(:both) { Fabricate(:status, tags: [tag_cats, tag_dogs]) } - - it 'can add tags in "any" mode' do - results = described_class.new(tag_cats, nil, any: [tag_dogs.name]).get(20) - expect(results).to include status_tagged_with_cats - expect(results).to include status_tagged_with_dogs - expect(results).to include both - end - - it 'can remove tags in "all" mode' do - results = described_class.new(tag_cats, nil, all: [tag_dogs.name]).get(20) - expect(results).to_not include status_tagged_with_cats - expect(results).to_not include status_tagged_with_dogs - expect(results).to include both - end - - it 'can remove tags in "none" mode' do - results = described_class.new(tag_cats, nil, none: [tag_dogs.name]).get(20) - expect(results).to include status_tagged_with_cats - expect(results).to_not include status_tagged_with_dogs - expect(results).to_not include both - end - - it 'ignores an invalid mode' do - results = described_class.new(tag_cats, nil, wark: [tag_dogs.name]).get(20) - expect(results).to include status_tagged_with_cats - expect(results).to_not include status_tagged_with_dogs - expect(results).to include both - end - - it 'handles being passed non existent tag names' do - results = described_class.new(tag_cats, nil, any: ['wark']).get(20) - expect(results).to include status_tagged_with_cats - expect(results).to_not include status_tagged_with_dogs - expect(results).to include both - end - - it 'can restrict to an account' do - BlockService.new.call(account, status_tagged_with_cats.account) - results = described_class.new(tag_cats, account, none: [tag_dogs.name]).get(20) - expect(results).to_not include status_tagged_with_cats - end - - it 'can restrict to local' do - status_tagged_with_cats.account.update(domain: 'example.com') - status_tagged_with_cats.update(local: false, uri: 'example.com/toot') - results = described_class.new(tag_cats, nil, any: [tag_dogs.name], local: true).get(20) - expect(results).to_not include status_tagged_with_cats - end - - it 'allows replies to be included' do - original = Fabricate(:status) - status = Fabricate(:status, tags: [tag_cats], in_reply_to_id: original.id) - - results = described_class.new(tag_cats, nil).get(20) - expect(results).to include(status) - end - - context 'when the feed contains a local-only status' do - let!(:status) { Fabricate(:status, tags: [tag_cats], local_only: true) } - - it 'does not show local-only statuses without a viewer' do - results = described_class.new(tag_cats, nil).get(20) - expect(results).to_not include(status) - end - - it 'shows local-only statuses given a viewer' do - results = described_class.new(tag_cats, account).get(20) - expect(results).to include(status) - end - end - end -end diff --git a/spec/models/tag_spec.rb b/spec/models/tag_spec.rb deleted file mode 100644 index 4d6e5c380..000000000 --- a/spec/models/tag_spec.rb +++ /dev/null @@ -1,173 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Tag do - describe 'validations' do - it 'invalid with #' do - expect(described_class.new(name: '#hello_world')).to_not be_valid - end - - it 'invalid with .' do - expect(described_class.new(name: '.abcdef123')).to_not be_valid - end - - it 'invalid with spaces' do - expect(described_class.new(name: 'hello world')).to_not be_valid - end - - it 'valid with aesthetic' do - expect(described_class.new(name: 'aesthetic')).to be_valid - end - end - - describe 'HASHTAG_RE' do - subject { Tag::HASHTAG_RE } - - it 'does not match URLs with anchors with non-hashtag characters' do - expect(subject.match('Check this out https://medium.com/@alice/some-article#.abcdef123')).to be_nil - end - - it 'does not match URLs with hashtag-like anchors' do - expect(subject.match('https://en.wikipedia.org/wiki/Ghostbusters_(song)#Lawsuit')).to be_nil - end - - it 'matches #aesthetic' do - expect(subject.match('this is #aesthetic').to_s).to eq ' #aesthetic' - end - - it 'matches digits at the start' do - expect(subject.match('hello #3d').to_s).to eq ' #3d' - end - - it 'matches digits in the middle' do - expect(subject.match('hello #l33ts35k').to_s).to eq ' #l33ts35k' - end - - it 'matches digits at the end' do - expect(subject.match('hello #world2016').to_s).to eq ' #world2016' - end - - it 'matches underscores at the beginning' do - expect(subject.match('hello #_test').to_s).to eq ' #_test' - end - - it 'matches underscores at the end' do - expect(subject.match('hello #test_').to_s).to eq ' #test_' - end - - it 'matches underscores in the middle' do - expect(subject.match('hello #one_two_three').to_s).to eq ' #one_two_three' - end - - it 'matches middle dots' do - expect(subject.match('hello #one·two·three').to_s).to eq ' #one·two·three' - end - - it 'matches ・unicode in ぼっち・ざ・ろっく correctly' do - expect(subject.match('testing #ぼっち・ざ・ろっく').to_s).to eq ' #ぼっち・ざ・ろっく' - end - - it 'matches ZWNJ' do - expect(subject.match('just add #نرم‌افزار and').to_s).to eq ' #نرم‌افزار' - end - - it 'does not match middle dots at the start' do - expect(subject.match('hello #·one·two·three')).to be_nil - end - - it 'does not match middle dots at the end' do - expect(subject.match('hello #one·two·three·').to_s).to eq ' #one·two·three' - end - - it 'does not match purely-numeric hashtags' do - expect(subject.match('hello #0123456')).to be_nil - end - end - - describe '#to_param' do - it 'returns name' do - tag = Fabricate(:tag, name: 'foo') - expect(tag.to_param).to eq 'foo' - end - end - - describe '.find_normalized' do - it 'returns tag for a multibyte case-insensitive name' do - upcase_string = 'abcABCabcABCやゆよ' - downcase_string = 'abcabcabcabcやゆよ' - - tag = Fabricate(:tag, name: HashtagNormalizer.new.normalize(downcase_string)) - expect(described_class.find_normalized(upcase_string)).to eq tag - end - end - - describe '.matches_name' do - it 'returns tags for multibyte case-insensitive names' do - upcase_string = 'abcABCabcABCやゆよ' - downcase_string = 'abcabcabcabcやゆよ' - - tag = Fabricate(:tag, name: HashtagNormalizer.new.normalize(downcase_string)) - expect(described_class.matches_name(upcase_string)).to eq [tag] - end - - it 'uses the LIKE operator' do - result = %q[SELECT "tags".* FROM "tags" WHERE LOWER("tags"."name") LIKE LOWER('100abc%')] - expect(described_class.matches_name('100%abc').to_sql).to eq result - end - end - - describe '.matching_name' do - it 'returns tags for multibyte case-insensitive names' do - upcase_string = 'abcABCabcABCやゆよ' - downcase_string = 'abcabcabcabcやゆよ' - - tag = Fabricate(:tag, name: HashtagNormalizer.new.normalize(downcase_string)) - expect(described_class.matching_name(upcase_string)).to eq [tag] - end - end - - describe '.find_or_create_by_names' do - let(:upcase_string) { 'abcABCabcABCやゆよ' } - let(:downcase_string) { 'abcabcabcabcやゆよ' } - - it 'runs a passed block once per tag regardless of duplicates' do - count = 0 - - described_class.find_or_create_by_names([upcase_string, downcase_string]) do |_tag| - count += 1 - end - - expect(count).to eq 1 - end - end - - describe '.search_for' do - it 'finds tag records with matching names' do - tag = Fabricate(:tag, name: 'match') - _miss_tag = Fabricate(:tag, name: 'miss') - - results = described_class.search_for('match') - - expect(results).to eq [tag] - end - - it 'finds tag records in case insensitive' do - tag = Fabricate(:tag, name: 'MATCH') - _miss_tag = Fabricate(:tag, name: 'miss') - - results = described_class.search_for('match') - - expect(results).to eq [tag] - end - - it 'finds the exact matching tag as the first item' do - similar_tag = Fabricate(:tag, name: 'matchlater', reviewed_at: Time.now.utc) - tag = Fabricate(:tag, name: 'match', reviewed_at: Time.now.utc) - - results = described_class.search_for('match') - - expect(results).to eq [tag, similar_tag] - end - end -end diff --git a/spec/models/trends/statuses_spec.rb b/spec/models/trends/statuses_spec.rb deleted file mode 100644 index 7c30b5b99..000000000 --- a/spec/models/trends/statuses_spec.rb +++ /dev/null @@ -1,115 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Trends::Statuses do - subject! { described_class.new(threshold: 5, review_threshold: 10, score_halflife: 8.hours) } - - let!(:at_time) { DateTime.new(2021, 11, 14, 10, 15, 0) } - - describe 'Trends::Statuses::Query' do - let!(:query) { subject.query } - let!(:today) { at_time } - - let!(:status_foo) { Fabricate(:status, text: 'Foo', language: 'en', trendable: true, created_at: today) } - let!(:status_bar) { Fabricate(:status, text: 'Bar', language: 'en', trendable: true, created_at: today) } - - before do - default_threshold_value.times { reblog(status_foo, today) } - default_threshold_value.times { reblog(status_bar, today) } - - subject.refresh(today) - end - - describe '#filtered_for' do - let(:account) { Fabricate(:account) } - - it 'returns a composable query scope' do - expect(query.filtered_for(account)).to be_a Trends::Query - end - - it 'filters out blocked accounts' do - account.block!(status_foo.account) - expect(query.filtered_for(account).to_a).to eq [status_bar] - end - - it 'filters out muted accounts' do - account.mute!(status_bar.account) - expect(query.filtered_for(account).to_a).to eq [status_foo] - end - - it 'filters out blocked-by accounts' do - status_foo.account.block!(account) - expect(query.filtered_for(account).to_a).to eq [status_bar] - end - end - end - - describe '#add' do - let(:status) { Fabricate(:status) } - - before do - subject.add(status, 1, at_time) - end - - it 'records use' do - expect(subject.send(:recently_used_ids, at_time)).to eq [status.id] - end - end - - describe '#query' do - it 'returns a composable query scope' do - expect(subject.query).to be_a Trends::Query - end - - it 'responds to filtered_for' do - expect(subject.query).to respond_to(:filtered_for) - end - end - - describe '#refresh' do - let!(:today) { at_time } - let!(:yesterday) { today - 1.day } - - let!(:status_foo) { Fabricate(:status, text: 'Foo', language: 'en', trendable: true, created_at: yesterday) } - let!(:status_bar) { Fabricate(:status, text: 'Bar', language: 'en', trendable: true, created_at: today) } - let!(:status_baz) { Fabricate(:status, text: 'Baz', language: 'en', trendable: true, created_at: today) } - - before do - default_threshold_value.times { reblog(status_foo, today) } - default_threshold_value.times { reblog(status_bar, today) } - (default_threshold_value - 1).times { reblog(status_baz, today) } - end - - context 'when status trends are refreshed' do - before do - subject.refresh(today) - end - - it 'returns correct statuses from query' do - results = subject.query.limit(10).to_a - - expect(results).to eq [status_bar, status_foo] - expect(results).to_not include(status_baz) - end - end - - it 'decays scores' do - subject.refresh(today) - original_score = status_bar.trend.score - expect(original_score).to be_a Float - subject.refresh(today + subject.options[:score_halflife]) - decayed_score = status_bar.trend.reload.score - expect(decayed_score).to be <= original_score / 2 - end - end - - def reblog(status, at_time) - reblog = Fabricate(:status, reblog: status, created_at: at_time) - subject.add(status, reblog.account_id, at_time) - end - - def default_threshold_value - described_class.default_options[:threshold] - end -end diff --git a/spec/models/trends/tags_spec.rb b/spec/models/trends/tags_spec.rb deleted file mode 100644 index f2818fca8..000000000 --- a/spec/models/trends/tags_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Trends::Tags do - subject { described_class.new(threshold: 5, review_threshold: 10) } - - let!(:at_time) { DateTime.new(2021, 11, 14, 10, 15, 0) } - - describe '#add' do - let(:tag) { Fabricate(:tag) } - - before do - subject.add(tag, 1, at_time) - end - - it 'records history' do - expect(tag.history.get(at_time).accounts).to eq 1 - end - - it 'records use' do - expect(subject.send(:recently_used_ids, at_time)).to eq [tag.id] - end - end - - describe '#query' do - it 'returns a composable query scope' do - expect(subject.query).to be_a Trends::Query - end - end - - describe '#refresh' do - let!(:today) { at_time } - let!(:yesterday) { today - 1.day } - - let!(:tag_cats) { Fabricate(:tag, name: 'Catstodon', trendable: true) } - let!(:tag_dogs) { Fabricate(:tag, name: 'DogsOfMastodon', trendable: true) } - let!(:tag_ocs) { Fabricate(:tag, name: 'OCs', trendable: true) } - - before do - 2.times { |i| subject.add(tag_cats, i, yesterday) } - 13.times { |i| subject.add(tag_ocs, i, yesterday) } - 16.times { |i| subject.add(tag_cats, i, today) } - 4.times { |i| subject.add(tag_dogs, i, today) } - end - - context 'when tag trends are refreshed' do - before do - subject.refresh(yesterday + 12.hours) - subject.refresh(at_time) - end - - it 'calculates and re-calculates scores' do - expect(subject.query.limit(10).to_a).to eq [tag_cats, tag_ocs] - end - - it 'omits hashtags below threshold' do - expect(subject.query.limit(10).to_a).to_not include(tag_dogs) - end - end - - it 'decays scores' do - subject.refresh(yesterday + 12.hours) - original_score = subject.score(tag_ocs.id) - expect(original_score).to eq 144.0 - subject.refresh(yesterday + 12.hours + subject.options[:max_score_halflife]) - decayed_score = subject.score(tag_ocs.id) - expect(decayed_score).to be <= original_score / 2 - end - end -end diff --git a/spec/models/user_role_spec.rb b/spec/models/user_role_spec.rb deleted file mode 100644 index f7cfe9bb0..000000000 --- a/spec/models/user_role_spec.rb +++ /dev/null @@ -1,189 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe UserRole do - subject { described_class.create(name: 'Foo', position: 1) } - - describe '#can?' do - context 'with a single flag' do - it 'returns true if any of them are present' do - subject.permissions = UserRole::FLAGS[:manage_reports] - expect(subject.can?(:manage_reports)).to be true - end - - it 'returns false if it is not set' do - expect(subject.can?(:manage_reports)).to be false - end - end - - context 'with multiple flags' do - it 'returns true if any of them are present' do - subject.permissions = UserRole::FLAGS[:manage_users] - expect(subject.can?(:manage_reports, :manage_users)).to be true - end - - it 'returns false if none of them are present' do - expect(subject.can?(:manage_reports, :manage_users)).to be false - end - end - - context 'with an unknown flag' do - it 'raises an error' do - expect { subject.can?(:foo) }.to raise_error ArgumentError - end - end - end - - describe '#overrides?' do - it 'returns true if other role has lower position' do - expect(subject.overrides?(described_class.new(position: subject.position - 1))).to be true - end - - it 'returns true if other role is nil' do - expect(subject.overrides?(nil)).to be true - end - - it 'returns false if other role has higher position' do - expect(subject.overrides?(described_class.new(position: subject.position + 1))).to be false - end - end - - describe '#permissions_as_keys' do - before do - subject.permissions = UserRole::FLAGS[:invite_users] | UserRole::FLAGS[:view_dashboard] | UserRole::FLAGS[:manage_reports] - end - - it 'returns an array' do - expect(subject.permissions_as_keys).to match_array %w(invite_users view_dashboard manage_reports) - end - end - - describe '#permissions_as_keys=' do - let(:input) {} - - before do - subject.permissions_as_keys = input - end - - context 'with a single value' do - let(:input) { %w(manage_users) } - - it 'sets permission flags' do - expect(subject.permissions).to eq UserRole::FLAGS[:manage_users] - end - end - - context 'with multiple values' do - let(:input) { %w(manage_users manage_reports) } - - it 'sets permission flags' do - expect(subject.permissions).to eq UserRole::FLAGS[:manage_users] | UserRole::FLAGS[:manage_reports] - end - end - - context 'with an unknown value' do - let(:input) { %w(foo) } - - it 'does not set permission flags' do - expect(subject.permissions).to eq UserRole::Flags::NONE - end - end - end - - describe '#computed_permissions' do - context 'when the role is nobody' do - subject { described_class.nobody } - - it 'returns none' do - expect(subject.computed_permissions).to eq UserRole::Flags::NONE - end - end - - context 'when the role is everyone' do - subject { described_class.everyone } - - it 'returns permissions' do - expect(subject.computed_permissions).to eq subject.permissions - end - end - - context 'when role has the administrator flag' do - before do - subject.permissions = UserRole::FLAGS[:administrator] - end - - it 'returns all permissions' do - expect(subject.computed_permissions).to eq UserRole::Flags::ALL - end - end - - it 'returns permissions combined with the everyone role' do - expect(subject.computed_permissions).to eq described_class.everyone.permissions - end - end - - describe '.everyone' do - subject { described_class.everyone } - - it 'returns a role' do - expect(subject).to be_a(described_class) - end - - it 'is identified as the everyone role' do - expect(subject.everyone?).to be true - end - - it 'has default permissions' do - expect(subject.permissions).to eq UserRole::FLAGS[:invite_users] - end - - it 'has negative position' do - expect(subject.position).to eq(-1) - end - end - - describe '.nobody' do - subject { described_class.nobody } - - it 'returns a role' do - expect(subject).to be_a(described_class) - end - - it 'is identified as the nobody role' do - expect(subject.nobody?).to be true - end - - it 'has no permissions' do - expect(subject.permissions).to eq UserRole::Flags::NONE - end - - it 'has negative position' do - expect(subject.position).to eq(-1) - end - end - - describe '#everyone?' do - it 'returns true when id is -99' do - subject.id = -99 - expect(subject.everyone?).to be true - end - - it 'returns false when id is not -99' do - subject.id = 123 - expect(subject.everyone?).to be false - end - end - - describe '#nobody?' do - it 'returns true when id is nil' do - subject.id = nil - expect(subject.nobody?).to be true - end - - it 'returns false when id is not nil' do - subject.id = 123 - expect(subject.nobody?).to be false - end - end -end diff --git a/spec/models/user_settings/namespace_spec.rb b/spec/models/user_settings/namespace_spec.rb deleted file mode 100644 index ae2fa7b48..000000000 --- a/spec/models/user_settings/namespace_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe UserSettings::Namespace do - subject { described_class.new(name) } - - let(:name) { :foo } - - describe '#setting' do - before do - subject.setting :bar, default: 'baz' - end - - it 'adds setting to definitions' do - expect(subject.definitions[:'foo.bar']).to have_attributes(name: :bar, namespace: :foo, default_value: 'baz') - end - end - - describe '#definitions' do - it 'returns a hash' do - expect(subject.definitions).to be_a Hash - end - end -end diff --git a/spec/models/user_settings/setting_spec.rb b/spec/models/user_settings/setting_spec.rb deleted file mode 100644 index 8c8d31ec5..000000000 --- a/spec/models/user_settings/setting_spec.rb +++ /dev/null @@ -1,106 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe UserSettings::Setting do - subject { described_class.new(name, options) } - - let(:name) { :foo } - let(:options) { { default: default, namespace: namespace } } - let(:default) { false } - let(:namespace) { nil } - - describe '#default_value' do - context 'when default value is a primitive value' do - it 'returns default value' do - expect(subject.default_value).to eq default - end - end - - context 'when default value is a proc' do - let(:default) { -> { 'bar' } } - - it 'returns value from proc' do - expect(subject.default_value).to eq 'bar' - end - end - end - - describe '#type' do - it 'returns a type' do - expect(subject.type).to be_a ActiveModel::Type::Value - end - - context 'when default value is a boolean' do - let(:default) { false } - - it 'returns boolean' do - expect(subject.type).to be_a ActiveModel::Type::Boolean - end - end - - context 'when default value is a string' do - let(:default) { '' } - - it 'returns string' do - expect(subject.type).to be_a ActiveModel::Type::String - end - end - - context 'when default value is a lambda returning a boolean' do - let(:default) { -> { false } } - - it 'returns boolean' do - expect(subject.type).to be_a ActiveModel::Type::Boolean - end - end - - context 'when default value is a lambda returning a string' do - let(:default) { -> { '' } } - - it 'returns boolean' do - expect(subject.type).to be_a ActiveModel::Type::String - end - end - end - - describe '#type_cast' do - context 'when default value is a boolean' do - let(:default) { false } - - it 'returns boolean' do - expect(subject.type_cast('1')).to be true - end - end - - context 'when default value is a string' do - let(:default) { '' } - - it 'returns string' do - expect(subject.type_cast(1)).to eq '1' - end - end - end - - describe '#to_a' do - it 'returns an array' do - expect(subject.to_a).to eq [name, default] - end - end - - describe '#key' do - context 'when there is no namespace' do - it 'returns a symbol' do - expect(subject.key).to eq :foo - end - end - - context 'when there is a namespace' do - let(:namespace) { :bar } - - it 'returns a symbol' do - expect(subject.key).to eq :'bar.foo' - end - end - end -end diff --git a/spec/models/user_settings_spec.rb b/spec/models/user_settings_spec.rb deleted file mode 100644 index 653597c90..000000000 --- a/spec/models/user_settings_spec.rb +++ /dev/null @@ -1,120 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe UserSettings do - subject { described_class.new(json) } - - let(:json) { {} } - - describe '#[]' do - context 'when setting is not set' do - it 'returns default value' do - expect(subject[:always_send_emails]).to be false - end - end - - context 'when setting is set' do - let(:json) { { default_language: 'fr' } } - - it 'returns value' do - expect(subject[:default_language]).to eq 'fr' - end - end - - context 'when setting was not defined' do - it 'raises error' do - expect { subject[:foo] }.to raise_error UserSettings::KeyError - end - end - end - - describe '#[]=' do - context 'when value matches type' do - before do - subject[:always_send_emails] = true - end - - it 'updates value' do - expect(subject[:always_send_emails]).to be true - end - end - - context 'when value needs to be type-cast' do - before do - subject[:always_send_emails] = '1' - end - - it 'updates value with a type-cast' do - expect(subject[:always_send_emails]).to be true - end - end - - context 'when the setting has a closed set of values' do - it 'updates the attribute when given a valid value' do - expect { subject[:'web.display_media'] = :show_all }.to change { subject[:'web.display_media'] }.from('default').to('show_all') - end - - it 'raises an error when given an invalid value' do - expect { subject[:'web.display_media'] = 'invalid value' }.to raise_error ArgumentError - end - end - end - - describe '#update' do - before do - subject.update(always_send_emails: true, default_language: 'fr', default_privacy: nil) - end - - it 'updates values' do - expect(subject[:always_send_emails]).to be true - expect(subject[:default_language]).to eq 'fr' - end - - it 'does not set values that are nil' do - expect(subject.as_json).to_not include(default_privacy: nil) - end - end - - describe '#as_json' do - let(:json) { { default_language: 'fr' } } - - it 'returns hash' do - expect(subject.as_json).to eq json - end - end - - describe '.keys' do - it 'returns an array' do - expect(described_class.keys).to be_a Array - end - end - - describe '.definition_for' do - context 'when key is defined' do - it 'returns a setting' do - expect(described_class.definition_for(:always_send_emails)).to be_a UserSettings::Setting - end - end - - context 'when key is not defined' do - it 'returns nil' do - expect(described_class.definition_for(:foo)).to be_nil - end - end - end - - describe '.definition_for?' do - context 'when key is defined' do - it 'returns true' do - expect(described_class.definition_for?(:always_send_emails)).to be true - end - end - - context 'when key is not defined' do - it 'returns false' do - expect(described_class.definition_for?(:foo)).to be false - end - end - end -end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb deleted file mode 100644 index bb61c02a6..000000000 --- a/spec/models/user_spec.rb +++ /dev/null @@ -1,554 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'devise_two_factor/spec_helpers' - -RSpec.describe User do - let(:password) { 'abcd1234' } - let(:account) { Fabricate(:account, username: 'alice') } - - it_behaves_like 'two_factor_backupable' - - describe 'otp_secret' do - it 'is encrypted with OTP_SECRET environment variable' do - user = Fabricate(:user, - encrypted_otp_secret: "Fttsy7QAa0edaDfdfSz094rRLAxc8cJweDQ4BsWH/zozcdVA8o9GLqcKhn2b\nGi/V\n", - encrypted_otp_secret_iv: 'rys3THICkr60BoWC', - encrypted_otp_secret_salt: '_LMkAGvdg7a+sDIKjI3mR2Q==') - - expect(user.otp_secret).to eq 'anotpsecretthatshouldbeencrypted' - end - end - - describe 'validations' do - it 'is invalid without an account' do - user = Fabricate.build(:user, account: nil) - user.valid? - expect(user).to model_have_error_on_field(:account) - end - - it 'is invalid without a valid locale' do - user = Fabricate.build(:user, locale: 'toto') - user.valid? - expect(user).to model_have_error_on_field(:locale) - end - - it 'is invalid without a valid email' do - user = Fabricate.build(:user, email: 'john@') - user.valid? - expect(user).to model_have_error_on_field(:email) - end - - it 'is valid with an invalid e-mail that has already been saved' do - user = Fabricate.build(:user, email: 'invalid-email') - user.save(validate: false) - expect(user.valid?).to be true - end - - it 'cleans out empty string from languages' do - user = Fabricate.build(:user, chosen_languages: ['']) - user.valid? - expect(user.chosen_languages).to be_nil - end - end - - describe 'scopes' do - describe 'recent' do - it 'returns an array of recent users ordered by id' do - user_1 = Fabricate(:user) - user_2 = Fabricate(:user) - expect(described_class.recent).to eq [user_2, user_1] - end - end - - describe 'confirmed' do - it 'returns an array of users who are confirmed' do - user_1 = Fabricate(:user, confirmed_at: nil) - user_2 = Fabricate(:user, confirmed_at: Time.zone.now) - expect(described_class.confirmed).to contain_exactly(user_2) - end - end - - describe 'inactive' do - it 'returns a relation of inactive users' do - specified = Fabricate(:user, current_sign_in_at: 15.days.ago) - Fabricate(:user, current_sign_in_at: 6.days.ago) - - expect(described_class.inactive).to contain_exactly(specified) - end - end - - describe 'matches_email' do - it 'returns a relation of users whose email starts with the given string' do - specified = Fabricate(:user, email: 'specified@spec') - Fabricate(:user, email: 'unspecified@spec') - - expect(described_class.matches_email('specified')).to contain_exactly(specified) - end - end - - describe 'matches_ip' do - it 'returns a relation of users whose ip address is matching with the given CIDR' do - user1 = Fabricate(:user) - user2 = Fabricate(:user) - Fabricate(:session_activation, user: user1, ip: '2160:2160::22', session_id: '1') - Fabricate(:session_activation, user: user1, ip: '2160:2160::23', session_id: '2') - Fabricate(:session_activation, user: user2, ip: '2160:8888::24', session_id: '3') - Fabricate(:session_activation, user: user2, ip: '2160:8888::25', session_id: '4') - - expect(described_class.matches_ip('2160:2160::/32')).to contain_exactly(user1) - end - end - end - - describe 'blacklist' do - around(:each) do |example| - old_blacklist = Rails.configuration.x.email_blacklist - - Rails.configuration.x.email_domains_blacklist = 'mvrht.com' - - example.run - - Rails.configuration.x.email_domains_blacklist = old_blacklist - end - - it 'allows a non-blacklisted user to be created' do - user = described_class.new(email: 'foo@example.com', account: account, password: password, agreement: true) - - expect(user).to be_valid - end - - it 'does not allow a blacklisted user to be created' do - user = described_class.new(email: 'foo@mvrht.com', account: account, password: password, agreement: true) - - expect(user).to_not be_valid - end - - it 'does not allow a subdomain blacklisted user to be created' do - user = described_class.new(email: 'foo@mvrht.com.topdomain.tld', account: account, password: password, agreement: true) - - expect(user).to_not be_valid - end - end - - describe '#confirmed?' do - it 'returns true when a confirmed_at is set' do - user = Fabricate.build(:user, confirmed_at: Time.now.utc) - expect(user.confirmed?).to be true - end - - it 'returns false if a confirmed_at is nil' do - user = Fabricate.build(:user, confirmed_at: nil) - expect(user.confirmed?).to be false - end - end - - describe '#confirm' do - subject { user.confirm } - - let(:new_email) { 'new-email@example.com' } - - before do - allow(TriggerWebhookWorker).to receive(:perform_async) - end - - context 'when the user is already confirmed' do - let!(:user) { Fabricate(:user, confirmed_at: Time.now.utc, approved: true, unconfirmed_email: new_email) } - - it 'sets email to unconfirmed_email' do - expect { subject }.to change { user.reload.email }.to(new_email) - end - - it 'does not trigger the account.approved Web Hook' do - subject - expect(TriggerWebhookWorker).to_not have_received(:perform_async).with('account.approved', 'Account', user.account_id) - end - end - - context 'when the user is a new user' do - let(:user) { Fabricate(:user, confirmed_at: nil, unconfirmed_email: new_email) } - - context 'when the user is already approved' do - around(:example) do |example| - registrations_mode = Setting.registrations_mode - Setting.registrations_mode = 'approved' - - example.run - - Setting.registrations_mode = registrations_mode - end - - before do - user.approve! - end - - it 'sets email to unconfirmed_email' do - expect { subject }.to change { user.reload.email }.to(new_email) - end - - it 'triggers the account.approved Web Hook' do - user.confirm - expect(TriggerWebhookWorker).to have_received(:perform_async).with('account.approved', 'Account', user.account_id).once - end - end - - context 'when the user does not require explicit approval' do - around(:example) do |example| - registrations_mode = Setting.registrations_mode - Setting.registrations_mode = 'open' - - example.run - - Setting.registrations_mode = registrations_mode - end - - it 'sets email to unconfirmed_email' do - expect { subject }.to change { user.reload.email }.to(new_email) - end - - it 'triggers the account.approved Web Hook' do - user.confirm - expect(TriggerWebhookWorker).to have_received(:perform_async).with('account.approved', 'Account', user.account_id).once - end - end - - context 'when the user requires explicit approval but is not approved' do - around(:example) do |example| - registrations_mode = Setting.registrations_mode - Setting.registrations_mode = 'approved' - - example.run - - Setting.registrations_mode = registrations_mode - end - - it 'sets email to unconfirmed_email' do - expect { subject }.to change { user.reload.email }.to(new_email) - end - - it 'does not trigger the account.approved Web Hook' do - subject - expect(TriggerWebhookWorker).to_not have_received(:perform_async).with('account.approved', 'Account', user.account_id) - end - end - end - end - - describe '#approve!' do - subject { user.approve! } - - around(:example) do |example| - registrations_mode = Setting.registrations_mode - Setting.registrations_mode = 'approved' - - example.run - - Setting.registrations_mode = registrations_mode - end - - before do - allow(TriggerWebhookWorker).to receive(:perform_async) - end - - context 'when the user is already confirmed' do - let(:user) { Fabricate(:user, confirmed_at: Time.now.utc, approved: false) } - - it 'sets the approved flag' do - expect { subject }.to change { user.reload.approved? }.to(true) - end - - it 'triggers the account.approved Web Hook' do - subject - expect(TriggerWebhookWorker).to have_received(:perform_async).with('account.approved', 'Account', user.account_id).once - end - end - - context 'when the user is not confirmed' do - let(:user) { Fabricate(:user, confirmed_at: nil, approved: false) } - - it 'sets the approved flag' do - expect { subject }.to change { user.reload.approved? }.to(true) - end - - it 'does not trigger the account.approved Web Hook' do - subject - expect(TriggerWebhookWorker).to_not have_received(:perform_async).with('account.approved', 'Account', user.account_id) - end - end - end - - describe '#disable_two_factor!' do - it 'saves false for otp_required_for_login' do - user = Fabricate.build(:user, otp_required_for_login: true) - user.disable_two_factor! - expect(user.reload.otp_required_for_login).to be false - end - - it 'saves nil for otp_secret' do - user = Fabricate.build(:user, otp_secret: 'oldotpcode') - user.disable_two_factor! - expect(user.reload.otp_secret).to be_nil - end - - it 'saves cleared otp_backup_codes' do - user = Fabricate.build(:user, otp_backup_codes: %w(dummy dummy)) - user.disable_two_factor! - expect(user.reload.otp_backup_codes.empty?).to be true - end - end - - describe '#send_confirmation_instructions' do - around do |example| - queue_adapter = ActiveJob::Base.queue_adapter - example.run - ActiveJob::Base.queue_adapter = queue_adapter - end - - it 'delivers confirmation instructions later' do - user = Fabricate(:user) - ActiveJob::Base.queue_adapter = :test - - expect { user.send_confirmation_instructions }.to have_enqueued_job(ActionMailer::MailDeliveryJob) - end - end - - describe 'settings' do - it 'is instance of UserSettings' do - user = Fabricate(:user) - expect(user.settings).to be_a UserSettings - end - end - - describe '#setting_default_privacy' do - it 'returns default privacy setting if user has configured' do - user = Fabricate(:user) - user.settings[:default_privacy] = 'unlisted' - expect(user.setting_default_privacy).to eq 'unlisted' - end - - it "returns 'private' if user has not configured default privacy setting and account is locked" do - user = Fabricate(:account, locked: true).user - expect(user.setting_default_privacy).to eq 'private' - end - - it "returns 'public' if user has not configured default privacy setting and account is not locked" do - user = Fabricate(:account, locked: false).user - expect(user.setting_default_privacy).to eq 'public' - end - end - - describe 'whitelist' do - around(:each) do |example| - old_whitelist = Rails.configuration.x.email_domains_whitelist - - Rails.configuration.x.email_domains_whitelist = 'mastodon.space' - - example.run - - Rails.configuration.x.email_domains_whitelist = old_whitelist - end - - it 'does not allow a user to be created unless they are whitelisted' do - user = described_class.new(email: 'foo@example.com', account: account, password: password, agreement: true) - expect(user).to_not be_valid - end - - it 'allows a user to be created if they are whitelisted' do - user = described_class.new(email: 'foo@mastodon.space', account: account, password: password, agreement: true) - expect(user).to be_valid - end - - it 'does not allow a user with a whitelisted top domain as subdomain in their email address to be created' do - user = described_class.new(email: 'foo@mastodon.space.userdomain.com', account: account, password: password, agreement: true) - expect(user).to_not be_valid - end - - context 'with a blacklisted subdomain' do - around do |example| - old_blacklist = Rails.configuration.x.email_blacklist - example.run - Rails.configuration.x.email_domains_blacklist = old_blacklist - end - - it 'does not allow a user to be created with a specific blacklisted subdomain even if the top domain is whitelisted' do - Rails.configuration.x.email_domains_blacklist = 'blacklisted.mastodon.space' - - user = described_class.new(email: 'foo@blacklisted.mastodon.space', account: account, password: password) - expect(user).to_not be_valid - end - end - end - - describe 'token_for_app' do - let(:user) { Fabricate(:user) } - let(:app) { Fabricate(:application, owner: user) } - - it 'returns a token' do - expect(user.token_for_app(app)).to be_a(Doorkeeper::AccessToken) - end - - it 'persists a token' do - t = user.token_for_app(app) - expect(user.token_for_app(app)).to eql(t) - end - - it 'is nil if user does not own app' do - app.update!(owner: nil) - - expect(user.token_for_app(app)).to be_nil - end - end - - describe '#disable!' do - subject(:user) { Fabricate(:user, disabled: false, current_sign_in_at: current_sign_in_at, last_sign_in_at: nil) } - - let(:current_sign_in_at) { Time.zone.now } - - before do - user.disable! - end - - it 'disables user' do - expect(user).to have_attributes(disabled: true) - end - end - - describe '#enable!' do - subject(:user) { Fabricate(:user, disabled: true) } - - before do - user.enable! - end - - it 'enables user' do - expect(user).to have_attributes(disabled: false) - end - end - - describe '#reset_password!' do - subject(:user) { Fabricate(:user, password: 'foobar12345') } - - let!(:session_activation) { Fabricate(:session_activation, user: user) } - let!(:access_token) { Fabricate(:access_token, resource_owner_id: user.id) } - let!(:web_push_subscription) { Fabricate(:web_push_subscription, access_token: access_token) } - - before do - user.reset_password! - end - - it 'changes the password immediately' do - expect(user.external_or_valid_password?('foobar12345')).to be false - end - - it 'deactivates all sessions' do - expect(user.session_activations.count).to eq 0 - end - - it 'revokes all access tokens' do - expect(Doorkeeper::AccessToken.active_for(user).count).to eq 0 - end - - it 'removes push subscriptions' do - expect(Web::PushSubscription.where(user: user).or(Web::PushSubscription.where(access_token: access_token)).count).to eq 0 - end - end - - describe '#confirm!' do - subject(:user) { Fabricate(:user, confirmed_at: confirmed_at) } - - before do - ActionMailer::Base.deliveries.clear - user.confirm! - end - - after { ActionMailer::Base.deliveries.clear } - - context 'when user is new' do - let(:confirmed_at) { nil } - - it 'confirms user' do - expect(user.confirmed_at).to be_present - end - - it 'delivers mails' do - expect(ActionMailer::Base.deliveries.count).to eq 2 - end - end - - context 'when user is not new' do - let(:confirmed_at) { Time.zone.now } - - it 'confirms user' do - expect(user.confirmed_at).to be_present - end - - it 'does not deliver mail' do - expect(ActionMailer::Base.deliveries.count).to eq 0 - end - end - end - - describe '#active_for_authentication?' do - subject { user.active_for_authentication? } - - let(:user) { Fabricate(:user, disabled: disabled, confirmed_at: confirmed_at) } - - context 'when user is disabled' do - let(:disabled) { true } - - context 'when user is confirmed' do - let(:confirmed_at) { Time.zone.now } - - it { is_expected.to be true } - end - - context 'when user is not confirmed' do - let(:confirmed_at) { nil } - - it { is_expected.to be true } - end - end - - context 'when user is not disabled' do - let(:disabled) { false } - - context 'when user is confirmed' do - let(:confirmed_at) { Time.zone.now } - - it { is_expected.to be true } - end - - context 'when user is not confirmed' do - let(:confirmed_at) { nil } - - it { is_expected.to be true } - end - end - end - - describe '.those_who_can' do - before { Fabricate(:user, role: UserRole.find_by(name: 'Moderator')) } - - context 'when there are not any user roles' do - before { UserRole.destroy_all } - - it 'returns an empty list' do - expect(described_class.those_who_can(:manage_blocks)).to eq([]) - end - end - - context 'when there are not users with the needed role' do - it 'returns an empty list' do - expect(described_class.those_who_can(:manage_blocks)).to eq([]) - end - end - - context 'when there are users with roles' do - let!(:admin_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - - it 'returns the users with the role' do - expect(described_class.those_who_can(:manage_blocks)).to eq([admin_user]) - end - end - end -end diff --git a/spec/models/web/push_subscription_spec.rb b/spec/models/web/push_subscription_spec.rb deleted file mode 100644 index 3c2cd3bac..000000000 --- a/spec/models/web/push_subscription_spec.rb +++ /dev/null @@ -1,96 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Web::PushSubscription do - subject { described_class.new(data: data) } - - let(:account) { Fabricate(:account) } - - let(:policy) { 'all' } - - let(:data) do - { - policy: policy, - - alerts: { - mention: true, - reblog: false, - follow: true, - follow_request: false, - favourite: true, - }, - } - end - - describe '#pushable?' do - let(:notification_type) { :mention } - let(:notification) { Fabricate(:notification, account: account, type: notification_type) } - - %i(mention reblog follow follow_request favourite).each do |type| - context "when notification is a #{type}" do - let(:notification_type) { type } - - it 'returns boolean corresponding to alert setting' do - expect(subject.pushable?(notification)).to eq data[:alerts][type] - end - end - end - - context 'when policy is all' do - let(:policy) { 'all' } - - it 'returns true' do - expect(subject.pushable?(notification)).to be true - end - end - - context 'when policy is none' do - let(:policy) { 'none' } - - it 'returns false' do - expect(subject.pushable?(notification)).to be false - end - end - - context 'when policy is followed' do - let(:policy) { 'followed' } - - context 'when notification is from someone you follow' do - before do - account.follow!(notification.from_account) - end - - it 'returns true' do - expect(subject.pushable?(notification)).to be true - end - end - - context 'when notification is not from someone you follow' do - it 'returns false' do - expect(subject.pushable?(notification)).to be false - end - end - end - - context 'when policy is follower' do - let(:policy) { 'follower' } - - context 'when notification is from someone who follows you' do - before do - notification.from_account.follow!(account) - end - - it 'returns true' do - expect(subject.pushable?(notification)).to be true - end - end - - context 'when notification is not from someone who follows you' do - it 'returns false' do - expect(subject.pushable?(notification)).to be false - end - end - end - end -end diff --git a/spec/models/webauthn_credentials_spec.rb b/spec/models/webauthn_credentials_spec.rb deleted file mode 100644 index 4579ebb82..000000000 --- a/spec/models/webauthn_credentials_spec.rb +++ /dev/null @@ -1,82 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe WebauthnCredential do - describe 'validations' do - it 'is invalid without an external id' do - webauthn_credential = Fabricate.build(:webauthn_credential, external_id: nil) - - webauthn_credential.valid? - - expect(webauthn_credential).to model_have_error_on_field(:external_id) - end - - it 'is invalid without a public key' do - webauthn_credential = Fabricate.build(:webauthn_credential, public_key: nil) - - webauthn_credential.valid? - - expect(webauthn_credential).to model_have_error_on_field(:public_key) - end - - it 'is invalid without a nickname' do - webauthn_credential = Fabricate.build(:webauthn_credential, nickname: nil) - - webauthn_credential.valid? - - expect(webauthn_credential).to model_have_error_on_field(:nickname) - end - - it 'is invalid without a sign_count' do - webauthn_credential = Fabricate.build(:webauthn_credential, sign_count: nil) - - webauthn_credential.valid? - - expect(webauthn_credential).to model_have_error_on_field(:sign_count) - end - - it 'is invalid if already exist a webauthn credential with the same external id' do - existing_webauthn_credential = Fabricate(:webauthn_credential, external_id: '_Typ0ygudDnk9YUVWLQayw') - new_webauthn_credential = Fabricate.build(:webauthn_credential, external_id: '_Typ0ygudDnk9YUVWLQayw') - - new_webauthn_credential.valid? - - expect(new_webauthn_credential).to model_have_error_on_field(:external_id) - end - - it 'is invalid if user already registered a webauthn credential with the same nickname' do - user = Fabricate(:user) - existing_webauthn_credential = Fabricate(:webauthn_credential, user_id: user.id, nickname: 'USB Key') - new_webauthn_credential = Fabricate.build(:webauthn_credential, user_id: user.id, nickname: 'USB Key') - - new_webauthn_credential.valid? - - expect(new_webauthn_credential).to model_have_error_on_field(:nickname) - end - - it 'is invalid if sign_count is not a number' do - webauthn_credential = Fabricate.build(:webauthn_credential, sign_count: 'invalid sign_count') - - webauthn_credential.valid? - - expect(webauthn_credential).to model_have_error_on_field(:sign_count) - end - - it 'is invalid if sign_count is negative number' do - webauthn_credential = Fabricate.build(:webauthn_credential, sign_count: -1) - - webauthn_credential.valid? - - expect(webauthn_credential).to model_have_error_on_field(:sign_count) - end - - it 'is invalid if sign_count is greater 2**63 - 1' do - webauthn_credential = Fabricate.build(:webauthn_credential, sign_count: 2**63) - - webauthn_credential.valid? - - expect(webauthn_credential).to model_have_error_on_field(:sign_count) - end - end -end diff --git a/spec/models/webhook_spec.rb b/spec/models/webhook_spec.rb deleted file mode 100644 index 715dd7574..000000000 --- a/spec/models/webhook_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe Webhook do - let(:webhook) { Fabricate(:webhook) } - - describe '#rotate_secret!' do - it 'changes the secret' do - previous_value = webhook.secret - webhook.rotate_secret! - expect(webhook.secret).to_not be_blank - expect(webhook.secret).to_not eq previous_value - end - end - - describe '#enable!' do - before do - webhook.disable! - end - - it 'enables the webhook' do - webhook.enable! - expect(webhook.enabled?).to be true - end - end - - describe '#disable!' do - it 'disables the webhook' do - webhook.disable! - expect(webhook.enabled?).to be false - end - end -end diff --git a/spec/policies/account_moderation_note_policy_spec.rb b/spec/policies/account_moderation_note_policy_spec.rb deleted file mode 100644 index 8c37acc39..000000000 --- a/spec/policies/account_moderation_note_policy_spec.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe AccountModerationNotePolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :create? do - context 'when staff' do - it 'grants to create' do - expect(subject).to permit(admin, described_class) - end - end - - context 'when not staff' do - it 'denies to create' do - expect(subject).to_not permit(john, described_class) - end - end - end - - permissions :destroy? do - let(:account_moderation_note) do - Fabricate(:account_moderation_note, - account: john, - target_account: Fabricate(:account)) - end - - context 'when admin' do - it 'grants to destroy' do - expect(subject).to permit(admin, account_moderation_note) - end - end - - context 'when owner' do - it 'grants to destroy' do - expect(subject).to permit(john, account_moderation_note) - end - end - - context 'when neither admin nor owner' do - let(:kevin) { Fabricate(:account) } - - it 'denies to destroy' do - expect(subject).to_not permit(kevin, account_moderation_note) - end - end - end -end diff --git a/spec/policies/account_policy_spec.rb b/spec/policies/account_policy_spec.rb deleted file mode 100644 index d7a21d8e3..000000000 --- a/spec/policies/account_policy_spec.rb +++ /dev/null @@ -1,160 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe AccountPolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - let(:alice) { Fabricate(:account) } - - permissions :index? do - context 'when staff' do - it 'permits' do - expect(subject).to permit(admin) - end - end - - context 'when not staff' do - it 'denies' do - expect(subject).to_not permit(john) - end - end - end - - permissions :show?, :unsilence?, :unsensitive?, :remove_avatar?, :remove_header? do - context 'when staff' do - it 'permits' do - expect(subject).to permit(admin, alice) - end - end - - context 'when not staff' do - it 'denies' do - expect(subject).to_not permit(john, alice) - end - end - end - - permissions :unsuspend?, :unblock_email? do - before do - alice.suspend! - end - - context 'when staff' do - it 'permits' do - expect(subject).to permit(admin, alice) - end - end - - context 'when not staff' do - it 'denies' do - expect(subject).to_not permit(john, alice) - end - end - end - - permissions :redownload? do - context 'when admin' do - it 'permits' do - expect(subject).to permit(admin) - end - end - - context 'when not admin' do - it 'denies' do - expect(subject).to_not permit(john) - end - end - end - - permissions :suspend?, :silence? do - let(:staff) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - - context 'when staff' do - context 'when record is staff' do - it 'denies' do - expect(subject).to_not permit(admin, staff) - end - end - - context 'when record is not staff' do - it 'permits' do - expect(subject).to permit(admin, john) - end - end - end - - context 'when not staff' do - it 'denies' do - expect(subject).to_not permit(john, Account) - end - end - end - - permissions :memorialize? do - let(:other_admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - - context 'when admin' do - context 'when record is admin' do - it 'denies' do - expect(subject).to_not permit(admin, other_admin) - end - end - - context 'when record is not admin' do - it 'permits' do - expect(subject).to permit(admin, john) - end - end - end - - context 'when not admin' do - it 'denies' do - expect(subject).to_not permit(john, Account) - end - end - end - - permissions :review? do - context 'when admin' do - it 'permits' do - expect(subject).to permit(admin) - end - end - - context 'when not admin' do - it 'denies' do - expect(subject).to_not permit(john) - end - end - end - - permissions :destroy? do - context 'when admin' do - context 'with a temporarily suspended account' do - before { allow(alice).to receive(:suspended_temporarily?).and_return(true) } - - it 'permits' do - expect(subject).to permit(admin, alice) - end - end - - context 'with a not temporarily suspended account' do - before { allow(alice).to receive(:suspended_temporarily?).and_return(false) } - - it 'denies' do - expect(subject).to_not permit(admin, alice) - end - end - end - - context 'when not admin' do - it 'denies' do - expect(subject).to_not permit(john, alice) - end - end - end -end diff --git a/spec/policies/account_warning_preset_policy_spec.rb b/spec/policies/account_warning_preset_policy_spec.rb deleted file mode 100644 index 63bf33de2..000000000 --- a/spec/policies/account_warning_preset_policy_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -describe AccountWarningPresetPolicy do - let(:policy) { described_class } - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :index?, :create?, :update?, :destroy? do - context 'with an admin' do - it 'permits' do - expect(policy).to permit(admin, Tag) - end - end - - context 'with a non-admin' do - it 'denies' do - expect(policy).to_not permit(john, Tag) - end - end - end -end diff --git a/spec/policies/admin/status_policy_spec.rb b/spec/policies/admin/status_policy_spec.rb deleted file mode 100644 index af9f7716b..000000000 --- a/spec/policies/admin/status_policy_spec.rb +++ /dev/null @@ -1,62 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -describe Admin::StatusPolicy do - let(:policy) { described_class } - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - let(:status) { Fabricate(:status, visibility: status_visibility) } - let(:status_visibility) { :public } - - permissions :index?, :update?, :review?, :destroy? do - context 'with an admin' do - it 'permits' do - expect(policy).to permit(admin, Tag) - end - end - - context 'with a non-admin' do - it 'denies' do - expect(policy).to_not permit(john, Tag) - end - end - end - - permissions :show? do - context 'with an admin' do - context 'with a public visible status' do - let(:status_visibility) { :public } - - it 'permits' do - expect(policy).to permit(admin, status) - end - end - - context 'with a not public visible status' do - let(:status_visibility) { :direct } - - it 'denies' do - expect(policy).to_not permit(admin, status) - end - - context 'when the status mentions the admin' do - before do - status.mentions.create!(account: admin) - end - - it 'permits' do - expect(policy).to permit(admin, status) - end - end - end - end - - context 'with a non admin' do - it 'denies' do - expect(policy).to_not permit(john, status) - end - end - end -end diff --git a/spec/policies/announcement_policy_spec.rb b/spec/policies/announcement_policy_spec.rb deleted file mode 100644 index 3d230b3cb..000000000 --- a/spec/policies/announcement_policy_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -describe AnnouncementPolicy do - let(:policy) { described_class } - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :index?, :create?, :update?, :destroy? do - context 'with an admin' do - it 'permits' do - expect(policy).to permit(admin, Tag) - end - end - - context 'with a non-admin' do - it 'denies' do - expect(policy).to_not permit(john, Tag) - end - end - end -end diff --git a/spec/policies/appeal_policy_spec.rb b/spec/policies/appeal_policy_spec.rb deleted file mode 100644 index d7498eb9f..000000000 --- a/spec/policies/appeal_policy_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -describe AppealPolicy do - let(:policy) { described_class } - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - let(:appeal) { Fabricate(:appeal) } - - permissions :index? do - context 'with an admin' do - it 'permits' do - expect(policy).to permit(admin, Tag) - end - end - - context 'with a non-admin' do - it 'denies' do - expect(policy).to_not permit(john, Tag) - end - end - end - - permissions :reject? do - context 'with an admin' do - context 'with a pending appeal' do - before { allow(appeal).to receive(:pending?).and_return(true) } - - it 'permits' do - expect(policy).to permit(admin, appeal) - end - end - - context 'with a not pending appeal' do - before { allow(appeal).to receive(:pending?).and_return(false) } - - it 'denies' do - expect(policy).to_not permit(admin, appeal) - end - end - end - - context 'with a non admin' do - it 'denies' do - expect(policy).to_not permit(john, appeal) - end - end - end -end diff --git a/spec/policies/backup_policy_spec.rb b/spec/policies/backup_policy_spec.rb deleted file mode 100644 index 28cb65d78..000000000 --- a/spec/policies/backup_policy_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe BackupPolicy do - subject { described_class } - - let(:john) { Fabricate(:account) } - - permissions :create? do - context 'when not user_signed_in?' do - it 'denies' do - expect(subject).to_not permit(nil, Backup) - end - end - - context 'when user_signed_in?' do - context 'with no backups' do - it 'permits' do - expect(subject).to permit(john, Backup) - end - end - - context 'when backups are too old' do - it 'permits' do - travel(-8.days) do - Fabricate(:backup, user: john.user) - end - - expect(subject).to permit(john, Backup) - end - end - - context 'when backups are newer' do - it 'denies' do - travel(-3.days) do - Fabricate(:backup, user: john.user) - end - - expect(subject).to_not permit(john, Backup) - end - end - end - end -end diff --git a/spec/policies/canonical_email_block_policy_spec.rb b/spec/policies/canonical_email_block_policy_spec.rb deleted file mode 100644 index 0e55febfa..000000000 --- a/spec/policies/canonical_email_block_policy_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -describe CanonicalEmailBlockPolicy do - let(:policy) { described_class } - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :index?, :show?, :test?, :create?, :destroy? do - context 'with an admin' do - it 'permits' do - expect(policy).to permit(admin, Tag) - end - end - - context 'with a non-admin' do - it 'denies' do - expect(policy).to_not permit(john, Tag) - end - end - end -end diff --git a/spec/policies/custom_emoji_policy_spec.rb b/spec/policies/custom_emoji_policy_spec.rb deleted file mode 100644 index cb869c7d9..000000000 --- a/spec/policies/custom_emoji_policy_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe CustomEmojiPolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :index?, :enable?, :disable? do - context 'when staff' do - it 'permits' do - expect(subject).to permit(admin, CustomEmoji) - end - end - - context 'when not staff' do - it 'denies' do - expect(subject).to_not permit(john, CustomEmoji) - end - end - end - - permissions :create?, :update?, :copy?, :destroy? do - context 'when admin' do - it 'permits' do - expect(subject).to permit(admin, CustomEmoji) - end - end - - context 'when not admin' do - it 'denies' do - expect(subject).to_not permit(john, CustomEmoji) - end - end - end -end diff --git a/spec/policies/delivery_policy_spec.rb b/spec/policies/delivery_policy_spec.rb deleted file mode 100644 index fbcbf390d..000000000 --- a/spec/policies/delivery_policy_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -describe DeliveryPolicy do - let(:policy) { described_class } - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :clear_delivery_errors?, :restart_delivery?, :stop_delivery? do - context 'with an admin' do - it 'permits' do - expect(policy).to permit(admin, Tag) - end - end - - context 'with a non-admin' do - it 'denies' do - expect(policy).to_not permit(john, Tag) - end - end - end -end diff --git a/spec/policies/domain_block_policy_spec.rb b/spec/policies/domain_block_policy_spec.rb deleted file mode 100644 index 4c89f3f37..000000000 --- a/spec/policies/domain_block_policy_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe DomainBlockPolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :index?, :show?, :create?, :destroy? do - context 'when admin' do - it 'permits' do - expect(subject).to permit(admin, DomainBlock) - end - end - - context 'when not admin' do - it 'denies' do - expect(subject).to_not permit(john, DomainBlock) - end - end - end -end diff --git a/spec/policies/email_domain_block_policy_spec.rb b/spec/policies/email_domain_block_policy_spec.rb deleted file mode 100644 index 7ecff4be4..000000000 --- a/spec/policies/email_domain_block_policy_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe EmailDomainBlockPolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :index?, :show?, :create?, :destroy? do - context 'when admin' do - it 'permits' do - expect(subject).to permit(admin, EmailDomainBlock) - end - end - - context 'when not admin' do - it 'denies' do - expect(subject).to_not permit(john, EmailDomainBlock) - end - end - end -end diff --git a/spec/policies/follow_recommendation_policy_spec.rb b/spec/policies/follow_recommendation_policy_spec.rb deleted file mode 100644 index 01f4da0be..000000000 --- a/spec/policies/follow_recommendation_policy_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -describe FollowRecommendationPolicy do - let(:policy) { described_class } - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :show?, :suppress?, :unsuppress? do - context 'with an admin' do - it 'permits' do - expect(policy).to permit(admin, Tag) - end - end - - context 'with a non-admin' do - it 'denies' do - expect(policy).to_not permit(john, Tag) - end - end - end -end diff --git a/spec/policies/instance_policy_spec.rb b/spec/policies/instance_policy_spec.rb deleted file mode 100644 index a0d9a008b..000000000 --- a/spec/policies/instance_policy_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe InstancePolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :index?, :show?, :destroy? do - context 'when admin' do - it 'permits' do - expect(subject).to permit(admin, Instance) - end - end - - context 'when not admin' do - it 'denies' do - expect(subject).to_not permit(john, Instance) - end - end - end -end diff --git a/spec/policies/invite_policy_spec.rb b/spec/policies/invite_policy_spec.rb deleted file mode 100644 index cbe3735d8..000000000 --- a/spec/policies/invite_policy_spec.rb +++ /dev/null @@ -1,77 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe InvitePolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:user).account } - - permissions :index? do - context 'when staff?' do - it 'permits' do - expect(subject).to permit(admin, Invite) - end - end - end - - permissions :create? do - context 'with privilege' do - before do - UserRole.everyone.update(permissions: UserRole::FLAGS[:invite_users]) - end - - it 'permits' do - expect(subject).to permit(john, Invite) - end - end - - context 'when does not have privilege' do - before do - UserRole.everyone.update(permissions: UserRole::Flags::NONE) - end - - it 'denies' do - expect(subject).to_not permit(john, Invite) - end - end - end - - permissions :deactivate_all? do - context 'when admin?' do - it 'permits' do - expect(subject).to permit(admin, Invite) - end - end - - context 'when not admin?' do - it 'denies' do - expect(subject).to_not permit(john, Invite) - end - end - end - - permissions :destroy? do - context 'when owner?' do - it 'permits' do - expect(subject).to permit(john, Fabricate(:invite, user: john.user)) - end - end - - context 'when not owner?' do - context 'when admin?' do - it 'permits' do - expect(subject).to permit(admin, Fabricate(:invite)) - end - end - - context 'when not admin?' do - it 'denies' do - expect(subject).to_not permit(john, Fabricate(:invite)) - end - end - end - end -end diff --git a/spec/policies/ip_block_policy_spec.rb b/spec/policies/ip_block_policy_spec.rb deleted file mode 100644 index 3cfa85863..000000000 --- a/spec/policies/ip_block_policy_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -describe IpBlockPolicy do - let(:policy) { described_class } - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :index?, :show?, :create?, :update?, :destroy? do - context 'with an admin' do - it 'permits' do - expect(policy).to permit(admin, Tag) - end - end - - context 'with a non-admin' do - it 'denies' do - expect(policy).to_not permit(john, Tag) - end - end - end -end diff --git a/spec/policies/preview_card_policy_spec.rb b/spec/policies/preview_card_policy_spec.rb deleted file mode 100644 index d6675c5b3..000000000 --- a/spec/policies/preview_card_policy_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -describe PreviewCardPolicy do - let(:policy) { described_class } - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :index?, :review? do - context 'with an admin' do - it 'permits' do - expect(policy).to permit(admin, Tag) - end - end - - context 'with a non-admin' do - it 'denies' do - expect(policy).to_not permit(john, Tag) - end - end - end -end diff --git a/spec/policies/preview_card_provider_policy_spec.rb b/spec/policies/preview_card_provider_policy_spec.rb deleted file mode 100644 index 8d3715de9..000000000 --- a/spec/policies/preview_card_provider_policy_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -describe PreviewCardProviderPolicy do - let(:policy) { described_class } - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :index?, :review? do - context 'with an admin' do - it 'permits' do - expect(policy).to permit(admin, Tag) - end - end - - context 'with a non-admin' do - it 'denies' do - expect(policy).to_not permit(john, Tag) - end - end - end -end diff --git a/spec/policies/relay_policy_spec.rb b/spec/policies/relay_policy_spec.rb deleted file mode 100644 index 29ba02c26..000000000 --- a/spec/policies/relay_policy_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe RelayPolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :update? do - context 'when admin?' do - it 'permits' do - expect(subject).to permit(admin, Relay) - end - end - - context 'with !admin?' do - it 'denies' do - expect(subject).to_not permit(john, Relay) - end - end - end -end diff --git a/spec/policies/report_note_policy_spec.rb b/spec/policies/report_note_policy_spec.rb deleted file mode 100644 index b40a87888..000000000 --- a/spec/policies/report_note_policy_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe ReportNotePolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :create? do - context 'when staff?' do - it 'permits' do - expect(subject).to permit(admin, ReportNote) - end - end - - context 'with !staff?' do - it 'denies' do - expect(subject).to_not permit(john, ReportNote) - end - end - end - - permissions :destroy? do - context 'when admin?' do - it 'permit' do - report_note = Fabricate(:report_note, account: john) - expect(subject).to permit(admin, report_note) - end - end - - context 'when owner?' do - it 'permit' do - report_note = Fabricate(:report_note, account: john) - expect(subject).to permit(john, report_note) - end - end - - context 'with !owner?' do - it 'denies' do - report_note = Fabricate(:report_note) - expect(subject).to_not permit(john, report_note) - end - end - end -end diff --git a/spec/policies/report_policy_spec.rb b/spec/policies/report_policy_spec.rb deleted file mode 100644 index 4fc417807..000000000 --- a/spec/policies/report_policy_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe ReportPolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :update?, :index?, :show? do - context 'when staff?' do - it 'permits' do - expect(subject).to permit(admin, Report) - end - end - - context 'with !staff?' do - it 'denies' do - expect(subject).to_not permit(john, Report) - end - end - end -end diff --git a/spec/policies/rule_policy_spec.rb b/spec/policies/rule_policy_spec.rb deleted file mode 100644 index 0e45f6df0..000000000 --- a/spec/policies/rule_policy_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -describe RulePolicy do - let(:policy) { described_class } - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :index?, :create?, :update?, :destroy? do - context 'with an admin' do - it 'permits' do - expect(policy).to permit(admin, Tag) - end - end - - context 'with a non-admin' do - it 'denies' do - expect(policy).to_not permit(john, Tag) - end - end - end -end diff --git a/spec/policies/settings_policy_spec.rb b/spec/policies/settings_policy_spec.rb deleted file mode 100644 index 4a9931490..000000000 --- a/spec/policies/settings_policy_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe SettingsPolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :update?, :show?, :destroy? do - context 'when admin?' do - it 'permits' do - expect(subject).to permit(admin, Settings) - end - end - - context 'with !admin?' do - it 'denies' do - expect(subject).to_not permit(john, Settings) - end - end - end -end diff --git a/spec/policies/software_update_policy_spec.rb b/spec/policies/software_update_policy_spec.rb deleted file mode 100644 index e19ba6161..000000000 --- a/spec/policies/software_update_policy_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe SoftwareUpdatePolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Owner')).account } - let(:john) { Fabricate(:account) } - - permissions :index? do - context 'when owner' do - it 'permits' do - expect(subject).to permit(admin, SoftwareUpdate) - end - end - - context 'when not owner' do - it 'denies' do - expect(subject).to_not permit(john, SoftwareUpdate) - end - end - end -end diff --git a/spec/policies/status_policy_spec.rb b/spec/policies/status_policy_spec.rb deleted file mode 100644 index 725bd0bbb..000000000 --- a/spec/policies/status_policy_spec.rb +++ /dev/null @@ -1,161 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe StatusPolicy, type: :model do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - let(:alice) { Fabricate(:account, username: 'alice') } - let(:bob) { Fabricate(:account, username: 'bob') } - let(:status) { Fabricate(:status, account: alice) } - - context 'with the permissions of show? and reblog?' do - permissions :show?, :reblog? do - it 'grants access when no viewer' do - expect(subject).to permit(nil, status) - end - - it 'denies access when viewer is blocked' do - block = Fabricate(:block) - status.visibility = :private - status.account = block.target_account - - expect(subject).to_not permit(block.account, status) - end - end - end - - context 'with the permission of show?' do - permissions :show? do - it 'grants access when direct and account is viewer' do - status.visibility = :direct - - expect(subject).to permit(status.account, status) - end - - it 'grants access when direct and viewer is mentioned' do - status.visibility = :direct - status.mentions = [Fabricate(:mention, account: alice)] - - expect(subject).to permit(alice, status) - end - - it 'grants access when direct and non-owner viewer is mentioned and mentions are loaded' do - status.visibility = :direct - status.mentions = [Fabricate(:mention, account: bob)] - status.mentions.load - - expect(subject).to permit(bob, status) - end - - it 'denies access when direct and viewer is not mentioned' do - viewer = Fabricate(:account) - status.visibility = :direct - - expect(subject).to_not permit(viewer, status) - end - - it 'grants access when private and account is viewer' do - status.visibility = :private - - expect(subject).to permit(status.account, status) - end - - it 'grants access when private and account is following viewer' do - follow = Fabricate(:follow) - status.visibility = :private - status.account = follow.target_account - - expect(subject).to permit(follow.account, status) - end - - it 'grants access when private and viewer is mentioned' do - status.visibility = :private - status.mentions = [Fabricate(:mention, account: alice)] - - expect(subject).to permit(alice, status) - end - - it 'denies access when private and viewer is not mentioned or followed' do - viewer = Fabricate(:account) - status.visibility = :private - - expect(subject).to_not permit(viewer, status) - end - - it 'denies access when local-only and the viewer is not logged in' do - allow(status).to receive(:local_only?).and_return(true) - - expect(subject).to_not permit(nil, status) - end - - it 'denies access when local-only and the viewer is from another domain' do - viewer = Fabricate(:account, domain: 'remote-domain') - allow(status).to receive(:local_only?).and_return(true) - expect(subject).to_not permit(viewer, status) - end - end - end - - context 'with the permission of reblog?' do - permissions :reblog? do - it 'denies access when private' do - viewer = Fabricate(:account) - status.visibility = :private - - expect(subject).to_not permit(viewer, status) - end - - it 'denies access when direct' do - viewer = Fabricate(:account) - status.visibility = :direct - - expect(subject).to_not permit(viewer, status) - end - end - end - - context 'with the permissions of destroy? and unreblog?' do - permissions :destroy?, :unreblog? do - it 'grants access when account is deleter' do - expect(subject).to permit(status.account, status) - end - - it 'denies access when account is not deleter' do - expect(subject).to_not permit(bob, status) - end - - it 'denies access when no deleter' do - expect(subject).to_not permit(nil, status) - end - end - end - - context 'with the permission of favourite?' do - permissions :favourite? do - it 'grants access when viewer is not blocked' do - follow = Fabricate(:follow) - status.account = follow.target_account - - expect(subject).to permit(follow.account, status) - end - - it 'denies when viewer is blocked' do - block = Fabricate(:block) - status.account = block.target_account - - expect(subject).to_not permit(block.account, status) - end - end - end - - context 'with the permission of update?' do - permissions :update? do - it 'grants access if owner' do - expect(subject).to permit(status.account, status) - end - end - end -end diff --git a/spec/policies/tag_policy_spec.rb b/spec/policies/tag_policy_spec.rb deleted file mode 100644 index 35da3cc62..000000000 --- a/spec/policies/tag_policy_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe TagPolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :index?, :show?, :update?, :review? do - context 'when staff?' do - it 'permits' do - expect(subject).to permit(admin, Tag) - end - end - - context 'with !staff?' do - it 'denies' do - expect(subject).to_not permit(john, Tag) - end - end - end -end diff --git a/spec/policies/user_policy_spec.rb b/spec/policies/user_policy_spec.rb deleted file mode 100644 index fa476a9fc..000000000 --- a/spec/policies/user_policy_spec.rb +++ /dev/null @@ -1,115 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -RSpec.describe UserPolicy do - subject { described_class } - - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :reset_password?, :change_email? do - context 'when staff?' do - context 'with !record.staff?' do - it 'permits' do - expect(subject).to permit(admin, john.user) - end - end - - context 'when record.staff?' do - it 'denies' do - expect(subject).to_not permit(admin, admin.user) - end - end - end - - context 'with !staff?' do - it 'denies' do - expect(subject).to_not permit(john, User) - end - end - end - - permissions :disable_2fa? do - context 'when admin?' do - context 'with !record.staff?' do - it 'permits' do - expect(subject).to permit(admin, john.user) - end - end - - context 'when record.staff?' do - it 'denies' do - expect(subject).to_not permit(admin, admin.user) - end - end - end - - context 'with !admin?' do - it 'denies' do - expect(subject).to_not permit(john, User) - end - end - end - - permissions :confirm? do - context 'when staff?' do - context 'with !record.confirmed?' do - it 'permits' do - john.user.update(confirmed_at: nil) - expect(subject).to permit(admin, john.user) - end - end - - context 'when record.confirmed?' do - it 'denies' do - john.user.confirm! - expect(subject).to_not permit(admin, john.user) - end - end - end - - context 'with !staff?' do - it 'denies' do - expect(subject).to_not permit(john, User) - end - end - end - - permissions :enable? do - context 'when staff?' do - it 'permits' do - expect(subject).to permit(admin, User) - end - end - - context 'with !staff?' do - it 'denies' do - expect(subject).to_not permit(john, User) - end - end - end - - permissions :disable? do - context 'when staff?' do - context 'with !record.admin?' do - it 'permits' do - expect(subject).to permit(admin, john.user) - end - end - - context 'when record.admin?' do - it 'denies' do - expect(subject).to_not permit(admin, admin.user) - end - end - end - - context 'with !staff?' do - it 'denies' do - expect(subject).to_not permit(john, User) - end - end - end -end diff --git a/spec/policies/webhook_policy_spec.rb b/spec/policies/webhook_policy_spec.rb deleted file mode 100644 index 909311461..000000000 --- a/spec/policies/webhook_policy_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' -require 'pundit/rspec' - -describe WebhookPolicy do - let(:policy) { described_class } - let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account } - let(:john) { Fabricate(:account) } - - permissions :index?, :create? do - context 'with an admin' do - it 'permits' do - expect(policy).to permit(admin, Webhook) - end - end - - context 'with a non-admin' do - it 'denies' do - expect(policy).to_not permit(john, Webhook) - end - end - end - - permissions :show?, :update?, :enable?, :disable?, :rotate_secret?, :destroy? do - let(:webhook) { Fabricate(:webhook, events: ['account.created', 'report.created']) } - - context 'with an admin' do - it 'permits' do - expect(policy).to permit(admin, webhook) - end - end - - context 'with a non-admin' do - it 'denies' do - expect(policy).to_not permit(john, webhook) - end - end - end -end diff --git a/spec/presenters/account_relationships_presenter_spec.rb b/spec/presenters/account_relationships_presenter_spec.rb deleted file mode 100644 index 5c2ba54e0..000000000 --- a/spec/presenters/account_relationships_presenter_spec.rb +++ /dev/null @@ -1,91 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe AccountRelationshipsPresenter do - describe '.initialize' do - before do - allow(Account).to receive(:following_map).with(account_ids, current_account_id).and_return(default_map) - allow(Account).to receive(:followed_by_map).with(account_ids, current_account_id).and_return(default_map) - allow(Account).to receive(:blocking_map).with(account_ids, current_account_id).and_return(default_map) - allow(Account).to receive(:muting_map).with(account_ids, current_account_id).and_return(default_map) - allow(Account).to receive(:requested_map).with(account_ids, current_account_id).and_return(default_map) - allow(Account).to receive(:requested_by_map).with(account_ids, current_account_id).and_return(default_map) - allow(Account).to receive(:domain_blocking_map).with(account_ids, current_account_id).and_return(default_map) - end - - let(:presenter) { described_class.new(account_ids, current_account_id, **options) } - let(:current_account_id) { Fabricate(:account).id } - let(:account_ids) { [Fabricate(:account).id] } - let(:default_map) { { 1 => true } } - - context 'when options are not set' do - let(:options) { {} } - - it 'sets default maps' do - expect(presenter.following).to eq default_map - expect(presenter.followed_by).to eq default_map - expect(presenter.blocking).to eq default_map - expect(presenter.muting).to eq default_map - expect(presenter.requested).to eq default_map - expect(presenter.domain_blocking).to eq default_map - end - end - - context 'when options[:following_map] is set' do - let(:options) { { following_map: { 2 => true } } } - - it 'sets @following merged with default_map and options[:following_map]' do - expect(presenter.following).to eq default_map.merge(options[:following_map]) - end - end - - context 'when options[:followed_by_map] is set' do - let(:options) { { followed_by_map: { 3 => true } } } - - it 'sets @followed_by merged with default_map and options[:followed_by_map]' do - expect(presenter.followed_by).to eq default_map.merge(options[:followed_by_map]) - end - end - - context 'when options[:blocking_map] is set' do - let(:options) { { blocking_map: { 4 => true } } } - - it 'sets @blocking merged with default_map and options[:blocking_map]' do - expect(presenter.blocking).to eq default_map.merge(options[:blocking_map]) - end - end - - context 'when options[:muting_map] is set' do - let(:options) { { muting_map: { 5 => true } } } - - it 'sets @muting merged with default_map and options[:muting_map]' do - expect(presenter.muting).to eq default_map.merge(options[:muting_map]) - end - end - - context 'when options[:requested_map] is set' do - let(:options) { { requested_map: { 6 => true } } } - - it 'sets @requested merged with default_map and options[:requested_map]' do - expect(presenter.requested).to eq default_map.merge(options[:requested_map]) - end - end - - context 'when options[:requested_by_map] is set' do - let(:options) { { requested_by_map: { 6 => true } } } - - it 'sets @requested merged with default_map and options[:requested_by_map]' do - expect(presenter.requested_by).to eq default_map.merge(options[:requested_by_map]) - end - end - - context 'when options[:domain_blocking_map] is set' do - let(:options) { { domain_blocking_map: { 7 => true } } } - - it 'sets @domain_blocking merged with default_map and options[:domain_blocking_map]' do - expect(presenter.domain_blocking).to eq default_map.merge(options[:domain_blocking_map]) - end - end - end -end diff --git a/spec/presenters/familiar_followers_presenter_spec.rb b/spec/presenters/familiar_followers_presenter_spec.rb deleted file mode 100644 index c21ffd36e..000000000 --- a/spec/presenters/familiar_followers_presenter_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe FamiliarFollowersPresenter do - describe '#accounts' do - subject { described_class.new(requested_accounts, account.id) } - - let(:account) { Fabricate(:account) } - let(:familiar_follower) { Fabricate(:account) } - let(:requested_accounts) { Fabricate.times(2, :account) } - - before do - familiar_follower.follow!(requested_accounts.first) - account.follow!(familiar_follower) - end - - it 'returns a result for each requested account' do - expect(subject.accounts.map(&:id)).to eq requested_accounts.map(&:id) - end - - it 'returns followers you follow' do - result = subject.accounts.first - - expect(result).to_not be_nil - expect(result.id).to eq requested_accounts.first.id - expect(result.accounts).to contain_exactly(familiar_follower) - end - - context 'when requested account hides followers' do - before do - requested_accounts.first.update(hide_collections: true) - end - - it 'does not return followers you follow' do - result = subject.accounts.first - - expect(result).to_not be_nil - expect(result.id).to eq requested_accounts.first.id - expect(result.accounts).to be_empty - end - end - - context 'when familiar follower hides follows' do - before do - familiar_follower.update(hide_collections: true) - end - - it 'does not return followers you follow' do - result = subject.accounts.first - - expect(result).to_not be_nil - expect(result.id).to eq requested_accounts.first.id - expect(result.accounts).to be_empty - end - end - end -end diff --git a/spec/presenters/instance_presenter_spec.rb b/spec/presenters/instance_presenter_spec.rb deleted file mode 100644 index f20dce593..000000000 --- a/spec/presenters/instance_presenter_spec.rb +++ /dev/null @@ -1,130 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe InstancePresenter do - let(:instance_presenter) { described_class.new } - - describe '#description' do - around do |example| - site_description = Setting.site_short_description - example.run - Setting.site_short_description = site_description - end - - it 'delegates site_description to Setting' do - Setting.site_short_description = 'Site desc' - expect(instance_presenter.description).to eq 'Site desc' - end - end - - describe '#extended_description' do - around do |example| - site_extended_description = Setting.site_extended_description - example.run - Setting.site_extended_description = site_extended_description - end - - it 'delegates site_extended_description to Setting' do - Setting.site_extended_description = 'Extended desc' - expect(instance_presenter.extended_description).to eq 'Extended desc' - end - end - - describe '#email' do - around do |example| - site_contact_email = Setting.site_contact_email - example.run - Setting.site_contact_email = site_contact_email - end - - it 'delegates contact_email to Setting' do - Setting.site_contact_email = 'admin@example.com' - expect(instance_presenter.contact.email).to eq 'admin@example.com' - end - end - - describe '#account' do - around do |example| - site_contact_username = Setting.site_contact_username - example.run - Setting.site_contact_username = site_contact_username - end - - it 'returns the account for the site contact username' do - Setting.site_contact_username = 'aaa' - account = Fabricate(:account, username: 'aaa') - expect(instance_presenter.contact.account).to eq(account) - end - end - - describe '#user_count' do - it 'returns the number of site users' do - Rails.cache.write 'user_count', 123 - - expect(instance_presenter.user_count).to eq(123) - end - end - - describe '#status_count' do - it 'returns the number of local statuses' do - Rails.cache.write 'local_status_count', 234 - - expect(instance_presenter.status_count).to eq(234) - end - end - - describe '#domain_count' do - it 'returns the number of known domains' do - Rails.cache.write 'distinct_domain_count', 345 - - expect(instance_presenter.domain_count).to eq(345) - end - end - - describe '#version' do - it 'returns string' do - expect(instance_presenter.version).to be_a String - end - end - - describe '#source_url' do - context 'with the GITHUB_REPOSITORY env variable set' do - around do |example| - ClimateControl.modify GITHUB_REPOSITORY: 'other/repo' do - example.run - end - end - - it 'uses the env variable to build a repo URL' do - expect(instance_presenter.source_url).to eq('https://github.com/other/repo') - end - end - - context 'without the GITHUB_REPOSITORY env variable set' do - around do |example| - ClimateControl.modify GITHUB_REPOSITORY: nil do - example.run - end - end - - it 'defaults to the core glitch-soc repo URL' do - expect(instance_presenter.source_url).to eq('https://github.com/glitch-soc/mastodon') - end - end - end - - describe '#thumbnail' do - it 'returns SiteUpload' do - thumbnail = Fabricate(:site_upload, var: 'thumbnail') - expect(instance_presenter.thumbnail).to eq(thumbnail) - end - end - - describe '#mascot' do - it 'returns SiteUpload' do - mascot = Fabricate(:site_upload, var: 'mascot') - expect(instance_presenter.mascot).to eq(mascot) - end - end -end diff --git a/spec/presenters/status_relationships_presenter_spec.rb b/spec/presenters/status_relationships_presenter_spec.rb deleted file mode 100644 index 7746c8cd7..000000000 --- a/spec/presenters/status_relationships_presenter_spec.rb +++ /dev/null @@ -1,125 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe StatusRelationshipsPresenter do - describe '.initialize' do - before do - allow(Status).to receive(:reblogs_map).with(match_array(status_ids), current_account_id).and_return(default_map) - allow(Status).to receive(:favourites_map).with(status_ids, current_account_id).and_return(default_map) - allow(Status).to receive(:bookmarks_map).with(status_ids, current_account_id).and_return(default_map) - allow(Status).to receive(:mutes_map).with(anything, current_account_id).and_return(default_map) - allow(Status).to receive(:pins_map).with(anything, current_account_id).and_return(default_map) - end - - let(:presenter) { described_class.new(statuses, current_account_id, **options) } - let(:current_account_id) { Fabricate(:account).id } - let(:statuses) { [Fabricate(:status)] } - let(:status_ids) { statuses.map(&:id) + statuses.filter_map(&:reblog_of_id) } - let(:default_map) { { 1 => true } } - - context 'when options are not set' do - let(:options) { {} } - - it 'sets default maps' do - expect(presenter.reblogs_map).to eq default_map - expect(presenter.favourites_map).to eq default_map - expect(presenter.bookmarks_map).to eq default_map - expect(presenter.mutes_map).to eq default_map - expect(presenter.pins_map).to eq default_map - end - end - - context 'when options[:reblogs_map] is set' do - let(:options) { { reblogs_map: { 2 => true } } } - - it 'sets @reblogs_map merged with default_map and options[:reblogs_map]' do - expect(presenter.reblogs_map).to eq default_map.merge(options[:reblogs_map]) - end - end - - context 'when options[:favourites_map] is set' do - let(:options) { { favourites_map: { 3 => true } } } - - it 'sets @favourites_map merged with default_map and options[:favourites_map]' do - expect(presenter.favourites_map).to eq default_map.merge(options[:favourites_map]) - end - end - - context 'when options[:bookmarks_map] is set' do - let(:options) { { bookmarks_map: { 4 => true } } } - - it 'sets @bookmarks_map merged with default_map and options[:bookmarks_map]' do - expect(presenter.bookmarks_map).to eq default_map.merge(options[:bookmarks_map]) - end - end - - context 'when options[:mutes_map] is set' do - let(:options) { { mutes_map: { 5 => true } } } - - it 'sets @mutes_map merged with default_map and options[:mutes_map]' do - expect(presenter.mutes_map).to eq default_map.merge(options[:mutes_map]) - end - end - - context 'when options[:pins_map] is set' do - let(:options) { { pins_map: { 6 => true } } } - - it 'sets @pins_map merged with default_map and options[:pins_map]' do - expect(presenter.pins_map).to eq default_map.merge(options[:pins_map]) - end - end - - context 'when post includes filtered terms' do - let(:statuses) { [Fabricate(:status, text: 'this toot is about that banned word'), Fabricate(:status, reblog: Fabricate(:status, text: 'this toot is about an irrelevant word'))] } - let(:options) { {} } - - before do - Account.find(current_account_id).custom_filters.create!(phrase: 'filter1', context: %w(home), action: :hide, keywords_attributes: [{ keyword: 'banned' }, { keyword: 'irrelevant' }]) - end - - it 'sets @filters_map to filter top-level status' do - matched_filters = presenter.filters_map[statuses[0].id] - expect(matched_filters.size).to eq 1 - - expect(matched_filters[0].filter.title).to eq 'filter1' - expect(matched_filters[0].keyword_matches).to eq ['banned'] - end - - it 'sets @filters_map to filter reblogged status' do - matched_filters = presenter.filters_map[statuses[1].reblog_of_id] - expect(matched_filters.size).to eq 1 - - expect(matched_filters[0].filter.title).to eq 'filter1' - expect(matched_filters[0].keyword_matches).to eq ['irrelevant'] - end - end - - context 'when post includes filtered individual statuses' do - let(:statuses) { [Fabricate(:status, text: 'hello world'), Fabricate(:status, reblog: Fabricate(:status, text: 'this toot is about an irrelevant word'))] } - let(:options) { {} } - - before do - filter = Account.find(current_account_id).custom_filters.create!(phrase: 'filter1', context: %w(home), action: :hide) - filter.statuses.create!(status_id: statuses[0].id) - filter.statuses.create!(status_id: statuses[1].reblog_of_id) - end - - it 'sets @filters_map to filter top-level status' do - matched_filters = presenter.filters_map[statuses[0].id] - expect(matched_filters.size).to eq 1 - - expect(matched_filters[0].filter.title).to eq 'filter1' - expect(matched_filters[0].status_matches).to eq [statuses[0].id] - end - - it 'sets @filters_map to filter reblogged status' do - matched_filters = presenter.filters_map[statuses[1].reblog_of_id] - expect(matched_filters.size).to eq 1 - - expect(matched_filters[0].filter.title).to eq 'filter1' - expect(matched_filters[0].status_matches).to eq [statuses[1].reblog_of_id] - end - end - end -end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb deleted file mode 100644 index 7b8dccb6a..000000000 --- a/spec/rails_helper.rb +++ /dev/null @@ -1,220 +0,0 @@ -# frozen_string_literal: true - -ENV['RAILS_ENV'] ||= 'test' - -# This needs to be defined before Rails is initialized -RUN_SYSTEM_SPECS = ENV.fetch('RUN_SYSTEM_SPECS', false) -RUN_SEARCH_SPECS = ENV.fetch('RUN_SEARCH_SPECS', false) - -if RUN_SYSTEM_SPECS - STREAMING_PORT = ENV.fetch('TEST_STREAMING_PORT', '4020') - ENV['STREAMING_API_BASE_URL'] = "http://localhost:#{STREAMING_PORT}" -end - -if RUN_SEARCH_SPECS - # Include any configuration or setups specific to search tests here -end - -require File.expand_path('../config/environment', __dir__) - -abort('The Rails environment is running in production mode!') if Rails.env.production? - -require 'spec_helper' -require 'rspec/rails' -require 'webmock/rspec' -require 'paperclip/matchers' -require 'capybara/rspec' -require 'chewy/rspec' - -Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f } - -ActiveRecord::Migration.maintain_test_schema! -WebMock.disable_net_connect!(allow: Chewy.settings[:host], allow_localhost: RUN_SYSTEM_SPECS) -Sidekiq::Testing.inline! -Sidekiq.logger = nil - -# System tests config -DatabaseCleaner.strategy = [:deletion] -streaming_server_manager = StreamingServerManager.new -search_data_manager = SearchDataManager.new - -Devise::Test::ControllerHelpers.module_eval do - alias_method :original_sign_in, :sign_in - - def sign_in(resource, _deprecated = nil, scope: nil) - original_sign_in(resource, scope: scope) - - SessionActivation.deactivate warden.cookies.signed['_session_id'] - - warden.cookies.signed['_session_id'] = { - value: resource.activate_session(warden.request), - expires: 1.year.from_now, - httponly: true, - } - end -end - -module SignedRequestHelpers - def get(path, headers: nil, sign_with: nil, **args) - return super path, headers: headers, **args if sign_with.nil? - - headers ||= {} - headers['Date'] = Time.now.utc.httpdate - headers['Host'] = ENV.fetch('LOCAL_DOMAIN') - signed_headers = headers.merge('(request-target)' => "get #{path}").slice('(request-target)', 'Host', 'Date') - - key_id = ActivityPub::TagManager.instance.key_uri_for(sign_with) - keypair = sign_with.keypair - signed_string = signed_headers.map { |key, value| "#{key.downcase}: #{value}" }.join("\n") - signature = Base64.strict_encode64(keypair.sign(OpenSSL::Digest.new('SHA256'), signed_string)) - - headers['Signature'] = "keyId=\"#{key_id}\",algorithm=\"rsa-sha256\",headers=\"#{signed_headers.keys.join(' ').downcase}\",signature=\"#{signature}\"" - - super path, headers: headers, **args - end -end - -RSpec.configure do |config| - # This is set before running spec:system, see lib/tasks/tests.rake - config.filter_run_excluding type: lambda { |type| - case type - when :system - !RUN_SYSTEM_SPECS - when :search - !RUN_SEARCH_SPECS - end - } - config.fixture_path = Rails.root.join('spec', 'fixtures') - config.use_transactional_fixtures = true - config.order = 'random' - config.infer_spec_type_from_file_location! - config.filter_rails_from_backtrace! - - config.define_derived_metadata(file_path: Regexp.new('spec/lib/mastodon/cli')) do |metadata| - metadata[:type] = :cli - end - - config.include Devise::Test::ControllerHelpers, type: :controller - config.include Devise::Test::ControllerHelpers, type: :helper - config.include Devise::Test::ControllerHelpers, type: :view - config.include Devise::Test::IntegrationHelpers, type: :feature - config.include Devise::Test::IntegrationHelpers, type: :request - config.include Paperclip::Shoulda::Matchers - config.include ActiveSupport::Testing::TimeHelpers - config.include Chewy::Rspec::Helpers - config.include Redisable - config.include SignedRequestHelpers, type: :request - - config.before :each, type: :cli do - stub_stdout - stub_reset_connection_pools - end - - config.before :each, type: :feature do - Capybara.current_driver = :rack_test - end - - config.before :each, type: :controller do - stub_jsonld_contexts! - end - - config.before :each, type: :service do - stub_jsonld_contexts! - end - - config.before :suite do - if RUN_SYSTEM_SPECS - Webpacker.compile - streaming_server_manager.start(port: STREAMING_PORT) - end - - if RUN_SEARCH_SPECS - Chewy.strategy(:urgent) - search_data_manager.prepare_test_data - end - end - - config.after :suite do - streaming_server_manager.stop - - search_data_manager.cleanup_test_data if RUN_SEARCH_SPECS - end - - config.around :each, type: :system do |example| - # driven_by :selenium, using: :chrome, screen_size: [1600, 1200] - driven_by :selenium, using: :headless_chrome, screen_size: [1600, 1200] - - # The streaming server needs access to the database - # but with use_transactional_tests every transaction - # is rolled-back, so the streaming server never sees the data - # So we disable this feature for system tests, and use DatabaseCleaner to clean - # the database tables between each test - self.use_transactional_tests = false - - DatabaseCleaner.cleaning do - example.run - end - - self.use_transactional_tests = true - end - - config.around :each, type: :search do |example| - search_data_manager.populate_indexes - example.run - search_data_manager.remove_indexes - end - - config.before(:each) do |example| - unless example.metadata[:paperclip_processing] - allow_any_instance_of(Paperclip::Attachment).to receive(:post_process).and_return(true) # rubocop:disable RSpec/AnyInstance - end - end - - config.after :each do - Rails.cache.clear - redis.del(redis.keys) - end - - # Assign types based on dir name for non-inferred types - config.define_derived_metadata(file_path: %r{/spec/}) do |metadata| - unless metadata.key?(:type) - match = metadata[:location].match(%r{/spec/([^/]+)/}) - metadata[:type] = match[1].singularize.to_sym - end - end -end - -RSpec::Sidekiq.configure do |config| - config.warn_when_jobs_not_processed_by_sidekiq = false -end - -RSpec::Matchers.define_negated_matcher :not_change, :change - -def request_fixture(name) - Rails.root.join('spec', 'fixtures', 'requests', name).read -end - -def attachment_fixture(name) - Rails.root.join('spec', 'fixtures', 'files', name).open -end - -def stub_stdout - # TODO: Is there a bettery way to: - # - Avoid CLI command output being printed out - # - Allow rspec to assert things against STDOUT - # - Avoid disabling stdout for other desirable output (deprecation warnings, for example) - allow($stdout).to receive(:write) -end - -def stub_reset_connection_pools - # TODO: Is there a better way to correctly run specs without stubbing this? - # (Avoids reset_connection_pools! in test env) - allow(ActiveRecord::Base).to receive(:establish_connection) - allow(RedisConfiguration).to receive(:establish_pool) -end - -def stub_jsonld_contexts! - stub_request(:get, 'https://www.w3.org/ns/activitystreams').to_return(request_fixture('json-ld.activitystreams.txt')) - stub_request(:get, 'https://w3id.org/identity/v1').to_return(request_fixture('json-ld.identity.txt')) - stub_request(:get, 'https://w3id.org/security/v1').to_return(request_fixture('json-ld.security.txt')) -end diff --git a/spec/requests/account_show_page_spec.rb b/spec/requests/account_show_page_spec.rb deleted file mode 100644 index e84c46c47..000000000 --- a/spec/requests/account_show_page_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'The account show page' do - it 'has valid opengraph tags' do - alice = Fabricate(:account, username: 'alice', display_name: 'Alice') - _status = Fabricate(:status, account: alice, text: 'Hello World') - - get '/@alice' - - expect(head_meta_content('og:title')).to match alice.display_name - expect(head_meta_content('og:type')).to eq 'profile' - expect(head_meta_content('og:image')).to match '.+' - expect(head_meta_content('og:url')).to match 'http://.+' - end - - def head_meta_content(property) - head_section.meta("[@property='#{property}']")[:content] - end - - def head_section - Nokogiri::Slop(response.body).html.head - end -end diff --git a/spec/requests/anonymous_cookies_spec.rb b/spec/requests/anonymous_cookies_spec.rb deleted file mode 100644 index 427f54e44..000000000 --- a/spec/requests/anonymous_cookies_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -context 'when visited anonymously' do - around do |example| - old = ActionController::Base.allow_forgery_protection - ActionController::Base.allow_forgery_protection = true - - example.run - - ActionController::Base.allow_forgery_protection = old - end - - describe 'account pages' do - it 'do not set cookies' do - alice = Fabricate(:account, username: 'alice', display_name: 'Alice') - _status = Fabricate(:status, account: alice, text: 'Hello World') - - get '/@alice' - - expect(response.cookies).to be_empty - end - end - - describe 'status pages' do - it 'do not set cookies' do - alice = Fabricate(:account, username: 'alice', display_name: 'Alice') - status = Fabricate(:status, account: alice, text: 'Hello World') - - get short_account_status_url(alice, status) - - expect(response.cookies).to be_empty - end - end - - describe 'the /about page' do - it 'does not set cookies' do - get '/about' - - expect(response.cookies).to be_empty - end - end -end diff --git a/spec/requests/api/v1/accounts/credentials_spec.rb b/spec/requests/api/v1/accounts/credentials_spec.rb deleted file mode 100644 index b13e79b12..000000000 --- a/spec/requests/api/v1/accounts/credentials_spec.rb +++ /dev/null @@ -1,64 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'credentials API' do - let(:user) { Fabricate(:user, account_attributes: { discoverable: false, locked: true, indexable: false }) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:scopes) { 'read:accounts write:accounts' } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/accounts/verify_credentials' do - subject do - get '/api/v1/accounts/verify_credentials', headers: headers - end - - it_behaves_like 'forbidden for wrong scope', 'write write:accounts' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the expected content' do - subject - - expect(body_as_json).to include({ - source: hash_including({ - discoverable: false, - indexable: false, - }), - locked: true, - }) - end - end - - describe 'POST /api/v1/accounts/update_credentials' do - subject do - patch '/api/v1/accounts/update_credentials', headers: headers, params: params - end - - let(:params) { { discoverable: true, locked: false, indexable: true } } - - it_behaves_like 'forbidden for wrong scope', 'read read:accounts' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns JSON with updated attributes' do - subject - - expect(body_as_json).to include({ - source: hash_including({ - discoverable: true, - indexable: true, - }), - locked: false, - }) - end - end -end diff --git a/spec/requests/api/v1/accounts_show_spec.rb b/spec/requests/api/v1/accounts_show_spec.rb deleted file mode 100644 index ee6e925aa..000000000 --- a/spec/requests/api/v1/accounts_show_spec.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'GET /api/v1/accounts/{account_id}' do - it 'returns account entity as 200 OK' do - account = Fabricate(:account) - - get "/api/v1/accounts/#{account.id}" - - aggregate_failures do - expect(response).to have_http_status(200) - expect(body_as_json[:id]).to eq(account.id.to_s) - end - end - - it 'returns 404 if account not found' do - get '/api/v1/accounts/1' - - aggregate_failures do - expect(response).to have_http_status(404) - expect(body_as_json[:error]).to eq('Record not found') - end - end - - context 'when with token' do - it 'returns account entity as 200 OK if token is valid' do - account = Fabricate(:account) - user = Fabricate(:user, account: account) - token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts').token - - get "/api/v1/accounts/#{account.id}", headers: { Authorization: "Bearer #{token}" } - - aggregate_failures do - expect(response).to have_http_status(200) - expect(body_as_json[:id]).to eq(account.id.to_s) - end - end - - it 'returns 403 if scope of token is invalid' do - account = Fabricate(:account) - user = Fabricate(:user, account: account) - token = Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:statuses').token - - get "/api/v1/accounts/#{account.id}", headers: { Authorization: "Bearer #{token}" } - - aggregate_failures do - expect(response).to have_http_status(403) - expect(body_as_json[:error]).to eq('This action is outside the authorized scopes') - end - end - end -end diff --git a/spec/requests/api/v1/admin/account_actions_spec.rb b/spec/requests/api/v1/admin/account_actions_spec.rb deleted file mode 100644 index 9295d262d..000000000 --- a/spec/requests/api/v1/admin/account_actions_spec.rb +++ /dev/null @@ -1,154 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Account actions' do - let(:role) { UserRole.find_by(name: 'Admin') } - let(:user) { Fabricate(:user, role: role) } - let(:scopes) { 'admin:write admin:write:accounts' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - let(:mailer) { instance_double(ActionMailer::MessageDelivery, deliver_later!: nil) } - - before do - allow(UserMailer).to receive(:warning).with(target_account.user, anything).and_return(mailer) - end - - shared_examples 'a successful notification delivery' do - it 'notifies the user about the action taken' do - subject - - expect(UserMailer).to have_received(:warning).with(target_account.user, anything).once - expect(mailer).to have_received(:deliver_later!).once - end - end - - shared_examples 'a successful logged action' do |action_type, target_type| - it 'logs action' do - subject - - log_item = Admin::ActionLog.last - - expect(log_item).to be_present - expect(log_item.action).to eq(action_type) - expect(log_item.account_id).to eq(user.account_id) - expect(log_item.target_id).to eq(target_type == :user ? target_account.user.id : target_account.id) - end - end - - describe 'POST /api/v1/admin/accounts/:id/action' do - subject do - post "/api/v1/admin/accounts/#{target_account.id}/action", headers: headers, params: params - end - - let(:target_account) { Fabricate(:account) } - - context 'with type of disable' do - let(:params) { { type: 'disable' } } - - it_behaves_like 'forbidden for wrong scope', 'admin:read admin:read:accounts' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'a successful notification delivery' - it_behaves_like 'a successful logged action', :disable, :user - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'disables the target account' do - expect { subject }.to change { target_account.reload.user_disabled? }.from(false).to(true) - end - end - - context 'with type of sensitive' do - let(:params) { { type: 'sensitive' } } - - it_behaves_like 'forbidden for wrong scope', 'admin:read admin:read:accounts' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'a successful notification delivery' - it_behaves_like 'a successful logged action', :sensitive, :account - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'marks the target account as sensitive' do - expect { subject }.to change { target_account.reload.sensitized? }.from(false).to(true) - end - end - - context 'with type of silence' do - let(:params) { { type: 'silence' } } - - it_behaves_like 'forbidden for wrong scope', 'admin:read admin:read:accounts' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'a successful notification delivery' - it_behaves_like 'a successful logged action', :silence, :account - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'marks the target account as silenced' do - expect { subject }.to change { target_account.reload.silenced? }.from(false).to(true) - end - end - - context 'with type of suspend' do - let(:params) { { type: 'suspend' } } - - it_behaves_like 'forbidden for wrong scope', 'admin:read admin:read:accounts' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'a successful notification delivery' - it_behaves_like 'a successful logged action', :suspend, :account - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'marks the target account as suspended' do - expect { subject }.to change { target_account.reload.suspended? }.from(false).to(true) - end - end - - context 'with type of none' do - let(:params) { { type: 'none' } } - - it_behaves_like 'a successful notification delivery' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - end - - context 'with no type' do - let(:params) { {} } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'with invalid type' do - let(:params) { { type: 'invalid' } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - end -end diff --git a/spec/requests/api/v1/admin/canonical_email_blocks_spec.rb b/spec/requests/api/v1/admin/canonical_email_blocks_spec.rb deleted file mode 100644 index 4382cb84e..000000000 --- a/spec/requests/api/v1/admin/canonical_email_blocks_spec.rb +++ /dev/null @@ -1,285 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Canonical Email Blocks' do - let(:role) { UserRole.find_by(name: 'Admin') } - let(:user) { Fabricate(:user, role: role) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:scopes) { 'admin:read:canonical_email_blocks admin:write:canonical_email_blocks' } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/admin/canonical_email_blocks' do - subject do - get '/api/v1/admin/canonical_email_blocks', headers: headers, params: params - end - - let(:params) { {} } - - it_behaves_like 'forbidden for wrong scope', 'read:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - context 'when there is no canonical email block' do - it 'returns an empty list' do - subject - - expect(body_as_json).to be_empty - end - end - - context 'when there are canonical email blocks' do - let!(:canonical_email_blocks) { Fabricate.times(5, :canonical_email_block) } - let(:expected_email_hashes) { canonical_email_blocks.pluck(:canonical_email_hash) } - - it 'returns the correct canonical email hashes' do - subject - - expect(body_as_json.pluck(:canonical_email_hash)).to match_array(expected_email_hashes) - end - - context 'with limit param' do - let(:params) { { limit: 2 } } - - it 'returns only the requested number of canonical email blocks' do - subject - - expect(body_as_json.size).to eq(params[:limit]) - end - end - - context 'with since_id param' do - let(:params) { { since_id: canonical_email_blocks[1].id } } - - it 'returns only the canonical email blocks after since_id' do - subject - - canonical_email_blocks_ids = canonical_email_blocks.pluck(:id).map(&:to_s) - - expect(body_as_json.pluck(:id)).to match_array(canonical_email_blocks_ids[2..]) - end - end - - context 'with max_id param' do - let(:params) { { max_id: canonical_email_blocks[3].id } } - - it 'returns only the canonical email blocks before max_id' do - subject - - canonical_email_blocks_ids = canonical_email_blocks.pluck(:id).map(&:to_s) - - expect(body_as_json.pluck(:id)).to match_array(canonical_email_blocks_ids[..2]) - end - end - end - end - - describe 'GET /api/v1/admin/canonical_email_blocks/:id' do - subject do - get "/api/v1/admin/canonical_email_blocks/#{canonical_email_block.id}", headers: headers - end - - let!(:canonical_email_block) { Fabricate(:canonical_email_block) } - - it_behaves_like 'forbidden for wrong scope', 'read:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - context 'when the requested canonical email block exists' do - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the requested canonical email block data correctly' do - subject - - json = body_as_json - - expect(json[:id]).to eq(canonical_email_block.id.to_s) - expect(json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash) - end - end - - context 'when the requested canonical block does not exist' do - it 'returns http not found' do - get '/api/v1/admin/canonical_email_blocks/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - end - - describe 'POST /api/v1/admin/canonical_email_blocks/test' do - subject do - post '/api/v1/admin/canonical_email_blocks/test', headers: headers, params: params - end - - let(:params) { { email: 'email@example.com' } } - - it_behaves_like 'forbidden for wrong scope', 'read:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - context 'when the required email param is not provided' do - let(:params) { {} } - - it 'returns http bad request' do - subject - - expect(response).to have_http_status(400) - end - end - - context 'when the required email param is provided' do - context 'when there is a matching canonical email block' do - let!(:canonical_email_block) { CanonicalEmailBlock.create(params) } - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the expected canonical email hash' do - subject - - expect(body_as_json[0][:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash) - end - end - - context 'when there is no matching canonical email block' do - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns an empty list' do - subject - - expect(body_as_json).to be_empty - end - end - end - end - - describe 'POST /api/v1/admin/canonical_email_blocks' do - subject do - post '/api/v1/admin/canonical_email_blocks', headers: headers, params: params - end - - let(:params) { { email: 'example@email.com' } } - let(:canonical_email_block) { CanonicalEmailBlock.new(email: params[:email]) } - - it_behaves_like 'forbidden for wrong scope', 'read:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the canonical_email_hash correctly' do - subject - - expect(body_as_json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash) - end - - context 'when the required email param is not provided' do - let(:params) { {} } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when the canonical_email_hash param is provided instead of email' do - let(:params) { { canonical_email_hash: 'dd501ce4e6b08698f19df96f2f15737e48a75660b1fa79b6ff58ea25ee4851a4' } } - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the correct canonical_email_hash' do - subject - - expect(body_as_json[:canonical_email_hash]).to eq(params[:canonical_email_hash]) - end - end - - context 'when both email and canonical_email_hash params are provided' do - let(:params) { { email: 'example@email.com', canonical_email_hash: 'dd501ce4e6b08698f19df96f2f15737e48a75660b1fa79b6ff58ea25ee4851a4' } } - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'ignores the canonical_email_hash param' do - subject - - expect(body_as_json[:canonical_email_hash]).to eq(canonical_email_block.canonical_email_hash) - end - end - - context 'when the given canonical email was already blocked' do - before do - canonical_email_block.save - end - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - end - - describe 'DELETE /api/v1/admin/canonical_email_blocks/:id' do - subject do - delete "/api/v1/admin/canonical_email_blocks/#{canonical_email_block.id}", headers: headers - end - - let!(:canonical_email_block) { Fabricate(:canonical_email_block) } - - it_behaves_like 'forbidden for wrong scope', 'read:statuses' - - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'deletes the canonical email block' do - subject - - expect(CanonicalEmailBlock.find_by(id: canonical_email_block.id)).to be_nil - end - - context 'when the canonical email block is not found' do - it 'returns http not found' do - delete '/api/v1/admin/canonical_email_blocks/0', headers: headers - - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/requests/api/v1/admin/domain_allows_spec.rb b/spec/requests/api/v1/admin/domain_allows_spec.rb deleted file mode 100644 index 96000e3ef..000000000 --- a/spec/requests/api/v1/admin/domain_allows_spec.rb +++ /dev/null @@ -1,194 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Domain Allows' do - let(:role) { UserRole.find_by(name: 'Admin') } - let(:user) { Fabricate(:user, role: role) } - let(:scopes) { 'admin:read admin:write' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/admin/domain_allows' do - subject do - get '/api/v1/admin/domain_allows', headers: headers, params: params - end - - let(:params) { {} } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - context 'when there is no allowed domains' do - it 'returns an empty body' do - subject - - expect(body_as_json).to be_empty - end - end - - context 'when there are allowed domains' do - let!(:domain_allows) { Fabricate.times(5, :domain_allow) } - let(:expected_response) do - domain_allows.map do |domain_allow| - { - id: domain_allow.id.to_s, - domain: domain_allow.domain, - created_at: domain_allow.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), - } - end - end - - it 'returns the correct allowed domains' do - subject - - expect(body_as_json).to match_array(expected_response) - end - - context 'with limit param' do - let(:params) { { limit: 2 } } - - it 'returns only the requested number of allowed domains' do - subject - - expect(body_as_json.size).to eq(params[:limit]) - end - end - end - end - - describe 'GET /api/v1/admin/domain_allows/:id' do - subject do - get "/api/v1/admin/domain_allows/#{domain_allow.id}", headers: headers - end - - let!(:domain_allow) { Fabricate(:domain_allow) } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the expected allowed domain name' do - subject - - expect(body_as_json[:domain]).to eq domain_allow.domain - end - - context 'when the requested allowed domain does not exist' do - it 'returns http not found' do - get '/api/v1/admin/domain_allows/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - end - - describe 'POST /api/v1/admin/domain_allows' do - subject do - post '/api/v1/admin/domain_allows', headers: headers, params: params - end - - let(:params) { { domain: 'foo.bar.com' } } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - context 'with a valid domain name' do - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the expected domain name' do - subject - - expect(body_as_json[:domain]).to eq 'foo.bar.com' - end - - it 'creates a domain allow' do - subject - - expect(DomainAllow.find_by(domain: 'foo.bar.com')).to be_present - end - end - - context 'with invalid domain name' do - let(:params) { 'foo bar' } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when domain name is not specified' do - let(:params) { {} } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when the domain is already allowed' do - before do - DomainAllow.create(params) - end - - it 'returns the existing allowed domain name' do - subject - - expect(body_as_json[:domain]).to eq(params[:domain]) - end - end - end - - describe 'DELETE /api/v1/admin/domain_allows/:id' do - subject do - delete "/api/v1/admin/domain_allows/#{domain_allow.id}", headers: headers - end - - let!(:domain_allow) { Fabricate(:domain_allow) } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'deletes the allowed domain' do - subject - - expect(DomainAllow.find_by(id: domain_allow.id)).to be_nil - end - - context 'when the allowed domain does not exist' do - it 'returns http not found' do - delete '/api/v1/admin/domain_allows/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/requests/api/v1/admin/domain_blocks_spec.rb b/spec/requests/api/v1/admin/domain_blocks_spec.rb deleted file mode 100644 index 7a5ac28c5..000000000 --- a/spec/requests/api/v1/admin/domain_blocks_spec.rb +++ /dev/null @@ -1,264 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Domain Blocks' do - let(:role) { UserRole.find_by(name: 'Admin') } - let(:user) { Fabricate(:user, role: role) } - let(:scopes) { 'admin:read:domain_blocks admin:write:domain_blocks' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/admin/domain_blocks' do - subject do - get '/api/v1/admin/domain_blocks', headers: headers, params: params - end - - let(:params) { {} } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - context 'when there are no domain blocks' do - it 'returns an empty list' do - subject - - expect(body_as_json).to be_empty - end - end - - context 'when there are domain blocks' do - let!(:domain_blocks) do - [ - Fabricate(:domain_block, severity: :silence, reject_media: true), - Fabricate(:domain_block, severity: :suspend, obfuscate: true), - Fabricate(:domain_block, severity: :noop, reject_reports: true), - Fabricate(:domain_block, public_comment: 'Spam'), - Fabricate(:domain_block, private_comment: 'Spam'), - ] - end - let(:expected_responde) do - domain_blocks.map do |domain_block| - { - id: domain_block.id.to_s, - domain: domain_block.domain, - created_at: domain_block.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), - severity: domain_block.severity.to_s, - reject_media: domain_block.reject_media, - reject_reports: domain_block.reject_reports, - private_comment: domain_block.private_comment, - public_comment: domain_block.public_comment, - obfuscate: domain_block.obfuscate, - } - end - end - - it 'returns the expected domain blocks' do - subject - - expect(body_as_json).to match_array(expected_responde) - end - - context 'with limit param' do - let(:params) { { limit: 2 } } - - it 'returns only the requested number of domain blocks' do - subject - - expect(body_as_json.size).to eq(params[:limit]) - end - end - end - end - - describe 'GET /api/v1/admin/domain_blocks/:id' do - subject do - get "/api/v1/admin/domain_blocks/#{domain_block.id}", headers: headers - end - - let!(:domain_block) { Fabricate(:domain_block) } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the expected domain block content' do - subject - - expect(body_as_json).to eq( - { - id: domain_block.id.to_s, - domain: domain_block.domain, - created_at: domain_block.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), - severity: domain_block.severity.to_s, - reject_media: domain_block.reject_media, - reject_reports: domain_block.reject_reports, - private_comment: domain_block.private_comment, - public_comment: domain_block.public_comment, - obfuscate: domain_block.obfuscate, - } - ) - end - - context 'when the requested domain block does not exist' do - it 'returns http not found' do - get '/api/v1/admin/domain_blocks/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - end - - describe 'POST /api/v1/admin/domain_blocks' do - subject do - post '/api/v1/admin/domain_blocks', headers: headers, params: params - end - - let(:params) { { domain: 'foo.bar.com', severity: :silence } } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns expected domain name and severity' do - subject - - body = body_as_json - - expect(body).to match a_hash_including( - { - domain: 'foo.bar.com', - severity: 'silence', - } - ) - end - - it 'creates a domain block' do - subject - - expect(DomainBlock.find_by(domain: 'foo.bar.com')).to be_present - end - - context 'when a stricter domain block already exists' do - before do - Fabricate(:domain_block, domain: 'bar.com', severity: :suspend) - end - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - - it 'returns existing domain block in error' do - subject - - expect(body_as_json[:existing_domain_block][:domain]).to eq('bar.com') - end - end - - context 'when given domain name is invalid' do - let(:params) { { domain: 'foo bar', severity: :silence } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - end - - describe 'PUT /api/v1/admin/domain_blocks/:id' do - subject do - put "/api/v1/admin/domain_blocks/#{domain_block.id}", headers: headers, params: params - end - - let!(:domain_block) { Fabricate(:domain_block, domain: 'example.com', severity: :silence) } - let(:params) { { domain: 'example.com', severity: 'suspend' } } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the updated domain block' do - subject - - expect(body_as_json).to match a_hash_including( - { - id: domain_block.id.to_s, - domain: domain_block.domain, - severity: 'suspend', - } - ) - end - - it 'updates the block severity' do - expect { subject }.to change { domain_block.reload.severity }.from('silence').to('suspend') - end - - context 'when domain block does not exist' do - it 'returns http not found' do - put '/api/v1/admin/domain_blocks/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - end - - describe 'DELETE /api/v1/admin/domain_blocks/:id' do - subject do - delete "/api/v1/admin/domain_blocks/#{domain_block.id}", headers: headers - end - - let!(:domain_block) { Fabricate(:domain_block) } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'deletes the domain block' do - subject - - expect(DomainBlock.find_by(id: domain_block.id)).to be_nil - end - - context 'when domain block does not exist' do - it 'returns http not found' do - delete '/api/v1/admin/domain_blocks/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/requests/api/v1/admin/email_domain_blocks_spec.rb b/spec/requests/api/v1/admin/email_domain_blocks_spec.rb deleted file mode 100644 index d512def86..000000000 --- a/spec/requests/api/v1/admin/email_domain_blocks_spec.rb +++ /dev/null @@ -1,211 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Email Domain Blocks' do - let(:role) { UserRole.find_by(name: 'Admin') } - let(:user) { Fabricate(:user, role: role) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:account) { Fabricate(:account) } - let(:scopes) { 'admin:read:email_domain_blocks admin:write:email_domain_blocks' } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/admin/email_domain_blocks' do - subject do - get '/api/v1/admin/email_domain_blocks', headers: headers, params: params - end - - let(:params) { {} } - - it_behaves_like 'forbidden for wrong scope', 'read:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - context 'when there is no email domain block' do - it 'returns an empty list' do - subject - - expect(body_as_json).to be_empty - end - end - - context 'when there are email domain blocks' do - let!(:email_domain_blocks) { Fabricate.times(5, :email_domain_block) } - let(:blocked_email_domains) { email_domain_blocks.pluck(:domain) } - - it 'return the correct blocked email domains' do - subject - - expect(body_as_json.pluck(:domain)).to match_array(blocked_email_domains) - end - - context 'with limit param' do - let(:params) { { limit: 2 } } - - it 'returns only the requested number of email domain blocks' do - subject - - expect(body_as_json.size).to eq(params[:limit]) - end - end - - context 'with since_id param' do - let(:params) { { since_id: email_domain_blocks[1].id } } - - it 'returns only the email domain blocks after since_id' do - subject - - email_domain_blocks_ids = email_domain_blocks.pluck(:id).map(&:to_s) - - expect(body_as_json.pluck(:id)).to match_array(email_domain_blocks_ids[2..]) - end - end - - context 'with max_id param' do - let(:params) { { max_id: email_domain_blocks[3].id } } - - it 'returns only the email domain blocks before max_id' do - subject - - email_domain_blocks_ids = email_domain_blocks.pluck(:id).map(&:to_s) - - expect(body_as_json.pluck(:id)).to match_array(email_domain_blocks_ids[..2]) - end - end - end - end - - describe 'GET /api/v1/admin/email_domain_blocks/:id' do - subject do - get "/api/v1/admin/email_domain_blocks/#{email_domain_block.id}", headers: headers - end - - let!(:email_domain_block) { Fabricate(:email_domain_block) } - - it_behaves_like 'forbidden for wrong scope', 'read:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - context 'when email domain block exists' do - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the correct blocked domain' do - subject - - expect(body_as_json[:domain]).to eq(email_domain_block.domain) - end - end - - context 'when email domain block does not exist' do - it 'returns http not found' do - get '/api/v1/admin/email_domain_blocks/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - end - - describe 'POST /api/v1/admin/email_domain_blocks' do - subject do - post '/api/v1/admin/email_domain_blocks', headers: headers, params: params - end - - let(:params) { { domain: 'example.com' } } - - it_behaves_like 'forbidden for wrong scope', 'read:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the correct blocked email domain' do - subject - - expect(body_as_json[:domain]).to eq(params[:domain]) - end - - context 'when domain param is not provided' do - let(:params) { { domain: '' } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when provided domain name has an invalid character' do - let(:params) { { domain: 'do\uD800.com' } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when provided domain is already blocked' do - before do - EmailDomainBlock.create(params) - end - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - end - - describe 'DELETE /api/v1/admin/email_domain_blocks' do - subject do - delete "/api/v1/admin/email_domain_blocks/#{email_domain_block.id}", headers: headers - end - - let!(:email_domain_block) { Fabricate(:email_domain_block) } - - it_behaves_like 'forbidden for wrong scope', 'read:statuses' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns an empty body' do - subject - - expect(body_as_json).to be_empty - end - - it 'deletes email domain block' do - subject - - expect(EmailDomainBlock.find_by(id: email_domain_block.id)).to be_nil - end - - context 'when email domain block does not exist' do - it 'returns http not found' do - delete '/api/v1/admin/email_domain_blocks/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/requests/api/v1/admin/ip_blocks_spec.rb b/spec/requests/api/v1/admin/ip_blocks_spec.rb deleted file mode 100644 index d03886c51..000000000 --- a/spec/requests/api/v1/admin/ip_blocks_spec.rb +++ /dev/null @@ -1,255 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'IP Blocks' do - let(:role) { UserRole.find_by(name: 'Admin') } - let(:user) { Fabricate(:user, role: role) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:scopes) { 'admin:read:ip_blocks admin:write:ip_blocks' } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/admin/ip_blocks' do - subject do - get '/api/v1/admin/ip_blocks', headers: headers, params: params - end - - let(:params) { {} } - - it_behaves_like 'forbidden for wrong scope', 'admin:write:ip_blocks' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - context 'when there is no ip block' do - it 'returns an empty body' do - subject - - expect(body_as_json).to be_empty - end - end - - context 'when there are ip blocks' do - let!(:ip_blocks) do - [ - IpBlock.create(ip: '192.0.2.0/24', severity: :no_access), - IpBlock.create(ip: '172.16.0.1', severity: :sign_up_requires_approval, comment: 'Spam'), - IpBlock.create(ip: '2001:0db8::/32', severity: :sign_up_block, expires_in: 10.days), - ] - end - let(:expected_response) do - ip_blocks.map do |ip_block| - { - id: ip_block.id.to_s, - ip: ip_block.ip, - severity: ip_block.severity.to_s, - comment: ip_block.comment, - created_at: ip_block.created_at.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), - expires_at: ip_block.expires_at&.strftime('%Y-%m-%dT%H:%M:%S.%LZ'), - } - end - end - - it 'returns the correct blocked ips' do - subject - - expect(body_as_json).to match_array(expected_response) - end - - context 'with limit param' do - let(:params) { { limit: 2 } } - - it 'returns only the requested number of ip blocks' do - subject - - expect(body_as_json.size).to eq(params[:limit]) - end - end - end - end - - describe 'GET /api/v1/admin/ip_blocks/:id' do - subject do - get "/api/v1/admin/ip_blocks/#{ip_block.id}", headers: headers - end - - let!(:ip_block) { IpBlock.create(ip: '192.0.2.0/24', severity: :no_access) } - - it_behaves_like 'forbidden for wrong scope', 'admin:write:ip_blocks' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the correct ip block' do - subject - - json = body_as_json - - expect(json[:ip]).to eq("#{ip_block.ip}/#{ip_block.ip.prefix}") - expect(json[:severity]).to eq(ip_block.severity.to_s) - end - - context 'when ip block does not exist' do - it 'returns http not found' do - get '/api/v1/admin/ip_blocks/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - end - - describe 'POST /api/v1/admin/ip_blocks' do - subject do - post '/api/v1/admin/ip_blocks', headers: headers, params: params - end - - let(:params) { { ip: '151.0.32.55', severity: 'no_access', comment: 'Spam' } } - - it_behaves_like 'forbidden for wrong scope', 'admin:read:ip_blocks' - it_behaves_like 'forbidden for wrong role', '' - it_behaves_like 'forbidden for wrong role', 'Moderator' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the correct ip block' do - subject - - json = body_as_json - - expect(json[:ip]).to eq("#{params[:ip]}/32") - expect(json[:severity]).to eq(params[:severity]) - expect(json[:comment]).to eq(params[:comment]) - end - - context 'when the required ip param is not provided' do - let(:params) { { ip: '', severity: 'no_access' } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when the required severity param is not provided' do - let(:params) { { ip: '173.65.23.1', severity: '' } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when the given ip address is already blocked' do - before do - IpBlock.create(params) - end - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when the given ip address is invalid' do - let(:params) { { ip: '520.13.54.120', severity: 'no_access' } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - end - - describe 'PUT /api/v1/admin/ip_blocks/:id' do - subject do - put "/api/v1/admin/ip_blocks/#{ip_block.id}", headers: headers, params: params - end - - let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access', comment: 'Spam', expires_in: 48.hours) } - let(:params) { { severity: 'sign_up_requires_approval', comment: 'Decreasing severity' } } - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the correct ip block' do - subject - - expect(body_as_json).to match(hash_including({ - ip: "#{ip_block.ip}/#{ip_block.ip.prefix}", - severity: 'sign_up_requires_approval', - comment: 'Decreasing severity', - })) - end - - it 'updates the severity correctly' do - expect { subject }.to change { ip_block.reload.severity }.from('no_access').to('sign_up_requires_approval') - end - - it 'updates the comment correctly' do - expect { subject }.to change { ip_block.reload.comment }.from('Spam').to('Decreasing severity') - end - - context 'when ip block does not exist' do - it 'returns http not found' do - put '/api/v1/admin/ip_blocks/-1', headers: headers, params: params - - expect(response).to have_http_status(404) - end - end - end - - describe 'DELETE /api/v1/admin/ip_blocks/:id' do - subject do - delete "/api/v1/admin/ip_blocks/#{ip_block.id}", headers: headers - end - - let!(:ip_block) { IpBlock.create(ip: '185.200.13.3', severity: 'no_access') } - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns an empty body' do - subject - - expect(body_as_json).to be_empty - end - - it 'deletes the ip block' do - subject - - expect(IpBlock.find_by(id: ip_block.id)).to be_nil - end - - context 'when ip block does not exist' do - it 'returns http not found' do - delete '/api/v1/admin/ip_blocks/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/requests/api/v1/admin/reports_spec.rb b/spec/requests/api/v1/admin/reports_spec.rb deleted file mode 100644 index 91c3c11f5..000000000 --- a/spec/requests/api/v1/admin/reports_spec.rb +++ /dev/null @@ -1,272 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Reports' do - let(:role) { UserRole.find_by(name: 'Admin') } - let(:user) { Fabricate(:user, role: role) } - let(:scopes) { 'admin:read:reports admin:write:reports' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/admin/reports' do - subject do - get '/api/v1/admin/reports', headers: headers, params: params - end - - let(:params) { {} } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - context 'when there are no reports' do - it 'returns an empty list' do - subject - - expect(body_as_json).to be_empty - end - end - - context 'when there are reports' do - let!(:reporter) { Fabricate(:account) } - let!(:spammer) { Fabricate(:account) } - let(:expected_response) do - scope.map do |report| - hash_including({ - id: report.id.to_s, - action_taken: report.action_taken?, - category: report.category, - comment: report.comment, - account: hash_including(id: report.account.id.to_s), - target_account: hash_including(id: report.target_account.id.to_s), - statuses: report.statuses, - rules: report.rules, - forwarded: report.forwarded, - }) - end - end - let(:scope) { Report.unresolved } - - before do - Fabricate(:report) - Fabricate(:report, target_account: spammer) - Fabricate(:report, account: reporter, target_account: spammer) - Fabricate(:report, action_taken_at: 4.days.ago, account: reporter) - Fabricate(:report, action_taken_at: 20.days.ago) - end - - it 'returns all unresolved reports' do - subject - - expect(body_as_json).to match_array(expected_response) - end - - context 'with resolved param' do - let(:params) { { resolved: true } } - let(:scope) { Report.resolved } - - it 'returns only the resolved reports' do - subject - - expect(body_as_json).to match_array(expected_response) - end - end - - context 'with account_id param' do - let(:params) { { account_id: reporter.id } } - let(:scope) { Report.unresolved.where(account: reporter) } - - it 'returns all unresolved reports filed by the specified account' do - subject - - expect(body_as_json).to match_array(expected_response) - end - end - - context 'with target_account_id param' do - let(:params) { { target_account_id: spammer.id } } - let(:scope) { Report.unresolved.where(target_account: spammer) } - - it 'returns all unresolved reports targeting the specified account' do - subject - - expect(body_as_json).to match_array(expected_response) - end - end - - context 'with limit param' do - let(:params) { { limit: 1 } } - - it 'returns only the requested number of reports' do - subject - - expect(body_as_json.size).to eq(1) - end - end - end - end - - describe 'GET /api/v1/admin/reports/:id' do - subject do - get "/api/v1/admin/reports/#{report.id}", headers: headers - end - - let(:report) { Fabricate(:report) } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the requested report content' do - subject - - expect(body_as_json).to include( - { - id: report.id.to_s, - action_taken: report.action_taken?, - category: report.category, - comment: report.comment, - account: a_hash_including(id: report.account.id.to_s), - target_account: a_hash_including(id: report.target_account.id.to_s), - statuses: report.statuses, - rules: report.rules, - forwarded: report.forwarded, - } - ) - end - end - - describe 'PUT /api/v1/admin/reports/:id' do - subject do - put "/api/v1/admin/reports/#{report.id}", headers: headers, params: params - end - - let!(:report) { Fabricate(:report, category: :other) } - let(:params) { { category: 'spam' } } - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'updates the report category' do - expect { subject }.to change { report.reload.category }.from('other').to('spam') - end - - it 'returns the updated report content' do - subject - - report.reload - - expect(body_as_json).to include( - { - id: report.id.to_s, - action_taken: report.action_taken?, - category: report.category, - comment: report.comment, - account: a_hash_including(id: report.account.id.to_s), - target_account: a_hash_including(id: report.target_account.id.to_s), - statuses: report.statuses, - rules: report.rules, - forwarded: report.forwarded, - } - ) - end - end - - describe 'POST #resolve' do - subject do - post "/api/v1/admin/reports/#{report.id}/resolve", headers: headers - end - - let(:report) { Fabricate(:report, action_taken_at: nil) } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'marks report as resolved' do - expect { subject }.to change { report.reload.unresolved? }.from(true).to(false) - end - end - - describe 'POST #reopen' do - subject do - post "/api/v1/admin/reports/#{report.id}/reopen", headers: headers - end - - let(:report) { Fabricate(:report, action_taken_at: 10.days.ago) } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'marks report as unresolved' do - expect { subject }.to change { report.reload.unresolved? }.from(false).to(true) - end - end - - describe 'POST #assign_to_self' do - subject do - post "/api/v1/admin/reports/#{report.id}/assign_to_self", headers: headers - end - - let(:report) { Fabricate(:report) } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'assigns report to the requesting user' do - expect { subject }.to change { report.reload.assigned_account_id }.from(nil).to(user.account.id) - end - end - - describe 'POST #unassign' do - subject do - post "/api/v1/admin/reports/#{report.id}/unassign", headers: headers - end - - let(:report) { Fabricate(:report, assigned_account_id: user.account.id) } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'unassigns report from assignee' do - expect { subject }.to change { report.reload.assigned_account_id }.from(user.account.id).to(nil) - end - end -end diff --git a/spec/requests/api/v1/admin/tags_spec.rb b/spec/requests/api/v1/admin/tags_spec.rb deleted file mode 100644 index 031be17f5..000000000 --- a/spec/requests/api/v1/admin/tags_spec.rb +++ /dev/null @@ -1,141 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Tags' do - let(:role) { UserRole.find_by(name: 'Admin') } - let(:user) { Fabricate(:user, role: role) } - let(:scopes) { 'admin:read admin:write' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:tag) { Fabricate(:tag) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/admin/tags' do - subject do - get '/api/v1/admin/tags', headers: headers, params: params - end - - let(:params) { {} } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - context 'when there are no tags' do - it 'returns an empty list' do - subject - - expect(body_as_json).to be_empty - end - end - - context 'when there are tagss' do - let!(:tags) do - [ - Fabricate(:tag), - Fabricate(:tag), - Fabricate(:tag), - Fabricate(:tag), - ] - end - - it 'returns the expected tags' do - subject - tags.each do |tag| - expect(body_as_json.find { |item| item[:id] == tag.id.to_s && item[:name] == tag.name }).to_not be_nil - end - end - - context 'with limit param' do - let(:params) { { limit: 2 } } - - it 'returns only the requested number of tags' do - subject - - expect(body_as_json.size).to eq(params[:limit]) - end - end - end - end - - describe 'GET /api/v1/admin/tags/:id' do - subject do - get "/api/v1/admin/tags/#{tag.id}", headers: headers - end - - let!(:tag) { Fabricate(:tag) } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong role', '' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns expected tag content' do - subject - - expect(body_as_json[:id].to_i).to eq(tag.id) - expect(body_as_json[:name]).to eq(tag.name) - end - - context 'when the requested tag does not exist' do - it 'returns http not found' do - get '/api/v1/admin/tags/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - end - - describe 'PUT /api/v1/admin/tags/:id' do - subject do - put "/api/v1/admin/tags/#{tag.id}", headers: headers, params: params - end - - let!(:tag) { Fabricate(:tag) } - let(:params) { { display_name: tag.name.upcase } } - - it_behaves_like 'forbidden for wrong scope', 'write:statuses' - it_behaves_like 'forbidden for wrong scope', 'admin:read' - it_behaves_like 'forbidden for wrong role', '' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns updated tag' do - subject - - expect(body_as_json[:id].to_i).to eq(tag.id) - expect(body_as_json[:name]).to eq(tag.name.upcase) - end - - context 'when the updated display name is invalid' do - let(:params) { { display_name: tag.name + tag.id.to_s } } - - it 'returns http unprocessable content' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when the requested tag does not exist' do - it 'returns http not found' do - get '/api/v1/admin/tags/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/requests/api/v1/apps/credentials_spec.rb b/spec/requests/api/v1/apps/credentials_spec.rb deleted file mode 100644 index dafe168c5..000000000 --- a/spec/requests/api/v1/apps/credentials_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'Credentials' do - describe 'GET /api/v1/apps/verify_credentials' do - subject do - get '/api/v1/apps/verify_credentials', headers: headers - end - - context 'with an oauth token' do - let(:token) { Fabricate(:accessible_access_token, scopes: 'read', application: Fabricate(:application)) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the app information correctly' do - subject - - expect(body_as_json).to match( - a_hash_including( - name: token.application.name, - website: token.application.website, - vapid_key: Rails.configuration.x.vapid_public_key - ) - ) - end - end - - context 'without an oauth token' do - let(:headers) { {} } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - end -end diff --git a/spec/requests/api/v1/apps_spec.rb b/spec/requests/api/v1/apps_spec.rb deleted file mode 100644 index 88f9eee36..000000000 --- a/spec/requests/api/v1/apps_spec.rb +++ /dev/null @@ -1,115 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Apps' do - describe 'POST /api/v1/apps' do - subject do - post '/api/v1/apps', params: params - end - - let(:client_name) { 'Test app' } - let(:scopes) { nil } - let(:redirect_uris) { 'urn:ietf:wg:oauth:2.0:oob' } - let(:website) { nil } - - let(:params) do - { - client_name: client_name, - redirect_uris: redirect_uris, - scopes: scopes, - website: website, - } - end - - context 'with valid params' do - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'creates an OAuth app' do - subject - - expect(Doorkeeper::Application.find_by(name: client_name)).to be_present - end - - it 'returns client ID and client secret' do - subject - - body = body_as_json - - expect(body[:client_id]).to be_present - expect(body[:client_secret]).to be_present - end - end - - context 'with an unsupported scope' do - let(:scopes) { 'hoge' } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'with many duplicate scopes' do - let(:scopes) { (%w(read) * 40).join(' ') } - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'only saves the scope once' do - subject - - expect(Doorkeeper::Application.find_by(name: client_name).scopes.to_s).to eq 'read' - end - end - - context 'with a too-long name' do - let(:client_name) { 'hoge' * 20 } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'with a too-long website' do - let(:website) { "https://foo.bar/#{'hoge' * 2_000}" } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'with a too-long redirect_uris' do - let(:redirect_uris) { "https://foo.bar/#{'hoge' * 2_000}" } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'without required params' do - let(:client_name) { '' } - let(:redirect_uris) { '' } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - end -end diff --git a/spec/requests/api/v1/bookmarks_spec.rb b/spec/requests/api/v1/bookmarks_spec.rb deleted file mode 100644 index 1f1cd35ca..000000000 --- a/spec/requests/api/v1/bookmarks_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Bookmarks' do - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:scopes) { 'read:bookmarks' } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/bookmarks' do - subject do - get '/api/v1/bookmarks', headers: headers, params: params - end - - let(:params) { {} } - let!(:bookmarks) { Fabricate.times(3, :bookmark, account: user.account) } - - let(:expected_response) do - bookmarks.map do |bookmark| - a_hash_including(id: bookmark.status.id.to_s, account: a_hash_including(id: bookmark.status.account.id.to_s)) - end - end - - it_behaves_like 'forbidden for wrong scope', 'write' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the bookmarked statuses' do - subject - - expect(body_as_json).to match_array(expected_response) - end - - context 'with limit param' do - let(:params) { { limit: 2 } } - - it 'paginates correctly', :aggregate_failures do - subject - - expect(body_as_json.size).to eq(params[:limit]) - expect(response.headers['Link'].find_link(%w(rel prev)).href).to eq(api_v1_bookmarks_url(limit: params[:limit], min_id: bookmarks.last.id)) - expect(response.headers['Link'].find_link(%w(rel next)).href).to eq(api_v1_bookmarks_url(limit: params[:limit], max_id: bookmarks[1].id)) - end - end - - context 'without the authorization header' do - let(:headers) { {} } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - end -end diff --git a/spec/requests/api/v1/domain_blocks_spec.rb b/spec/requests/api/v1/domain_blocks_spec.rb deleted file mode 100644 index 0f4fd4e90..000000000 --- a/spec/requests/api/v1/domain_blocks_spec.rb +++ /dev/null @@ -1,125 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Domain blocks' do - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:scopes) { 'read:blocks write:blocks' } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/domain_blocks' do - subject do - get '/api/v1/domain_blocks', headers: headers, params: params - end - - let(:blocked_domains) { ['example.com', 'example.net', 'example.org', 'example.com.br'] } - let(:params) { {} } - - before do - blocked_domains.each { |domain| user.account.block_domain!(domain) } - end - - it_behaves_like 'forbidden for wrong scope', 'write:blocks' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the domains blocked by the requesting user' do - subject - - expect(body_as_json).to match_array(blocked_domains) - end - - context 'with limit param' do - let(:params) { { limit: 2 } } - - it 'returns only the requested number of blocked domains' do - subject - - expect(body_as_json.size).to eq(params[:limit]) - end - end - end - - describe 'POST /api/v1/domain_blocks' do - subject do - post '/api/v1/domain_blocks', headers: headers, params: params - end - - let(:params) { { domain: 'example.com' } } - - it_behaves_like 'forbidden for wrong scope', 'read read:blocks' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'creates a domain block' do - subject - - expect(user.account.domain_blocking?(params[:domain])).to be(true) - end - - context 'when no domain name is given' do - let(:params) { { domain: '' } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when the given domain name is invalid' do - let(:params) { { domain: 'example com' } } - - it 'returns unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - end - - describe 'DELETE /api/v1/domain_blocks' do - subject do - delete '/api/v1/domain_blocks/', headers: headers, params: params - end - - let(:params) { { domain: 'example.com' } } - - before do - user.account.block_domain!('example.com') - end - - it_behaves_like 'forbidden for wrong scope', 'read read:blocks' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'deletes the specified domain block' do - subject - - expect(user.account.domain_blocking?('example.com')).to be(false) - end - - context 'when the given domain name is not blocked' do - let(:params) { { domain: 'example.org' } } - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - end - end -end diff --git a/spec/requests/api/v1/emails/confirmations_spec.rb b/spec/requests/api/v1/emails/confirmations_spec.rb deleted file mode 100644 index 8f5171ee7..000000000 --- a/spec/requests/api/v1/emails/confirmations_spec.rb +++ /dev/null @@ -1,168 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Confirmations' do - let(:confirmed_at) { nil } - let(:user) { Fabricate(:user, confirmed_at: confirmed_at) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:scopes) { 'read:accounts write:accounts' } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'POST /api/v1/emails/confirmations' do - subject do - post '/api/v1/emails/confirmations', headers: headers, params: params - end - - let(:params) { {} } - - it_behaves_like 'forbidden for wrong scope', 'read read:accounts' - - context 'with an oauth token' do - context 'when user was created by a different application' do - let(:user) { Fabricate(:user, confirmed_at: confirmed_at, created_by_application: Fabricate(:application)) } - - it 'returns http forbidden' do - subject - - expect(response).to have_http_status(403) - end - end - - context 'when user was created by the same application' do - before do - user.update(created_by_application: token.application) - end - - context 'when the account is already confirmed' do - let(:confirmed_at) { Time.now.utc } - - it 'returns http forbidden' do - subject - - expect(response).to have_http_status(403) - end - - context 'when user changed e-mail and has not confirmed it' do - before do - user.update(email: 'foo@bar.com') - end - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - end - end - - context 'when the account is unconfirmed' do - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - end - - context 'with email param' do - let(:params) { { email: 'foo@bar.com' } } - - it "updates the user's e-mail address", :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(user.reload.unconfirmed_email).to eq('foo@bar.com') - end - end - - context 'with invalid email param' do - let(:params) { { email: 'invalid' } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - end - end - - context 'without an oauth token' do - let(:headers) { {} } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - end - - describe 'GET /api/v1/emails/check_confirmation' do - subject do - get '/api/v1/emails/check_confirmation', headers: headers - end - - it_behaves_like 'forbidden for wrong scope', 'write' - - context 'with an oauth token' do - context 'when the account is not confirmed' do - it 'returns the confirmation status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(body_as_json).to be false - end - end - - context 'when the account is confirmed' do - let(:confirmed_at) { Time.now.utc } - - it 'returns the confirmation status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(body_as_json).to be true - end - end - end - - context 'with an authentication cookie' do - let(:headers) { {} } - - before do - sign_in user, scope: :user - end - - context 'when the account is not confirmed' do - it 'returns the confirmation status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(body_as_json).to be false - end - end - - context 'when the account is confirmed' do - let(:confirmed_at) { Time.now.utc } - - it 'returns the confirmation status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(body_as_json).to be true - end - end - end - - context 'without an oauth token and an authentication cookie' do - let(:headers) { {} } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - end -end diff --git a/spec/requests/api/v1/featured_tags_spec.rb b/spec/requests/api/v1/featured_tags_spec.rb deleted file mode 100644 index 6c171f6e4..000000000 --- a/spec/requests/api/v1/featured_tags_spec.rb +++ /dev/null @@ -1,193 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'FeaturedTags' do - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:scopes) { 'read:accounts write:accounts' } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/featured_tags' do - context 'with wrong scope' do - before do - get '/api/v1/featured_tags', headers: headers - end - - it_behaves_like 'forbidden for wrong scope', 'read:statuses' - end - - context 'when Authorization header is missing' do - it 'returns http unauthorized' do - get '/api/v1/featured_tags' - - expect(response).to have_http_status(401) - end - end - - it 'returns http success' do - get '/api/v1/featured_tags', headers: headers - - expect(response).to have_http_status(200) - end - - context 'when the requesting user has no featured tag' do - before { Fabricate.times(3, :featured_tag) } - - it 'returns an empty body' do - get '/api/v1/featured_tags', headers: headers - - body = body_as_json - - expect(body).to be_empty - end - end - - context 'when the requesting user has featured tags' do - let!(:user_featured_tags) { Fabricate.times(5, :featured_tag, account: user.account) } - - it 'returns only the featured tags belonging to the requesting user' do - get '/api/v1/featured_tags', headers: headers - - body = body_as_json - expected_ids = user_featured_tags.pluck(:id).map(&:to_s) - - expect(body.pluck(:id)).to match_array(expected_ids) - end - end - end - - describe 'POST /api/v1/featured_tags' do - let(:params) { { name: 'tag' } } - - it 'returns http success' do - post '/api/v1/featured_tags', headers: headers, params: params - - expect(response).to have_http_status(200) - end - - it 'returns the correct tag name' do - post '/api/v1/featured_tags', headers: headers, params: params - - body = body_as_json - - expect(body[:name]).to eq(params[:name]) - end - - it 'creates a new featured tag for the requesting user' do - post '/api/v1/featured_tags', headers: headers, params: params - - featured_tag = FeaturedTag.find_by(name: params[:name], account: user.account) - - expect(featured_tag).to be_present - end - - context 'with wrong scope' do - before do - post '/api/v1/featured_tags', headers: headers, params: params - end - - it_behaves_like 'forbidden for wrong scope', 'read:statuses' - end - - context 'when Authorization header is missing' do - it 'returns http unauthorized' do - post '/api/v1/featured_tags', params: params - - expect(response).to have_http_status(401) - end - end - - context 'when required param "name" is not provided' do - it 'returns http bad request' do - post '/api/v1/featured_tags', headers: headers - - expect(response).to have_http_status(400) - end - end - - context 'when provided tag name is invalid' do - let(:params) { { name: 'asj&*!' } } - - it 'returns http unprocessable entity' do - post '/api/v1/featured_tags', headers: headers, params: params - - expect(response).to have_http_status(422) - end - end - - context 'when tag name is already taken' do - before do - FeaturedTag.create(name: params[:name], account: user.account) - end - - it 'returns http unprocessable entity' do - post '/api/v1/featured_tags', headers: headers, params: params - - expect(response).to have_http_status(422) - end - end - end - - describe 'DELETE /api/v1/featured_tags' do - let!(:featured_tag) { FeaturedTag.create(name: 'tag', account: user.account) } - let(:id) { featured_tag.id } - - it 'returns http success' do - delete "/api/v1/featured_tags/#{id}", headers: headers - - expect(response).to have_http_status(200) - end - - it 'returns an empty body' do - delete "/api/v1/featured_tags/#{id}", headers: headers - - body = body_as_json - - expect(body).to be_empty - end - - it 'deletes the featured tag' do - delete "/api/v1/featured_tags/#{id}", headers: headers - - featured_tag = FeaturedTag.find_by(id: id) - - expect(featured_tag).to be_nil - end - - context 'with wrong scope' do - before do - delete "/api/v1/featured_tags/#{id}", headers: headers - end - - it_behaves_like 'forbidden for wrong scope', 'read:statuses' - end - - context 'when Authorization header is missing' do - it 'returns http unauthorized' do - delete "/api/v1/featured_tags/#{id}" - - expect(response).to have_http_status(401) - end - end - - context 'when featured tag with given id does not exist' do - it 'returns http not found' do - delete '/api/v1/featured_tags/0', headers: headers - - expect(response).to have_http_status(404) - end - end - - context 'when deleting a featured tag of another user' do - let!(:other_user_featured_tag) { Fabricate(:featured_tag) } - let(:id) { other_user_featured_tag.id } - - it 'returns http not found' do - delete "/api/v1/featured_tags/#{id}", headers: headers - - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/requests/api/v1/follow_requests_spec.rb b/spec/requests/api/v1/follow_requests_spec.rb deleted file mode 100644 index 9d4ef8cd5..000000000 --- a/spec/requests/api/v1/follow_requests_spec.rb +++ /dev/null @@ -1,119 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Follow requests' do - let(:user) { Fabricate(:user, account_attributes: { locked: true }) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:scopes) { 'read:follows write:follows' } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/follow_requests' do - subject do - get '/api/v1/follow_requests', headers: headers, params: params - end - - let(:accounts) { Fabricate.times(5, :account) } - let(:params) { {} } - - let(:expected_response) do - accounts.map do |account| - a_hash_including( - id: account.id.to_s, - username: account.username, - acct: account.acct - ) - end - end - - before do - accounts.each { |account| FollowService.new.call(account, user.account) } - end - - it_behaves_like 'forbidden for wrong scope', 'write write:follows' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the expected content from accounts requesting to follow' do - subject - - expect(body_as_json).to match_array(expected_response) - end - - context 'with limit param' do - let(:params) { { limit: 2 } } - - it 'returns only the requested number of follow requests' do - subject - - expect(body_as_json.size).to eq(params[:limit]) - end - end - end - - describe 'POST /api/v1/follow_requests/:account_id/authorize' do - subject do - post "/api/v1/follow_requests/#{follower.id}/authorize", headers: headers - end - - let(:follower) { Fabricate(:account) } - - before do - FollowService.new.call(follower, user.account) - end - - it_behaves_like 'forbidden for wrong scope', 'read read:follows' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'allows the requesting follower to follow' do - expect { subject }.to change { follower.following?(user.account) }.from(false).to(true) - end - - it 'returns JSON with followed_by set to true' do - subject - - expect(body_as_json[:followed_by]).to be true - end - end - - describe 'POST /api/v1/follow_requests/:account_id/reject' do - subject do - post "/api/v1/follow_requests/#{follower.id}/reject", headers: headers - end - - let(:follower) { Fabricate(:account) } - - before do - FollowService.new.call(follower, user.account) - end - - it_behaves_like 'forbidden for wrong scope', 'read read:follows' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'removes the follow request' do - subject - - expect(FollowRequest.where(target_account: user.account, account: follower)).to_not exist - end - - it 'returns JSON with followed_by set to false' do - subject - - expect(body_as_json[:followed_by]).to be false - end - end -end diff --git a/spec/requests/api/v1/instances/languages_spec.rb b/spec/requests/api/v1/instances/languages_spec.rb deleted file mode 100644 index 8ab8bf99c..000000000 --- a/spec/requests/api/v1/instances/languages_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Languages' do - describe 'GET /api/v1/instance/languages' do - before do - get '/api/v1/instance/languages' - end - - it 'returns http success' do - expect(response).to have_http_status(200) - end - - it 'returns the supported languages' do - expect(body_as_json.pluck(:code)).to match_array LanguagesHelper::SUPPORTED_LOCALES.keys.map(&:to_s) - end - end -end diff --git a/spec/requests/api/v1/lists_spec.rb b/spec/requests/api/v1/lists_spec.rb deleted file mode 100644 index 383e09d0c..000000000 --- a/spec/requests/api/v1/lists_spec.rb +++ /dev/null @@ -1,247 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Lists' do - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:scopes) { 'read:lists write:lists' } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/lists' do - subject do - get '/api/v1/lists', headers: headers - end - - let!(:lists) do - [ - Fabricate(:list, account: user.account, title: 'first list', replies_policy: :followed), - Fabricate(:list, account: user.account, title: 'second list', replies_policy: :list), - Fabricate(:list, account: user.account, title: 'third list', replies_policy: :none), - Fabricate(:list, account: user.account, title: 'fourth list', exclusive: true), - ] - end - - let(:expected_response) do - lists.map do |list| - { - id: list.id.to_s, - title: list.title, - replies_policy: list.replies_policy, - exclusive: list.exclusive, - } - end - end - - before do - Fabricate(:list) - end - - it_behaves_like 'forbidden for wrong scope', 'write write:lists' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the expected lists' do - subject - - expect(body_as_json).to match_array(expected_response) - end - end - - describe 'GET /api/v1/lists/:id' do - subject do - get "/api/v1/lists/#{list.id}", headers: headers - end - - let(:list) { Fabricate(:list, account: user.account) } - - it_behaves_like 'forbidden for wrong scope', 'write write:lists' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the requested list correctly' do - subject - - expect(body_as_json).to eq({ - id: list.id.to_s, - title: list.title, - replies_policy: list.replies_policy, - exclusive: list.exclusive, - }) - end - - context 'when the list belongs to a different user' do - let(:list) { Fabricate(:list) } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - - context 'when the list does not exist' do - it 'returns http not found' do - get '/api/v1/lists/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - end - - describe 'POST /api/v1/lists' do - subject do - post '/api/v1/lists', headers: headers, params: params - end - - let(:params) { { title: 'my list', replies_policy: 'none', exclusive: 'true' } } - - it_behaves_like 'forbidden for wrong scope', 'read read:lists' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the new list' do - subject - - expect(body_as_json).to match(a_hash_including(title: 'my list', replies_policy: 'none', exclusive: true)) - end - - it 'creates a list' do - subject - - expect(List.where(account: user.account).count).to eq(1) - end - - context 'when a title is not given' do - let(:params) { { title: '' } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when the given replies_policy is invalid' do - let(:params) { { title: 'a list', replies_policy: 'whatever' } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - end - - describe 'PUT /api/v1/lists/:id' do - subject do - put "/api/v1/lists/#{list.id}", headers: headers, params: params - end - - let(:list) { Fabricate(:list, account: user.account, title: 'my list') } - let(:params) { { title: 'list', replies_policy: 'followed', exclusive: 'true' } } - - it_behaves_like 'forbidden for wrong scope', 'read read:lists' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the updated list' do - subject - - list.reload - - expect(body_as_json).to eq({ - id: list.id.to_s, - title: list.title, - replies_policy: list.replies_policy, - exclusive: list.exclusive, - }) - end - - it 'updates the list title' do - expect { subject }.to change { list.reload.title }.from('my list').to('list') - end - - it 'updates the list replies_policy' do - expect { subject }.to change { list.reload.replies_policy }.from('list').to('followed') - end - - it 'updates the list exclusive' do - expect { subject }.to change { list.reload.exclusive }.from(false).to(true) - end - - context 'when the list does not exist' do - it 'returns http not found' do - put '/api/v1/lists/-1', headers: headers, params: params - - expect(response).to have_http_status(404) - end - end - - context 'when the list belongs to another user' do - let(:list) { Fabricate(:list) } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end - - describe 'DELETE /api/v1/lists/:id' do - subject do - delete "/api/v1/lists/#{list.id}", headers: headers - end - - let(:list) { Fabricate(:list, account: user.account) } - - it_behaves_like 'forbidden for wrong scope', 'read read:lists' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'deletes the list' do - subject - - expect(List.where(id: list.id)).to_not exist - end - - context 'when the list does not exist' do - it 'returns http not found' do - delete '/api/v1/lists/-1', headers: headers - - expect(response).to have_http_status(404) - end - end - - context 'when the list belongs to another user' do - let(:list) { Fabricate(:list) } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/requests/api/v1/mutes_spec.rb b/spec/requests/api/v1/mutes_spec.rb deleted file mode 100644 index 9a1d16200..000000000 --- a/spec/requests/api/v1/mutes_spec.rb +++ /dev/null @@ -1,90 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Mutes' do - let(:user) { Fabricate(:user) } - let(:scopes) { 'read:mutes' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/mutes' do - subject do - get '/api/v1/mutes', headers: headers, params: params - end - - let!(:mutes) { Fabricate.times(3, :mute, account: user.account) } - let(:params) { {} } - - it_behaves_like 'forbidden for wrong scope', 'write write:mutes' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the muted accounts' do - subject - - muted_accounts = mutes.map(&:target_account) - - expect(body_as_json.pluck(:id)).to match_array(muted_accounts.map { |account| account.id.to_s }) - end - - context 'with limit param' do - let(:params) { { limit: 2 } } - - it 'returns only the requested number of muted accounts' do - subject - - expect(body_as_json.size).to eq(params[:limit]) - end - - it 'sets the correct pagination headers', :aggregate_failures do - subject - - headers = response.headers['Link'] - - expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_mutes_url(limit: params[:limit], since_id: mutes[2].id.to_s)) - expect(headers.find_link(%w(rel next)).href).to eq(api_v1_mutes_url(limit: params[:limit], max_id: mutes[1].id.to_s)) - end - end - - context 'with max_id param' do - let(:params) { { max_id: mutes[1].id } } - - it 'queries mutes in range according to max_id', :aggregate_failures do - subject - - body = body_as_json - - expect(body.size).to eq 1 - expect(body[0][:id]).to eq mutes[0].target_account_id.to_s - end - end - - context 'with since_id param' do - let(:params) { { since_id: mutes[0].id } } - - it 'queries mutes in range according to since_id', :aggregate_failures do - subject - - body = body_as_json - - expect(body.size).to eq 2 - expect(body[0][:id]).to eq mutes[2].target_account_id.to_s - end - end - - context 'without an authentication header' do - let(:headers) { {} } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - end -end diff --git a/spec/requests/api/v1/polls_spec.rb b/spec/requests/api/v1/polls_spec.rb deleted file mode 100644 index 1c8a818d5..000000000 --- a/spec/requests/api/v1/polls_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Polls' do - let(:user) { Fabricate(:user) } - let(:scopes) { 'read:statuses' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/polls/:id' do - subject do - get "/api/v1/polls/#{poll.id}", headers: headers - end - - let(:poll) { Fabricate(:poll, status: Fabricate(:status, visibility: visibility)) } - let(:visibility) { 'public' } - - it_behaves_like 'forbidden for wrong scope', 'write write:statuses' - - context 'when parent status is public' do - it 'returns the poll data successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(body_as_json).to match( - a_hash_including( - id: poll.id.to_s, - voted: false, - voters_count: poll.voters_count, - votes_count: poll.votes_count - ) - ) - end - end - - context 'when parent status is private' do - let(:visibility) { 'private' } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/requests/api/v1/profiles_spec.rb b/spec/requests/api/v1/profiles_spec.rb deleted file mode 100644 index 26a9b848e..000000000 --- a/spec/requests/api/v1/profiles_spec.rb +++ /dev/null @@ -1,98 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Deleting profile images' do - let(:account) do - Fabricate( - :account, - avatar: fixture_file_upload('avatar.gif', 'image/gif'), - header: fixture_file_upload('attachment.jpg', 'image/jpeg') - ) - end - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: account.user.id, scopes: scopes) } - let(:scopes) { 'write:accounts' } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'DELETE /api/v1/profile' do - before do - allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async) - end - - context 'when deleting an avatar' do - context 'with wrong scope' do - before do - delete '/api/v1/profile/avatar', headers: headers - end - - it_behaves_like 'forbidden for wrong scope', 'read' - end - - it 'returns http success' do - delete '/api/v1/profile/avatar', headers: headers - - expect(response).to have_http_status(200) - end - - it 'deletes the avatar' do - delete '/api/v1/profile/avatar', headers: headers - - account.reload - - expect(account.avatar).to_not exist - end - - it 'does not delete the header' do - delete '/api/v1/profile/avatar', headers: headers - - account.reload - - expect(account.header).to exist - end - - it 'queues up an account update distribution' do - delete '/api/v1/profile/avatar', headers: headers - - expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id) - end - end - - context 'when deleting a header' do - context 'with wrong scope' do - before do - delete '/api/v1/profile/header', headers: headers - end - - it_behaves_like 'forbidden for wrong scope', 'read' - end - - it 'returns http success' do - delete '/api/v1/profile/header', headers: headers - - expect(response).to have_http_status(200) - end - - it 'does not delete the avatar' do - delete '/api/v1/profile/header', headers: headers - - account.reload - - expect(account.avatar).to exist - end - - it 'deletes the header' do - delete '/api/v1/profile/header', headers: headers - - account.reload - - expect(account.header).to_not exist - end - - it 'queues up an account update distribution' do - delete '/api/v1/profile/header', headers: headers - - expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id) - end - end - end -end diff --git a/spec/requests/api/v1/statuses/bookmarks_spec.rb b/spec/requests/api/v1/statuses/bookmarks_spec.rb deleted file mode 100644 index d3007740a..000000000 --- a/spec/requests/api/v1/statuses/bookmarks_spec.rb +++ /dev/null @@ -1,155 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Bookmarks' do - let(:user) { Fabricate(:user) } - let(:scopes) { 'write:bookmarks' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'POST /api/v1/statuses/:status_id/bookmark' do - subject do - post "/api/v1/statuses/#{status.id}/bookmark", headers: headers - end - - let(:status) { Fabricate(:status) } - - it_behaves_like 'forbidden for wrong scope', 'read' - - context 'with public status' do - it 'bookmarks the status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(user.account.bookmarked?(status)).to be true - end - - it 'returns json with updated attributes' do - subject - - expect(body_as_json).to match( - a_hash_including(id: status.id.to_s, bookmarked: true) - ) - end - end - - context 'with private status of not-followed account' do - let(:status) { Fabricate(:status, visibility: :private) } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - - context 'with private status of followed account' do - let(:status) { Fabricate(:status, visibility: :private) } - - before do - user.account.follow!(status.account) - end - - it 'bookmarks the status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(user.account.bookmarked?(status)).to be true - end - end - - context 'when the status does not exist' do - it 'returns http not found' do - post '/api/v1/statuses/-1/bookmark', headers: headers - - expect(response).to have_http_status(404) - end - end - - context 'without an authorization header' do - let(:headers) { {} } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - end - - describe 'POST /api/v1/statuses/:status_id/unbookmark' do - subject do - post "/api/v1/statuses/#{status.id}/unbookmark", headers: headers - end - - let(:status) { Fabricate(:status) } - - it_behaves_like 'forbidden for wrong scope', 'read' - - context 'with public status' do - context 'when the status was previously bookmarked' do - before do - Bookmark.find_or_create_by!(account: user.account, status: status) - end - - it 'unbookmarks the status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(user.account.bookmarked?(status)).to be false - end - - it 'returns json with updated attributes' do - subject - - expect(body_as_json).to match( - a_hash_including(id: status.id.to_s, bookmarked: false) - ) - end - end - - context 'when the requesting user was blocked by the status author' do - let(:status) { Fabricate(:status) } - - before do - Bookmark.find_or_create_by!(account: user.account, status: status) - status.account.block!(user.account) - end - - it 'unbookmarks the status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(user.account.bookmarked?(status)).to be false - end - - it 'returns json with updated attributes' do - subject - - expect(body_as_json).to match( - a_hash_including(id: status.id.to_s, bookmarked: false) - ) - end - end - - context 'when the status is not bookmarked' do - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - end - end - - context 'with private status that was not bookmarked' do - let(:status) { Fabricate(:status, visibility: :private) } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/requests/api/v1/statuses/favourites_spec.rb b/spec/requests/api/v1/statuses/favourites_spec.rb deleted file mode 100644 index ac5e86f29..000000000 --- a/spec/requests/api/v1/statuses/favourites_spec.rb +++ /dev/null @@ -1,155 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Favourites' do - let(:user) { Fabricate(:user) } - let(:scopes) { 'write:favourites' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'POST /api/v1/statuses/:status_id/favourite' do - subject do - post "/api/v1/statuses/#{status.id}/favourite", headers: headers - end - - let(:status) { Fabricate(:status) } - - it_behaves_like 'forbidden for wrong scope', 'read read:favourites' - - context 'with public status' do - it 'favourites the status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(user.account.favourited?(status)).to be true - end - - it 'returns json with updated attributes' do - subject - - expect(body_as_json).to match( - a_hash_including(id: status.id.to_s, favourites_count: 1, favourited: true) - ) - end - end - - context 'with private status of not-followed account' do - let(:status) { Fabricate(:status, visibility: :private) } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - - context 'with private status of followed account' do - let(:status) { Fabricate(:status, visibility: :private) } - - before do - user.account.follow!(status.account) - end - - it 'favourites the status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(user.account.favourited?(status)).to be true - end - end - - context 'without an authorization header' do - let(:headers) { {} } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - end - - describe 'POST /api/v1/statuses/:status_id/unfavourite' do - subject do - post "/api/v1/statuses/#{status.id}/unfavourite", headers: headers - end - - let(:status) { Fabricate(:status) } - - around do |example| - Sidekiq::Testing.fake! do - example.run - end - end - - it_behaves_like 'forbidden for wrong scope', 'read read:favourites' - - context 'with public status' do - before do - FavouriteService.new.call(user.account, status) - end - - it 'unfavourites the status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(user.account.favourited?(status)).to be true - - UnfavouriteWorker.drain - expect(user.account.favourited?(status)).to be false - end - - it 'returns json with updated attributes' do - subject - - expect(body_as_json).to match( - a_hash_including(id: status.id.to_s, favourites_count: 0, favourited: false) - ) - end - end - - context 'when the requesting user was blocked by the status author' do - before do - FavouriteService.new.call(user.account, status) - status.account.block!(user.account) - end - - it 'unfavourites the status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(user.account.favourited?(status)).to be true - - UnfavouriteWorker.drain - expect(user.account.favourited?(status)).to be false - end - - it 'returns json with updated attributes' do - subject - - expect(body_as_json).to match( - a_hash_including(id: status.id.to_s, favourites_count: 0, favourited: false) - ) - end - end - - context 'when status is not favourited' do - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - end - - context 'with private status that was not favourited' do - let(:status) { Fabricate(:status, visibility: :private) } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/requests/api/v1/statuses/pins_spec.rb b/spec/requests/api/v1/statuses/pins_spec.rb deleted file mode 100644 index db07fa424..000000000 --- a/spec/requests/api/v1/statuses/pins_spec.rb +++ /dev/null @@ -1,131 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'Pins' do - let(:user) { Fabricate(:user) } - let(:scopes) { 'write:accounts' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'POST /api/v1/statuses/:status_id/pin' do - subject do - post "/api/v1/statuses/#{status.id}/pin", headers: headers - end - - let(:status) { Fabricate(:status, account: user.account) } - - it_behaves_like 'forbidden for wrong scope', 'read read:accounts' - - context 'when the status is public' do - it 'pins the status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(user.account.pinned?(status)).to be true - end - - it 'return json with updated attributes' do - subject - - expect(body_as_json).to match( - a_hash_including(id: status.id.to_s, pinned: true) - ) - end - end - - context 'when the status is private' do - let(:status) { Fabricate(:status, account: user.account, visibility: :private) } - - it 'pins the status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(user.account.pinned?(status)).to be true - end - end - - context 'when the status belongs to somebody else' do - let(:status) { Fabricate(:status) } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when the status does not exist' do - it 'returns http not found' do - post '/api/v1/statuses/-1/pin', headers: headers - - expect(response).to have_http_status(404) - end - end - - context 'without an authorization header' do - let(:headers) { {} } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - end - - describe 'POST /api/v1/statuses/:status_id/unpin' do - subject do - post "/api/v1/statuses/#{status.id}/unpin", headers: headers - end - - let(:status) { Fabricate(:status, account: user.account) } - - context 'when the status is pinned' do - before do - Fabricate(:status_pin, status: status, account: user.account) - end - - it 'unpins the status successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(user.account.pinned?(status)).to be false - end - - it 'return json with updated attributes' do - subject - - expect(body_as_json).to match( - a_hash_including(id: status.id.to_s, pinned: false) - ) - end - end - - context 'when the status is not pinned' do - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - end - - context 'when the status does not exist' do - it 'returns http not found' do - post '/api/v1/statuses/-1/unpin', headers: headers - - expect(response).to have_http_status(404) - end - end - - context 'without an authorization header' do - let(:headers) { {} } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - end -end diff --git a/spec/requests/api/v1/suggestions_spec.rb b/spec/requests/api/v1/suggestions_spec.rb deleted file mode 100644 index 42b7f8662..000000000 --- a/spec/requests/api/v1/suggestions_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Suggestions' do - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:scopes) { 'read' } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/suggestions' do - subject do - get '/api/v1/suggestions', headers: headers, params: params - end - - let(:bob) { Fabricate(:account) } - let(:jeff) { Fabricate(:account) } - let(:params) { {} } - - before do - PotentialFriendshipTracker.record(user.account_id, bob.id, :reblog) - PotentialFriendshipTracker.record(user.account_id, jeff.id, :favourite) - end - - it_behaves_like 'forbidden for wrong scope', 'write' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns accounts' do - subject - - body = body_as_json - - expect(body.size).to eq 2 - expect(body.pluck(:id)).to match_array([bob, jeff].map { |i| i.id.to_s }) - end - - context 'with limit param' do - let(:params) { { limit: 1 } } - - it 'returns only the requested number of accounts' do - subject - - expect(body_as_json.size).to eq 1 - end - end - - context 'without an authorization header' do - let(:headers) { {} } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - end - - describe 'DELETE /api/v1/suggestions/:id' do - subject do - delete "/api/v1/suggestions/#{jeff.id}", headers: headers - end - - let(:suggestions_source) { instance_double(AccountSuggestions::PastInteractionsSource, remove: nil) } - let(:bob) { Fabricate(:account) } - let(:jeff) { Fabricate(:account) } - - before do - PotentialFriendshipTracker.record(user.account_id, bob.id, :reblog) - PotentialFriendshipTracker.record(user.account_id, jeff.id, :favourite) - allow(AccountSuggestions::PastInteractionsSource).to receive(:new).and_return(suggestions_source) - end - - it_behaves_like 'forbidden for wrong scope', 'write' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'removes the specified suggestion' do - subject - - expect(suggestions_source).to have_received(:remove).with(user.account, jeff.id.to_s).once - expect(suggestions_source).to_not have_received(:remove).with(user.account, bob.id.to_s) - end - - context 'without an authorization header' do - let(:headers) { {} } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - end -end diff --git a/spec/requests/api/v1/tags_spec.rb b/spec/requests/api/v1/tags_spec.rb deleted file mode 100644 index 300ddf805..000000000 --- a/spec/requests/api/v1/tags_spec.rb +++ /dev/null @@ -1,169 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Tags' do - let(:user) { Fabricate(:user) } - let(:scopes) { 'write:follows' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/tags/:id' do - subject do - get "/api/v1/tags/#{name}" - end - - context 'when the tag exists' do - let!(:tag) { Fabricate(:tag) } - let(:name) { tag.name } - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the tag' do - subject - - expect(body_as_json[:name]).to eq(name) - end - end - - context 'when the tag does not exist' do - let(:name) { 'hoge' } - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - end - - context 'when the tag name is invalid' do - let(:name) { 'tag-name' } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end - - describe 'POST /api/v1/tags/:id/follow' do - subject do - post "/api/v1/tags/#{name}/follow", headers: headers - end - - let!(:tag) { Fabricate(:tag) } - let(:name) { tag.name } - - it_behaves_like 'forbidden for wrong scope', 'read read:follows' - - context 'when the tag exists' do - it 'returns http success' do - subject - - expect(response).to have_http_status(:success) - end - - it 'creates follow' do - subject - - expect(TagFollow.where(tag: tag, account: user.account)).to exist - end - end - - context 'when the tag does not exist' do - let(:name) { 'hoge' } - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'creates a new tag with the specified name' do - subject - - expect(Tag.where(name: name)).to exist - end - - it 'creates follow' do - subject - - expect(TagFollow.where(tag: Tag.find_by(name: name), account: user.account)).to exist - end - end - - context 'when the tag name is invalid' do - let(:name) { 'tag-name' } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - - context 'when the Authorization header is missing' do - let(:headers) { {} } - let(:name) { 'unauthorized' } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - end - - describe 'POST #unfollow' do - subject do - post "/api/v1/tags/#{name}/unfollow", headers: headers - end - - let(:name) { tag.name } - let!(:tag) { Fabricate(:tag, name: 'foo') } - - before do - Fabricate(:tag_follow, account: user.account, tag: tag) - end - - it_behaves_like 'forbidden for wrong scope', 'read read:follows' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'removes the follow' do - subject - - expect(TagFollow.where(tag: tag, account: user.account)).to_not exist - end - - context 'when the tag name is invalid' do - let(:name) { 'tag-name' } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - - context 'when the Authorization header is missing' do - let(:headers) { {} } - let(:name) { 'unauthorized' } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - end -end diff --git a/spec/requests/api/v1/timelines/home_spec.rb b/spec/requests/api/v1/timelines/home_spec.rb deleted file mode 100644 index 5834b9095..000000000 --- a/spec/requests/api/v1/timelines/home_spec.rb +++ /dev/null @@ -1,101 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'Home' do - let(:user) { Fabricate(:user) } - let(:scopes) { 'read:statuses' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'GET /api/v1/timelines/home' do - subject do - get '/api/v1/timelines/home', headers: headers, params: params - end - - let(:params) { {} } - - it_behaves_like 'forbidden for wrong scope', 'write write:statuses' - - context 'when the timeline is available' do - let(:home_statuses) { bob.statuses + ana.statuses } - let!(:bob) { Fabricate(:account) } - let!(:tim) { Fabricate(:account) } - let!(:ana) { Fabricate(:account) } - - before do - user.account.follow!(bob) - user.account.follow!(ana) - PostStatusService.new.call(bob, text: 'New toot from bob.') - PostStatusService.new.call(tim, text: 'New toot from tim.') - PostStatusService.new.call(ana, text: 'New toot from ana.') - end - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns the statuses of followed users' do - subject - - expect(body_as_json.pluck(:id)).to match_array(home_statuses.map { |status| status.id.to_s }) - end - - context 'with limit param' do - let(:params) { { limit: 1 } } - - it 'returns only the requested number of statuses' do - subject - - expect(body_as_json.size).to eq(params[:limit]) - end - - it 'sets the correct pagination headers', :aggregate_failures do - subject - - headers = response.headers['Link'] - - expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_timelines_home_url(limit: 1, min_id: ana.statuses.first.id.to_s)) - expect(headers.find_link(%w(rel next)).href).to eq(api_v1_timelines_home_url(limit: 1, max_id: ana.statuses.first.id.to_s)) - end - end - end - - context 'when the timeline is regenerating' do - let(:timeline) { instance_double(HomeFeed, regenerating?: true, get: []) } - - before do - allow(HomeFeed).to receive(:new).and_return(timeline) - end - - it 'returns http partial content' do - subject - - expect(response).to have_http_status(206) - end - end - - context 'without an authorization header' do - let(:headers) { {} } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - - context 'without a user context' do - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: scopes) } - - it 'returns http unprocessable entity', :aggregate_failures do - subject - - expect(response).to have_http_status(422) - expect(response.headers['Link']).to be_nil - end - end - end -end diff --git a/spec/requests/api/v1/timelines/public_spec.rb b/spec/requests/api/v1/timelines/public_spec.rb deleted file mode 100644 index 4afa40e58..000000000 --- a/spec/requests/api/v1/timelines/public_spec.rb +++ /dev/null @@ -1,120 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'Public' do - let(:user) { Fabricate(:user) } - let(:scopes) { 'read:statuses' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - shared_examples 'a successful request to the public timeline' do - it 'returns the expected statuses successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(body_as_json.pluck(:id)).to match_array(expected_statuses.map { |status| status.id.to_s }) - end - end - - describe 'GET /api/v1/timelines/public' do - subject do - get '/api/v1/timelines/public', headers: headers, params: params - end - - let!(:private_status) { Fabricate(:status, visibility: :private) } # rubocop:disable RSpec/LetSetup - let!(:local_status) { Fabricate(:status, account: Fabricate.build(:account, domain: nil)) } - let!(:remote_status) { Fabricate(:status, account: Fabricate.build(:account, domain: 'example.com')) } - let!(:media_status) { Fabricate(:status, media_attachments: [Fabricate.build(:media_attachment)]) } - - let(:params) { {} } - - context 'when the instance allows public preview' do - let(:expected_statuses) { [local_status, remote_status, media_status] } - - before do - Setting.timeline_preview = true - end - - context 'with an authorized user' do - it_behaves_like 'a successful request to the public timeline' - end - - context 'with an anonymous user' do - let(:headers) { {} } - - it_behaves_like 'a successful request to the public timeline' - end - - context 'with local param' do - let(:params) { { local: true } } - let(:expected_statuses) { [local_status, media_status] } - - it_behaves_like 'a successful request to the public timeline' - end - - context 'with remote param' do - let(:params) { { remote: true } } - let(:expected_statuses) { [remote_status] } - - it_behaves_like 'a successful request to the public timeline' - end - - context 'with local and remote params' do - let(:params) { { local: true, remote: true } } - let(:expected_statuses) { [local_status, remote_status, media_status] } - - it_behaves_like 'a successful request to the public timeline' - end - - context 'with only_media param' do - let(:params) { { only_media: true } } - let(:expected_statuses) { [media_status] } - - it_behaves_like 'a successful request to the public timeline' - end - - context 'with limit param' do - let(:params) { { limit: 1 } } - - it 'returns only the requested number of statuses', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(body_as_json.size).to eq(params[:limit]) - end - - it 'sets the correct pagination headers', :aggregate_failures do - subject - - headers = response.headers['Link'] - - expect(headers.find_link(%w(rel prev)).href).to eq(api_v1_timelines_public_url(limit: 1, min_id: media_status.id.to_s)) - expect(headers.find_link(%w(rel next)).href).to eq(api_v1_timelines_public_url(limit: 1, max_id: media_status.id.to_s)) - end - end - end - - context 'when the instance does not allow public preview' do - before do - Form::AdminSettings.new(timeline_preview: false).save - end - - context 'with an authenticated user' do - let(:expected_statuses) { [local_status, remote_status, media_status] } - - it_behaves_like 'a successful request to the public timeline' - end - - context 'with an unauthenticated user' do - let(:headers) { {} } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - end - end -end diff --git a/spec/requests/api/v2/filters/filters_spec.rb b/spec/requests/api/v2/filters/filters_spec.rb deleted file mode 100644 index 2ee24d809..000000000 --- a/spec/requests/api/v2/filters/filters_spec.rb +++ /dev/null @@ -1,248 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Filters' do - let(:user) { Fabricate(:user) } - let(:scopes) { 'read:filters write:filters' } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - shared_examples 'unauthorized for invalid token' do - let(:headers) { { 'Authorization' => '' } } - - it 'returns http unauthorized' do - subject - - expect(response).to have_http_status(401) - end - end - - describe 'GET /api/v2/filters' do - subject do - get '/api/v2/filters', headers: headers - end - - let!(:filters) { Fabricate.times(3, :custom_filter, account: user.account) } - - it_behaves_like 'forbidden for wrong scope', 'write write:filters' - it_behaves_like 'unauthorized for invalid token' - - it 'returns the existing filters successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(body_as_json.pluck(:id)).to match_array(filters.map { |filter| filter.id.to_s }) - end - end - - describe 'POST /api/v2/filters' do - subject do - post '/api/v2/filters', params: params, headers: headers - end - - let(:params) { {} } - - it_behaves_like 'forbidden for wrong scope', 'read read:filters' - it_behaves_like 'unauthorized for invalid token' - - context 'with valid params' do - let(:params) { { title: 'magic', context: %w(home), filter_action: 'hide', keywords_attributes: [keyword: 'magic'] } } - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'returns a filter with keywords', :aggregate_failures do - subject - - json = body_as_json - - expect(json[:title]).to eq 'magic' - expect(json[:filter_action]).to eq 'hide' - expect(json[:context]).to eq ['home'] - expect(json[:keywords].map { |keyword| keyword.slice(:keyword, :whole_word) }).to eq [{ keyword: 'magic', whole_word: true }] - end - - it 'creates a filter', :aggregate_failures do - subject - - filter = user.account.custom_filters.first - - expect(filter).to be_present - expect(filter.keywords.pluck(:keyword)).to eq ['magic'] - expect(filter.context).to eq %w(home) - expect(filter.irreversible?).to be true - expect(filter.expires_at).to be_nil - end - end - - context 'when the required title param is missing' do - let(:params) { { context: %w(home), filter_action: 'hide', keywords_attributes: [keyword: 'magic'] } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when the required context param is missing' do - let(:params) { { title: 'magic', filter_action: 'hide', keywords_attributes: [keyword: 'magic'] } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - - context 'when the given context value is invalid' do - let(:params) { { title: 'magic', context: %w(shaolin), filter_action: 'hide', keywords_attributes: [keyword: 'magic'] } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - end - - describe 'GET /api/v2/filters/:id' do - subject do - get "/api/v2/filters/#{filter.id}", headers: headers - end - - let(:filter) { Fabricate(:custom_filter, account: user.account) } - - it_behaves_like 'forbidden for wrong scope', 'write write:filters' - it_behaves_like 'unauthorized for invalid token' - - it 'returns the filter successfully', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - expect(body_as_json[:id]).to eq(filter.id.to_s) - end - - context 'when the filter belongs to someone else' do - let(:filter) { Fabricate(:custom_filter) } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end - - describe 'PUT /api/v2/filters/:id' do - subject do - put "/api/v2/filters/#{filter.id}", params: params, headers: headers - end - - let!(:filter) { Fabricate(:custom_filter, account: user.account) } - let!(:keyword) { Fabricate(:custom_filter_keyword, custom_filter: filter) } - let(:params) { {} } - - it_behaves_like 'forbidden for wrong scope', 'read read:filters' - it_behaves_like 'unauthorized for invalid token' - - context 'when updating filter parameters' do - context 'with valid params' do - let(:params) { { title: 'updated', context: %w(home public) } } - - it 'updates the filter successfully', :aggregate_failures do - subject - - filter.reload - - expect(response).to have_http_status(200) - expect(filter.title).to eq 'updated' - expect(filter.reload.context).to eq %w(home public) - end - end - - context 'with invalid params' do - let(:params) { { title: 'updated', context: %w(word) } } - - it 'returns http unprocessable entity' do - subject - - expect(response).to have_http_status(422) - end - end - end - - context 'when updating keywords in bulk' do - let(:params) { { keywords_attributes: [{ id: keyword.id, keyword: 'updated' }] } } - - before do - allow(redis).to receive_messages(publish: nil) - end - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'updates the keyword' do - subject - - expect(keyword.reload.keyword).to eq 'updated' - end - - it 'sends exactly one filters_changed event' do - subject - - expect(redis).to have_received(:publish).with("timeline:#{user.account.id}", Oj.dump(event: :filters_changed)).once - end - end - - context 'when the filter belongs to someone else' do - let(:filter) { Fabricate(:custom_filter) } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end - - describe 'DELETE /api/v2/filters/:id' do - subject do - delete "/api/v2/filters/#{filter.id}", headers: headers - end - - let(:filter) { Fabricate(:custom_filter, account: user.account) } - - it_behaves_like 'forbidden for wrong scope', 'read read:filters' - it_behaves_like 'unauthorized for invalid token' - - it 'returns http success' do - subject - - expect(response).to have_http_status(200) - end - - it 'removes the filter' do - subject - - expect { filter.reload }.to raise_error ActiveRecord::RecordNotFound - end - - context 'when the filter belongs to someone else' do - let(:filter) { Fabricate(:custom_filter) } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/requests/api/v2/media_spec.rb b/spec/requests/api/v2/media_spec.rb deleted file mode 100644 index 89384d0ca..000000000 --- a/spec/requests/api/v2/media_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Media API', paperclip_processing: true do - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } - let(:scopes) { 'write' } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - describe 'POST /api/v2/media' do - it 'returns http success' do - post '/api/v2/media', headers: headers, params: { file: fixture_file_upload('attachment-jpg.123456_abcd', 'image/jpeg') } - expect(File.exist?(user.account.media_attachments.first.file.path(:small))).to be true - expect(response).to have_http_status(200) - end - end -end diff --git a/spec/requests/api/web/embeds_spec.rb b/spec/requests/api/web/embeds_spec.rb deleted file mode 100644 index 6314f43aa..000000000 --- a/spec/requests/api/web/embeds_spec.rb +++ /dev/null @@ -1,161 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe '/api/web/embed' do - subject { get "/api/web/embeds/#{id}", headers: headers } - - context 'when accessed anonymously' do - let(:headers) { {} } - - context 'when the requested status is local' do - let(:id) { status.id } - - context 'when the requested status is public' do - let(:status) { Fabricate(:status, visibility: :public) } - - it 'returns JSON with an html attribute' do - subject - - expect(response).to have_http_status(200) - expect(body_as_json[:html]).to be_present - end - end - - context 'when the requested status is private' do - let(:status) { Fabricate(:status, visibility: :private) } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end - - context 'when the requested status is remote' do - let(:remote_account) { Fabricate(:account, domain: 'example.com') } - let(:status) { Fabricate(:status, visibility: :public, account: remote_account, url: 'https://example.com/statuses/1') } - let(:id) { status.id } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - - context 'when the requested status does not exist' do - let(:id) { -1 } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end - - context 'with an API token' do - let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } - let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - - context 'when the requested status is local' do - let(:id) { status.id } - - context 'when the requested status is public' do - let(:status) { Fabricate(:status, visibility: :public) } - - it 'returns JSON with an html attribute' do - subject - - expect(response).to have_http_status(200) - expect(body_as_json[:html]).to be_present - end - - context 'when the requesting user is blocked' do - before do - status.account.block!(user.account) - end - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end - - context 'when the requested status is private' do - let(:status) { Fabricate(:status, visibility: :private) } - - before do - user.account.follow!(status.account) - end - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end - - context 'when the requested status is remote' do - let(:remote_account) { Fabricate(:account, domain: 'example.com') } - let(:status) { Fabricate(:status, visibility: :public, account: remote_account, url: 'https://example.com/statuses/1') } - let(:id) { status.id } - - let(:service_instance) { instance_double(FetchOEmbedService) } - - before do - allow(FetchOEmbedService).to receive(:new) { service_instance } - allow(service_instance).to receive(:call) { call_result } - end - - context 'when the requesting user is blocked' do - before do - status.account.block!(user.account) - end - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - - context 'when successfully fetching OEmbed' do - let(:call_result) { { html: 'ok' } } - - it 'returns JSON with an html attribute' do - subject - - expect(response).to have_http_status(200) - expect(body_as_json[:html]).to be_present - end - end - - context 'when failing to fetch OEmbed' do - let(:call_result) { nil } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end - - context 'when the requested status does not exist' do - let(:id) { -1 } - - it 'returns http not found' do - subject - - expect(response).to have_http_status(404) - end - end - end -end diff --git a/spec/requests/backups_spec.rb b/spec/requests/backups_spec.rb deleted file mode 100644 index a6c2efe0d..000000000 --- a/spec/requests/backups_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'Backups' do - include RoutingHelper - - describe 'GET backups#download' do - let(:user) { Fabricate(:user) } - let(:backup) { Fabricate(:backup, user: user) } - - before do - sign_in user - end - - it 'Downloads a user backup' do - get download_backup_path(backup) - - expect(response).to redirect_to(backup_dump_url) - end - - def backup_dump_url - full_asset_url(backup.dump.url) - end - end -end diff --git a/spec/requests/cache_spec.rb b/spec/requests/cache_spec.rb deleted file mode 100644 index c391c8b3d..000000000 --- a/spec/requests/cache_spec.rb +++ /dev/null @@ -1,686 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -module TestEndpoints - # Endpoints that do not include authorization-dependent results - # and should be cacheable no matter what. - ALWAYS_CACHED = %w( - /.well-known/host-meta - /.well-known/nodeinfo - /nodeinfo/2.0 - /manifest - /custom.css - /actor - /api/v1/instance/extended_description - /api/v1/instance/rules - /api/v1/instance/peers - /api/v1/instance - /api/v2/instance - ).freeze - - # Endpoints that should be cachable when accessed anonymously but have a Vary - # on Cookie to prevent logged-in users from getting values from logged-out cache. - COOKIE_DEPENDENT_CACHABLE = %w( - / - /explore - /public - /about - /privacy-policy - /directory - /@alice - /@alice/110224538612341312 - /deck/home - ).freeze - - # Endpoints that should be cachable when accessed anonymously but have a Vary - # on Authorization to prevent logged-in users from getting values from logged-out cache. - AUTHORIZATION_DEPENDENT_CACHABLE = %w( - /api/v1/accounts/lookup?acct=alice - /api/v1/statuses/110224538612341312 - /api/v1/statuses/110224538612341312/context - /api/v1/polls/12345 - /api/v1/trends/statuses - /api/v1/directory - ).freeze - - # Private status that should only be returned with to a valid signature from - # a specific user. - # Should never be cached. - REQUIRE_SIGNATURE = %w( - /users/alice/statuses/110224538643211312 - ).freeze - - # Pages only available to logged-in users. - # Should never be cached. - REQUIRE_LOGIN = %w( - /settings/preferences/appearance - /settings/profile - /settings/featured_tags - /settings/export - /relationships - /filters - /statuses_cleanup - /auth/edit - /oauth/authorized_applications - /admin/dashboard - ).freeze - - # API endpoints only available to logged-in users. - # Should never be cached. - REQUIRE_TOKEN = %w( - /api/v1/announcements - /api/v1/timelines/home - /api/v1/notifications - /api/v1/bookmarks - /api/v1/favourites - /api/v1/follow_requests - /api/v1/conversations - /api/v1/statuses/110224538643211312 - /api/v1/statuses/110224538643211312/context - /api/v1/lists - /api/v2/filters - ).freeze - - # Pages that are only shown to logged-out users, and should never get cached - # because of CSRF protection. - REQUIRE_LOGGED_OUT = %w( - /invite/abcdef - /auth/sign_in - /auth/sign_up - /auth/password/new - /auth/confirmation/new - ).freeze - - # Non-exhaustive list of endpoints that feature language-dependent results - # and thus need to have a Vary on Accept-Language - LANGUAGE_DEPENDENT = %w( - / - /explore - /about - /api/v1/trends/statuses - ).freeze - - module AuthorizedFetch - # Endpoints that require a signature with AUTHORIZED_FETCH and LIMITED_FEDERATION_MODE - # and thus should not be cached in those modes. - REQUIRE_SIGNATURE = %w( - /users/alice - ).freeze - end - - module DisabledAnonymousAPI - # Endpoints that require a signature with DISALLOW_UNAUTHENTICATED_API_ACCESS - # and thus should not be cached in this mode. - REQUIRE_TOKEN = %w( - /api/v1/custom_emojis - ).freeze - end -end - -describe 'Caching behavior' do - shared_examples 'cachable response' do - it 'does not set cookies' do - expect(response.cookies).to be_empty - end - - it 'sets public cache control' do - # expect(response.cache_control[:max_age]&.to_i).to be_positive - expect(response.cache_control[:public]).to be_truthy - expect(response.cache_control[:private]).to be_falsy - expect(response.cache_control[:no_store]).to be_falsy - expect(response.cache_control[:no_cache]).to be_falsy - end - end - - shared_examples 'non-cacheable response' do - it 'sets private cache control' do - expect(response.cache_control[:private]).to be_truthy - expect(response.cache_control[:no_store]).to be_truthy - end - end - - shared_examples 'non-cacheable error' do - it 'does not return HTTP success' do - expect(response).to_not have_http_status(200) - end - - it 'does not have cache headers' do - expect(response.cache_control[:public]).to be_falsy - end - end - - shared_examples 'language-dependent' do - it 'has a Vary on Accept-Language' do - expect(response.headers['Vary']&.split(',')&.map { |x| x.strip.downcase }).to include('accept-language') - end - end - - # Enable CSRF protection like it is in production, as it can cause cookies - # to be set and thus mess with cache. - around do |example| - old = ActionController::Base.allow_forgery_protection - ActionController::Base.allow_forgery_protection = true - - example.run - - ActionController::Base.allow_forgery_protection = old - end - - let(:alice) { Fabricate(:account, username: 'alice') } - let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Moderator')) } - - before do - # rubocop:disable Style/NumericLiterals - status = Fabricate(:status, account: alice, id: 110224538612341312) - Fabricate(:status, account: alice, id: 110224538643211312, visibility: :private) - Fabricate(:invite, code: 'abcdef') - Fabricate(:poll, status: status, account: alice, id: 12345) - # rubocop:enable Style/NumericLiterals - - user.account.follow!(alice) - end - - context 'when anonymously accessed' do - TestEndpoints::ALWAYS_CACHED.each do |endpoint| - describe endpoint do - before { get endpoint } - - it_behaves_like 'cachable response' - it_behaves_like 'language-dependent' if TestEndpoints::LANGUAGE_DEPENDENT.include?(endpoint) - end - end - - TestEndpoints::COOKIE_DEPENDENT_CACHABLE.each do |endpoint| - describe endpoint do - before { get endpoint } - - it_behaves_like 'cachable response' - - it 'has a Vary on Cookie' do - expect(response.headers['Vary']&.split(',')&.map { |x| x.strip.downcase }).to include('cookie') - end - - it_behaves_like 'language-dependent' if TestEndpoints::LANGUAGE_DEPENDENT.include?(endpoint) - end - end - - TestEndpoints::AUTHORIZATION_DEPENDENT_CACHABLE.each do |endpoint| - describe endpoint do - before { get endpoint } - - it_behaves_like 'cachable response' - - it 'has a Vary on Authorization' do - expect(response.headers['Vary']&.split(',')&.map { |x| x.strip.downcase }).to include('authorization') - end - - it_behaves_like 'language-dependent' if TestEndpoints::LANGUAGE_DEPENDENT.include?(endpoint) - end - end - - TestEndpoints::REQUIRE_LOGGED_OUT.each do |endpoint| - describe endpoint do - before { get endpoint } - - it_behaves_like 'non-cacheable response' - end - end - - (TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::REQUIRE_LOGIN + TestEndpoints::REQUIRE_TOKEN).each do |endpoint| - describe endpoint do - before { get endpoint } - - it_behaves_like 'non-cacheable error' - end - end - - describe '/api/v1/instance/domain_blocks' do - around do |example| - old_setting = Setting.show_domain_blocks - Setting.show_domain_blocks = show_domain_blocks - - example.run - - Setting.show_domain_blocks = old_setting - end - - before { get '/api/v1/instance/domain_blocks' } - - context 'when set to be publicly-available' do - let(:show_domain_blocks) { 'all' } - - it_behaves_like 'cachable response' - end - - context 'when allowed for local users only' do - let(:show_domain_blocks) { 'users' } - - it_behaves_like 'non-cacheable error' - end - - context 'when disabled' do - let(:show_domain_blocks) { 'disabled' } - - it_behaves_like 'non-cacheable error' - end - end - end - - context 'when logged in' do - before do - sign_in user, scope: :user - - # Unfortunately, devise's `sign_in` helper causes the `session` to be - # loaded in the next request regardless of whether it's actually accessed - # by the client code. - # - # So, we make an extra query to clear issue a session cookie instead. - # - # A less resource-intensive way to deal with that would be to generate the - # session cookie manually, but this seems pretty involved. - get '/' - end - - TestEndpoints::ALWAYS_CACHED.each do |endpoint| - describe endpoint do - before { get endpoint } - - it_behaves_like 'cachable response' - it_behaves_like 'language-dependent' if TestEndpoints::LANGUAGE_DEPENDENT.include?(endpoint) - end - end - - TestEndpoints::COOKIE_DEPENDENT_CACHABLE.each do |endpoint| - describe endpoint do - before { get endpoint } - - it_behaves_like 'non-cacheable response' - - it 'has a Vary on Cookie' do - expect(response.headers['Vary']&.split(',')&.map { |x| x.strip.downcase }).to include('cookie') - end - end - end - - TestEndpoints::REQUIRE_LOGIN.each do |endpoint| - describe endpoint do - before { get endpoint } - - it_behaves_like 'non-cacheable response' - - it 'returns HTTP success' do - expect(response).to have_http_status(200) - end - end - end - - TestEndpoints::REQUIRE_LOGGED_OUT.each do |endpoint| - describe endpoint do - before { get endpoint } - - it_behaves_like 'non-cacheable error' - end - end - end - - context 'with an auth token' do - let!(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } - - TestEndpoints::ALWAYS_CACHED.each do |endpoint| - describe endpoint do - before do - get endpoint, headers: { 'Authorization' => "Bearer #{token.token}" } - end - - it_behaves_like 'cachable response' - it_behaves_like 'language-dependent' if TestEndpoints::LANGUAGE_DEPENDENT.include?(endpoint) - end - end - - TestEndpoints::AUTHORIZATION_DEPENDENT_CACHABLE.each do |endpoint| - describe endpoint do - before do - get endpoint, headers: { 'Authorization' => "Bearer #{token.token}" } - end - - it_behaves_like 'non-cacheable response' - - it 'has a Vary on Authorization' do - expect(response.headers['Vary']&.split(',')&.map { |x| x.strip.downcase }).to include('authorization') - end - end - end - - (TestEndpoints::REQUIRE_LOGGED_OUT + TestEndpoints::REQUIRE_TOKEN).each do |endpoint| - describe endpoint do - before do - get endpoint, headers: { 'Authorization' => "Bearer #{token.token}" } - end - - it_behaves_like 'non-cacheable response' - - it 'returns HTTP success' do - expect(response).to have_http_status(200) - end - end - end - - describe '/api/v1/instance/domain_blocks' do - around do |example| - old_setting = Setting.show_domain_blocks - Setting.show_domain_blocks = show_domain_blocks - - example.run - - Setting.show_domain_blocks = old_setting - end - - before do - get '/api/v1/instance/domain_blocks', headers: { 'Authorization' => "Bearer #{token.token}" } - end - - context 'when set to be publicly-available' do - let(:show_domain_blocks) { 'all' } - - it_behaves_like 'cachable response' - end - - context 'when allowed for local users only' do - let(:show_domain_blocks) { 'users' } - - it_behaves_like 'non-cacheable response' - - it 'returns HTTP success' do - expect(response).to have_http_status(200) - end - end - - context 'when disabled' do - let(:show_domain_blocks) { 'disabled' } - - it_behaves_like 'non-cacheable error' - end - end - end - - context 'with a Signature header' do - let(:remote_actor) { Fabricate(:account, domain: 'example.org', uri: 'https://example.org/remote', protocol: :activitypub) } - let(:dummy_signature) { 'dummy-signature' } - - before do - remote_actor.follow!(alice) - end - - describe '/actor' do - before do - get '/actor', sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' } - end - - it_behaves_like 'cachable response' - - it 'returns HTTP success' do - expect(response).to have_http_status(200) - end - end - - TestEndpoints::REQUIRE_SIGNATURE.each do |endpoint| - describe endpoint do - before do - get endpoint, sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' } - end - - it_behaves_like 'non-cacheable response' - - it 'returns HTTP success' do - expect(response).to have_http_status(200) - end - end - end - end - - context 'when enabling AUTHORIZED_FETCH mode' do - around do |example| - ClimateControl.modify AUTHORIZED_FETCH: 'true' do - example.run - end - end - - context 'when not providing a Signature' do - describe '/actor' do - before do - get '/actor', headers: { 'Accept' => 'application/activity+json' } - end - - it_behaves_like 'cachable response' - - it 'returns HTTP success' do - expect(response).to have_http_status(200) - end - end - - (TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint| - describe endpoint do - before do - get endpoint, headers: { 'Accept' => 'application/activity+json' } - end - - it_behaves_like 'non-cacheable error' - end - end - end - - context 'when providing a Signature' do - let(:remote_actor) { Fabricate(:account, domain: 'example.org', uri: 'https://example.org/remote', protocol: :activitypub) } - let(:dummy_signature) { 'dummy-signature' } - - before do - remote_actor.follow!(alice) - end - - describe '/actor' do - before do - get '/actor', sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' } - end - - it_behaves_like 'cachable response' - - it 'returns HTTP success' do - expect(response).to have_http_status(200) - end - end - - (TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint| - describe endpoint do - before do - get endpoint, sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' } - end - - it_behaves_like 'non-cacheable response' - - it 'returns HTTP success' do - expect(response).to have_http_status(200) - end - end - end - end - end - - context 'when enabling LIMITED_FEDERATION_MODE mode' do - around do |example| - ClimateControl.modify LIMITED_FEDERATION_MODE: 'true' do - old_limited_federation_mode = Rails.configuration.x.limited_federation_mode - Rails.configuration.x.limited_federation_mode = true - - example.run - - Rails.configuration.x.limited_federation_mode = old_limited_federation_mode - end - end - - context 'when not providing a Signature' do - describe '/actor' do - before do - get '/actor', headers: { 'Accept' => 'application/activity+json' } - end - - it_behaves_like 'cachable response' - - it 'returns HTTP success' do - expect(response).to have_http_status(200) - end - end - - (TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint| - describe endpoint do - before do - get endpoint, headers: { 'Accept' => 'application/activity+json' } - end - - it_behaves_like 'non-cacheable error' - end - end - end - - context 'when providing a Signature from an allowed domain' do - let(:remote_actor) { Fabricate(:account, domain: 'example.org', uri: 'https://example.org/remote', protocol: :activitypub) } - let(:dummy_signature) { 'dummy-signature' } - - before do - DomainAllow.create!(domain: remote_actor.domain) - remote_actor.follow!(alice) - end - - describe '/actor' do - before do - get '/actor', sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' } - end - - it_behaves_like 'cachable response' - - it 'returns HTTP success' do - expect(response).to have_http_status(200) - end - end - - (TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint| - describe endpoint do - before do - get endpoint, sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' } - end - - it_behaves_like 'non-cacheable response' - - it 'returns HTTP success' do - expect(response).to have_http_status(200) - end - end - end - end - - context 'when providing a Signature from a non-allowed domain' do - let(:remote_actor) { Fabricate(:account, domain: 'example.org', uri: 'https://example.org/remote', protocol: :activitypub) } - let(:dummy_signature) { 'dummy-signature' } - - describe '/actor' do - before do - get '/actor', sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' } - end - - it_behaves_like 'cachable response' - - it 'returns HTTP success' do - expect(response).to have_http_status(200) - end - end - - (TestEndpoints::REQUIRE_SIGNATURE + TestEndpoints::AuthorizedFetch::REQUIRE_SIGNATURE).each do |endpoint| - describe endpoint do - before do - get endpoint, sign_with: remote_actor, headers: { 'Accept' => 'application/activity+json' } - end - - it_behaves_like 'non-cacheable error' - end - end - end - end - - context 'when enabling DISALLOW_UNAUTHENTICATED_API_ACCESS' do - around do |example| - ClimateControl.modify DISALLOW_UNAUTHENTICATED_API_ACCESS: 'true' do - example.run - end - end - - context 'when anonymously accessed' do - TestEndpoints::ALWAYS_CACHED.each do |endpoint| - describe endpoint do - before { get endpoint } - - it_behaves_like 'cachable response' - it_behaves_like 'language-dependent' if TestEndpoints::LANGUAGE_DEPENDENT.include?(endpoint) - end - end - - TestEndpoints::REQUIRE_LOGGED_OUT.each do |endpoint| - describe endpoint do - before { get endpoint } - - it_behaves_like 'non-cacheable response' - end - end - - (TestEndpoints::REQUIRE_TOKEN + TestEndpoints::AUTHORIZATION_DEPENDENT_CACHABLE + TestEndpoints::DisabledAnonymousAPI::REQUIRE_TOKEN).each do |endpoint| - describe endpoint do - before { get endpoint } - - it_behaves_like 'non-cacheable error' - end - end - end - - context 'with an auth token' do - let!(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } - - TestEndpoints::ALWAYS_CACHED.each do |endpoint| - describe endpoint do - before do - get endpoint, headers: { 'Authorization' => "Bearer #{token.token}" } - end - - it_behaves_like 'cachable response' - it_behaves_like 'language-dependent' if TestEndpoints::LANGUAGE_DEPENDENT.include?(endpoint) - end - end - - TestEndpoints::AUTHORIZATION_DEPENDENT_CACHABLE.each do |endpoint| - describe endpoint do - before do - get endpoint, headers: { 'Authorization' => "Bearer #{token.token}" } - end - - it_behaves_like 'non-cacheable response' - - it 'has a Vary on Authorization' do - expect(response.headers['Vary']&.split(',')&.map { |x| x.strip.downcase }).to include('authorization') - end - end - end - - (TestEndpoints::REQUIRE_LOGGED_OUT + TestEndpoints::REQUIRE_TOKEN + TestEndpoints::DisabledAnonymousAPI::REQUIRE_TOKEN).each do |endpoint| - describe endpoint do - before do - get endpoint, headers: { 'Authorization' => "Bearer #{token.token}" } - end - - it_behaves_like 'non-cacheable response' - - it 'returns HTTP success' do - expect(response).to have_http_status(200) - end - end - end - end - end -end diff --git a/spec/requests/catch_all_route_request_spec.rb b/spec/requests/catch_all_route_request_spec.rb deleted file mode 100644 index e600bedfe..000000000 --- a/spec/requests/catch_all_route_request_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'The catch all route' do - describe 'with a simple value' do - it 'returns a 404 page as html' do - get '/test' - - expect(response).to have_http_status 404 - expect(response.media_type).to eq 'text/html' - end - end - - describe 'with an implied format' do - it 'returns a 404 page as html' do - get '/test.test' - - expect(response).to have_http_status 404 - expect(response.media_type).to eq 'text/html' - end - end -end diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb deleted file mode 100644 index d327ac1b4..000000000 --- a/spec/requests/content_security_policy_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'Content-Security-Policy' do - it 'sets the expected CSP headers' do - allow(SecureRandom).to receive(:base64).with(16).and_return('ZbA+JmE7+bK8F5qvADZHuQ==') - - get '/' - expect(response.headers['Content-Security-Policy'].split(';').map(&:strip)).to contain_exactly( - "base-uri 'none'", - "default-src 'none'", - "frame-ancestors 'none'", - "font-src 'self' https://cb6e6126.ngrok.io", - "img-src 'self' data: blob: https://cb6e6126.ngrok.io", - "style-src 'self' https://cb6e6126.ngrok.io 'nonce-ZbA+JmE7+bK8F5qvADZHuQ=='", - "media-src 'self' data: https://cb6e6126.ngrok.io", - "frame-src 'self' https:", - "manifest-src 'self' https://cb6e6126.ngrok.io", - "form-action 'self'", - "child-src 'self' blob: https://cb6e6126.ngrok.io", - "worker-src 'self' blob: https://cb6e6126.ngrok.io", - "connect-src 'self' blob: data: ws://localhost:4000 https://cb6e6126.ngrok.io", - "script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval'" - ) - end -end diff --git a/spec/requests/follower_accounts_spec.rb b/spec/requests/follower_accounts_spec.rb deleted file mode 100644 index 52e86e13f..000000000 --- a/spec/requests/follower_accounts_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'FollowerAccountsController' do - describe 'The follower_accounts route' do - it "returns a http 'moved_permanently' code" do - get '/users/:username/followers' - - expect(response).to have_http_status(301) - end - end -end diff --git a/spec/requests/following_accounts_spec.rb b/spec/requests/following_accounts_spec.rb deleted file mode 100644 index f0955ceb3..000000000 --- a/spec/requests/following_accounts_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'FollowingAccountsController' do - describe 'The following_accounts route' do - it "returns a http 'moved_permanently' code" do - get '/users/:username/following' - - expect(response).to have_http_status(301) - end - end -end diff --git a/spec/requests/host_meta_request_spec.rb b/spec/requests/host_meta_request_spec.rb deleted file mode 100644 index ec26ecba7..000000000 --- a/spec/requests/host_meta_request_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'The host_meta route' do - describe 'requested without accepts headers' do - it 'returns an xml response' do - get host_meta_url - - expect(response).to have_http_status(200) - expect(response.media_type).to eq 'application/xrd+xml' - end - end -end diff --git a/spec/requests/link_headers_spec.rb b/spec/requests/link_headers_spec.rb deleted file mode 100644 index b822adbfb..000000000 --- a/spec/requests/link_headers_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'Link headers' do - describe 'on the account show page' do - let(:account) { Fabricate(:account, username: 'test') } - - before do - get short_account_path(username: account) - end - - it 'contains webfinger url in link header' do - link_header = link_header_with_type('application/jrd+json') - - expect(link_header.href).to eq 'http://www.example.com/.well-known/webfinger?resource=acct%3Atest%40cb6e6126.ngrok.io' - expect(link_header.attr_pairs.first).to eq %w(rel lrdd) - end - - it 'contains activitypub url in link header' do - link_header = link_header_with_type('application/activity+json') - - expect(link_header.href).to eq 'https://cb6e6126.ngrok.io/users/test' - expect(link_header.attr_pairs.first).to eq %w(rel alternate) - end - - def link_header_with_type(type) - LinkHeader.parse(response.headers['Link'].to_s).links.find do |link| - link.attr_pairs.any?(['type', type]) - end - end - end -end diff --git a/spec/requests/localization_spec.rb b/spec/requests/localization_spec.rb deleted file mode 100644 index b7fb53ed8..000000000 --- a/spec/requests/localization_spec.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'Localization' do - around do |example| - I18n.with_locale(I18n.locale) do - example.run - end - end - - it 'uses a specific region when provided' do - headers = { 'Accept-Language' => 'zh-HK' } - - get '/auth/sign_in', headers: headers - - expect(response.body).to include( - I18n.t('auth.login', locale: 'zh-HK') - ) - end - - it 'falls back to a locale when region missing' do - headers = { 'Accept-Language' => 'es-FAKE' } - - get '/auth/sign_in', headers: headers - - expect(response.body).to include( - I18n.t('auth.login', locale: 'es') - ) - end - - it 'falls back to english when locale is missing' do - headers = { 'Accept-Language' => '12-FAKE' } - - get '/auth/sign_in', headers: headers - - expect(response.body).to include( - I18n.t('auth.login', locale: 'en') - ) - end -end diff --git a/spec/requests/mail_subscriptions_spec.rb b/spec/requests/mail_subscriptions_spec.rb deleted file mode 100644 index cc6557cab..000000000 --- a/spec/requests/mail_subscriptions_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'MailSubscriptionsController' do - let(:user) { Fabricate(:user) } - let(:token) { user.to_sgid(for: 'unsubscribe').to_s } - let(:type) { 'follow' } - - shared_examples 'not found with invalid token' do - context 'with invalid token' do - let(:token) { 'invalid-token' } - - it 'returns http not found' do - expect(response).to have_http_status(404) - end - end - end - - shared_examples 'not found with invalid type' do - context 'with invalid type' do - let(:type) { 'invalid_type' } - - it 'returns http not found' do - expect(response).to have_http_status(404) - end - end - end - - describe 'on the unsubscribe confirmation page' do - before do - get unsubscribe_url(token: token, type: type) - end - - it_behaves_like 'not found with invalid token' - it_behaves_like 'not found with invalid type' - - it 'shows unsubscribe form' do - expect(response).to have_http_status(200) - - expect(response.body).to include( - I18n.t('mail_subscriptions.unsubscribe.action') - ) - expect(response.body).to include(user.email) - end - end - - describe 'submitting the unsubscribe confirmation page' do - before do - user.settings.update('notification_emails.follow': true) - user.save! - - post unsubscribe_url, params: { token: token, type: type } - end - - it_behaves_like 'not found with invalid token' - it_behaves_like 'not found with invalid type' - - it 'shows confirmation page' do - expect(response).to have_http_status(200) - - expect(response.body).to include( - I18n.t('mail_subscriptions.unsubscribe.complete') - ) - expect(response.body).to include(user.email) - end - - it 'updates notification settings' do - user.reload - expect(user.settings['notification_emails.follow']).to be false - end - end - - describe 'unsubscribing with List-Unsubscribe-Post' do - around do |example| - old = ActionController::Base.allow_forgery_protection - ActionController::Base.allow_forgery_protection = true - - example.run - - ActionController::Base.allow_forgery_protection = old - end - - before do - user.settings.update('notification_emails.follow': true) - user.save! - - post unsubscribe_url(token: token, type: type), params: { 'List-Unsubscribe' => 'One-Click' } - end - - it_behaves_like 'not found with invalid token' - it_behaves_like 'not found with invalid type' - - it 'return http success' do - expect(response).to have_http_status(200) - end - - it 'updates notification settings' do - user.reload - expect(user.settings['notification_emails.follow']).to be false - end - end -end diff --git a/spec/requests/omniauth_callbacks_spec.rb b/spec/requests/omniauth_callbacks_spec.rb deleted file mode 100644 index 27aa5ec50..000000000 --- a/spec/requests/omniauth_callbacks_spec.rb +++ /dev/null @@ -1,124 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'OmniAuth callbacks' do - shared_examples 'omniauth provider callbacks' do |provider| - subject { post send "user_#{provider}_omniauth_callback_path" } - - context 'with full information in response' do - before do - mock_omniauth(provider, { - provider: provider.to_s, - uid: '123', - info: { - verified: 'true', - email: 'user@host.example', - }, - }) - end - - context 'without a matching user' do - it 'creates a user and an identity and redirects to root path' do - expect { subject } - .to change(User, :count) - .by(1) - .and change(Identity, :count) - .by(1) - .and change(LoginActivity, :count) - .by(1) - - expect(User.last.email).to eq('user@host.example') - expect(Identity.find_by(user: User.last).uid).to eq('123') - expect(response).to redirect_to(root_path) - end - end - - context 'with a matching user and no matching identity' do - before do - Fabricate(:user, email: 'user@host.example') - end - - it 'matches the existing user, creates an identity, and redirects to root path' do - expect { subject } - .to not_change(User, :count) - .and change(Identity, :count) - .by(1) - .and change(LoginActivity, :count) - .by(1) - - expect(Identity.find_by(user: User.last).uid).to eq('123') - expect(response).to redirect_to(root_path) - end - end - - context 'with a matching user and a matching identity' do - before do - user = Fabricate(:user, email: 'user@host.example') - Fabricate(:identity, user: user, uid: '123', provider: provider) - end - - it 'matches the existing records and redirects to root path' do - expect { subject } - .to not_change(User, :count) - .and not_change(Identity, :count) - .and change(LoginActivity, :count) - .by(1) - - expect(response).to redirect_to(root_path) - end - end - end - - context 'with a response missing email address' do - before do - mock_omniauth(provider, { - provider: provider.to_s, - uid: '123', - info: { - verified: 'true', - }, - }) - end - - it 'redirects to the auth setup page' do - expect { subject } - .to change(User, :count) - .by(1) - .and change(Identity, :count) - .by(1) - .and change(LoginActivity, :count) - .by(1) - - expect(response).to redirect_to(auth_setup_path(missing_email: '1')) - end - end - - context 'when a user cannot be built' do - before do - allow(User).to receive(:find_for_oauth).and_return(User.new) - end - - it 'redirects to the new user signup page' do - expect { subject } - .to not_change(User, :count) - .and not_change(Identity, :count) - .and not_change(LoginActivity, :count) - - expect(response).to redirect_to(new_user_registration_url) - end - end - end - - describe '#openid_connect', if: ENV['OIDC_ENABLED'] == 'true' && ENV['OIDC_SCOPE'].present? do - include_examples 'omniauth provider callbacks', :openid_connect - end - - describe '#cas', if: ENV['CAS_ENABLED'] == 'true' do - include_examples 'omniauth provider callbacks', :cas - end - - describe '#saml', if: ENV['SAML_ENABLED'] == 'true' do - include_examples 'omniauth provider callbacks', :saml - end -end diff --git a/spec/requests/webfinger_request_spec.rb b/spec/requests/webfinger_request_spec.rb deleted file mode 100644 index 68a1478be..000000000 --- a/spec/requests/webfinger_request_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'The webfinger route' do - let(:alice) { Fabricate(:account, username: 'alice') } - - describe 'requested with standard accepts headers' do - it 'returns a json response' do - get webfinger_url(resource: alice.to_webfinger_s) - - expect(response).to have_http_status(200) - expect(response.media_type).to eq 'application/jrd+json' - end - end - - describe 'asking for json format' do - it 'returns a json response for json format' do - get webfinger_url(resource: alice.to_webfinger_s, format: :json) - - expect(response).to have_http_status(200) - expect(response.media_type).to eq 'application/jrd+json' - end - - it 'returns a json response for json accept header' do - headers = { 'HTTP_ACCEPT' => 'application/jrd+json' } - get webfinger_url(resource: alice.to_webfinger_s), headers: headers - - expect(response).to have_http_status(200) - expect(response.media_type).to eq 'application/jrd+json' - end - end -end diff --git a/spec/routing/accounts_routing_spec.rb b/spec/routing/accounts_routing_spec.rb deleted file mode 100644 index 8b2c124fd..000000000 --- a/spec/routing/accounts_routing_spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'Routes under accounts/' do - context 'with local username' do - let(:username) { 'alice' } - - it 'routes /@:username' do - expect(get("/@#{username}")).to route_to('accounts#show', username: username) - end - - it 'routes /@:username.json' do - expect(get("/@#{username}.json")).to route_to('accounts#show', username: username, format: 'json') - end - - it 'routes /@:username.rss' do - expect(get("/@#{username}.rss")).to route_to('accounts#show', username: username, format: 'rss') - end - - it 'routes /@:username/:id' do - expect(get("/@#{username}/123")).to route_to('statuses#show', account_username: username, id: '123') - end - - it 'routes /@:username/:id/embed' do - expect(get("/@#{username}/123/embed")).to route_to('statuses#embed', account_username: username, id: '123') - end - - it 'routes /@:username/following' do - expect(get("/@#{username}/following")).to route_to('following_accounts#index', account_username: username) - end - - it 'routes /@:username/followers' do - expect(get("/@#{username}/followers")).to route_to('follower_accounts#index', account_username: username) - end - - it 'routes /@:username/with_replies' do - expect(get("/@#{username}/with_replies")).to route_to('accounts#show', username: username) - end - - it 'routes /@:username/media' do - expect(get("/@#{username}/media")).to route_to('accounts#show', username: username) - end - - it 'routes /@:username/tagged/:tag' do - expect(get("/@#{username}/tagged/foo")).to route_to('accounts#show', username: username, tag: 'foo') - end - end - - context 'with remote username' do - let(:username) { 'alice@example.com' } - - it 'routes /@:username' do - expect(get("/@#{username}")).to route_to('home#index', username_with_domain: username) - end - - it 'routes /@:username/:id' do - expect(get("/@#{username}/123")).to route_to('home#index', username_with_domain: username, any: '123') - end - - it 'routes /@:username/:id/embed' do - expect(get("/@#{username}/123/embed")).to route_to('home#index', username_with_domain: username, any: '123/embed') - end - - it 'routes /@:username/following' do - expect(get("/@#{username}/following")).to route_to('home#index', username_with_domain: username, any: 'following') - end - - it 'routes /@:username/followers' do - expect(get("/@#{username}/followers")).to route_to('home#index', username_with_domain: username, any: 'followers') - end - - it 'routes /@:username/with_replies' do - expect(get("/@#{username}/with_replies")).to route_to('home#index', username_with_domain: username, any: 'with_replies') - end - - it 'routes /@:username/media' do - expect(get("/@#{username}/media")).to route_to('home#index', username_with_domain: username, any: 'media') - end - - it 'routes /@:username/tagged/:tag' do - expect(get("/@#{username}/tagged/foo")).to route_to('home#index', username_with_domain: username, any: 'tagged/foo') - end - end -end diff --git a/spec/routing/api_routing_spec.rb b/spec/routing/api_routing_spec.rb deleted file mode 100644 index a822fba4c..000000000 --- a/spec/routing/api_routing_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'API routes' do - describe 'Credentials routes' do - it 'routes to verify credentials' do - expect(get('/api/v1/accounts/verify_credentials')) - .to route_to('api/v1/accounts/credentials#show') - end - - it 'routes to update credentials' do - expect(patch('/api/v1/accounts/update_credentials')) - .to route_to('api/v1/accounts/credentials#update') - end - end - - describe 'Account routes' do - it 'routes to statuses' do - expect(get('/api/v1/accounts/user/statuses')) - .to route_to('api/v1/accounts/statuses#index', account_id: 'user') - end - - it 'routes to followers' do - expect(get('/api/v1/accounts/user/followers')) - .to route_to('api/v1/accounts/follower_accounts#index', account_id: 'user') - end - - it 'routes to following' do - expect(get('/api/v1/accounts/user/following')) - .to route_to('api/v1/accounts/following_accounts#index', account_id: 'user') - end - - it 'routes to search' do - expect(get('/api/v1/accounts/search')) - .to route_to('api/v1/accounts/search#show') - end - - it 'routes to relationships' do - expect(get('/api/v1/accounts/relationships')) - .to route_to('api/v1/accounts/relationships#index') - end - end - - describe 'Statuses routes' do - it 'routes reblogged_by' do - expect(get('/api/v1/statuses/123/reblogged_by')) - .to route_to('api/v1/statuses/reblogged_by_accounts#index', status_id: '123') - end - - it 'routes favourited_by' do - expect(get('/api/v1/statuses/123/favourited_by')) - .to route_to('api/v1/statuses/favourited_by_accounts#index', status_id: '123') - end - - it 'routes reblog' do - expect(post('/api/v1/statuses/123/reblog')) - .to route_to('api/v1/statuses/reblogs#create', status_id: '123') - end - - it 'routes unreblog' do - expect(post('/api/v1/statuses/123/unreblog')) - .to route_to('api/v1/statuses/reblogs#destroy', status_id: '123') - end - - it 'routes favourite' do - expect(post('/api/v1/statuses/123/favourite')) - .to route_to('api/v1/statuses/favourites#create', status_id: '123') - end - - it 'routes unfavourite' do - expect(post('/api/v1/statuses/123/unfavourite')) - .to route_to('api/v1/statuses/favourites#destroy', status_id: '123') - end - - it 'routes mute' do - expect(post('/api/v1/statuses/123/mute')) - .to route_to('api/v1/statuses/mutes#create', status_id: '123') - end - - it 'routes unmute' do - expect(post('/api/v1/statuses/123/unmute')) - .to route_to('api/v1/statuses/mutes#destroy', status_id: '123') - end - end - - describe 'Timeline routes' do - it 'routes to home timeline' do - expect(get('/api/v1/timelines/home')) - .to route_to('api/v1/timelines/home#show') - end - - it 'routes to public timeline' do - expect(get('/api/v1/timelines/public')) - .to route_to('api/v1/timelines/public#show') - end - - it 'routes to tag timeline' do - expect(get('/api/v1/timelines/tag/test')) - .to route_to('api/v1/timelines/tag#show', id: 'test') - end - end -end diff --git a/spec/routing/well_known_routes_spec.rb b/spec/routing/well_known_routes_spec.rb deleted file mode 100644 index 8cf08c13c..000000000 --- a/spec/routing/well_known_routes_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'Well Known routes' do - describe 'the host-meta route' do - it 'routes to correct place with xml format' do - expect(get('/.well-known/host-meta')) - .to route_to('well_known/host_meta#show', format: 'xml') - end - end - - describe 'the webfinger route' do - it 'routes to correct place with json format' do - expect(get('/.well-known/webfinger')) - .to route_to('well_known/webfinger#show') - end - end -end diff --git a/spec/search/models/concerns/account_search_spec.rb b/spec/search/models/concerns/account_search_spec.rb deleted file mode 100644 index 65e1e4de1..000000000 --- a/spec/search/models/concerns/account_search_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe AccountSearch do - describe 'a non-discoverable account becoming discoverable' do - let(:account) { Account.find_by(username: 'search_test_account_1') } - - context 'when picking a non-discoverable account' do - it 'its bio is not in the AccountsIndex' do - results = AccountsIndex.filter(term: { username: account.username }) - expect(results.count).to eq(1) - expect(results.first.text).to be_nil - end - end - - context 'when the non-discoverable account becomes discoverable' do - it 'its bio is added to the AccountsIndex' do - account.discoverable = true - account.save! - - results = AccountsIndex.filter(term: { username: account.username }) - expect(results.count).to eq(1) - expect(results.first.text).to eq(account.note) - end - end - end - - describe 'a discoverable account becoming non-discoverable' do - let(:account) { Account.find_by(username: 'search_test_account_0') } - - context 'when picking an discoverable account' do - it 'has its bio in the AccountsIndex' do - results = AccountsIndex.filter(term: { username: account.username }) - expect(results.count).to eq(1) - expect(results.first.text).to eq(account.note) - end - end - - context 'when the discoverable account becomes non-discoverable' do - it 'its bio is removed from the AccountsIndex' do - account.discoverable = false - account.save! - - results = AccountsIndex.filter(term: { username: account.username }) - expect(results.count).to eq(1) - expect(results.first.text).to be_nil - end - end - end -end diff --git a/spec/search/models/concerns/account_statuses_search_spec.rb b/spec/search/models/concerns/account_statuses_search_spec.rb deleted file mode 100644 index d35cfa563..000000000 --- a/spec/search/models/concerns/account_statuses_search_spec.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe AccountStatusesSearch do - describe 'a non-indexable account becoming indexable' do - let(:account) { Account.find_by(username: 'search_test_account_1') } - - context 'when picking a non-indexable account' do - it 'has no statuses in the PublicStatusesIndex' do - expect(PublicStatusesIndex.filter(term: { account_id: account.id }).count).to eq(0) - end - - it 'has statuses in the StatusesIndex' do - expect(StatusesIndex.filter(term: { account_id: account.id }).count).to eq(account.statuses.count) - end - end - - context 'when the non-indexable account becomes indexable' do - it 'adds the public statuses to the PublicStatusesIndex' do - account.indexable = true - account.save! - - expect(PublicStatusesIndex.filter(term: { account_id: account.id }).count).to eq(account.statuses.where(visibility: :public).count) - expect(StatusesIndex.filter(term: { account_id: account.id }).count).to eq(account.statuses.count) - end - end - end - - describe 'an indexable account becoming non-indexable' do - let(:account) { Account.find_by(username: 'search_test_account_0') } - - context 'when picking an indexable account' do - it 'has statuses in the PublicStatusesIndex' do - expect(PublicStatusesIndex.filter(term: { account_id: account.id }).count).to eq(account.statuses.where(visibility: :public).count) - end - - it 'has statuses in the StatusesIndex' do - expect(StatusesIndex.filter(term: { account_id: account.id }).count).to eq(account.statuses.count) - end - end - - context 'when the indexable account becomes non-indexable' do - it 'removes the statuses from the PublicStatusesIndex' do - account.indexable = false - account.save! - - expect(PublicStatusesIndex.filter(term: { account_id: account.id }).count).to eq(0) - expect(StatusesIndex.filter(term: { account_id: account.id }).count).to eq(account.statuses.count) - end - end - end -end diff --git a/spec/serializers/activitypub/device_serializer_spec.rb b/spec/serializers/activitypub/device_serializer_spec.rb deleted file mode 100644 index 2a3be8212..000000000 --- a/spec/serializers/activitypub/device_serializer_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::DeviceSerializer do - let(:serialization) do - JSON.parse( - ActiveModelSerializers::SerializableResource.new( - record, serializer: described_class - ).to_json - ) - end - let(:record) { Fabricate(:device) } - - describe 'type' do - it 'returns correct serialized type' do - expect(serialization['type']).to eq('Device') - end - end -end diff --git a/spec/serializers/activitypub/note_serializer_spec.rb b/spec/serializers/activitypub/note_serializer_spec.rb deleted file mode 100644 index 31ee31f13..000000000 --- a/spec/serializers/activitypub/note_serializer_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::NoteSerializer do - subject { JSON.parse(@serialization.to_json) } - - let!(:account) { Fabricate(:account) } - let!(:other) { Fabricate(:account) } - let!(:parent) { Fabricate(:status, account: account, visibility: :public, language: 'zh-TW') } - let!(:reply_by_account_first) { Fabricate(:status, account: account, thread: parent, visibility: :public) } - let!(:reply_by_account_next) { Fabricate(:status, account: account, thread: parent, visibility: :public) } - let!(:reply_by_other_first) { Fabricate(:status, account: other, thread: parent, visibility: :public) } - let!(:reply_by_account_third) { Fabricate(:status, account: account, thread: parent, visibility: :public) } - let!(:reply_by_account_visibility_direct) { Fabricate(:status, account: account, thread: parent, visibility: :direct) } - - before(:each) do - @serialization = ActiveModelSerializers::SerializableResource.new(parent, serializer: described_class, adapter: ActivityPub::Adapter) - end - - it 'has the expected shape' do - expect(subject).to include({ - '@context' => include('https://www.w3.org/ns/activitystreams'), - 'type' => 'Note', - 'attributedTo' => ActivityPub::TagManager.instance.uri_for(account), - 'contentMap' => include({ - 'zh-TW' => a_kind_of(String), - }), - }) - end - - it 'has a replies collection' do - expect(subject['replies']['type']).to eql('Collection') - end - - it 'has a replies collection with a first Page' do - expect(subject['replies']['first']['type']).to eql('CollectionPage') - end - - it 'includes public self-replies in its replies collection' do - expect(subject['replies']['first']['items']).to include(reply_by_account_first.uri, reply_by_account_next.uri, reply_by_account_third.uri) - end - - it 'does not include replies from others in its replies collection' do - expect(subject['replies']['first']['items']).to_not include(reply_by_other_first.uri) - end - - it 'does not include replies with direct visibility in its replies collection' do - expect(subject['replies']['first']['items']).to_not include(reply_by_account_visibility_direct.uri) - end -end diff --git a/spec/serializers/activitypub/one_time_key_serializer_spec.rb b/spec/serializers/activitypub/one_time_key_serializer_spec.rb deleted file mode 100644 index 6fe1f0618..000000000 --- a/spec/serializers/activitypub/one_time_key_serializer_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::OneTimeKeySerializer do - let(:serialization) do - JSON.parse( - ActiveModelSerializers::SerializableResource.new( - record, serializer: described_class - ).to_json - ) - end - let(:record) { Fabricate(:one_time_key) } - - describe 'type' do - it 'returns correct serialized type' do - expect(serialization['type']).to eq('Curve25519Key') - end - end -end diff --git a/spec/serializers/activitypub/undo_like_serializer_spec.rb b/spec/serializers/activitypub/undo_like_serializer_spec.rb deleted file mode 100644 index 43cf7192e..000000000 --- a/spec/serializers/activitypub/undo_like_serializer_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::UndoLikeSerializer do - let(:serialization) do - JSON.parse( - ActiveModelSerializers::SerializableResource.new( - record, serializer: described_class - ).to_json - ) - end - let(:record) { Fabricate(:favourite) } - - describe 'type' do - it 'returns correct serialized type' do - expect(serialization['type']).to eq('Undo') - end - end -end diff --git a/spec/serializers/activitypub/update_poll_serializer_spec.rb b/spec/serializers/activitypub/update_poll_serializer_spec.rb deleted file mode 100644 index 14c24c70c..000000000 --- a/spec/serializers/activitypub/update_poll_serializer_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::UpdatePollSerializer do - subject { JSON.parse(@serialization.to_json) } - - let(:account) { Fabricate(:account) } - let(:poll) { Fabricate(:poll, account: account) } - let!(:status) { Fabricate(:status, account: account, poll: poll) } - - before(:each) do - @serialization = ActiveModelSerializers::SerializableResource.new(status, serializer: described_class, adapter: ActivityPub::Adapter) - end - - it 'has a Update type' do - expect(subject['type']).to eql('Update') - end - - it 'has an object with Question type' do - expect(subject['object']['type']).to eql('Question') - end - - it 'has the correct actor URI set' do - expect(subject['actor']).to eql(ActivityPub::TagManager.instance.uri_for(account)) - end -end diff --git a/spec/serializers/activitypub/vote_serializer_spec.rb b/spec/serializers/activitypub/vote_serializer_spec.rb deleted file mode 100644 index c329542d7..000000000 --- a/spec/serializers/activitypub/vote_serializer_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::VoteSerializer do - let(:serialization) do - JSON.parse( - ActiveModelSerializers::SerializableResource.new( - record, serializer: described_class - ).to_json - ) - end - let(:record) { Fabricate(:poll_vote) } - - describe 'type' do - it 'returns correct serialized type' do - expect(serialization['type']).to eq('Create') - end - end -end diff --git a/spec/serializers/rest/account_serializer_spec.rb b/spec/serializers/rest/account_serializer_spec.rb deleted file mode 100644 index e399e88f3..000000000 --- a/spec/serializers/rest/account_serializer_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe REST::AccountSerializer do - subject { JSON.parse(ActiveModelSerializers::SerializableResource.new(account, serializer: described_class).to_json) } - - let(:role) { Fabricate(:user_role, name: 'Role', highlighted: true) } - let(:user) { Fabricate(:user, role: role) } - let(:account) { user.account } - - context 'when the account is suspended' do - before do - account.suspend! - end - - it 'returns empty roles' do - expect(subject['roles']).to eq [] - end - end - - context 'when the account has a highlighted role' do - let(:role) { Fabricate(:user_role, name: 'Role', highlighted: true) } - - it 'returns the expected role' do - expect(subject['roles'].first).to include({ 'name' => 'Role' }) - end - end - - context 'when the account has a non-highlighted role' do - let(:role) { Fabricate(:user_role, name: 'Role', highlighted: false) } - - it 'returns empty roles' do - expect(subject['roles']).to eq [] - end - end - - context 'when the account is memorialized' do - before do - account.memorialize! - end - - it 'marks it as such' do - expect(subject['memorial']).to be true - end - end -end diff --git a/spec/serializers/rest/encrypted_message_serializer_spec.rb b/spec/serializers/rest/encrypted_message_serializer_spec.rb deleted file mode 100644 index e0e70a3b8..000000000 --- a/spec/serializers/rest/encrypted_message_serializer_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe REST::EncryptedMessageSerializer do - let(:serialization) do - JSON.parse( - ActiveModelSerializers::SerializableResource.new( - record, serializer: described_class - ).to_json - ) - end - let(:record) { Fabricate(:encrypted_message) } - - describe 'account' do - it 'returns the associated account' do - expect(serialization['account_id']).to eq(record.from_account.id.to_s) - end - end -end diff --git a/spec/serializers/rest/instance_serializer_spec.rb b/spec/serializers/rest/instance_serializer_spec.rb deleted file mode 100644 index 15a5de18d..000000000 --- a/spec/serializers/rest/instance_serializer_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe REST::InstanceSerializer do - let(:serialization) do - JSON.parse( - ActiveModelSerializers::SerializableResource.new( - record, serializer: described_class - ).to_json - ) - end - let(:record) { InstancePresenter.new } - - describe 'usage' do - it 'returns recent usage data' do - expect(serialization['usage']).to eq({ 'users' => { 'active_month' => 0 } }) - end - end -end diff --git a/spec/serializers/rest/keys/claim_result_serializer_spec.rb b/spec/serializers/rest/keys/claim_result_serializer_spec.rb deleted file mode 100644 index cf9416f03..000000000 --- a/spec/serializers/rest/keys/claim_result_serializer_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe REST::Keys::ClaimResultSerializer do - let(:serialization) do - JSON.parse( - ActiveModelSerializers::SerializableResource.new( - record, serializer: described_class - ).to_json - ) - end - let(:record) { Keys::ClaimService::Result.new(Account.new(id: 123), 456) } - - describe 'account' do - it 'returns the associated account' do - expect(serialization['account_id']).to eq('123') - end - end -end diff --git a/spec/serializers/rest/keys/device_serializer_spec.rb b/spec/serializers/rest/keys/device_serializer_spec.rb deleted file mode 100644 index c15e197cb..000000000 --- a/spec/serializers/rest/keys/device_serializer_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe REST::Keys::DeviceSerializer do - let(:serialization) do - JSON.parse( - ActiveModelSerializers::SerializableResource.new( - record, serializer: described_class - ).to_json - ) - end - let(:record) { Device.new(name: 'Device name') } - - describe 'name' do - it 'returns the name' do - expect(serialization['name']).to eq('Device name') - end - end -end diff --git a/spec/serializers/rest/keys/query_result_serializer_spec.rb b/spec/serializers/rest/keys/query_result_serializer_spec.rb deleted file mode 100644 index 983780ae9..000000000 --- a/spec/serializers/rest/keys/query_result_serializer_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe REST::Keys::QueryResultSerializer do - let(:serialization) do - JSON.parse( - ActiveModelSerializers::SerializableResource.new( - record, serializer: described_class - ).to_json - ) - end - let(:record) { Keys::QueryService::Result.new(Account.new(id: 123), []) } - - describe 'account' do - it 'returns the associated account id' do - expect(serialization['account_id']).to eq('123') - end - end -end diff --git a/spec/serializers/rest/suggestion_serializer_spec.rb b/spec/serializers/rest/suggestion_serializer_spec.rb deleted file mode 100644 index b3c086208..000000000 --- a/spec/serializers/rest/suggestion_serializer_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe REST::SuggestionSerializer do - let(:serialization) do - JSON.parse( - ActiveModelSerializers::SerializableResource.new( - record, serializer: described_class - ).to_json - ) - end - let(:record) do - AccountSuggestions::Suggestion.new( - account: account, - source: 'SuggestionSource' - ) - end - let(:account) { Fabricate(:account) } - - describe 'account' do - it 'returns the associated account' do - expect(serialization['account']['id']).to eq(account.id.to_s) - end - end -end diff --git a/spec/services/account_search_service_spec.rb b/spec/services/account_search_service_spec.rb deleted file mode 100644 index 1cd036f48..000000000 --- a/spec/services/account_search_service_spec.rb +++ /dev/null @@ -1,89 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe AccountSearchService, type: :service do - describe '#call' do - context 'with a query to ignore' do - it 'returns empty array for missing query' do - results = subject.call('', nil, limit: 10) - - expect(results).to eq [] - end - - it 'returns empty array for limit zero' do - Fabricate(:account, username: 'match') - - results = subject.call('match', nil, limit: 0) - - expect(results).to eq [] - end - end - - context 'when searching for a simple term that is not an exact match' do - it 'does not return a nil entry in the array for the exact match' do - account = Fabricate(:account, username: 'matchingusername') - results = subject.call('match', nil, limit: 5) - - expect(results).to eq [account] - end - end - - context 'when there is a local domain' do - around do |example| - before = Rails.configuration.x.local_domain - - example.run - - Rails.configuration.x.local_domain = before - end - - it 'returns exact match first' do - remote = Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e') - remote_too = Fabricate(:account, username: 'b', domain: 'remote', display_name: 'e') - exact = Fabricate(:account, username: 'e') - - Rails.configuration.x.local_domain = 'example.com' - - results = subject.call('e@example.com', nil, limit: 2) - - expect(results).to eq([exact, remote]).or eq([exact, remote_too]) - end - end - - context 'when there is a domain but no exact match' do - it 'follows the remote account when resolve is true' do - service = instance_double(ResolveAccountService, call: nil) - allow(ResolveAccountService).to receive(:new).and_return(service) - - results = subject.call('newuser@remote.com', nil, limit: 10, resolve: true) - expect(service).to have_received(:call).with('newuser@remote.com') - end - - it 'does not follow the remote account when resolve is false' do - service = instance_double(ResolveAccountService, call: nil) - allow(ResolveAccountService).to receive(:new).and_return(service) - - results = subject.call('newuser@remote.com', nil, limit: 10, resolve: false) - expect(service).to_not have_received(:call) - end - end - - it 'returns the fuzzy match first, and does not return suspended exacts' do - partial = Fabricate(:account, username: 'exactness') - exact = Fabricate(:account, username: 'exact', suspended: true) - results = subject.call('exact', nil, limit: 10) - - expect(results.size).to eq 1 - expect(results).to eq [partial] - end - - it 'does not return suspended remote accounts' do - remote = Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e', suspended: true) - results = subject.call('a@example.com', nil, limit: 2) - - expect(results.size).to eq 0 - expect(results).to eq [] - end - end -end diff --git a/spec/services/account_statuses_cleanup_service_spec.rb b/spec/services/account_statuses_cleanup_service_spec.rb deleted file mode 100644 index f7a88a917..000000000 --- a/spec/services/account_statuses_cleanup_service_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe AccountStatusesCleanupService, type: :service do - let(:account) { Fabricate(:account, username: 'alice', domain: nil) } - let(:account_policy) { Fabricate(:account_statuses_cleanup_policy, account: account) } - let!(:unrelated_status) { Fabricate(:status, created_at: 3.years.ago) } - - describe '#call' do - context 'when the account has not posted anything' do - it 'returns 0 deleted toots' do - expect(subject.call(account_policy)).to eq 0 - end - end - - context 'when the account has posted several old statuses' do - let!(:very_old_status) { Fabricate(:status, created_at: 3.years.ago, account: account) } - let!(:old_status) { Fabricate(:status, created_at: 1.year.ago, account: account) } - let!(:another_old_status) { Fabricate(:status, created_at: 1.year.ago, account: account) } - let!(:recent_status) { Fabricate(:status, created_at: 1.day.ago, account: account) } - - context 'when given a budget of 1' do - it 'reports 1 deleted toot' do - expect(subject.call(account_policy, 1)).to eq 1 - end - end - - context 'when given a normal budget of 10' do - it 'reports 3 deleted statuses' do - expect(subject.call(account_policy, 10)).to eq 3 - end - - it 'records the last deleted id' do - subject.call(account_policy, 10) - expect(account_policy.last_inspected).to eq [old_status.id, another_old_status.id].max - end - - it 'actually deletes the statuses' do - subject.call(account_policy, 10) - expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])).to be_nil - end - end - - context 'when called repeatedly with a budget of 2' do - it 'reports 2 then 1 deleted statuses' do - expect(subject.call(account_policy, 2)).to eq 2 - expect(subject.call(account_policy, 2)).to eq 1 - end - - it 'actually deletes the statuses in the expected order' do - subject.call(account_policy, 2) - expect(Status.find_by(id: very_old_status.id)).to be_nil - subject.call(account_policy, 2) - expect(Status.find_by(id: [very_old_status.id, old_status.id, another_old_status.id])).to be_nil - end - end - - context 'when a self-faved toot is unfaved' do - let!(:self_faved) { Fabricate(:status, created_at: 6.months.ago, account: account) } - let!(:favourite) { Fabricate(:favourite, account: account, status: self_faved) } - - it 'deletes it once unfaved' do - expect(subject.call(account_policy, 20)).to eq 3 - expect(Status.find_by(id: self_faved.id)).to_not be_nil - expect(subject.call(account_policy, 20)).to eq 0 - favourite.destroy! - expect(subject.call(account_policy, 20)).to eq 1 - expect(Status.find_by(id: self_faved.id)).to be_nil - end - end - - context 'when there are more un-deletable old toots than the early search cutoff' do - before do - stub_const 'AccountStatusesCleanupPolicy::EARLY_SEARCH_CUTOFF', 5 - # Old statuses that should be cut-off - 10.times do - Fabricate(:status, created_at: 4.years.ago, visibility: :direct, account: account) - end - # New statuses that prevent cut-off id to reach the last status - 10.times do - Fabricate(:status, created_at: 4.seconds.ago, visibility: :direct, account: account) - end - end - - it 'reports 0 deleted statuses then 0 then 3 then 0 again' do - expect(subject.call(account_policy, 10)).to eq 0 - expect(subject.call(account_policy, 10)).to eq 0 - expect(subject.call(account_policy, 10)).to eq 3 - expect(subject.call(account_policy, 10)).to eq 0 - end - - it 'never causes the recorded id to get higher than oldest deletable toot' do - subject.call(account_policy, 10) - subject.call(account_policy, 10) - subject.call(account_policy, 10) - subject.call(account_policy, 10) - expect(account_policy.last_inspected).to be < Mastodon::Snowflake.id_at(account_policy.min_status_age.seconds.ago, with_random: false) - end - end - end - end -end diff --git a/spec/services/activitypub/fetch_featured_collection_service_spec.rb b/spec/services/activitypub/fetch_featured_collection_service_spec.rb deleted file mode 100644 index 5975c81a1..000000000 --- a/spec/services/activitypub/fetch_featured_collection_service_spec.rb +++ /dev/null @@ -1,129 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do - subject { described_class.new } - - let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/account', featured_collection_url: 'https://example.com/account/pinned') } - - let!(:known_status) { Fabricate(:status, account: actor, uri: 'https://example.com/account/pinned/1') } - - let(:status_json_pinned_known) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'Note', - id: 'https://example.com/account/pinned/known', - content: 'foo', - attributedTo: actor.uri, - to: 'https://www.w3.org/ns/activitystreams#Public', - } - end - - let(:status_json_pinned_unknown_inlined) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'Note', - id: 'https://example.com/account/pinned/unknown-inlined', - content: 'foo', - attributedTo: actor.uri, - to: 'https://www.w3.org/ns/activitystreams#Public', - } - end - - let(:status_json_pinned_unknown_unreachable) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'Note', - id: 'https://example.com/account/pinned/unknown-reachable', - content: 'foo', - attributedTo: actor.uri, - to: 'https://www.w3.org/ns/activitystreams#Public', - } - end - - let(:items) do - [ - 'https://example.com/account/pinned/known', # known - status_json_pinned_unknown_inlined, # unknown inlined - 'https://example.com/account/pinned/unknown-unreachable', # unknown unreachable - 'https://example.com/account/pinned/unknown-reachable', # unknown reachable - ] - end - - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'Collection', - id: actor.featured_collection_url, - items: items, - }.with_indifferent_access - end - - shared_examples 'sets pinned posts' do - before do - stub_request(:get, 'https://example.com/account/pinned/known').to_return(status: 200, body: Oj.dump(status_json_pinned_known)) - stub_request(:get, 'https://example.com/account/pinned/unknown-inlined').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_inlined)) - stub_request(:get, 'https://example.com/account/pinned/unknown-unreachable').to_return(status: 404) - stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_unreachable)) - - subject.call(actor, note: true, hashtag: false) - end - - it 'sets expected posts as pinned posts' do - expect(actor.pinned_statuses.pluck(:uri)).to contain_exactly( - 'https://example.com/account/pinned/known', - 'https://example.com/account/pinned/unknown-inlined', - 'https://example.com/account/pinned/unknown-reachable' - ) - end - end - - describe '#call' do - context 'when the endpoint is a Collection' do - before do - stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload)) - end - - it_behaves_like 'sets pinned posts' - end - - context 'when the endpoint is an OrderedCollection' do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'OrderedCollection', - id: actor.featured_collection_url, - orderedItems: items, - }.with_indifferent_access - end - - before do - stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload)) - end - - it_behaves_like 'sets pinned posts' - end - - context 'when the endpoint is a paginated Collection' do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'Collection', - id: actor.featured_collection_url, - first: { - type: 'CollectionPage', - partOf: actor.featured_collection_url, - items: items, - }, - }.with_indifferent_access - end - - before do - stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload)) - end - - it_behaves_like 'sets pinned posts' - end - end -end diff --git a/spec/services/activitypub/fetch_featured_tags_collection_service_spec.rb b/spec/services/activitypub/fetch_featured_tags_collection_service_spec.rb deleted file mode 100644 index 071e4d92d..000000000 --- a/spec/services/activitypub/fetch_featured_tags_collection_service_spec.rb +++ /dev/null @@ -1,97 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service do - subject { described_class.new } - - let(:collection_url) { 'https://example.com/account/tags' } - let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/account') } - - let(:items) do - [ - { type: 'Hashtag', href: 'https://example.com/account/tagged/foo', name: 'Foo' }, - { type: 'Hashtag', href: 'https://example.com/account/tagged/bar', name: 'bar' }, - { type: 'Hashtag', href: 'https://example.com/account/tagged/baz', name: 'baZ' }, - ] - end - - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'Collection', - id: collection_url, - items: items, - }.with_indifferent_access - end - - shared_examples 'sets featured tags' do - before do - subject.call(actor, collection_url) - end - - it 'sets expected tags as pinned tags' do - expect(actor.featured_tags.map(&:display_name)).to match_array %w(Foo bar baZ) - end - end - - describe '#call' do - context 'when the endpoint is a Collection' do - before do - stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload)) - end - - it_behaves_like 'sets featured tags' - end - - context 'when the account already has featured tags' do - before do - stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload)) - - actor.featured_tags.create!(name: 'FoO') - actor.featured_tags.create!(name: 'baz') - actor.featured_tags.create!(name: 'oh').update(name: nil) - end - - it_behaves_like 'sets featured tags' - end - - context 'when the endpoint is an OrderedCollection' do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'OrderedCollection', - id: collection_url, - orderedItems: items, - }.with_indifferent_access - end - - before do - stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload)) - end - - it_behaves_like 'sets featured tags' - end - - context 'when the endpoint is a paginated Collection' do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'Collection', - id: collection_url, - first: { - type: 'CollectionPage', - partOf: collection_url, - items: items, - }, - }.with_indifferent_access - end - - before do - stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload)) - end - - it_behaves_like 'sets featured tags' - end - end -end diff --git a/spec/services/activitypub/fetch_remote_account_service_spec.rb b/spec/services/activitypub/fetch_remote_account_service_spec.rb deleted file mode 100644 index ac7484d96..000000000 --- a/spec/services/activitypub/fetch_remote_account_service_spec.rb +++ /dev/null @@ -1,182 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do - subject { described_class.new } - - let!(:actor) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://example.com/alice', - type: 'Person', - preferredUsername: 'alice', - name: 'Alice', - summary: 'Foo bar', - inbox: 'http://example.com/alice/inbox', - } - end - - describe '#call' do - let(:account) { subject.call('https://example.com/alice', id: true) } - - shared_examples 'sets profile data' do - it 'returns an account' do - expect(account).to be_an Account - end - - it 'sets display name' do - expect(account.display_name).to eq 'Alice' - end - - it 'sets note' do - expect(account.note).to eq 'Foo bar' - end - - it 'sets URL' do - expect(account.url).to eq 'https://example.com/alice' - end - end - - context 'when the account does not have a inbox' do - let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } } - - before do - actor[:inbox] = nil - - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - it 'fetches resource' do - account - expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once - end - - it 'looks up webfinger' do - account - expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once - end - - it 'returns nil' do - expect(account).to be_nil - end - end - - context 'when URI and WebFinger share the same host' do - let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } } - - before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - it 'fetches resource' do - account - expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once - end - - it 'looks up webfinger' do - account - expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once - end - - it 'sets username and domain from webfinger' do - expect(account.username).to eq 'alice' - expect(account.domain).to eq 'example.com' - end - - include_examples 'sets profile data' - end - - context 'when WebFinger presents different domain than URI' do - let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/alice' }] } } - - before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - it 'fetches resource' do - account - expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once - end - - it 'looks up webfinger' do - account - expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once - end - - it 'looks up "redirected" webfinger' do - account - expect(a_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af')).to have_been_made.once - end - - it 'sets username and domain from final webfinger' do - expect(account.username).to eq 'alice' - expect(account.domain).to eq 'iscool.af' - end - - include_examples 'sets profile data' - end - - context 'when WebFinger returns a different URI' do - let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/bob' }] } } - - before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - it 'fetches resource' do - account - expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once - end - - it 'looks up webfinger' do - account - expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once - end - - it 'does not create account' do - expect(account).to be_nil - end - end - - context 'when WebFinger returns a different URI after a redirection' do - let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/bob' }] } } - - before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - it 'fetches resource' do - account - expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once - end - - it 'looks up webfinger' do - account - expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once - end - - it 'looks up "redirected" webfinger' do - account - expect(a_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af')).to have_been_made.once - end - - it 'does not create account' do - expect(account).to be_nil - end - end - - context 'with wrong id' do - it 'does not create account' do - expect(subject.call('https://fake.address/@foo', prefetched_body: Oj.dump(actor))).to be_nil - end - end - end -end diff --git a/spec/services/activitypub/fetch_remote_actor_service_spec.rb b/spec/services/activitypub/fetch_remote_actor_service_spec.rb deleted file mode 100644 index 93d31b69d..000000000 --- a/spec/services/activitypub/fetch_remote_actor_service_spec.rb +++ /dev/null @@ -1,182 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do - subject { described_class.new } - - let!(:actor) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://example.com/alice', - type: 'Person', - preferredUsername: 'alice', - name: 'Alice', - summary: 'Foo bar', - inbox: 'http://example.com/alice/inbox', - } - end - - describe '#call' do - let(:account) { subject.call('https://example.com/alice', id: true) } - - shared_examples 'sets profile data' do - it 'returns an account' do - expect(account).to be_an Account - end - - it 'sets display name' do - expect(account.display_name).to eq 'Alice' - end - - it 'sets note' do - expect(account.note).to eq 'Foo bar' - end - - it 'sets URL' do - expect(account.url).to eq 'https://example.com/alice' - end - end - - context 'when the account does not have a inbox' do - let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } } - - before do - actor[:inbox] = nil - - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - it 'fetches resource' do - account - expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once - end - - it 'looks up webfinger' do - account - expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once - end - - it 'returns nil' do - expect(account).to be_nil - end - end - - context 'when URI and WebFinger share the same host' do - let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } } - - before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - it 'fetches resource' do - account - expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once - end - - it 'looks up webfinger' do - account - expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once - end - - it 'sets username and domain from webfinger' do - expect(account.username).to eq 'alice' - expect(account.domain).to eq 'example.com' - end - - include_examples 'sets profile data' - end - - context 'when WebFinger presents different domain than URI' do - let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/alice' }] } } - - before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - it 'fetches resource' do - account - expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once - end - - it 'looks up webfinger' do - account - expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once - end - - it 'looks up "redirected" webfinger' do - account - expect(a_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af')).to have_been_made.once - end - - it 'sets username and domain from final webfinger' do - expect(account.username).to eq 'alice' - expect(account.domain).to eq 'iscool.af' - end - - include_examples 'sets profile data' - end - - context 'when WebFinger returns a different URI' do - let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/bob' }] } } - - before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - it 'fetches resource' do - account - expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once - end - - it 'looks up webfinger' do - account - expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once - end - - it 'does not create account' do - expect(account).to be_nil - end - end - - context 'when WebFinger returns a different URI after a redirection' do - let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/bob' }] } } - - before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - it 'fetches resource' do - account - expect(a_request(:get, 'https://example.com/alice')).to have_been_made.once - end - - it 'looks up webfinger' do - account - expect(a_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com')).to have_been_made.once - end - - it 'looks up "redirected" webfinger' do - account - expect(a_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af')).to have_been_made.once - end - - it 'does not create account' do - expect(account).to be_nil - end - end - - context 'with wrong id' do - it 'does not create account' do - expect(subject.call('https://fake.address/@foo', prefetched_body: Oj.dump(actor))).to be_nil - end - end - end -end diff --git a/spec/services/activitypub/fetch_remote_key_service_spec.rb b/spec/services/activitypub/fetch_remote_key_service_spec.rb deleted file mode 100644 index e210d20ec..000000000 --- a/spec/services/activitypub/fetch_remote_key_service_spec.rb +++ /dev/null @@ -1,95 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do - subject { described_class.new } - - let(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } } - - let(:public_key_pem) do - <<~TEXT - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu3L4vnpNLzVH31MeWI39 - 4F0wKeJFsLDAsNXGeOu0QF2x+h1zLWZw/agqD2R3JPU9/kaDJGPIV2Sn5zLyUA9S - 6swCCMOtn7BBR9g9sucgXJmUFB0tACH2QSgHywMAybGfmSb3LsEMNKsGJ9VsvYoh - 8lDET6X4Pyw+ZJU0/OLo/41q9w+OrGtlsTm/PuPIeXnxa6BLqnDaxC+4IcjG/FiP - ahNCTINl/1F/TgSSDZ4Taf4U9XFEIFw8wmgploELozzIzKq+t8nhQYkgAkt64euW - pva3qL5KD1mTIZQEP+LZvh3s2WHrLi3fhbdRuwQ2c0KkJA2oSTFPDpqqbPGZ3Qvu - HQIDAQAB - -----END PUBLIC KEY----- - TEXT - end - - let(:public_key_id) { 'https://example.com/alice#main-key' } - - let(:key_json) do - { - id: public_key_id, - owner: 'https://example.com/alice', - publicKeyPem: public_key_pem, - } - end - - let(:actor_public_key) { key_json } - - let(:actor) do - { - '@context': [ - 'https://www.w3.org/ns/activitystreams', - 'https://w3id.org/security/v1', - ], - id: 'https://example.com/alice', - type: 'Person', - preferredUsername: 'alice', - name: 'Alice', - summary: 'Foo bar', - inbox: 'http://example.com/alice/inbox', - publicKey: actor_public_key, - } - end - - before do - stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor)) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - describe '#call' do - let(:account) { subject.call(public_key_id, id: false) } - - context 'when the key is a sub-object from the actor' do - before do - stub_request(:get, public_key_id).to_return(body: Oj.dump(actor)) - end - - it 'returns the expected account' do - expect(account.uri).to eq 'https://example.com/alice' - end - end - - context 'when the key is a separate document' do - let(:public_key_id) { 'https://example.com/alice-public-key.json' } - - before do - stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] }))) - end - - it 'returns the expected account' do - expect(account.uri).to eq 'https://example.com/alice' - end - end - - context 'when the key and owner do not match' do - let(:public_key_id) { 'https://example.com/fake-public-key.json' } - let(:actor_public_key) { 'https://example.com/alice-public-key.json' } - - before do - stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] }))) - end - - it 'returns the nil' do - expect(account).to be_nil - end - end - end -end diff --git a/spec/services/activitypub/fetch_remote_status_service_spec.rb b/spec/services/activitypub/fetch_remote_status_service_spec.rb deleted file mode 100644 index 826b67d88..000000000 --- a/spec/services/activitypub/fetch_remote_status_service_spec.rb +++ /dev/null @@ -1,322 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do - include ActionView::Helpers::TextHelper - - subject { described_class.new } - - let!(:sender) { Fabricate(:account, domain: 'foo.bar', uri: 'https://foo.bar') } - let!(:recipient) { Fabricate(:account) } - - let(:existing_status) { nil } - - let(:note) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://foo.bar/@foo/1234', - type: 'Note', - content: 'Lorem ipsum', - attributedTo: ActivityPub::TagManager.instance.uri_for(sender), - } - end - - before do - stub_request(:get, 'https://foo.bar/watch?v=12345').to_return(status: 404, body: '') - stub_request(:get, object[:id]).to_return(body: Oj.dump(object)) - end - - describe '#call' do - before do - existing_status - subject.call(object[:id], prefetched_body: Oj.dump(object)) - end - - context 'with Note object' do - let(:object) { note } - - it 'creates status' do - status = sender.statuses.first - - expect(status).to_not be_nil - expect(status.text).to eq 'Lorem ipsum' - end - end - - context 'with Video object' do - let(:object) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://foo.bar/@foo/1234', - type: 'Video', - name: 'Nyan Cat 10 hours remix', - attributedTo: ActivityPub::TagManager.instance.uri_for(sender), - url: [ - { - type: 'Link', - mimeType: 'application/x-bittorrent', - href: 'https://foo.bar/12345.torrent', - }, - - { - type: 'Link', - mimeType: 'text/html', - href: 'https://foo.bar/watch?v=12345', - }, - ], - } - end - - it 'creates status' do - status = sender.statuses.first - - expect(status).to_not be_nil - expect(status.url).to eq 'https://foo.bar/watch?v=12345' - expect(strip_tags(status.text)).to eq 'Nyan Cat 10 hours remixhttps://foo.bar/watch?v=12345' - end - end - - context 'with Audio object' do - let(:object) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://foo.bar/@foo/1234', - type: 'Audio', - name: 'Nyan Cat 10 hours remix', - attributedTo: ActivityPub::TagManager.instance.uri_for(sender), - url: [ - { - type: 'Link', - mimeType: 'application/x-bittorrent', - href: 'https://foo.bar/12345.torrent', - }, - - { - type: 'Link', - mimeType: 'text/html', - href: 'https://foo.bar/watch?v=12345', - }, - ], - } - end - - it 'creates status' do - status = sender.statuses.first - - expect(status).to_not be_nil - expect(status.url).to eq 'https://foo.bar/watch?v=12345' - expect(strip_tags(status.text)).to eq 'Nyan Cat 10 hours remixhttps://foo.bar/watch?v=12345' - end - end - - context 'with Event object' do - let(:object) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://foo.bar/@foo/1234', - type: 'Event', - name: "Let's change the world", - attributedTo: ActivityPub::TagManager.instance.uri_for(sender), - } - end - - it 'creates status' do - status = sender.statuses.first - - expect(status).to_not be_nil - expect(status.url).to eq 'https://foo.bar/@foo/1234' - expect(strip_tags(status.text)).to eq "Let's change the worldhttps://foo.bar/@foo/1234" - end - end - - context 'with wrong id' do - let(:note) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://real.address/@foo/1234', - type: 'Note', - content: 'Lorem ipsum', - attributedTo: ActivityPub::TagManager.instance.uri_for(sender), - } - end - - let(:object) do - temp = note.dup - temp[:id] = 'https://fake.address/@foo/5678' - temp - end - - it 'does not create status' do - expect(sender.statuses.first).to be_nil - end - end - - context 'with a valid Create activity' do - let(:object) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://foo.bar/@foo/1234/create', - type: 'Create', - actor: ActivityPub::TagManager.instance.uri_for(sender), - object: note, - } - end - - it 'creates status' do - status = sender.statuses.first - - expect(status).to_not be_nil - expect(status.uri).to eq note[:id] - expect(status.text).to eq note[:content] - end - end - - context 'with a Create activity with a mismatching id' do - let(:object) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://foo.bar/@foo/1234/create', - type: 'Create', - actor: ActivityPub::TagManager.instance.uri_for(sender), - object: { - id: 'https://real.address/@foo/1234', - type: 'Note', - content: 'Lorem ipsum', - attributedTo: ActivityPub::TagManager.instance.uri_for(sender), - }, - } - end - - it 'does not create status' do - expect(sender.statuses.first).to be_nil - end - end - - context 'when status already exists' do - let(:existing_status) { Fabricate(:status, account: sender, text: 'Foo', uri: note[:id]) } - - context 'with a Note object' do - let(:object) { note.merge(updated: '2021-09-08T22:39:25Z') } - - it 'updates status' do - existing_status.reload - expect(existing_status.text).to eq 'Lorem ipsum' - expect(existing_status.edits).to_not be_empty - end - end - - context 'with a Create activity' do - let(:object) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://foo.bar/@foo/1234/create', - type: 'Create', - actor: ActivityPub::TagManager.instance.uri_for(sender), - object: note.merge(updated: '2021-09-08T22:39:25Z'), - } - end - - it 'updates status' do - existing_status.reload - expect(existing_status.text).to eq 'Lorem ipsum' - expect(existing_status.edits).to_not be_empty - end - end - end - end - - context 'with statuses referencing other statuses' do - before do - stub_const 'ActivityPub::FetchRemoteStatusService::DISCOVERIES_PER_REQUEST', 5 - end - - context 'when using inReplyTo' do - let(:object) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://foo.bar/@foo/1', - type: 'Note', - content: 'Lorem ipsum', - inReplyTo: 'https://foo.bar/@foo/2', - attributedTo: ActivityPub::TagManager.instance.uri_for(sender), - } - end - - before do - 8.times do |i| - status_json = { - '@context': 'https://www.w3.org/ns/activitystreams', - id: "https://foo.bar/@foo/#{i}", - type: 'Note', - content: 'Lorem ipsum', - inReplyTo: "https://foo.bar/@foo/#{i + 1}", - attributedTo: ActivityPub::TagManager.instance.uri_for(sender), - to: 'as:Public', - }.with_indifferent_access - stub_request(:get, "https://foo.bar/@foo/#{i}").to_return(status: 200, body: status_json.to_json, headers: { 'Content-Type': 'application/activity+json' }) - end - end - - it 'creates at least some statuses' do - expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_least(2) - end - - it 'creates no more account than the limit allows' do - expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_most(5) - end - end - - context 'when using replies' do - let(:object) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://foo.bar/@foo/1', - type: 'Note', - content: 'Lorem ipsum', - replies: { - type: 'Collection', - id: 'https://foo.bar/@foo/1/replies', - first: { - type: 'CollectionPage', - partOf: 'https://foo.bar/@foo/1/replies', - items: ['https://foo.bar/@foo/2'], - }, - }, - attributedTo: ActivityPub::TagManager.instance.uri_for(sender), - } - end - - before do - 8.times do |i| - status_json = { - '@context': 'https://www.w3.org/ns/activitystreams', - id: "https://foo.bar/@foo/#{i}", - type: 'Note', - content: 'Lorem ipsum', - replies: { - type: 'Collection', - id: "https://foo.bar/@foo/#{i}/replies", - first: { - type: 'CollectionPage', - partOf: "https://foo.bar/@foo/#{i}/replies", - items: ["https://foo.bar/@foo/#{i + 1}"], - }, - }, - attributedTo: ActivityPub::TagManager.instance.uri_for(sender), - to: 'as:Public', - }.with_indifferent_access - stub_request(:get, "https://foo.bar/@foo/#{i}").to_return(status: 200, body: status_json.to_json, headers: { 'Content-Type': 'application/activity+json' }) - end - end - - it 'creates at least some statuses' do - expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_least(2) - end - - it 'creates no more account than the limit allows' do - expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_most(5) - end - end - end -end diff --git a/spec/services/activitypub/fetch_replies_service_spec.rb b/spec/services/activitypub/fetch_replies_service_spec.rb deleted file mode 100644 index bf8e29676..000000000 --- a/spec/services/activitypub/fetch_replies_service_spec.rb +++ /dev/null @@ -1,118 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ActivityPub::FetchRepliesService, type: :service do - subject { described_class.new } - - let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account') } - let(:status) { Fabricate(:status, account: actor) } - let(:collection_uri) { 'http://example.com/replies/1' } - - let(:items) do - [ - 'http://example.com/self-reply-1', - 'http://example.com/self-reply-2', - 'http://example.com/self-reply-3', - 'http://other.com/other-reply-1', - 'http://other.com/other-reply-2', - 'http://other.com/other-reply-3', - 'http://example.com/self-reply-4', - 'http://example.com/self-reply-5', - 'http://example.com/self-reply-6', - ] - end - - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'Collection', - id: collection_uri, - items: items, - }.with_indifferent_access - end - - describe '#call' do - context 'when the payload is a Collection with inlined replies' do - context 'when passing the collection itself' do - it 'spawns workers for up to 5 replies on the same server' do - expect(FetchReplyWorker).to receive(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5']) - subject.call(status, payload) - end - end - - context 'when passing the URL to the collection' do - before do - stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload)) - end - - it 'spawns workers for up to 5 replies on the same server' do - expect(FetchReplyWorker).to receive(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5']) - subject.call(status, collection_uri) - end - end - end - - context 'when the payload is an OrderedCollection with inlined replies' do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'OrderedCollection', - id: collection_uri, - orderedItems: items, - }.with_indifferent_access - end - - context 'when passing the collection itself' do - it 'spawns workers for up to 5 replies on the same server' do - expect(FetchReplyWorker).to receive(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5']) - subject.call(status, payload) - end - end - - context 'when passing the URL to the collection' do - before do - stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload)) - end - - it 'spawns workers for up to 5 replies on the same server' do - expect(FetchReplyWorker).to receive(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5']) - subject.call(status, collection_uri) - end - end - end - - context 'when the payload is a paginated Collection with inlined replies' do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'Collection', - id: collection_uri, - first: { - type: 'CollectionPage', - partOf: collection_uri, - items: items, - }, - }.with_indifferent_access - end - - context 'when passing the collection itself' do - it 'spawns workers for up to 5 replies on the same server' do - expect(FetchReplyWorker).to receive(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5']) - subject.call(status, payload) - end - end - - context 'when passing the URL to the collection' do - before do - stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload)) - end - - it 'spawns workers for up to 5 replies on the same server' do - expect(FetchReplyWorker).to receive(:push_bulk).with(['http://example.com/self-reply-1', 'http://example.com/self-reply-2', 'http://example.com/self-reply-3', 'http://example.com/self-reply-4', 'http://example.com/self-reply-5']) - subject.call(status, collection_uri) - end - end - end - end -end diff --git a/spec/services/activitypub/process_account_service_spec.rb b/spec/services/activitypub/process_account_service_spec.rb deleted file mode 100644 index c02a0800a..000000000 --- a/spec/services/activitypub/process_account_service_spec.rb +++ /dev/null @@ -1,206 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ActivityPub::ProcessAccountService, type: :service do - subject { described_class.new } - - context 'with property values' do - let(:payload) do - { - id: 'https://foo.test', - type: 'Actor', - inbox: 'https://foo.test/inbox', - attachment: [ - { type: 'PropertyValue', name: 'Pronouns', value: 'They/them' }, - { type: 'PropertyValue', name: 'Occupation', value: 'Unit test' }, - { type: 'PropertyValue', name: 'non-string', value: %w(foo bar) }, - ], - }.with_indifferent_access - end - - it 'parses out of attachment' do - account = subject.call('alice', 'example.com', payload) - expect(account.fields).to be_a Array - expect(account.fields.size).to eq 2 - expect(account.fields[0]).to be_a Account::Field - expect(account.fields[0].name).to eq 'Pronouns' - expect(account.fields[0].value).to eq 'They/them' - expect(account.fields[1]).to be_a Account::Field - expect(account.fields[1].name).to eq 'Occupation' - expect(account.fields[1].value).to eq 'Unit test' - end - end - - context 'when account is not suspended' do - subject { described_class.new.call('alice', 'example.com', payload) } - - let!(:account) { Fabricate(:account, username: 'alice', domain: 'example.com') } - - let(:payload) do - { - id: 'https://foo.test', - type: 'Actor', - inbox: 'https://foo.test/inbox', - suspended: true, - }.with_indifferent_access - end - - before do - allow(Admin::SuspensionWorker).to receive(:perform_async) - end - - it 'suspends account remotely' do - expect(subject.suspended?).to be true - expect(subject.suspension_origin_remote?).to be true - end - - it 'queues suspension worker' do - subject - expect(Admin::SuspensionWorker).to have_received(:perform_async) - end - end - - context 'when account is suspended' do - subject { described_class.new.call('alice', 'example.com', payload) } - - let!(:account) { Fabricate(:account, username: 'alice', domain: 'example.com', display_name: '') } - - let(:payload) do - { - id: 'https://foo.test', - type: 'Actor', - inbox: 'https://foo.test/inbox', - suspended: false, - name: 'Hoge', - }.with_indifferent_access - end - - before do - allow(Admin::UnsuspensionWorker).to receive(:perform_async) - - account.suspend!(origin: suspension_origin) - end - - context 'when locally' do - let(:suspension_origin) { :local } - - it 'does not unsuspend it' do - expect(subject.suspended?).to be true - end - - it 'does not update any attributes' do - expect(subject.display_name).to_not eq 'Hoge' - end - end - - context 'when remotely' do - let(:suspension_origin) { :remote } - - it 'unsuspends it' do - expect(subject.suspended?).to be false - end - - it 'queues unsuspension worker' do - subject - expect(Admin::UnsuspensionWorker).to have_received(:perform_async) - end - - it 'updates attributes' do - expect(subject.display_name).to eq 'Hoge' - end - end - end - - context 'when discovering many subdomains in a short timeframe' do - subject do - 8.times do |i| - domain = "test#{i}.testdomain.com" - json = { - id: "https://#{domain}/users/1", - type: 'Actor', - inbox: "https://#{domain}/inbox", - }.with_indifferent_access - described_class.new.call('alice', domain, json) - end - end - - before do - stub_const 'ActivityPub::ProcessAccountService::SUBDOMAINS_RATELIMIT', 5 - end - - it 'creates at least some accounts' do - expect { subject }.to change { Account.remote.count }.by_at_least(2) - end - - it 'creates no more account than the limit allows' do - expect { subject }.to change { Account.remote.count }.by_at_most(5) - end - end - - context 'when Accounts referencing other accounts' do - let(:payload) do - { - '@context': ['https://www.w3.org/ns/activitystreams'], - id: 'https://foo.test/users/1', - type: 'Person', - inbox: 'https://foo.test/inbox', - featured: 'https://foo.test/users/1/featured', - preferredUsername: 'user1', - }.with_indifferent_access - end - - before do - stub_const 'ActivityPub::ProcessAccountService::DISCOVERIES_PER_REQUEST', 5 - - 8.times do |i| - actor_json = { - '@context': ['https://www.w3.org/ns/activitystreams'], - id: "https://foo.test/users/#{i}", - type: 'Person', - inbox: 'https://foo.test/inbox', - featured: "https://foo.test/users/#{i}/featured", - preferredUsername: "user#{i}", - }.with_indifferent_access - status_json = { - '@context': ['https://www.w3.org/ns/activitystreams'], - id: "https://foo.test/users/#{i}/status", - attributedTo: "https://foo.test/users/#{i}", - type: 'Note', - content: "@user#{i + 1} test", - tag: [ - { - type: 'Mention', - href: "https://foo.test/users/#{i + 1}", - name: "@user#{i + 1}", - }, - ], - to: ['as:Public', "https://foo.test/users/#{i + 1}"], - }.with_indifferent_access - featured_json = { - '@context': ['https://www.w3.org/ns/activitystreams'], - id: "https://foo.test/users/#{i}/featured", - type: 'OrderedCollection', - totalItems: 1, - orderedItems: [status_json], - }.with_indifferent_access - webfinger = { - subject: "acct:user#{i}@foo.test", - links: [{ rel: 'self', href: "https://foo.test/users/#{i}" }], - }.with_indifferent_access - stub_request(:get, "https://foo.test/users/#{i}").to_return(status: 200, body: actor_json.to_json, headers: { 'Content-Type': 'application/activity+json' }) - stub_request(:get, "https://foo.test/users/#{i}/featured").to_return(status: 200, body: featured_json.to_json, headers: { 'Content-Type': 'application/activity+json' }) - stub_request(:get, "https://foo.test/users/#{i}/status").to_return(status: 200, body: status_json.to_json, headers: { 'Content-Type': 'application/activity+json' }) - stub_request(:get, "https://foo.test/.well-known/webfinger?resource=acct:user#{i}@foo.test").to_return(body: webfinger.to_json, headers: { 'Content-Type': 'application/jrd+json' }) - end - end - - it 'creates at least some accounts' do - expect { subject.call('user1', 'foo.test', payload) }.to change { Account.remote.count }.by_at_least(2) - end - - it 'creates no more account than the limit allows' do - expect { subject.call('user1', 'foo.test', payload) }.to change { Account.remote.count }.by_at_most(5) - end - end -end diff --git a/spec/services/activitypub/process_collection_service_spec.rb b/spec/services/activitypub/process_collection_service_spec.rb deleted file mode 100644 index 02011afea..000000000 --- a/spec/services/activitypub/process_collection_service_spec.rb +++ /dev/null @@ -1,255 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ActivityPub::ProcessCollectionService, type: :service do - subject { described_class.new } - - let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account') } - - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'foo', - type: 'Create', - actor: ActivityPub::TagManager.instance.uri_for(actor), - object: { - id: 'bar', - type: 'Note', - content: 'Lorem ipsum', - }, - } - end - - let(:json) { Oj.dump(payload) } - - describe '#call' do - context 'when actor is suspended' do - before do - actor.suspend!(origin: :remote) - end - - %w(Accept Add Announce Block Create Flag Follow Like Move Remove).each do |activity_type| - context "with #{activity_type} activity" do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'foo', - type: activity_type, - actor: ActivityPub::TagManager.instance.uri_for(actor), - } - end - - it 'does not process payload' do - expect(ActivityPub::Activity).to_not receive(:factory) - subject.call(json, actor) - end - end - end - - %w(Delete Reject Undo Update).each do |activity_type| - context "with #{activity_type} activity" do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'foo', - type: activity_type, - actor: ActivityPub::TagManager.instance.uri_for(actor), - } - end - - it 'processes the payload' do - expect(ActivityPub::Activity).to receive(:factory) - subject.call(json, actor) - end - end - end - end - - context 'when actor differs from sender' do - let(:forwarder) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/other_account') } - - it 'does not process payload if no signature exists' do - allow_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil) - expect(ActivityPub::Activity).to_not receive(:factory) - - subject.call(json, forwarder) - end - - it 'processes payload with actor if valid signature exists' do - payload['signature'] = { 'type' => 'RsaSignature2017' } - - allow_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(actor) - expect(ActivityPub::Activity).to receive(:factory).with(instance_of(Hash), actor, instance_of(Hash)) - - subject.call(json, forwarder) - end - - it 'does not process payload if invalid signature exists' do - payload['signature'] = { 'type' => 'RsaSignature2017' } - - allow_any_instance_of(ActivityPub::LinkedDataSignature).to receive(:verify_actor!).and_return(nil) - expect(ActivityPub::Activity).to_not receive(:factory) - - subject.call(json, forwarder) - end - - context 'when receiving a fabricated status' do - let!(:actor) do - Fabricate(:account, - username: 'bob', - domain: 'example.com', - uri: 'https://example.com/users/bob', - private_key: nil, - public_key: <<~TEXT) - -----BEGIN PUBLIC KEY----- - MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuuYyoyfsRkYnXRotMsId - W3euBDDfiv9oVqOxUVC7bhel8KednIMrMCRWFAkgJhbrlzbIkjVr68o1MP9qLcn7 - CmH/BXHp7yhuFTr4byjdJKpwB+/i2jNEsvDH5jR8WTAeTCe0x/QHg21V3F7dSI5m - CCZ/1dSIyOXLRTWVlfDlm3rE4ntlCo+US3/7oSWbg/4/4qEnt1HC32kvklgScxua - 4LR5ATdoXa5bFoopPWhul7MJ6NyWCyQyScUuGdlj8EN4kmKQJvphKHrI9fvhgOuG - TvhTR1S5InA4azSSchY0tXEEw/VNxraeX0KPjbgr6DPcwhPd/m0nhVDq0zVyVBBD - MwIDAQAB - -----END PUBLIC KEY----- - TEXT - end - - let(:payload) do - { - '@context': [ - 'https://www.w3.org/ns/activitystreams', - nil, - { object: 'https://www.w3.org/ns/activitystreams#object' }, - ], - id: 'https://example.com/users/bob/fake-status/activity', - type: 'Create', - actor: 'https://example.com/users/bob', - published: '2022-01-22T15:00:00Z', - to: [ - 'https://www.w3.org/ns/activitystreams#Public', - ], - cc: [ - 'https://example.com/users/bob/followers', - ], - signature: { - type: 'RsaSignature2017', - creator: 'https://example.com/users/bob#main-key', - created: '2022-03-09T21:57:25Z', - signatureValue: 'WculK0LelTQ0MvGwU9TPoq5pFzFfGYRDCJqjZ232/Udj4' \ - 'CHqDTGOSw5UTDLShqBOyycCkbZGrQwXG+dpyDpQLSe1UV' \ - 'PZ5TPQtc/9XtI57WlS2nMNpdvRuxGnnb2btPdesXZ7n3p' \ - 'Cxo0zjaXrJMe0mqQh5QJO22mahb4bDwwmfTHgbD3nmkD+' \ - 'fBfGi+UV2qWwqr+jlV4L4JqNkh0gWljF5KTePLRRZCuWi' \ - 'Q/FAt7c67636cdIPf7fR+usjuZltTQyLZKEGuK8VUn2Gk' \ - 'fsx5qns7Vcjvlz1JqlAjyO8HPBbzTTHzUG2nUOIgC3Poj' \ - 'CSWv6mNTmRGoLZzOscCAYQA6cKw==', - }, - '@id': 'https://example.com/users/bob/statuses/107928807471117876/activity', - '@type': 'https://www.w3.org/ns/activitystreams#Create', - 'https://www.w3.org/ns/activitystreams#actor': { - '@id': 'https://example.com/users/bob', - }, - 'https://www.w3.org/ns/activitystreams#cc': { - '@id': 'https://example.com/users/bob/followers', - }, - object: { - id: 'https://example.com/users/bob/fake-status', - type: 'Note', - published: '2022-01-22T15:00:00Z', - url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=puck-was-here', - attributedTo: 'https://example.com/users/bob', - to: [ - 'https://www.w3.org/ns/activitystreams#Public', - ], - cc: [ - 'https://example.com/users/bob/followers', - ], - sensitive: false, - atomUri: 'https://example.com/users/bob/fake-status', - conversation: 'tag:example.com,2022-03-09:objectId=15:objectType=Conversation', - content: '

puck was here

', - - '@id': 'https://example.com/users/bob/statuses/107928807471117876', - '@type': 'https://www.w3.org/ns/activitystreams#Note', - 'http://ostatus.org#atomUri': 'https://example.com/users/bob/statuses/107928807471117876', - 'http://ostatus.org#conversation': 'tag:example.com,2022-03-09:objectId=15:objectType=Conversation', - 'https://www.w3.org/ns/activitystreams#attachment': [], - 'https://www.w3.org/ns/activitystreams#attributedTo': { - '@id': 'https://example.com/users/bob', - }, - 'https://www.w3.org/ns/activitystreams#cc': { - '@id': 'https://example.com/users/bob/followers', - }, - 'https://www.w3.org/ns/activitystreams#content': [ - '

hello world

', - { - '@value': '

hello world

', - '@language': 'en', - }, - ], - 'https://www.w3.org/ns/activitystreams#published': { - '@type': 'http://www.w3.org/2001/XMLSchema#dateTime', - '@value': '2022-03-09T21:55:07Z', - }, - 'https://www.w3.org/ns/activitystreams#replies': { - '@id': 'https://example.com/users/bob/statuses/107928807471117876/replies', - '@type': 'https://www.w3.org/ns/activitystreams#Collection', - 'https://www.w3.org/ns/activitystreams#first': { - '@type': 'https://www.w3.org/ns/activitystreams#CollectionPage', - 'https://www.w3.org/ns/activitystreams#items': [], - 'https://www.w3.org/ns/activitystreams#next': { - '@id': 'https://example.com/users/bob/statuses/107928807471117876/replies?only_other_accounts=true&page=true', - }, - 'https://www.w3.org/ns/activitystreams#partOf': { - '@id': 'https://example.com/users/bob/statuses/107928807471117876/replies', - }, - }, - }, - 'https://www.w3.org/ns/activitystreams#sensitive': false, - 'https://www.w3.org/ns/activitystreams#tag': [], - 'https://www.w3.org/ns/activitystreams#to': { - '@id': 'https://www.w3.org/ns/activitystreams#Public', - }, - 'https://www.w3.org/ns/activitystreams#url': { - '@id': 'https://example.com/@bob/107928807471117876', - }, - }, - 'https://www.w3.org/ns/activitystreams#published': { - '@type': 'http://www.w3.org/2001/XMLSchema#dateTime', - '@value': '2022-03-09T21:55:07Z', - }, - 'https://www.w3.org/ns/activitystreams#to': { - '@id': 'https://www.w3.org/ns/activitystreams#Public', - }, - } - end - - it 'does not process forged payload' do - expect(ActivityPub::Activity).to_not receive(:factory).with( - hash_including( - 'object' => hash_including( - 'id' => 'https://example.com/users/bob/fake-status' - ) - ), - anything, - anything - ) - - expect(ActivityPub::Activity).to_not receive(:factory).with( - hash_including( - 'object' => hash_including( - 'content' => '

puck was here

' - ) - ), - anything, - anything - ) - - subject.call(json, forwarder) - - expect(Status.where(uri: 'https://example.com/users/bob/fake-status').exists?).to be false - end - end - end - end -end diff --git a/spec/services/activitypub/process_status_update_service_spec.rb b/spec/services/activitypub/process_status_update_service_spec.rb deleted file mode 100644 index 9d91f31cc..000000000 --- a/spec/services/activitypub/process_status_update_service_spec.rb +++ /dev/null @@ -1,466 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -def poll_option_json(name, votes) - { type: 'Note', name: name, replies: { type: 'Collection', totalItems: votes } } -end - -RSpec.describe ActivityPub::ProcessStatusUpdateService, type: :service do - subject { described_class.new } - - let!(:status) { Fabricate(:status, text: 'Hello world', account: Fabricate(:account, domain: 'example.com')) } - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'foo', - type: 'Note', - summary: 'Show more', - content: 'Hello universe', - updated: '2021-09-08T22:39:25Z', - tag: [ - { type: 'Hashtag', name: 'hoge' }, - { type: 'Mention', href: ActivityPub::TagManager.instance.uri_for(alice) }, - ], - } - end - let(:json) { Oj.load(Oj.dump(payload)) } - - let(:alice) { Fabricate(:account) } - let(:bob) { Fabricate(:account) } - - let(:mentions) { [] } - let(:tags) { [] } - let(:media_attachments) { [] } - - before do - mentions.each { |a| Fabricate(:mention, status: status, account: a) } - tags.each { |t| status.tags << t } - media_attachments.each { |m| status.media_attachments << m } - end - - describe '#call' do - it 'updates text' do - subject.call(status, json, json) - expect(status.reload.text).to eq 'Hello universe' - end - - it 'updates content warning' do - subject.call(status, json, json) - expect(status.reload.spoiler_text).to eq 'Show more' - end - - context 'when the changes are only in sanitized-out HTML' do - let!(:status) { Fabricate(:status, text: '

Hello world joinmastodon.org

', account: Fabricate(:account, domain: 'example.com')) } - - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'foo', - type: 'Note', - updated: '2021-09-08T22:39:25Z', - content: '

Hello world joinmastodon.org

', - } - end - - before do - subject.call(status, json, json) - end - - it 'does not create any edits' do - expect(status.reload.edits).to be_empty - end - - it 'does not mark status as edited' do - expect(status.edited?).to be false - end - end - - context 'when the status has not been explicitly edited' do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'foo', - type: 'Note', - content: 'Updated text', - } - end - - before do - subject.call(status, json, json) - end - - it 'does not create any edits' do - expect(status.reload.edits).to be_empty - end - - it 'does not mark status as edited' do - expect(status.reload.edited?).to be false - end - - it 'does not update the text' do - expect(status.reload.text).to eq 'Hello world' - end - end - - context 'when the status has not been explicitly edited and features a poll' do - let(:account) { Fabricate(:account, domain: 'example.com') } - let!(:expiration) { 10.days.from_now.utc } - let!(:status) do - Fabricate(:status, - text: 'Hello world', - account: account, - poll_attributes: { - options: %w(Foo Bar), - account: account, - multiple: false, - hide_totals: false, - expires_at: expiration, - }) - end - - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://example.com/foo', - type: 'Question', - content: 'Hello world', - endTime: expiration.iso8601, - oneOf: [ - poll_option_json('Foo', 4), - poll_option_json('Bar', 3), - ], - } - end - - before do - subject.call(status, json, json) - end - - it 'does not create any edits' do - expect(status.reload.edits).to be_empty - end - - it 'does not mark status as edited' do - expect(status.reload.edited?).to be false - end - - it 'does not update the text' do - expect(status.reload.text).to eq 'Hello world' - end - - it 'updates tallies' do - expect(status.poll.reload.cached_tallies).to eq [4, 3] - end - end - - context 'when the status changes a poll despite being not explicitly marked as updated' do - let(:account) { Fabricate(:account, domain: 'example.com') } - let!(:expiration) { 10.days.from_now.utc } - let!(:status) do - Fabricate(:status, - text: 'Hello world', - account: account, - poll_attributes: { - options: %w(Foo Bar), - account: account, - multiple: false, - hide_totals: false, - expires_at: expiration, - }) - end - - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://example.com/foo', - type: 'Question', - content: 'Hello world', - endTime: expiration.iso8601, - oneOf: [ - poll_option_json('Foo', 4), - poll_option_json('Bar', 3), - poll_option_json('Baz', 3), - ], - } - end - - before do - subject.call(status, json, json) - end - - it 'does not create any edits' do - expect(status.reload.edits).to be_empty - end - - it 'does not mark status as edited' do - expect(status.reload.edited?).to be false - end - - it 'does not update the text' do - expect(status.reload.text).to eq 'Hello world' - end - - it 'does not update tallies' do - expect(status.poll.reload.cached_tallies).to eq [0, 0] - end - end - - context 'when receiving an edit older than the latest processed' do - before do - status.snapshot!(at_time: status.created_at, rate_limit: false) - status.update!(text: 'Hello newer world', edited_at: Time.now.utc) - status.snapshot!(rate_limit: false) - end - - it 'does not create any edits' do - expect { subject.call(status, json, json) }.to_not(change { status.reload.edits.pluck(&:id) }) - end - - it 'does not update the text, spoiler_text or edited_at' do - expect { subject.call(status, json, json) }.to_not(change { s = status.reload; [s.text, s.spoiler_text, s.edited_at] }) - end - end - - context 'with no changes at all' do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'foo', - type: 'Note', - content: 'Hello world', - } - end - - before do - subject.call(status, json, json) - end - - it 'does not create any edits' do - expect(status.reload.edits).to be_empty - end - - it 'does not mark status as edited' do - expect(status.edited?).to be false - end - end - - context 'with no changes and originally with no ordered_media_attachment_ids' do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'foo', - type: 'Note', - content: 'Hello world', - } - end - - before do - status.update(ordered_media_attachment_ids: nil) - subject.call(status, json, json) - end - - it 'does not create any edits' do - expect(status.reload.edits).to be_empty - end - - it 'does not mark status as edited' do - expect(status.edited?).to be false - end - end - - context 'when originally without tags' do - before do - subject.call(status, json, json) - end - - it 'updates tags' do - expect(status.tags.reload.map(&:name)).to eq %w(hoge) - end - end - - context 'when originally with tags' do - let(:tags) { [Fabricate(:tag, name: 'test'), Fabricate(:tag, name: 'foo')] } - - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'foo', - type: 'Note', - summary: 'Show more', - content: 'Hello universe', - updated: '2021-09-08T22:39:25Z', - tag: [ - { type: 'Hashtag', name: 'foo' }, - ], - } - end - - before do - subject.call(status, json, json) - end - - it 'updates tags' do - expect(status.tags.reload.map(&:name)).to eq %w(foo) - end - end - - context 'when originally without mentions' do - before do - subject.call(status, json, json) - end - - it 'updates mentions' do - expect(status.active_mentions.reload.map(&:account_id)).to eq [alice.id] - end - end - - context 'when originally with mentions' do - let(:mentions) { [alice, bob] } - - before do - subject.call(status, json, json) - end - - it 'updates mentions' do - expect(status.active_mentions.reload.map(&:account_id)).to eq [alice.id] - end - end - - context 'when originally without media attachments' do - before do - stub_request(:get, 'https://example.com/foo.png').to_return(body: attachment_fixture('emojo.png')) - subject.call(status, json, json) - end - - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'foo', - type: 'Note', - content: 'Hello universe', - updated: '2021-09-08T22:39:25Z', - attachment: [ - { type: 'Image', mediaType: 'image/png', url: 'https://example.com/foo.png' }, - ], - } - end - - it 'updates media attachments' do - media_attachment = status.reload.ordered_media_attachments.first - - expect(media_attachment).to_not be_nil - expect(media_attachment.remote_url).to eq 'https://example.com/foo.png' - end - - it 'fetches the attachment' do - expect(a_request(:get, 'https://example.com/foo.png')).to have_been_made - end - - it 'records media change in edit' do - expect(status.edits.reload.last.ordered_media_attachment_ids).to_not be_empty - end - end - - context 'when originally with media attachments' do - let(:media_attachments) { [Fabricate(:media_attachment, remote_url: 'https://example.com/foo.png'), Fabricate(:media_attachment, remote_url: 'https://example.com/unused.png')] } - - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'foo', - type: 'Note', - content: 'Hello universe', - updated: '2021-09-08T22:39:25Z', - attachment: [ - { type: 'Image', mediaType: 'image/png', url: 'https://example.com/foo.png', name: 'A picture' }, - ], - } - end - - before do - allow(RedownloadMediaWorker).to receive(:perform_async) - subject.call(status, json, json) - end - - it 'updates the existing media attachment in-place' do - media_attachment = status.media_attachments.reload.first - - expect(media_attachment).to_not be_nil - expect(media_attachment.remote_url).to eq 'https://example.com/foo.png' - expect(media_attachment.description).to eq 'A picture' - end - - it 'does not queue redownload for the existing media attachment' do - expect(RedownloadMediaWorker).to_not have_received(:perform_async) - end - - it 'updates media attachments' do - expect(status.ordered_media_attachments.map(&:remote_url)).to eq %w(https://example.com/foo.png) - end - - it 'records media change in edit' do - expect(status.edits.reload.last.ordered_media_attachment_ids).to_not be_empty - end - end - - context 'when originally with a poll' do - before do - poll = Fabricate(:poll, status: status) - status.update(preloadable_poll: poll) - subject.call(status, json, json) - end - - it 'removes poll' do - expect(status.reload.poll).to be_nil - end - - it 'records media change in edit' do - expect(status.edits.reload.last.poll_options).to be_nil - end - end - - context 'when originally without a poll' do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'foo', - type: 'Question', - content: 'Hello universe', - updated: '2021-09-08T22:39:25Z', - closed: true, - oneOf: [ - { type: 'Note', name: 'Foo' }, - { type: 'Note', name: 'Bar' }, - { type: 'Note', name: 'Baz' }, - ], - } - end - - before do - subject.call(status, json, json) - end - - it 'creates a poll' do - poll = status.reload.poll - - expect(poll).to_not be_nil - expect(poll.options).to eq %w(Foo Bar Baz) - end - - it 'records media change in edit' do - expect(status.edits.reload.last.poll_options).to eq %w(Foo Bar Baz) - end - end - - it 'creates edit history' do - subject.call(status, json, json) - expect(status.edits.reload.map(&:text)).to eq ['Hello world', 'Hello universe'] - end - - it 'sets edited timestamp' do - subject.call(status, json, json) - expect(status.reload.edited_at.to_s).to eq '2021-09-08 22:39:25 UTC' - end - end -end diff --git a/spec/services/activitypub/synchronize_followers_service_spec.rb b/spec/services/activitypub/synchronize_followers_service_spec.rb deleted file mode 100644 index c9a513e24..000000000 --- a/spec/services/activitypub/synchronize_followers_service_spec.rb +++ /dev/null @@ -1,107 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do - subject { described_class.new } - - let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'http://example.com/account', inbox_url: 'http://example.com/inbox') } - let(:alice) { Fabricate(:account, username: 'alice') } - let(:bob) { Fabricate(:account, username: 'bob') } - let(:eve) { Fabricate(:account, username: 'eve') } - let(:mallory) { Fabricate(:account, username: 'mallory') } - let(:collection_uri) { 'http://example.com/partial-followers' } - - let(:items) do - [ - ActivityPub::TagManager.instance.uri_for(alice), - ActivityPub::TagManager.instance.uri_for(eve), - ActivityPub::TagManager.instance.uri_for(mallory), - ] - end - - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'Collection', - id: collection_uri, - items: items, - }.with_indifferent_access - end - - shared_examples 'synchronizes followers' do - before do - alice.follow!(actor) - bob.follow!(actor) - mallory.request_follow!(actor) - - allow(ActivityPub::DeliveryWorker).to receive(:perform_async) - - subject.call(actor, collection_uri) - end - - it 'keeps expected followers' do - expect(alice.following?(actor)).to be true - end - - it 'removes local followers not in the remote list' do - expect(bob.following?(actor)).to be false - end - - it 'converts follow requests to follow relationships when they have been accepted' do - expect(mallory.following?(actor)).to be true - end - - it 'sends an Undo Follow to the actor' do - expect(ActivityPub::DeliveryWorker).to have_received(:perform_async).with(anything, eve.id, actor.inbox_url) - end - end - - describe '#call' do - context 'when the endpoint is a Collection of actor URIs' do - before do - stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload)) - end - - it_behaves_like 'synchronizes followers' - end - - context 'when the endpoint is an OrderedCollection of actor URIs' do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'OrderedCollection', - id: collection_uri, - orderedItems: items, - }.with_indifferent_access - end - - before do - stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload)) - end - - it_behaves_like 'synchronizes followers' - end - - context 'when the endpoint is a paginated Collection of actor URIs' do - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - type: 'Collection', - id: collection_uri, - first: { - type: 'CollectionPage', - partOf: collection_uri, - items: items, - }, - }.with_indifferent_access - end - - before do - stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload)) - end - - it_behaves_like 'synchronizes followers' - end - end -end diff --git a/spec/services/after_block_domain_from_account_service_spec.rb b/spec/services/after_block_domain_from_account_service_spec.rb deleted file mode 100644 index 9bfaa3580..000000000 --- a/spec/services/after_block_domain_from_account_service_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe AfterBlockDomainFromAccountService, type: :service do - subject { described_class.new } - - let!(:wolf) { Fabricate(:account, username: 'wolf', domain: 'evil.org', inbox_url: 'https://evil.org/inbox', protocol: :activitypub) } - let!(:alice) { Fabricate(:account, username: 'alice') } - - before do - stub_jsonld_contexts! - allow(ActivityPub::DeliveryWorker).to receive(:perform_async) - end - - it 'purge followers from blocked domain' do - wolf.follow!(alice) - subject.call(alice, 'evil.org') - expect(wolf.following?(alice)).to be false - end - - it 'sends Reject->Follow to followers from blocked domain' do - wolf.follow!(alice) - subject.call(alice, 'evil.org') - expect(ActivityPub::DeliveryWorker).to have_received(:perform_async).once - end -end diff --git a/spec/services/after_block_service_spec.rb b/spec/services/after_block_service_spec.rb deleted file mode 100644 index d81bba1d8..000000000 --- a/spec/services/after_block_service_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe AfterBlockService, type: :service do - subject { described_class.new.call(account, target_account) } - - let(:account) { Fabricate(:account) } - let(:target_account) { Fabricate(:account) } - let(:status) { Fabricate(:status, account: target_account) } - let(:other_status) { Fabricate(:status, account: target_account) } - let(:other_account_status) { Fabricate(:status) } - let(:other_account_reblog) { Fabricate(:status, reblog_of_id: other_status.id) } - - describe 'home timeline' do - let(:home_timeline_key) { FeedManager.instance.key(:home, account.id) } - - before do - redis.del(home_timeline_key) - end - - it "clears account's statuses" do - FeedManager.instance.push_to_home(account, status) - FeedManager.instance.push_to_home(account, other_account_status) - FeedManager.instance.push_to_home(account, other_account_reblog) - - expect { subject }.to change { - redis.zrange(home_timeline_key, 0, -1) - }.from([status.id.to_s, other_account_status.id.to_s, other_account_reblog.id.to_s]).to([other_account_status.id.to_s]) - end - end - - describe 'lists' do - let(:list) { Fabricate(:list, account: account) } - let(:list_timeline_key) { FeedManager.instance.key(:list, list.id) } - - before do - redis.del(list_timeline_key) - end - - it "clears account's statuses" do - FeedManager.instance.push_to_list(list, status) - FeedManager.instance.push_to_list(list, other_account_status) - FeedManager.instance.push_to_list(list, other_account_reblog) - - expect { subject }.to change { - redis.zrange(list_timeline_key, 0, -1) - }.from([status.id.to_s, other_account_status.id.to_s, other_account_reblog.id.to_s]).to([other_account_status.id.to_s]) - end - end -end diff --git a/spec/services/app_sign_up_service_spec.rb b/spec/services/app_sign_up_service_spec.rb deleted file mode 100644 index 253230496..000000000 --- a/spec/services/app_sign_up_service_spec.rb +++ /dev/null @@ -1,55 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe AppSignUpService, type: :service do - subject { described_class.new } - - let(:app) { Fabricate(:application, scopes: 'read write') } - let(:good_params) { { username: 'alice', password: '12345678', email: 'good@email.com', agreement: true } } - let(:remote_ip) { IPAddr.new('198.0.2.1') } - - describe '#call' do - it 'returns nil when registrations are closed' do - tmp = Setting.registrations_mode - Setting.registrations_mode = 'none' - expect { subject.call(app, remote_ip, good_params) }.to raise_error Mastodon::NotPermittedError - Setting.registrations_mode = tmp - end - - it 'raises an error when params are missing' do - expect { subject.call(app, remote_ip, {}) }.to raise_error ActiveRecord::RecordInvalid - end - - it 'creates an unconfirmed user with access token' do - access_token = subject.call(app, remote_ip, good_params) - expect(access_token).to_not be_nil - user = User.find_by(id: access_token.resource_owner_id) - expect(user).to_not be_nil - expect(user.confirmed?).to be false - end - - it 'creates access token with the app\'s scopes' do - access_token = subject.call(app, remote_ip, good_params) - expect(access_token).to_not be_nil - expect(access_token.scopes.to_s).to eq 'read write' - end - - it 'creates an account' do - access_token = subject.call(app, remote_ip, good_params) - expect(access_token).to_not be_nil - user = User.find_by(id: access_token.resource_owner_id) - expect(user).to_not be_nil - expect(user.account).to_not be_nil - expect(user.invite_request).to be_nil - end - - it 'creates an account with invite request text' do - access_token = subject.call(app, remote_ip, good_params.merge(reason: 'Foo bar')) - expect(access_token).to_not be_nil - user = User.find_by(id: access_token.resource_owner_id) - expect(user).to_not be_nil - expect(user.invite_request&.text).to eq 'Foo bar' - end - end -end diff --git a/spec/services/authorize_follow_service_spec.rb b/spec/services/authorize_follow_service_spec.rb deleted file mode 100644 index d07645ab6..000000000 --- a/spec/services/authorize_follow_service_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe AuthorizeFollowService, type: :service do - subject { described_class.new } - - let(:sender) { Fabricate(:account, username: 'alice') } - - describe 'local' do - let(:bob) { Fabricate(:account, username: 'bob') } - - before do - FollowRequest.create(account: bob, target_account: sender) - subject.call(bob, sender) - end - - it 'removes follow request' do - expect(bob.requested?(sender)).to be false - end - - it 'creates follow relation' do - expect(bob.following?(sender)).to be true - end - end - - describe 'remote ActivityPub' do - let(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') } - - before do - FollowRequest.create(account: bob, target_account: sender) - stub_request(:post, bob.inbox_url).to_return(status: 200) - subject.call(bob, sender) - end - - it 'removes follow request' do - expect(bob.requested?(sender)).to be false - end - - it 'creates follow relation' do - expect(bob.following?(sender)).to be true - end - - it 'sends an accept activity' do - expect(a_request(:post, bob.inbox_url)).to have_been_made.once - end - end -end diff --git a/spec/services/backup_service_spec.rb b/spec/services/backup_service_spec.rb deleted file mode 100644 index 806ba1832..000000000 --- a/spec/services/backup_service_spec.rb +++ /dev/null @@ -1,101 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe BackupService, type: :service do - subject(:service_call) { described_class.new.call(backup) } - - let!(:user) { Fabricate(:user) } - let!(:attachment) { Fabricate(:media_attachment, account: user.account) } - let!(:status) { Fabricate(:status, account: user.account, text: 'Hello', visibility: :public, media_attachments: [attachment]) } - let!(:private_status) { Fabricate(:status, account: user.account, text: 'secret', visibility: :private) } - let!(:favourite) { Fabricate(:favourite, account: user.account) } - let!(:bookmark) { Fabricate(:bookmark, account: user.account) } - let!(:backup) { Fabricate(:backup, user: user) } - - def read_zip_file(backup, filename) - file = Paperclip.io_adapters.for(backup.dump) - Zip::File.open(file) do |zipfile| - entry = zipfile.glob(filename).first - return entry.get_input_stream.read - end - end - - context 'when the user has an avatar and header' do - before do - user.account.update!(avatar: attachment_fixture('avatar.gif')) - user.account.update!(header: attachment_fixture('emojo.png')) - end - - it 'stores them as expected' do - service_call - - json = export_json(:actor) - avatar_path = json.dig('icon', 'url') - header_path = json.dig('image', 'url') - - expect(avatar_path).to_not be_nil - expect(header_path).to_not be_nil - - expect(read_zip_file(backup, avatar_path)).to be_present - expect(read_zip_file(backup, header_path)).to be_present - end - end - - it 'marks the backup as processed and exports files' do - expect { service_call }.to process_backup - - expect_outbox_export - expect_likes_export - expect_bookmarks_export - end - - def process_backup - change(backup, :processed).from(false).to(true) - end - - def expect_outbox_export - json = export_json(:outbox) - - aggregate_failures do - expect(json['@context']).to_not be_nil - expect(json['type']).to eq 'OrderedCollection' - expect(json['totalItems']).to eq 2 - expect(json['orderedItems'][0]['@context']).to be_nil - expect(json['orderedItems'][0]).to include_create_item(status) - expect(json['orderedItems'][1]).to include_create_item(private_status) - end - end - - def expect_likes_export - json = export_json(:likes) - - aggregate_failures do - expect(json['type']).to eq 'OrderedCollection' - expect(json['orderedItems']).to eq [ActivityPub::TagManager.instance.uri_for(favourite.status)] - end - end - - def expect_bookmarks_export - json = export_json(:bookmarks) - - aggregate_failures do - expect(json['type']).to eq 'OrderedCollection' - expect(json['orderedItems']).to eq [ActivityPub::TagManager.instance.uri_for(bookmark.status)] - end - end - - def export_json(type) - Oj.load(read_zip_file(backup, "#{type}.json")) - end - - def include_create_item(status) - include({ - 'type' => 'Create', - 'object' => include({ - 'id' => ActivityPub::TagManager.instance.uri_for(status), - 'content' => "

#{status.text}

", - }), - }) - end -end diff --git a/spec/services/batched_remove_status_service_spec.rb b/spec/services/batched_remove_status_service_spec.rb deleted file mode 100644 index 8201c9d51..000000000 --- a/spec/services/batched_remove_status_service_spec.rb +++ /dev/null @@ -1,55 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe BatchedRemoveStatusService, type: :service do - subject { described_class.new } - - let!(:alice) { Fabricate(:account) } - let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com') } - let!(:jeff) { Fabricate(:account) } - let!(:hank) { Fabricate(:account, username: 'hank', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } - - let(:status_alice_hello) { PostStatusService.new.call(alice, text: 'Hello @bob@example.com') } - let(:status_alice_other) { PostStatusService.new.call(alice, text: 'Another status') } - - before do - allow(redis).to receive_messages(publish: nil) - - stub_request(:post, 'http://example.com/inbox').to_return(status: 200) - - jeff.user.update(current_sign_in_at: Time.zone.now) - jeff.follow!(alice) - hank.follow!(alice) - - status_alice_hello - status_alice_other - - subject.call([status_alice_hello, status_alice_other]) - end - - it 'removes statuses' do - expect { Status.find(status_alice_hello.id) }.to raise_error ActiveRecord::RecordNotFound - expect { Status.find(status_alice_other.id) }.to raise_error ActiveRecord::RecordNotFound - end - - it 'removes statuses from author\'s home feed' do - expect(HomeFeed.new(alice).get(10).pluck(:id)).to_not include(status_alice_hello.id, status_alice_other.id) - end - - it 'removes statuses from local follower\'s home feed' do - expect(HomeFeed.new(jeff).get(10).pluck(:id)).to_not include(status_alice_hello.id, status_alice_other.id) - end - - it 'notifies streaming API of followers' do - expect(redis).to have_received(:publish).with("timeline:#{jeff.id}", any_args).at_least(:once) - end - - it 'notifies streaming API of public timeline' do - expect(redis).to have_received(:publish).with('timeline:public', any_args).at_least(:once) - end - - it 'sends delete activity to followers' do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.at_least_once - end -end diff --git a/spec/services/block_domain_service_spec.rb b/spec/services/block_domain_service_spec.rb deleted file mode 100644 index 36dce9d19..000000000 --- a/spec/services/block_domain_service_spec.rb +++ /dev/null @@ -1,78 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe BlockDomainService, type: :service do - subject { described_class.new } - - let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') } - let!(:bad_status_plain) { Fabricate(:status, account: bad_account, text: 'You suck') } - let!(:bad_status_with_attachment) { Fabricate(:status, account: bad_account, text: 'Hahaha') } - let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status_with_attachment, file: attachment_fixture('attachment.jpg')) } - let!(:already_banned_account) { Fabricate(:account, username: 'badguy', domain: 'evil.org', suspended: true, silenced: true) } - - describe 'for a suspension' do - before do - subject.call(DomainBlock.create!(domain: 'evil.org', severity: :suspend)) - end - - it 'creates a domain block' do - expect(DomainBlock.blocked?('evil.org')).to be true - end - - it 'removes remote accounts from that domain' do - expect(Account.find_remote('badguy666', 'evil.org').suspended?).to be true - end - - it 'records suspension date appropriately' do - expect(Account.find_remote('badguy666', 'evil.org').suspended_at).to eq DomainBlock.find_by(domain: 'evil.org').created_at - end - - it 'keeps already-banned accounts banned' do - expect(Account.find_remote('badguy', 'evil.org').suspended?).to be true - end - - it 'does not overwrite suspension date of already-banned accounts' do - expect(Account.find_remote('badguy', 'evil.org').suspended_at).to_not eq DomainBlock.find_by(domain: 'evil.org').created_at - end - - it 'removes the remote accounts\'s statuses and media attachments' do - expect { bad_status_plain.reload }.to raise_exception ActiveRecord::RecordNotFound - expect { bad_status_with_attachment.reload }.to raise_exception ActiveRecord::RecordNotFound - expect { bad_attachment.reload }.to raise_exception ActiveRecord::RecordNotFound - end - end - - describe 'for a silence with reject media' do - before do - subject.call(DomainBlock.create!(domain: 'evil.org', severity: :silence, reject_media: true)) - end - - it 'does not create a domain block' do - expect(DomainBlock.blocked?('evil.org')).to be false - end - - it 'silences remote accounts from that domain' do - expect(Account.find_remote('badguy666', 'evil.org').silenced?).to be true - end - - it 'records suspension date appropriately' do - expect(Account.find_remote('badguy666', 'evil.org').silenced_at).to eq DomainBlock.find_by(domain: 'evil.org').created_at - end - - it 'keeps already-banned accounts banned' do - expect(Account.find_remote('badguy', 'evil.org').silenced?).to be true - end - - it 'does not overwrite suspension date of already-banned accounts' do - expect(Account.find_remote('badguy', 'evil.org').silenced_at).to_not eq DomainBlock.find_by(domain: 'evil.org').created_at - end - - it 'leaves the domains status and attachments, but clears media' do - expect { bad_status_plain.reload }.to_not raise_error - expect { bad_status_with_attachment.reload }.to_not raise_error - expect { bad_attachment.reload }.to_not raise_error - expect(bad_attachment.file.exists?).to be false - end - end -end diff --git a/spec/services/block_service_spec.rb b/spec/services/block_service_spec.rb deleted file mode 100644 index 5f7c2e8da..000000000 --- a/spec/services/block_service_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe BlockService, type: :service do - subject { described_class.new } - - let(:sender) { Fabricate(:account, username: 'alice') } - - describe 'local' do - let(:bob) { Fabricate(:account, username: 'bob') } - - before do - subject.call(sender, bob) - end - - it 'creates a blocking relation' do - expect(sender.blocking?(bob)).to be true - end - end - - describe 'remote ActivityPub' do - let(:bob) { Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } - - before do - stub_request(:post, 'http://example.com/inbox').to_return(status: 200) - subject.call(sender, bob) - end - - it 'creates a blocking relation' do - expect(sender.blocking?(bob)).to be true - end - - it 'sends a block activity' do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once - end - end -end diff --git a/spec/services/bootstrap_timeline_service_spec.rb b/spec/services/bootstrap_timeline_service_spec.rb deleted file mode 100644 index 721a0337f..000000000 --- a/spec/services/bootstrap_timeline_service_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe BootstrapTimelineService, type: :service do - subject { described_class.new } - - context 'when the new user has registered from an invite' do - let(:service) { instance_double(FollowService) } - let(:autofollow) { false } - let(:inviter) { Fabricate(:user, confirmed_at: 2.days.ago) } - let(:invite) { Fabricate(:invite, user: inviter, max_uses: nil, expires_at: 1.hour.from_now, autofollow: autofollow) } - let(:new_user) { Fabricate(:user, invite_code: invite.code) } - - before do - allow(FollowService).to receive(:new).and_return(service) - allow(service).to receive(:call) - end - - context 'when the invite has auto-follow enabled' do - let(:autofollow) { true } - - it 'calls FollowService to follow the inviter' do - subject.call(new_user.account) - expect(service).to have_received(:call).with(new_user.account, inviter.account) - end - end - - context 'when the invite does not have auto-follow enable' do - let(:autofollow) { false } - - it 'calls FollowService to follow the inviter' do - subject.call(new_user.account) - expect(service).to_not have_received(:call) - end - end - end -end diff --git a/spec/services/bulk_import_row_service_spec.rb b/spec/services/bulk_import_row_service_spec.rb deleted file mode 100644 index a77acc073..000000000 --- a/spec/services/bulk_import_row_service_spec.rb +++ /dev/null @@ -1,173 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe BulkImportRowService do - subject { described_class.new } - - let(:account) { Fabricate(:account) } - let(:import) { Fabricate(:bulk_import, account: account, type: import_type) } - let(:import_row) { Fabricate(:bulk_import_row, bulk_import: import, data: data) } - - describe '#call' do - context 'when importing a follow' do - let(:import_type) { 'following' } - let(:target_account) { Fabricate(:account) } - let(:service_double) { instance_double(FollowService, call: nil) } - let(:data) do - { 'acct' => target_account.acct } - end - - before do - allow(FollowService).to receive(:new).and_return(service_double) - end - - it 'calls FollowService with the expected arguments and returns true' do - expect(subject.call(import_row)).to be true - - expect(service_double).to have_received(:call).with(account, target_account, { reblogs: nil, notify: nil, languages: nil }) - end - end - - context 'when importing a block' do - let(:import_type) { 'blocking' } - let(:target_account) { Fabricate(:account) } - let(:service_double) { instance_double(BlockService, call: nil) } - let(:data) do - { 'acct' => target_account.acct } - end - - before do - allow(BlockService).to receive(:new).and_return(service_double) - end - - it 'calls BlockService with the expected arguments and returns true' do - expect(subject.call(import_row)).to be true - - expect(service_double).to have_received(:call).with(account, target_account) - end - end - - context 'when importing a mute' do - let(:import_type) { 'muting' } - let(:target_account) { Fabricate(:account) } - let(:service_double) { instance_double(MuteService, call: nil) } - let(:data) do - { 'acct' => target_account.acct } - end - - before do - allow(MuteService).to receive(:new).and_return(service_double) - end - - it 'calls MuteService with the expected arguments and returns true' do - expect(subject.call(import_row)).to be true - - expect(service_double).to have_received(:call).with(account, target_account, { notifications: nil }) - end - end - - context 'when importing a bookmark' do - let(:import_type) { 'bookmarks' } - let(:data) do - { 'uri' => ActivityPub::TagManager.instance.uri_for(target_status) } - end - - context 'when the status is public' do - let(:target_status) { Fabricate(:status) } - - it 'bookmarks the status and returns true' do - expect(subject.call(import_row)).to be true - expect(account.bookmarked?(target_status)).to be true - end - end - - context 'when the status is not accessible to the user' do - let(:target_status) { Fabricate(:status, visibility: :direct) } - - it 'does not bookmark the status and returns false' do - expect(subject.call(import_row)).to be false - expect(account.bookmarked?(target_status)).to be false - end - end - end - - context 'when importing a list row' do - let(:import_type) { 'lists' } - let(:target_account) { Fabricate(:account) } - let(:data) do - { 'acct' => target_account.acct, 'list_name' => 'my list' } - end - - shared_examples 'common behavior' do - context 'when the target account is already followed' do - before do - account.follow!(target_account) - end - - it 'returns true' do - expect(subject.call(import_row)).to be true - end - - it 'adds the target account to the list' do - expect { subject.call(import_row) }.to change { ListAccount.joins(:list).exists?(account_id: target_account.id, list: { title: 'my list' }) }.from(false).to(true) - end - end - - context 'when the user already requested to follow the target account' do - before do - account.request_follow!(target_account) - end - - it 'returns true' do - expect(subject.call(import_row)).to be true - end - - it 'adds the target account to the list' do - expect { subject.call(import_row) }.to change { ListAccount.joins(:list).exists?(account_id: target_account.id, list: { title: 'my list' }) }.from(false).to(true) - end - end - - context 'when the target account is neither followed nor requested' do - it 'returns true' do - expect(subject.call(import_row)).to be true - end - - it 'adds the target account to the list' do - expect { subject.call(import_row) }.to change { ListAccount.joins(:list).exists?(account_id: target_account.id, list: { title: 'my list' }) }.from(false).to(true) - end - end - - context 'when the target account is the user themself' do - let(:target_account) { account } - - it 'returns true' do - expect(subject.call(import_row)).to be true - end - - it 'adds the target account to the list' do - expect { subject.call(import_row) }.to change { ListAccount.joins(:list).exists?(account_id: target_account.id, list: { title: 'my list' }) }.from(false).to(true) - end - end - end - - context 'when the list does not exist yet' do - include_examples 'common behavior' - end - - context 'when the list exists' do - before do - Fabricate(:list, account: account, title: 'my list') - end - - include_examples 'common behavior' - - it 'does not create a new list' do - account.follow!(target_account) - - expect { subject.call(import_row) }.to_not(change { List.where(title: 'my list').count }) - end - end - end - end -end diff --git a/spec/services/bulk_import_service_spec.rb b/spec/services/bulk_import_service_spec.rb deleted file mode 100644 index 281b642ea..000000000 --- a/spec/services/bulk_import_service_spec.rb +++ /dev/null @@ -1,417 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe BulkImportService do - subject { described_class.new } - - let(:account) { Fabricate(:account) } - let(:import) { Fabricate(:bulk_import, account: account, type: import_type, overwrite: overwrite, state: :in_progress, imported_items: 0, processed_items: 0) } - - before do - import.update(total_items: import.rows.count) - end - - describe '#call' do - around do |example| - Sidekiq::Testing.fake! do - example.run - Sidekiq::Worker.clear_all - end - end - - context 'when importing follows' do - let(:import_type) { 'following' } - let(:overwrite) { false } - - let!(:rows) do - [ - { 'acct' => 'user@foo.bar' }, - { 'acct' => 'unknown@unknown.bar' }, - ].map { |data| import.rows.create!(data: data) } - end - - before do - account.follow!(Fabricate(:account)) - end - - it 'does not immediately change who the account follows' do - expect { subject.call(import) }.to_not(change { account.reload.active_relationships.to_a }) - end - - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) - end - - it 'requests to follow all the listed users once the workers have run' do - subject.call(import) - - resolve_account_service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) - allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) } - allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) } - - Import::RowWorker.drain - - expect(FollowRequest.includes(:target_account).where(account: account).map(&:target_account).map(&:acct)).to contain_exactly('user@foo.bar', 'unknown@unknown.bar') - end - end - - context 'when importing follows with overwrite' do - let(:import_type) { 'following' } - let(:overwrite) { true } - - let!(:followed) { Fabricate(:account, username: 'followed', domain: 'foo.bar', protocol: :activitypub) } - let!(:to_be_unfollowed) { Fabricate(:account, username: 'to_be_unfollowed', domain: 'foo.bar', protocol: :activitypub) } - - let!(:rows) do - [ - { 'acct' => 'followed@foo.bar', 'show_reblogs' => false, 'notify' => true, 'languages' => ['en'] }, - { 'acct' => 'user@foo.bar' }, - { 'acct' => 'unknown@unknown.bar' }, - ].map { |data| import.rows.create!(data: data) } - end - - before do - account.follow!(followed, reblogs: true, notify: false) - account.follow!(to_be_unfollowed) - end - - it 'unfollows user not present on list' do - subject.call(import) - expect(account.following?(to_be_unfollowed)).to be false - end - - it 'updates the existing follow relationship as expected' do - expect { subject.call(import) }.to change { Follow.where(account: account, target_account: followed).pick(:show_reblogs, :notify, :languages) }.from([true, false, nil]).to([false, true, ['en']]) - end - - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows[1..].map(&:id)) - end - - it 'requests to follow all the expected users once the workers have run' do - subject.call(import) - - resolve_account_service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) - allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) } - allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) } - - Import::RowWorker.drain - - expect(FollowRequest.includes(:target_account).where(account: account).map(&:target_account).map(&:acct)).to contain_exactly('user@foo.bar', 'unknown@unknown.bar') - end - end - - context 'when importing blocks' do - let(:import_type) { 'blocking' } - let(:overwrite) { false } - - let!(:rows) do - [ - { 'acct' => 'user@foo.bar' }, - { 'acct' => 'unknown@unknown.bar' }, - ].map { |data| import.rows.create!(data: data) } - end - - before do - account.block!(Fabricate(:account, username: 'already_blocked', domain: 'remote.org')) - end - - it 'does not immediately change who the account blocks' do - expect { subject.call(import) }.to_not(change { account.reload.blocking.to_a }) - end - - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) - end - - it 'blocks all the listed users once the workers have run' do - subject.call(import) - - resolve_account_service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) - allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) } - allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) } - - Import::RowWorker.drain - - expect(account.blocking.map(&:acct)).to contain_exactly('already_blocked@remote.org', 'user@foo.bar', 'unknown@unknown.bar') - end - end - - context 'when importing blocks with overwrite' do - let(:import_type) { 'blocking' } - let(:overwrite) { true } - - let!(:blocked) { Fabricate(:account, username: 'blocked', domain: 'foo.bar', protocol: :activitypub) } - let!(:to_be_unblocked) { Fabricate(:account, username: 'to_be_unblocked', domain: 'foo.bar', protocol: :activitypub) } - - let!(:rows) do - [ - { 'acct' => 'blocked@foo.bar' }, - { 'acct' => 'user@foo.bar' }, - { 'acct' => 'unknown@unknown.bar' }, - ].map { |data| import.rows.create!(data: data) } - end - - before do - account.block!(blocked) - account.block!(to_be_unblocked) - end - - it 'unblocks user not present on list' do - subject.call(import) - expect(account.blocking?(to_be_unblocked)).to be false - end - - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows[1..].map(&:id)) - end - - it 'requests to follow all the expected users once the workers have run' do - subject.call(import) - - resolve_account_service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) - allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) } - allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) } - - Import::RowWorker.drain - - expect(account.blocking.map(&:acct)).to contain_exactly('blocked@foo.bar', 'user@foo.bar', 'unknown@unknown.bar') - end - end - - context 'when importing mutes' do - let(:import_type) { 'muting' } - let(:overwrite) { false } - - let!(:rows) do - [ - { 'acct' => 'user@foo.bar' }, - { 'acct' => 'unknown@unknown.bar' }, - ].map { |data| import.rows.create!(data: data) } - end - - before do - account.mute!(Fabricate(:account, username: 'already_muted', domain: 'remote.org')) - end - - it 'does not immediately change who the account blocks' do - expect { subject.call(import) }.to_not(change { account.reload.muting.to_a }) - end - - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) - end - - it 'mutes all the listed users once the workers have run' do - subject.call(import) - - resolve_account_service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) - allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) } - allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) } - - Import::RowWorker.drain - - expect(account.muting.map(&:acct)).to contain_exactly('already_muted@remote.org', 'user@foo.bar', 'unknown@unknown.bar') - end - end - - context 'when importing mutes with overwrite' do - let(:import_type) { 'muting' } - let(:overwrite) { true } - - let!(:muted) { Fabricate(:account, username: 'muted', domain: 'foo.bar', protocol: :activitypub) } - let!(:to_be_unmuted) { Fabricate(:account, username: 'to_be_unmuted', domain: 'foo.bar', protocol: :activitypub) } - - let!(:rows) do - [ - { 'acct' => 'muted@foo.bar', 'hide_notifications' => true }, - { 'acct' => 'user@foo.bar' }, - { 'acct' => 'unknown@unknown.bar' }, - ].map { |data| import.rows.create!(data: data) } - end - - before do - account.mute!(muted, notifications: false) - account.mute!(to_be_unmuted) - end - - it 'updates the existing mute as expected' do - expect { subject.call(import) }.to change { Mute.where(account: account, target_account: muted).pick(:hide_notifications) }.from(false).to(true) - end - - it 'unblocks user not present on list' do - subject.call(import) - expect(account.muting?(to_be_unmuted)).to be false - end - - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows[1..].map(&:id)) - end - - it 'requests to follow all the expected users once the workers have run' do - subject.call(import) - - resolve_account_service_double = instance_double(ResolveAccountService) - allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service_double) - allow(resolve_account_service_double).to receive(:call).with('user@foo.bar', any_args) { Fabricate(:account, username: 'user', domain: 'foo.bar', protocol: :activitypub) } - allow(resolve_account_service_double).to receive(:call).with('unknown@unknown.bar', any_args) { Fabricate(:account, username: 'unknown', domain: 'unknown.bar', protocol: :activitypub) } - - Import::RowWorker.drain - - expect(account.muting.map(&:acct)).to contain_exactly('muted@foo.bar', 'user@foo.bar', 'unknown@unknown.bar') - end - end - - context 'when importing domain blocks' do - let(:import_type) { 'domain_blocking' } - let(:overwrite) { false } - - let!(:rows) do - [ - { 'domain' => 'blocked.com' }, - { 'domain' => 'to_block.com' }, - ].map { |data| import.rows.create!(data: data) } - end - - before do - account.block_domain!('alreadyblocked.com') - account.block_domain!('blocked.com') - end - - it 'blocks all the new domains' do - subject.call(import) - expect(account.domain_blocks.pluck(:domain)).to contain_exactly('alreadyblocked.com', 'blocked.com', 'to_block.com') - end - - it 'marks the import as finished' do - subject.call(import) - expect(import.reload.finished?).to be true - end - end - - context 'when importing domain blocks with overwrite' do - let(:import_type) { 'domain_blocking' } - let(:overwrite) { true } - - let!(:rows) do - [ - { 'domain' => 'blocked.com' }, - { 'domain' => 'to_block.com' }, - ].map { |data| import.rows.create!(data: data) } - end - - before do - account.block_domain!('alreadyblocked.com') - account.block_domain!('blocked.com') - end - - it 'blocks all the new domains' do - subject.call(import) - expect(account.domain_blocks.pluck(:domain)).to contain_exactly('blocked.com', 'to_block.com') - end - - it 'marks the import as finished' do - subject.call(import) - expect(import.reload.finished?).to be true - end - end - - context 'when importing bookmarks' do - let(:import_type) { 'bookmarks' } - let(:overwrite) { false } - - let!(:already_bookmarked) { Fabricate(:status, uri: 'https://already.bookmarked/1') } - let!(:status) { Fabricate(:status, uri: 'https://foo.bar/posts/1') } - let!(:inaccessible_status) { Fabricate(:status, uri: 'https://foo.bar/posts/inaccessible', visibility: :direct) } - let!(:bookmarked) { Fabricate(:status, uri: 'https://foo.bar/posts/already-bookmarked') } - - let!(:rows) do - [ - { 'uri' => status.uri }, - { 'uri' => inaccessible_status.uri }, - { 'uri' => bookmarked.uri }, - { 'uri' => 'https://domain.unknown/foo' }, - { 'uri' => 'https://domain.unknown/private' }, - ].map { |data| import.rows.create!(data: data) } - end - - before do - account.bookmarks.create!(status: already_bookmarked) - account.bookmarks.create!(status: bookmarked) - end - - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) - end - - it 'updates the bookmarks as expected once the workers have run' do - subject.call(import) - - service_double = instance_double(ActivityPub::FetchRemoteStatusService) - allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service_double) - allow(service_double).to receive(:call).with('https://domain.unknown/foo') { Fabricate(:status, uri: 'https://domain.unknown/foo') } - allow(service_double).to receive(:call).with('https://domain.unknown/private') { Fabricate(:status, uri: 'https://domain.unknown/private', visibility: :direct) } - - Import::RowWorker.drain - - expect(account.bookmarks.map(&:status).map(&:uri)).to contain_exactly(already_bookmarked.uri, status.uri, bookmarked.uri, 'https://domain.unknown/foo') - end - end - - context 'when importing bookmarks with overwrite' do - let(:import_type) { 'bookmarks' } - let(:overwrite) { true } - - let!(:already_bookmarked) { Fabricate(:status, uri: 'https://already.bookmarked/1') } - let!(:status) { Fabricate(:status, uri: 'https://foo.bar/posts/1') } - let!(:inaccessible_status) { Fabricate(:status, uri: 'https://foo.bar/posts/inaccessible', visibility: :direct) } - let!(:bookmarked) { Fabricate(:status, uri: 'https://foo.bar/posts/already-bookmarked') } - - let!(:rows) do - [ - { 'uri' => status.uri }, - { 'uri' => inaccessible_status.uri }, - { 'uri' => bookmarked.uri }, - { 'uri' => 'https://domain.unknown/foo' }, - { 'uri' => 'https://domain.unknown/private' }, - ].map { |data| import.rows.create!(data: data) } - end - - before do - account.bookmarks.create!(status: already_bookmarked) - account.bookmarks.create!(status: bookmarked) - end - - it 'enqueues workers for the expected rows' do - subject.call(import) - expect(Import::RowWorker.jobs.pluck('args').flatten).to match_array(rows.map(&:id)) - end - - it 'updates the bookmarks as expected once the workers have run' do - subject.call(import) - - service_double = instance_double(ActivityPub::FetchRemoteStatusService) - allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service_double) - allow(service_double).to receive(:call).with('https://domain.unknown/foo') { Fabricate(:status, uri: 'https://domain.unknown/foo') } - allow(service_double).to receive(:call).with('https://domain.unknown/private') { Fabricate(:status, uri: 'https://domain.unknown/private', visibility: :direct) } - - Import::RowWorker.drain - - expect(account.bookmarks.map(&:status).map(&:uri)).to contain_exactly(status.uri, bookmarked.uri, 'https://domain.unknown/foo') - end - end - end -end diff --git a/spec/services/clear_domain_media_service_spec.rb b/spec/services/clear_domain_media_service_spec.rb deleted file mode 100644 index 9766e62de..000000000 --- a/spec/services/clear_domain_media_service_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ClearDomainMediaService, type: :service do - subject { described_class.new } - - let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') } - let!(:bad_status_plain) { Fabricate(:status, account: bad_account, text: 'You suck') } - let!(:bad_status_with_attachment) { Fabricate(:status, account: bad_account, text: 'Hahaha') } - let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status_with_attachment, file: attachment_fixture('attachment.jpg')) } - - describe 'for a silence with reject media' do - before do - subject.call(DomainBlock.create!(domain: 'evil.org', severity: :silence, reject_media: true)) - end - - it 'leaves the domains status and attachments, but clears media' do - expect { bad_status_plain.reload }.to_not raise_error - expect { bad_status_with_attachment.reload }.to_not raise_error - expect { bad_attachment.reload }.to_not raise_error - expect(bad_attachment.file.exists?).to be false - end - end -end diff --git a/spec/services/delete_account_service_spec.rb b/spec/services/delete_account_service_spec.rb deleted file mode 100644 index 68ab491e4..000000000 --- a/spec/services/delete_account_service_spec.rb +++ /dev/null @@ -1,121 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe DeleteAccountService, type: :service do - shared_examples 'common behavior' do - subject { described_class.new.call(account) } - - let!(:status) { Fabricate(:status, account: account) } - let!(:mention) { Fabricate(:mention, account: local_follower) } - let!(:status_with_mention) { Fabricate(:status, account: account, mentions: [mention]) } - let!(:media_attachment) { Fabricate(:media_attachment, account: account) } - let!(:notification) { Fabricate(:notification, account: account) } - let!(:favourite) { Fabricate(:favourite, account: account, status: Fabricate(:status, account: local_follower)) } - let!(:poll) { Fabricate(:poll, account: account) } - let!(:poll_vote) { Fabricate(:poll_vote, account: local_follower, poll: poll) } - - let!(:active_relationship) { Fabricate(:follow, account: account, target_account: local_follower) } - let!(:passive_relationship) { Fabricate(:follow, account: local_follower, target_account: account) } - let!(:endorsement) { Fabricate(:account_pin, account: local_follower, target_account: account) } - - let!(:mention_notification) { Fabricate(:notification, account: local_follower, activity: mention, type: :mention) } - let!(:status_notification) { Fabricate(:notification, account: local_follower, activity: status, type: :status) } - let!(:poll_notification) { Fabricate(:notification, account: local_follower, activity: poll, type: :poll) } - let!(:favourite_notification) { Fabricate(:notification, account: local_follower, activity: favourite, type: :favourite) } - let!(:follow_notification) { Fabricate(:notification, account: local_follower, activity: active_relationship, type: :follow) } - - let!(:account_note) { Fabricate(:account_note, account: account) } - - it 'deletes associated owned records' do - expect { subject }.to change { - [ - account.statuses, - account.media_attachments, - account.notifications, - account.favourites, - account.active_relationships, - account.passive_relationships, - account.polls, - account.account_notes, - ].map(&:count) - }.from([2, 1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0, 0]) - end - - it 'deletes associated target records' do - expect { subject }.to change { - [ - AccountPin.where(target_account: account), - ].map(&:count) - }.from([1]).to([0]) - end - - it 'deletes associated target notifications' do - expect { subject }.to change { - %w( - poll favourite status mention follow - ).map { |type| Notification.where(type: type).count } - }.from([1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0]) - end - end - - describe '#call on local account' do - before do - stub_request(:post, 'https://alice.com/inbox').to_return(status: 201) - stub_request(:post, 'https://bob.com/inbox').to_return(status: 201) - end - - let!(:remote_alice) { Fabricate(:account, inbox_url: 'https://alice.com/inbox', domain: 'alice.com', protocol: :activitypub) } - let!(:remote_bob) { Fabricate(:account, inbox_url: 'https://bob.com/inbox', domain: 'bob.com', protocol: :activitypub) } - - include_examples 'common behavior' do - let!(:account) { Fabricate(:account) } - let!(:local_follower) { Fabricate(:account) } - - it 'sends a delete actor activity to all known inboxes' do - subject - expect(a_request(:post, 'https://alice.com/inbox')).to have_been_made.once - expect(a_request(:post, 'https://bob.com/inbox')).to have_been_made.once - end - end - end - - describe '#call on remote account' do - before do - stub_request(:post, 'https://alice.com/inbox').to_return(status: 201) - stub_request(:post, 'https://bob.com/inbox').to_return(status: 201) - end - - include_examples 'common behavior' do - let!(:account) { Fabricate(:account, inbox_url: 'https://bob.com/inbox', protocol: :activitypub, domain: 'bob.com') } - let!(:local_follower) { Fabricate(:account) } - - it 'sends expected activities to followed and follower inboxes' do - subject - - expect(a_request(:post, account.inbox_url).with( - body: - hash_including({ - 'type' => 'Reject', - 'object' => hash_including({ - 'type' => 'Follow', - 'actor' => account.uri, - 'object' => ActivityPub::TagManager.instance.uri_for(local_follower), - }), - }) - )).to have_been_made.once - - expect(a_request(:post, account.inbox_url).with( - body: hash_including({ - 'type' => 'Undo', - 'object' => hash_including({ - 'type' => 'Follow', - 'actor' => ActivityPub::TagManager.instance.uri_for(local_follower), - 'object' => account.uri, - }), - }) - )).to have_been_made.once - end - end - end -end diff --git a/spec/services/fan_out_on_write_service_spec.rb b/spec/services/fan_out_on_write_service_spec.rb deleted file mode 100644 index 3b554f9ea..000000000 --- a/spec/services/fan_out_on_write_service_spec.rb +++ /dev/null @@ -1,113 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe FanOutOnWriteService, type: :service do - subject { described_class.new } - - let(:last_active_at) { Time.now.utc } - let(:status) { Fabricate(:status, account: alice, visibility: visibility, text: 'Hello @bob #hoge') } - - let!(:alice) { Fabricate(:user, current_sign_in_at: last_active_at).account } - let!(:bob) { Fabricate(:user, current_sign_in_at: last_active_at, account_attributes: { username: 'bob' }).account } - let!(:tom) { Fabricate(:user, current_sign_in_at: last_active_at).account } - - before do - bob.follow!(alice) - tom.follow!(alice) - - ProcessMentionsService.new.call(status) - ProcessHashtagsService.new.call(status) - - allow(redis).to receive(:publish) - - subject.call(status) - end - - def home_feed_of(account) - HomeFeed.new(account).get(10).map(&:id) - end - - context 'when status is public' do - let(:visibility) { 'public' } - - it 'is added to the home feed of its author' do - expect(home_feed_of(alice)).to include status.id - end - - it 'is added to the home feed of a follower' do - expect(home_feed_of(bob)).to include status.id - expect(home_feed_of(tom)).to include status.id - end - - it 'is broadcast to the hashtag stream' do - expect(redis).to have_received(:publish).with('timeline:hashtag:hoge', anything) - expect(redis).to have_received(:publish).with('timeline:hashtag:hoge:local', anything) - end - - it 'is broadcast to the public stream' do - expect(redis).to have_received(:publish).with('timeline:public', anything) - expect(redis).to have_received(:publish).with('timeline:public:local', anything) - end - end - - context 'when status is limited' do - let(:visibility) { 'limited' } - - it 'is added to the home feed of its author' do - expect(home_feed_of(alice)).to include status.id - end - - it 'is added to the home feed of the mentioned follower' do - expect(home_feed_of(bob)).to include status.id - end - - it 'is not added to the home feed of the other follower' do - expect(home_feed_of(tom)).to_not include status.id - end - - it 'is not broadcast publicly' do - expect(redis).to_not have_received(:publish).with('timeline:hashtag:hoge', anything) - expect(redis).to_not have_received(:publish).with('timeline:public', anything) - end - end - - context 'when status is private' do - let(:visibility) { 'private' } - - it 'is added to the home feed of its author' do - expect(home_feed_of(alice)).to include status.id - end - - it 'is added to the home feed of a follower' do - expect(home_feed_of(bob)).to include status.id - expect(home_feed_of(tom)).to include status.id - end - - it 'is not broadcast publicly' do - expect(redis).to_not have_received(:publish).with('timeline:hashtag:hoge', anything) - expect(redis).to_not have_received(:publish).with('timeline:public', anything) - end - end - - context 'when status is direct' do - let(:visibility) { 'direct' } - - it 'is added to the home feed of its author' do - expect(home_feed_of(alice)).to include status.id - end - - it 'is added to the home feed of the mentioned follower' do - expect(home_feed_of(bob)).to include status.id - end - - it 'is not added to the home feed of the other follower' do - expect(home_feed_of(tom)).to_not include status.id - end - - it 'is not broadcast publicly' do - expect(redis).to_not have_received(:publish).with('timeline:hashtag:hoge', anything) - expect(redis).to_not have_received(:publish).with('timeline:public', anything) - end - end -end diff --git a/spec/services/favourite_service_spec.rb b/spec/services/favourite_service_spec.rb deleted file mode 100644 index 782c235c4..000000000 --- a/spec/services/favourite_service_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe FavouriteService, type: :service do - subject { described_class.new } - - let(:sender) { Fabricate(:account, username: 'alice') } - - describe 'local' do - let(:bob) { Fabricate(:account) } - let(:status) { Fabricate(:status, account: bob) } - - before do - subject.call(sender, status) - end - - it 'creates a favourite' do - expect(status.favourites.first).to_not be_nil - end - end - - describe 'remote ActivityPub' do - let(:bob) { Fabricate(:account, protocol: :activitypub, username: 'bob', domain: 'example.com', inbox_url: 'http://example.com/inbox') } - let(:status) { Fabricate(:status, account: bob) } - - before do - stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {}) - subject.call(sender, status) - end - - it 'creates a favourite' do - expect(status.favourites.first).to_not be_nil - end - - it 'sends a like activity' do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once - end - end -end diff --git a/spec/services/fetch_link_card_service_spec.rb b/spec/services/fetch_link_card_service_spec.rb deleted file mode 100644 index f44cbb750..000000000 --- a/spec/services/fetch_link_card_service_spec.rb +++ /dev/null @@ -1,257 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe FetchLinkCardService, type: :service do - subject { described_class.new } - - let(:html) { 'Hello world' } - let(:oembed_cache) { nil } - - before do - stub_request(:get, 'http://example.com/html').to_return(headers: { 'Content-Type' => 'text/html' }, body: html) - stub_request(:get, 'http://example.com/not-found').to_return(status: 404, headers: { 'Content-Type' => 'text/html' }, body: html) - stub_request(:get, 'http://example.com/text').to_return(status: 404, headers: { 'Content-Type' => 'text/plain' }, body: 'Hello') - stub_request(:get, 'http://example.com/redirect').to_return(status: 302, headers: { 'Location' => 'http://example.com/html' }) - stub_request(:get, 'http://example.com/redirect-to-404').to_return(status: 302, headers: { 'Location' => 'http://example.com/not-found' }) - stub_request(:get, 'http://example.com/oembed?url=http://example.com/html').to_return(headers: { 'Content-Type' => 'application/json' }, body: '{ "version": "1.0", "type": "link", "title": "oEmbed title" }') - stub_request(:get, 'http://example.com/oembed?format=json&url=http://example.com/html').to_return(headers: { 'Content-Type' => 'application/json' }, body: '{ "version": "1.0", "type": "link", "title": "oEmbed title" }') - - stub_request(:get, 'http://example.xn--fiqs8s') - stub_request(:get, 'http://example.com/日本語') - stub_request(:get, 'http://example.com/test?data=file.gpx%5E1') - stub_request(:get, 'http://example.com/test-') - - stub_request(:get, 'http://example.com/sjis').to_return(request_fixture('sjis.txt')) - stub_request(:get, 'http://example.com/sjis_with_wrong_charset').to_return(request_fixture('sjis_with_wrong_charset.txt')) - stub_request(:get, 'http://example.com/koi8-r').to_return(request_fixture('koi8-r.txt')) - stub_request(:get, 'http://example.com/windows-1251').to_return(request_fixture('windows-1251.txt')) - - Rails.cache.write('oembed_endpoint:example.com', oembed_cache) if oembed_cache - - subject.call(status) - end - - context 'with a local status' do - context 'with URL of a regular HTML page' do - let(:status) { Fabricate(:status, text: 'http://example.com/html') } - - it 'creates preview card' do - expect(status.preview_card).to_not be_nil - expect(status.preview_card.url).to eq 'http://example.com/html' - expect(status.preview_card.title).to eq 'Hello world' - end - end - - context 'with URL of a page with no title' do - let(:status) { Fabricate(:status, text: 'http://example.com/html') } - let(:html) { '' } - - it 'does not create a preview card' do - expect(status.preview_card).to be_nil - end - end - - context 'with a URL of a plain-text page' do - let(:status) { Fabricate(:status, text: 'http://example.com/text') } - - it 'does not create a preview card' do - expect(status.preview_card).to be_nil - end - end - - context 'with multiple URLs' do - let(:status) { Fabricate(:status, text: 'ftp://example.com http://example.com/html http://example.com/text') } - - it 'fetches the first valid URL' do - expect(a_request(:get, 'http://example.com/html')).to have_been_made - end - - it 'does not fetch the second valid URL' do - expect(a_request(:get, 'http://example.com/text/')).to_not have_been_made - end - end - - context 'with a redirect URL' do - let(:status) { Fabricate(:status, text: 'http://example.com/redirect') } - - it 'follows redirect' do - expect(a_request(:get, 'http://example.com/redirect')).to have_been_made.once - expect(a_request(:get, 'http://example.com/html')).to have_been_made.once - end - - it 'creates preview card' do - expect(status.preview_card).to_not be_nil - expect(status.preview_card.url).to eq 'http://example.com/html' - expect(status.preview_card.title).to eq 'Hello world' - end - end - - context 'with a broken redirect URL' do - let(:status) { Fabricate(:status, text: 'http://example.com/redirect-to-404') } - - it 'follows redirect' do - expect(a_request(:get, 'http://example.com/redirect-to-404')).to have_been_made.once - expect(a_request(:get, 'http://example.com/not-found')).to have_been_made.once - end - - it 'does not create a preview card' do - expect(status.preview_card).to be_nil - end - end - - context 'with a 404 URL' do - let(:status) { Fabricate(:status, text: 'http://example.com/not-found') } - - it 'does not create a preview card' do - expect(status.preview_card).to be_nil - end - end - - context 'with an IDN URL' do - let(:status) { Fabricate(:status, text: 'Check out http://example.中国') } - - it 'fetches the URL' do - expect(a_request(:get, 'http://example.xn--fiqs8s/')).to have_been_made.once - end - end - - context 'with a URL of a page in Shift JIS encoding' do - let(:status) { Fabricate(:status, text: 'Check out http://example.com/sjis') } - - it 'decodes the HTML' do - expect(status.preview_cards.first.title).to eq('SJISのページ') - end - end - - context 'with a URL of a page in Shift JIS encoding labeled as UTF-8' do - let(:status) { Fabricate(:status, text: 'Check out http://example.com/sjis_with_wrong_charset') } - - it 'decodes the HTML despite the wrong charset header' do - expect(status.preview_cards.first.title).to eq('SJISのページ') - end - end - - context 'with a URL of a page in KOI8-R encoding' do - let(:status) { Fabricate(:status, text: 'Check out http://example.com/koi8-r') } - - it 'decodes the HTML' do - expect(status.preview_cards.first.title).to eq('Московя начинаетъ только въ XVI ст. привлекать внимане иностранцевъ.') - end - end - - context 'with a URL of a page in Windows-1251 encoding' do - let(:status) { Fabricate(:status, text: 'Check out http://example.com/windows-1251') } - - it 'decodes the HTML' do - expect(status.preview_cards.first.title).to eq('сэмпл текст') - end - end - - context 'with a Japanese path URL' do - let(:status) { Fabricate(:status, text: 'テストhttp://example.com/日本語') } - - it 'fetches the URL' do - expect(a_request(:get, 'http://example.com/日本語')).to have_been_made.once - end - end - - context 'with a hyphen-suffixed URL' do - let(:status) { Fabricate(:status, text: 'test http://example.com/test-') } - - it 'fetches the URL' do - expect(a_request(:get, 'http://example.com/test-')).to have_been_made.once - end - end - - context 'with a caret-suffixed URL' do - let(:status) { Fabricate(:status, text: 'test http://example.com/test?data=file.gpx^1') } - - it 'fetches the URL' do - expect(a_request(:get, 'http://example.com/test?data=file.gpx%5E1')).to have_been_made.once - end - - it 'does not strip the caret before fetching' do - expect(a_request(:get, 'http://example.com/test?data=file.gpx')).to_not have_been_made - end - end - - context 'with a non-isolated URL' do - let(:status) { Fabricate(:status, text: 'testhttp://example.com/sjis') } - - it 'does not fetch URLs not isolated from their surroundings' do - expect(a_request(:get, 'http://example.com/sjis')).to_not have_been_made - end - end - - context 'with a URL of a page with oEmbed support' do - let(:html) { 'Hello world' } - let(:status) { Fabricate(:status, text: 'http://example.com/html') } - - it 'fetches the oEmbed URL' do - expect(a_request(:get, 'http://example.com/oembed?url=http://example.com/html')).to have_been_made.once - end - - it 'creates preview card' do - expect(status.preview_card).to_not be_nil - expect(status.preview_card.url).to eq 'http://example.com/html' - expect(status.preview_card.title).to eq 'oEmbed title' - end - - context 'when oEmbed endpoint cache populated' do - let(:oembed_cache) { { endpoint: 'http://example.com/oembed?format=json&url={url}', format: :json } } - - it 'uses the cached oEmbed response' do - expect(a_request(:get, 'http://example.com/oembed?url=http://example.com/html')).to_not have_been_made - expect(a_request(:get, 'http://example.com/oembed?format=json&url=http://example.com/html')).to have_been_made - end - - it 'creates preview card' do - expect(status.preview_card).to_not be_nil - expect(status.preview_card.url).to eq 'http://example.com/html' - expect(status.preview_card.title).to eq 'oEmbed title' - end - end - - # If the original HTML URL for whatever reason (e.g. DOS protection) redirects to - # an error page, we can still use the cached oEmbed but should not use the - # redirect URL on the card. - context 'when oEmbed endpoint cache populated but page returns 404' do - let(:status) { Fabricate(:status, text: 'http://example.com/redirect-to-404') } - let(:oembed_cache) { { endpoint: 'http://example.com/oembed?url=http://example.com/html', format: :json } } - - it 'uses the cached oEmbed response' do - expect(a_request(:get, 'http://example.com/oembed?url=http://example.com/html')).to have_been_made - end - - it 'creates preview card' do - expect(status.preview_card).to_not be_nil - expect(status.preview_card.title).to eq 'oEmbed title' - end - - it 'uses the original URL' do - expect(status.preview_card&.url).to eq 'http://example.com/redirect-to-404' - end - end - end - end - - context 'with a remote status' do - let(:status) do - Fabricate(:status, account: Fabricate(:account, domain: 'example.com'), text: <<-TEXT) - Habt ihr ein paar gute Links zu foo - #Wannacry herumfliegen? - Ich will mal unter
http://example.com/not-found was sammeln. ! - security  - TEXT - end - - it 'parses out URLs' do - expect(a_request(:get, 'http://example.com/not-found')).to have_been_made.once - end - - it 'ignores URLs to hashtags' do - expect(a_request(:get, 'https://quitter.se/tag/wannacry')).to_not have_been_made - end - end -end diff --git a/spec/services/fetch_oembed_service_spec.rb b/spec/services/fetch_oembed_service_spec.rb deleted file mode 100644 index 777cbae3f..000000000 --- a/spec/services/fetch_oembed_service_spec.rb +++ /dev/null @@ -1,201 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe FetchOEmbedService, type: :service do - subject { described_class.new } - - before do - stub_request(:get, 'https://host.test/provider.json').to_return(status: 404) - stub_request(:get, 'https://host.test/provider.xml').to_return(status: 404) - stub_request(:get, 'https://host.test/empty_provider.json').to_return(status: 200) - end - - describe 'discover_provider' do - context 'when status code is 200 and MIME type is text/html' do - context 'when OEmbed endpoint contains URL as parameter' do - before do - stub_request(:get, 'https://www.youtube.com/watch?v=IPSbNdBmWKE').to_return( - status: 200, - headers: { 'Content-Type': 'text/html' }, - body: request_fixture('oembed_youtube.html') - ) - stub_request(:get, 'https://www.youtube.com/oembed?format=json&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DIPSbNdBmWKE').to_return( - status: 200, - headers: { 'Content-Type': 'text/html' }, - body: request_fixture('oembed_json_empty.html') - ) - end - - it 'returns new OEmbed::Provider for JSON provider' do - subject.call('https://www.youtube.com/watch?v=IPSbNdBmWKE') - expect(subject.endpoint_url).to eq 'https://www.youtube.com/oembed?format=json&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DIPSbNdBmWKE' - expect(subject.format).to eq :json - end - - it 'stores URL template' do - subject.call('https://www.youtube.com/watch?v=IPSbNdBmWKE') - expect(Rails.cache.read('oembed_endpoint:www.youtube.com')[:endpoint]).to eq 'https://www.youtube.com/oembed?format=json&url={url}' - end - end - - context 'when both of JSON and XML provider are discoverable' do - before do - stub_request(:get, 'https://host.test/oembed.html').to_return( - status: 200, - headers: { 'Content-Type': 'text/html' }, - body: request_fixture('oembed_json_xml.html') - ) - end - - it 'returns new OEmbed::Provider for JSON provider if :format option is set to :json' do - subject.call('https://host.test/oembed.html', format: :json) - expect(subject.endpoint_url).to eq 'https://host.test/provider.json' - expect(subject.format).to eq :json - end - - it 'returns new OEmbed::Provider for XML provider if :format option is set to :xml' do - subject.call('https://host.test/oembed.html', format: :xml) - expect(subject.endpoint_url).to eq 'https://host.test/provider.xml' - expect(subject.format).to eq :xml - end - - it 'does not cache OEmbed endpoint' do - subject.call('https://host.test/oembed.html', format: :xml) - expect(Rails.cache.exist?('oembed_endpoint:host.test')).to be false - end - end - - context 'when JSON provider is discoverable while XML provider is not' do - before do - stub_request(:get, 'https://host.test/oembed.html').to_return( - status: 200, - headers: { 'Content-Type': 'text/html' }, - body: request_fixture('oembed_json.html') - ) - end - - it 'returns new OEmbed::Provider for JSON provider' do - subject.call('https://host.test/oembed.html') - expect(subject.endpoint_url).to eq 'https://host.test/provider.json' - expect(subject.format).to eq :json - end - - it 'does not cache OEmbed endpoint' do - subject.call('https://host.test/oembed.html') - expect(Rails.cache.exist?('oembed_endpoint:host.test')).to be false - end - end - - context 'when XML provider is discoverable while JSON provider is not' do - before do - stub_request(:get, 'https://host.test/oembed.html').to_return( - status: 200, - headers: { 'Content-Type': 'text/html' }, - body: request_fixture('oembed_xml.html') - ) - end - - it 'returns new OEmbed::Provider for XML provider' do - subject.call('https://host.test/oembed.html') - expect(subject.endpoint_url).to eq 'https://host.test/provider.xml' - expect(subject.format).to eq :xml - end - - it 'does not cache OEmbed endpoint' do - subject.call('https://host.test/oembed.html') - expect(Rails.cache.exist?('oembed_endpoint:host.test')).to be false - end - end - - context 'with Invalid XML provider is discoverable while JSON provider is not' do - before do - stub_request(:get, 'https://host.test/oembed.html').to_return( - status: 200, - headers: { 'Content-Type': 'text/html' }, - body: request_fixture('oembed_invalid_xml.html') - ) - end - - it 'returns nil' do - expect(subject.call('https://host.test/oembed.html')).to be_nil - end - end - - context 'with neither of JSON and XML provider is discoverable' do - before do - stub_request(:get, 'https://host.test/oembed.html').to_return( - status: 200, - headers: { 'Content-Type': 'text/html' }, - body: request_fixture('oembed_undiscoverable.html') - ) - end - - it 'returns nil' do - expect(subject.call('https://host.test/oembed.html')).to be_nil - end - end - - context 'when empty JSON provider is discoverable' do - before do - stub_request(:get, 'https://host.test/oembed.html').to_return( - status: 200, - headers: { 'Content-Type': 'text/html' }, - body: request_fixture('oembed_json_empty.html') - ) - end - - it 'returns new OEmbed::Provider for JSON provider' do - subject.call('https://host.test/oembed.html') - expect(subject.endpoint_url).to eq 'https://host.test/empty_provider.json' - expect(subject.format).to eq :json - end - end - end - - context 'when endpoint is cached' do - before do - stub_request(:get, 'http://www.youtube.com/oembed?format=json&url=https://www.youtube.com/watch?v=dqwpQarrDwk').to_return( - status: 200, - headers: { 'Content-Type': 'text/html' }, - body: request_fixture('oembed_json_empty.html') - ) - end - - it 'returns new provider without fetching original URL first' do - subject.call('https://www.youtube.com/watch?v=dqwpQarrDwk', cached_endpoint: { endpoint: 'http://www.youtube.com/oembed?format=json&url={url}', format: :json }) - expect(a_request(:get, 'https://www.youtube.com/watch?v=dqwpQarrDwk')).to_not have_been_made - expect(subject.endpoint_url).to eq 'http://www.youtube.com/oembed?format=json&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdqwpQarrDwk' - expect(subject.format).to eq :json - expect(a_request(:get, 'http://www.youtube.com/oembed?format=json&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdqwpQarrDwk')).to have_been_made - end - end - - context 'when status code is not 200' do - before do - stub_request(:get, 'https://host.test/oembed.html').to_return( - status: 400, - headers: { 'Content-Type': 'text/html' }, - body: request_fixture('oembed_xml.html') - ) - end - - it 'returns nil' do - expect(subject.call('https://host.test/oembed.html')).to be_nil - end - end - - context 'when MIME type is not text/html' do - before do - stub_request(:get, 'https://host.test/oembed.html').to_return( - status: 200, - body: request_fixture('oembed_xml.html') - ) - end - - it 'returns nil' do - expect(subject.call('https://host.test/oembed.html')).to be_nil - end - end - end -end diff --git a/spec/services/fetch_remote_status_service_spec.rb b/spec/services/fetch_remote_status_service_spec.rb deleted file mode 100644 index 798740c9b..000000000 --- a/spec/services/fetch_remote_status_service_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe FetchRemoteStatusService, type: :service do - let(:account) { Fabricate(:account, domain: 'example.org', uri: 'https://example.org/foo') } - let(:prefetched_body) { nil } - - let(:note) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://example.org/@foo/1234', - type: 'Note', - content: 'Lorem ipsum', - attributedTo: ActivityPub::TagManager.instance.uri_for(account), - } - end - - context 'when protocol is :activitypub' do - subject { described_class.new.call(note[:id], prefetched_body: prefetched_body) } - - let(:prefetched_body) { Oj.dump(note) } - - before do - subject - end - - it 'creates status' do - status = account.statuses.first - - expect(status).to_not be_nil - expect(status.text).to eq 'Lorem ipsum' - end - end -end diff --git a/spec/services/fetch_resource_service_spec.rb b/spec/services/fetch_resource_service_spec.rb deleted file mode 100644 index 0f1068471..000000000 --- a/spec/services/fetch_resource_service_spec.rb +++ /dev/null @@ -1,110 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe FetchResourceService, type: :service do - describe '#call' do - subject { described_class.new.call(url) } - - let(:url) { 'http://example.com' } - - context 'with blank url' do - let(:url) { '' } - - it { is_expected.to be_nil } - end - - context 'when request fails' do - before do - stub_request(:get, url).to_return(status: 500, body: '', headers: {}) - end - - it { is_expected.to be_nil } - end - - context 'when OpenSSL::SSL::SSLError is raised' do - before do - request = instance_double(Request) - allow(Request).to receive(:new).and_return(request) - allow(request).to receive(:add_headers) - allow(request).to receive(:on_behalf_of) - allow(request).to receive(:perform).and_raise(OpenSSL::SSL::SSLError) - end - - it { is_expected.to be_nil } - end - - context 'when HTTP::ConnectionError is raised' do - before do - request = instance_double(Request) - allow(Request).to receive(:new).and_return(request) - allow(request).to receive(:add_headers) - allow(request).to receive(:on_behalf_of) - allow(request).to receive(:perform).and_raise(HTTP::ConnectionError) - end - - it { is_expected.to be_nil } - end - - context 'when request succeeds' do - let(:body) { '' } - - let(:content_type) { 'application/json' } - - let(:headers) do - { 'Content-Type' => content_type } - end - - let(:json) do - { - id: 1, - '@context': ActivityPub::TagManager::CONTEXT, - type: 'Note', - }.to_json - end - - before do - stub_request(:get, url).to_return(status: 200, body: body, headers: headers) - stub_request(:get, 'http://example.com/foo').to_return(status: 200, body: json, headers: { 'Content-Type' => 'application/activity+json' }) - end - - it 'signs request' do - subject - expect(a_request(:get, url).with(headers: { 'Signature' => /keyId="#{Regexp.escape(ActivityPub::TagManager.instance.key_uri_for(Account.representative))}"/ })).to have_been_made - end - - context 'when content type is application/atom+xml' do - let(:content_type) { 'application/atom+xml' } - - it { is_expected.to be_nil } - end - - context 'when content type is activity+json' do - let(:content_type) { 'application/activity+json; charset=utf-8' } - let(:body) { json } - - it { is_expected.to eq [1, { prefetched_body: body, id: true }] } - end - - context 'when content type is ld+json with profile' do - let(:content_type) { 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' } - let(:body) { json } - - it { is_expected.to eq [1, { prefetched_body: body, id: true }] } - end - - context 'when link header is present' do - let(:headers) { { 'Link' => '; rel="alternate"; type="application/activity+json"' } } - - it { is_expected.to eq [1, { prefetched_body: json, id: true }] } - end - - context 'when content type is text/html' do - let(:content_type) { 'text/html' } - let(:body) { '' } - - it { is_expected.to eq [1, { prefetched_body: json, id: true }] } - end - end - end -end diff --git a/spec/services/follow_service_spec.rb b/spec/services/follow_service_spec.rb deleted file mode 100644 index c2ad0d717..000000000 --- a/spec/services/follow_service_spec.rb +++ /dev/null @@ -1,157 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe FollowService, type: :service do - subject { described_class.new } - - let(:sender) { Fabricate(:account, username: 'alice') } - - context 'when local account' do - describe 'locked account' do - let(:bob) { Fabricate(:account, locked: true, username: 'bob') } - - before do - subject.call(sender, bob) - end - - it 'creates a follow request with reblogs' do - expect(FollowRequest.find_by(account: sender, target_account: bob, show_reblogs: true)).to_not be_nil - end - end - - describe 'locked account, no reblogs' do - let(:bob) { Fabricate(:account, locked: true, username: 'bob') } - - before do - subject.call(sender, bob, reblogs: false) - end - - it 'creates a follow request without reblogs' do - expect(FollowRequest.find_by(account: sender, target_account: bob, show_reblogs: false)).to_not be_nil - end - end - - describe 'unlocked account, from silenced account' do - let(:bob) { Fabricate(:account, username: 'bob') } - - before do - sender.touch(:silenced_at) - subject.call(sender, bob) - end - - it 'creates a follow request with reblogs' do - expect(FollowRequest.find_by(account: sender, target_account: bob, show_reblogs: true)).to_not be_nil - end - end - - describe 'unlocked account, from a muted account' do - let(:bob) { Fabricate(:account, username: 'bob') } - - before do - bob.mute!(sender) - subject.call(sender, bob) - end - - it 'creates a following relation with reblogs' do - expect(sender.following?(bob)).to be true - expect(sender.muting_reblogs?(bob)).to be false - end - end - - describe 'unlocked account' do - let(:bob) { Fabricate(:account, username: 'bob') } - - before do - subject.call(sender, bob) - end - - it 'creates a following relation with reblogs' do - expect(sender.following?(bob)).to be true - expect(sender.muting_reblogs?(bob)).to be false - end - end - - describe 'unlocked account, no reblogs' do - let(:bob) { Fabricate(:account, username: 'bob') } - - before do - subject.call(sender, bob, reblogs: false) - end - - it 'creates a following relation without reblogs' do - expect(sender.following?(bob)).to be true - expect(sender.muting_reblogs?(bob)).to be true - end - end - - describe 'already followed account' do - let(:bob) { Fabricate(:account, username: 'bob') } - - before do - sender.follow!(bob) - subject.call(sender, bob) - end - - it 'keeps a following relation' do - expect(sender.following?(bob)).to be true - end - end - - describe 'already followed account, turning reblogs off' do - let(:bob) { Fabricate(:account, username: 'bob') } - - before do - sender.follow!(bob, reblogs: true) - subject.call(sender, bob, reblogs: false) - end - - it 'disables reblogs' do - expect(sender.muting_reblogs?(bob)).to be true - end - end - - describe 'already followed account, turning reblogs on' do - let(:bob) { Fabricate(:account, username: 'bob') } - - before do - sender.follow!(bob, reblogs: false) - subject.call(sender, bob, reblogs: true) - end - - it 'disables reblogs' do - expect(sender.muting_reblogs?(bob)).to be false - end - end - - describe 'already followed account, changing languages' do - let(:bob) { Fabricate(:account, username: 'bob') } - - before do - sender.follow!(bob) - subject.call(sender, bob, languages: %w(en es)) - end - - it 'changes languages' do - expect(Follow.find_by(account: sender, target_account: bob)&.languages).to match_array %w(en es) - end - end - end - - context 'when remote ActivityPub account' do - let(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') } - - before do - stub_request(:post, 'http://example.com/inbox').to_return(status: 200, body: '', headers: {}) - subject.call(sender, bob) - end - - it 'creates follow request' do - expect(FollowRequest.find_by(account: sender, target_account: bob)).to_not be_nil - end - - it 'sends a follow activity to the inbox' do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once - end - end -end diff --git a/spec/services/import_service_spec.rb b/spec/services/import_service_spec.rb deleted file mode 100644 index 1904ac8dc..000000000 --- a/spec/services/import_service_spec.rb +++ /dev/null @@ -1,242 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ImportService, type: :service do - include RoutingHelper - - let!(:account) { Fabricate(:account, locked: false) } - let!(:bob) { Fabricate(:account, username: 'bob', locked: false) } - let!(:eve) { Fabricate(:account, username: 'eve', domain: 'example.com', locked: false, protocol: :activitypub, inbox_url: 'https://example.com/inbox') } - - before do - stub_request(:post, 'https://example.com/inbox').to_return(status: 200) - end - - context 'when importing old-style list of muted users' do - subject { described_class.new } - - let(:csv) { attachment_fixture('mute-imports.txt') } - - describe 'when no accounts are muted' do - let(:import) { Import.create(account: account, type: 'muting', data: csv) } - - it 'mutes the listed accounts, including notifications' do - subject.call(import) - expect(account.muting.count).to eq 2 - expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true - end - end - - describe 'when some accounts are muted and overwrite is not set' do - let(:import) { Import.create(account: account, type: 'muting', data: csv) } - - it 'mutes the listed accounts, including notifications' do - account.mute!(bob, notifications: false) - subject.call(import) - expect(account.muting.count).to eq 2 - expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true - end - end - - describe 'when some accounts are muted and overwrite is set' do - let(:import) { Import.create(account: account, type: 'muting', data: csv, overwrite: true) } - - it 'mutes the listed accounts, including notifications' do - account.mute!(bob, notifications: false) - subject.call(import) - expect(account.muting.count).to eq 2 - expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true - end - end - end - - context 'when importing new-style list of muted users' do - subject { described_class.new } - - let(:csv) { attachment_fixture('new-mute-imports.txt') } - - describe 'when no accounts are muted' do - let(:import) { Import.create(account: account, type: 'muting', data: csv) } - - it 'mutes the listed accounts, respecting notifications' do - subject.call(import) - expect(account.muting.count).to eq 2 - expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true - expect(Mute.find_by(account: account, target_account: eve).hide_notifications).to be false - end - end - - describe 'when some accounts are muted and overwrite is not set' do - let(:import) { Import.create(account: account, type: 'muting', data: csv) } - - it 'mutes the listed accounts, respecting notifications' do - account.mute!(bob, notifications: true) - subject.call(import) - expect(account.muting.count).to eq 2 - expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true - expect(Mute.find_by(account: account, target_account: eve).hide_notifications).to be false - end - end - - describe 'when some accounts are muted and overwrite is set' do - let(:import) { Import.create(account: account, type: 'muting', data: csv, overwrite: true) } - - it 'mutes the listed accounts, respecting notifications' do - account.mute!(bob, notifications: true) - subject.call(import) - expect(account.muting.count).to eq 2 - expect(Mute.find_by(account: account, target_account: bob).hide_notifications).to be true - expect(Mute.find_by(account: account, target_account: eve).hide_notifications).to be false - end - end - end - - context 'when importing old-style list of followed users' do - subject { described_class.new } - - let(:csv) { attachment_fixture('mute-imports.txt') } - - describe 'when no accounts are followed' do - let(:import) { Import.create(account: account, type: 'following', data: csv) } - - it 'follows the listed accounts, including boosts' do - subject.call(import) - - expect(account.following.count).to eq 1 - expect(account.follow_requests.count).to eq 1 - expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true - end - end - - describe 'when some accounts are already followed and overwrite is not set' do - let(:import) { Import.create(account: account, type: 'following', data: csv) } - - it 'follows the listed accounts, including notifications' do - account.follow!(bob, reblogs: false) - subject.call(import) - expect(account.following.count).to eq 1 - expect(account.follow_requests.count).to eq 1 - expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true - end - end - - describe 'when some accounts are already followed and overwrite is set' do - let(:import) { Import.create(account: account, type: 'following', data: csv, overwrite: true) } - - it 'mutes the listed accounts, including notifications' do - account.follow!(bob, reblogs: false) - subject.call(import) - expect(account.following.count).to eq 1 - expect(account.follow_requests.count).to eq 1 - expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true - end - end - end - - context 'when importing new-style list of followed users' do - subject { described_class.new } - - let(:csv) { attachment_fixture('new-following-imports.txt') } - - describe 'when no accounts are followed' do - let(:import) { Import.create(account: account, type: 'following', data: csv) } - - it 'follows the listed accounts, respecting boosts' do - subject.call(import) - expect(account.following.count).to eq 1 - expect(account.follow_requests.count).to eq 1 - expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true - expect(FollowRequest.find_by(account: account, target_account: eve).show_reblogs).to be false - end - end - - describe 'when some accounts are already followed and overwrite is not set' do - let(:import) { Import.create(account: account, type: 'following', data: csv) } - - it 'mutes the listed accounts, respecting notifications' do - account.follow!(bob, reblogs: true) - subject.call(import) - expect(account.following.count).to eq 1 - expect(account.follow_requests.count).to eq 1 - expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true - expect(FollowRequest.find_by(account: account, target_account: eve).show_reblogs).to be false - end - end - - describe 'when some accounts are already followed and overwrite is set' do - let(:import) { Import.create(account: account, type: 'following', data: csv, overwrite: true) } - - it 'mutes the listed accounts, respecting notifications' do - account.follow!(bob, reblogs: true) - subject.call(import) - expect(account.following.count).to eq 1 - expect(account.follow_requests.count).to eq 1 - expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true - expect(FollowRequest.find_by(account: account, target_account: eve).show_reblogs).to be false - end - end - end - - # Based on the bug report 20571 where UTF-8 encoded domains were rejecting import of their users - # - # https://github.com/mastodon/mastodon/issues/20571 - context 'with a utf-8 encoded domains' do - subject { described_class.new } - - let!(:nare) { Fabricate(:account, username: 'nare', domain: 'թութ.հայ', locked: false, protocol: :activitypub, inbox_url: 'https://թութ.հայ/inbox') } - let(:csv) { attachment_fixture('utf8-followers.txt') } - let(:import) { Import.create(account: account, type: 'following', data: csv) } - - # Make sure to not actually go to the remote server - before do - stub_request(:post, 'https://թութ.հայ/inbox').to_return(status: 200) - end - - it 'follows the listed account' do - expect(account.follow_requests.count).to eq 0 - subject.call(import) - expect(account.follow_requests.count).to eq 1 - end - end - - context 'when importing bookmarks' do - subject { described_class.new } - - let(:csv) { attachment_fixture('bookmark-imports.txt') } - let(:local_account) { Fabricate(:account, username: 'foo', domain: '') } - let!(:remote_status) { Fabricate(:status, uri: 'https://example.com/statuses/1312') } - let!(:direct_status) { Fabricate(:status, uri: 'https://example.com/statuses/direct', visibility: :direct) } - - around(:each) do |example| - local_before = Rails.configuration.x.local_domain - web_before = Rails.configuration.x.web_domain - Rails.configuration.x.local_domain = 'local.com' - Rails.configuration.x.web_domain = 'local.com' - example.run - Rails.configuration.x.web_domain = web_before - Rails.configuration.x.local_domain = local_before - end - - before do - service = instance_double(ActivityPub::FetchRemoteStatusService) - allow(ActivityPub::FetchRemoteStatusService).to receive(:new).and_return(service) - allow(service).to receive(:call).with('https://unknown-remote.com/users/bar/statuses/1') do - Fabricate(:status, uri: 'https://unknown-remote.com/users/bar/statuses/1') - end - end - - describe 'when no bookmarks are set' do - let(:import) { Import.create(account: account, type: 'bookmarks', data: csv) } - - it 'adds the toots the user has access to to bookmarks' do - local_status = Fabricate(:status, account: local_account, uri: 'https://local.com/users/foo/statuses/42', id: 42, local: true) - subject.call(import) - expect(account.bookmarks.map(&:status).map(&:id)).to include(local_status.id) - expect(account.bookmarks.map(&:status).map(&:id)).to include(remote_status.id) - expect(account.bookmarks.map(&:status).map(&:id)).to_not include(direct_status.id) - expect(account.bookmarks.count).to eq 3 - end - end - end -end diff --git a/spec/services/mute_service_spec.rb b/spec/services/mute_service_spec.rb deleted file mode 100644 index 50f74ff27..000000000 --- a/spec/services/mute_service_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe MuteService, type: :service do - subject { described_class.new.call(account, target_account) } - - let(:account) { Fabricate(:account) } - let(:target_account) { Fabricate(:account) } - - describe 'home timeline' do - let(:status) { Fabricate(:status, account: target_account) } - let(:other_account_status) { Fabricate(:status) } - let(:home_timeline_key) { FeedManager.instance.key(:home, account.id) } - - before do - redis.del(home_timeline_key) - end - - it "clears account's statuses" do - FeedManager.instance.push_to_home(account, status) - FeedManager.instance.push_to_home(account, other_account_status) - - expect { subject }.to change { - redis.zrange(home_timeline_key, 0, -1) - }.from([status.id.to_s, other_account_status.id.to_s]).to([other_account_status.id.to_s]) - end - end - - it 'mutes account' do - expect { subject }.to change { - account.muting?(target_account) - }.from(false).to(true) - end - - context 'without specifying a notifications parameter' do - it 'mutes notifications from the account' do - expect { subject }.to change { - account.muting_notifications?(target_account) - }.from(false).to(true) - end - end - - context 'with a true notifications parameter' do - subject { described_class.new.call(account, target_account, notifications: true) } - - it 'mutes notifications from the account' do - expect { subject }.to change { - account.muting_notifications?(target_account) - }.from(false).to(true) - end - end - - context 'with a false notifications parameter' do - subject { described_class.new.call(account, target_account, notifications: false) } - - it 'does not mute notifications from the account' do - expect { subject }.to_not change { - account.muting_notifications?(target_account) - }.from(false) - end - end -end diff --git a/spec/services/notify_service_spec.rb b/spec/services/notify_service_spec.rb deleted file mode 100644 index 8fcb58658..000000000 --- a/spec/services/notify_service_spec.rb +++ /dev/null @@ -1,179 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe NotifyService, type: :service do - subject { described_class.new.call(recipient, type, activity) } - - let(:user) { Fabricate(:user) } - let(:recipient) { user.account } - let(:sender) { Fabricate(:account, domain: 'example.com') } - let(:activity) { Fabricate(:follow, account: sender, target_account: recipient) } - let(:type) { :follow } - - it { expect { subject }.to change(Notification, :count).by(1) } - - it 'does not notify when sender is blocked' do - recipient.block!(sender) - expect { subject }.to_not change(Notification, :count) - end - - it 'does not notify when sender is muted with hide_notifications' do - recipient.mute!(sender, notifications: true) - expect { subject }.to_not change(Notification, :count) - end - - it 'does notify when sender is muted without hide_notifications' do - recipient.mute!(sender, notifications: false) - expect { subject }.to change(Notification, :count) - end - - it 'does not notify when sender\'s domain is blocked' do - recipient.block_domain!(sender.domain) - expect { subject }.to_not change(Notification, :count) - end - - it 'does still notify when sender\'s domain is blocked but sender is followed' do - recipient.block_domain!(sender.domain) - recipient.follow!(sender) - expect { subject }.to change(Notification, :count) - end - - it 'does not notify when sender is silenced and not followed' do - sender.silence! - expect { subject }.to_not change(Notification, :count) - end - - it 'does not notify when recipient is suspended' do - recipient.suspend! - expect { subject }.to_not change(Notification, :count) - end - - context 'with direct messages' do - let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct)) } - let(:type) { :mention } - - before do - user.settings.update('interactions.must_be_following_dm': enabled) - user.save - end - - context 'when recipient is supposed to be following sender' do - let(:enabled) { true } - - it 'does not notify' do - expect { subject }.to_not change(Notification, :count) - end - - context 'when the message chain is initiated by recipient, but is not direct message' do - let(:reply_to) { Fabricate(:status, account: recipient) } - let!(:mention) { Fabricate(:mention, account: sender, status: reply_to) } - let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct, thread: reply_to)) } - - it 'does not notify' do - expect { subject }.to_not change(Notification, :count) - end - end - - context 'when the message chain is initiated by recipient, but without a mention to the sender, even if the sender sends multiple messages in a row' do - let(:reply_to) { Fabricate(:status, account: recipient) } - let!(:mention) { Fabricate(:mention, account: sender, status: reply_to) } - let(:dummy_reply) { Fabricate(:status, account: sender, visibility: :direct, thread: reply_to) } - let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct, thread: dummy_reply)) } - - it 'does not notify' do - expect { subject }.to_not change(Notification, :count) - end - end - - context 'when the message chain is initiated by the recipient with a mention to the sender' do - let(:reply_to) { Fabricate(:status, account: recipient, visibility: :direct) } - let!(:mention) { Fabricate(:mention, account: sender, status: reply_to) } - let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct, thread: reply_to)) } - - it 'does notify' do - expect { subject }.to change(Notification, :count) - end - end - end - - context 'when recipient is NOT supposed to be following sender' do - let(:enabled) { false } - - it 'does notify' do - expect { subject }.to change(Notification, :count) - end - end - end - - describe 'reblogs' do - let(:status) { Fabricate(:status, account: Fabricate(:account)) } - let(:activity) { Fabricate(:status, account: sender, reblog: status) } - let(:type) { :reblog } - - it 'shows reblogs by default' do - recipient.follow!(sender) - expect { subject }.to change(Notification, :count) - end - - it 'shows reblogs when explicitly enabled' do - recipient.follow!(sender, reblogs: true) - expect { subject }.to change(Notification, :count) - end - - it 'shows reblogs when disabled' do - recipient.follow!(sender, reblogs: false) - expect { subject }.to change(Notification, :count) - end - end - - context 'with muted and blocked users' do - let(:asshole) { Fabricate(:account, username: 'asshole') } - let(:reply_to) { Fabricate(:status, account: asshole) } - let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, thread: reply_to)) } - let(:type) { :mention } - - it 'does not notify when conversation is muted' do - recipient.mute_conversation!(activity.status.conversation) - expect { subject }.to_not change(Notification, :count) - end - - it 'does not notify when it is a reply to a blocked user' do - recipient.block!(asshole) - expect { subject }.to_not change(Notification, :count) - end - end - - context 'with sender as recipient' do - let(:sender) { recipient } - - it 'does not notify when recipient is the sender' do - expect { subject }.to_not change(Notification, :count) - end - end - - describe 'email' do - before do - ActionMailer::Base.deliveries.clear - - user.settings.update('notification_emails.follow': enabled) - user.save - end - - context 'when email notification is enabled' do - let(:enabled) { true } - - it 'sends email' do - expect { subject }.to change(ActionMailer::Base.deliveries, :count).by(1) - end - end - - context 'when email notification is disabled' do - let(:enabled) { false } - - it "doesn't send email" do - expect { subject }.to_not change(ActionMailer::Base.deliveries, :count).from(0) - end - end - end -end diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb deleted file mode 100644 index 7d7679c88..000000000 --- a/spec/services/post_status_service_spec.rb +++ /dev/null @@ -1,277 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe PostStatusService, type: :service do - subject { described_class.new } - - it 'creates a new status' do - account = Fabricate(:account) - text = 'test status update' - - status = subject.call(account, text: text) - - expect(status).to be_persisted - expect(status.text).to eq text - end - - it 'creates a new response status' do - in_reply_to_status = Fabricate(:status) - account = Fabricate(:account) - text = 'test status update' - - status = subject.call(account, text: text, thread: in_reply_to_status) - - expect(status).to be_persisted - expect(status.text).to eq text - expect(status.thread).to eq in_reply_to_status - end - - context 'when scheduling a status' do - let!(:account) { Fabricate(:account) } - let!(:future) { Time.now.utc + 2.hours } - let!(:previous_status) { Fabricate(:status, account: account) } - - it 'schedules a status' do - status = subject.call(account, text: 'Hi future!', scheduled_at: future) - expect(status).to be_a ScheduledStatus - expect(status.scheduled_at).to eq future - expect(status.params['text']).to eq 'Hi future!' - end - - it 'does not immediately create a status' do - media = Fabricate(:media_attachment, account: account) - status = subject.call(account, text: 'Hi future!', media_ids: [media.id], scheduled_at: future) - - expect(status).to be_a ScheduledStatus - expect(status.scheduled_at).to eq future - expect(status.params['text']).to eq 'Hi future!' - expect(status.params['media_ids']).to eq [media.id] - expect(media.reload.status).to be_nil - expect(Status.where(text: 'Hi future!')).to_not exist - end - - it 'does not change statuses count' do - expect { subject.call(account, text: 'Hi future!', scheduled_at: future, thread: previous_status) }.to_not(change { [account.statuses_count, previous_status.replies_count] }) - end - end - - it 'creates response to the original status of boost' do - boosted_status = Fabricate(:status) - in_reply_to_status = Fabricate(:status, reblog: boosted_status) - account = Fabricate(:account) - text = 'test status update' - - status = subject.call(account, text: text, thread: in_reply_to_status) - - expect(status).to be_persisted - expect(status.text).to eq text - expect(status.thread).to eq boosted_status - end - - it 'creates a sensitive status' do - status = create_status_with_options(sensitive: true) - - expect(status).to be_persisted - expect(status).to be_sensitive - end - - it 'creates a status with spoiler text' do - spoiler_text = 'spoiler text' - - status = create_status_with_options(spoiler_text: spoiler_text) - - expect(status).to be_persisted - expect(status.spoiler_text).to eq spoiler_text - end - - it 'creates a sensitive status when there is a CW but no text' do - status = subject.call(Fabricate(:account), text: '', spoiler_text: 'foo') - - expect(status).to be_persisted - expect(status).to be_sensitive - end - - it 'creates a status with empty default spoiler text' do - status = create_status_with_options(spoiler_text: nil) - - expect(status).to be_persisted - expect(status.spoiler_text).to eq '' - end - - it 'creates a status with the given visibility' do - status = create_status_with_options(visibility: :private) - - expect(status).to be_persisted - expect(status.visibility).to eq 'private' - end - - it 'creates a status with limited visibility for silenced users' do - status = subject.call(Fabricate(:account, silenced: true), text: 'test', visibility: :public) - - expect(status).to be_persisted - expect(status.visibility).to eq 'unlisted' - end - - it 'creates a status for the given application' do - application = Fabricate(:application) - - status = create_status_with_options(application: application) - - expect(status).to be_persisted - expect(status.application).to eq application - end - - it 'creates a status with a language set' do - account = Fabricate(:account) - text = 'This is an English text.' - - status = subject.call(account, text: text) - - expect(status.language).to eq 'en' - end - - it 'processes mentions' do - mention_service = instance_double(ProcessMentionsService) - allow(mention_service).to receive(:call) - allow(ProcessMentionsService).to receive(:new).and_return(mention_service) - account = Fabricate(:account) - - status = subject.call(account, text: 'test status update') - - expect(ProcessMentionsService).to have_received(:new) - expect(mention_service).to have_received(:call).with(status, save_records: false) - end - - it 'safeguards mentions' do - account = Fabricate(:account) - mentioned_account = Fabricate(:account, username: 'alice') - unexpected_mentioned_account = Fabricate(:account, username: 'bob') - - expect do - subject.call(account, text: '@alice hm, @bob is really annoying lately', allowed_mentions: [mentioned_account.id]) - end.to raise_error(an_instance_of(PostStatusService::UnexpectedMentionsError).and(having_attributes(accounts: [unexpected_mentioned_account]))) - end - - it 'processes duplicate mentions correctly' do - account = Fabricate(:account) - mentioned_account = Fabricate(:account, username: 'alice') - - expect do - subject.call(account, text: '@alice @alice @alice hey @alice') - end.to_not raise_error - end - - it 'processes hashtags' do - hashtags_service = instance_double(ProcessHashtagsService) - allow(hashtags_service).to receive(:call) - allow(ProcessHashtagsService).to receive(:new).and_return(hashtags_service) - account = Fabricate(:account) - - status = subject.call(account, text: 'test status update') - - expect(ProcessHashtagsService).to have_received(:new) - expect(hashtags_service).to have_received(:call).with(status) - end - - it 'gets distributed' do - allow(DistributionWorker).to receive(:perform_async) - allow(ActivityPub::DistributionWorker).to receive(:perform_async) - - account = Fabricate(:account) - - status = subject.call(account, text: 'test status update') - - expect(DistributionWorker).to have_received(:perform_async).with(status.id) - expect(ActivityPub::DistributionWorker).to have_received(:perform_async).with(status.id) - end - - it 'crawls links' do - allow(LinkCrawlWorker).to receive(:perform_async) - account = Fabricate(:account) - - status = subject.call(account, text: 'test status update') - - expect(LinkCrawlWorker).to have_received(:perform_async).with(status.id) - end - - it 'attaches the given media to the created status' do - account = Fabricate(:account) - media = Fabricate(:media_attachment, account: account) - - status = subject.call( - account, - text: 'test status update', - media_ids: [media.id] - ) - - expect(media.reload.status).to eq status - end - - it 'does not attach media from another account to the created status' do - account = Fabricate(:account) - media = Fabricate(:media_attachment, account: Fabricate(:account)) - - status = subject.call( - account, - text: 'test status update', - media_ids: [media.id] - ) - - expect(media.reload.status).to be_nil - end - - it 'does not allow attaching more than 4 files' do - account = Fabricate(:account) - - expect do - subject.call( - account, - text: 'test status update', - media_ids: [ - Fabricate(:media_attachment, account: account), - Fabricate(:media_attachment, account: account), - Fabricate(:media_attachment, account: account), - Fabricate(:media_attachment, account: account), - Fabricate(:media_attachment, account: account), - ].map(&:id) - ) - end.to raise_error( - Mastodon::ValidationError, - I18n.t('media_attachments.validations.too_many') - ) - end - - it 'does not allow attaching both videos and images' do - account = Fabricate(:account) - video = Fabricate(:media_attachment, type: :video, account: account) - image = Fabricate(:media_attachment, type: :image, account: account) - - video.update(type: :video) - - expect do - subject.call( - account, - text: 'test status update', - media_ids: [ - video, - image, - ].map(&:id) - ) - end.to raise_error( - Mastodon::ValidationError, - I18n.t('media_attachments.validations.images_and_video') - ) - end - - it 'returns existing status when used twice with idempotency key' do - account = Fabricate(:account) - status1 = subject.call(account, text: 'test', idempotency: 'meepmeep') - status2 = subject.call(account, text: 'test', idempotency: 'meepmeep') - expect(status2.id).to eq status1.id - end - - def create_status_with_options(**options) - subject.call(Fabricate(:account), options.merge(text: 'test')) - end -end diff --git a/spec/services/precompute_feed_service_spec.rb b/spec/services/precompute_feed_service_spec.rb deleted file mode 100644 index 54e0d94ee..000000000 --- a/spec/services/precompute_feed_service_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe PrecomputeFeedService, type: :service do - subject { described_class.new } - - describe 'call' do - let(:account) { Fabricate(:account) } - - it 'fills a user timeline with statuses' do - account = Fabricate(:account) - status = Fabricate(:status, account: account) - - subject.call(account) - - expect(redis.zscore(FeedManager.instance.key(:home, account.id), status.id)).to be_within(0.1).of(status.id.to_f) - end - - it 'does not raise an error even if it could not find any status' do - account = Fabricate(:account) - expect { subject.call(account) }.to_not raise_error - end - - it 'filters statuses' do - account = Fabricate(:account) - muted_account = Fabricate(:account) - Fabricate(:mute, account: account, target_account: muted_account) - reblog = Fabricate(:status, account: muted_account) - status = Fabricate(:status, account: account, reblog: reblog) - - subject.call(account) - - expect(redis.zscore(FeedManager.instance.key(:home, account.id), reblog.id)).to be_nil - end - end -end diff --git a/spec/services/process_mentions_service_spec.rb b/spec/services/process_mentions_service_spec.rb deleted file mode 100644 index 0db73c41f..000000000 --- a/spec/services/process_mentions_service_spec.rb +++ /dev/null @@ -1,106 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ProcessMentionsService, type: :service do - subject { described_class.new } - - let(:account) { Fabricate(:account, username: 'alice') } - - context 'when mentions contain blocked accounts' do - let(:non_blocked_account) { Fabricate(:account) } - let(:individually_blocked_account) { Fabricate(:account) } - let(:domain_blocked_account) { Fabricate(:account, domain: 'evil.com') } - let(:status) { Fabricate(:status, account: account, text: "Hello @#{non_blocked_account.acct} @#{individually_blocked_account.acct} @#{domain_blocked_account.acct}", visibility: :public) } - - before do - account.block!(individually_blocked_account) - account.domain_blocks.create!(domain: domain_blocked_account.domain) - - subject.call(status) - end - - it 'creates a mention to the non-blocked account' do - expect(non_blocked_account.mentions.where(status: status).count).to eq 1 - end - - it 'does not create a mention to the individually blocked account' do - expect(individually_blocked_account.mentions.where(status: status).count).to eq 0 - end - - it 'does not create a mention to the domain-blocked account' do - expect(domain_blocked_account.mentions.where(status: status).count).to eq 0 - end - end - - context 'with resolving a mention to a remote account' do - let(:status) { Fabricate(:status, account: account, text: "Hello @#{remote_user.acct}", visibility: :public) } - - context 'with ActivityPub' do - context 'with a valid remote user' do - let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } - - before do - subject.call(status) - end - - it 'creates a mention' do - expect(remote_user.mentions.where(status: status).count).to eq 1 - end - end - - context 'when mentioning a user several times when not saving records' do - let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } - let(:status) { Fabricate(:status, account: account, text: "Hello @#{remote_user.acct} @#{remote_user.acct} @#{remote_user.acct}", visibility: :public) } - - before do - subject.call(status, save_records: false) - end - - it 'creates exactly one mention' do - expect(status.mentions.size).to eq 1 - end - end - - context 'with an IDN domain' do - let!(:remote_user) { Fabricate(:account, username: 'sneak', protocol: :activitypub, domain: 'xn--hresiar-mxa.ch', inbox_url: 'http://example.com/inbox') } - let!(:status) { Fabricate(:status, account: account, text: 'Hello @sneak@hæresiar.ch') } - - before do - subject.call(status) - end - - it 'creates a mention' do - expect(remote_user.mentions.where(status: status).count).to eq 1 - end - end - - context 'with an IDN TLD' do - let!(:remote_user) { Fabricate(:account, username: 'foo', protocol: :activitypub, domain: 'xn--y9a3aq.xn--y9a3aq', inbox_url: 'http://example.com/inbox') } - let!(:status) { Fabricate(:status, account: account, text: 'Hello @foo@հայ.հայ') } - - before do - subject.call(status) - end - - it 'creates a mention' do - expect(remote_user.mentions.where(status: status).count).to eq 1 - end - end - end - - context 'with a Temporarily-unreachable ActivityPub user' do - let!(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox', last_webfingered_at: nil) } - - before do - stub_request(:get, 'https://example.com/.well-known/host-meta').to_return(status: 404) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:remote_user@example.com').to_return(status: 500) - subject.call(status) - end - - it 'creates a mention' do - expect(remote_user.mentions.where(status: status).count).to eq 1 - end - end - end -end diff --git a/spec/services/purge_domain_service_spec.rb b/spec/services/purge_domain_service_spec.rb deleted file mode 100644 index e96618310..000000000 --- a/spec/services/purge_domain_service_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe PurgeDomainService, type: :service do - subject { described_class.new } - - let!(:old_account) { Fabricate(:account, domain: 'obsolete.org') } - let!(:old_status_plain) { Fabricate(:status, account: old_account) } - let!(:old_status_with_attachment) { Fabricate(:status, account: old_account) } - let!(:old_attachment) { Fabricate(:media_attachment, account: old_account, status: old_status_with_attachment, file: attachment_fixture('attachment.jpg')) } - - describe 'for a suspension' do - before do - subject.call('obsolete.org') - end - - it 'removes the remote accounts\'s statuses and media attachments' do - expect { old_account.reload }.to raise_exception ActiveRecord::RecordNotFound - expect { old_status_plain.reload }.to raise_exception ActiveRecord::RecordNotFound - expect { old_status_with_attachment.reload }.to raise_exception ActiveRecord::RecordNotFound - expect { old_attachment.reload }.to raise_exception ActiveRecord::RecordNotFound - end - - it 'refreshes instances view' do - expect(Instance.where(domain: 'obsolete.org').exists?).to be false - end - end -end diff --git a/spec/services/reblog_service_spec.rb b/spec/services/reblog_service_spec.rb deleted file mode 100644 index 7b85e37ed..000000000 --- a/spec/services/reblog_service_spec.rb +++ /dev/null @@ -1,94 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ReblogService, type: :service do - let(:alice) { Fabricate(:account, username: 'alice') } - - context 'when creates a reblog with appropriate visibility' do - subject { described_class.new } - - let(:visibility) { :public } - let(:reblog_visibility) { :public } - let(:status) { Fabricate(:status, account: alice, visibility: visibility) } - - before do - subject.call(alice, status, visibility: reblog_visibility) - end - - describe 'boosting privately' do - let(:reblog_visibility) { :private } - - it 'reblogs privately' do - expect(status.reblogs.first.visibility).to eq 'private' - end - end - - describe 'public reblogs of private toots should remain private' do - let(:visibility) { :private } - let(:reblog_visibility) { :public } - - it 'reblogs privately' do - expect(status.reblogs.first.visibility).to eq 'private' - end - end - end - - context 'when the reblogged status is discarded in the meantime' do - let(:status) { Fabricate(:status, account: alice, visibility: :public, text: 'discard-status-text') } - - # Add a callback to discard the status being reblogged after the - # validations pass but before the database commit is executed. - before do - Status.class_eval do - before_save :discard_status - def discard_status - Status - .where(id: reblog_of_id) - .where(text: 'discard-status-text') - .update_all(deleted_at: Time.now.utc) # rubocop:disable Rails/SkipsModelValidations - end - end - end - - # Remove race condition simulating `discard_status` callback. - after do - Status._save_callbacks.delete(:discard_status) - end - - it 'raises an exception' do - expect { subject.call(alice, status) }.to raise_error ActiveRecord::ActiveRecordError - end - end - - context 'with ActivityPub' do - subject { described_class.new } - - let(:bob) { Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } - let(:status) { Fabricate(:status, account: bob) } - - before do - stub_request(:post, bob.inbox_url) - allow(ActivityPub::DistributionWorker).to receive(:perform_async) - subject.call(alice, status) - end - - it 'creates a reblog' do - expect(status.reblogs.count).to eq 1 - end - - describe 'after_create_commit :store_uri' do - it 'keeps consistent reblog count' do - expect(status.reblogs.count).to eq 1 - end - end - - it 'distributes to followers' do - expect(ActivityPub::DistributionWorker).to have_received(:perform_async) - end - - it 'sends an announce activity to the author' do - expect(a_request(:post, bob.inbox_url)).to have_been_made.once - end - end -end diff --git a/spec/services/reject_follow_service_spec.rb b/spec/services/reject_follow_service_spec.rb deleted file mode 100644 index d28104b2c..000000000 --- a/spec/services/reject_follow_service_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe RejectFollowService, type: :service do - subject { described_class.new } - - let(:sender) { Fabricate(:account, username: 'alice') } - - describe 'local' do - let(:bob) { Fabricate(:account) } - - before do - FollowRequest.create(account: bob, target_account: sender) - subject.call(bob, sender) - end - - it 'removes follow request' do - expect(bob.requested?(sender)).to be false - end - - it 'does not create follow relation' do - expect(bob.following?(sender)).to be false - end - end - - describe 'remote ActivityPub' do - let(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') } - - before do - FollowRequest.create(account: bob, target_account: sender) - stub_request(:post, bob.inbox_url).to_return(status: 200) - subject.call(bob, sender) - end - - it 'removes follow request' do - expect(bob.requested?(sender)).to be false - end - - it 'does not create follow relation' do - expect(bob.following?(sender)).to be false - end - - it 'sends a reject activity' do - expect(a_request(:post, bob.inbox_url)).to have_been_made.once - end - end -end diff --git a/spec/services/remove_from_followers_service_spec.rb b/spec/services/remove_from_followers_service_spec.rb deleted file mode 100644 index 1b29cdcbe..000000000 --- a/spec/services/remove_from_followers_service_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe RemoveFromFollowersService, type: :service do - subject { described_class.new } - - let(:bob) { Fabricate(:account, username: 'bob') } - - describe 'local' do - let(:sender) { Fabricate(:account, username: 'alice') } - - before do - Follow.create(account: sender, target_account: bob) - subject.call(bob, sender) - end - - it 'does not create follow relation' do - expect(bob.followed_by?(sender)).to be false - end - end - - describe 'remote ActivityPub' do - let(:sender) { Fabricate(:account, username: 'alice', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') } - - before do - Follow.create(account: sender, target_account: bob) - stub_request(:post, sender.inbox_url).to_return(status: 200) - subject.call(bob, sender) - end - - it 'does not create follow relation' do - expect(bob.followed_by?(sender)).to be false - end - - it 'sends a reject activity' do - expect(a_request(:post, sender.inbox_url)).to have_been_made.once - end - end -end diff --git a/spec/services/remove_status_service_spec.rb b/spec/services/remove_status_service_spec.rb deleted file mode 100644 index c19b4fac1..000000000 --- a/spec/services/remove_status_service_spec.rb +++ /dev/null @@ -1,113 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe RemoveStatusService, type: :service do - subject { described_class.new } - - let!(:alice) { Fabricate(:account) } - let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example.com') } - let!(:jeff) { Fabricate(:account) } - let!(:hank) { Fabricate(:account, username: 'hank', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } - let!(:bill) { Fabricate(:account, username: 'bill', protocol: :activitypub, domain: 'example2.com', inbox_url: 'http://example2.com/inbox') } - - before do - stub_request(:post, 'http://example.com/inbox').to_return(status: 200) - stub_request(:post, 'http://example2.com/inbox').to_return(status: 200) - - jeff.follow!(alice) - hank.follow!(alice) - end - - context 'when removed status is not a reblog' do - before do - @status = PostStatusService.new.call(alice, text: 'Hello @bob@example.com ThisIsASecret') - FavouriteService.new.call(jeff, @status) - Fabricate(:status, account: bill, reblog: @status, uri: 'hoge') - end - - it 'removes status from author\'s home feed' do - subject.call(@status) - expect(HomeFeed.new(alice).get(10).pluck(:id)).to_not include(@status.id) - end - - it 'removes status from local follower\'s home feed' do - subject.call(@status) - expect(HomeFeed.new(jeff).get(10).pluck(:id)).to_not include(@status.id) - end - - it 'sends Delete activity to followers' do - subject.call(@status) - expect(a_request(:post, 'http://example.com/inbox').with( - body: hash_including({ - 'type' => 'Delete', - 'object' => { - 'type' => 'Tombstone', - 'id' => ActivityPub::TagManager.instance.uri_for(@status), - 'atomUri' => OStatus::TagManager.instance.uri_for(@status), - }, - }) - )).to have_been_made.once - end - - it 'sends Delete activity to rebloggers' do - subject.call(@status) - expect(a_request(:post, 'http://example2.com/inbox').with( - body: hash_including({ - 'type' => 'Delete', - 'object' => { - 'type' => 'Tombstone', - 'id' => ActivityPub::TagManager.instance.uri_for(@status), - 'atomUri' => OStatus::TagManager.instance.uri_for(@status), - }, - }) - )).to have_been_made.once - end - - it 'remove status from notifications' do - expect { subject.call(@status) }.to change { - Notification.where(activity_type: 'Favourite', from_account: jeff, account: alice).count - }.from(1).to(0) - end - end - - context 'when removed status is a private self-reblog' do - before do - @original_status = Fabricate(:status, account: alice, text: 'Hello ThisIsASecret', visibility: :private) - @status = ReblogService.new.call(alice, @original_status) - end - - it 'sends Undo activity to followers' do - subject.call(@status) - expect(a_request(:post, 'http://example.com/inbox').with( - body: hash_including({ - 'type' => 'Undo', - 'object' => hash_including({ - 'type' => 'Announce', - 'object' => ActivityPub::TagManager.instance.uri_for(@original_status), - }), - }) - )).to have_been_made.once - end - end - - context 'when removed status is public self-reblog' do - before do - @original_status = Fabricate(:status, account: alice, text: 'Hello ThisIsASecret', visibility: :public) - @status = ReblogService.new.call(alice, @original_status) - end - - it 'sends Undo activity to followers' do - subject.call(@status) - expect(a_request(:post, 'http://example.com/inbox').with( - body: hash_including({ - 'type' => 'Undo', - 'object' => hash_including({ - 'type' => 'Announce', - 'object' => ActivityPub::TagManager.instance.uri_for(@original_status), - }), - }) - )).to have_been_made.once - end - end -end diff --git a/spec/services/report_service_spec.rb b/spec/services/report_service_spec.rb deleted file mode 100644 index d3bcd5d31..000000000 --- a/spec/services/report_service_spec.rb +++ /dev/null @@ -1,171 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ReportService, type: :service do - subject { described_class.new } - - let(:source_account) { Fabricate(:account) } - let(:target_account) { Fabricate(:account) } - - context 'with a local account' do - it 'has a uri' do - report = subject.call(source_account, target_account) - expect(report.uri).to_not be_nil - end - end - - context 'with a remote account' do - let(:remote_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') } - let(:forward) { false } - - before do - stub_request(:post, 'http://example.com/inbox').to_return(status: 200) - end - - context 'when forward is true' do - let(:forward) { true } - - it 'sends ActivityPub payload when forward is true' do - subject.call(source_account, remote_account, forward: forward) - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made - end - - it 'has an uri' do - report = subject.call(source_account, remote_account, forward: forward) - expect(report.uri).to_not be_nil - end - - context 'when reporting a reply on a different remote server' do - let(:remote_thread_account) { Fabricate(:account, domain: 'foo.com', protocol: :activitypub, inbox_url: 'http://foo.com/inbox') } - let(:reported_status) { Fabricate(:status, account: remote_account, thread: Fabricate(:status, account: remote_thread_account)) } - - before do - stub_request(:post, 'http://foo.com/inbox').to_return(status: 200) - end - - context 'when forward_to_domains includes both the replied-to domain and the origin domain' do - it 'sends ActivityPub payload to both the author of the replied-to post and the reported user' do - subject.call(source_account, remote_account, status_ids: [reported_status.id], forward: forward, forward_to_domains: [remote_account.domain, remote_thread_account.domain]) - expect(a_request(:post, 'http://foo.com/inbox')).to have_been_made - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made - end - end - - context 'when forward_to_domains includes only the replied-to domain' do - it 'sends ActivityPub payload only to the author of the replied-to post' do - subject.call(source_account, remote_account, status_ids: [reported_status.id], forward: forward, forward_to_domains: [remote_thread_account.domain]) - expect(a_request(:post, 'http://foo.com/inbox')).to have_been_made - expect(a_request(:post, 'http://example.com/inbox')).to_not have_been_made - end - end - - context 'when forward_to_domains does not include the replied-to domain' do - it 'does not send ActivityPub payload to the author of the replied-to post' do - subject.call(source_account, remote_account, status_ids: [reported_status.id], forward: forward) - expect(a_request(:post, 'http://foo.com/inbox')).to_not have_been_made - end - end - end - - context 'when reporting a reply on the same remote server as the person being replied-to' do - let(:remote_thread_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox') } - let(:reported_status) { Fabricate(:status, account: remote_account, thread: Fabricate(:status, account: remote_thread_account)) } - - context 'when forward_to_domains includes both the replied-to domain and the origin domain' do - it 'sends ActivityPub payload only once' do - subject.call(source_account, remote_account, status_ids: [reported_status.id], forward: forward, forward_to_domains: [remote_account.domain]) - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once - end - end - - context 'when forward_to_domains does not include the replied-to domain' do - it 'sends ActivityPub payload only once' do - subject.call(source_account, remote_account, status_ids: [reported_status.id], forward: forward) - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once - end - end - end - end - - context 'when forward is false' do - it 'does not send anything' do - subject.call(source_account, remote_account, forward: forward) - expect(a_request(:post, 'http://example.com/inbox')).to_not have_been_made - end - end - end - - context 'when the reported status is a DM' do - subject do - -> { described_class.new.call(source_account, target_account, status_ids: [status.id]) } - end - - let(:status) { Fabricate(:status, account: target_account, visibility: :direct) } - - context 'when it is addressed to the reporter' do - before do - status.mentions.create(account: source_account) - end - - it 'creates a report' do - expect { subject.call }.to change { target_account.targeted_reports.count }.from(0).to(1) - end - - it 'attaches the DM to the report' do - subject.call - expect(target_account.targeted_reports.pluck(:status_ids)).to eq [[status.id]] - end - end - - context 'when it is not addressed to the reporter' do - it 'errors out' do - expect { subject.call }.to raise_error(ActiveRecord::RecordNotFound) - end - end - - context 'when the reporter is remote' do - let(:source_account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/users/1') } - - context 'when it is addressed to the reporter' do - before do - status.mentions.create(account: source_account) - end - - it 'creates a report' do - expect { subject.call }.to change { target_account.targeted_reports.count }.from(0).to(1) - end - - it 'attaches the DM to the report' do - subject.call - expect(target_account.targeted_reports.pluck(:status_ids)).to eq [[status.id]] - end - end - - context 'when it is not addressed to the reporter' do - it 'does not add the DM to the report' do - subject.call - expect(target_account.targeted_reports.pluck(:status_ids)).to eq [[]] - end - end - end - end - - context 'when other reports already exist for the same target' do - subject do - -> { described_class.new.call(source_account, target_account) } - end - - let!(:other_report) { Fabricate(:report, target_account: target_account) } - - before do - ActionMailer::Base.deliveries.clear - source_account.user.settings['notification_emails.report'] = true - source_account.user.save - end - - it 'does not send an e-mail' do - expect { subject.call }.to_not change(ActionMailer::Base.deliveries, :count).from(0) - end - end -end diff --git a/spec/services/resolve_account_service_spec.rb b/spec/services/resolve_account_service_spec.rb deleted file mode 100644 index f446d0ca6..000000000 --- a/spec/services/resolve_account_service_spec.rb +++ /dev/null @@ -1,232 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe ResolveAccountService, type: :service do - subject { described_class.new } - - before do - stub_request(:get, 'https://example.com/.well-known/host-meta').to_return(status: 404) - stub_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png').to_return(request_fixture('avatar.txt')) - stub_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com').to_return(request_fixture('activitypub-webfinger.txt')) - stub_request(:get, 'https://ap.example.com/users/foo').to_return(request_fixture('activitypub-actor.txt')) - stub_request(:get, 'https://ap.example.com/users/foo.atom').to_return(request_fixture('activitypub-feed.txt')) - stub_request(:get, %r{https://ap\.example\.com/users/foo/\w+}).to_return(status: 404) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:hoge@example.com').to_return(status: 410) - end - - context 'when using skip_webfinger' do - context 'when account is known' do - let!(:remote_account) { Fabricate(:account, username: 'foo', domain: 'ap.example.com', protocol: 'activitypub') } - - context 'when domain is banned' do - let!(:domain_block) { Fabricate(:domain_block, domain: 'ap.example.com', severity: :suspend) } - - it 'does not return an account' do - expect(subject.call('foo@ap.example.com', skip_webfinger: true)).to be_nil - end - - it 'does not make a webfinger query' do - subject.call('foo@ap.example.com', skip_webfinger: true) - expect(a_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com')).to_not have_been_made - end - end - - context 'when domain is not banned' do - it 'returns the expected account' do - expect(subject.call('foo@ap.example.com', skip_webfinger: true)).to eq remote_account - end - - it 'does not make a webfinger query' do - subject.call('foo@ap.example.com', skip_webfinger: true) - expect(a_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com')).to_not have_been_made - end - end - end - - context 'when account is not known' do - it 'does not return an account' do - expect(subject.call('foo@ap.example.com', skip_webfinger: true)).to be_nil - end - - it 'does not make a webfinger query' do - subject.call('foo@ap.example.com', skip_webfinger: true) - expect(a_request(:get, 'https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com')).to_not have_been_made - end - end - end - - context 'when there is an LRDD endpoint but no resolvable account' do - before do - stub_request(:get, 'https://quitter.no/.well-known/host-meta').to_return(request_fixture('.host-meta.txt')) - stub_request(:get, 'https://quitter.no/.well-known/webfinger?resource=acct:catsrgr8@quitter.no').to_return(status: 404) - end - - it 'returns nil' do - expect(subject.call('catsrgr8@quitter.no')).to be_nil - end - end - - context 'when there is no LRDD endpoint nor resolvable account' do - before do - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:catsrgr8@example.com').to_return(status: 404) - end - - it 'returns nil' do - expect(subject.call('catsrgr8@example.com')).to be_nil - end - end - - context 'when webfinger returns http gone' do - context 'with a previously known account' do - before do - Fabricate(:account, username: 'hoge', domain: 'example.com', last_webfingered_at: nil) - allow(AccountDeletionWorker).to receive(:perform_async) - end - - it 'returns nil' do - expect(subject.call('hoge@example.com')).to be_nil - end - - it 'queues account deletion worker' do - subject.call('hoge@example.com') - expect(AccountDeletionWorker).to have_received(:perform_async) - end - end - - context 'with a previously unknown account' do - it 'returns nil' do - expect(subject.call('hoge@example.com')).to be_nil - end - end - end - - context 'with a legitimate webfinger redirection' do - before do - webfinger = { subject: 'acct:foo@ap.example.com', links: [{ rel: 'self', href: 'https://ap.example.com/users/foo', type: 'application/activity+json' }] } - stub_request(:get, 'https://redirected.example.com/.well-known/webfinger?resource=acct:Foo@redirected.example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - it 'returns new remote account' do - account = subject.call('Foo@redirected.example.com') - - expect(account.activitypub?).to be true - expect(account.acct).to eq 'foo@ap.example.com' - expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' - end - end - - context 'with a misconfigured redirection' do - before do - webfinger = { subject: 'acct:Foo@redirected.example.com', links: [{ rel: 'self', href: 'https://ap.example.com/users/foo', type: 'application/activity+json' }] } - stub_request(:get, 'https://redirected.example.com/.well-known/webfinger?resource=acct:Foo@redirected.example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - it 'returns new remote account' do - account = subject.call('Foo@redirected.example.com') - - expect(account.activitypub?).to be true - expect(account.acct).to eq 'foo@ap.example.com' - expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' - end - end - - context 'with too many webfinger redirections' do - before do - webfinger = { subject: 'acct:foo@evil.example.com', links: [{ rel: 'self', href: 'https://ap.example.com/users/foo', type: 'application/activity+json' }] } - stub_request(:get, 'https://redirected.example.com/.well-known/webfinger?resource=acct:Foo@redirected.example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - webfinger2 = { subject: 'acct:foo@ap.example.com', links: [{ rel: 'self', href: 'https://ap.example.com/users/foo', type: 'application/activity+json' }] } - stub_request(:get, 'https://evil.example.com/.well-known/webfinger?resource=acct:foo@evil.example.com').to_return(body: Oj.dump(webfinger2), headers: { 'Content-Type': 'application/jrd+json' }) - end - - it 'does not return a new remote account' do - expect(subject.call('Foo@redirected.example.com')).to be_nil - end - end - - context 'with an ActivityPub account' do - it 'returns new remote account' do - account = subject.call('foo@ap.example.com') - - expect(account.activitypub?).to be true - expect(account.domain).to eq 'ap.example.com' - expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' - end - - context 'with multiple types' do - before do - stub_request(:get, 'https://ap.example.com/users/foo').to_return(request_fixture('activitypub-actor-individual.txt')) - end - - it 'returns new remote account' do - account = subject.call('foo@ap.example.com') - - expect(account.activitypub?).to be true - expect(account.domain).to eq 'ap.example.com' - expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' - expect(account.actor_type).to eq 'Person' - end - end - end - - context 'with an already-known actor changing acct: URI' do - let!(:duplicate) { Fabricate(:account, username: 'foo', domain: 'old.example.com', uri: 'https://ap.example.com/users/foo') } - let!(:status) { Fabricate(:status, account: duplicate, text: 'foo') } - - it 'returns new remote account' do - account = subject.call('foo@ap.example.com') - - expect(account.activitypub?).to be true - expect(account.domain).to eq 'ap.example.com' - expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' - expect(account.uri).to eq 'https://ap.example.com/users/foo' - end - - it 'merges accounts' do - account = subject.call('foo@ap.example.com') - - expect(status.reload.account_id).to eq account.id - expect(Account.where(uri: account.uri).count).to eq 1 - end - end - - context 'with an already-known acct: URI changing ActivityPub id' do - let!(:old_account) { Fabricate(:account, username: 'foo', domain: 'ap.example.com', uri: 'https://old.example.com/users/foo', last_webfingered_at: nil) } - let!(:status) { Fabricate(:status, account: old_account, text: 'foo') } - - it 'returns new remote account' do - account = subject.call('foo@ap.example.com') - - expect(account.activitypub?).to be true - expect(account.domain).to eq 'ap.example.com' - expect(account.inbox_url).to eq 'https://ap.example.com/users/foo/inbox' - expect(account.uri).to eq 'https://ap.example.com/users/foo' - end - end - - it 'processes one remote account at a time using locks' do - wait_for_start = true - fail_occurred = false - return_values = Concurrent::Array.new - - threads = Array.new(5) do - Thread.new do - true while wait_for_start - - begin - return_values << described_class.new.call('foo@ap.example.com') - rescue ActiveRecord::RecordNotUnique - fail_occurred = true - ensure - RedisConfiguration.pool.checkin if Thread.current[:redis] - end - end - end - - wait_for_start = false - threads.each(&:join) - - expect(fail_occurred).to be false - expect(return_values).to_not include(nil) - end -end diff --git a/spec/services/resolve_url_service_spec.rb b/spec/services/resolve_url_service_spec.rb deleted file mode 100644 index 7991aa6ef..000000000 --- a/spec/services/resolve_url_service_spec.rb +++ /dev/null @@ -1,179 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ResolveURLService, type: :service do - subject { described_class.new } - - describe '#call' do - it 'returns nil when there is no resource url' do - url = 'http://example.com/missing-resource' - known_account = Fabricate(:account, uri: url, domain: 'example.com') - service = instance_double(FetchResourceService) - - allow(FetchResourceService).to receive(:new).and_return service - allow(service).to receive(:response_code).and_return(404) - allow(service).to receive(:call).with(url).and_return(nil) - - expect(subject.call(url)).to be_nil - end - - it 'returns known account on temporary error' do - url = 'http://example.com/missing-resource' - known_account = Fabricate(:account, uri: url, domain: 'example.com') - service = instance_double(FetchResourceService) - - allow(FetchResourceService).to receive(:new).and_return service - allow(service).to receive(:response_code).and_return(500) - allow(service).to receive(:call).with(url).and_return(nil) - - expect(subject.call(url)).to eq known_account - end - - context 'when searching for a remote private status' do - let(:account) { Fabricate(:account) } - let(:poster) { Fabricate(:account, domain: 'example.com') } - let(:url) { 'https://example.com/@foo/42' } - let(:uri) { 'https://example.com/users/foo/statuses/42' } - let!(:status) { Fabricate(:status, url: url, uri: uri, account: poster, visibility: :private) } - - before do - stub_request(:get, url).to_return(status: 404) if url.present? - stub_request(:get, uri).to_return(status: 404) - end - - context 'when the account follows the poster' do - before do - account.follow!(poster) - end - - context 'when the status uses Mastodon-style URLs' do - let(:url) { 'https://example.com/@foo/42' } - let(:uri) { 'https://example.com/users/foo/statuses/42' } - - it 'returns status by url' do - expect(subject.call(url, on_behalf_of: account)).to eq(status) - end - - it 'returns status by uri' do - expect(subject.call(uri, on_behalf_of: account)).to eq(status) - end - end - - context 'when the status uses pleroma-style URLs' do - let(:url) { nil } - let(:uri) { 'https://example.com/objects/0123-456-789-abc-def' } - - it 'returns status by uri' do - expect(subject.call(uri, on_behalf_of: account)).to eq(status) - end - end - end - - context 'when the account does not follow the poster' do - context 'when the status uses Mastodon-style URLs' do - let(:url) { 'https://example.com/@foo/42' } - let(:uri) { 'https://example.com/users/foo/statuses/42' } - - it 'does not return the status by url' do - expect(subject.call(url, on_behalf_of: account)).to be_nil - end - - it 'does not return the status by uri' do - expect(subject.call(uri, on_behalf_of: account)).to be_nil - end - end - - context 'when the status uses pleroma-style URLs' do - let(:url) { nil } - let(:uri) { 'https://example.com/objects/0123-456-789-abc-def' } - - it 'returns status by uri' do - expect(subject.call(uri, on_behalf_of: account)).to be_nil - end - end - end - end - - context 'when searching for a local private status' do - let(:account) { Fabricate(:account) } - let(:poster) { Fabricate(:account) } - let!(:status) { Fabricate(:status, account: poster, visibility: :private) } - let(:url) { ActivityPub::TagManager.instance.url_for(status) } - let(:uri) { ActivityPub::TagManager.instance.uri_for(status) } - - context 'when the account follows the poster' do - before do - account.follow!(poster) - end - - it 'returns status by url' do - expect(subject.call(url, on_behalf_of: account)).to eq(status) - end - - it 'returns status by uri' do - expect(subject.call(uri, on_behalf_of: account)).to eq(status) - end - end - - context 'when the account does not follow the poster' do - it 'does not return the status by url' do - expect(subject.call(url, on_behalf_of: account)).to be_nil - end - - it 'does not return the status by uri' do - expect(subject.call(uri, on_behalf_of: account)).to be_nil - end - end - end - - context 'when searching for a link that redirects to a local public status' do - let(:account) { Fabricate(:account) } - let(:poster) { Fabricate(:account) } - let!(:status) { Fabricate(:status, account: poster, visibility: :public) } - let(:url) { 'https://link.to/foobar' } - let(:status_url) { ActivityPub::TagManager.instance.url_for(status) } - let(:uri) { ActivityPub::TagManager.instance.uri_for(status) } - - before do - stub_request(:get, url).to_return(status: 302, headers: { 'Location' => status_url }) - body = ActiveModelSerializers::SerializableResource.new(status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter).to_json - stub_request(:get, status_url).to_return(body: body, headers: { 'Content-Type' => 'application/activity+json' }) - end - - it 'returns status by url' do - expect(subject.call(url, on_behalf_of: account)).to eq(status) - end - end - - context 'when searching for a local link of a remote private status' do - let(:account) { Fabricate(:account) } - let(:poster) { Fabricate(:account, username: 'foo', domain: 'example.com') } - let(:url) { 'https://example.com/@foo/42' } - let(:uri) { 'https://example.com/users/foo/statuses/42' } - let!(:status) { Fabricate(:status, url: url, uri: uri, account: poster, visibility: :private) } - let(:search_url) { "https://#{Rails.configuration.x.local_domain}/@foo@example.com/#{status.id}" } - - before do - stub_request(:get, url).to_return(status: 404) if url.present? - stub_request(:get, uri).to_return(status: 404) - end - - context 'when the account follows the poster' do - before do - account.follow!(poster) - end - - it 'returns the status' do - expect(subject.call(search_url, on_behalf_of: account)).to eq(status) - end - end - - context 'when the account does not follow the poster' do - it 'does not return the status' do - expect(subject.call(search_url, on_behalf_of: account)).to be_nil - end - end - end - end -end diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb deleted file mode 100644 index cb69af5f5..000000000 --- a/spec/services/search_service_spec.rb +++ /dev/null @@ -1,93 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe SearchService, type: :service do - subject { described_class.new } - - describe '#call' do - describe 'with a blank query' do - it 'returns empty results without searching' do - allow(AccountSearchService).to receive(:new) - allow(Tag).to receive(:search_for) - results = subject.call('', nil, 10) - - expect(results).to eq(empty_results) - expect(AccountSearchService).to_not have_received(:new) - expect(Tag).to_not have_received(:search_for) - end - end - - describe 'with an url query' do - before do - @query = 'http://test.host/query' - end - - context 'when it does not find anything' do - it 'returns the empty results' do - service = instance_double(ResolveURLService, call: nil) - allow(ResolveURLService).to receive(:new).and_return(service) - results = subject.call(@query, nil, 10, resolve: true) - - expect(service).to have_received(:call).with(@query, on_behalf_of: nil) - expect(results).to eq empty_results - end - end - - context 'when it finds an account' do - it 'includes the account in the results' do - account = Account.new - service = instance_double(ResolveURLService, call: account) - allow(ResolveURLService).to receive(:new).and_return(service) - - results = subject.call(@query, nil, 10, resolve: true) - expect(service).to have_received(:call).with(@query, on_behalf_of: nil) - expect(results).to eq empty_results.merge(accounts: [account]) - end - end - - context 'when it finds a status' do - it 'includes the status in the results' do - status = Status.new - service = instance_double(ResolveURLService, call: status) - allow(ResolveURLService).to receive(:new).and_return(service) - - results = subject.call(@query, nil, 10, resolve: true) - expect(service).to have_received(:call).with(@query, on_behalf_of: nil) - expect(results).to eq empty_results.merge(statuses: [status]) - end - end - end - - describe 'with a non-url query' do - context 'when it matches an account' do - it 'includes the account in the results' do - query = 'username' - account = Account.new - service = instance_double(AccountSearchService, call: [account]) - allow(AccountSearchService).to receive(:new).and_return(service) - - results = subject.call(query, nil, 10) - expect(service).to have_received(:call).with(query, nil, limit: 10, offset: 0, resolve: false, start_with_hashtag: false, use_searchable_text: true, following: false) - expect(results).to eq empty_results.merge(accounts: [account]) - end - end - - context 'when it matches a tag' do - it 'includes the tag in the results' do - query = '#tag' - tag = Tag.new - allow(Tag).to receive(:search_for).with('tag', 10, 0, { exclude_unreviewed: nil }).and_return([tag]) - - results = subject.call(query, nil, 10) - expect(Tag).to have_received(:search_for).with('tag', 10, 0, exclude_unreviewed: nil) - expect(results).to eq empty_results.merge(hashtags: [tag]) - end - end - end - end - - def empty_results - { accounts: [], hashtags: [], statuses: [] } - end -end diff --git a/spec/services/software_update_check_service_spec.rb b/spec/services/software_update_check_service_spec.rb deleted file mode 100644 index c8821348a..000000000 --- a/spec/services/software_update_check_service_spec.rb +++ /dev/null @@ -1,158 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe SoftwareUpdateCheckService, type: :service do - subject { described_class.new } - - shared_examples 'when the feature is enabled' do - let(:full_update_check_url) { "#{update_check_url}?version=#{Mastodon::Version.to_s.split('+')[0]}" } - - let(:devops_role) { Fabricate(:user_role, name: 'DevOps', permissions: UserRole::FLAGS[:view_devops]) } - let(:owner_user) { Fabricate(:user, role: UserRole.find_by(name: 'Owner')) } - let(:old_devops_user) { Fabricate(:user) } - let(:none_user) { Fabricate(:user, role: devops_role) } - let(:patch_user) { Fabricate(:user, role: devops_role) } - let(:critical_user) { Fabricate(:user, role: devops_role) } - - around do |example| - queue_adapter = ActiveJob::Base.queue_adapter - ActiveJob::Base.queue_adapter = :test - - example.run - - ActiveJob::Base.queue_adapter = queue_adapter - end - - before do - Fabricate(:software_update, version: '3.5.0', type: 'major', urgent: false) - Fabricate(:software_update, version: '42.13.12', type: 'major', urgent: false) - - owner_user.settings.update('notification_emails.software_updates': 'all') - owner_user.save! - - old_devops_user.settings.update('notification_emails.software_updates': 'all') - old_devops_user.save! - - none_user.settings.update('notification_emails.software_updates': 'none') - none_user.save! - - patch_user.settings.update('notification_emails.software_updates': 'patch') - patch_user.save! - - critical_user.settings.update('notification_emails.software_updates': 'critical') - critical_user.save! - end - - context 'when the update server errors out' do - before do - stub_request(:get, full_update_check_url).to_return(status: 404) - end - - it 'deletes outdated update records but keeps valid update records' do - expect { subject.call }.to change { SoftwareUpdate.pluck(:version).sort }.from(['3.5.0', '42.13.12']).to(['42.13.12']) - end - end - - context 'when the server returns new versions' do - let(:server_json) do - { - updatesAvailable: [ - { - version: '4.2.1', - urgent: false, - type: 'patch', - releaseNotes: 'https://github.com/mastodon/mastodon/releases/v4.2.1', - }, - { - version: '4.3.0', - urgent: false, - type: 'minor', - releaseNotes: 'https://github.com/mastodon/mastodon/releases/v4.3.0', - }, - { - version: '5.0.0', - urgent: false, - type: 'minor', - releaseNotes: 'https://github.com/mastodon/mastodon/releases/v5.0.0', - }, - ], - } - end - - before do - stub_request(:get, full_update_check_url).to_return(body: Oj.dump(server_json)) - end - - it 'updates the list of known updates' do - expect { subject.call }.to change { SoftwareUpdate.pluck(:version).sort }.from(['3.5.0', '42.13.12']).to(['4.2.1', '4.3.0', '5.0.0']) - end - - context 'when no update is urgent' do - it 'sends e-mail notifications according to settings', :aggregate_failures do - expect { subject.call }.to have_enqueued_mail(AdminMailer, :new_software_updates) - .with(hash_including(params: { recipient: owner_user.account })).once - .and(have_enqueued_mail(AdminMailer, :new_software_updates).with(hash_including(params: { recipient: patch_user.account })).once) - .and(have_enqueued_mail.at_most(2)) - end - end - - context 'when an update is urgent' do - let(:server_json) do - { - updatesAvailable: [ - { - version: '5.0.0', - urgent: true, - type: 'minor', - releaseNotes: 'https://github.com/mastodon/mastodon/releases/v5.0.0', - }, - ], - } - end - - it 'sends e-mail notifications according to settings', :aggregate_failures do - expect { subject.call }.to have_enqueued_mail(AdminMailer, :new_critical_software_updates) - .with(hash_including(params: { recipient: owner_user.account })).once - .and(have_enqueued_mail(AdminMailer, :new_critical_software_updates).with(hash_including(params: { recipient: patch_user.account })).once) - .and(have_enqueued_mail(AdminMailer, :new_critical_software_updates).with(hash_including(params: { recipient: critical_user.account })).once) - .and(have_enqueued_mail.at_most(3)) - end - end - end - end - - context 'when update checking is disabled' do - around do |example| - ClimateControl.modify UPDATE_CHECK_URL: '' do - example.run - end - end - - before do - Fabricate(:software_update, version: '3.5.0', type: 'major', urgent: false) - end - - it 'deletes outdated update records' do - expect { subject.call }.to change(SoftwareUpdate, :count).from(1).to(0) - end - end - - context 'when using the default update checking API' do - let(:update_check_url) { 'https://api.joinmastodon.org/update-check' } - - it_behaves_like 'when the feature is enabled' - end - - context 'when using a custom update check URL' do - let(:update_check_url) { 'https://api.example.com/update_check' } - - around do |example| - ClimateControl.modify UPDATE_CHECK_URL: 'https://api.example.com/update_check' do - example.run - end - end - - it_behaves_like 'when the feature is enabled' - end -end diff --git a/spec/services/suspend_account_service_spec.rb b/spec/services/suspend_account_service_spec.rb deleted file mode 100644 index edb705008..000000000 --- a/spec/services/suspend_account_service_spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe SuspendAccountService, type: :service do - shared_examples 'common behavior' do - subject { described_class.new.call(account) } - - let!(:local_follower) { Fabricate(:user, current_sign_in_at: 1.hour.ago).account } - let!(:list) { Fabricate(:list, account: local_follower) } - - before do - allow(FeedManager.instance).to receive_messages(unmerge_from_home: nil, unmerge_from_list: nil) - - local_follower.follow!(account) - list.accounts << account - - account.suspend! - end - - it "unmerges from local followers' feeds" do - subject - expect(FeedManager.instance).to have_received(:unmerge_from_home).with(account, local_follower) - expect(FeedManager.instance).to have_received(:unmerge_from_list).with(account, list) - end - - it 'does not change the “suspended” flag' do - expect { subject }.to_not change(account, :suspended?) - end - end - - describe 'suspending a local account' do - def match_update_actor_request(req, account) - json = JSON.parse(req.body) - actor_id = ActivityPub::TagManager.instance.uri_for(account) - json['type'] == 'Update' && json['actor'] == actor_id && json['object']['id'] == actor_id && json['object']['suspended'] - end - - before do - stub_request(:post, 'https://alice.com/inbox').to_return(status: 201) - stub_request(:post, 'https://bob.com/inbox').to_return(status: 201) - end - - include_examples 'common behavior' do - let!(:account) { Fabricate(:account) } - let!(:remote_follower) { Fabricate(:account, uri: 'https://alice.com', inbox_url: 'https://alice.com/inbox', protocol: :activitypub, domain: 'alice.com') } - let!(:remote_reporter) { Fabricate(:account, uri: 'https://bob.com', inbox_url: 'https://bob.com/inbox', protocol: :activitypub, domain: 'bob.com') } - let!(:report) { Fabricate(:report, account: remote_reporter, target_account: account) } - - before do - remote_follower.follow!(account) - end - - it 'sends an update actor to followers and reporters' do - subject - expect(a_request(:post, remote_follower.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once - expect(a_request(:post, remote_reporter.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once - end - end - end - - describe 'suspending a remote account' do - def match_reject_follow_request(req, account, followee) - json = JSON.parse(req.body) - json['type'] == 'Reject' && json['actor'] == ActivityPub::TagManager.instance.uri_for(followee) && json['object']['actor'] == account.uri - end - - before do - stub_request(:post, 'https://bob.com/inbox').to_return(status: 201) - end - - include_examples 'common behavior' do - let!(:account) { Fabricate(:account, domain: 'bob.com', uri: 'https://bob.com', inbox_url: 'https://bob.com/inbox', protocol: :activitypub) } - let!(:local_followee) { Fabricate(:account) } - - before do - account.follow!(local_followee) - end - - it 'sends a reject follow' do - subject - expect(a_request(:post, account.inbox_url).with { |req| match_reject_follow_request(req, account, local_followee) }).to have_been_made.once - end - end - end -end diff --git a/spec/services/translate_status_service_spec.rb b/spec/services/translate_status_service_spec.rb deleted file mode 100644 index 5f6418f5d..000000000 --- a/spec/services/translate_status_service_spec.rb +++ /dev/null @@ -1,234 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe TranslateStatusService, type: :service do - subject(:service) { described_class.new } - - let(:status) { Fabricate(:status, text: text, spoiler_text: spoiler_text, language: 'en', preloadable_poll: poll, media_attachments: media_attachments) } - let(:text) { 'Hello' } - let(:spoiler_text) { '' } - let(:poll) { nil } - let(:media_attachments) { [] } - - before do - Fabricate(:custom_emoji, shortcode: 'highfive') - end - - describe '#call' do - before do - translation_service = TranslationService.new - allow(translation_service).to receive(:languages).and_return({ 'en' => ['es'] }) - allow(translation_service).to receive(:translate) do |texts| - texts.map do |text| - TranslationService::Translation.new( - text: text.gsub('Hello', 'Hola').gsub('higfive', 'cincoaltos'), - detected_source_language: 'en', - provider: 'Dummy' - ) - end - end - - allow(TranslationService).to receive_messages(configured?: true, configured: translation_service) - end - - it 'returns translated status content' do - expect(service.call(status, 'es').content).to eq '

Hola

' - end - - it 'returns source language' do - expect(service.call(status, 'es').detected_source_language).to eq 'en' - end - - it 'returns translation provider' do - expect(service.call(status, 'es').provider).to eq 'Dummy' - end - - it 'returns original status' do - expect(service.call(status, 'es').status).to eq status - end - - describe 'status has content with custom emoji' do - let(:text) { 'Hello & :highfive:' } - - it 'does not translate shortcode' do - expect(service.call(status, 'es').content).to eq '

Hola & :highfive:

' - end - end - - describe 'status has no spoiler_text' do - it 'returns an empty string' do - expect(service.call(status, 'es').spoiler_text).to eq '' - end - end - - describe 'status has spoiler_text' do - let(:spoiler_text) { 'Hello & Hello!' } - - it 'translates the spoiler text' do - expect(service.call(status, 'es').spoiler_text).to eq 'Hola & Hola!' - end - end - - describe 'status has spoiler_text with custom emoji' do - let(:spoiler_text) { 'Hello :highfive:' } - - it 'does not translate shortcode' do - expect(service.call(status, 'es').spoiler_text).to eq 'Hola :highfive:' - end - end - - describe 'status has spoiler_text with unmatched custom emoji' do - let(:spoiler_text) { 'Hello :Hello:' } - - it 'translates the invalid shortcode' do - expect(service.call(status, 'es').spoiler_text).to eq 'Hola :Hola:' - end - end - - describe 'status has poll' do - let(:poll) { Fabricate(:poll, options: ['Hello 1', 'Hello 2']) } - - it 'translates the poll option title' do - status_translation = service.call(status, 'es') - expect(status_translation.poll_options.size).to eq 2 - expect(status_translation.poll_options.first.title).to eq 'Hola 1' - end - end - - describe 'status has media attachment' do - let(:media_attachments) { [Fabricate(:media_attachment, description: 'Hello & :highfive:')] } - - it 'translates the media attachment description' do - status_translation = service.call(status, 'es') - - media_attachment = status_translation.media_attachments.first - expect(media_attachment.id).to eq media_attachments.first.id - expect(media_attachment.description).to eq 'Hola & :highfive:' - end - end - end - - describe '#source_texts' do - before do - service.instance_variable_set(:@status, status) - end - - describe 'status only has content' do - it 'returns formatted content' do - expect(service.send(:source_texts)).to eq({ content: '

Hello

' }) - end - end - - describe 'status content contains custom emoji' do - let(:status) { Fabricate(:status, text: 'Hello :highfive:') } - - it 'returns formatted content' do - source_texts = service.send(:source_texts) - expect(source_texts[:content]).to eq '

Hello :highfive:

' - end - end - - describe 'status content contains tags' do - let(:status) { Fabricate(:status, text: 'Hello #hola') } - - it 'returns formatted content' do - source_texts = service.send(:source_texts) - expect(source_texts[:content]).to include '

Hello :highfive:' - end - end - - describe 'status has poll' do - let(:poll) { Fabricate(:poll, options: %w(Blue Green)) } - - context 'with source texts from the service' do - let!(:source_texts) { service.send(:source_texts) } - - it 'returns formatted poll options' do - expect(source_texts.size).to eq 3 - expect(source_texts.values).to eq %w(

Hello

Blue Green) - end - - it 'has a first key with content' do - expect(source_texts.keys.first).to eq :content - end - - it 'has the first option in the second key with correct options' do - option1 = source_texts.keys.second - expect(option1).to be_a Poll::Option - expect(option1.id).to eq '0' - expect(option1.title).to eq 'Blue' - end - - it 'has the second option in the third key with correct options' do - option2 = source_texts.keys.third - expect(option2).to be_a Poll::Option - expect(option2.id).to eq '1' - expect(option2.title).to eq 'Green' - end - end - end - - describe 'status has poll with custom emoji' do - let(:poll) { Fabricate(:poll, options: ['Blue', 'Green :highfive:']) } - - it 'returns formatted poll options' do - html = service.send(:source_texts).values.last - expect(html).to eq 'Green :highfive:' - end - end - - describe 'status has media attachments' do - let(:text) { '' } - let(:media_attachments) { [Fabricate(:media_attachment, description: 'Hello :highfive:')] } - - it 'returns media attachments without custom emoji rendering' do - source_texts = service.send(:source_texts) - expect(source_texts.size).to eq 1 - - key, text = source_texts.first - expect(key).to eq media_attachments.first - expect(text).to eq 'Hello :highfive:' - end - end - end - - describe '#wrap_emoji_shortcodes' do - before do - service.instance_variable_set(:@status, status) - end - - describe 'string contains custom emoji' do - let(:text) { ':highfive:' } - - it 'renders the emoji' do - html = service.send(:wrap_emoji_shortcodes, 'Hello :highfive:'.html_safe) - expect(html).to eq 'Hello :highfive:' - end - end - end - - describe '#unwrap_emoji_shortcodes' do - describe 'string contains custom emoji' do - it 'inserts the shortcode' do - fragment = service.send(:unwrap_emoji_shortcodes, '

Hello :highfive:!

') - expect(fragment.to_html).to eq '

Hello :highfive:!

' - end - - it 'preserves other attributes than translate=no' do - fragment = service.send(:unwrap_emoji_shortcodes, '

Hello :highfive:!

') - expect(fragment.to_html).to eq '

Hello :highfive:!

' - end - end - end -end diff --git a/spec/services/unallow_domain_service_spec.rb b/spec/services/unallow_domain_service_spec.rb deleted file mode 100644 index 19d40e7e8..000000000 --- a/spec/services/unallow_domain_service_spec.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe UnallowDomainService, type: :service do - subject { described_class.new } - - let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') } - let!(:bad_status_harassment) { Fabricate(:status, account: bad_account, text: 'You suck') } - let!(:bad_status_mean) { Fabricate(:status, account: bad_account, text: 'Hahaha') } - let!(:bad_attachment) { Fabricate(:media_attachment, account: bad_account, status: bad_status_mean, file: attachment_fixture('attachment.jpg')) } - let!(:already_banned_account) { Fabricate(:account, username: 'badguy', domain: 'evil.org', suspended: true, silenced: true) } - let!(:domain_allow) { Fabricate(:domain_allow, domain: 'evil.org') } - - context 'with limited federation mode' do - before do - allow(Rails.configuration.x).to receive(:limited_federation_mode).and_return(true) - end - - describe '#call' do - before do - subject.call(domain_allow) - end - - it 'removes the allowed domain' do - expect(DomainAllow.allowed?('evil.org')).to be false - end - - it 'removes remote accounts from that domain' do - expect(Account.where(domain: 'evil.org').exists?).to be false - end - - it 'removes the remote accounts\'s statuses and media attachments' do - expect { bad_status_harassment.reload }.to raise_exception ActiveRecord::RecordNotFound - expect { bad_status_mean.reload }.to raise_exception ActiveRecord::RecordNotFound - expect { bad_attachment.reload }.to raise_exception ActiveRecord::RecordNotFound - end - end - end - - context 'without limited federation mode' do - before do - allow(Rails.configuration.x).to receive(:limited_federation_mode).and_return(false) - end - - describe '#call' do - before do - subject.call(domain_allow) - end - - it 'removes the allowed domain' do - expect(DomainAllow.allowed?('evil.org')).to be false - end - - it 'does not remove accounts from that domain' do - expect(Account.where(domain: 'evil.org').exists?).to be true - end - - it 'removes the remote accounts\'s statuses and media attachments' do - expect { bad_status_harassment.reload }.to_not raise_error - expect { bad_status_mean.reload }.to_not raise_error - expect { bad_attachment.reload }.to_not raise_error - end - end - end -end diff --git a/spec/services/unblock_domain_service_spec.rb b/spec/services/unblock_domain_service_spec.rb deleted file mode 100644 index 27dbc92ad..000000000 --- a/spec/services/unblock_domain_service_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe UnblockDomainService, type: :service do - subject { described_class.new } - - describe 'call' do - before do - @independently_suspended = Fabricate(:account, domain: 'example.com', suspended_at: 1.hour.ago) - @independently_silenced = Fabricate(:account, domain: 'example.com', silenced_at: 1.hour.ago) - @domain_block = Fabricate(:domain_block, domain: 'example.com') - @silenced = Fabricate(:account, domain: 'example.com', silenced_at: @domain_block.created_at) - @suspended = Fabricate(:account, domain: 'example.com', suspended_at: @domain_block.created_at) - end - - it 'unsilences accounts and removes block' do - @domain_block.update(severity: :silence) - - subject.call(@domain_block) - expect_deleted_domain_block - expect(@silenced.reload.silenced?).to be false - expect(@suspended.reload.suspended?).to be true - expect(@independently_suspended.reload.suspended?).to be true - expect(@independently_silenced.reload.silenced?).to be true - end - - it 'unsuspends accounts and removes block' do - @domain_block.update(severity: :suspend) - - subject.call(@domain_block) - expect_deleted_domain_block - expect(@suspended.reload.suspended?).to be false - expect(@silenced.reload.silenced?).to be false - expect(@independently_suspended.reload.suspended?).to be true - expect(@independently_silenced.reload.silenced?).to be true - end - end - - def expect_deleted_domain_block - expect { @domain_block.reload }.to raise_error(ActiveRecord::RecordNotFound) - end -end diff --git a/spec/services/unblock_service_spec.rb b/spec/services/unblock_service_spec.rb deleted file mode 100644 index 86632c393..000000000 --- a/spec/services/unblock_service_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe UnblockService, type: :service do - subject { described_class.new } - - let(:sender) { Fabricate(:account, username: 'alice') } - - describe 'local' do - let(:bob) { Fabricate(:account) } - - before do - sender.block!(bob) - subject.call(sender, bob) - end - - it 'destroys the blocking relation' do - expect(sender.blocking?(bob)).to be false - end - end - - describe 'remote ActivityPub' do - let(:bob) { Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } - - before do - sender.block!(bob) - stub_request(:post, 'http://example.com/inbox').to_return(status: 200) - subject.call(sender, bob) - end - - it 'destroys the blocking relation' do - expect(sender.blocking?(bob)).to be false - end - - it 'sends an unblock activity' do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once - end - end -end diff --git a/spec/services/unfollow_service_spec.rb b/spec/services/unfollow_service_spec.rb deleted file mode 100644 index 3e65e610b..000000000 --- a/spec/services/unfollow_service_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe UnfollowService, type: :service do - subject { described_class.new } - - let(:sender) { Fabricate(:account, username: 'alice') } - - describe 'local' do - let(:bob) { Fabricate(:account, username: 'bob') } - - before do - sender.follow!(bob) - subject.call(sender, bob) - end - - it 'destroys the following relation' do - expect(sender.following?(bob)).to be false - end - end - - describe 'remote ActivityPub' do - let(:bob) { Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } - - before do - sender.follow!(bob) - stub_request(:post, 'http://example.com/inbox').to_return(status: 200) - subject.call(sender, bob) - end - - it 'destroys the following relation' do - expect(sender.following?(bob)).to be false - end - - it 'sends an unfollow activity' do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once - end - end - - describe 'remote ActivityPub (reverse)' do - let(:bob) { Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } - - before do - bob.follow!(sender) - stub_request(:post, 'http://example.com/inbox').to_return(status: 200) - subject.call(bob, sender) - end - - it 'destroys the following relation' do - expect(bob.following?(sender)).to be false - end - - it 'sends a reject activity' do - expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once - end - end -end diff --git a/spec/services/unsuspend_account_service_spec.rb b/spec/services/unsuspend_account_service_spec.rb deleted file mode 100644 index c555b661e..000000000 --- a/spec/services/unsuspend_account_service_spec.rb +++ /dev/null @@ -1,134 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe UnsuspendAccountService, type: :service do - shared_context 'with common context' do - subject { described_class.new.call(account) } - - let!(:local_follower) { Fabricate(:user, current_sign_in_at: 1.hour.ago).account } - let!(:list) { Fabricate(:list, account: local_follower) } - - before do - allow(FeedManager.instance).to receive_messages(merge_into_home: nil, merge_into_list: nil) - - local_follower.follow!(account) - list.accounts << account - - account.unsuspend! - end - end - - describe 'unsuspending a local account' do - def match_update_actor_request(req, account) - json = JSON.parse(req.body) - actor_id = ActivityPub::TagManager.instance.uri_for(account) - json['type'] == 'Update' && json['actor'] == actor_id && json['object']['id'] == actor_id && !json['object']['suspended'] - end - - before do - stub_request(:post, 'https://alice.com/inbox').to_return(status: 201) - stub_request(:post, 'https://bob.com/inbox').to_return(status: 201) - end - - it 'does not change the “suspended” flag' do - expect { subject }.to_not change(account, :suspended?) - end - - include_examples 'with common context' do - let!(:account) { Fabricate(:account) } - let!(:remote_follower) { Fabricate(:account, uri: 'https://alice.com', inbox_url: 'https://alice.com/inbox', protocol: :activitypub, domain: 'alice.com') } - let!(:remote_reporter) { Fabricate(:account, uri: 'https://bob.com', inbox_url: 'https://bob.com/inbox', protocol: :activitypub, domain: 'bob.com') } - let!(:report) { Fabricate(:report, account: remote_reporter, target_account: account) } - - before do - remote_follower.follow!(account) - end - - it "merges back into local followers' feeds" do - subject - expect(FeedManager.instance).to have_received(:merge_into_home).with(account, local_follower) - expect(FeedManager.instance).to have_received(:merge_into_list).with(account, list) - end - - it 'sends an update actor to followers and reporters' do - subject - expect(a_request(:post, remote_follower.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once - expect(a_request(:post, remote_reporter.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once - end - end - end - - describe 'unsuspending a remote account' do - include_examples 'with common context' do - let!(:account) { Fabricate(:account, domain: 'bob.com', uri: 'https://bob.com', inbox_url: 'https://bob.com/inbox', protocol: :activitypub) } - let!(:resolve_account_service) { instance_double(ResolveAccountService) } - - before do - allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service) - end - - context 'when the account is not remotely suspended' do - before do - allow(resolve_account_service).to receive(:call).with(account).and_return(account) - end - - it 're-fetches the account' do - subject - expect(resolve_account_service).to have_received(:call).with(account) - end - - it "merges back into local followers' feeds" do - subject - expect(FeedManager.instance).to have_received(:merge_into_home).with(account, local_follower) - expect(FeedManager.instance).to have_received(:merge_into_list).with(account, list) - end - - it 'does not change the “suspended” flag' do - expect { subject }.to_not change(account, :suspended?) - end - end - - context 'when the account is remotely suspended' do - before do - allow(resolve_account_service).to receive(:call).with(account) do |account| - account.suspend!(origin: :remote) - account - end - end - - it 're-fetches the account' do - subject - expect(resolve_account_service).to have_received(:call).with(account) - end - - it "does not merge back into local followers' feeds" do - subject - expect(FeedManager.instance).to_not have_received(:merge_into_home).with(account, local_follower) - expect(FeedManager.instance).to_not have_received(:merge_into_list).with(account, list) - end - - it 'marks account as suspended' do - expect { subject }.to change(account, :suspended?).from(false).to(true) - end - end - - context 'when the account is remotely deleted' do - before do - allow(resolve_account_service).to receive(:call).with(account).and_return(nil) - end - - it 're-fetches the account' do - subject - expect(resolve_account_service).to have_received(:call).with(account) - end - - it "does not merge back into local followers' feeds" do - subject - expect(FeedManager.instance).to_not have_received(:merge_into_home).with(account, local_follower) - expect(FeedManager.instance).to_not have_received(:merge_into_list).with(account, list) - end - end - end - end -end diff --git a/spec/services/update_account_service_spec.rb b/spec/services/update_account_service_spec.rb deleted file mode 100644 index 6318cc95f..000000000 --- a/spec/services/update_account_service_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe UpdateAccountService, type: :service do - subject { described_class.new } - - describe 'switching form locked to unlocked accounts' do - let(:account) { Fabricate(:account, locked: true) } - let(:alice) { Fabricate(:account) } - let(:bob) { Fabricate(:account) } - let(:eve) { Fabricate(:account) } - - before do - bob.touch(:silenced_at) - account.mute!(eve) - - FollowService.new.call(alice, account) - FollowService.new.call(bob, account) - FollowService.new.call(eve, account) - - subject.call(account, { locked: false }) - end - - it 'auto-accepts pending follow requests' do - expect(alice.following?(account)).to be true - expect(alice.requested?(account)).to be false - end - - it 'does not auto-accept pending follow requests from silenced users' do - expect(bob.following?(account)).to be false - expect(bob.requested?(account)).to be true - end - - it 'auto-accepts pending follow requests from muted users so as to not leak mute' do - expect(eve.following?(account)).to be true - expect(eve.requested?(account)).to be false - end - end -end diff --git a/spec/services/update_status_service_spec.rb b/spec/services/update_status_service_spec.rb deleted file mode 100644 index 9c53ebb2f..000000000 --- a/spec/services/update_status_service_spec.rb +++ /dev/null @@ -1,188 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe UpdateStatusService, type: :service do - subject { described_class.new } - - context 'when nothing changes' do - let!(:status) { Fabricate(:status, text: 'Foo', language: 'en') } - - before do - allow(ActivityPub::DistributionWorker).to receive(:perform_async) - subject.call(status, status.account_id, text: 'Foo') - end - - it 'does not create an edit' do - expect(status.reload.edits).to be_empty - end - - it 'does not notify anyone' do - expect(ActivityPub::DistributionWorker).to_not have_received(:perform_async) - end - end - - context 'when text changes' do - let!(:status) { Fabricate(:status, text: 'Foo') } - let(:preview_card) { Fabricate(:preview_card) } - - before do - status.preview_cards << preview_card - subject.call(status, status.account_id, text: 'Bar') - end - - it 'updates text' do - expect(status.reload.text).to eq 'Bar' - end - - it 'resets preview card' do - expect(status.reload.preview_card).to be_nil - end - - it 'saves edit history' do - expect(status.edits.pluck(:text)).to eq %w(Foo Bar) - end - end - - context 'when content warning changes' do - let!(:status) { Fabricate(:status, text: 'Foo', spoiler_text: '') } - let(:preview_card) { Fabricate(:preview_card) } - - before do - status.preview_cards << preview_card - subject.call(status, status.account_id, text: 'Foo', spoiler_text: 'Bar') - end - - it 'updates content warning' do - expect(status.reload.spoiler_text).to eq 'Bar' - end - - it 'saves edit history' do - expect(status.edits.pluck(:text, :spoiler_text)).to eq [['Foo', ''], ['Foo', 'Bar']] - end - end - - context 'when media attachments change' do - let!(:status) { Fabricate(:status, text: 'Foo') } - let!(:detached_media_attachment) { Fabricate(:media_attachment, account: status.account) } - let!(:attached_media_attachment) { Fabricate(:media_attachment, account: status.account) } - - before do - status.media_attachments << detached_media_attachment - subject.call(status, status.account_id, text: 'Foo', media_ids: [attached_media_attachment.id]) - end - - it 'updates media attachments' do - expect(status.ordered_media_attachments).to eq [attached_media_attachment] - end - - it 'does not detach detached media attachments' do - expect(detached_media_attachment.reload.status_id).to eq status.id - end - - it 'attaches attached media attachments' do - expect(attached_media_attachment.reload.status_id).to eq status.id - end - - it 'saves edit history' do - expect(status.edits.pluck(:ordered_media_attachment_ids)).to eq [[detached_media_attachment.id], [attached_media_attachment.id]] - end - end - - context 'when already-attached media changes' do - let!(:status) { Fabricate(:status, text: 'Foo') } - let!(:media_attachment) { Fabricate(:media_attachment, account: status.account, description: 'Old description') } - - before do - status.media_attachments << media_attachment - subject.call(status, status.account_id, text: 'Foo', media_ids: [media_attachment.id], media_attributes: [{ id: media_attachment.id, description: 'New description' }]) - end - - it 'does not detach media attachment' do - expect(media_attachment.reload.status_id).to eq status.id - end - - it 'updates the media attachment description' do - expect(media_attachment.reload.description).to eq 'New description' - end - - it 'saves edit history' do - expect(status.edits.map { |edit| edit.ordered_media_attachments.map(&:description) }).to eq [['Old description'], ['New description']] - end - end - - context 'when poll changes' do - let(:account) { Fabricate(:account) } - let!(:status) { Fabricate(:status, text: 'Foo', account: account, poll_attributes: { options: %w(Foo Bar), account: account, multiple: false, hide_totals: false, expires_at: 7.days.from_now }) } - let!(:poll) { status.poll } - let!(:voter) { Fabricate(:account) } - - before do - status.update(poll: poll) - VoteService.new.call(voter, poll, [0]) - Sidekiq::Testing.fake! do - subject.call(status, status.account_id, text: 'Foo', poll: { options: %w(Bar Baz Foo), expires_in: 5.days.to_i }) - end - end - - it 'updates poll' do - poll = status.poll.reload - expect(poll.options).to eq %w(Bar Baz Foo) - end - - it 'resets votes' do - poll = status.poll.reload - expect(poll.votes_count).to eq 0 - expect(poll.votes.count).to eq 0 - expect(poll.cached_tallies).to eq [0, 0, 0] - end - - it 'saves edit history' do - expect(status.edits.pluck(:poll_options)).to eq [%w(Foo Bar), %w(Bar Baz Foo)] - end - - it 'requeues expiration notification' do - poll = status.poll.reload - expect(PollExpirationNotifyWorker).to have_enqueued_sidekiq_job(poll.id).at(poll.expires_at + 5.minutes) - end - end - - context 'when mentions in text change' do - let!(:account) { Fabricate(:account) } - let!(:alice) { Fabricate(:account, username: 'alice') } - let!(:bob) { Fabricate(:account, username: 'bob') } - let!(:status) { PostStatusService.new.call(account, text: 'Hello @alice') } - - before do - subject.call(status, status.account_id, text: 'Hello @bob') - end - - it 'changes mentions' do - expect(status.active_mentions.pluck(:account_id)).to eq [bob.id] - end - - it 'keeps old mentions as silent mentions' do - expect(status.mentions.pluck(:account_id)).to contain_exactly(alice.id, bob.id) - end - end - - context 'when hashtags in text change' do - let!(:account) { Fabricate(:account) } - let!(:status) { PostStatusService.new.call(account, text: 'Hello #foo') } - - before do - subject.call(status, status.account_id, text: 'Hello #bar') - end - - it 'changes tags' do - expect(status.tags.pluck(:name)).to eq %w(bar) - end - end - - it 'notifies ActivityPub about the update' do - status = Fabricate(:status, text: 'Foo') - allow(ActivityPub::DistributionWorker).to receive(:perform_async) - subject.call(status, status.account_id, text: 'Bar') - expect(ActivityPub::DistributionWorker).to have_received(:perform_async) - end -end diff --git a/spec/services/verify_link_service_spec.rb b/spec/services/verify_link_service_spec.rb deleted file mode 100644 index 415788cb5..000000000 --- a/spec/services/verify_link_service_spec.rb +++ /dev/null @@ -1,178 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe VerifyLinkService, type: :service do - subject { described_class.new } - - context 'when given a local account' do - let(:account) { Fabricate(:account, username: 'alice') } - let(:field) { Account::Field.new(account, 'name' => 'Website', 'value' => 'http://example.com') } - - before do - stub_request(:head, 'https://redirect.me/abc').to_return(status: 301, headers: { 'Location' => ActivityPub::TagManager.instance.url_for(account) }) - stub_request(:get, 'http://example.com').to_return(status: 200, body: html) - subject.call(field) - end - - context 'when a link contains an back' do - let(:html) do - <<-HTML - - - Follow me on Mastodon - - HTML - end - - it 'marks the field as verified' do - expect(field.verified?).to be true - end - end - - context 'when a link contains an back' do - let(:html) do - <<-HTML - - - Follow me on Mastodon - - HTML - end - - it 'marks the field as verified' do - expect(field.verified?).to be true - end - end - - context 'when a link contains a back' do - let(:html) do - <<-HTML - - - - - HTML - end - - it 'marks the field as verified' do - expect(field.verified?).to be true - end - end - - context 'when a link goes through a redirect back' do - let(:html) do - <<-HTML - - - - - HTML - end - - it 'marks the field as verified' do - expect(field.verified?).to be true - end - end - - context 'when a document is truncated but the link back is valid' do - let(:html) do - " - - - - - - - - - - Follow me on Mastodon - - HTML - end - - it 'does not mark the field as verified' do - expect(field.verified?).to be false - end - end - end - - context 'when given a remote account' do - let(:account) { Fabricate(:account, username: 'alice', domain: 'example.com', url: 'https://profile.example.com/alice') } - let(:field) { Account::Field.new(account, 'name' => 'Website', 'value' => 'example.com') } - - before do - stub_request(:get, 'http://example.com').to_return(status: 200, body: html) - subject.call(field) - end - - context 'when a link contains an back' do - let(:html) do - <<-HTML - - - Follow me on Mastodon - - HTML - end - - it 'marks the field as verified' do - expect(field.verified?).to be true - end - end - - context 'when the link contains a link with a missing protocol slash' do - # This was seen in the wild where a user had three pages: - # 1. their mastodon profile, which linked to github and the personal website - # 2. their personal website correctly linking back to mastodon - # 3. a github profile that was linking to the personal website, but with - # a malformed protocol of http:/ - # - # This caused link verification between the mastodon profile and the - # website to fail. - # - # apparently github allows the user to enter website URLs with a single - # slash and makes no attempts to correct that. - let(:html) { 'Hello' } - - it 'does not crash' do - # We could probably put more effort into perhaps auto-correcting the - # link and following it anyway, but at the very least we shouldn't let - # exceptions bubble up - expect(field.verified?).to be false - end - end - end -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb deleted file mode 100644 index b4c20545f..000000000 --- a/spec/spec_helper.rb +++ /dev/null @@ -1,173 +0,0 @@ -# frozen_string_literal: true - -if ENV['DISABLE_SIMPLECOV'] != 'true' - require 'simplecov' - SimpleCov.start 'rails' do - add_filter 'lib/linter' - add_group 'Policies', 'app/policies' - add_group 'Presenters', 'app/presenters' - add_group 'Serializers', 'app/serializers' - add_group 'Services', 'app/services' - add_group 'Validators', 'app/validators' - end -end - -RSpec.configure do |config| - config.example_status_persistence_file_path = 'tmp/rspec/examples.txt' - config.expect_with :rspec do |expectations| - expectations.include_chain_clauses_in_custom_matcher_descriptions = true - end - - config.mock_with :rspec do |mocks| - mocks.verify_partial_doubles = true - - config.around(:example, :without_verify_partial_doubles) do |example| - mocks.verify_partial_doubles = false - example.call - mocks.verify_partial_doubles = true - end - end - - config.before :suite do - Rails.application.load_seed - Chewy.strategy(:bypass) - end - - config.after :suite do - FileUtils.rm_rf(Dir[Rails.root.join('spec', 'test_files')]) - end -end - -def body_as_json - json_str_to_hash(response.body) -end - -def json_str_to_hash(str) - JSON.parse(str, symbolize_names: true) -end - -def expect_push_bulk_to_match(klass, matcher) - expect(Sidekiq::Client).to receive(:push_bulk).with(hash_including({ - 'class' => klass, - 'args' => matcher, - })) -end - -class StreamingServerManager - @running_thread = nil - - def initialize - at_exit { stop } - end - - def start(port: 4020) - return if @running_thread - - queue = Queue.new - - @queue = queue - - @running_thread = Thread.new do - Open3.popen2e( - { - 'REDIS_NAMESPACE' => ENV.fetch('REDIS_NAMESPACE'), - 'DB_NAME' => "#{ENV.fetch('DB_NAME', 'mastodon')}_test#{ENV.fetch('TEST_ENV_NUMBER', '')}", - 'RAILS_ENV' => ENV.fetch('RAILS_ENV', 'test'), - 'NODE_ENV' => ENV.fetch('STREAMING_NODE_ENV', 'development'), - 'PORT' => port.to_s, - }, - 'node index.js', # must not call yarn here, otherwise it will fail because yarn does not send signals to its child process - chdir: Rails.root.join('streaming') - ) do |_stdin, stdout_err, process_thread| - status = :starting - - # Spawn a thread to listen on streaming server output - output_thread = Thread.new do - stdout_err.each_line do |line| - Rails.logger.info "Streaming server: #{line}" - - if status == :starting && line.match('Streaming API now listening on') - status = :started - @queue.enq 'started' - end - end - end - - # And another thread to listen on commands from the main thread - loop do - msg = queue.pop - - case msg - when 'stop' - # we need to properly stop the reading thread - output_thread.kill - - # Then stop the node process - Process.kill('KILL', process_thread.pid) - - # And we stop ourselves - @running_thread.kill - end - end - end - end - - # wait for 10 seconds for the streaming server to start - Timeout.timeout(10) do - loop do - break if @queue.pop == 'started' - end - end - end - - def stop - return unless @running_thread - - @queue.enq 'stop' - - # Wait for the thread to end - @running_thread.join - end -end - -class SearchDataManager - def prepare_test_data - 4.times do |i| - username = "search_test_account_#{i}" - account = Fabricate.create(:account, username: username, indexable: i.even?, discoverable: i.even?, note: "Lover of #{i}.") - 2.times do |j| - Fabricate.create(:status, account: account, text: "#{username}'s #{j} post", visibility: j.even? ? :public : :private) - end - end - - 3.times do |i| - Fabricate.create(:tag, name: "search_test_tag_#{i}") - end - end - - def indexes - [ - AccountsIndex, - PublicStatusesIndex, - StatusesIndex, - TagsIndex, - ] - end - - def populate_indexes - indexes.each do |index_class| - index_class.purge! - index_class.import! - end - end - - def remove_indexes - indexes.each(&:delete!) - end - - def cleanup_test_data - Status.destroy_all - Account.destroy_all - Tag.destroy_all - end -end diff --git a/spec/support/examples/api.rb b/spec/support/examples/api.rb deleted file mode 100644 index d531860ab..000000000 --- a/spec/support/examples/api.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -shared_examples 'forbidden for wrong scope' do |wrong_scope| - let(:scopes) { wrong_scope } - - it 'returns http forbidden' do - # Some examples have a subject which needs to be called to make a request - subject if request.nil? - - expect(response).to have_http_status(403) - end -end - -shared_examples 'forbidden for wrong role' do |wrong_role| - let(:role) { UserRole.find_by(name: wrong_role) } - - it 'returns http forbidden' do - # Some examples have a subject which needs to be called to make a request - subject if request.nil? - - expect(response).to have_http_status(403) - end -end diff --git a/spec/support/examples/lib/admin/checks.rb b/spec/support/examples/lib/admin/checks.rb deleted file mode 100644 index b50faa77b..000000000 --- a/spec/support/examples/lib/admin/checks.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -shared_examples 'a check available to devops users' do - describe 'skip?' do - context 'when user can view devops' do - before { allow(user).to receive(:can?).with(:view_devops).and_return(true) } - - it 'returns false' do - expect(check.skip?).to be false - end - end - - context 'when user cannot view devops' do - before { allow(user).to receive(:can?).with(:view_devops).and_return(false) } - - it 'returns true' do - expect(check.skip?).to be true - end - end - end -end diff --git a/spec/support/examples/mailers.rb b/spec/support/examples/mailers.rb deleted file mode 100644 index 213e873b4..000000000 --- a/spec/support/examples/mailers.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -shared_examples 'localized subject' do |*args, **kwrest| - it 'renders subject localized for the locale of the receiver' do - locale = :de - receiver.update!(locale: locale) - expect(mail.subject).to eq I18n.t(*args, **kwrest.merge(locale: locale)) - end - - it 'renders subject localized for the default locale if the locale of the receiver is unavailable' do - receiver.update!(locale: nil) - expect(mail.subject).to eq I18n.t(*args, **kwrest.merge(locale: I18n.default_locale)) - end -end diff --git a/spec/support/examples/models/concerns/account_avatar.rb b/spec/support/examples/models/concerns/account_avatar.rb deleted file mode 100644 index 16ebda564..000000000 --- a/spec/support/examples/models/concerns/account_avatar.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -shared_examples 'AccountAvatar' do |fabricator| - describe 'static avatars', paperclip_processing: true do - describe 'when GIF' do - it 'creates a png static style' do - account = Fabricate(fabricator, avatar: attachment_fixture('avatar.gif')) - expect(account.avatar_static_url).to_not eq account.avatar_original_url - end - end - - describe 'when non-GIF' do - it 'does not create extra static style' do - account = Fabricate(fabricator, avatar: attachment_fixture('attachment.jpg')) - expect(account.avatar_static_url).to eq account.avatar_original_url - end - end - end - - describe 'base64-encoded files', paperclip_processing: true do - let(:base64_attachment) { "data:image/jpeg;base64,#{Base64.encode64(attachment_fixture('attachment.jpg').read)}" } - let(:account) { Fabricate(fabricator, avatar: base64_attachment) } - - it 'saves avatar' do - expect(account.persisted?).to be true - expect(account.avatar).to_not be_nil - end - - it 'gives the avatar a file name' do - expect(account.avatar_file_name).to_not be_blank - end - - it 'saves a new avatar under a different file name' do - previous_file_name = account.avatar_file_name - account.update(avatar: base64_attachment) - expect(account.avatar_file_name).to_not eq previous_file_name - end - end -end diff --git a/spec/support/examples/models/concerns/account_header.rb b/spec/support/examples/models/concerns/account_header.rb deleted file mode 100644 index d65f54f00..000000000 --- a/spec/support/examples/models/concerns/account_header.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -shared_examples 'AccountHeader' do |fabricator| - describe 'base64-encoded files', paperclip_processing: true do - let(:base64_attachment) { "data:image/jpeg;base64,#{Base64.encode64(attachment_fixture('attachment.jpg').read)}" } - let(:account) { Fabricate(fabricator, header: base64_attachment) } - - it 'saves header' do - expect(account.persisted?).to be true - expect(account.header).to_not be_nil - end - - it 'gives the header a file name' do - expect(account.header_file_name).to_not be_blank - end - - it 'saves a new header under a different file name' do - previous_file_name = account.header_file_name - account.update(header: base64_attachment) - expect(account.header_file_name).to_not eq previous_file_name - end - end -end diff --git a/spec/support/matchers/json/match_json_schema.rb b/spec/support/matchers/json/match_json_schema.rb deleted file mode 100644 index 3a275199e..000000000 --- a/spec/support/matchers/json/match_json_schema.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -RSpec::Matchers.define :match_json_schema do |schema| - match do |input_json| - schema_path = Rails.root.join('spec', 'support', 'schema', "#{schema}.json").to_s - JSON::Validator.validate(schema_path, input_json, validate_schema: true) - end -end diff --git a/spec/support/matchers/model/model_have_error_on_field.rb b/spec/support/matchers/model/model_have_error_on_field.rb deleted file mode 100644 index 0f9c81a47..000000000 --- a/spec/support/matchers/model/model_have_error_on_field.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -RSpec::Matchers.define :model_have_error_on_field do |expected| - match do |record| - record.valid? if record.errors.empty? - - record.errors.key?(expected) - end - - failure_message do |record| - keys = record.errors.attribute_names - - "expect record.errors(#{keys}) to include #{expected}" - end -end diff --git a/spec/support/omniauth_mocks.rb b/spec/support/omniauth_mocks.rb deleted file mode 100644 index 9883adec7..000000000 --- a/spec/support/omniauth_mocks.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -OmniAuth.config.test_mode = true - -def mock_omniauth(provider, data) - OmniAuth.config.mock_auth[provider] = OmniAuth::AuthHash.new(data) -end diff --git a/spec/support/schema/nodeinfo_2.0.json b/spec/support/schema/nodeinfo_2.0.json deleted file mode 100644 index 085ce542b..000000000 --- a/spec/support/schema/nodeinfo_2.0.json +++ /dev/null @@ -1,170 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "id": "http://nodeinfo.diaspora.software/ns/schema/2.0#", - "description": "NodeInfo schema version 2.0.", - "type": "object", - "additionalProperties": false, - "required": [ - "version", - "software", - "protocols", - "services", - "openRegistrations", - "usage", - "metadata" - ], - "properties": { - "version": { - "description": "The schema version, must be 2.0.", - "enum": ["2.0"] - }, - "software": { - "description": "Metadata about server software in use.", - "type": "object", - "additionalProperties": false, - "required": ["name", "version"], - "properties": { - "name": { - "description": "The canonical name of this server software.", - "type": "string", - "pattern": "^[a-z0-9-]+$" - }, - "version": { - "description": "The version of this server software.", - "type": "string" - } - } - }, - "protocols": { - "description": "The protocols supported on this server.", - "type": "array", - "minItems": 1, - "items": { - "enum": [ - "activitypub", - "buddycloud", - "dfrn", - "diaspora", - "libertree", - "ostatus", - "pumpio", - "tent", - "xmpp", - "zot" - ] - } - }, - "services": { - "description": "The third party sites this server can connect to via their application API.", - "type": "object", - "additionalProperties": false, - "required": ["inbound", "outbound"], - "properties": { - "inbound": { - "description": "The third party sites this server can retrieve messages from for combined display with regular traffic.", - "type": "array", - "minItems": 0, - "items": { - "enum": [ - "atom1.0", - "gnusocial", - "imap", - "pnut", - "pop3", - "pumpio", - "rss2.0", - "twitter" - ] - } - }, - "outbound": { - "description": "The third party sites this server can publish messages to on the behalf of a user.", - "type": "array", - "minItems": 0, - "items": { - "enum": [ - "atom1.0", - "blogger", - "buddycloud", - "diaspora", - "dreamwidth", - "drupal", - "facebook", - "friendica", - "gnusocial", - "google", - "insanejournal", - "libertree", - "linkedin", - "livejournal", - "mediagoblin", - "myspace", - "pinterest", - "pnut", - "posterous", - "pumpio", - "redmatrix", - "rss2.0", - "smtp", - "tent", - "tumblr", - "twitter", - "wordpress", - "xmpp" - ] - } - } - } - }, - "openRegistrations": { - "description": "Whether this server allows open self-registration.", - "type": "boolean" - }, - "usage": { - "description": "Usage statistics for this server.", - "type": "object", - "additionalProperties": false, - "required": ["users"], - "properties": { - "users": { - "description": "statistics about the users of this server.", - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "description": "The total amount of on this server registered users.", - "type": "integer", - "minimum": 0 - }, - "activeHalfyear": { - "description": "The amount of users that signed in at least once in the last 180 days.", - "type": "integer", - "minimum": 0 - }, - "activeMonth": { - "description": "The amount of users that signed in at least once in the last 30 days.", - "type": "integer", - "minimum": 0 - } - } - }, - "localPosts": { - "description": "The amount of posts that were made by users that are registered on this server.", - "type": "integer", - "minimum": 0 - }, - "localComments": { - "description": "The amount of comments that were made by users that are registered on this server.", - "type": "integer", - "minimum": 0 - } - } - }, - "metadata": { - "description": "Free form key value pairs for software specific values. Clients should not rely on any specific key present.", - "type": "object", - "minProperties": 0, - "additionalProperties": true - } - } -} diff --git a/spec/support/stories/profile_stories.rb b/spec/support/stories/profile_stories.rb deleted file mode 100644 index 2b345ddef..000000000 --- a/spec/support/stories/profile_stories.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -module ProfileStories - attr_reader :bob, :alice, :alice_bio - - def as_a_registered_user - @bob = Fabricate( - :user, - email: email, password: password, confirmed_at: confirmed_at, - account: Fabricate(:account, username: 'bob') - ) - - Web::Setting.where(user: bob).first_or_initialize(user: bob).update!(data: { introductionVersion: 201812160442020 }) if finished_onboarding # rubocop:disable Style/NumericLiterals - end - - def as_a_logged_in_user - as_a_registered_user - visit new_user_session_path - fill_in 'user_email', with: email - fill_in 'user_password', with: password - click_on I18n.t('auth.login') - end - - def with_alice_as_local_user - @alice_bio = '@alice and @bob are fictional characters commonly used as' \ - 'placeholder names in #cryptology, as well as #science and' \ - 'engineering 📖 literature. Not affiliated with @pepe.' - - @alice = Fabricate( - :user, - email: 'alice@example.com', password: password, confirmed_at: confirmed_at, - account: Fabricate(:account, username: 'alice', note: @alice_bio) - ) - end - - def confirmed_at - @confirmed_at ||= Time.zone.now - end - - def email - @email ||= 'test@example.com' - end - - def password - @password ||= 'password' - end - - def finished_onboarding - @finished_onboarding || false - end -end diff --git a/spec/system/new_statuses_spec.rb b/spec/system/new_statuses_spec.rb deleted file mode 100644 index 6faed6c80..000000000 --- a/spec/system/new_statuses_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'NewStatuses' do - include ProfileStories - - subject { page } - - let(:email) { 'test@example.com' } - let(:password) { 'password' } - let(:confirmed_at) { Time.zone.now } - let(:finished_onboarding) { true } - - before do - as_a_logged_in_user - visit root_path - end - - it 'can be posted' do - expect(subject).to have_css('div.app-holder') - - status_text = 'This is a new status!' - - within('.compose-form') do - fill_in "What's on your mind?", with: status_text - click_on 'Publish!' - end - - expect(subject).to have_selector('.status__content__text', text: status_text) - end - - it 'can be posted again' do - expect(subject).to have_css('div.app-holder') - - status_text = 'This is a second status!' - - within('.compose-form') do - fill_in "What's on your mind?", with: status_text - click_on 'Publish!' - end - - expect(subject).to have_selector('.status__content__text', text: status_text) - end -end diff --git a/spec/validators/blacklisted_email_validator_spec.rb b/spec/validators/blacklisted_email_validator_spec.rb deleted file mode 100644 index bfe2a11a9..000000000 --- a/spec/validators/blacklisted_email_validator_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe BlacklistedEmailValidator, type: :validator do - describe '#validate' do - subject { described_class.new.validate(user); errors } - - let(:user) { instance_double(User, email: 'info@mail.com', sign_up_ip: '1.2.3.4', errors: errors) } - let(:errors) { instance_double(ActiveModel::Errors, add: nil) } - - before do - allow(user).to receive(:valid_invitation?).and_return(false) - allow(EmailDomainBlock).to receive(:block?) { blocked_email } - end - - context 'when e-mail provider is blocked' do - let(:blocked_email) { true } - - it 'adds error' do - described_class.new.validate(user) - expect(errors).to have_received(:add).with(:email, :blocked).once - end - end - - context 'when e-mail provider is not blocked' do - let(:blocked_email) { false } - - it 'does not add errors' do - described_class.new.validate(user) - expect(errors).to_not have_received(:add) - end - - context 'when canonical e-mail is blocked' do - let(:other_user) { Fabricate(:user, email: 'i.n.f.o@mail.com') } - - before do - other_user.account.suspend! - end - - it 'adds error' do - described_class.new.validate(user) - expect(errors).to have_received(:add).with(:email, :taken).once - end - end - end - end -end diff --git a/spec/validators/disallowed_hashtags_validator_spec.rb b/spec/validators/disallowed_hashtags_validator_spec.rb deleted file mode 100644 index 7144d2891..000000000 --- a/spec/validators/disallowed_hashtags_validator_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe DisallowedHashtagsValidator, type: :validator do - let(:disallowed_tags) { [] } - - describe '#validate' do - before do - disallowed_tags.each { |name| Fabricate(:tag, name: name, usable: false) } - described_class.new.validate(status) - end - - let(:status) { instance_double(Status, errors: errors, local?: local, reblog?: reblog, text: disallowed_tags.map { |x| "##{x}" }.join(' ')) } - let(:errors) { instance_double(ActiveModel::Errors, add: nil) } - - context 'with a remote reblog' do - let(:local) { false } - let(:reblog) { true } - - it 'does not add errors' do - expect(errors).to_not have_received(:add).with(:text, any_args) - end - end - - context 'with a local original status' do - let(:local) { true } - let(:reblog) { false } - - context 'when does not contain any disallowed hashtags' do - let(:disallowed_tags) { [] } - - it 'does not add errors' do - expect(errors).to_not have_received(:add).with(:text, any_args) - end - end - - context 'when contains disallowed hashtags' do - let(:disallowed_tags) { %w(a b c) } - - it 'adds an error' do - expect(errors).to have_received(:add) - .with(:text, I18n.t('statuses.disallowed_hashtags', tags: disallowed_tags.join(', '), count: disallowed_tags.size)) - end - end - end - end -end diff --git a/spec/validators/email_mx_validator_spec.rb b/spec/validators/email_mx_validator_spec.rb deleted file mode 100644 index 876d73c18..000000000 --- a/spec/validators/email_mx_validator_spec.rb +++ /dev/null @@ -1,122 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe EmailMxValidator do - describe '#validate' do - let(:user) { instance_double(User, email: 'foo@example.com', sign_up_ip: '1.2.3.4', errors: instance_double(ActiveModel::Errors, add: nil)) } - - context 'with an e-mail domain that is explicitly allowed' do - around do |block| - tmp = Rails.configuration.x.email_domains_whitelist - Rails.configuration.x.email_domains_whitelist = 'example.com' - block.call - Rails.configuration.x.email_domains_whitelist = tmp - end - - it 'does not add errors if there are no DNS records' do - resolver = instance_double(Resolv::DNS) - - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) - - subject.validate(user) - expect(user.errors).to_not have_received(:add) - end - end - - it 'adds no error if there are DNS records for the e-mail domain' do - resolver = instance_double(Resolv::DNS) - - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([Resolv::DNS::Resource::IN::A.new('192.0.2.42')]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) - - subject.validate(user) - expect(user.errors).to_not have_received(:add) - end - - it 'adds an error if the TagManager fails to normalize domain' do - double = instance_double(TagManager) - allow(TagManager).to receive(:instance).and_return(double) - allow(double).to receive(:normalize_domain).with('example.com').and_raise(Addressable::URI::InvalidURIError) - - user = instance_double(User, email: 'foo@example.com', errors: instance_double(ActiveModel::Errors, add: nil)) - subject.validate(user) - expect(user.errors).to have_received(:add) - end - - it 'adds an error if the domain email portion is blank' do - user = instance_double(User, email: 'foo@', errors: instance_double(ActiveModel::Errors, add: nil)) - subject.validate(user) - expect(user.errors).to have_received(:add) - end - - it 'adds an error if the email domain name contains empty labels' do - resolver = instance_double(Resolv::DNS) - - allow(resolver).to receive(:getresources).with('example..com', Resolv::DNS::Resource::IN::MX).and_return([]) - allow(resolver).to receive(:getresources).with('example..com', Resolv::DNS::Resource::IN::A).and_return([Resolv::DNS::Resource::IN::A.new('192.0.2.42')]) - allow(resolver).to receive(:getresources).with('example..com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) - - user = instance_double(User, email: 'foo@example..com', sign_up_ip: '1.2.3.4', errors: instance_double(ActiveModel::Errors, add: nil)) - subject.validate(user) - expect(user.errors).to have_received(:add) - end - - it 'adds an error if there are no DNS records for the e-mail domain' do - resolver = instance_double(Resolv::DNS) - - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::MX).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) - - subject.validate(user) - expect(user.errors).to have_received(:add) - end - - it 'adds an error if a MX record does not lead to an IP' do - resolver = instance_double(Resolv::DNS) - - allow(resolver).to receive(:getresources) - .with('example.com', Resolv::DNS::Resource::IN::MX) - .and_return([instance_double(Resolv::DNS::Resource::MX, exchange: 'mail.example.com')]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::A).and_return([]) - allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) - - subject.validate(user) - expect(user.errors).to have_received(:add) - end - - it 'adds an error if the MX record is blacklisted' do - EmailDomainBlock.create!(domain: 'mail.example.com') - resolver = instance_double(Resolv::DNS) - - allow(resolver).to receive(:getresources) - .with('example.com', Resolv::DNS::Resource::IN::MX) - .and_return([instance_double(Resolv::DNS::Resource::MX, exchange: 'mail.example.com')]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::A).and_return([]) - allow(resolver).to receive(:getresources).with('example.com', Resolv::DNS::Resource::IN::AAAA).and_return([]) - allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::A).and_return([instance_double(Resolv::DNS::Resource::IN::A, address: '2.3.4.5')]) - allow(resolver).to receive(:getresources).with('mail.example.com', Resolv::DNS::Resource::IN::AAAA).and_return([instance_double(Resolv::DNS::Resource::IN::A, address: 'fd00::2')]) - allow(resolver).to receive(:timeouts=).and_return(nil) - allow(Resolv::DNS).to receive(:open).and_yield(resolver) - - subject.validate(user) - expect(user.errors).to have_received(:add) - end - end -end diff --git a/spec/validators/follow_limit_validator_spec.rb b/spec/validators/follow_limit_validator_spec.rb deleted file mode 100644 index 86b6511d6..000000000 --- a/spec/validators/follow_limit_validator_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe FollowLimitValidator, type: :validator do - describe '#validate' do - before do - allow_any_instance_of(described_class).to receive(:limit_reached?).with(account) do - limit_reached - end - - described_class.new.validate(follow) - end - - let(:follow) { instance_double(Follow, account: account, errors: errors) } - let(:errors) { instance_double(ActiveModel::Errors, add: nil) } - let(:account) { instance_double(Account, nil?: _nil, local?: local, following_count: 0, followers_count: 0) } - let(:_nil) { true } - let(:local) { false } - - context 'with follow.account.nil? || !follow.account.local?' do - let(:_nil) { true } - - it 'not calls errors.add' do - expect(errors).to_not have_received(:add).with(:base, any_args) - end - end - - context 'with !(follow.account.nil? || !follow.account.local?)' do - let(:_nil) { false } - let(:local) { true } - - context 'when limit_reached?' do - let(:limit_reached) { true } - - it 'calls errors.add' do - expect(errors).to have_received(:add) - .with(:base, I18n.t('users.follow_limit_reached', limit: FollowLimitValidator::LIMIT)) - end - end - - context 'with !limit_reached?' do - let(:limit_reached) { false } - - it 'not calls errors.add' do - expect(errors).to_not have_received(:add).with(:base, any_args) - end - end - end - end -end diff --git a/spec/validators/language_validator_spec.rb b/spec/validators/language_validator_spec.rb deleted file mode 100644 index cb693dcd8..000000000 --- a/spec/validators/language_validator_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe LanguageValidator do - let(:record_class) do - Class.new do - include ActiveModel::Validations - attr_accessor :locale - - validates :locale, language: true - end - end - let(:record) { record_class.new } - - describe '#validate_each' do - context 'with a nil value' do - it 'does not add errors' do - record.locale = nil - - expect(record).to be_valid - expect(record.errors).to be_empty - end - end - - context 'with an array of values' do - it 'does not add errors with array of existing locales' do - record.locale = %w(en fr) - - expect(record).to be_valid - expect(record.errors).to be_empty - end - - it 'adds errors with array having some non-existing locales' do - record.locale = %w(en fr missing) - - expect(record).to_not be_valid - expect(record.errors.first.attribute).to eq(:locale) - expect(record.errors.first.type).to eq(:invalid) - end - end - - context 'with a locale string' do - it 'does not add errors when string is an existing locale' do - record.locale = 'en' - - expect(record).to be_valid - expect(record.errors).to be_empty - end - - it 'adds errors when string is non-existing locale' do - record.locale = 'missing' - - expect(record).to_not be_valid - expect(record.errors.first.attribute).to eq(:locale) - expect(record.errors.first.type).to eq(:invalid) - end - end - end -end diff --git a/spec/validators/note_length_validator_spec.rb b/spec/validators/note_length_validator_spec.rb deleted file mode 100644 index 66fccad3e..000000000 --- a/spec/validators/note_length_validator_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe NoteLengthValidator do - subject { described_class.new(attributes: { note: true }, maximum: 500) } - - describe '#validate' do - it 'adds an error when text is over 500 characters' do - text = 'a' * 520 - account = instance_double(Account, note: text, errors: activemodel_errors) - - subject.validate_each(account, 'note', text) - expect(account.errors).to have_received(:add) - end - - it 'counts URLs as 23 characters flat' do - text = ('a' * 476) + " http://#{'b' * 30}.com/example" - account = instance_double(Account, note: text, errors: activemodel_errors) - - subject.validate_each(account, 'note', text) - expect(account.errors).to_not have_received(:add) - end - - it 'does not count non-autolinkable URLs as 23 characters flat' do - text = ('a' * 476) + "http://#{'b' * 30}.com/example" - account = instance_double(Account, note: text, errors: activemodel_errors) - - subject.validate_each(account, 'note', text) - expect(account.errors).to have_received(:add) - end - - private - - def activemodel_errors - instance_double(ActiveModel::Errors, add: nil) - end - end -end diff --git a/spec/validators/poll_validator_spec.rb b/spec/validators/poll_validator_spec.rb deleted file mode 100644 index 95feb043d..000000000 --- a/spec/validators/poll_validator_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe PollValidator, type: :validator do - describe '#validate' do - before do - validator.validate(poll) - end - - let(:validator) { described_class.new } - let(:poll) { instance_double(Poll, options: options, expires_at: expires_at, errors: errors) } - let(:errors) { instance_double(ActiveModel::Errors, add: nil) } - let(:options) { %w(foo bar) } - let(:expires_at) { 1.day.from_now } - - it 'have no errors' do - expect(errors).to_not have_received(:add) - end - - context 'when expires is just 5 min ago' do - let(:expires_at) { 5.minutes.from_now } - - it 'not calls errors add' do - expect(errors).to_not have_received(:add) - end - end - end -end diff --git a/spec/validators/reaction_validator_spec.rb b/spec/validators/reaction_validator_spec.rb deleted file mode 100644 index d73104cb6..000000000 --- a/spec/validators/reaction_validator_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ReactionValidator do - let(:announcement) { Fabricate(:announcement) } - - describe '#validate' do - it 'adds error when not a valid unicode emoji' do - reaction = announcement.announcement_reactions.build(name: 'F') - subject.validate(reaction) - expect(reaction.errors).to_not be_empty - end - - it 'does not add error when non-unicode emoji is a custom emoji' do - custom_emoji = Fabricate(:custom_emoji) - reaction = announcement.announcement_reactions.build(name: custom_emoji.shortcode, custom_emoji_id: custom_emoji.id) - subject.validate(reaction) - expect(reaction.errors).to be_empty - end - - it 'adds error when 8 reactions already exist' do - %w(🐘 ❤️ 🙉 😍 😋 😂 😞 👍).each do |name| - announcement.announcement_reactions.create!(name: name, account: Fabricate(:account)) - end - - reaction = announcement.announcement_reactions.build(name: '😘') - subject.validate(reaction) - expect(reaction.errors).to_not be_empty - end - - it 'does not add error when new reaction is part of the existing ones' do - %w(🐘 ❤️ 🙉 😍 😋 😂 😞 👍).each do |name| - announcement.announcement_reactions.create!(name: name, account: Fabricate(:account)) - end - - reaction = announcement.announcement_reactions.build(name: '😋') - subject.validate(reaction) - expect(reaction.errors).to be_empty - end - end -end diff --git a/spec/validators/status_length_validator_spec.rb b/spec/validators/status_length_validator_spec.rb deleted file mode 100644 index 8535ddd75..000000000 --- a/spec/validators/status_length_validator_spec.rb +++ /dev/null @@ -1,89 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe StatusLengthValidator do - describe '#validate' do - it 'does not add errors onto remote statuses' do - status = instance_double(Status, local?: false) - subject.validate(status) - expect(status).to_not receive(:errors) - end - - it 'does not add errors onto local reblogs' do - status = instance_double(Status, local?: false, reblog?: true) - subject.validate(status) - expect(status).to_not receive(:errors) - end - - it 'adds an error when content warning is over MAX_CHARS characters' do - chars = StatusLengthValidator::MAX_CHARS + 1 - status = instance_double(Status, spoiler_text: 'a' * chars, text: '', errors: activemodel_errors, local?: true, reblog?: false) - subject.validate(status) - expect(status.errors).to have_received(:add) - end - - it 'adds an error when text is over MAX_CHARS characters' do - chars = StatusLengthValidator::MAX_CHARS + 1 - status = instance_double(Status, spoiler_text: '', text: 'a' * chars, errors: activemodel_errors, local?: true, reblog?: false) - subject.validate(status) - expect(status.errors).to have_received(:add) - end - - it 'adds an error when text and content warning are over MAX_CHARS characters total' do - chars1 = 20 - chars2 = StatusLengthValidator::MAX_CHARS + 1 - chars1 - status = instance_double(Status, spoiler_text: 'a' * chars1, text: 'b' * chars2, errors: activemodel_errors, local?: true, reblog?: false) - subject.validate(status) - expect(status.errors).to have_received(:add) - end - - it 'counts URLs as 23 characters flat' do - chars = StatusLengthValidator::MAX_CHARS - 1 - 23 - text = ('a' * chars) + " http://#{'b' * 30}.com/example" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) - - subject.validate(status) - expect(status.errors).to_not have_received(:add) - end - - it 'does not count non-autolinkable URLs as 23 characters flat' do - text = ('a' * 476) + "http://#{'b' * 30}.com/example" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) - - subject.validate(status) - expect(status.errors).to have_received(:add) - end - - it 'does not count overly long URLs as 23 characters flat' do - text = "http://example.com/valid?#{'#foo?' * 1000}" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) - subject.validate(status) - expect(status.errors).to have_received(:add) - end - - it 'counts only the front part of remote usernames' do - username = '@alice' - chars = StatusLengthValidator::MAX_CHARS - 1 - username.length - text = ('a' * chars) + " #{username}@#{'b' * 30}.com" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) - - subject.validate(status) - expect(status.errors).to_not have_received(:add) - end - - it 'does count both parts of remote usernames for overly long domains' do - text = "@alice@#{'b' * 500}.com" - status = instance_double(Status, spoiler_text: '', text: text, errors: activemodel_errors, local?: true, reblog?: false) - - subject.validate(status) - expect(status.errors).to have_received(:add) - end - end - - private - - def activemodel_errors - instance_double(ActiveModel::Errors, add: nil) - end -end diff --git a/spec/validators/status_pin_validator_spec.rb b/spec/validators/status_pin_validator_spec.rb deleted file mode 100644 index e8f8a4543..000000000 --- a/spec/validators/status_pin_validator_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe StatusPinValidator, type: :validator do - describe '#validate' do - before do - subject.validate(pin) - end - - let(:pin) { instance_double(StatusPin, account: account, errors: errors, status: status, account_id: pin_account_id) } - let(:status) { instance_double(Status, reblog?: reblog, account_id: status_account_id, visibility: visibility, direct_visibility?: visibility == 'direct') } - let(:account) { instance_double(Account, status_pins: status_pins, local?: local) } - let(:status_pins) { instance_double(Array, count: count) } - let(:errors) { instance_double(ActiveModel::Errors, add: nil) } - let(:pin_account_id) { 1 } - let(:status_account_id) { 1 } - let(:visibility) { 'public' } - let(:local) { false } - let(:reblog) { false } - let(:count) { 0 } - - context 'when pin.status.reblog?' do - let(:reblog) { true } - - it 'calls errors.add' do - expect(errors).to have_received(:add).with(:base, I18n.t('statuses.pin_errors.reblog')) - end - end - - context 'when pin.account_id != pin.status.account_id' do - let(:pin_account_id) { 1 } - let(:status_account_id) { 2 } - - it 'calls errors.add' do - expect(errors).to have_received(:add).with(:base, I18n.t('statuses.pin_errors.ownership')) - end - end - - context 'when pin.status.direct_visibility?' do - let(:visibility) { 'direct' } - - it 'calls errors.add' do - expect(errors).to have_received(:add).with(:base, I18n.t('statuses.pin_errors.direct')) - end - end - - context 'when pin.account.status_pins.count > 4 && pin.account.local?' do - let(:count) { 5 } - let(:local) { true } - - it 'calls errors.add' do - expect(errors).to have_received(:add).with(:base, I18n.t('statuses.pin_errors.limit')) - end - end - end -end diff --git a/spec/validators/unique_username_validator_spec.rb b/spec/validators/unique_username_validator_spec.rb deleted file mode 100644 index 0d172c840..000000000 --- a/spec/validators/unique_username_validator_spec.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe UniqueUsernameValidator do - describe '#validate' do - context 'when local account' do - it 'does not add errors if username is nil' do - account = instance_double(Account, username: nil, domain: nil, persisted?: false, errors: activemodel_errors) - subject.validate(account) - expect(account.errors).to_not have_received(:add) - end - - it 'does not add errors when existing one is subject itself' do - account = Fabricate(:account, username: 'abcdef') - expect(account).to be_valid - end - - it 'adds an error when the username is already used with ignoring cases' do - Fabricate(:account, username: 'ABCdef') - account = instance_double(Account, username: 'abcDEF', domain: nil, persisted?: false, errors: activemodel_errors) - subject.validate(account) - expect(account.errors).to have_received(:add) - end - - it 'does not add errors when same username remote account exists' do - Fabricate(:account, username: 'abcdef', domain: 'example.com') - account = instance_double(Account, username: 'abcdef', domain: nil, persisted?: false, errors: activemodel_errors) - subject.validate(account) - expect(account.errors).to_not have_received(:add) - end - end - end - - context 'when remote account' do - it 'does not add errors if username is nil' do - account = instance_double(Account, username: nil, domain: 'example.com', persisted?: false, errors: activemodel_errors) - subject.validate(account) - expect(account.errors).to_not have_received(:add) - end - - it 'does not add errors when existing one is subject itself' do - account = Fabricate(:account, username: 'abcdef', domain: 'example.com') - expect(account).to be_valid - end - - it 'adds an error when the username is already used with ignoring cases' do - Fabricate(:account, username: 'ABCdef', domain: 'example.com') - account = instance_double(Account, username: 'abcDEF', domain: 'example.com', persisted?: false, errors: activemodel_errors) - subject.validate(account) - expect(account.errors).to have_received(:add) - end - - it 'adds an error when the domain is already used with ignoring cases' do - Fabricate(:account, username: 'ABCdef', domain: 'example.com') - account = instance_double(Account, username: 'ABCdef', domain: 'EXAMPLE.COM', persisted?: false, errors: activemodel_errors) - subject.validate(account) - expect(account.errors).to have_received(:add) - end - - it 'does not add errors when account with the same username and another domain exists' do - Fabricate(:account, username: 'abcdef', domain: 'example.com') - account = instance_double(Account, username: 'abcdef', domain: 'example2.com', persisted?: false, errors: activemodel_errors) - subject.validate(account) - expect(account.errors).to_not have_received(:add) - end - end - - private - - def activemodel_errors - instance_double(ActiveModel::Errors, add: nil) - end -end diff --git a/spec/validators/unreserved_username_validator_spec.rb b/spec/validators/unreserved_username_validator_spec.rb deleted file mode 100644 index 6f353eeaf..000000000 --- a/spec/validators/unreserved_username_validator_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe UnreservedUsernameValidator, type: :validator do - describe '#validate' do - before do - allow(validator).to receive(:reserved_username?) { reserved_username } - validator.validate(account) - end - - let(:validator) { described_class.new } - let(:account) { instance_double(Account, username: username, errors: errors) } - let(:errors) { instance_double(ActiveModel::Errors, add: nil) } - - context 'when @username is blank?' do - let(:username) { nil } - - it 'not calls errors.add' do - expect(errors).to_not have_received(:add).with(:username, any_args) - end - end - - context 'when @username is not blank?' do - let(:username) { 'f' } - - context 'with reserved_username?' do - let(:reserved_username) { true } - - it 'calls errors.add' do - expect(errors).to have_received(:add).with(:username, :reserved) - end - end - - context 'when username is not reserved' do - let(:reserved_username) { false } - - it 'not calls errors.add' do - expect(errors).to_not have_received(:add).with(:username, any_args) - end - end - end - end -end diff --git a/spec/validators/url_validator_spec.rb b/spec/validators/url_validator_spec.rb deleted file mode 100644 index 4f32b7b39..000000000 --- a/spec/validators/url_validator_spec.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe URLValidator do - let(:record_class) do - Class.new do - include ActiveModel::Validations - attr_accessor :profile - - validates :profile, url: true - end - end - let(:record) { record_class.new } - - describe '#validate_each' do - context 'with a nil value' do - it 'adds errors' do - record.profile = nil - - expect(record).to_not be_valid - expect(record.errors.first.attribute).to eq(:profile) - expect(record.errors.first.type).to eq(:invalid) - end - end - - context 'with an invalid url scheme' do - it 'adds errors' do - record.profile = 'ftp://example.com/page' - - expect(record).to_not be_valid - expect(record.errors.first.attribute).to eq(:profile) - expect(record.errors.first.type).to eq(:invalid) - end - end - - context 'without a hostname' do - it 'adds errors' do - record.profile = 'https:///page' - - expect(record).to_not be_valid - expect(record.errors.first.attribute).to eq(:profile) - expect(record.errors.first.type).to eq(:invalid) - end - end - - context 'with an unparseable value' do - it 'adds errors' do - record.profile = 'https://host:port/page' # non-numeric port string causes invalid uri error - - expect(record).to_not be_valid - expect(record.errors.first.attribute).to eq(:profile) - expect(record.errors.first.type).to eq(:invalid) - end - end - - context 'with a valid url' do - it 'does not add errors' do - record.profile = 'https://example.com/page' - - expect(record).to be_valid - expect(record.errors).to be_empty - end - end - end -end diff --git a/spec/views/statuses/show.html.haml_spec.rb b/spec/views/statuses/show.html.haml_spec.rb deleted file mode 100644 index 354f9d3e6..000000000 --- a/spec/views/statuses/show.html.haml_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe 'statuses/show.html.haml', without_verify_partial_doubles: true do - before do - allow(view).to receive_messages(api_oembed_url: '', show_landing_strip?: true, site_title: 'example site', site_hostname: 'example.com', full_asset_url: '//asset.host/image.svg', current_account: nil, single_user_mode?: false) - allow(view).to receive(:local_time) - allow(view).to receive(:local_time_ago) - assign(:instance_presenter, InstancePresenter.new) - end - - it 'has valid opengraph tags' do - alice = Fabricate(:account, username: 'alice', display_name: 'Alice') - status = Fabricate(:status, account: alice, text: 'Hello World') - media = Fabricate(:media_attachment, account: alice, status: status, type: :video) - - assign(:status, status) - assign(:account, alice) - assign(:descendant_threads, []) - - render - - header_tags = view.content_for(:header_tags) - - expect(header_tags).to match(//) - expect(header_tags).to match(//) - expect(header_tags).to match(//) - expect(header_tags).to match(%r{}) - end - - it 'has twitter player tag' do - alice = Fabricate(:account, username: 'alice', display_name: 'Alice') - status = Fabricate(:status, account: alice, text: 'Hello World') - media = Fabricate(:media_attachment, account: alice, status: status, type: :video) - - assign(:status, status) - assign(:account, alice) - assign(:descendant_threads, []) - - render - - header_tags = view.content_for(:header_tags) - - expect(header_tags).to match(%r{}) - expect(header_tags).to match(//) - end -end diff --git a/spec/workers/activitypub/delivery_worker_spec.rb b/spec/workers/activitypub/delivery_worker_spec.rb deleted file mode 100644 index d39393d50..000000000 --- a/spec/workers/activitypub/delivery_worker_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::DeliveryWorker do - include RoutingHelper - - subject { described_class.new } - - let(:sender) { Fabricate(:account) } - let(:payload) { 'test' } - - before do - allow_any_instance_of(Account).to receive(:remote_followers_hash).with('https://example.com/api').and_return('somehash') - end - - describe 'perform' do - it 'performs a request' do - stub_request(:post, 'https://example.com/api').to_return(status: 200) - subject.perform(payload, sender.id, 'https://example.com/api', { synchronize_followers: true }) - expect(a_request(:post, 'https://example.com/api').with(headers: { 'Collection-Synchronization' => "collectionId=\"#{account_followers_url(sender)}\", digest=\"somehash\", url=\"#{account_followers_synchronization_url(sender)}\"" })).to have_been_made.once - end - - it 'raises when request fails' do - stub_request(:post, 'https://example.com/api').to_return(status: 500) - expect { subject.perform(payload, sender.id, 'https://example.com/api') }.to raise_error Mastodon::UnexpectedResponseError - end - end -end diff --git a/spec/workers/activitypub/distribute_poll_update_worker_spec.rb b/spec/workers/activitypub/distribute_poll_update_worker_spec.rb deleted file mode 100644 index 0bdbf6390..000000000 --- a/spec/workers/activitypub/distribute_poll_update_worker_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::DistributePollUpdateWorker do - subject { described_class.new } - - let(:account) { Fabricate(:account) } - let(:follower) { Fabricate(:account, protocol: :activitypub, inbox_url: 'http://example.com', domain: 'example.com') } - let(:poll) { Fabricate(:poll, account: account) } - let!(:status) { Fabricate(:status, account: account, poll: poll) } - - describe '#perform' do - before do - follower.follow!(account) - end - - it 'delivers to followers' do - expect_push_bulk_to_match(ActivityPub::DeliveryWorker, [[kind_of(String), account.id, 'http://example.com']]) - subject.perform(status.id) - end - end -end diff --git a/spec/workers/activitypub/distribution_worker_spec.rb b/spec/workers/activitypub/distribution_worker_spec.rb deleted file mode 100644 index d8803f6b8..000000000 --- a/spec/workers/activitypub/distribution_worker_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::DistributionWorker do - subject { described_class.new } - - let(:status) { Fabricate(:status) } - let(:follower) { Fabricate(:account, protocol: :activitypub, inbox_url: 'http://example.com', domain: 'example.com') } - - describe '#perform' do - before do - follower.follow!(status.account) - end - - context 'with public status' do - before do - status.update(visibility: :public) - end - - it 'delivers to followers' do - expect_push_bulk_to_match(ActivityPub::DeliveryWorker, [[kind_of(String), status.account.id, 'http://example.com', anything]]) - subject.perform(status.id) - end - end - - context 'with private status' do - before do - status.update(visibility: :private) - end - - it 'delivers to followers' do - expect_push_bulk_to_match(ActivityPub::DeliveryWorker, [[kind_of(String), status.account.id, 'http://example.com', anything]]) - subject.perform(status.id) - end - end - - context 'with direct status' do - let(:mentioned_account) { Fabricate(:account, protocol: :activitypub, inbox_url: 'https://foo.bar/inbox', domain: 'foo.bar') } - - before do - status.update(visibility: :direct) - status.mentions.create!(account: mentioned_account) - end - - it 'delivers to mentioned accounts' do - expect_push_bulk_to_match(ActivityPub::DeliveryWorker, [[kind_of(String), status.account.id, 'https://foo.bar/inbox', anything]]) - subject.perform(status.id) - end - end - end -end diff --git a/spec/workers/activitypub/fetch_replies_worker_spec.rb b/spec/workers/activitypub/fetch_replies_worker_spec.rb deleted file mode 100644 index ff4d049a2..000000000 --- a/spec/workers/activitypub/fetch_replies_worker_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::FetchRepliesWorker do - subject { described_class.new } - - let(:account) { Fabricate(:account, domain: 'example.com') } - let(:status) { Fabricate(:status, account: account) } - - let(:payload) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://example.com/statuses_replies/1', - type: 'Collection', - items: [], - } - end - - let(:json) { Oj.dump(payload) } - - describe 'perform' do - it 'performs a request if the collection URI is from the same host' do - stub_request(:get, 'https://example.com/statuses_replies/1').to_return(status: 200, body: json) - subject.perform(status.id, 'https://example.com/statuses_replies/1') - expect(a_request(:get, 'https://example.com/statuses_replies/1')).to have_been_made.once - end - - it 'does not perform a request if the collection URI is from a different host' do - stub_request(:get, 'https://other.com/statuses_replies/1').to_return(status: 200) - subject.perform(status.id, 'https://other.com/statuses_replies/1') - expect(a_request(:get, 'https://other.com/statuses_replies/1')).to_not have_been_made - end - - it 'raises when request fails' do - stub_request(:get, 'https://example.com/statuses_replies/1').to_return(status: 500) - expect { subject.perform(status.id, 'https://example.com/statuses_replies/1') }.to raise_error Mastodon::UnexpectedResponseError - end - end -end diff --git a/spec/workers/activitypub/move_distribution_worker_spec.rb b/spec/workers/activitypub/move_distribution_worker_spec.rb deleted file mode 100644 index b8601f78c..000000000 --- a/spec/workers/activitypub/move_distribution_worker_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::MoveDistributionWorker do - subject { described_class.new } - - let(:migration) { Fabricate(:account_migration) } - let(:follower) { Fabricate(:account, protocol: :activitypub, inbox_url: 'http://example.com', domain: 'example.com') } - let(:blocker) { Fabricate(:account, protocol: :activitypub, inbox_url: 'http://example2.com', domain: 'example2.com') } - - describe '#perform' do - before do - follower.follow!(migration.account) - blocker.block!(migration.account) - end - - it 'delivers to followers and known blockers' do - expect_push_bulk_to_match(ActivityPub::DeliveryWorker, [ - [kind_of(String), migration.account.id, 'http://example.com'], - [kind_of(String), migration.account.id, 'http://example2.com'], - ]) - subject.perform(migration.id) - end - end -end diff --git a/spec/workers/activitypub/processing_worker_spec.rb b/spec/workers/activitypub/processing_worker_spec.rb deleted file mode 100644 index 66d1cf489..000000000 --- a/spec/workers/activitypub/processing_worker_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::ProcessingWorker do - subject { described_class.new } - - let(:account) { Fabricate(:account) } - - describe '#perform' do - it 'delegates to ActivityPub::ProcessCollectionService' do - allow(ActivityPub::ProcessCollectionService).to receive(:new) - .and_return(instance_double(ActivityPub::ProcessCollectionService, call: nil)) - subject.perform(account.id, '') - expect(ActivityPub::ProcessCollectionService).to have_received(:new) - end - end -end diff --git a/spec/workers/activitypub/status_update_distribution_worker_spec.rb b/spec/workers/activitypub/status_update_distribution_worker_spec.rb deleted file mode 100644 index c500bac95..000000000 --- a/spec/workers/activitypub/status_update_distribution_worker_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::StatusUpdateDistributionWorker do - subject { described_class.new } - - let(:status) { Fabricate(:status, text: 'foo') } - let(:follower) { Fabricate(:account, protocol: :activitypub, inbox_url: 'http://example.com', domain: 'example.com') } - - describe '#perform' do - before do - follower.follow!(status.account) - - status.snapshot! - status.text = 'bar' - status.edited_at = Time.now.utc - status.snapshot! - status.save! - end - - context 'with public status' do - before do - status.update(visibility: :public) - end - - it 'delivers to followers' do - expect_push_bulk_to_match(ActivityPub::DeliveryWorker, [[kind_of(String), status.account.id, 'http://example.com', anything]]) - - subject.perform(status.id) - end - end - - context 'with private status' do - before do - status.update(visibility: :private) - end - - it 'delivers to followers' do - expect_push_bulk_to_match(ActivityPub::DeliveryWorker, [[kind_of(String), status.account.id, 'http://example.com', anything]]) - - subject.perform(status.id) - end - end - end -end diff --git a/spec/workers/activitypub/update_distribution_worker_spec.rb b/spec/workers/activitypub/update_distribution_worker_spec.rb deleted file mode 100644 index d0eeda43b..000000000 --- a/spec/workers/activitypub/update_distribution_worker_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ActivityPub::UpdateDistributionWorker do - subject { described_class.new } - - let(:account) { Fabricate(:account) } - let(:follower) { Fabricate(:account, protocol: :activitypub, inbox_url: 'http://example.com', domain: 'example.com') } - - describe '#perform' do - before do - follower.follow!(account) - end - - it 'delivers to followers' do - expect_push_bulk_to_match(ActivityPub::DeliveryWorker, [[kind_of(String), account.id, 'http://example.com', anything]]) - subject.perform(account.id) - end - end -end diff --git a/spec/workers/add_to_public_statuses_index_worker_spec.rb b/spec/workers/add_to_public_statuses_index_worker_spec.rb deleted file mode 100644 index fa1507224..000000000 --- a/spec/workers/add_to_public_statuses_index_worker_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe AddToPublicStatusesIndexWorker do - describe '#perform' do - let(:account) { Fabricate(:account, indexable: indexable) } - let(:account_id) { account.id } - - before do - allow(Account).to receive(:find).with(account_id).and_return(account) unless account.nil? - allow(account).to receive(:add_to_public_statuses_index!) unless account.nil? - end - - context 'when account is indexable' do - let(:indexable) { true } - - it 'adds the account to the public statuses index' do - subject.perform(account_id) - expect(account).to have_received(:add_to_public_statuses_index!) - end - end - - context 'when account is not indexable' do - let(:indexable) { false } - - it 'does not add the account to public statuses index' do - subject.perform(account_id) - expect(account).to_not have_received(:add_to_public_statuses_index!) - end - end - - context 'when account does not exist' do - let(:account) { nil } - let(:account_id) { 999 } - - it 'does not raise an error' do - expect { subject.perform(account_id) }.to_not raise_error - end - end - end -end diff --git a/spec/workers/admin/account_deletion_worker_spec.rb b/spec/workers/admin/account_deletion_worker_spec.rb deleted file mode 100644 index 631cab664..000000000 --- a/spec/workers/admin/account_deletion_worker_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Admin::AccountDeletionWorker do - let(:worker) { described_class.new } - - describe 'perform' do - let(:account) { Fabricate(:account) } - let(:service) { instance_double(DeleteAccountService, call: true) } - - it 'calls delete account service' do - allow(DeleteAccountService).to receive(:new).and_return(service) - worker.perform(account.id) - - expect(service).to have_received(:call).with(account, { reserve_email: true, reserve_username: true }) - end - end -end diff --git a/spec/workers/admin/domain_purge_worker_spec.rb b/spec/workers/admin/domain_purge_worker_spec.rb deleted file mode 100644 index 861fd71a7..000000000 --- a/spec/workers/admin/domain_purge_worker_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Admin::DomainPurgeWorker do - subject { described_class.new } - - describe 'perform' do - it 'calls domain purge service for relevant domain block' do - service = instance_double(PurgeDomainService, call: nil) - allow(PurgeDomainService).to receive(:new).and_return(service) - result = subject.perform('example.com') - - expect(result).to be_nil - expect(service).to have_received(:call).with('example.com') - end - end -end diff --git a/spec/workers/bulk_import_worker_spec.rb b/spec/workers/bulk_import_worker_spec.rb deleted file mode 100644 index 91f51fbb4..000000000 --- a/spec/workers/bulk_import_worker_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe BulkImportWorker do - subject { described_class.new } - - let(:import) { Fabricate(:bulk_import, state: :scheduled) } - - describe '#perform' do - let(:service_double) { instance_double(BulkImportService, call: nil) } - - before do - allow(BulkImportService).to receive(:new).and_return(service_double) - end - - it 'changes the import\'s state as appropriate' do - expect { subject.perform(import.id) }.to change { import.reload.state.to_sym }.from(:scheduled).to(:in_progress) - end - - it 'calls BulkImportService' do - subject.perform(import.id) - expect(service_double).to have_received(:call).with(import) - end - end -end diff --git a/spec/workers/cache_buster_worker_spec.rb b/spec/workers/cache_buster_worker_spec.rb deleted file mode 100644 index adeb287fa..000000000 --- a/spec/workers/cache_buster_worker_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe CacheBusterWorker do - let(:worker) { described_class.new } - - describe 'perform' do - let(:path) { 'https://example.com' } - let(:service) { instance_double(CacheBuster, bust: true) } - - it 'calls the cache buster' do - allow(CacheBuster).to receive(:new).and_return(service) - worker.perform(path) - - expect(service).to have_received(:bust).with(path) - end - end -end diff --git a/spec/workers/domain_block_worker_spec.rb b/spec/workers/domain_block_worker_spec.rb deleted file mode 100644 index 33c3ca009..000000000 --- a/spec/workers/domain_block_worker_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe DomainBlockWorker do - subject { described_class.new } - - describe 'perform' do - let(:domain_block) { Fabricate(:domain_block) } - - it 'calls domain block service for relevant domain block' do - service = instance_double(BlockDomainService, call: nil) - allow(BlockDomainService).to receive(:new).and_return(service) - result = subject.perform(domain_block.id) - - expect(result).to be_nil - expect(service).to have_received(:call).with(domain_block, false) - end - - it 'returns true for non-existent domain block' do - result = subject.perform('aaa') - - expect(result).to be(true) - end - end -end diff --git a/spec/workers/domain_clear_media_worker_spec.rb b/spec/workers/domain_clear_media_worker_spec.rb deleted file mode 100644 index 21f8f87b2..000000000 --- a/spec/workers/domain_clear_media_worker_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe DomainClearMediaWorker do - subject { described_class.new } - - describe 'perform' do - let(:domain_block) { Fabricate(:domain_block, severity: :silence, reject_media: true) } - - it 'calls domain clear media service for relevant domain block' do - service = instance_double(ClearDomainMediaService, call: nil) - allow(ClearDomainMediaService).to receive(:new).and_return(service) - result = subject.perform(domain_block.id) - - expect(result).to be_nil - expect(service).to have_received(:call).with(domain_block) - end - - it 'returns true for non-existent domain block' do - result = subject.perform('aaa') - - expect(result).to be(true) - end - end -end diff --git a/spec/workers/feed_insert_worker_spec.rb b/spec/workers/feed_insert_worker_spec.rb deleted file mode 100644 index 97c73c599..000000000 --- a/spec/workers/feed_insert_worker_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe FeedInsertWorker do - subject { described_class.new } - - describe 'perform' do - let(:follower) { Fabricate(:account) } - let(:status) { Fabricate(:status) } - - context 'when there are no records' do - it 'skips push with missing status' do - instance = instance_double(FeedManager, push_to_home: nil) - allow(FeedManager).to receive(:instance).and_return(instance) - result = subject.perform(nil, follower.id) - - expect(result).to be true - expect(instance).to_not have_received(:push_to_home) - end - - it 'skips push with missing account' do - instance = instance_double(FeedManager, push_to_home: nil) - allow(FeedManager).to receive(:instance).and_return(instance) - result = subject.perform(status.id, nil) - - expect(result).to be true - expect(instance).to_not have_received(:push_to_home) - end - end - - context 'when there are real records' do - it 'skips the push when there is a filter' do - instance = instance_double(FeedManager, push_to_home: nil, filter?: true) - allow(FeedManager).to receive(:instance).and_return(instance) - result = subject.perform(status.id, follower.id) - - expect(result).to be_nil - expect(instance).to_not have_received(:push_to_home) - end - - it 'pushes the status onto the home timeline without filter' do - instance = instance_double(FeedManager, push_to_home: nil, filter?: false) - allow(FeedManager).to receive(:instance).and_return(instance) - result = subject.perform(status.id, follower.id) - - expect(result).to be_nil - expect(instance).to have_received(:push_to_home).with(follower, status, update: nil) - end - end - end -end diff --git a/spec/workers/import/row_worker_spec.rb b/spec/workers/import/row_worker_spec.rb deleted file mode 100644 index 0a71a838f..000000000 --- a/spec/workers/import/row_worker_spec.rb +++ /dev/null @@ -1,127 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Import::RowWorker do - subject { described_class.new } - - let(:row) { Fabricate(:bulk_import_row, bulk_import: import) } - - describe '#perform' do - before do - allow(BulkImportRowService).to receive(:new).and_return(service_double) - end - - shared_examples 'clean failure' do - let(:service_double) { instance_double(BulkImportRowService, call: false) } - - it 'calls BulkImportRowService' do - subject.perform(row.id) - expect(service_double).to have_received(:call).with(row) - end - - it 'increases the number of processed items' do - expect { subject.perform(row.id) }.to(change { import.reload.processed_items }.by(+1)) - end - - it 'does not increase the number of imported items' do - expect { subject.perform(row.id) }.to_not(change { import.reload.imported_items }) - end - - it 'does not delete the row' do - subject.perform(row.id) - expect(BulkImportRow.exists?(row.id)).to be true - end - end - - shared_examples 'unclean failure' do - let(:service_double) { instance_double(BulkImportRowService) } - - before do - allow(service_double).to receive(:call) do - raise 'dummy error' - end - end - - it 'raises an error and does not change processed items count' do - expect { subject.perform(row.id) }.to raise_error(StandardError, 'dummy error').and(not_change { import.reload.processed_items }) - end - - it 'does not delete the row' do - expect { subject.perform(row.id) }.to raise_error(StandardError, 'dummy error').and(not_change { BulkImportRow.exists?(row.id) }) - end - end - - shared_examples 'clean success' do - let(:service_double) { instance_double(BulkImportRowService, call: true) } - - it 'calls BulkImportRowService' do - subject.perform(row.id) - expect(service_double).to have_received(:call).with(row) - end - - it 'increases the number of processed items' do - expect { subject.perform(row.id) }.to(change { import.reload.processed_items }.by(+1)) - end - - it 'increases the number of imported items' do - expect { subject.perform(row.id) }.to(change { import.reload.imported_items }.by(+1)) - end - - it 'deletes the row' do - expect { subject.perform(row.id) }.to change { BulkImportRow.exists?(row.id) }.from(true).to(false) - end - end - - context 'when there are multiple rows to process' do - let(:import) { Fabricate(:bulk_import, total_items: 2, processed_items: 0, imported_items: 0, state: :in_progress) } - - context 'with a clean failure' do - include_examples 'clean failure' - - it 'does not mark the import as finished' do - expect { subject.perform(row.id) }.to_not(change { import.reload.state.to_sym }) - end - end - - context 'with an unclean failure' do - include_examples 'unclean failure' - - it 'does not mark the import as finished' do - expect { subject.perform(row.id) }.to raise_error(StandardError).and(not_change { import.reload.state.to_sym }) - end - end - - context 'with a clean success' do - include_examples 'clean success' - - it 'does not mark the import as finished' do - expect { subject.perform(row.id) }.to_not(change { import.reload.state.to_sym }) - end - end - end - - context 'when this is the last row to process' do - let(:import) { Fabricate(:bulk_import, total_items: 2, processed_items: 1, imported_items: 0, state: :in_progress) } - - context 'with a clean failure' do - include_examples 'clean failure' - - it 'marks the import as finished' do - expect { subject.perform(row.id) }.to change { import.reload.state.to_sym }.from(:in_progress).to(:finished) - end - end - - # NOTE: sidekiq retry logic may be a bit too difficult to test, so leaving this blind spot for now - it_behaves_like 'unclean failure' - - context 'with a clean success' do - include_examples 'clean success' - - it 'marks the import as finished' do - expect { subject.perform(row.id) }.to change { import.reload.state.to_sym }.from(:in_progress).to(:finished) - end - end - end - end -end diff --git a/spec/workers/move_worker_spec.rb b/spec/workers/move_worker_spec.rb deleted file mode 100644 index 7577f6e89..000000000 --- a/spec/workers/move_worker_spec.rb +++ /dev/null @@ -1,197 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe MoveWorker do - subject { described_class.new } - - let(:local_follower) { Fabricate(:account, domain: nil) } - let(:blocking_account) { Fabricate(:account) } - let(:muting_account) { Fabricate(:account) } - let(:source_account) { Fabricate(:account, protocol: :activitypub, domain: 'example.com', uri: 'https://example.org/a', inbox_url: 'https://example.org/a/inbox') } - let(:target_account) { Fabricate(:account, protocol: :activitypub, domain: 'example.com', uri: 'https://example.org/b', inbox_url: 'https://example.org/b/inbox') } - let(:local_user) { Fabricate(:user) } - let(:comment) { 'old note prior to move' } - let!(:account_note) { Fabricate(:account_note, account: local_user.account, target_account: source_account, comment: comment) } - let(:list) { Fabricate(:list, account: local_follower) } - - let(:block_service) { instance_double(BlockService) } - - before do - stub_request(:post, 'https://example.org/a/inbox').to_return(status: 200) - stub_request(:post, 'https://example.org/b/inbox').to_return(status: 200) - - local_follower.follow!(source_account) - blocking_account.block!(source_account) - muting_account.mute!(source_account) - - list.accounts << source_account - - allow(BlockService).to receive(:new).and_return(block_service) - allow(block_service).to receive(:call) - end - - shared_examples 'user note handling' do - context 'when user notes are short enough' do - it 'copies user note with prelude' do - subject.perform(source_account.id, target_account.id) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(source_account.acct) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(account_note.comment) - end - - it 'merges user notes when needed' do - new_account_note = AccountNote.create!(account: account_note.account, target_account: target_account, comment: 'new note prior to move') - - subject.perform(source_account.id, target_account.id) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(source_account.acct) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(account_note.comment) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(new_account_note.comment) - end - end - - context 'when user notes are too long' do - let(:comment) { 'abc' * 333 } - - it 'copies user note without prelude' do - subject.perform(source_account.id, target_account.id) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(account_note.comment) - end - - it 'keeps user notes unchanged' do - new_account_note = AccountNote.create!(account: account_note.account, target_account: target_account, comment: 'new note prior to move') - - subject.perform(source_account.id, target_account.id) - expect(AccountNote.find_by(account: account_note.account, target_account: target_account).comment).to include(new_account_note.comment) - end - end - end - - shared_examples 'block and mute handling' do - it 'makes blocks carry over and add a note' do - subject.perform(source_account.id, target_account.id) - expect(block_service).to have_received(:call).with(blocking_account, target_account) - expect(AccountNote.find_by(account: blocking_account, target_account: target_account).comment).to include(source_account.acct) - end - - it 'makes mutes carry over and add a note' do - subject.perform(source_account.id, target_account.id) - expect(muting_account.muting?(target_account)).to be true - expect(AccountNote.find_by(account: muting_account, target_account: target_account).comment).to include(source_account.acct) - end - end - - shared_examples 'followers count handling' do - it 'updates the source account followers count' do - subject.perform(source_account.id, target_account.id) - expect(source_account.reload.followers_count).to eq(source_account.passive_relationships.count) - end - - it 'updates the target account followers count' do - subject.perform(source_account.id, target_account.id) - expect(target_account.reload.followers_count).to eq(target_account.passive_relationships.count) - end - end - - shared_examples 'lists handling' do - it 'puts the new account on the list' do - subject.perform(source_account.id, target_account.id) - expect(list.accounts.include?(target_account)).to be true - end - - it 'does not create invalid list memberships' do - subject.perform(source_account.id, target_account.id) - expect(ListAccount.all).to all be_valid - end - end - - shared_examples 'common tests' do - include_examples 'user note handling' - include_examples 'block and mute handling' - include_examples 'followers count handling' - include_examples 'lists handling' - - context 'when a local user already follows both source and target' do - before do - local_follower.request_follow!(target_account) - end - - include_examples 'user note handling' - include_examples 'block and mute handling' - include_examples 'followers count handling' - include_examples 'lists handling' - - context 'when the local user already has the target in a list' do - before do - list.accounts << target_account - end - - include_examples 'lists handling' - end - end - - context 'when a local follower already has a pending request to the target' do - before do - local_follower.follow!(target_account) - end - - include_examples 'user note handling' - include_examples 'block and mute handling' - include_examples 'followers count handling' - include_examples 'lists handling' - - context 'when the local user already has the target in a list' do - before do - list.accounts << target_account - end - - include_examples 'lists handling' - end - end - end - - describe '#perform' do - context 'when both accounts are distant' do - it 'calls UnfollowFollowWorker' do - Sidekiq::Testing.fake! do - subject.perform(source_account.id, target_account.id) - expect(UnfollowFollowWorker).to have_enqueued_sidekiq_job(local_follower.id, source_account.id, target_account.id, false) - Sidekiq::Worker.drain_all - end - end - - include_examples 'common tests' - end - - context 'when target account is local' do - let(:target_account) { Fabricate(:account) } - - it 'calls UnfollowFollowWorker' do - Sidekiq::Testing.fake! do - subject.perform(source_account.id, target_account.id) - expect(UnfollowFollowWorker).to have_enqueued_sidekiq_job(local_follower.id, source_account.id, target_account.id, true) - Sidekiq::Worker.clear_all - end - end - - include_examples 'common tests' - end - - context 'when both target and source accounts are local' do - let(:target_account) { Fabricate(:account) } - let(:source_account) { Fabricate(:account) } - - it 'calls makes local followers follow the target account' do - subject.perform(source_account.id, target_account.id) - expect(local_follower.following?(target_account)).to be true - end - - include_examples 'common tests' - - it 'does not allow the moved account to follow themselves' do - source_account.follow!(target_account) - subject.perform(source_account.id, target_account.id) - expect(target_account.following?(target_account)).to be false - end - end - end -end diff --git a/spec/workers/poll_expiration_notify_worker_spec.rb b/spec/workers/poll_expiration_notify_worker_spec.rb deleted file mode 100644 index 78cbc1ee4..000000000 --- a/spec/workers/poll_expiration_notify_worker_spec.rb +++ /dev/null @@ -1,72 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe PollExpirationNotifyWorker do - let(:worker) { described_class.new } - let(:account) { Fabricate(:account, domain: remote? ? 'example.com' : nil) } - let(:status) { Fabricate(:status, account: account) } - let(:poll) { Fabricate(:poll, status: status, account: account) } - let(:remote?) { false } - let(:poll_vote) { Fabricate(:poll_vote, poll: poll) } - - describe '#perform' do - around do |example| - Sidekiq::Testing.fake! do - example.run - end - end - - it 'runs without error for missing record' do - expect { worker.perform(nil) }.to_not raise_error - end - - context 'when poll is not expired' do - it 'requeues job' do - worker.perform(poll.id) - expect(described_class.sidekiq_options_hash['lock']).to be :until_executing - expect(described_class).to have_enqueued_sidekiq_job(poll.id).at(poll.expires_at + 5.minutes) - end - end - - context 'when poll is expired' do - before do - poll_vote - - travel_to poll.expires_at + 5.minutes - - worker.perform(poll.id) - end - - context 'when poll is local' do - it 'notifies voters' do - expect(ActivityPub::DistributePollUpdateWorker).to have_enqueued_sidekiq_job(poll.status.id) - end - - it 'notifies owner' do - expect(LocalNotificationWorker).to have_enqueued_sidekiq_job(poll.account.id, poll.id, 'Poll', 'poll') - end - - it 'notifies local voters' do - expect(LocalNotificationWorker).to have_enqueued_sidekiq_job(poll_vote.account.id, poll.id, 'Poll', 'poll') - end - end - - context 'when poll is remote' do - let(:remote?) { true } - - it 'does not notify remote voters' do - expect(ActivityPub::DistributePollUpdateWorker).to_not have_enqueued_sidekiq_job(poll.status.id) - end - - it 'does not notify owner' do - expect(LocalNotificationWorker).to_not have_enqueued_sidekiq_job(poll.account.id, poll.id, 'Poll', 'poll') - end - - it 'notifies local voters' do - expect(LocalNotificationWorker).to have_enqueued_sidekiq_job(poll_vote.account.id, poll.id, 'Poll', 'poll') - end - end - end - end -end diff --git a/spec/workers/post_process_media_worker_spec.rb b/spec/workers/post_process_media_worker_spec.rb deleted file mode 100644 index 33072704b..000000000 --- a/spec/workers/post_process_media_worker_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe PostProcessMediaWorker do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error for missing record' do - expect { worker.perform(nil) }.to_not raise_error - end - end -end diff --git a/spec/workers/publish_scheduled_announcement_worker_spec.rb b/spec/workers/publish_scheduled_announcement_worker_spec.rb deleted file mode 100644 index 2e50d4a50..000000000 --- a/spec/workers/publish_scheduled_announcement_worker_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe PublishScheduledAnnouncementWorker do - subject { described_class.new } - - let!(:remote_account) { Fabricate(:account, domain: 'domain.com', username: 'foo', uri: 'https://domain.com/users/foo') } - let!(:remote_status) { Fabricate(:status, uri: 'https://domain.com/users/foo/12345', account: remote_account) } - let!(:local_status) { Fabricate(:status) } - let(:scheduled_announcement) { Fabricate(:announcement, text: "rebooting very soon, see #{ActivityPub::TagManager.instance.uri_for(remote_status)} and #{ActivityPub::TagManager.instance.uri_for(local_status)}") } - - describe 'perform' do - before do - service = instance_double(FetchRemoteStatusService) - allow(FetchRemoteStatusService).to receive(:new).and_return(service) - allow(service).to receive(:call).with('https://domain.com/users/foo/12345') { remote_status.reload } - - subject.perform(scheduled_announcement.id) - end - - it 'updates the linked statuses' do - expect(scheduled_announcement.reload.status_ids).to eq [remote_status.id, local_status.id] - end - end -end diff --git a/spec/workers/publish_scheduled_status_worker_spec.rb b/spec/workers/publish_scheduled_status_worker_spec.rb deleted file mode 100644 index f8547e6fe..000000000 --- a/spec/workers/publish_scheduled_status_worker_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe PublishScheduledStatusWorker do - subject { described_class.new } - - let(:scheduled_status) { Fabricate(:scheduled_status, params: { text: 'Hello world, future!' }) } - - describe 'perform' do - before do - subject.perform(scheduled_status.id) - end - - it 'creates a status' do - expect(scheduled_status.account.statuses.first.text).to eq 'Hello world, future!' - end - - it 'removes the scheduled status' do - expect(ScheduledStatus.find_by(id: scheduled_status.id)).to be_nil - end - end -end diff --git a/spec/workers/push_conversation_worker_spec.rb b/spec/workers/push_conversation_worker_spec.rb deleted file mode 100644 index 5fbb4c685..000000000 --- a/spec/workers/push_conversation_worker_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe PushConversationWorker do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error for missing record' do - expect { worker.perform(nil) }.to_not raise_error - end - end -end diff --git a/spec/workers/push_encrypted_message_worker_spec.rb b/spec/workers/push_encrypted_message_worker_spec.rb deleted file mode 100644 index 3cd04ce7b..000000000 --- a/spec/workers/push_encrypted_message_worker_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe PushEncryptedMessageWorker do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error for missing record' do - expect { worker.perform(nil) }.to_not raise_error - end - end -end diff --git a/spec/workers/push_update_worker_spec.rb b/spec/workers/push_update_worker_spec.rb deleted file mode 100644 index c8f94fa82..000000000 --- a/spec/workers/push_update_worker_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe PushUpdateWorker do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error for missing record' do - account_id = nil - status_id = nil - - expect { worker.perform(account_id, status_id) }.to_not raise_error - end - end -end diff --git a/spec/workers/redownload_avatar_worker_spec.rb b/spec/workers/redownload_avatar_worker_spec.rb deleted file mode 100644 index b44ae9f03..000000000 --- a/spec/workers/redownload_avatar_worker_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe RedownloadAvatarWorker do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error for missing record' do - expect { worker.perform(nil) }.to_not raise_error - end - end -end diff --git a/spec/workers/redownload_header_worker_spec.rb b/spec/workers/redownload_header_worker_spec.rb deleted file mode 100644 index 767ae7a5a..000000000 --- a/spec/workers/redownload_header_worker_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe RedownloadHeaderWorker do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error for missing record' do - expect { worker.perform(nil) }.to_not raise_error - end - end -end diff --git a/spec/workers/refollow_worker_spec.rb b/spec/workers/refollow_worker_spec.rb deleted file mode 100644 index 5718d4db4..000000000 --- a/spec/workers/refollow_worker_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe RefollowWorker do - subject { described_class.new } - - let(:account) { Fabricate(:account, domain: 'example.org', protocol: :activitypub) } - let(:alice) { Fabricate(:account, domain: nil, username: 'alice') } - let(:bob) { Fabricate(:account, domain: nil, username: 'bob') } - - describe 'perform' do - let(:service) { instance_double(FollowService) } - - before do - allow(FollowService).to receive(:new).and_return(service) - allow(service).to receive(:call) - - alice.follow!(account, reblogs: true) - bob.follow!(account, reblogs: false) - end - - it 'calls FollowService for local followers' do - result = subject.perform(account.id) - - expect(result).to be_nil - expect(service).to have_received(:call).with(alice, account, reblogs: true, notify: false, languages: nil, bypass_limit: true) - expect(service).to have_received(:call).with(bob, account, reblogs: false, notify: false, languages: nil, bypass_limit: true) - end - end -end diff --git a/spec/workers/regeneration_worker_spec.rb b/spec/workers/regeneration_worker_spec.rb deleted file mode 100644 index 37b0a04c4..000000000 --- a/spec/workers/regeneration_worker_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe RegenerationWorker do - subject { described_class.new } - - describe 'perform' do - let(:account) { Fabricate(:account) } - - it 'calls the precompute feed service for the account' do - service = instance_double(PrecomputeFeedService, call: nil) - allow(PrecomputeFeedService).to receive(:new).and_return(service) - result = subject.perform(account.id) - - expect(result).to be_nil - expect(service).to have_received(:call).with(account) - end - - it 'fails when account does not exist' do - result = subject.perform('aaa') - - expect(result).to be(true) - end - end -end diff --git a/spec/workers/remove_featured_tag_worker_spec.rb b/spec/workers/remove_featured_tag_worker_spec.rb deleted file mode 100644 index a64bd0605..000000000 --- a/spec/workers/remove_featured_tag_worker_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe RemoveFeaturedTagWorker do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error for missing record' do - account_id = nil - featured_tag_id = nil - expect { worker.perform(account_id, featured_tag_id) }.to_not raise_error - end - end -end diff --git a/spec/workers/remove_from_public_statuses_index_worker_spec.rb b/spec/workers/remove_from_public_statuses_index_worker_spec.rb deleted file mode 100644 index 43ff211ea..000000000 --- a/spec/workers/remove_from_public_statuses_index_worker_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe RemoveFromPublicStatusesIndexWorker do - describe '#perform' do - let(:account) { Fabricate(:account, indexable: indexable) } - let(:account_id) { account.id } - - before do - allow(Account).to receive(:find).with(account_id).and_return(account) unless account.nil? - allow(account).to receive(:remove_from_public_statuses_index!) unless account.nil? - end - - context 'when account is not indexable' do - let(:indexable) { false } - - it 'removes the account from public statuses index' do - subject.perform(account_id) - expect(account).to have_received(:remove_from_public_statuses_index!) - end - end - - context 'when account is indexable' do - let(:indexable) { true } - - it 'does not remove the account from public statuses index' do - subject.perform(account_id) - expect(account).to_not have_received(:remove_from_public_statuses_index!) - end - end - - context 'when account does not exist' do - let(:account) { nil } - let(:account_id) { 999 } - - it 'does not raise an error' do - expect { subject.perform(account_id) }.to_not raise_error - end - end - end -end diff --git a/spec/workers/resolve_account_worker_spec.rb b/spec/workers/resolve_account_worker_spec.rb deleted file mode 100644 index 6f3cff099..000000000 --- a/spec/workers/resolve_account_worker_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ResolveAccountWorker do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error for missing record' do - expect { worker.perform(nil) }.to_not raise_error - end - end -end diff --git a/spec/workers/scheduler/accounts_statuses_cleanup_scheduler_spec.rb b/spec/workers/scheduler/accounts_statuses_cleanup_scheduler_spec.rb deleted file mode 100644 index 4d9185093..000000000 --- a/spec/workers/scheduler/accounts_statuses_cleanup_scheduler_spec.rb +++ /dev/null @@ -1,171 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Scheduler::AccountsStatusesCleanupScheduler do - subject { described_class.new } - - let!(:account_alice) { Fabricate(:account, domain: nil, username: 'alice') } - let!(:account_bob) { Fabricate(:account, domain: nil, username: 'bob') } - let!(:account_chris) { Fabricate(:account, domain: nil, username: 'chris') } - let!(:account_dave) { Fabricate(:account, domain: nil, username: 'dave') } - let!(:account_erin) { Fabricate(:account, domain: nil, username: 'erin') } - let!(:remote) { Fabricate(:account) } - - let(:queue_size) { 0 } - let(:queue_latency) { 0 } - let(:process_set_stub) do - [ - { - 'concurrency' => 2, - 'queues' => %w(push default), - }, - ] - end - - before do - queue_stub = instance_double(Sidekiq::Queue, size: queue_size, latency: queue_latency) - allow(Sidekiq::Queue).to receive(:new).and_return(queue_stub) - allow(Sidekiq::ProcessSet).to receive(:new).and_return(process_set_stub) - - sidekiq_stats_stub = instance_double(Sidekiq::Stats) - allow(Sidekiq::Stats).to receive(:new).and_return(sidekiq_stats_stub) - end - - describe '#under_load?' do - context 'when nothing is queued' do - it 'returns false' do - expect(subject.under_load?).to be false - end - end - - context 'when numerous jobs are queued' do - let(:queue_size) { 5 } - let(:queue_latency) { 120 } - - it 'returns true' do - expect(subject.under_load?).to be true - end - end - end - - describe '#compute_budget' do - context 'with a single thread' do - let(:process_set_stub) { [{ 'concurrency' => 1, 'queues' => %w(push default) }] } - - it 'returns a low value' do - expect(subject.compute_budget).to be < 10 - end - end - - context 'with a lot of threads' do - let(:process_set_stub) do - [ - { 'concurrency' => 2, 'queues' => %w(push default) }, - { 'concurrency' => 2, 'queues' => ['push'] }, - { 'concurrency' => 2, 'queues' => ['push'] }, - { 'concurrency' => 2, 'queues' => ['push'] }, - ] - end - - it 'returns a larger value' do - expect(subject.compute_budget).to be > 10 - end - end - end - - describe '#perform' do - around do |example| - Timeout.timeout(30) do - example.run - end - end - - before do - # Policies for the accounts - Fabricate(:account_statuses_cleanup_policy, account: account_alice) - Fabricate(:account_statuses_cleanup_policy, account: account_chris) - Fabricate(:account_statuses_cleanup_policy, account: account_dave, enabled: false) - Fabricate(:account_statuses_cleanup_policy, account: account_erin) - - # Create a bunch of old statuses - 4.times do - Fabricate(:status, account: account_alice, created_at: 3.years.ago) - Fabricate(:status, account: account_bob, created_at: 3.years.ago) - Fabricate(:status, account: account_chris, created_at: 3.years.ago) - Fabricate(:status, account: account_dave, created_at: 3.years.ago) - Fabricate(:status, account: account_erin, created_at: 3.years.ago) - Fabricate(:status, account: remote, created_at: 3.years.ago) - end - - # Create a bunch of newer statuses - Fabricate(:status, account: account_alice, created_at: 3.minutes.ago) - Fabricate(:status, account: account_bob, created_at: 3.minutes.ago) - Fabricate(:status, account: account_chris, created_at: 3.minutes.ago) - Fabricate(:status, account: account_dave, created_at: 3.minutes.ago) - Fabricate(:status, account: remote, created_at: 3.minutes.ago) - end - - context 'when the budget is lower than the number of toots to delete' do - it 'deletes the appropriate statuses' do - expect(Status.count).to be > (subject.compute_budget) # Data check - - expect { subject.perform } - .to change(Status, :count).by(-subject.compute_budget) # Cleanable statuses - .and (not_change { account_bob.statuses.count }) # No cleanup policy for account - .and(not_change { account_dave.statuses.count }) # Disabled cleanup policy - end - - it 'eventually deletes every deletable toot given enough runs' do - stub_const 'Scheduler::AccountsStatusesCleanupScheduler::MAX_BUDGET', 4 - - expect { 3.times { subject.perform } }.to change(Status, :count).by(-cleanable_statuses_count) - end - - it 'correctly round-trips between users across several runs' do - stub_const 'Scheduler::AccountsStatusesCleanupScheduler::MAX_BUDGET', 3 - stub_const 'Scheduler::AccountsStatusesCleanupScheduler::PER_ACCOUNT_BUDGET', 2 - - expect { 3.times { subject.perform } } - .to change(Status, :count).by(-3 * 3) - .and change { account_alice.statuses.count } - .and change { account_chris.statuses.count } - .and(change { account_erin.statuses.count }) - end - - context 'when given a big budget' do - let(:process_set_stub) { [{ 'concurrency' => 400, 'queues' => %w(push default) }] } - - before do - stub_const 'Scheduler::AccountsStatusesCleanupScheduler::MAX_BUDGET', 400 - end - - it 'correctly handles looping in a single run' do - expect(subject.compute_budget).to eq(400) - expect { subject.perform }.to change(Status, :count).by(-cleanable_statuses_count) - end - end - - context 'when there is no work to be done' do - let(:process_set_stub) { [{ 'concurrency' => 400, 'queues' => %w(push default) }] } - - before do - stub_const 'Scheduler::AccountsStatusesCleanupScheduler::MAX_BUDGET', 400 - subject.perform - end - - it 'does not get stuck' do - expect(subject.compute_budget).to eq(400) - expect { subject.perform }.to_not change(Status, :count) - end - end - - def cleanable_statuses_count - Status - .where(account_id: [account_alice, account_chris, account_erin]) # Accounts with enabled policies - .where('created_at < ?', 2.weeks.ago) # Policy defaults is 2.weeks - .count - end - end - end -end diff --git a/spec/workers/scheduler/follow_recommendations_scheduler_spec.rb b/spec/workers/scheduler/follow_recommendations_scheduler_spec.rb deleted file mode 100644 index 18d5260e4..000000000 --- a/spec/workers/scheduler/follow_recommendations_scheduler_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Scheduler::FollowRecommendationsScheduler do - let!(:target_accounts) do - Fabricate.times(3, :account) do - statuses(count: 6) - end - end - let!(:follower_accounts) do - Fabricate.times(5, :account) do - statuses(count: 6) - end - end - - describe '#perform' do - subject(:scheduled_run) { described_class.new.perform } - - context 'when there are accounts to recommend' do - before do - # Follow the target accounts by follow accounts to make them recommendable - follower_accounts.each do |follower_account| - target_accounts.each do |target_account| - Fabricate(:follow, account: follower_account, target_account: target_account) - end - end - end - - it 'creates recommendations' do - expect { scheduled_run }.to change(FollowRecommendation, :count).from(0).to(target_accounts.size) - expect(redis.zrange('follow_recommendations:en', 0, -1)).to match_array(target_accounts.pluck(:id).map(&:to_s)) - end - end - - context 'when there are no accounts to recommend' do - it 'does not create follow recommendations' do - expect { scheduled_run }.to_not change(FollowRecommendation, :count) - expect(redis.zrange('follow_recommendations:en', 0, -1)).to be_empty - end - end - end -end diff --git a/spec/workers/scheduler/indexing_scheduler_spec.rb b/spec/workers/scheduler/indexing_scheduler_spec.rb deleted file mode 100644 index 568f0fc84..000000000 --- a/spec/workers/scheduler/indexing_scheduler_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Scheduler::IndexingScheduler do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error' do - expect { worker.perform }.to_not raise_error - end - end -end diff --git a/spec/workers/scheduler/instance_refresh_scheduler_spec.rb b/spec/workers/scheduler/instance_refresh_scheduler_spec.rb deleted file mode 100644 index 8f686a699..000000000 --- a/spec/workers/scheduler/instance_refresh_scheduler_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Scheduler::InstanceRefreshScheduler do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error' do - expect { worker.perform }.to_not raise_error - end - end -end diff --git a/spec/workers/scheduler/ip_cleanup_scheduler_spec.rb b/spec/workers/scheduler/ip_cleanup_scheduler_spec.rb deleted file mode 100644 index 50af03011..000000000 --- a/spec/workers/scheduler/ip_cleanup_scheduler_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Scheduler::IpCleanupScheduler do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error' do - expect { worker.perform }.to_not raise_error - end - end -end diff --git a/spec/workers/scheduler/pghero_scheduler_spec.rb b/spec/workers/scheduler/pghero_scheduler_spec.rb deleted file mode 100644 index e404e5fe4..000000000 --- a/spec/workers/scheduler/pghero_scheduler_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Scheduler::PgheroScheduler do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error' do - expect { worker.perform }.to_not raise_error - end - end -end diff --git a/spec/workers/scheduler/scheduled_statuses_scheduler_spec.rb b/spec/workers/scheduler/scheduled_statuses_scheduler_spec.rb deleted file mode 100644 index 13c853c62..000000000 --- a/spec/workers/scheduler/scheduled_statuses_scheduler_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Scheduler::ScheduledStatusesScheduler do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error' do - expect { worker.perform }.to_not raise_error - end - end -end diff --git a/spec/workers/scheduler/software_update_check_scheduler_spec.rb b/spec/workers/scheduler/software_update_check_scheduler_spec.rb deleted file mode 100644 index f596c0a1e..000000000 --- a/spec/workers/scheduler/software_update_check_scheduler_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Scheduler::SoftwareUpdateCheckScheduler do - subject { described_class.new } - - describe 'perform' do - let(:service_double) { instance_double(SoftwareUpdateCheckService, call: nil) } - - before do - allow(SoftwareUpdateCheckService).to receive(:new).and_return(service_double) - end - - it 'calls SoftwareUpdateCheckService' do - subject.perform - expect(service_double).to have_received(:call) - end - end -end diff --git a/spec/workers/scheduler/suspended_user_cleanup_scheduler_spec.rb b/spec/workers/scheduler/suspended_user_cleanup_scheduler_spec.rb deleted file mode 100644 index 25f0e1fce..000000000 --- a/spec/workers/scheduler/suspended_user_cleanup_scheduler_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Scheduler::SuspendedUserCleanupScheduler do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error' do - expect { worker.perform }.to_not raise_error - end - end -end diff --git a/spec/workers/scheduler/trends/refresh_scheduler_spec.rb b/spec/workers/scheduler/trends/refresh_scheduler_spec.rb deleted file mode 100644 index c0c5f032b..000000000 --- a/spec/workers/scheduler/trends/refresh_scheduler_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Scheduler::Trends::RefreshScheduler do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error' do - expect { worker.perform }.to_not raise_error - end - end -end diff --git a/spec/workers/scheduler/trends/review_notifications_scheduler_spec.rb b/spec/workers/scheduler/trends/review_notifications_scheduler_spec.rb deleted file mode 100644 index cc971c24b..000000000 --- a/spec/workers/scheduler/trends/review_notifications_scheduler_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Scheduler::Trends::ReviewNotificationsScheduler do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error' do - expect { worker.perform }.to_not raise_error - end - end -end diff --git a/spec/workers/scheduler/user_cleanup_scheduler_spec.rb b/spec/workers/scheduler/user_cleanup_scheduler_spec.rb deleted file mode 100644 index 990979500..000000000 --- a/spec/workers/scheduler/user_cleanup_scheduler_spec.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Scheduler::UserCleanupScheduler do - subject { described_class.new } - - let!(:new_unconfirmed_user) { Fabricate(:user) } - let!(:old_unconfirmed_user) { Fabricate(:user) } - let!(:confirmed_user) { Fabricate(:user) } - let!(:moderation_note) { Fabricate(:account_moderation_note, account: Fabricate(:account), target_account: old_unconfirmed_user.account) } - - describe '#perform' do - before do - # Need to update the already-existing users because their initialization overrides confirmation_sent_at - new_unconfirmed_user.update!(confirmed_at: nil, confirmation_sent_at: Time.now.utc) - old_unconfirmed_user.update!(confirmed_at: nil, confirmation_sent_at: 1.week.ago) - confirmed_user.update!(confirmed_at: 1.day.ago) - end - - it 'deletes the old unconfirmed user' do - expect { subject.perform }.to change { User.exists?(old_unconfirmed_user.id) }.from(true).to(false) - end - - it "deletes the old unconfirmed user's account" do - expect { subject.perform }.to change { Account.exists?(old_unconfirmed_user.account_id) }.from(true).to(false) - end - - it 'does not delete the new unconfirmed user or their account' do - subject.perform - expect(User.exists?(new_unconfirmed_user.id)).to be true - expect(Account.exists?(new_unconfirmed_user.account_id)).to be true - end - - it 'does not delete the confirmed user or their account' do - subject.perform - expect(User.exists?(confirmed_user.id)).to be true - expect(Account.exists?(confirmed_user.account_id)).to be true - end - end -end diff --git a/spec/workers/scheduler/vacuum_scheduler_spec.rb b/spec/workers/scheduler/vacuum_scheduler_spec.rb deleted file mode 100644 index 36ecc93d8..000000000 --- a/spec/workers/scheduler/vacuum_scheduler_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Scheduler::VacuumScheduler do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error' do - expect { worker.perform }.to_not raise_error - end - end -end diff --git a/spec/workers/tag_unmerge_worker_spec.rb b/spec/workers/tag_unmerge_worker_spec.rb deleted file mode 100644 index 5d3a12c44..000000000 --- a/spec/workers/tag_unmerge_worker_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe TagUnmergeWorker do - subject { described_class.new } - - describe 'perform' do - let(:follower) { Fabricate(:account) } - let(:followed) { Fabricate(:account) } - let(:followed_tag) { Fabricate(:tag) } - let(:unchanged_followed_tag) { Fabricate(:tag) } - let(:status_from_followed) { Fabricate(:status, created_at: 2.hours.ago, account: followed) } - let(:tagged_status) { Fabricate(:status, created_at: 1.hour.ago) } - let(:unchanged_tagged_status) { Fabricate(:status) } - - before do - tagged_status.tags << followed_tag - unchanged_tagged_status.tags << followed_tag - unchanged_tagged_status.tags << unchanged_followed_tag - - tag_follow = TagFollow.create_with(rate_limit: false).find_or_create_by!(tag: followed_tag, account: follower) - TagFollow.create_with(rate_limit: false).find_or_create_by!(tag: unchanged_followed_tag, account: follower) - - FeedManager.instance.push_to_home(follower, status_from_followed, update: false) - FeedManager.instance.push_to_home(follower, tagged_status, update: false) - FeedManager.instance.push_to_home(follower, unchanged_tagged_status, update: false) - - tag_follow.destroy! - end - - it 'removes the expected status from the feed' do - expect { subject.perform(followed_tag.id, follower.id) } - .to change { HomeFeed.new(follower).get(10).pluck(:id) } - .from([unchanged_tagged_status.id, tagged_status.id, status_from_followed.id]) - .to([unchanged_tagged_status.id, status_from_followed.id]) - end - end -end diff --git a/spec/workers/unfollow_follow_worker_spec.rb b/spec/workers/unfollow_follow_worker_spec.rb deleted file mode 100644 index 8025b88c0..000000000 --- a/spec/workers/unfollow_follow_worker_spec.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe UnfollowFollowWorker do - subject { described_class.new } - - let(:local_follower) { Fabricate(:account) } - let(:source_account) { Fabricate(:account) } - let(:target_account) { Fabricate(:account) } - let(:show_reblogs) { true } - - before do - local_follower.follow!(source_account, reblogs: show_reblogs) - end - - context 'when show_reblogs is true' do - let(:show_reblogs) { true } - - describe 'perform' do - it 'unfollows source account and follows target account' do - subject.perform(local_follower.id, source_account.id, target_account.id) - expect(local_follower.following?(source_account)).to be false - expect(local_follower.following?(target_account)).to be true - end - - it 'preserves show_reblogs' do - subject.perform(local_follower.id, source_account.id, target_account.id) - expect(Follow.find_by(account: local_follower, target_account: target_account).show_reblogs?).to be show_reblogs - end - end - end - - context 'when show_reblogs is false' do - let(:show_reblogs) { false } - - describe 'perform' do - it 'unfollows source account and follows target account' do - subject.perform(local_follower.id, source_account.id, target_account.id) - expect(local_follower.following?(source_account)).to be false - expect(local_follower.following?(target_account)).to be true - end - - it 'preserves show_reblogs' do - subject.perform(local_follower.id, source_account.id, target_account.id) - expect(Follow.find_by(account: local_follower, target_account: target_account).show_reblogs?).to be show_reblogs - end - end - end -end diff --git a/spec/workers/unpublish_announcement_worker_spec.rb b/spec/workers/unpublish_announcement_worker_spec.rb deleted file mode 100644 index c742c30bc..000000000 --- a/spec/workers/unpublish_announcement_worker_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe UnpublishAnnouncementWorker do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error for missing record' do - expect { worker.perform(nil) }.to_not raise_error - end - end -end diff --git a/spec/workers/verify_account_links_worker_spec.rb b/spec/workers/verify_account_links_worker_spec.rb deleted file mode 100644 index 227591392..000000000 --- a/spec/workers/verify_account_links_worker_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe VerifyAccountLinksWorker do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error for missing record' do - expect { worker.perform(nil) }.to_not raise_error - end - end -end diff --git a/spec/workers/web/push_notification_worker_spec.rb b/spec/workers/web/push_notification_worker_spec.rb deleted file mode 100644 index 822ef5257..000000000 --- a/spec/workers/web/push_notification_worker_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Web::PushNotificationWorker do - subject { described_class.new } - - let(:p256dh) { 'BN4GvZtEZiZuqFxSKVZfSfluwKBD7UxHNBmWkfiZfCtgDE8Bwh-_MtLXbBxTBAWH9r7IPKL0lhdcaqtL1dfxU5E=' } - let(:auth) { 'Q2BoAjC09xH3ywDLNJr-dA==' } - let(:endpoint) { 'https://updates.push.services.mozilla.com/push/v1/subscription-id' } - let(:user) { Fabricate(:user) } - let(:notification) { Fabricate(:notification) } - let(:subscription) { Fabricate(:web_push_subscription, user_id: user.id, key_p256dh: p256dh, key_auth: auth, endpoint: endpoint, data: { alerts: { notification.type => true } }) } - let(:vapid_public_key) { 'BB37UCyc8LLX4PNQSe-04vSFvpUWGrENubUaslVFM_l5TxcGVMY0C3RXPeUJAQHKYlcOM2P4vTYmkoo0VZGZTM4=' } - let(:vapid_private_key) { 'OPrw1Sum3gRoL4-DXfSCC266r-qfFSRZrnj8MgIhRHg=' } - let(:vapid_key) { Webpush::VapidKey.from_keys(vapid_public_key, vapid_private_key) } - let(:contact_email) { 'sender@example.com' } - let(:ciphertext) { "+\xB8\xDBT}\x13\xB6\xDD.\xF9\xB0\xA7\xC8\xD2\x80\xFD\x99#\xF7\xAC\x83\xA4\xDB,\x1F\xB5\xB9w\x85>\xF7\xADr" } - let(:salt) { "X\x97\x953\xE4X\xF8_w\xE7T\x95\xC51q\xFE" } - let(:server_public_key) { "\x04\b-RK9w\xDD$\x16lFz\xF9=\xB4~\xC6\x12k\xF3\xF40t\xA9\xC1\fR\xC3\x81\x80\xAC\f\x7F\xE4\xCC\x8E\xC2\x88 n\x8BB\xF1\x9C\x14\a\xFA\x8D\xC9\x80\xA1\xDDyU\\&c\x01\x88#\x118Ua" } - let(:shared_secret) { "\t\xA7&\x85\t\xC5m\b\xA8\xA7\xF8B{1\xADk\xE1y'm\xEDE\xEC\xDD\xEDj\xB3$s\xA9\xDA\xF0" } - let(:payload) { { ciphertext: ciphertext, salt: salt, server_public_key: server_public_key, shared_secret: shared_secret } } - - describe 'perform' do - before do - allow_any_instance_of(subscription.class).to receive(:contact_email).and_return(contact_email) - allow_any_instance_of(subscription.class).to receive(:vapid_key).and_return(vapid_key) - allow(Webpush::Encryption).to receive(:encrypt).and_return(payload) - allow(JWT).to receive(:encode).and_return('jwt.encoded.payload') - - stub_request(:post, endpoint).to_return(status: 201, body: '') - - subject.perform(subscription.id, notification.id) - end - - it 'calls the relevant service with the correct headers' do - expect(a_request(:post, endpoint).with(headers: { - 'Content-Encoding' => 'aesgcm', - 'Content-Type' => 'application/octet-stream', - 'Crypto-Key' => "dh=BAgtUks5d90kFmxGevk9tH7GEmvz9DB0qcEMUsOBgKwMf-TMjsKIIG6LQvGcFAf6jcmAod15VVwmYwGIIxE4VWE;p256ecdsa=#{vapid_public_key.delete('=')}", - 'Encryption' => 'salt=WJeVM-RY-F9351SVxTFx_g', - 'Ttl' => '172800', - 'Urgency' => 'normal', - 'Authorization' => 'WebPush jwt.encoded.payload', - }, body: "+\xB8\xDBT}\u0013\xB6\xDD.\xF9\xB0\xA7\xC8Ҁ\xFD\x99#\xF7\xAC\x83\xA4\xDB,\u001F\xB5\xB9w\x85>\xF7\xADr")).to have_been_made - end - end -end diff --git a/spec/workers/webhooks/delivery_worker_spec.rb b/spec/workers/webhooks/delivery_worker_spec.rb deleted file mode 100644 index daf8a3e28..000000000 --- a/spec/workers/webhooks/delivery_worker_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe Webhooks::DeliveryWorker do - let(:worker) { described_class.new } - - describe 'perform' do - it 'runs without error' do - expect { worker.perform(nil, nil) }.to_not raise_error - end - end -end diff --git a/vendor/.keep b/vendor/.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/yarn.lock b/yarn.lock index 1d2b608df..5cf4ac9ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3940,20 +3940,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0: - version "1.0.30001503" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz#88b6ff1b2cf735f1f3361dc1a15b59f0561aa398" - integrity sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw== - -caniuse-lite@^1.0.30001502: - version "1.0.30001515" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001515.tgz#418aefeed9d024cd3129bfae0ccc782d4cb8f12b" - integrity sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA== - -caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001538: - version "1.0.30001538" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz#9dbc6b9af1ff06b5eb12350c2012b3af56744f3f" - integrity sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001502, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001538: + version "1.0.30001688" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001688.tgz" + integrity sha512-Nmqpru91cuABu/DTCXbM2NSRHzM2uVHfPnhJ/1zEAJx/ILBRVmz3pzH4N7DZqbdG0gWClsCC05Oj0mJ/1AWMbA== chalk@5.2.0: version "5.2.0" @@ -5762,7 +5752,7 @@ expect@^29.6.2: jest-message-util "^29.6.2" jest-util "^29.6.2" -express@^4.17.1, express@^4.18.2: +express@^4.17.1: version "4.18.2" resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== @@ -11488,6 +11478,7 @@ stringz@^2.1.0: char-regex "^1.0.2" "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + name strip-ansi-cjs version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==