diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index 0d0215bc06..f2d2d02fc0 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -113,6 +113,7 @@ jobs: CAS_ENABLED: true BUNDLE_WITH: 'pam_authentication test' CI_JOBS: ${{ matrix.ci_job }}/4 + GITHUB_RSPEC: ${{ matrix.ruby-version == '.ruby-version' && github.event.pull_request && 'true' }} strategy: fail-fast: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 296976ff72..452711e3d4 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -48,27 +48,6 @@ Lint/UnusedBlockArgument: - 'config/initializers/paperclip.rb' - 'config/initializers/simple_form.rb' -# This cop supports unsafe autocorrection (--autocorrect-all). -Lint/UselessAssignment: - Exclude: - - 'app/services/activitypub/process_status_update_service.rb' - - 'config/initializers/3_omniauth.rb' - - 'db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb' - - 'db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb' - - 'spec/controllers/api/v1/favourites_controller_spec.rb' - - 'spec/controllers/concerns/account_controller_concern_spec.rb' - - 'spec/helpers/jsonld_helper_spec.rb' - - 'spec/models/account_spec.rb' - - 'spec/models/domain_block_spec.rb' - - 'spec/models/status_spec.rb' - - 'spec/models/user_spec.rb' - - 'spec/models/webauthn_credentials_spec.rb' - - 'spec/services/account_search_service_spec.rb' - - 'spec/services/post_status_service_spec.rb' - - 'spec/services/precompute_feed_service_spec.rb' - - 'spec/services/resolve_url_service_spec.rb' - - 'spec/views/statuses/show.html.haml_spec.rb' - # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. Metrics/AbcSize: Max: 144 @@ -88,26 +67,6 @@ Metrics/CyclomaticComplexity: Metrics/PerceivedComplexity: Max: 27 -# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns. -# SupportedStyles: snake_case, normalcase, non_integer -# AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64 -Naming/VariableNumber: - Exclude: - - 'db/migrate/20180106000232_add_index_on_statuses_for_api_v1_accounts_account_id_statuses.rb' - - 'db/migrate/20180514140000_revert_index_change_on_statuses_for_api_v1_accounts_account_id_statuses.rb' - - 'db/migrate/20190820003045_update_statuses_index.rb' - - 'db/migrate/20190823221802_add_local_index_to_statuses.rb' - - 'db/migrate/20200119112504_add_public_index_to_statuses.rb' - - 'spec/models/account_spec.rb' - - 'spec/models/domain_block_spec.rb' - - 'spec/models/user_spec.rb' - -# This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: SafeMultiline. -Performance/DeletePrefix: - Exclude: - - 'app/models/featured_tag.rb' - Performance/MapMethodChain: Exclude: - 'app/models/feed.rb' diff --git a/app/controllers/api/v1/apps/credentials_controller.rb b/app/controllers/api/v1/apps/credentials_controller.rb index 0475b2d4a2..6256bed64c 100644 --- a/app/controllers/api/v1/apps/credentials_controller.rb +++ b/app/controllers/api/v1/apps/credentials_controller.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true class Api::V1::Apps::CredentialsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read } - def show - render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer, fields: %i(name website vapid_key) + return doorkeeper_render_error unless valid_doorkeeper_token? + + render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer, fields: %i(name website vapid_key client_id scopes) end end diff --git a/app/helpers/admin/disputes_helper.rb b/app/helpers/admin/disputes_helper.rb new file mode 100644 index 0000000000..366a470ed2 --- /dev/null +++ b/app/helpers/admin/disputes_helper.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Admin + module DisputesHelper + def strike_action_label(appeal) + t(key_for_action(appeal), + scope: 'admin.strikes.actions', + name: content_tag(:span, appeal.strike.account.username, class: 'username'), + target: content_tag(:span, appeal.account.username, class: 'target')) + .html_safe + end + + private + + def key_for_action(appeal) + AccountWarning.actions.slice(appeal.strike.action).keys.first + end + end +end diff --git a/app/javascript/mastodon/features/home_timeline/index.jsx b/app/javascript/mastodon/features/home_timeline/index.jsx index 93f9376285..f19eaf935e 100644 --- a/app/javascript/mastodon/features/home_timeline/index.jsx +++ b/app/javascript/mastodon/features/home_timeline/index.jsx @@ -37,7 +37,7 @@ const getHomeFeedSpeed = createSelector([ state => state.getIn(['timelines', 'home', 'pendingItems'], ImmutableList()), state => state.get('statuses'), ], (statusIds, pendingStatusIds, statusMap) => { - const recentStatusIds = pendingStatusIds.size > 0 ? pendingStatusIds : statusIds; + const recentStatusIds = pendingStatusIds.concat(statusIds); const statuses = recentStatusIds.filter(id => id !== null).map(id => statusMap.get(id)).filter(status => status?.get('account') !== me).take(20); if (statuses.isEmpty()) { diff --git a/app/javascript/mastodon/features/ui/components/link_footer.jsx b/app/javascript/mastodon/features/ui/components/link_footer.jsx index 9585df2ec4..6b1555243b 100644 --- a/app/javascript/mastodon/features/ui/components/link_footer.jsx +++ b/app/javascript/mastodon/features/ui/components/link_footer.jsx @@ -100,7 +100,7 @@ class LinkFooter extends PureComponent { {DividingCircle} {DividingCircle} - v{version} + v{version}

); diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx index 8006ca89a2..22eee79c0a 100644 --- a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx +++ b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx @@ -59,10 +59,10 @@ class NavigationPanel extends Component { {transientSingleColumn ? ( -
+
{intl.formatMessage(messages.openedInClassicInterface)} {" "} - + {intl.formatMessage(messages.advancedInterface)}
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index a7a68533d6..aac4256ffd 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -71,11 +71,11 @@ "account.unmute_notifications_short": "Poista ilmoitusten mykistys", "account.unmute_short": "Poista mykistys", "account_note.placeholder": "Lisää muistiinpano napsauttamalla", - "admin.dashboard.daily_retention": "Käyttäjän pysyminen rekisteröitymisen jälkeiseen päivään mennessä", - "admin.dashboard.monthly_retention": "Käyttäjän pysyminen rekisteröitymisen jälkeiseen kuukauteen mennessä", + "admin.dashboard.daily_retention": "Käyttäjien pysyvyys rekisteröitymisen jälkeen päivittäin", + "admin.dashboard.monthly_retention": "Käyttäjien pysyvyys rekisteröitymisen jälkeen kuukausittain", "admin.dashboard.retention.average": "Keskimäärin", - "admin.dashboard.retention.cohort": "Kirjautumiset", - "admin.dashboard.retention.cohort_size": "Uudet käyttäjät", + "admin.dashboard.retention.cohort": "Rekisteröitymis-kk.", + "admin.dashboard.retention.cohort_size": "Uusia käyttäjiä", "admin.impact_report.instance_accounts": "Tilien profiilit, jotka tämä poistaisi", "admin.impact_report.instance_followers": "Seuraajat, jotka käyttäjämme menettäisivät", "admin.impact_report.instance_follows": "Seuraajat, jotka heidän käyttäjänsä menettäisivät", @@ -114,7 +114,7 @@ "column.directory": "Selaa profiileja", "column.domain_blocks": "Estetyt verkkotunnukset", "column.favourites": "Suosikit", - "column.firehose": "Live-syötteet", + "column.firehose": "Livesyötteet", "column.follow_requests": "Seuraamispyynnöt", "column.home": "Koti", "column.lists": "Listat", @@ -135,7 +135,7 @@ "community.column_settings.remote_only": "Vain etätilit", "compose.language.change": "Vaihda kieli", "compose.language.search": "Hae kieliä...", - "compose.published.body": "Julkaisusi julkaistiin.", + "compose.published.body": "Julkaisu lähetetty.", "compose.published.open": "Avaa", "compose.saved.body": "Julkaisu tallennettu.", "compose_form.direct_message_warning_learn_more": "Lisätietoja", @@ -436,10 +436,10 @@ "notifications.clear": "Tyhjennä ilmoitukset", "notifications.clear_confirmation": "Haluatko varmasti poistaa kaikki ilmoitukset pysyvästi?", "notifications.column_settings.admin.report": "Uudet ilmoitukset:", - "notifications.column_settings.admin.sign_up": "Uudet kirjautumiset:", + "notifications.column_settings.admin.sign_up": "Uudet rekisteröitymiset:", "notifications.column_settings.alert": "Työpöytäilmoitukset", "notifications.column_settings.favourite": "Suosikit:", - "notifications.column_settings.filter_bar.advanced": "Näytä kaikki kategoriat", + "notifications.column_settings.filter_bar.advanced": "Näytä kaikki luokat", "notifications.column_settings.filter_bar.category": "Pikasuodatuspalkki", "notifications.column_settings.filter_bar.show_bar": "Näytä suodatinpalkki", "notifications.column_settings.follow": "Uudet seuraajat:", @@ -517,7 +517,7 @@ "privacy.private.short": "Vain seuraajat", "privacy.public.long": "Näkyy kaikille", "privacy.public.short": "Julkinen", - "privacy.unlisted.long": "Näkyy kaikille, mutta jää pois löytämisominaisuuksista", + "privacy.unlisted.long": "Näkyy kaikille mutta jää pois löytämisominaisuuksista", "privacy.unlisted.short": "Listaamaton", "privacy_policy.last_updated": "Viimeksi päivitetty {date}", "privacy_policy.title": "Tietosuojakäytäntö", @@ -589,13 +589,13 @@ "search.quick_action.go_to_hashtag": "Siirry aihetunnisteeseen {x}", "search.quick_action.open_url": "Avaa URL-osoite Mastodonissa", "search.quick_action.status_search": "Julkaisut haulla {x}", - "search.search_or_paste": "Hae tai kirjoita URL-osoite", + "search.search_or_paste": "Hae tai liitä URL-osoite", "search_popout.full_text_search_disabled_message": "Ei saatavilla palvelimella {domain}.", "search_popout.language_code": "ISO-kielikoodi", "search_popout.options": "Hakuvalinnat", "search_popout.quick_actions": "Pikatoiminnot", "search_popout.recent": "Viimeaikaiset haut", - "search_popout.specific_date": "tietty päivämäärä", + "search_popout.specific_date": "tarkka päiväys", "search_popout.user": "käyttäjä", "search_results.accounts": "Profiilit", "search_results.all": "Kaikki", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index c5817c199e..a01354463f 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -137,7 +137,7 @@ "compose.language.search": "言語を検索...", "compose.published.body": "投稿されました!", "compose.published.open": "開く", - "compose.saved.body": "投稿が保存されました", + "compose.saved.body": "変更を保存しました。", "compose_form.direct_message_warning_learn_more": "もっと詳しく", "compose_form.encryption_warning": "Mastodonの投稿はエンドツーエンド暗号化に対応していません。安全に送受信されるべき情報をMastodonで共有しないでください。", "compose_form.hashtag_warning": "この投稿は公開設定ではないのでハッシュタグの一覧に表示されません。公開投稿だけがハッシュタグで検索できます。", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index b1cd0ca753..f8dcb6a89f 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -114,7 +114,7 @@ "column.directory": "瀏覽個人檔案", "column.domain_blocks": "已封鎖網域", "column.favourites": "最愛", - "column.firehose": "即時內容", + "column.firehose": "即時河道", "column.follow_requests": "跟隨請求", "column.home": "首頁", "column.lists": "列表", diff --git a/app/models/featured_tag.rb b/app/models/featured_tag.rb index 587dcf9912..df23114a3e 100644 --- a/app/models/featured_tag.rb +++ b/app/models/featured_tag.rb @@ -51,7 +51,7 @@ class FeaturedTag < ApplicationRecord private def strip_name - self.name = name&.strip&.gsub(/\A#/, '') + self.name = name&.strip&.delete_prefix('#') end def set_tag diff --git a/app/serializers/rest/application_serializer.rb b/app/serializers/rest/application_serializer.rb index ab68219ade..e4806a3c9f 100644 --- a/app/serializers/rest/application_serializer.rb +++ b/app/serializers/rest/application_serializer.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class REST::ApplicationSerializer < ActiveModel::Serializer - attributes :id, :name, :website, :redirect_uri, + attributes :id, :name, :website, :scopes, :redirect_uri, :client_id, :client_secret, :vapid_key def id diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index ec983510b9..4ff92da01f 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -97,8 +97,6 @@ class ActivityPub::ProcessStatusUpdateService < BaseService end end - added_media_attachments = @next_media_attachments - previous_media_attachments - @status.ordered_media_attachment_ids = @next_media_attachments.map(&:id) @media_attachments_changed = true if @status.ordered_media_attachment_ids != previous_media_attachments_ids diff --git a/app/views/admin/disputes/appeals/_appeal.html.haml b/app/views/admin/disputes/appeals/_appeal.html.haml index 3f6efb856e..d5611211ed 100644 --- a/app/views/admin/disputes/appeals/_appeal.html.haml +++ b/app/views/admin/disputes/appeals/_appeal.html.haml @@ -4,7 +4,7 @@ = image_tag appeal.account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar' .log-entry__content .log-entry__title - = t(appeal.strike.action, scope: 'admin.strikes.actions', name: content_tag(:span, appeal.strike.account.username, class: 'username'), target: content_tag(:span, appeal.account.username, class: 'target')).html_safe + = strike_action_label(appeal) .log-entry__timestamp %time.formatted{ datetime: appeal.strike.created_at.iso8601 } = l(appeal.strike.created_at) diff --git a/config/brakeman.ignore b/config/brakeman.ignore index 9f85ccb6a4..d5c0b94436 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -1,38 +1,5 @@ { "ignored_warnings": [ - { - "warning_type": "Cross-Site Scripting", - "warning_code": 2, - "fingerprint": "71cf98c8235b5cfa9946b5db8fdc1a2f3a862566abb34e4542be6f3acae78233", - "check_name": "CrossSiteScripting", - "message": "Unescaped model attribute", - "file": "app/views/admin/disputes/appeals/_appeal.html.haml", - "line": 7, - "link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting", - "code": "t((Unresolved Model).new.strike.action, :scope => \"admin.strikes.actions\", :name => content_tag(:span, (Unresolved Model).new.strike.account.username, :class => \"username\"), :target => content_tag(:span, (Unresolved Model).new.account.username, :class => \"target\"))", - "render_path": [ - { - "type": "template", - "name": "admin/disputes/appeals/index", - "line": 20, - "file": "app/views/admin/disputes/appeals/index.html.haml", - "rendered": { - "name": "admin/disputes/appeals/_appeal", - "file": "app/views/admin/disputes/appeals/_appeal.html.haml" - } - } - ], - "location": { - "type": "template", - "template": "admin/disputes/appeals/_appeal" - }, - "user_input": "(Unresolved Model).new.strike", - "confidence": "Weak", - "cwe_id": [ - 79 - ], - "note": "" - }, { "warning_type": "Cross-Site Scripting", "warning_code": 4, diff --git a/config/initializers/3_omniauth.rb b/config/initializers/3_omniauth.rb index 566e7362a5..d316c3b73a 100644 --- a/config/initializers/3_omniauth.rb +++ b/config/initializers/3_omniauth.rb @@ -9,9 +9,6 @@ Rails.application.config.middleware.use OmniAuth::Builder do end Devise.setup do |config| - # Devise omniauth strategies - options = {} - # CAS strategy if ENV['CAS_ENABLED'] == 'true' cas_options = {} diff --git a/config/locales/activerecord.sk.yml b/config/locales/activerecord.sk.yml index 33f53a88ed..d13c416e51 100644 --- a/config/locales/activerecord.sk.yml +++ b/config/locales/activerecord.sk.yml @@ -53,3 +53,7 @@ sk: position: elevated: nemôže byť vyššia ako vaša súčasná rola own_role: nie je možné zmeniť s vašou aktuálnou rolou + webhook: + attributes: + events: + invalid_permissions: nemožno zahrnúť udalosti, ku ktorým nemáte práva diff --git a/config/locales/doorkeeper.sk.yml b/config/locales/doorkeeper.sk.yml index acfd59b3e7..91c9430b30 100644 --- a/config/locales/doorkeeper.sk.yml +++ b/config/locales/doorkeeper.sk.yml @@ -129,6 +129,7 @@ sk: crypto: Šifrovanie End-to-end favourites: Obľúbené filters: Filtre + follow: Sledovanie, stlmenie a blokovanie follows: Sledovania lists: Zoznamy media: Mediálne prílohy @@ -148,9 +149,19 @@ sk: scopes: admin:read: prezeraj všetky dáta na serveri admin:read:accounts: prezeraj chúlostivé informácie na všetkých účtoch + admin:read:canonical_email_blocks: čítať citlivé informácie všetkých kanonických e-mailových blokov + admin:read:domain_allows: čítať citlivé informácie zo všetkých povolených domén + admin:read:domain_blocks: čítať citlivé informácie zo všetkých blokov domén + admin:read:email_domain_blocks: čítať citlivé informácie zo všetkých blokov emailových domén + admin:read:ip_blocks: čítať citlivé informácie zo všetkých blokov IP admin:read:reports: čítaj chulostivé informácie o všetkých hláseniach a nahlásených účtoch admin:write: uprav všetky dáta na serveri admin:write:accounts: urob moderovacie úkony na účtoch + admin:write:canonical_email_blocks: vykonať akcie moderácie na kanonických emailových blokoch + admin:write:domain_allows: vykonať akcie moderácie na povolených doménach + admin:write:domain_blocks: vykonať akcie moderácie na doménových blokoch + admin:write:email_domain_blocks: vykonať akcie moderácie na blokoch emailových domén + admin:write:ip_blocks: vykonať akcie moderácie na blokoch IP admin:write:reports: urob moderovacie úkony voči hláseniam crypto: používať end-to-end šifrovanie follow: uprav vzťahy svojho účtu @@ -159,6 +170,7 @@ sk: read:accounts: prezri si informácie o účte read:blocks: prezri svoje bloky read:bookmarks: pozri svoje záložky + read:favourites: zobraziť vaše obľúbené read:filters: prezri svoje filtrovanie read:follows: prezri si svoje sledovania read:lists: prezri si svoje zoznamy diff --git a/config/locales/fi.yml b/config/locales/fi.yml index cdc5d12678..09d2a68779 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -33,7 +33,7 @@ fi: accounts: add_email_domain_block: Estä sähköpostiverkkotunnus approve: Hyväksy - approved_msg: Käyttäjän %{username} liittymishakemus hyväksyttiin + approved_msg: Käyttäjän %{username} rekisteröitymishakemus hyväksyttiin are_you_sure: Oletko varma? avatar: Profiilikuva by_domain: Verkkotunnus @@ -364,7 +364,7 @@ fi: other: "%{count} odottavaa käyttäjää" resolved_reports: ratkaistut raportit software: Ohjelmisto - sources: Rekisteröitymisen lähteet + sources: Rekisteröitymislähteet space: Tilankäyttö title: Hallintapaneeli top_languages: Aktiivisimmat kielet @@ -440,7 +440,7 @@ fi: title: Estä uusi sähköpostiverkkotunnus no_email_domain_block_selected: Sähköpostin verkkotunnuksia ei muutettu, koska yhtään ei ollut valittuna not_permitted: Ei sallittu - resolved_dns_records_hint_html: Verkkotunnuksen nimi määräytyy seuraaviin MX-verkkotunnuksiin, jotka ovat viime kädessä vastuussa sähköpostin vastaanottamisesta. MX-verkkotunnuksen estäminen estää kirjautumisen mistä tahansa sähköpostiosoitteesta, joka käyttää samaa MX-verkkotunnusta, vaikka näkyvä verkkotunnuksen nimi olisikin erilainen. Varo estämästä suuria sähköpostin palveluntarjoajia. + resolved_dns_records_hint_html: Verkkotunnuksen nimi määräytyy seuraaviin MX-verkkotunnuksiin, jotka ovat viime kädessä vastuussa sähköpostin vastaanottamisesta. MX-verkkotunnuksen estäminen estää rekisteröitymisen mistä tahansa sähköpostiosoitteesta, joka käyttää samaa MX-verkkotunnusta, vaikka näkyvä verkkotunnuksen nimi olisikin erilainen. Varo estämästä suuria sähköpostin palveluntarjoajia. resolved_through_html: Ratkaistu %{domain} kautta title: Estetyt sähköpostiverkkotunnukset export_domain_allows: @@ -1405,7 +1405,7 @@ fi: migrations: acct: Muuttanut tunnukselle cancel: Peruuta uudelleenohjaus - cancel_explanation: Uudelleenohjauksen peruuttaminen aktivoi uudelleen nykyisen tilisi, mutta ei palauta seuraajia, jotka on siirretty kyseiselle tilille. + cancel_explanation: Uudelleenohjauksen peruuttaminen aktivoi nykyisen tilisi uudelleen mutta ei palauta seuraajia, jotka on siirretty kyseiselle tilille. cancelled_msg: Uudelleenohjaus peruttu onnistuneesti. errors: already_moved: on sama tili, jonka olet jo siirtänyt diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml index 6c8875327b..403162b820 100644 --- a/config/locales/simple_form.fi.yml +++ b/config/locales/simple_form.fi.yml @@ -59,14 +59,14 @@ fi: setting_display_media_default: Piilota arkaluonteiseksi merkitty media setting_display_media_hide_all: Piilota media aina setting_display_media_show_all: Näytä media aina - setting_use_blurhash: Liukuvärit perustuvat piilotettujen kuvien väreihin, mutta sumentavat yksityiskohdat + setting_use_blurhash: Liukuvärit perustuvat piilotettujen kuvien väreihin mutta sumentavat yksityiskohdat setting_use_pending_items: Piilota aikajanan päivitykset napsautuksen taakse syötteen automaattisen vierityksen sijaan username: Voit käyttää kirjaimia, numeroita ja alaviivoja whole_word: Kun avainsana tai -fraasi on kokonaan aakkosnumeerinen, se on voimassa vain, jos se vastaa koko sanaa domain_allow: domain: Tämä verkkotunnus voi noutaa tietoja tältä palvelimelta ja sieltä saapuvat tiedot käsitellään ja tallennetaan email_domain_block: - domain: Tämä voi olla se verkkotunnus, joka näkyy sähköpostiosoitteessa tai MX tietueessa jota se käyttää. Ne tarkistetaan rekisteröitymisen yhteydessä. + domain: Tämä voi olla verkkotunnus, joka näkyy sähköpostiosoitteessa tai sen käyttämässä MX-tietueessa. Ne tarkistetaan rekisteröitymisen yhteydessä. with_dns_records: Annetun verkkotunnuksen DNS-tietueet yritetään ratkaista ja tulokset myös estetään featured_tag: name: 'Tässä muutamia hiljattain käyttämiäsi aihetunnisteita:' @@ -112,7 +112,7 @@ fi: ip: Kirjoita IPv4- tai IPv6-osoite. Voit estää kokonaisia alueita käyttämällä CIDR-syntaksia. Varo, että et lukitse itseäsi ulos! severities: no_access: Estä pääsy kaikkiin resursseihin - sign_up_block: Uudet kirjautumiset eivät ole mahdollisia + sign_up_block: Uudet rekisteröitymiset eivät ole mahdollisia sign_up_requires_approval: Uudet rekisteröitymiset edellyttävät hyväksyntääsi severity: Valitse, mitä tapahtuu tämän IP-osoitteen pyynnöille rule: diff --git a/config/locales/simple_form.zh-TW.yml b/config/locales/simple_form.zh-TW.yml index c48c659fa6..4580e772fc 100644 --- a/config/locales/simple_form.zh-TW.yml +++ b/config/locales/simple_form.zh-TW.yml @@ -30,7 +30,7 @@ zh-TW: suspend: 禁止所有對該帳號任何互動,並且刪除其內容。三十天內可以撤銷此動作。關閉所有對此帳號之檢舉報告。 warning_preset_id: 選用。您仍可在預設的結尾新增自訂文字 announcement: - all_day: 核取後,只會顯示出時間範圍中的日期部分 + all_day: 當選取時,僅顯示出時間範圍中的日期部分 ends_at: 可選的,公告會於該時間點自動取消發布 scheduled_at: 空白則立即發布公告 starts_at: 可選的,讓公告在特定時間範圍內顯示 @@ -60,7 +60,7 @@ zh-TW: setting_display_media_hide_all: 總是隱藏所有媒體 setting_display_media_show_all: 總是顯示標為敏感內容的媒體 setting_use_blurhash: 彩色漸層圖樣是基於隱藏媒體內容顏色產生,所有細節將變得模糊 - setting_use_pending_items: 關閉自動捲動更新,時間軸只會於點擊後更新 + setting_use_pending_items: 關閉自動捲動更新,時間軸僅於點擊後更新 username: 您可以使用字幕、數字與底線 whole_word: 如果關鍵字或詞組僅有字母與數字,則其將只在符合整個單字的時候才會套用 domain_allow: diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index e139742ff1..fd93481509 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -578,7 +578,7 @@ zh-TW: mark_as_sensitive_description_html: 被檢舉的嘟文中的媒體將會被標記為敏感內容,並將會記錄一次警告,以協助您升級同一帳號未來的違規行為。 other_description_html: 檢視更多控制帳號行為以及自訂檢舉帳號通知之選項。 resolve_description_html: 被檢舉的帳號將不被採取任何行動,不會加以刪除線標記,並且此份報告將被關閉。 - silence_description_html: 此帳號僅會對已跟隨帳號之使用者或手動查詢可見,將大幅度限制觸及範圍。此設定可隨時被還原。關閉所有對此帳號之檢舉報告。 + silence_description_html: 此帳號僅對已跟隨帳號之使用者或手動查詢可見,將大幅度限制觸及範圍。此設定可隨時被還原。關閉所有對此帳號之檢舉報告。 suspend_description_html: 此帳號及其所有內容將不可被存取並且最終被移除,並且無法與之進行互動。三十天內可以撤銷此動作。關閉所有對此帳號之檢舉報告。 actions_description_html: 決定應對此報告採取何種行動。若您對檢舉之帳號採取懲罰措施,則將對他們發送 e-mail 通知,如非選擇了 垃圾郵件 類別。 actions_description_remote_html: 決定將對此檢舉報告採取何種動作。這將僅作用於您的伺服器與此遠端帳號及其內容之通訊行為。 diff --git a/db/migrate/.rubocop.yml b/db/migrate/.rubocop.yml new file mode 100644 index 0000000000..4e23800dd1 --- /dev/null +++ b/db/migrate/.rubocop.yml @@ -0,0 +1,4 @@ +inherit_from: ../../.rubocop.yml + +Naming/VariableNumber: + CheckSymbols: false diff --git a/db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb b/db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb index 7301e960d5..c9f0849557 100644 --- a/db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb +++ b/db/migrate/20190511134027_add_silenced_at_suspended_at_to_accounts.rb @@ -19,7 +19,6 @@ class AddSilencedAtSuspendedAtToAccounts < ActiveRecord::Migration[5.2] # Record suspend date of blocks and silences for users whose limitations match # a domain block DomainBlock.where(severity: [:silence, :suspend]).find_each do |block| - scope = block.accounts if block.suspend? block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at) else diff --git a/db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb b/db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb index 615f35cd0d..7788431cd5 100644 --- a/db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb +++ b/db/post_migrate/20190511152737_remove_suspended_silenced_account_fields.rb @@ -18,7 +18,6 @@ class RemoveSuspendedSilencedAccountFields < ActiveRecord::Migration[5.2] # Record suspend date of blocks and silences for users whose limitations match # a domain block DomainBlock.where(severity: [:silence, :suspend]).find_each do |block| - scope = block.accounts if block.suspend? block.accounts.where(suspended: true).in_batches.update_all(suspended_at: block.created_at) else diff --git a/spec/controllers/admin/disputes/appeals_controller_spec.rb b/spec/controllers/admin/disputes/appeals_controller_spec.rb index 4afe074921..3f4175a281 100644 --- a/spec/controllers/admin/disputes/appeals_controller_spec.rb +++ b/spec/controllers/admin/disputes/appeals_controller_spec.rb @@ -18,10 +18,14 @@ RSpec.describe Admin::Disputes::AppealsController do describe 'GET #index' do let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - it 'lists appeals' do + before { appeal } + + it 'returns a page that lists details of appeals' do get :index - expect(response).to have_http_status(200) + expect(response).to have_http_status(:success) + expect(response.body).to include("#{strike.account.username}") + expect(response.body).to include("#{appeal.account.username}") end end diff --git a/spec/controllers/concerns/account_controller_concern_spec.rb b/spec/controllers/concerns/account_controller_concern_spec.rb index d080475c32..56ffcfb047 100644 --- a/spec/controllers/concerns/account_controller_concern_spec.rb +++ b/spec/controllers/concerns/account_controller_concern_spec.rb @@ -62,7 +62,7 @@ describe AccountControllerConcern do end it 'sets link headers' do - account = Fabricate(:account, username: 'username') + Fabricate(:account, username: 'username') get 'success', params: { account_username: 'username' } expect(response.headers['Link'].to_s).to eq '; rel="lrdd"; type="application/jrd+json", ; rel="alternate"; type="application/activity+json"' end diff --git a/spec/helpers/admin/disputes_helper_spec.rb b/spec/helpers/admin/disputes_helper_spec.rb new file mode 100644 index 0000000000..5f9a85df86 --- /dev/null +++ b/spec/helpers/admin/disputes_helper_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Admin::DisputesHelper do + describe 'strike_action_label' do + it 'returns html describing the appeal' do + adam = Account.new(username: 'Adam') + becky = Account.new(username: 'Becky') + strike = AccountWarning.new(account: adam, action: :suspend) + appeal = Appeal.new(strike: strike, account: becky) + + expected = <<~OUTPUT.strip + Adam suspended Becky's account + OUTPUT + result = helper.strike_action_label(appeal) + + expect(result).to eq(expected) + end + end +end diff --git a/spec/helpers/jsonld_helper_spec.rb b/spec/helpers/jsonld_helper_spec.rb index 3575bba859..5124bcf855 100644 --- a/spec/helpers/jsonld_helper_spec.rb +++ b/spec/helpers/jsonld_helper_spec.rb @@ -158,14 +158,14 @@ describe JsonLdHelper do it 'deems a safe compacting as such' do json['object'].delete('convo') compacted = compact(json) - deemed_compatible = patch_for_forwarding!(json, compacted) + patch_for_forwarding!(json, compacted) expect(compacted['to']).to eq ['https://www.w3.org/ns/activitystreams#Public'] expect(safe_for_forwarding?(json, compacted)).to be true end it 'deems an unsafe compacting as such' do compacted = compact(json) - deemed_compatible = patch_for_forwarding!(json, compacted) + patch_for_forwarding!(json, compacted) expect(compacted['to']).to eq ['https://www.w3.org/ns/activitystreams#Public'] expect(safe_for_forwarding?(json, compacted)).to be false end diff --git a/spec/lib/mastodon/cli/accounts_spec.rb b/spec/lib/mastodon/cli/accounts_spec.rb index 5ecea5ea16..2c8c994712 100644 --- a/spec/lib/mastodon/cli/accounts_spec.rb +++ b/spec/lib/mastodon/cli/accounts_spec.rb @@ -1356,4 +1356,254 @@ describe Mastodon::CLI::Accounts do end end end + + describe '#prune' do + let!(:local_account) { Fabricate(:account) } + let!(:bot_account) { Fabricate(:account, bot: true, domain: 'example.com') } + let!(:group_account) { Fabricate(:account, actor_type: 'Group', domain: 'example.com') } + let!(:mentioned_account) { Fabricate(:account, domain: 'example.com') } + let!(:prunable_accounts) do + Fabricate.times(3, :account, domain: 'example.com', bot: false, suspended_at: nil, silenced_at: nil) + end + + before do + Fabricate(:mention, account: mentioned_account, status: Fabricate(:status, account: Fabricate(:account))) + stub_parallelize_with_progress! + end + + it 'prunes all remote accounts with no interactions with local users' do + cli.prune + + prunable_account_ids = prunable_accounts.pluck(:id) + + expect(Account.where(id: prunable_account_ids).count).to eq(0) + end + + it 'displays a successful message' do + expect { cli.prune }.to output( + a_string_including("OK, pruned #{prunable_accounts.size} accounts") + ).to_stdout + end + + it 'does not prune local accounts' do + cli.prune + + expect(Account.exists?(id: local_account.id)).to be(true) + end + + it 'does not prune bot accounts' do + cli.prune + + expect(Account.exists?(id: bot_account.id)).to be(true) + end + + it 'does not prune group accounts' do + cli.prune + + expect(Account.exists?(id: group_account.id)).to be(true) + end + + it 'does not prune accounts that have been mentioned' do + cli.prune + + expect(Account.exists?(id: mentioned_account.id)).to be true + end + + context 'with --dry-run option' do + before do + cli.options = { dry_run: true } + end + + it 'does not prune any account' do + cli.prune + + prunable_account_ids = prunable_accounts.pluck(:id) + + expect(Account.where(id: prunable_account_ids).count).to eq(prunable_accounts.size) + end + + it 'displays a successful message with (DRY RUN)' do + expect { cli.prune }.to output( + a_string_including("OK, pruned #{prunable_accounts.size} accounts (DRY RUN)") + ).to_stdout + end + end + end + + describe '#migrate' do + let!(:source_account) { Fabricate(:account) } + let!(:target_account) { Fabricate(:account, domain: 'example.com') } + let(:arguments) { [source_account.username] } + let(:resolve_account_service) { instance_double(ResolveAccountService, call: nil) } + let(:move_service) { instance_double(MoveService, call: nil) } + + before do + allow(ResolveAccountService).to receive(:new).and_return(resolve_account_service) + allow(MoveService).to receive(:new).and_return(move_service) + end + + shared_examples 'a successful migration' do + it 'calls the MoveService for the last migration' do + cli.invoke(:migrate, arguments, options) + + last_migration = source_account.migrations.last + + expect(move_service).to have_received(:call).with(last_migration).once + end + + it 'displays a successful message' do + expect { cli.invoke(:migrate, arguments, options) }.to output( + a_string_including("OK, migrated #{source_account.acct} to #{target_account.acct}") + ).to_stdout + end + end + + context 'when both --replay and --target options are given' do + let(:options) { { replay: true, target: "#{target_account.username}@example.com" } } + + it 'exits with an error message indicating that using both options is not possible' do + expect { cli.invoke(:migrate, arguments, options) }.to output( + a_string_including('Use --replay or --target, not both') + ).to_stdout + .and raise_error(SystemExit) + end + end + + context 'when no option is given' do + it 'exits with an error message indicating that at least one option must be used' do + expect { cli.invoke(:migrate, arguments, {}) }.to output( + a_string_including('Use either --replay or --target') + ).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(:migrate, arguments, replay: true) }.to output( + a_string_including("No such account: #{arguments.first}") + ).to_stdout + .and raise_error(SystemExit) + end + end + + context 'with --replay option' do + let(:options) { { replay: true } } + + context 'when the specified account has no previous migrations' do + it 'exits with an error message indicating that the given account has no previous migrations' do + expect { cli.invoke(:migrate, arguments, options) }.to output( + a_string_including('The specified account has not performed any migration') + ).to_stdout + .and raise_error(SystemExit) + end + end + + context 'when the specified account has a previous migration' do + before do + allow(resolve_account_service).to receive(:call).with(source_account.acct, any_args).and_return(source_account) + allow(resolve_account_service).to receive(:call).with(target_account.acct, any_args).and_return(target_account) + target_account.aliases.create!(acct: source_account.acct) + source_account.migrations.create!(acct: target_account.acct) + source_account.update!(moved_to_account: target_account) + end + + it_behaves_like 'a successful migration' + + context 'when the specified account is redirecting to a different target account' do + before do + source_account.update!(moved_to_account: nil) + end + + it 'exits with an error message' do + expect { cli.invoke(:migrate, arguments, options) }.to output( + a_string_including('The specified account is not redirecting to its last migration target. Use --force if you want to replay the migration anyway') + ).to_stdout + .and raise_error(SystemExit) + end + end + + context 'with --force option' do + let(:options) { { replay: true, force: true } } + + it_behaves_like 'a successful migration' + end + end + end + + context 'with --target option' do + let(:options) { { target: target_account.acct } } + + before do + allow(resolve_account_service).to receive(:call).with(source_account.acct, any_args).and_return(source_account) + allow(resolve_account_service).to receive(:call).with(target_account.acct, any_args).and_return(target_account) + end + + context 'when the specified target account is not found' do + before do + allow(resolve_account_service).to receive(:call).with(target_account.acct).and_return(nil) + end + + it 'exits with an error message indicating that there is no such account' do + expect { cli.invoke(:migrate, arguments, options) }.to output( + a_string_including("The specified target account could not be found: #{options[:target]}") + ).to_stdout + .and raise_error(SystemExit) + end + end + + context 'when the specified target account exists' do + before do + target_account.aliases.create!(acct: source_account.acct) + end + + it 'creates a migration for the specified account with the target account' do + cli.invoke(:migrate, arguments, options) + + last_migration = source_account.migrations.last + + expect(last_migration.acct).to eq(target_account.acct) + end + + it_behaves_like 'a successful migration' + end + + context 'when the migration record is invalid' do + it 'exits with an error indicating that the validation failed' do + expect { cli.invoke(:migrate, arguments, options) }.to output( + a_string_including('Error: Validation failed') + ).to_stdout + .and raise_error(SystemExit) + end + end + + context 'when the specified account is redirecting to a different target account' do + before do + allow(Account).to receive(:find_local).with(source_account.username).and_return(source_account) + allow(source_account).to receive(:moved_to_account_id).and_return(-1) + end + + it 'exits with an error message' do + expect { cli.invoke(:migrate, arguments, options) }.to output( + a_string_including('The specified account is redirecting to a different target account. Use --force if you want to change the migration target') + ).to_stdout + .and raise_error(SystemExit) + end + end + + context 'with --target and --force options' do + let(:options) { { target: target_account.acct, force: true } } + + before do + target_account.aliases.create!(acct: source_account.acct) + allow(Account).to receive(:find_local).with(source_account.username).and_return(source_account) + allow(source_account).to receive(:moved_to_account_id).and_return(-1) + end + + it_behaves_like 'a successful migration' + end + end + end end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index fc7a43110b..b5d942412e 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -356,7 +356,7 @@ RSpec.describe Account do end it 'does not return suspended users' do - match = Fabricate( + Fabricate( :account, display_name: 'Display Name', username: 'username', @@ -483,7 +483,7 @@ RSpec.describe Account do end it 'does not return non-followed accounts' do - match = Fabricate( + Fabricate( :account, display_name: 'A & l & i & c & e', username: 'username', @@ -495,7 +495,7 @@ RSpec.describe Account do end it 'does not return suspended users' do - match = Fabricate( + Fabricate( :account, display_name: 'Display Name', username: 'username', @@ -535,7 +535,7 @@ RSpec.describe Account do end it 'does not return suspended users' do - match = Fabricate( + Fabricate( :account, display_name: 'Display Name', username: 'username', @@ -719,10 +719,10 @@ RSpec.describe Account do 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) + _account = Fabricate(:account, username: 'the_doctor') + non_unique_account = Fabricate.build(:account, username: 'the_Doctor') + non_unique_account.valid? + expect(non_unique_account).to model_have_error_on_field(:username) end it 'is invalid if the username is reserved' do @@ -743,9 +743,9 @@ RSpec.describe Account do 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 + _account = Fabricate(:account, username: 'examplecom') + instance_account = Fabricate.build(:account, id: -99, actor_type: 'Application', locked: true, username: 'example.com') + expect(instance_account.valid?).to be true end it 'is invalid if the username doesn\'t only contains letters, numbers and underscores' do @@ -877,17 +877,17 @@ RSpec.describe Account do 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) + _account = Fabricate(:account, domain: nil) + account_with_domain = Fabricate(:account, domain: 'example.com') + expect(described_class.remote).to contain_exactly(account_with_domain) 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) + local_account = Fabricate(:account, domain: nil) + _account_with_domain = Fabricate(:account, domain: 'example.com') + expect(described_class.where('id > 0').local).to contain_exactly(local_account) end end @@ -911,17 +911,17 @@ RSpec.describe Account do 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) + silenced_account = Fabricate(:account, silenced: true) + _account = Fabricate(:account, silenced: false) + expect(described_class.silenced).to contain_exactly(silenced_account) 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) + suspended_account = Fabricate(:account, suspended: true) + _account = Fabricate(:account, suspended: false) + expect(described_class.suspended).to contain_exactly(suspended_account) end end diff --git a/spec/models/domain_block_spec.rb b/spec/models/domain_block_spec.rb index 67f53fa785..d595441fd3 100644 --- a/spec/models/domain_block_spec.rb +++ b/spec/models/domain_block_spec.rb @@ -11,10 +11,10 @@ RSpec.describe DomainBlock do 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) + _domain_block = Fabricate(:domain_block, domain: 'にゃん') + domain_block_with_normalized_value = Fabricate.build(:domain_block, domain: 'xn--r9j5b5b') + domain_block_with_normalized_value.valid? + expect(domain_block_with_normalized_value).to model_have_error_on_field(:domain) end end diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb index f38e7c2371..8868308d32 100644 --- a/spec/models/status_spec.rb +++ b/spec/models/status_spec.rb @@ -166,7 +166,7 @@ RSpec.describe Status do describe '#replies_count' do it 'is the number of replies' do - reply = Fabricate(:status, account: bob, thread: subject) + Fabricate(:status, account: bob, thread: subject) expect(subject.replies_count).to eq 1 end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index bb61c02a63..92ce87e369 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -55,17 +55,17 @@ RSpec.describe User do 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] + first_user = Fabricate(:user) + second_user = Fabricate(:user) + expect(described_class.recent).to eq [second_user, first_user] 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) + Fabricate(:user, confirmed_at: nil) + confirmed_user = Fabricate(:user, confirmed_at: Time.zone.now) + expect(described_class.confirmed).to contain_exactly(confirmed_user) end end diff --git a/spec/models/webauthn_credentials_spec.rb b/spec/models/webauthn_credentials_spec.rb index 4579ebb82e..9631245e11 100644 --- a/spec/models/webauthn_credentials_spec.rb +++ b/spec/models/webauthn_credentials_spec.rb @@ -37,7 +37,7 @@ RSpec.describe WebauthnCredential do 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') + Fabricate(:webauthn_credential, external_id: '_Typ0ygudDnk9YUVWLQayw') new_webauthn_credential = Fabricate.build(:webauthn_credential, external_id: '_Typ0ygudDnk9YUVWLQayw') new_webauthn_credential.valid? @@ -47,7 +47,7 @@ RSpec.describe WebauthnCredential do 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') + 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? diff --git a/spec/requests/api/v1/apps/credentials_spec.rb b/spec/requests/api/v1/apps/credentials_spec.rb index 1268b36f8a..e1455fe799 100644 --- a/spec/requests/api/v1/apps/credentials_spec.rb +++ b/spec/requests/api/v1/apps/credentials_spec.rb @@ -9,7 +9,8 @@ describe 'Credentials' do end context 'with an oauth token' do - let(:token) { Fabricate(:accessible_access_token, scopes: 'read', application: Fabricate(:application)) } + let(:application) { Fabricate(:application, scopes: 'read') } + let(:token) { Fabricate(:accessible_access_token, application: application) } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } it 'returns the app information correctly', :aggregate_failures do @@ -21,7 +22,35 @@ describe 'Credentials' do a_hash_including( name: token.application.name, website: token.application.website, - vapid_key: Rails.configuration.x.vapid_public_key + vapid_key: Rails.configuration.x.vapid_public_key, + scopes: token.application.scopes.map(&:to_s), + client_id: token.application.uid + ) + ) + end + end + + context 'with a non-read scoped oauth token' do + let(:application) { Fabricate(:application, scopes: 'admin:write') } + let(:token) { Fabricate(:accessible_access_token, application: 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, + scopes: token.application.scopes.map(&:to_s), + client_id: token.application.uid ) ) end @@ -36,5 +65,49 @@ describe 'Credentials' do expect(response).to have_http_status(401) end end + + context 'with a revoked oauth token' do + let(:application) { Fabricate(:application, scopes: 'read') } + let(:token) { Fabricate(:accessible_access_token, application: application, revoked_at: DateTime.now.utc) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } + + it 'returns http authorization error' do + subject + + expect(response).to have_http_status(401) + end + + it 'returns the error in the json response' do + subject + + expect(body_as_json).to match( + a_hash_including( + error: 'The access token was revoked' + ) + ) + end + end + + context 'with an invalid oauth token' do + let(:application) { Fabricate(:application, scopes: 'read') } + let(:token) { Fabricate(:accessible_access_token, application: application) } + let(:headers) { { 'Authorization' => "Bearer #{token.token}-invalid" } } + + it 'returns http authorization error' do + subject + + expect(response).to have_http_status(401) + end + + it 'returns the error in the json response' do + subject + + expect(body_as_json).to match( + a_hash_including( + error: 'The access token is invalid' + ) + ) + end + end end end diff --git a/spec/services/account_search_service_spec.rb b/spec/services/account_search_service_spec.rb index 1cd036f484..4f89cd220c 100644 --- a/spec/services/account_search_service_spec.rb +++ b/spec/services/account_search_service_spec.rb @@ -56,7 +56,7 @@ describe AccountSearchService, type: :service 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) + subject.call('newuser@remote.com', nil, limit: 10, resolve: true) expect(service).to have_received(:call).with('newuser@remote.com') end @@ -64,14 +64,14 @@ describe AccountSearchService, type: :service 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) + 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) + Fabricate(:account, username: 'exact', suspended: true) results = subject.call('exact', nil, limit: 10) expect(results.size).to eq 1 @@ -79,7 +79,7 @@ describe AccountSearchService, type: :service do end it 'does not return suspended remote accounts' do - remote = Fabricate(:account, username: 'a', domain: 'remote', display_name: 'e', suspended: true) + 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 diff --git a/spec/services/post_status_service_spec.rb b/spec/services/post_status_service_spec.rb index 7d7679c889..1e5c420a63 100644 --- a/spec/services/post_status_service_spec.rb +++ b/spec/services/post_status_service_spec.rb @@ -155,7 +155,7 @@ RSpec.describe PostStatusService, type: :service do it 'processes duplicate mentions correctly' do account = Fabricate(:account) - mentioned_account = Fabricate(:account, username: 'alice') + Fabricate(:account, username: 'alice') expect do subject.call(account, text: '@alice @alice @alice hey @alice') @@ -212,7 +212,7 @@ RSpec.describe PostStatusService, type: :service do account = Fabricate(:account) media = Fabricate(:media_attachment, account: Fabricate(:account)) - status = subject.call( + subject.call( account, text: 'test status update', media_ids: [media.id] diff --git a/spec/services/precompute_feed_service_spec.rb b/spec/services/precompute_feed_service_spec.rb index 54e0d94ee0..663babae8a 100644 --- a/spec/services/precompute_feed_service_spec.rb +++ b/spec/services/precompute_feed_service_spec.rb @@ -27,7 +27,7 @@ RSpec.describe PrecomputeFeedService, type: :service do 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) + Fabricate(:status, account: account, reblog: reblog) subject.call(account) diff --git a/spec/services/resolve_url_service_spec.rb b/spec/services/resolve_url_service_spec.rb index 7991aa6ef1..bcfb9dbfb0 100644 --- a/spec/services/resolve_url_service_spec.rb +++ b/spec/services/resolve_url_service_spec.rb @@ -7,8 +7,8 @@ describe ResolveURLService, type: :service do 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') + url = 'http://example.com/missing-resource' + Fabricate(:account, uri: url, domain: 'example.com') service = instance_double(FetchResourceService) allow(FetchResourceService).to receive(:new).and_return service diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4d3c234a0e..6ff0a8f842 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -38,7 +38,7 @@ RSpec.configure do |config| end # Use the GitHub Annotations formatter for CI - if ENV['GITHUB_ACTIONS'] == 'true' + if ENV['GITHUB_ACTIONS'] == 'true' && ENV['GITHUB_RSPEC'] == 'true' require 'rspec/github' config.add_formatter RSpec::Github::Formatter end diff --git a/spec/views/statuses/show.html.haml_spec.rb b/spec/views/statuses/show.html.haml_spec.rb index 354f9d3e63..a9d3edf7a1 100644 --- a/spec/views/statuses/show.html.haml_spec.rb +++ b/spec/views/statuses/show.html.haml_spec.rb @@ -13,7 +13,7 @@ describe 'statuses/show.html.haml', without_verify_partial_doubles: true do 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) + Fabricate(:media_attachment, account: alice, status: status, type: :video) assign(:status, status) assign(:account, alice) @@ -32,7 +32,7 @@ describe 'statuses/show.html.haml', without_verify_partial_doubles: true do 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) + Fabricate(:media_attachment, account: alice, status: status, type: :video) assign(:status, status) assign(:account, alice)