2015-03-31 11:58:56 -05:00
|
|
|
require_dependency 'post_creator'
|
|
|
|
require_dependency 'new_post_result'
|
2017-06-28 15:56:44 -05:00
|
|
|
require_dependency 'word_watcher'
|
2015-03-31 11:58:56 -05:00
|
|
|
|
|
|
|
# Determines what actions should be taken with new posts.
|
|
|
|
#
|
|
|
|
# The default action is to create the post, but this can be extended
|
|
|
|
# with `NewPostManager.add_handler` to take other approaches depending
|
|
|
|
# on the user or input.
|
|
|
|
class NewPostManager
|
|
|
|
|
|
|
|
attr_reader :user, :args
|
|
|
|
|
2015-04-28 12:53:05 -05:00
|
|
|
def self.sorted_handlers
|
|
|
|
@sorted_handlers ||= clear_handlers!
|
|
|
|
end
|
|
|
|
|
2015-03-31 11:58:56 -05:00
|
|
|
def self.handlers
|
2017-07-27 20:20:09 -05:00
|
|
|
sorted_handlers.map { |h| h[:proc] }
|
2015-03-31 11:58:56 -05:00
|
|
|
end
|
|
|
|
|
2015-04-28 12:53:05 -05:00
|
|
|
def self.clear_handlers!
|
|
|
|
@sorted_handlers = [{ priority: 0, proc: method(:default_handler) }]
|
|
|
|
end
|
|
|
|
|
2017-07-27 20:20:09 -05:00
|
|
|
def self.add_handler(priority = 0, &block)
|
2015-04-28 12:53:05 -05:00
|
|
|
sorted_handlers << { priority: priority, proc: block }
|
2017-07-27 20:20:09 -05:00
|
|
|
@sorted_handlers.sort_by! { |h| -h[:priority] }
|
2015-03-31 11:58:56 -05:00
|
|
|
end
|
|
|
|
|
2015-08-04 22:08:21 -05:00
|
|
|
def self.is_first_post?(manager)
|
2015-08-03 19:55:59 -05:00
|
|
|
user = manager.user
|
|
|
|
args = manager.args
|
|
|
|
|
2015-08-05 19:07:07 -05:00
|
|
|
!!(
|
|
|
|
args[:first_post_checks] &&
|
|
|
|
user.post_count == 0
|
|
|
|
)
|
2015-08-04 22:08:21 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.is_fast_typer?(manager)
|
|
|
|
args = manager.args
|
|
|
|
|
|
|
|
is_first_post?(manager) &&
|
2015-08-05 19:07:07 -05:00
|
|
|
args[:typing_duration_msecs].to_i < SiteSetting.min_first_post_typing_time &&
|
2017-11-10 11:18:08 -06:00
|
|
|
SiteSetting.auto_silence_fast_typers_on_first_post &&
|
|
|
|
manager.user.trust_level <= SiteSetting.auto_silence_fast_typers_max_trust_level
|
2015-08-03 21:06:07 -05:00
|
|
|
end
|
|
|
|
|
2017-11-10 11:18:08 -06:00
|
|
|
def self.matches_auto_silence_regex?(manager)
|
2015-08-04 22:08:21 -05:00
|
|
|
args = manager.args
|
|
|
|
|
2017-11-10 11:18:08 -06:00
|
|
|
pattern = SiteSetting.auto_silence_first_post_regex
|
2015-08-04 22:08:21 -05:00
|
|
|
|
|
|
|
return false unless pattern.present?
|
|
|
|
return false unless is_first_post?(manager)
|
|
|
|
|
|
|
|
begin
|
|
|
|
regex = Regexp.new(pattern, Regexp::IGNORECASE)
|
|
|
|
rescue => e
|
2017-11-10 11:18:08 -06:00
|
|
|
Rails.logger.warn "Invalid regex in auto_silence_first_post_regex #{e}"
|
2015-08-04 22:08:21 -05:00
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
"#{args[:title]} #{args[:raw]}" =~ regex
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2017-06-28 15:56:44 -05:00
|
|
|
def self.exempt_user?(user)
|
2018-04-06 04:41:25 -05:00
|
|
|
user.staff?
|
2017-06-28 15:56:44 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.post_needs_approval?(manager)
|
2015-08-03 21:06:07 -05:00
|
|
|
user = manager.user
|
|
|
|
|
2017-06-28 15:56:44 -05:00
|
|
|
return false if exempt_user?(user)
|
2015-06-04 10:35:36 -05:00
|
|
|
|
2016-03-02 13:54:03 -06:00
|
|
|
(user.trust_level <= TrustLevel.levels[:basic] && user.post_count < SiteSetting.approve_post_count) ||
|
2015-08-03 19:55:59 -05:00
|
|
|
(user.trust_level < SiteSetting.approve_unless_trust_level.to_i) ||
|
2016-09-19 13:07:15 -05:00
|
|
|
(manager.args[:title].present? && user.trust_level < SiteSetting.approve_new_topics_unless_trust_level.to_i) ||
|
2015-08-04 22:08:21 -05:00
|
|
|
is_fast_typer?(manager) ||
|
2017-11-10 11:18:08 -06:00
|
|
|
matches_auto_silence_regex?(manager) ||
|
2018-04-06 04:41:25 -05:00
|
|
|
WordWatcher.new("#{manager.args[:title]} #{manager.args[:raw]}").requires_approval? ||
|
2018-07-12 21:51:08 -05:00
|
|
|
(SiteSetting.approve_unless_staged && user.staged) ||
|
|
|
|
post_needs_approval_in_its_category?(manager)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.post_needs_approval_in_its_category?(manager)
|
|
|
|
if manager.args[:topic_id].present?
|
|
|
|
cat = Category.joins(:topics).find_by(topics: { id: manager.args[:topic_id] })
|
|
|
|
return false unless cat
|
|
|
|
cat.require_reply_approval?
|
|
|
|
elsif manager.args[:category].present?
|
|
|
|
Category.find(manager.args[:category]).require_topic_approval?
|
|
|
|
else
|
|
|
|
false
|
|
|
|
end
|
2015-04-28 15:14:36 -05:00
|
|
|
end
|
|
|
|
|
2015-04-15 11:12:20 -05:00
|
|
|
def self.default_handler(manager)
|
2017-06-28 15:56:44 -05:00
|
|
|
if post_needs_approval?(manager)
|
2016-09-12 11:26:49 -05:00
|
|
|
validator = Validators::PostValidator.new
|
|
|
|
post = Post.new(raw: manager.args[:raw])
|
2016-09-16 12:15:01 -05:00
|
|
|
post.user = manager.user
|
2016-09-12 11:26:49 -05:00
|
|
|
validator.validate(post)
|
2018-11-09 11:24:28 -06:00
|
|
|
|
2016-09-12 11:26:49 -05:00
|
|
|
if post.errors[:raw].present?
|
|
|
|
result = NewPostResult.new(:created_post, false)
|
2017-08-30 23:06:56 -05:00
|
|
|
result.errors[:base] << post.errors[:raw]
|
2016-09-12 11:26:49 -05:00
|
|
|
return result
|
2018-11-09 11:24:28 -06:00
|
|
|
elsif manager.args[:topic_id]
|
2016-09-09 11:15:56 -05:00
|
|
|
topic = Topic.unscoped.where(id: manager.args[:topic_id]).first
|
|
|
|
|
|
|
|
unless manager.user.guardian.can_create_post_on_topic?(topic)
|
|
|
|
result = NewPostResult.new(:created_post, false)
|
|
|
|
result.errors[:base] << I18n.t(:topic_not_found)
|
|
|
|
return result
|
|
|
|
end
|
2018-11-09 11:24:28 -06:00
|
|
|
elsif manager.args[:category]
|
|
|
|
category = Category.find_by(id: manager.args[:category])
|
|
|
|
|
|
|
|
unless manager.user.guardian.can_create_topic_on_category?(category)
|
|
|
|
result = NewPostResult.new(:created_post, false)
|
|
|
|
result.errors[:base] << I18n.t("js.errors.reasons.forbidden")
|
|
|
|
return result
|
|
|
|
end
|
2016-09-09 11:15:56 -05:00
|
|
|
end
|
|
|
|
|
2019-01-03 11:03:01 -06:00
|
|
|
result = manager.enqueue
|
2015-08-03 21:06:07 -05:00
|
|
|
|
2017-03-10 14:45:48 -06:00
|
|
|
if is_fast_typer?(manager)
|
2017-11-10 11:18:08 -06:00
|
|
|
UserSilencer.silence(manager.user, Discourse.system_user, keep_posts: true, reason: I18n.t("user.new_user_typed_too_fast"))
|
|
|
|
elsif matches_auto_silence_regex?(manager)
|
|
|
|
UserSilencer.silence(manager.user, Discourse.system_user, keep_posts: true, reason: I18n.t("user.content_matches_auto_silence_regex"))
|
2016-03-18 06:16:37 -05:00
|
|
|
end
|
2015-08-03 21:06:07 -05:00
|
|
|
|
|
|
|
result
|
|
|
|
end
|
2015-04-15 11:12:20 -05:00
|
|
|
end
|
|
|
|
|
2015-04-21 12:59:57 -05:00
|
|
|
def self.queue_enabled?
|
|
|
|
SiteSetting.approve_post_count > 0 ||
|
|
|
|
SiteSetting.approve_unless_trust_level.to_i > 0 ||
|
2016-09-22 13:51:36 -05:00
|
|
|
SiteSetting.approve_new_topics_unless_trust_level.to_i > 0 ||
|
2018-04-06 04:41:25 -05:00
|
|
|
SiteSetting.approve_unless_staged ||
|
2017-06-28 15:56:44 -05:00
|
|
|
WordWatcher.words_for_action_exists?(:require_approval) ||
|
2015-04-21 12:59:57 -05:00
|
|
|
handlers.size > 1
|
|
|
|
end
|
|
|
|
|
2015-03-31 11:58:56 -05:00
|
|
|
def initialize(user, args)
|
|
|
|
@user = user
|
2017-07-27 20:20:09 -05:00
|
|
|
@args = args.delete_if { |_, v| v.nil? }
|
2015-03-31 11:58:56 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def perform
|
2018-02-28 10:22:04 -06:00
|
|
|
if !self.class.exempt_user?(@user) && matches = WordWatcher.new("#{@args[:title]} #{@args[:raw]}").should_block?
|
2017-06-28 15:56:44 -05:00
|
|
|
result = NewPostResult.new(:created_post, false)
|
2018-02-28 10:22:04 -06:00
|
|
|
result.errors[:base] << I18n.t('contains_blocked_words', word: matches[0])
|
2017-06-28 15:56:44 -05:00
|
|
|
return result
|
|
|
|
end
|
|
|
|
|
2015-05-04 10:07:46 -05:00
|
|
|
# We never queue private messages
|
|
|
|
return perform_create_post if @args[:archetype] == Archetype.private_message
|
2017-06-28 15:56:44 -05:00
|
|
|
|
2015-05-13 11:08:39 -05:00
|
|
|
if args[:topic_id] && Topic.where(id: args[:topic_id], archetype: Archetype.private_message).exists?
|
|
|
|
return perform_create_post
|
|
|
|
end
|
2015-05-04 10:07:46 -05:00
|
|
|
|
2015-03-31 11:58:56 -05:00
|
|
|
# Perform handlers until one returns a result
|
|
|
|
handled = NewPostManager.handlers.any? do |handler|
|
|
|
|
result = handler.call(self)
|
|
|
|
return result if result
|
|
|
|
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
|
|
|
perform_create_post unless handled
|
|
|
|
end
|
|
|
|
|
2019-01-03 11:03:01 -06:00
|
|
|
# Enqueue this post
|
|
|
|
def enqueue(reason = nil)
|
2015-03-31 11:58:56 -05:00
|
|
|
result = NewPostResult.new(:enqueued)
|
|
|
|
|
2019-01-03 11:03:01 -06:00
|
|
|
reviewable = ReviewableQueuedPost.new(
|
|
|
|
created_by: @user,
|
|
|
|
payload: { raw: @args[:raw] },
|
|
|
|
topic_id: @args[:topic_id],
|
|
|
|
reviewable_by_moderator: true
|
|
|
|
)
|
|
|
|
reviewable.payload['title'] = @args[:title] if @args[:title].present?
|
|
|
|
|
|
|
|
create_options = reviewable.create_options
|
|
|
|
|
|
|
|
creator = @args[:topic_id] ?
|
|
|
|
PostCreator.new(@user, create_options) :
|
|
|
|
TopicCreator.new(@user, Guardian.new(@user), create_options)
|
|
|
|
|
|
|
|
errors = Set.new
|
|
|
|
creator.valid?
|
|
|
|
creator.errors.full_messages.each { |msg| errors << msg }
|
|
|
|
errors = creator.errors.full_messages.uniq
|
|
|
|
if errors.blank?
|
|
|
|
if reviewable.save
|
|
|
|
reviewable.add_score(
|
|
|
|
Discourse.system_user,
|
|
|
|
ReviewableScore.types[:needs_approval],
|
|
|
|
force_review: true
|
|
|
|
)
|
|
|
|
else
|
|
|
|
reviewable.errors.full_messages.each { |msg| errors << msg }
|
|
|
|
end
|
|
|
|
end
|
2015-04-10 16:00:50 -05:00
|
|
|
|
2019-01-03 11:03:01 -06:00
|
|
|
result.reviewable = reviewable
|
2015-04-28 14:06:27 -05:00
|
|
|
result.reason = reason if reason
|
2019-01-03 11:03:01 -06:00
|
|
|
result.check_errors(errors)
|
|
|
|
result.pending_count = Reviewable.where(created_by: @user).pending.count
|
2015-03-31 11:58:56 -05:00
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def perform_create_post
|
|
|
|
result = NewPostResult.new(:create_post)
|
|
|
|
creator = PostCreator.new(@user, @args)
|
|
|
|
post = creator.create
|
|
|
|
result.check_errors_from(creator)
|
|
|
|
|
|
|
|
if result.success?
|
|
|
|
result.post = post
|
|
|
|
else
|
|
|
|
@user.flag_linked_posts_as_spam if creator.spam?
|
|
|
|
end
|
|
|
|
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|