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
a5b874e2
Commit
a5b874e2
authored
May 24, 2019
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Update] 改密支持windows
parent
75fb37d2
Show whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
643 additions
and
244 deletions
+643
-244
asset.py
apps/assets/api/asset.py
+3
-2
asset.py
apps/assets/forms/asset.py
+27
-11
0027_auto_20190521_1703.py
apps/assets/migrations/0027_auto_20190521_1703.py
+5
-0
0028_protocol.py
apps/assets/migrations/0028_protocol.py
+29
-0
0029_auto_20190522_1114.py
apps/assets/migrations/0029_auto_20190522_1114.py
+22
-0
__init__.py
apps/assets/models/__init__.py
+0
-1
asset.py
apps/assets/models/asset.py
+31
-14
asset.py
apps/assets/serializers/asset.py
+70
-16
signals_handler.py
apps/assets/signals_handler.py
+4
-0
asset_create.html
apps/assets/templates/assets/asset_create.html
+151
-12
asset_update.html
apps/assets/templates/assets/asset_update.html
+40
-83
asset.py
apps/assets/views/asset.py
+32
-2
decorator.py
apps/common/decorator.py
+12
-0
mixins.py
apps/common/mixins.py
+24
-0
validators.py
apps/common/validators.py
+17
-0
conf.py
apps/jumpserver/conf.py
+3
-0
django.mo
apps/locale/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/locale/zh/LC_MESSAGES/django.po
+129
-98
mixins.py
apps/orgs/mixins.py
+13
-0
hands.py
apps/perms/hands.py
+2
-1
remote_app_permission.py
apps/perms/views/remote_app_permission.py
+1
-2
jumpserver.css
apps/static/css/jumpserver.css
+12
-0
jumpserver.js
apps/static/js/jumpserver.js
+16
-2
No files found.
apps/assets/api/asset.py
View file @
a5b874e2
...
...
@@ -16,7 +16,7 @@ from django.urls import reverse_lazy
from
django.core.cache
import
cache
from
django.db.models
import
Q
from
common.mixins
import
IDInCacheFilterMixin
from
common.mixins
import
IDInCacheFilterMixin
,
ApiMessageMixin
from
common.utils
import
get_logger
,
get_object_or_none
from
common.permissions
import
IsOrgAdmin
,
IsOrgAdminOrAppUser
...
...
@@ -36,7 +36,7 @@ __all__ = [
]
class
AssetViewSet
(
IDInCacheFilterMixin
,
LabelFilter
,
BulkModelViewSet
):
class
AssetViewSet
(
IDInCacheFilterMixin
,
LabelFilter
,
ApiMessageMixin
,
BulkModelViewSet
):
"""
API endpoint that allows Asset to be viewed or edited.
"""
...
...
@@ -47,6 +47,7 @@ class AssetViewSet(IDInCacheFilterMixin, LabelFilter, BulkModelViewSet):
serializer_class
=
serializers
.
AssetSerializer
pagination_class
=
LimitOffsetPagination
permission_classes
=
(
IsOrgAdminOrAppUser
,)
success_message
=
_
(
"
%(hostname)
s was
%(action)
s successfully"
)
def
set_assets_node
(
self
,
assets
):
if
not
isinstance
(
assets
,
list
):
...
...
apps/assets/forms/asset.py
View file @
a5b874e2
...
...
@@ -6,21 +6,39 @@ from django.utils.translation import gettext_lazy as _
from
common.utils
import
get_logger
from
orgs.mixins
import
OrgModelForm
from
..models
import
Asset
,
AdminUser
from
..models
import
Asset
,
AdminUser
,
Protocol
logger
=
get_logger
(
__file__
)
__all__
=
[
'AssetCreateForm'
,
'AssetUpdateForm'
,
'AssetBulkUpdateForm'
]
__all__
=
[
'AssetCreateForm'
,
'AssetUpdateForm'
,
'AssetBulkUpdateForm'
,
'ProtocolForm'
]
class
ProtocolForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
Protocol
fields
=
[
'name'
,
'port'
]
widgets
=
{
'name'
:
forms
.
Select
(
attrs
=
{
'class'
:
'form-control protocol-name'
}),
'port'
:
forms
.
TextInput
(
attrs
=
{
'class'
:
'form-control protocol-port'
}),
}
class
AssetCreateForm
(
OrgModelForm
):
PROTOCOL_CHOICES
=
Protocol
.
PROTOCOL_CHOICES
class
Meta
:
model
=
Asset
fields
=
[
'hostname'
,
'ip'
,
'public_ip'
,
'p
ort'
,
'comment'
,
'hostname'
,
'ip'
,
'public_ip'
,
'p
rotocols'
,
'comment'
,
'nodes'
,
'is_active'
,
'admin_user'
,
'labels'
,
'platform'
,
'domain'
,
'protocol'
,
'domain'
,
]
widgets
=
{
'nodes'
:
forms
.
SelectMultiple
(
attrs
=
{
...
...
@@ -32,7 +50,6 @@ class AssetCreateForm(OrgModelForm):
'labels'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Label'
)
}),
'port'
:
forms
.
TextInput
(),
'domain'
:
forms
.
Select
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Domain'
)
}),
...
...
@@ -54,9 +71,9 @@ class AssetUpdateForm(OrgModelForm):
class
Meta
:
model
=
Asset
fields
=
[
'hostname'
,
'ip'
,
'p
ort
'
,
'nodes'
,
'is_active'
,
'platform'
,
'hostname'
,
'ip'
,
'p
rotocols
'
,
'nodes'
,
'is_active'
,
'platform'
,
'public_ip'
,
'number'
,
'comment'
,
'admin_user'
,
'labels'
,
'domain'
,
'protocol'
,
'domain'
,
]
widgets
=
{
'nodes'
:
forms
.
SelectMultiple
(
attrs
=
{
...
...
@@ -68,7 +85,6 @@ class AssetUpdateForm(OrgModelForm):
'labels'
:
forms
.
SelectMultiple
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Label'
)
}),
'port'
:
forms
.
TextInput
(),
'domain'
:
forms
.
Select
(
attrs
=
{
'class'
:
'select2'
,
'data-placeholder'
:
_
(
'Domain'
)
}),
...
...
@@ -101,8 +117,8 @@ class AssetBulkUpdateForm(OrgModelForm):
class
Meta
:
model
=
Asset
fields
=
[
'assets'
,
'
port'
,
'
admin_user'
,
'labels'
,
'platform'
,
'
protocol'
,
'
domain'
,
'assets'
,
'admin_user'
,
'labels'
,
'platform'
,
'domain'
,
]
widgets
=
{
'labels'
:
forms
.
SelectMultiple
(
...
...
apps/assets/migrations/0027_auto_20190521_1703.py
View file @
a5b874e2
...
...
@@ -15,4 +15,9 @@ class Migration(migrations.Migration):
name
=
'ip'
,
field
=
models
.
CharField
(
db_index
=
True
,
max_length
=
128
,
verbose_name
=
'IP'
),
),
migrations
.
AlterField
(
model_name
=
'asset'
,
name
=
'public_ip'
,
field
=
models
.
CharField
(
blank
=
True
,
max_length
=
128
,
null
=
True
,
verbose_name
=
'Public IP'
),
),
]
apps/assets/migrations/0028_protocol.py
0 → 100644
View file @
a5b874e2
# Generated by Django 2.1.7 on 2019-05-22 02:58
import
django.core.validators
from
django.db
import
migrations
,
models
import
uuid
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'assets'
,
'0027_auto_20190521_1703'
),
]
operations
=
[
migrations
.
CreateModel
(
name
=
'Protocol'
,
fields
=
[
(
'id'
,
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
,
serialize
=
False
)),
(
'name'
,
models
.
CharField
(
choices
=
[(
'ssh'
,
'ssh'
),
(
'rdp'
,
'rdp'
),
(
'telnet'
,
'telnet (beta)'
),
(
'vnc'
,
'vnc'
)],
default
=
'ssh'
,
max_length
=
16
,
verbose_name
=
'Name'
)),
(
'port'
,
models
.
IntegerField
(
default
=
22
,
validators
=
[
django
.
core
.
validators
.
MaxValueValidator
(
65535
),
django
.
core
.
validators
.
MinValueValidator
(
1
)],
verbose_name
=
'Port'
)),
],
),
migrations
.
AddField
(
model_name
=
'asset'
,
name
=
'protocols'
,
field
=
models
.
ManyToManyField
(
to
=
'assets.Protocol'
,
verbose_name
=
'Protocol'
),
),
]
apps/assets/migrations/0029_auto_20190522_1114.py
0 → 100644
View file @
a5b874e2
# Generated by Django 2.1.7 on 2019-05-22 03:14
from
django.db
import
migrations
def
migrate_assets_protocol
(
apps
,
schema_editor
):
asset_model
=
apps
.
get_model
(
"assets"
,
"Asset"
)
db_alias
=
schema_editor
.
connection
.
alias
assets
=
asset_model
.
objects
.
using
(
db_alias
)
.
all
()
for
asset
in
assets
:
asset
.
protocols
.
create
(
name
=
asset
.
protocol
,
port
=
asset
.
port
)
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'assets'
,
'0028_protocol'
),
]
operations
=
[
migrations
.
RunPython
(
migrate_assets_protocol
),
]
apps/assets/models/__init__.py
View file @
a5b874e2
...
...
@@ -8,4 +8,3 @@ from .asset import *
from
.cmd_filter
import
*
from
.utils
import
*
from
.authbook
import
*
from
applications.models.remote_app
import
*
apps/assets/models/asset.py
View file @
a5b874e2
...
...
@@ -12,11 +12,12 @@ from django.db import models
from
django.db.models
import
Q
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.core.cache
import
cache
from
django.core.validators
import
MinValueValidator
,
MaxValueValidator
from
.user
import
AdminUser
,
SystemUser
from
orgs.mixins
import
OrgModelMixin
,
OrgManager
__all__
=
[
'Asset'
]
__all__
=
[
'Asset'
,
'Protocol'
]
logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -47,6 +48,29 @@ class AssetQuerySet(models.QuerySet):
return
self
.
active
()
class
Protocol
(
models
.
Model
):
PROTOCOL_SSH
=
'ssh'
PROTOCOL_RDP
=
'rdp'
PROTOCOL_TELNET
=
'telnet'
PROTOCOL_VNC
=
'vnc'
PROTOCOL_CHOICES
=
(
(
PROTOCOL_SSH
,
'ssh'
),
(
PROTOCOL_RDP
,
'rdp'
),
(
PROTOCOL_TELNET
,
'telnet (beta)'
),
(
PROTOCOL_VNC
,
'vnc'
),
)
PORT_VALIDATORS
=
[
MaxValueValidator
(
65535
),
MinValueValidator
(
1
)]
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
name
=
models
.
CharField
(
max_length
=
16
,
choices
=
PROTOCOL_CHOICES
,
default
=
PROTOCOL_SSH
,
verbose_name
=
_
(
"Name"
))
port
=
models
.
IntegerField
(
default
=
22
,
verbose_name
=
_
(
"Port"
),
validators
=
PORT_VALIDATORS
)
def
__str__
(
self
):
return
"{}:{}"
.
format
(
self
.
name
,
self
.
port
)
class
Asset
(
OrgModelMixin
):
# Important
PLATFORM_CHOICES
=
(
...
...
@@ -59,22 +83,15 @@ class Asset(OrgModelMixin):
(
'Other'
,
'Other'
),
)
PROTOCOL_SSH
=
'ssh'
PROTOCOL_RDP
=
'rdp'
PROTOCOL_TELNET
=
'telnet'
PROTOCOL_VNC
=
'vnc'
PROTOCOL_CHOICES
=
(
(
PROTOCOL_SSH
,
'ssh'
),
(
PROTOCOL_RDP
,
'rdp'
),
(
PROTOCOL_TELNET
,
'telnet (beta)'
),
(
PROTOCOL_VNC
,
'vnc'
),
)
id
=
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
)
ip
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
'IP'
),
db_index
=
True
)
hostname
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
'Hostname'
))
protocol
=
models
.
CharField
(
max_length
=
128
,
default
=
PROTOCOL_SSH
,
choices
=
PROTOCOL_CHOICES
,
verbose_name
=
_
(
'Protocol'
))
protocol
=
models
.
CharField
(
max_length
=
128
,
default
=
Protocol
.
PROTOCOL_SSH
,
choices
=
Protocol
.
PROTOCOL_CHOICES
,
verbose_name
=
_
(
'Protocol'
))
port
=
models
.
IntegerField
(
default
=
22
,
verbose_name
=
_
(
'Port'
))
protocols
=
models
.
ManyToManyField
(
'Protocol'
,
verbose_name
=
_
(
"Protocol"
))
platform
=
models
.
CharField
(
max_length
=
128
,
choices
=
PLATFORM_CHOICES
,
default
=
'Linux'
,
verbose_name
=
_
(
'Platform'
))
domain
=
models
.
ForeignKey
(
"assets.Domain"
,
null
=
True
,
blank
=
True
,
related_name
=
'assets'
,
verbose_name
=
_
(
"Domain"
),
on_delete
=
models
.
SET_NULL
)
nodes
=
models
.
ManyToManyField
(
'assets.Node'
,
default
=
default_node
,
related_name
=
'assets'
,
verbose_name
=
_
(
"Nodes"
))
...
...
@@ -84,7 +101,7 @@ class Asset(OrgModelMixin):
admin_user
=
models
.
ForeignKey
(
'assets.AdminUser'
,
on_delete
=
models
.
PROTECT
,
null
=
True
,
verbose_name
=
_
(
"Admin user"
))
# Some information
public_ip
=
models
.
GenericIPAddressField
(
max_length
=
32
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Public IP'
))
public_ip
=
models
.
CharField
(
max_length
=
128
,
blank
=
True
,
null
=
True
,
verbose_name
=
_
(
'Public IP'
))
number
=
models
.
CharField
(
max_length
=
32
,
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Asset number'
))
# Collect
...
...
apps/assets/serializers/asset.py
View file @
a5b874e2
# -*- coding: utf-8 -*-
#
from
rest_framework
import
serializers
from
rest_framework.validators
import
ValidationError
from
django.utils.translation
import
ugettext_lazy
as
_
from
orgs.mixins
import
OrgResourceSerializerMixin
from
common.mixins
import
BulkSerializerMixin
from
common.serializers
import
AdaptedBulkListSerializer
from
..models
import
Asset
from
common.validators
import
ProjectUniqueValidator
from
..models
import
Asset
,
Protocol
from
.system_user
import
AssetSystemUserSerializer
__all__
=
[
...
...
@@ -16,25 +18,32 @@ __all__ = [
]
class
AssetSerializer
(
BulkSerializerMixin
,
serializers
.
ModelSerializer
,
OrgResourceSerializerMixin
):
class
ProtocolSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Protocol
fields
=
[
"name"
,
"port"
]
class
AssetSerializer
(
BulkSerializerMixin
,
OrgResourceSerializerMixin
,
serializers
.
ModelSerializer
):
protocols
=
ProtocolSerializer
(
many
=
True
)
"""
资产的数据结构
"""
class
Meta
:
model
=
Asset
list_serializer_class
=
AdaptedBulkListSerializer
# validators = [] # 解决批量导入时unique_together字段校验失败
fields
=
[
'id'
,
'org_id'
,
'org_name'
,
'ip'
,
'hostname'
,
'protocol'
,
'port'
,
'p
latform'
,
'is_active'
,
'public_ip'
,
'domain'
,
'admin_user
'
,
'nodes'
,
'labels'
,
'number'
,
'vendor'
,
'model'
,
'sn'
,
'p
rotocols'
,
'platform'
,
'is_active'
,
'public_ip'
,
'domain
'
,
'
admin_user'
,
'
nodes'
,
'labels'
,
'number'
,
'vendor'
,
'model'
,
'sn'
,
'cpu_model'
,
'cpu_count'
,
'cpu_cores'
,
'cpu_vcpus'
,
'memory'
,
'disk_total'
,
'disk_info'
,
'os'
,
'os_version'
,
'os_arch'
,
'hostname_raw'
,
'comment'
,
'created_by'
,
'date_created'
,
'hardware_info'
,
'connectivity'
]
read_only_fields
=
(
'
number'
,
'
vendor'
,
'model'
,
'sn'
,
'cpu_model'
,
'cpu_count'
,
'vendor'
,
'model'
,
'sn'
,
'cpu_model'
,
'cpu_count'
,
'cpu_cores'
,
'cpu_vcpus'
,
'memory'
,
'disk_total'
,
'disk_info'
,
'os'
,
'os_version'
,
'os_arch'
,
'hostname_raw'
,
'created_by'
,
'date_created'
,
...
...
@@ -43,7 +52,6 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer, OrgResou
'hardware_info'
:
{
'label'
:
_
(
'Hardware info'
)},
'connectivity'
:
{
'label'
:
_
(
'Connectivity'
)},
'org_name'
:
{
'label'
:
_
(
'Org name'
)}
}
@classmethod
...
...
@@ -53,18 +61,64 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer, OrgResou
.
select_related
(
'admin_user'
)
return
queryset
def
get_field_names
(
self
,
declared_fields
,
info
):
fields
=
super
()
.
get_field_names
(
declared_fields
,
info
)
fields
.
extend
([
'hardware_info'
,
'connectivity'
,
'org_name'
])
return
fields
@staticmethod
def
validate_protocols
(
attr
):
protocols_name
=
[
i
.
get
(
"name"
,
"ssh"
)
for
i
in
attr
]
errors
=
[{}
for
i
in
protocols_name
]
for
i
,
name
in
enumerate
(
protocols_name
):
if
name
in
protocols_name
[:
i
]:
errors
[
i
]
=
{
"name"
:
_
(
"Protocol duplicate: {}"
)
.
format
(
name
)}
if
any
(
errors
):
raise
ValidationError
(
errors
)
return
attr
def
create
(
self
,
validated_data
):
protocols_data
=
validated_data
.
pop
(
"protocols"
)
# 兼容老的api
protocol
=
validated_data
.
get
(
"protocol"
)
port
=
validated_data
.
get
(
"port"
)
if
not
protocols_data
and
protocol
and
port
:
protocols_data
=
[{
"name"
:
protocol
,
"port"
:
port
}]
if
not
protocol
and
not
port
and
protocols_data
:
validated_data
[
"protocol"
]
=
protocols_data
[
0
][
"name"
]
validated_data
[
"port"
]
=
protocols_data
[
0
][
"port"
]
protocols_serializer
=
ProtocolSerializer
(
data
=
protocols_data
,
many
=
True
)
protocols_serializer
.
is_valid
(
raise_exception
=
True
)
protocols
=
protocols_serializer
.
save
()
instance
=
super
()
.
create
(
validated_data
)
instance
.
protocols
.
set
(
protocols
)
return
instance
def
update
(
self
,
instance
,
validated_data
):
protocols_data
=
validated_data
.
pop
(
"protocols"
)
# 兼容老的api
protocol
=
validated_data
.
get
(
"protocol"
)
port
=
validated_data
.
get
(
"port"
)
if
not
protocols_data
and
protocol
and
port
:
protocols_data
=
[{
"name"
:
protocol
,
"port"
:
port
}]
if
not
protocol
and
not
port
and
protocols_data
:
validated_data
[
"protocol"
]
=
protocols_data
[
0
][
"name"
]
validated_data
[
"port"
]
=
protocols_data
[
0
][
"port"
]
protocols_serializer
=
ProtocolSerializer
(
data
=
protocols_data
,
many
=
True
)
protocols_serializer
.
is_valid
(
raise_exception
=
True
)
protocols
=
protocols_serializer
.
save
()
instance
=
super
()
.
update
(
instance
,
validated_data
)
instance
.
protocols
.
all
()
.
delete
()
instance
.
protocols
.
set
(
protocols
)
return
instance
class
AssetAsNodeSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
Asset
fields
=
[
'id'
,
'hostname'
,
'ip'
,
'p
ort'
,
'platform'
,
'protocol
'
]
fields
=
[
'id'
,
'hostname'
,
'ip'
,
'p
latform'
,
'protocols
'
]
class
AssetGrantedSerializer
(
serializers
.
ModelSerializer
):
...
...
@@ -78,9 +132,9 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
class
Meta
:
model
=
Asset
fields
=
(
"id"
,
"hostname"
,
"ip"
,
"
port"
,
"
system_users_granted"
,
"id"
,
"hostname"
,
"ip"
,
"system_users_granted"
,
"is_active"
,
"system_users_join"
,
"os"
,
'domain'
,
"platform"
,
"comment"
,
"protocol"
,
"org_id"
,
"org_name"
,
"platform"
,
"comment"
,
"protocol
s
"
,
"org_id"
,
"org_name"
,
)
@staticmethod
...
...
apps/assets/signals_handler.py
View file @
a5b874e2
...
...
@@ -5,6 +5,7 @@ from django.db.models.signals import post_save, m2m_changed, post_delete
from
django.dispatch
import
receiver
from
common.utils
import
get_logger
from
common.decorator
import
on_transaction_commit
from
.models
import
Asset
,
SystemUser
,
Node
,
AuthBook
from
.tasks
import
(
update_assets_hardware_info_util
,
...
...
@@ -32,9 +33,12 @@ def set_asset_root_node(asset):
@receiver
(
post_save
,
sender
=
Asset
,
dispatch_uid
=
"my_unique_identifier"
)
@on_transaction_commit
def
on_asset_created_or_update
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
if
created
:
logger
.
info
(
"Asset `{}` create signal received"
.
format
(
instance
))
# 获取资产硬件信息
update_asset_hardware_info_on_created
(
instance
)
test_asset_conn_on_created
(
instance
)
...
...
apps/assets/templates/assets/asset_create.html
View file @
a5b874e2
...
...
@@ -16,12 +16,24 @@
<h3>
{% trans 'Basic' %}
</h3>
{% bootstrap_field form.hostname layout="horizontal" %}
{% bootstrap_field form.ip layout="horizontal" %}
{% bootstrap_field form.protocol layout="horizontal" %}
{% bootstrap_field form.port layout="horizontal" %}
{% bootstrap_field form.platform layout="horizontal" %}
{% bootstrap_field form.public_ip layout="horizontal" %}
{% bootstrap_field form.domain layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Protocols' %}
</h3>
<div
class=
"protocols"
>
{% for fm in formset.forms %}
<div
class=
"form-group"
>
<div
class=
"col-md-2 col-md-offset-2"
style=
"text-align: right"
>
{{ fm.name }}
</div>
<div
class=
"col-md-6"
>
{{ fm.port }}
</div>
<div
class=
"col-md-1"
style=
"padding: 6px 0"
>
<a
class=
"btn btn-danger btn-xs btn-protocol btn-del"
><span
class=
"fa fa-minus"
></span>
</a>
<a
class=
"btn btn-primary btn-xs btn-protocol btn-add"
style=
"display: none"
><span
class=
"fa fa-plus"
></span></a>
</div>
</div>
{% endfor %}
</div>
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Auth' %}
</h3>
{% bootstrap_field form.admin_user layout="horizontal" %}
...
...
@@ -55,6 +67,8 @@
{% endif %}
</div>
</div>
{% block extra %}
{% endblock %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Other' %}
</h3>
...
...
@@ -73,11 +87,25 @@
{% block custom_foot_js %}
<script>
var
instanceId
=
"{{ object.id }}"
;
var
protocolLen
=
0
;
function
format
(
item
)
{
var
group
=
item
.
element
.
parentElement
.
label
;
return
group
+
':'
+
item
.
text
;
}
function
protocolBtnShow
()
{
$
(
".btn-protocol.btn-add"
).
hide
();
$
(
".btn-protocol.btn-add:last"
).
show
();
var
btnDel
=
$
(
".btn-protocol.btn-del"
);
if
(
btnDel
.
length
===
1
)
{
btnDel
.
addClass
(
"disabled"
)
}
else
{
btnDel
.
removeClass
(
"disabled"
)
}
}
$
(
document
).
ready
(
function
()
{
$
(
'.select2'
).
select2
({
allowClear
:
true
...
...
@@ -89,20 +117,130 @@ $(document).ready(function () {
$
(
'#id_nodes.select2'
).
select2
({
closeOnSelect
:
false
});
$
(
"#id_protocol"
).
change
(
function
(){
var
protocol
=
$
(
"#id_protocol option:selected"
).
text
();
var
port
=
22
;
if
(
protocol
===
'rdp'
)
{
port
=
3389
;
protocolBtnShow
()
})
.
on
(
"change"
,
"#id_platform"
,
function
()
{
if
(
instanceId
!==
""
)
{
return
}
else
if
(
protocol
===
'telnet (beta)'
){
port
=
23
;
var
platform
=
$
(
this
).
val
();
var
protocolRef
=
$
(
".protocols"
).
find
(
"select"
).
first
()
var
protocol
=
protocolRef
.
val
();
var
protocolShould
=
""
;
if
(
platform
.
startsWith
(
"Windows"
)){
protocolShould
=
"rdp"
}
else
{
protocolShould
=
"ssh"
}
else
if
(
protocol
===
'vnc'
){
port
=
5901
;
if
(
protocol
!==
protocolShould
)
{
protocolRef
.
val
(
protocolShould
);
protocolRef
.
trigger
(
"change"
)
}
$
(
"#id_port"
).
val
(
port
);
})
.
on
(
"click"
,
".btn-protocol.btn-del"
,
function
()
{
$
(
this
).
parent
().
parent
().
remove
();
protocolBtnShow
()
})
.
on
(
"click"
,
".btn-protocol.btn-add"
,
function
()
{
var
protocol
=
""
;
var
protocolsRef
=
$
(
".protocols"
);
var
firstProtocolForm
=
protocolsRef
.
children
().
first
();
var
newProtocolForm
=
firstProtocolForm
.
clone
();
var
protocolChoices
=
$
.
map
(
$
(
firstProtocolForm
.
find
(
'select option'
)),
function
(
option
)
{
return
option
.
value
});
var
protocolsSet
=
$
.
map
(
protocolsRef
.
find
(
'select option:selected'
),
function
(
option
)
{
return
option
.
value
});
for
(
var
i
=
0
;
i
<
protocolChoices
.
length
;
i
++
)
{
var
p
=
protocolChoices
[
i
];
if
(
protocolsSet
.
indexOf
(
p
)
===
-
1
)
{
protocol
=
p
;
break
}
}
if
(
protocol
===
""
)
{
return
}
if
(
protocolLen
===
0
)
{
protocolLen
=
protocolsRef
.
length
;
}
var
selectName
=
"form-"
+
protocolLen
+
"-name"
;
var
selectId
=
"id_"
+
selectName
;
var
portName
=
"form-"
+
protocolLen
+
"-port"
;
var
portId
=
"id_"
+
portName
;
newProtocolForm
.
find
(
"select"
).
prop
(
"name"
,
selectName
).
prop
(
"id"
,
selectId
);
newProtocolForm
.
find
(
"input"
).
prop
(
"name"
,
portName
).
prop
(
"id"
,
portId
);
newProtocolForm
.
find
(
"option[value='"
+
protocol
+
"']"
).
attr
(
"selected"
,
true
);
protocolsRef
.
append
(
newProtocolForm
);
protocolLen
+=
1
;
$
(
"#"
+
selectId
).
trigger
(
"change"
);
protocolBtnShow
()
})
.
on
(
"change"
,
".protocol-name"
,
function
()
{
var
name
=
$
(
this
).
val
();
var
port
=
22
;
switch
(
name
)
{
case
"ssh"
:
port
=
22
;
break
;
case
"rdp"
:
port
=
3389
;
break
;
case
"telnet"
:
port
=
21
;
break
;
case
"vnc"
:
port
=
5901
;
break
;
default
:
port
=
22
;
break
}
$
(
this
).
parent
().
parent
().
find
(
".protocol-port"
).
val
(
port
);
})
</script>
{% block form_submit %}
<script>
$
(
document
).
ready
(
function
()
{
})
.
on
(
"submit"
,
"form"
,
function
(
evt
)
{
evt
.
preventDefault
();
var
the_url
=
'{% url '
api
-
assets
:
asset
-
list
' %}'
;
var
redirect_to
=
'{% url "assets:asset-list" %}'
;
var
form
=
$
(
"form"
);
var
protocols
=
{};
var
data
=
form
.
serializeObject
();
$
.
each
(
data
,
function
(
k
,
v
)
{
if
(
k
.
startsWith
(
"form"
)){
delete
data
[
k
];
var
_k
=
k
.
split
(
"-"
);
var
formName
=
_k
.
slice
(
0
,
2
).
join
(
"-"
);
var
key
=
_k
[
_k
.
length
-
1
];
if
(
!
protocols
[
formName
])
{
protocols
[
formName
]
=
{}
}
protocols
[
formName
][
key
]
=
v
}
});
protocols
=
$
.
map
(
protocols
,
function
(
v
)
{
return
v
});
data
[
"protocols"
]
=
protocols
;
if
(
typeof
data
[
"nodes"
]
==
"string"
)
{
data
[
"nodes"
]
=
[
data
[
"nodes"
]]
}
var
props
=
{
url
:
the_url
,
data
:
data
,
method
:
"POST"
,
form
:
form
,
redirect_to
:
redirect_to
};
formSubmit
(
props
);
})
</script>
{% endblock %}
{% endblock %}
\ No newline at end of file
apps/assets/templates/assets/asset_update.html
View file @
a5b874e2
{% extends '_base_create_update.html' %}
{% load static %}
{% extends 'assets/asset_create.html' %}
{% load bootstrap3 %}
{% load i18n %}
{% load asset_tags %}
{% load common_tags %}
{% block custom_head_css_js_create %}
<link
href=
"{% static "
css
/
plugins
/
inputTags
.
css
"
%}"
rel=
"stylesheet"
>
<script
src=
"{% static "
js
/
plugins
/
inputTags
.
jquery
.
min
.
js
"
%}"
></script>
{% endblock %}
{% block form %}
<form
action=
""
method=
"post"
class=
"form-horizontal"
>
{% if form.non_field_errors %}
<div
class=
"alert alert-danger"
>
{{ form.non_field_errors }}
</div>
{% endif %}
{% csrf_token %}
<h3>
{% trans 'Basic' %}
</h3>
{% bootstrap_field form.hostname layout="horizontal" %}
{% bootstrap_field form.ip layout="horizontal" %}
{% bootstrap_field form.protocol layout="horizontal" %}
{% bootstrap_field form.port layout="horizontal" %}
{% bootstrap_field form.platform layout="horizontal" %}
{% bootstrap_field form.public_ip layout="horizontal" %}
{% bootstrap_field form.domain layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Auth' %}
</h3>
{% bootstrap_field form.admin_user layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Node' %}
</h3>
{% bootstrap_field form.nodes layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Labels' %}
</h3>
<div
class=
"form-group"
>
<label
for=
"{{ form.labels.id_for_label }}"
class=
"col-md-2 control-label"
>
{% trans 'Label' %}
</label>
<div
class=
"col-md-9"
>
<select
name=
"labels"
class=
"select2 labels"
data-placeholder=
"{% trans 'Label' %}"
style=
"width: 100%"
multiple=
""
tabindex=
"4"
id=
"{{ form.labels.id_for_label }}"
>
{% for name, labels in form.labels.field.queryset|group_labels %}
<optgroup
label=
"{{ name }}"
>
{% for label in labels %}
{% if label in form.labels.initial %}
<option
value=
"{{ label.id }}"
selected
>
{{ label.value }}
</option>
{% else %}
<option
value=
"{{ label.id }}"
>
{{ label.value }}
</option>
{% endif %}
{% endfor %}
</optgroup>
{% endfor %}
</select>
</div>
</div>
{% block extra %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Configuration' %}
</h3>
{% bootstrap_field form.number layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<h3>
{% trans 'Other' %}
</h3>
{% bootstrap_field form.comment layout="horizontal" %}
{% bootstrap_field form.is_active layout="horizontal" %}
<div
class=
"hr-line-dashed"
></div>
<div
class=
"form-group"
>
<div
class=
"col-sm-4 col-sm-offset-2"
>
<button
class=
"btn btn-white"
type=
"reset"
>
{% trans 'Reset' %}
</button>
<button
id=
"submit_button"
class=
"btn btn-primary"
type=
"submit"
>
{% trans 'Submit' %}
</button>
</div>
</div>
</form>
{% endblock %}
{% block custom_foot_js %}
<script>
function
format
(
item
)
{
var
group
=
item
.
element
.
parentElement
.
label
;
return
group
+
':'
+
item
.
text
;
}
{% block form_submit %}
<script>
$
(
document
).
ready
(
function
()
{
$
(
'.select2'
).
select2
({
allowClear
:
true
})
.
on
(
"submit"
,
"form"
,
function
(
evt
)
{
evt
.
preventDefault
();
var
the_url
=
'{% url '
api
-
assets
:
asset
-
detail
' pk=object.id %}'
;
var
redirect_to
=
'{% url "assets:asset-list" %}'
;
var
form
=
$
(
"form"
);
var
protocols
=
{};
var
data
=
form
.
serializeObject
();
$
.
each
(
data
,
function
(
k
,
v
)
{
if
(
k
.
startsWith
(
"form"
)){
delete
data
[
k
];
var
_k
=
k
.
split
(
"-"
);
var
formName
=
_k
.
slice
(
0
,
2
).
join
(
"-"
);
var
key
=
_k
[
_k
.
length
-
1
];
if
(
!
protocols
[
formName
])
{
protocols
[
formName
]
=
{}
}
protocols
[
formName
][
key
]
=
v
}
});
$
(
".labels"
).
select2
({
allowClear
:
true
,
templateSelection
:
format
protocols
=
$
.
map
(
protocols
,
function
(
v
)
{
return
v
});
})
</script>
data
[
"protocols"
]
=
protocols
;
if
(
typeof
data
[
"nodes"
]
==
"string"
)
{
data
[
"nodes"
]
=
[
data
[
"nodes"
]]
}
var
props
=
{
url
:
the_url
,
data
:
data
,
method
:
"PUT"
,
form
:
form
,
redirect_to
:
redirect_to
};
formSubmit
(
props
);
});
</script>
{% endblock %}
\ No newline at end of file
apps/assets/views/asset.py
View file @
a5b874e2
...
...
@@ -23,6 +23,7 @@ from django.utils import timezone
from
django.contrib.auth.mixins
import
LoginRequiredMixin
from
django.shortcuts
import
redirect
from
django.contrib.messages.views
import
SuccessMessageMixin
from
django.forms.formsets
import
formset_factory
from
common.mixins
import
JSONResponseMixin
from
common.utils
import
get_object_or_none
,
get_logger
...
...
@@ -30,8 +31,6 @@ from common.permissions import AdminUserRequiredMixin
from
common.const
import
(
create_success_msg
,
update_success_msg
,
KEY_CACHE_RESOURCES_ID
)
from
..const
import
CACHE_KEY_ASSET_BULK_UPDATE_ID_PREFIX
from
orgs.utils
import
current_org
from
..
import
forms
from
..models
import
Asset
,
AdminUser
,
SystemUser
,
Label
,
Node
,
Domain
...
...
@@ -101,10 +100,30 @@ class AssetCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
form
[
"nodes"
]
.
initial
=
node
return
form
def
get_protocol_formset
(
self
):
ProtocolFormset
=
formset_factory
(
forms
.
ProtocolForm
,
extra
=
0
,
min_num
=
1
,
max_num
=
5
)
if
self
.
request
.
method
==
"POST"
:
formset
=
ProtocolFormset
(
self
.
request
.
POST
)
else
:
formset
=
ProtocolFormset
()
return
formset
def
form_valid
(
self
,
form
):
formset
=
self
.
get_protocol_formset
()
valid
=
formset
.
is_valid
()
if
not
valid
:
return
self
.
form_invalid
(
form
)
protocols
=
formset
.
save
()
instance
=
super
()
.
form_valid
(
form
)
instance
.
protocols
.
set
(
protocols
)
return
instance
def
get_context_data
(
self
,
**
kwargs
):
formset
=
self
.
get_protocol_formset
()
context
=
{
'app'
:
_
(
'Assets'
),
'action'
:
_
(
'Create asset'
),
'formset'
:
formset
,
}
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
...
...
@@ -159,10 +178,21 @@ class AssetUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
template_name
=
'assets/asset_update.html'
success_url
=
reverse_lazy
(
'assets:asset-list'
)
def
get_protocol_formset
(
self
):
ProtocolFormset
=
formset_factory
(
forms
.
ProtocolForm
,
extra
=
0
,
min_num
=
1
,
max_num
=
5
)
if
self
.
request
.
method
==
"POST"
:
formset
=
ProtocolFormset
(
self
.
request
.
POST
)
else
:
initial_data
=
[{
"name"
:
p
.
name
,
"port"
:
p
.
port
}
for
p
in
self
.
object
.
protocols
.
all
()]
formset
=
ProtocolFormset
(
initial
=
initial_data
)
return
formset
def
get_context_data
(
self
,
**
kwargs
):
formset
=
self
.
get_protocol_formset
()
context
=
{
'app'
:
_
(
'Assets'
),
'action'
:
_
(
'Update asset'
),
'formset'
:
formset
,
}
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
...
...
apps/common/decorator.py
0 → 100644
View file @
a5b874e2
# -*- coding: utf-8 -*-
#
from
django.db
import
transaction
def
on_transaction_commit
(
func
):
"""
如果不调用on_commit, 对象创建时添加多对多字段值失败
"""
def
inner
(
*
args
,
**
kwargs
):
transaction
.
on_commit
(
lambda
:
func
(
*
args
,
**
kwargs
))
return
inner
apps/common/mixins.py
View file @
a5b874e2
...
...
@@ -5,6 +5,7 @@ from django.http import JsonResponse
from
django.utils
import
timezone
from
django.core.cache
import
cache
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.contrib
import
messages
from
rest_framework.utils
import
html
from
rest_framework.settings
import
api_settings
from
rest_framework.exceptions
import
ValidationError
...
...
@@ -203,3 +204,26 @@ class DatetimeSearchMixin:
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
get_date_range
()
return
super
()
.
get
(
request
,
*
args
,
**
kwargs
)
class
ApiMessageMixin
:
success_message
=
_
(
"
%(name)
s was
%(action)
s successfully"
)
_action_map
=
{
"create"
:
_
(
"create"
),
"update"
:
_
(
"update"
)}
def
get_success_message
(
self
,
cleaned_data
):
data
=
{
k
:
v
for
k
,
v
in
cleaned_data
.
items
()}
action
=
getattr
(
self
,
"action"
,
"create"
)
data
[
"action"
]
=
self
.
_action_map
.
get
(
action
)
message
=
self
.
success_message
%
data
return
message
def
dispatch
(
self
,
request
,
*
args
,
**
kwargs
):
resp
=
super
()
.
dispatch
(
request
,
*
args
,
**
kwargs
)
if
request
.
method
.
lower
()
in
(
"get"
,
"delete"
):
return
resp
if
resp
.
status_code
>=
400
:
return
resp
message
=
self
.
get_success_message
(
resp
.
data
)
if
message
:
messages
.
success
(
request
,
message
)
return
resp
apps/common/validators.py
View file @
a5b874e2
...
...
@@ -3,5 +3,22 @@
from
django.core.validators
import
RegexValidator
from
django.utils.translation
import
ugettext_lazy
as
_
from
rest_framework.validators
import
(
UniqueTogetherValidator
,
ValidationError
)
alphanumeric
=
RegexValidator
(
r'^[0-9a-zA-Z_@\-\.]*$'
,
_
(
'Special char not allowed'
))
class
ProjectUniqueValidator
(
UniqueTogetherValidator
):
def
__call__
(
self
,
attrs
):
try
:
super
()
.
__call__
(
attrs
)
except
ValidationError
as
e
:
errors
=
{}
for
field
in
self
.
fields
:
if
field
==
"org_id"
:
continue
errors
[
field
]
=
_
(
'This field must be unique.'
)
raise
ValidationError
(
errors
)
apps/jumpserver/conf.py
View file @
a5b874e2
...
...
@@ -274,6 +274,9 @@ class Config(dict):
return
v
tp
=
type
(
default_value
)
try
:
if
tp
in
[
list
,
dict
]:
v
=
json
.
loads
(
v
)
else
:
v
=
tp
(
v
)
except
Exception
:
pass
...
...
apps/locale/zh/LC_MESSAGES/django.mo
View file @
a5b874e2
No preview for this file type
apps/locale/zh/LC_MESSAGES/django.po
View file @
a5b874e2
...
...
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-05-2
1 21:0
9+0800\n"
"POT-Creation-Date: 2019-05-2
4 10:2
9+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
...
...
@@ -76,7 +76,7 @@ msgstr "运行参数"
#: applications/templates/applications/remote_app_list.html:22
#: applications/templates/applications/user_remote_app_list.html:18
#: assets/forms/domain.py:15 assets/forms/label.py:13
#: assets/models/asset.py:2
79
assets/models/authbook.py:27
#: assets/models/asset.py:2
96
assets/models/authbook.py:27
#: assets/serializers/admin_user.py:23 assets/serializers/system_user.py:28
#: assets/templates/assets/admin_user_list.html:49
#: assets/templates/assets/domain_detail.html:60
...
...
@@ -133,10 +133,10 @@ msgstr "系统用户"
#: applications/templates/applications/remote_app_list.html:20
#: applications/templates/applications/user_remote_app_list.html:16
#: assets/forms/domain.py:73 assets/forms/user.py:84 assets/forms/user.py:146
#: assets/models/
base.py:26 assets/models/cluster.py:18
#: assets/models/c
md_filter.py:20 assets/models/domain
.py:20
#: assets/models/
group.py:20 assets/models/label.py:18
#: assets/templates/assets/admin_user_detail.html:56
#: assets/models/
asset.py:66 assets/models/base.py:26
#: assets/models/c
luster.py:18 assets/models/cmd_filter
.py:20
#: assets/models/
domain.py:20 assets/models/group.py:20
#: assets/
models/label.py:18 assets/
templates/assets/admin_user_detail.html:56
#: assets/templates/assets/admin_user_list.html:47
#: assets/templates/assets/cmd_filter_detail.html:61
#: assets/templates/assets/cmd_filter_list.html:24
...
...
@@ -204,7 +204,7 @@ msgstr "参数"
#: applications/models/remote_app.py:43
#: applications/templates/applications/remote_app_detail.html:77
#: assets/models/asset.py:1
09
assets/models/base.py:34
#: assets/models/asset.py:1
26
assets/models/base.py:34
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:25
#: assets/models/cmd_filter.py:58 assets/models/group.py:21
#: assets/templates/assets/admin_user_detail.html:68
...
...
@@ -226,7 +226,7 @@ msgstr "创建者"
#: applications/models/remote_app.py:46
#: applications/templates/applications/remote_app_detail.html:73
#: assets/models/asset.py:1
10
assets/models/cluster.py:26
#: assets/models/asset.py:1
27
assets/models/cluster.py:26
#: assets/models/domain.py:23 assets/models/group.py:22
#: assets/models/label.py:25 assets/serializers/admin_user.py:37
#: assets/templates/assets/admin_user_detail.html:64
...
...
@@ -252,7 +252,7 @@ msgstr "创建日期"
#: applications/templates/applications/remote_app_detail.html:81
#: applications/templates/applications/remote_app_list.html:24
#: applications/templates/applications/user_remote_app_list.html:20
#: assets/models/asset.py:1
11
assets/models/base.py:31
#: assets/models/asset.py:1
28
assets/models/base.py:31
#: assets/models/cluster.py:29 assets/models/cmd_filter.py:22
#: assets/models/cmd_filter.py:55 assets/models/domain.py:21
#: assets/models/domain.py:53 assets/models/group.py:23
...
...
@@ -306,7 +306,7 @@ msgstr "远程应用"
#: assets/templates/assets/_system_user.html:75
#: assets/templates/assets/admin_user_create_update.html:45
#: assets/templates/assets/asset_bulk_update.html:23
#: assets/templates/assets/asset_create.html:
67
#: assets/templates/assets/asset_create.html:
79
#: assets/templates/assets/asset_update.html:71
#: assets/templates/assets/cmd_filter_create_update.html:15
#: assets/templates/assets/cmd_filter_rule_create_update.html:40
...
...
@@ -342,7 +342,7 @@ msgstr "重置"
#: assets/templates/assets/_system_user.html:76
#: assets/templates/assets/admin_user_create_update.html:46
#: assets/templates/assets/asset_bulk_update.html:24
#: assets/templates/assets/asset_create.html:
68
#: assets/templates/assets/asset_create.html:
80
#: assets/templates/assets/asset_list.html:125
#: assets/templates/assets/asset_update.html:72
#: assets/templates/assets/cmd_filter_create_update.html:16
...
...
@@ -556,9 +556,9 @@ msgstr "连接"
#: assets/templates/assets/system_user_detail.html:22
#: assets/views/admin_user.py:29 assets/views/admin_user.py:47
#: assets/views/admin_user.py:63 assets/views/admin_user.py:78
#: assets/views/admin_user.py:102 assets/views/asset.py:5
3
#: assets/views/asset.py:6
9 assets/views/asset.py:106 assets/views/asset.py:147
#: assets/views/asset.py:1
64 assets/views/asset.py:188
#: assets/views/admin_user.py:102 assets/views/asset.py:5
2
#: assets/views/asset.py:6
8 assets/views/asset.py:124 assets/views/asset.py:166
#: assets/views/asset.py:1
83 assets/views/asset.py:207
#: assets/views/cmd_filter.py:30 assets/views/cmd_filter.py:46
#: assets/views/cmd_filter.py:62 assets/views/cmd_filter.py:78
#: assets/views/cmd_filter.py:97 assets/views/cmd_filter.py:130
...
...
@@ -589,7 +589,12 @@ msgstr "远程应用详情"
msgid "My RemoteApp"
msgstr "我的远程应用"
#: assets/api/asset.py:126
#: assets/api/asset.py:50
#, python-format
msgid "%(hostname)s was %(action)s successfully"
msgstr "%(hostname)s %(action)s成功"
#: assets/api/asset.py:127
msgid "Please select assets that need to be updated"
msgstr "请选择需要更新的资产"
...
...
@@ -605,7 +610,7 @@ msgstr "更新节点资产硬件信息: {}"
msgid "Test if the assets under the node are connectable: {}"
msgstr "测试节点下资产是否可连接: {}"
#: assets/forms/asset.py:
27 assets/models/asset.py:80
assets/models/user.py:133
#: assets/forms/asset.py:
45 assets/models/asset.py:97
assets/models/user.py:133
#: assets/templates/assets/asset_detail.html:194
#: assets/templates/assets/asset_detail.html:202
#: assets/templates/assets/system_user_asset.html:95
...
...
@@ -614,7 +619,7 @@ msgstr "测试节点下资产是否可连接: {}"
msgid "Nodes"
msgstr "节点管理"
#: assets/forms/asset.py:
30 assets/forms/asset.py:66 assets/models/asset.py:84
#: assets/forms/asset.py:
48 assets/forms/asset.py:83 assets/models/asset.py:101
#: assets/models/cluster.py:19 assets/models/user.py:91
#: assets/templates/assets/asset_detail.html:80 templates/_nav.html:24
#: xpack/plugins/cloud/models.py:124
...
...
@@ -623,9 +628,9 @@ msgstr "节点管理"
msgid "Admin user"
msgstr "管理用户"
#: assets/forms/asset.py:
33 assets/forms/asset.py:69 assets/forms/asset.py:109
#: assets/templates/assets/asset_create.html:
36
#: assets/templates/assets/asset_create.html:
38
#: assets/forms/asset.py:
51 assets/forms/asset.py:86 assets/forms/asset.py:125
#: assets/templates/assets/asset_create.html:
48
#: assets/templates/assets/asset_create.html:
50
#: assets/templates/assets/asset_list.html:93
#: assets/templates/assets/asset_update.html:41
#: assets/templates/assets/asset_update.html:43
...
...
@@ -634,7 +639,7 @@ msgstr "管理用户"
msgid "Label"
msgstr "标签"
#: assets/forms/asset.py:
37 assets/forms/asset.py:73 assets/models/asset.py:79
#: assets/forms/asset.py:
54 assets/forms/asset.py:89 assets/models/asset.py:96
#: assets/models/domain.py:26 assets/models/domain.py:52
#: assets/templates/assets/asset_detail.html:84
#: assets/templates/assets/user_asset_list.html:169
...
...
@@ -642,9 +647,9 @@ msgstr "标签"
msgid "Domain"
msgstr "网域"
#: assets/forms/asset.py:
41 assets/forms/asset.py:63 assets/forms/asset.py:77
#: assets/forms/asset.py:1
12
assets/models/node.py:31
#: assets/templates/assets/asset_create.html:
30
#: assets/forms/asset.py:
58 assets/forms/asset.py:80 assets/forms/asset.py:93
#: assets/forms/asset.py:1
28
assets/models/node.py:31
#: assets/templates/assets/asset_create.html:
42
#: assets/templates/assets/asset_update.html:35
#: perms/forms/asset_permission.py:49 perms/forms/asset_permission.py:59
#: perms/models/asset_permission.py:57
...
...
@@ -660,7 +665,7 @@ msgstr "网域"
msgid "Node"
msgstr "节点"
#: assets/forms/asset.py:
45 assets/forms/asset.py:81
#: assets/forms/asset.py:
62 assets/forms/asset.py:97
msgid ""
"root or other NOPASSWD sudo privilege user existed in asset,If asset is "
"windows or other set any one, more see admin user left menu"
...
...
@@ -668,17 +673,17 @@ msgstr ""
"root或其他拥有NOPASSWD: ALL权限的用户, 如果是windows或其它硬件可以随意设置一"
"个, 更多信息查看左侧 `管理用户` 菜单"
#: assets/forms/asset.py:
48 assets/forms/asset.py:84
#: assets/forms/asset.py:
65 assets/forms/asset.py:100
msgid "Windows 2016 RDP protocol is different, If is window 2016, set it"
msgstr "Windows 2016的RDP协议与之前不同,如果是请设置"
#: assets/forms/asset.py:
49 assets/forms/asset.py:85
#: assets/forms/asset.py:
66 assets/forms/asset.py:101
msgid ""
"If your have some network not connect with each other, you can set domain"
msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,使用网域网关跳转登录"
#: assets/forms/asset.py:
92 assets/forms/asset.py:96 assets/forms/domain.py:17
#: assets/forms/label.py:15
#: assets/forms/asset.py:
108 assets/forms/asset.py:112
#: assets/forms/
domain.py:17 assets/forms/
label.py:15
#: perms/templates/perms/asset_permission_asset.html:88
#: xpack/plugins/change_auth_plan/forms.py:105
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:84
...
...
@@ -794,7 +799,17 @@ msgstr "如果选择手动登录模式,用户名和密码可以不填写"
msgid "Use comma split multi command, ex: /bin/whoami,/bin/ifconfig"
msgstr "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig"
#: assets/models/asset.py:74 assets/models/domain.py:49
#: assets/models/asset.py:67 assets/models/asset.py:92
#: assets/models/domain.py:50 assets/templates/assets/admin_user_assets.html:50
#: assets/templates/assets/asset_detail.html:72
#: assets/templates/assets/domain_gateway_list.html:69
#: assets/templates/assets/system_user_asset.html:52
#: assets/templates/assets/user_asset_list.html:164
#: settings/templates/settings/replay_storage_create.html:59
msgid "Port"
msgstr "端口"
#: assets/models/asset.py:87 assets/models/domain.py:49
#: assets/templates/assets/_asset_list_modal.html:46
#: assets/templates/assets/admin_user_assets.html:49
#: assets/templates/assets/asset_detail.html:64
...
...
@@ -811,7 +826,7 @@ msgstr "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig"
msgid "IP"
msgstr "IP"
#: assets/models/asset.py:
75
assets/templates/assets/_asset_list_modal.html:45
#: assets/models/asset.py:
88
assets/templates/assets/_asset_list_modal.html:45
#: assets/templates/assets/_asset_user_auth_modal.html:9
#: assets/templates/assets/_asset_user_view_auth_modal.html:25
#: assets/templates/assets/admin_user_assets.html:48
...
...
@@ -828,8 +843,9 @@ msgstr "IP"
msgid "Hostname"
msgstr "主机名"
#: assets/models/asset.py:76 assets/models/domain.py:51
#: assets/models/user.py:136 assets/templates/assets/asset_detail.html:76
#: assets/models/asset.py:91 assets/models/asset.py:94
#: assets/models/domain.py:51 assets/models/user.py:136
#: assets/templates/assets/asset_detail.html:76
#: assets/templates/assets/domain_gateway_list.html:70
#: assets/templates/assets/system_user_detail.html:70
#: assets/templates/assets/system_user_list.html:53
...
...
@@ -838,108 +854,98 @@ msgstr "主机名"
msgid "Protocol"
msgstr "协议"
#: assets/models/asset.py:77 assets/models/domain.py:50
#: assets/templates/assets/admin_user_assets.html:50
#: assets/templates/assets/asset_detail.html:72
#: assets/templates/assets/domain_gateway_list.html:69
#: assets/templates/assets/system_user_asset.html:52
#: assets/templates/assets/user_asset_list.html:164
#: settings/templates/settings/replay_storage_create.html:59
msgid "Port"
msgstr "端口"
#: assets/models/asset.py:78 assets/templates/assets/asset_detail.html:108
#: assets/models/asset.py:95 assets/templates/assets/asset_detail.html:108
#: assets/templates/assets/user_asset_list.html:166
msgid "Platform"
msgstr "系统平台"
#: assets/models/asset.py:
81
assets/models/cmd_filter.py:21
#: assets/models/asset.py:
98
assets/models/cmd_filter.py:21
#: assets/models/domain.py:54 assets/models/label.py:22
#: assets/templates/assets/asset_detail.html:116
#: assets/templates/assets/user_asset_list.html:170
msgid "Is active"
msgstr "激活"
#: assets/models/asset.py:
87
assets/templates/assets/asset_detail.html:68
#: assets/models/asset.py:
104
assets/templates/assets/asset_detail.html:68
msgid "Public IP"
msgstr "公网IP"
#: assets/models/asset.py:
88
assets/templates/assets/asset_detail.html:124
#: assets/models/asset.py:
105
assets/templates/assets/asset_detail.html:124
msgid "Asset number"
msgstr "资产编号"
#: assets/models/asset.py:
91
assets/templates/assets/asset_detail.html:88
#: assets/models/asset.py:
108
assets/templates/assets/asset_detail.html:88
msgid "Vendor"
msgstr "制造商"
#: assets/models/asset.py:
92
assets/templates/assets/asset_detail.html:92
#: assets/models/asset.py:
109
assets/templates/assets/asset_detail.html:92
msgid "Model"
msgstr "型号"
#: assets/models/asset.py:
93
assets/templates/assets/asset_detail.html:120
#: assets/models/asset.py:
110
assets/templates/assets/asset_detail.html:120
msgid "Serial number"
msgstr "序列号"
#: assets/models/asset.py:
95
#: assets/models/asset.py:
112
msgid "CPU model"
msgstr "CPU型号"
#: assets/models/asset.py:
96
#: assets/models/asset.py:
113
#: xpack/plugins/license/templates/license/license_detail.html:80
msgid "CPU count"
msgstr "CPU数量"
#: assets/models/asset.py:
97
#: assets/models/asset.py:
114
msgid "CPU cores"
msgstr "CPU核数"
#: assets/models/asset.py:
98
#: assets/models/asset.py:
115
msgid "CPU vcpus"
msgstr "CPU总数"
#: assets/models/asset.py:
99
assets/templates/assets/asset_detail.html:100
#: assets/models/asset.py:
116
assets/templates/assets/asset_detail.html:100
msgid "Memory"
msgstr "内存"
#: assets/models/asset.py:1
00
#: assets/models/asset.py:1
17
msgid "Disk total"
msgstr "硬盘大小"
#: assets/models/asset.py:1
01
#: assets/models/asset.py:1
18
msgid "Disk info"
msgstr "硬盘信息"
#: assets/models/asset.py:1
03
assets/templates/assets/asset_detail.html:112
#: assets/models/asset.py:1
20
assets/templates/assets/asset_detail.html:112
#: assets/templates/assets/user_asset_list.html:167
msgid "OS"
msgstr "操作系统"
#: assets/models/asset.py:1
04
#: assets/models/asset.py:1
21
msgid "OS version"
msgstr "系统版本"
#: assets/models/asset.py:1
05
#: assets/models/asset.py:1
22
msgid "OS arch"
msgstr "系统架构"
#: assets/models/asset.py:1
06
#: assets/models/asset.py:1
23
msgid "Hostname raw"
msgstr "主机名原始"
#: assets/models/asset.py:1
08 assets/templates/assets/asset_create.html:34
#: assets/models/asset.py:1
25 assets/templates/assets/asset_create.html:46
#: assets/templates/assets/asset_detail.html:231
#: assets/templates/assets/asset_update.html:39 templates/_nav.html:26
msgid "Labels"
msgstr "标签管理"
#: assets/models/asset.py:1
17
assets/models/base.py:38
#: assets/models/asset.py:1
34
assets/models/base.py:38
#: assets/serializers/admin_user.py:22 assets/serializers/system_user.py:19
#: assets/templates/assets/admin_user_list.html:51
#: assets/templates/assets/system_user_list.html:57
msgid "Unreachable"
msgstr "不可达"
#: assets/models/asset.py:1
18
assets/models/base.py:39
#: assets/models/asset.py:1
35
assets/models/base.py:39
#: assets/serializers/admin_user.py:24 assets/serializers/system_user.py:27
#: assets/templates/assets/admin_user_assets.html:51
#: assets/templates/assets/admin_user_list.html:50
...
...
@@ -951,7 +957,7 @@ msgstr "不可达"
msgid "Reachable"
msgstr "可连接"
#: assets/models/asset.py:1
19
assets/models/base.py:40
#: assets/models/asset.py:1
36
assets/models/base.py:40
#: authentication/utils.py:9 xpack/plugins/license/models.py:78
msgid "Unknown"
msgstr "未知"
...
...
@@ -1198,18 +1204,22 @@ msgstr "%(value)s is not an even number"
msgid "Date updated"
msgstr "更新日期"
#: assets/serializers/asset.py:
43
#: assets/serializers/asset.py:
52
msgid "Hardware info"
msgstr "硬件信息"
#: assets/serializers/asset.py:
44
#: assets/serializers/asset.py:
53
msgid "Connectivity"
msgstr "连接"
#: assets/serializers/asset.py:
45
#: assets/serializers/asset.py:
54
msgid "Org name"
msgstr "组织名"
#: assets/serializers/asset.py:70
msgid "Protocol duplicate: {}"
msgstr "协议重复: {}"
#: assets/serializers/asset_user.py:23 users/forms.py:230
#: users/models/user.py:91 users/templates/users/first_login.html:42
#: users/templates/users/user_password_update.html:46
...
...
@@ -1341,7 +1351,7 @@ msgstr "启用MFA"
msgid "Import assets"
msgstr "导入资产"
#: assets/templates/assets/_asset_list_modal.html:7 assets/views/asset.py:5
4
#: assets/templates/assets/_asset_list_modal.html:7 assets/views/asset.py:5
3
#: templates/_nav.html:22 xpack/plugins/change_auth_plan/views.py:110
msgid "Asset list"
msgstr "资产列表"
...
...
@@ -1437,7 +1447,7 @@ msgid "Basic"
msgstr "基本"
#: assets/templates/assets/_system_user.html:44
#: assets/templates/assets/asset_create.html:
26
#: assets/templates/assets/asset_create.html:
38
#: assets/templates/assets/asset_update.html:31
#: assets/templates/assets/gateway_create_update.html:45
#: users/templates/users/_user.html:21
...
...
@@ -1449,7 +1459,7 @@ msgid "Auto generate key"
msgstr "自动生成密钥"
#: assets/templates/assets/_system_user.html:69
#: assets/templates/assets/asset_create.html:
60
#: assets/templates/assets/asset_create.html:
72
#: assets/templates/assets/asset_update.html:64
#: assets/templates/assets/gateway_create_update.html:53
#: perms/templates/perms/asset_permission_create_update.html:53
...
...
@@ -1470,7 +1480,7 @@ msgstr "更新系统用户"
#: assets/templates/assets/_user_asset_detail_modal.html:11
#: assets/templates/assets/asset_asset_user_list.html:13
#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:
189
#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:
208
msgid "Asset detail"
msgstr "资产详情"
...
...
@@ -1611,7 +1621,7 @@ msgid "Please select file"
msgstr "选择文件"
#: assets/templates/assets/asset_asset_user_list.html:16
#: assets/templates/assets/asset_detail.html:23 assets/views/asset.py:
70
#: assets/templates/assets/asset_detail.html:23 assets/views/asset.py:
69
msgid "Asset user list"
msgstr "资产用户列表"
...
...
@@ -1643,6 +1653,10 @@ msgstr "选择需要修改属性"
msgid "Select all"
msgstr "全选"
#: assets/templates/assets/asset_create.html:24
msgid "Protocols"
msgstr "协议"
#: assets/templates/assets/asset_detail.html:96
msgid "CPU"
msgstr "CPU"
...
...
@@ -1690,7 +1704,7 @@ msgstr ""
"左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的,"
"右侧是属于该节点下的资产"
#: assets/templates/assets/asset_list.html:69 assets/views/asset.py:1
07
#: assets/templates/assets/asset_list.html:69 assets/views/asset.py:1
25
msgid "Create asset"
msgstr "创建资产"
...
...
@@ -2033,23 +2047,23 @@ msgstr "管理用户列表"
msgid "Admin user detail"
msgstr "管理用户详情"
#: assets/views/asset.py:8
1
templates/_nav_user.html:4
#: assets/views/asset.py:8
0
templates/_nav_user.html:4
msgid "My assets"
msgstr "我的资产"
#: assets/views/asset.py:1
21
#: assets/views/asset.py:1
40
msgid "Bulk update asset success"
msgstr "批量更新资产成功"
#: assets/views/asset.py:1
48
#: assets/views/asset.py:1
67
msgid "Bulk update asset"
msgstr "批量更新资产"
#: assets/views/asset.py:1
65
#: assets/views/asset.py:1
84
msgid "Update asset"
msgstr "更新资产"
#: assets/views/asset.py:3
06
#: assets/views/asset.py:3
25
msgid "already exists"
msgstr "已经存在"
...
...
@@ -2597,18 +2611,35 @@ msgstr ""
msgid "Encrypt field using Secret Key"
msgstr ""
#: common/mixins.py:3
5
#: common/mixins.py:3
6
msgid "is discard"
msgstr ""
#: common/mixins.py:3
6
#: common/mixins.py:3
7
msgid "discard time"
msgstr ""
#: common/validators.py:7
#: common/mixins.py:210
#, fuzzy, python-format
msgid "%(name)s was %(action)s successfully"
msgstr "%(name)s %(action)s成功"
#: common/mixins.py:211
msgid "create"
msgstr "创建"
#: common/mixins.py:211
msgid "update"
msgstr "更新"
#: common/validators.py:11
msgid "Special char not allowed"
msgstr "不能包含特殊字符"
#: common/validators.py:23
msgid "This field must be unique."
msgstr ""
#: jumpserver/views.py:185
msgid ""
"<div>Luna is a separately deployed program, you need to deploy Luna, coco, "
...
...
@@ -2960,7 +2991,7 @@ msgstr "命令执行列表"
msgid "Command execution"
msgstr "命令执行"
#: orgs/mixins.py:8
1
orgs/models.py:24
#: orgs/mixins.py:8
3
orgs/models.py:24
msgid "Organization"
msgstr "组织管理"
...
...
@@ -3161,12 +3192,12 @@ msgstr "添加用户组"
#: perms/views/asset_permission.py:33 perms/views/asset_permission.py:65
#: perms/views/asset_permission.py:80 perms/views/asset_permission.py:95
#: perms/views/asset_permission.py:130 perms/views/asset_permission.py:162
#: perms/views/remote_app_permission.py:3
3
#: perms/views/remote_app_permission.py:4
8
#: perms/views/remote_app_permission.py:6
3
#: perms/views/remote_app_permission.py:7
6
#: perms/views/remote_app_permission.py:10
2
#: perms/views/remote_app_permission.py:13
8
templates/_nav.html:39
#: perms/views/remote_app_permission.py:3
2
#: perms/views/remote_app_permission.py:4
7
#: perms/views/remote_app_permission.py:6
2
#: perms/views/remote_app_permission.py:7
5
#: perms/views/remote_app_permission.py:10
1
#: perms/views/remote_app_permission.py:13
7
templates/_nav.html:39
#: xpack/plugins/orgs/templates/orgs/org_list.html:21
msgid "Perms"
msgstr "权限管理"
...
...
@@ -3195,27 +3226,27 @@ msgstr "资产授权用户列表"
msgid "Asset permission asset list"
msgstr "资产授权资产列表"
#: perms/views/remote_app_permission.py:3
4
#: perms/views/remote_app_permission.py:3
3
msgid "RemoteApp permission list"
msgstr "远程应用授权列表"
#: perms/views/remote_app_permission.py:4
9
#: perms/views/remote_app_permission.py:4
8
msgid "Create RemoteApp permission"
msgstr "创建远程应用授权规则"
#: perms/views/remote_app_permission.py:6
4
#: perms/views/remote_app_permission.py:6
3
msgid "Update RemoteApp permission"
msgstr "更新远程应用授权规则"
#: perms/views/remote_app_permission.py:7
7
#: perms/views/remote_app_permission.py:7
6
msgid "RemoteApp permission detail"
msgstr "远程应用授权详情"
#: perms/views/remote_app_permission.py:10
3
#: perms/views/remote_app_permission.py:10
2
msgid "RemoteApp permission user list"
msgstr "远程应用授权用户列表"
#: perms/views/remote_app_permission.py:13
9
#: perms/views/remote_app_permission.py:13
8
msgid "RemoteApp permission RemoteApp list"
msgstr "远程应用授权远程应用列表"
...
...
@@ -3861,7 +3892,7 @@ msgid "File manager"
msgstr "文件管理"
#: templates/_nav.html:68 terminal/views/command.py:50
#: terminal/views/session.py:7
5 terminal/views/session.py:93
#: terminal/views/session.py:7
4 terminal/views/session.py:92
#: terminal/views/session.py:115 terminal/views/terminal.py:31
#: terminal/views/terminal.py:46 terminal/views/terminal.py:58
msgid "Terminal"
...
...
@@ -4241,11 +4272,11 @@ msgstr "接受终端注册"
msgid "Info"
msgstr "信息"
#: terminal/views/session.py:7
6
#: terminal/views/session.py:7
5
msgid "Session online list"
msgstr "在线会话"
#: terminal/views/session.py:9
4
#: terminal/views/session.py:9
3
msgid "Session offline list"
msgstr "离线会话"
...
...
apps/orgs/mixins.py
View file @
a5b874e2
...
...
@@ -9,8 +9,10 @@ from django.forms import ModelForm
from
django.http.response
import
HttpResponseForbidden
from
django.core.exceptions
import
ValidationError
from
rest_framework
import
serializers
from
rest_framework.validators
import
UniqueTogetherValidator
from
common.utils
import
get_logger
from
common.validators
import
ProjectUniqueValidator
from
.utils
import
(
current_org
,
set_current_org
,
set_to_root_org
,
get_current_org_id
)
...
...
@@ -214,3 +216,14 @@ class OrgResourceSerializerMixin(serializers.Serializer):
(同时为serializer.is_valid()对Model的unique_together校验做准备)
"""
org_id
=
serializers
.
HiddenField
(
default
=
get_current_org_id
)
def
get_validators
(
self
):
_validators
=
super
()
.
get_validators
()
validators
=
[]
for
v
in
_validators
:
if
isinstance
(
v
,
UniqueTogetherValidator
)
\
and
"org_id"
in
v
.
fields
:
v
=
ProjectUniqueValidator
(
v
.
queryset
,
v
.
fields
)
validators
.
append
(
v
)
return
validators
apps/perms/hands.py
View file @
a5b874e2
...
...
@@ -3,11 +3,12 @@
from
common.permissions
import
AdminUserRequiredMixin
from
users.models
import
User
,
UserGroup
from
assets.models
import
Asset
,
SystemUser
,
Node
,
RemoteApp
from
assets.models
import
Asset
,
SystemUser
,
Node
from
assets.serializers
import
(
AssetGrantedSerializer
,
NodeSerializer
)
from
applications.serializers
import
RemoteAppSerializer
from
applications.models
import
RemoteApp
apps/perms/views/remote_app_permission.py
View file @
a5b874e2
...
...
@@ -11,9 +11,8 @@ from django.conf import settings
from
common.permissions
import
AdminUserRequiredMixin
from
orgs.utils
import
current_org
from
users.models
import
UserGroup
from
assets.models
import
RemoteApp
from
..hands
import
RemoteApp
,
UserGroup
from
..models
import
RemoteAppPermission
from
..forms
import
RemoteAppPermissionCreateUpdateForm
...
...
apps/static/css/jumpserver.css
View file @
a5b874e2
...
...
@@ -454,3 +454,15 @@ div.dataTables_wrapper div.dataTables_filter {
#tree-refresh
.fa-refresh
{
font
:
normal
normal
normal
14px
/
1
FontAwesome
!important
;
}
.select2-selection__rendered
span
.select2-selection
,
.select2-container
.select2-selection--single
,
.select2-selection__arrow
{
height
:
34px
!important
;
}
.select2-selection
{
border-radius
:
0
!important
;
}
span
.select2-selection__placeholder
{
line-height
:
34px
!important
;
}
apps/static/js/jumpserver.js
View file @
a5b874e2
...
...
@@ -165,11 +165,13 @@ function formSubmit(props) {
/*
{
"form": $("form"),
"data": {},
"url": "",
"method": "POST",
"redirect_to": "",
"success": function(data, textStatue, jqXHR){},
"error": function(jqXHR, textStatus, errorThrown) {}
"error": function(jqXHR, textStatus, errorThrown) {},
"message": "",
}
*/
props
=
props
||
{};
...
...
@@ -183,6 +185,10 @@ function formSubmit(props) {
dataType
:
props
.
data_type
||
"json"
}).
done
(
function
(
data
,
textState
,
jqXHR
)
{
if
(
redirect_to
)
{
if
(
props
.
message
)
{
var
messages
=
"ed65330a45559c87345a0eb6ac7812d18d0d8976$[[
\"
__json_message
\"
\
0540
\
05425
\
054
\"
asdfasdf
\\
u521b
\\
u5efa
\\
u6210
\\
u529f
\"
]]"
setCookie
(
"messages"
,
messages
)
}
location
.
href
=
redirect_to
;
}
else
if
(
typeof
props
.
success
===
'function'
)
{
return
props
.
success
(
data
,
textState
,
jqXHR
);
...
...
@@ -230,7 +236,15 @@ function formSubmit(props) {
var
help_msg
=
v
.
join
(
"<br/>"
)
;
helpBlockRef
.
html
(
help_msg
);
}
else
{
noneFieldErrorMsg
+=
v
+
'<br/>'
;
$
.
each
(
v
,
function
(
kk
,
vv
)
{
if
(
typeof
errors
===
"object"
)
{
$
.
each
(
vv
,
function
(
kkk
,
vvv
)
{
noneFieldErrorMsg
+=
" "
+
vvv
+
'<br/>'
;
})
}
else
{
noneFieldErrorMsg
+=
vv
+
'<br/>'
;
}
})
}
});
if
(
noneFieldErrorRef
.
length
===
1
&&
noneFieldErrorMsg
!==
''
)
{
...
...
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