Merge remote-tracking branch 'ungleich/master'
This commit is contained in:
		
				commit
				
					
						b782c6212a
					
				
			
		
					 10 changed files with 154 additions and 24 deletions
				
			
		|  | @ -1,4 +1,4 @@ | ||||||
| Pre-changelog: 1.2.3 2017-09-20 | 1.2.3: 2017-09-25 | ||||||
|     * #3484: [dcl, hosting] Refactored account activation, password reset, VM order and cancellation email |     * #3484: [dcl, hosting] Refactored account activation, password reset, VM order and cancellation email | ||||||
|     * #3731: [dcl, hosting] Added cdist ssh key handler  |     * #3731: [dcl, hosting] Added cdist ssh key handler  | ||||||
|     * #3628: [dcl] on hosting, VM is created at credit card info submit |     * #3628: [dcl] on hosting, VM is created at credit card info submit | ||||||
|  | @ -6,6 +6,7 @@ Pre-changelog: 1.2.3 2017-09-20 | ||||||
|     * #3786: [hosting] Redesigned the hosting invoice and order-confirmation page |     * #3786: [hosting] Redesigned the hosting invoice and order-confirmation page | ||||||
|     * #3728: [hosting] VM Termination animation added |     * #3728: [hosting] VM Termination animation added | ||||||
|     * #3777: [hosting] Create new VM calculator added like dcl landing |     * #3777: [hosting] Create new VM calculator added like dcl landing | ||||||
|  |     * #3781: [hosting] Resend activation mail | ||||||
|     * #3806: [hosting] Fix can not create VMs after password reset |     * #3806: [hosting] Fix can not create VMs after password reset | ||||||
|     * Feature: [cms, blog] Added /cms prefix for all the django-cms generated urls |     * Feature: [cms, blog] Added /cms prefix for all the django-cms generated urls | ||||||
|     * Bugfix: [dcl, hosting] added host to celery error mails |     * Bugfix: [dcl, hosting] added host to celery error mails | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ msgid "" | ||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: PACKAGE VERSION\n" | "Project-Id-Version: PACKAGE VERSION\n" | ||||||
| "Report-Msgid-Bugs-To: \n" | "Report-Msgid-Bugs-To: \n" | ||||||
| "POT-Creation-Date: 2017-09-23 19:00+0530\n" | "POT-Creation-Date: 2017-09-24 12:34+0000\n" | ||||||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||||
| "Language-Team: LANGUAGE <LL@li.org>\n" | "Language-Team: LANGUAGE <LL@li.org>\n" | ||||||
|  | @ -306,6 +306,9 @@ msgstr "Registrieren" | ||||||
| msgid "Forgot your password ? " | msgid "Forgot your password ? " | ||||||
| msgstr "Passwort vergessen?" | msgstr "Passwort vergessen?" | ||||||
| 
 | 
 | ||||||
|  | msgid "Resend activation link" | ||||||
|  | msgstr "Aktivierungslink noch einmal senden" | ||||||
|  | 
 | ||||||
| msgid "Notifications" | msgid "Notifications" | ||||||
| msgstr "Benachrichtigungen" | msgstr "Benachrichtigungen" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -44,6 +44,8 @@ | ||||||
|                         <a class="unlink" href="{% url 'hosting:signup' %}">{% trans "Sign up"%}</a> |                         <a class="unlink" href="{% url 'hosting:signup' %}">{% trans "Sign up"%}</a> | ||||||
|                         <span class="text"> or </span> |                         <span class="text"> or </span> | ||||||
|                         <a class="unlink" href="{% url 'hosting:reset_password' %}">{% trans "Forgot your password ? "%}</a> |                         <a class="unlink" href="{% url 'hosting:reset_password' %}">{% trans "Forgot your password ? "%}</a> | ||||||
|  |                         <span class="text"> or </span><br/> | ||||||
|  |                         <a class="unlink" href="{% url 'hosting:resend_activation_link' %}">{% trans "Resend activation link"%}</a> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|  |  | ||||||
							
								
								
									
										36
									
								
								hosting/templates/hosting/resend_activation_link.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								hosting/templates/hosting/resend_activation_link.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | ||||||
|  | {% extends "hosting/base_short.html" %} | ||||||
|  | {% load staticfiles bootstrap3%} | ||||||
|  | {% load i18n %} | ||||||
|  | 
 | ||||||
|  | {% block navbar %} | ||||||
|  |     {% include  'hosting/includes/_navbar_transparent.html' %} | ||||||
|  | {% endblock navbar %} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  | <div class="auth-container"> | ||||||
|  |    <div class="auth-bg"></div> | ||||||
|  |         <div class="auth-center"> | ||||||
|  |             <div class="auth-title"> | ||||||
|  |                 <h2>{% trans "Your VM hosted in Switzerland"%}</h2> | ||||||
|  |             </div> | ||||||
|  |             <div class="auth-content"> | ||||||
|  |                 <div class="intro-message auth-box sign-up"> | ||||||
|  |                     <h2  class="section-heading">{% trans "Resend activation link"%}</h2> | ||||||
|  |                     <form action="{% url 'hosting:resend_activation_link' %}" method="post" class="form" novalidate> | ||||||
|  |                         {% csrf_token %} | ||||||
|  |                         {% for field in form %} | ||||||
|  |                             {% bootstrap_field field show_label=False %} | ||||||
|  |                         {% endfor %} | ||||||
|  |                         {% buttons %} | ||||||
|  |                             <button type="submit" class="btn btn-block btn-success"> | ||||||
|  |                                 {% trans "Submit"%} | ||||||
|  |                             </button> | ||||||
|  |                         {% endbuttons %} | ||||||
|  |                     </form> | ||||||
|  | 
 | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  | </div> | ||||||
|  | {% endblock %} | ||||||
|  | @ -8,8 +8,7 @@ from .views import ( | ||||||
|     MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, |     MarkAsReadNotificationView, PasswordResetView, PasswordResetConfirmView, | ||||||
|     HostingPricingView, CreateVirtualMachinesView, HostingBillListView, |     HostingPricingView, CreateVirtualMachinesView, HostingBillListView, | ||||||
|     HostingBillDetailView, SSHKeyDeleteView, SSHKeyCreateView, SSHKeyListView, |     HostingBillDetailView, SSHKeyDeleteView, SSHKeyCreateView, SSHKeyListView, | ||||||
|     SSHKeyChoiceView, DashboardView, SettingsView) |     SSHKeyChoiceView, DashboardView, SettingsView, ResendActivationEmailView) | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| urlpatterns = [ | urlpatterns = [ | ||||||
|     url(r'index/?$', IndexView.as_view(), name='index'), |     url(r'index/?$', IndexView.as_view(), name='index'), | ||||||
|  | @ -52,6 +51,8 @@ urlpatterns = [ | ||||||
|     url(r'signup/?$', SignupView.as_view(), name='signup'), |     url(r'signup/?$', SignupView.as_view(), name='signup'), | ||||||
|     url(r'signup-validate/?$', SignupValidateView.as_view(), |     url(r'signup-validate/?$', SignupValidateView.as_view(), | ||||||
|         name='signup-validate'), |         name='signup-validate'), | ||||||
|  |     url(r'resend-activation-link/?$', ResendActivationEmailView.as_view(), | ||||||
|  |         name='resend_activation_link'), | ||||||
|     url(r'reset-password/?$', PasswordResetView.as_view(), |     url(r'reset-password/?$', PasswordResetView.as_view(), | ||||||
|         name='reset_password'), |         name='reset_password'), | ||||||
|     url(r'reset-password-confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$', |     url(r'reset-password-confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$', | ||||||
|  |  | ||||||
|  | @ -33,12 +33,15 @@ from membership.models import CustomUser, StripeCustomer | ||||||
| from opennebula_api.models import OpenNebulaManager | from opennebula_api.models import OpenNebulaManager | ||||||
| from opennebula_api.serializers import VirtualMachineSerializer, \ | from opennebula_api.serializers import VirtualMachineSerializer, \ | ||||||
|     VirtualMachineTemplateSerializer, VMTemplateSerializer |     VirtualMachineTemplateSerializer, VMTemplateSerializer | ||||||
| from utils.forms import BillingAddressForm, PasswordResetRequestForm, \ | from utils.forms import ( | ||||||
|     UserBillingAddressForm |     BillingAddressForm, PasswordResetRequestForm, UserBillingAddressForm, | ||||||
|  |     ResendActivationEmailForm | ||||||
|  | ) | ||||||
| from utils.mailer import BaseEmail | from utils.mailer import BaseEmail | ||||||
| from utils.stripe_utils import StripeUtils | from utils.stripe_utils import StripeUtils | ||||||
| from utils.views import ( | from utils.views import ( | ||||||
|     PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin |     PasswordResetViewMixin, PasswordResetConfirmViewMixin, LoginViewMixin, | ||||||
|  |     ResendActivationLinkViewMixin | ||||||
| ) | ) | ||||||
| from .forms import HostingUserSignupForm, HostingUserLoginForm, \ | from .forms import HostingUserSignupForm, HostingUserLoginForm, \ | ||||||
|     UserHostingKeyForm, generate_ssh_key_name |     UserHostingKeyForm, generate_ssh_key_name | ||||||
|  | @ -282,6 +285,14 @@ class SignupValidatedView(SignupValidateView): | ||||||
|         return context |         return context | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class ResendActivationEmailView(ResendActivationLinkViewMixin): | ||||||
|  |     template_name = 'hosting/resend_activation_link.html' | ||||||
|  |     form_class = ResendActivationEmailForm | ||||||
|  |     success_url = reverse_lazy('hosting:login') | ||||||
|  |     email_template_path = 'datacenterlight/emails/' | ||||||
|  |     email_template_name = 'user_activation' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class PasswordResetView(PasswordResetViewMixin): | class PasswordResetView(PasswordResetViewMixin): | ||||||
|     site = 'dcl' |     site = 'dcl' | ||||||
|     template_name = 'hosting/reset_password.html' |     template_name = 'hosting/reset_password.html' | ||||||
|  |  | ||||||
|  | @ -96,5 +96,4 @@ pyflakes==1.5.0 | ||||||
| billiard==3.5.0.3 | billiard==3.5.0.3 | ||||||
| amqp==2.2.1 | amqp==2.2.1 | ||||||
| vine==1.1.4 | vine==1.1.4 | ||||||
| #git+https://github.com/ungleich/cdist.git#egg=cdist | cdist==4.7.0 | ||||||
| file:///home/app/cdist#egg=cdist |  | ||||||
|  |  | ||||||
|  | @ -18,7 +18,8 @@ class SignupFormMixin(forms.ModelForm): | ||||||
|         model = CustomUser |         model = CustomUser | ||||||
|         fields = ['name', 'email', 'password'] |         fields = ['name', 'email', 'password'] | ||||||
|         widgets = { |         widgets = { | ||||||
|             'name': forms.TextInput(attrs={'placeholder': _('Enter your name or company name')}), |             'name': forms.TextInput( | ||||||
|  |                 attrs={'placeholder': _('Enter your name or company name')}), | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     def clean_confirm_password(self): |     def clean_confirm_password(self): | ||||||
|  | @ -42,7 +43,7 @@ class LoginFormMixin(forms.Form): | ||||||
|         is_auth = authenticate(email=email, password=password) |         is_auth = authenticate(email=email, password=password) | ||||||
|         if not is_auth: |         if not is_auth: | ||||||
|             raise forms.ValidationError( |             raise forms.ValidationError( | ||||||
|                 "Your username and/or password were incorrect.") |                 _("Your username and/or password were incorrect.")) | ||||||
|         return self.cleaned_data |         return self.cleaned_data | ||||||
| 
 | 
 | ||||||
|     def clean_email(self): |     def clean_email(self): | ||||||
|  | @ -51,7 +52,24 @@ class LoginFormMixin(forms.Form): | ||||||
|             CustomUser.objects.get(email=email) |             CustomUser.objects.get(email=email) | ||||||
|             return email |             return email | ||||||
|         except CustomUser.DoesNotExist: |         except CustomUser.DoesNotExist: | ||||||
|             raise forms.ValidationError("User does not exist") |             raise forms.ValidationError(_("User does not exist")) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ResendActivationEmailForm(forms.Form): | ||||||
|  |     email = forms.CharField(widget=forms.EmailInput()) | ||||||
|  | 
 | ||||||
|  |     class Meta: | ||||||
|  |         fields = ['email'] | ||||||
|  | 
 | ||||||
|  |     def clean_email(self): | ||||||
|  |         email = self.cleaned_data.get('email') | ||||||
|  |         try: | ||||||
|  |             c = CustomUser.objects.get(email=email) | ||||||
|  |             if c.validated == 1: | ||||||
|  |                 raise forms.ValidationError(_("The account is already active.")) | ||||||
|  |             return email | ||||||
|  |         except CustomUser.DoesNotExist: | ||||||
|  |             raise forms.ValidationError(_("User does not exist")) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class PasswordResetRequestForm(forms.Form): | class PasswordResetRequestForm(forms.Form): | ||||||
|  | @ -66,7 +84,7 @@ class PasswordResetRequestForm(forms.Form): | ||||||
|             CustomUser.objects.get(email=email) |             CustomUser.objects.get(email=email) | ||||||
|             return email |             return email | ||||||
|         except CustomUser.DoesNotExist: |         except CustomUser.DoesNotExist: | ||||||
|             raise forms.ValidationError("User does not exist") |             raise forms.ValidationError(_("User does not exist")) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class SetPasswordForm(forms.Form): | class SetPasswordForm(forms.Form): | ||||||
|  | @ -75,11 +93,11 @@ class SetPasswordForm(forms.Form): | ||||||
|     password |     password | ||||||
|     """ |     """ | ||||||
|     error_messages = { |     error_messages = { | ||||||
|         'password_mismatch': ("The two password fields didn't match."), |         'password_mismatch': _("The two password fields didn't match."), | ||||||
|     } |     } | ||||||
|     new_password1 = forms.CharField(label=("New password"), |     new_password1 = forms.CharField(label=_("New password"), | ||||||
|                                     widget=forms.PasswordInput) |                                     widget=forms.PasswordInput) | ||||||
|     new_password2 = forms.CharField(label=("New password confirmation"), |     new_password2 = forms.CharField(label=_("New password confirmation"), | ||||||
|                                     widget=forms.PasswordInput) |                                     widget=forms.PasswordInput) | ||||||
| 
 | 
 | ||||||
|     def clean_new_password2(self): |     def clean_new_password2(self): | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ msgid "" | ||||||
| msgstr "" | msgstr "" | ||||||
| "Project-Id-Version: PACKAGE VERSION\n" | "Project-Id-Version: PACKAGE VERSION\n" | ||||||
| "Report-Msgid-Bugs-To: \n" | "Report-Msgid-Bugs-To: \n" | ||||||
| "POT-Creation-Date: 2017-09-02 11:50+0000\n" | "POT-Creation-Date: 2017-09-25 20:11+0000\n" | ||||||
| "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||||
| "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||||
| "Language-Team: LANGUAGE <LL@li.org>\n" | "Language-Team: LANGUAGE <LL@li.org>\n" | ||||||
|  | @ -738,6 +738,24 @@ msgstr "" | ||||||
| msgid "Enter your name or company name" | msgid "Enter your name or company name" | ||||||
| msgstr "Geben Sie Ihren Namen oder der Ihrer Firma ein" | msgstr "Geben Sie Ihren Namen oder der Ihrer Firma ein" | ||||||
| 
 | 
 | ||||||
|  | msgid "Your username and/or password were incorrect." | ||||||
|  | msgstr "Dein Benutzername und/oder Dein Passwort ist falsch." | ||||||
|  | 
 | ||||||
|  | msgid "User does not exist" | ||||||
|  | msgstr "Der Benutzer existiert nicht" | ||||||
|  | 
 | ||||||
|  | msgid "The account is already active." | ||||||
|  | msgstr "Das Benutzerkonto ist bereits aktiv." | ||||||
|  | 
 | ||||||
|  | msgid "The two password fields didn't match." | ||||||
|  | msgstr "Die beiden Passwörter stimmen nicht überein." | ||||||
|  | 
 | ||||||
|  | msgid "New password" | ||||||
|  | msgstr "Neues Passwort" | ||||||
|  | 
 | ||||||
|  | msgid "New password confirmation" | ||||||
|  | msgstr "Neues Passwort Bestätigung" | ||||||
|  | 
 | ||||||
| msgid "Cardholder Name" | msgid "Cardholder Name" | ||||||
| msgstr "Name des Kartenbesitzer" | msgstr "Name des Kartenbesitzer" | ||||||
| 
 | 
 | ||||||
|  | @ -768,8 +786,16 @@ msgstr "Telefon" | ||||||
| msgid "Message" | msgid "Message" | ||||||
| msgstr "Nachricht" | msgstr "Nachricht" | ||||||
| 
 | 
 | ||||||
|  | msgid "An email with the activation link has been sent to your email" | ||||||
|  | msgstr "" | ||||||
|  | "Der Link zum Zurücksetzen deines Passwortes wurde an deine E-Mail gesendet" | ||||||
|  | 
 | ||||||
|  | msgid "Account Activation" | ||||||
|  | msgstr "Accountaktivierung" | ||||||
|  | 
 | ||||||
| msgid "The link to reset your email has been sent to your email" | msgid "The link to reset your email has been sent to your email" | ||||||
| msgstr "Der Link zum Zurücksetzen deines Passwortes wurde an deine E-Mail gesendet" | msgstr "" | ||||||
|  | "Der Link zum Zurücksetzen deines Passwortes wurde an deine E-Mail gesendet" | ||||||
| 
 | 
 | ||||||
| msgid "Password Reset" | msgid "Password Reset" | ||||||
| msgstr "Passwort zurücksetzen" | msgstr "Passwort zurücksetzen" | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ from django.conf import settings | ||||||
| from django.contrib import messages | from django.contrib import messages | ||||||
| from django.contrib.auth import authenticate, login | from django.contrib.auth import authenticate, login | ||||||
| from django.contrib.auth.tokens import default_token_generator | from django.contrib.auth.tokens import default_token_generator | ||||||
|  | from django.core.urlresolvers import reverse_lazy | ||||||
| from django.http import HttpResponseRedirect | from django.http import HttpResponseRedirect | ||||||
| from django.utils.encoding import force_bytes | from django.utils.encoding import force_bytes | ||||||
| from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode | from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode | ||||||
|  | @ -63,9 +64,45 @@ class LoginViewMixin(FormView): | ||||||
|         return super(LoginViewMixin, self).get(request, *args, **kwargs) |         return super(LoginViewMixin, self).get(request, *args, **kwargs) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class ResendActivationLinkViewMixin(FormView): | ||||||
|  |     success_message = _( | ||||||
|  |         "An email with the activation link has been sent to your email") | ||||||
|  | 
 | ||||||
|  |     def generate_email_context(self, user): | ||||||
|  |         context = { | ||||||
|  |             'base_url': "{0}://{1}".format(self.request.scheme, | ||||||
|  |                                            self.request.get_host()), | ||||||
|  |             'activation_link': reverse_lazy( | ||||||
|  |                 'hosting:validate', | ||||||
|  |                 kwargs={'validate_slug': user.validation_slug} | ||||||
|  |             ), | ||||||
|  |             'dcl_text': settings.DCL_TEXT, | ||||||
|  |         } | ||||||
|  |         return context | ||||||
|  | 
 | ||||||
|  |     def form_valid(self, form): | ||||||
|  |         email = form.cleaned_data.get('email') | ||||||
|  |         user = CustomUser.objects.get(email=email) | ||||||
|  |         messages.add_message(self.request, messages.SUCCESS, | ||||||
|  |                              self.success_message) | ||||||
|  |         context = self.generate_email_context(user) | ||||||
|  |         email_data = { | ||||||
|  |             'subject': '{dcl_text} {account_activation}'.format( | ||||||
|  |                 dcl_text=settings.DCL_TEXT, | ||||||
|  |                 account_activation=_('Account Activation') | ||||||
|  |             ), | ||||||
|  |             'to': email, | ||||||
|  |             'context': context, | ||||||
|  |             'template_name': self.email_template_name, | ||||||
|  |             'template_path': self.email_template_path, | ||||||
|  |             'from_address': settings.DCL_SUPPORT_FROM_ADDRESS | ||||||
|  |         } | ||||||
|  |         email = BaseEmail(**email_data) | ||||||
|  |         email.send() | ||||||
|  |         return HttpResponseRedirect(self.get_success_url()) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class PasswordResetViewMixin(FormView): | class PasswordResetViewMixin(FormView): | ||||||
|     # template_name = 'hosting/reset_password.html' |  | ||||||
|     # form_class = PasswordResetRequestForm |  | ||||||
|     success_message = _( |     success_message = _( | ||||||
|         "The link to reset your email has been sent to your email") |         "The link to reset your email has been sent to your email") | ||||||
|     site = '' |     site = '' | ||||||
|  | @ -78,7 +115,6 @@ class PasswordResetViewMixin(FormView): | ||||||
|             'site_name': 'ungleich' if self.site != 'dcl' else settings.DCL_TEXT, |             'site_name': 'ungleich' if self.site != 'dcl' else settings.DCL_TEXT, | ||||||
|             'base_url': "{0}://{1}".format(self.request.scheme, |             'base_url': "{0}://{1}".format(self.request.scheme, | ||||||
|                                            self.request.get_host()) |                                            self.request.get_host()) | ||||||
| 
 |  | ||||||
|         } |         } | ||||||
|         return context |         return context | ||||||
| 
 | 
 | ||||||
|  | @ -104,11 +140,8 @@ class PasswordResetViewMixin(FormView): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class PasswordResetConfirmViewMixin(FormView): | class PasswordResetConfirmViewMixin(FormView): | ||||||
|     # template_name = 'hosting/confirm_reset_password.html' |  | ||||||
|     form_class = SetPasswordForm |     form_class = SetPasswordForm | ||||||
| 
 | 
 | ||||||
|     # success_url = reverse_lazy('hosting:login') |  | ||||||
| 
 |  | ||||||
|     def post(self, request, uidb64=None, token=None, *arg, **kwargs): |     def post(self, request, uidb64=None, token=None, *arg, **kwargs): | ||||||
|         try: |         try: | ||||||
|             uid = urlsafe_base64_decode(uidb64) |             uid = urlsafe_base64_decode(uidb64) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue