from django import forms from .models import CustomUser, BillingAddress, UserBillingAddress from django.utils.translation import gettext_lazy as _ import datetime import logging import subprocess import tempfile import xml from django import forms from django.conf import settings from django.contrib.auth import authenticate from django.utils.translation import gettext_lazy as _ from .models import CustomUser from .models import UserHostingKey, GenericProduct logger = logging.getLogger(__name__) 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): email = forms.CharField(widget=forms.EmailInput()) class Meta: fields = ['email'] def clean_email(self): email = self.cleaned_data.get('email') try: CustomUser.objects.get(email=email) return email except CustomUser.DoesNotExist: raise forms.ValidationError(_("User does not exist")) class SetPasswordForm(forms.Form): """ A form that lets a user change set their password without entering the old password """ error_messages = { 'password_mismatch': _("The two password fields didn't match."), } new_password1 = forms.CharField(label=_("New password"), widget=forms.PasswordInput) new_password2 = forms.CharField(label=_("New password confirmation"), widget=forms.PasswordInput) def clean_new_password2(self): password1 = self.cleaned_data.get('new_password1') password2 = self.cleaned_data.get('new_password2') if password1 and password2: if password1 != password2: raise forms.ValidationError( self.error_messages['password_mismatch'], code='password_mismatch', ) return password2 class EditCreditCardForm(forms.Form): token = forms.CharField(widget=forms.HiddenInput()) class BillingAddressForm(forms.ModelForm): token = forms.CharField(widget=forms.HiddenInput(), required=False) card = forms.CharField(widget=forms.HiddenInput(), required=False) class Meta: model = BillingAddress fields = ['cardholder_name', 'street_address', 'city', 'postal_code', 'country', 'vat_number'] labels = { 'cardholder_name': _('Cardholder Name'), 'street_address': _('Street Address'), 'city': _('City'), 'postal_code': _('Postal Code'), 'Country': _('Country'), 'VAT Number': _('VAT Number') } class BillingAddressFormSignup(BillingAddressForm): name = forms.CharField(label=_('Name')) email = forms.EmailField(label=_('Email Address')) field_order = ['name', 'email'] class Meta: model = BillingAddress fields = ['name', 'email', 'cardholder_name', 'street_address', 'city', 'postal_code', 'country', 'vat_number'] labels = { 'name': 'Name', 'email': _('Email'), 'cardholder_name': _('Cardholder Name'), 'street_address': _('Street Address'), 'city': _('City'), 'postal_code': _('Postal Code'), 'Country': _('Country'), 'vat_number': _('VAT Number') } def clean_email(self): email = self.cleaned_data.get('email') try: CustomUser.objects.get(email=email) raise forms.ValidationError( _("The email %(email)s is already registered with us. " "Please reset your password and access your account.") % {'email': email} ) except CustomUser.DoesNotExist: return email class UserBillingAddressForm(forms.ModelForm): user = forms.ModelChoiceField(queryset=CustomUser.objects.all(), widget=forms.HiddenInput()) class Meta: model = UserBillingAddress fields = ['cardholder_name', 'street_address', 'city', 'postal_code', 'country', 'user', 'vat_number'] labels = { 'cardholder_name': _('Cardholder Name'), 'street_address': _('Street Building'), 'city': _('City'), 'postal_code': _('Postal Code'), 'Country': _('Country'), 'vat_number': _('VAT Number'), } def generate_ssh_key_name(): return '{prefix}{date_time_str}'.format( prefix=settings.DCL_SSH_KEY_NAME_PREFIX, date_time_str=datetime.datetime.now().strftime('%m%d%y%H%M%S') ) class HostingUserLoginForm(forms.Form): email = forms.CharField(widget=forms.EmailInput()) password = forms.CharField(widget=forms.PasswordInput()) class Meta: fields = ['email', 'password'] def clean(self): email = self.cleaned_data.get('email') password = self.cleaned_data.get('password') if self.errors: return self.cleaned_data is_auth = authenticate(email=email, password=password) if not is_auth: raise forms.ValidationError( _("Your username and/or password were incorrect.")) elif is_auth.validated == 0: raise forms.ValidationError( _("Your account is not activated yet.")) return self.cleaned_data def clean_email(self): email = self.cleaned_data.get('email') try: CustomUser.objects.get(email=email) return email except CustomUser.DoesNotExist: raise forms.ValidationError(_("User does not exist")) class ProductModelChoiceField(forms.ModelChoiceField): def label_from_instance(self, obj): return obj.product_name class GenericPaymentForm(forms.Form): product_name = ProductModelChoiceField( queryset=GenericProduct.objects.all().order_by('product_name'), empty_label=_("Choose a product"), ) amount = forms.FloatField( widget=forms.TextInput( attrs={'placeholder': _('Amount in CHF'), 'readonly': 'readonly', } ), max_value=999999, min_value=1, label=_('Amount in CHF') ) recurring = forms.BooleanField(required=False, label=_("Recurring monthly"), ) description = forms.CharField( widget=forms.Textarea(attrs={'style': "height: 60px;"}), required=False ) class Meta: model = GenericProduct fields = ['product_name', 'amount', 'recurring', 'description'] def clean_amount(self): amount = self.cleaned_data.get('amount') if (float(self.cleaned_data.get('product_name').get_actual_price()) != amount): raise forms.ValidationError(_("Amount field does not match")) return amount def clean_recurring(self): recurring = self.cleaned_data.get('recurring') if (self.cleaned_data.get('product_name').product_is_subscription != (True if recurring else False)): raise forms.ValidationError(_("Recurring field does not match")) return recurring class ProductPaymentForm(GenericPaymentForm): def __init__(self, *args, **kwargs): product_id = kwargs.pop('product_id', None) if product_id is not None: self.product = GenericProduct.objects.get(id=product_id) super(ProductPaymentForm, self).__init__(*args, **kwargs) self.fields['product_name'] = forms.CharField( widget=forms.TextInput( attrs={'placeholder': _('Product name'), 'readonly': 'readonly'} ) ) if self.product.product_is_subscription: payment_type = "month" if self.product.product_subscription_interval == "month": payment_type = _('Monthly subscription') elif self.product.product_subscription_interval == "year": payment_type = _('Yearly subscription') self.fields['amount'].label = "{amt} ({payment_type})".format( amt=_('Amount in CHF'), payment_type=payment_type ) else: self.fields['amount'].label = "{amt} ({payment_type})".format( amt=_('Amount in CHF'), payment_type=_('One time payment') ) self.fields['recurring'].widget = forms.HiddenInput() self.fields['product_name'].widget.attrs['class'] = 'input-no-border' self.fields['amount'].widget.attrs['class'] = 'input-no-border' self.fields['description'].widget.attrs['class'] = 'input-no-border' def clean_amount(self): amount = self.cleaned_data.get('amount') if (self.product is None or float(self.product.get_actual_price()) != amount): raise forms.ValidationError(_("Amount field does not match")) return amount def clean_recurring(self): recurring = self.cleaned_data.get('recurring') if (self.product.product_is_subscription != (True if recurring else False)): raise forms.ValidationError(_("Recurring field does not match")) return recurring class HostingUserSignupForm(forms.ModelForm): confirm_password = forms.CharField(label=_("Confirm Password"), widget=forms.PasswordInput()) password = forms.CharField(label=_("Password"), widget=forms.PasswordInput()) class Meta: model = CustomUser fields = ['name', 'email', 'password'] widgets = { 'name': forms.TextInput( attrs={'placeholder': _('Enter your name or company name')}), } def clean_confirm_password(self): password = self.cleaned_data.get('password') confirm_password = self.cleaned_data.get('confirm_password') if not confirm_password == password: raise forms.ValidationError("Passwords don't match") return confirm_password class UserHostingKeyForm(forms.ModelForm): private_key = forms.CharField(widget=forms.HiddenInput(), required=False) public_key = forms.CharField(widget=forms.Textarea( attrs={'class': 'form_public_key', 'placeholder': _('Paste here your public key')}), required=False, ) user = forms.models.ModelChoiceField(queryset=CustomUser.objects.all(), required=False, widget=forms.HiddenInput()) name = forms.CharField(required=False, widget=forms.TextInput( attrs={'class': 'form_key_name', 'placeholder': _('Give a name to your key')})) def __init__(self, *args, **kwargs): self.request = kwargs.pop("request") super(UserHostingKeyForm, self).__init__(*args, **kwargs) self.fields['name'].label = _('Key name') def clean_public_key(self): """ Validates a public ssh key using `ssh-keygen -lf key.pub` Also checks if a given key already exists in the database and alerts the user of it. :return: """ if ('generate' in self.request.POST or not self.fields['public_key'].required): return self.data.get('public_key') KEY_ERROR_MESSAGE = _("Please input a proper SSH key") openssh_pubkey_str = self.data.get('public_key').strip() with tempfile.NamedTemporaryFile(delete=True) as tmp_public_key_file: tmp_public_key_file.write(openssh_pubkey_str.encode('utf-8')) tmp_public_key_file.flush() try: subprocess.check_output( ['ssh-keygen', '-lf', tmp_public_key_file.name]) except subprocess.CalledProcessError as cpe: logger.debug( "Not a correct ssh format {error}".format(error=str(cpe))) raise forms.ValidationError(KEY_ERROR_MESSAGE) return xml.sax.saxutils.escape(openssh_pubkey_str) def clean_name(self): INVALID_NAME_MESSAGE = _("Comma not accepted in the name of the key") if "," in self.data.get('name'): logger.debug(INVALID_NAME_MESSAGE) raise forms.ValidationError(INVALID_NAME_MESSAGE) return self.data.get('name') def clean_user(self): return self.request.user if self.request.user.is_authenticated else None def clean(self): cleaned_data = self.cleaned_data if 'generate' in self.request.POST: self.cleaned_data['name'] = generate_ssh_key_name() private_key, public_key = UserHostingKey.generate_keys() cleaned_data.update({ 'private_key': private_key, 'public_key': public_key }) return cleaned_data class Meta: model = UserHostingKey fields = ['user', 'name', 'public_key']