mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 17:46:05 -05:00
FEATURE: Allow admins to lock users from TL3 promotion/demotion
Also, update the display logic for the leader promotion screen to account for the demotion grace period.
This commit is contained in:
parent
41d53c7222
commit
c8111ada6e
12 changed files with 121 additions and 18 deletions
|
@ -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'),
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
@ -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')
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -17,6 +17,7 @@ class Admin::UsersController < Admin::AdminController
|
|||
:block,
|
||||
:unblock,
|
||||
:trust_level,
|
||||
:trust_level_lock,
|
||||
:add_group,
|
||||
:remove_group,
|
||||
:primary_group,
|
||||
|
@ -134,6 +135,19 @@ class Admin::UsersController < Admin::AdminController
|
|||
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)
|
||||
|
|
|
@ -8,11 +8,7 @@ module Jobs
|
|||
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
|
||||
|
|
|
@ -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 &&
|
||||
|
@ -37,6 +39,7 @@ class TrustLevel3Requirements
|
|||
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 ||
|
||||
|
@ -50,6 +53,14 @@ class TrustLevel3Requirements
|
|||
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
|
||||
|
|
|
@ -574,6 +574,14 @@ class User < ActiveRecord::Base
|
|||
@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
|
||||
|
|
|
@ -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,
|
||||
|
@ -19,4 +21,8 @@ class TrustLevel3RequirementsSerializer < ApplicationSerializer
|
|||
def requirements_met
|
||||
object.requirements_met?
|
||||
end
|
||||
|
||||
def requirements_lost
|
||||
object.requirements_lost?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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."
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ Discourse::Application.routes.draw do
|
|||
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
|
||||
|
|
Loading…
Reference in a new issue