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 b3b1d97a241b7b772059df125eb4e673abf28759..0000000000000000000000000000000000000000 --- 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 ca9156fdaa4bf16ea8ed66a8283eab6c88b21277..0000000000000000000000000000000000000000 --- 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 fa8d6542c18aeca0f7ac8f0717bef4bb9e6f116a..0000000000000000000000000000000000000000 --- 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 0369521963f16caa92216bf93bd6424f26fb6328..0000000000000000000000000000000000000000 --- 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 a075cc7b3bc298d26e996a7d9c1b9d17b15b6b35..0000000000000000000000000000000000000000 --- 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 488cf92857ac6bb0b52d601eaa71dbd23f0e8d2b..0000000000000000000000000000000000000000 --- 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 fedbea236df0fb3b15b5107b86854d6dd1427fc3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 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 7bcce0f7e59b985cc733ea2edf32350c4dee54bf..0000000000000000000000000000000000000000 --- 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 69c1bf1fb3d8015f4be78cd973500e750fd02663..0000000000000000000000000000000000000000 --- 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 be750a5e41033abeb9b2e3f0b8069827831a4188..0000000000000000000000000000000000000000 --- 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 879a564e1ce64633018a5ccf36cad6f77859ca53..0000000000000000000000000000000000000000 --- 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 6601ef8c063b432b603f1765b21ac1b3327082be..0000000000000000000000000000000000000000 --- 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 cdfd4086bd4200314fbb492c67294589e17c8fdf..0000000000000000000000000000000000000000 --- 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 29868c72f8a7e11609ec3a80125ea58f6fcb0661..0000000000000000000000000000000000000000 --- 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 d2c3eea1979e6e8d1094d4ee455ecf32bae60fda..0000000000000000000000000000000000000000 --- 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 b5f6cbc74631ea69e12b78597746664de3d0f7dc..0000000000000000000000000000000000000000 --- 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 2b7e7aaa42bc170a207e11e133f45469ac9d4954..0000000000000000000000000000000000000000 --- 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 bfb93a36cd052c2101e8bba69e9fa591a71fb648..0000000000000000000000000000000000000000 --- 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 39cf32ddc43a66c43289a325122405b67cceb7f0..0000000000000000000000000000000000000000 --- 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 3b40c3fd07be907f8e40d4b0b31147f027b71f86..0000000000000000000000000000000000000000 --- 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 dc6fd874d1296b577c6596a0aa07a93845f2c185..0000000000000000000000000000000000000000 --- 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 75d66c2a6bc0cf73983571accbafb8434ac29101..0000000000000000000000000000000000000000 --- 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 3523ea29515a2535031fd99179426c59eefc4de6..0000000000000000000000000000000000000000 --- 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 bd775dba2061b51e91939af364f7609fc2ef79aa..0000000000000000000000000000000000000000 --- 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 ca9bd66a4ae1b1a5b0775cdd90130ff9441be6ea..0000000000000000000000000000000000000000 --- 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 67d28589cb09caacac5b0d3780b2bdac7b7cee7e..0000000000000000000000000000000000000000 --- 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 1d98c52673f7f340d7b2701bf1a7f8a1210ccff3..0000000000000000000000000000000000000000 --- 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 1b3f92c972730ce616105ec4c1ba5e1ea0502677..0000000000000000000000000000000000000000 --- 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 92882a084d126ee4a57cf010ef69dff0c5cc3183..0000000000000000000000000000000000000000 --- 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 e77cc988919279bc1b867ce6da1868ba3d324e0e..0000000000000000000000000000000000000000 --- 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 06d835c090e15cc02a73e2a42a32cff119a353ed..0000000000000000000000000000000000000000 --- 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 778e341771ec40f617aaf1bd218a2cda7ba9c626..0000000000000000000000000000000000000000 --- 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 0ef1d9b7c8279720be5e180b0b55cc18f7d4bed0..0000000000000000000000000000000000000000 --- 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 59287e88cf255351597d027c8ed231b39a9b4b4d..0000000000000000000000000000000000000000 --- 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 8f3c84d8f36884ed78e86eee4ecdd4e81696feed..0000000000000000000000000000000000000000 --- 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 0d0215bc06b5ed888495b6e1fb5cb7d2e127cc57..0000000000000000000000000000000000000000 --- 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 d1ed30b260c06a68d98aad05d3fdfc91d4a20f39..0000000000000000000000000000000000000000 --- 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 69937c4c48d286c0da58c5bba42edd181dac494c..0000000000000000000000000000000000000000 --- 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 2ee2e538bc48bbcc46fca38c19e0cee0debc82a8..0000000000000000000000000000000000000000 --- 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 a232915b6f52b8f7046372590dd172844375f0d4..0000000000000000000000000000000000000000 --- 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 8e40091add4c9e088ba4a41761ee802475f35ede..9f05bffcea9ff1c48696630236784845d2003b12 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 e3721d7241e033984fee96b98b5841f2eceb2d8c..0000000000000000000000000000000000000000 --- 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 449b0a920378989aa90a6c1042adb0d5ef62143b..0000000000000000000000000000000000000000 --- 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 affe1bf7f22e26a239acd1389b92ce6892523af4..0000000000000000000000000000000000000000 --- 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 d15c835b867517918a583987552da231be9c5487..0000000000000000000000000000000000000000 --- 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 e51cf0e17e838a503df0eb8b02ede5efcc46b656..0000000000000000000000000000000000000000 --- 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 3e13377db63eb4e46783e30e836b8fd9f16ee5fa..0000000000000000000000000000000000000000 --- 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 4303f8e067c23f52a34c1c051f5a726ad2a410ce..0000000000000000000000000000000000000000 --- 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 73f9bce39914d9cfd0b3470355833d2fbe728c40..0000000000000000000000000000000000000000 --- 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 78e9a869b8beed488a27b39c44bf4f6686436c1b..0000000000000000000000000000000000000000 --- 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 bc7c038a97c5a801a777453fdbe0c5ccd20327d5..0000000000000000000000000000000000000000 --- 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 d5e1c9f2cb9a0ff718e2c95fd97b81663dccc296..0000000000000000000000000000000000000000 --- 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 348990c01e8235de8ad5cfa233e28d7557bd79d0..0000000000000000000000000000000000000000 --- 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 599bc4e6de2f60f03111ea4f335c738e5d1f84d2..0000000000000000000000000000000000000000 --- 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 a263d673de760ba9dff562ac53e6b821d6dd8400..0000000000000000000000000000000000000000 --- 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 3ab42dc8cee6f6b5cd3ceba160188f15d50bf2df..0000000000000000000000000000000000000000 --- 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 eb57a3cd15a6e578b75d89dad85d00cba3ff0cc6..0000000000000000000000000000000000000000 --- 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 ea58845c00bfe9b175ed4885e3a432c29bd08ce5..0000000000000000000000000000000000000000 --- 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 333ae3f2b745108e544b100cf873bb677928a689..0000000000000000000000000000000000000000 --- 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 9b586537299f16585498fe5367138bb73a28fbf8..0000000000000000000000000000000000000000 --- 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 030f0872124b19a8ccf3432d4b928966f2338974..0000000000000000000000000000000000000000 --- 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 030d9fcb19e487b4bfbf3047fc9c3f2d23dfa799..0000000000000000000000000000000000000000 --- 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 e3709afe37adc0fec8fe7f62460dde423aa6fed7..0000000000000000000000000000000000000000 --- 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 12cd9ca8a6500ba23d879b085c45f1bde245a66c..0000000000000000000000000000000000000000 --- 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 29f7d424a9cbfe4c5c895c94e0fc036c473066ed..0000000000000000000000000000000000000000 --- 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 b4b018b3be5cb56269f0c9fac3c58cefa83eddc6..0000000000000000000000000000000000000000 --- 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 d5cae5bf49f7081963b8a43b7ab3e0d42f6e0047..0000000000000000000000000000000000000000 --- 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 ae58e74e56dbd2fd587826dcd7758a8d3cde3873..0000000000000000000000000000000000000000 --- 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 2430a8841644b85e16b292809751f502d97fb1d7..0000000000000000000000000000000000000000 --- 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 9e0ab9d06e403a1cb1ac411b04c648556950f9f7..0000000000000000000000000000000000000000 --- 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 4adf0837ab23d7ddc2a2536fc595e9b5885c8f3c..0000000000000000000000000000000000000000 --- 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 0e20f26c7c335a314ba87c696522cb0dd88d4882..0000000000000000000000000000000000000000 --- 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 a0091365616f677dc83e1c58fa0cfce0e992afd2..0000000000000000000000000000000000000000 --- 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 80b3c331a6bfcfb204adc19b580627cc5402c9ba..0000000000000000000000000000000000000000 --- 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 f179e6ca94a079e08fa983ab2b235c460d668cfa..0000000000000000000000000000000000000000 --- 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 f0861376b99da8b6459beb1094c3f189fb97ecfc..0000000000000000000000000000000000000000 --- 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 cc9916bfd40e4a7c0dde20521ea6a3d7189a32a9..0000000000000000000000000000000000000000 --- 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 8a9c7cf967217fb360dcb2dc1f646508a4980bab..0000000000000000000000000000000000000000 --- 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 66b0e8f9e2367b3764c8b9feb37e9d8d12c14815..0000000000000000000000000000000000000000 --- 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 5817e3d1d2015c83350748b92687f91b444003c1..0000000000000000000000000000000000000000 --- 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 5b80ccb97080fac2fa63993e02ccf5a351db0520..0000000000000000000000000000000000000000 --- 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 c994ad419fa79fd732ba78dc08fc01b4a262c9b9..0000000000000000000000000000000000000000 --- 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 53f5039af97838947fc2f9c8331d368127677d2b..0000000000000000000000000000000000000000 --- 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 7181717dc11e5842cd828255476ec7543306b475..0000000000000000000000000000000000000000 --- 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 9e64aff08a16e0ed14d978c59bf736a275a7b967..0000000000000000000000000000000000000000 --- 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 38203a55f70ad9d2121db7336ef5a94c287cf685..0000000000000000000000000000000000000000 --- 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 8b922c018b00782faddfa851281945ac10745d9d..0000000000000000000000000000000000000000 --- 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 5a1d0f094a8f6601f0b73e182818159a7b55a6f9..0000000000000000000000000000000000000000 --- 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 90966a8ebf644945494fd4f6e6c8f6188dffd9fd..0000000000000000000000000000000000000000 --- 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 54760c41bd4531cf0c6c675288215e4cf4bf0651..0000000000000000000000000000000000000000 --- 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 57a222aafc8589cb721440c4d8f9e1975001d30c..0000000000000000000000000000000000000000 --- 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 867dbe4020c1f08b74752b55cb479526bf10323f..0000000000000000000000000000000000000000 --- 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 ede1e3c36097e6f3fd07242a1698538bdad1147f..0000000000000000000000000000000000000000 --- 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 1e0abc5e0113a19046df26fed6eeeea84192b3c1..0000000000000000000000000000000000000000 --- 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 3c17ecb0003f83e61940f95b4b92ef322ae2d175..0000000000000000000000000000000000000000 --- 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 c1b7f7e9c508f5ca2b6d4444a2f424501c5ecb8e..0000000000000000000000000000000000000000 --- 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 d5c01395064e16bafd3316ff9da2191f72accb69..0000000000000000000000000000000000000000 --- 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 84cae30411e760752679f2fed24e154794cf5252..0000000000000000000000000000000000000000 --- 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 558a318927fcc8cf015b66543cb6a909a83481c8..0000000000000000000000000000000000000000 --- 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 074847c74c569b230b9369f5797e221a737c3cc0..0000000000000000000000000000000000000000 --- 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 cfce8e2234b4efc5d70469760e2a8caba05a196a..0000000000000000000000000000000000000000 --- 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 423dce88ab09ee1be287feb1b409f822928d8040..0000000000000000000000000000000000000000 --- 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 78a497c06bd44fb235939e0ab36e0fc36058fc10..0000000000000000000000000000000000000000 --- 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 bc8f0193b9cd7bba5c5467c68750b5d70ea37375..0000000000000000000000000000000000000000 --- 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 a63c20c27c5e6533ae4776dc27d58898ca0f8ffc..0000000000000000000000000000000000000000 --- 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 098c9cd901f2ab9ad769c736a450c03560b7c732..0000000000000000000000000000000000000000 --- 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 5affa66e078eabcc1bed4a48530eb1be3c40a337..0000000000000000000000000000000000000000 --- 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 22593bb218babf54387a1381a7e51281e84de80d..0000000000000000000000000000000000000000 --- 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 4e8727ca395933073767fc0622a46e43703e8cb7..0000000000000000000000000000000000000000 --- 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 10bd579363c486a4f2049000799470b5076c4a46..0000000000000000000000000000000000000000 --- 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 fa47b5954a8e31d677aa0286d8bb6b0aafaac9aa..0000000000000000000000000000000000000000 --- 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 1f32c6082ef00b0010f471d4bc3e35f1c9537d0d..0000000000000000000000000000000000000000 --- 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 fc7a43110b20e43530fa80631136c6731244605d..0000000000000000000000000000000000000000 --- 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 7405bdfa2d73d9014530c2561469d06495f830e9..0000000000000000000000000000000000000000 --- 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 f171df7c974ea6336f381e2a467a4824caa28b74..0000000000000000000000000000000000000000 --- 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 b47561dd4855f738b94c6f876e20d4df1f622e01..0000000000000000000000000000000000000000 --- 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 1e3649b833bf31939cff09924df0884608267824..0000000000000000000000000000000000000000 --- 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 e840bc3bc12575857dc8481b867a3d8fa77b0a85..0000000000000000000000000000000000000000 --- 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 12373a9494e75a6c6918c1a934aac4abf4b3ab79..0000000000000000000000000000000000000000 --- 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 8249503c592a67ed61c37cc1823bda647b1fcd82..0000000000000000000000000000000000000000 --- 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 0acff82377957df6c7cfc10a639ab4259387f4a4..0000000000000000000000000000000000000000 --- 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 fb02d79f11831f79882d23bdf79153dc139f5c1d..0000000000000000000000000000000000000000 --- 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 25f4fdec4bb7532afdb6c4fd86cbf3de034456d8..0000000000000000000000000000000000000000 --- 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 41aedd18b2da2d73da08a112d7968802d3c8709f..0000000000000000000000000000000000000000 --- 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 46362936f4a330dea0091e723b16412c7e5c3605..0000000000000000000000000000000000000000 --- 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 b2aa56a7047c8b8ac1424c27f004b97dd6d9cd67..0000000000000000000000000000000000000000 --- 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 2eac1ca6e5ceb4511baa9f21d36655e5720f1ca8..0000000000000000000000000000000000000000 --- 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 c1d6659aa7baf63a0ab8251eaeb796db69b024bd..0000000000000000000000000000000000000000 --- 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 30de07bd81c7fb5a4c1643c10415c0e0362c9582..0000000000000000000000000000000000000000 --- 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 c36fecd60d4ceabb06970fa039fba5fbb31c3e19..0000000000000000000000000000000000000000 --- 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 8a6487c321161864c1ca1c02449e2a9e346f8db1..0000000000000000000000000000000000000000 --- 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 49e16376eaf46ec61605efbec4b4d1a01dde6212..0000000000000000000000000000000000000000 --- 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 67f53fa7851349e6a3117c76ab7f8d389075267f..0000000000000000000000000000000000000000 --- 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 5874c5e53c45954d14c57727bb120589f35b216f..0000000000000000000000000000000000000000 --- 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 75468898d2739ccf40b80744a79ec3876f1cfc84..0000000000000000000000000000000000000000 --- 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 ecc27c0f6dd2a33acdd127b4d84a82cf0dfd7fb8..0000000000000000000000000000000000000000 --- 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 ef7fbdefcd49714f8f762ea908fa4514f3dc4998..0000000000000000000000000000000000000000 --- 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 01faec0e707fb2688c570938581b1221644c9ed7..0000000000000000000000000000000000000000 --- 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 c7743183cc612bda679263ece0d0162da2fe7260..0000000000000000000000000000000000000000 --- 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 fd8e90901065ecc78e5f2b4757f5f800d28ad110..0000000000000000000000000000000000000000 --- 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 0dc2d881ad2fced9073a5a24de5650544503dc12..0000000000000000000000000000000000000000 --- 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 2b70e396b9f85b7141bc414ebf3162209b5d6a00..0000000000000000000000000000000000000000 --- 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 f06a11cc8b03208eb99a33fa2929a517e2e88dd5..0000000000000000000000000000000000000000 --- 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 bd649d82693ce0724ab9adc7ac62e67a0903bcbf..0000000000000000000000000000000000000000 --- 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 2fca1e1c14e254422aabf03e5cb66ec33debd0d4..0000000000000000000000000000000000000000 --- 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 3605f0b9bf8d2180322543603ba0d45741a5ae36..0000000000000000000000000000000000000000 --- 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 4ad589f2c7a7d1d8cb9d6bd19c91b24e3a75f250..0000000000000000000000000000000000000000 --- 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 ed58826672e31e8285aab2c3f3e6c678ebbd06cd..0000000000000000000000000000000000000000 --- 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 51dd584388dfca2fb66e8bc272ded9690b194d07..0000000000000000000000000000000000000000 --- 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 6a82c8135a9486d721835877c0637208c77a264f..0000000000000000000000000000000000000000 --- 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 b241049a54b346b7053fed2644fcf61fd0433701..0000000000000000000000000000000000000000 --- 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 d6e2282022fdefb3429417e1c505aa9596dc5f6b..0000000000000000000000000000000000000000 --- 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 6ff7ffc5c148e3c562ea00e7500571c2f8b09620..0000000000000000000000000000000000000000 --- 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 8ae04ca41f81881aefd4a1a3cd0689fad1c61378..0000000000000000000000000000000000000000 --- 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 b017ea527999715fc29f9f8e72eff7ff386f30e1..0000000000000000000000000000000000000000 --- 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 7425b939462f699862ea12c6d7b3848da24c5627..0000000000000000000000000000000000000000 --- 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 0d7471375509abc5d876a123985cc4728e9b4b4c..0000000000000000000000000000000000000000 --- 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 fbbdf62584b8d1701fae67f9f3e4336f46b0cb00..0000000000000000000000000000000000000000 --- 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 fccd42aaad0622517f70834595e4cd4fed36a1e8..0000000000000000000000000000000000000000 --- 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 81c726a40ba337cba3404af4a7a41164805a496f..0000000000000000000000000000000000000000 --- 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 6baf0ea421c54e356b86223dc3afdce1f240bb1b..0000000000000000000000000000000000000000 --- 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 0093dcd8de94966dce19ce94733b96f917af79d9..0000000000000000000000000000000000000000 --- 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 c9b9c55028f366b4a7408ec4a7e59c06d170bc68..0000000000000000000000000000000000000000 --- 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 75842e25bad2230e8c6ef00be5af03263976030e..0000000000000000000000000000000000000000 --- 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 5ed5c5d766c5ec4c2761b7d6f3d7a3b3842856d9..0000000000000000000000000000000000000000 --- 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 9689bce9ee1a59577c5aeb856f4f42442df4c27e..0000000000000000000000000000000000000000 --- 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 0a494b0c4ce6265c098d915dc6c6b8155838bebc..0000000000000000000000000000000000000000 --- 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 2d3351452258bc73a1868930b0d5b9b6ba3b91e3..0000000000000000000000000000000000000000 --- 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 660b2e92ac862379597616166671621bd2665da1..0000000000000000000000000000000000000000 --- 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 f38e7c23719129daf20023489cfad1cd12ff08a0..0000000000000000000000000000000000000000 --- 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 e836144f0474e9d68fbfc3f75e418c786385e2e9..0000000000000000000000000000000000000000 --- 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 4d6e5c380b047066fa68d5ad58ad525a52120170..0000000000000000000000000000000000000000 --- 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 7c30b5b9976869e6509624116280df4eaa01cd19..0000000000000000000000000000000000000000 --- 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 f2818fca87bed57daff7b48426643926a3be78da..0000000000000000000000000000000000000000 --- 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 f7cfe9bb043123afcd436616cd6c6491db48acbb..0000000000000000000000000000000000000000 --- 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 ae2fa7b482c2d34e70c34921a329b2635c527107..0000000000000000000000000000000000000000 --- 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 8c8d31ec54122cefe69f22728e5ebe09a3753a4d..0000000000000000000000000000000000000000 --- 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 653597c90de59743e0a554005a0afd3b55190d72..0000000000000000000000000000000000000000 --- 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 bb61c02a637ce1d631adabd837bf46d77546bbcc..0000000000000000000000000000000000000000 --- 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 3c2cd3bac1b910e7fa0ca61c01069a723fda6395..0000000000000000000000000000000000000000 --- 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 4579ebb82e99a4cbdf9a9945aff8705ca569ef6c..0000000000000000000000000000000000000000 --- 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 715dd7574ff81f7f2c14621c5ebfc08990376219..0000000000000000000000000000000000000000 --- 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 8c37acc39fee8367e48819972fa1ee1c05eb938b..0000000000000000000000000000000000000000 --- 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 d7a21d8e39a77efe54f699ea7814a9bb0e52ed05..0000000000000000000000000000000000000000 --- 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 63bf33de249948046f81ccb8d4966723075826ea..0000000000000000000000000000000000000000 --- 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 af9f7716be382c16f7173869b712d13ae2b15544..0000000000000000000000000000000000000000 --- 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 3d230b3cb46179933c01d9df40ecde3e77228794..0000000000000000000000000000000000000000 --- 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 d7498eb9f09eaeaeb12769c9278cc9b241321adf..0000000000000000000000000000000000000000 --- 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 28cb65d78907305d3029f3c121ae91cc28b4654a..0000000000000000000000000000000000000000 --- 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 0e55febfa90fa479d318e84bc030d9b79c61b20e..0000000000000000000000000000000000000000 --- 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 cb869c7d9a7ed7c91a4407a9a7cc16edc40b1c1e..0000000000000000000000000000000000000000 --- 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 fbcbf390d733124ee651d7e0e75c83d33c92c867..0000000000000000000000000000000000000000 --- 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 4c89f3f37429ab1d565314c909fb5f23eb08cbc9..0000000000000000000000000000000000000000 --- 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 7ecff4be499a169efde59690313508efe95dd61b..0000000000000000000000000000000000000000 --- 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 01f4da0be2929e9f0ac87526347a13e6bfef86c7..0000000000000000000000000000000000000000 --- 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 a0d9a008b7b4d66df774431b738aea68843589ca..0000000000000000000000000000000000000000 --- 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 cbe3735d806ba5ee2716fffe74978d28c05519ba..0000000000000000000000000000000000000000 --- 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 3cfa85863ca7fe024988e1d98d583b288f74c912..0000000000000000000000000000000000000000 --- 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 d6675c5b341ad26f39368a8ebd5246b1fc7a190f..0000000000000000000000000000000000000000 --- 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 8d3715de9552ff34ae90df6dfe757405e00be32c..0000000000000000000000000000000000000000 --- 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 29ba02c26a8bae8b649d779117f57206ab8bc7e9..0000000000000000000000000000000000000000 --- 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 b40a8788875fe52ddc090e2b7545b04030e63ee0..0000000000000000000000000000000000000000 --- 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 4fc417807589334aa8004622aecefd0d4ef284ca..0000000000000000000000000000000000000000 --- 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 0e45f6df02f9dab8b5f1e3b722adca78ce19c7a0..0000000000000000000000000000000000000000 --- 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 4a993149052b15ae20f6abc9c136d36270d4f546..0000000000000000000000000000000000000000 --- 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 e19ba616128db2c759e140adab8ef04c0b4416a6..0000000000000000000000000000000000000000 --- 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 725bd0bbb3f078cdc52cbbe64c8f2f15383ed603..0000000000000000000000000000000000000000 --- 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 35da3cc62a03dff51b459cbac3d5aac2badc35b7..0000000000000000000000000000000000000000 --- 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 fa476a9fc3d835cd2e0e5cbc133f0c007989c7e9..0000000000000000000000000000000000000000 --- 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 909311461a842f6068b4ac6e48264a2255162d93..0000000000000000000000000000000000000000 --- 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 5c2ba54e000f1c304cef8d1a238cd66c7d667d42..0000000000000000000000000000000000000000 --- 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 c21ffd36ecdd9892233c9c84a71097ad28a3e3ae..0000000000000000000000000000000000000000 --- 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 f20dce5931f0fcf310308d8ca636f7553e09a63b..0000000000000000000000000000000000000000 --- 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 7746c8cd78c43e45f650512c8d6dab78dc94e1a8..0000000000000000000000000000000000000000 --- 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 7b8dccb6a0b34c5b4a5acb6193bb02636b182fc0..0000000000000000000000000000000000000000 --- 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 e84c46c47f29f37067702c4263caf7ff57f20caa..0000000000000000000000000000000000000000 --- 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 427f54e449ca03ac72b615d864618acfddd28cf1..0000000000000000000000000000000000000000 --- 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 b13e79b12b9137fa7f7518931ff0efbf4af93cca..0000000000000000000000000000000000000000 --- 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 ee6e925aa96c3ee19ab798f76291d0adc6b76886..0000000000000000000000000000000000000000 --- 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 9295d262d61d5e15fbd01877c08962f3a0213b0d..0000000000000000000000000000000000000000 --- 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 4382cb84e545f2157898c7bd59b1f04e3dbf4961..0000000000000000000000000000000000000000 --- 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 96000e3ef4832cc84f233844018f4e6a6bd370d3..0000000000000000000000000000000000000000 --- 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 7a5ac28c565e1f7405f2ae546bd12025726828d8..0000000000000000000000000000000000000000 --- 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 d512def86690d081fbc9461c1620a3e23d34a88a..0000000000000000000000000000000000000000 --- 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 d03886c51b06d18b1a2d60d862ce97975a0bdef2..0000000000000000000000000000000000000000 --- 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 91c3c11f5dab49f2e6d703c4e55735470fda25a3..0000000000000000000000000000000000000000 --- 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 031be17f52a5a3ad2b07fa5d55f2d8bc7d350e0e..0000000000000000000000000000000000000000 --- 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 dafe168c56f6458b639c64ed67504df406ebeec4..0000000000000000000000000000000000000000 --- 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 88f9eee360c1c74d8cb42fc4a051488b65238f8d..0000000000000000000000000000000000000000 --- 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 1f1cd35caacc9d5a2807db10e920278290cb9786..0000000000000000000000000000000000000000 --- 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 0f4fd4e90e544840eea68163d13e9849f1ed146a..0000000000000000000000000000000000000000 --- 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 8f5171ee782c09436aa60a7b25b70f6ac0ebb74f..0000000000000000000000000000000000000000 --- 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 6c171f6e47a47b1a16068bf65f53b0df7a0f7bd3..0000000000000000000000000000000000000000 --- 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 9d4ef8cd55970a5cb362ae55ce348d03897d3110..0000000000000000000000000000000000000000 --- 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 8ab8bf99ce52bb2c93adda1ae9b30a29dea77676..0000000000000000000000000000000000000000 --- 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 383e09d0c3fe3165ffd67e40880129fcadca86d3..0000000000000000000000000000000000000000 --- 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 9a1d16200a28fd8632da87ae90bea21cb34496b1..0000000000000000000000000000000000000000 --- 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 1c8a818d596e9bb7561c5869f8a8cbb6a76b8180..0000000000000000000000000000000000000000 --- 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 26a9b848e56e5055f9367e3460ab1c5be16991f6..0000000000000000000000000000000000000000 --- 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 d3007740a5dd75fd9f645f732c804ca67dbbfd1f..0000000000000000000000000000000000000000 --- 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 ac5e86f297074cac332573801734a70d73f591e2..0000000000000000000000000000000000000000 --- 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 db07fa424f7a61a94890fd255322d4d232bb4830..0000000000000000000000000000000000000000 --- 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 42b7f86629bb0e608f0899028b38cfad94196890..0000000000000000000000000000000000000000 --- 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 300ddf805c91f1df44f3a607fa7b73443d09b1e6..0000000000000000000000000000000000000000 --- 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 5834b909557d7434faea920964d040af1cbd0030..0000000000000000000000000000000000000000 --- 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 4afa40e580d14b3073f08f5fb204604db6d56258..0000000000000000000000000000000000000000 --- 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 2ee24d80951d679533994eb148ae2c623ab9fe94..0000000000000000000000000000000000000000 --- 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 89384d0ca36206846464524dbbe6ba9cccc22573..0000000000000000000000000000000000000000 --- 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 6314f43aafe6aff27e3dfc0a231c655593514558..0000000000000000000000000000000000000000 --- 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 a6c2efe0db02f14a1bd6fb250edd9f1438fa0876..0000000000000000000000000000000000000000 --- 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 c391c8b3da9f51e8fa413e713a97d2a4f4672ebf..0000000000000000000000000000000000000000 --- 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 e600bedfe07eb9b0dff41d0b6e77388ac881706e..0000000000000000000000000000000000000000 --- 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 d327ac1b45d0c3748b4f978270008a829e2d42ed..0000000000000000000000000000000000000000 --- 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 52e86e13feaec5477dd47c50f60f2119ca565f8b..0000000000000000000000000000000000000000 --- 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 f0955ceb36bd286cfd21e332ea399b385f6d698b..0000000000000000000000000000000000000000 --- 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 ec26ecba7d96e06adbc798d886e66c69372c247e..0000000000000000000000000000000000000000 --- 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 b822adbfb85559d9423af3e9056bfa6f56e89a9a..0000000000000000000000000000000000000000 --- 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 b7fb53ed8d7374dedf2c14c26f6f3c15ee105ec1..0000000000000000000000000000000000000000 --- 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 cc6557cab01903c2e3307f48b1fb7c2eb95c5752..0000000000000000000000000000000000000000 --- 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 27aa5ec506db43e48c132a4a3fae023f4c83d6ca..0000000000000000000000000000000000000000 --- 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 68a1478bed6b62ff85f957e768b07cb403d6e693..0000000000000000000000000000000000000000 --- 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 8b2c124fd21a72c69b0ccd35d7521edf39233492..0000000000000000000000000000000000000000 --- 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 a822fba4c55c7d9974c4be4ad3f26cf1c2ae829a..0000000000000000000000000000000000000000 --- 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 8cf08c13c127ed0ec0ee1f7e3132cbed7239a91f..0000000000000000000000000000000000000000 --- 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 65e1e4de1c9289d1fa10f77c42bd11b00d4d3fd7..0000000000000000000000000000000000000000 --- 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 d35cfa563927604790ece210b2d18c3597e4fca0..0000000000000000000000000000000000000000 --- 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 2a3be821214132e27c2f435186b400aed87ee0af..0000000000000000000000000000000000000000 --- 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 31ee31f132f4c3ffd81bf4443b6fe54033d597c6..0000000000000000000000000000000000000000 --- 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 6fe1f06185e6f6921eb4d6a633a1876b403d3e12..0000000000000000000000000000000000000000 --- 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 43cf7192e45ebb1bfdbafdeafad81fbae597f0b3..0000000000000000000000000000000000000000 --- 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 14c24c70cc7d180e7730fc659501e932691a4707..0000000000000000000000000000000000000000 --- 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 c329542d7914e7682f930a4d5a45b1121249e559..0000000000000000000000000000000000000000 --- 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 e399e88f37c3b38569031408aa868c49ed9f12ba..0000000000000000000000000000000000000000 --- 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 e0e70a3b8466c814a1d4f206c9eef47061d90632..0000000000000000000000000000000000000000 --- 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 15a5de18dd039ae49d690a980eb98a36adb5a3f6..0000000000000000000000000000000000000000 --- 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 cf9416f03289c115b9f05b6f0c6b10463c3f1edf..0000000000000000000000000000000000000000 --- 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 c15e197cb8fb39461d36436f8747742a5f763ea1..0000000000000000000000000000000000000000 --- 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 983780ae98fb6a10a92982edd9ff0a066b31df60..0000000000000000000000000000000000000000 --- 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 b3c086208db8bdfc6b6b661cffd79175a81e69be..0000000000000000000000000000000000000000 --- 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 1cd036f484887806a9927253305a255b4ec16164..0000000000000000000000000000000000000000 --- 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 f7a88a9172f57c8c5c455ea6f567d4799e7bd204..0000000000000000000000000000000000000000 --- 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 5975c81a1018ac15e03ed76d8306d125f37e105c..0000000000000000000000000000000000000000 --- 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 071e4d92d598655ae72bf1ed49c996d1aca7fe9b..0000000000000000000000000000000000000000 --- 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 ac7484d96d1a442b8794bdc8a2f269556b4553da..0000000000000000000000000000000000000000 --- 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 93d31b69d5190f031114b22fea7868b546174a29..0000000000000000000000000000000000000000 --- 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 e210d20ec77d40f515a7596dc75dd64f6a0cefeb..0000000000000000000000000000000000000000 --- 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 826b67d8840f60e3d8adb1cf845e339711095c6d..0000000000000000000000000000000000000000 --- 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 bf8e2967643fa368d6b880912a38b8998c337619..0000000000000000000000000000000000000000 --- 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 c02a0800a3ccf87215d88a71e8f9a2c10648fdb9..0000000000000000000000000000000000000000 --- 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 02011afea05499012be541ed4f93ac2f76c2526a..0000000000000000000000000000000000000000 --- 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 9d91f31cc5c2c53b30e8f7a393ccf19de37d3580..0000000000000000000000000000000000000000 --- 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 c9a513e24b7c3b330efa2f73cf17e009b36ca93e..0000000000000000000000000000000000000000 --- 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 9bfaa35807f20a9b49fc0cae4f3096448a09f73f..0000000000000000000000000000000000000000 --- 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 d81bba1d8d917b8bc7684f400bfde8c7efc11bb6..0000000000000000000000000000000000000000 --- 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 2532304964c9f9865d07289a7883b46bbd7f2f40..0000000000000000000000000000000000000000 --- 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 d07645ab6b112a299da7b4fc3750da19f4583204..0000000000000000000000000000000000000000 --- 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 806ba18323ea56dfa3bb8937dd27b8fb2bdc395e..0000000000000000000000000000000000000000 --- 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 8201c9d51f9982c4d7501bba013eaa38eba46853..0000000000000000000000000000000000000000 --- 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 36dce9d1963f2d9991387b4e2d586b722bebca81..0000000000000000000000000000000000000000 --- 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 5f7c2e8da088ba403d070bfd38dbb6910a440dbb..0000000000000000000000000000000000000000 --- 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 721a0337fd3094218c13b282fcdf0ebc1a40cb27..0000000000000000000000000000000000000000 --- 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 a77acc073212a329d7e1ea6693b77e5d89777e74..0000000000000000000000000000000000000000 --- 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 281b642ea41c2559959b060299d99b4c645bc440..0000000000000000000000000000000000000000 --- 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 9766e62de8cd0d6b7c13a7fb718916e1c758a8c6..0000000000000000000000000000000000000000 --- 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 68ab491e4eae7c64fbd1c92f000219bbc8a856dc..0000000000000000000000000000000000000000 --- 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 3b554f9ea3bbfc5d83fb27e6be334b462f810d3f..0000000000000000000000000000000000000000 --- 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 782c235c4182cb6882c7bf5ea58cb939b2e0b8a1..0000000000000000000000000000000000000000 --- 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 f44cbb750c7ec0a968ca4b8ffeceb9dce9a2508f..0000000000000000000000000000000000000000 --- 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 777cbae3fbd1bf40d9662ef7d4c49008aef996db..0000000000000000000000000000000000000000 --- 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 798740c9b310236d32446311c52b5f82f388aa1d..0000000000000000000000000000000000000000 --- 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 0f1068471f8e38d40b843a58e20a3dba12c3e7f0..0000000000000000000000000000000000000000 --- 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 c2ad0d71739990c6dc00d89cf44f97d86dac1e78..0000000000000000000000000000000000000000 --- 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 1904ac8dc914a981baf16277bfa98e088de981d4..0000000000000000000000000000000000000000 --- 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 50f74ff277f87f7b1ce82c6f346d7a0bceb6a876..0000000000000000000000000000000000000000 --- 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 8fcb5865804a6f08dfd6c8e69d41c32e3ecd9ec1..0000000000000000000000000000000000000000 --- 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 7d7679c889bcc250f2de7eae9c096468a849386c..0000000000000000000000000000000000000000 --- 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 54e0d94ee0a80ebfb8e32e877f987f4f16e18d66..0000000000000000000000000000000000000000 --- 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 0db73c41fabdbbc20ac5ebf71dc9bcb773402827..0000000000000000000000000000000000000000 --- 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 e96618310bab4be442ca3d8b793357fb58193032..0000000000000000000000000000000000000000 --- 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 7b85e37ed8cd7dea6e657724a658ef349ac48724..0000000000000000000000000000000000000000 --- 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 d28104b2c785c13e2e07e515cef7b0defb3bba2b..0000000000000000000000000000000000000000 --- 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 1b29cdcbea3198cafddabfc953cb86e83f28c25c..0000000000000000000000000000000000000000 --- 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 c19b4fac152c83965c00fc082d555e638fce23d0..0000000000000000000000000000000000000000 --- 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 d3bcd5d31cbdfa5d175f80b4ebfb93be4edac7c6..0000000000000000000000000000000000000000 --- 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 f446d0ca6da5bda82ed77b6e02866772293acdac..0000000000000000000000000000000000000000 --- 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 7991aa6ef14383493e85547320c6caea94fb83b9..0000000000000000000000000000000000000000 --- 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 cb69af5f548a26fe71745421debebcc43ff20b6c..0000000000000000000000000000000000000000 --- 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 c8821348ac237f4c8f455260c101b4efc0da969b..0000000000000000000000000000000000000000 --- 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 edb70500833336300be5d3f01680687fd34e2eda..0000000000000000000000000000000000000000 --- 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 5f6418f5d6f61f63ad06297fb7aa2545bd130f81..0000000000000000000000000000000000000000 --- 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 19d40e7e8694559e9a11f222e122f3833d807072..0000000000000000000000000000000000000000 --- 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 27dbc92ada08e7e9ce88adacf9c810abfec675be..0000000000000000000000000000000000000000 --- 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 86632c393887b8e12f9911913d6f00424f4afdb4..0000000000000000000000000000000000000000 --- 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 3e65e610ba540512691a56573ff77f1fc468a9d1..0000000000000000000000000000000000000000 --- 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 c555b661ecb77600529e824974de3a8b13daa447..0000000000000000000000000000000000000000 --- 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 6318cc95fbb5aa59f43d235df5e1a6d39fe4ff5a..0000000000000000000000000000000000000000 --- 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 9c53ebb2fd8271f8f867a5c23e69ce1680187752..0000000000000000000000000000000000000000 --- 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 415788cb585a1fae5397b565cae29e40765bb84f..0000000000000000000000000000000000000000 --- 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 b4c20545f541a155aad066ccfc12abb41a8edfe1..0000000000000000000000000000000000000000 --- 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 d531860abfddfe2bbe4eff97266cf0cc9d2cfd60..0000000000000000000000000000000000000000 --- 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 b50faa77ba00abbd2ee126616a14ffb3e5d91c35..0000000000000000000000000000000000000000 --- 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 213e873b4e18e78642e07ab3a64a64f9b0a70ca6..0000000000000000000000000000000000000000 --- 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 16ebda564152ed1d55a63351b77edcc8de844a25..0000000000000000000000000000000000000000 --- 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 d65f54f00f79c3efd329f001962a257f85813fb8..0000000000000000000000000000000000000000 --- 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 3a275199efd112238637259d1b21ced7140cc711..0000000000000000000000000000000000000000 --- 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 0f9c81a475a26582603be9a6be2e0750eb70b20e..0000000000000000000000000000000000000000 --- 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 9883adec7a6cad9a88dea647d90793547ec84818..0000000000000000000000000000000000000000 --- 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 085ce542bd687c50d8999af41c0b215b45538f31..0000000000000000000000000000000000000000 --- 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 2b345ddef10b31966fb1b8ee5dbdd683c39ca761..0000000000000000000000000000000000000000 --- 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 6faed6c808c30c310ef714b4de030f27c77e605a..0000000000000000000000000000000000000000 --- 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 bfe2a11a999bd56981a6596eb5b70916b1a98145..0000000000000000000000000000000000000000 --- 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 7144d2891883859a2a7ba42a9175934811cab8fd..0000000000000000000000000000000000000000 --- 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 876d73c18427b7dadb0df82c650bf35c3748c80e..0000000000000000000000000000000000000000 --- 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 86b6511d6554f5c1e5f0362f28e1953da8b2a66a..0000000000000000000000000000000000000000 --- 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 cb693dcd81fc5e66ee0a1566ee4d5af146357138..0000000000000000000000000000000000000000 --- 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 66fccad3ece3be2248b993d3b67637d0b71a1a01..0000000000000000000000000000000000000000 --- 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 95feb043dbb9c6bed374eb80e1a53aa82ec391ab..0000000000000000000000000000000000000000 --- 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 d73104cb6928faf41b0a2899a58720af875607f1..0000000000000000000000000000000000000000 --- 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 8535ddd7503556275e273acdbf27d0cec75f6d2f..0000000000000000000000000000000000000000 --- 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 e8f8a45434896ab74f245988caad97117c54a904..0000000000000000000000000000000000000000 --- 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 0d172c8408959d2175ceedc3136bdd1dc60ea523..0000000000000000000000000000000000000000 --- 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 6f353eeafdc5171e8633336e972fbbe60fea2763..0000000000000000000000000000000000000000 --- 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 4f32b7b39957ac1d87419663d11d889aa7e1304d..0000000000000000000000000000000000000000 --- 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 354f9d3e63e73fd1fa9fe0faf2cf4dc21f9c1721..0000000000000000000000000000000000000000 --- 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 d39393d5077b411656a1fa34a4040baf148502b8..0000000000000000000000000000000000000000 --- 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 0bdbf639032405a5616e47744e0b41df09bc8894..0000000000000000000000000000000000000000 --- 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 d8803f6b8a94cb430b11c27086262d4065848449..0000000000000000000000000000000000000000 --- 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 ff4d049a269ed9e7aa872721e18de40c40c42992..0000000000000000000000000000000000000000 --- 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 b8601f78cf3943298dfcb2010909c17d1c4566c2..0000000000000000000000000000000000000000 --- 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 66d1cf48904b9e978b7afc273657d487b1608a53..0000000000000000000000000000000000000000 --- 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 c500bac95918485d48b77b7a9cce45e7c6157c92..0000000000000000000000000000000000000000 --- 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 d0eeda43bfa21428333b18fa60e94e4f72c6bc85..0000000000000000000000000000000000000000 --- 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 fa150722419bd4a4a429d8cf7055023cd278dc0b..0000000000000000000000000000000000000000 --- 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 631cab6648ef5f20594e14e87d873c481ec3529e..0000000000000000000000000000000000000000 --- 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 861fd71a7f91d590455548820560f3a53fccfbb2..0000000000000000000000000000000000000000 --- 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 91f51fbb425428472e15b7f32c75086769a0397e..0000000000000000000000000000000000000000 --- 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 adeb287fa3724697acfb5963ee6c3a029fa9e939..0000000000000000000000000000000000000000 --- 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 33c3ca009ac32af7e5fe9a6021c09fa71e383096..0000000000000000000000000000000000000000 --- 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 21f8f87b2f615c638b15cad8714aed47e6542cb7..0000000000000000000000000000000000000000 --- 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 97c73c5999fd2aef9e96ff308b4261da7e46c6af..0000000000000000000000000000000000000000 --- 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 0a71a838fcc57324a1ddf0ac88af3fc341cdb94b..0000000000000000000000000000000000000000 --- 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 7577f6e896847f12600b7f51a85e01c76235c15e..0000000000000000000000000000000000000000 --- 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 78cbc1ee402f51f817603c4e1a01e2d3a7ad11b3..0000000000000000000000000000000000000000 --- 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 33072704bf3c9476d7eb92f732c695a2465cb170..0000000000000000000000000000000000000000 --- 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 2e50d4a50da3985ae69b2663159f0ccd40f6e06f..0000000000000000000000000000000000000000 --- 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 f8547e6fe2a6853b7ff458f998482225f3e3bbd0..0000000000000000000000000000000000000000 --- 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 5fbb4c6853b4a9ab8c8387c5ba8146ad2d5b977c..0000000000000000000000000000000000000000 --- 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 3cd04ce7b4c60f8d3eb74bd5da7f55ff0211a682..0000000000000000000000000000000000000000 --- 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 c8f94fa82a81d19450da8fa84cb947bc393a2904..0000000000000000000000000000000000000000 --- 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 b44ae9f035c72c591fad6d5d30187c50edd0ead9..0000000000000000000000000000000000000000 --- 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 767ae7a5ab1dff9ba8df2b105bf45c90e78d81c4..0000000000000000000000000000000000000000 --- 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 5718d4db4976525c6445f5c1976ba838949b2969..0000000000000000000000000000000000000000 --- 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 37b0a04c49fb5b69da756538f10b5285660e3f73..0000000000000000000000000000000000000000 --- 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 a64bd0605f3db063446625eb30a67c0efbc6a0fc..0000000000000000000000000000000000000000 --- 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 43ff211eaa772a3f01972690f02b9f0c09b3e52d..0000000000000000000000000000000000000000 --- 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 6f3cff099f16c4e74cb5cf35928831a75f8ab4a0..0000000000000000000000000000000000000000 --- 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 4d9185093a2d3b61fe23bc971898cfc699674057..0000000000000000000000000000000000000000 --- 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 18d5260e426f8c3d0856715bf80fab5ffd6e3596..0000000000000000000000000000000000000000 --- 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 568f0fc84dbd06a01fae5d34f941e46882043d1a..0000000000000000000000000000000000000000 --- 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 8f686a69988c798ac4af79a0b63fb64be44473ec..0000000000000000000000000000000000000000 --- 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 50af0301174d1aa4fd69e3e8442ffe9607368a28..0000000000000000000000000000000000000000 --- 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 e404e5fe4726a74a6b4c1e0e6401e9aadadc5ad9..0000000000000000000000000000000000000000 --- 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 13c853c62ac9f7fa0b2c7f0964b7ec24e1602d38..0000000000000000000000000000000000000000 --- 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 f596c0a1eca5a7ddeb6ef03a6d621a3217d0c213..0000000000000000000000000000000000000000 --- 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 25f0e1fce4793ebe4d1178bbc42349a10f544c36..0000000000000000000000000000000000000000 --- 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 c0c5f032bfcc8e6957bbd4d84a8c926741fd391c..0000000000000000000000000000000000000000 --- 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 cc971c24b4097889ce2e49267f4722750eb523e6..0000000000000000000000000000000000000000 --- 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 9909795008c5aad8d1a6801da9a9892adf23f11c..0000000000000000000000000000000000000000 --- 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 36ecc93d8e4aac78bc833a87a993378e6f986f27..0000000000000000000000000000000000000000 --- 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 5d3a12c4492af66bb8e8b79feb4b5d8c3deafe2d..0000000000000000000000000000000000000000 --- 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 8025b88c0c366caaf254db387660c8e52bcbc7dd..0000000000000000000000000000000000000000 --- 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 c742c30bcea4a2639eb0d611dfd391e2efe1fd67..0000000000000000000000000000000000000000 --- 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 227591392c5bc15d89d5bb8d594885ef4f7027b2..0000000000000000000000000000000000000000 --- 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 822ef5257f4a7d0d558248113ba53288d470c237..0000000000000000000000000000000000000000 --- 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 daf8a3e285596941a7b6c850a1620f38f34870f3..0000000000000000000000000000000000000000 --- 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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/yarn.lock b/yarn.lock index 1d2b608df2ce42b3ce707e8bae9085c35fe2494d..5cf4ac9ff244248e1ddbe37194e0fe5bd3ae3999 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==