mirror of https://github.com/jumpserver/jumpserver
perf: mfa interface optimization, mobile phone number can be empty
parent
f95cbd6977
commit
91a1da57e9
|
@ -44,13 +44,13 @@ class MFASms(BaseMFA):
|
||||||
return settings.SMS_ENABLED
|
return settings.SMS_ENABLED
|
||||||
|
|
||||||
def get_enable_url(self) -> str:
|
def get_enable_url(self) -> str:
|
||||||
return '/ui/#/profile/setting?activeTab=ProfileUpdate'
|
return '/ui/#/profile/index'
|
||||||
|
|
||||||
def can_disable(self) -> bool:
|
def can_disable(self) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def disable(self):
|
def disable(self):
|
||||||
return '/ui/#/profile/setting?activeTab=ProfileUpdate'
|
return '/ui/#/profile/index'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def help_text_of_enable():
|
def help_text_of_enable():
|
||||||
|
@ -61,4 +61,4 @@ class MFASms(BaseMFA):
|
||||||
return _("Clear phone number to disable")
|
return _("Clear phone number to disable")
|
||||||
|
|
||||||
def get_disable_url(self) -> str:
|
def get_disable_url(self) -> str:
|
||||||
return '/ui/#/profile/setting?activeTab=ProfileUpdate'
|
return '/ui/#/profile/index'
|
||||||
|
|
|
@ -26,10 +26,12 @@ COUNTRY_CALLING_CODES = [
|
||||||
{'name': 'HongKong(中国香港)', 'value': '+852'},
|
{'name': 'HongKong(中国香港)', 'value': '+852'},
|
||||||
{'name': 'Macao(中国澳门)', 'value': '+853'},
|
{'name': 'Macao(中国澳门)', 'value': '+853'},
|
||||||
{'name': 'Taiwan(中国台湾)', 'value': '+886'},
|
{'name': 'Taiwan(中国台湾)', 'value': '+886'},
|
||||||
{'name': 'America(America)', 'value': '+1'}, {'name': 'Russia(Россия)', 'value': '+7'},
|
{'name': 'America(America)', 'value': '+1'},
|
||||||
|
{'name': 'Russia(Россия)', 'value': '+7'},
|
||||||
{'name': 'France(français)', 'value': '+33'},
|
{'name': 'France(français)', 'value': '+33'},
|
||||||
{'name': 'Britain(Britain)', 'value': '+44'},
|
{'name': 'Britain(Britain)', 'value': '+44'},
|
||||||
{'name': 'Germany(Deutschland)', 'value': '+49'},
|
{'name': 'Germany(Deutschland)', 'value': '+49'},
|
||||||
{'name': 'Japan(日本)', 'value': '+81'}, {'name': 'Korea(한국)', 'value': '+82'},
|
{'name': 'Japan(日本)', 'value': '+81'},
|
||||||
|
{'name': 'Korea(한국)', 'value': '+82'},
|
||||||
{'name': 'India(भारत)', 'value': '+91'}
|
{'name': 'India(भारत)', 'value': '+91'}
|
||||||
]
|
]
|
||||||
|
|
|
@ -251,6 +251,7 @@ class PhoneField(serializers.CharField):
|
||||||
data = '+{}{}'.format(code, phone)
|
data = '+{}{}'.format(code, phone)
|
||||||
else:
|
else:
|
||||||
data = phone
|
data = phone
|
||||||
|
if data:
|
||||||
try:
|
try:
|
||||||
phone = phonenumbers.parse(data, 'CN')
|
phone = phonenumbers.parse(data, 'CN')
|
||||||
data = '+{}{}'.format(phone.country_code, phone.national_number)
|
data = '+{}{}'.format(phone.country_code, phone.national_number)
|
||||||
|
@ -260,7 +261,6 @@ class PhoneField(serializers.CharField):
|
||||||
return super().to_internal_value(data)
|
return super().to_internal_value(data)
|
||||||
|
|
||||||
def to_representation(self, value):
|
def to_representation(self, value):
|
||||||
if value:
|
|
||||||
try:
|
try:
|
||||||
phone = phonenumbers.parse(value, 'CN')
|
phone = phonenumbers.parse(value, 'CN')
|
||||||
value = {'code': '+%s' % phone.country_code, 'phone': phone.national_number}
|
value = {'code': '+%s' % phone.country_code, 'phone': phone.national_number}
|
||||||
|
|
|
@ -47,6 +47,9 @@ class PhoneValidator:
|
||||||
message = _('The mobile phone number format is incorrect')
|
message = _('The mobile phone number format is incorrect')
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
|
if not value:
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
phone = phonenumbers.parse(value, 'CN')
|
phone = phonenumbers.parse(value, 'CN')
|
||||||
valid = phonenumbers.is_valid_number(phone)
|
valid = phonenumbers.is_valid_number(phone)
|
||||||
|
|
|
@ -23,8 +23,8 @@ button{
|
||||||
/*header样式*/
|
/*header样式*/
|
||||||
header{
|
header{
|
||||||
overflow:hidden ;
|
overflow:hidden ;
|
||||||
background: #dedede;
|
background: #ffffff;
|
||||||
padding:15px 200px;
|
padding:15px 10%;
|
||||||
}
|
}
|
||||||
header .logo a{
|
header .logo a{
|
||||||
float:left;
|
float:left;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
<button class="btn btn-primary full-width btn-challenge"
|
<button class="btn btn-primary full-width btn-challenge"
|
||||||
type='button' onclick="sendChallengeCode(this)"
|
type='button' onclick="sendChallengeCode(this)"
|
||||||
>
|
>
|
||||||
{% trans 'Send verification code' %}
|
{% trans 'Send' %}
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -39,15 +39,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.challenge-required .input-style {
|
.challenge-required .input-style {
|
||||||
width: calc(100% - 160px);
|
width: calc(100% - 104px);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-challenge {
|
.btn-challenge {
|
||||||
width: 156px !important;
|
width: 100px !important;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
padding: 8px 12px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<a href="{% url 'index' %}">
|
<a href="{% url 'index' %}">
|
||||||
<img src="{{ INTERFACE.logo_logout }}" alt="" width="50px" height="50px"/>
|
<img src="{{ INTERFACE.logo_logout }}" alt="" width="50px" height="50px"/>
|
||||||
</a>
|
</a>
|
||||||
<span style="font-size: 18px; line-height: 50px">{{ INTERFACE.login_title }}</span>
|
<span style="font-size: 21px; line-height: 50px">{{ INTERFACE.login_title }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="{% url 'index' %}">{% trans 'Home page' %}</a>
|
<a href="{% url 'index' %}">{% trans 'Home page' %}</a>
|
||||||
|
|
|
@ -143,7 +143,7 @@ class PasswordExpirationReminderMsg(UserMessage):
|
||||||
subject = _('Password is about expire')
|
subject = _('Password is about expire')
|
||||||
|
|
||||||
date_password_expired_local = timezone.localtime(user.date_password_expired)
|
date_password_expired_local = timezone.localtime(user.date_password_expired)
|
||||||
update_password_url = urljoin(settings.SITE_URL, '/ui/#/profile/setting/?activeTab=PasswordUpdate')
|
update_password_url = urljoin(settings.SITE_URL, '/ui/#/profile/index')
|
||||||
date_password_expired = date_password_expired_local.strftime('%Y-%m-%d %H:%M:%S')
|
date_password_expired = date_password_expired_local.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
context = {
|
context = {
|
||||||
'name': user.name,
|
'name': user.name,
|
||||||
|
|
|
@ -17,11 +17,105 @@
|
||||||
.onoffswitch-switch {
|
.onoffswitch-switch {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 72%;
|
||||||
|
margin: 20px auto;
|
||||||
|
background-color: #ffffff;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h2 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 15px 0;
|
||||||
|
border-bottom: 1px dashed #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section .title {
|
||||||
|
flex: 2;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section .description {
|
||||||
|
flex: 10;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section .summarize {
|
||||||
|
flex: 12;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section .action {
|
||||||
|
flex: 3;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section .status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section .status .status-text {
|
||||||
|
margin-left: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section .action-buttons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section .action-buttons .divider {
|
||||||
|
margin: 0 10px;
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section .action-buttons a {
|
||||||
|
color: #1e88e5;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-warning {
|
||||||
|
color: #ff9800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-set {
|
||||||
|
color: #4caf50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<article>
|
<div class="container">
|
||||||
<div>
|
<div class="header">
|
||||||
{# // Todoi:#}
|
<h2>MFA</h2>
|
||||||
<h3>{% trans 'Enable MFA' %}</h3>
|
</div>
|
||||||
|
<hr>
|
||||||
<div class="row" style="padding-top: 10px">
|
<div class="row" style="padding-top: 10px">
|
||||||
<li class="col-sm-6" style="font-size: 14px">{% trans 'Enable' %} MFA</li>
|
<li class="col-sm-6" style="font-size: 14px">{% trans 'Enable' %} MFA</li>
|
||||||
<div class="switch col-sm-6">
|
<div class="switch col-sm-6">
|
||||||
|
@ -44,37 +138,50 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="mfa-setting" style="display: none; padding-top: 30px">
|
<div id="mfa-setting" class="container">
|
||||||
<h3>{% trans 'MFA setting' %}</h3>
|
<div class="header">
|
||||||
<div style="height: 100%; width: 100%;">
|
<h2>{% trans 'MFA setting' %}</h2>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
{% for b in mfa_backends %}
|
{% for b in mfa_backends %}
|
||||||
<div class="row" style="padding-top: 10px">
|
<div class="section">
|
||||||
<li class="col-sm-6" style="font-size: 14px">
|
<div class="title">{{ b.display_name }}</div>
|
||||||
{{ b.display_name }}
|
|
||||||
</li>
|
|
||||||
<span class="col-sm-6">
|
|
||||||
{% if b.is_active %}
|
{% if b.is_active %}
|
||||||
<button class="btn btn-warning btn-xs" style="float: right"
|
<div class="description">{{ b.help_text_of_disable }}</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="description">{{ b.help_text_of_enable }}</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="action">
|
||||||
|
<div class="status {% if b.is_active %}status-set{% else %}status-warning{% endif %}">
|
||||||
|
<span class="status-icon">{% if b.is_active %}✔{% else %}⚠️{% endif %}</span>
|
||||||
|
<span class="status-text">
|
||||||
|
{% if b.is_active %}{% trans 'Enable' %}
|
||||||
|
{% else %}
|
||||||
|
{% trans 'Not enabled' %}
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-buttons">
|
||||||
|
<span class="divider">|</span>
|
||||||
|
{% if b.is_active %}
|
||||||
|
<button class="btn btn-warning btn-xs"
|
||||||
{% if not b.can_disable %} disabled {% endif %}
|
{% if not b.can_disable %} disabled {% endif %}
|
||||||
onclick="goTo('{{ b.get_disable_url }}')"
|
onclick="goTo('{{ b.get_disable_url }}')"
|
||||||
>
|
>
|
||||||
{% trans 'Reset' %}
|
{% trans 'Reset' %}
|
||||||
</button>
|
</button>
|
||||||
<span class="help-inline">{{ b.help_text_of_disable }}</span>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<button class="btn btn-primary btn-xs" style="float: right"
|
<button class="btn btn-primary btn-xs"
|
||||||
onclick="goTo('{{ b.get_enable_url }}')"
|
onclick="goTo('{{ b.get_enable_url }}')"
|
||||||
>
|
>
|
||||||
{% trans 'Enable' %}
|
{% trans 'Enable' %}
|
||||||
</button>
|
</button>
|
||||||
<span class="help-inline">{{ b.help_text_of_enable }}</span>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
<script src="{% static 'js/jumpserver.js' %}"></script>
|
<script src="{% static 'js/jumpserver.js' %}"></script>
|
||||||
<script>
|
<script>
|
||||||
function goTo(url) {
|
function goTo(url) {
|
||||||
|
|
Loading…
Reference in New Issue