mirror of https://github.com/jumpserver/jumpserver
[Fixture] 添加runner run record
parent
a822f667af
commit
915873135e
|
@ -23,19 +23,16 @@ class AssetCreateForm(forms.ModelForm):
|
|||
self.instance.tags.clear()
|
||||
self.instance.tags.add(*tuple(tags))
|
||||
|
||||
# def clean(self):
|
||||
# clean_data = super(AssetCreateForm, self).clean()
|
||||
# ip = clean_data.get('ip')
|
||||
# port = clean_data.get('port')
|
||||
# query = Asset.objects.filter(ip=ip, port=port)
|
||||
# if query:
|
||||
# raise forms.ValidationError('this asset has exists.')
|
||||
def clean_admin_user(self):
|
||||
if not self.cleaned_data['admin_user']:
|
||||
raise forms.ValidationError(_('Select admin user'))
|
||||
return self.cleaned_data['admin_user']
|
||||
|
||||
class Meta:
|
||||
model = Asset
|
||||
tags = forms.ModelMultipleChoiceField(queryset=Tag.objects.all())
|
||||
fields = [
|
||||
'hostname', 'ip', 'port', 'type', 'comment', 'admin_user', 'system_users', 'idc', 'groups',
|
||||
'hostname', 'ip', 'port', 'type', 'comment', 'admin_user', 'idc', 'groups',
|
||||
'other_ip', 'remote_card_ip', 'mac_address', 'brand', 'cpu', 'memory', 'disk', 'os', 'cabinet_no',
|
||||
'cabinet_pos', 'number', 'status', 'env', 'sn', 'tags',
|
||||
]
|
||||
|
@ -44,8 +41,6 @@ class AssetCreateForm(forms.ModelForm):
|
|||
'data-placeholder': _('Select asset groups')}),
|
||||
'tags': forms.SelectMultiple(attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset tags')}),
|
||||
'system_users': forms.SelectMultiple(attrs={'class': 'select2',
|
||||
'data-placeholder': _('Select asset system users')}),
|
||||
'admin_user': forms.Select(attrs={'class': 'select2', 'data-placeholder': _('Select asset admin user')}),
|
||||
}
|
||||
help_texts = {
|
||||
|
|
|
@ -94,9 +94,9 @@ class Asset(models.Model):
|
|||
'ip': self.ip,
|
||||
'port': self.port,
|
||||
'groups': [group.name for group in self.groups.all()],
|
||||
'username': self.admin_user.username,
|
||||
'password': self.admin_user.password,
|
||||
'private_key': self.admin_user.private_key,
|
||||
'username': self.admin_user.username if self.admin_user else '',
|
||||
'password': self.admin_user.password if self.admin_user else '',
|
||||
'private_key': self.admin_user.private_key if self.admin_user else None,
|
||||
}
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Asset user' %}</h3>
|
||||
{{ form.admin_user|bootstrap_horizontal }}
|
||||
{{ form.system_users|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Other' %}</h3>
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Asset user' %}</h3>
|
||||
{{ form.admin_user|bootstrap_horizontal }}
|
||||
{{ form.system_users|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Hardware' %}</h3>
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import logging
|
||||
from collections import OrderedDict
|
||||
import json
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
@ -17,10 +19,14 @@ class TaskRecord(models.Model):
|
|||
name = models.CharField(max_length=128, blank=True, verbose_name=_('Name'))
|
||||
date_start = models.DateTimeField(auto_now_add=True, verbose_name=_('Start time'))
|
||||
date_finished = models.DateTimeField(blank=True, null=True, verbose_name=_('End time'))
|
||||
timedelta = models.FloatField(default=0.0, verbose_name=_('Time'), null=True)
|
||||
is_finished = models.BooleanField(default=False, verbose_name=_('Is finished'))
|
||||
is_success = models.BooleanField(default=False, verbose_name=_('Is success'))
|
||||
assets = models.TextField(blank=True, null=True, verbose_name=_('Assets'))
|
||||
result = models.TextField(blank=True, null=True, verbose_name=_('Task result'))
|
||||
assets = models.TextField(blank=True, null=True, verbose_name=_('Assets for hostname')) # Asset inventory may be change
|
||||
_modules_args = models.TextField(blank=True, null=True, verbose_name=_('Task module and args json format'))
|
||||
pattern = models.CharField(max_length=64, default='all', verbose_name=_('Task run pattern'))
|
||||
result = models.TextField(blank=True, null=True, verbose_name=_('Task raw result'))
|
||||
summary = models.TextField(blank=True, null=True, verbose_name=_('Task summary'))
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s" % self.uuid
|
||||
|
@ -29,3 +35,25 @@ class TaskRecord(models.Model):
|
|||
def total_assets(self):
|
||||
return self.assets.split(',')
|
||||
|
||||
@property
|
||||
def assets_json(self):
|
||||
from assets.models import Asset
|
||||
return [Asset.objects.get(hostname=hostname)._to_secret_json()
|
||||
for hostname in self.total_assets
|
||||
if Asset.objects.exists(hostname=hostname)]
|
||||
|
||||
@property
|
||||
def module_args(self):
|
||||
task_tuple = []
|
||||
for module, args in json.loads(self._modules_args, object_pairs_hook=OrderedDict).items():
|
||||
task_tuple.append((module, args))
|
||||
return task_tuple
|
||||
|
||||
@module_args.setter
|
||||
def module_args(self, task_tuple):
|
||||
module_args_ = OrderedDict({})
|
||||
for module, args in task_tuple:
|
||||
module_args_[module] = args
|
||||
self._modules_args = json.dumps(module_args_)
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# coding: utf-8
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
import json
|
||||
import time
|
||||
|
||||
|
||||
|
@ -33,13 +34,50 @@ def asset_test_ping_check(assets):
|
|||
return result['contacted'].keys(), result['dark'].keys()
|
||||
|
||||
|
||||
@shared_task(bind=True)
|
||||
def run_AdHoc(self, task_tuple, assets,
|
||||
task_name='Ansible AdHoc runner', pattern='all', record=True):
|
||||
|
||||
runner = AdHocRunner(assets)
|
||||
if record:
|
||||
from .models import TaskRecord
|
||||
if not TaskRecord.objects.filter(uuid=self.request.id):
|
||||
record = TaskRecord(uuid=self.request.id,
|
||||
name=task_name,
|
||||
assets=','.join(asset['hostname'] for asset in assets),
|
||||
module_args=task_tuple,
|
||||
pattern=pattern)
|
||||
record.save()
|
||||
else:
|
||||
record = TaskRecord.objects.get(uuid=self.request.id)
|
||||
record.date_start = timezone.now()
|
||||
ts_start = time.time()
|
||||
logger.warn('Start runner {}'.format(task_name))
|
||||
result = runner.run(task_tuple, pattern=pattern, task_name=task_name)
|
||||
timedelta = round(time.time() - ts_start, 2)
|
||||
summary = runner.clean_result()
|
||||
if record:
|
||||
record.date_finished = timezone.now()
|
||||
record.is_finished = True
|
||||
record.result = json.dumps(result)
|
||||
record.summary = json.dumps(summary)
|
||||
record.timedelta = timedelta
|
||||
if len(summary['failed']) == 0:
|
||||
record.is_success = True
|
||||
else:
|
||||
record.is_success = False
|
||||
record.save()
|
||||
return summary
|
||||
|
||||
|
||||
@shared_task(bind=True)
|
||||
def push_users(self, assets, users):
|
||||
"""
|
||||
user: {
|
||||
username: xxx,
|
||||
shell: /bin/bash,
|
||||
password: 'staf',
|
||||
name: 'web',
|
||||
username: 'web',
|
||||
shell: '/bin/bash',
|
||||
password: '123123123',
|
||||
public_key: 'string',
|
||||
sudo: '/bin/whoami,/sbin/ifconfig'
|
||||
}
|
||||
|
@ -49,8 +87,8 @@ def push_users(self, assets, users):
|
|||
if isinstance(assets, dict):
|
||||
assets = [assets]
|
||||
task_tuple = []
|
||||
|
||||
for user in users:
|
||||
logger.debug('Push user: {}'.format(user))
|
||||
# 添加用户, 设置公钥, 设置sudo
|
||||
task_tuple.extend([
|
||||
('user', 'name={} shell={} state=present password={}'.format(
|
||||
|
@ -65,16 +103,19 @@ def push_users(self, assets, users):
|
|||
user['username'], user.get('sudo', '/bin/whoami')
|
||||
))
|
||||
])
|
||||
record = TaskRecord(name='Push user',
|
||||
task_name = 'Push user {}'.format(','.join([user['name'] for user in users]))
|
||||
record = TaskRecord(name=task_name,
|
||||
uuid=self.request.id,
|
||||
date_start=timezone.now(),
|
||||
assets=','.join(asset['hostname'] for asset in assets))
|
||||
record.save()
|
||||
logger.info('Runner start {0}'.format(timezone.now()))
|
||||
logger.info('Runner {0} start {1}'.format(task_name, timezone.now()))
|
||||
hoc = AdHocRunner(assets)
|
||||
ts_start = time.time()
|
||||
_ = hoc.run(task_tuple)
|
||||
logger.info('Runner complete {0}'.format(timezone.now()))
|
||||
logger.info('Runner {0} complete {1}'.format(task_name, timezone.now()))
|
||||
result_clean = hoc.clean_result()
|
||||
record.time = int(time.time() - ts_start)
|
||||
record.date_finished = timezone.now()
|
||||
record.is_finished = True
|
||||
|
||||
|
@ -82,6 +123,6 @@ def push_users(self, assets, users):
|
|||
record.is_success = True
|
||||
else:
|
||||
record.is_success = False
|
||||
record.result = result_clean
|
||||
record.result = json.dumps(result_clean)
|
||||
record.save()
|
||||
return result_clean
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load bootstrap %}
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
||||
<link href="{% static "css/plugins/datepicker/datepicker3.css" %}" rel="stylesheet">
|
||||
{% 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="ibox-title">
|
||||
<h5>{% block user_template_title %}{% trans 'Create user' %}{% endblock %}</h5>
|
||||
<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>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<h3>{% trans 'Account' %}</h3>
|
||||
{% block username %} {% endblock %}
|
||||
{{ form.email|bootstrap_horizontal }}
|
||||
{{ form.name|bootstrap_horizontal }}
|
||||
{{ form.groups|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{% block password %} {% endblock %}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Security and Role' %}</h3>
|
||||
{{ form.role|bootstrap_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>
|
||||
<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' }}">
|
||||
</div>
|
||||
<span class="help-block ">{{ form.date_expired.errors }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{# {{ form.date_expired|bootstrap_horizontal }}#}
|
||||
<div class="form-group">
|
||||
<label for="{{ form.enable_otp.id_for_label }}" class="col-sm-2 control-label">{% trans 'Enable OTP' %}</label>
|
||||
<div class="col-sm-8">
|
||||
{{ form.enable_otp }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Profile' %}</h3>
|
||||
{{ form.phone|bootstrap_horizontal }}
|
||||
{{ form.wechat|bootstrap_horizontal }}
|
||||
{{ form.comment|bootstrap_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>
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/plugins/datapicker/bootstrap-datepicker.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2();
|
||||
|
||||
$('.input-group.date').datepicker({
|
||||
format: "yyyy-mm-dd",
|
||||
todayBtn: "linked",
|
||||
keyboardNavigation: false,
|
||||
forceParse: false,
|
||||
calendarWeeks: true,
|
||||
autoclose: true
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,16 +0,0 @@
|
|||
{% extends 'cron/_cron.html' %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap %}
|
||||
{% block user_template_title %}{% trans "Create user" %}{% endblock %}
|
||||
{% block username %}
|
||||
{{ form.username|bootstrap_horizontal }}
|
||||
{% endblock %}
|
||||
{% block password %}
|
||||
<h3>{% trans 'Password' %}</h3>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">{% trans 'Password' %}</label>
|
||||
<div class="col-sm-8 controls" >
|
||||
{% trans 'Reset link will be generated and sent to the user. ' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,280 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
||||
<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 'ops:page-cron-detail' pk=cron.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Cron detail' %} </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'ops:page-cron-detail' pk=cron.id %}" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset permission' %}</a>
|
||||
</li>
|
||||
<li><a href="{% url 'ops:page-cron-detail' pk=cron.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a></li>
|
||||
<li><a href="{% url 'ops:page-cron-detail' pk=cron.id %}" class="text-center"><i class="fa fa-calculator-o"></i> {% trans 'Login history' %}</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>{{ cron.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>
|
||||
<td width="20%">{% trans 'Name' %}:</td>
|
||||
<td><b>{{ cron.name }}</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 '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 cron.is_active %} checked {% 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 'Enable OTP' %}:</td>
|
||||
<td><span class="pull-right">
|
||||
<div class="switch">
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" class="onoffswitch-checkbox" {% if cron.enable_otp %} checked {% endif %}
|
||||
id="enable_otp">
|
||||
<label class="onoffswitch-label" for="enable_otp">
|
||||
<span class="onoffswitch-inner"></span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Reset password' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_reset_password" style="width: 54px">{% trans 'Reset' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Reset ssh key' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_reset_pk" style="width: 54px;">{% trans 'Reset' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Update ssh key' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_update_pk" style="width: 54px;" data-toggle="modal" data-target="#user_update_pk_modal">{% trans 'Update' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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="slct_groups" 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_add_user_group">{% trans 'Join' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
|
||||
{% for group in user_object.groups.all %}
|
||||
<tr>
|
||||
<td ><b class="bdg_user_group" data-gid={{ group.id }}>{{ group.name }}</b></td>
|
||||
<td>
|
||||
<button class="btn btn-danger pull-right btn-xs btn_delete_user_group" type="button"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'users/_user_update_pk_modal.html' %}
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
jumpserver.selected_groups = {};
|
||||
|
||||
function updateCrons(crons) {
|
||||
var the_url = "{% url 'api-ops:crontable-detail' pk=cron.id %}";
|
||||
var body = {
|
||||
id: {{ user_object.id }},
|
||||
groups: Object.assign([], crons)
|
||||
};
|
||||
var success = function(data) {
|
||||
// remove all the selected groups from select > option and rendered ul element;
|
||||
$('.select2-selection__rendered').empty();
|
||||
$('#slct_groups').val('');
|
||||
$.map(jumpserver.selected_groups, function(group_name, index) {
|
||||
$('#opt_' + index).remove();
|
||||
// change tr html of user groups.
|
||||
$('.group_edit tbody').append(
|
||||
'<tr>' +
|
||||
'<td><b class="bdg_user_group" data-gid="' + index + '">' + group_name + '</b></td>' +
|
||||
'<td><button class="btn btn-danger btn-xs pull-right btn_delete_user_group" type="button"><i class="fa fa-minus"></i></button></td>' +
|
||||
'</tr>'
|
||||
)
|
||||
});
|
||||
// clear jumpserver.selected_groups
|
||||
jumpserver.selected_groups = {};
|
||||
toastr.success('{% trans "UserGroup Update Success!" %}')
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success,
|
||||
method: 'PUT'
|
||||
});
|
||||
}
|
||||
$(document).ready(function() {
|
||||
$('.select2').select2()
|
||||
.on('select2:select', function(evt) {
|
||||
var data = evt.params.data;
|
||||
jumpserver.selected_groups[data.id] = data.text;
|
||||
}).on('select2:unselect', function(evt) {
|
||||
var data = evt.params.data;
|
||||
delete jumpserver.selected_groups[data.id]
|
||||
})
|
||||
}).on('click', '#is_active', function() {
|
||||
var the_url = "{% url 'api-ops:crontable-detail' pk=cron.id %}";
|
||||
var checked = !$(this).prop('checked');
|
||||
var body = {
|
||||
'is_active': checked
|
||||
};
|
||||
var success = '{% trans "Update Successfully!" %}';
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success_message: success
|
||||
});
|
||||
}).on('click', '#btn_add_user_group', function() {
|
||||
if (Object.keys(jumpserver.selected_groups).length === 0) {
|
||||
return false;
|
||||
}
|
||||
var user_groups = $('.bdg_user_group').map(function() {
|
||||
return $(this).data('gid');
|
||||
}).get();
|
||||
$.map(jumpserver.selected_groups, function(value, index) {
|
||||
user_groups.push(parseInt(index));
|
||||
$('#opt_' + index).remove();
|
||||
});
|
||||
updateCrons(user_groups)
|
||||
}).on('click', '.btn_delete_user_group', function() {
|
||||
var $this = $(this);
|
||||
var $tr = $this.closest('tr');
|
||||
var $badge = $tr.find('.bdg_user_group');
|
||||
var gid = $badge.data('gid');
|
||||
var group_name = $badge.html() || $badge.text();
|
||||
$('#slct_groups').append(
|
||||
'<option value="' + gid + '" id="opt_' + gid + '">' + group_name + '</option>'
|
||||
);
|
||||
$tr.remove();
|
||||
var user_groups = $('.bdg_user_group').map(function() {
|
||||
return $(this).data('gid');
|
||||
}).get();
|
||||
updateCrons(user_groups)
|
||||
}).on('click', '#btn_user_update_pk', function(){
|
||||
var $this = $(this);
|
||||
var pk = $('#txt_pk').val();
|
||||
var the_url = '{% url "api-ops:crontable-detail" pk=cron.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() {
|
||||
var msg = "{% trans 'Failed to update the user\'s SSH public key.' %}";
|
||||
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();
|
||||
}
|
||||
);
|
||||
}
|
||||
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,231 +0,0 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n static %}
|
||||
{% block table_search %}
|
||||
{% endblock %}
|
||||
{% block table_container %}
|
||||
<div class="uc pull-left m-l-5 m-r-5"><a href="{% url "users:user-create" %}" class="btn btn-sm btn-primary"> {% trans "Create cron" %} </a></div>
|
||||
{#<div class="uc pull-left"><a href="javascript:void(0);" class="btn btn-sm btn-primary" data-toggle="modal" data-target="#user_import_modal"> {% trans "Import user" %} </a></div>#}
|
||||
<table class="table table-striped table-bordered table-hover " id="cron_list_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">
|
||||
{# <div><input id="" type="checkbox" class="ipt_check_all"><label></label></div>#}
|
||||
<input id="" type="checkbox" class="ipt_check_all">
|
||||
</th>
|
||||
<th class="text-center">{% trans 'Name' %}</th>
|
||||
<th class="text-center">{% trans 'Time(minute-hour-day-month-weekday)' %}</th>
|
||||
<th class="text-center">{% trans 'Job' %}</th>
|
||||
<th class="text-center">{% trans 'User' %}</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">
|
||||
<option value="delete">{% trans 'Delete selected' %}</option>
|
||||
<option value="update">{% trans 'Update selected' %}</option>
|
||||
<option value="deactive">{% trans 'Deactive 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>
|
||||
{% include "users/_user_bulk_update_modal.html" %}
|
||||
{#{% include "users/_user_import_modal.html" %}#}
|
||||
{% endblock %}
|
||||
{% block content_bottom_left %}{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/jquery.form.min.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
var options = {
|
||||
ele: $('#cron_list_table'),
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a href="{% url "ops:page-cron-detail" pk=99991937 %}">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('99991937', rowData.id));
|
||||
}},
|
||||
{targets: 2, createdCell: function (td, cellData, rowData) {
|
||||
var cron_time_tmp = "{0}-{1}-{2}-{3}-{4}";
|
||||
var cron_time = cron_time_tmp.format(rowData.minute, rowData.hour, rowData.day, rowData.month, rowData.weekday);
|
||||
var innerHtml = '<span>' + cron_time + '</span>';
|
||||
$(td).html(innerHtml.replace('99991937', rowData.id));
|
||||
}},
|
||||
{targets: 5, createdCell: function (td, cellData, rowData) {
|
||||
var job_btn = '<a href="{% url "users:user-update" pk=99991937 %}" class="btn btn-xs btn-primary m-l-xs">{% trans "Job" %}</a>'.replace('99991937', cellData);
|
||||
var update_btn = '<a href="{% url "users:user-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('99991937', cellData);
|
||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_user_delete" data-uid="99991937">{% trans "Delete" %}</a>'.replace('99991937', cellData);
|
||||
if (rowData.id === 1 || rowData.username == "admin") {
|
||||
$(td).html(update_btn)
|
||||
} else {
|
||||
$(td).html(job_btn + update_btn + del_btn)
|
||||
}
|
||||
}}],
|
||||
ajax_url: '{% url "api-ops:crontable-list" %}',
|
||||
columns: [{data: "id"}, {data: "name" }, {data: "month" }, {data: "job" }, {data: "user" }, {data: "id" }],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
var table = jumpserver.initDataTable(options);
|
||||
|
||||
$('.buttons-pdf').click(function () {
|
||||
var users = [];
|
||||
var rows = table.rows('.selected').data();
|
||||
$.each(rows, function (index, obj) {
|
||||
users.push(obj.id)
|
||||
})
|
||||
});
|
||||
|
||||
}).on('click', '#btn_bulk_update', function(){
|
||||
var action = $('#slct_bulk_update').val();
|
||||
var $data_table = $('#cron_list_table').DataTable();
|
||||
var id_list = [];
|
||||
var plain_id_list = [];
|
||||
$data_table.rows({selected: true}).every(function(){
|
||||
id_list.push({id: this.data().id});
|
||||
plain_id_list.push(this.data().id);
|
||||
});
|
||||
if (id_list === []) {
|
||||
return false;
|
||||
}
|
||||
var the_url = "{% url 'api-users:user-list' %}";
|
||||
function doDeactive() {
|
||||
var body = $.each(id_list, function(index, user_object) {
|
||||
user_object['is_active'] = false;
|
||||
});
|
||||
APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(body)});
|
||||
$data_table.ajax.reload();
|
||||
jumpserver.checked = false;
|
||||
}
|
||||
function doDelete() {
|
||||
swal({
|
||||
title: "{% trans 'Are you sure?' %}",
|
||||
text: "{% trans 'This will delete the selected users !!!' %}",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: "{% trans 'Confirm' %}",
|
||||
closeOnConfirm: false
|
||||
}, function() {
|
||||
var success = function() {
|
||||
var msg = "{% trans 'User Deleted.' %}";
|
||||
swal("{% trans 'User Delete' %}", msg, "success");
|
||||
$('#cron_list_table').DataTable().ajax.reload();
|
||||
};
|
||||
var fail = function() {
|
||||
var msg = "{% trans 'User Deleting failed.' %}";
|
||||
swal("{% trans 'User Delete' %}", msg, "error");
|
||||
};
|
||||
var url_delete = the_url + '?id__in=' + JSON.stringify(plain_id_list);
|
||||
APIUpdateAttr({url: url_delete, method: 'DELETE', success: success, error: fail});
|
||||
jumpserver.checked = false;
|
||||
});
|
||||
}
|
||||
function doUpdate() {
|
||||
$('#user_bulk_update_modal').modal('show');
|
||||
}
|
||||
switch(action) {
|
||||
case 'deactive':
|
||||
doDeactive();
|
||||
break;
|
||||
case 'delete':
|
||||
doDelete();
|
||||
break;
|
||||
case 'update':
|
||||
doUpdate();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}).on('click', '.btn_user_delete', function(){
|
||||
var $this = $(this);
|
||||
function doDelete() {
|
||||
var uid = $this.data('uid');
|
||||
var the_url = '{% url "api-users:user-detail" pk=99991937 %}'.replace('99991937', uid);
|
||||
var body = {};
|
||||
var success = function() {
|
||||
var msg = "{% trans 'User Deleted.' %}";
|
||||
swal("{% trans 'User Delete' %}", msg, "success");
|
||||
$('#cron_list_table').DataTable().ajax.reload();
|
||||
};
|
||||
var fail = function() {
|
||||
var msg = "{% trans 'User Deleting failed.' %}";
|
||||
swal("{% trans 'User Delete' %}", msg, "error");
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'DELETE',
|
||||
success: success,
|
||||
error: fail
|
||||
});
|
||||
}
|
||||
swal({
|
||||
title: "{% trans 'Are you sure?' %}",
|
||||
text: "{% trans 'This will delete the selected user.' %}",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: "{% trans 'Confirm' %}",
|
||||
closeOnConfirm: false
|
||||
}, function() {
|
||||
doDelete();
|
||||
});
|
||||
}).on('click', '#btn_user_bulk_update', function(){
|
||||
var json_data = $('#fm_user_bulk_update').serializeObject();
|
||||
var body = {};
|
||||
body.enable_otp = (json_data.enable_otp === 'on')? true: false;
|
||||
if (json_data.role != '') {
|
||||
body.role = json_data.role;
|
||||
}
|
||||
if (json_data.groups != undefined) {
|
||||
body.groups = json_data.groups;
|
||||
}
|
||||
if (typeof body.groups === 'string') {
|
||||
body.groups = [parseInt(body.groups)]
|
||||
} else if(typeof body.groups === 'array') {
|
||||
new_groups = body.groups.map(Number);
|
||||
body.groups = new_groups;
|
||||
}
|
||||
var $data_table = $('#cron_list_table').DataTable()
|
||||
var post_list = [];
|
||||
$data_table.rows({selected: true}).every(function(){
|
||||
var content = Object.assign({id: this.data().id}, body);
|
||||
post_list.push(content);
|
||||
});
|
||||
if (post_list === []) {
|
||||
return false
|
||||
}
|
||||
var the_url = "{% url 'api-users:user-list' %}";
|
||||
var success = function() {
|
||||
var msg = "{% trans 'The selected users has been updated successfully.' %}";
|
||||
swal("{% trans 'User Updated' %}", msg, "success");
|
||||
$('#cron_list_table').DataTable().ajax.reload();
|
||||
jumpserver.checked = false;
|
||||
};
|
||||
APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(post_list), success: success});
|
||||
$('#user_bulk_update_modal').modal('hide');
|
||||
}).on('click', '#btn_user_import', function() {
|
||||
var $form = $('#fm_user_import');
|
||||
$form.find('.help-block').remove();
|
||||
function success (data) {
|
||||
if (data.success === false) {
|
||||
var $help = $form.find('.help-block');
|
||||
$('<span />', {class: 'help-block text-danger'}).html(data.msg).insertAfter($('#id_excel'));
|
||||
} else {
|
||||
$('#user_import_modal').modal('hide');
|
||||
var $data_table = $('#cron_list_table').DataTable();
|
||||
toastr.success("{% trans 'Import User Success.' %}");
|
||||
$data_table.ajax.reload();
|
||||
}
|
||||
}
|
||||
$form.ajaxSubmit({success: success});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
{% extends 'cron/_cron.html' %}
|
||||
{% load i18n %}
|
||||
{% block user_template_title %}{% trans "Update user" %}{% endblock %}
|
||||
{% block username %}
|
||||
<div class="form-group">
|
||||
<label for="{{ form.username.id_for_label }}" class="col-sm-2 control-label">{% trans 'Username' %}</label>
|
||||
<div class="col-sm-9 controls" >
|
||||
<input id="{{ form.username.id_for_label }}" name="{{ form.username.html_name }}" type="text" value="{{ user_object.username }}" readonly class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block password %}
|
||||
<h3>{% trans 'Password' %}</h3>
|
||||
<div class="form-group">
|
||||
<label for="password" class="col-sm-2 control-label">{% trans 'Password' %}</label>
|
||||
<div class="col-sm-9 controls" >
|
||||
<input id="password" name="password" type="password" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,147 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
||||
<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 'Task record detail' %} </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>{{ 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 width="20%">{% trans 'UUID' %}:</td>
|
||||
<td><b>{{ object.uuid }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%">{% trans 'Name' %}:</td>
|
||||
<td><b>{{ object.name }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date start' %}:</td>
|
||||
<td><b>{{ object.date_start}}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date finished' %}:</td>
|
||||
<td><b>{{ object.date_finished }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Time delta' %}:</td>
|
||||
<td><b>{{ object.timedelta}} s</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Is finished' %}:</td>
|
||||
<td><b>{{ object.is_finished }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Is success ' %}:</td>
|
||||
<td><b>{{ object.is_success }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Assets ' %}:</td>
|
||||
<td>
|
||||
<b>
|
||||
{% for asset in object.total_assets %}
|
||||
{{ asset }} <br/>
|
||||
{% endfor %}
|
||||
</b>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5" style="padding-left: 0;padding-right: 0">
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Failed assets' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
{% for host, msg in results.failed %}
|
||||
{% if forloop.first %}
|
||||
<tr class="no-borders-tr">
|
||||
{% else %}
|
||||
<tr>
|
||||
{% endif %}
|
||||
<td>{{ host }}: </td>
|
||||
<td>{{ msg }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr class="no-borders-tr">
|
||||
<td>{% trans 'No assets' %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-info-circle"></i> {% trans 'Success assets' %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
{% for host in results.success %}
|
||||
{% if forloop.first %}
|
||||
<tr class="no-borders-tr">
|
||||
{% else %}
|
||||
<tr>
|
||||
{% endif %}
|
||||
<td>{{ host }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr class="no-borders-tr">
|
||||
<td>{% trans 'No assets' %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'users/_user_update_pk_modal.html' %}
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% block content_left_head %}
|
||||
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
|
||||
<style>
|
||||
#search_btn {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block table_search %}
|
||||
<form id="search_form" method="get" action="" class="pull-right form-inline">
|
||||
<div class="form-group" id="date">
|
||||
<div class="input-daterange input-group" id="datepicker">
|
||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
||||
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_from" value="{{ date_from }}">
|
||||
<span class="input-group-addon">to</span>
|
||||
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_to" value="{{ date_to }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control input-sm" name="keyword" placeholder="Keyword" value="{{ keyword }}">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
|
||||
搜索
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block table_head %}
|
||||
<th></th>
|
||||
<th class="text-center">{% trans 'Name' %}</th>
|
||||
<th class="text-center">{% trans 'Asset' %}</th>
|
||||
<th class="text-center">{% trans 'Success' %}</th>
|
||||
<th class="text-center">{% trans 'Finished' %}</th>
|
||||
<th class="text-center">{% trans 'Date start' %}</th>
|
||||
<th class="text-center">{% trans 'Time' %}</th>
|
||||
<th class="text-center">{% trans 'Action' %}</th>
|
||||
{% endblock %}
|
||||
|
||||
{% block table_body %}
|
||||
{% for object in task_record_list %}
|
||||
<tr class="gradeX">
|
||||
<td class="text-center"><input type="checkbox" class="cbx-term"> </td>
|
||||
<td class="text-center"><a href="{% url 'ops:task-record-detail' pk=object.uuid %}">{{ object.name }}</a></td>
|
||||
<td class="text-center">{{ object.total_assets|length }}</td>
|
||||
<td class="text-center">
|
||||
{% if object.is_success %}
|
||||
<i class="fa fa-check text-navy"></i>
|
||||
{% else %}
|
||||
<i class="fa fa-times text-danger"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
{% if object.is_finished %}
|
||||
<i class="fa fa-check text-navy"></i>
|
||||
{% else %}
|
||||
<i class="fa fa-times text-danger"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center">{{ object.date_start }}</td>
|
||||
<td class="text-center">{{ object.timedelta }} s</td>
|
||||
<td class="text-center">
|
||||
<a href="" class="btn btn-xs btn-info">{% trans "Repush" %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{# comment #}
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('table').DataTable({
|
||||
"searching": false,
|
||||
"paging": false,
|
||||
"bInfo" : false,
|
||||
"order": []
|
||||
});
|
||||
$('.select2').select2();
|
||||
$('#date .input-daterange').datepicker({
|
||||
dateFormat: 'mm/dd/yy',
|
||||
keyboardNavigation: false,
|
||||
forceParse: false,
|
||||
autoclose: true
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{# function terminateConnection(data) {#}
|
||||
{# function success() {#}
|
||||
{# window.setTimeout(function () {#}
|
||||
{# window.location.reload()#}
|
||||
{# }, 300)#}
|
||||
{# }#}
|
||||
{# var the_url = "{% url 'api-applications:terminate-connection' %}";#}
|
||||
{# APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});#}
|
||||
{# }#}
|
||||
{# $(document).ready(function() {#}
|
||||
{# $('table').DataTable({#}
|
||||
{# "searching": false,#}
|
||||
{# "paging": false,#}
|
||||
{# "bInfo" : false,#}
|
||||
{# "order": []#}
|
||||
{# });#}
|
||||
{# $('.select2').select2();#}
|
||||
{# $('#date .input-daterange').datepicker({#}
|
||||
{# dateFormat: 'mm/dd/yy',#}
|
||||
{# keyboardNavigation: false,#}
|
||||
{# forceParse: false,#}
|
||||
{# autoclose: true#}
|
||||
{# });#}
|
||||
{# }).on('click', '.btn-term', function () {#}
|
||||
{# var $this = $(this);#}
|
||||
{# var proxy_log_id = $this.attr('value');#}
|
||||
{# var data = {#}
|
||||
{# proxy_log_id: proxy_log_id#}
|
||||
{# };#}
|
||||
{# terminateConnection(data)#}
|
||||
{# }).on('click', '#btn_bulk_update', function () {#}
|
||||
{# var data = [];#}
|
||||
{# $('.cbx-term:checked').each(function () {#}
|
||||
{# data.push({proxy_log_id: $(this).attr('value')})#}
|
||||
{# });#}
|
||||
{# terminateConnection(data)#}
|
||||
{# })#}
|
||||
{# </script>#}
|
||||
{% endblock %}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load bootstrap %}
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
||||
<link href="{% static "css/plugins/datepicker/datepicker3.css" %}" rel="stylesheet">
|
||||
{% 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="ibox-title">
|
||||
<h5>{% block user_template_title %}{% trans 'Create user' %}{% endblock %}</h5>
|
||||
<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>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<h3>{% trans 'Account' %}</h3>
|
||||
{% block username %} {% endblock %}
|
||||
{{ form.email|bootstrap_horizontal }}
|
||||
{{ form.name|bootstrap_horizontal }}
|
||||
{{ form.groups|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{% block password %} {% endblock %}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Security and Role' %}</h3>
|
||||
{{ form.role|bootstrap_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>
|
||||
<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' }}">
|
||||
</div>
|
||||
<span class="help-block ">{{ form.date_expired.errors }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{# {{ form.date_expired|bootstrap_horizontal }}#}
|
||||
<div class="form-group">
|
||||
<label for="{{ form.enable_otp.id_for_label }}" class="col-sm-2 control-label">{% trans 'Enable OTP' %}</label>
|
||||
<div class="col-sm-8">
|
||||
{{ form.enable_otp }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Profile' %}</h3>
|
||||
{{ form.phone|bootstrap_horizontal }}
|
||||
{{ form.wechat|bootstrap_horizontal }}
|
||||
{{ form.comment|bootstrap_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>
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/plugins/datapicker/bootstrap-datepicker.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2();
|
||||
|
||||
$('.input-group.date').datepicker({
|
||||
format: "yyyy-mm-dd",
|
||||
todayBtn: "linked",
|
||||
keyboardNavigation: false,
|
||||
forceParse: false,
|
||||
calendarWeeks: true,
|
||||
autoclose: true
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,16 +0,0 @@
|
|||
{% extends 'sudo/_sudo.html' %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap %}
|
||||
{% block user_template_title %}{% trans "Create user" %}{% endblock %}
|
||||
{% block username %}
|
||||
{{ form.username|bootstrap_horizontal }}
|
||||
{% endblock %}
|
||||
{% block password %}
|
||||
<h3>{% trans 'Password' %}</h3>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">{% trans 'Password' %}</label>
|
||||
<div class="col-sm-8 controls" >
|
||||
{% trans 'Reset link will be generated and sent to the user. ' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,280 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
||||
<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 'ops:page-sudo-detail' pk=sudo.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Cron detail' %} </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'ops:page-sudo-detail' pk=sudo.id %}" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset permission' %}</a>
|
||||
</li>
|
||||
<li><a href="{% url 'ops:page-sudo-detail' pk=sudo.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a></li>
|
||||
<li><a href="{% url 'ops:page-sudo-detail' pk=sudo.id %}" class="text-center"><i class="fa fa-calculator-o"></i> {% trans 'Login history' %}</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>{{ sudo.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>
|
||||
<td width="20%">{% trans 'Name' %}:</td>
|
||||
<td><b>{{ sudo.name }}</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 '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 sudo.is_active %} checked {% 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 'Enable OTP' %}:</td>
|
||||
<td><span class="pull-right">
|
||||
<div class="switch">
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" class="onoffswitch-checkbox" {% if sudo.enable_otp %} checked {% endif %}
|
||||
id="enable_otp">
|
||||
<label class="onoffswitch-label" for="enable_otp">
|
||||
<span class="onoffswitch-inner"></span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Reset password' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_reset_password" style="width: 54px">{% trans 'Reset' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Reset ssh key' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_reset_pk" style="width: 54px;">{% trans 'Reset' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Update ssh key' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_update_pk" style="width: 54px;" data-toggle="modal" data-target="#user_update_pk_modal">{% trans 'Update' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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="slct_groups" 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_add_user_group">{% trans 'Join' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
|
||||
{% for group in user_object.groups.all %}
|
||||
<tr>
|
||||
<td ><b class="bdg_user_group" data-gid={{ group.id }}>{{ group.name }}</b></td>
|
||||
<td>
|
||||
<button class="btn btn-danger pull-right btn-xs btn_delete_user_group" type="button"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'users/_user_update_pk_modal.html' %}
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
jumpserver.selected_groups = {};
|
||||
|
||||
function updateCrons(crons) {
|
||||
var the_url = "{% url 'api-ops:sudo-detail' pk=sudo.id %}";
|
||||
var body = {
|
||||
id: {{ user_object.id }},
|
||||
groups: Object.assign([], crons)
|
||||
};
|
||||
var success = function(data) {
|
||||
// remove all the selected groups from select > option and rendered ul element;
|
||||
$('.select2-selection__rendered').empty();
|
||||
$('#slct_groups').val('');
|
||||
$.map(jumpserver.selected_groups, function(group_name, index) {
|
||||
$('#opt_' + index).remove();
|
||||
// change tr html of user groups.
|
||||
$('.group_edit tbody').append(
|
||||
'<tr>' +
|
||||
'<td><b class="bdg_user_group" data-gid="' + index + '">' + group_name + '</b></td>' +
|
||||
'<td><button class="btn btn-danger btn-xs pull-right btn_delete_user_group" type="button"><i class="fa fa-minus"></i></button></td>' +
|
||||
'</tr>'
|
||||
)
|
||||
});
|
||||
// clear jumpserver.selected_groups
|
||||
jumpserver.selected_groups = {};
|
||||
toastr.success('{% trans "UserGroup Update Success!" %}')
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success,
|
||||
method: 'PUT'
|
||||
});
|
||||
}
|
||||
$(document).ready(function() {
|
||||
$('.select2').select2()
|
||||
.on('select2:select', function(evt) {
|
||||
var data = evt.params.data;
|
||||
jumpserver.selected_groups[data.id] = data.text;
|
||||
}).on('select2:unselect', function(evt) {
|
||||
var data = evt.params.data;
|
||||
delete jumpserver.selected_groups[data.id]
|
||||
})
|
||||
}).on('click', '#is_active', function() {
|
||||
var the_url = "{% url 'api-ops:sudo-detail' pk=sudo.id %}";
|
||||
var checked = !$(this).prop('checked');
|
||||
var body = {
|
||||
'is_active': checked
|
||||
};
|
||||
var success = '{% trans "Update Successfully!" %}';
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success_message: success
|
||||
});
|
||||
}).on('click', '#btn_add_user_group', function() {
|
||||
if (Object.keys(jumpserver.selected_groups).length === 0) {
|
||||
return false;
|
||||
}
|
||||
var user_groups = $('.bdg_user_group').map(function() {
|
||||
return $(this).data('gid');
|
||||
}).get();
|
||||
$.map(jumpserver.selected_groups, function(value, index) {
|
||||
user_groups.push(parseInt(index));
|
||||
$('#opt_' + index).remove();
|
||||
});
|
||||
updateCrons(user_groups)
|
||||
}).on('click', '.btn_delete_user_group', function() {
|
||||
var $this = $(this);
|
||||
var $tr = $this.closest('tr');
|
||||
var $badge = $tr.find('.bdg_user_group');
|
||||
var gid = $badge.data('gid');
|
||||
var group_name = $badge.html() || $badge.text();
|
||||
$('#slct_groups').append(
|
||||
'<option value="' + gid + '" id="opt_' + gid + '">' + group_name + '</option>'
|
||||
);
|
||||
$tr.remove();
|
||||
var user_groups = $('.bdg_user_group').map(function() {
|
||||
return $(this).data('gid');
|
||||
}).get();
|
||||
updateCrons(user_groups)
|
||||
}).on('click', '#btn_user_update_pk', function(){
|
||||
var $this = $(this);
|
||||
var pk = $('#txt_pk').val();
|
||||
var the_url = '{% url "api-ops:sudo-detail" pk=sudo.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() {
|
||||
var msg = "{% trans 'Failed to update the user\'s SSH public key.' %}";
|
||||
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();
|
||||
}
|
||||
);
|
||||
}
|
||||
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,226 +0,0 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n static %}
|
||||
{% block table_search %}
|
||||
{% endblock %}
|
||||
{% block table_container %}
|
||||
<div class="uc pull-left m-l-5 m-r-5"><a href="{% url "users:user-create" %}" class="btn btn-sm btn-primary"> {% trans "Create sudo" %} </a></div>
|
||||
{#<div class="uc pull-left"><a href="javascript:void(0);" class="btn btnbtn-sm btn-primary" data-toggle="modal" data-target="#user_import_modal"> {% trans "Import user" %} </a></div>#}
|
||||
<table class="table table-striped table-bordered table-hover " id="sudo_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 'Privileges' %}</th>
|
||||
<th class="text-center">{% trans 'Extra Lines' %}</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">
|
||||
<option value="delete">{% trans 'Delete selected' %}</option>
|
||||
<option value="update">{% trans 'Update selected' %}</option>
|
||||
<option value="deactive">{% trans 'Deactive 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>
|
||||
{#{% include "users/_user_bulk_update_modal.html" %}#}
|
||||
{#{% include "users/_user_import_modal.html" %}#}
|
||||
{% endblock %}
|
||||
{% block content_bottom_left %}{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/jquery.form.min.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
var options = {
|
||||
ele: $('#sudo_list_table'),
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a href="{% url "ops:page-sudo-detail" pk=99991937 %}">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('99991937', rowData.id));
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData, rowData) {
|
||||
var update_btn = '<a href="{% url "users:user-update" pk=99991937 %}" class="btn btn-xs btn-info m-l-xs">{% trans "Update" %}</a>'.replace('99991937', cellData);
|
||||
var preview_btn = '<a href="{% url "users:user-update" pk=99991937 %}" class="btn btn-xs btn-info m-l-xs">{% trans "Preview" %}</a>'.replace('99991937', cellData);
|
||||
var job_btn = '<a href="{% url "users:user-update" pk=99991937 %}" class="btn btn-xs btn-primary m-l-xs">{% trans "Job" %}</a>'.replace('99991937', cellData);
|
||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_user_delete" data-uid="99991937">{% trans "Delete" %}</a>'.replace('99991937', cellData);
|
||||
|
||||
if (rowData.id === 1 || rowData.username == "admin") {
|
||||
$(td).html(update_btn)
|
||||
} else {
|
||||
$(td).html(preview_btn + job_btn + update_btn + del_btn)
|
||||
}
|
||||
}}],
|
||||
ajax_url: '{% url "api-ops:sudo-list" %}',
|
||||
columns: [{data: "id"}, {data: "name" }, {data: "privilege_items" }, {data: "extra_lines" }, {data: "id" }],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
var table = jumpserver.initDataTable(options);
|
||||
|
||||
$('.buttons-pdf').click(function () {
|
||||
var users = [];
|
||||
var rows = table.rows('.selected').data();
|
||||
$.each(rows, function (index, obj) {
|
||||
users.push(obj.id)
|
||||
})
|
||||
});
|
||||
|
||||
}).on('click', '#btn_bulk_update', function(){
|
||||
var action = $('#slct_bulk_update').val();
|
||||
var $data_table = $('#sudo_list_table').DataTable();
|
||||
var id_list = [];
|
||||
var plain_id_list = [];
|
||||
$data_table.rows({selected: true}).every(function(){
|
||||
id_list.push({id: this.data().id});
|
||||
plain_id_list.push(this.data().id);
|
||||
});
|
||||
if (id_list === []) {
|
||||
return false;
|
||||
}
|
||||
var the_url = "{% url 'api-users:user-list' %}";
|
||||
function doDeactive() {
|
||||
var body = $.each(id_list, function(index, user_object) {
|
||||
user_object['is_active'] = false;
|
||||
});
|
||||
APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(body)});
|
||||
$data_table.ajax.reload();
|
||||
jumpserver.checked = false;
|
||||
}
|
||||
function doDelete() {
|
||||
swal({
|
||||
title: "{% trans 'Are you sure?' %}",
|
||||
text: "{% trans 'This will delete the selected users !!!' %}",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: "{% trans 'Confirm' %}",
|
||||
closeOnConfirm: false
|
||||
}, function() {
|
||||
var success = function() {
|
||||
var msg = "{% trans 'User Deleted.' %}";
|
||||
swal("{% trans 'User Delete' %}", msg, "success");
|
||||
$('#sudo_list_table').DataTable().ajax.reload();
|
||||
};
|
||||
var fail = function() {
|
||||
var msg = "{% trans 'User Deleting failed.' %}";
|
||||
swal("{% trans 'User Delete' %}", msg, "error");
|
||||
};
|
||||
var url_delete = the_url + '?id__in=' + JSON.stringify(plain_id_list);
|
||||
APIUpdateAttr({url: url_delete, method: 'DELETE', success: success, error: fail});
|
||||
jumpserver.checked = false;
|
||||
});
|
||||
}
|
||||
function doUpdate() {
|
||||
$('#user_bulk_update_modal').modal('show');
|
||||
}
|
||||
switch(action) {
|
||||
case 'deactive':
|
||||
doDeactive();
|
||||
break;
|
||||
case 'delete':
|
||||
doDelete();
|
||||
break;
|
||||
case 'update':
|
||||
doUpdate();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}).on('click', '.btn_user_delete', function(){
|
||||
var $this = $(this);
|
||||
function doDelete() {
|
||||
var uid = $this.data('uid');
|
||||
var the_url = '{% url "api-users:user-detail" pk=99991937 %}'.replace('99991937', uid);
|
||||
var body = {};
|
||||
var success = function() {
|
||||
var msg = "{% trans 'User Deleted.' %}";
|
||||
swal("{% trans 'User Delete' %}", msg, "success");
|
||||
$('#sudo_list_table').DataTable().ajax.reload();
|
||||
};
|
||||
var fail = function() {
|
||||
var msg = "{% trans 'User Deleting failed.' %}";
|
||||
swal("{% trans 'User Delete' %}", msg, "error");
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'DELETE',
|
||||
success: success,
|
||||
error: fail
|
||||
});
|
||||
}
|
||||
swal({
|
||||
title: "{% trans 'Are you sure?' %}",
|
||||
text: "{% trans 'This will delete the selected user.' %}",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: "{% trans 'Confirm' %}",
|
||||
closeOnConfirm: false
|
||||
}, function() {
|
||||
doDelete();
|
||||
});
|
||||
}).on('click', '#btn_user_bulk_update', function(){
|
||||
var json_data = $('#fm_user_bulk_update').serializeObject();
|
||||
var body = {};
|
||||
body.enable_otp = (json_data.enable_otp === 'on')? true: false;
|
||||
if (json_data.role != '') {
|
||||
body.role = json_data.role;
|
||||
}
|
||||
if (json_data.groups != undefined) {
|
||||
body.groups = json_data.groups;
|
||||
}
|
||||
if (typeof body.groups === 'string') {
|
||||
body.groups = [parseInt(body.groups)]
|
||||
} else if(typeof body.groups === 'array') {
|
||||
new_groups = body.groups.map(Number);
|
||||
body.groups = new_groups;
|
||||
}
|
||||
var $data_table = $('#sudo_list_table').DataTable()
|
||||
var post_list = [];
|
||||
$data_table.rows({selected: true}).every(function(){
|
||||
var content = Object.assign({id: this.data().id}, body);
|
||||
post_list.push(content);
|
||||
});
|
||||
if (post_list === []) {
|
||||
return false
|
||||
}
|
||||
var the_url = "{% url 'api-users:user-list' %}";
|
||||
var success = function() {
|
||||
var msg = "{% trans 'The selected users has been updated successfully.' %}";
|
||||
swal("{% trans 'User Updated' %}", msg, "success");
|
||||
$('#sudo_list_table').DataTable().ajax.reload();
|
||||
jumpserver.checked = false;
|
||||
};
|
||||
APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(post_list), success: success});
|
||||
$('#user_bulk_update_modal').modal('hide');
|
||||
}).on('click', '#btn_user_import', function() {
|
||||
var $form = $('#fm_user_import');
|
||||
$form.find('.help-block').remove();
|
||||
function success (data) {
|
||||
if (data.success === false) {
|
||||
var $help = $form.find('.help-block');
|
||||
$('<span />', {class: 'help-block text-danger'}).html(data.msg).insertAfter($('#id_excel'));
|
||||
} else {
|
||||
$('#user_import_modal').modal('hide');
|
||||
var $data_table = $('#sudo_list_table').DataTable();
|
||||
toastr.success("{% trans 'Import User Success.' %}");
|
||||
$data_table.ajax.reload();
|
||||
}
|
||||
}
|
||||
$form.ajaxSubmit({success: success});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
{% extends 'sudo/_sudo.html' %}
|
||||
{% load i18n %}
|
||||
{% block user_template_title %}{% trans "Update user" %}{% endblock %}
|
||||
{% block username %}
|
||||
<div class="form-group">
|
||||
<label for="{{ form.username.id_for_label }}" class="col-sm-2 control-label">{% trans 'Username' %}</label>
|
||||
<div class="col-sm-9 controls" >
|
||||
<input id="{{ form.username.id_for_label }}" name="{{ form.username.html_name }}" type="text" value="{{ user_object.username }}" readonly class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block password %}
|
||||
<h3>{% trans 'Password' %}</h3>
|
||||
<div class="form-group">
|
||||
<label for="password" class="col-sm-2 control-label">{% trans 'Password' %}</label>
|
||||
<div class="col-sm-9 controls" >
|
||||
<input id="password" name="password" type="password" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,97 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load bootstrap %}
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
||||
<link href="{% static "css/plugins/datepicker/datepicker3.css" %}" rel="stylesheet">
|
||||
{% 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="ibox-title">
|
||||
<h5>{% block user_template_title %}{% trans 'Create user' %}{% endblock %}</h5>
|
||||
<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>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<h3>{% trans 'Account' %}</h3>
|
||||
{% block username %} {% endblock %}
|
||||
{{ form.email|bootstrap_horizontal }}
|
||||
{{ form.name|bootstrap_horizontal }}
|
||||
{{ form.groups|bootstrap_horizontal }}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
{% block password %} {% endblock %}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Security and Role' %}</h3>
|
||||
{{ form.role|bootstrap_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>
|
||||
<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' }}">
|
||||
</div>
|
||||
<span class="help-block ">{{ form.date_expired.errors }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{# {{ form.date_expired|bootstrap_horizontal }}#}
|
||||
<div class="form-group">
|
||||
<label for="{{ form.enable_otp.id_for_label }}" class="col-sm-2 control-label">{% trans 'Enable OTP' %}</label>
|
||||
<div class="col-sm-8">
|
||||
{{ form.enable_otp }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3>{% trans 'Profile' %}</h3>
|
||||
{{ form.phone|bootstrap_horizontal }}
|
||||
{{ form.wechat|bootstrap_horizontal }}
|
||||
{{ form.comment|bootstrap_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>
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/plugins/datapicker/bootstrap-datepicker.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.select2').select2();
|
||||
|
||||
$('.input-group.date').datepicker({
|
||||
format: "yyyy-mm-dd",
|
||||
todayBtn: "linked",
|
||||
keyboardNavigation: false,
|
||||
forceParse: false,
|
||||
calendarWeeks: true,
|
||||
autoclose: true
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,16 +0,0 @@
|
|||
{% extends 'sudo/_sudo.html' %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap %}
|
||||
{% block user_template_title %}{% trans "Create user" %}{% endblock %}
|
||||
{% block username %}
|
||||
{{ form.username|bootstrap_horizontal }}
|
||||
{% endblock %}
|
||||
{% block password %}
|
||||
<h3>{% trans 'Password' %}</h3>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">{% trans 'Password' %}</label>
|
||||
<div class="col-sm-8 controls" >
|
||||
{% trans 'Reset link will be generated and sent to the user. ' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,280 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/select2/select2.min.css" %}" rel="stylesheet">
|
||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/select2/select2.full.min.js" %}"></script>
|
||||
<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 'ops:page-sudo-detail' pk=sudo.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Cron detail' %} </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'ops:page-sudo-detail' pk=sudo.id %}" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset permission' %}</a>
|
||||
</li>
|
||||
<li><a href="{% url 'ops:page-sudo-detail' pk=sudo.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a></li>
|
||||
<li><a href="{% url 'ops:page-sudo-detail' pk=sudo.id %}" class="text-center"><i class="fa fa-calculator-o"></i> {% trans 'Login history' %}</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>{{ sudo.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>
|
||||
<td width="20%">{% trans 'Name' %}:</td>
|
||||
<td><b>{{ sudo.name }}</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 '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 sudo.is_active %} checked {% 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 'Enable OTP' %}:</td>
|
||||
<td><span class="pull-right">
|
||||
<div class="switch">
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" class="onoffswitch-checkbox" {% if sudo.enable_otp %} checked {% endif %}
|
||||
id="enable_otp">
|
||||
<label class="onoffswitch-label" for="enable_otp">
|
||||
<span class="onoffswitch-inner"></span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Reset password' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_reset_password" style="width: 54px">{% trans 'Reset' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Reset ssh key' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_reset_pk" style="width: 54px;">{% trans 'Reset' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Update ssh key' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_update_pk" style="width: 54px;" data-toggle="modal" data-target="#user_update_pk_modal">{% trans 'Update' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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="slct_groups" 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_add_user_group">{% trans 'Join' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
|
||||
{% for group in user_object.groups.all %}
|
||||
<tr>
|
||||
<td ><b class="bdg_user_group" data-gid={{ group.id }}>{{ group.name }}</b></td>
|
||||
<td>
|
||||
<button class="btn btn-danger pull-right btn-xs btn_delete_user_group" type="button"><i class="fa fa-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'users/_user_update_pk_modal.html' %}
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
jumpserver.selected_groups = {};
|
||||
|
||||
function updateCrons(crons) {
|
||||
var the_url = "{% url 'api-ops:sudo-detail' pk=sudo.id %}";
|
||||
var body = {
|
||||
id: {{ user_object.id }},
|
||||
groups: Object.assign([], crons)
|
||||
};
|
||||
var success = function(data) {
|
||||
// remove all the selected groups from select > option and rendered ul element;
|
||||
$('.select2-selection__rendered').empty();
|
||||
$('#slct_groups').val('');
|
||||
$.map(jumpserver.selected_groups, function(group_name, index) {
|
||||
$('#opt_' + index).remove();
|
||||
// change tr html of user groups.
|
||||
$('.group_edit tbody').append(
|
||||
'<tr>' +
|
||||
'<td><b class="bdg_user_group" data-gid="' + index + '">' + group_name + '</b></td>' +
|
||||
'<td><button class="btn btn-danger btn-xs pull-right btn_delete_user_group" type="button"><i class="fa fa-minus"></i></button></td>' +
|
||||
'</tr>'
|
||||
)
|
||||
});
|
||||
// clear jumpserver.selected_groups
|
||||
jumpserver.selected_groups = {};
|
||||
toastr.success('{% trans "UserGroup Update Success!" %}')
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success,
|
||||
method: 'PUT'
|
||||
});
|
||||
}
|
||||
$(document).ready(function() {
|
||||
$('.select2').select2()
|
||||
.on('select2:select', function(evt) {
|
||||
var data = evt.params.data;
|
||||
jumpserver.selected_groups[data.id] = data.text;
|
||||
}).on('select2:unselect', function(evt) {
|
||||
var data = evt.params.data;
|
||||
delete jumpserver.selected_groups[data.id]
|
||||
})
|
||||
}).on('click', '#is_active', function() {
|
||||
var the_url = "{% url 'api-ops:sudo-detail' pk=sudo.id %}";
|
||||
var checked = !$(this).prop('checked');
|
||||
var body = {
|
||||
'is_active': checked
|
||||
};
|
||||
var success = '{% trans "Update Successfully!" %}';
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success_message: success
|
||||
});
|
||||
}).on('click', '#btn_add_user_group', function() {
|
||||
if (Object.keys(jumpserver.selected_groups).length === 0) {
|
||||
return false;
|
||||
}
|
||||
var user_groups = $('.bdg_user_group').map(function() {
|
||||
return $(this).data('gid');
|
||||
}).get();
|
||||
$.map(jumpserver.selected_groups, function(value, index) {
|
||||
user_groups.push(parseInt(index));
|
||||
$('#opt_' + index).remove();
|
||||
});
|
||||
updateCrons(user_groups)
|
||||
}).on('click', '.btn_delete_user_group', function() {
|
||||
var $this = $(this);
|
||||
var $tr = $this.closest('tr');
|
||||
var $badge = $tr.find('.bdg_user_group');
|
||||
var gid = $badge.data('gid');
|
||||
var group_name = $badge.html() || $badge.text();
|
||||
$('#slct_groups').append(
|
||||
'<option value="' + gid + '" id="opt_' + gid + '">' + group_name + '</option>'
|
||||
);
|
||||
$tr.remove();
|
||||
var user_groups = $('.bdg_user_group').map(function() {
|
||||
return $(this).data('gid');
|
||||
}).get();
|
||||
updateCrons(user_groups)
|
||||
}).on('click', '#btn_user_update_pk', function(){
|
||||
var $this = $(this);
|
||||
var pk = $('#txt_pk').val();
|
||||
var the_url = '{% url "api-ops:sudo-detail" pk=sudo.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() {
|
||||
var msg = "{% trans 'Failed to update the user\'s SSH public key.' %}";
|
||||
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();
|
||||
}
|
||||
);
|
||||
}
|
||||
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,225 +0,0 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n static %}
|
||||
{% block table_search %}
|
||||
{% endblock %}
|
||||
{% block table_container %}
|
||||
<div class="uc pull-left m-l-5 m-r-5"><a href="{% url "ops:page-task-create" %}" class="btn btn-sm btn-primary"> {% trans "Create task" %} </a></div>
|
||||
{#<div class="uc pull-left"><a href="javascript:void(0);" class="btn btnbtn-sm btn-primary" data-toggle="modal" data-target="#user_import_modal"> {% trans "Import user" %} </a></div>#}
|
||||
<table class="table table-striped table-bordered table-hover " id="sudo_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 'UUID' %}</th>
|
||||
<th class="text-center">{% trans 'Start' %}</th>
|
||||
<th class="text-center">{% trans 'Completed' %}</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">
|
||||
<option value="delete">{% trans 'Delete selected' %}</option>
|
||||
<option value="update">{% trans 'Update selected' %}</option>
|
||||
<option value="deactive">{% trans 'Deactive 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>
|
||||
$(document).ready(function(){
|
||||
var options = {
|
||||
ele: $('#sudo_list_table'),
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a href="{% url "ops:page-task-detail" pk=99991937 %}">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('99991937', rowData.id));
|
||||
}},
|
||||
{targets: 3, 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: 4, createdCell: function (td, cellData) {
|
||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_user_delete" data-uid="99991937">{% trans "Delete" %}</a>'.replace('99991937', cellData)
|
||||
$(td).html(del_btn)
|
||||
|
||||
}}],
|
||||
ajax_url: '{% url "api-ops:task-list" %}',
|
||||
columns: [{data: "name"}, {data: "uuid" }, {data: "start" }, {data: "completed" }, {data: "id" }],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
var table = jumpserver.initDataTable(options);
|
||||
|
||||
$('.buttons-pdf').click(function () {
|
||||
var users = [];
|
||||
var rows = table.rows('.selected').data();
|
||||
$.each(rows, function (index, obj) {
|
||||
users.push(obj.id)
|
||||
})
|
||||
});
|
||||
|
||||
}).on('click', '#btn_bulk_update', function(){
|
||||
var action = $('#slct_bulk_update').val();
|
||||
var $data_table = $('#sudo_list_table').DataTable();
|
||||
var id_list = [];
|
||||
var plain_id_list = [];
|
||||
$data_table.rows({selected: true}).every(function(){
|
||||
id_list.push({id: this.data().id});
|
||||
plain_id_list.push(this.data().id);
|
||||
});
|
||||
if (id_list === []) {
|
||||
return false;
|
||||
}
|
||||
var the_url = "{% url 'api-users:user-list' %}";
|
||||
function doDeactive() {
|
||||
var body = $.each(id_list, function(index, user_object) {
|
||||
user_object['is_active'] = false;
|
||||
});
|
||||
APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(body)});
|
||||
$data_table.ajax.reload();
|
||||
jumpserver.checked = false;
|
||||
}
|
||||
function doDelete() {
|
||||
swal({
|
||||
title: "{% trans 'Are you sure?' %}",
|
||||
text: "{% trans 'This will delete the selected users !!!' %}",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: "{% trans 'Confirm' %}",
|
||||
closeOnConfirm: false
|
||||
}, function() {
|
||||
var success = function() {
|
||||
var msg = "{% trans 'User Deleted.' %}";
|
||||
swal("{% trans 'User Delete' %}", msg, "success");
|
||||
$('#sudo_list_table').DataTable().ajax.reload();
|
||||
};
|
||||
var fail = function() {
|
||||
var msg = "{% trans 'User Deleting failed.' %}";
|
||||
swal("{% trans 'User Delete' %}", msg, "error");
|
||||
};
|
||||
var url_delete = the_url + '?id__in=' + JSON.stringify(plain_id_list);
|
||||
APIUpdateAttr({url: url_delete, method: 'DELETE', success: success, error: fail});
|
||||
jumpserver.checked = false;
|
||||
});
|
||||
}
|
||||
function doUpdate() {
|
||||
$('#user_bulk_update_modal').modal('show');
|
||||
}
|
||||
switch(action) {
|
||||
case 'deactive':
|
||||
doDeactive();
|
||||
break;
|
||||
case 'delete':
|
||||
doDelete();
|
||||
break;
|
||||
case 'update':
|
||||
doUpdate();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}).on('click', '.btn_user_delete', function(){
|
||||
var $this = $(this);
|
||||
function doDelete() {
|
||||
var uid = $this.data('uid');
|
||||
var the_url = '{% url "api-users:user-detail" pk=99991937 %}'.replace('99991937', uid);
|
||||
var body = {};
|
||||
var success = function() {
|
||||
var msg = "{% trans 'User Deleted.' %}";
|
||||
swal("{% trans 'User Delete' %}", msg, "success");
|
||||
$('#sudo_list_table').DataTable().ajax.reload();
|
||||
};
|
||||
var fail = function() {
|
||||
var msg = "{% trans 'User Deleting failed.' %}";
|
||||
swal("{% trans 'User Delete' %}", msg, "error");
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'DELETE',
|
||||
success: success,
|
||||
error: fail
|
||||
});
|
||||
}
|
||||
swal({
|
||||
title: "{% trans 'Are you sure?' %}",
|
||||
text: "{% trans 'This will delete the selected user.' %}",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: "{% trans 'Confirm' %}",
|
||||
closeOnConfirm: false
|
||||
}, function() {
|
||||
doDelete();
|
||||
});
|
||||
}).on('click', '#btn_user_bulk_update', function(){
|
||||
var json_data = $('#fm_user_bulk_update').serializeObject();
|
||||
var body = {};
|
||||
body.enable_otp = (json_data.enable_otp === 'on')? true: false;
|
||||
if (json_data.role != '') {
|
||||
body.role = json_data.role;
|
||||
}
|
||||
if (json_data.groups != undefined) {
|
||||
body.groups = json_data.groups;
|
||||
}
|
||||
if (typeof body.groups === 'string') {
|
||||
body.groups = [parseInt(body.groups)]
|
||||
} else if(typeof body.groups === 'array') {
|
||||
new_groups = body.groups.map(Number);
|
||||
body.groups = new_groups;
|
||||
}
|
||||
var $data_table = $('#sudo_list_table').DataTable()
|
||||
var post_list = [];
|
||||
$data_table.rows({selected: true}).every(function(){
|
||||
var content = Object.assign({id: this.data().id}, body);
|
||||
post_list.push(content);
|
||||
});
|
||||
if (post_list === []) {
|
||||
return false
|
||||
}
|
||||
var the_url = "{% url 'api-users:user-list' %}";
|
||||
var success = function() {
|
||||
var msg = "{% trans 'The selected users has been updated successfully.' %}";
|
||||
swal("{% trans 'User Updated' %}", msg, "success");
|
||||
$('#sudo_list_table').DataTable().ajax.reload();
|
||||
jumpserver.checked = false;
|
||||
};
|
||||
APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(post_list), success: success});
|
||||
$('#user_bulk_update_modal').modal('hide');
|
||||
}).on('click', '#btn_user_import', function() {
|
||||
var $form = $('#fm_user_import');
|
||||
$form.find('.help-block').remove();
|
||||
function success (data) {
|
||||
if (data.success === false) {
|
||||
var $help = $form.find('.help-block');
|
||||
$('<span />', {class: 'help-block text-danger'}).html(data.msg).insertAfter($('#id_excel'));
|
||||
} else {
|
||||
$('#user_import_modal').modal('hide');
|
||||
var $data_table = $('#sudo_list_table').DataTable();
|
||||
toastr.success("{% trans 'Import User Success.' %}");
|
||||
$data_table.ajax.reload();
|
||||
}
|
||||
}
|
||||
$form.ajaxSubmit({success: success});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
{% extends 'sudo/_sudo.html' %}
|
||||
{% load i18n %}
|
||||
{% block user_template_title %}{% trans "Update user" %}{% endblock %}
|
||||
{% block username %}
|
||||
<div class="form-group">
|
||||
<label for="{{ form.username.id_for_label }}" class="col-sm-2 control-label">{% trans 'Username' %}</label>
|
||||
<div class="col-sm-9 controls" >
|
||||
<input id="{{ form.username.id_for_label }}" name="{{ form.username.html_name }}" type="text" value="{{ user_object.username }}" readonly class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block password %}
|
||||
<h3>{% trans 'Password' %}</h3>
|
||||
<div class="form-group">
|
||||
<label for="password" class="col-sm-2 control-label">{% trans 'Password' %}</label>
|
||||
<div class="col-sm-9 controls" >
|
||||
<input id="password" name="password" type="password" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -3,11 +3,12 @@ from __future__ import unicode_literals
|
|||
|
||||
|
||||
from django.conf.urls import url
|
||||
from ops import views as page_view
|
||||
from .. import views
|
||||
|
||||
__all__ = ["urlpatterns"]
|
||||
|
||||
urlpatterns = [
|
||||
# TResource Task url
|
||||
url(r'^task/list$', page_view.TaskListView.as_view(), name='page-task-list'),
|
||||
url(r'^task-record/$', views.TaskRecordListView.as_view(), name='task-record-list'),
|
||||
url(r'^task-record/(?P<pk>[0-9a-zA-Z-]+)/$', views.TaskRecordDetailView.as_view(), name='task-record-detail'),
|
||||
]
|
|
@ -1,11 +1,37 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
from collections import defaultdict
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
|
||||
class CommandResultCallback(CallbackBase):
|
||||
def __init__(self, display=None):
|
||||
self.result_q = dict(contacted={}, dark={})
|
||||
super(CommandResultCallback, self).__init__(display)
|
||||
|
||||
def gather_result(self, n, res):
|
||||
self.result_q[n][res._host.name] = {}
|
||||
self.result_q[n][res._host.name]['cmd'] = res._result.get('cmd')
|
||||
self.result_q[n][res._host.name]['stderr'] = res._result.get('stderr')
|
||||
self.result_q[n][res._host.name]['stdout'] = res._result.get('stdout')
|
||||
self.result_q[n][res._host.name]['rc'] = res._result.get('rc')
|
||||
|
||||
def v2_runner_on_ok(self, result):
|
||||
self.gather_result("contacted", result)
|
||||
|
||||
def v2_runner_on_failed(self, result, ignore_errors=False):
|
||||
self.gather_result("dark", result)
|
||||
|
||||
def v2_runner_on_unreachable(self, result):
|
||||
self.gather_result("dark", result)
|
||||
|
||||
def v2_runner_on_skipped(self, result):
|
||||
self.gather_result("dark", result)
|
||||
|
||||
|
||||
class AdHocResultCallback(CallbackBase):
|
||||
"""
|
||||
Custom Callback
|
||||
AdHoc result Callback
|
||||
"""
|
||||
def __init__(self, display=None):
|
||||
self.result_q = dict(contacted={}, dark={})
|
||||
|
|
|
@ -14,7 +14,8 @@ from ansible.utils.vars import load_extra_vars
|
|||
from ansible.utils.vars import load_options_vars
|
||||
|
||||
from .inventory import JMSInventory
|
||||
from .callback import AdHocResultCallback, PlaybookResultCallBack
|
||||
from .callback import AdHocResultCallback, PlaybookResultCallBack, \
|
||||
CommandResultCallback
|
||||
from common.utils import get_logger
|
||||
|
||||
|
||||
|
@ -29,6 +30,7 @@ class AnsibleError(StandardError):
|
|||
pass
|
||||
|
||||
|
||||
# Jumpserver not use playbook
|
||||
class PlayBookRunner(object):
|
||||
"""
|
||||
用于执行AnsiblePlaybook的接口.简化Playbook对象的使用.
|
||||
|
@ -136,6 +138,8 @@ class AdHocRunner(object):
|
|||
]
|
||||
)
|
||||
|
||||
results_callback_class = AdHocResultCallback
|
||||
|
||||
def __init__(self,
|
||||
hosts=C.DEFAULT_HOST_LIST,
|
||||
forks=C.DEFAULT_FORKS, # 5
|
||||
|
@ -156,7 +160,7 @@ class AdHocRunner(object):
|
|||
self.variable_manager = VariableManager()
|
||||
self.loader = DataLoader()
|
||||
self.gather_facts = gather_facts
|
||||
self.results_callback = AdHocResultCallback()
|
||||
self.results_callback = AdHocRunner.results_callback_class()
|
||||
self.options = self.Options(
|
||||
connection=connection_type,
|
||||
timeout=timeout,
|
||||
|
@ -171,7 +175,8 @@ class AdHocRunner(object):
|
|||
private_key_file=private_key_file,
|
||||
)
|
||||
|
||||
self.variable_manager.extra_vars = load_extra_vars(self.loader, options=self.options)
|
||||
self.variable_manager.extra_vars = load_extra_vars(self.loader,
|
||||
options=self.options)
|
||||
self.variable_manager.options_vars = load_options_vars(self.options)
|
||||
self.passwords = passwords or {}
|
||||
self.inventory = JMSInventory(hosts)
|
||||
|
@ -252,7 +257,7 @@ class AdHocRunner(object):
|
|||
"""
|
||||
:return: {
|
||||
"success": ['hostname',],
|
||||
"failed": [{'hostname': 'msg'}, {}],
|
||||
"failed": [('hostname', 'msg'), {}],
|
||||
}
|
||||
"""
|
||||
result = {'success': [], 'failed': []}
|
||||
|
@ -262,26 +267,30 @@ class AdHocRunner(object):
|
|||
for host, msgs in self.results_callback.result_q['dark'].items():
|
||||
msg = '\n'.join(['{}: {}'.format(msg.get('invocation', {}).get('module_name'),
|
||||
msg.get('msg', '')) for msg in msgs])
|
||||
result['failed'].append({host: msg})
|
||||
result['failed'].append((host, msg))
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def test_run():
|
||||
assets = [
|
||||
{
|
||||
"hostname": "192.168.152.129",
|
||||
"ip": "192.168.152.129",
|
||||
"hostname": "192.168.244.129",
|
||||
"ip": "192.168.244.129",
|
||||
"port": 22,
|
||||
"username": "root",
|
||||
"password": "redhat",
|
||||
},
|
||||
]
|
||||
task_tuple = (('shell', 'ls'), ('ping', ''))
|
||||
task_tuple = (('shell', 'ls'),)
|
||||
hoc = AdHocRunner(hosts=assets)
|
||||
hoc.results_callback = CommandResultCallback()
|
||||
ret = hoc.run(task_tuple)
|
||||
print(ret)
|
||||
|
||||
play = PlayBookRunner(assets, playbook_path='/tmp/some.yml')
|
||||
#play = PlayBookRunner(assets, playbook_path='/tmp/some.yml')
|
||||
"""
|
||||
# /tmp/some.yml
|
||||
---
|
||||
|
@ -293,7 +302,7 @@ def test_run():
|
|||
- name: exec uptime
|
||||
shell: uptime
|
||||
"""
|
||||
play.run()
|
||||
#play.run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -1,24 +1,39 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.views.generic.list import ListView
|
||||
import json
|
||||
|
||||
from django.conf import settings
|
||||
from django.views.generic import ListView, DetailView
|
||||
|
||||
from users.utils import AdminUserRequiredMixin
|
||||
from .models import TaskRecord
|
||||
|
||||
|
||||
class TaskListView(AdminUserRequiredMixin, ListView):
|
||||
class TaskRecordListView(ListView):
|
||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||
model = TaskRecord
|
||||
context_object_name = 'tasks'
|
||||
template_name = 'task/list.html'
|
||||
ordering = ('-date_start',)
|
||||
context_object_name = 'task_record_list'
|
||||
template_name = 'ops/task_record_list.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'task': 'Assets',
|
||||
'action': 'Create asset',
|
||||
'app': 'Ops',
|
||||
'action': 'Task record list',
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(TaskListView, self).get_context_data(**kwargs)
|
||||
return super(TaskRecordListView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class TaskRecordDetailView(DetailView):
|
||||
model = TaskRecord
|
||||
template_name = 'ops/task_record_detail.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': 'Ops',
|
||||
'action': 'Task record detail',
|
||||
'results': json.loads(self.object.summary),
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(TaskRecordDetailView, self).get_context_data(**kwargs)
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
<i class="fa fa-coffee"></i> <span class="nav-label">{% trans 'Job Center' %}</span><span class="fa arrow"></span>
|
||||
</a>
|
||||
<ul class="nav nav-second-level">
|
||||
<li id="task"><a href="{% url 'ops:page-task-list' %}">{% trans 'Task' %}</a></li>
|
||||
<li id="task"><a href="{% url 'ops:task-record-list' %}">{% trans 'Task Record' %}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
|
Loading…
Reference in New Issue