__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" import datetime from django import forms from django.contrib.auth.models import User from django.contrib.auth.password_validation import validate_password from django.core.exceptions import ValidationError from django.db import transaction from django.utils import timezone from .constants import ROLE_GENERAL from .models import Contact, ContactRole from scipost.constants import TITLE_CHOICES class ContactForm(forms.ModelForm): """ This Contact form is mainly used for editing Contact instances. """ class Meta: model = Contact fields = ['title', 'key_expires'] class NewContactForm(ContactForm): """ This Contact form is used to create new Contact instances, as it will also handle possible sending and activation of User instances coming with the new Contact. """ title = forms.ChoiceField(choices=TITLE_CHOICES, label='Title') first_name = forms.CharField() last_name = forms.CharField() email = forms.CharField() existing_user = None def __init__(self, *args, **kwargs): """ Organization is a required argument to tell the formset which Organization the Contact is being edited for in the current form. """ self.organization = kwargs.pop('organization') super().__init__(*args, **kwargs) def clean_email(self): """ Check if User already is known in the system. """ email = self.cleaned_data['email'] try: self.existing_user = User.objects.get(email=email) if not self.data.get('confirm_use_existing', '') == 'on': # Do not give error if user wants to use existing User self.add_error('email', 'This User is already registered.') self.fields['confirm_use_existing'] = forms.BooleanField( required=False, initial=False, label='Use the existing user instead: %s %s' % (self.existing_user.first_name, self.existing_user.last_name)) except User.DoesNotExist: pass return email @transaction.atomic def save(self, current_user, commit=True): """ If existing user is found, link it to the Organization. """ if self.existing_user and self.data.get('confirm_use_existing', '') == 'on': # Create new Contact if it doesn't already exist try: # Link Contact to new Organization contact = self.existing_user.org_contact except Contact.DoesNotExist: # Not yet a 'Contact-User' contact = super().save(commit=False) contact.title = self.existing_user.org_contact.title contact.user = self.existing_user contact.save() return contact # Create complete new Account (User + Contact) user = User( first_name=self.cleaned_data['first_name'], last_name=self.cleaned_data['last_name'], email=self.cleaned_data['email'], username=self.cleaned_data['email'], is_active=False, ) user.save() contact = Contact( user=user, title=self.cleaned_data['title'] ) contact.generate_key() contact.save() # Create the role with to-be-updated info contactrole = ContactRole( contact=contact, organization=self.organization, kind=[ROLE_GENERAL,], date_from=timezone.now(), date_until=timezone.now() + datetime.timedelta(days=3650) ) contactrole.save() return contact class ContactActivationForm(forms.ModelForm): class Meta: model = User fields = [] password_new = forms.CharField(label='* Password', widget=forms.PasswordInput()) password_verif = forms.CharField(label='* Verify password', widget=forms.PasswordInput(), help_text='Your password must contain at least 8 characters') def clean(self, *args, **kwargs): try: self.instance.org_contact except Contact.DoesNotExist: self.add_error(None, 'Your account is invalid, please contact the administrator.') return super().clean(*args, **kwargs) def clean_password(self): password = self.cleaned_data.get('password_new', '') try: validate_password(password, self.instance) except ValidationError as error_message: self.add_error('password_new', error_message) return password def clean_password_verif(self): if self.cleaned_data.get('password_new', '') != self.cleaned_data.get('password_verif', ''): self.add_error('password_verif', 'Your password entries must match') return self.cleaned_data.get('password_verif', '') @transaction.atomic def activate_user(self): if self.errors: return forms.ValidationError # Activate account self.instance.is_active = True self.instance.set_password(self.cleaned_data['password_new']) self.instance.save() return self.instance