mirror of https://github.com/jumpserver/jumpserver
				
				
				
			perf: 去掉单独的flash msg (#7013)
* perf: 去掉单独的flash msg perf: 修改使用库 * fix: guangbug * pref: 修改 context Co-authored-by: ibuler <ibuler@qq.com> Co-authored-by: xinwen <coderWen@126.com>pull/7027/head
							parent
							
								
									63b338085a
								
							
						
					
					
						commit
						fa68389028
					
				|  | @ -1,7 +1,7 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| # | ||||
| import inspect | ||||
| from urllib.parse import urlencode | ||||
| from django.utils.http import urlencode | ||||
| from functools import partial | ||||
| import time | ||||
| 
 | ||||
|  | @ -204,7 +204,7 @@ class AuthMixin(PasswordEncryptionViewMixin): | |||
|             data = request.POST | ||||
| 
 | ||||
|         items = ['username', 'password', 'challenge', 'public_key', 'auto_login'] | ||||
|         username, password, challenge, public_key, auto_login = bulk_get(data, *items, default='') | ||||
|         username, password, challenge, public_key, auto_login = bulk_get(data, items, default='') | ||||
|         ip = self.get_request_ip() | ||||
|         self._set_partial_credential_error(username=username, ip=ip, request=request) | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,24 +22,18 @@ urlpatterns = [ | |||
|     path('password/reset/', users_view.UserResetPasswordView.as_view(), name='reset-password'), | ||||
|     path('password/verify/', users_view.UserVerifyPasswordView.as_view(), name='user-verify-password'), | ||||
| 
 | ||||
|     path('wecom/bind/success-flash-msg/', views.FlashWeComBindSucceedMsgView.as_view(), name='wecom-bind-success-flash-msg'), | ||||
|     path('wecom/bind/failed-flash-msg/', views.FlashWeComBindFailedMsgView.as_view(), name='wecom-bind-failed-flash-msg'), | ||||
|     path('wecom/bind/start/', views.WeComEnableStartView.as_view(), name='wecom-bind-start'), | ||||
|     path('wecom/qr/bind/', views.WeComQRBindView.as_view(), name='wecom-qr-bind'), | ||||
|     path('wecom/qr/login/', views.WeComQRLoginView.as_view(), name='wecom-qr-login'), | ||||
|     path('wecom/qr/bind/<uuid:user_id>/callback/', views.WeComQRBindCallbackView.as_view(), name='wecom-qr-bind-callback'), | ||||
|     path('wecom/qr/login/callback/', views.WeComQRLoginCallbackView.as_view(), name='wecom-qr-login-callback'), | ||||
| 
 | ||||
|     path('dingtalk/bind/success-flash-msg/', views.FlashDingTalkBindSucceedMsgView.as_view(), name='dingtalk-bind-success-flash-msg'), | ||||
|     path('dingtalk/bind/failed-flash-msg/', views.FlashDingTalkBindFailedMsgView.as_view(), name='dingtalk-bind-failed-flash-msg'), | ||||
|     path('dingtalk/bind/start/', views.DingTalkEnableStartView.as_view(), name='dingtalk-bind-start'), | ||||
|     path('dingtalk/qr/bind/', views.DingTalkQRBindView.as_view(), name='dingtalk-qr-bind'), | ||||
|     path('dingtalk/qr/login/', views.DingTalkQRLoginView.as_view(), name='dingtalk-qr-login'), | ||||
|     path('dingtalk/qr/bind/<uuid:user_id>/callback/', views.DingTalkQRBindCallbackView.as_view(), name='dingtalk-qr-bind-callback'), | ||||
|     path('dingtalk/qr/login/callback/', views.DingTalkQRLoginCallbackView.as_view(), name='dingtalk-qr-login-callback'), | ||||
| 
 | ||||
|     path('feishu/bind/success-flash-msg/', views.FlashDingTalkBindSucceedMsgView.as_view(), name='feishu-bind-success-flash-msg'), | ||||
|     path('feishu/bind/failed-flash-msg/', views.FlashDingTalkBindFailedMsgView.as_view(), name='feishu-bind-failed-flash-msg'), | ||||
|     path('feishu/bind/start/', views.FeiShuEnableStartView.as_view(), name='feishu-bind-start'), | ||||
|     path('feishu/qr/bind/', views.FeiShuQRBindView.as_view(), name='feishu-qr-bind'), | ||||
|     path('feishu/qr/login/', views.FeiShuQRLoginView.as_view(), name='feishu-qr-login'), | ||||
|  |  | |||
|  | @ -1,10 +1,6 @@ | |||
| import urllib | ||||
| 
 | ||||
| from django.http.response import HttpResponseRedirect | ||||
| from django.utils.decorators import method_decorator | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| from django.views.decorators.cache import never_cache | ||||
| from django.views.generic import TemplateView | ||||
| from urllib.parse import urlencode | ||||
| from django.views import View | ||||
| from django.conf import settings | ||||
| from django.http.request import HttpRequest | ||||
|  | @ -15,7 +11,7 @@ from rest_framework.exceptions import APIException | |||
| from users.views import UserVerifyPasswordView | ||||
| from users.utils import is_auth_password_time_valid | ||||
| from users.models import User | ||||
| from common.utils import get_logger | ||||
| from common.utils import get_logger, FlashMessageUtil | ||||
| from common.utils.random import random_string | ||||
| from common.utils.django import reverse, get_object_or_none | ||||
| from common.message.backends.dingtalk import URL | ||||
|  | @ -39,7 +35,7 @@ class DingTalkQRMixin(PermissionsMixin, View): | |||
|                 msg = e.detail['errmsg'] | ||||
|             except Exception: | ||||
|                 msg = _('DingTalk Error, Please contact your system administrator') | ||||
|             return self.get_failed_reponse( | ||||
|             return self.get_failed_response( | ||||
|                 '/', | ||||
|                 _('DingTalk Error'), | ||||
|                 msg | ||||
|  | @ -67,30 +63,32 @@ class DingTalkQRMixin(PermissionsMixin, View): | |||
|             'state': state, | ||||
|             'redirect_uri': redirect_uri, | ||||
|         } | ||||
|         url = URL.QR_CONNECT + '?' + urllib.parse.urlencode(params) | ||||
|         url = URL.QR_CONNECT + '?' + urlencode(params) | ||||
|         return url | ||||
| 
 | ||||
|     def get_success_reponse(self, redirect_url, title, msg): | ||||
|         ok_flash_msg_url = reverse('authentication:dingtalk-bind-success-flash-msg') | ||||
|         ok_flash_msg_url += '?' + urllib.parse.urlencode({ | ||||
|             'redirect_url': redirect_url, | ||||
|     @staticmethod | ||||
|     def get_success_response(redirect_url, title, msg): | ||||
|         message_data = { | ||||
|             'title': title, | ||||
|             'msg': msg | ||||
|         }) | ||||
|         return HttpResponseRedirect(ok_flash_msg_url) | ||||
|             'message': msg, | ||||
|             'interval': 5, | ||||
|             'redirect_url': redirect_url, | ||||
|         } | ||||
|         return FlashMessageUtil.gen_and_redirect_to(message_data) | ||||
| 
 | ||||
|     def get_failed_reponse(self, redirect_url, title, msg): | ||||
|         failed_flash_msg_url = reverse('authentication:dingtalk-bind-failed-flash-msg') | ||||
|         failed_flash_msg_url += '?' + urllib.parse.urlencode({ | ||||
|             'redirect_url': redirect_url, | ||||
|     @staticmethod | ||||
|     def get_failed_response(redirect_url, title, msg): | ||||
|         message_data = { | ||||
|             'title': title, | ||||
|             'msg': msg | ||||
|         }) | ||||
|         return HttpResponseRedirect(failed_flash_msg_url) | ||||
|             'error': msg, | ||||
|             'interval': 5, | ||||
|             'redirect_url': redirect_url, | ||||
|         } | ||||
|         return FlashMessageUtil.gen_and_redirect_to(message_data) | ||||
| 
 | ||||
|     def get_already_bound_response(self, redirect_url): | ||||
|         msg = _('DingTalk is already bound') | ||||
|         response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|         response = self.get_failed_response(redirect_url, msg, msg) | ||||
|         return response | ||||
| 
 | ||||
| 
 | ||||
|  | @ -103,11 +101,11 @@ class DingTalkQRBindView(DingTalkQRMixin, View): | |||
| 
 | ||||
|         if not is_auth_password_time_valid(request.session): | ||||
|             msg = _('Please verify your password first') | ||||
|             response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|             response = self.get_failed_response(redirect_url, msg, msg) | ||||
|             return response | ||||
| 
 | ||||
|         redirect_uri = reverse('authentication:dingtalk-qr-bind-callback', kwargs={'user_id': user.id}, external=True) | ||||
|         redirect_uri += '?' + urllib.parse.urlencode({'redirect_url': redirect_url}) | ||||
|         redirect_uri += '?' + urlencode({'redirect_url': redirect_url}) | ||||
| 
 | ||||
|         url = self.get_qr_url(redirect_uri) | ||||
|         return HttpResponseRedirect(url) | ||||
|  | @ -127,7 +125,7 @@ class DingTalkQRBindCallbackView(DingTalkQRMixin, View): | |||
|         if user is None: | ||||
|             logger.error(f'DingTalkQR bind callback error, user_id invalid: user_id={user_id}') | ||||
|             msg = _('Invalid user_id') | ||||
|             response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|             response = self.get_failed_response(redirect_url, msg, msg) | ||||
|             return response | ||||
| 
 | ||||
|         if user.dingtalk_id: | ||||
|  | @ -143,7 +141,7 @@ class DingTalkQRBindCallbackView(DingTalkQRMixin, View): | |||
| 
 | ||||
|         if not userid: | ||||
|             msg = _('DingTalk query user failed') | ||||
|             response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|             response = self.get_failed_response(redirect_url, msg, msg) | ||||
|             return response | ||||
| 
 | ||||
|         try: | ||||
|  | @ -152,12 +150,12 @@ class DingTalkQRBindCallbackView(DingTalkQRMixin, View): | |||
|         except IntegrityError as e: | ||||
|             if e.args[0] == 1062: | ||||
|                 msg = _('The DingTalk is already bound to another user') | ||||
|                 response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|                 response = self.get_failed_response(redirect_url, msg, msg) | ||||
|                 return response | ||||
|             raise e | ||||
| 
 | ||||
|         msg = _('Binding DingTalk successfully') | ||||
|         response = self.get_success_reponse(redirect_url, msg, msg) | ||||
|         response = self.get_success_response(redirect_url, msg, msg) | ||||
|         return response | ||||
| 
 | ||||
| 
 | ||||
|  | @ -169,7 +167,7 @@ class DingTalkEnableStartView(UserVerifyPasswordView): | |||
| 
 | ||||
|         success_url = reverse('authentication:dingtalk-qr-bind') | ||||
| 
 | ||||
|         success_url += '?' + urllib.parse.urlencode({ | ||||
|         success_url += '?' + urlencode({ | ||||
|             'redirect_url': redirect_url or referer | ||||
|         }) | ||||
| 
 | ||||
|  | @ -183,7 +181,7 @@ class DingTalkQRLoginView(DingTalkQRMixin, View): | |||
|         redirect_url = request.GET.get('redirect_url') | ||||
| 
 | ||||
|         redirect_uri = reverse('authentication:dingtalk-qr-login-callback', external=True) | ||||
|         redirect_uri += '?' + urllib.parse.urlencode({'redirect_url': redirect_url}) | ||||
|         redirect_uri += '?' + urlencode({'redirect_url': redirect_url}) | ||||
| 
 | ||||
|         url = self.get_qr_url(redirect_uri) | ||||
|         return HttpResponseRedirect(url) | ||||
|  | @ -209,14 +207,14 @@ class DingTalkQRLoginCallbackView(AuthMixin, DingTalkQRMixin, View): | |||
|         if not userid: | ||||
|             # 正常流程不会出这个错误,hack 行为 | ||||
|             msg = _('Failed to get user from DingTalk') | ||||
|             response = self.get_failed_reponse(login_url, title=msg, msg=msg) | ||||
|             response = self.get_failed_response(login_url, title=msg, msg=msg) | ||||
|             return response | ||||
| 
 | ||||
|         user = get_object_or_none(User, dingtalk_id=userid) | ||||
|         if user is None: | ||||
|             title = _('DingTalk is not bound') | ||||
|             msg = _('Please login with a password and then bind the DingTalk') | ||||
|             response = self.get_failed_reponse(login_url, title=title, msg=msg) | ||||
|             response = self.get_failed_response(login_url, title=title, msg=msg) | ||||
|             return response | ||||
| 
 | ||||
|         try: | ||||
|  | @ -224,43 +222,7 @@ class DingTalkQRLoginCallbackView(AuthMixin, DingTalkQRMixin, View): | |||
|         except errors.AuthFailedError as e: | ||||
|             self.set_login_failed_mark() | ||||
|             msg = e.msg | ||||
|             response = self.get_failed_reponse(login_url, title=msg, msg=msg) | ||||
|             response = self.get_failed_response(login_url, title=msg, msg=msg) | ||||
|             return response | ||||
| 
 | ||||
|         return self.redirect_to_guard_view() | ||||
| 
 | ||||
| 
 | ||||
| @method_decorator(never_cache, name='dispatch') | ||||
| class FlashDingTalkBindSucceedMsgView(TemplateView): | ||||
|     template_name = 'flash_message_standalone.html' | ||||
| 
 | ||||
|     def get(self, request, *args, **kwargs): | ||||
|         title = request.GET.get('title') | ||||
|         msg = request.GET.get('msg') | ||||
| 
 | ||||
|         context = { | ||||
|             'title': title or _('Binding DingTalk successfully'), | ||||
|             'messages': msg or _('Binding DingTalk successfully'), | ||||
|             'interval': 5, | ||||
|             'redirect_url': request.GET.get('redirect_url'), | ||||
|             'auto_redirect': True, | ||||
|         } | ||||
|         return self.render_to_response(context) | ||||
| 
 | ||||
| 
 | ||||
| @method_decorator(never_cache, name='dispatch') | ||||
| class FlashDingTalkBindFailedMsgView(TemplateView): | ||||
|     template_name = 'flash_message_standalone.html' | ||||
| 
 | ||||
|     def get(self, request, *args, **kwargs): | ||||
|         title = request.GET.get('title') | ||||
|         msg = request.GET.get('msg') | ||||
| 
 | ||||
|         context = { | ||||
|             'title': title or _('Binding DingTalk failed'), | ||||
|             'messages': msg or _('Binding DingTalk failed'), | ||||
|             'interval': 5, | ||||
|             'redirect_url': request.GET.get('redirect_url'), | ||||
|             'auto_redirect': True, | ||||
|         } | ||||
|         return self.render_to_response(context) | ||||
|  |  | |||
|  | @ -1,10 +1,6 @@ | |||
| import urllib | ||||
| 
 | ||||
| from django.http.response import HttpResponseRedirect, HttpResponse | ||||
| from django.utils.decorators import method_decorator | ||||
| from django.http.response import HttpResponseRedirect | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| from django.views.decorators.cache import never_cache | ||||
| from django.views.generic import TemplateView | ||||
| from urllib.parse import urlencode | ||||
| from django.views import View | ||||
| from django.conf import settings | ||||
| from django.http.request import HttpRequest | ||||
|  | @ -15,7 +11,7 @@ from rest_framework.exceptions import APIException | |||
| from users.utils import is_auth_password_time_valid | ||||
| from users.views import UserVerifyPasswordView | ||||
| from users.models import User | ||||
| from common.utils import get_logger | ||||
| from common.utils import get_logger, FlashMessageUtil | ||||
| from common.utils.random import random_string | ||||
| from common.utils.django import reverse, get_object_or_none | ||||
| from common.mixins.views import PermissionsMixin | ||||
|  | @ -35,7 +31,7 @@ class FeiShuQRMixin(PermissionsMixin, View): | |||
|             return super().dispatch(request, *args, **kwargs) | ||||
|         except APIException as e: | ||||
|             msg = str(e.detail) | ||||
|             return self.get_failed_reponse( | ||||
|             return self.get_failed_response( | ||||
|                 '/', | ||||
|                 _('FeiShu Error'), | ||||
|                 msg | ||||
|  | @ -50,7 +46,7 @@ class FeiShuQRMixin(PermissionsMixin, View): | |||
| 
 | ||||
|     def get_verify_state_failed_response(self, redirect_uri): | ||||
|         msg = _("The system configuration is incorrect. Please contact your administrator") | ||||
|         return self.get_failed_reponse(redirect_uri, msg, msg) | ||||
|         return self.get_failed_response(redirect_uri, msg, msg) | ||||
| 
 | ||||
|     def get_qr_url(self, redirect_uri): | ||||
|         state = random_string(16) | ||||
|  | @ -61,30 +57,32 @@ class FeiShuQRMixin(PermissionsMixin, View): | |||
|             'state': state, | ||||
|             'redirect_uri': redirect_uri, | ||||
|         } | ||||
|         url =  URL.AUTHEN + '?' + urllib.parse.urlencode(params) | ||||
|         url = URL.AUTHEN + '?' + urlencode(params) | ||||
|         return url | ||||
| 
 | ||||
|     def get_success_reponse(self, redirect_url, title, msg): | ||||
|         ok_flash_msg_url = reverse('authentication:feishu-bind-success-flash-msg') | ||||
|         ok_flash_msg_url += '?' + urllib.parse.urlencode({ | ||||
|             'redirect_url': redirect_url, | ||||
|     @staticmethod | ||||
|     def get_success_response(redirect_url, title, msg): | ||||
|         message_data = { | ||||
|             'title': title, | ||||
|             'msg': msg | ||||
|         }) | ||||
|         return HttpResponseRedirect(ok_flash_msg_url) | ||||
|             'message': msg, | ||||
|             'interval': 5, | ||||
|             'redirect_url': redirect_url, | ||||
|         } | ||||
|         return FlashMessageUtil.gen_and_redirect_to(message_data) | ||||
| 
 | ||||
|     def get_failed_reponse(self, redirect_url, title, msg): | ||||
|         failed_flash_msg_url = reverse('authentication:feishu-bind-failed-flash-msg') | ||||
|         failed_flash_msg_url += '?' + urllib.parse.urlencode({ | ||||
|             'redirect_url': redirect_url, | ||||
|     @staticmethod | ||||
|     def get_failed_response(redirect_url, title, msg): | ||||
|         message_data = { | ||||
|             'title': title, | ||||
|             'msg': msg | ||||
|         }) | ||||
|         return HttpResponseRedirect(failed_flash_msg_url) | ||||
|             'error': msg, | ||||
|             'interval': 5, | ||||
|             'redirect_url': redirect_url, | ||||
|         } | ||||
|         return FlashMessageUtil.gen_and_redirect_to(message_data) | ||||
| 
 | ||||
|     def get_already_bound_response(self, redirect_url): | ||||
|         msg = _('FeiShu is already bound') | ||||
|         response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|         response = self.get_failed_response(redirect_url, msg, msg) | ||||
|         return response | ||||
| 
 | ||||
| 
 | ||||
|  | @ -97,11 +95,11 @@ class FeiShuQRBindView(FeiShuQRMixin, View): | |||
| 
 | ||||
|         if not is_auth_password_time_valid(request.session): | ||||
|             msg = _('Please verify your password first') | ||||
|             response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|             response = self.get_failed_response(redirect_url, msg, msg) | ||||
|             return response | ||||
| 
 | ||||
|         redirect_uri = reverse('authentication:feishu-qr-bind-callback', external=True) | ||||
|         redirect_uri += '?' + urllib.parse.urlencode({'redirect_url': redirect_url}) | ||||
|         redirect_uri += '?' + urlencode({'redirect_url': redirect_url}) | ||||
| 
 | ||||
|         url = self.get_qr_url(redirect_uri) | ||||
|         return HttpResponseRedirect(url) | ||||
|  | @ -131,7 +129,7 @@ class FeiShuQRBindCallbackView(FeiShuQRMixin, View): | |||
| 
 | ||||
|         if not user_id: | ||||
|             msg = _('FeiShu query user failed') | ||||
|             response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|             response = self.get_failed_response(redirect_url, msg, msg) | ||||
|             return response | ||||
| 
 | ||||
|         try: | ||||
|  | @ -140,12 +138,12 @@ class FeiShuQRBindCallbackView(FeiShuQRMixin, View): | |||
|         except IntegrityError as e: | ||||
|             if e.args[0] == 1062: | ||||
|                 msg = _('The FeiShu is already bound to another user') | ||||
|                 response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|                 response = self.get_failed_response(redirect_url, msg, msg) | ||||
|                 return response | ||||
|             raise e | ||||
| 
 | ||||
|         msg = _('Binding FeiShu successfully') | ||||
|         response = self.get_success_reponse(redirect_url, msg, msg) | ||||
|         response = self.get_success_response(redirect_url, msg, msg) | ||||
|         return response | ||||
| 
 | ||||
| 
 | ||||
|  | @ -157,7 +155,7 @@ class FeiShuEnableStartView(UserVerifyPasswordView): | |||
| 
 | ||||
|         success_url = reverse('authentication:feishu-qr-bind') | ||||
| 
 | ||||
|         success_url += '?' + urllib.parse.urlencode({ | ||||
|         success_url += '?' + urlencode({ | ||||
|             'redirect_url': redirect_url or referer | ||||
|         }) | ||||
| 
 | ||||
|  | @ -171,7 +169,7 @@ class FeiShuQRLoginView(FeiShuQRMixin, View): | |||
|         redirect_url = request.GET.get('redirect_url') | ||||
| 
 | ||||
|         redirect_uri = reverse('authentication:feishu-qr-login-callback', external=True) | ||||
|         redirect_uri += '?' + urllib.parse.urlencode({'redirect_url': redirect_url}) | ||||
|         redirect_uri += '?' + urlencode({'redirect_url': redirect_url}) | ||||
| 
 | ||||
|         url = self.get_qr_url(redirect_uri) | ||||
|         return HttpResponseRedirect(url) | ||||
|  | @ -196,14 +194,14 @@ class FeiShuQRLoginCallbackView(AuthMixin, FeiShuQRMixin, View): | |||
|         if not user_id: | ||||
|             # 正常流程不会出这个错误,hack 行为 | ||||
|             msg = _('Failed to get user from FeiShu') | ||||
|             response = self.get_failed_reponse(login_url, title=msg, msg=msg) | ||||
|             response = self.get_failed_response(login_url, title=msg, msg=msg) | ||||
|             return response | ||||
| 
 | ||||
|         user = get_object_or_none(User, feishu_id=user_id) | ||||
|         if user is None: | ||||
|             title = _('FeiShu is not bound') | ||||
|             msg = _('Please login with a password and then bind the FeiShu') | ||||
|             response = self.get_failed_reponse(login_url, title=title, msg=msg) | ||||
|             response = self.get_failed_response(login_url, title=title, msg=msg) | ||||
|             return response | ||||
| 
 | ||||
|         try: | ||||
|  | @ -211,43 +209,7 @@ class FeiShuQRLoginCallbackView(AuthMixin, FeiShuQRMixin, View): | |||
|         except errors.AuthFailedError as e: | ||||
|             self.set_login_failed_mark() | ||||
|             msg = e.msg | ||||
|             response = self.get_failed_reponse(login_url, title=msg, msg=msg) | ||||
|             response = self.get_failed_response(login_url, title=msg, msg=msg) | ||||
|             return response | ||||
| 
 | ||||
|         return self.redirect_to_guard_view() | ||||
| 
 | ||||
| 
 | ||||
| @method_decorator(never_cache, name='dispatch') | ||||
| class FlashFeiShuBindSucceedMsgView(TemplateView): | ||||
|     template_name = 'flash_message_standalone.html' | ||||
| 
 | ||||
|     def get(self, request, *args, **kwargs): | ||||
|         title = request.GET.get('title') | ||||
|         msg = request.GET.get('msg') | ||||
| 
 | ||||
|         context = { | ||||
|             'title': title or _('Binding FeiShu successfully'), | ||||
|             'messages': msg or _('Binding FeiShu successfully'), | ||||
|             'interval': 5, | ||||
|             'redirect_url': request.GET.get('redirect_url'), | ||||
|             'auto_redirect': True, | ||||
|         } | ||||
|         return self.render_to_response(context) | ||||
| 
 | ||||
| 
 | ||||
| @method_decorator(never_cache, name='dispatch') | ||||
| class FlashFeiShuBindFailedMsgView(TemplateView): | ||||
|     template_name = 'flash_message_standalone.html' | ||||
| 
 | ||||
|     def get(self, request, *args, **kwargs): | ||||
|         title = request.GET.get('title') | ||||
|         msg = request.GET.get('msg') | ||||
| 
 | ||||
|         context = { | ||||
|             'title': title or _('Binding FeiShu failed'), | ||||
|             'messages': msg or _('Binding FeiShu failed'), | ||||
|             'interval': 5, | ||||
|             'redirect_url': request.GET.get('redirect_url'), | ||||
|             'auto_redirect': True, | ||||
|         } | ||||
|         return self.render_to_response(context) | ||||
|  |  | |||
|  | @ -1,10 +1,6 @@ | |||
| import urllib | ||||
| 
 | ||||
| from django.http.response import HttpResponseRedirect | ||||
| from django.utils.decorators import method_decorator | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| from django.views.decorators.cache import never_cache | ||||
| from django.views.generic import TemplateView | ||||
| from urllib.parse import urlencode | ||||
| from django.views import View | ||||
| from django.conf import settings | ||||
| from django.http.request import HttpRequest | ||||
|  | @ -15,7 +11,7 @@ from rest_framework.exceptions import APIException | |||
| from users.views import UserVerifyPasswordView | ||||
| from users.utils import is_auth_password_time_valid | ||||
| from users.models import User | ||||
| from common.utils import get_logger | ||||
| from common.utils import get_logger, FlashMessageUtil | ||||
| from common.utils.random import random_string | ||||
| from common.utils.django import reverse, get_object_or_none | ||||
| from common.message.backends.wecom import URL | ||||
|  | @ -39,7 +35,7 @@ class WeComQRMixin(PermissionsMixin, View): | |||
|                 msg = e.detail['errmsg'] | ||||
|             except Exception: | ||||
|                 msg = _('WeCom Error, Please contact your system administrator') | ||||
|             return self.get_failed_reponse( | ||||
|             return self.get_failed_response( | ||||
|                 '/', | ||||
|                 _('WeCom Error'), | ||||
|                 msg | ||||
|  | @ -54,7 +50,7 @@ class WeComQRMixin(PermissionsMixin, View): | |||
| 
 | ||||
|     def get_verify_state_failed_response(self, redirect_uri): | ||||
|         msg = _("The system configuration is incorrect. Please contact your administrator") | ||||
|         return self.get_failed_reponse(redirect_uri, msg, msg) | ||||
|         return self.get_failed_response(redirect_uri, msg, msg) | ||||
| 
 | ||||
|     def get_qr_url(self, redirect_uri): | ||||
|         state = random_string(16) | ||||
|  | @ -66,30 +62,32 @@ class WeComQRMixin(PermissionsMixin, View): | |||
|             'state': state, | ||||
|             'redirect_uri': redirect_uri, | ||||
|         } | ||||
|         url = URL.QR_CONNECT + '?' + urllib.parse.urlencode(params) | ||||
|         url = URL.QR_CONNECT + '?' + urlencode(params) | ||||
|         return url | ||||
| 
 | ||||
|     def get_success_reponse(self, redirect_url, title, msg): | ||||
|         ok_flash_msg_url = reverse('authentication:wecom-bind-success-flash-msg') | ||||
|         ok_flash_msg_url += '?' + urllib.parse.urlencode({ | ||||
|             'redirect_url': redirect_url, | ||||
|     @staticmethod | ||||
|     def get_success_response(redirect_url, title, msg): | ||||
|         message_data = { | ||||
|             'title': title, | ||||
|             'msg': msg | ||||
|         }) | ||||
|         return HttpResponseRedirect(ok_flash_msg_url) | ||||
|             'message': msg, | ||||
|             'interval': 5, | ||||
|             'redirect_url': redirect_url, | ||||
|         } | ||||
|         return FlashMessageUtil.gen_and_redirect_to(message_data) | ||||
| 
 | ||||
|     def get_failed_reponse(self, redirect_url, title, msg): | ||||
|         failed_flash_msg_url = reverse('authentication:wecom-bind-failed-flash-msg') | ||||
|         failed_flash_msg_url += '?' + urllib.parse.urlencode({ | ||||
|             'redirect_url': redirect_url, | ||||
|     @staticmethod | ||||
|     def get_failed_response(redirect_url, title, msg): | ||||
|         message_data = { | ||||
|             'title': title, | ||||
|             'msg': msg | ||||
|         }) | ||||
|         return HttpResponseRedirect(failed_flash_msg_url) | ||||
|             'error': msg, | ||||
|             'interval': 5, | ||||
|             'redirect_url': redirect_url, | ||||
|         } | ||||
|         return FlashMessageUtil.gen_and_redirect_to(message_data) | ||||
| 
 | ||||
|     def get_already_bound_response(self, redirect_url): | ||||
|         msg = _('WeCom is already bound') | ||||
|         response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|         response = self.get_failed_response(redirect_url, msg, msg) | ||||
|         return response | ||||
| 
 | ||||
| 
 | ||||
|  | @ -102,11 +100,11 @@ class WeComQRBindView(WeComQRMixin, View): | |||
| 
 | ||||
|         if not is_auth_password_time_valid(request.session): | ||||
|             msg = _('Please verify your password first') | ||||
|             response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|             response = self.get_failed_response(redirect_url, msg, msg) | ||||
|             return response | ||||
| 
 | ||||
|         redirect_uri = reverse('authentication:wecom-qr-bind-callback', kwargs={'user_id': user.id}, external=True) | ||||
|         redirect_uri += '?' + urllib.parse.urlencode({'redirect_url': redirect_url}) | ||||
|         redirect_uri += '?' + urlencode({'redirect_url': redirect_url}) | ||||
| 
 | ||||
|         url = self.get_qr_url(redirect_uri) | ||||
|         return HttpResponseRedirect(url) | ||||
|  | @ -126,7 +124,7 @@ class WeComQRBindCallbackView(WeComQRMixin, View): | |||
|         if user is None: | ||||
|             logger.error(f'WeComQR bind callback error, user_id invalid: user_id={user_id}') | ||||
|             msg = _('Invalid user_id') | ||||
|             response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|             response = self.get_failed_response(redirect_url, msg, msg) | ||||
|             return response | ||||
| 
 | ||||
|         if user.wecom_id: | ||||
|  | @ -141,7 +139,7 @@ class WeComQRBindCallbackView(WeComQRMixin, View): | |||
|         wecom_userid, __ = wecom.get_user_id_by_code(code) | ||||
|         if not wecom_userid: | ||||
|             msg = _('WeCom query user failed') | ||||
|             response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|             response = self.get_failed_response(redirect_url, msg, msg) | ||||
|             return response | ||||
| 
 | ||||
|         try: | ||||
|  | @ -150,27 +148,24 @@ class WeComQRBindCallbackView(WeComQRMixin, View): | |||
|         except IntegrityError as e: | ||||
|             if e.args[0] == 1062: | ||||
|                 msg = _('The WeCom is already bound to another user') | ||||
|                 response = self.get_failed_reponse(redirect_url, msg, msg) | ||||
|                 response = self.get_failed_response(redirect_url, msg, msg) | ||||
|                 return response | ||||
|             raise e | ||||
| 
 | ||||
|         msg = _('Binding WeCom successfully') | ||||
|         response = self.get_success_reponse(redirect_url, msg, msg) | ||||
|         response = self.get_success_response(redirect_url, msg, msg) | ||||
|         return response | ||||
| 
 | ||||
| 
 | ||||
| class WeComEnableStartView(UserVerifyPasswordView): | ||||
| 
 | ||||
|     def get_success_url(self): | ||||
|         referer = self.request.META.get('HTTP_REFERER') | ||||
|         redirect_url = self.request.GET.get("redirect_url") | ||||
| 
 | ||||
|         success_url = reverse('authentication:wecom-qr-bind') | ||||
| 
 | ||||
|         success_url += '?' + urllib.parse.urlencode({ | ||||
|         success_url += '?' + urlencode({ | ||||
|             'redirect_url': redirect_url or referer | ||||
|         }) | ||||
| 
 | ||||
|         return success_url | ||||
| 
 | ||||
| 
 | ||||
|  | @ -181,7 +176,7 @@ class WeComQRLoginView(WeComQRMixin, View): | |||
|         redirect_url = request.GET.get('redirect_url') | ||||
| 
 | ||||
|         redirect_uri = reverse('authentication:wecom-qr-login-callback', external=True) | ||||
|         redirect_uri += '?' + urllib.parse.urlencode({'redirect_url': redirect_url}) | ||||
|         redirect_uri += '?' + urlencode({'redirect_url': redirect_url}) | ||||
| 
 | ||||
|         url = self.get_qr_url(redirect_uri) | ||||
|         return HttpResponseRedirect(url) | ||||
|  | @ -207,14 +202,14 @@ class WeComQRLoginCallbackView(AuthMixin, WeComQRMixin, View): | |||
|         if not wecom_userid: | ||||
|             # 正常流程不会出这个错误,hack 行为 | ||||
|             msg = _('Failed to get user from WeCom') | ||||
|             response = self.get_failed_reponse(login_url, title=msg, msg=msg) | ||||
|             response = self.get_failed_response(login_url, title=msg, msg=msg) | ||||
|             return response | ||||
| 
 | ||||
|         user = get_object_or_none(User, wecom_id=wecom_userid) | ||||
|         if user is None: | ||||
|             title = _('WeCom is not bound') | ||||
|             msg = _('Please login with a password and then bind the WeCom') | ||||
|             response = self.get_failed_reponse(login_url, title=title, msg=msg) | ||||
|             response = self.get_failed_response(login_url, title=title, msg=msg) | ||||
|             return response | ||||
| 
 | ||||
|         try: | ||||
|  | @ -222,43 +217,7 @@ class WeComQRLoginCallbackView(AuthMixin, WeComQRMixin, View): | |||
|         except errors.AuthFailedError as e: | ||||
|             self.set_login_failed_mark() | ||||
|             msg = e.msg | ||||
|             response = self.get_failed_reponse(login_url, title=msg, msg=msg) | ||||
|             response = self.get_failed_response(login_url, title=msg, msg=msg) | ||||
|             return response | ||||
| 
 | ||||
|         return self.redirect_to_guard_view() | ||||
| 
 | ||||
| 
 | ||||
| @method_decorator(never_cache, name='dispatch') | ||||
| class FlashWeComBindSucceedMsgView(TemplateView): | ||||
|     template_name = 'flash_message_standalone.html' | ||||
| 
 | ||||
|     def get(self, request, *args, **kwargs): | ||||
|         title = request.GET.get('title') | ||||
|         msg = request.GET.get('msg') | ||||
| 
 | ||||
|         context = { | ||||
|             'title': title or _('Binding WeCom successfully'), | ||||
|             'messages': msg or _('Binding WeCom successfully'), | ||||
|             'interval': 5, | ||||
|             'redirect_url': request.GET.get('redirect_url'), | ||||
|             'auto_redirect': True, | ||||
|         } | ||||
|         return self.render_to_response(context) | ||||
| 
 | ||||
| 
 | ||||
| @method_decorator(never_cache, name='dispatch') | ||||
| class FlashWeComBindFailedMsgView(TemplateView): | ||||
|     template_name = 'flash_message_standalone.html' | ||||
| 
 | ||||
|     def get(self, request, *args, **kwargs): | ||||
|         title = request.GET.get('title') | ||||
|         msg = request.GET.get('msg') | ||||
| 
 | ||||
|         context = { | ||||
|             'title': title or _('Binding WeCom failed'), | ||||
|             'messages': msg or _('Binding WeCom failed'), | ||||
|             'interval': 5, | ||||
|             'redirect_url': request.GET.get('redirect_url'), | ||||
|             'auto_redirect': True, | ||||
|         } | ||||
|         return self.render_to_response(context) | ||||
|  |  | |||
|  | @ -14,7 +14,8 @@ def sign(secret, data): | |||
|     digest = hmac.HMAC( | ||||
|         key=secret.encode('utf8'), | ||||
|         msg=data.encode('utf8'), | ||||
|         digestmod=hmac._hashlib.sha256).digest() | ||||
|         digestmod=hmac._hashlib.sha256 | ||||
|     ).digest() | ||||
|     signature = base64.standard_b64encode(digest).decode('utf8') | ||||
|     # signature = urllib.parse.quote(signature, safe='') | ||||
|     # signature = signature.replace('+', '%20').replace('*', '%2A').replace('~', '%7E').replace('/', '%2F') | ||||
|  | @ -39,9 +40,9 @@ class DingTalkRequests(BaseRequest): | |||
|     invalid_token_errcodes = (ErrorCode.INVALID_TOKEN,) | ||||
| 
 | ||||
|     def __init__(self, appid, appsecret, agentid, timeout=None): | ||||
|         self._appid = appid | ||||
|         self._appsecret = appsecret | ||||
|         self._agentid = agentid | ||||
|         self._appid = appid or '' | ||||
|         self._appsecret = appsecret or '' | ||||
|         self._agentid = agentid or '' | ||||
| 
 | ||||
|         super().__init__(timeout=timeout) | ||||
| 
 | ||||
|  | @ -74,7 +75,7 @@ class DingTalkRequests(BaseRequest): | |||
|     def post(self, url, json=None, params=None, | ||||
|              with_token=False, with_sign=False, | ||||
|              check_errcode_is_0=True, | ||||
|              **kwargs): | ||||
|              **kwargs) -> dict: | ||||
|         pass | ||||
|     post = as_request(post) | ||||
| 
 | ||||
|  | @ -86,11 +87,10 @@ class DingTalkRequests(BaseRequest): | |||
| 
 | ||||
|         timestamp = str(int(time.time() * 1000)) | ||||
|         signature = sign(self._appsecret, timestamp) | ||||
|         accessKey = self._appid | ||||
| 
 | ||||
|         params['timestamp'] = timestamp | ||||
|         params['signature'] = signature | ||||
|         params['accessKey'] = accessKey | ||||
|         params['accessKey'] = self._appid | ||||
| 
 | ||||
|     def request(self, method, url, | ||||
|                 with_token=False, with_sign=False, | ||||
|  | @ -102,15 +102,16 @@ class DingTalkRequests(BaseRequest): | |||
| 
 | ||||
|         data = super().request( | ||||
|             method, url, with_token=with_token, | ||||
|             check_errcode_is_0=check_errcode_is_0, **kwargs) | ||||
|             check_errcode_is_0=check_errcode_is_0, **kwargs | ||||
|         ) | ||||
|         return data | ||||
| 
 | ||||
| 
 | ||||
| class DingTalk: | ||||
|     def __init__(self, appid, appsecret, agentid, timeout=None): | ||||
|         self._appid = appid | ||||
|         self._appsecret = appsecret | ||||
|         self._agentid = agentid | ||||
|         self._appid = appid or '' | ||||
|         self._appsecret = appsecret or '' | ||||
|         self._agentid = agentid or '' | ||||
| 
 | ||||
|         self._request = DingTalkRequests( | ||||
|             appid=appid, appsecret=appsecret, agentid=agentid, | ||||
|  |  | |||
|  | @ -69,8 +69,8 @@ class FeiShu(RequestMixin): | |||
|     """ | ||||
| 
 | ||||
|     def __init__(self, app_id, app_secret, timeout=None): | ||||
|         self._app_id = app_id | ||||
|         self._app_secret = app_secret | ||||
|         self._app_id = app_id or '' | ||||
|         self._app_secret = app_secret or '' | ||||
| 
 | ||||
|         self._requests = FeishuRequests( | ||||
|             app_id=app_id, | ||||
|  |  | |||
|  | @ -8,12 +8,12 @@ from common.message.backends import exceptions as exce | |||
| logger = get_logger(__name__) | ||||
| 
 | ||||
| 
 | ||||
| def digest(corpid, corpsecret): | ||||
| def digest(corp_id, corp_secret): | ||||
|     md5 = hashlib.md5() | ||||
|     md5.update(corpid.encode()) | ||||
|     md5.update(corpsecret.encode()) | ||||
|     digest = md5.hexdigest() | ||||
|     return digest | ||||
|     md5.update(corp_id.encode()) | ||||
|     md5.update(corp_secret.encode()) | ||||
|     dist = md5.hexdigest() | ||||
|     return dist | ||||
| 
 | ||||
| 
 | ||||
| def update_values(default: dict, others: dict): | ||||
|  |  | |||
|  | @ -47,9 +47,9 @@ class WeComRequests(BaseRequest): | |||
|     invalid_token_errcodes = (ErrorCode.INVALID_TOKEN,) | ||||
| 
 | ||||
|     def __init__(self, corpid, corpsecret, agentid, timeout=None): | ||||
|         self._corpid = corpid | ||||
|         self._corpsecret = corpsecret | ||||
|         self._agentid = agentid | ||||
|         self._corpid = corpid or '' | ||||
|         self._corpsecret = corpsecret or '' | ||||
|         self._agentid = agentid or '' | ||||
| 
 | ||||
|         super().__init__(timeout=timeout) | ||||
| 
 | ||||
|  | @ -79,9 +79,9 @@ class WeCom(RequestMixin): | |||
|     """ | ||||
| 
 | ||||
|     def __init__(self, corpid, corpsecret, agentid, timeout=None): | ||||
|         self._corpid = corpid | ||||
|         self._corpsecret = corpsecret | ||||
|         self._agentid = agentid | ||||
|         self._corpid = corpid or '' | ||||
|         self._corpsecret = corpsecret or '' | ||||
|         self._agentid = agentid or '' | ||||
| 
 | ||||
|         self._requests = WeComRequests( | ||||
|             corpid=corpid, | ||||
|  |  | |||
|  | @ -275,7 +275,7 @@ class Time: | |||
|             last = timestamp | ||||
| 
 | ||||
| 
 | ||||
| def bulk_get(d, *keys, default=None): | ||||
| def bulk_get(d, keys, default=None): | ||||
|     values = [] | ||||
|     for key in keys: | ||||
|         values.append(d.get(key, default)) | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| from django.core.cache import cache | ||||
| from django.shortcuts import reverse | ||||
| from django.shortcuts import redirect | ||||
| 
 | ||||
| from .random import random_string | ||||
| 
 | ||||
|  | @ -8,6 +9,17 @@ __all__ = ['FlashMessageUtil'] | |||
| 
 | ||||
| 
 | ||||
| class FlashMessageUtil: | ||||
|     """ | ||||
|     跳转到通用msg页面 | ||||
|     message_data: { | ||||
|         'title': '', | ||||
|         'message': '', | ||||
|         'error': '', | ||||
|         'redirect_url': '', | ||||
|         'confirm_button': '', | ||||
|         'cancel_url': '' | ||||
|     } | ||||
|     """ | ||||
|     @staticmethod | ||||
|     def get_key(code): | ||||
|         key = 'MESSAGE_{}'.format(code) | ||||
|  | @ -29,3 +41,8 @@ class FlashMessageUtil: | |||
|     def gen_message_url(cls, message_data): | ||||
|         code = cls.get_message_code(message_data) | ||||
|         return reverse('common:flash-message') + f'?code={code}' | ||||
| 
 | ||||
|     @classmethod | ||||
|     def gen_and_redirect_to(cls, message_data): | ||||
|         url = cls.gen_message_url(message_data) | ||||
|         return redirect(url) | ||||
|  |  | |||
|  | @ -20,21 +20,21 @@ class FlashMessageMsgView(TemplateView): | |||
|         if not message_data: | ||||
|             return HttpResponse('Message code error') | ||||
| 
 | ||||
|         title, message, redirect_url, confirm_button, cancel_url = bulk_get( | ||||
|             message_data, 'title', 'message', 'redirect_url', 'confirm_button', 'cancel_url' | ||||
|         ) | ||||
|         items = ('title', 'message', 'error', 'redirect_url', 'confirm_button', 'cancel_url') | ||||
|         title, msg, error, redirect_url, confirm_btn, cancel_url = bulk_get(message_data, items) | ||||
| 
 | ||||
|         interval = message_data.get('interval', 3) | ||||
|         auto_redirect = message_data.get('auto_redirect', True) | ||||
|         has_cancel = message_data.get('has_cancel', False) | ||||
|         context = { | ||||
|             'title': title, | ||||
|             'messages': message, | ||||
|             'message': msg, | ||||
|             'error': error, | ||||
|             'interval': interval, | ||||
|             'redirect_url': redirect_url, | ||||
|             'auto_redirect': auto_redirect, | ||||
|             'confirm_button': confirm_button, | ||||
|             'confirm_button': confirm_btn, | ||||
|             'has_cancel': has_cancel, | ||||
|             'cancel_url': cancel_url, | ||||
|         } | ||||
|         return self.render_to_response(context) | ||||
|         return self.render_to_response(context) | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ from rest_framework.exceptions import APIException | |||
| from rest_framework import status | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| 
 | ||||
| from settings.models import Setting | ||||
| from django.conf import settings | ||||
| from common.permissions import IsSuperUser | ||||
| from common.message.backends.dingtalk import DingTalk | ||||
| 
 | ||||
|  | @ -19,24 +19,19 @@ class DingTalkTestingAPI(GenericAPIView): | |||
|         serializer = self.serializer_class(data=request.data) | ||||
|         serializer.is_valid(raise_exception=True) | ||||
| 
 | ||||
|         dingtalk_appkey = serializer.validated_data['DINGTALK_APPKEY'] | ||||
|         dingtalk_agentid = serializer.validated_data['DINGTALK_AGENTID'] | ||||
|         dingtalk_appsecret = serializer.validated_data.get('DINGTALK_APPSECRET') | ||||
| 
 | ||||
|         if not dingtalk_appsecret: | ||||
|             secret = Setting.objects.filter(name='DINGTALK_APPSECRET').first() | ||||
|             if secret: | ||||
|                 dingtalk_appsecret = secret.cleaned_value | ||||
| 
 | ||||
|         dingtalk_appsecret = dingtalk_appsecret or '' | ||||
|         app_key = serializer.validated_data['DINGTALK_APPKEY'] | ||||
|         agent_id = serializer.validated_data['DINGTALK_AGENTID'] | ||||
|         app_secret = serializer.validated_data.get('DINGTALK_APPSECRET') \ | ||||
|                      or settings.DINGTALK_APPSECRET \ | ||||
|                      or '' | ||||
| 
 | ||||
|         try: | ||||
|             dingtalk = DingTalk(appid=dingtalk_appkey, appsecret=dingtalk_appsecret, agentid=dingtalk_agentid) | ||||
|             dingtalk = DingTalk(appid=app_key, appsecret=app_secret, agentid=agent_id) | ||||
|             dingtalk.send_text(['test'], 'test') | ||||
|             return Response(status=status.HTTP_200_OK, data={'msg': _('Test success')}) | ||||
|         except APIException as e: | ||||
|             try: | ||||
|             if 'errmsg' in e.detail: | ||||
|                 error = e.detail['errmsg'] | ||||
|             except: | ||||
|             else: | ||||
|                 error = e.detail | ||||
|             return Response(status=status.HTTP_400_BAD_REQUEST, data={'error': error}) | ||||
|  |  | |||
|  | @ -6,21 +6,18 @@ | |||
| 
 | ||||
| {% block content %} | ||||
|     <div> | ||||
|         {% if errors %} | ||||
|             <p> | ||||
|             <div class="alert alert-danger"> | ||||
|                 {{ errors }} | ||||
|         <p> | ||||
|             {% if error %} | ||||
|             <div class="alert alert-danger" id="messages"> | ||||
|                 {{ error }} | ||||
|             </div> | ||||
|             </p> | ||||
|         {% endif %} | ||||
| 
 | ||||
|         {% if messages %} | ||||
|             <p> | ||||
|             {% else %} | ||||
|             <div class="alert alert-success" id="messages"> | ||||
|                 {{ messages|safe }} | ||||
|                 {{ message|safe }} | ||||
|             </div> | ||||
|             </p> | ||||
|         {% endif %} | ||||
|             {% endif %} | ||||
|         </p> | ||||
| 
 | ||||
|         <div class="row"> | ||||
|             {% if has_cancel %} | ||||
|             <div class="col-sm-3"> | ||||
|  | @ -44,17 +41,19 @@ | |||
| 
 | ||||
| {% block custom_foot_js %} | ||||
| <script> | ||||
|     var time = '{{ interval }}'; | ||||
|     if (!time) { | ||||
|         time = 5; | ||||
|     } else { | ||||
|         time = parseInt(time); | ||||
|     } | ||||
|     var message = '' | ||||
|     var time = '{{ interval }}' | ||||
| 
 | ||||
|     {% if error %} | ||||
|         message = '{{ error }}' | ||||
|     {% else %} | ||||
|         message = '{{ message|safe }}' | ||||
|     {% endif %} | ||||
| 
 | ||||
|     function redirect_page() { | ||||
|         if (time >= 0) { | ||||
|             var messages = '{{ messages|safe }}, <b>' + time + '</b> ...'; | ||||
|             $('#messages').html(messages); | ||||
|             var msg = message + ', <b>' + time + '</b> ...'; | ||||
|             $('#messages').html(msg); | ||||
|             time--; | ||||
|             setTimeout(redirect_page, 1000); | ||||
|         } else { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 fit2bot
						fit2bot