Skip to content

Commit

Permalink
FEATURE: Allow admins to lock users from TL3 promotion/demotion
Browse files Browse the repository at this point in the history
Also, update the display logic for the leader promotion screen to
account for the demotion grace period.
  • Loading branch information
riking authored and SamSaffron committed Sep 30, 2014
1 parent 41d53c7 commit c8111ad
Show file tree
Hide file tree
Showing 12 changed files with 121 additions and 18 deletions.
18 changes: 18 additions & 0 deletions app/assets/javascripts/admin/models/admin_user.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,24 @@ Discourse.AdminUser = Discourse.User.extend({
this.set('trustLevel.id', this.get('originalTrustLevel'));
},

lockTrustLevel: function(locked) {
Discourse.ajax("/admin/users/" + this.id + "/trust_level_lock", {
type: 'PUT',
data: { locked: !!locked }
}).then(function() {
// succeeded
window.location.reload();
}, function(e) {
// failure
var error;
if (e.responseJSON && e.responseJSON.errors) {
error = e.responseJSON.errors[0];
}
error = error || I18n.t('admin.user.trust_level_change_failed', { error: "http: " + e.status + " - " + e.body });
bootbox.alert(error);
});
},

isSuspended: Em.computed.equal('suspended', true),
canSuspend: Em.computed.not('staff'),

Expand Down
6 changes: 4 additions & 2 deletions app/assets/javascripts/admin/models/leader_requirements.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ Discourse.LeaderRequirements = Discourse.Model.extend({
flagged_posts: this.get('num_flagged_posts') <= this.get('max_flagged_posts'),
flagged_by_users: this.get('num_flagged_by_users') <= this.get('max_flagged_by_users'),
likes_given: this.get('num_likes_given') >= this.get('min_likes_given'),
likes_received: this.get('num_likes_received') >= this.get('min_likes_received')
likes_received: this.get('num_likes_received') >= this.get('min_likes_received'),
level_locked: this.get('trust_level_locked')
};
}.property('days_visited', 'min_days_visited',
'num_topics_replied_to', 'min_topics_replied_to',
Expand All @@ -29,5 +30,6 @@ Discourse.LeaderRequirements = Discourse.Model.extend({
'posts_read_all_time', 'min_posts_read_all_time',
'num_flagged_by_users', 'max_flagged_by_users',
'num_likes_given', 'min_likes_given',
'num_likes_received', 'min_likes_received')
'num_likes_received', 'min_likes_received',
'trust_level_locked')
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,15 @@
Discourse.AdminUserLeaderRequirementsRoute = Discourse.Route.extend({
model: function() {
return this.modelFor('adminUser');
},

actions: {
lock_trust_level: function() {
this.modelFor('adminUser').lockTrustLevel(true);
},

unlock_trust_level: function() {
this.modelFor('adminUser').lockTrustLevel(false);
}
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,50 @@
<td>{{num_likes_received}}</td>
<td>{{min_likes_received}}</td>
</tr>
<tr>
<th>{{i18n admin.user.tl3_requirements.trust_level_locked}}</th>
<td><i {{bind-attr class=":fa met.level_locked:fa-lock:fa-unlock"}}></i></td>
{{#if trust_level_locked}}
<td>{{i18n yes_value}}</td>
<td><a class="btn" {{action unlock_trust_level}}>{{i18n admin.user.tl3_requirements.unlock_tl}}</a></td>
{{else}}
<td>{{i18n no_value}}</td>
<td><a class="btn" {{action lock_trust_level}}>{{i18n admin.user.tl3_requirements.lock_tl}}</a></td>
{{/if}}
</tr>
</tbody>
</table>
{{/with}}

<br/>
<p>
{{#if leaderRequirements.requirements_met}}
<i class="fa fa-check"></i> {{i18n admin.user.tl3_requirements.qualifies}}
{{#unless isLeader}}
{{i18n admin.user.tl3_requirements.will_be_promoted}}
{{/unless}}
{{else}}
<i class="fa fa-times"></i> {{i18n admin.user.tl3_requirements.does_not_qualify}}
{{#if suspended}}
{{i18n user.suspended_notice date="suspendedTillDate"}}
{{#if isLeader}}
{{#if leaderRequirements.requirements_lost}}
{{! tl implicitly not locked }}
{{#if leaderRequirements.on_grace_period}}
<i class="fa fa-times"></i> {{i18n admin.user.tl3_requirements.on_grace_period}}
{{else}} {{! not on grace period }}
<i class="fa fa-times"></i> {{i18n admin.user.tl3_requirements.does_not_qualify}}
{{i18n admin.user.tl3_requirements.will_be_demoted}}
{{/if}}
{{else}} {{! requirements not lost - remains leader }}
{{#if leaderRequirements.trust_level_locked}}
<i class="fa fa-lock"></i> {{i18n admin.user.tl3_requirements.locked_will_not_be_demoted}}
{{else}} {{! tl not locked }}
<i class="fa fa-check"></i> {{i18n admin.user.tl3_requirements.qualifies}}
{{/if}}
{{/if}}
{{else}} {{! is not leader }}
{{#if leaderRequirements.requirements_met}}
{{! met & not leader - will be promoted}}
<i class="fa fa-check"></i> {{i18n admin.user.tl3_requirements.qualifies}}
{{i18n admin.user.tl3_requirements.will_be_promoted}}
{{else}} {{! requirements not met - remains regular }}
{{#if leaderRequirements.trust_level_locked}}
<i class="fa fa-lock"></i> {{i18n admin.user.tl3_requirements.locked_will_not_be_promoted}}
{{else}}
<i class="fa fa-times"></i> {{i18n admin.user.tl3_requirements.does_not_qualify}}
{{/if}}
{{/if}}
{{/if}}
</p>
Expand Down
14 changes: 14 additions & 0 deletions app/controllers/admin/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Admin::UsersController < Admin::AdminController
:block,
:unblock,
:trust_level,
:trust_level_lock,
:add_group,
:remove_group,
:primary_group,
Expand Down Expand Up @@ -134,6 +135,19 @@ def trust_level
render_json_error(e.message)
end

def trust_level_lock
guardian.ensure_can_change_trust_level!(@user)

new_lock = params[:locked]
unless new_lock =~ /t|f|true|false/
return render_json_error I18n.t('errors.invalid_boolaen')
end

@user.trust_level_locked = !!(new_lock =~ /t|true/)
@user.save
render nothing: true
end

def approve
guardian.ensure_can_approve!(@user)
@user.approve(current_user)
Expand Down
6 changes: 1 addition & 5 deletions app/jobs/scheduled/leader_promotions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ def execute(args)
demoted_user_ids = []
User.real.where(trust_level: TrustLevel[3]).find_each do |u|
# Don't demote too soon after being promoted
next if UserHistory.for(u, :auto_trust_level_change)
.where('created_at >= ?', SiteSetting.tl3_promotion_min_duration.to_i.days.ago)
.where(previous_value: TrustLevel[2].to_s)
.where(new_value: TrustLevel[3].to_s)
.exists?
next if user.on_leader_grace_period?

if Promotion.tl3_lost?(u)
demoted_user_ids << u.id
Expand Down
13 changes: 12 additions & 1 deletion app/models/trust_level3_requirements.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ class TrustLevel3Requirements
:posts_read_all_time, :min_posts_read_all_time,
:num_flagged_posts, :max_flagged_posts,
:num_likes_given, :min_likes_given,
:num_likes_received, :min_likes_received
:num_likes_received, :min_likes_received,
:trust_level_locked, :on_grace_period

def initialize(user)
@user = user
end

def requirements_met?
return false if trust_level_locked
!@user.suspended? &&
days_visited >= min_days_visited &&
num_topics_replied_to >= min_topics_replied_to &&
Expand All @@ -37,6 +39,7 @@ def requirements_met?
end

def requirements_lost?
return false if trust_level_locked
@user.suspended? ||
days_visited < min_days_visited * LOW_WATER_MARK ||
num_topics_replied_to < min_topics_replied_to * LOW_WATER_MARK ||
Expand All @@ -50,6 +53,14 @@ def requirements_lost?
num_likes_received < min_likes_received * LOW_WATER_MARK
end

def trust_level_locked
@user.trust_level_locked
end

def on_grace_period
@user.on_leader_grace_period?
end

def days_visited
@user.user_visits.where("visited_at > ? and posts_read > 0", TIME_PERIOD.days.ago).count
end
Expand Down
8 changes: 8 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,14 @@ def leader_requirements
@lq ||= TrustLevel3Requirements.new(self)
end

def on_leader_grace_period?
UserHistory.for(self, :auto_trust_level_change)
.where('created_at >= ?', SiteSetting.tl3_promotion_min_duration.to_i.days.ago)
.where(previous_value: TrustLevel[2].to_s)
.where(new_value: TrustLevel[3].to_s)
.exists?
end

def should_be_redirected_to_top
redirected_to_top_reason.present?
end
Expand Down
6 changes: 6 additions & 0 deletions app/serializers/trust_level3_requirements_serializer.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
class TrustLevel3RequirementsSerializer < ApplicationSerializer
attributes :time_period,
:requirements_met,
:requirements_lost,
:trust_level_locked, :on_grace_period,
:days_visited, :min_days_visited,
:num_topics_replied_to, :min_topics_replied_to,
:topics_viewed, :min_topics_viewed,
Expand All @@ -19,4 +21,8 @@ def time_period
def requirements_met
object.requirements_met?
end

def requirements_lost
object.requirements_lost?
end
end
9 changes: 8 additions & 1 deletion config/locales/client.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1975,9 +1975,16 @@ en:
flagged_by_users: "Users Who Flagged"
likes_given: "Likes Given"
likes_received: "Likes Received"
trust_level_locked: "Trust Level Locked"
lock_tl: "Lock"
unlock_tl: "Unlock"
qualifies: "Qualifies for trust level 3."
will_be_promoted: "Will be promoted within 24 hours."
does_not_qualify: "Doesn't qualify for trust level 3."
will_be_promoted: "Will be promoted within 24 hours."
will_be_demoted: "Will be demoted within 24 hours."
on_grace_period: "Currently in promotion grace period, will not be demoted."
locked_will_not_be_promoted: "Trust level locked. Will never be promoted."
locked_will_not_be_demoted: "Trust level locked. Will never be demoted."
sso:
title: "Single Sign On"
external_id: "External ID"
Expand Down
1 change: 1 addition & 0 deletions config/locales/server.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ en:
errors:
messages:
too_long_validation: "is limited to %{max} characters; you entered %{length}."
invalid_boolean: "Invalid boolean."
embed:
load_from_remote: "There was an error loading that post."

Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
put "block"
put "unblock"
put "trust_level"
put "trust_level_lock"
put "primary_group"
post "groups" => "users#add_group", constraints: AdminConstraint.new
delete "groups/:group_id" => "users#remove_group", constraints: AdminConstraint.new
Expand Down

0 comments on commit c8111ad

Please sign in to comment.