diff --git a/app/controllers/ajax/moderation_controller.rb b/app/controllers/ajax/moderation_controller.rb index 8bd822e6..f2149885 100644 --- a/app/controllers/ajax/moderation_controller.rb +++ b/app/controllers/ajax/moderation_controller.rb @@ -109,13 +109,15 @@ class Ajax::ModerationController < AjaxController params.require :user params.require :ban params.require :permaban + params.require :duration + params.require :duration_unit - reason = params[:reason] + duration = params[:duration].to_s + duration_unit = params[:duration_unit].to_s + reason = params[:reason].to_s target = User.find_by_screen_name!(params[:user]) - unban = params[:ban] == "0" - perma = params[:permaban] == "1" - - buntil = DateTime.strptime params[:until], "%m/%d/%Y %I:%M %p" unless unban || perma + unban = params[:ban] == '0' + perma = params[:permaban] == '1' if !unban && target.has_role?(:administrator) @response[:status] = :nopriv @@ -128,11 +130,11 @@ class Ajax::ModerationController < AjaxController @response[:message] = I18n.t('messages.moderation.ban.unban') @response[:success] = true elsif perma - target.ban nil, reason + target.ban nil, nil, reason, current_user @response[:message] = I18n.t('messages.moderation.ban.perma') else - target.ban buntil, reason - @response[:message] = I18n.t('messages.moderation.ban.temp', date: buntil.to_s) + target.ban duration, duration_unit, reason, current_user + @response[:message] = "User banned for #{duration} #{duration_unit}" end target.save! @@ -162,7 +164,7 @@ class Ajax::ModerationController < AjaxController @response[:checked] = status type = params[:type].downcase - target_role = {"admin" => "administrator"}.fetch(type, type).to_sym + target_role = {'admin' => 'administrator'}.fetch(type, type).to_sym if status target_user.add_role target_role diff --git a/app/models/user.rb b/app/models/user.rb index 0c23c4cd..bbcc8f6b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -223,21 +223,24 @@ class User < ApplicationRecord end # endregion - # forwards fill def banned? - self.permanently_banned? or ((not self.banned_until.nil?) and self.banned_until >= DateTime.current) + self.user_bans.current.any? end def unban - self.update(permanently_banned: false, ban_reason: nil, banned_until: nil) + self.user_bans.current.update(expires_at: DateTime.now) end - def ban(buntil=nil, reason=nil) - if buntil == nil - self.update(permanently_banned: true, ban_reason: reason) - else - self.update(permanently_banned: false, banned_until: buntil, ban_reason: reason) - end + # Bans a user. + # @param duration [Fixnum, nil] Ban duration + # @param duration_unit [String, nil] Unit for the duration parameter. Accepted units: hours, days, weeks, months + # @param reason [String] Reason for the ban. This is displayed to the user. + # @param banned_by [User] User who instated the ban + def ban(duration, duration_unit = 'hours', reason = nil, banned_by = nil) + raise Errors::InvalidBanDuration unless %w[hours days weeks months].include? duration_unit + + expiry = duration && DateTime.now + duration.public_send(duration_unit) + self.user_bans.create(expires_at: expiry, reason: reason, banned_by: banned_by) end def can_export? diff --git a/app/models/user_ban.rb b/app/models/user_ban.rb index ee143412..e7b3c1fe 100644 --- a/app/models/user_ban.rb +++ b/app/models/user_ban.rb @@ -1,4 +1,6 @@ class UserBan < ApplicationRecord belongs_to :user belongs_to :banned_by, class_name: 'User' + + scope :current, -> { where('expires_at IS NULL or expires_at < NOW()') } end diff --git a/lib/errors.rb b/lib/errors.rb new file mode 100644 index 00000000..c13228a8 --- /dev/null +++ b/lib/errors.rb @@ -0,0 +1,7 @@ +module Errors + class Base < StandardError + end + + class InvalidBanDuration < Base + end +end \ No newline at end of file