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
This commit is contained in:
parent
29a91b871e
commit
ff168ef202
45 changed files with 211 additions and 216 deletions
|
@ -473,6 +473,7 @@ RSpec/ContextWording:
|
||||||
- 'spec/lib/activitypub/activity/create_spec.rb'
|
- 'spec/lib/activitypub/activity/create_spec.rb'
|
||||||
- 'spec/lib/activitypub/activity/follow_spec.rb'
|
- 'spec/lib/activitypub/activity/follow_spec.rb'
|
||||||
- 'spec/lib/activitypub/activity/reject_spec.rb'
|
- 'spec/lib/activitypub/activity/reject_spec.rb'
|
||||||
|
- 'spec/lib/advanced_text_formatter_spec.rb'
|
||||||
- 'spec/lib/emoji_formatter_spec.rb'
|
- 'spec/lib/emoji_formatter_spec.rb'
|
||||||
- 'spec/lib/entity_cache_spec.rb'
|
- 'spec/lib/entity_cache_spec.rb'
|
||||||
- 'spec/lib/feed_manager_spec.rb'
|
- 'spec/lib/feed_manager_spec.rb'
|
||||||
|
@ -1321,6 +1322,7 @@ Rails/FilePath:
|
||||||
- 'app/models/setting.rb'
|
- 'app/models/setting.rb'
|
||||||
- 'app/validators/reaction_validator.rb'
|
- 'app/validators/reaction_validator.rb'
|
||||||
- 'config/environments/test.rb'
|
- 'config/environments/test.rb'
|
||||||
|
- 'config/initializers/locale.rb'
|
||||||
- 'db/migrate/20170716191202_add_hide_notifications_to_mute.rb'
|
- 'db/migrate/20170716191202_add_hide_notifications_to_mute.rb'
|
||||||
- 'db/migrate/20171005171936_add_disabled_to_custom_emojis.rb'
|
- 'db/migrate/20171005171936_add_disabled_to_custom_emojis.rb'
|
||||||
- 'db/migrate/20171028221157_add_reblogs_to_follows.rb'
|
- 'db/migrate/20171028221157_add_reblogs_to_follows.rb'
|
||||||
|
|
|
@ -40,7 +40,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController
|
||||||
only_media: truthy_param?(:only_media),
|
only_media: truthy_param?(:only_media),
|
||||||
allow_local_only: truthy_param?(:allow_local_only),
|
allow_local_only: truthy_param?(:allow_local_only),
|
||||||
with_replies: Setting.show_replies_in_public_timelines,
|
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
|
end
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,6 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
|
||||||
|
|
||||||
skip_before_action :require_functional!
|
skip_before_action :require_functional!
|
||||||
|
|
||||||
def new
|
|
||||||
super
|
|
||||||
|
|
||||||
resource.email = current_user.unconfirmed_email || current_user.email if user_signed_in?
|
|
||||||
end
|
|
||||||
|
|
||||||
def show
|
def show
|
||||||
old_session_values = session.to_hash
|
old_session_values = session.to_hash
|
||||||
reset_session
|
reset_session
|
||||||
|
@ -29,6 +23,12 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
super
|
||||||
|
|
||||||
|
resource.email = current_user.unconfirmed_email || current_user.email if user_signed_in?
|
||||||
|
end
|
||||||
|
|
||||||
def confirm_captcha
|
def confirm_captcha
|
||||||
check_captcha! do |message|
|
check_captcha! do |message|
|
||||||
flash.now[:alert] = message
|
flash.now[:alert] = message
|
||||||
|
@ -51,6 +51,7 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
|
||||||
# step.
|
# step.
|
||||||
confirmation_token = params[:confirmation_token]
|
confirmation_token = params[:confirmation_token]
|
||||||
return if confirmation_token.nil?
|
return if confirmation_token.nil?
|
||||||
|
|
||||||
@confirmation_user = User.find_first_by_auth_conditions(confirmation_token: confirmation_token)
|
@confirmation_user = User.find_first_by_auth_conditions(confirmation_token: confirmation_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,7 @@ class Settings::FlavoursController < Settings::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
unless Themes.instance.flavours.include?(params[:flavour]) || (params[:flavour] == current_flavour)
|
redirect_to action: 'show', flavour: current_flavour unless Themes.instance.flavours.include?(params[:flavour]) || (params[:flavour] == current_flavour)
|
||||||
redirect_to action: 'show', flavour: current_flavour
|
|
||||||
end
|
|
||||||
|
|
||||||
@listing = Themes.instance.flavours
|
@listing = Themes.instance.flavours
|
||||||
@selected = params[:flavour]
|
@selected = params[:flavour]
|
||||||
|
|
|
@ -28,7 +28,7 @@ module AccountsHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def hide_followers_count?(account)
|
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
|
end
|
||||||
|
|
||||||
def account_description(account)
|
def account_description(account)
|
||||||
|
|
|
@ -15,6 +15,7 @@ class AdvancedTextFormatter < TextFormatter
|
||||||
|
|
||||||
def autolink(link, link_type)
|
def autolink(link, link_type)
|
||||||
return link if link_type == :email
|
return link if link_type == :email
|
||||||
|
|
||||||
@format_link.call(link)
|
@format_link.call(link)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -306,6 +306,7 @@ class FeedManager
|
||||||
|
|
||||||
statuses.each do |status|
|
statuses.each do |status|
|
||||||
next if filter_from_direct?(status, account)
|
next if filter_from_direct?(status, account)
|
||||||
|
|
||||||
added += 1 if add_to_feed(:direct, account.id, status)
|
added += 1 if add_to_feed(:direct, account.id, status)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -459,6 +460,7 @@ class FeedManager
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
def filter_from_direct?(status, receiver_id)
|
def filter_from_direct?(status, receiver_id)
|
||||||
return false if receiver_id == status.account_id
|
return false if receiver_id == status.account_id
|
||||||
|
|
||||||
filter_from_mentions?(status, receiver_id)
|
filter_from_mentions?(status, receiver_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,24 +7,23 @@ class Themes
|
||||||
include Singleton
|
include Singleton
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
|
|
||||||
core = YAML.load_file(Rails.root.join('app', 'javascript', 'core', 'theme.yml'))
|
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
|
result = {}
|
||||||
Dir.glob(Rails.root.join('app', 'javascript', 'flavours', '*', 'theme.yml')) do |path|
|
Rails.root.glob('app/javascript/flavours/*/theme.yml') do |pathname|
|
||||||
data = YAML.load_file(path)
|
data = YAML.load_file(pathname)
|
||||||
next unless data['pack']
|
next unless data['pack']
|
||||||
|
|
||||||
dir = File.dirname(path)
|
dir = pathname.dirname
|
||||||
name = File.basename(dir)
|
name = dir.basename.to_s
|
||||||
locales = []
|
locales = []
|
||||||
screenshots = []
|
screenshots = []
|
||||||
|
|
||||||
if data['locales']
|
if data['locales']
|
||||||
Dir.glob(File.join(dir, data['locales'], '*.{js,json}')) do |locale|
|
Dir.glob(File.join(dir, data['locales'], '*.{js,json}')) do |locale|
|
||||||
localeName = File.basename(locale, File.extname(locale))
|
locale_name = File.basename(locale, File.extname(locale))
|
||||||
locales.push(localeName) unless localeName.match(/defaultMessages|whitelist|index/)
|
locales.push(locale_name) unless /defaultMessages|whitelist|index/.match?(locale_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -43,34 +42,30 @@ class Themes
|
||||||
result[name] = data
|
result[name] = data
|
||||||
end
|
end
|
||||||
|
|
||||||
Dir.glob(Rails.root.join('app', 'javascript', 'skins', '*', '*')) do |path|
|
Rails.root.glob('app/javascript/skins/*/*') do |pathname|
|
||||||
ext = File.extname(path)
|
ext = pathname.extname.to_s
|
||||||
skin = File.basename(path)
|
skin = pathname.basename.to_s
|
||||||
name = File.basename(File.dirname(path))
|
name = pathname.dirname.basename.to_s
|
||||||
next unless result[name]
|
next unless result[name]
|
||||||
|
|
||||||
if File.directory?(path)
|
if pathname.directory?
|
||||||
pack = []
|
pack = []
|
||||||
Dir.glob(File.join(path, '*.{css,scss}')) do |sheet|
|
pathname.glob('*.{css,scss}') do |sheet|
|
||||||
pack.push(File.basename(sheet, File.extname(sheet)))
|
pack.push(sheet.basename(sheet.extname).to_s)
|
||||||
end
|
end
|
||||||
elsif ext.match(/^\.s?css$/i)
|
elsif /^\.s?css$/i.match?(ext)
|
||||||
skin = File.basename(path, ext)
|
skin = pathname.basename(ext).to_s
|
||||||
pack = ['common']
|
pack = ['common']
|
||||||
end
|
end
|
||||||
|
|
||||||
if skin != 'default'
|
result[name]['skin'][skin] = pack if skin != 'default'
|
||||||
result[name]['skin'][skin] = pack
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@core = core
|
@core = core
|
||||||
@conf = result
|
@conf = result
|
||||||
end
|
end
|
||||||
|
|
||||||
def core
|
attr_reader :core
|
||||||
@core
|
|
||||||
end
|
|
||||||
|
|
||||||
def flavour(name)
|
def flavour(name)
|
||||||
@conf[name]
|
@conf[name]
|
||||||
|
|
|
@ -4,9 +4,8 @@ class DirectFeed < Feed
|
||||||
include Redisable
|
include Redisable
|
||||||
|
|
||||||
def initialize(account)
|
def initialize(account)
|
||||||
@type = :direct
|
|
||||||
@id = account.id
|
|
||||||
@account = account
|
@account = account
|
||||||
|
super(:direct, account.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(limit, max_id = nil, since_id = nil, min_id = nil)
|
def get(limit, max_id = nil, since_id = nil, min_id = nil)
|
||||||
|
@ -19,10 +18,12 @@ class DirectFeed < Feed
|
||||||
|
|
||||||
private
|
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
|
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?
|
return statuses if statuses.empty?
|
||||||
|
|
||||||
max_id = statuses.last.id
|
max_id = statuses.last.id
|
||||||
statuses = statuses.reject { |status| FeedManager.instance.filter?(:direct, status, @account) }
|
statuses = statuses.reject { |status| FeedManager.instance.filter?(:direct, status, @account) }
|
||||||
return statuses unless statuses.empty?
|
return statuses unless statuses.empty?
|
||||||
|
|
|
@ -338,7 +338,7 @@ class Status < ApplicationRecord
|
||||||
visibilities.keys - %w(direct limited)
|
visibilities.keys - %w(direct limited)
|
||||||
end
|
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.
|
# direct timeline is mix of direct message from_me and to_me.
|
||||||
# 2 queries are executed with pagination.
|
# 2 queries are executed with pagination.
|
||||||
# constant expression using arel_table is required for partial index
|
# constant expression using arel_table is required for partial index
|
||||||
|
@ -369,15 +369,10 @@ class Status < ApplicationRecord
|
||||||
query_to_me = query_to_me.where('mentions.status_id > ?', since_id)
|
query_to_me = query_to_me.where('mentions.status_id > ?', since_id)
|
||||||
end
|
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
|
# 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)
|
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))
|
Status.where(id: items.map(&:id))
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def favourites_map(status_ids, account_id)
|
def favourites_map(status_ids, account_id)
|
||||||
Favourite.select('status_id').where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |f, h| h[f.status_id] = true }
|
Favourite.select('status_id').where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |f, h| h[f.status_id] = true }
|
||||||
|
@ -553,10 +548,10 @@ class Status < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_locality
|
def set_locality
|
||||||
if account.domain.nil? && !attribute_changed?(:local_only)
|
return unless account.domain.nil? && !attribute_changed?(:local_only)
|
||||||
|
|
||||||
self.local_only = marked_local_only?
|
self.local_only = marked_local_only?
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def set_conversation
|
def set_conversation
|
||||||
self.thread = thread.reblog if thread&.reblog?
|
self.thread = thread.reblog if thread&.reblog?
|
||||||
|
|
|
@ -244,7 +244,6 @@ class User < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def functional?
|
def functional?
|
||||||
|
|
||||||
functional_or_moved?
|
functional_or_moved?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer
|
||||||
|
|
||||||
def id
|
def id
|
||||||
raise Mastodon::NotPermittedError, 'Local-only statuses should not be serialized' if object.local_only? && !instance_options[:allow_local_only]
|
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)
|
ActivityPub::TagManager.instance.uri_for(object)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ class REST::AccountSerializer < ActiveModel::Serializer
|
||||||
end
|
end
|
||||||
|
|
||||||
def followers_count
|
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
|
end
|
||||||
|
|
||||||
def display_name
|
def display_name
|
||||||
|
|
|
@ -13,7 +13,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
||||||
attribute :muted, if: :current_user?
|
attribute :muted, if: :current_user?
|
||||||
attribute :bookmarked, if: :current_user?
|
attribute :bookmarked, if: :current_user?
|
||||||
attribute :pinned, if: :pinnable?
|
attribute :pinned, if: :pinnable?
|
||||||
attribute :local_only if :local?
|
attribute :local_only, if: :local?
|
||||||
has_many :filtered, serializer: REST::FilterResultSerializer, if: :current_user?
|
has_many :filtered, serializer: REST::FilterResultSerializer, if: :current_user?
|
||||||
|
|
||||||
attribute :content, unless: :source_requested?
|
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 :preview_card, key: :card, serializer: REST::PreviewCardSerializer
|
||||||
has_one :preloadable_poll, key: :poll, serializer: REST::PollSerializer
|
has_one :preloadable_poll, key: :poll, serializer: REST::PollSerializer
|
||||||
|
|
||||||
|
delegate :local?, to: :object
|
||||||
|
|
||||||
def id
|
def id
|
||||||
object.id.to_s
|
object.id.to_s
|
||||||
end
|
end
|
||||||
|
|
|
@ -154,7 +154,7 @@ class BackupService < BaseService
|
||||||
object,
|
object,
|
||||||
serializer: serializer,
|
serializer: serializer,
|
||||||
adapter: ActivityPub::Adapter,
|
adapter: ActivityPub::Adapter,
|
||||||
allow_local_only: true,
|
allow_local_only: true
|
||||||
).as_json
|
).as_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ class FanOutOnWriteService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def deliver_to_direct_timelines!
|
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? }]
|
[@status.id, account.id, 'direct', { 'update' => update? }]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -61,17 +61,22 @@ class PostStatusService < BaseService
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def preprocess_attributes!
|
def fill_blank_text!
|
||||||
if @text.blank? && @options[:spoiler_text].present?
|
return unless @text.blank? && @options[:spoiler_text].present?
|
||||||
@text = '.'
|
|
||||||
if @media&.find(&:video?) || @media&.find(&:gifv?)
|
if @media&.any?(&:video?) || @media&.any?(&:gifv?)
|
||||||
@text = '📹'
|
@text = '📹'
|
||||||
elsif @media&.find(&:audio?)
|
elsif @media&.any?(&:audio?)
|
||||||
@text = '🎵'
|
@text = '🎵'
|
||||||
elsif @media&.find(&:image?)
|
elsif @media&.any?(&:image?)
|
||||||
@text = '🖼'
|
@text = '🖼'
|
||||||
|
else
|
||||||
|
@text = '.'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def preprocess_attributes!
|
||||||
|
fill_blank_text!
|
||||||
@sensitive = (@options[:sensitive].nil? ? @account.user&.setting_default_sensitive : @options[:sensitive]) || @options[:spoiler_text].present?
|
@sensitive = (@options[:sensitive].nil? ? @account.user&.setting_default_sensitive : @options[:sensitive]) || @options[:spoiler_text].present?
|
||||||
@visibility = @options[:visibility] || @account.user&.setting_default_privacy
|
@visibility = @options[:visibility] || @account.user&.setting_default_privacy
|
||||||
@visibility = :unlisted if @visibility&.to_sym == :public && @account.silenced?
|
@visibility = :unlisted if @visibility&.to_sym == :public && @account.silenced?
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Some migrations have been present in glitch-soc for a long time and have then
|
# 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.
|
# 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,
|
# we decided monkey-patching Rails' Migrator to completely ignore the duplicate,
|
||||||
# keeping only the one that has run, or an arbitrary one.
|
# 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
|
module ActiveRecord
|
||||||
class Migrator
|
class Migrator
|
||||||
def self.new(direction, migrations, schema_migration, target_version = nil)
|
def self.new(direction, migrations, schema_migration, target_version = nil)
|
||||||
migrated = Set.new(Base.connection.migration_context.get_all_versions)
|
migrated = Set.new(Base.connection.migration_context.get_all_versions)
|
||||||
|
|
||||||
migrations.group_by(&:name).each do |name, duplicates|
|
migrations.group_by(&:name).each do |_name, duplicates|
|
||||||
if duplicates.length > 1 && duplicates.all? { |m| ALLOWED_DUPLICATES.include?(m.version) }
|
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.
|
# We have a set of allowed duplicates. Keep the migrated one, if any.
|
||||||
non_migrated = duplicates.reject { |m| migrated.include?(m.version.to_i) }
|
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
|
# There weren't any migrated one, so we have to pick one “canonical” migration
|
||||||
migrations = migrations - duplicates[1..-1]
|
migrations - duplicates[1..]
|
||||||
else
|
else
|
||||||
# Just reject every duplicate which hasn't been migrated yet
|
# Just reject every duplicate which hasn't been migrated yet
|
||||||
migrations = migrations - non_migrated
|
migrations - non_migrated
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -43,10 +47,10 @@ module ActiveRecord
|
||||||
# A set of duplicated migrations is considered migrated if at least one of
|
# A set of duplicated migrations is considered migrated if at least one of
|
||||||
# them is migrated.
|
# them is migrated.
|
||||||
migrated = get_all_versions
|
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) }
|
return true unless duplicates.any? { |m| migrated.include?(m.version.to_i) }
|
||||||
end
|
end
|
||||||
return false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,6 +22,7 @@ end
|
||||||
module GlitchOnlyComponent
|
module GlitchOnlyComponent
|
||||||
def glitch_only(_wrapper_options = nil)
|
def glitch_only(_wrapper_options = nil)
|
||||||
return unless options[:glitch_only]
|
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')]) }
|
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
|
nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class CreateKeywordMutes < ActiveRecord::Migration[5.1]
|
class CreateKeywordMutes < ActiveRecord::Migration[5.1]
|
||||||
def change
|
def change
|
||||||
create_table :keyword_mutes do |t|
|
create_table :keyword_mutes do |t|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class MoveKeywordMutesIntoGlitchNamespace < ActiveRecord::Migration[5.1]
|
class MoveKeywordMutesIntoGlitchNamespace < ActiveRecord::Migration[5.1]
|
||||||
def change
|
def change
|
||||||
safety_assured do
|
safety_assured do
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class AddLocalOnlyFlagToStatuses < ActiveRecord::Migration[5.1]
|
class AddLocalOnlyFlagToStatuses < ActiveRecord::Migration[5.1]
|
||||||
def change
|
def change
|
||||||
add_column :statuses, :local_only, :boolean
|
add_column :statuses, :local_only, :boolean
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# This migration is a duplicate of 20180831171112 and may get ignored, see
|
# This migration is a duplicate of 20180831171112 and may get ignored, see
|
||||||
# config/initializers/0_duplicate_migrations.rb
|
# config/initializers/0_duplicate_migrations.rb
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'mastodon/migration_helpers'
|
require 'mastodon/migration_helpers'
|
||||||
|
|
||||||
class AddApplyToMentionsFlagToKeywordMutes < ActiveRecord::Migration[5.2]
|
class AddApplyToMentionsFlagToKeywordMutes < ActiveRecord::Migration[5.2]
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class MigrateFilters < ActiveRecord::Migration[5.2]
|
class MigrateFilters < ActiveRecord::Migration[5.2]
|
||||||
class GlitchKeywordMute < ApplicationRecord
|
class GlitchKeywordMute < ApplicationRecord
|
||||||
# Dummy class, as we removed Glitch::KeywordMute
|
# Dummy class, as we removed Glitch::KeywordMute
|
||||||
belongs_to :account, required: true
|
belongs_to :account, optional: false
|
||||||
validates_presence_of :keyword
|
validates_presence_of :keyword
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -15,7 +17,7 @@ class MigrateFilters < ActiveRecord::Migration[5.2]
|
||||||
private
|
private
|
||||||
|
|
||||||
def clean_up_contexts
|
def clean_up_contexts
|
||||||
self.context = Array(context).map(&:strip).map(&:presence).compact
|
self.context = Array(context).map(&:strip).filter_map(&:presence)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -27,7 +29,8 @@ class MigrateFilters < ActiveRecord::Migration[5.2]
|
||||||
phrase: filter.keyword,
|
phrase: filter.keyword,
|
||||||
context: filter.apply_to_mentions ? %w(home public notifications) : %w(home public),
|
context: filter.apply_to_mentions ? %w(home public notifications) : %w(home public),
|
||||||
whole_word: filter.whole_word,
|
whole_word: filter.whole_word,
|
||||||
irreversible: true)
|
irreversible: true
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -48,7 +51,8 @@ class MigrateFilters < ActiveRecord::Migration[5.2]
|
||||||
GlitchKeywordMute.where(account: filter.account).create!(
|
GlitchKeywordMute.where(account: filter.account).create!(
|
||||||
keyword: filter.phrase,
|
keyword: filter.phrase,
|
||||||
whole_word: filter.whole_word,
|
whole_word: filter.whole_word,
|
||||||
apply_to_mentions: filter.context.include?('notifications'))
|
apply_to_mentions: filter.context.include?('notifications')
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class AddContentTypeToStatuses < ActiveRecord::Migration[5.2]
|
class AddContentTypeToStatuses < ActiveRecord::Migration[5.2]
|
||||||
def change
|
def change
|
||||||
add_column :statuses, :content_type, :string
|
add_column :statuses, :content_type, :string
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class AddContentTypeToStatusEdits < ActiveRecord::Migration[6.1]
|
class AddContentTypeToStatusEdits < ActiveRecord::Migration[6.1]
|
||||||
def change
|
def change
|
||||||
add_column :status_edits, :content_type, :string
|
add_column :status_edits, :content_type, :string
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class PostMigrateFilters < ActiveRecord::Migration[5.2]
|
class PostMigrateFilters < ActiveRecord::Migration[5.2]
|
||||||
disable_ddl_transaction!
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
@ -5,7 +7,5 @@ class PostMigrateFilters < ActiveRecord::Migration[5.2]
|
||||||
drop_table :glitch_keyword_mutes if table_exists? :glitch_keyword_mutes
|
drop_table :glitch_keyword_mutes if table_exists? :glitch_keyword_mutes
|
||||||
end
|
end
|
||||||
|
|
||||||
def down
|
def down; end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
|
|
|
@ -48,9 +48,9 @@ class Sanitize
|
||||||
node.content = "[🖼 #{node['alt']}]"
|
node.content = "[🖼 #{node['alt']}]"
|
||||||
else
|
else
|
||||||
url = node['href']
|
url = node['href']
|
||||||
prefix = url.match(/\Ahttps?:\/\/(www\.)?/).to_s
|
prefix = url.match(%r{\Ahttps?://(www\.)?}).to_s
|
||||||
text = url[prefix.length, 30]
|
text = url[prefix.length, 30]
|
||||||
text = text + "…" if url[prefix.length..-1].length > 30
|
text += '…' if url.length - prefix.length > 30
|
||||||
node.content = "[🖼 #{text}]"
|
node.content = "[🖼 #{text}]"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -126,7 +126,7 @@ class Sanitize
|
||||||
|
|
||||||
node = env[:node]
|
node = env[:node]
|
||||||
|
|
||||||
rel = (node['rel'] || '').split(' ') & ['tag']
|
rel = (node['rel'] || '').split & ['tag']
|
||||||
rel += ['nofollow', 'noopener', 'noreferrer'] unless TagManager.instance.local_url?(node['href'])
|
rel += ['nofollow', 'noopener', 'noreferrer'] unless TagManager.instance.local_url?(node['href'])
|
||||||
|
|
||||||
if rel.empty?
|
if rel.empty?
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
namespace :assets do
|
namespace :assets do
|
||||||
desc 'Generate static pages'
|
desc 'Generate static pages'
|
||||||
task generate_static_pages: :environment do
|
task generate_static_pages: :environment do
|
||||||
class StaticApplicationController < ApplicationController
|
def render_static_page(action, dest:, **opts)
|
||||||
|
renderer = Class.new(ApplicationController) do
|
||||||
def current_user
|
def current_user
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_static_page(action, dest:, **opts)
|
html = renderer.render(action, opts)
|
||||||
html = StaticApplicationController.render(action, opts)
|
|
||||||
File.write(dest, html)
|
File.write(dest, html)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
namespace :glitchsoc do
|
namespace :glitchsoc do
|
||||||
desc 'Backfill local-only flag on statuses table'
|
desc 'Backfill local-only flag on statuses table'
|
||||||
task backfill_local_only: :environment do
|
task backfill_local_only: :environment do
|
||||||
Status.local.where(local_only: nil).find_each do |st|
|
Status.local.where(local_only: nil).find_each do |status|
|
||||||
ActiveRecord::Base.logger.silence { st.update_attribute(:local_only, st.marked_local_only?) }
|
ActiveRecord::Base.logger.silence do
|
||||||
|
status.update_attribute(:local_only, status.marked_local_only?) # rubocop:disable Rails/SkipsModelValidations
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -75,10 +75,10 @@ describe Api::V1::Accounts::CredentialsController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'with invalid data' do
|
describe 'with a too long profile bio' do
|
||||||
before do
|
before do
|
||||||
note = 'This is too long. '
|
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 }
|
patch :update, params: { note: note }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe Api::V1::Timelines::DirectController, type: :controller do
|
RSpec.describe Api::V1::Timelines::DirectController do
|
||||||
let(:user) { Fabricate(:user) }
|
let(:user) { Fabricate(:user) }
|
||||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }
|
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe Settings::FlavoursController, type: :controller do
|
RSpec.describe Settings::FlavoursController do
|
||||||
let(:user) { Fabricate(:user) }
|
let(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe AdvancedTextFormatter do
|
RSpec.describe AdvancedTextFormatter do
|
||||||
describe '#to_s' 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(:preloaded_accounts) { nil }
|
||||||
let(:content_type) { 'text/markdown' }
|
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
|
context 'given a markdown source' do
|
||||||
let(:content_type) { 'text/markdown' }
|
let(:content_type) { 'text/markdown' }
|
||||||
|
|
||||||
|
@ -14,7 +16,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'text' }
|
let(:text) { 'text' }
|
||||||
|
|
||||||
it 'paragraphizes the text' do
|
it 'paragraphizes the text' do
|
||||||
is_expected.to eq '<p>text</p>'
|
expect(subject).to eq '<p>text</p>'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -22,7 +24,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { "line\nfeed" }
|
let(:text) { "line\nfeed" }
|
||||||
|
|
||||||
it 'removes line feeds' do
|
it 'removes line feeds' do
|
||||||
is_expected.not_to include "\n"
|
expect(subject).to_not include "\n"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -30,7 +32,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'test `foo` bar' }
|
let(:text) { 'test `foo` bar' }
|
||||||
|
|
||||||
it 'formats code using <code>' do
|
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
|
||||||
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" }
|
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
|
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
|
end
|
||||||
|
|
||||||
it 'does not strip leading spaces' do
|
it 'does not strip leading spaces' do
|
||||||
is_expected.to include '> return 0'
|
expect(subject).to include '> return 0'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not format links' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -54,7 +56,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'test `https://foo.bar/bar` bar' }
|
let(:text) { 'test `https://foo.bar/bar` bar' }
|
||||||
|
|
||||||
it 'does not rewrite the link' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -62,7 +64,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'foo https://cb6e6126.ngrok.io/about/more' }
|
let(:text) { 'foo https://cb6e6126.ngrok.io/about/more' }
|
||||||
|
|
||||||
it 'creates a link' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -71,7 +73,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { '@alice' }
|
let(:text) { '@alice' }
|
||||||
|
|
||||||
it 'creates a mention link' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -80,7 +82,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { '@alice' }
|
let(:text) { '@alice' }
|
||||||
|
|
||||||
it 'does not create a mention link' do
|
it 'does not create a mention link' do
|
||||||
is_expected.to include '@alice'
|
expect(subject).to include '@alice'
|
||||||
end
|
end
|
||||||
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' }
|
let(:text) { 'https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4' }
|
||||||
|
|
||||||
it 'matches the full URL' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -96,7 +98,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'http://google.com' }
|
let(:text) { 'http://google.com' }
|
||||||
|
|
||||||
it 'matches the full URL' do
|
it 'matches the full URL' do
|
||||||
is_expected.to include 'href="http://google.com"'
|
expect(subject).to include 'href="http://google.com"'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -104,7 +106,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'http://example.gay' }
|
let(:text) { 'http://example.gay' }
|
||||||
|
|
||||||
it 'matches the full URL' do
|
it 'matches the full URL' do
|
||||||
is_expected.to include 'href="http://example.gay"'
|
expect(subject).to include 'href="http://example.gay"'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -112,11 +114,11 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'https://nic.みんな/' }
|
let(:text) { 'https://nic.みんな/' }
|
||||||
|
|
||||||
it 'matches the full URL' do
|
it 'matches the full URL' do
|
||||||
is_expected.to include 'href="https://nic.みんな/"'
|
expect(subject).to include 'href="https://nic.みんな/"'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'has display URL' do
|
it 'has display URL' do
|
||||||
is_expected.to include '<span class="">nic.みんな/</span>'
|
expect(subject).to include '<span class="">nic.みんな/</span>'
|
||||||
end
|
end
|
||||||
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. ' }
|
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
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -132,7 +134,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { '(http://google.com/)' }
|
let(:text) { '(http://google.com/)' }
|
||||||
|
|
||||||
it 'matches the full URL but not the parentheses' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -140,7 +142,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'http://www.google.com!' }
|
let(:text) { 'http://www.google.com!' }
|
||||||
|
|
||||||
it 'matches the full URL but not the exclamation point' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -148,7 +150,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { "http://www.google.com'" }
|
let(:text) { "http://www.google.com'" }
|
||||||
|
|
||||||
it 'matches the full URL but not the single quote' do
|
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
|
end
|
||||||
end
|
end
|
||||||
|
@ -157,7 +159,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'http://www.google.com>' }
|
let(:text) { 'http://www.google.com>' }
|
||||||
|
|
||||||
it 'matches the full URL but not the angle bracket' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -166,7 +168,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink' }
|
let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink' }
|
||||||
|
|
||||||
it 'matches the full URL' do
|
it 'matches the full URL' do
|
||||||
is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink"'
|
expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink"'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -174,7 +176,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓&q=autolink' }
|
let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓&q=autolink' }
|
||||||
|
|
||||||
it 'matches the full URL' do
|
it 'matches the full URL' do
|
||||||
is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=✓&q=autolink"'
|
expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=✓&q=autolink"'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -182,7 +184,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓' }
|
let(:text) { 'https://www.ruby-toolbox.com/search?utf8=✓' }
|
||||||
|
|
||||||
it 'matches the full URL' do
|
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
|
||||||
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' }
|
let(:text) { 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink' }
|
||||||
|
|
||||||
it 'preserves escaped unicode characters' do
|
it 'preserves escaped unicode characters' do
|
||||||
is_expected.to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink"'
|
expect(subject).to include 'href="https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&utf81=✓&q=autolink"'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -198,7 +200,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'https://en.wikipedia.org/wiki/Diaspora_(software)' }
|
let(:text) { 'https://en.wikipedia.org/wiki/Diaspora_(software)' }
|
||||||
|
|
||||||
it 'matches the full URL' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -206,7 +208,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { '"https://example.com/"' }
|
let(:text) { '"https://example.com/"' }
|
||||||
|
|
||||||
it 'does not match the quotation marks' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -214,19 +216,19 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { '<https://example.com/>' }
|
let(:text) { '<https://example.com/>' }
|
||||||
|
|
||||||
it 'does not match the angle brackets' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'given a URL containing unsafe code (XSS attack, invisible part)' do
|
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
|
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
|
end
|
||||||
|
|
||||||
it 'does not include a script tag' do
|
it 'does not include a script tag' do
|
||||||
is_expected.to_not include '<script>'
|
expect(subject).to_not include '<script>'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -234,7 +236,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { '<script>alert("Hello")</script>' }
|
let(:text) { '<script>alert("Hello")</script>' }
|
||||||
|
|
||||||
it 'does not include a script tag' do
|
it 'does not include a script tag' do
|
||||||
is_expected.to_not include '<script>'
|
expect(subject).to_not include '<script>'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -242,7 +244,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { %q{<img src="javascript:alert('XSS');">} }
|
let(:text) { %q{<img src="javascript:alert('XSS');">} }
|
||||||
|
|
||||||
it 'does not include the javascript' do
|
it 'does not include the javascript' do
|
||||||
is_expected.to_not include 'href="javascript:'
|
expect(subject).to_not include 'href="javascript:'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -250,7 +252,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'http://www\.google\.com' }
|
let(:text) { 'http://www\.google\.com' }
|
||||||
|
|
||||||
it 'outputs the raw URL' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -258,7 +260,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { '#hashtag' }
|
let(:text) { '#hashtag' }
|
||||||
|
|
||||||
it 'creates a hashtag link' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -266,7 +268,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { '#hashtagタグ' }
|
let(:text) { '#hashtagタグ' }
|
||||||
|
|
||||||
it 'creates a hashtag link' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -274,7 +276,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'xmpp:user@instance.com' }
|
let(:text) { 'xmpp:user@instance.com' }
|
||||||
|
|
||||||
it 'matches the full URI' do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -282,7 +284,7 @@ RSpec.describe AdvancedTextFormatter do
|
||||||
let(:text) { 'please join xmpp:muc@instance.com?join right now' }
|
let(:text) { 'please join xmpp:muc@instance.com?join right now' }
|
||||||
|
|
||||||
it 'matches the full URI' do
|
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
|
||||||
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' }
|
let(:text) { 'wikipedia gives this example of a magnet uri: magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a' }
|
||||||
|
|
||||||
it 'matches the full URI' do
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,7 +23,7 @@ describe AccountInteractions do
|
||||||
context 'account with Follow but with reblogs disabled' do
|
context 'account with Follow but with reblogs disabled' do
|
||||||
it 'returns { target_account_id => { reblogs: false } }' do
|
it 'returns { target_account_id => { reblogs: false } }' do
|
||||||
Fabricate(:follow, account: account, target_account: target_account, show_reblogs: false)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -690,41 +690,4 @@ describe AccountInteractions do
|
||||||
end
|
end
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -64,7 +64,7 @@ RSpec.describe PublicFeed, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not include local-only statuses' do
|
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
|
end
|
||||||
|
|
||||||
|
@ -80,12 +80,14 @@ RSpec.describe PublicFeed, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not include local-only statuses' do
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'without local_only option but allow_local_only' do
|
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(:viewer) { nil }
|
||||||
|
|
||||||
let!(:local_account) { Fabricate(:account, domain: 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!(:remote_status) { Fabricate(:status, account: remote_account) }
|
||||||
let!(:local_only_status) { Fabricate(:status, account: local_account, local_only: true) }
|
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
|
context 'without a viewer' do
|
||||||
let(:viewer) { nil }
|
let(:viewer) { nil }
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ RSpec.describe PublicFeed, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not include local-only statuses' do
|
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
|
end
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ RSpec.describe PublicFeed, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not include local-only statuses' do
|
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
|
end
|
||||||
|
|
||||||
|
|
|
@ -206,14 +206,14 @@ RSpec.describe Status, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'on create' do
|
describe 'on create' do
|
||||||
|
subject { Status.new }
|
||||||
|
|
||||||
let(:local_account) { Fabricate(:account, username: 'local', domain: nil) }
|
let(:local_account) { Fabricate(:account, username: 'local', domain: nil) }
|
||||||
let(:remote_account) { Fabricate(:account, username: 'remote', domain: 'example.com') }
|
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
|
describe 'on a status that ends with the local-only emoji' do
|
||||||
before do
|
before do
|
||||||
subject.text = 'A toot ' + subject.local_only_emoji
|
subject.text = "A toot #{subject.local_only_emoji}"
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'if the status originates from this instance' do
|
context 'if the status originates from this instance' do
|
||||||
|
@ -291,52 +291,52 @@ RSpec.describe Status, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.as_direct_timeline' do
|
describe '.as_direct_timeline' do
|
||||||
|
subject(:results) { Status.as_direct_timeline(account) }
|
||||||
|
|
||||||
let(:account) { Fabricate(:account) }
|
let(:account) { Fabricate(:account) }
|
||||||
let(:followed) { Fabricate(:account) }
|
let(:followed) { Fabricate(:account) }
|
||||||
let(:not_followed) { Fabricate(:account) }
|
let(:not_followed) { Fabricate(:account) }
|
||||||
|
|
||||||
|
let!(:self_public_status) { Fabricate(:status, account: account, visibility: :public) }
|
||||||
|
let!(:self_direct_status) { Fabricate(:status, account: account, visibility: :direct) }
|
||||||
|
let!(:followed_public_status) { Fabricate(:status, account: followed, visibility: :public) }
|
||||||
|
let!(:followed_direct_status) { Fabricate(:status, account: followed, visibility: :direct) }
|
||||||
|
let!(:not_followed_direct_status) { Fabricate(:status, account: not_followed, visibility: :direct) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
Fabricate(:follow, account: account, target_account: followed)
|
account.follow!(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)
|
|
||||||
|
|
||||||
@results = Status.as_direct_timeline(account)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not include public statuses from self' do
|
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
|
end
|
||||||
|
|
||||||
it 'includes direct statuses from self' do
|
it 'includes direct statuses from self' do
|
||||||
expect(@results).to include(@self_direct_status)
|
expect(results).to include(self_direct_status)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not include public statuses from followed' do
|
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
|
end
|
||||||
|
|
||||||
it 'does not include direct statuses not mentioning recipient from followed' do
|
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
|
end
|
||||||
|
|
||||||
it 'does not include direct statuses not mentioning recipient from non-followed' do
|
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
|
end
|
||||||
|
|
||||||
it 'includes direct statuses mentioning recipient from followed' do
|
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)
|
results2 = Status.as_direct_timeline(account)
|
||||||
expect(results2).to include(@followed_direct_status)
|
expect(results2).to include(followed_direct_status)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'includes direct statuses mentioning recipient from non-followed' do
|
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)
|
results2 = Status.as_direct_timeline(account)
|
||||||
expect(results2).to include(@not_followed_direct_status)
|
expect(results2).to include(not_followed_direct_status)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ describe TagFeed, type: :service do
|
||||||
expect(results).to include(status)
|
expect(results).to include(status)
|
||||||
end
|
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) }
|
let!(:status) { Fabricate(:status, tags: [tag1], local_only: true) }
|
||||||
|
|
||||||
it 'does not show local-only statuses without a viewer' do
|
it 'does not show local-only statuses without a viewer' do
|
||||||
|
|
|
@ -83,14 +83,14 @@ RSpec.describe StatusPolicy, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'denies access when local-only and the viewer is not logged in' do
|
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)
|
expect(subject).to_not permit(nil, status)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'denies access when local-only and the viewer is from another domain' do
|
it 'denies access when local-only and the viewer is from another domain' do
|
||||||
viewer = Fabricate(:account, domain: 'remote-domain')
|
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)
|
expect(subject).to_not permit(viewer, status)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -65,7 +65,7 @@ describe StatusLengthValidator do
|
||||||
it 'counts only the front part of remote usernames' do
|
it 'counts only the front part of remote usernames' do
|
||||||
username = '@alice'
|
username = '@alice'
|
||||||
chars = StatusLengthValidator::MAX_CHARS - 1 - username.length
|
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)
|
status = double(spoiler_text: '', text: text, errors: double(add: nil), local?: true, reblog?: false)
|
||||||
|
|
||||||
subject.validate(status)
|
subject.validate(status)
|
||||||
|
|
Loading…
Reference in a new issue