Merge pull request #6037 from jumpserver/pr@dev@perf_public_key_setting

perf: 优化公钥设置,并删掉一部分不用的 html
This commit is contained in:
老广 2021-04-27 05:07:53 -05:00 committed by GitHub
commit c0875f6a87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 338 additions and 2928 deletions

File diff suppressed because it is too large Load Diff

View File

@ -121,7 +121,11 @@ class TerminalSettingSerializer(serializers.Serializer):
('50', '50'), ('50', '50'),
) )
TERMINAL_PASSWORD_AUTH = serializers.BooleanField(required=False, label=_('Password auth')) TERMINAL_PASSWORD_AUTH = serializers.BooleanField(required=False, label=_('Password auth'))
TERMINAL_PUBLIC_KEY_AUTH = serializers.BooleanField(required=False, label=_('Public key auth')) TERMINAL_PUBLIC_KEY_AUTH = serializers.BooleanField(
required=False, label=_('Public key auth'),
help_text=_('Tips: If use other auth method, like AD/LDAP, you should disable this to '
'avoid being able to log in after deleting')
)
TERMINAL_ASSET_LIST_SORT_BY = serializers.ChoiceField(SORT_BY_CHOICES, required=False, label=_('List sort by')) TERMINAL_ASSET_LIST_SORT_BY = serializers.ChoiceField(SORT_BY_CHOICES, required=False, label=_('List sort by'))
TERMINAL_ASSET_LIST_PAGE_SIZE = serializers.ChoiceField(PAGE_SIZE_CHOICES, required=False, label=_('List page size')) TERMINAL_ASSET_LIST_PAGE_SIZE = serializers.ChoiceField(PAGE_SIZE_CHOICES, required=False, label=_('List page size'))
TERMINAL_SESSION_KEEP_DURATION = serializers.IntegerField( TERMINAL_SESSION_KEEP_DURATION = serializers.IntegerField(

View File

@ -5,6 +5,7 @@ import uuid
import base64 import base64
import string import string
import random import random
import datetime
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
@ -32,6 +33,9 @@ logger = get_logger(__file__)
class AuthMixin: class AuthMixin:
date_password_last_updated: datetime.datetime
is_local: bool
@property @property
def password_raw(self): def password_raw(self):
raise AttributeError('Password raw is not a readable attribute') raise AttributeError('Password raw is not a readable attribute')
@ -62,8 +66,9 @@ class AuthMixin:
def can_update_ssh_key(self): def can_update_ssh_key(self):
return self.can_use_ssh_key_login() return self.can_use_ssh_key_login()
def can_use_ssh_key_login(self): @staticmethod
return self.is_local and settings.TERMINAL_PUBLIC_KEY_AUTH def can_use_ssh_key_login():
return settings.TERMINAL_PUBLIC_KEY_AUTH
def is_public_key_valid(self): def is_public_key_valid(self):
""" """

View File

@ -101,7 +101,8 @@ class UserProfileSerializer(UserSerializer):
class Meta(UserSerializer.Meta): class Meta(UserSerializer.Meta):
fields = UserSerializer.Meta.fields + [ fields = UserSerializer.Meta.fields + [
'public_key_comment', 'public_key_hash_md5', 'admin_or_audit_orgs', 'current_org_roles', 'public_key_comment', 'public_key_hash_md5',
'admin_or_audit_orgs', 'current_org_roles',
'guide_url', 'user_all_orgs' 'guide_url', 'user_all_orgs'
] ]
read_only_fields = [ read_only_fields = [
@ -164,6 +165,7 @@ class ChangeUserPasswordSerializer(serializers.ModelSerializer):
model = User model = User
fields = ['password'] fields = ['password']
class ResetOTPSerializer(serializers.Serializer): class ResetOTPSerializer(serializers.Serializer):
msg = serializers.CharField(read_only=True) msg = serializers.CharField(read_only=True)

View File

@ -34,6 +34,7 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
is_expired = serializers.BooleanField(read_only=True, label=_('Is expired')) is_expired = serializers.BooleanField(read_only=True, label=_('Is expired'))
can_update = serializers.SerializerMethodField(label=_('Can update')) can_update = serializers.SerializerMethodField(label=_('Can update'))
can_delete = serializers.SerializerMethodField(label=_('Can delete')) can_delete = serializers.SerializerMethodField(label=_('Can delete'))
can_public_key_auth = serializers.ReadOnlyField(source='can_use_ssh_key_login')
org_roles = serializers.ListField( org_roles = serializers.ListField(
label=_('Organization role name'), allow_null=True, required=False, label=_('Organization role name'), allow_null=True, required=False,
child=serializers.ChoiceField(choices=ORG_ROLE.choices), default=["User"] child=serializers.ChoiceField(choices=ORG_ROLE.choices), default=["User"]
@ -48,7 +49,7 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
'password', 'email', 'public_key', 'wechat', 'phone', 'mfa_level', 'mfa_enabled', 'password', 'email', 'public_key', 'wechat', 'phone', 'mfa_level', 'mfa_enabled',
'mfa_level_display', 'mfa_force_enabled', 'role_display', 'org_role_display', 'mfa_level_display', 'mfa_force_enabled', 'role_display', 'org_role_display',
'total_role_display', 'comment', 'source', 'is_valid', 'is_expired', 'total_role_display', 'comment', 'source', 'is_valid', 'is_expired',
'is_active', 'created_by', 'is_first_login', 'is_active', 'created_by', 'is_first_login', 'can_public_key_auth',
'password_strategy', 'date_password_last_updated', 'date_expired', 'password_strategy', 'date_password_last_updated', 'date_expired',
'avatar_url', 'source_display', 'date_joined', 'last_login' 'avatar_url', 'source_display', 'date_joined', 'last_login'
] ]

View File

@ -1,88 +0,0 @@
{% extends '_base_create_update.html' %}
{% load i18n %}
{% load static %}
{% load bootstrap3 %}
{% block form %}
{% if form.non_field_errors %}
<div class="alert alert-danger">
{{ form.non_field_errors }}
</div>
{% endif %}
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
{% csrf_token %}
<h3>{% trans 'Account' %}</h3>
{% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.username layout="horizontal" %}
{% bootstrap_field form.email layout="horizontal" %}
{% bootstrap_field form.groups layout="horizontal" %}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Auth' %}</h3>
{% block password %}{% endblock %}
{% bootstrap_field form.mfa_level layout="horizontal" %}
{% bootstrap_field form.source layout="horizontal" %}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Security and Role' %}</h3>
{% bootstrap_field form.role layout="horizontal" %}
<div class="form-group {% if form.date_expired.errors %} has-error {% endif %}" id="date_5">
<label for="{{ form.date_expired.id_for_label }}" class="col-sm-2 control-label">{{ form.date_expired.label }}</label>
<div class="col-sm-9">
<div class="input-group date">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
{% if form.errors %}
<input id="{{ form.date_expired.id_for_label }}" name="{{ form.date_expired.html_name }}" type="text" class="form-control" value="{{ form.date_expired.value }}">
{% else %}
<input id="{{ form.date_expired.id_for_label }}" name="{{ form.date_expired.html_name }}" type="text" class="form-control" value="{{ form.date_expired.value|date:'Y-m-d H:i' }}">
{% endif %}
</div>
<span class="help-block ">{{ form.date_expired.errors }}</span>
</div>
</div>
<div class="hr-line-dashed"></div>
<h3>{% trans 'Profile' %}</h3>
{% bootstrap_field form.phone layout="horizontal" %}
{% bootstrap_field form.wechat layout="horizontal" %}
{% bootstrap_field form.comment layout="horizontal" %}
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
</div>
</div>
</form>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.zh-CN.min.js' %}"></script>
<script type="text/javascript" src='{% static "js/plugins/daterangepicker/moment.min.js" %}'></script>
<script type="text/javascript" src='{% static "js/plugins/daterangepicker/daterangepicker.min.js" %}'></script>
<link rel="stylesheet" type="text/css" href={% static "css/plugins/daterangepicker/daterangepicker.css" %} />
<script>
var role_id = '#' + '{{ form.role.id_for_label }}';
var groups_id = '#' + '{{ form.groups.id_for_label }}';
function fieldDisplay(){
var role = $(role_id).val();
if (role === 'Auditor'){
$(groups_id).closest('.form-group').addClass('hidden');
}
else {
$(groups_id).closest('.form-group').removeClass('hidden');
}}
$(document).ready(function () {
$('.select2').select2();
initDateRangePicker('#id_date_expired');
var mfa_radio = $('#id_mfa_level');
mfa_radio.addClass("form-inline");
mfa_radio.children().css("margin-right","15px");
fieldDisplay()
}).on('change', role_id, function(){
fieldDisplay();
})
</script>
{% endblock %}

View File

@ -1,70 +0,0 @@
{% extends '_base_create_update.html' %}
{% load static %}
{% load bootstrap3 %}
{% load i18n %}
{% block form %}
<div class="ydxbd" id="formlists" style="display: block;">
<p id="tags_p" class="mgl-5 c02">{% trans 'Select properties that need to be modified' %}</p>
<div class="tagBtnList">
<a class="label label-primary" id="change_all" value="1">{% trans 'Select all' %}</a>
{% for field in form %}
{% if field.name != 'users' %}
<a data-id="{{ field.id_for_label }}" class="label label-default label-primary field-tag" value="1">{{ field.label }}</a>
{% endif %}
{% endfor %}
</div>
</div>
<form method="post" class="form-horizontal" id="add_form">
{% csrf_token %}
{% bootstrap_form form layout="horizontal" %}
<div class="form-group abc">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
<button class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
</div>
</div>
</form>
{% endblock %}
{% block custom_foot_js %}
<script>
$(document).ready(function () {
$('.select2').select2();
usersSelect2Init('.users-select2')
}).on('click', '.field-tag', function() {
changeField(this);
}).on('click', '#change_all', function () {
var tag_fields = $('.field-tag');
var $this = $(this);
var active = '1';
if ($this.attr('value') == '0'){
active = '0';
$this.attr('value', '1').addClass('label-primary')
} else {
active = '1';
$this.attr('value', '0').removeClass('label-primary')
}
$.each(tag_fields, function (k, v) {
changeField(v, active)
})
});
function changeField(obj, active) {
var $this = $(obj);
var field_id = $this.data('id');
if (!active) {
active = $this.attr('value');
}
if (active == '0') {
$this.attr('value', '1').addClass('label-primary');
var form_groups = $('#add_form .form-group');
form_groups.filter(':has(#' + field_id + ')').show().find('select,input').prop('disabled', false)
} else {
$this.attr('value', '0').removeClass('label-primary');
var form_groups = $('#add_form .form-group');
form_groups.filter(':has(#' + field_id + ')').hide().find('select,input').prop('disabled', true)
}
}
</script>
{% endblock %}

View File

@ -1,100 +0,0 @@
{% extends 'users/_user.html' %}
{% load i18n %}
{% load bootstrap3 %}
{% block user_template_title %}{% trans "Create user" %}{% endblock %}
{% block password %}
{% bootstrap_field form.password_strategy layout="horizontal" %}
{% bootstrap_field form.password layout="horizontal" %}
{# 密码popover #}
<div id="container">
<div class="popover fade bottom in" role="tooltip" id="popover777" style=" display: none; width:260px;">
<div class="arrow" style="left: 50%;"></div>
<h3 class="popover-title" style="display: none;"></h3>
<h4>{% trans 'Your password must satisfy' %}</h4><div id="id_password_rules" style="color: #908a8a; margin-left:20px; font-size:15px;"></div>
<h4 style="margin-top: 10px;">{% trans 'Password strength' %}</h4><div id="id_progress"></div>
<div class="popover-content"></div>
</div>
</div>
<script>
function passwordCheck() {
if ($('#id_password').length != 1) {
return
}
var el = $('#id_password_rules'),
idPassword = $('#id_password'),
idPopover = $('#popover777'),
container = $('#container'),
progress = $('#id_progress'),
password_check_rules = {{ password_check_rules|safe }},
minLength = 6,
top = idPassword.offset().top - $('.navbar').outerHeight(true) - $('.page-heading').outerHeight(true) -77 + 34,
left = 377,
i18n_fallback = {
"veryWeak": "{% trans 'Very weak' %}",
"weak": "{% trans 'Weak' %}",
"normal": "{% trans 'Normal' %}",
"medium": "{% trans 'Medium' %}",
"strong": "{% trans 'Strong' %}",
"veryStrong": "{% trans 'Very strong' %}"
};
$.each(password_check_rules, function (idx, rules) {
if(rules.key === 'id_security_password_min_length'){
minLength = rules.value
}
});
// 初始化popover
initPopover(container, progress, idPassword, el, password_check_rules, i18n_fallback);
// 监听事件
idPassword.on('focus', function () {
idPopover.css('top', top);
idPopover.css('left', left);
idPopover.css('display', 'block');
});
idPassword.on('blur', function () {
idPopover.css('display', 'none');
});
idPassword.on('keyup', function(){
var password = idPassword.val();
checkPasswordRules(password, minLength);
});
}
var password_strategy_radio_input = 'input[type=radio][name=password_strategy]';
function passwordStrategyFieldsDisplay(){
var val = $('input:radio[name="password_strategy"]:checked').val();
if(val === '0'){
$('#id_password').parents('.form-group').addClass('hidden')
}else {
$('#id_password').parents('.form-group').removeClass('hidden')
}
}
$(document).ready(function () {
passwordCheck();
passwordStrategyFieldsDisplay()
}).on('change', password_strategy_radio_input, function(){
passwordStrategyFieldsDisplay()
})
.on("submit", "form", function (evt) {
evt.preventDefault();
var the_url = '{% url 'api-users:user-list' %}';
var redirect_to = '{% url "users:user-list" %}';
var method = "POST";
var form = $("form");
var data = form.serializeObject();
objectAttrsIsList(data, ['groups']);
objectAttrsIsDatetime(data,['date_expired']);
var props = {
url: the_url,
data: data,
method: method,
form: form,
redirect_to: redirect_to
};
formSubmit(props);
})
</script>
{% endblock %}

View File

@ -1,550 +0,0 @@
{% extends 'users/_base_user_detail.html' %}
{% load static %}
{% load i18n %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
{% endblock %}
{% block content_nav_delete_update %}
<li class="pull-right">
<a class="btn btn-outline {% if can_update %} btn-default {% else %} disabled {% endif %}" href="{% url 'users:user-update' pk=object.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
</li>
<li class="pull-right">
<a class="btn btn-outline {% if can_delete %} btn-danger btn-delete-user {% else %} disabled {% endif %}">
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
</a>
</li>
{% endblock %}
{% block content_table %}
<div class="col-sm-8" style="padding-left: 0">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label"><b>{{ object.name }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td colspan="2">
<img src="{{ object.avatar_url }}" class="img-circle" width="64" height="64">
</td>
</tr>
<tr>
<td width="20%">{% trans 'Name' %}:</td>
<td><b>{{ object.name }}</b></td>
</tr>
<tr>
<td>{% trans 'Username' %}:</td>
<td><b>{{ object.username }}</b></td>
</tr>
<tr>
<td>{% trans 'Email' %}:</td>
<td><b>{{ object.email }}</b></td>
</tr>
{% if user.phone %}
<tr>
<td>{% trans 'Phone' %}:</td>
<td><b>{{ object.phone }}</b></td>
</tr>
{% endif %}
{% if object.wechat %}
<tr>
<td>{% trans 'Wechat' %}:</td>
<td><b>{{ object.wechat }}</b></td>
</tr>
{% endif %}
<tr>
<td>{% trans 'Role' %}:</td>
<td><b>{{ object.org_role_display }}</b></td>
</tr>
<tr>
<td>{% trans 'MFA' %}:</td>
<td><b>
{% if object.mfa_force_enabled %}
{% trans 'Force enabled' %}
{% elif object.mfa_enabled%}
{% trans 'Enabled' %}
{% else %}
{% trans 'Disabled' %}
{% endif %}
</b></td>
</tr>
<tr>
<td>{% trans 'Source' %}:</td>
<td><b>{{ object.get_source_display }}</b></td>
</tr>
<tr>
<td>{% trans 'Date expired' %}:</td>
<td><b>{{ object.date_expired|date:"Y-m-j H:i:s" }}</b></td>
</tr>
<tr>
<td>{% trans 'Created by' %}:</td>
<td><b>{{ object.created_by }}</b></td>
</tr>
<tr>
<td>{% trans 'Date joined' %}:</td>
<td><b>{{ object.date_joined|date:"Y-m-j H:i:s" }}</b></td>
</tr>
<tr>
<td>{% trans 'Last login' %}:</td>
<td><b>{{ object.last_login|date:"Y-m-j H:i:s" }}</b></td>
</tr>
{% if object.can_update_password %}
<tr>
<td>{% trans 'Last password updated' %}:</td>
<td><b>{{ object.date_password_last_updated|date:"Y-m-j H:i:s" }}</b></td>
</tr>
{% endif %}
<tr>
<td>{% trans 'Comment' %}:</td>
<td><b>{{ object.comment }}</b></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick modify' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td width="50%">{% trans 'Active' %}:</td>
<td>
<span class="pull-right">
<div class="switch">
<div class="onoffswitch">
<input type="checkbox" {% if object.is_active %} checked {% endif %} {% if request.user == object %} disabled {% endif %} class="onoffswitch-checkbox" id="is_active">
<label class="onoffswitch-label" for="is_active">
<span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span>
</label>
</div>
</div>
</span>
</td>
</tr>
<tr>
<td>{% trans 'Force enabled MFA' %}:</td>
<td>
<span class="pull-right">
<div class="switch">
<div class="onoffswitch">
<input type="checkbox" class="onoffswitch-checkbox" {% if object.mfa_force_enabled %} checked {% endif %}
id="force_enable_mfa">
<label class="onoffswitch-label" for="force_enable_mfa">
<span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span>
</label>
</div>
</div>
</span>
</td>
</tr>
<tr>
<td>{% trans 'Reset MFA' %}:</td>
<td>
<span class="pull-right">
<button type="button" class="btn btn-primary btn-xs" id="btn-reset-mfa" style="width: 54px">{% trans 'Reset' %}</button>
</span>
</td>
</tr>
{% if object.can_update_password %}
<tr>
<td>{% trans 'Send reset password mail' %}:</td>
<td>
<span class="pull-right">
<button type="button" class="btn btn-primary btn-xs" {% if request.user == object %} disabled="disabled" {% endif %} id="btn-reset-password" style="width: 54px">{% trans 'Send' %}</button>
</span>
</td>
</tr>
{% endif %}
{% if object.can_update_ssh_key %}
<tr>
<td>{% trans 'Send reset ssh key mail' %}:</td>
<td>
<span class="pull-right">
<button type="button" class="btn btn-primary btn-xs" {% if request.user == object %} disabled="disabled" {% endif %} id="btn-reset-pk" style="width: 54px;">{% trans 'Send' %}</button>
</span>
</td>
</tr>
{% endif %}
<tr style="{% if not unblock %}display:none{% endif %}">
<td>{% trans 'Unblock user' %}</td>
<td>
<span class="pull-right">
<button type="button" class="btn btn-primary btn-xs" id="btn-unblock-user" style="width: 54px">{% trans 'Unblock' %}</button>
</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
{% if request.user.can_admin_current_org %}
{% if object.can_user_current_org or object.can_admin_current_org %}
<div class="panel panel-info">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'User group' %}
</div>
<div class="panel-body">
<table class="table group_edit">
<tbody>
<form>
<tr>
<td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Join user groups' %}" id="groups_selected" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for group in groups %}
<option value="{{ group.id }}" id="opt_{{ group.id }}" >{{ group.name }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr>
<td colspan="2" class="no-borders">
<button type="button" class="btn btn-info btn-small" id="btn_join_group">{% trans 'Join' %}</button>
</td>
</tr>
</form>
{% for group in object.groups.all %}
<tr>
<td >
<b class="bdg_group" >{{ group.name }}</b>
</td>
<td>
<button class="btn btn-danger pull-right btn-xs btn_leave_group" data-uid={{ group.id }} type="button"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
{% if LICENSE_VALID and LOGIN_CONFIRM_ENABLE %}
<div class="panel panel-warning">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Login confirm' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<form>
<tr>
<td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Reviewers' %}" id="id_assignees" class="users-select2" style="width: 100%" multiple="" tabindex="4">
</select>
</td>
</tr>
<tr>
<td colspan="2" class="no-borders">
<button type="button" class="btn btn-warning btn-small" id="btn_reviewer_confirm">{% trans 'Confirm' %}</button>
</td>
</tr>
</form>
{% if object.get_login_confirm_setting %}
{% for u in object.login_confirm_setting.reviewers.all %}
<tr>
<td >
<b class="bdg_reviewer">{{ u }}</b>
</td>
<td>
<button class="btn btn-danger pull-right btn-xs btn-leave-reviewer" data-uid={{ u.id }} type="button"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
</div>
{% endif %}
{% endif %}
</div>
{% include 'users/_user_update_pk_modal.html' %}
{% endblock %}
{% block custom_foot_js %}
<script>
var usersSelect2;
function updateUserLoginReviewer(reviewers) {
var url = "{% url 'api-auth:login-confirm-setting-update' user_id=object.id %}";
var data = {reviewers: reviewers};
requestApi({
url: url,
data: JSON.stringify(data),
method: 'PATCH',
success: function () {
window.location.reload();
}
})
}
var usersGroupsRelationUrl = "{% url 'api-users:users-groups-relation-list' %}";
function addObjects(objectsId) {
if (!objectsId || objectsId.length === 0) {
return
}
var theUrl = usersGroupsRelationUrl;
var body = [];
objectsId.forEach(function (v) {
var data = {user: "{{ object.id }}"};
data["usergroup"] = v;
body.push(data)
});
requestApi({
url: theUrl,
body: JSON.stringify(body),
method: "POST",
success: reloadPage
});
}
function removeObject(objectId) {
if (!objectId) {
return
}
var theUrl = usersGroupsRelationUrl;
theUrl = setUrlParam(theUrl, 'user', "{{ object.id }}");
theUrl = setUrlParam(theUrl, 'usergroup', objectId);
requestApi({
url: theUrl,
method: "DELETE",
success: reloadPage
});
}
$(document).ready(function() {
$('.select2').select2();
usersSelect2 = usersSelect2Init('.users-select2')
})
.on('click', '#is_active', function() {
var the_url = "{% url 'api-users:user-detail' pk=object.id %}";
var checked = $(this).prop('checked');
var body = {
'is_active': checked
};
var success = '{% trans "Update successfully!" %}';
requestApi({
url: the_url,
body: JSON.stringify(body),
success_message: success
});
})
.on('click', '#force_enable_mfa', function() {
{% if request.user == object %}
toastr.error("{% trans 'Goto profile page enable MFA' %}");
return;
{% endif %}
var the_url = "{% url 'api-users:user-detail' pk=object.id %}";
var checked = $(this).prop('checked');
var mfa_level;
var otp_secret_key;
if(checked){
mfa_level = 2
}else{
mfa_level = 0;
otp_secret_key = '';
}
var body = {
'mfa_level': mfa_level,
'otp_secret_key': otp_secret_key
};
var success = '{% trans "Update successfully!" %}';
requestApi({
url: the_url,
body: JSON.stringify(body),
success_message: success
});
})
.on('click', '#btn_join_group', function() {
var objectsId = $("#groups_selected").val();
addObjects(objectsId);
}).on('click', '.btn_leave_group', function() {
var objectId = $(this).data('uid');
removeObject(objectId)
}).on('click', '#btn-reset-password', function() {
function doReset() {
var the_url = '{% url "api-users:user-reset-password" pk=object.id %}';
var body = {};
var success = function() {
var msg = "{% trans "An e-mail has been sent to the user`s mailbox." %}";
swal("{% trans 'Reset password' %}", msg, "success");
};
requestApi({
url: the_url,
body: JSON.stringify(body),
success: success
});
}
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans "This will reset the user password and send a reset mail"%}",
type: "warning",
showCancelButton: true,
cancelButtonText: "{% trans 'Cancel' %}",
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
}, function() {
doReset();
});
}).on('click', '#btn-reset-pk', function() {
function doReset() {
var the_url = '{% url "api-users:user-public-key-reset" pk=object.id %}';
var body = {};
var success = function() {
var msg = "{% trans 'The reset-ssh-public-key E-mail has been sent successfully. Please inform the user to update his new ssh public key.' %}";
swal("{% trans 'Reset SSH public key' %}", msg, "success");
};
requestApi({
url: the_url,
body: body,
success: success
});
}
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans 'This will reset the user public key and send a reset mail' %}",
type: "warning",
showCancelButton: true,
cancelButtonText: "{% trans 'Cancel' %}",
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
}, function() {
doReset();
});
}).on('click', '#btn-user-update-pk', function(){
var $this = $(this);
var pk = $('#txt_pk').val();
var the_url = '{% url "api-users:user-public-key-reset" pk=user.id %}';
var body = {'_public_key': pk};
var success = function() {
$('#txt_pk').val('');
$this.closest('.modal').modal('hide');
var msg = "{% trans 'Successfully updated the SSH public key.' %}";
swal("{% trans 'User SSH public key update' %}", msg, "success");
};
var fail = function(msg) {
swal({
title: "{% trans 'User SSH public key update' %}",
text: msg,
type: "error",
showCancelButton: false,
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: true
}, function () {
$('#txt_pk').focus();
}
);
};
requestApi({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
}).on('click', '.btn-delete-user', function () {
var $this = $(this);
var name = "{{ object.name }}";
var uid = "{{ object.id }}";
var the_url = '{% url "api-users:user-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
var redirect_url = "{% url 'users:user-list' %}";
objectDelete($this, name, the_url, redirect_url);
}).on('click', '#btn-unblock-user', function () {
function doReset() {
{#var the_url = '{% url "api-users:user-reset-password" pk=object.id %}';#}
var the_url = '{% url "api-users:user-unblock" pk=object.id %}';
var body = {};
var success = function() {
var msg = "{% trans "Success" %}";
{#swal("{% trans 'Unblock user' %}", msg, "success");#}
swal({
title: "{% trans 'Unblock user' %}",
text: msg,
type: "success"
}, function() {
location.reload()
}
);
};
requestApi({
url: the_url,
body: JSON.stringify(body),
success: success
});
}
swal({
title: "{% trans 'Are you sure?' %}",
text: "{% trans "After unlocking the user, the user can log in normally."%}",
type: "warning",
showCancelButton: true,
cancelButtonText: "{% trans 'Cancel' %}",
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
}, function() {
doReset();
});
}).on('click', '#btn-reset-mfa', function () {
requestApi({
url: "{% url 'api-users:user-reset-otp' pk=object.id %}",
method: "GET",
success_message: "{% trans 'Reset user MFA success' %}"
})
}).on('click', '.btn-leave-reviewer', function () {
var reviewersId = [];
var removeReviewerId = $(this).data('uid');
$('.btn-leave-reviewer').each(function (i, v) {
var reviewerId = $(v).data('uid');
if (reviewerId !== removeReviewerId) {
reviewersId.push(reviewerId);
}
});
updateUserLoginReviewer(reviewersId);
}).on('click', '#btn_reviewer_confirm', function () {
var reviewersId = [];
$('.btn-leave-reviewer').each(function (i, v) {
var reviewerId = $(v).data('uid');
reviewersId.push(reviewerId);
});
var selectedId = usersSelect2.val();
if (selectedId.length === 0) {
return
}
selectedId.forEach(function (i) {
if (reviewersId.indexOf(i) === -1) {
reviewersId.push(i)
}
});
updateUserLoginReviewer(reviewersId);
})
</script>
{% endblock %}

View File

@ -1,26 +0,0 @@
{% extends 'users/_base_user_detail.html' %}
{% load bootstrap3 %}
{% load static %}
{% load i18n %}
{% block custom_head_css_js %}
<link href="{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}" rel="stylesheet">
<script type="text/javascript" src="{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"></script>
{% endblock %}
{% block content_table %}
{% include 'users/_granted_assets.html' %}
{% endblock %}
{% block custom_foot_js %}
<script>
var assetTableUrl = "{% url 'api-perms:user-assets' pk=object.id %}?cache_policy=1";
var selectUrl = '{% url "api-perms:user-node-assets" pk=object.id node_id=DEFAULT_PK %}?cache_policy=1&all=1';
var treeUrl = "{% url 'api-perms:user-nodes-children-as-tree' pk=object.id %}?cache_policy=1";
var systemUsersUrl = "{% url 'api-perms:user-asset-system-users' pk=object.id asset_id=DEFAULT_PK %}?cache_policy=1";
$(document).ready(function () {
initTree();
});
</script>
{% endblock %}

View File

@ -1,100 +0,0 @@
{% extends 'users/_base_user_detail.html' %}
{% load i18n static %}
{% block custom_head_css_js %}
<script src="{% static 'js/jquery.form.min.js' %}"></script>
{% endblock %}
{% block content_table %}
<div class="col-sm-10" style="padding-left: 0">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label"><b>{{ object.name }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table table-striped table-bordered table-hover " id="database_app_list_table" >
<thead>
<tr>
<th class="text-center">
<input type="checkbox" id="check_all" class="ipt_check_all" >
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Type' %}</th>
<th class="text-center">{% trans 'Host' %}</th>
<th class="text-center">{% trans 'Database' %}</th>
<th class="text-center">{% trans 'Comment' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
var inited = false;
var database_app_table, url;
function initTable() {
if (inited){
return
} else {
inited = true;
}
url = '{% url "api-perms:user-database-apps" pk=object.id %}';
var options = {
ele: $('#database_app_list_table'),
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
{% url 'applications:database-app-detail' pk=DEFAULT_PK as the_url %}
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 2, createdCell: function (td, cellData, rowData) {
var type = htmlEscape(rowData.get_type_display);
$(td).html(type);
}},
{targets: 3, createdCell: function (td, cellData, rowData) {
var host = htmlEscape(cellData);
$(td).html(host);
}},
{targets: 4, createdCell: function (td, cellData, rowData) {
var database = htmlEscape(cellData);
$(td).html(database);
}}
],
ajax_url: url,
columns: [
{data: "id"},
{data: "name"},
{data: "type"},
{data: "host"},
{data: "database"},
{data: "comment", orderable: false},
]
};
database_app_table = jumpserver.initServerSideDataTable(options);
return database_app_table
}
$(document).ready(function(){
initTable();
})
</script>
{% endblock %}

View File

@ -1,93 +0,0 @@
{% extends 'users/_base_user_detail.html' %}
{% load i18n static %}
{% block custom_head_css_js %}
<script src="{% static 'js/jquery.form.min.js' %}"></script>
{% endblock %}
{% block content_table %}
<div class="col-sm-10" style="padding-left: 0">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label"><b>{{ object.name }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table table-striped table-bordered table-hover " id="remote_app_list_table" >
<thead>
<tr>
<th class="text-center">
<input type="checkbox" id="check_all" class="ipt_check_all" >
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'App type' %}</th>
<th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'Comment' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
var inited = false;
var remote_app_table, url;
function initTable() {
if (inited){
return
} else {
inited = true;
}
url = '{% url "api-perms:user-remote-apps" pk=object.id %}';
var options = {
ele: $('#remote_app_list_table'),
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
{% url 'applications:remote-app-detail' pk=DEFAULT_PK as the_url %}
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 1, createdCell: function (td, cellData, rowData) {
$(td).html(rowData.get_type_display)
}},
{targets: 3, createdCell: function (td, cellData, rowData) {
var hostname = htmlEscape(cellData.hostname);
$(td).html(hostname);
}}
],
ajax_url: url,
columns: [
{data: "id"},
{data: "name"},
{data: "type"},
{data: "asset_info", orderable: false},
{data: "comment", orderable: false}
]
};
remote_app_table = jumpserver.initServerSideDataTable(options);
return remote_app_table
}
$(document).ready(function(){
initTable();
})
</script>
{% endblock %}

View File

@ -1,69 +0,0 @@
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% load bootstrap3 %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>{{ action }}</h5>
</div>
<div class="ibox-content">
{% if form.non_field_errors %}
<div class="alert alert-danger">
{{ form.non_field_errors }}
</div>
{% endif %}
<form method="post" class="form-horizontal" action="" >
{% csrf_token %}
{% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.users layout="horizontal" %}
{% bootstrap_field form.comment layout="horizontal" %}
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Confirm' %}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% include "users/_select_user_modal.html" %}
{% endblock %}
{% block custom_foot_js %}
<script>
$(document).ready(function () {
$('.select2').select2({
closeOnSelect: false
});
usersSelect2Init('.users-select2')
})
.on("submit", "form", function (evt) {
evt.preventDefault();
var the_url = '{% url 'api-users:user-group-list' %}';
var redirect_to = '{% url "users:user-group-list" %}';
var method = "POST";
{% if type == "update" %}
the_url = '{% url 'api-users:user-group-detail' pk=object.id %}';
method = "PUT";
{% endif %}
var form = $("form");
var data = form.serializeObject();
objectAttrsIsList(data, ['users']);
var props = {
url: the_url,
data: data,
method: method,
form: form,
redirect_to: redirect_to
};
formSubmit(props);
})
</script>
{% endblock %}

View File

@ -1,168 +0,0 @@
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="panel-options">
<ul class="nav nav-tabs">
<li class="active">
<a href="{% url 'users:user-group-detail' pk=user_group.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'User group detail' %} </a>
</li>
<li>
<a href="{% url 'users:user-group-granted-asset' pk=user_group.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a>
</li>
<li class="pull-right">
<a class="btn btn-outline btn-default" href="{% url 'users:user-group-update' pk=user_group.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a>
</li>
<li class="pull-right">
<a class="btn btn-outline btn-danger btn-delete-user-group">
<i class="fa fa-trash-o"></i>{% trans 'Delete' %}
</a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-7" style="padding-left: 0">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label"><b>{{ user_group.name }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td width="20%">{% trans 'Name' %}:</td>
<td><b>{{ user_group.name }}</b></td>
</tr>
<tr>
<td>{% trans 'Create by' %}:</td>
<td><b>{{ user_group.created_by }}</b></td>
</tr>
<tr>
<td>{% trans 'Date created' %}:</td>
<td><b>{{ user_group.date_created }}</b></td>
</tr>
<tr>
<td>{% trans 'Comment' %}:</td>
<td><b>{{ user_group.comment }}</b></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'User' %}
</div>
<div class="panel-body">
<table class="table user_edit">
<tbody>
<form>
<tr>
<td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Add user' %}" id="slct_users" class="select2" style="width: 100%" multiple="" tabindex="4">
</select>
</td>
</tr>
<tr>
<td colspan="2" class="no-borders">
<button type="button" class="btn btn-primary btn-small" id="btn_add_user">{% trans 'Add' %}</button>
</td>
</tr>
</form>
{% for user in user_group.users.all %}
<tr>
<td ><b class="bdg_user" >{{ user.name }}</b></td>
<td>
<button class="btn btn-danger pull-right btn-xs btn-remove-user" data-uid={{ user.id }} type="button"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
var usersGroupsRelationUrl = "{% url 'api-users:users-groups-relation-list' %}";
function addObjects(objectsId) {
if (!objectsId || objectsId.length === 0) {
return
}
var theUrl = usersGroupsRelationUrl;
var body = [];
objectsId.forEach(function (v) {
var data = {usergroup: "{{ object.id }}"};
data["user"] = v;
body.push(data)
});
requestApi({
url: theUrl,
body: JSON.stringify(body),
method: "POST",
success: reloadPage
});
}
function removeObject(objectId, type) {
if (!objectId) {
return
}
var theUrl = usersGroupsRelationUrl;
theUrl = setUrlParam(theUrl, 'usergroup', "{{ object.id }}");
theUrl = setUrlParam(theUrl, 'user', objectId);
requestApi({
url: theUrl,
method: "DELETE",
success: reloadPage
});
}
$(document).ready(function () {
$('.select2').select2();
usersSelect2Init('#slct_users')
}).on('click', '.btn-remove-user', function() {
var objectId = $(this).data("uid");
removeObject(objectId);
}).on('click', '#btn_add_user', function() {
var objectsId = $("#slct_users").val();
addObjects(objectsId);
}).on('click', '.btn-delete-user-group', function () {
var $this = $(this);
var name = "{{ user_group.name }}";
var uid = "{{ user_group.id }}";
var the_url = '{% url "api-users:user-group-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
var redirect_url = "{% url 'users:user-group-list' %}";
objectDelete($this, name, the_url, redirect_url);
})
</script>
{% endblock %}

View File

@ -1,47 +0,0 @@
{% extends 'base.html' %}
{% load bootstrap3 %}
{% load static %}
{% load i18n %}
{% block custom_head_css_js %}
<link href="{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}" rel="stylesheet">
<script type="text/javascript" src="{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"></script>
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="panel-options">
<ul class="nav nav-tabs">
<li>
<a href="{% url 'users:user-group-detail' pk=object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'User group detail' %} </a>
</li>
<li class="active">
<a href="{% url 'users:user-group-granted-asset' pk=object.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a>
</li>
</ul>
</div>
<div class="tab-content">
{% include 'users/_granted_assets.html' %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
var assetTableUrl = "{% url 'api-perms:user-group-assets' pk=object.id %}?cache_policy=1";
var selectUrl = '{% url "api-perms:user-group-node-assets" pk=object.id node_id=DEFAULT_PK %}?cache_policy=1&all=1';
var treeUrl = "{% url 'api-perms:user-group-nodes-children-as-tree' pk=object.id %}?cache_policy=1";
var systemUsersUrl = "{% url 'api-perms:user-group-asset-system-users' pk=object.id asset_id=DEFAULT_PK %}?cache_policy=1";
var showAssetHref = true; // Need input default true
$(document).ready(function () {
initTree();
});
</script>
{% endblock %}

View File

@ -1,112 +0,0 @@
{% extends '_base_list.html' %}
{% load i18n static %}
{% block table_search %}
{% include '_csv_import_export.html' %}
{% endblock %}
{% block table_container %}
<div class="pull-left m-r-5"><a href="{% url 'users:user-group-create' %}" class="btn btn-sm btn-primary ">{% trans "Create user group" %}</a></div>
<table class="table table-striped table-bordered table-hover " id="group_list_table" >
<thead>
<tr>
<th class="text-center">
<input id="" type="checkbox" class="ipt_check_all">
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'User' %}</th>
<th class="text-center">{% trans 'Comment' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
</table>
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block custom_foot_js %}
<script>
var groupsTable = 0;
var usersAmountTpl = '<a class="group-users-amount" data-uid="ID">NUM</a>';
function initTable() {
var options = {
ele: $('#group_list_table'),
buttons: [],
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url "users:user-group-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 2, createdCell: function (td, cellData, rowData) {
var data = usersAmountTpl
.replace("ID", rowData.id)
.replace('NUM', cellData);
$(td).html(data);
}},
{targets: 3, createdCell: function (td, cellData) {
cellData = htmlEscape(cellData);
var innerHtml = cellData.length > 30 ? cellData.substring(0, 30) + '...': cellData;
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
}},
{targets: 4, createdCell: function (td, cellData, rowData) {
var name = htmlEscape(rowData.name);
var update_btn = '<a href="{% url "users:user-group-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_delete_user_group" data-gid="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', name);
if (rowData.id === 1) {
$(td).html(update_btn)
} else {
$(td).html(update_btn + del_btn)
}
}}
],
ajax_url: '{% url "api-users:user-group-list" %}',
columns: [{data: "id"}, {data: "name" }, {data: "users_amount", orderable: false},
{data: "comment"}, {data: "id", orderable: false, width: "120px"}],
op_html: $('#actions').html()
};
groupsTable = jumpserver.initServerSideDataTable(options);
return groupsTable
}
var usersGroupsRelationUrl = "{% url 'api-users:users-groups-relation-list' %}";
function getGroupUsers(groupId, callback) {
var theUrl = setUrlParam(usersGroupsRelationUrl, "usergroup", groupId);
if (!callback) {
callback = function (data) {
console.log(data)
}
}
requestApi({
url: theUrl,
method: "GET",
success: callback,
flash_message: false,
})
}
$(document).ready(function() {
groupsTable = initTable();
initCsvImportExport(groupsTable, "{% trans 'User groups' %}")
}).on('click', '.btn_delete_user_group', function(){
var $this = $(this);
var group_id = $this.data('gid');
var name = $this.data('name');
var the_url = "{% url 'api-users:user-group-detail' pk=DEFAULT_PK %}".replace('{{ DEFAULT_PK }}', group_id);
objectDelete($this, name, the_url)
})
.on('click', '.group-users-amount', function () {
var $this = $(this);
var groupId = $(this).data("uid");
getGroupUsers(groupId, function (data) {
var groups = [];
data.forEach(function (v) {
groups.push(v.user_display);
});
var popover = createPopover(groups);
$this.parent().html(popover);
$(popover).trigger('click');
})
});
</script>
{% endblock %}

View File

@ -1,280 +0,0 @@
{% extends '_base_list.html' %}
{% load i18n static %}
{% block table_search %}
{% include '_csv_import_export.html' %}
{% endblock %}
{% block table_container %}
<div class="uc pull-left m-r-5"><a href="{% url "users:user-create" %}" class="btn btn-sm btn-primary"> {% trans "Create user" %} </a></div>
<table class="table table-striped table-bordered table-hover " id="user_list_table">
<thead>
<tr>
<th class="text-center">
<input id="" type="checkbox" class="ipt_check_all">
</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Username' %}</th>
<th class="text-center">{% trans 'Role' %}</th>
<th class="text-center">{% trans 'User group' %}</th>
<th class="text-center">{% trans 'Source' %}</th>
<th class="text-center">{% trans 'Validity' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div id="actions" class="hide">
<div class="input-group">
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
{% if CURRENT_ORG.is_default %}
<option value="delete">{% trans 'Delete selected' %}</option>
{% else %}
<option value="remove">{% trans 'Remove selected' %}</option>
{% endif %}
<option value="update">{% trans 'Update selected' %}</option>
<option value="deactive">{% trans 'Deactive selected' %}</option>
<option value="active">{% trans 'Active selected' %}</option>
</select>
<div class="input-group-btn pull-left" style="padding-left: 5px;">
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary">
{% trans 'Submit' %}
</button>
</div>
</div>
</div>
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/jquery.form.min.js' %}"></script>
<script>
var usersTable = 0;
function initTable() {
var options = {
ele: $('#user_list_table'),
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url "users:user-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace("{{ DEFAULT_PK }}", rowData.id));
}},
{targets: 3, createdCell: function (td, cellData, rowData) {
$(td).html(rowData.role_display);
}},
{targets: 4, createdCell: function (td, cellData) {
var innerHtml = cellData.length > 20 ? cellData.substring(0, 20) + '...': cellData;
$(td).html('<span href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</span>');
}},
{targets: 5, createdCell: function (td, cellData, rowData) {
$(td).html(rowData.source_display);
}},
{targets: 6, createdCell: function (td, cellData, rowData) {
if (cellData) {
$(td).html('<i class="fa fa-check text-navy"></i>')
} else if (!rowData.is_active) {
$(td).html('<i class="fa fa-times text-danger inactive"></i>')
} else if (rowData.is_expired) {
$(td).html('<i class="fa fa-times text-danger expired"></i>')
}
}},
{targets: 7, createdCell: function (td, cellData, rowData) {
var name = htmlEscape(rowData.name);
var update_btn = "";
if (rowData.can_update === false){
update_btn = '<a class="btn btn-xs disabled btn-info">{% trans "Update" %}</a>';
}
else{
update_btn = '<a href="{% url "users:user-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('00000000-0000-0000-0000-000000000000', cellData);
}
var del_btn = "";
var rm_btn = "";
if ("{{ CURRENT_ORG }}" === 'DEFAULT'){
if (rowData.can_delete === false){
del_btn = '<a class="btn btn-xs btn-danger m-l-xs" disabled>{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', name);
} else {
del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_user_delete" data-action="delete" data-uid="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', name);
}
$(td).html(update_btn + del_btn)
}
else{
if (rowData.can_delete === false){
rm_btn = '<a class="btn btn-xs btn-warning m-l-xs" disabled>{% trans "Remove" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', name);
} else {
rm_btn = '<a class="btn btn-xs btn-warning m-l-xs btn_user_delete" data-action="remove" data-uid="{{ DEFAULT_PK }}" data-name="99991938">{% trans "Remove" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', name);
}
$(td).html(update_btn + rm_btn)
}
}}],
ajax_url: '{% url "api-users:user-list" %}',
columns: [
{data: "id"}, {data: "name" }, {data: "username" },
{data: "role"},
{data: "groups_display", orderable: false},
{data: "source"},
{data: "is_valid", orderable: false, width: "50px"},
{data: "id", orderable: false, width: "120px"}
],
op_html: $('#actions').html()
};
usersTable = jumpserver.initServerSideDataTable(options);
return usersTable
}
$(document).ready(function(){
usersTable = initTable();
initCsvImportExport(usersTable, "{% trans 'User' %}")
}).on('click', '#btn_bulk_update', function(){
var action = $('#slct_bulk_update').val();
var id_list = usersTable.selected;
if (id_list.length === 0) {
return false;
}
var the_url = "{% url 'api-users:user-list' %}";
var data = {
'resources': id_list
};
function reloadPage() {
setTimeout( function () {window.location.reload();}, 300);
}
function doDeactive() {
var data = [];
$.each(id_list, function(index, object_id) {
var obj = {"pk": object_id, "is_active": false};
data.push(obj);
});
requestApi({
url: the_url,
method: 'PATCH',
body: JSON.stringify(data),
success: reloadPage
});
}
function doActive() {
var data = [];
$.each(id_list, function(index, object_id) {
var obj = {"pk": object_id, "is_active": true};
data.push(obj);
});
requestApi({
url: the_url,
method: 'PATCH',
body: JSON.stringify(data),
success: reloadPage
});
}
function doDelete(props) {
props = props || {};
swal({
title: "{% trans 'Are you sure?' %}",
text: props.text || "{% trans 'This will delete the selected users !!!' %}",
type: "warning",
showCancelButton: true,
cancelButtonText: "{% trans 'Cancel' %}",
confirmButtonColor: "#DD6B55",
confirmButtonText: "{% trans 'Confirm' %}",
closeOnConfirm: false
},function () {
function success(data) {
url = setUrlParam(the_url, 'spm', data.spm);
function fail() {
var msg = "{% trans 'User Deleting failed.' %}";
swal("{% trans 'User Delete' %}", msg, "error");
}
requestApi({
url:url,
method:'DELETE',
flash_message:true,
success:reloadPage,
error: props.fail || fail
});
}
requestApi({
url: "{% url 'api-common:resources-cache' %}",
method:'POST',
body:JSON.stringify(data),
flash_message:false,
success:success,
})
})
}
function doRemove(){
var props = {
text: "{% trans 'This will remove the selected users !!' %}",
fail: function fail(){
var msg = "{% trans 'User Removing failed.' %}";
swal("{% trans 'User Remove' %}", msg, "error");
}
};
doDelete(props);
}
function doUpdate() {
function fail(data) {
toastr.error(JSON.parse(data))
}
function success(data) {
var url = "{% url 'users:user-bulk-update' %}";
location.href= setUrlParam(url, 'spm', data.spm);
}
requestApi({
url: "{% url 'api-common:resources-cache' %}",
method:'POST',
body:JSON.stringify(data),
flash_message:false,
success:success,
error:fail
})
}
switch(action) {
case 'deactive':
doDeactive();
break;
case 'delete':
doDelete();
break;
case 'remove':
doRemove();
break;
case 'update':
doUpdate();
break;
case 'active':
doActive();
break;
default:
break;
}
}).on('click', '.btn_user_delete', function(){
var $this = $(this);
var name = $this.data('name');
var uid = $this.data('uid');
var action = $this.data('action');
var title, success_message = null;
if (action === 'remove'){
title = "{% trans 'Are you sure about removing it?' %}";
success_message = "{% trans 'Remove the success' %}";
}
var the_url = '{% url "api-users:user-detail" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", uid);
objectDelete($this, name, the_url, null, title, success_message);
}).on('click', '.expired', function () {
var msg = '{% trans "User is expired" %}';
toastr.error(msg)
}).on('click', '.inactive', function () {
var msg = '{% trans 'User is inactive' %}';
toastr.error(msg)
})
</script>
{% endblock %}

View File

@ -1,233 +0,0 @@
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="panel-options">
<ul class="nav nav-tabs">
<li class="active">
<a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Profile' %} </a>
</li>
<li class="pull-right">
<a class="btn btn-outline btn-default" href="{% url 'users:user-profile-update' %}"><i class="fa fa-edit"></i>{% trans 'Setting' %}</a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-8" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label label-primary"><b>{{ user.name }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<div class="text-left">
<table class="table">
<tr class="no-borders-tr">
<td colspan="2">
<img src="{{ user.avatar_url }}" class="img-circle" width="64" height="64">
</td>
</tr>
<tr class="no-borders-tr">
<td class="text-navy">{% trans 'Username' %}</td>
<td>{{ user.username }}</td>
</tr>
<tr>
<td class="text-navy">{% trans 'Name' %}</td>
<td>{{ user.name }}</td>
</tr>
<tr>
<td class="text-navy">{% trans 'Role' %}</td>
<td>{{ user.get_role_display }}</td>
</tr>
<tr>
<td class="text-navy">{% trans 'Email' %}</td>
<td>{{ user.email }}</td>
</tr>
<tr>
<td class="text-navy">{% trans 'Active' %}</td>
<td>{{ user.is_active|yesno:"Yes,No,Unkown" }}</td>
</tr>
{% if user.can_update_ssh_key %}
<tr>
<td class="text-navy">{% trans 'Public key' %}</td>
<td>
<table>
<tr>
<td>
{{ user.public_key_obj.comment }}
</td>
</tr>
<tr>
<td>
{{ user.public_key_obj.hash_md5 }}
</td>
</tr>
</table>
</td>
</tr>
{% endif %}
<tr>
<td class="text-navy">{% trans 'MFA' %}</td>
<td>
{% if user.mfa_force_enabled %}
{% trans 'Force enable' %}
{% elif user.mfa_enabled%}
{% trans 'Enable' %}
{% else %}
{% trans 'Disable' %}
{% endif %}
{% if mfa_setting %}
( {% trans 'Administrator Settings force MFA login' %} )
{% endif %}
</td>
</tr>
<tr>
<td class="text-navy">{% trans 'Source' %}</td>
<td>{{ user.get_source_display }}</td>
</tr>
<tr>
<td class="text-navy">{% trans 'Date joined' %}</td>
<td>{{ user.date_joined|date:"Y-m-d H:i:s" }}</td>
</tr>
<tr>
<td class="text-navy">{% trans 'Last login' %}</td>
<td>{{ user.last_login|date:"Y-m-d H:i:s" }}</td>
</tr>
{% if user.can_update_password %}
<tr>
<td class="text-navy">{% trans 'Last password updated' %}</td>
<td>{{ user.date_password_last_updated|date:"Y-m-d H:i:s" }}</td>
</tr>
{% endif %}
<tr>
<td class="text-navy">{% trans 'Date expired' %}</td>
<td>{{ user.date_expired|date:"Y-m-d H:i:s" }}</td>
</tr>
<tr>
<td class="text-navy">{% trans 'User groups' %}</td>
<td>
<table>
{% for group in user.groups.all %}
<tr>
<td>
{{ group.name }}
</td>
</tr>
{% endfor %}
</table>
</td>
</tr>
<tr>
<td class="text-navy">{% trans 'Comment' %}:</td>
<td><b>{{ user.comment }}</b></td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-4" style="padding-left: 0;padding-right: 0">
<div class="panel panel-primary">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'Quick modify' %}
</div>
<div class="panel-body">
<table class="table">
<tbody>
<tr class="no-borders-tr">
<td>{% trans 'Set MFA' %}:</td>
<td>
<span class="pull-right">
<a type="button" class="btn btn-primary btn-xs" style="width: 54px" id=""
href="
{% if request.user.mfa_enabled %}
{% if request.user.mfa_force_enabled %}
" disabled >{% trans 'Disable' %}
{% else %}
{% url 'authentication:user-otp-disable-authentication' %}
">{% trans 'Disable' %}
{% endif %}
{% else %}
{% url 'authentication:user-otp-enable-start' %}
">{% trans 'Enable' %}
{% endif %}
</a>
</span>
</td>
</tr>
{% if request.user.mfa_enabled %}
<tr>
<td>{% trans 'Update MFA' %}:</td>
<td>
<span class="pull-right">
<a type="button" class="btn btn-primary btn-xs" style="width: 54px" href="{% url 'authentication:user-otp-update' %}">{% trans 'Update' %}</a>
</span>
</td>
</tr>
{% endif %}
{% if request.user.can_update_password %}
<tr class="no-borders">
<td>{% trans 'Update password' %}:</td>
<td>
<span class="pull-right">
<a type="button" class="btn btn-primary btn-xs" style="width: 54px" href="{% url 'users:user-password-update' %}">{% trans 'Update' %}</a>
</span>
</td>
</tr>
{% endif %}
{% if request.user.can_update_ssh_key %}
<tr>
<td>{% trans 'Update SSH public key' %}:</td>
<td>
<span class="pull-right">
<a type="button" class="btn btn-primary btn-xs" style="width: 54px" href="{% url 'users:user-pubkey-update' %}">{% trans 'Update' %}</a>
</span>
</td>
</tr>
<tr>
<td>{% trans 'Reset public key and download' %}:</td>
<td>
<span class="pull-right">
<a type="button" class="btn btn-primary btn-xs btn-reset-pubkey" style="width: 54px">{% trans 'Reset' %}</a>
</span>
</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
$(document).ready(function () {
})
.on('click', '.btn-reset-pubkey', function () {
var the_url = '{% url "users:user-pubkey-generate" %}';
window.open(the_url, "_blank")
})
</script>
{% endblock %}

View File

@ -1,84 +0,0 @@
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% load bootstrap3 %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/cropper/cropper.min.css" %}" rel="stylesheet">
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
<style>
.crop {
width: 200px;
height: 150px;
overflow: hidden;
}
.img-preview-sm img {
width: 64px;
height: 64px;
margin: -75px 0 0 -100px;
}
img {
max-width: 100%; /* This rule is very important, please do not ignore this! */
}
</style>
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="panel-options">
<ul class="nav nav-tabs">
<li class="active">
<a href="{% url 'users:user-profile-update' %}" class="text-center">{% trans 'Profile' %} </a>
</li>
{% if request.user.can_update_password %}
<li>
<a href="{% url 'users:user-password-update' %}" class="text-center">{% trans 'Password' %} </a>
</li>
{% endif %}
{% if request.user.can_update_ssh_key %}
<li>
<a href="{% url 'users:user-pubkey-update' %}" class="text-center">{% trans 'Public key' %} </a>
</li>
{% endif %}
</ul>
</div>
<div class="tab-content" style="background-color: #ffffff">
<div class="wrapper wrapper-content animated fadeInRight">
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
{% csrf_token %}
<h3>{% trans 'Account' %}</h3>
{% bootstrap_field form.username layout="horizontal" %}
{% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.email layout="horizontal" %}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Profile' %}</h3>
{% bootstrap_field form.phone layout="horizontal" %}
{% bootstrap_field form.wechat layout="horizontal" %}
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/cropper/cropper.min.js' %}"></script>
<script>
</script>
{% endblock %}

View File

@ -1,102 +0,0 @@
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% load bootstrap3 %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/cropper/cropper.min.css" %}" rel="stylesheet">
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
<style>
.crop {
width: 200px;
height: 150px;
overflow: hidden;
}
.img-preview-sm img {
width: 64px;
height: 64px;
margin: -75px 0 0 -100px;
}
img {
max-width: 100%; /* This rule is very important, please do not ignore this! */
}
</style>
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="panel-options">
<ul class="nav nav-tabs">
<li>
<a href="{% url 'users:user-profile-update' %}" class="text-center">{% trans 'Profile' %} </a>
</li>
{% if request.user.can_update_password %}
<li>
<a href="{% url 'users:user-password-update' %}" class="text-center">{% trans 'Password' %} </a>
</li>
{% endif %}
{% if request.user.can_update_ssh_key %}
<li class="active">
<a href="{% url 'users:user-pubkey-update' %}" class="text-center">{% trans 'Public key' %} </a>
</li>
{% endif %}
</ul>
</div>
<div class="tab-content" style="background-color: #ffffff">
<div class="wrapper wrapper-content animated fadeInRight">
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
{% csrf_token %}
<h3>{% trans 'Old public key' %}</h3>
<div class="form-group">
<label class="control-label col-sm-2 col-lg-2" style="padding-top: 0" >{% trans 'Name' %}</label>
<div class=" col-sm-9 col-lg-9">
<label>{{ user.public_key_obj.comment }}</label>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2 col-lg-2" style="padding-top: 0">{% trans 'Fingerprint' %}</label>
<div class=" col-sm-9 col-lg-9 ">
<label>{{ user.public_key_obj.hash_md5 }}</label>
</div>
</div>
<div class="hr-line-dashed"></div>
<h3>{% trans 'Update public key' %}</h3>
{% bootstrap_field form.public_key layout="horizontal" %}
<div class="form-group">
<label class="control-label col-sm-2 col-lg-2" style="padding-top: 0">{% trans 'Or reset by server' %}</label>
<div class=" col-sm-9 col-lg-9 ">
<a id="reset_pubkey" href="{% url 'users:user-pubkey-generate' %}">{% trans 'Reset' %}</a>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-2">
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/cropper/cropper.min.js' %}"></script>
<script>
$(document).ready(function () {
}).on('click', '#reset_pubkey', function () {
var message = "{% trans 'The new public key has been set successfully, Please download the corresponding private key.' %}";
toastr.success(message)
})
</script>
{% endblock %}

View File

@ -1,168 +0,0 @@
{% extends 'users/_base_user_detail.html' %}
{% load static %}
{% load i18n %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
{% endblock %}
{% block content_table %}
<div class="col-sm-10" style="padding-left: 0">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label"><b>{{ object.name }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table class="table table-striped table-bordered table-hover"
id="permission_list_table"
style="width: 100%">
<thead>
<tr>
<th></th>
<th>{% trans 'Name' %}</th>
<th class="text-center">{% trans 'User' %}</th>
<th class="text-center">{% trans 'User group' %}</th>
<th class="text-center">{% trans 'RemoteApp' %}</th>
<th class="text-center">{% trans 'System user' %}</th>
<th class="text-center">{% trans 'Validity' %}</th>
<th class="text-center">{% trans 'Action' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
function format(d) {
var data = "";
if (d.users.length > 0 ) {
data += makeLabel(["{% trans 'User' %}", d.users.join(", ")])
}
if (d.user_groups.length > 0) {
data += makeLabel(["{% trans 'User group' %}", d.user_groups.join(", ")])
}
if (d.remote_apps.length > 0) {
data += makeLabel(["{% trans 'RemoteApp' %}", d.remote_apps.join(", ")])
}
if (d.system_users.length > 0) {
data += makeLabel(["{% trans 'System user' %}", d.system_users.join(", ")])
}
return data
}
function initTable() {
var options = {
ele: $('#permission_list_table'),
toggle: true,
columnDefs: [
{targets: 0, createdCell: function (td, cellData, rowData) {
$(td).addClass("toggle");
$(td).html("<i class='fa fa-angle-right'></i>");
}},
{targets: 1, createdCell: function (td, cellData, rowData) {
cellData = htmlEscape(cellData);
var detail_btn = '<a href="{% url "perms:remote-app-permission-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 2, createdCell: function (td, cellData) {
var num = cellData.length;
$(td).html(num);
}},
{targets: 3, createdCell: function (td, cellData) {
var num = cellData.length;
$(td).html(num);
}},
{targets: 4, createdCell: function (td, cellData) {
var num = cellData.length;
$(td).html(num);
}},
{targets: 5, createdCell: function (td, cellData) {
var num = cellData.length;
$(td).html(num);
}},
{targets: 6, createdCell: function (td, cellData) {
if (!cellData) {
$(td).html('<i class="fa fa-times text-danger"></i>')
} else {
$(td).html('<i class="fa fa-check text-navy"></i>')
}
}},
{targets: 7, createdCell: function (td, cellData, rowData) {
var name = htmlEscape(rowData.name);
var update_btn = '<a href="{% url "perms:remote-app-permission-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-uid="{{ DEFAULT_PK }}" mark=1 data-name="99991938">{% trans "Delete" %}</a>'
.replace('{{ DEFAULT_PK }}', cellData)
.replace('99991938', name);
$(td).html(update_btn + del_btn);
}}
],
ajax_url: '{% url "api-perms:remote-app-permission-list" %}?user_id={{ object.id }}',
columns: [
{data: "id"}, {data: "name"}, {data: "users", orderable: false},
{data: "user_groups", orderable: false}, {data: "remote_apps", orderable: false},
{data: "system_users", orderable: false}, {data: "is_valid", orderable: false},
{data: "id", orderable: false, width: "120px"}
],
select: {},
op_html: $('#actions').html()
};
table = jumpserver.initServerSideDataTable(options);
return table
}
$(document).ready(function() {
initTable();
})
.on('click', '.toggle', function (e) {
e.preventDefault();
var detailRows = [];
var tr = $(this).closest('tr');
var row = table.row(tr);
var idx = $.inArray(tr.attr('id'), detailRows);
if (row.child.isShown()) {
tr.removeClass('details');
$(this).children('i:first-child').removeClass('fa-angle-down').addClass('fa-angle-right');
row.child.hide();
// Remove from the 'open' array
detailRows.splice(idx, 1);
}
else {
tr.addClass('details');
$(this).children('i:first-child').removeClass('fa-angle-right').addClass('fa-angle-down');
row.child(format(row.data())).show();
// Add to the 'open' array
if ( idx === -1 ) {
detailRows.push(tr.attr('id'));
}
}
})
.on('click', '.btn-del', function () {
var $this = $(this);
var uid = $this.data('uid');
var name = $this.data('name');
var the_url = '{% url "api-perms:remote-app-permission-detail" pk=DEFAULT_PK %}'
.replace('{{ DEFAULT_PK }}', uid);
objectDelete($this, name, the_url);
})
</script>
{% endblock %}

View File

@ -1,117 +0,0 @@
{% extends 'users/_user.html' %}
{% load i18n %}
{% load bootstrap3 %}
{% block user_template_title %}{% trans "Update user" %}{% endblock %}
{% block password %}
{% if object.can_update_password %}
{% bootstrap_field form.password layout="horizontal" %}
{# 密码popover #}
<div id="container">
<div class="popover fade bottom in" role="tooltip" id="popover777" style=" display: none; width:260px;">
<div class="arrow" style="left: 50%;"></div>
<h3 class="popover-title" style="display: none;"></h3>
<h4>{% trans 'Your password must satisfy' %}</h4><div id="id_password_rules" style="color: #908a8a; margin-left:20px; font-size:15px;"></div>
<h4 style="margin-top: 10px;">{% trans 'Password strength' %}</h4><div id="id_progress"></div>
<div class="popover-content"></div>
</div>
</div>
{% else %}
<div class="form-group">
<label class="col-sm-2 control-label">{% trans 'Password' %}</label>
<div class="col-sm-8 controls" style="margin-top: 8px;" id="password_help_text">
{% trans 'User auth from {}, go there change password' %}
</div>
</div>
{% endif %}
{% if object.can_update_ssh_key %}
{% bootstrap_field form.public_key layout="horizontal" %}
{% else %}
<div class="form-group">
<label class="col-sm-2 control-label">{% trans 'ssh public key' %}</label>
<div class="col-sm-8 controls" style="margin-top: 8px;" id="ssh_key_help_text">
{% trans 'User auth from {}, ssh key login is not supported' %}
</div>
</div>
{% endif %}
{% endblock %}
{% block custom_foot_js %}
{{ block.super }}
<script>
function passwordCheck() {
if ($('#id_password').length != 1) {
return
}
var el = $('#id_password_rules'),
idPassword = $('#id_password'),
idPopover = $('#popover777'),
container = $('#container'),
progress = $('#id_progress'),
password_check_rules = {{ password_check_rules|safe }},
minLength = 6,
top = idPassword.offset().top - $('.navbar').outerHeight(true) - $('.page-heading').outerHeight(true) - 10 + 34,
left = 377,
i18n_fallback = {
"veryWeak": "{% trans 'Very weak' %}",
"weak": "{% trans 'Weak' %}",
"normal": "{% trans 'Normal' %}",
"medium": "{% trans 'Medium' %}",
"strong": "{% trans 'Strong' %}",
"veryStrong": "{% trans 'Very strong' %}"
};
$.each(password_check_rules, function (idx, rules) {
if(rules.key === 'id_security_password_min_length'){
minLength = rules.value
}
});
// 初始化popover
initPopover(container, progress, idPassword, el, password_check_rules, i18n_fallback);
// 监听事件
idPassword.on('focus', function () {
idPopover.css('top', top);
idPopover.css('left', left);
idPopover.css('display', 'block');
});
idPassword.on('blur', function () {
idPopover.css('display', 'none');
});
idPassword.on('keyup', function(){
var password = idPassword.val();
checkPasswordRules(password, minLength);
});
}
$(document).ready(function(){
passwordCheck();
var origin_password_text = $("#password_help_text").text();
var new_password_text = origin_password_text.replace('{}', "{{ object.source_display }}");
$("#password_help_text").html(new_password_text);
var origin_ssh_key_text = $("#ssh_key_help_text").text();
var new_ssh_key_text = origin_ssh_key_text.replace('{}', "{{ object.source_display }}");
$("#ssh_key_help_text").html(new_ssh_key_text)
})
.on("submit", "form", function (evt) {
evt.preventDefault();
var the_url = '{% url 'api-users:user-detail' pk=object.id %}';
var redirect_to = '{% url "users:user-list" %}';
var method = "PUT";
var form = $("form");
var data = form.serializeObject();
objectAttrsIsList(data, ['groups']);
objectAttrsIsDatetime(data,['date_expired']);
var props = {
url: the_url,
data: data,
method: method,
form: form,
redirect_to: redirect_to
};
formSubmit(props);
})
</script>
{% endblock %}