From 16fe7aa307a28eba34161d4597df8c2fd486c5c8 Mon Sep 17 00:00:00 2001
From: Neil Lalonde <neillalonde@gmail.com>
Date: Thu, 14 Sep 2017 12:00:37 -0400
Subject: [PATCH] FEATURE: automatically handle flags and posts that have been
 waiting in a queue for a long time. Flags will be deferred. Posts waiting for
 approval will be rejected. Control how old the records need to be with the
 auto_handle_queued_age site setting.

---
 app/jobs/scheduled/auto_queue_handler.rb | 31 ++++++++++++++++
 config/locales/server.en.yml             |  3 ++
 config/site_settings.yml                 |  4 +++
 spec/jobs/auto_queue_handler_spec.rb     | 45 ++++++++++++++++++++++++
 4 files changed, 83 insertions(+)
 create mode 100644 app/jobs/scheduled/auto_queue_handler.rb
 create mode 100644 spec/jobs/auto_queue_handler_spec.rb

diff --git a/app/jobs/scheduled/auto_queue_handler.rb b/app/jobs/scheduled/auto_queue_handler.rb
new file mode 100644
index 00000000000..40d6f811e7e
--- /dev/null
+++ b/app/jobs/scheduled/auto_queue_handler.rb
@@ -0,0 +1,31 @@
+# This job will automatically act on records that have gone unhandled on a
+# queue for a long time.
+module Jobs
+  class AutoQueueHandler < Jobs::Scheduled
+
+    every 1.day
+
+    def execute(args)
+      return unless SiteSetting.auto_handle_queued_age.to_i > 0
+
+      guardian = Guardian.new(Discourse.system_user)
+
+      # Flags
+      flags = FlagQuery.flagged_post_actions('active')
+        .where('post_actions.created_at < ?', SiteSetting.auto_handle_queued_age.to_i.days.ago)
+
+      Post.where(id: flags.pluck(:post_id).uniq).each do |post|
+        PostAction.defer_flags!(post, Discourse.system_user)
+      end
+
+      # Posts
+      queued_posts = QueuedPost.visible
+        .where(state: QueuedPost.states[:new])
+        .where('created_at < ?', SiteSetting.auto_handle_queued_age.to_i.days.ago)
+
+      queued_posts.each do |queued_post|
+        queued_post.reject!(Discourse.system_user)
+      end
+    end
+  end
+end
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 81f6f201ba0..1728eca737c 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -1472,6 +1472,8 @@ en:
 
     share_anonymized_statistics: "Share anonymized usage statistics."
 
+    auto_handle_queued_age: "Automatically handle records that are waiting to be reviewed after this many days. Flags will be deferred. Queued posts and users will be rejected. Set to 0 to disable this feature."
+
     max_prints_per_hour_per_user: "Maximum number of /print page impressions (set to 0 to disable)"
 
     full_name_required: "Full name is a required field of a user's profile."
@@ -1753,6 +1755,7 @@ en:
       max_new_accounts_per_registration_ip: "New registrations are not allowed from your IP address (maximum limit reached). Contact a staff member."
     website:
       domain_not_allowed: "Website is invalid. Allowed domains are: %{domains}"
+    auto_rejected: "Rejected automatically due to age. See auto_handle_queued_age site setting."
 
   flags_reminder:
     flags_were_submitted:
diff --git a/config/site_settings.yml b/config/site_settings.yml
index 2cd16d920ff..85ba28dd91e 100644
--- a/config/site_settings.yml
+++ b/config/site_settings.yml
@@ -1358,6 +1358,10 @@ uncategorized:
 
   share_anonymized_statistics: true
 
+  auto_handle_queued_age:
+    default: 60
+    min: 0
+
 user_preferences:
   default_email_digest_frequency:
     enum: 'DigestEmailSiteSetting'
diff --git a/spec/jobs/auto_queue_handler_spec.rb b/spec/jobs/auto_queue_handler_spec.rb
new file mode 100644
index 00000000000..89b84a2f5f5
--- /dev/null
+++ b/spec/jobs/auto_queue_handler_spec.rb
@@ -0,0 +1,45 @@
+require 'rails_helper'
+
+describe Jobs::AutoQueueHandler do
+
+  subject { Jobs::AutoQueueHandler.new.execute({}) }
+
+  context "old flag" do
+    let!(:old) { Fabricate(:flag, created_at: 61.days.ago) }
+    let!(:not_old) { Fabricate(:flag, created_at: 59.days.ago) }
+
+    it "defers the old flag if auto_handle_queued_age is 60" do
+      SiteSetting.auto_handle_queued_age = 60
+      subject
+      expect(not_old.reload.deferred_at).to be_nil
+      expect(old.reload.deferred_at).to_not be_nil
+    end
+
+    it "doesn't defer the old flag if auto_handle_queued_age is 0" do
+      SiteSetting.auto_handle_queued_age = 0
+      subject
+      expect(not_old.reload.deferred_at).to be_nil
+      expect(old.reload.deferred_at).to be_nil
+    end
+  end
+
+  context "old queued post" do
+    let!(:old) { Fabricate(:queued_post, created_at: 61.days.ago, queue: 'default') }
+    let!(:not_old) { Fabricate(:queued_post, created_at: 59.days.ago, queue: 'default') }
+
+    it "rejects the post when auto_handle_queued_age is 60" do
+      SiteSetting.auto_handle_queued_age = 60
+      subject
+      expect(not_old.reload.state).to eq(QueuedPost.states[:new])
+      expect(old.reload.state).to eq(QueuedPost.states[:rejected])
+    end
+
+    it "doesn't reject the post when auto_handle_queued_age is 0" do
+      SiteSetting.auto_handle_queued_age = 0
+      subject
+      expect(not_old.reload.state).to eq(QueuedPost.states[:new])
+      expect(old.reload.state).to eq(QueuedPost.states[:new])
+    end
+  end
+
+end