mirror of https://github.com/zulip/zulip.git
Add administrative panel to allow for user deactivations etc.
We now show a list of users and allow you to deactivate a user using the same process as `python manage.py deactivate_user`. We add a new menu item accessible from the gear icon which will eventually have much more than just this, but we have a good start here. Here we also add a property to UserProfile which determines whether you're eligible to access the administration panel, and then have code which shows the menu option if so. This introduces a new JS file, admin.js. (imported from commit 52296fdedb46b4f32d541df43022ffccfb277297)
This commit is contained in:
parent
78d8153e6b
commit
ecc42bc9f8
|
@ -0,0 +1,70 @@
|
|||
var admin = (function () {
|
||||
|
||||
var exports = {};
|
||||
|
||||
function populate_users () {
|
||||
var tb = $("#admin_users_table");
|
||||
tb.empty();
|
||||
page_params.people_list.sort(function (a, b) {
|
||||
return a.full_name.toLowerCase().localeCompare(b.full_name.toLowerCase());
|
||||
});
|
||||
|
||||
$.each(page_params.people_list, function (index, person) {
|
||||
if (person.email.indexOf("+") === -1 && person.email.indexOf("-bot@") === -1) {
|
||||
tb.append(templates.render("admin_user_list", {person: person}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
exports.setup_page = function () {
|
||||
populate_users();
|
||||
|
||||
$("#admin_users_table").on("click", ".activation_toggle_button", function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
$(".active_user_row").removeClass("active_user_row");
|
||||
|
||||
// Go up the tree until we find the user row, then grab the email element
|
||||
$(e.target).closest(".user_row").addClass("active_user_row");
|
||||
|
||||
var user_name = $(".active_user_row").find('.user_name').text();
|
||||
var email = $(".active_user_row").find('.email').text();
|
||||
|
||||
$("#deactivation_modal .email").text(email);
|
||||
$("#deactivation_modal .user_name").text(user_name);
|
||||
$("#deactivation_modal").modal("show");
|
||||
});
|
||||
|
||||
$("#do_deactivate_button").click(function (e) {
|
||||
if ($("#deactivation_modal .email").html() !== $(".active_user_row").find('.email').text()) {
|
||||
blueslip.error("User deactivation canceled due to non-matching fields.");
|
||||
ui.report_message("Deactivation encountered an error. Please reload and try again.",
|
||||
$("#home-error"), 'alert-error');
|
||||
}
|
||||
$("#deactivation_modal").modal("hide");
|
||||
$(".active_user_row button").prop("disabled", true).text("Working…");
|
||||
$.ajax({
|
||||
type: 'DELETE',
|
||||
url: '/json/users/' + $(".active_user_row").find('.email').text(),
|
||||
error: function (xhr, error_type) {
|
||||
if (xhr.status.toString().charAt(0) === "4") {
|
||||
$(".active_user_row button").closest("td").html(
|
||||
$("<p>").addClass("text-error").text($.parseJSON(xhr.responseText).msg)
|
||||
);
|
||||
} else {
|
||||
$(".active_user_row button").text("Failed!");
|
||||
}
|
||||
},
|
||||
success: function () {
|
||||
$(".active_user_row button").removeClass("btn-danger").text("Deactivated");
|
||||
$(".active_user_row span").wrap("<strike>");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
return exports;
|
||||
|
||||
}());
|
|
@ -130,6 +130,9 @@ function do_hashchange() {
|
|||
case "#subscriptions":
|
||||
ui.change_tab_to("#subscriptions");
|
||||
break;
|
||||
case "#administration":
|
||||
ui.change_tab_to("#administration");
|
||||
break;
|
||||
case "#settings":
|
||||
ui.change_tab_to("#settings");
|
||||
break;
|
||||
|
|
|
@ -858,6 +858,9 @@ $(function () {
|
|||
// Whenever the streams page comes up (from anywhere), populate it.
|
||||
subs_link.on('shown', subs.setup_page);
|
||||
|
||||
var admin_link = $('#gear-menu a[href="#administration"]');
|
||||
admin_link.on('shown', admin.setup_page);
|
||||
|
||||
$('#pw_change_link').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
$('#pw_change_link').hide();
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
{{#with person}}
|
||||
<tr class="user_row" id="user_{{email}}">
|
||||
<td>
|
||||
<span class="user_name">{{full_name}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="email">{{email}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn activation_toggle_button btn-danger"
|
||||
{{#inactive}}disabled{{/inactive}}
|
||||
type="button" name="activation_toggle">
|
||||
{{#inactive}}
|
||||
Reactivate
|
||||
{{/inactive}}
|
||||
{{^inactive}}
|
||||
Deactivate
|
||||
{{/inactive}}
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{/with}}
|
|
@ -0,0 +1,32 @@
|
|||
{# Administration panel #}
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="administration">
|
||||
<h1>Administration</h1>
|
||||
<h2>Users</h2>
|
||||
<table class="table table-condensed table-striped">
|
||||
<tbody id="admin_users_table">
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th>Actions</th>
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="deactivation_modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="deactivation_modal_label" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="deactivation_modal_label">Deactivate <span class="email"></span></h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>By deactivating <strong><span class="user_name"></span></strong> <<span class="email"></span>>, they will be logged out of Zulip immediately.</p>
|
||||
<p>Their password will be cleared from our systems, and any bots they maintain will be disabled.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
|
||||
<button class="btn btn-danger" id="do_deactivate_button">Deactivate now</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -51,6 +51,11 @@ var page_params = {{ page_params }};
|
|||
<div class="tab-pane" id="subscriptions">
|
||||
{% include "zerver/subscriptions.html" %}
|
||||
</div>
|
||||
{% if show_admin %}
|
||||
<div class="tab-pane" id="administration">
|
||||
{% include "zephyr/administration.html" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="tab-pane" id="settings">
|
||||
{% include "zerver/settings.html" %}
|
||||
</div>
|
||||
|
|
|
@ -58,6 +58,13 @@
|
|||
</a>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
{% if show_admin %}
|
||||
<li title="Administration">
|
||||
<a href="#administration" role="button" data-toggle="tab">
|
||||
<i class="icon-vector-bolt"></i> Administration
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if show_invites %}
|
||||
<li title="Invite coworkers to Zulip">
|
||||
<a href="#invite-user" role="button" data-toggle="modal">
|
||||
|
|
|
@ -26,7 +26,7 @@ var globals =
|
|||
+ ' invite ui util activity timerender MessageList blueslip unread stream_list'
|
||||
+ ' onboarding message_edit tab_bar emoji popovers navigate message_tour'
|
||||
+ ' avatar feature_flags search_suggestion referral stream_color Dict'
|
||||
+ ' Filter summary'
|
||||
+ ' Filter summary admin'
|
||||
|
||||
// colorspace.js
|
||||
+ ' colorspace'
|
||||
|
|
|
@ -150,6 +150,14 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
|
|||
|
||||
objects = UserManager()
|
||||
|
||||
@property
|
||||
def show_admin(self):
|
||||
# Logic to determine if the user should see the administration tools.
|
||||
# Do NOT use this to check if a user is authorized to perform a specific action!
|
||||
return 0 < self.userobjectpermission_set.filter(
|
||||
content_type__name="realm",
|
||||
permission__codename="administer").count()
|
||||
|
||||
def __repr__(self):
|
||||
return (u"<UserProfile: %s %s>" % (self.email, self.realm)).encode("utf-8")
|
||||
def __str__(self):
|
||||
|
|
|
@ -659,7 +659,8 @@ def home(request):
|
|||
'nofontface': is_buggy_ua(request.META["HTTP_USER_AGENT"]),
|
||||
'show_debug':
|
||||
settings.DEBUG and ('show_debug' in request.GET),
|
||||
'show_invites': show_invites
|
||||
'show_invites': show_invites,
|
||||
'show_admin': user_profile.show_admin,
|
||||
},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
|
|
@ -378,6 +378,7 @@ JS_SPECS = {
|
|||
'js/compose_fade.js',
|
||||
'js/compose.js',
|
||||
'js/stream_color.js',
|
||||
'js/admin.js',
|
||||
'js/subs.js',
|
||||
'js/message_edit.js',
|
||||
'js/ui.js',
|
||||
|
|
Loading…
Reference in New Issue