Merge commit '9f218c9924b883207a3463a29314c92032cf06df' into glitch-soc/merge-upstream
This commit is contained in:
		
						commit
						74fd46d3ab
					
				
					 42 changed files with 476 additions and 169 deletions
				
			
		
							
								
								
									
										1
									
								
								.github/workflows/test-ruby.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/test-ruby.yml
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								app/helpers/admin/disputes_helper.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/helpers/admin/disputes_helper.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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()) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,7 +100,7 @@ class LinkFooter extends PureComponent {
 | 
			
		|||
          {DividingCircle}
 | 
			
		||||
          <a href={source_url} rel='noopener noreferrer' target='_blank'><FormattedMessage id='footer.source_code' defaultMessage='View source code' /></a>
 | 
			
		||||
          {DividingCircle}
 | 
			
		||||
          <span class='version'>v{version}</span>
 | 
			
		||||
          <span className='version'>v{version}</span>
 | 
			
		||||
        </p>
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,10 +59,10 @@ class NavigationPanel extends Component {
 | 
			
		|||
          <Link to='/' className='column-link column-link--logo'><WordmarkLogo /></Link>
 | 
			
		||||
 | 
			
		||||
          {transientSingleColumn ? (
 | 
			
		||||
            <div class='switch-to-advanced'>
 | 
			
		||||
            <div className='switch-to-advanced'>
 | 
			
		||||
              {intl.formatMessage(messages.openedInClassicInterface)}
 | 
			
		||||
              {" "}
 | 
			
		||||
              <a href={`/deck${location.pathname}`} class='switch-to-advanced__toggle'>
 | 
			
		||||
              <a href={`/deck${location.pathname}`} className='switch-to-advanced__toggle'>
 | 
			
		||||
                {intl.formatMessage(messages.advancedInterface)}
 | 
			
		||||
              </a>
 | 
			
		||||
            </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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": "この投稿は公開設定ではないのでハッシュタグの一覧に表示されません。公開投稿だけがハッシュタグで検索できます。",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -114,7 +114,7 @@
 | 
			
		|||
  "column.directory": "瀏覽個人檔案",
 | 
			
		||||
  "column.domain_blocks": "已封鎖網域",
 | 
			
		||||
  "column.favourites": "最愛",
 | 
			
		||||
  "column.firehose": "即時內容",
 | 
			
		||||
  "column.firehose": "即時河道",
 | 
			
		||||
  "column.follow_requests": "跟隨請求",
 | 
			
		||||
  "column.home": "首頁",
 | 
			
		||||
  "column.lists": "列表",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 = {}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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: "<strong>%{count}</strong> 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. <strong>Varo estämästä suuria sähköpostin palveluntarjoajia.</strong>
 | 
			
		||||
      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. <strong>Varo estämästä suuria sähköpostin palveluntarjoajia.</strong>
 | 
			
		||||
      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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 通知,如非選擇了 <strong>垃圾郵件</strong> 類別。
 | 
			
		||||
      actions_description_remote_html: 決定將對此檢舉報告採取何種動作。這將僅作用於<strong>您的伺服器</strong>與此遠端帳號及其內容之通訊行為。
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								db/migrate/.rubocop.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								db/migrate/.rubocop.yml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
inherit_from: ../../.rubocop.yml
 | 
			
		||||
 | 
			
		||||
Naming/VariableNumber:
 | 
			
		||||
  CheckSymbols: false
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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("<span class=\"username\">#{strike.account.username}</span>")
 | 
			
		||||
      expect(response.body).to include("<span class=\"target\">#{appeal.account.username}</span>")
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 '<http://test.host/.well-known/webfinger?resource=acct%3Ausername%40cb6e6126.ngrok.io>; rel="lrdd"; type="application/jrd+json", <https://cb6e6126.ngrok.io/users/username>; rel="alternate"; type="application/activity+json"'
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										21
									
								
								spec/helpers/admin/disputes_helper_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								spec/helpers/admin/disputes_helper_spec.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
        <span class="username">Adam</span> suspended <span class="target">Becky</span>'s account
 | 
			
		||||
      OUTPUT
 | 
			
		||||
      result = helper.strike_action_label(appeal)
 | 
			
		||||
 | 
			
		||||
      expect(result).to eq(expected)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue