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…
Reference in a new issue