Browse Source

Automatically switch from open to approved registrations in absence of moderators (#29337)

Claire 3 months ago
parent
commit
2fc87611be

+ 9 - 0
app/mailers/admin_mailer.rb

@@ -47,4 +47,13 @@ class AdminMailer < ApplicationMailer
       mail to: @me.user_email, subject: I18n.t('admin_mailer.new_trends.subject', instance: @instance)
     end
   end
+
+  def auto_close_registrations(recipient)
+    @me       = recipient
+    @instance = Rails.configuration.x.local_domain
+
+    locale_for_account(@me) do
+      mail to: @me.user_email, subject: I18n.t('admin_mailer.auto_close_registrations.subject', instance: @instance)
+    end
+  end
 end

+ 3 - 0
app/views/admin_mailer/auto_close_registrations.text.erb

@@ -0,0 +1,3 @@
+<%= raw t('admin_mailer.auto_close_registrations.body', instance: @instance) %>
+
+<%= raw t('application_mailer.view')%> <%= admin_settings_registrations_url %>

+ 33 - 0
app/workers/scheduler/auto_close_registrations_scheduler.rb

@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+class Scheduler::AutoCloseRegistrationsScheduler
+  include Sidekiq::Worker
+  include Redisable
+
+  sidekiq_options retry: 0
+
+  # Automatically switch away from open registrations if no
+  # moderator had any activity in that period of time
+  OPEN_REGISTRATIONS_MODERATOR_THRESHOLD = 1.week + UserTrackingConcern::SIGN_IN_UPDATE_FREQUENCY
+
+  def perform
+    return if Rails.configuration.x.email_domains_whitelist.present? || ENV['DISABLE_AUTOMATIC_SWITCHING_TO_APPROVED_REGISTRATIONS'] == 'true'
+    return unless Setting.registrations_mode == 'open'
+
+    switch_to_approval_mode! unless active_moderators?
+  end
+
+  private
+
+  def active_moderators?
+    User.those_who_can(:manage_reports).exists?(current_sign_in_at: OPEN_REGISTRATIONS_MODERATOR_THRESHOLD.ago...)
+  end
+
+  def switch_to_approval_mode!
+    Setting.registrations_mode = 'approved'
+
+    User.those_who_can(:view_devops).includes(:account).find_each do |user|
+      AdminMailer.auto_close_registrations(recipient: user.account).deliver_later
+    end
+  end
+end

+ 3 - 0
config/locales/en.yml

@@ -905,6 +905,9 @@ en:
       title: Webhooks
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: Due to a lack of recent moderator activity, registrations on %{instance} have been automatically switched to requiring manual review, to prevent %{instance} from being used as a platform for potential bad actors. You can switch it back to open registrations at any time.
+      subject: Registrations for %{instance} have been automatically switched to requiring approval
     new_appeal:
       actions:
         delete_statuses: to delete their posts

+ 4 - 0
config/sidekiq.yml

@@ -58,3 +58,7 @@
     interval: 1 minute
     class: Scheduler::SuspendedUserCleanupScheduler
     queue: scheduler
+  auto_close_registrations_scheduler:
+    interval: 1 hour
+    class: Scheduler::AutoCloseRegistrationsScheduler
+    queue: scheduler

+ 60 - 0
spec/workers/scheduler/auto_close_registrations_scheduler_spec.rb

@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Scheduler::AutoCloseRegistrationsScheduler do
+  subject { described_class.new }
+
+  describe '#perform' do
+    let(:moderator_activity_date) { Time.now.utc }
+
+    before do
+      Fabricate(:user, role: UserRole.find_by(name: 'Owner'), current_sign_in_at: 10.years.ago)
+      Fabricate(:user, role: UserRole.find_by(name: 'Moderator'), current_sign_in_at: moderator_activity_date)
+    end
+
+    context 'when registrations are open' do
+      before do
+        Setting.registrations_mode = 'open'
+      end
+
+      context 'when a moderator has logged in recently' do
+        let(:moderator_activity_date) { Time.now.utc }
+
+        it 'does not change registrations mode' do
+          expect { subject.perform }.to_not change(Setting, :registrations_mode)
+        end
+      end
+
+      context 'when a moderator has not recently signed in' do
+        let(:moderator_activity_date) { 1.year.ago }
+
+        it 'changes registrations mode from open to approved' do
+          expect { subject.perform }.to change(Setting, :registrations_mode).from('open').to('approved')
+        end
+      end
+    end
+
+    context 'when registrations are closed' do
+      before do
+        Setting.registrations_mode = 'none'
+      end
+
+      context 'when a moderator has logged in recently' do
+        let(:moderator_activity_date) { Time.now.utc }
+
+        it 'does not change registrations mode' do
+          expect { subject.perform }.to_not change(Setting, :registrations_mode)
+        end
+      end
+
+      context 'when a moderator has not recently signed in' do
+        let(:moderator_activity_date) { 1.year.ago }
+
+        it 'does not change registrations mode' do
+          expect { subject.perform }.to_not change(Setting, :registrations_mode)
+        end
+      end
+    end
+  end
+end