Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
8e9b3f13
Commit
8e9b3f13
authored
Jun 28, 2019
by
ibuler
Browse files
Options
Browse Files
Download
Plain Diff
[Update] 修改permission actions
parents
48ba1993
320b17c8
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
267 additions
and
353 deletions
+267
-353
node.py
apps/assets/api/node.py
+7
-6
asset.py
apps/assets/forms/asset.py
+7
-1
node.py
apps/assets/models/node.py
+12
-8
node.py
apps/assets/serializers/node.py
+5
-4
_asset_list_modal.html
apps/assets/templates/assets/_asset_list_modal.html
+1
-0
_node_tree.html
apps/assets/templates/assets/_node_tree.html
+0
-0
asset_list.html
apps/assets/templates/assets/asset_list.html
+0
-0
utils.py
apps/assets/utils.py
+3
-0
common.py
apps/common/utils/common.py
+6
-9
settings.py
apps/jumpserver/settings.py
+1
-1
django.mo
apps/locale/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/locale/zh/LC_MESSAGES/django.po
+0
-0
hands.py
apps/orgs/hands.py
+1
-1
mixins.py
apps/orgs/mixins.py
+23
-4
signals_handler.py
apps/orgs/signals_handler.py
+2
-2
asset_permission.py
apps/perms/api/asset_permission.py
+1
-7
user_permission.py
apps/perms/api/user_permission.py
+1
-1
asset_permission.py
apps/perms/forms/asset_permission.py
+12
-8
0003_auto_20180225_1815.py
apps/perms/migrations/0003_auto_20180225_1815.py
+0
-41
0004_auto_20180411_1135.py
apps/perms/migrations/0004_auto_20180411_1135.py
+0
-31
0005_migrate_data_20180411_1144.py
apps/perms/migrations/0005_migrate_data_20180411_1144.py
+0
-49
0006_auto_20180606_1505.py
apps/perms/migrations/0006_auto_20180606_1505.py
+0
-27
0006_auto_20190628_1921.py
apps/perms/migrations/0006_auto_20190628_1921.py
+45
-0
0007_auto_20180807_1116.py
apps/perms/migrations/0007_auto_20180807_1116.py
+0
-37
0007_remove_assetpermission_actions.py
apps/perms/migrations/0007_remove_assetpermission_actions.py
+5
-5
0008_auto_20180816_1652.py
apps/perms/migrations/0008_auto_20180816_1652.py
+0
-23
asset_permission.py
apps/perms/models/asset_permission.py
+19
-2
asset_permission.py
apps/perms/serializers/asset_permission.py
+2
-8
signals_handler.py
apps/perms/signals_handler.py
+0
-7
asset_permission_create_update.html
...perms/templates/perms/asset_permission_create_update.html
+31
-2
asset_permission_list.html
apps/perms/templates/perms/asset_permission_list.html
+9
-33
api_urls.py
apps/perms/urls/api_urls.py
+0
-1
asset_permission.py
apps/perms/utils/asset_permission.py
+48
-31
asset_permission.py
apps/perms/views/asset_permission.py
+0
-2
jumpserver.js
apps/static/js/jumpserver.js
+26
-2
No files found.
apps/assets/api/node.py
View file @
8e9b3f13
...
...
@@ -112,12 +112,16 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
is_root
=
False
def
get_queryset
(
self
):
self
.
check_need_refresh_nodes
()
node_key
=
self
.
request
.
query_params
.
get
(
'key'
)
util
=
NodeUtil
()
# 是否包含自己
with_self
=
False
if
not
node_key
:
node_key
=
Node
.
root
()
.
key
with_self
=
True
self
.
node
=
util
.
get_node_by_key
(
node_key
)
queryset
=
self
.
node
.
get_children
(
with_self
=
True
)
queryset
=
self
.
node
.
get_children
(
with_self
=
with_self
)
queryset
=
[
node
.
as_tree_node
()
for
node
in
queryset
]
queryset
=
sorted
(
queryset
)
return
queryset
...
...
@@ -133,14 +137,11 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
def
filter_queryset
(
self
,
queryset
):
queryset
=
self
.
filter_assets
(
queryset
)
queryset
=
self
.
filter_refresh_nodes
(
queryset
)
return
queryset
def
filter_refresh_nodes
(
self
,
queryset
):
def
check_need_refresh_nodes
(
self
):
if
self
.
request
.
query_params
.
get
(
'refresh'
,
'0'
)
==
'1'
:
Node
.
expire_nodes_assets_amount
()
Node
.
expire_nodes_full_value
()
return
queryset
Node
.
refresh_nodes
()
class
NodeChildrenApi
(
mixins
.
ListModelMixin
,
generics
.
CreateAPIView
):
...
...
apps/assets/forms/asset.py
View file @
8e9b3f13
...
...
@@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _
from
common.utils
import
get_logger
from
orgs.mixins
import
OrgModelForm
from
..models
import
Asset
,
Protocol
from
..models
import
Asset
,
Protocol
,
Node
logger
=
get_logger
(
__file__
)
...
...
@@ -33,6 +33,12 @@ class ProtocolForm(forms.ModelForm):
class
AssetCreateForm
(
OrgModelForm
):
PROTOCOL_CHOICES
=
Protocol
.
PROTOCOL_CHOICES
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
()
.
__init__
(
*
args
,
**
kwargs
)
if
not
self
.
data
:
nodes_field
=
self
.
fields
[
'nodes'
]
nodes_field
.
_queryset
=
Node
.
get_queryset
()
class
Meta
:
model
=
Asset
fields
=
[
...
...
apps/assets/models/node.py
View file @
8e9b3f13
...
...
@@ -186,9 +186,6 @@ class FullValueMixin:
def
expire_nodes_full_value
(
cls
,
nodes
=
None
):
key
=
cls
.
_full_value_cache_key
.
format
(
'*'
)
cache
.
delete_pattern
(
key
+
'*'
)
from
..utils
import
NodeUtil
util
=
NodeUtil
()
util
.
set_full_value
()
class
AssetsAmountMixin
:
...
...
@@ -216,7 +213,7 @@ class AssetsAmountMixin:
def
assets_amount
(
self
,
value
):
self
.
_assets_amount
=
value
cache_key
=
self
.
_assets_amount_cache_key
.
format
(
self
.
key
)
cache
.
set
(
cache_key
,
value
,
3600
*
24
)
cache
.
set
(
cache_key
,
value
)
def
expire_assets_amount
(
self
):
ancestor_keys
=
self
.
get_ancestor_keys
(
with_self
=
True
)
...
...
@@ -226,11 +223,15 @@ class AssetsAmountMixin:
@classmethod
def
expire_nodes_assets_amount
(
cls
,
nodes
=
None
):
from
..utils
import
NodeUtil
key
=
cls
.
_assets_amount_cache_key
.
format
(
'*'
)
cache
.
delete_pattern
(
key
)
@classmethod
def
refresh_nodes
(
cls
):
from
..utils
import
NodeUtil
util
=
NodeUtil
(
with_assets_amount
=
True
)
util
.
set_assets_amount
()
util
.
set_full_value
()
class
Node
(
OrgModelMixin
,
FamilyMixin
,
FullValueMixin
,
AssetsAmountMixin
):
...
...
@@ -375,9 +376,7 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
def
as_tree_node
(
self
):
from
common.tree
import
TreeNode
from
..serializers
import
NodeSerializer
name
=
'{} ({})'
.
format
(
self
.
value
,
self
.
assets_amount
)
node_serializer
=
NodeSerializer
(
instance
=
self
)
data
=
{
'id'
:
self
.
key
,
'name'
:
name
,
...
...
@@ -386,7 +385,12 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
'isParent'
:
True
,
'open'
:
self
.
is_root
(),
'meta'
:
{
'node'
:
node_serializer
.
data
,
'node'
:
{
"id"
:
self
.
id
,
"name"
:
self
.
name
,
"value"
:
self
.
value
,
"key"
:
self
.
key
,
},
'type'
:
'node'
}
}
...
...
apps/assets/serializers/node.py
View file @
8e9b3f13
# -*- coding: utf-8 -*-
from
rest_framework
import
serializers
from
django.utils.translation
import
ugettext
as
_
from
orgs.mixins
import
BulkOrgResourceModelSerializer
from
..models
import
Asset
,
Node
...
...
@@ -25,11 +26,11 @@ class NodeSerializer(BulkOrgResourceModelSerializer):
def
validate_value
(
self
,
data
):
instance
=
self
.
instance
if
self
.
instance
else
Node
.
root
()
children
=
instance
.
parent
.
get_children
()
.
exclude
(
key
=
instance
.
key
)
values
=
[
child
.
value
for
child
in
children
]
if
data
in
values
:
children
=
instance
.
parent
.
get_children
()
children_values
=
[
node
.
value
for
node
in
children
if
node
!=
instance
]
if
data
in
children_
values
:
raise
serializers
.
ValidationError
(
'The same level node name cannot be the same'
_
(
'The same level node name cannot be the same'
)
)
return
data
...
...
apps/assets/templates/assets/_asset_list_modal.html
View file @
8e9b3f13
...
...
@@ -67,6 +67,7 @@ function initTable2() {
columns
:
[
{
data
:
"id"
},
{
data
:
"hostname"
},
{
data
:
"ip"
}
],
lengthMenu
:
[[
10
,
25
,
50
],
[
10
,
25
,
50
]],
pageLength
:
10
};
asset_table2
=
jumpserver
.
initServerSideDataTable
(
options
);
...
...
apps/assets/templates/assets/_node_tree.html
0 → 100644
View file @
8e9b3f13
This diff is collapsed.
Click to expand it.
apps/assets/templates/assets/asset_list.html
View file @
8e9b3f13
This diff is collapsed.
Click to expand it.
apps/assets/utils.py
View file @
8e9b3f13
# ~*~ coding: utf-8 ~*~
#
import
time
from
django.db.models
import
Prefetch
from
common.utils
import
get_object_or_none
,
get_logger
...
...
@@ -56,9 +57,11 @@ class NodeUtil:
def
get_all_nodes
(
self
):
all_nodes
=
Node
.
objects
.
all
()
if
self
.
with_assets_amount
:
now
=
time
.
time
()
all_nodes
=
all_nodes
.
prefetch_related
(
Prefetch
(
'assets'
,
queryset
=
Asset
.
objects
.
all
()
.
only
(
'id'
))
)
all_nodes
=
list
(
all_nodes
)
for
node
in
all_nodes
:
node
.
_assets
=
set
(
node
.
assets
.
all
())
all_nodes
=
sorted
(
all_nodes
,
key
=
self
.
sorted_by
)
...
...
apps/common/utils/common.py
View file @
8e9b3f13
...
...
@@ -130,16 +130,13 @@ def get_short_uuid_str():
def
is_uuid
(
seq
):
if
isinstance
(
seq
,
str
):
if
UUID_PATTERN
.
match
(
seq
):
return
True
else
:
return
False
else
:
for
s
in
seq
:
if
not
is_uuid
(
s
):
return
False
if
isinstance
(
seq
,
uuid
.
UUID
):
return
True
elif
isinstance
(
seq
,
str
)
and
UUID_PATTERN
.
match
(
seq
):
return
True
elif
isinstance
(
seq
,
(
list
,
tuple
)):
all
([
is_uuid
(
x
)
for
x
in
seq
])
return
False
def
get_request_ip
(
request
):
...
...
apps/jumpserver/settings.py
View file @
8e9b3f13
...
...
@@ -399,7 +399,7 @@ REST_FRAMEWORK = {
'ORDERING_PARAM'
:
"order"
,
'SEARCH_PARAM'
:
"search"
,
'DATETIME_FORMAT'
:
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S
%
z'
,
'DATETIME_INPUT_FORMATS'
:
[
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S
%
z'
],
'DATETIME_INPUT_FORMATS'
:
[
'
iso-8601'
,
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S
%
z'
],
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
# 'PAGE_SIZE': 15
}
...
...
apps/locale/zh/LC_MESSAGES/django.mo
View file @
8e9b3f13
No preview for this file type
apps/locale/zh/LC_MESSAGES/django.po
View file @
8e9b3f13
This diff is collapsed.
Click to expand it.
apps/orgs/hands.py
View file @
8e9b3f13
# -*- coding: utf-8 -*-
#
from
assets.models
import
Node
from
orgs.utils
import
set_current_org
,
current_org
from
orgs.utils
import
set_current_org
,
current_org
,
get_current_org
apps/orgs/mixins.py
View file @
8e9b3f13
...
...
@@ -4,7 +4,8 @@ import traceback
from
django.db
import
models
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.shortcuts
import
redirect
,
get_object_or_404
from
django.forms
import
ModelForm
from
django
import
forms
from
django.core.exceptions
import
ValidationError
from
django.http.response
import
HttpResponseForbidden
from
rest_framework
import
serializers
from
rest_framework.validators
import
UniqueTogetherValidator
...
...
@@ -101,6 +102,26 @@ class OrgModelMixin(models.Model):
else
:
return
name
def
validate_unique
(
self
,
exclude
=
None
):
"""
Check unique constraints on the model and raise ValidationError if any
failed.
Form 提交时会使用这个检验
"""
self
.
org_id
=
current_org
.
id
if
current_org
.
is_real
()
else
''
if
exclude
and
'org_id'
in
exclude
:
exclude
.
remove
(
'org_id'
)
unique_checks
,
date_checks
=
self
.
_get_unique_checks
(
exclude
=
exclude
)
errors
=
self
.
_perform_unique_checks
(
unique_checks
)
date_errors
=
self
.
_perform_date_checks
(
date_checks
)
for
k
,
v
in
date_errors
.
items
():
errors
.
setdefault
(
k
,
[])
.
extend
(
v
)
if
errors
:
raise
ValidationError
(
errors
)
class
Meta
:
abstract
=
True
...
...
@@ -123,11 +144,9 @@ class RootOrgViewMixin:
return
super
()
.
dispatch
(
request
,
*
args
,
**
kwargs
)
class
OrgModelForm
(
ModelForm
):
class
OrgModelForm
(
forms
.
ModelForm
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
()
.
__init__
(
*
args
,
**
kwargs
)
# if 'initial' not in kwargs:
# return
for
name
,
field
in
self
.
fields
.
items
():
if
not
hasattr
(
field
,
'queryset'
):
continue
...
...
apps/orgs/signals_handler.py
View file @
8e9b3f13
...
...
@@ -6,7 +6,7 @@ from django.db.models.signals import post_save
from
django.dispatch
import
receiver
from
.models
import
Organization
from
.hands
import
set_current_org
,
current_org
,
Node
from
.hands
import
set_current_org
,
current_org
,
Node
,
get_current_org
from
perms.models
import
AssetPermission
from
users.models
import
UserGroup
...
...
@@ -14,7 +14,7 @@ from users.models import UserGroup
@receiver
(
post_save
,
sender
=
Organization
)
def
on_org_create_or_update
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
if
instance
:
old_org
=
current_org
old_org
=
get_current_org
()
set_current_org
(
instance
)
node_root
=
Node
.
root
()
if
node_root
.
value
!=
instance
.
name
:
...
...
apps/perms/api/asset_permission.py
View file @
8e9b3f13
...
...
@@ -20,16 +20,10 @@ from .. import serializers
__all__
=
[
'AssetPermissionViewSet'
,
'AssetPermissionRemoveUserApi'
,
'AssetPermissionAddUserApi'
,
'AssetPermissionRemoveAssetApi'
,
'AssetPermissionAddAssetApi'
,
'ActionViewSet'
,
'AssetPermissionAddAssetApi'
,
]
class
ActionViewSet
(
viewsets
.
ReadOnlyModelViewSet
):
queryset
=
Action
.
objects
.
all
()
serializer_class
=
serializers
.
ActionSerializer
permission_classes
=
(
IsOrgAdmin
,)
class
AssetPermissionViewSet
(
viewsets
.
ModelViewSet
):
"""
资产授权列表的增删改查api
...
...
apps/perms/api/user_permission.py
View file @
8e9b3f13
...
...
@@ -14,7 +14,6 @@ from rest_framework.pagination import LimitOffsetPagination
from
common.permissions
import
IsValidUser
,
IsOrgAdminOrAppUser
from
common.tree
import
TreeNodeSerializer
from
common.utils
import
get_logger
from
orgs.utils
import
set_to_root_org
from
..utils
import
(
AssetPermissionUtil
,
parse_asset_to_tree_node
,
parse_node_to_tree_node
,
check_system_user_action
,
RemoteAppPermissionUtil
,
...
...
@@ -515,6 +514,7 @@ class ValidateUserRemoteAppPermissionApi(APIView):
permission_classes
=
(
IsOrgAdminOrAppUser
,)
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
change_org_if_need
(
request
,
kwargs
)
user_id
=
request
.
query_params
.
get
(
'user_id'
,
''
)
remote_app_id
=
request
.
query_params
.
get
(
'remote_app_id'
,
''
)
user
=
get_object_or_404
(
User
,
id
=
user_id
)
...
...
apps/perms/forms/asset_permission.py
View file @
8e9b3f13
# ~*~ coding: utf-8 ~*~
from
__future__
import
absolute_import
,
unicode_literals
from
functools
import
reduce
from
django
import
forms
from
django.utils.translation
import
ugettext_lazy
as
_
...
...
@@ -18,17 +19,22 @@ class AssetPermissionForm(OrgModelForm):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
()
.
__init__
(
*
args
,
**
kwargs
)
users_field
=
self
.
fields
.
get
(
'users'
)
if
hasattr
(
users_field
,
'queryset'
):
users_field
.
queryset
=
current_org
.
get_org_users
()
assets_field
=
self
.
fields
.
get
(
'assets'
)
users_field
.
queryset
=
current_org
.
get_org_users
()
# 前端渲染优化, 防止过多资产
if
not
self
.
data
:
instance
=
kwargs
.
get
(
'instance'
)
assets_field
=
self
.
fields
[
'assets'
]
if
instance
:
assets_field
.
queryset
=
instance
.
assets
.
all
()
else
:
assets_field
.
queryset
=
Asset
.
objects
.
none
()
nodes_field
=
self
.
fields
[
'nodes'
]
nodes_field
.
_queryset
=
Node
.
get_queryset
()
def
clean_action
(
self
):
actions
=
self
.
cleaned_data
.
get
(
"action"
)
return
reduce
(
lambda
x
,
y
:
x
|
y
,
actions
)
class
Meta
:
model
=
AssetPermission
...
...
@@ -51,16 +57,14 @@ class AssetPermissionForm(OrgModelForm):
'system_users'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'System user'
)}
),
'actions'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Action'
)}
)
'action'
:
forms
.
CheckboxSelectMultiple
()
}
labels
=
{
'nodes'
:
_
(
"Node"
),
}
help_texts
=
{
'action
s
'
:
_
(
'Tips: The RDP protocol does not support separate '
'controls for uploading or downloading files'
)
'action'
:
_
(
'Tips: The RDP protocol does not support separate '
'controls for uploading or downloading files'
)
}
def
clean_user_groups
(
self
):
...
...
apps/perms/migrations/0003_auto_20180225_1815.py
deleted
100644 → 0
View file @
48ba1993
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-02-25 10:15
from
__future__
import
unicode_literals
import
common.utils
from
django.db
import
migrations
,
models
import
django.db.models.deletion
import
uuid
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'users'
,
'0004_auto_20180125_1218'
),
(
'assets'
,
'0007_auto_20180225_1815'
),
(
'perms'
,
'0002_auto_20171228_0025'
),
]
operations
=
[
migrations
.
CreateModel
(
name
=
'NodePermission'
,
fields
=
[
(
'id'
,
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
,
serialize
=
False
)),
(
'is_active'
,
models
.
BooleanField
(
default
=
True
,
verbose_name
=
'Active'
)),
(
'date_expired'
,
models
.
DateTimeField
(
default
=
common
.
utils
.
date_expired_default
,
verbose_name
=
'Date expired'
)),
(
'created_by'
,
models
.
CharField
(
blank
=
True
,
max_length
=
128
,
verbose_name
=
'Created by'
)),
(
'date_created'
,
models
.
DateTimeField
(
auto_now_add
=
True
,
verbose_name
=
'Date created'
)),
(
'comment'
,
models
.
TextField
(
blank
=
True
,
verbose_name
=
'Comment'
)),
(
'node'
,
models
.
ForeignKey
(
on_delete
=
django
.
db
.
models
.
deletion
.
CASCADE
,
to
=
'assets.Node'
,
verbose_name
=
'Node'
)),
(
'system_user'
,
models
.
ForeignKey
(
on_delete
=
django
.
db
.
models
.
deletion
.
CASCADE
,
to
=
'assets.SystemUser'
,
verbose_name
=
'System user'
)),
(
'user_group'
,
models
.
ForeignKey
(
on_delete
=
django
.
db
.
models
.
deletion
.
CASCADE
,
to
=
'users.UserGroup'
,
verbose_name
=
'User group'
)),
],
options
=
{
'verbose_name'
:
'Asset permission'
,
},
),
migrations
.
AlterUniqueTogether
(
name
=
'nodepermission'
,
unique_together
=
set
([(
'node'
,
'user_group'
,
'system_user'
)]),
),
]
apps/perms/migrations/0004_auto_20180411_1135.py
deleted
100644 → 0
View file @
48ba1993
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-11 03:35
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
import
django.utils.timezone
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'assets'
,
'0013_auto_20180411_1135'
),
(
'perms'
,
'0003_auto_20180225_1815'
),
]
operations
=
[
migrations
.
RemoveField
(
model_name
=
'assetpermission'
,
name
=
'asset_groups'
,
),
migrations
.
AddField
(
model_name
=
'assetpermission'
,
name
=
'date_start'
,
field
=
models
.
DateTimeField
(
default
=
django
.
utils
.
timezone
.
now
,
verbose_name
=
'Date start'
),
),
migrations
.
AddField
(
model_name
=
'assetpermission'
,
name
=
'nodes'
,
field
=
models
.
ManyToManyField
(
blank
=
True
,
related_name
=
'granted_by_permissions'
,
to
=
'assets.Node'
,
verbose_name
=
'Nodes'
),
),
]
apps/perms/migrations/0005_migrate_data_20180411_1144.py
deleted
100644 → 0
View file @
48ba1993
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-11 03:35
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
import
django.utils.timezone
def
migrate_node_permissions
(
apps
,
schema_editor
):
node_perm_model
=
apps
.
get_model
(
"perms"
,
"NodePermission"
)
asset_perm_model
=
apps
.
get_model
(
"perms"
,
"AssetPermission"
)
db_alias
=
schema_editor
.
connection
.
alias
for
old
in
node_perm_model
.
objects
.
using
(
db_alias
)
.
all
():
perm
=
asset_perm_model
.
objects
.
using
(
db_alias
)
.
create
(
name
=
"{}-{}-{}"
.
format
(
old
.
node
.
value
,
old
.
user_group
.
name
,
old
.
system_user
.
name
),
is_active
=
old
.
is_active
,
date_expired
=
old
.
date_expired
,
created_by
=
old
.
date_expired
,
date_created
=
old
.
date_created
,
comment
=
old
.
comment
,
)
perm
.
user_groups
.
add
(
old
.
user_group
)
perm
.
nodes
.
add
(
old
.
node
)
perm
.
system_users
.
add
(
old
.
system_user
)
def
migrate_system_assets_relation
(
apps
,
schema_editor
):
system_user_model
=
apps
.
get_model
(
"assets"
,
"SystemUser"
)
db_alias
=
schema_editor
.
connection
.
alias
for
s
in
system_user_model
.
objects
.
using
(
db_alias
)
.
all
():
nodes
=
list
(
s
.
nodes
.
all
())
s
.
nodes
.
set
([])
s
.
nodes
.
set
(
nodes
)
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'perms'
,
'0004_auto_20180411_1135'
),
]
operations
=
[
migrations
.
RunPython
(
migrate_node_permissions
),
migrations
.
RunPython
(
migrate_system_assets_relation
),
]
apps/perms/migrations/0006_auto_20180606_1505.py
deleted
100644 → 0
View file @
48ba1993
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-06-06 07:05
from
__future__
import
unicode_literals
import
common.utils
from
django.db
import
migrations
,
models
import
django.utils.timezone
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'perms'
,
'0005_migrate_data_20180411_1144'
),
]
operations
=
[
migrations
.
AlterField
(
model_name
=
'assetpermission'
,
name
=
'date_expired'
,
field
=
models
.
DateTimeField
(
db_index
=
True
,
default
=
common
.
utils
.
date_expired_default
,
verbose_name
=
'Date expired'
),
),
migrations
.
AlterField
(
model_name
=
'assetpermission'
,
name
=
'date_start'
,
field
=
models
.
DateTimeField
(
db_index
=
True
,
default
=
django
.
utils
.
timezone
.
now
,
verbose_name
=
'Date start'
),
),
]
apps/perms/migrations/0006_auto_20190628_1921.py
0 → 100644
View file @
8e9b3f13
# Generated by Django 2.1.7 on 2019-06-28 11:47
from
django.db
import
migrations
,
models
from
functools
import
reduce
def
migrate_old_actions
(
apps
,
schema_editor
):
from
orgs.utils
import
set_to_root_org
from
..models
import
ActionFlag
set_to_root_org
()
perm_model
=
apps
.
get_model
(
'perms'
,
'AssetPermission'
)
db_alias
=
schema_editor
.
connection
.
alias
perms
=
perm_model
.
objects
.
using
(
db_alias
)
.
all
()
actions_map
=
{
"all"
:
ActionFlag
.
ALL
,
"connect"
:
ActionFlag
.
CONNECT
,
"upload_file"
:
ActionFlag
.
UPLOAD
,
"download_file"
:
ActionFlag
.
DOWNLOAD
,
}
for
perm
in
perms
:
actions
=
perm
.
actions
.
all
()
new_actions
=
[
actions_map
.
get
(
action
.
name
,
ActionFlag
.
ALL
)
for
action
in
actions
]
new_action
=
reduce
(
lambda
x
,
y
:
x
|
y
,
new_actions
)
perm
.
action
=
new_action
perm
.
save
()
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'perms'
,
'0005_auto_20190521_1619'
),
]
operations
=
[
migrations
.
AddField
(
model_name
=
'assetpermission'
,
name
=
'action'
,
field
=
models
.
IntegerField
(
choices
=
[(
255
,
'All'
),
(
1
,
'Connect'
),
(
2
,
'Upload file'
),
(
6
,
'Upload download'
),
(
4
,
'Download file'
)],
default
=
255
,
verbose_name
=
'Action'
),
),
migrations
.
RunPython
(
migrate_old_actions
),
]
apps/perms/migrations/0007_auto_20180807_1116.py
deleted
100644 → 0
View file @
48ba1993
# Generated by Django 2.0.7 on 2018-08-07 03:16
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'perms'
,
'0006_auto_20180606_1505'
),
]
operations
=
[
migrations
.
AddField
(
model_name
=
'assetpermission'
,
name
=
'org_id'
,
field
=
models
.
CharField
(
blank
=
True
,
default
=
None
,
max_length
=
36
,
null
=
True
),
),
migrations
.
AddField
(
model_name
=
'nodepermission'
,
name
=
'org_id'
,
field
=
models
.
CharField
(
blank
=
True
,
default
=
None
,
max_length
=
36
,
null
=
True
),
),
migrations
.
AlterField
(
model_name
=
'assetpermission'
,
name
=
'name'
,
field
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
'Name'
),
),
migrations
.
AlterUniqueTogether
(
name
=
'assetpermission'
,
unique_together
=
{(
'org_id'
,
'name'
)},
),
migrations
.
AlterUniqueTogether
(
name
=
'nodepermission'
,
unique_together
=
set
(),
),
]
apps/perms/migrations/000
9_auto_20180903_1132
.py
→
apps/perms/migrations/000
7_remove_assetpermission_actions
.py
View file @
8e9b3f13
# Generated by Django 2.1
on 2018-09-03 03:3
2
# Generated by Django 2.1
.7 on 2019-06-28 12:0
2
from
django.db
import
migrations
...
...
@@ -6,12 +6,12 @@ from django.db import migrations
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'perms'
,
'000
8_auto_20180816_1652
'
),
(
'perms'
,
'000
6_auto_20190628_1921
'
),
]
operations
=
[
migrations
.
AlterModelOptions
(
name
=
'assetpermission'
,
options
=
{
'verbose_name'
:
'Asset permission'
}
,
migrations
.
RemoveField
(
model_
name
=
'assetpermission'
,
name
=
'actions'
,
),
]
apps/perms/migrations/0008_auto_20180816_1652.py
deleted
100644 → 0
View file @
48ba1993
# Generated by Django 2.0.7 on 2018-08-16 08:52
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'perms'
,
'0007_auto_20180807_1116'
),
]
operations
=
[
migrations
.
AlterField
(
model_name
=
'assetpermission'
,
name
=
'org_id'
,
field
=
models
.
CharField
(
blank
=
True
,
db_index
=
True
,
default
=
''
,
max_length
=
36
,
verbose_name
=
'Organization'
),
),
migrations
.
AlterField
(
model_name
=
'nodepermission'
,
name
=
'org_id'
,
field
=
models
.
CharField
(
blank
=
True
,
db_index
=
True
,
default
=
''
,
max_length
=
36
,
verbose_name
=
'Organization'
),
),
]
apps/perms/models/asset_permission.py
View file @
8e9b3f13
...
...
@@ -11,7 +11,7 @@ from .base import BasePermission
__all__
=
[
'Action'
,
'AssetPermission'
,
'NodePermission'
,
'Action'
,
'AssetPermission'
,
'NodePermission'
,
'ActionFlag'
]
...
...
@@ -33,11 +33,28 @@ class Action(models.Model):
return
cls
.
objects
.
get
(
name
=
PERMS_ACTION_NAME_ALL
)
class
ActionFlag
:
CONNECT
=
0
b00000001
UPLOAD
=
0
b00000010
DOWNLOAD
=
0
b00000100
UPDOWNLOAD
=
CONNECT
|
DOWNLOAD
ALL
=
0
b11111111
CHOICES
=
(
(
ALL
,
_
(
'All'
)),
(
CONNECT
,
_
(
'Connect'
)),
(
UPLOAD
,
_
(
'Upload file'
)),
(
UPDOWNLOAD
,
_
(
"Upload download"
)),
(
DOWNLOAD
,
_
(
'Download file'
)),
)
class
AssetPermission
(
BasePermission
):
assets
=
models
.
ManyToManyField
(
'assets.Asset'
,
related_name
=
'granted_by_permissions'
,
blank
=
True
,
verbose_name
=
_
(
"Asset"
))
nodes
=
models
.
ManyToManyField
(
'assets.Node'
,
related_name
=
'granted_by_permissions'
,
blank
=
True
,
verbose_name
=
_
(
"Nodes"
))
system_users
=
models
.
ManyToManyField
(
'assets.SystemUser'
,
related_name
=
'granted_by_permissions'
,
verbose_name
=
_
(
"System user"
))
actions
=
models
.
ManyToManyField
(
'Action'
,
related_name
=
'permissions'
,
blank
=
True
,
verbose_name
=
_
(
'Action'
))
# actions = models.ManyToManyField(Action, related_name='permissions', blank=True, verbose_name=_('Action'))
action
=
models
.
IntegerField
(
choices
=
ActionFlag
.
CHOICES
,
default
=
ActionFlag
.
ALL
,
verbose_name
=
_
(
"Action"
))
class
Meta
:
unique_together
=
[(
'org_id'
,
'name'
)]
...
...
apps/perms/serializers/asset_permission.py
View file @
8e9b3f13
...
...
@@ -13,16 +13,10 @@ __all__ = [
'AssetPermissionCreateUpdateSerializer'
,
'AssetPermissionListSerializer'
,
'AssetPermissionUpdateUserSerializer'
,
'AssetPermissionUpdateAssetSerializer'
,
'AssetPermissionNodeSerializer'
,
'GrantedNodeSerializer'
,
'
ActionSerializer'
,
'
NodeGrantedSerializer'
,
'NodeGrantedSerializer'
,
]
class
ActionSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Action
fields
=
'__all__'
class
AssetPermissionCreateUpdateSerializer
(
BulkOrgResourceModelSerializer
):
class
Meta
:
model
=
AssetPermission
...
...
@@ -35,7 +29,7 @@ class AssetPermissionListSerializer(BulkOrgResourceModelSerializer):
assets
=
StringManyToManyField
(
many
=
True
,
read_only
=
True
)
nodes
=
StringManyToManyField
(
many
=
True
,
read_only
=
True
)
system_users
=
StringManyToManyField
(
many
=
True
,
read_only
=
True
)
action
s
=
StringManyToManyField
(
many
=
True
,
read_only
=
True
)
action
=
serializers
.
IntegerField
(
read_only
=
True
)
is_valid
=
serializers
.
BooleanField
()
is_expired
=
serializers
.
BooleanField
()
...
...
apps/perms/signals_handler.py
View file @
8e9b3f13
...
...
@@ -25,13 +25,6 @@ def on_transaction_commit(func):
@on_transaction_commit
def
on_permission_created
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
AssetPermissionUtil
.
expire_all_cache
()
actions
=
instance
.
actions
.
all
()
if
created
and
not
actions
:
default_action
=
Action
.
get_action_all
()
instance
.
actions
.
add
(
default_action
)
logger
.
debug
(
"Set default action to perms: {}"
.
format
(
default_action
,
instance
)
)
@receiver
(
post_save
,
sender
=
AssetPermission
)
...
...
apps/perms/templates/perms/asset_permission_create_update.html
View file @
8e9b3f13
...
...
@@ -48,7 +48,7 @@
{% bootstrap_field form.system_users layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Action' %}
</h3>
{% bootstrap_field form.action
s
layout="horizontal" %}
{% bootstrap_field form.action layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Other' %}
</h3>
<div
class=
"form-group"
>
...
...
@@ -143,6 +143,34 @@ $(document).ready(function () {
$
(
'#id_assets'
).
val
(
assets
).
trigger
(
'change'
);
$
(
"#asset_list_modal"
).
modal
(
'hide'
);
});
})
.
on
(
"submit"
,
"form"
,
function
(
evt
)
{
evt
.
preventDefault
();
var
the_url
=
'{% url '
api
-
perms
:
asset
-
permission
-
list
' %}'
;
var
redirect_to
=
'{% url "perms:asset-permission-list" %}'
;
var
method
=
"POST"
;
var
form
=
$
(
"form"
);
var
data
=
form
.
serializeObject
();
console
.
log
(
data
)
var
actions
=
data
.
action
;
var
action
=
0
;
for
(
i
=
0
;
i
<
actions
.
length
;
i
++
)
{
console
.
log
(
actions
[
i
])
action
|=
actions
[
i
];
}
data
.
action
=
action
;
objectAttrsIsList
(
data
,
[
'users'
,
'user_groups'
,
'system_users'
,
'nodes'
,
'assets'
]);
objectAttrsIsDatetime
(
data
,
[
'date_start'
,
'date_expired'
]);
objectAttrsIsBool
(
data
,
[
'is_active'
])
console
.
log
(
data
)
var
props
=
{
url
:
the_url
,
data
:
data
,
method
:
method
,
form
:
form
,
redirect_to
:
redirect_to
};
formSubmit
(
props
);
})
</script>
{% endblock %}
\ No newline at end of file
apps/perms/templates/perms/asset_permission_list.html
View file @
8e9b3f13
...
...
@@ -24,15 +24,7 @@
<div
class=
"wrapper wrapper-content"
>
<div
class=
"row"
>
<div
class=
"col-lg-3"
id=
"split-left"
style=
"padding-left: 3px"
>
<div
class=
"ibox float-e-margins"
>
<div
class=
"ibox-content mailbox-content"
style=
"padding-top: 0;padding-left: 1px"
>
<div
class=
"file-manager "
>
<div
id=
"assetTree"
class=
"ztree"
>
</div>
<div
class=
"clearfix"
></div>
</div>
</div>
</div>
{% include 'assets/_node_tree.html' %}
</div>
<div
class=
"col-lg-9 animated fadeInRight"
id=
"split-right"
>
<div
class=
"tree-toggle"
>
...
...
@@ -86,7 +78,7 @@
<script>
var
zTree
,
table
,
show
=
0
;
function
onSelected
(
event
,
treeNode
)
{
function
on
Node
Selected
(
event
,
treeNode
)
{
setCookie
(
'node_selected'
,
treeNode
.
id
);
var
url
=
table
.
ajax
.
url
();
if
(
treeNode
.
meta
.
type
===
'node'
)
{
...
...
@@ -102,7 +94,7 @@ function onSelected(event, treeNode) {
}
function
beforeAsync
(
treeId
,
treeNode
)
{
function
before
Node
Async
(
treeId
,
treeNode
)
{
if
(
treeNode
)
{
return
treeNode
.
meta
.
type
===
'node'
}
...
...
@@ -204,28 +196,12 @@ function initTable() {
function
initTree
()
{
var
setting
=
{
view
:
{
dblClickExpand
:
false
,
showLine
:
true
},
data
:
{
simpleData
:
{
enable
:
true
}
},
async
:
{
enable
:
true
,
url
:
"{% url 'api-assets:node-children-tree' %}?assets=1"
,
autoParam
:[
"id=key"
,
"name=n"
,
"level=lv"
],
type
:
'get'
},
callback
:
{
onSelected
:
onSelected
,
beforeAsync
:
beforeAsync
}
};
zTree
=
$
.
fn
.
zTree
.
init
(
$
(
"#assetTree"
),
setting
);
initNodeTree
({
onSelected
:
onNodeSelected
,
beforeAsync
:
beforeNodeAsync
,
showMenu
:
false
,
showAssets
:
true
,
})
}
function
toggle
()
{
...
...
apps/perms/urls/api_urls.py
View file @
8e9b3f13
...
...
@@ -7,7 +7,6 @@ from .. import api
app_name
=
'perms'
router
=
routers
.
DefaultRouter
()
router
.
register
(
'actions'
,
api
.
ActionViewSet
,
'action'
)
router
.
register
(
'asset-permissions'
,
api
.
AssetPermissionViewSet
,
'asset-permission'
)
router
.
register
(
'remote-app-permissions'
,
api
.
RemoteAppPermissionViewSet
,
'remote-app-permission'
)
...
...
apps/perms/utils/asset_permission.py
View file @
8e9b3f13
...
...
@@ -5,6 +5,7 @@ from collections import defaultdict
import
json
from
hashlib
import
md5
import
time
import
itertools
from
django.utils
import
timezone
from
django.db.models
import
Q
...
...
@@ -102,11 +103,11 @@ def get_user_permissions(user, include_group=True):
arg
=
Q
(
users
=
user
)
|
Q
(
user_groups__in
=
groups
)
else
:
arg
=
Q
(
users
=
user
)
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
arg
)
return
AssetPermission
.
objects
.
valid
()
.
filter
(
arg
)
def
get_user_group_permissions
(
user_group
):
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
return
AssetPermission
.
objects
.
valid
()
.
filter
(
user_groups
=
user_group
)
...
...
@@ -117,15 +118,15 @@ def get_asset_permissions(asset, include_node=True):
arg
=
Q
(
assets
=
asset
)
|
Q
(
nodes__in
=
nodes
)
else
:
arg
=
Q
(
assets
=
asset
)
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
arg
)
return
AssetPermission
.
objects
.
valid
()
.
filter
(
arg
)
def
get_node_permissions
(
node
):
return
AssetPermission
.
objects
.
all
()
.
valid
()
.
filter
(
nodes
=
node
)
return
AssetPermission
.
objects
.
valid
()
.
filter
(
nodes
=
node
)
def
get_system_user_permissions
(
system_user
):
return
AssetPermission
.
objects
.
valid
()
.
all
()
.
filter
(
return
AssetPermission
.
objects
.
valid
()
.
filter
(
system_users
=
system_user
)
...
...
@@ -141,11 +142,6 @@ def timeit(func):
return
wrapper
class
AssetGranted
:
def
__init__
(
self
):
self
.
system_users
=
{}
class
AssetPermissionCacheMixin
:
CACHE_KEY_PREFIX
=
'_ASSET_PERM_CACHE_'
CACHE_META_KEY_PREFIX
=
'_ASSET_PERM_META_KEY_'
...
...
@@ -286,6 +282,38 @@ class AssetPermissionCacheMixin:
cache
.
delete_pattern
(
key
)
class
FlatPermissionQueryset
:
def
__init__
(
self
):
self
.
queryset
=
defaultdict
(
list
)
def
add
(
self
,
permission
):
self
.
queryset
[
permission
.
id
]
.
append
(
permission
)
def
add_many
(
self
,
assets_or_nodes
,
system_users
,
actions
):
if
any
([
assets_or_nodes
,
system_users
,
actions
]):
return
iterable
=
itertools
.
product
(
assets_or_nodes
,
system_users
,
actions
)
for
source
,
sysuser
,
action
in
iterable
:
permission
=
FlatPermission
(
source
,
sysuser
,
action
)
self
.
add
(
permission
)
def
clean
(
self
):
pass
class
FlatPermission
:
def
__init__
(
self
,
asset_or_node
,
system_user
,
action
):
self
.
id
=
asset_or_node
.
id
self
.
source
=
asset_or_node
self
.
system_user
=
system_user
self
.
action
=
action
def
__eq__
(
self
,
other
):
pass
class
AssetPermissionUtil
(
AssetPermissionCacheMixin
):
get_permissions_map
=
{
"User"
:
get_user_permissions
,
...
...
@@ -344,19 +372,15 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
def
get_nodes_direct
(
self
):
"""
返回用户/组授权规则直接关联的节点
:return: {
asset
1: {system_user1: {'actions': set()},}}
:return: {
node
1: {system_user1: {'actions': set()},}}
"""
nodes
=
defaultdict
(
dict
)
permissions
=
self
.
permissions
.
prefetch_related
(
'nodes'
,
'system_users'
,
'actions'
)
nodes
=
FlatPermissionQueryset
(
)
permissions
=
self
.
permissions
for
perm
in
permissions
:
actions
=
perm
.
actions
.
all
()
for
node
in
perm
.
nodes
.
all
():
system_users
=
perm
.
system_users
.
all
()
system_users
=
self
.
_structured_system_user
(
system_users
,
actions
)
nodes
[
node
]
.
update
(
system_users
)
self
.
tree
.
add_nodes
(
nodes
.
keys
())
# 替换成优化过的node
nodes
=
{
self
.
tree
.
node_util
.
get_node_by_key
(
k
.
key
):
v
for
k
,
v
in
nodes
.
items
()}
system_users
=
perm
.
system_users
.
all
()
_nodes
=
perm
.
nodes
.
all
()
nodes
.
add_many
(
_nodes
,
system_users
,
actions
)
return
nodes
@timeit
...
...
@@ -385,24 +409,18 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
assets
=
self
.
get_assets_direct
()
nodes
=
self
.
get_nodes_direct
()
# for node, system_users in nodes.items():
# print(9999, node)
# _assets = node.get_all_valid_assets()
# print(".......... end .......")
# print(">>>>> Node<<<<<<<<<<<<: ", node.value)
# _assets = list(node.get_all_valid_assets())
# for asset in _assets:
# print(">>asset")
# for system_user, attr_dict in system_users.items():
# print(">>>system user")
# if not asset.has_protocol(system_user.protocol):
# continue
# if system_user in assets[asset]:
# actions = assets[asset][system_user]['actions']
# attr_dict['actions'].update(actions)
# system_users.update({system_user: attr_dict})
# print("<<<system user")
# print("<<<asset")
# assets[asset].update(system_users)
# print(">>>>>>")
#
__assets
=
defaultdict
(
set
)
for
asset
,
system_users
in
assets
.
items
():
for
system_user
,
attr_dict
in
system_users
.
items
():
...
...
@@ -507,8 +525,7 @@ def parse_asset_to_tree_node(node, asset, system_users):
'id'
:
asset
.
id
,
'hostname'
:
asset
.
hostname
,
'ip'
:
asset
.
ip
,
'protocols'
:
[{
"name"
:
p
.
name
,
"port"
:
p
.
port
}
for
p
in
asset
.
protocols
.
all
()],
'protocols'
:
[
str
(
p
)
for
p
in
asset
.
protocols
.
all
()],
'platform'
:
asset
.
platform
,
'domain'
:
None
if
not
asset
.
domain
else
asset
.
domain
.
id
,
'is_active'
:
asset
.
is_active
,
...
...
apps/perms/views/asset_permission.py
View file @
8e9b3f13
...
...
@@ -58,8 +58,6 @@ class AssetPermissionCreateView(PermissionsMixin, CreateView):
assets_id
=
assets_id
.
split
(
","
)
assets
=
Asset
.
objects
.
filter
(
id__in
=
assets_id
)
form
[
'assets'
]
.
initial
=
assets
form
[
'actions'
]
.
initial
=
Action
.
objects
.
get
(
name
=
PERMS_ACTION_NAME_ALL
)
return
form
def
get_context_data
(
self
,
**
kwargs
):
...
...
apps/static/js/jumpserver.js
View file @
8e9b3f13
...
...
@@ -277,7 +277,7 @@ function APIUpdateAttr(props) {
}).
done
(
function
(
data
,
textStatue
,
jqXHR
)
{
if
(
flash_message
)
{
var
msg
=
""
;
if
(
user_
fail
_message
)
{
if
(
user_
success
_message
)
{
msg
=
user_success_message
;
}
else
{
msg
=
default_success_message
;
...
...
@@ -635,7 +635,7 @@ jumpserver.initServerSideDataTable = function (options) {
columns
:
options
.
columns
||
[],
select
:
options
.
select
||
select
,
language
:
jumpserver
.
language
,
lengthMenu
:
[[
15
,
25
,
50
,
9999
],
[
15
,
25
,
50
,
'All'
]]
lengthMenu
:
options
.
lengthMenu
||
[[
15
,
25
,
50
,
9999
],
[
15
,
25
,
50
,
'All'
]]
});
table
.
selected
=
[];
table
.
selected_rows
=
[];
...
...
@@ -1072,3 +1072,27 @@ function htmlEscape ( d ) {
d
.
replace
(
/</g
,
'<'
).
replace
(
/>/g
,
'>'
).
replace
(
/"/g
,
'"'
)
:
d
;
}
function
objectAttrsIsList
(
obj
,
attrs
)
{
attrs
.
forEach
(
function
(
attr
)
{
if
(
obj
[
attr
]
&&
!
(
obj
[
attr
]
instanceof
Array
)){
obj
[
attr
]
=
[
obj
[
attr
]]
}
})
}
function
objectAttrsIsDatetime
(
obj
,
attrs
)
{
attrs
.
forEach
(
function
(
attr
)
{
obj
[
attr
]
=
new
Date
(
obj
[
attr
]).
toISOString
();
})
}
function
objectAttrsIsBool
(
obj
,
attrs
)
{
attrs
.
forEach
(
function
(
attr
)
{
if
(
!
obj
[
attr
])
{
obj
[
attr
]
=
false
}
else
if
([
'on'
,
'1'
].
includes
(
obj
[
attr
]))
{
obj
[
attr
]
=
true
}
})
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment