~cytrogen/masto-fe

ff168ef2024626f37fa776fde5739dcd58ecb9f2 — Claire 3 years ago 29a91b8
Fix most rubocop issues (#2165)

* Run rubocop --autocorrect on app/, config/ and lib/, also manually fix some remaining style issues

* Run rubocop --autocorrect-all on db/

* Run rubocop --autocorrect-all on `spec/` and fix remaining issues
45 files changed, 210 insertions(+), 215 deletions(-)

M .rubocop_todo.yml
M app/controllers/api/v1/timelines/public_controller.rb
M app/controllers/auth/confirmations_controller.rb
M app/controllers/settings/flavours_controller.rb
M app/helpers/accounts_helper.rb
M app/lib/advanced_text_formatter.rb
M app/lib/feed_manager.rb
M app/lib/themes.rb
M app/models/direct_feed.rb
M app/models/status.rb
M app/models/user.rb
M app/serializers/activitypub/note_serializer.rb
M app/serializers/rest/account_serializer.rb
M app/serializers/rest/mute_serializer.rb
M app/serializers/rest/status_serializer.rb
M app/services/backup_service.rb
M app/services/fan_out_on_write_service.rb
M app/services/post_status_service.rb
M app/validators/status_pin_validator.rb
M config/initializers/0_duplicate_migrations.rb
M config/initializers/simple_form.rb
M db/migrate/20171009222537_create_keyword_mutes.rb
M db/migrate/20171021191900_move_keyword_mutes_into_glitch_namespace.rb
M db/migrate/20171210213213_add_local_only_flag_to_statuses.rb
M db/migrate/20180410220657_create_bookmarks.rb
M db/migrate/20180604000556_add_apply_to_mentions_flag_to_keyword_mutes.rb
M db/migrate/20180707193142_migrate_filters.rb
M db/migrate/20190512200918_add_content_type_to_statuses.rb
M db/migrate/20220209175231_add_content_type_to_status_edits.rb
M db/post_migrate/20180813160548_post_migrate_filters.rb
M lib/sanitize_ext/sanitize_config.rb
M lib/tasks/assets.rake
M lib/tasks/glitchsoc.rake
M spec/controllers/api/v1/accounts/credentials_controller_spec.rb
M spec/controllers/api/v1/timelines/direct_controller_spec.rb
M spec/controllers/application_controller_spec.rb
M spec/controllers/settings/flavours_controller_spec.rb
M spec/lib/advanced_text_formatter_spec.rb
M spec/models/concerns/account_interactions_spec.rb
M spec/models/public_feed_spec.rb
M spec/models/status_spec.rb
M spec/models/tag_feed_spec.rb
M spec/policies/status_policy_spec.rb
M spec/services/notify_service_spec.rb
M spec/validators/status_length_validator_spec.rb
M .rubocop_todo.yml => .rubocop_todo.yml +2 -0
@@ 473,6 473,7 @@ RSpec/ContextWording:
    - 'spec/lib/activitypub/activity/create_spec.rb'
    - 'spec/lib/activitypub/activity/follow_spec.rb'
    - 'spec/lib/activitypub/activity/reject_spec.rb'
    - 'spec/lib/advanced_text_formatter_spec.rb'
    - 'spec/lib/emoji_formatter_spec.rb'
    - 'spec/lib/entity_cache_spec.rb'
    - 'spec/lib/feed_manager_spec.rb'


@@ 1321,6 1322,7 @@ Rails/FilePath:
    - 'app/models/setting.rb'
    - 'app/validators/reaction_validator.rb'
    - 'config/environments/test.rb'
    - 'config/initializers/locale.rb'
    - 'db/migrate/20170716191202_add_hide_notifications_to_mute.rb'
    - 'db/migrate/20171005171936_add_disabled_to_custom_emojis.rb'
    - 'db/migrate/20171028221157_add_reblogs_to_follows.rb'

M app/controllers/api/v1/timelines/public_controller.rb => app/controllers/api/v1/timelines/public_controller.rb +1 -1
@@ 40,7 40,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController
      only_media: truthy_param?(:only_media),
      allow_local_only: truthy_param?(:allow_local_only),
      with_replies: Setting.show_replies_in_public_timelines,
      with_reblogs: Setting.show_reblogs_in_public_timelines,
      with_reblogs: Setting.show_reblogs_in_public_timelines
    )
  end


M app/controllers/auth/confirmations_controller.rb => app/controllers/auth/confirmations_controller.rb +7 -6
@@ 15,12 15,6 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController

  skip_before_action :require_functional!

  def new
    super

    resource.email = current_user.unconfirmed_email || current_user.email if user_signed_in?
  end

  def show
    old_session_values = session.to_hash
    reset_session


@@ 29,6 23,12 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
    super
  end

  def new
    super

    resource.email = current_user.unconfirmed_email || current_user.email if user_signed_in?
  end

  def confirm_captcha
    check_captcha! do |message|
      flash.now[:alert] = message


@@ 51,6 51,7 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
    # step.
    confirmation_token = params[:confirmation_token]
    return if confirmation_token.nil?

    @confirmation_user = User.find_first_by_auth_conditions(confirmation_token: confirmation_token)
  end


M app/controllers/settings/flavours_controller.rb => app/controllers/settings/flavours_controller.rb +1 -3
@@ 12,9 12,7 @@ class Settings::FlavoursController < Settings::BaseController
  end

  def show
    unless Themes.instance.flavours.include?(params[:flavour]) || (params[:flavour] == current_flavour)
      redirect_to action: 'show', flavour: current_flavour
    end
    redirect_to action: 'show', flavour: current_flavour unless Themes.instance.flavours.include?(params[:flavour]) || (params[:flavour] == current_flavour)

    @listing = Themes.instance.flavours
    @selected = params[:flavour]

M app/helpers/accounts_helper.rb => app/helpers/accounts_helper.rb +1 -1
@@ 28,7 28,7 @@ module AccountsHelper
  end

  def hide_followers_count?(account)
    Setting.hide_followers_count || account.user&.settings['hide_followers_count']
    Setting.hide_followers_count || account.user&.settings&.[]('hide_followers_count')
  end

  def account_description(account)

M app/lib/advanced_text_formatter.rb => app/lib/advanced_text_formatter.rb +1 -0
@@ 15,6 15,7 @@ class AdvancedTextFormatter < TextFormatter

    def autolink(link, link_type)
      return link if link_type == :email

      @format_link.call(link)
    end
  end

M app/lib/feed_manager.rb => app/lib/feed_manager.rb +2 -0
@@ 306,6 306,7 @@ class FeedManager

      statuses.each do |status|
        next if filter_from_direct?(status, account)

        added += 1 if add_to_feed(:direct, account.id, status)
      end



@@ 459,6 460,7 @@ class FeedManager
  # @return [Boolean]
  def filter_from_direct?(status, receiver_id)
    return false if receiver_id == status.account_id

    filter_from_mentions?(status, receiver_id)
  end


M app/lib/themes.rb => app/lib/themes.rb +20 -25
@@ 7,24 7,23 @@ class Themes
  include Singleton

  def initialize

    core = YAML.load_file(Rails.root.join('app', 'javascript', 'core', 'theme.yml'))
    core['pack'] = Hash.new unless core['pack']
    core['pack'] = {} unless core['pack']

    result = Hash.new
    Dir.glob(Rails.root.join('app', 'javascript', 'flavours', '*', 'theme.yml')) do |path|
      data = YAML.load_file(path)
    result = {}
    Rails.root.glob('app/javascript/flavours/*/theme.yml') do |pathname|
      data = YAML.load_file(pathname)
      next unless data['pack']

      dir = File.dirname(path)
      name = File.basename(dir)
      dir = pathname.dirname
      name = dir.basename.to_s
      locales = []
      screenshots = []

      if data['locales']
        Dir.glob(File.join(dir, data['locales'], '*.{js,json}')) do |locale|
          localeName = File.basename(locale, File.extname(locale))
          locales.push(localeName) unless localeName.match(/defaultMessages|whitelist|index/)
          locale_name = File.basename(locale, File.extname(locale))
          locales.push(locale_name) unless /defaultMessages|whitelist|index/.match?(locale_name)
        end
      end



@@ 43,34 42,30 @@ class Themes
      result[name] = data
    end

    Dir.glob(Rails.root.join('app', 'javascript', 'skins', '*', '*')) do |path|
      ext = File.extname(path)
      skin = File.basename(path)
      name = File.basename(File.dirname(path))
    Rails.root.glob('app/javascript/skins/*/*') do |pathname|
      ext = pathname.extname.to_s
      skin = pathname.basename.to_s
      name = pathname.dirname.basename.to_s
      next unless result[name]

      if File.directory?(path)
      if pathname.directory?
        pack = []
        Dir.glob(File.join(path, '*.{css,scss}')) do |sheet|
          pack.push(File.basename(sheet, File.extname(sheet)))
        pathname.glob('*.{css,scss}') do |sheet|
          pack.push(sheet.basename(sheet.extname).to_s)
        end
      elsif ext.match(/^\.s?css$/i)
        skin = File.basename(path, ext)
      elsif /^\.s?css$/i.match?(ext)
        skin = pathname.basename(ext).to_s
        pack = ['common']
      end

      if skin != 'default'
        result[name]['skin'][skin] = pack
      end
      result[name]['skin'][skin] = pack if skin != 'default'
    end

    @core = core
    @conf = result
  end

  def core
    @core
  end
  attr_reader :core

  def flavour(name)
    @conf[name]


@@ 86,7 81,7 @@ class Themes

  def flavours_and_skins
    flavours.map do |flavour|
      [flavour, skins_for(flavour).map{ |skin| [flavour, skin] }]
      [flavour, skins_for(flavour).map { |skin| [flavour, skin] }]
    end
  end
end

M app/models/direct_feed.rb => app/models/direct_feed.rb +5 -4
@@ 4,9 4,8 @@ class DirectFeed < Feed
  include Redisable

  def initialize(account)
    @type    = :direct
    @id      = account.id
    @account = account
    super(:direct, account.id)
  end

  def get(limit, max_id = nil, since_id = nil, min_id = nil)


@@ 19,10 18,12 @@ class DirectFeed < Feed

  private

  def from_database(limit, max_id, since_id, min_id)
  # TODO: _min_id is not actually handled by `as_direct_timeline`
  def from_database(limit, max_id, since_id, _min_id)
    loop do
      statuses = Status.as_direct_timeline(@account, limit, max_id, since_id, min_id)
      statuses = Status.as_direct_timeline(@account, limit, max_id, since_id)
      return statuses if statuses.empty?

      max_id = statuses.last.id
      statuses = statuses.reject { |status| FeedManager.instance.filter?(:direct, status, @account) }
      return statuses unless statuses.empty?

M app/models/status.rb => app/models/status.rb +7 -12
@@ 338,7 338,7 @@ class Status < ApplicationRecord
      visibilities.keys - %w(direct limited)
    end

    def as_direct_timeline(account, limit = 20, max_id = nil, since_id = nil, cache_ids = false)
    def as_direct_timeline(account, limit = 20, max_id = nil, since_id = nil)
      # direct timeline is mix of direct message from_me and to_me.
      # 2 queries are executed with pagination.
      # constant expression using arel_table is required for partial index


@@ 369,14 369,9 @@ class Status < ApplicationRecord
        query_to_me = query_to_me.where('mentions.status_id > ?', since_id)
      end

      if cache_ids
        # returns array of cache_ids object that have id and updated_at
        (query_from_me.cache_ids.to_a + query_to_me.cache_ids.to_a).uniq(&:id).sort_by(&:id).reverse.take(limit)
      else
        # returns ActiveRecord.Relation
        items = (query_from_me.select(:id).to_a + query_to_me.select(:id).to_a).uniq(&:id).sort_by(&:id).reverse.take(limit)
        Status.where(id: items.map(&:id))
      end
      # returns ActiveRecord.Relation
      items = (query_from_me.select(:id).to_a + query_to_me.select(:id).to_a).uniq(&:id).sort_by(&:id).reverse.take(limit)
      Status.where(id: items.map(&:id))
    end

    def favourites_map(status_ids, account_id)


@@ 553,9 548,9 @@ class Status < ApplicationRecord
  end

  def set_locality
    if account.domain.nil? && !attribute_changed?(:local_only)
      self.local_only = marked_local_only?
    end
    return unless account.domain.nil? && !attribute_changed?(:local_only)

    self.local_only = marked_local_only?
  end

  def set_conversation

M app/models/user.rb => app/models/user.rb +0 -1
@@ 244,7 244,6 @@ class User < ApplicationRecord
  end

  def functional?

    functional_or_moved?
  end


M app/serializers/activitypub/note_serializer.rb => app/serializers/activitypub/note_serializer.rb +1 -0
@@ 32,6 32,7 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer

  def id
    raise Mastodon::NotPermittedError, 'Local-only statuses should not be serialized' if object.local_only? && !instance_options[:allow_local_only]

    ActivityPub::TagManager.instance.uri_for(object)
  end


M app/serializers/rest/account_serializer.rb => app/serializers/rest/account_serializer.rb +1 -1
@@ 91,7 91,7 @@ class REST::AccountSerializer < ActiveModel::Serializer
  end

  def followers_count
    (Setting.hide_followers_count || object.user&.setting_hide_followers_count) ? -1 : object.followers_count
    Setting.hide_followers_count || object.user&.setting_hide_followers_count ? -1 : object.followers_count
  end

  def display_name

M app/serializers/rest/mute_serializer.rb => app/serializers/rest/mute_serializer.rb +2 -2
@@ 2,7 2,7 @@

class REST::MuteSerializer < ActiveModel::Serializer
  include RoutingHelper
  

  attributes :id, :account, :target_account, :created_at, :hide_notifications

  def account


@@ 12,4 12,4 @@ class REST::MuteSerializer < ActiveModel::Serializer
  def target_account
    REST::AccountSerializer.new(object.target_account)
  end
end
\ No newline at end of file
end

M app/serializers/rest/status_serializer.rb => app/serializers/rest/status_serializer.rb +3 -1
@@ 13,7 13,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
  attribute :muted, if: :current_user?
  attribute :bookmarked, if: :current_user?
  attribute :pinned, if: :pinnable?
  attribute :local_only if :local?
  attribute :local_only, if: :local?
  has_many :filtered, serializer: REST::FilterResultSerializer, if: :current_user?

  attribute :content, unless: :source_requested?


@@ 32,6 32,8 @@ class REST::StatusSerializer < ActiveModel::Serializer
  has_one :preview_card, key: :card, serializer: REST::PreviewCardSerializer
  has_one :preloadable_poll, key: :poll, serializer: REST::PollSerializer

  delegate :local?, to: :object

  def id
    object.id.to_s
  end

M app/services/backup_service.rb => app/services/backup_service.rb +1 -1
@@ 154,7 154,7 @@ class BackupService < BaseService
      object,
      serializer: serializer,
      adapter: ActivityPub::Adapter,
      allow_local_only: true,
      allow_local_only: true
    ).as_json
  end


M app/services/fan_out_on_write_service.rb => app/services/fan_out_on_write_service.rb +1 -1
@@ 116,7 116,7 @@ class FanOutOnWriteService < BaseService
  end

  def deliver_to_direct_timelines!
    FeedInsertWorker.push_bulk(@status.mentions.includes(:account).map(&:account).select { |mentioned_account| mentioned_account.local? }) do |account|
    FeedInsertWorker.push_bulk(@status.mentions.includes(:account).map(&:account).select(&:local?)) do |account|
      [@status.id, account.id, 'direct', { 'update' => update? }]
    end
  end

M app/services/post_status_service.rb => app/services/post_status_service.rb +15 -10
@@ 61,17 61,22 @@ class PostStatusService < BaseService

  private

  def preprocess_attributes!
    if @text.blank? && @options[:spoiler_text].present?
     @text = '.'
     if @media&.find(&:video?) || @media&.find(&:gifv?)
       @text = '📹'
     elsif @media&.find(&:audio?)
       @text = '🎵'
     elsif @media&.find(&:image?)
       @text = '🖼'
     end
  def fill_blank_text!
    return unless @text.blank? && @options[:spoiler_text].present?

    if @media&.any?(&:video?) || @media&.any?(&:gifv?)
      @text = '📹'
    elsif @media&.any?(&:audio?)
      @text = '🎵'
    elsif @media&.any?(&:image?)
      @text = '🖼'
    else
      @text = '.'
    end
  end

  def preprocess_attributes!
    fill_blank_text!
    @sensitive    = (@options[:sensitive].nil? ? @account.user&.setting_default_sensitive : @options[:sensitive]) || @options[:spoiler_text].present?
    @visibility   = @options[:visibility] || @account.user&.setting_default_privacy
    @visibility   = :unlisted if @visibility&.to_sym == :public && @account.silenced?

M app/validators/status_pin_validator.rb => app/validators/status_pin_validator.rb +1 -1
@@ 7,6 7,6 @@ class StatusPinValidator < ActiveModel::Validator
    pin.errors.add(:base, I18n.t('statuses.pin_errors.reblog')) if pin.status.reblog?
    pin.errors.add(:base, I18n.t('statuses.pin_errors.ownership')) if pin.account_id != pin.status.account_id
    pin.errors.add(:base, I18n.t('statuses.pin_errors.direct')) if pin.status.direct_visibility?
    pin.errors.add(:base, I18n.t('statuses.pin_errors.limit')) if pin.account.status_pins.count >= MAX_PINNED  && pin.account.local?
    pin.errors.add(:base, I18n.t('statuses.pin_errors.limit')) if pin.account.status_pins.count >= MAX_PINNED && pin.account.local?
  end
end

M config/initializers/0_duplicate_migrations.rb => config/initializers/0_duplicate_migrations.rb +14 -10
@@ 1,3 1,5 @@
# frozen_string_literal: true

# Some migrations have been present in glitch-soc for a long time and have then
# been merged in upstream Mastodon, under a different version number.
#


@@ 12,24 14,26 @@
# we decided monkey-patching Rails' Migrator to completely ignore the duplicate,
# keeping only the one that has run, or an arbitrary one.

ALLOWED_DUPLICATES = [20180410220657, 20180831171112].freeze
ALLOWED_DUPLICATES = [2018_04_10_220657, 2018_08_31_171112].freeze

module ActiveRecord
  class Migrator
    def self.new(direction, migrations, schema_migration, target_version = nil)
      migrated = Set.new(Base.connection.migration_context.get_all_versions)

      migrations.group_by(&:name).each do |name, duplicates|
        if duplicates.length > 1 && duplicates.all? { |m| ALLOWED_DUPLICATES.include?(m.version) }
          # We have a set of allowed duplicates. Keep the migrated one, if any.
          non_migrated = duplicates.reject { |m| migrated.include?(m.version.to_i) }
      migrations.group_by(&:name).each do |_name, duplicates|
        next unless duplicates.length > 1 && duplicates.all? { |m| ALLOWED_DUPLICATES.include?(m.version) }

        # We have a set of allowed duplicates. Keep the migrated one, if any.
        non_migrated = duplicates.reject { |m| migrated.include?(m.version.to_i) }

          if duplicates.length == non_migrated.length || non_migrated.length == 0
        migrations = begin
          if duplicates.length == non_migrated.length || non_migrated.empty?
            # There weren't any migrated one, so we have to pick one “canonical” migration
            migrations = migrations - duplicates[1..-1]
            migrations - duplicates[1..]
          else
            # Just reject every duplicate which hasn't been migrated yet
            migrations = migrations - non_migrated
            migrations - non_migrated
          end
        end
      end


@@ 43,10 47,10 @@ module ActiveRecord
      # A set of duplicated migrations is considered migrated if at least one of
      # them is migrated.
      migrated = get_all_versions
      migrations.group_by(&:name).each do |name, duplicates|
      migrations.group_by(&:name).each do |_name, duplicates|
        return true unless duplicates.any? { |m| migrated.include?(m.version.to_i) }
      end
      return false
      false
    end
  end
end

M config/initializers/simple_form.rb => config/initializers/simple_form.rb +1 -0
@@ 22,6 22,7 @@ end
module GlitchOnlyComponent
  def glitch_only(_wrapper_options = nil)
    return unless options[:glitch_only]

    options[:label_text] = ->(raw_label_text, _required_label_text, _label_present) { safe_join([raw_label_text, ' ', content_tag(:span, I18n.t('simple_form.glitch_only'), class: 'glitch_only')]) }
    nil
  end

M db/migrate/20171009222537_create_keyword_mutes.rb => db/migrate/20171009222537_create_keyword_mutes.rb +2 -0
@@ 1,3 1,5 @@
# frozen_string_literal: true

class CreateKeywordMutes < ActiveRecord::Migration[5.1]
  def change
    create_table :keyword_mutes do |t|

M db/migrate/20171021191900_move_keyword_mutes_into_glitch_namespace.rb => db/migrate/20171021191900_move_keyword_mutes_into_glitch_namespace.rb +2 -0
@@ 1,3 1,5 @@
# frozen_string_literal: true

class MoveKeywordMutesIntoGlitchNamespace < ActiveRecord::Migration[5.1]
  def change
    safety_assured do

M db/migrate/20171210213213_add_local_only_flag_to_statuses.rb => db/migrate/20171210213213_add_local_only_flag_to_statuses.rb +2 -0
@@ 1,3 1,5 @@
# frozen_string_literal: true

class AddLocalOnlyFlagToStatuses < ActiveRecord::Migration[5.1]
  def change
    add_column :statuses, :local_only, :boolean

M db/migrate/20180410220657_create_bookmarks.rb => db/migrate/20180410220657_create_bookmarks.rb +2 -0
@@ 1,3 1,5 @@
# frozen_string_literal: true

# This migration is a duplicate of 20180831171112 and may get ignored, see
# config/initializers/0_duplicate_migrations.rb


M db/migrate/20180604000556_add_apply_to_mentions_flag_to_keyword_mutes.rb => db/migrate/20180604000556_add_apply_to_mentions_flag_to_keyword_mutes.rb +2 -0
@@ 1,3 1,5 @@
# frozen_string_literal: true

require 'mastodon/migration_helpers'

class AddApplyToMentionsFlagToKeywordMutes < ActiveRecord::Migration[5.2]

M db/migrate/20180707193142_migrate_filters.rb => db/migrate/20180707193142_migrate_filters.rb +8 -4
@@ 1,7 1,9 @@
# frozen_string_literal: true

class MigrateFilters < ActiveRecord::Migration[5.2]
  class GlitchKeywordMute < ApplicationRecord
    # Dummy class, as we removed Glitch::KeywordMute
    belongs_to :account, required: true
    belongs_to :account, optional: false
    validates_presence_of :keyword
  end



@@ 15,7 17,7 @@ class MigrateFilters < ActiveRecord::Migration[5.2]
    private

    def clean_up_contexts
      self.context = Array(context).map(&:strip).map(&:presence).compact
      self.context = Array(context).map(&:strip).filter_map(&:presence)
    end
  end



@@ 27,7 29,8 @@ class MigrateFilters < ActiveRecord::Migration[5.2]
        phrase: filter.keyword,
        context: filter.apply_to_mentions ? %w(home public notifications) : %w(home public),
        whole_word: filter.whole_word,
        irreversible: true)
        irreversible: true
      )
    end
  end



@@ 48,7 51,8 @@ class MigrateFilters < ActiveRecord::Migration[5.2]
      GlitchKeywordMute.where(account: filter.account).create!(
        keyword: filter.phrase,
        whole_word: filter.whole_word,
        apply_to_mentions: filter.context.include?('notifications'))
        apply_to_mentions: filter.context.include?('notifications')
      )
    end
  end
end

M db/migrate/20190512200918_add_content_type_to_statuses.rb => db/migrate/20190512200918_add_content_type_to_statuses.rb +2 -0
@@ 1,3 1,5 @@
# frozen_string_literal: true

class AddContentTypeToStatuses < ActiveRecord::Migration[5.2]
  def change
    add_column :statuses, :content_type, :string

M db/migrate/20220209175231_add_content_type_to_status_edits.rb => db/migrate/20220209175231_add_content_type_to_status_edits.rb +2 -0
@@ 1,3 1,5 @@
# frozen_string_literal: true

class AddContentTypeToStatusEdits < ActiveRecord::Migration[6.1]
  def change
    add_column :status_edits, :content_type, :string

M db/post_migrate/20180813160548_post_migrate_filters.rb => db/post_migrate/20180813160548_post_migrate_filters.rb +3 -3
@@ 1,3 1,5 @@
# frozen_string_literal: true

class PostMigrateFilters < ActiveRecord::Migration[5.2]
  disable_ddl_transaction!



@@ 5,7 7,5 @@ class PostMigrateFilters < ActiveRecord::Migration[5.2]
    drop_table :glitch_keyword_mutes if table_exists? :glitch_keyword_mutes
  end

  def down
  end
  def down; end
end


M lib/sanitize_ext/sanitize_config.rb => lib/sanitize_ext/sanitize_config.rb +4 -4
@@ 48,9 48,9 @@ class Sanitize
        node.content = "[🖼  #{node['alt']}]"
      else
        url = node['href']
        prefix = url.match(/\Ahttps?:\/\/(www\.)?/).to_s
        prefix = url.match(%r{\Ahttps?://(www\.)?}).to_s
        text   = url[prefix.length, 30]
        text   = text + "…" if url[prefix.length..-1].length > 30
        text += '…' if url.length - prefix.length > 30
        node.content = "[🖼  #{text}]"
      end
    end


@@ 88,7 88,7 @@ class Sanitize
      },

      protocols: {
        'a'          => { 'href' => LINK_PROTOCOLS },
        'a' => { 'href' => LINK_PROTOCOLS },
        'blockquote' => { 'cite' => LINK_PROTOCOLS },
      },



@@ 126,7 126,7 @@ class Sanitize

      node = env[:node]

      rel = (node['rel'] || '').split(' ') & ['tag']
      rel = (node['rel'] || '').split & ['tag']
      rel += ['nofollow', 'noopener', 'noreferrer'] unless TagManager.instance.local_url?(node['href'])

      if rel.empty?

M lib/tasks/assets.rake => lib/tasks/assets.rake +6 -6
@@ 3,14 3,14 @@
namespace :assets do
  desc 'Generate static pages'
  task generate_static_pages: :environment do
    class StaticApplicationController < ApplicationController
      def current_user
        nil
    def render_static_page(action, dest:, **opts)
      renderer = Class.new(ApplicationController) do
        def current_user
          nil
        end
      end
    end

    def render_static_page(action, dest:, **opts)
      html = StaticApplicationController.render(action, opts)
      html = renderer.render(action, opts)
      File.write(dest, html)
    end


M lib/tasks/glitchsoc.rake => lib/tasks/glitchsoc.rake +6 -2
@@ 1,8 1,12 @@
# frozen_string_literal: true

namespace :glitchsoc do
  desc 'Backfill local-only flag on statuses table'
  task backfill_local_only: :environment do
    Status.local.where(local_only: nil).find_each do |st|
      ActiveRecord::Base.logger.silence { st.update_attribute(:local_only, st.marked_local_only?) }
    Status.local.where(local_only: nil).find_each do |status|
      ActiveRecord::Base.logger.silence do
        status.update_attribute(:local_only, status.marked_local_only?) # rubocop:disable Rails/SkipsModelValidations
      end
    end
  end
end

M spec/controllers/api/v1/accounts/credentials_controller_spec.rb => spec/controllers/api/v1/accounts/credentials_controller_spec.rb +2 -2
@@ 75,10 75,10 @@ describe Api::V1::Accounts::CredentialsController do
        end
      end

      describe 'with invalid data' do
      describe 'with a too long profile bio' do
        before do
          note = 'This is too long. '
          note = note + 'a' * (Account::MAX_NOTE_LENGTH - note.length + 1)
          note += 'a' * (Account::MAX_NOTE_LENGTH - note.length + 1)
          patch :update, params: { note: note }
        end


M spec/controllers/api/v1/timelines/direct_controller_spec.rb => spec/controllers/api/v1/timelines/direct_controller_spec.rb +1 -1
@@ 2,7 2,7 @@

require 'rails_helper'

RSpec.describe Api::V1::Timelines::DirectController, type: :controller do
RSpec.describe Api::V1::Timelines::DirectController do
  let(:user)  { Fabricate(:user) }
  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }


M spec/controllers/application_controller_spec.rb => spec/controllers/application_controller_spec.rb +2 -2
@@ 75,8 75,8 @@ describe ApplicationController, type: :controller do

  describe 'helper_method :current_flavour' do
    it 'returns "glitch" when theme wasn\'t changed in admin settings' do
      allow(Setting).to receive(:default_settings).and_return({'skin' => 'default'})
      allow(Setting).to receive(:default_settings).and_return({'flavour' => 'glitch'})
      allow(Setting).to receive(:default_settings).and_return({ 'skin' => 'default' })
      allow(Setting).to receive(:default_settings).and_return({ 'flavour' => 'glitch' })

      expect(controller.view_context.current_flavour).to eq 'glitch'
    end

M spec/controllers/settings/flavours_controller_spec.rb => spec/controllers/settings/flavours_controller_spec.rb +2 -1
@@ 1,7 1,8 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe Settings::FlavoursController, type: :controller do
RSpec.describe Settings::FlavoursController do
  let(:user) { Fabricate(:user) }

  before do

M spec/lib/advanced_text_formatter_spec.rb => spec/lib/advanced_text_formatter_spec.rb +42 -40
@@ 1,12 1,14 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe AdvancedTextFormatter do
  describe '#to_s' do
    subject { described_class.new(text, preloaded_accounts: preloaded_accounts, content_type: content_type).to_s }

    let(:preloaded_accounts) { nil }
    let(:content_type) { 'text/markdown' }

    subject { described_class.new(text, preloaded_accounts: preloaded_accounts, content_type: content_type).to_s }

    context 'given a markdown source' do
      let(:content_type) { 'text/markdown' }



@@ 14,7 16,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'text' }

        it 'paragraphizes the text' do
          is_expected.to eq '<p>text</p>'
          expect(subject).to eq '<p>text</p>'
        end
      end



@@ 22,7 24,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { "line\nfeed" }

        it 'removes line feeds' do
          is_expected.not_to include "\n"
          expect(subject).to_not include "\n"
        end
      end



@@ 30,7 32,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'test `foo` bar' }

        it 'formats code using <code>' do
          is_expected.to include 'test <code>foo</code> bar'
          expect(subject).to include 'test <code>foo</code> bar'
        end
      end



@@ 38,15 40,15 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { "test\n\n```\nint main(void) {\n  return 0; // https://joinmastodon.org/foo\n}\n```\n" }

        it 'formats code using <pre> and <code>' do
          is_expected.to include '<pre><code>int main'
          expect(subject).to include '<pre><code>int main'
        end

        it 'does not strip leading spaces' do
          is_expected.to include '>  return 0'
          expect(subject).to include '>  return 0'
        end

        it 'does not format links' do
          is_expected.to include 'return 0; // https://joinmastodon.org/foo'
          expect(subject).to include 'return 0; // https://joinmastodon.org/foo'
        end
      end



@@ 54,7 56,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'test `https://foo.bar/bar` bar' }

        it 'does not rewrite the link' do
          is_expected.to include 'test <code>https://foo.bar/bar</code> bar'
          expect(subject).to include 'test <code>https://foo.bar/bar</code> bar'
        end
      end



@@ 62,7 64,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'foo https://cb6e6126.ngrok.io/about/more' }

        it 'creates a link' do
          is_expected.to include '<a href="https://cb6e6126.ngrok.io/about/more"'
          expect(subject).to include '<a href="https://cb6e6126.ngrok.io/about/more"'
        end
      end



@@ 71,7 73,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { '@alice' }

        it 'creates a mention link' do
          is_expected.to include '<a href="https://cb6e6126.ngrok.io/@alice" class="u-url mention">@<span>alice</span></a></span>'
          expect(subject).to include '<a href="https://cb6e6126.ngrok.io/@alice" class="u-url mention">@<span>alice</span></a></span>'
        end
      end



@@ 80,7 82,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { '@alice' }

        it 'does not create a mention link' do
          is_expected.to include '@alice'
          expect(subject).to include '@alice'
        end
      end



@@ 88,7 90,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4' }

        it 'matches the full URL' do
          is_expected.to include 'href="https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4"'
          expect(subject).to include 'href="https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4"'
        end
      end



@@ 96,7 98,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'http://google.com' }

        it 'matches the full URL' do
          is_expected.to include 'href="http://google.com"'
          expect(subject).to include 'href="http://google.com"'
        end
      end



@@ 104,7 106,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'http://example.gay' }

        it 'matches the full URL' do
          is_expected.to include 'href="http://example.gay"'
          expect(subject).to include 'href="http://example.gay"'
        end
      end



@@ 112,11 114,11 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'https://nic.みんな/' }

        it 'matches the full URL' do
          is_expected.to include 'href="https://nic.みんな/"'
          expect(subject).to include 'href="https://nic.みんな/"'
        end

        it 'has display URL' do
          is_expected.to include '<span class="">nic.みんな/</span>'
          expect(subject).to include '<span class="">nic.みんな/</span>'
        end
      end



@@ 124,7 126,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona. ' }

        it 'matches the full URL but not the period' do
          is_expected.to include 'href="http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona"'
          expect(subject).to include 'href="http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona"'
        end
      end



@@ 132,7 134,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { '(http://google.com/)' }

        it 'matches the full URL but not the parentheses' do
          is_expected.to include 'href="http://google.com/"'
          expect(subject).to include 'href="http://google.com/"'
        end
      end



@@ 140,7 142,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'http://www.google.com!' }

        it 'matches the full URL but not the exclamation point' do
          is_expected.to include 'href="http://www.google.com"'
          expect(subject).to include 'href="http://www.google.com"'
        end
      end



@@ 148,7 150,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { "http://www.google.com'" }

        it 'matches the full URL but not the single quote' do
          is_expected.to include 'href="http://www.google.com"'
          expect(subject).to include 'href="http://www.google.com"'
        end
      end
    end


@@ 157,7 159,7 @@ RSpec.describe AdvancedTextFormatter do
      let(:text) { 'http://www.google.com>' }

      it 'matches the full URL but not the angle bracket' do
        is_expected.to include 'href="http://www.google.com"'
        expect(subject).to include 'href="http://www.google.com"'
      end
    end



@@ 166,7 168,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink' }

        it 'matches the full URL' do
          is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&amp;q=autolink"'
          expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&amp;q=autolink"'
        end
      end



@@ 174,7 176,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓&q=autolink' }

        it 'matches the full URL' do
          is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=✓&amp;q=autolink"'
          expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=✓&amp;q=autolink"'
        end
      end



@@ 182,7 184,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓' }

        it 'matches the full URL' do
          is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=✓"'
          expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=✓"'
        end
      end



@@ 190,7 192,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink' }

        it 'preserves escaped unicode characters' do
          is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&amp;utf81=✓&amp;q=autolink"'
          expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&amp;utf81=✓&amp;q=autolink"'
        end
      end



@@ 198,7 200,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'https://en.wikipedia.org/wiki/Diaspora_(software)' }

        it 'matches the full URL' do
          is_expected.to include 'href="https://en.wikipedia.org/wiki/Diaspora_(software)"'
          expect(subject).to include 'href="https://en.wikipedia.org/wiki/Diaspora_(software)"'
        end
      end



@@ 206,7 208,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { '"https://example.com/"' }

        it 'does not match the quotation marks' do
          is_expected.to include 'href="https://example.com/"'
          expect(subject).to include 'href="https://example.com/"'
        end
      end



@@ 214,19 216,19 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { '<https://example.com/>' }

        it 'does not match the angle brackets' do
          is_expected.to include 'href="https://example.com/"'
          expect(subject).to include 'href="https://example.com/"'
        end
      end

      context 'given a URL containing unsafe code (XSS attack, invisible part)' do
        let(:text) { %q{http://example.com/blahblahblahblah/a<script>alert("Hello")</script>} }
        let(:text) { 'http://example.com/blahblahblahblah/a<script>alert("Hello")</script>' }

        it 'does not include the HTML in the URL' do
          is_expected.to include '"http://example.com/blahblahblahblah/a"'
          expect(subject).to include '"http://example.com/blahblahblahblah/a"'
        end

        it 'does not include a script tag' do
          is_expected.to_not include '<script>'
          expect(subject).to_not include '<script>'
        end
      end



@@ 234,7 236,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { '<script>alert("Hello")</script>' }

        it 'does not include a script tag' do
          is_expected.to_not include '<script>'
          expect(subject).to_not include '<script>'
        end
      end



@@ 242,7 244,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { %q{<img src="javascript:alert('XSS');">} }

        it 'does not include the javascript' do
          is_expected.to_not include 'href="javascript:'
          expect(subject).to_not include 'href="javascript:'
        end
      end



@@ 250,7 252,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'http://www\.google\.com' }

        it 'outputs the raw URL' do
          is_expected.to eq '<p>http://www\.google\.com</p>'
          expect(subject).to eq '<p>http://www\.google\.com</p>'
        end
      end



@@ 258,7 260,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text)  { '#hashtag' }

        it 'creates a hashtag link' do
          is_expected.to include '/tags/hashtag" class="mention hashtag" rel="tag">#<span>hashtag</span></a>'
          expect(subject).to include '/tags/hashtag" class="mention hashtag" rel="tag">#<span>hashtag</span></a>'
        end
      end



@@ 266,7 268,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text)  { '#hashtagタグ' }

        it 'creates a hashtag link' do
          is_expected.to include '/tags/hashtag%E3%82%BF%E3%82%B0" class="mention hashtag" rel="tag">#<span>hashtagタグ</span></a>'
          expect(subject).to include '/tags/hashtag%E3%82%BF%E3%82%B0" class="mention hashtag" rel="tag">#<span>hashtagタグ</span></a>'
        end
      end



@@ 274,7 276,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'xmpp:user@instance.com' }

        it 'matches the full URI' do
          is_expected.to include 'href="xmpp:user@instance.com"'
          expect(subject).to include 'href="xmpp:user@instance.com"'
        end
      end



@@ 282,7 284,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'please join xmpp:muc@instance.com?join right now' }

        it 'matches the full URI' do
          is_expected.to include 'href="xmpp:muc@instance.com?join"'
          expect(subject).to include 'href="xmpp:muc@instance.com?join"'
        end
      end



@@ 290,7 292,7 @@ RSpec.describe AdvancedTextFormatter do
        let(:text) { 'wikipedia gives this example of a magnet uri: magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a' }

        it 'matches the full URI' do
          is_expected.to include 'href="magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a"'
          expect(subject).to include 'href="magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a"'
        end
      end
    end

M spec/models/concerns/account_interactions_spec.rb => spec/models/concerns/account_interactions_spec.rb +1 -38
@@ 23,7 23,7 @@ describe AccountInteractions do
    context 'account with Follow but with reblogs disabled' do
      it 'returns { target_account_id => { reblogs: false } }' do
        Fabricate(:follow, account: account, target_account: target_account, show_reblogs: false)
        is_expected.to eq(target_account_id => { reblogs: false, notify: false, languages: nil })
        expect(subject).to eq(target_account_id => { reblogs: false, notify: false, languages: nil })
      end
    end



@@ 690,41 690,4 @@ describe AccountInteractions do
      end
    end
  end

  describe 'ignoring reblogs from an account' do
    before do
      @me = Fabricate(:account, username: 'Me')
      @you = Fabricate(:account, username: 'You')
    end

    context 'with the reblogs option unspecified' do
      before do
        @me.follow!(@you)
      end

      it 'defaults to showing reblogs' do
        expect(@me.muting_reblogs?(@you)).to be(false)
      end
    end

    context 'with the reblogs option set to false' do
      before do
        @me.follow!(@you, reblogs: false)
      end

      it 'does mute reblogs' do
        expect(@me.muting_reblogs?(@you)).to be(true)
      end
    end

    context 'with the reblogs option set to true' do
      before do
        @me.follow!(@you, reblogs: true)
      end

      it 'does not mute reblogs' do
        expect(@me.muting_reblogs?(@you)).to be(false)
      end
    end
  end
end

M spec/models/public_feed_spec.rb => spec/models/public_feed_spec.rb +6 -6
@@ 64,7 64,7 @@ RSpec.describe PublicFeed, type: :model do
        end

        it 'does not include local-only statuses' do
          expect(subject).not_to include(local_only_status.id)
          expect(subject).to_not include(local_only_status.id)
        end
      end



@@ 80,12 80,14 @@ RSpec.describe PublicFeed, type: :model do
        end

        it 'does not include local-only statuses' do
          expect(subject).not_to include(local_only_status.id)
          expect(subject).to_not include(local_only_status.id)
        end
      end
    end

    context 'without local_only option but allow_local_only' do
      subject { described_class.new(viewer, allow_local_only: true).get(20).map(&:id) }

      let(:viewer) { nil }

      let!(:local_account)  { Fabricate(:account, domain: nil) }


@@ 94,8 96,6 @@ RSpec.describe PublicFeed, type: :model do
      let!(:remote_status)  { Fabricate(:status, account: remote_account) }
      let!(:local_only_status) { Fabricate(:status, account: local_account, local_only: true) }

      subject { described_class.new(viewer, allow_local_only: true).get(20).map(&:id) }

      context 'without a viewer' do
        let(:viewer) { nil }



@@ 108,7 108,7 @@ RSpec.describe PublicFeed, type: :model do
        end

        it 'does not include local-only statuses' do
          expect(subject).not_to include(local_only_status.id)
          expect(subject).to_not include(local_only_status.id)
        end
      end



@@ 147,7 147,7 @@ RSpec.describe PublicFeed, type: :model do
        end

        it 'does not include local-only statuses' do
          expect(subject).not_to include(local_only_status.id)
          expect(subject).to_not include(local_only_status.id)
        end
      end


M spec/models/status_spec.rb => spec/models/status_spec.rb +21 -21
@@ 206,14 206,14 @@ RSpec.describe Status, type: :model do
  end

  describe 'on create' do
    subject { Status.new }

    let(:local_account) { Fabricate(:account, username: 'local', domain: nil) }
    let(:remote_account) { Fabricate(:account, username: 'remote', domain: 'example.com') }

    subject { Status.new }

    describe 'on a status that ends with the local-only emoji' do
      before do
        subject.text = 'A toot ' + subject.local_only_emoji
        subject.text = "A toot #{subject.local_only_emoji}"
      end

      context 'if the status originates from this instance' do


@@ 291,52 291,52 @@ RSpec.describe Status, type: :model do
  end

  describe '.as_direct_timeline' do
    subject(:results) { Status.as_direct_timeline(account) }

    let(:account) { Fabricate(:account) }
    let(:followed) { Fabricate(:account) }
    let(:not_followed) { Fabricate(:account) }

    before do
      Fabricate(:follow, account: account, target_account: followed)

      @self_public_status = Fabricate(:status, account: account, visibility: :public)
      @self_direct_status = Fabricate(:status, account: account, visibility: :direct)
      @followed_public_status = Fabricate(:status, account: followed, visibility: :public)
      @followed_direct_status = Fabricate(:status, account: followed, visibility: :direct)
      @not_followed_direct_status = Fabricate(:status, account: not_followed, visibility: :direct)
    let!(:self_public_status) { Fabricate(:status, account: account, visibility: :public) }
    let!(:self_direct_status) { Fabricate(:status, account: account, visibility: :direct) }
    let!(:followed_public_status) { Fabricate(:status, account: followed, visibility: :public) }
    let!(:followed_direct_status) { Fabricate(:status, account: followed, visibility: :direct) }
    let!(:not_followed_direct_status) { Fabricate(:status, account: not_followed, visibility: :direct) }

      @results = Status.as_direct_timeline(account)
    before do
      account.follow!(followed)
    end

    it 'does not include public statuses from self' do
      expect(@results).to_not include(@self_public_status)
      expect(results).to_not include(self_public_status)
    end

    it 'includes direct statuses from self' do
      expect(@results).to include(@self_direct_status)
      expect(results).to include(self_direct_status)
    end

    it 'does not include public statuses from followed' do
      expect(@results).to_not include(@followed_public_status)
      expect(results).to_not include(followed_public_status)
    end

    it 'does not include direct statuses not mentioning recipient from followed' do
      expect(@results).to_not include(@followed_direct_status)
      expect(results).to_not include(followed_direct_status)
    end

    it 'does not include direct statuses not mentioning recipient from non-followed' do
      expect(@results).to_not include(@not_followed_direct_status)
      expect(results).to_not include(not_followed_direct_status)
    end

    it 'includes direct statuses mentioning recipient from followed' do
      Fabricate(:mention, account: account, status: @followed_direct_status)
      Fabricate(:mention, account: account, status: followed_direct_status)
      results2 = Status.as_direct_timeline(account)
      expect(results2).to include(@followed_direct_status)
      expect(results2).to include(followed_direct_status)
    end

    it 'includes direct statuses mentioning recipient from non-followed' do
      Fabricate(:mention, account: account, status: @not_followed_direct_status)
      Fabricate(:mention, account: account, status: not_followed_direct_status)
      results2 = Status.as_direct_timeline(account)
      expect(results2).to include(@not_followed_direct_status)
      expect(results2).to include(not_followed_direct_status)
    end
  end


M spec/models/tag_feed_spec.rb => spec/models/tag_feed_spec.rb +1 -1
@@ 67,7 67,7 @@ describe TagFeed, type: :service do
      expect(results).to include(status)
    end

    context 'on a local-only status' do
    context 'when the feed contains a local-only status' do
      let!(:status) { Fabricate(:status, tags: [tag1], local_only: true) }

      it 'does not show local-only statuses without a viewer' do

M spec/policies/status_policy_spec.rb => spec/policies/status_policy_spec.rb +2 -2
@@ 83,14 83,14 @@ RSpec.describe StatusPolicy, type: :model do
    end

    it 'denies access when local-only and the viewer is not logged in' do
      allow(status).to receive(:local_only?) { true }
      allow(status).to receive(:local_only?).and_return(true)

      expect(subject).to_not permit(nil, status)
    end

    it 'denies access when local-only and the viewer is from another domain' do
      viewer = Fabricate(:account, domain: 'remote-domain')
      allow(status).to receive(:local_only?) { true }
      allow(status).to receive(:local_only?).and_return(true)
      expect(subject).to_not permit(viewer, status)
    end
  end

M spec/services/notify_service_spec.rb => spec/services/notify_service_spec.rb +1 -1
@@ 48,7 48,7 @@ RSpec.describe NotifyService, type: :service do
    recipient.suspend!
    expect { subject }.to_not change(Notification, :count)
  end
  

  context 'for direct messages' do
    let(:activity) { Fabricate(:mention, account: recipient, status: Fabricate(:status, account: sender, visibility: :direct)) }
    let(:type)     { :mention }

M spec/validators/status_length_validator_spec.rb => spec/validators/status_length_validator_spec.rb +1 -1
@@ 65,7 65,7 @@ describe StatusLengthValidator do
    it 'counts only the front part of remote usernames' do
      username = '@alice'
      chars = StatusLengthValidator::MAX_CHARS - 1 - username.length
      text   = ('a' * 475) + " #{username}@#{'b' * 30}.com"
      text   = ('a' * chars) + " #{username}@#{'b' * 30}.com"
      status = double(spoiler_text: '', text: text, errors: double(add: nil), local?: true, reblog?: false)

      subject.validate(status)