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
dc3a9561
Commit
dc3a9561
authored
Oct 31, 2019
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Update] 基本完成登陆审核
parent
23b777b2
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
256 additions
and
77 deletions
+256
-77
__init__.py
apps/authentication/api/__init__.py
+1
-0
login_confirm.py
apps/authentication/api/login_confirm.py
+25
-0
0003_loginconfirmsetting.py
apps/authentication/migrations/0003_loginconfirmsetting.py
+32
-0
models.py
apps/authentication/models.py
+4
-4
serializers.py
apps/authentication/serializers.py
+8
-3
login_wait_confirm.html
...tication/templates/authentication/login_wait_confirm.html
+0
-3
api_urls.py
apps/authentication/urls/api_urls.py
+2
-1
login.py
apps/authentication/views/login.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
0001_initial.py
apps/orders/migrations/0001_initial.py
+59
-0
models.py
apps/orders/models.py
+8
-0
signals_handler.py
apps/orders/signals_handler.py
+17
-44
login_confirm_order_list.html
apps/orders/templates/orders/login_confirm_order_list.html
+29
-18
utils.py
apps/orders/utils.py
+60
-0
jumpserver.js
apps/static/js/jumpserver.js
+3
-0
flash_message_standalone.html
apps/templates/flash_message_standalone.html
+0
-3
user.py
apps/users/models/user.py
+7
-0
user_detail.html
apps/users/templates/users/user_detail.html
+0
-0
No files found.
apps/authentication/api/__init__.py
View file @
dc3a9561
...
...
@@ -5,3 +5,4 @@ from .auth import *
from
.token
import
*
from
.mfa
import
*
from
.access_key
import
*
from
.login_confirm
import
*
apps/authentication/api/login_confirm.py
0 → 100644
View file @
dc3a9561
# -*- coding: utf-8 -*-
#
from
rest_framework.generics
import
UpdateAPIView
from
django.shortcuts
import
get_object_or_404
from
common.permissions
import
IsOrgAdmin
from
..models
import
LoginConfirmSetting
from
..serializers
import
LoginConfirmSettingSerializer
__all__
=
[
'LoginConfirmSettingUpdateApi'
]
class
LoginConfirmSettingUpdateApi
(
UpdateAPIView
):
permission_classes
=
(
IsOrgAdmin
,)
serializer_class
=
LoginConfirmSettingSerializer
def
get_object
(
self
):
from
users.models
import
User
user_id
=
self
.
kwargs
.
get
(
'user_id'
)
user
=
get_object_or_404
(
User
,
pk
=
user_id
)
defaults
=
{
'user'
:
user
}
s
,
created
=
LoginConfirmSetting
.
objects
.
get_or_create
(
defaults
,
user
=
user
,
)
return
s
apps/authentication/migrations/0003_loginconfirmsetting.py
0 → 100644
View file @
dc3a9561
# Generated by Django 2.2.5 on 2019-10-31 10:23
from
django.conf
import
settings
from
django.db
import
migrations
,
models
import
django.db.models.deletion
import
uuid
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
migrations
.
swappable_dependency
(
settings
.
AUTH_USER_MODEL
),
(
'authentication'
,
'0002_auto_20190729_1423'
),
]
operations
=
[
migrations
.
CreateModel
(
name
=
'LoginConfirmSetting'
,
fields
=
[
(
'id'
,
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
,
serialize
=
False
)),
(
'created_by'
,
models
.
CharField
(
blank
=
True
,
max_length
=
32
,
null
=
True
,
verbose_name
=
'Created by'
)),
(
'date_created'
,
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
,
verbose_name
=
'Date created'
)),
(
'date_updated'
,
models
.
DateTimeField
(
auto_now
=
True
,
verbose_name
=
'Date updated'
)),
(
'is_active'
,
models
.
BooleanField
(
default
=
True
,
verbose_name
=
'Is active'
)),
(
'reviewers'
,
models
.
ManyToManyField
(
blank
=
True
,
related_name
=
'review_login_confirm_settings'
,
to
=
settings
.
AUTH_USER_MODEL
,
verbose_name
=
'Reviewers'
)),
(
'user'
,
models
.
OneToOneField
(
on_delete
=
django
.
db
.
models
.
deletion
.
CASCADE
,
related_name
=
'login_confirm_setting'
,
to
=
settings
.
AUTH_USER_MODEL
,
verbose_name
=
'User'
)),
],
options
=
{
'abstract'
:
False
,
},
),
]
apps/authentication/models.py
View file @
dc3a9561
import
uuid
from
django.db
import
models
from
django.utils
import
timezone
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
,
ugettext
as
__
from
rest_framework.authtoken.models
import
Token
from
django.conf
import
settings
...
...
@@ -40,8 +40,8 @@ class PrivateToken(Token):
class
LoginConfirmSetting
(
CommonModelMixin
):
user
=
models
.
OneToOneField
(
'users.User'
,
on_delete
=
models
.
CASCADE
,
verbose_name
=
_
(
"User"
),
related_name
=
_
(
"login_confirmation_setting"
)
)
reviewers
=
models
.
ManyToManyField
(
'users.User'
,
verbose_name
=
_
(
"Reviewers"
),
related_name
=
_
(
"review_login_confirmation_settings"
)
)
user
=
models
.
OneToOneField
(
'users.User'
,
on_delete
=
models
.
CASCADE
,
verbose_name
=
_
(
"User"
),
related_name
=
"login_confirm_setting"
)
reviewers
=
models
.
ManyToManyField
(
'users.User'
,
verbose_name
=
_
(
"Reviewers"
),
related_name
=
"review_login_confirm_settings"
,
blank
=
True
)
is_active
=
models
.
BooleanField
(
default
=
True
,
verbose_name
=
_
(
"Is active"
))
@classmethod
...
...
@@ -50,7 +50,7 @@ class LoginConfirmSetting(CommonModelMixin):
def
create_confirm_order
(
self
,
request
=
None
):
from
orders.models
import
LoginConfirmOrder
title
=
_
(
'User login confirm: {}'
.
format
(
self
.
user
)
)
title
=
_
(
'User login confirm: {}'
)
.
format
(
self
.
user
)
if
request
:
remote_addr
=
get_request_ip
(
request
)
city
=
get_ip_city
(
remote_addr
)
...
...
apps/authentication/serializers.py
View file @
dc3a9561
...
...
@@ -4,17 +4,16 @@ from django.core.cache import cache
from
rest_framework
import
serializers
from
users.models
import
User
from
.models
import
AccessKey
from
.models
import
AccessKey
,
LoginConfirmSetting
__all__
=
[
'AccessKeySerializer'
,
'OtpVerifySerializer'
,
'BearerTokenSerializer'
,
'MFAChallengeSerializer'
,
'MFAChallengeSerializer'
,
'LoginConfirmSettingSerializer'
,
]
class
AccessKeySerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
AccessKey
fields
=
[
'id'
,
'secret'
,
'is_active'
,
'date_created'
]
...
...
@@ -87,3 +86,9 @@ class MFAChallengeSerializer(BearerTokenMixin, serializers.Serializer):
username
=
self
.
context
[
"username"
]
return
self
.
create_response
(
username
)
class
LoginConfirmSettingSerializer
(
serializers
.
ModelSerializer
):
class
Meta
:
model
=
LoginConfirmSetting
fields
=
[
'id'
,
'user'
,
'reviewers'
,
'date_created'
,
'date_updated'
]
read_only_fields
=
[
'date_created'
,
'date_updated'
]
apps/authentication/templates/authentication/login_wait_confirm.html
View file @
dc3a9561
...
...
@@ -61,9 +61,6 @@
<div
class=
"col-md-6"
>
{% include '_copyright.html' %}
</div>
<div
class=
"col-md-6 text-right"
>
<small>
2014-2019
</small>
</div>
</div>
</div>
</body>
...
...
apps/authentication/urls/api_urls.py
View file @
dc3a9561
...
...
@@ -19,7 +19,8 @@ urlpatterns = [
api
.
UserConnectionTokenApi
.
as_view
(),
name
=
'connection-token'
),
path
(
'otp/auth/'
,
api
.
UserOtpAuthApi
.
as_view
(),
name
=
'user-otp-auth'
),
path
(
'otp/verify/'
,
api
.
UserOtpVerifyApi
.
as_view
(),
name
=
'user-otp-verify'
),
path
(
'order/auth/'
,
api
.
UserOrderAcceptAuthApi
.
as_view
(),
name
=
'user-order-auth'
)
path
(
'order/auth/'
,
api
.
UserOrderAcceptAuthApi
.
as_view
(),
name
=
'user-order-auth'
),
path
(
'login-confirm-settings/<uuid:user_id>/'
,
api
.
LoginConfirmSettingUpdateApi
.
as_view
(),
name
=
'login-confirm-setting-update'
)
]
urlpatterns
+=
router
.
urls
...
...
apps/authentication/views/login.py
View file @
dc3a9561
...
...
@@ -179,7 +179,7 @@ class UserLoginGuardView(RedirectView):
if
user
.
otp_enabled
and
user
.
otp_secret_key
and
\
not
self
.
request
.
session
.
get
(
'auth_otp'
):
return
reverse
(
'authentication:login-otp'
)
confirm_setting
=
LoginConfirmSetting
.
get_user_confirm_setting
(
user
)
confirm_setting
=
user
.
get_login_confirm_setting
(
)
if
confirm_setting
and
not
self
.
request
.
session
.
get
(
'auth_confirm'
):
order
=
confirm_setting
.
create_confirm_order
(
self
.
request
)
self
.
request
.
session
[
'auth_order_id'
]
=
str
(
order
.
id
)
...
...
apps/locale/zh/LC_MESSAGES/django.mo
View file @
dc3a9561
No preview for this file type
apps/locale/zh/LC_MESSAGES/django.po
View file @
dc3a9561
This diff is collapsed.
Click to expand it.
apps/orders/migrations/0001_initial.py
0 → 100644
View file @
dc3a9561
# Generated by Django 2.2.5 on 2019-10-31 10:23
from
django.conf
import
settings
from
django.db
import
migrations
,
models
import
django.db.models.deletion
import
uuid
class
Migration
(
migrations
.
Migration
):
initial
=
True
dependencies
=
[
migrations
.
swappable_dependency
(
settings
.
AUTH_USER_MODEL
),
]
operations
=
[
migrations
.
CreateModel
(
name
=
'LoginConfirmOrder'
,
fields
=
[
(
'id'
,
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
,
serialize
=
False
)),
(
'created_by'
,
models
.
CharField
(
blank
=
True
,
max_length
=
32
,
null
=
True
,
verbose_name
=
'Created by'
)),
(
'date_created'
,
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
,
verbose_name
=
'Date created'
)),
(
'date_updated'
,
models
.
DateTimeField
(
auto_now
=
True
,
verbose_name
=
'Date updated'
)),
(
'user_display'
,
models
.
CharField
(
max_length
=
128
,
verbose_name
=
'User display name'
)),
(
'title'
,
models
.
CharField
(
max_length
=
256
,
verbose_name
=
'Title'
)),
(
'body'
,
models
.
TextField
(
verbose_name
=
'Body'
)),
(
'assignee_display'
,
models
.
CharField
(
blank
=
True
,
max_length
=
128
,
null
=
True
,
verbose_name
=
'Assignee display name'
)),
(
'assignees_display'
,
models
.
CharField
(
blank
=
True
,
max_length
=
128
,
verbose_name
=
'Assignees display name'
)),
(
'type'
,
models
.
CharField
(
choices
=
[(
'login_confirm'
,
'Login confirm'
)],
max_length
=
16
,
verbose_name
=
'Type'
)),
(
'status'
,
models
.
CharField
(
choices
=
[(
'accepted'
,
'Accepted'
),
(
'rejected'
,
'Rejected'
),
(
'pending'
,
'Pending'
)],
default
=
'pending'
,
max_length
=
16
)),
(
'ip'
,
models
.
GenericIPAddressField
(
blank
=
True
,
null
=
True
)),
(
'city'
,
models
.
CharField
(
blank
=
True
,
default
=
''
,
max_length
=
16
)),
(
'assignee'
,
models
.
ForeignKey
(
null
=
True
,
on_delete
=
django
.
db
.
models
.
deletion
.
SET_NULL
,
related_name
=
'loginconfirmorder_handled'
,
to
=
settings
.
AUTH_USER_MODEL
,
verbose_name
=
'Assignee'
)),
(
'assignees'
,
models
.
ManyToManyField
(
related_name
=
'loginconfirmorder_assigned'
,
to
=
settings
.
AUTH_USER_MODEL
,
verbose_name
=
'Assignees'
)),
(
'user'
,
models
.
ForeignKey
(
null
=
True
,
on_delete
=
django
.
db
.
models
.
deletion
.
SET_NULL
,
related_name
=
'loginconfirmorder_requested'
,
to
=
settings
.
AUTH_USER_MODEL
,
verbose_name
=
'User'
)),
],
options
=
{
'ordering'
:
(
'-date_created'
,),
'abstract'
:
False
,
},
),
migrations
.
CreateModel
(
name
=
'Comment'
,
fields
=
[
(
'id'
,
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
primary_key
=
True
,
serialize
=
False
)),
(
'created_by'
,
models
.
CharField
(
blank
=
True
,
max_length
=
32
,
null
=
True
,
verbose_name
=
'Created by'
)),
(
'date_created'
,
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
,
verbose_name
=
'Date created'
)),
(
'date_updated'
,
models
.
DateTimeField
(
auto_now
=
True
,
verbose_name
=
'Date updated'
)),
(
'order_id'
,
models
.
UUIDField
()),
(
'user_display'
,
models
.
CharField
(
max_length
=
128
,
verbose_name
=
'User display name'
)),
(
'body'
,
models
.
TextField
(
verbose_name
=
'Body'
)),
(
'user'
,
models
.
ForeignKey
(
null
=
True
,
on_delete
=
django
.
db
.
models
.
deletion
.
SET_NULL
,
related_name
=
'comments'
,
to
=
settings
.
AUTH_USER_MODEL
,
verbose_name
=
'User'
)),
],
options
=
{
'ordering'
:
(
'date_created'
,),
},
),
]
apps/orders/models.py
View file @
dc3a9561
...
...
@@ -48,6 +48,14 @@ class BaseOrder(CommonModelMixin):
def
comments
(
self
):
return
Comment
.
objects
.
filter
(
order_id
=
self
.
id
)
@property
def
body_as_html
(
self
):
return
self
.
body
.
replace
(
'
\n
'
,
'<br/>'
)
@property
def
status_display
(
self
):
return
self
.
get_status_display
()
class
Meta
:
abstract
=
True
ordering
=
(
'-date_created'
,)
...
...
apps/orders/signals_handler.py
View file @
dc3a9561
# -*- coding: utf-8 -*-
#
from
django.utils.translation
import
ugettext
as
_
from
django.dispatch
import
receiver
from
django.db.models.signals
import
m2m_changed
from
django.conf
import
settings
from
django.db.models.signals
import
m2m_changed
,
post_save
from
common.tasks
import
send_mail_async
from
common.utils
import
get_logger
,
reverse
from
common.utils
import
get_logger
from
.models
import
LoginConfirmOrder
from
.utils
import
(
send_login_confirm_order_mail_to_assignees
,
send_login_confirm_action_mail_to_user
)
logger
=
get_logger
(
__name__
)
def
send_mail
(
order
,
assignees
):
recipient_list
=
[
user
.
email
for
user
in
assignees
]
user
=
order
.
user
if
not
recipient_list
:
logger
.
error
(
"Order not has assignees: {}"
.
format
(
order
.
id
))
return
subject
=
'{}: {}'
.
format
(
_
(
"New order"
),
order
.
title
)
detail_url
=
reverse
(
'orders:login-confirm-order-detail'
,
kwargs
=
{
'pk'
:
order
.
id
},
external
=
True
)
message
=
_
(
"""
<div>
<p>Your has a new order</p>
<div>
<b>Title:</b> {order.title}
<br/>
<b>User:</b> {user}
<br/>
<b>City:</b> {order.city}
<br/>
<b>IP:</b> {order.ip}
<br/>
<a href={url}>click here to review</a>
</div>
</div>
"""
)
.
format
(
order
=
order
,
user
=
user
,
url
=
detail_url
)
if
settings
.
DEBUG
:
try
:
print
(
message
)
except
OSError
:
pass
send_mail_async
.
delay
(
subject
,
message
,
recipient_list
,
html_message
=
message
)
logger
=
get_logger
(
__name__
)
@receiver
(
m2m_changed
,
sender
=
LoginConfirmOrder
.
assignees
.
through
)
def
on_login_confirm_order_assignee_set
(
sender
,
instance
=
None
,
action
=
None
,
def
on_login_confirm_order_assignee
s
_set
(
sender
,
instance
=
None
,
action
=
None
,
model
=
None
,
pk_set
=
None
,
**
kwargs
):
print
(
">>>>>>>>>>>>>>>>>>>>>>>."
)
print
(
action
)
if
action
==
'post_add'
:
print
(
"<<<<<<<<<<<<<<<<<<<<"
)
logger
.
debug
(
'New order create, send mail: {}'
.
format
(
instance
.
id
))
assignees
=
model
.
objects
.
filter
(
pk__in
=
pk_set
)
send_mail
(
instance
,
assignees
)
print
(
assignees
)
send_login_confirm_order_mail_to_assignees
(
instance
,
assignees
)
@receiver
(
post_save
,
sender
=
LoginConfirmOrder
)
def
on_login_confirm_order_status_change
(
sender
,
instance
=
None
,
created
=
False
,
**
kwargs
):
if
created
or
instance
.
status
==
"pending"
:
return
logger
.
debug
(
'Order changed, send mail: {}'
.
format
(
instance
.
id
))
send_login_confirm_action_mail_to_user
(
instance
)
apps/orders/templates/orders/login_confirm_order_list.html
View file @
dc3a9561
...
...
@@ -14,7 +14,6 @@
<th
class=
"text-center"
>
{% trans 'Title' %}
</th>
<th
class=
"text-center"
>
{% trans 'User' %}
</th>
<th
class=
"text-center"
>
{% trans 'IP' %}
</th>
<th
class=
"text-center"
>
{% trans 'City' %}
</th>
<th
class=
"text-center"
>
{% trans 'Status' %}
</th>
<th
class=
"text-center"
>
{% trans 'Datetime' %}
</th>
<th
class=
"text-center"
>
{% trans 'Action' %}
</th>
...
...
@@ -38,8 +37,12 @@ function initTable() {
cellData
=
htmlEscape
(
cellData
);
var
detailBtn
=
'<a href="{% url "orders:login-confirm-order-detail" pk=DEFAULT_PK %}">'
+
cellData
+
'</a>'
;
$
(
td
).
html
(
detailBtn
.
replace
(
"{{ DEFAULT_PK }}"
,
rowData
.
id
));
}},
{
targets
:
5
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
}},
{
targets
:
3
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
d
=
cellData
+
"("
+
rowData
.
city
+
")"
;
$
(
td
).
html
(
d
)
}},
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
if
(
cellData
===
"accepted"
)
{
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
}
else
if
(
cellData
===
"rejected"
)
{
...
...
@@ -48,13 +51,13 @@ function initTable() {
$
(
td
).
html
(
'<i class="fa fa-spinner text-info"></i>'
)
}
}},
{
targets
:
6
,
createdCell
:
function
(
td
,
cellData
)
{
{
targets
:
5
,
createdCell
:
function
(
td
,
cellData
)
{
var
d
=
toSafeLocalDateStr
(
cellData
);
$
(
td
).
html
(
d
)
}},
{
targets
:
7
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
acceptBtn
=
'<a class="btn btn-xs btn-info" data-uid="{{ DEFAULT_PK }}" >{% trans "Accept" %}</a> '
;
var
rejectBtn
=
'<a class="btn btn-xs btn-danger " data-uid="{{ DEFAULT_PK }}" >{% trans "Reject" %}</a>'
;
{
targets
:
6
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
acceptBtn
=
'<a class="btn btn-xs btn-info
btn-action" data-action="accept
" data-uid="{{ DEFAULT_PK }}" >{% trans "Accept" %}</a> '
;
var
rejectBtn
=
'<a class="btn btn-xs btn-danger
btn-action" data-action="reject
" data-uid="{{ DEFAULT_PK }}" >{% trans "Reject" %}</a>'
;
acceptBtn
=
acceptBtn
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
rejectBtn
=
rejectBtn
.
replace
(
'{{ DEFAULT_PK }}'
,
cellData
);
var
acceptBtnRef
=
$
(
acceptBtn
);
...
...
@@ -68,10 +71,10 @@ function initTable() {
}}],
ajax_url
:
'{% url "api-orders:login-confirm-order-list" %}'
,
columns
:
[
{
data
:
"id"
},
{
data
:
"title"
,
className
:
"text-left"
},
{
data
:
"user_display"
},
{
data
:
"
ip"
},
{
data
:
"city
"
},
{
data
:
"status"
,
orderable
:
false
},
{
data
:
"date_created"
},
{
data
:
"id"
},
{
data
:
"title"
,
className
:
"text-left"
},
{
data
:
"
user_display"
},
{
data
:
"ip
"
},
{
data
:
"status"
,
orderable
:
false
,
width
:
"30px"
},
{
data
:
"date_created"
,
width
:
"120px"
},
{
data
:
"id"
,
orderable
:
false
,
width
:
"100px"
}
],
op_html
:
$
(
'#actions'
).
html
()
...
...
@@ -82,7 +85,6 @@ function initTable() {
$
(
document
).
ready
(
function
(){
initTable
();
$
(
''
)
var
menu
=
[
{
title
:
"IP"
,
value
:
"ip"
},
{
title
:
"{% trans 'Title' %}"
,
value
:
"title"
},
...
...
@@ -93,12 +95,21 @@ $(document).ready(function(){
]}
];
initTableFilterDropdown
(
'#login_confirm_order_list_table_filter input'
,
menu
)
}).
on
(
'click'
,
'.expired'
,
function
()
{
var
msg
=
'{% trans "User is expired" %}'
;
toastr
.
error
(
msg
)
}).
on
(
'click'
,
'.inactive'
,
function
()
{
var
msg
=
'{% trans '
User
is
inactive
' %}'
;
toastr
.
error
(
msg
)
}).
on
(
'click'
,
'.btn-action'
,
function
()
{
var
actionCreateUrl
=
"{% url 'api-orders:login-confirm-order-create-action' pk=DEFAULT_PK %}"
;
var
orderId
=
$
(
this
).
data
(
'uid'
);
actionCreateUrl
=
actionCreateUrl
.
replace
(
"{{ DEFAULT_PK }}"
,
orderId
);
var
action
=
$
(
this
).
data
(
'action'
);
var
comment
=
''
;
var
data
=
{
url
:
actionCreateUrl
,
method
:
'POST'
,
body
:
JSON
.
stringify
({
action
:
action
,
comment
:
comment
}),
success
:
function
()
{
window
.
location
.
reload
();
}
};
requestApi
(
data
);
})
</script>
{% endblock %}
...
...
apps/orders/utils.py
View file @
dc3a9561
# -*- coding: utf-8 -*-
#
from
django.conf
import
settings
from
django.utils.translation
import
ugettext
as
_
from
common.utils
import
get_logger
,
reverse
from
common.tasks
import
send_mail_async
logger
=
get_logger
(
__name__
)
def
send_login_confirm_order_mail_to_assignees
(
order
,
assignees
):
recipient_list
=
[
user
.
email
for
user
in
assignees
]
user
=
order
.
user
if
not
recipient_list
:
logger
.
error
(
"Order not has assignees: {}"
.
format
(
order
.
id
))
return
subject
=
'{}: {}'
.
format
(
_
(
"New order"
),
order
.
title
)
detail_url
=
reverse
(
'orders:login-confirm-order-detail'
,
kwargs
=
{
'pk'
:
order
.
id
},
external
=
True
)
message
=
_
(
"""
<div>
<p>Your has a new order</p>
<div>
<b>Title:</b> {order.title}
<br/>
<b>User:</b> {user}
<br/>
<b>Assignees:</b> {order.assignees_display}
<br/>
<b>City:</b> {order.city}
<br/>
<b>IP:</b> {order.ip}
<br/>
<a href={url}>click here to review</a>
</div>
</div>
"""
)
.
format
(
order
=
order
,
user
=
user
,
url
=
detail_url
)
send_mail_async
.
delay
(
subject
,
message
,
recipient_list
,
html_message
=
message
)
def
send_login_confirm_action_mail_to_user
(
order
):
if
not
order
.
user
:
logger
.
error
(
"Order not has user: {}"
.
format
(
order
.
id
))
return
user
=
order
.
user
recipient_list
=
[
user
.
email
]
subject
=
'{}: {}'
.
format
(
_
(
"Order has been reply"
),
order
.
title
)
message
=
_
(
"""
<div>
<p>Your order has been replay</p>
<div>
<b>Title:</b> {order.title}
<br/>
<b>Assignee:</b> {order.assignee_display}
<br/>
<b>Status:</b> {order.status_display}
<br/>
</div>
</div>
"""
)
.
format
(
order
=
order
)
send_mail_async
.
delay
(
subject
,
message
,
recipient_list
,
html_message
=
message
)
apps/static/js/jumpserver.js
View file @
dc3a9561
...
...
@@ -416,6 +416,9 @@ function makeLabel(data) {
function
parseTableFilter
(
value
)
{
var
cleanValues
=
[];
if
(
!
value
)
{
return
{}
}
var
valuesArray
=
value
.
split
(
':'
);
for
(
var
i
=
0
;
i
<
valuesArray
.
length
;
i
++
)
{
var
v
=
valuesArray
[
i
].
trim
();
...
...
apps/templates/flash_message_standalone.html
View file @
dc3a9561
...
...
@@ -55,9 +55,6 @@
<div
class=
"col-md-6"
>
{% include '_copyright.html' %}
</div>
<div
class=
"col-md-6 text-right"
>
<small>
2014-2019
</small>
</div>
</div>
</div>
</body>
...
...
apps/users/models/user.py
View file @
dc3a9561
...
...
@@ -117,6 +117,13 @@ class AuthMixin:
return
True
return
False
def
get_login_confirm_setting
(
self
):
if
hasattr
(
self
,
'login_confirm_setting'
):
s
=
self
.
login_confirm_setting
if
s
.
reviewers
.
all
()
.
count
()
and
s
.
is_active
:
return
s
return
False
class
RoleMixin
:
ROLE_ADMIN
=
'Admin'
...
...
apps/users/templates/users/user_detail.html
View file @
dc3a9561
This diff is collapsed.
Click to expand it.
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