Remove deprecated mb_chars method (#34039)
				
					
				
			This commit is contained in:
		
							parent
							
								
									43f616a1c8
								
							
						
					
					
						commit
						d90d68bddf
					
				@ -16,7 +16,7 @@ class HashtagNormalizer
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def lowercase(str)
 | 
					  def lowercase(str)
 | 
				
			||||||
    str.mb_chars.downcase.to_s
 | 
					    str.downcase.to_s
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def cjk_width(str)
 | 
					  def cjk_width(str)
 | 
				
			||||||
 | 
				
			|||||||
@ -160,11 +160,11 @@ class Tag < ApplicationRecord
 | 
				
			|||||||
  private
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def validate_name_change
 | 
					  def validate_name_change
 | 
				
			||||||
    errors.add(:name, I18n.t('tags.does_not_match_previous_name')) unless name_was.mb_chars.casecmp(name.mb_chars).zero?
 | 
					    errors.add(:name, I18n.t('tags.does_not_match_previous_name')) unless name_was.casecmp(name).zero?
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def validate_display_name_change
 | 
					  def validate_display_name_change
 | 
				
			||||||
    unless HashtagNormalizer.new.normalize(display_name).casecmp(name.mb_chars).zero?
 | 
					    unless HashtagNormalizer.new.normalize(display_name).casecmp(name).zero?
 | 
				
			||||||
      errors.add(:display_name,
 | 
					      errors.add(:display_name,
 | 
				
			||||||
                 I18n.t('tags.does_not_match_previous_name'))
 | 
					                 I18n.t('tags.does_not_match_previous_name'))
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
				
			|||||||
@ -92,7 +92,7 @@ class BatchedRemoveStatusService < BaseService
 | 
				
			|||||||
      pipeline.publish(status.local? ? 'timeline:public:local:media' : 'timeline:public:remote:media', payload)
 | 
					      pipeline.publish(status.local? ? 'timeline:public:local:media' : 'timeline:public:remote:media', payload)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    status.tags.map { |tag| tag.name.mb_chars.downcase }.each do |hashtag|
 | 
					    status.tags.map { |tag| tag.name.downcase }.each do |hashtag|
 | 
				
			||||||
      pipeline.publish("timeline:hashtag:#{hashtag}", payload)
 | 
					      pipeline.publish("timeline:hashtag:#{hashtag}", payload)
 | 
				
			||||||
      pipeline.publish("timeline:hashtag:#{hashtag}:local", payload) if status.local?
 | 
					      pipeline.publish("timeline:hashtag:#{hashtag}:local", payload) if status.local?
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
				
			|||||||
@ -128,8 +128,8 @@ class FanOutOnWriteService < BaseService
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  def broadcast_to_hashtag_streams!
 | 
					  def broadcast_to_hashtag_streams!
 | 
				
			||||||
    @status.tags.map(&:name).each do |hashtag|
 | 
					    @status.tags.map(&:name).each do |hashtag|
 | 
				
			||||||
      redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}", anonymous_payload)
 | 
					      redis.publish("timeline:hashtag:#{hashtag.downcase}", anonymous_payload)
 | 
				
			||||||
      redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}:local", anonymous_payload) if @status.local?
 | 
					      redis.publish("timeline:hashtag:#{hashtag.downcase}:local", anonymous_payload) if @status.local?
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -123,8 +123,8 @@ class RemoveStatusService < BaseService
 | 
				
			|||||||
    return if skip_streaming?
 | 
					    return if skip_streaming?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @status.tags.map(&:name).each do |hashtag|
 | 
					    @status.tags.map(&:name).each do |hashtag|
 | 
				
			||||||
      redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}", @payload)
 | 
					      redis.publish("timeline:hashtag:#{hashtag.downcase}", @payload)
 | 
				
			||||||
      redis.publish("timeline:hashtag:#{hashtag.mb_chars.downcase}:local", @payload) if @status.local?
 | 
					      redis.publish("timeline:hashtag:#{hashtag.downcase}:local", @payload) if @status.local?
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@ class NoteLengthValidator < ActiveModel::EachValidator
 | 
				
			|||||||
  private
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def too_long?(value)
 | 
					  def too_long?(value)
 | 
				
			||||||
    countable_text(value).mb_chars.grapheme_length > options[:maximum]
 | 
					    countable_text(value).each_grapheme_cluster.size > options[:maximum]
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def countable_text(value)
 | 
					  def countable_text(value)
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ class PollOptionsValidator < ActiveModel::Validator
 | 
				
			|||||||
  def validate(poll)
 | 
					  def validate(poll)
 | 
				
			||||||
    poll.errors.add(:options, I18n.t('polls.errors.too_few_options')) unless poll.options.size > 1
 | 
					    poll.errors.add(:options, I18n.t('polls.errors.too_few_options')) unless poll.options.size > 1
 | 
				
			||||||
    poll.errors.add(:options, I18n.t('polls.errors.too_many_options', max: MAX_OPTIONS)) if poll.options.size > MAX_OPTIONS
 | 
					    poll.errors.add(:options, I18n.t('polls.errors.too_many_options', max: MAX_OPTIONS)) if poll.options.size > MAX_OPTIONS
 | 
				
			||||||
    poll.errors.add(:options, I18n.t('polls.errors.over_character_limit', max: MAX_OPTION_CHARS)) if poll.options.any? { |option| option.mb_chars.grapheme_length > MAX_OPTION_CHARS }
 | 
					    poll.errors.add(:options, I18n.t('polls.errors.over_character_limit', max: MAX_OPTION_CHARS)) if poll.options.any? { |option| option.each_grapheme_cluster.size > MAX_OPTION_CHARS }
 | 
				
			||||||
    poll.errors.add(:options, I18n.t('polls.errors.duplicate_options')) unless poll.options.uniq.size == poll.options.size
 | 
					    poll.errors.add(:options, I18n.t('polls.errors.duplicate_options')) unless poll.options.uniq.size == poll.options.size
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ class StatusLengthValidator < ActiveModel::Validator
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def countable_length(str)
 | 
					  def countable_length(str)
 | 
				
			||||||
    str.mb_chars.grapheme_length
 | 
					    str.each_grapheme_cluster.size
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def combined_text(status)
 | 
					  def combined_text(status)
 | 
				
			||||||
 | 
				
			|||||||
@ -30,6 +30,22 @@ RSpec.describe NoteLengthValidator do
 | 
				
			|||||||
      expect(account.errors).to have_received(:add)
 | 
					      expect(account.errors).to have_received(:add)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'counts multi byte emoji as single character' do
 | 
				
			||||||
 | 
					      text = '✨' * 500
 | 
				
			||||||
 | 
					      account = instance_double(Account, note: text, errors: activemodel_errors)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      subject.validate_each(account, 'note', text)
 | 
				
			||||||
 | 
					      expect(account.errors).to_not have_received(:add)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'counts ZWJ sequence emoji as single character' do
 | 
				
			||||||
 | 
					      text = '🏳️⚧️' * 500
 | 
				
			||||||
 | 
					      account = instance_double(Account, note: text, errors: activemodel_errors)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      subject.validate_each(account, 'note', text)
 | 
				
			||||||
 | 
					      expect(account.errors).to_not have_received(:add)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private
 | 
					    private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def starting_string
 | 
					    def starting_string
 | 
				
			||||||
 | 
				
			|||||||
@ -41,5 +41,31 @@ RSpec.describe PollOptionsValidator do
 | 
				
			|||||||
        expect(errors).to have_received(:add)
 | 
					        expect(errors).to have_received(:add)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    describe 'character length of poll options' do
 | 
				
			||||||
 | 
					      context 'when poll has acceptable length options' do
 | 
				
			||||||
 | 
					        let(:options) { %w(test this) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it 'has no errors' do
 | 
				
			||||||
 | 
					          expect(errors).to_not have_received(:add)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      context 'when poll has multibyte and ZWJ emoji options' do
 | 
				
			||||||
 | 
					        let(:options) { ['✨' * described_class::MAX_OPTION_CHARS, '🏳️⚧️' * described_class::MAX_OPTION_CHARS] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it 'has no errors' do
 | 
				
			||||||
 | 
					          expect(errors).to_not have_received(:add)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      context 'when poll has options that are too long' do
 | 
				
			||||||
 | 
					        let(:options) { ['ok', 'a' * (described_class::MAX_OPTION_CHARS**2)] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it 'has errors' do
 | 
				
			||||||
 | 
					          expect(errors).to have_received(:add)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
@ -80,6 +80,22 @@ RSpec.describe StatusLengthValidator do
 | 
				
			|||||||
      subject.validate(status)
 | 
					      subject.validate(status)
 | 
				
			||||||
      expect(status.errors).to have_received(:add)
 | 
					      expect(status.errors).to have_received(:add)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'counts multi byte emoji as single character' do
 | 
				
			||||||
 | 
					      text = '✨' * 500
 | 
				
			||||||
 | 
					      status = status_double(text: text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      subject.validate(status)
 | 
				
			||||||
 | 
					      expect(status.errors).to_not have_received(:add)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'counts ZWJ sequence emoji as single character' do
 | 
				
			||||||
 | 
					      text = '🏳️⚧️' * 500
 | 
				
			||||||
 | 
					      status = status_double(text: text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      subject.validate(status)
 | 
				
			||||||
 | 
					      expect(status.errors).to_not have_received(:add)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private
 | 
					  private
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user