#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2010-2013 Étienne Loks # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # See the file COPYING for details. """ Administrative forms definitions: manage accounts and persons """ import datetime from django import forms from django.conf import settings from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.core import validators from django.core.mail import send_mail from django.core.exceptions import ObjectDoesNotExist from django.forms.formsets import formset_factory, DELETION_FIELD_NAME from django.template import Context, RequestContext, loader from django.shortcuts import render_to_response from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ import models import widgets from forms import FinalForm, FormSet, reverse_lazy, name_validator, TableSelect def get_town_field(label=_(u"Town"), required=True): help_text = _(u"

Type name, department code and/or postal code of the " u"town you would like to select. The search is insensitive to case.

\n" u"

Only the first twenty results are displayed but specifying the " u"department code is generally sufficient to get the appropriate result.

" u"\n

For instance type \"saint denis 93\" for getting " u"the french town Saint-Denis in the Seine-Saint-Denis department.

") # !FIXME hard_link, reverse_lazy doen't seem to work with formsets return forms.IntegerField( widget=widgets.JQueryAutoComplete("/" + settings.URL_PATH + \ 'autocomplete-town', associated_model=models.Town), validators=[models.valid_id(models.Town)], label=label, help_text=mark_safe(help_text), required=required) def get_person_field(label=_(u"Person"), required=True, person_types=[]): # !FIXME hard_link, reverse_lazy doen't seem to work with formsets widget = None url = "/" + settings.URL_PATH + 'autocomplete-person' if person_types: person_types = [ unicode(models.PersonType.objects.get(txt_idx=person_type).pk) for person_type in person_types] url += u"/" + u'_'.join(person_types) widget = widgets.JQueryAutoComplete(url, associated_model=models.Person) return forms.IntegerField(widget=widget, label=label, required=required, validators=[models.valid_id(models.Person)]) class OrganizationForm(forms.Form): name = forms.CharField(label=_(u"Name"), max_length=40, validators=[name_validator]) organization_type = forms.ChoiceField(label=_(u"Organization type"), choices=[]) address = forms.CharField(label=_(u"Address"), widget=forms.Textarea, required=False) address_complement = forms.CharField(label=_(u"Address complement"), widget=forms.Textarea, required=False) postal_code = forms.CharField(label=_(u"Postal code"), max_length=10, required=False) town = forms.CharField(label=_(u"Town"), max_length=30, required=False) country = forms.CharField(label=_(u"Country"), max_length=30, required=False) phone = forms.CharField(label=_(u"Phone"), max_length=18, required=False) mobile_phone = forms.CharField(label=_(u"Town"), max_length=18, required=False) def __init__(self, *args, **kwargs): super(OrganizationForm, self).__init__(*args, **kwargs) self.fields['organization_type'].choices = \ models.OrganizationType.get_types() self.fields['organization_type'].help_text = \ models.OrganizationType.get_help() def save(self, user): dct = self.cleaned_data dct['history_modifier'] = user dct['organization_type'] = models.OrganizationType.objects.get( pk=dct['organization_type']) new_item = models.Organization(**dct) new_item.save() return new_item class PersonSelect(TableSelect): name = forms.CharField(label=_(u"Name"), max_length=30) surname = forms.CharField(label=_(u"Surname"), max_length=20) email = forms.CharField(label=_(u"Email"), max_length=40) person_types = forms.ChoiceField(label=_(u"Type"), choices=[]) attached_to = forms.IntegerField(label=_("Organization"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-organization'), associated_model=models.Organization), validators=[models.valid_id(models.Organization)]) def __init__(self, *args, **kwargs): super(PersonSelect, self).__init__(*args, **kwargs) self.fields['person_types'].choices = models.PersonType.get_types() class PersonFormSelection(forms.Form): form_label = _(u"Person search") associated_models = {'pk':models.Person} currents = {'pk':models.Person} pk = forms.IntegerField(label="", widget=widgets.JQueryJqGrid(reverse_lazy('get-person'), PersonSelect, models.Person), validators=[models.valid_id(models.Person)]) class PersonForm(forms.Form): form_label = _("Identity") associated_models = {'attached_to':models.Organization} title = forms.ChoiceField(label=_("Title"), choices=models.Person.TYPE) surname = forms.CharField(label=_(u"Surname"), max_length=20, validators=[name_validator]) name = forms.CharField(label=_(u"Name"), max_length=30, validators=[name_validator]) email = forms.CharField(label=_(u"Email"), max_length=40, required=False, validators=[validators.validate_email]) attached_to = forms.IntegerField(label=_("Current organization"), widget=widgets.JQueryAutoComplete( reverse_lazy('autocomplete-organization'), associated_model=models.Organization, new=True), validators=[models.valid_id(models.Organization)], required=False) def save(self, user): dct = self.cleaned_data dct['history_modifier'] = user if 'attached_to' in dct and dct['attached_to']: dct['attached_to'] = models.Organization.objects.get( pk=dct['attached_to']) new_item = models.Person(**dct) new_item.save() return new_item class PersonTypeForm(forms.Form): form_label = _("Person type") base_model = 'person_type' associated_models = {'person_type':models.PersonType} person_type = forms.MultipleChoiceField(label=_("Person type"), choices=[], widget=forms.CheckboxSelectMultiple) def __init__(self, *args, **kwargs): super(PersonTypeForm, self).__init__(*args, **kwargs) self.fields['person_type'].choices = models.PersonType.get_types( empty_first=False) self.fields['person_type'].help_text = models.PersonType.get_help() class AccountForm(forms.Form): form_label = _("Account") associated_models = {'pk':models.Person} currents = {'pk':models.Person} pk = forms.IntegerField(label=u"", widget=forms.HiddenInput, required=False) username = forms.CharField(label=_(u"Account"), max_length=30) email = forms.CharField(label=_(u"Email"), max_length=75, validators=[validators.validate_email]) hidden_password = forms.CharField(label=_(u"New password"), max_length=128, widget=forms.PasswordInput, required=False, validators=[validators.MinLengthValidator(4)]) hidden_password_confirm = forms.CharField( label=_(u"New password (confirmation)"), max_length=128, widget=forms.PasswordInput, required=False) def __init__(self, *args, **kwargs): if 'initial' in kwargs and 'pk' in kwargs['initial']: try: person = models.Person.objects.get(pk=kwargs['initial']['pk']) account = models.IshtarUser.objects.get(person=person) kwargs['initial'].update({'username':account.username, 'email':account.email}) except ObjectDoesNotExist: pass return super(AccountForm, self).__init__(*args, **kwargs) def clean(self): cleaned_data = self.cleaned_data password = cleaned_data.get("hidden_password") if password and password != cleaned_data.get("hidden_password_confirm"): raise forms.ValidationError(_(u"Your password and confirmation " u"password do not match.")) if not cleaned_data.get("pk"): models.is_unique(User, 'username')(cleaned_data.get("username")) if not password: raise forms.ValidationError(_(u"You must provide a correct "\ u"password.")) # check username unicity usernames = models.IshtarUser.objects.filter(username= cleaned_data.get('username')) if cleaned_data.get('pk'): usernames.exclude(pk=cleaned_data.get('pk')) if usernames.count(): raise forms.ValidationError(_(u"This username already exists.")) return cleaned_data class FinalAccountForm(forms.Form): final = True form_label = _("Confirm") send_password = forms.BooleanField(label=_(u"Send the new password by " u"email?"), required=False) def __init__(self, *args, **kwargs): self.is_hidden = True return super(FinalAccountForm, self).__init__(*args, **kwargs) class TownForm(forms.Form): form_label = _("Towns") base_model = 'town' associated_models = {'town':models.Town} town = get_town_field(required=False) class TownFormSet(FormSet): def clean(self): """Checks that no towns are duplicated.""" return self.check_duplicate(('town',), _("There are identical towns.")) TownFormset = formset_factory(TownForm, can_delete=True, formset=TownFormSet) TownFormset.form_label = _("Towns") ###################### # Sources management # ###################### class SourceForm(forms.Form): form_label = _(u"Documentation informations") associated_models = {'source_type':models.SourceType} title = forms.CharField(label=_(u"Title"), validators=[validators.MaxLengthValidator(200)]) source_type = forms.ChoiceField(label=_(u"Source type"), choices=[]) associated_url = forms.URLField(required=False, label=_(u"Numerical ressource (web address)")) receipt_date = forms.DateField(label=_(u"Receipt date"), required=False, widget=widgets.JQueryDate) creation_date = forms.DateField(label=_(u"Creation date"), required=False, widget=widgets.JQueryDate) def __init__(self, *args, **kwargs): super(SourceForm, self).__init__(*args, **kwargs) self.fields['source_type'].choices = models.SourceType.get_types() class SourceSelect(TableSelect): authors = forms.IntegerField( widget=widgets.JQueryAutoComplete("/" + settings.URL_PATH + \ 'autocomplete-author', associated_model=models.Author), validators=[models.valid_id(models.Author)], label=_(u"Author"), required=False) source_type = forms.ChoiceField(label=_("Source type"), choices=[]) def __init__(self, *args, **kwargs): super(SourceSelect, self).__init__(*args, **kwargs) self.fields['source_type'].choices = models.SourceType.get_types() self.fields['source_type'].help_text = models.SourceType.get_help() class SourceDeletionForm(FinalForm): confirm_msg = " " confirm_end_msg = _(u"Would you like to delete this documentation?") ###################### # Authors management # ###################### class AuthorForm(forms.Form): form_label = _(u"Author") associated_models = {'person':models.Person, 'author_type':models.AuthorType} person = forms.IntegerField( widget=widgets.JQueryAutoComplete("/" + settings.URL_PATH + \ 'autocomplete-person', associated_model=models.Person, new=True), validators=[models.valid_id(models.Person)], label=_(u"Person")) author_type = forms.ChoiceField(label=_(u"Author type"), choices=[]) def __init__(self, *args, **kwargs): super(AuthorForm, self).__init__(*args, **kwargs) self.fields['author_type'].choices = models.AuthorType.get_types() def save(self, user): dct = self.cleaned_data dct['author_type'] = models.AuthorType.objects.get( pk=dct['author_type']) dct['person'] = models.Person.objects.get(pk=dct['person']) new_item = models.Author(**dct) new_item.save() return new_item class AuthorFormSelection(forms.Form): form_label = _(u"Author selection") base_model = 'author' associated_models = {'author':models.Author} author = forms.IntegerField( widget=widgets.JQueryAutoComplete("/" + settings.URL_PATH + \ 'autocomplete-author', associated_model=models.Author, new=True), validators=[models.valid_id(models.Author)], label=_(u"Author")) class AuthorFormSet(FormSet): def clean(self): """Checks that no author are duplicated.""" return self.check_duplicate(('author',), _("There are identical authors.")) AuthorFormset = formset_factory(AuthorFormSelection, can_delete=True, formset=AuthorFormSet) AuthorFormset.form_label = _("Authors")