Merge remote-tracking branch 'ungleich/master'

This commit is contained in:
Arvind Tiwari 2017-09-26 02:53:25 +05:30
commit b782c6212a
10 changed files with 154 additions and 24 deletions

View file

@ -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

View file

@ -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"

View file

@ -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>

View 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 %}

View file

@ -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>.+)/$',

View file

@ -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'

View file

@ -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

View file

@ -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):

View file

@ -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"

View file

@ -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)