2016-07-12 23:08:55 +08:00
|
|
|
# Whe use ActiveSupport mb_chars from here to properly support non ascii downcase
|
|
|
|
# TODO remove when ruby 2.4 lands
|
|
|
|
require 'active_support/core_ext/string/multibyte'
|
|
|
|
|
2013-02-07 09:09:31 +08:00
|
|
|
#
|
2013-04-10 17:00:50 +08:00
|
|
|
# Given a string, tell us whether or not is acceptable.
|
2013-02-07 09:09:31 +08:00
|
|
|
#
|
|
|
|
class TextSentinel
|
|
|
|
|
|
|
|
attr_accessor :text
|
|
|
|
|
2013-08-30 23:27:24 +08:00
|
|
|
ENTROPY_SCALE ||= 0.7
|
2013-08-28 23:04:28 +08:00
|
|
|
|
2017-07-28 09:20:09 +08:00
|
|
|
def initialize(text, opts = nil)
|
2013-04-10 17:00:50 +08:00
|
|
|
@opts = opts || {}
|
2013-05-23 12:52:12 +08:00
|
|
|
@text = text.to_s.encode('UTF-8', invalid: :replace, undef: :replace, replace: '')
|
2013-04-10 17:00:50 +08:00
|
|
|
end
|
|
|
|
|
2017-07-28 09:20:09 +08:00
|
|
|
def self.body_sentinel(text, opts = {})
|
2013-06-13 16:18:17 +08:00
|
|
|
entropy = SiteSetting.body_min_entropy
|
|
|
|
if opts[:private_message]
|
2018-01-31 13:56:00 +08:00
|
|
|
scale_entropy = SiteSetting.min_personal_message_post_length.to_f / SiteSetting.min_post_length.to_f
|
2013-06-13 16:18:17 +08:00
|
|
|
entropy = (entropy * scale_entropy).to_i
|
2018-01-31 13:56:00 +08:00
|
|
|
entropy = (SiteSetting.min_personal_message_post_length.to_f * ENTROPY_SCALE).to_i if entropy > SiteSetting.min_personal_message_post_length
|
2013-08-28 23:04:28 +08:00
|
|
|
else
|
|
|
|
entropy = (SiteSetting.min_post_length.to_f * ENTROPY_SCALE).to_i if entropy > SiteSetting.min_post_length
|
2013-06-13 16:18:17 +08:00
|
|
|
end
|
|
|
|
TextSentinel.new(text, min_entropy: entropy)
|
2013-02-07 09:09:31 +08:00
|
|
|
end
|
|
|
|
|
2013-02-09 05:55:40 +08:00
|
|
|
def self.title_sentinel(text)
|
2013-08-28 23:04:28 +08:00
|
|
|
entropy = if SiteSetting.min_topic_title_length > SiteSetting.title_min_entropy
|
|
|
|
SiteSetting.title_min_entropy
|
|
|
|
else
|
|
|
|
(SiteSetting.min_topic_title_length.to_f * ENTROPY_SCALE).to_i
|
|
|
|
end
|
2015-04-02 13:46:53 +08:00
|
|
|
TextSentinel.new(text, min_entropy: entropy, max_word_length: SiteSetting.title_max_word_length)
|
2013-02-09 05:55:40 +08:00
|
|
|
end
|
|
|
|
|
2013-02-26 00:42:20 +08:00
|
|
|
# Entropy is a number of how many unique characters the string needs.
|
2013-06-08 02:47:07 +08:00
|
|
|
# Non-ASCII characters are weighted heavier since they contain more "information"
|
2013-02-07 09:09:31 +08:00
|
|
|
def entropy
|
2013-06-08 02:47:07 +08:00
|
|
|
chars = @text.to_s.strip.split('')
|
2017-07-28 09:20:09 +08:00
|
|
|
@entropy ||= chars.pack('M*' * chars.size).gsub("\n", '').split('=').uniq.size
|
2013-02-07 09:09:31 +08:00
|
|
|
end
|
|
|
|
|
2013-02-26 00:42:20 +08:00
|
|
|
def valid?
|
2013-05-23 12:52:12 +08:00
|
|
|
@text.present? &&
|
2013-05-24 01:48:37 +08:00
|
|
|
seems_meaningful? &&
|
|
|
|
seems_pronounceable? &&
|
|
|
|
seems_unpretentious? &&
|
2013-06-18 13:49:10 +08:00
|
|
|
seems_quiet?
|
2013-05-24 01:48:37 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
2013-02-07 09:09:31 +08:00
|
|
|
|
2013-05-24 01:48:37 +08:00
|
|
|
def symbols_regex
|
|
|
|
/[\ -\/\[-\`\:-\@\{-\~]/m
|
|
|
|
end
|
2013-02-07 09:09:31 +08:00
|
|
|
|
2013-05-24 01:48:37 +08:00
|
|
|
def seems_meaningful?
|
2013-05-23 12:52:12 +08:00
|
|
|
# Minimum entropy if entropy check required
|
2013-05-24 01:48:37 +08:00
|
|
|
@opts[:min_entropy].blank? || (entropy >= @opts[:min_entropy])
|
|
|
|
end
|
2013-02-07 09:09:31 +08:00
|
|
|
|
2013-05-24 01:48:37 +08:00
|
|
|
def seems_pronounceable?
|
2013-05-23 12:52:12 +08:00
|
|
|
# At least some non-symbol characters
|
|
|
|
# (We don't have a comprehensive list of symbols, but this will eliminate some noise)
|
2013-05-24 01:48:37 +08:00
|
|
|
@text.gsub(symbols_regex, '').size > 0
|
|
|
|
end
|
2013-02-07 09:09:31 +08:00
|
|
|
|
2019-04-05 21:07:49 +08:00
|
|
|
def skipped_locale
|
|
|
|
%w(zh_CN zh_TW ko ja).freeze
|
|
|
|
end
|
|
|
|
|
2013-05-24 01:48:37 +08:00
|
|
|
def seems_unpretentious?
|
2019-04-05 21:07:49 +08:00
|
|
|
return true if skipped_locale.include?(SiteSetting.default_locale)
|
2013-05-23 12:52:12 +08:00
|
|
|
# Don't allow super long words if there is a word length maximum
|
2016-09-13 11:45:05 +08:00
|
|
|
@opts[:max_word_length].blank? || @text.split(/\s|\/|-|\.|:/).map(&:size).max <= @opts[:max_word_length]
|
2013-05-24 01:48:37 +08:00
|
|
|
end
|
2013-02-07 09:09:31 +08:00
|
|
|
|
2013-05-24 01:48:37 +08:00
|
|
|
def seems_quiet?
|
2019-04-05 21:07:49 +08:00
|
|
|
return true if skipped_locale.include?(SiteSetting.default_locale)
|
2016-07-12 23:08:55 +08:00
|
|
|
# We don't allow all upper case content
|
|
|
|
SiteSetting.allow_uppercase_posts || @text == @text.mb_chars.downcase.to_s || @text != @text.mb_chars.upcase.to_s
|
2013-02-07 09:09:31 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|