diff options
Diffstat (limited to 'ishtar/ishtar_base/forms_common.py')
| -rw-r--r-- | ishtar/ishtar_base/forms_common.py | 467 | 
1 files changed, 467 insertions, 0 deletions
| diff --git a/ishtar/ishtar_base/forms_common.py b/ishtar/ishtar_base/forms_common.py new file mode 100644 index 000000000..aff263a3b --- /dev/null +++ b/ishtar/ishtar_base/forms_common.py @@ -0,0 +1,467 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> + +# 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 <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Administrative forms definitions: manage accounts and persons +""" +import datetime + +from django import forms +from django.template import Context, RequestContext, loader +from django.shortcuts import render_to_response +from django.core import validators +from django.core.mail import send_mail +from django.core.exceptions import ObjectDoesNotExist +from django.utils.safestring import mark_safe +from django.forms.formsets import formset_factory, DELETION_FIELD_NAME +from django.utils.translation import ugettext_lazy as _ +from django.contrib.auth.models import User +from django.contrib.sites.models import Site + +from ishtar import settings + +import models +import widgets +from forms import Wizard, FinalForm, FormSet, reverse_lazy, name_validator + +def get_town_field(required=True): +    help_text = _(u"<p>Type name, department code and/or postal code of the " +    u"town you would like to select. The search is insensitive to case.</p>\n" +    u"<p>Only the first twenty results are displayed but specifying the " +    u"department code is generally sufficient to get the appropriate result.</p>" +    u"\n<p class='example'>For instance type \"saint denis 93\" for getting " +    u"the french town Saint-Denis in the Seine-Saint-Denis department.</p>") +    # !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=_(u"Town"), +         help_text=mark_safe(help_text), required=required) + +class WarehouseForm(forms.Form): +    name = forms.CharField(label=_(u"Name"), max_length=40, +                              validators=[name_validator]) +    warehouse_type = forms.ChoiceField(label=_(u"Warehouse type"), +                                       choices=[]) +    person_in_charge = forms.IntegerField(label=_(u"Person in charge"), +         widget=widgets.JQueryAutoComplete( +           reverse_lazy('autocomplete-person'), associated_model=models.Person), +           validators=[models.valid_id(models.Person)], +           required=False) +    comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea, +                              required=False) +    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(WarehouseForm, self).__init__(*args, **kwargs) +        self.fields['warehouse_type'].choices = \ +                                          models.WarehouseType.get_types() +        self.fields['warehouse_type'].help_text = \ +                                          models.WarehouseType.get_help() + +    def save(self, user): +        dct = self.cleaned_data +        dct['history_modifier'] = user +        dct['warehouse_type'] = models.WarehouseType.objects.get( +                                                     pk=dct['warehouse_type']) +        if 'person_in_charge' in dct and dct['person_in_charge']: +            dct['person_in_charge'] = models.Person.objects.get( +                                                     pk=dct['person_in_charge']) +        new_item = models.Warehouse(**dct) +        new_item.save() +        return new_item + +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 PersonWizard(Wizard): +    model = models.Person + +class PersonFormSelection(forms.Form): +    form_label = _(u"Person search") +    associated_models = {'pk':models.Person} +    currents = {'pk':models.Person} +    pk = forms.IntegerField(label=_("Person"), +         widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person'), +                                           associated_model=models.Person), +         validators=[models.valid_id(models.Person)]) + +class PersonForm(forms.Form): +    form_label = _("Identity") +    associated_models = {'attached_to':models.Organization, +                         'person_type':models.PersonType} +    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]) +    person_type = forms.ChoiceField(label=_("Person type"), +                                  choices=[]) +    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) +    is_author = forms.BooleanField(label=_(u"Is an author?"), +                                       required=False) +    in_charge_storage = forms.BooleanField(required=False, +                                       label=_(u"In charge of a storage?")) + +    def __init__(self, *args, **kwargs): +        super(PersonForm, self).__init__(*args, **kwargs) +        self.fields['person_type'].choices = models.PersonType.get_types() +        self.fields['person_type'].help_text = models.PersonType.get_help() + +    def save(self, user): +        dct = self.cleaned_data +        dct['history_modifier'] = user +        dct['person_type'] = models.PersonType.objects.get( +                                                     pk=dct['person_type']) +        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 + +person_creation_wizard = PersonWizard([ +                        ('identity-person_creation', PersonForm), +                        ('final-person_creation', FinalForm)], +                         url_name='person_creation',) + + +person_modification_wizard = PersonWizard([ +                          ('selec-person_modification', PersonFormSelection), +                          ('identity-person_modification', PersonForm), +                          ('final-person_modification', FinalForm)], +                          url_name='person_modification',) + +class AccountWizard(Wizard): +    model = models.Person +    def get_formated_datas(self, forms): +        datas = super(AccountWizard, self).get_formated_datas(forms) +        for form in forms: +            if not hasattr(form, "cleaned_data"): +                continue +            for key in form.cleaned_data: +                if key == 'hidden_password' and form.cleaned_data[key]: +                    datas[-1][1].append((_("New password"), "*"*8)) +        return datas + +    def done(self, request, storage, form_list, **kwargs): +        ''' +        Save the account +        ''' +        dct = {} +        for form in form_list: +            if not form.is_valid(): +                return self.render(request, storage, form) +            associated_models = hasattr(form, 'associated_models') and \ +                                form.associated_models or {} +            if type(form.cleaned_data) == dict: +                for key in form.cleaned_data: +                    if key == 'pk': +                        continue +                    value = form.cleaned_data[key] +                    if key in associated_models and value: +                        value = associated_models[key].objects.get(pk=value) +                    dct[key] = value +        person = self.get_current_object(request, storage) +        if not person: +            return self.render(request, storage, form) +        for key in dct.keys(): +            if key.startswith('hidden_password'): +                dct['password'] = dct.pop(key) +        try: +            account = models.IshtarUser.objects.get(person=person) +            account.username = dct['username'] +            account.email = dct['email'] +        except ObjectDoesNotExist: +            now = datetime.datetime.now() +            account = models.IshtarUser(person=person, username=dct['username'], +                    email=dct['email'], first_name=person.surname, +                    last_name=person.name, is_staff=False, is_active=True, +                    is_superuser=False, last_login=now, date_joined=now) +        if dct['password']: +            account.set_password(dct['password']) +        account.save() + +        if 'send_password' in dct and dct['send_password'] and \ +           settings.ADMINS: +            site = Site.objects.get_current() + +            app_name = site and ("Ishtar - " + site.name) \ +                       or "Ishtar" +            context = Context({'login':dct['username'], +                               'password':dct['password'], +                               'app_name':app_name, +                               'site': site and site.domain or "" +                              }) +            t = loader.get_template('account_activation_email.txt') +            msg = t.render(context) +            subject = _(u"[%(app_name)s] Account creation/modification") % { +                                                           "app_name":app_name} +            send_mail(subject, msg, settings.ADMINS[0][1], +                      [dct['email']], fail_silently=True) +        res = render_to_response('wizard_done.html', {}, +                                  context_instance=RequestContext(request)) +        return res + +    def get_form(self, request, storage, step=None, data=None, files=None): +        """ +        Display the "Send email" field if necessary +        """ +        form = super(AccountWizard, self).get_form(request, storage, step, data, +                                                   files) +        if not hasattr(form, 'is_hidden'): +            return form +        if self.session_get_value(request, storage, +                               'account-account_management', 'hidden_password'): +            form.is_hidden = False +        return form + + +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 \ +password.")) +        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) + +account_management_wizard = AccountWizard([ +                        ('selec-account_management', PersonFormSelection), +                        ('account-account_management', AccountForm), +                        ('final-account_management', FinalAccountForm)], +                         url_name='account_management',) + +class TownForm(forms.Form): +    form_label = _("Towns") +    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") + +class ParcelForm(forms.Form): +    form_label = _("Parcels") +    base_model = 'parcel' +    associated_models = {'parcel':models.Parcel, 'town':models.Town} +    town = forms.ChoiceField(label=_("Town"), choices=(), required=False, +                             validators=[models.valid_id(models.Town)]) +    section = forms.CharField(label=_(u"Section"), required=False, +                             validators=[validators.MaxLengthValidator(4)]) +    parcel_number = forms.CharField(label=_(u"Parcel number"), required=False, +                             validators=[validators.MaxLengthValidator(6)]) +    year = forms.IntegerField(label=_("Year"), required=False, +                              initial=lambda:datetime.datetime.now().year, +                           validators=[validators.MinValueValidator(1900), +                                       validators.MaxValueValidator(2100)]) +    def __init__(self, *args, **kwargs): +        towns = None +        if 'data' in kwargs and 'TOWNS' in kwargs['data']: +            towns = kwargs['data']['TOWNS'] +            # clean data if not "real" data +            prefix_value = kwargs['prefix'] + '-town' +            if not [k for k in kwargs['data'].keys() +                    if k.startswith(prefix_value) and kwargs['data'][k]]: +                kwargs['data'] = None +                if 'files' in kwargs: +                    kwargs.pop('files') +        super(ParcelForm, self).__init__(*args, **kwargs) +        if towns: +            self.fields['town'].choices = [('', '--')] + towns + +    def clean(self): +        """Check required fields""" +        if any(self.errors): +            return +        if not self.cleaned_data or DELETION_FIELD_NAME in self.cleaned_data \ +           and self.cleaned_data[DELETION_FIELD_NAME]: +            return +        for key in ('town', 'parcel_number', 'year'): +            if not key in self.cleaned_data or not self.cleaned_data[key]: +                raise forms.ValidationError(_(u"All fields are required")) +        return self.cleaned_data + + +class ParcelFormSet(FormSet): +    def clean(self): +        """Checks that no parcels are duplicated.""" +        return self.check_duplicate(('town', 'parcel_number', 'year'), +                                    _(u"There are identical parcels.")) + +ParcelFormSet = formset_factory(ParcelForm, can_delete=True, +                                formset=ParcelFormSet) +ParcelFormSet.form_label = _(u"Parcels") + +# sources management + +class SourceWizard(Wizard): +    model = None +    def get_extra_model(self, dct, request, storage, form_list): +        dct = super(SourceWizard, self).get_extra_model(dct, request, storage, +                                                        form_list) +        if 'history_modifier' in dct: +            dct.pop('history_modifier') +        return dct + +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=[]) + +    def __init__(self, *args, **kwargs): +        super(SourceForm, self).__init__(*args, **kwargs) +        self.fields['source_type'].choices = models.SourceType.get_types() + +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") +    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") + | 
