mirror of https://github.com/jumpserver/jumpserver
feat: 工作台区分组织 (#8040)
* perf: 工作台受组织角色控制 * perf: workspace => workbench * perf: 修改 workspace codename Co-authored-by: ibuler <ibuler@qq.com>pull/8047/head
parent
7c7d7d52b2
commit
1f8ded49fa
|
@ -55,7 +55,6 @@ urlpatterns = [
|
|||
path('profile/otp/enable/bind/', users_view.UserOtpEnableBindView.as_view(), name='user-otp-enable-bind'),
|
||||
path('profile/otp/disable/', users_view.UserOtpDisableView.as_view(),
|
||||
name='user-otp-disable'),
|
||||
path('first-login/', users_view.UserFirstLoginView.as_view(), name='user-first-login'),
|
||||
|
||||
# openid
|
||||
path('cas/', include(('authentication.backends.cas.urls', 'authentication'), namespace='cas')),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from django.views.generic import TemplateView
|
||||
from django.views.generic import View
|
||||
from django.shortcuts import redirect
|
||||
from common.permissions import IsValidUser
|
||||
from common.mixins.views import PermissionsMixin
|
||||
|
@ -6,8 +6,7 @@ from common.mixins.views import PermissionsMixin
|
|||
__all__ = ['IndexView']
|
||||
|
||||
|
||||
class IndexView(PermissionsMixin, TemplateView):
|
||||
template_name = 'index.html'
|
||||
class IndexView(PermissionsMixin, View):
|
||||
permission_classes = [IsValidUser]
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:17e378f009274c169039e815158ea9072ee89811bb27a5b17a628f2066fcfb86
|
||||
oid sha256:097c6d06ed8dcf2e1807560b6eb52d98cba31f25fe8d67ce4315668c150ca6b8
|
||||
size 129989
|
||||
|
|
|
@ -3188,7 +3188,7 @@ msgid "Can view audit view"
|
|||
msgstr "監査ビューを表示できます"
|
||||
|
||||
#: rbac/models/menu.py:17
|
||||
msgid "Can view workspace view"
|
||||
msgid "Can view workbench view"
|
||||
msgstr "ワークスペースビューを表示できます"
|
||||
|
||||
#: rbac/models/menu.py:18
|
||||
|
@ -3271,7 +3271,7 @@ msgid "Console view"
|
|||
msgstr "コンソールビュー"
|
||||
|
||||
#: rbac/tree.py:27
|
||||
msgid "Workspace view"
|
||||
msgid "Workbench view"
|
||||
msgstr "ワークスペースビュー"
|
||||
|
||||
#: rbac/tree.py:28
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:51c19db490e2e3a7cc3c3fce33b2e4422239d8c64d591208cadaf062c5ccb0c9
|
||||
oid sha256:3d6a0d40534209f3ffab0b0ecfab7ec82f137156fc8e7b19ce1711036d14aeca
|
||||
size 107709
|
||||
|
|
|
@ -3151,7 +3151,7 @@ msgid "Can view audit view"
|
|||
msgstr "可以显示审计台"
|
||||
|
||||
#: rbac/models/menu.py:17
|
||||
msgid "Can view workspace view"
|
||||
msgid "Can view workbench view"
|
||||
msgstr "可以显示工作台"
|
||||
|
||||
#: rbac/models/menu.py:18
|
||||
|
@ -3233,7 +3233,7 @@ msgid "Console view"
|
|||
msgstr "控制台"
|
||||
|
||||
#: rbac/tree.py:27
|
||||
msgid "Workspace view"
|
||||
msgid "Workbench view"
|
||||
msgstr "工作台"
|
||||
|
||||
#: rbac/tree.py:28
|
||||
|
|
|
@ -22,7 +22,3 @@ class AppRoleUserMixin(_RoleUserMixin):
|
|||
('get_tree', 'perms.view_myapps'),
|
||||
('GET', 'perms.view_myapps'),
|
||||
)
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
with tmp_to_root_org():
|
||||
return super().dispatch(*args, **kwargs)
|
|
@ -36,7 +36,3 @@ class AssetRoleUserMixin(PermBaseMixin, _RoleUserMixin):
|
|||
('get_tree', 'perms.view_myassets'),
|
||||
('GET', 'perms.view_myassets'),
|
||||
)
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
with tmp_to_root_org():
|
||||
return super().dispatch(*args, **kwargs)
|
||||
|
|
|
@ -202,7 +202,9 @@ class UserGrantedTreeRefreshController:
|
|||
user = self.user
|
||||
|
||||
with tmp_to_root_org():
|
||||
UserAssetGrantedTreeNodeRelation.objects.filter(user=user).exclude(org_id__in=self.org_ids).delete()
|
||||
UserAssetGrantedTreeNodeRelation.objects.filter(user=user)\
|
||||
.exclude(org_id__in=self.org_ids)\
|
||||
.delete()
|
||||
|
||||
if force or self.have_need_refresh_orgs():
|
||||
with UserGrantedTreeRebuildLock(user_id=user.id):
|
||||
|
@ -219,7 +221,9 @@ class UserGrantedTreeRefreshController:
|
|||
utils = UserGrantedTreeBuildUtils(user)
|
||||
utils.rebuild_user_granted_tree()
|
||||
logger.info(
|
||||
f'Rebuild user tree ok: cost={time.time() - t_start} user={self.user} org={current_org}')
|
||||
f'Rebuild user tree ok: cost={time.time() - t_start} '
|
||||
f'user={self.user} org={current_org}'
|
||||
)
|
||||
|
||||
|
||||
class UserGrantedUtilsBase:
|
||||
|
|
|
@ -5,7 +5,7 @@ from .const import Scope, system_exclude_permissions, org_exclude_permissions
|
|||
# Todo: 获取应该区分 系统用户,和组织用户的权限
|
||||
# 工作台也区分组织后再考虑
|
||||
user_perms = (
|
||||
('rbac', 'menupermission', 'view', 'workspace'),
|
||||
('rbac', 'menupermission', 'view', 'workbench'),
|
||||
('rbac', 'menupermission', 'view', 'webterminal'),
|
||||
('rbac', 'menupermission', 'view', 'filemanager'),
|
||||
('perms', 'permedasset', 'view,connect', 'myassets'),
|
||||
|
@ -17,6 +17,7 @@ user_perms = (
|
|||
('ops', 'commandexecution', 'add', 'commandexecution'),
|
||||
('authentication', 'connectiontoken', 'add', 'connectiontoken'),
|
||||
('tickets', 'ticket', 'view', 'ticket'),
|
||||
('orgs', 'organization', 'view', 'rootorg'),
|
||||
)
|
||||
|
||||
auditor_perms = user_perms + (
|
||||
|
|
|
@ -27,7 +27,7 @@ class Migration(migrations.Migration):
|
|||
],
|
||||
options={
|
||||
'verbose_name': 'Menu permission',
|
||||
'permissions': [('view_console', 'Can view console view'), ('view_audit', 'Can view audit view'), ('view_workspace', 'Can view workspace view')],
|
||||
'permissions': [('view_console', 'Can view console view'), ('view_audit', 'Can view audit view'), ('view_workspace', 'Can view workbench view')],
|
||||
'default_permissions': [],
|
||||
},
|
||||
),
|
||||
|
|
|
@ -12,6 +12,6 @@ class Migration(migrations.Migration):
|
|||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='menupermission',
|
||||
options={'default_permissions': [], 'permissions': [('view_console', 'Can view console view'), ('view_audit', 'Can view audit view'), ('view_workspace', 'Can view workspace view'), ('view_webterminal', 'Can view web terminal'), ('view_filemanager', 'Can view file manager')], 'verbose_name': 'Menu permission'},
|
||||
options={'default_permissions': [], 'permissions': [('view_console', 'Can view console view'), ('view_audit', 'Can view audit view'), ('view_workspace', 'Can view workbench view'), ('view_webterminal', 'Can view web terminal'), ('view_filemanager', 'Can view file manager')], 'verbose_name': 'Menu permission'},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -12,6 +12,6 @@ class Migration(migrations.Migration):
|
|||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='menupermission',
|
||||
options={'default_permissions': [], 'permissions': [('view_console', 'Can view console view'), ('view_audit', 'Can view audit view'), ('view_workspace', 'Can view workspace view'), ('view_webterminal', 'Can view web terminal'), ('view_filemanager', 'Can view file manager') ], 'verbose_name': 'Menu permission'},
|
||||
options={'default_permissions': [], 'permissions': [('view_console', 'Can view console view'), ('view_audit', 'Can view audit view'), ('view_workspace', 'Can view workbench view'), ('view_webterminal', 'Can view web terminal'), ('view_filemanager', 'Can view file manager') ], 'verbose_name': 'Menu permission'},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 3.1.14 on 2022-04-11 09:09
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def migrate_workspace_to_workbench(apps, *args):
|
||||
model = apps.get_model('auth', 'Permission')
|
||||
model.objects.filter(codename='view_workspace').delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rbac', '0007_auto_20220314_1525'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='menupermission',
|
||||
options={'default_permissions': [], 'permissions': [('view_console', 'Can view console view'), ('view_audit', 'Can view audit view'), ('view_workbench', 'Can view workbench view'), ('view_webterminal', 'Can view web terminal'), ('view_filemanager', 'Can view file manager')], 'verbose_name': 'Menu permission'},
|
||||
),
|
||||
]
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 3.1.14 on 2022-04-11 09:24
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def migrate_workspace_to_workbench(apps, *args):
|
||||
model = apps.get_model('auth', 'Permission')
|
||||
model.objects.filter(codename='view_workspace').delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rbac', '0008_auto_20220411_1709'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(migrate_workspace_to_workbench)
|
||||
]
|
|
@ -14,7 +14,7 @@ class MenuPermission(models.Model):
|
|||
permissions = [
|
||||
('view_console', _('Can view console view')),
|
||||
('view_audit', _('Can view audit view')),
|
||||
('view_workspace', _('Can view workspace view')),
|
||||
('view_workbench', _('Can view workbench view')),
|
||||
('view_webterminal', _('Can view web terminal')),
|
||||
('view_filemanager', _('Can view file manager')),
|
||||
]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/python
|
||||
import os
|
||||
from collections import defaultdict
|
||||
from typing import Callable
|
||||
import os
|
||||
|
||||
from django.utils.translation import gettext_lazy as _, gettext, get_language
|
||||
from django.conf import settings
|
||||
|
@ -24,7 +24,7 @@ root_node_data = {
|
|||
# 第二层 view 节点,手动创建的
|
||||
view_nodes_data = [
|
||||
{'id': 'view_console', 'name': _('Console view')},
|
||||
{'id': 'view_workspace', 'name': _('Workspace view')},
|
||||
{'id': 'view_workbench', 'name': _('Workbench view')},
|
||||
{'id': 'view_audit', 'name': _('Audit view')},
|
||||
{'id': 'view_setting', 'name': _('System setting')},
|
||||
{'id': 'view_other', 'name': _('Other')},
|
||||
|
@ -55,8 +55,8 @@ extra_nodes_data = [
|
|||
{"id": "app_change_plan_node", "name": _("App change auth"), "pId": "accounts"},
|
||||
{"id": "asset_change_plan_node", "name": _("Asset change auth"), "pId": "accounts"},
|
||||
{"id": "terminal_node", "name": _("Terminal setting"), "pId": "view_setting"},
|
||||
{'id': "my_assets", "name": _("My assets"), "pId": "view_workspace"},
|
||||
{'id': "my_apps", "name": _("My apps"), "pId": "view_workspace"},
|
||||
{'id': "my_assets", "name": _("My assets"), "pId": "view_workbench"},
|
||||
{'id': "my_apps", "name": _("My apps"), "pId": "view_workbench"},
|
||||
]
|
||||
|
||||
# 将 model 放到其它节点下,而不是本来的 app 中
|
||||
|
@ -89,7 +89,7 @@ special_pid_mapper = {
|
|||
'audits.ftplog': 'terminal',
|
||||
'perms.view_myassets': 'my_assets',
|
||||
'perms.view_myapps': 'my_apps',
|
||||
'ops.add_commandexecution': 'view_workspace',
|
||||
'ops.add_commandexecution': 'view_workbench',
|
||||
'ops.view_commandexecution': 'audits',
|
||||
"perms.view_mykubernetsapp": "my_apps",
|
||||
"perms.connect_mykubernetsapp": "my_apps",
|
||||
|
@ -102,9 +102,9 @@ special_pid_mapper = {
|
|||
"settings.view_setting": "view_setting",
|
||||
"rbac.view_console": "view_console",
|
||||
"rbac.view_audit": "view_audit",
|
||||
"rbac.view_workspace": "view_workspace",
|
||||
"rbac.view_webterminal": "view_workspace",
|
||||
"rbac.view_filemanager": "view_workspace",
|
||||
"rbac.view_workbench": "view_workbench",
|
||||
"rbac.view_webterminal": "view_workbench",
|
||||
"rbac.view_filemanager": "view_workbench",
|
||||
'tickets.view_ticket': 'tickets'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block help_message %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content">
|
||||
<div class="row">
|
||||
<div class="col-sm-3" id="split-left" style="padding-left: 3px;padding-right: 0">
|
||||
{% include 'assets/_node_tree.html' %}
|
||||
</div>
|
||||
<div class="col-sm-9 animated fadeInRight" id="split-right">
|
||||
<div class="tree-toggle" style="z-index: 10">
|
||||
<div class="btn btn-sm btn-primary tree-toggle-btn" onclick="toggleSpliter()">
|
||||
<i class="fa fa-angle-left fa-x" id="toggle-icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mail-box-header">
|
||||
{% block table_container %}
|
||||
<table class="table table-striped table-bordered table-hover" id="{% block table_id %}editable{% endblock %}" >
|
||||
<thead>
|
||||
<tr>
|
||||
{% block table_head %} {% endblock %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% block table_body %} {% endblock %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var showTree = 1;
|
||||
function toggleSpliter() {
|
||||
if (showTree === 1) {
|
||||
$("#split-left").hide(500, function () {
|
||||
$("#split-right").attr("class", "col-sm-12");
|
||||
$("#toggle-icon").attr("class", "fa fa-angle-right fa-x");
|
||||
showTree = 1;
|
||||
});
|
||||
} else {
|
||||
$("#split-right").attr("class", "col-sm-9");
|
||||
$("#toggle-icon").attr("class", "fa fa-angle-left fa-x");
|
||||
$("#split-left").show(500);
|
||||
showTree = 0;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,43 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load bootstrap3 %}
|
||||
{% block custom_head_css_js %}
|
||||
<script type="text/javascript" src="{% static 'js/pwstrength-bootstrap.js' %}"></script>
|
||||
{% block custom_head_css_js_create %} {% endblock %}
|
||||
{% 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>{{ action }}</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">
|
||||
{% if form.errors.all %}
|
||||
<div class="alert alert-danger" style="margin: 20px auto 0px">
|
||||
{{ form.errors.all }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% block form %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<h5>
|
||||
{{ action }}
|
||||
</h5>
|
||||
<div 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">
|
||||
<div class="" id="content_start">
|
||||
{% block content_left_head %} {% endblock %}
|
||||
{% block table_search %}
|
||||
<form id="search_form" method="get" action="" class="pull-right mail-search form-inline">
|
||||
{% block search_form %}
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control input-sm" name="keyword" placeholder="Search" value="{{ keyword }}">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
|
||||
{% trans 'Search' %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% block table_container %}
|
||||
<table class="table table-striped table-bordered table-hover" id="editable" >
|
||||
<thead>
|
||||
<tr>
|
||||
{% block table_head %} {% endblock %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% block table_body %} {% endblock %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
{% block content_bottom_left %} {% endblock %}
|
||||
</div>
|
||||
{% block table_pagination %}
|
||||
{% include '_pagination.html' %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,66 +0,0 @@
|
|||
{% load i18n %}
|
||||
{% load common_tags %}
|
||||
{% if is_paginated %}
|
||||
<div class="col-sm-4">
|
||||
<div class="dataTables_info text-center" id="editable_info" role="status" aria-live="polite">
|
||||
{# 显示第 {{ page_obj.start_index }} 至 {{ page_obj.end_index }} 项结果,共 {{ paginator.count }} 项#}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="dataTables_paginate paging_simple_numbers" id="editable_paginate">
|
||||
<ul class="pagination" style="margin-top: 0; float: right">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="paginate_button previous" aria-controls="editable" tabindex="0" id="previous">
|
||||
<a data-page="next" class="page" href="?page={{ page_obj.previous_page_number}}">‹</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% for page in paginator.num_pages|pagination_range:page_obj.number %}
|
||||
{% if page == page_obj.number %}
|
||||
<li class="paginate_button active" aria-controls="editable" tabindex="0">
|
||||
{% else %}
|
||||
<li class="paginate_button" aria-controls="editable" tabindex="0">
|
||||
{% endif %}
|
||||
<a class="page" href="?page={{ page }}" title="第{{ page }}页">{{ page }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<li class="paginate_button next" aria-controls="editable" tabindex="0" id="next">
|
||||
<a data-page="next" class="page" href="?page={{ page_obj.next_page_number }}">›</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('.page').click(function () {
|
||||
var searchStr = location.search;
|
||||
var old_href = $(this).attr('href').replace('?', '');
|
||||
var searchArray = searchStr.split('&');
|
||||
|
||||
if (searchStr === '') {
|
||||
searchStr = '?page=1'
|
||||
}
|
||||
|
||||
if (searchStr.indexOf('page') >= 0) {
|
||||
searchArray.pop();
|
||||
}
|
||||
|
||||
searchArray.push(old_href);
|
||||
if (searchArray.length > 1) {
|
||||
$(this).attr('href', searchArray.join('&'));
|
||||
}
|
||||
})
|
||||
|
||||
$('#editable_info').html(
|
||||
"{% trans 'Displays the results of items _START_ to _END_; A total of _TOTAL_ entries' %}"
|
||||
.replace('_START_', {{ page_obj.start_index }})
|
||||
.replace('_END_', {{ page_obj.end_index }})
|
||||
.replace('_TOTAL_', {{ paginator.count }})
|
||||
)
|
||||
});
|
||||
|
||||
</script>
|
|
@ -1,15 +0,0 @@
|
|||
{% load i18n %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% trans 'Confirm delete' %}</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<p>{% trans 'Are you sure delete' %} <b>{{ object.name }} </b> ?</p>
|
||||
<input type="submit" value="Confirm" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
|
@ -1,618 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content">
|
||||
<div class="row">
|
||||
<div class="col-sm-3">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-success pull-right">Users</span>
|
||||
<h5>{% trans 'Total users' %}</h5>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<h1 class="no-margins"><a href="{% url 'users:user-list' %}"><span id="total_count_users"></span></a></h1>
|
||||
<small>All users</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-info pull-right">Assets</span>
|
||||
<h5>{% trans 'Total assets' %}</h5>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<h1 class="no-margins"><a href="{% url 'assets:asset-list' %}"><span id="total_count_assets"></span></a></h1>
|
||||
<small>All assets</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary pull-right">Online</span>
|
||||
<h5>{% trans 'Online users' %}</h5>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<h1 class="no-margins"><a href="{% url 'terminal:session-online-list' %}"> <span id="total_count_online_users"></span></a></h1>
|
||||
<small>Online users</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-danger pull-right">Connected</span>
|
||||
<h5>{% trans 'Online sessions' %}</h5>
|
||||
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<h1 class="no-margins"><a href="{% url 'terminal:session-online-list' %}"> <span id="total_count_online_sessions"></span></a></h1>
|
||||
<small>Online sessions</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-2 border-bottom white-bg dashboard-header" style="margin-left:15px;height: 346px">
|
||||
<small>{% trans 'In the past week, a total of ' %}<span class="text-info" id="dates_total_count_login_users"></span>{% trans ' users have logged in ' %}<span class="text-success" id="dates_total_count_login_times"></span>{% trans ' times asset.' %}</small>
|
||||
<ul class="list-group clear-list m-t" id="dates_login_times_top5_users">
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-7" id="dates_metrics_echarts" style="margin-left: -15px;height: 346px;padding: 15px 0 15px 0;"></div>
|
||||
<div class="col-sm-3 white-bg" id="top1" style="margin-left: -15px;height: 346px">
|
||||
<div class="statistic-box">
|
||||
<h4>
|
||||
{% trans 'Active user asset ratio' %}
|
||||
</h4>
|
||||
<p>
|
||||
{% trans 'The following graphs describe the percentage of active users per month and assets per user host per month, respectively.' %}
|
||||
</p>
|
||||
<div class="row text-center">
|
||||
<div class="col-sm-6">
|
||||
<div id="dates_total_count_users_pie" style="width: 140px; height: 140px;">
|
||||
</div>
|
||||
<h5>{% trans 'User' %}</h5>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div id="dates_total_count_assets_pie" style="width: 140px; height: 140px;"></div>
|
||||
<h5>{% trans 'Asset' %}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-t">
|
||||
<small></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<h5>{% trans 'Top 10 assets in a week' %}</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>
|
||||
<ul class="dropdown-menu dropdown-user"></ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content ibox-heading">
|
||||
<h3><i class="fa fa-inbox"></i>{% trans 'Top 10 assets in a week'%}</h3>
|
||||
<small><i class="fa fa-map-marker"></i>{% trans 'Login frequency and last login record.' %}</small>
|
||||
</div>
|
||||
<div class="ibox-content inspinia-timeline" id="dates_login_times_top10_assets">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<h5>{% trans 'Last 10 login' %}</h5>
|
||||
<div class="ibox-tools">
|
||||
<span class="label label-info-light">10 Messages</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content ibox-heading">
|
||||
<h3><i class="fa fa-paper-plane-o"></i> {% trans 'Login record' %}</h3>
|
||||
<small><i class="fa fa-map-marker"></i>{% trans 'Last 10 login records.' %}</small>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div>
|
||||
<div class="feed-activity-list" id="dates_login_record_top10_sessions">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<h5>{% trans 'Top 10 users in a week' %}</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>
|
||||
<ul class="dropdown-menu dropdown-user"></ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content ibox-heading">
|
||||
<h3><i class="fa fa-user"></i>{% trans 'Top 10 users in a week' %}</h3>
|
||||
<small><i class="fa fa-map-marker"></i>{% trans 'User login frequency and last login record.' %}</small>
|
||||
</div>
|
||||
<div class="ibox-content inspinia-timeline" id="dates_login_times_top10_users">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/plugins/echarts/echarts.js' %}"></script>
|
||||
<script>
|
||||
|
||||
function requireMonthMetricsECharts(data){
|
||||
require(
|
||||
[
|
||||
'echarts',
|
||||
'echarts/chart/line'
|
||||
],
|
||||
function (ec) {
|
||||
var monthMetricsECharts = ec.init(document.getElementById('dates_metrics_echarts'));
|
||||
var option = {
|
||||
title : {
|
||||
text: "{% trans 'Monthly data overview' %}",
|
||||
subtext: "{% trans 'History summary in one month' %}",
|
||||
x: 'center'
|
||||
},
|
||||
tooltip : {
|
||||
trigger: 'axis'
|
||||
},
|
||||
backgroundColor: '#fff',
|
||||
legend: {
|
||||
data:["{% trans 'Login count' %}", "{% trans 'Active users' %}", "{% trans 'Active assets' %}"],
|
||||
y: 'bottom'
|
||||
},
|
||||
toolbox: {
|
||||
show : false,
|
||||
feature : {
|
||||
magicType : {show: true, type: ['line', 'bar']}
|
||||
}
|
||||
},
|
||||
calculable : true,
|
||||
xAxis : [
|
||||
{
|
||||
type : 'category',
|
||||
boundaryGap : false,
|
||||
data : data['dates_metrics_date'],
|
||||
}
|
||||
],
|
||||
yAxis : [
|
||||
{
|
||||
type : 'value'
|
||||
}
|
||||
],
|
||||
series : [
|
||||
{
|
||||
name: "{% trans 'Login count' %}",
|
||||
type:'line',
|
||||
smooth: true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: data['dates_metrics_total_count_login']
|
||||
},
|
||||
{
|
||||
name: "{% trans 'Active users' %}",
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: data['dates_metrics_total_count_active_users']
|
||||
},
|
||||
{
|
||||
name:"{% trans 'Active assets' %}",
|
||||
type:'line',
|
||||
smooth:true,
|
||||
itemStyle: {normal: {areaStyle: {type: 'default'}}},
|
||||
data: data['dates_metrics_total_count_active_assets']
|
||||
}
|
||||
]
|
||||
};
|
||||
monthMetricsECharts.setOption(option);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function requireMonthTotalCountUsersPie(data){
|
||||
require(
|
||||
[
|
||||
'echarts',
|
||||
'echarts/chart/pie'
|
||||
],
|
||||
function (ec) {
|
||||
var monthTotalCountUsersPie = ec.init(document.getElementById('dates_total_count_users_pie'));
|
||||
var option = {
|
||||
tooltip : {
|
||||
trigger: 'item',
|
||||
formatter: "{b} <br> {c} <br> ({d}%)"
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
orient : 'vertical',
|
||||
x : 'left',
|
||||
data:["{% trans 'Monthly active users' %}", "{% trans 'Disable user' %}", "{% trans 'Month not logged in user' %}"]
|
||||
},
|
||||
toolbox: {
|
||||
show : false,
|
||||
feature : {
|
||||
mark : {show: true},
|
||||
dataView : {show: true, readOnly: false},
|
||||
magicType : {
|
||||
show: true,
|
||||
type: ['pie', 'funnel'],
|
||||
option: {
|
||||
funnel: {
|
||||
x: '25%',
|
||||
width: '50%',
|
||||
funnelAlign: 'center',
|
||||
max: 1548
|
||||
}
|
||||
}
|
||||
},
|
||||
restore : {show: true},
|
||||
saveAsImage : {show: true}
|
||||
}
|
||||
},
|
||||
calculable : true,
|
||||
series : [
|
||||
{
|
||||
name:"{% trans 'Access to the source' %}",
|
||||
type:'pie',
|
||||
radius : ['50%', '70%'],
|
||||
avoidLabelOverlap: false,
|
||||
itemStyle : {
|
||||
normal : {
|
||||
label : {
|
||||
show : false
|
||||
},
|
||||
labelLine : {
|
||||
show : false
|
||||
}
|
||||
},
|
||||
emphasis : {
|
||||
label : {
|
||||
show : true,
|
||||
position : 'center',
|
||||
textStyle : {
|
||||
fontSize : '5',
|
||||
fontWeight : 'bold'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data:[
|
||||
{value:data['dates_total_count_active_users'], name:"{% trans 'Monthly active users' %}"},
|
||||
{value:data['dates_total_count_disabled_users'], name:"{% trans 'Disable user' %}"},
|
||||
{value:data['dates_total_count_inactive_users'], name:"{% trans 'Month not logged in user' %}"}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
monthTotalCountUsersPie.setOption(option);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function requireMonthTotalCountAssetsPie(data){
|
||||
require(
|
||||
[
|
||||
'echarts',
|
||||
'echarts/chart/pie'
|
||||
],
|
||||
function (ec) {
|
||||
var monthTotalCountAssetsPie = ec.init(document.getElementById('dates_total_count_assets_pie'));
|
||||
var option = {
|
||||
tooltip : {
|
||||
trigger: 'item',
|
||||
formatter: "{b} <br> {c} <br> ({d}%)"
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
orient : 'vertical',
|
||||
x : 'left',
|
||||
data:["{% trans 'Month is logged into the asset' %}", "{% trans 'Disable host' %}", "{% trans 'Month not logged on host' %}"]
|
||||
},
|
||||
toolbox: {
|
||||
show : false,
|
||||
feature : {
|
||||
mark : {show: true},
|
||||
dataView : {show: true, readOnly: false},
|
||||
magicType : {
|
||||
show: true,
|
||||
type: ['pie', 'funnel'],
|
||||
option: {
|
||||
funnel: {
|
||||
x: '25%',
|
||||
width: '50%',
|
||||
funnelAlign: 'center',
|
||||
max: 1548
|
||||
}
|
||||
}
|
||||
},
|
||||
restore : {show: true},
|
||||
saveAsImage : {show: true}
|
||||
}
|
||||
},
|
||||
calculable : true,
|
||||
series : [
|
||||
{
|
||||
name:"{% trans 'Access to the source' %}",
|
||||
type:'pie',
|
||||
radius : ['50%', '70%'],
|
||||
itemStyle : {
|
||||
normal : {
|
||||
label : {
|
||||
show : false
|
||||
},
|
||||
labelLine : {
|
||||
show : false
|
||||
}
|
||||
},
|
||||
emphasis : {
|
||||
label : {
|
||||
show : true,
|
||||
position : 'center',
|
||||
textStyle : {
|
||||
fontSize : '5',
|
||||
fontWeight : 'bold'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data:[
|
||||
{value:data['dates_total_count_active_assets'], name:"{% trans 'Month is logged into the host' %}"},
|
||||
{value:data['dates_total_count_disabled_assets'], name:"{% trans 'Disable host' %}"},
|
||||
{value:data['dates_total_count_inactive_assets'], name:"{% trans 'Month not logged on host' %}"}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
monthTotalCountAssetsPie.setOption(option);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var indexUrl = "/api/v1/index/";
|
||||
|
||||
function renderRequestApi(query, success, error){
|
||||
var url = indexUrl + "?" + query;
|
||||
if (!error){
|
||||
error = function (){console.log("Request url error: " + url)}
|
||||
}
|
||||
requestApi({
|
||||
url: url,
|
||||
method: "GET",
|
||||
success: success,
|
||||
error: error,
|
||||
flash_message: false,
|
||||
})
|
||||
}
|
||||
|
||||
function renderTotalCount(){
|
||||
var success = function (data) {
|
||||
$('#total_count_assets').html(data['total_count_assets']);
|
||||
$('#total_count_users').html(data['total_count_users']);
|
||||
$('#total_count_online_users').html(data['total_count_online_users']);
|
||||
$('#total_count_online_sessions').html(data['total_count_online_sessions']);
|
||||
};
|
||||
renderRequestApi('total_count=1', success);
|
||||
}
|
||||
|
||||
function renderMonthMetricsECharts(){
|
||||
var success = function (data) {
|
||||
requireMonthMetricsECharts(data)
|
||||
};
|
||||
renderRequestApi('dates_metrics=1', success)
|
||||
}
|
||||
|
||||
function renderMonthTotalCountUsersPie(){
|
||||
var success = function (data) {
|
||||
requireMonthTotalCountUsersPie(data)
|
||||
};
|
||||
renderRequestApi('dates_total_count_users=1', success)
|
||||
|
||||
}
|
||||
|
||||
function renderMonthTotalCountAssetsPie(){
|
||||
var success = function (data) {
|
||||
requireMonthTotalCountAssetsPie(data)
|
||||
};
|
||||
renderRequestApi('dates_total_count_assets=1', success)
|
||||
}
|
||||
|
||||
function renderWeekTotalCount(){
|
||||
var success = function (data) {
|
||||
$('#dates_total_count_login_users').html(data['dates_total_count_login_users']);
|
||||
$('#dates_total_count_login_times').html(data['dates_total_count_login_times'])
|
||||
};
|
||||
renderRequestApi('dates_total_count=1', success)
|
||||
}
|
||||
|
||||
function renderWeekLoginTimesTop5Users(){
|
||||
var success = function (data){
|
||||
var html = "";
|
||||
var html_cell = "" +
|
||||
"<li class=\"list-group-item fist-item\">" +
|
||||
"<span class=\"pull-right\">" +
|
||||
"{TOTAL} {% trans ' times/week' %}" +
|
||||
"</span>" +
|
||||
"<span class=\"label \">{INDEX}</span> {USER}" +
|
||||
"</li>";
|
||||
|
||||
$.each(data['dates_login_times_top5_users'], function(index, value){
|
||||
html += html_cell.replace('{TOTAL}', value['total'])
|
||||
.replace('{USER}', value['user'])
|
||||
.replace('{INDEX}', index+1)
|
||||
});
|
||||
$('#dates_login_times_top5_users').html(html)
|
||||
};
|
||||
renderRequestApi('dates_login_times_top5_users=1', success)
|
||||
}
|
||||
|
||||
function renderWeekLoginTimesTop10Assets(){
|
||||
var success = function (data){
|
||||
var html = "";
|
||||
var html_cell = "" +
|
||||
"<div class=\"timeline-item\">" +
|
||||
"<div class=\"row\">" +
|
||||
"<div class=\"col-xs-5 date ellipsis\">" +
|
||||
"<i class=\"fa fa-info-circle\"></i>" +
|
||||
"<strong data-toggle=\"tooltip\" title=\"{ASSET}\">{ASSET}</strong>" +
|
||||
"<br/>" +
|
||||
"<small class=\"text-navy\">{TOTAL}{% trans ' times' %}</small>" +
|
||||
"</div>" +
|
||||
"<div class=\"col-xs-7 content no-top-border\">" +
|
||||
"<p class=\"m-b-xs\">{% trans 'The time last logged in' %}</p>" +
|
||||
"<p>{% trans 'At' %} {DATE_LAST}</p>" +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"</div>";
|
||||
|
||||
var assets = data['dates_login_times_top10_assets'];
|
||||
if (assets.length !== 0){
|
||||
$.each(assets, function(index, value){
|
||||
html += html_cell
|
||||
.replaceAll('{ASSET}', value['asset'])
|
||||
.replace('{TOTAL}', value['total'])
|
||||
.replace('{DATE_LAST}', toSafeLocalDateStr(value['last']))
|
||||
});
|
||||
}
|
||||
else{
|
||||
html += "<p class=\"text-center\">{% trans '(No)' %}</p>"
|
||||
}
|
||||
$('#dates_login_times_top10_assets').html(html)
|
||||
};
|
||||
renderRequestApi('dates_login_times_top10_assets=1', success)
|
||||
}
|
||||
|
||||
function renderWeekLoginTimesTop10Users(){
|
||||
var success = function (data){
|
||||
var html = "";
|
||||
var html_cell = "" +
|
||||
"<div class=\"timeline-item\">" +
|
||||
"<div class=\"row\">" +
|
||||
"<div class=\"col-xs-5 date ellipsis\">" +
|
||||
"<i class=\"fa fa-info-circle\"></i>" +
|
||||
"<strong data-toggle=\"tooltip\" title=\"{USER}\">{USER}</strong>" +
|
||||
"<br/>" +
|
||||
"<small class=\"text-navy\">{TOTAL}{% trans ' times' %}</small>" +
|
||||
"</div>" +
|
||||
"<div class=\"col-xs-7 content no-top-border\">" +
|
||||
"<p class=\"m-b-xs\">{% trans 'The time last logged in' %}</p>" +
|
||||
"<p>{% trans 'At' %} {DATE_LAST}</p>" +
|
||||
"</div>" +
|
||||
"</div>" +
|
||||
"</div>";
|
||||
|
||||
var users = data['dates_login_times_top10_users'];
|
||||
if (users.length !== 0){
|
||||
$.each(users, function(index, value){
|
||||
html += html_cell.replaceAll('{USER}', value['user'])
|
||||
.replace('{TOTAL}', value['total'])
|
||||
.replace('{DATE_LAST}', toSafeLocalDateStr(value['last']))
|
||||
});
|
||||
}
|
||||
else{
|
||||
html += "<p class=\"text-center\">{% trans '(No)' %}</p>"
|
||||
}
|
||||
$('#dates_login_times_top10_users').html(html)
|
||||
};
|
||||
renderRequestApi('dates_login_times_top10_users=1', success)
|
||||
}
|
||||
|
||||
function renderWeekLoginRecordTop10Sessions(){
|
||||
var success = function (data){
|
||||
var html = "";
|
||||
var html_cell = "" +
|
||||
"<div class=\"feed-element\">" +
|
||||
"<a href=\"#\" class=\"pull-left\">" +
|
||||
"<img alt=\"image\" class=\"img-circle\" src=\"{% static 'img/avatar/user.png' %}\">" +
|
||||
"</a>" +
|
||||
"<div class=\"media-body \">" +
|
||||
"<small class=\"pull-right {TEXT_NAVY}\">{TIMESINCE} {% trans 'Before' %}</small>" +
|
||||
"<strong>{USER}</strong> {% trans 'Login in ' %}{ASSET} <br>" +
|
||||
"<small class=\"text-muted\">{DATE_START}</small>" +
|
||||
"</div>" +
|
||||
"</div>";
|
||||
|
||||
var users = data['dates_login_record_top10_sessions'];
|
||||
if (users.length !== 0){
|
||||
$.each(users, function(index, value){
|
||||
console.log(value['is_finished'])
|
||||
html += html_cell.replaceAll('{USER}', value['user'])
|
||||
.replace('{ASSET}', value['asset'])
|
||||
.replace('{DATE_START}', toSafeLocalDateStr(value['date_start']))
|
||||
.replace('{TEXT_NAVY}', value['is_finished']?'':'text-navy')
|
||||
.replace('{TIMESINCE}', value['timesince'])
|
||||
|
||||
});
|
||||
}
|
||||
else{
|
||||
html += "<p class=\"text-center\">{% trans '(No)' %}</p>"
|
||||
}
|
||||
$('#dates_login_record_top10_sessions').html(html)
|
||||
|
||||
};
|
||||
renderRequestApi('dates_login_record_top10_sessions=1', success)
|
||||
}
|
||||
|
||||
function renderData(){
|
||||
renderTotalCount();
|
||||
renderMonthMetricsECharts();
|
||||
renderMonthTotalCountUsersPie();
|
||||
renderMonthTotalCountAssetsPie();
|
||||
renderWeekTotalCount();
|
||||
renderWeekLoginTimesTop5Users();
|
||||
renderWeekLoginTimesTop10Assets();
|
||||
renderWeekLoginRecordTop10Sessions();
|
||||
renderWeekLoginTimesTop10Users();
|
||||
}
|
||||
|
||||
require.config({
|
||||
paths: {
|
||||
'echarts': '/static/js/plugins/echarts/chart/',
|
||||
'echarts/chart/line': '/static/js/plugins/echarts/chart/line',
|
||||
'echarts/chart/pie': '/static/js/plugins/echarts/chart/pie'
|
||||
}
|
||||
});
|
||||
|
||||
$(document).ready(function(){
|
||||
$('#show').click(function(){
|
||||
$('#show').css('display', 'none');
|
||||
$('#more').css('display', 'block');
|
||||
});
|
||||
$("[data-toggle='tooltip']").tooltip();
|
||||
renderData()
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
|
@ -42,10 +42,9 @@ class MySessionAPIView(generics.ListAPIView):
|
|||
serializer_class = serializers.SessionSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
with tmp_to_root_org():
|
||||
user = self.request.user
|
||||
qs = Session.objects.filter(user_id=user.id)
|
||||
return qs
|
||||
user = self.request.user
|
||||
qs = Session.objects.filter(user_id=user.id)
|
||||
return qs
|
||||
|
||||
|
||||
class SessionViewSet(OrgBulkModelViewSet):
|
||||
|
|
|
@ -24,10 +24,11 @@ class TicketSessionApi(views.APIView):
|
|||
|
||||
def get(self, request, *args, **kwargs):
|
||||
with tmp_to_root_org():
|
||||
ticketsession = TicketSession.objects.filter(ticket=self.kwargs['ticket_id']).first()
|
||||
if not ticketsession:
|
||||
tid = self.kwargs['ticket_id']
|
||||
ticket_session = TicketSession.objects.filter(ticket=tid).first()
|
||||
if not ticket_session:
|
||||
return Response(status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
session = ticketsession.session
|
||||
session = ticket_session.session
|
||||
serializer = SessionSerializer(session)
|
||||
return Response(serializer.data)
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% 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">
|
||||
{% include 'users/_user_detail_nav_header.html' %}
|
||||
|
||||
{% block content_nav_delete_update %}
|
||||
{% endblock %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
{% block content_table %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,222 +0,0 @@
|
|||
{% load i18n %}
|
||||
<div class="col-lg-3" style="padding-left: 0" id="split-left">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-content mailbox-content" style="padding-top: 0">
|
||||
<div class="file-manager ">
|
||||
<div id="assetTree" class="ztree">
|
||||
{% trans 'Loading' %} ...
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-9 animated fadeInRight" id="split-right">
|
||||
<div class="tree-toggle">
|
||||
<div class="btn btn-sm btn-primary tree-toggle-btn" onclick="toggle()">
|
||||
<i class="fa fa-angle-left fa-x" id="toggle-icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mail-box-header">
|
||||
<table class="table table-striped table-bordered table-hover" id="user_assets_table" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center"><input type="checkbox" class="ipt_check_all"></th>
|
||||
<th class="text-center">{% trans 'Hostname' %}</th>
|
||||
<th class="text-center">{% trans 'IP' %}</th>
|
||||
<th class="text-center">{% trans 'System user' %}</th>
|
||||
{% if show_actions %}
|
||||
<th class="text-center">{% trans 'Action' %}</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var zTree;
|
||||
var inited = false;
|
||||
var url;
|
||||
var assetTable;
|
||||
var treeUrl = "NeedInput";
|
||||
var assetTableUrl = 'NeedInput';
|
||||
var selectUrl = 'NeedInput';
|
||||
var systemUsersUrl = "NeedInput";
|
||||
var showAssetHref = true; // Need input default true
|
||||
var actions = {};
|
||||
var labels = '';
|
||||
var requesting = false;
|
||||
|
||||
function initTable() {
|
||||
if (inited){
|
||||
return assetTable
|
||||
} else {
|
||||
inited = true;
|
||||
}
|
||||
var options = {
|
||||
ele: $('#user_assets_table'),
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
cellData = htmlEscape(cellData);
|
||||
var assetDetailUrl = '{% url 'assets:asset-detail' pk=DEFAULT_PK %}'
|
||||
.replace("{{ DEFAULT_PK }}", rowData.id);
|
||||
var detailBtn = '<a href="assetDetailUrl" class="asset-detail" data-asset="assetId">' + cellData + '</a>';
|
||||
if (showAssetHref) {
|
||||
cellData = detailBtn.replace("assetDetailUrl", assetDetailUrl);
|
||||
} else {
|
||||
detailBtn = detailBtn.replace("assetId", rowData.id);
|
||||
cellData = detailBtn.replace("assetDetailUrl", "");
|
||||
}
|
||||
$(td).html(cellData);
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
var innerHtml = '<a class="btn-show-system-users" data-aid="99999999"> {% trans "Show" %} </a>'
|
||||
.replace('99999999', cellData);
|
||||
$(td).html(innerHtml);
|
||||
|
||||
}},
|
||||
],
|
||||
ajax_url: assetTableUrl,
|
||||
columns: [
|
||||
{data: "id"}, {data: "hostname" }, {data: "ip" },
|
||||
{data: "id", orderable: false},
|
||||
{% if show_actions %}
|
||||
{data: "id", orderable: false}
|
||||
{% endif %}
|
||||
]
|
||||
};
|
||||
{% if show_actions %}
|
||||
options.columnDefs.push(actions);
|
||||
{% endif %}
|
||||
assetTable = jumpserver.initServerSideDataTable(options);
|
||||
return assetTable
|
||||
}
|
||||
|
||||
function onSelected(event, treeNode) {
|
||||
var node_id = treeNode.meta.node.id;
|
||||
url = selectUrl.replace("{{ DEFAULT_PK }}", node_id);
|
||||
assetTable.ajax.url(url);
|
||||
assetTable.ajax.reload();
|
||||
}
|
||||
|
||||
|
||||
function initTree(refresh) {
|
||||
var asyncUrl = setUrlParam(treeUrl, 'cache_policy', '1');
|
||||
var setting = {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showLine: true
|
||||
},
|
||||
data: {
|
||||
simpleData: {
|
||||
enable: true
|
||||
}
|
||||
},
|
||||
async: {
|
||||
enable: true,
|
||||
url: asyncUrl,
|
||||
autoParam: ["id=key", "name=n", "level=lv"],
|
||||
type: 'get'
|
||||
},
|
||||
callback: {
|
||||
onSelected: onSelected
|
||||
}
|
||||
};
|
||||
|
||||
$.get(treeUrl, function(data, status) {
|
||||
if (data.length === 0) {
|
||||
data.push({"name": "{% trans 'empty' %}", "id": ""})
|
||||
}
|
||||
zTree = $.fn.zTree.init($("#assetTree"), setting, data);
|
||||
if (!refresh) {
|
||||
initTable();
|
||||
}
|
||||
rootNodeAddDom(zTree, function () {
|
||||
treeUrl = setUrlParam(treeUrl, 'cache_policy', '2');
|
||||
initTree(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getGrantedAssetSystemUsers(assetID, success) {
|
||||
var url = systemUsersUrl.replace("{{ DEFAULT_PK }}", assetID);
|
||||
requestApi({
|
||||
url: url,
|
||||
method: "GET",
|
||||
success: success,
|
||||
flash_message: false
|
||||
})
|
||||
}
|
||||
|
||||
function loadLabels() {
|
||||
var labelListUrl = '{% url "api-assets:label-list" %}';
|
||||
var label = '<li><a style="font-weight: bolder">labelName:labelValue</a></li>';
|
||||
if (requesting) {
|
||||
return
|
||||
}
|
||||
if (!labels) {
|
||||
var data = {
|
||||
url: labelListUrl,
|
||||
method: "GET",
|
||||
success: function (data) {
|
||||
data.forEach(function (value) {
|
||||
labels += label.replace("labelName", value.name).replace("labelValue", value.value)
|
||||
});
|
||||
$(".labels-menu").append(labels);
|
||||
requesting = false;
|
||||
},
|
||||
error: function() {
|
||||
requesting = false;
|
||||
},
|
||||
flash_message: false
|
||||
};
|
||||
requesting = true;
|
||||
requestApi(data)
|
||||
}
|
||||
}
|
||||
|
||||
var show = 0;
|
||||
|
||||
function toggle() {
|
||||
if (show === 0) {
|
||||
$("#split-left").hide(500, function () {
|
||||
$("#split-right").attr("class", "col-lg-12");
|
||||
$("#toggle-icon").attr("class", "fa fa-angle-right fa-x");
|
||||
show = 1;
|
||||
});
|
||||
} else {
|
||||
$("#split-right").attr("class", "col-lg-9");
|
||||
$("#toggle-icon").attr("class", "fa fa-angle-left fa-x");
|
||||
$("#split-left").show(500);
|
||||
show = 0;
|
||||
}
|
||||
setTimeout(function () {
|
||||
$(".table").css("width", "100%");
|
||||
{#assetTable.columns.adjust();#}
|
||||
}, 500)
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
{#loadLabels()#}
|
||||
}).on('click', '.labels-menu li', function () {
|
||||
var val = $(this).text();
|
||||
$("#user_assets_table_filter input").val(val);
|
||||
assetTable.search(val).draw();
|
||||
}).on('click', '.btn-show-system-users', function () {
|
||||
var $this = $(this);
|
||||
var assetId = $this.data('aid');
|
||||
|
||||
function success(systemUsers) {
|
||||
var users = [];
|
||||
$.each(systemUsers, function (id, data) {
|
||||
var name = htmlEscape(data.name);
|
||||
users.push(name);
|
||||
});
|
||||
$this.parent().html(users.join(','))
|
||||
}
|
||||
|
||||
getGrantedAssetSystemUsers(assetId, success)
|
||||
})
|
||||
</script>
|
|
@ -1,23 +0,0 @@
|
|||
{% extends '_modal.html' %}
|
||||
{% load i18n %}
|
||||
{% block modal_class %}modal-lg{% endblock %}
|
||||
{% block modal_id %}select_user_modal{% endblock %}
|
||||
{% block modal_title%}{% trans "Please Select User" %}{% endblock %}
|
||||
{% block modal_body %}
|
||||
<table class="table table-striped table-bordered table-hover " id="select_user_table" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">
|
||||
<div class="checkbox checkbox-default"><input id="" type="checkbox" class="ipt_check_all"><label></label></div>
|
||||
</th>
|
||||
<th class="text-center">{% trans 'Name' %}</th>
|
||||
<th class="text-center">{% trans 'Username' %}</th>
|
||||
<th class="text-center">{% trans 'Role' %}</th>
|
||||
<th class="text-center">{% trans 'User group' %}</th>
|
||||
<th class="text-center">{% trans 'Asset num' %}</th>
|
||||
<th class="text-center">{% trans 'Active' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
{% endblock %}
|
||||
{% block modal_confirm_id %}btn_select_user{% endblock %}
|
|
@ -1,97 +0,0 @@
|
|||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
<style>
|
||||
.nav .open>a, .nav .open>a:hover, .nav .open>a:focus{
|
||||
border-color: white;
|
||||
}
|
||||
</style>
|
||||
|
||||
<li id="id_nav_user_detail">
|
||||
<a href="{% url 'users:user-detail' pk=object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'User detail' %} </a>
|
||||
</li>
|
||||
<li id="id_nav_user_detail_user_permission" class="btn-group">
|
||||
<a class="btn btn-sm dropdown-toggle" data-toggle="dropdown">
|
||||
<span>{% trans "User permissions" %}</span>
|
||||
<i class="caret"></i>
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu">
|
||||
<li id="id_nav_user_detail_assets">
|
||||
<a href="{% url 'users:user-granted-asset' pk=object.id %}" class="text-center">
|
||||
<i class="fa fa-cubes"></i>
|
||||
<span>{% trans 'Asset granted' %}</span>
|
||||
<i class="highlight-circle"></i>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
<li id="id_nav_user_detail_asset_permissions">
|
||||
<a href="{% url 'users:user-asset-permission' pk=object.id %}" class="text-center">
|
||||
<i class="fa fa-edit"></i>
|
||||
<span>{% trans 'Asset permission' %}</span>
|
||||
<i class="highlight-circle"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{% if LICENSE_VALID %}
|
||||
<li id="id_nav_user_detail_remote_apps">
|
||||
<a href="{% url 'users:user-granted-remote-app' pk=object.id %}" class="text-center">
|
||||
<i class="fa fa-desktop"></i>
|
||||
<span>{% trans 'RemoteApp granted' %}</span>
|
||||
<i class="highlight-circle"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li id="id_nav_user_detail_remote_app_permissions">
|
||||
<a href="{% url 'users:user-remote-app-permission' pk=object.id %}" class="text-center">
|
||||
<i class="fa fa-edit"></i>
|
||||
<span>{% trans 'RemoteApp permission' %}</span>
|
||||
<i class="highlight-circle"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li id="id_nav_user_detail_database_apps">
|
||||
<a href="{% url 'users:user-granted-database-app' pk=object.id %}" class="text-center">
|
||||
<i class="fa fa-database"></i>
|
||||
<span>{% trans 'DatabaseApp granted' %}</span>
|
||||
<i class="highlight-circle"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li id="id_nav_user_detail_database_app_permissions">
|
||||
<a href="{% url 'users:user-database-app-permission' pk=object.id %}" class="text-center">
|
||||
<i class="fa fa-edit"></i>
|
||||
<span>{% trans 'DatabaseApp permission' %}</span>
|
||||
<i class="highlight-circle"></i>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<script>
|
||||
function activeUserDetailNav(prefix) {
|
||||
var path = document.location.pathname;
|
||||
if (prefix) {
|
||||
path = path.replace(prefix, '');
|
||||
console.log(path);
|
||||
}
|
||||
var navId, navId2 = '';
|
||||
var idPrefix = 'id_nav_user_detail';
|
||||
var navUserDetailId = "#" + idPrefix;
|
||||
var navUserPermissionId = "#" + idPrefix + "_user_permission";
|
||||
var urlArray = path.split("/");
|
||||
var page = urlArray[urlArray.length-2];
|
||||
|
||||
if (page === "{{ object.id }}" || page === undefined){
|
||||
navId = navUserDetailId;
|
||||
}
|
||||
else{
|
||||
navId = navUserPermissionId;
|
||||
navId2 = "#" + idPrefix + '_' + page.replace(/-/g, '_');
|
||||
var highlightCircle = '<span class="fa fa-circle" style="padding-left: 5px; color: #1ab394"></span>';
|
||||
$(navId2 + '>a>i.highlight-circle').html(highlightCircle);
|
||||
$(navId + '>a>span').html($(navId2 + '>a>span').html());
|
||||
}
|
||||
$(navId).addClass('active')
|
||||
}
|
||||
activeUserDetailNav("{{ FORCE_SCRIPT_NAME }}");
|
||||
</script>
|
|
@ -1,8 +0,0 @@
|
|||
{% extends '_modal.html' %}
|
||||
{% load i18n %}
|
||||
{% block modal_id %}user_update_pk_modal{% endblock %}
|
||||
{% block modal_title%}{% trans "Update User SSH Public Key" %}{% endblock %}
|
||||
{% block modal_body %}
|
||||
<textarea id="txt_pk" class="form-control" cols="30" rows="10" placeholder="ssh-rsa AAAAB3NzaC1yc2EAA....."></textarea>
|
||||
{% endblock %}
|
||||
{% block modal_confirm_id %}btn_user_update_pk{% endblock %}
|
|
@ -1,10 +0,0 @@
|
|||
{% extends '_base_only_content.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block title %} {% trans 'First Login' %} {% endblock %}
|
||||
|
||||
{% block content %}
|
||||
使用UI重构这个页面
|
||||
{% endblock %}
|
|
@ -1,54 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
{{ wizard.form.media }}
|
||||
<link href="{% static 'css/plugins/steps/jquery.steps.css' %}" rel="stylesheet">
|
||||
{% endblock %}
|
||||
{% block first_login_message %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="ibox">
|
||||
<div class="ibox-title">
|
||||
<h5>{% trans 'First Login' %}</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>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div class="alert alert-success" id="messages">
|
||||
{% trans 'Welcome to use jumpserver, visit ' %}
|
||||
<a href="{{ user_guide_url }}" target="_blank">{% trans 'Use guide' %}</a> {% trans ' for more information' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
$(document).on('click', ".fl_goto", function(){
|
||||
var $form = $('#fl_form');
|
||||
$('<input />', {'name': 'wizard_goto_step', 'value': $(this).data('goto'), 'type': 'hidden'}).appendTo($form);
|
||||
$form.submit();
|
||||
return false;
|
||||
}).on('click', '#fl_submit', function(){
|
||||
$('#fl_form').submit();
|
||||
return false;
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,201 +0,0 @@
|
|||
{% extends 'users/_base_user_detail.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content_table %}
|
||||
<div class="col-sm-10" style="padding-left: 0">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label"><b>{{ object.name }}</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-user">
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<table class="table table-striped table-bordered table-hover"
|
||||
id="permission_list_table"
|
||||
style="width: 100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>{% trans 'Name' %}</th>
|
||||
<th class="text-center">{% trans 'User' %}</th>
|
||||
<th class="text-center">{% trans 'User group' %}</th>
|
||||
<th class="text-center">{% trans 'Asset' %}</th>
|
||||
<th class="text-center">{% trans 'Node' %}</th>
|
||||
<th class="text-center">{% trans 'System user' %}</th>
|
||||
<th class="text-center">{% trans 'Validity' %}</th>
|
||||
<th class="text-center">{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include '_filter_dropdown.html' %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
jumpserver.nodes_selected = {};
|
||||
function format(d) {
|
||||
var data = "";
|
||||
if (d.users.length > 0 ) {
|
||||
data += makeLabel(["{% trans 'User' %}", d.users.join(", ")])
|
||||
}
|
||||
if (d.user_groups.length > 0) {
|
||||
data += makeLabel(["{% trans 'User group' %}", d.user_groups.join(", ")])
|
||||
}
|
||||
if (d.assets.length > 0) {
|
||||
data += makeLabel(["{% trans 'Asset' %}", d.assets.join(", ")])
|
||||
}
|
||||
if (d.nodes.length > 0) {
|
||||
data += makeLabel(["{% trans 'Node' %}", d.nodes.join(", ")])
|
||||
}
|
||||
if (d.system_users.length > 0) {
|
||||
data += makeLabel(["{% trans 'System user' %}", d.system_users.join(", ")])
|
||||
}
|
||||
if (d.actions.length > 0) {
|
||||
data += makeLabel(["{% trans 'Action' %}", d.actions.join(", ")])
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
function initTable() {
|
||||
var options = {
|
||||
ele: $('#permission_list_table'),
|
||||
toggle: true,
|
||||
columnDefs: [
|
||||
{targets: 0, createdCell: function (td, cellData, rowData) {
|
||||
$(td).addClass("toggle");
|
||||
$(td).html("<i class='fa fa-angle-right'></i>");
|
||||
}},
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
cellData = htmlEscape(cellData);
|
||||
var detail_btn = '<a href="{% url "perms:asset-permission-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
|
||||
}},
|
||||
{targets: 2, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 5, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 6, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 7, 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: 8, createdCell: function (td, cellData, rowData) {
|
||||
var name = htmlEscape(rowData.name);
|
||||
var update_btn = '<a href="{% url "perms:asset-permission-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-uid="{{ DEFAULT_PK }}" mark=1 data-name="99991938">{% trans "Delete" %}</a>'
|
||||
.replace('{{ DEFAULT_PK }}', cellData)
|
||||
.replace('99991938', name);
|
||||
if (rowData.inherit) {
|
||||
del_btn = del_btn.replace("mark", "disabled")
|
||||
}
|
||||
$(td).html(update_btn + del_btn);
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-perms:asset-permission-list" %}?user_id={{ object.id }}',
|
||||
columns: [
|
||||
{data: "id"}, {data: "name"}, {data: "users", orderable: false},
|
||||
{data: "user_groups", orderable: false}, {data: "assets", orderable: false},
|
||||
{data: "nodes", orderable: false}, {data: "system_users", orderable: false},
|
||||
{data: "is_valid", orderable: false}, {data: "id", orderable: false, width: "120px"}
|
||||
],
|
||||
select: {},
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
table = jumpserver.initServerSideDataTable(options);
|
||||
return table
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
initTable();
|
||||
var filterMenu = [
|
||||
{title: "{% trans 'Name' %}", value: "name"},
|
||||
{title: "{% trans 'Validity' %}", value: "is_valid"},
|
||||
{title: "{% trans 'IP' %}", value: "ip"},
|
||||
{title: "{% trans 'Hostname' %}", value: "hostname"},
|
||||
{title: "{% trans 'Node' %}", value: "node"},
|
||||
{title: "{% trans 'System user' %}", value: "system_user"},
|
||||
{title: "{% trans 'Inherit' %}", value: "all", submenu: [
|
||||
{title: "{% trans 'Include' %}", value: "1"},
|
||||
{title: "{% trans 'Exclude' %}", value: "0"},
|
||||
]},
|
||||
];
|
||||
initTableFilterDropdown('#permission_list_table_filter input', filterMenu, 15, 38)
|
||||
})
|
||||
.on('click', '.toggle', function (e) {
|
||||
e.preventDefault();
|
||||
var detailRows = [];
|
||||
var tr = $(this).closest('tr');
|
||||
var row = table.row(tr);
|
||||
var idx = $.inArray(tr.attr('id'), detailRows);
|
||||
|
||||
if (row.child.isShown()) {
|
||||
tr.removeClass('details');
|
||||
$(this).children('i:first-child').removeClass('fa-angle-down').addClass('fa-angle-right');
|
||||
row.child.hide();
|
||||
|
||||
// Remove from the 'open' array
|
||||
detailRows.splice(idx, 1);
|
||||
}
|
||||
else {
|
||||
tr.addClass('details');
|
||||
$(this).children('i:first-child').removeClass('fa-angle-right').addClass('fa-angle-down');
|
||||
row.child(format(row.data())).show();
|
||||
// Add to the 'open' array
|
||||
if ( idx === -1 ) {
|
||||
detailRows.push(tr.attr('id'));
|
||||
}
|
||||
}
|
||||
})
|
||||
.on('click', '.btn-del', function () {
|
||||
var $this = $(this);
|
||||
var uid = $this.data('uid');
|
||||
var name = $this.data('name');
|
||||
var the_url = '{% url "api-perms:asset-permission-detail" pk=DEFAULT_PK %}'
|
||||
.replace('{{ DEFAULT_PK }}', uid);
|
||||
objectDelete($this, name, the_url);
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,168 +0,0 @@
|
|||
{% extends 'users/_base_user_detail.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content_table %}
|
||||
<div class="col-sm-10" style="padding-left: 0">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label"><b>{{ object.name }}</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<i class="fa fa-wrench"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-user">
|
||||
</ul>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<table class="table table-striped table-bordered table-hover"
|
||||
id="permission_list_table"
|
||||
style="width: 100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>{% trans 'Name' %}</th>
|
||||
<th class="text-center">{% trans 'User' %}</th>
|
||||
<th class="text-center">{% trans 'User group' %}</th>
|
||||
<th class="text-center">{% trans 'DatabaseApp' %}</th>
|
||||
<th class="text-center">{% trans 'System user' %}</th>
|
||||
<th class="text-center">{% trans 'Validity' %}</th>
|
||||
<th class="text-center">{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
function format(d) {
|
||||
var data = "";
|
||||
if (d.users.length > 0 ) {
|
||||
data += makeLabel(["{% trans 'User' %}", d.users.join(", ")])
|
||||
}
|
||||
if (d.user_groups.length > 0) {
|
||||
data += makeLabel(["{% trans 'User group' %}", d.user_groups.join(", ")])
|
||||
}
|
||||
if (d.database_apps.length > 0) {
|
||||
data += makeLabel(["{% trans 'DatabaseApp' %}", d.database_apps.join(", ")])
|
||||
}
|
||||
if (d.system_users.length > 0) {
|
||||
data += makeLabel(["{% trans 'System user' %}", d.system_users.join(", ")])
|
||||
}
|
||||
return data
|
||||
}
|
||||
function initTable() {
|
||||
var options = {
|
||||
ele: $('#permission_list_table'),
|
||||
toggle: true,
|
||||
columnDefs: [
|
||||
{targets: 0, createdCell: function (td, cellData, rowData) {
|
||||
$(td).addClass("toggle");
|
||||
$(td).html("<i class='fa fa-angle-right'></i>");
|
||||
}},
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
cellData = htmlEscape(cellData);
|
||||
var detail_btn = '<a href="{% url "perms:database-app-permission-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
|
||||
}},
|
||||
{targets: 2, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 5, createdCell: function (td, cellData) {
|
||||
var num = cellData.length;
|
||||
$(td).html(num);
|
||||
}},
|
||||
{targets: 6, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 7, createdCell: function (td, cellData, rowData) {
|
||||
var name = htmlEscape(rowData.name);
|
||||
var update_btn = '<a href="{% url "perms:database-app-permission-update" pk=DEFAULT_PK %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
|
||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-del" data-uid="{{ DEFAULT_PK }}" mark=1 data-name="99991938">{% trans "Delete" %}</a>'
|
||||
.replace('{{ DEFAULT_PK }}', cellData)
|
||||
.replace('99991938', name);
|
||||
$(td).html(update_btn + del_btn);
|
||||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-perms:database-app-permission-list" %}?user_id={{ object.id }}',
|
||||
columns: [
|
||||
{data: "id"}, {data: "name"}, {data: "users", orderable: false},
|
||||
{data: "user_groups", orderable: false}, {data: "database_apps", orderable: false},
|
||||
{data: "system_users", orderable: false}, {data: "is_valid", orderable: false},
|
||||
{data: "id", orderable: false, width: "120px"}
|
||||
],
|
||||
select: {},
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
table = jumpserver.initServerSideDataTable(options);
|
||||
return table
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
initTable();
|
||||
})
|
||||
.on('click', '.toggle', function (e) {
|
||||
e.preventDefault();
|
||||
var detailRows = [];
|
||||
var tr = $(this).closest('tr');
|
||||
var row = table.row(tr);
|
||||
var idx = $.inArray(tr.attr('id'), detailRows);
|
||||
|
||||
if (row.child.isShown()) {
|
||||
tr.removeClass('details');
|
||||
$(this).children('i:first-child').removeClass('fa-angle-down').addClass('fa-angle-right');
|
||||
row.child.hide();
|
||||
|
||||
// Remove from the 'open' array
|
||||
detailRows.splice(idx, 1);
|
||||
}
|
||||
else {
|
||||
tr.addClass('details');
|
||||
$(this).children('i:first-child').removeClass('fa-angle-right').addClass('fa-angle-down');
|
||||
row.child(format(row.data())).show();
|
||||
// Add to the 'open' array
|
||||
if ( idx === -1 ) {
|
||||
detailRows.push(tr.attr('id'));
|
||||
}
|
||||
}
|
||||
})
|
||||
.on('click', '.btn-del', function () {
|
||||
var $this = $(this);
|
||||
var uid = $this.data('uid');
|
||||
var name = $this.data('name');
|
||||
var the_url = '{% url "api-perms:database-app-permission-detail" pk=DEFAULT_PK %}'
|
||||
.replace('{{ DEFAULT_PK }}', uid);
|
||||
objectDelete($this, name, the_url);
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,134 +0,0 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/cropper/cropper.min.css" %}" rel="stylesheet">
|
||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static 'js/pwstrength-bootstrap.js' %}"></script>
|
||||
<script src="{% static "js/jumpserver.js" %}"></script>
|
||||
|
||||
<style>
|
||||
.crop {
|
||||
width: 200px;
|
||||
height: 150px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.img-preview-sm img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin: -75px 0 0 -100px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%; /* This rule is very important, please do not ignore this! */
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li>
|
||||
<a href="{% url 'users:user-profile-update' %}" class="text-center">{% trans 'Profile' %} </a>
|
||||
</li>
|
||||
{% if request.user.can_update_password %}
|
||||
<li class="active">
|
||||
<a href="{% url 'users:user-password-update' %}" class="text-center">{% trans 'Password' %} </a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if request.user.can_update_ssh_key %}
|
||||
<li>
|
||||
<a href="{% url 'users:user-pubkey-update' %}" class="text-center">{% trans 'Public key' %} </a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content" style="background-color: #ffffff">
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_field form.old_password layout="horizontal" %}
|
||||
{% bootstrap_field form.new_password layout="horizontal" %}
|
||||
{# 密码popover #}
|
||||
<div id="container">
|
||||
<div class="popover fade bottom in" role="tooltip" id="popover777" style=" display: none; width:260px;">
|
||||
<div class="arrow" style="left: 50%;"></div>
|
||||
<h3 class="popover-title" style="display: none;"></h3>
|
||||
<h4>{% trans 'Your password must satisfy' %}</h4><div id="id_password_rules" style="color: #908a8a; margin-left:20px; font-size:15px;"></div>
|
||||
<h4 style="margin-top: 10px;">{% trans 'Password strength' %}</h4><div id="id_progress"></div>
|
||||
<div class="popover-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% bootstrap_field form.confirm_password layout="horizontal" %}
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-4 col-sm-offset-2">
|
||||
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
|
||||
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/plugins/cropper/cropper.min.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
|
||||
var el = $('#id_password_rules'),
|
||||
idPassword = $('#id_new_password'),
|
||||
idPopover = $('#popover777'),
|
||||
container = $('#container'),
|
||||
progress = $('#id_progress'),
|
||||
password_check_rules = {{ password_check_rules|safe }},
|
||||
minLength = 6,
|
||||
top = idPassword.offset().top - $('.navbar').outerHeight(true) - $('.page-heading').outerHeight(true) - 10 + 34,
|
||||
left = 377,
|
||||
i18n_fallback = {
|
||||
"veryWeak": "{% trans 'Very weak' %}",
|
||||
"weak": "{% trans 'Weak' %}",
|
||||
"normal": "{% trans 'Normal' %}",
|
||||
"medium": "{% trans 'Medium' %}",
|
||||
"strong": "{% trans 'Strong' %}",
|
||||
"veryStrong": "{% trans 'Very strong' %}"
|
||||
};
|
||||
|
||||
jQuery.each(password_check_rules, function (idx, rules) {
|
||||
if(rules.key === 'id_security_password_min_length'){
|
||||
minLength = rules.value
|
||||
}
|
||||
});
|
||||
|
||||
// 初始化popover
|
||||
initPopover(container, progress, idPassword, el, password_check_rules, i18n_fallback);
|
||||
|
||||
// 监听事件
|
||||
idPassword.on('focus', function () {
|
||||
idPopover.css('top', top);
|
||||
idPopover.css('left', left);
|
||||
idPopover.css('display', 'block');
|
||||
});
|
||||
idPassword.on('blur', function () {
|
||||
idPopover.css('display', 'none');
|
||||
});
|
||||
idPassword.on('keyup', function(){
|
||||
var password = idPassword.val();
|
||||
checkPasswordRules(password, minLength);
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -46,8 +46,6 @@ def get_user_or_pre_auth_user(request):
|
|||
|
||||
|
||||
def redirect_user_first_login_or_index(request, redirect_field_name):
|
||||
# if request.user.is_first_login:
|
||||
# return reverse('authentication:user-first-login')
|
||||
url_in_post = request.POST.get(redirect_field_name)
|
||||
if url_in_post:
|
||||
return url_in_post
|
||||
|
|
|
@ -21,7 +21,7 @@ from ... import forms
|
|||
|
||||
|
||||
__all__ = [
|
||||
'UserLoginView', 'UserResetPasswordView', 'UserForgotPasswordView', 'UserFirstLoginView',
|
||||
'UserLoginView', 'UserResetPasswordView', 'UserForgotPasswordView',
|
||||
]
|
||||
|
||||
|
||||
|
@ -130,8 +130,3 @@ class UserResetPasswordView(FormView):
|
|||
'auto_redirect': True,
|
||||
}
|
||||
return FlashMessageUtil.gen_message_url(message_data)
|
||||
|
||||
|
||||
class UserFirstLoginView(PermissionsMixin, TemplateView):
|
||||
template_name = 'users/first_login.html'
|
||||
permission_classes = [IsValidUser]
|
||||
|
|
Loading…
Reference in New Issue