diff options
| -rw-r--r-- | archaeological_context_records/forms.py | 12 | ||||
| -rw-r--r-- | archaeological_context_records/views.py | 1 | ||||
| -rw-r--r-- | archaeological_files/forms.py | 456 | ||||
| -rw-r--r-- | archaeological_files/models.py | 15 | ||||
| -rw-r--r-- | archaeological_files/views.py | 4 | ||||
| -rw-r--r-- | archaeological_files_pdl/forms.py | 43 | ||||
| -rw-r--r-- | archaeological_files_pdl/templates/ishtar/wizard/wizard_planningservice.html | 38 | ||||
| -rw-r--r-- | archaeological_files_pdl/views.py | 114 | ||||
| -rw-r--r-- | archaeological_files_pdl/wizards.py | 3 | ||||
| -rw-r--r-- | archaeological_finds/forms.py | 16 | ||||
| -rw-r--r-- | archaeological_finds/views.py | 44 | ||||
| -rw-r--r-- | archaeological_operations/forms.py | 6 | ||||
| -rw-r--r-- | ishtar_common/forms.py | 63 | ||||
| -rw-r--r-- | ishtar_common/forms_common.py | 268 | ||||
| -rw-r--r-- | ishtar_common/templates/blocks/JQueryAutocomplete.js | 21 | ||||
| -rw-r--r-- | ishtar_common/templatetags/replace_underscore.py | 1 | ||||
| -rw-r--r-- | ishtar_common/urls.py | 188 | ||||
| -rw-r--r-- | ishtar_common/views.py | 496 | ||||
| -rw-r--r-- | ishtar_common/widgets.py | 178 | ||||
| -rw-r--r-- | ishtar_common/wizards.py | 168 | 
20 files changed, 1201 insertions, 934 deletions
| diff --git a/archaeological_context_records/forms.py b/archaeological_context_records/forms.py index 34f1a5101..2a9071f64 100644 --- a/archaeological_context_records/forms.py +++ b/archaeological_context_records/forms.py @@ -20,14 +20,12 @@  """  Context records forms definitions  """ -import datetime  from itertools import groupby  from django import forms  from django.conf import settings  from django.core import validators -from django.core.exceptions import ObjectDoesNotExist -from django.db.models import Max +from django.forms.formsets import formset_factory  from django.utils.translation import ugettext_lazy as _  from ishtar_common.models import valid_id @@ -35,12 +33,12 @@ from archaeological_operations.models import Period, Parcel, Operation  import models  from ishtar_common import widgets -from ishtar_common.forms import FinalForm, FinalForm, FormSet, \ -      formset_factory, get_now, reverse_lazy, get_form_selection, TableSelect -from ishtar_common.forms_common import get_town_field, SourceForm, \ -                                       SourceSelect, AuthorFormset +from ishtar_common.forms import FinalForm, FormSet, \ +    reverse_lazy, get_form_selection, TableSelect +from ishtar_common.forms_common import get_town_field, SourceSelect  from archaeological_operations.forms import OperationSelect, ParcelField +  class RecordSelect(TableSelect):      label = forms.CharField(label=_(u"ID"), max_length=100)      parcel__town = get_town_field() diff --git a/archaeological_context_records/views.py b/archaeological_context_records/views.py index 73e1cd7b3..526f5aca6 100644 --- a/archaeological_context_records/views.py +++ b/archaeological_context_records/views.py @@ -21,6 +21,7 @@ from django.core.urlresolvers import reverse  from django.shortcuts import redirect  from django.utils.translation import ugettext_lazy as _ +from ishtar_common.forms_common import AuthorFormset, SourceForm  from ishtar_common.views import get_item, show_item, revert_item  from ishtar_common.wizards import SearchWizard  from wizards import * diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py index 5e7229eab..4bde6f97e 100644 --- a/archaeological_files/forms.py +++ b/archaeological_files/forms.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2014  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2015  É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 @@ -25,31 +25,27 @@ import datetime  from django import forms  from django.conf import settings  from django.core import validators -from django.core.exceptions import ObjectDoesNotExist -from django.db.models import Max -from django.shortcuts import render_to_response -from django.template import RequestContext  from django.utils.translation import ugettext_lazy as _  from django.utils.safestring import mark_safe -from ishtar_common.models import Person, PersonType, Town, Organization, \ -                         OrganizationType, valid_id, is_unique, Department +from ishtar_common.models import Person, PersonType, Organization, \ +    OrganizationType, valid_id, Department  from archaeological_operations.models import ActType, AdministrativeAct, \ -                                             OperationType +    OperationType  import models -from ishtar_common.forms import FinalForm, FormSet, ClosingDateFormSelection, \ -    formset_factory, get_now, reverse_lazy, TableSelect -from ishtar_common.forms_common import get_town_field, get_person_field +from ishtar_common.forms import FinalForm, get_now, reverse_lazy, TableSelect +from ishtar_common.forms_common import get_town_field  from archaeological_operations.forms import AdministrativeActOpeForm, \ -    AdministrativeActOpeFormSelection, FinalAdministrativeActDeleteForm, \ +    AdministrativeActOpeFormSelection, \      ParcelField, SLICING, HEAD_SCIENTIST, SRA_AGENT  from ishtar_common import widgets  GENERAL_CONTRACTOR, created = PersonType.objects.get_or_create( -                                    txt_idx='general_contractor') +    txt_idx='general_contractor')  GENERAL_CONTRACTOR_ORGA, created = OrganizationType.objects.get_or_create( -                                    txt_idx='general_contractor') +    txt_idx='general_contractor') +  class FileSelect(TableSelect):      year = forms.IntegerField(label=_("Year")) @@ -63,33 +59,33 @@ class FileSelect(TableSelect):      parcel = ParcelField(label=_("Parcel (section/number)"))      end_date = forms.NullBooleanField(label=_(u"Is active?"))      general_contractor = forms.IntegerField( -            label=_(u"General contractor"), -            widget=widgets.JQueryAutoComplete( -                reverse_lazy('autocomplete-person', -                args=[GENERAL_CONTRACTOR.pk]), -                associated_model=Person), -            validators=[valid_id(Person)]) +        label=_(u"General contractor"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy('autocomplete-person', +                         args=[GENERAL_CONTRACTOR.pk]), +            associated_model=Person), +        validators=[valid_id(Person)])      general_contractor__attached_to = forms.IntegerField( -                label=_(u"Organization of general contractor"), -            widget=widgets.JQueryAutoComplete( -                reverse_lazy('autocomplete-organization', -                args=[GENERAL_CONTRACTOR_ORGA.pk]), -                associated_model=Organization), -            validators=[valid_id(Organization)]) +        label=_(u"Organization of general contractor"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy('autocomplete-organization', +                         args=[GENERAL_CONTRACTOR_ORGA.pk]), +            associated_model=Organization), +        validators=[valid_id(Organization)])      in_charge = forms.IntegerField( -            label=_(u"In charge"), -            widget=widgets.JQueryAutoComplete( -                reverse_lazy('autocomplete-person', -                args=[SRA_AGENT.pk]), -                associated_model=Person), -            validators=[valid_id(Person)]) +        label=_(u"In charge"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy('autocomplete-person', +                         args=[SRA_AGENT.pk]), +            associated_model=Person), +        validators=[valid_id(Person)])      history_creator = forms.IntegerField( -            label=_(u"Created by"), -            widget=widgets.JQueryAutoComplete( -                reverse_lazy('autocomplete-person', -                args=['0', 'user']), -                associated_model=Person), -            validators=[valid_id(Person)]) +        label=_(u"Created by"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy('autocomplete-person', +                         args=['0', 'user']), +            associated_model=Person), +        validators=[valid_id(Person)])      permit_reference = forms.CharField(max_length=200,                                         label=_("Permit reference")) @@ -107,14 +103,18 @@ class FileSelect(TableSelect):          ids.append('parcel_1')          return ids +  class FileFormSelection(forms.Form):      form_label = _("Archaeological file search") -    associated_models = {'pk':models.File} -    currents = {'pk':models.File} -    pk = forms.IntegerField(label="", required=False, -       widget=widgets.JQueryJqGrid(reverse_lazy('get-file'), -        FileSelect, models.File, source_full=reverse_lazy('get-file-full')), -       validators=[valid_id(models.File)]) +    associated_models = {'pk': models.File} +    currents = {'pk': models.File} +    pk = forms.IntegerField( +        label="", required=False, +        widget=widgets.JQueryJqGrid( +            reverse_lazy('get-file'), +            FileSelect, models.File, +            source_full=reverse_lazy('get-file-full')), +        validators=[valid_id(models.File)])      def clean(self):          cleaned_data = self.cleaned_data @@ -122,24 +122,25 @@ class FileFormSelection(forms.Form):              raise forms.ValidationError(_(u"You should select a file."))          return cleaned_data -DATE_SOURCE = (('creation',_(u"Creation date")), -               ("reception",_(u"Reception date"))) +DATE_SOURCE = (('creation', _(u"Creation date")), +               ("reception", _(u"Reception date"))) +  class DashboardForm(forms.Form): -    slicing = forms.ChoiceField(label=_("Slicing"), choices=SLICING, -                              required=False) -    department_detail = forms.BooleanField(label=_("Department detail"), -                              required=False) -    date_source = forms.ChoiceField(label=_("Date get from"), -                            choices=DATE_SOURCE, required=False) -    file_type = forms.ChoiceField(label=_("File type"), choices=[], -                                  required=False) -    saisine_type = forms.ChoiceField(label=_("Saisine type"), choices=[], -                                  required=False) -    after = forms.DateField(label=_(u"Date after"), -                            widget=widgets.JQueryDate, required=False) -    before = forms.DateField(label=_(u"Date before"), -                            widget=widgets.JQueryDate, required=False) +    slicing = forms.ChoiceField( +        label=_("Slicing"), choices=SLICING, required=False) +    department_detail = forms.BooleanField( +        label=_("Department detail"), required=False) +    date_source = forms.ChoiceField( +        label=_("Date get from"), choices=DATE_SOURCE, required=False) +    file_type = forms.ChoiceField( +        label=_("File type"), choices=[], required=False) +    saisine_type = forms.ChoiceField( +        label=_("Saisine type"), choices=[], required=False) +    after = forms.DateField( +        label=_(u"Date after"), widget=widgets.JQueryDate, required=False) +    before = forms.DateField( +        label=_(u"Date before"), widget=widgets.JQueryDate, required=False)      def __init__(self, *args, **kwargs):          if 'prefix' not in kwargs: @@ -150,7 +151,7 @@ class DashboardForm(forms.Form):      def get_show_detail(self):          return hasattr(self, 'cleaned_data') and \ -           self.cleaned_data.get('department_detail') +            self.cleaned_data.get('department_detail')      def get_date_source(self):          date_source = 'creation' @@ -174,40 +175,43 @@ class DashboardForm(forms.Form):              fltr[date_source+'_date__lte'] = self.cleaned_data['before']          return fltr +  class FileFormGeneral(forms.Form):      form_label = _("General") -    associated_models = {'in_charge':Person, -                         'related_file':models.File, -                         'file_type':models.FileType} -    in_charge = forms.IntegerField(label=_("Person in charge"), -        widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person', -          args=[SRA_AGENT.pk]), -        limit={'person_types':[SRA_AGENT.pk]}, -        associated_model=Person, new=True), +    associated_models = {'in_charge': Person, +                         'related_file': models.File, +                         'file_type': models.FileType} +    in_charge = forms.IntegerField( +        label=_("Person in charge"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy('autocomplete-person', args=[SRA_AGENT.pk]), +            limit={'person_types': [SRA_AGENT.pk]}, +            associated_model=Person, new=True),          validators=[valid_id(Person)])      year = forms.IntegerField(label=_("Year"), -                              initial=lambda:datetime.datetime.now().year, +                              initial=lambda: datetime.datetime.now().year,                                validators=[validators.MinValueValidator(1900),                                            validators.MaxValueValidator(2100)]) -    numeric_reference = forms.IntegerField(label=_("Numeric reference"), -                widget=forms.HiddenInput, required=False) -    internal_reference = forms.CharField(label=_(u"Other reference"), -                                       max_length=60, required=False) +    numeric_reference = forms.IntegerField( +        label=_("Numeric reference"), widget=forms.HiddenInput, required=False) +    internal_reference = forms.CharField( +        label=_(u"Other reference"), max_length=60, required=False)      name = forms.CharField(label=_(u"Name"), required=False, max_length=100)      creation_date = forms.DateField(label=_(u"Creation date"),                                      initial=get_now, widget=widgets.JQueryDate)      file_type = forms.ChoiceField(label=_("File type"), choices=[]) -    related_file = forms.IntegerField(label=_("Related file"), required=False, -         widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-file'), -                                           associated_model=models.File), -         validators=[valid_id(models.File)]) +    related_file = forms.IntegerField( +        label=_("Related file"), required=False, +        widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-file'), +                                          associated_model=models.File), +        validators=[valid_id(models.File)])      comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea,                                required=False) -    total_surface = forms.IntegerField(required=False, -                           widget=widgets.AreaWidget, -                           label=_(u"Total surface (m²)"), -                           validators=[validators.MinValueValidator(0), -                                       validators.MaxValueValidator(999999999)]) +    total_surface = forms.IntegerField( +        required=False, widget=widgets.AreaWidget, +        label=_(u"Total surface (m²)"), +        validators=[validators.MinValueValidator(0), +                    validators.MaxValueValidator(999999999)])      address = forms.CharField(label=_(u"Main address"), widget=forms.Textarea)      address_complement = forms.CharField(label=_(u"Main address - complement"),                                           required=False) @@ -216,19 +220,21 @@ class FileFormGeneral(forms.Form):          super(FileFormGeneral, self).__init__(*args, **kwargs)          self.fields['file_type'].choices = models.FileType.get_types()          self.fields['file_type'].help_text = models.FileType.get_help() -        q = models.File.objects.filter(internal_reference__isnull=False -                   ).exclude(internal_reference='').order_by('-pk') +        q = models.File.objects\ +                  .filter(internal_reference__isnull=False)\ +                  .exclude(internal_reference='').order_by('-pk')          if q.count():              lbl = self.fields['internal_reference'].label              lbl += _(u"<br/>(last recorded: %s)") % ( -                                q.all()[0].internal_reference) +                q.all()[0].internal_reference)              self.fields['internal_reference'].label = mark_safe(lbl) +  class FileFormGeneralRO(FileFormGeneral): -    year = forms.IntegerField(label=_(u"Year"), -                        widget=forms.TextInput(attrs={'readonly':True})) -    numeric_reference = forms.IntegerField(label=_(u"Numeric reference"), -                        widget=forms.TextInput()) +    year = forms.IntegerField( +        label=_(u"Year"), widget=forms.TextInput(attrs={'readonly': True})) +    numeric_reference = forms.IntegerField( +        label=_(u"Numeric reference"), widget=forms.TextInput())      id = forms.IntegerField(' ', widget=forms.HiddenInput, required=False)      def clean(self): @@ -236,123 +242,136 @@ class FileFormGeneralRO(FileFormGeneral):          year = cleaned_data.get('year')          pk = cleaned_data.get('id')          numeric_reference = cleaned_data.get('numeric_reference') -        q = models.File.objects.filter(year=year, -                                       numeric_reference=numeric_reference -                              ).exclude(pk=pk) +        q = models.File.objects\ +                       .filter(year=year, numeric_reference=numeric_reference)\ +                       .exclude(pk=pk)          if numeric_reference and q.count():              raise forms.ValidationError( -                     _(u"Another file with this numeric id exists.")) +                _(u"Another file with this numeric id exists."))          return cleaned_data  RESPONSIBLE_PLANNING_SERVICE, created = PersonType.objects.get_or_create( -                               txt_idx='responsible_planning_service') +    txt_idx='responsible_planning_service')  RESPONSIBLE_PLANNING_SERVICE_ORGA, created = \ -            OrganizationType.objects.get_or_create( -                                    txt_idx='planning_service') +    OrganizationType.objects.get_or_create(txt_idx='planning_service') + +  class FileFormPreventive(forms.Form):      form_label = _(u"Preventive informations") -    associated_models = {'general_contractor':Person, -                         'saisine_type':models.SaisineType, -                         'permit_type':models.PermitType, -                         'responsible_town_planning_service':Person} -    general_contractor = forms.IntegerField(label=_(u"General contractor"), -            widget=widgets.JQueryAutoComplete( -                reverse_lazy('autocomplete-person', -                args=[PersonType.objects.get(txt_idx='general_contractor').pk]), -                limit={'person_types': -                    [PersonType.objects.get(txt_idx='general_contractor').pk]}, -                associated_model=Person, new=True), -            validators=[valid_id(Person)]) -    responsible_town_planning_service = forms.IntegerField(required=False, -            label=_(u"Responsible for town planning service"), -            widget=widgets.JQueryAutoComplete( -                reverse_lazy('autocomplete-person', -                    args=[RESPONSIBLE_PLANNING_SERVICE.pk]), -                    limit={'person_types': -                        [RESPONSIBLE_PLANNING_SERVICE.pk]}, -                    associated_model=Person, new=True), -            validators=[valid_id(Person)]) +    associated_models = {'general_contractor': Person, +                         'saisine_type': models.SaisineType, +                         'permit_type': models.PermitType, +                         'responsible_town_planning_service': Person} +    general_contractor = forms.IntegerField( +        label=_(u"General contractor"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy( +                'autocomplete-person', +                args=[PersonType.objects.get(txt_idx='general_contractor').pk] +                ), +            limit={'person_types': [ +                PersonType.objects.get(txt_idx='general_contractor').pk]}, +            associated_model=Person, new=True), +        validators=[valid_id(Person)]) +    responsible_town_planning_service = forms.IntegerField( +        required=False, +        label=_(u"Responsible for town planning service"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy( +                'autocomplete-person', +                args=[RESPONSIBLE_PLANNING_SERVICE.pk] +            ), +            limit={'person_types': [ +                RESPONSIBLE_PLANNING_SERVICE.pk]}, +            associated_model=Person, new=True), +        validators=[valid_id(Person)])      permit_type = forms.ChoiceField(label=_(u"Permit type"), required=False,                                      choices=[]) -    permit_reference = forms.CharField(label=_(u"Permit reference"), -            required=False, validators=[validators.MaxLengthValidator(60)]) -    total_developed_surface = forms.IntegerField(widget=widgets.AreaWidget, -           label=_(u"Total developed surface (m²)"), -           required=False, validators=[validators.MinValueValidator(0), -                                       validators.MaxValueValidator(999999999)]) +    permit_reference = forms.CharField( +        label=_(u"Permit reference"), required=False, +        validators=[validators.MaxLengthValidator(60)]) +    total_developed_surface = forms.IntegerField( +        widget=widgets.AreaWidget, label=_(u"Total developed surface (m²)"), +        required=False, validators=[validators.MinValueValidator(0), +                                    validators.MaxValueValidator(999999999)])      if settings.COUNTRY == 'fr':          saisine_type = forms.ChoiceField(label=_(u"Saisine type"),                                           choices=[]) -    reception_date = forms.DateField(label=_(u"Reception date"), -                                     initial=get_now, widget=widgets.JQueryDate) +    reception_date = forms.DateField( +        label=_(u"Reception date"), initial=get_now, widget=widgets.JQueryDate) +      def __init__(self, *args, **kwargs):          super(FileFormPreventive, self).__init__(*args, **kwargs)          self.fields['saisine_type'].choices = models.SaisineType.get_types()          self.fields['saisine_type'].help_text = models.SaisineType.get_help()          self.fields['permit_type'].choices = models.PermitType.get_types( -                                                              default='NP') +            default='NP')          self.fields['permit_type'].help_text = models.PermitType.get_help() +  class FileFormResearch(forms.Form):      form_label = _("Research archaeology")      base_model = 'department' -    associated_models = {'scientist':Person, -                         'requested_operation_type':OperationType, -                         'organization':Organization, -                         'department':Department} +    associated_models = {'scientist': Person, +                         'requested_operation_type': OperationType, +                         'organization': Organization, +                         'department': Department}      department = widgets.MultipleAutocompleteField( -                                model=Department, -                                label=_("Departments"), -                                required=False) +        model=Department, +        label=_("Departments"), +        required=False)      scientist = forms.IntegerField( -        widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person', -          args=["_".join( -         [unicode(HEAD_SCIENTIST.pk), -          unicode(SRA_AGENT.pk)])]), -          limit={'person_types': -            [unicode(HEAD_SCIENTIST.pk), -             unicode(SRA_AGENT.pk)]}, -        associated_model=Person, new=True), label=_(u"Scientist in charge")) +        widget=widgets.JQueryAutoComplete( +            reverse_lazy( +                'autocomplete-person', +                args=["_".join([unicode(HEAD_SCIENTIST.pk), +                                unicode(SRA_AGENT.pk)])]), +                limit={'person_types': [unicode(HEAD_SCIENTIST.pk), +                                        unicode(SRA_AGENT.pk)]}, +            associated_model=Person, new=True), +        label=_(u"Scientist in charge"))      requested_operation_type = forms.ChoiceField( -                    label=_(u"Requested operation type"), -                    choices=[]) -    organization = forms.IntegerField(label=_(u"Lead organization"), -            widget=widgets.JQueryAutoComplete( -                reverse_lazy('autocomplete-organization'), -                associated_model=Organization, new=True), -            validators=[valid_id(Organization)], required=False) +        label=_(u"Requested operation type"), choices=[]) +    organization = forms.IntegerField( +        label=_(u"Lead organization"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy('autocomplete-organization'), +            associated_model=Organization, new=True), +        validators=[valid_id(Organization)], required=False)      if settings.COUNTRY == 'fr':          cira_advised = forms.NullBooleanField(label=u"Passage en CIRA",                                                required=False) -    research_comment = forms.CharField(label=_(u"Comment"), -                        widget=forms.Textarea, required=False) +    research_comment = forms.CharField( +        label=_(u"Comment"), widget=forms.Textarea, required=False)      if settings.COUNTRY == 'fr':          mh_register = forms.NullBooleanField( -                            label=u"Sur Monument Historique classé", -                            required=False) +            label=u"Sur Monument Historique classé", required=False)          mh_listing = forms.NullBooleanField( -                            label=u"Sur Monument Historique inscrit", -                            required=False) -    classified_area = forms.NullBooleanField(label=_(u"Classified area"), -                                             required=False) -    protected_area = forms.NullBooleanField(label=_(u"Protected area"), -                                            required=False) +            label=u"Sur Monument Historique inscrit", required=False) +    classified_area = forms.NullBooleanField( +        label=_(u"Classified area"), required=False) +    protected_area = forms.NullBooleanField( +        label=_(u"Protected area"), required=False) +      def __init__(self, *args, **kwargs):          super(FileFormResearch, self).__init__(*args, **kwargs)          self.fields['requested_operation_type'].choices = \ -                    OperationType.get_types(dct={"preventive":False}) +            OperationType.get_types(dct={"preventive": False})          self.fields['requested_operation_type'].help_text = \ -                    OperationType.get_help() +            OperationType.get_help() +  class FinalFileClosingForm(FinalForm):      confirm_msg = " "      confirm_end_msg = _(u"Would you like to close this archaeological file?") +  class FinalFileDeleteForm(FinalForm):      confirm_msg = " "      confirm_end_msg = _(u"Would you like to delete this archaelogical file ?") +  class AdministrativeActFileModifySelect(TableSelect):      year = forms.IntegerField(label=_("Year"))      index = forms.IntegerField(label=_("Index")) @@ -363,77 +382,92 @@ class AdministrativeActFileModifySelect(TableSelect):      operation__towns = get_town_field()      def __init__(self, *args, **kwargs): -        super(AdministrativeActFileModifySelect, self).__init__(*args, **kwargs) +        super(AdministrativeActFileModifySelect, self).__init__(*args, +                                                                **kwargs)          self.fields['act_type'].choices = ActType.get_types( -                                                   dct={'intented_to':'F'}) +            dct={'intented_to': 'F'})          self.fields['act_type'].help_text = ActType.get_help( -                                                   dct={'intented_to':'F'}) +            dct={'intented_to': 'F'}) +  class AdministrativeActFileSelect(TableSelect):      associated_file__towns = get_town_field()      act_type = forms.ChoiceField(label=_("Act type"), choices=[]) -    signature_date_after = forms.DateField(label=_(u"Signature date after"), -                                            widget=widgets.JQueryDate) -    signature_date_before = forms.DateField(label=_(u"Signature date before"), -                                            widget=widgets.JQueryDate) -    associated_file__name = forms.CharField(label=_(u"File name"), -                                            max_length=200) +    signature_date_after = forms.DateField( +        label=_(u"Signature date after"), widget=widgets.JQueryDate) +    signature_date_before = forms.DateField( +        label=_(u"Signature date before"), widget=widgets.JQueryDate) +    associated_file__name = forms.CharField( +        label=_(u"File name"), max_length=200)      associated_file__general_contractor = forms.IntegerField( -            label=_(u"General contractor"), -            widget=widgets.JQueryAutoComplete( -                reverse_lazy('autocomplete-person', -                args=[PersonType.objects.get(txt_idx='general_contractor').pk]), +        label=_(u"General contractor"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy( +                'autocomplete-person', +                args=[ +                    PersonType.objects.get(txt_idx='general_contractor').pk]),                  associated_model=Person), -            validators=[valid_id(Person)]) +        validators=[valid_id(Person)])      associated_file__general_contractor__attached_to = forms.IntegerField( -                label=_(u"Organization of general contractor"), -            widget=widgets.JQueryAutoComplete( -                reverse_lazy('autocomplete-organization', +        label=_(u"Organization of general contractor"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy( +                'autocomplete-organization',                  args=[GENERAL_CONTRACTOR_ORGA.pk]), -                associated_model=Organization), -            validators=[valid_id(Organization)]) +            associated_model=Organization), +        validators=[valid_id(Organization)])      associated_file__numeric_reference = forms.IntegerField( -                                           label=_("Numeric reference")) +        label=_("Numeric reference"))      associated_file__year = forms.IntegerField(label=_("Year")) -    associated_file__internal_reference = forms.CharField(max_length=200, -                                           label=_("Other reference")) +    associated_file__internal_reference = forms.CharField( +        max_length=200, label=_("Other reference"))      associated_file__in_charge = forms.IntegerField( -            label=_(u"In charge"), -            widget=widgets.JQueryAutoComplete( -                reverse_lazy('autocomplete-person', +        label=_(u"In charge"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy( +                'autocomplete-person',                  args=[SRA_AGENT.pk]), -                associated_model=Person), -            validators=[valid_id(Person)]) -    associated_file__permit_reference = forms.CharField(max_length=200, -                                           label=_("Permit reference")) +            associated_model=Person), +        validators=[valid_id(Person)]) +    associated_file__permit_reference = forms.CharField( +        max_length=200, label=_("Permit reference"))      history_creator = forms.IntegerField( -            label=_(u"Created by"), -            widget=widgets.JQueryAutoComplete( -                reverse_lazy('autocomplete-person', +        label=_(u"Created by"), +        widget=widgets.JQueryAutoComplete( +            reverse_lazy( +                'autocomplete-person',                  args=['0', 'user']), -                associated_model=Person), -            validators=[valid_id(Person)]) +            associated_model=Person), +        validators=[valid_id(Person)])      def __init__(self, *args, **kwargs):          super(AdministrativeActFileSelect, self).__init__(*args, **kwargs)          self.fields['act_type'].choices = ActType.get_types( -                                                   dct={'intented_to':'F'}) +            dct={'intented_to': 'F'})          self.fields['act_type'].help_text = ActType.get_help( -                                                   dct={'intented_to':'F'}) +            dct={'intented_to': 'F'}) +  class AdministrativeActFileFormSelection(AdministrativeActOpeFormSelection): -    pk = forms.IntegerField(label="", required=False, -       widget=widgets.JQueryJqGrid(reverse_lazy('get-administrativeactfile'), -                      AdministrativeActFileSelect, AdministrativeAct, -                      table_cols='TABLE_COLS_FILE'), -       validators=[valid_id(AdministrativeAct)]) - -class AdministrativeActFileModifyFormSelection(AdministrativeActOpeFormSelection): -    pk = forms.IntegerField(label="", required=False, -       widget=widgets.JQueryJqGrid(reverse_lazy('get-administrativeactfile'), -                      AdministrativeActFileModifySelect, AdministrativeAct, -                      table_cols='TABLE_COLS_FILE'), -       validators=[valid_id(AdministrativeAct)]) +    pk = forms.IntegerField( +        label="", required=False, +        widget=widgets.JQueryJqGrid( +            reverse_lazy('get-administrativeactfile'), +            AdministrativeActFileSelect, AdministrativeAct, +            table_cols='TABLE_COLS_FILE'), +        validators=[valid_id(AdministrativeAct)]) + + +class AdministrativeActFileModifyFormSelection( +        AdministrativeActOpeFormSelection): +    pk = forms.IntegerField( +        label="", required=False, +        widget=widgets.JQueryJqGrid( +            reverse_lazy('get-administrativeactfile'), +            AdministrativeActFileModifySelect, AdministrativeAct, +            table_cols='TABLE_COLS_FILE'), +        validators=[valid_id(AdministrativeAct)]) +  class AdministrativeActFileForm(AdministrativeActOpeForm):      act_type = forms.ChoiceField(label=_(u"Act type"), choices=[]) @@ -441,6 +475,6 @@ class AdministrativeActFileForm(AdministrativeActOpeForm):      def __init__(self, *args, **kwargs):          super(AdministrativeActFileForm, self).__init__(*args, **kwargs)          self.fields['act_type'].choices = ActType.get_types( -                                                   dct={'intented_to':'F'}) +            dct={'intented_to': 'F'})          self.fields['act_type'].help_text = ActType.get_help( -                                                   dct={'intented_to':'F'}) +            dct={'intented_to': 'F'}) diff --git a/archaeological_files/models.py b/archaeological_files/models.py index f79de4f98..a7b23564d 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -359,13 +359,23 @@ class File(BaseHistorizedItem, OwnPerms, ValueGetter, ShortMenuItem,      def update_planning_service(self):          if not self.responsible_town_planning_service or \ -           self.responsible_town_planning_service.attached_to \ -           == self.planning_service: +           not self.responsible_town_planning_service.attached_to or \ +           self.planning_service:              return False          self.planning_service = \              self.responsible_town_planning_service.attached_to          return True +    def update_resp_planning_service(self): +        if not self.responsible_town_planning_service or \ +           self.responsible_town_planning_service.attached_to or \ +           not self.planning_service: +            return False +        self.responsible_town_planning_service.attached_to = \ +            self.planning_service +        self.responsible_town_planning_service.save() +        return True +      def update_raw_general_contractor(self):          if (self.raw_general_contractor and not             self.general_contractor) or \ @@ -395,6 +405,7 @@ class File(BaseHistorizedItem, OwnPerms, ValueGetter, ShortMenuItem,              self.towns.add(self.main_town)          updated = self.update_raw_town_planning_service()          updated += self.update_planning_service() +        self.update_resp_planning_service()          updated += self.update_raw_general_contractor()          updated += self.update_corpo_general_contractor()          if updated: diff --git a/archaeological_files/views.py b/archaeological_files/views.py index fd0507295..686578933 100644 --- a/archaeological_files/views.py +++ b/archaeological_files/views.py @@ -38,7 +38,9 @@ from archaeological_operations.wizards import AdministrativeActDeletionWizard, \  from wizards import *  from ishtar_common.forms_common import TownFormset -from archaeological_operations.forms import ParcelFormSet +from archaeological_operations.forms import ParcelFormSet, \ +    FinalAdministrativeActDeleteForm +from ishtar_common.forms import ClosingDateFormSelection  from forms import * diff --git a/archaeological_files_pdl/forms.py b/archaeological_files_pdl/forms.py index 393f53b8c..a0c5037e7 100644 --- a/archaeological_files_pdl/forms.py +++ b/archaeological_files_pdl/forms.py @@ -230,25 +230,44 @@ class FileFormGeneralContractor(PersonOrgaForm):          label=" ", widget=forms.HiddenInput, required=False) -class FileFormPlanningService(PersonOrgaForm): +class FileFormPlanningService(forms.Form):      form_label = _(u"Town planning service")      associated_models = {'responsible_town_planning_service': models.Person,                           'planning_service': models.Organization}      reference_number = forms.IntegerField(label=_(u"File reference"),                                            required=False) -    PERSON_FIELD = 'responsible_town_planning_service' -    PERSON_TYPE = RESPONSIBLE_PLANNING_SERVICE -    PERSON_LABEL = _(u"Responsible town planning service") -    ORGA_FIELD = 'planning_service' -    ORGA_TYPE = RESPONSIBLE_PLANNING_SERVICE_ORGA -    ORGA_LABEL = _(u"Planning service") - -    # default initialisation before dynamic +    planning_service = forms.IntegerField( +        label=_("Planning service"), +        required=False, +        widget=widgets.JQueryAutoComplete( +            reverse_lazy('autocomplete-organization', +                         args=[RESPONSIBLE_PLANNING_SERVICE_ORGA.pk]), +            limit={ +                'organization_type': [RESPONSIBLE_PLANNING_SERVICE_ORGA.pk] +            }, +            associated_model=models.Organization, +            new=True), +        validators=[valid_id(models.Organization)] +    )      responsible_town_planning_service = forms.IntegerField( -        label=" ", widget=forms.HiddenInput, required=False) -    planning_service = forms.IntegerField(label=" ", widget=forms.HiddenInput, -                                          required=False) +        label=_(u"In charge"), +        required=False, +        widget=widgets.JQueryAutoComplete( +            reverse_lazy('autocomplete-person', +                         args=[RESPONSIBLE_PLANNING_SERVICE.pk]), +            associated_model=Person, +            limit={'person_types': [RESPONSIBLE_PLANNING_SERVICE.pk]}, +            dynamic_limit=['planning_service'], +            url_new='new-person-noorga', +            new=True), +        validators=[valid_id(Person)] +    ) + +    def is_valid(self, *args, **kwargs): +        c = super(FileFormPlanningService, self).is_valid(*args, **kwargs) +        print(self.cleaned_data) +        return c  class FileFormInstruction(forms.Form): diff --git a/archaeological_files_pdl/templates/ishtar/wizard/wizard_planningservice.html b/archaeological_files_pdl/templates/ishtar/wizard/wizard_planningservice.html index 6fd9eef71..85a1156aa 100644 --- a/archaeological_files_pdl/templates/ishtar/wizard/wizard_planningservice.html +++ b/archaeological_files_pdl/templates/ishtar/wizard/wizard_planningservice.html @@ -1,22 +1,44 @@ -{% extends "ishtar/wizard/wizard_person_orga.html" %} +{% extends "ishtar/wizard/default_wizard.html" %} +{% load i18n range table_form %} +{% block wizard_form %} +<form action="." method="post" name='wizard'{% if wizard.form.file_upload %} enctype="multipart/form-data"{% endif %}>{% csrf_token %} +<div class='form'> +{% if wizard.form.media %}{{ wizard.form.media }}{% endif %} +{{ wizard.management_form }} + +<table> +  {% if wizard.form.non_field_errors %}<tr class='errors'> +    <td colspan='3'>{{wizard.form.non_field_errors}}</td> +  </tr>{%endif%} -{% block corporation %}    <tr class='required'>      <th>{{ wizard.form.planning_service.label_tag }}</th>      <td> {{ wizard.form.planning_service.errors }}{{wizard.form.planning_service|safe}}</td>    </tr> -{% endblock %} - -{% block natural %} -  <tr class='required'> +  <tr>      <th>{{ wizard.form.responsible_town_planning_service.label_tag }}</th>      <td> {{ wizard.form.responsible_town_planning_service.errors }}{{wizard.form.responsible_town_planning_service|safe}}</td>    </tr> -{% endblock %} +</table> + -{% block otherfields %} +<div> +<table>    <tr class='required'>      <th>{{ wizard.form.reference_number.label_tag }}</th>      <td> {{ wizard.form.reference_number.errors }}{{wizard.form.reference_number|safe}}</td>    </tr> +</table> +</div> + +<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" /> +{{ previous_fields|safe }} +{% block "validation_bar" %} +{% include 'ishtar/wizard/validation_bar.html' %} +{% endblock %} +</div> +</form>  {% endblock %} + + + diff --git a/archaeological_files_pdl/views.py b/archaeological_files_pdl/views.py index bcb1c0211..8305bdab7 100644 --- a/archaeological_files_pdl/views.py +++ b/archaeological_files_pdl/views.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2014  Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2015  É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 @@ -22,7 +22,8 @@ from django.utils.translation import ugettext_lazy as _  from archaeological_files_pdl.wizards import FileWizard, FileModificationWizard  from archaeological_operations.wizards import is_preventive, is_not_preventive -from ishtar_common.views import OrganizationPersonCreate, OrganizationPersonEdit +from ishtar_common.views import OrganizationPersonCreate, \ +    OrganizationPersonEdit  from archaeological_files_pdl import forms  from archaeological_files import forms as ref_forms @@ -31,69 +32,68 @@ from archaeological_operations.forms import ParcelFormSet  from archaeological_files import models -file_creation_wizard_is_preventive = is_preventive('general-file_creation', -                                models.FileType, type_key='file_type') +file_creation_wizard_is_preventive = is_preventive( +    'general-file_creation', models.FileType, type_key='file_type')  file_creation_wizard_is_not_preventive = is_not_preventive( -        'general-file_creation', models.FileType, type_key='file_type') +    'general-file_creation', models.FileType, type_key='file_type')  file_creation_wizard = FileWizard.as_view([ -                ('general-file_creation', forms.FileFormGeneral), -                ('preventivetype-file_creation', forms.FileFormPreventiveType), -                ('preventiveplanning-file_creation', forms.FileFormPlanning), -                ('researchaddress-file_creation', forms.FileFormResearchAddress), -                ('parcelspdl-file_creation', ParcelFormSet), -                ('generalcontractor-file_creation', -                                            forms.FileFormGeneralContractor), -                ('planningservice-file_creation', -                                            forms.FileFormPlanningService), -                ('research-file_creation', ref_forms.FileFormResearch), -                ('instruction-file_creation', -                                            forms.FileFormInstruction), -                ('final-file_creation', ref_forms.FinalForm)], -             label=_(u"New file"), -             condition_dict={ -        'preventivetype-file_creation':file_creation_wizard_is_preventive, -        'preventiveplanning-file_creation':file_creation_wizard_is_preventive, -        'generalcontractor-file_creation':file_creation_wizard_is_preventive, -        'planningservice-file_creation':file_creation_wizard_is_preventive, -        'researchaddress-file_creation':file_creation_wizard_is_not_preventive, -        'research-file_creation':file_creation_wizard_is_not_preventive -             }, -             url_name='file_creation',) - -file_modification_wizard_is_preventive = is_preventive('general-file_modification', -                                models.FileType, type_key='file_type') +    ('general-file_creation', forms.FileFormGeneral), +    ('preventivetype-file_creation', forms.FileFormPreventiveType), +    ('preventiveplanning-file_creation', forms.FileFormPlanning), +    ('researchaddress-file_creation', forms.FileFormResearchAddress), +    ('parcelspdl-file_creation', ParcelFormSet), +    ('generalcontractor-file_creation', forms.FileFormGeneralContractor), +    ('planningservice-file_creation', forms.FileFormPlanningService), +    ('research-file_creation', ref_forms.FileFormResearch), +    ('instruction-file_creation', forms.FileFormInstruction), +    ('final-file_creation', ref_forms.FinalForm)], +    label=_(u"New file"), +    condition_dict={ +        'preventivetype-file_creation': file_creation_wizard_is_preventive, +        'preventiveplanning-file_creation': file_creation_wizard_is_preventive, +        'generalcontractor-file_creation': file_creation_wizard_is_preventive, +        'planningservice-file_creation': file_creation_wizard_is_preventive, +        'researchaddress-file_creation': +        file_creation_wizard_is_not_preventive, +        'research-file_creation': file_creation_wizard_is_not_preventive +    }, +    url_name='file_creation',) + +file_modification_wizard_is_preventive = is_preventive( +    'general-file_modification', models.FileType, type_key='file_type')  file_modification_wizard_is_not_preventive = is_not_preventive( -        'general-file_modification', models.FileType, type_key='file_type') +    'general-file_modification', models.FileType, type_key='file_type')  file_modification_wizard = FileModificationWizard.as_view([ -            ('selec-file_modification', ref_forms.FileFormSelection), - -            ('general-file_modification', forms.FileFormGeneral), -            ('preventivetype-file_modification', forms.FileFormPreventiveType), -            ('preventiveplanning-file_modification', forms.FileFormPlanning), -            ('researchaddress-file_modification', forms.FileFormResearchAddress), -            ('parcelspdl-file_modification', ParcelFormSet), -            ('generalcontractor-file_modification', -                                        forms.FileFormGeneralContractor), -            ('planningservice-file_modification', -                                        forms.FileFormPlanningService), -            ('research-file_modification', ref_forms.FileFormResearch), -            ('instruction-file_modification', -                                        forms.FileFormInstruction), -            ('final-file_modification', ref_forms.FinalForm)], -             label=_(u"File modification"), -             condition_dict={ -    'preventivetype-file_modification':file_modification_wizard_is_preventive, -    'preventiveplanning-file_modification':file_modification_wizard_is_preventive, -    'generalcontractor-file_modification':file_modification_wizard_is_preventive, -    'planningservice-file_modification':file_modification_wizard_is_preventive, -    'researchaddress-file_modification':file_modification_wizard_is_not_preventive, -    'research-file_modification':file_modification_wizard_is_not_preventive -         }, -         url_name='file_modification',) +    ('selec-file_modification', ref_forms.FileFormSelection), +    ('general-file_modification', forms.FileFormGeneral), +    ('preventivetype-file_modification', forms.FileFormPreventiveType), +    ('preventiveplanning-file_modification', forms.FileFormPlanning), +    ('researchaddress-file_modification', forms.FileFormResearchAddress), +    ('parcelspdl-file_modification', ParcelFormSet), +    ('generalcontractor-file_modification', forms.FileFormGeneralContractor), +    ('planningservice-file_modification', forms.FileFormPlanningService), +    ('research-file_modification', ref_forms.FileFormResearch), +    ('instruction-file_modification', forms.FileFormInstruction), +    ('final-file_modification', ref_forms.FinalForm)], +    label=_(u"File modification"), +    condition_dict={ +    'preventivetype-file_modification': file_modification_wizard_is_preventive, +    'preventiveplanning-file_modification': +    file_modification_wizard_is_preventive, +    'generalcontractor-file_modification': +    file_modification_wizard_is_preventive, +    'planningservice-file_modification': +    file_modification_wizard_is_preventive, +    'researchaddress-file_modification': +    file_modification_wizard_is_not_preventive, +    'research-file_modification': file_modification_wizard_is_not_preventive +    }, +    url_name='file_modification',)  class TownPlanningEdit(OrganizationPersonEdit):      relative_label = _("File followed by") +  class TownPlanningCreate(OrganizationPersonCreate):      relative_label = _("File followed by") diff --git a/archaeological_files_pdl/wizards.py b/archaeological_files_pdl/wizards.py index c081d13d1..666de8155 100644 --- a/archaeological_files_pdl/wizards.py +++ b/archaeological_files_pdl/wizards.py @@ -42,8 +42,7 @@ class FileWizard(BaseFileWizard):      def get_form_kwargs(self, *args, **kwargs):          returned = super(FileWizard, self).get_form_kwargs(*args, **kwargs) -        if args and (args[0].startswith('generalcontractor-') or -                     args[0].startswith('planningservice-')): +        if args and args[0].startswith('generalcontractor-'):              if 'status' in self.request.GET:                  returned['status'] = self.request.GET['status']          if args and args[0].startswith('instruction-'): diff --git a/archaeological_finds/forms.py b/archaeological_finds/forms.py index 5a3ff4ec1..65a1570d8 100644 --- a/archaeological_finds/forms.py +++ b/archaeological_finds/forms.py @@ -20,30 +20,24 @@  """  Finds forms definitions  """ -import datetime  from django import forms  from django.conf import settings  from django.core import validators -from django.core.exceptions import ObjectDoesNotExist -from django.db.models import Max -from django.shortcuts import render_to_response -from django.template import RequestContext +from django.forms.formsets import formset_factory  from django.utils.safestring import mark_safe  from django.utils.translation import ugettext_lazy as _  from ishtar_common.models import Person, valid_id, valid_ids -from archaeological_operations.models import Period, OperationType +from archaeological_operations.models import Period  from archaeological_context_records.models import DatingType, DatingQuality  from archaeological_warehouse.models import Warehouse  import models  from ishtar_common import widgets -from ishtar_common.forms import FinalForm, FormSet, FloatField, \ -    formset_factory, get_now, get_form_selection, reverse_lazy, TableSelect -from ishtar_common.forms_common import get_town_field, \ -    SourceForm, SourceSelect, SourceDeletionForm, AuthorFormset -from archaeological_context_records.forms import RecordFormSelection +from ishtar_common.forms import FormSet, FloatField, \ +    get_form_selection, reverse_lazy, TableSelect +from ishtar_common.forms_common import get_town_field, SourceSelect  class FindForm(forms.Form): diff --git a/archaeological_finds/views.py b/archaeological_finds/views.py index b5a3debce..63a173edb 100644 --- a/archaeological_finds/views.py +++ b/archaeological_finds/views.py @@ -21,16 +21,23 @@ from django.core.urlresolvers import reverse  from django.shortcuts import redirect  from django.utils.translation import ugettext_lazy as _ +from ishtar_common.forms import FinalForm +from ishtar_common.forms_common import SourceForm, AuthorFormset, \ +    SourceDeletionForm +from archaeological_context_records.forms import RecordFormSelection +  from ishtar_common.views import get_item, show_item, revert_item  from ishtar_common.wizards import SearchWizard +  from wizards import *  from forms import *  import models -get_find = get_item(models.Find, 'get_find', 'find', -    bool_fields = ['base_finds__is_isolated'], -    reversed_bool_fields = ['image__isnull'], -    base_request={'downstream_treatment__isnull':True}, +get_find = get_item( +    models.Find, 'get_find', 'find', +    bool_fields=['base_finds__is_isolated'], +    reversed_bool_fields=['image__isnull'], +    base_request={'downstream_treatment__isnull': True},      extra_request_keys={          'base_finds__context_record__parcel__town':              'base_finds__context_record__parcel__town', @@ -38,18 +45,19 @@ get_find = get_item(models.Find, 'get_find', 'find',              'base_finds__context_record__operation__year__contains',          'base_finds__context_record__operation__code_patriarche':              'base_finds__context_record__operation__code_patriarche', -        'dating__period':'dating__period__pk', +        'dating__period': 'dating__period__pk',          'base_finds__find__description':              'base_finds__find__description__icontains', -        'base_finds__is_isolated':'base_finds__is_isolated', -        'image':'image__isnull'}) -get_findsource = get_item(models.FindSource, 'get_findsource', 'findsource', +        'base_finds__is_isolated': 'base_finds__is_isolated', +        'image': 'image__isnull'}) +get_findsource = get_item( +    models.FindSource, 'get_findsource', 'findsource',      extra_request_keys={          'find__context_record__operation__year':              'find__context_record__operation__year', -        'find__dating__period':'find__dating__period__pk', -        'find__description':'find__description__icontains', -}) +        'find__dating__period': 'find__dating__period__pk', +        'find__description': 'find__description__icontains', +    })  show_find = show_item(models.Find, 'find')  revert_find = revert_item(models.Find) @@ -74,12 +82,14 @@ find_modification_wizard = FindModificationWizard.as_view([      label=_(u"Find modification"),      url_name='find_modification',) +  def find_modify(request, pk): -    view = find_modification_wizard(request) +    # view = find_modification_wizard(request)      FindModificationWizard.session_set_value( -                    request, 'selec-find_modification', 'pk', pk, reset=True) -    return redirect(reverse('find_modification', -                            kwargs={'step':'find-find_modification'})) +        request, 'selec-find_modification', 'pk', pk, reset=True) +    return redirect( +        reverse('find_modification', +                kwargs={'step': 'find-find_modification'}))  find_source_creation_wizard = FindSourceWizard.as_view([ @@ -116,8 +126,8 @@ treatment_creation_wizard = TreatmentWizard.as_view([      condition_dict={          'selecfind-treatment_creation':              check_treatment('basetreatment-treatment_creation', -                           'treatment_type', not_type_list=['physical_grouping', -                                                            'packaging']), +                          'treatment_type', not_type_list=['physical_grouping', +                                                           'packaging']),          'multiselecfinds-treatment_creation':              check_treatment('basetreatment-treatment_creation',                              'treatment_type', ['physical_grouping', diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index b1f2e053b..27f8bae08 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -27,7 +27,9 @@ from django import forms  from django.conf import settings  from django.core import validators  from django.db.models import Max -from django.forms.formsets import DELETION_FIELD_NAME, TOTAL_FORM_COUNT + +from django.forms.formsets import formset_factory, DELETION_FIELD_NAME, \ +    TOTAL_FORM_COUNT  from django.utils.translation import ugettext_lazy as _, pgettext_lazy  from django.utils.safestring import mark_safe @@ -45,7 +47,7 @@ import models  from widgets import ParcelWidget, SelectParcelWidget  from ishtar_common import widgets -from ishtar_common.forms import FinalForm, FormSet, formset_factory, get_now, \ +from ishtar_common.forms import FinalForm, FormSet, get_now, \      reverse_lazy, get_form_selection, TableSelect  from ishtar_common.forms_common import TownFormSet, SourceForm, SourceSelect, \      get_town_field diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index e6f21ae5b..a5abdddcd 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -22,27 +22,18 @@ Forms definition  """  import datetime  import re -from itertools import groupby  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.urlresolvers import reverse  from django.core import validators -from django.core.exceptions import ObjectDoesNotExist -from django.core.mail import send_mail -from django.db.models import Max -from django.forms.formsets import formset_factory, BaseFormSet, \ -                                  DELETION_FIELD_NAME -from django.shortcuts import render_to_response -from django.template import Context, RequestContext, loader +from django.forms.formsets import BaseFormSet, DELETION_FIELD_NAME  from django.utils import formats  from django.utils.functional import lazy  from django.utils.translation import ugettext_lazy as _  # from formwizard.forms import NamedUrlSessionFormWizard +  class NamedUrlSessionFormWizard(forms.Form):      def __init__(self, form_list, condition_list={}, url_name=''):          self.form_list = dict(form_list) @@ -59,8 +50,11 @@ import widgets  reverse_lazy = lazy(reverse, unicode)  regexp_name = re.compile(r"^[,:/\w\-'\"() \&\[\]@]+$", re.UNICODE) -name_validator = validators.RegexValidator(regexp_name, -_(u"Enter a valid name consisting of letters, spaces and hyphens."), 'invalid') +name_validator = validators.RegexValidator( +    regexp_name, +    _(u"Enter a valid name consisting of letters, spaces and hyphens."), +    'invalid') +  class FloatField(forms.FloatField):      """ @@ -71,14 +65,17 @@ class FloatField(forms.FloatField):              value = value.replace(',', '.').replace('%', '')          return super(FloatField, self).clean(value) +  class FinalForm(forms.Form):      final = True      form_label = _(u"Confirm") +  class FinalDeleteForm(FinalForm):      confirm_msg = " "      confirm_end_msg = _(u"Are you sure you want to delete?") +  class FormSet(BaseFormSet):      def check_duplicate(self, key_names, error_msg=""):          """Check for duplicate items in the formset""" @@ -91,7 +88,8 @@ class FormSet(BaseFormSet):              form = self.forms[i]              if not form.is_valid():                  continue -            item = [key_name in form.cleaned_data and form.cleaned_data[key_name] +            item = [key_name in form.cleaned_data and +                    form.cleaned_data[key_name]                      for key_name in key_names]              if not [v for v in item if v]:                  continue @@ -104,6 +102,7 @@ class FormSet(BaseFormSet):          form.fields[DELETION_FIELD_NAME].label = ''          form.fields[DELETION_FIELD_NAME].widget = widgets.DeleteWidget() +  class TableSelect(forms.Form):      def __init__(self, *args, **kwargs):          super(TableSelect, self).__init__(*args, **kwargs) @@ -113,19 +112,23 @@ class TableSelect(forms.Form):      def get_input_ids(self):          return self.fields.keys() +  def get_now():      format = formats.get_format('DATE_INPUT_FORMATS')[0]      value = datetime.datetime.now().strftime(format)      return value +  class ClosingDateFormSelection(forms.Form):      form_label = _("Closing date")      end_date = forms.DateField(label=_(u"Closing date"),                                 widget=widgets.JQueryDate) -def get_form_selection(class_name, label, key, model, base_form, get_url, -                not_selected_error=_(u"You should select an item."), new=False, -                new_message=_(u"Add a new item")): + +def get_form_selection( +        class_name, label, key, model, base_form, get_url, +        not_selected_error=_(u"You should select an item."), new=False, +        new_message=_(u"Add a new item")):      """      Generate a class selection form          class_name -- name of the class @@ -137,15 +140,17 @@ def get_form_selection(class_name, label, key, model, base_form, get_url,          new -- can add new items          new_message -- message of link to add new items      """ -    attrs = {'_main_key':key, -             '_not_selected_error':not_selected_error, -             'form_label':label, -             'associated_models':{key:model}, -             'currents':{key:model},} -    attrs[key] = forms.IntegerField(label="", required=False, +    attrs = {'_main_key': key, +             '_not_selected_error': not_selected_error, +             'form_label': label, +             'associated_models': {key: model}, +             'currents': {key: model}} +    attrs[key] = forms.IntegerField( +        label="", required=False,          validators=[models.valid_id(model)],          widget=widgets.JQueryJqGrid(reverse_lazy(get_url), base_form, model,                                      new=new, new_message=new_message)) +      def clean(self):          cleaned_data = self.cleaned_data          if self._main_key not in cleaned_data \ @@ -155,19 +160,21 @@ def get_form_selection(class_name, label, key, model, base_form, get_url,      attrs['clean'] = clean      return type(class_name, (forms.Form,), attrs) +  class DocumentGenerationForm(forms.Form):      """      Form to generate document by choosing the template      """ -    _associated_model = None # ex: AdministrativeAct -    _associated_object_name = '' # ex: 'archaeological_operations.models.AdministrativeAct' +    _associated_model = None  # ex: AdministrativeAct +    # ex: 'archaeological_operations.models.AdministrativeAct' +    _associated_object_name = ''      document_template = forms.ChoiceField(label=_("Template"), choices=[])      def __init__(self, *args, **kwargs):          super(DocumentGenerationForm, self).__init__(*args, **kwargs)          self.fields['document_template'].choices = \ -                models.DocumentTemplate.get_tuples( -                    dct={'associated_object_name':self._associated_object_name}) +            models.DocumentTemplate.get_tuples( +                dct={'associated_object_name': self._associated_object_name})      def save(self, object_pk):          try: @@ -176,7 +183,7 @@ class DocumentGenerationForm(forms.Form):              return          try:              template = models.DocumentTemplate.objects.get( -                            pk=self.cleaned_data.get('document_template')) +                pk=self.cleaned_data.get('document_template'))          except models.DocumentTemplate.DoesNotExist:              return          return template.publish(c_object) diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py index 509b9fbc5..b2aa565bb 100644 --- a/ishtar_common/forms_common.py +++ b/ishtar_common/forms_common.py @@ -20,19 +20,14 @@  """  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.exceptions import ObjectDoesNotExist, ValidationError -from django.core.mail import send_mail -from django.forms.formsets import formset_factory, DELETION_FIELD_NAME +from django.core.exceptions import ObjectDoesNotExist +from django.forms.formsets import formset_factory  from django.forms.models import BaseModelFormSet -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 _ @@ -40,27 +35,33 @@ 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"<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>") +    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." +        u"</p>\n<p>Only the first twenty results are displayed but specifying " +        u"the department code is generally sufficient to get the appropriate " +        u"result.</p>\n<p class='example'>For instance type \"saint denis 93\"" +        u" for getting the french town Saint-Denis in the Seine-Saint-Denis " +        u"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=label, -         help_text=mark_safe(help_text), required=required) +        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_advanced_town_field(label=_(u"Town"), required=True):      # !FIXME hard_link, reverse_lazy doen't seem to work with formsets      return forms.IntegerField( -         widget=widgets.JQueryTown("/" + settings.URL_PATH + \ -                                   'autocomplete-advanced-town'), -         validators=[models.valid_id(models.Town)], label=label, -         required=required) +        widget=widgets.JQueryTown( +            "/" + settings.URL_PATH + 'autocomplete-advanced-town'), +        validators=[models.valid_id(models.Town)], label=label, +        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 @@ -69,12 +70,13 @@ def get_person_field(label=_(u"Person"), required=True, person_types=[]):      if person_types:          person_types = [              unicode(models.PersonType.objects.get(txt_idx=person_type).pk) -                       for person_type in person_types] +            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 NewItemForm(forms.Form):      def __init__(self, *args, **kwargs):          self.limits = {} @@ -97,6 +99,7 @@ class NewItemForm(forms.Form):                  if len(new_choices) == 1:                      self.fields[key].initial = [new_choices[0][0]] +  class NewImportForm(forms.ModelForm):      class Meta:          model = models.Import @@ -106,12 +109,13 @@ class NewImportForm(forms.ModelForm):          self.instance.user = user          return super(NewImportForm, self).save(commit) +  class TargetKeyForm(forms.ModelForm):      class Meta:          model = models.TargetKey          fields = ('target', 'key', 'value')          widgets = { -            'key': forms.TextInput(attrs={'readonly':'readonly'}), +            'key': forms.TextInput(attrs={'readonly': 'readonly'}),              'value': forms.Select(),          } @@ -121,7 +125,8 @@ class TargetKeyForm(forms.ModelForm):          if instance and instance.pk:              self.fields['target'].widget.attrs['readonly'] = True              self.fields['key'].widget.attrs['readonly'] = True -        self.fields['value'].widget.choices = list(instance.target.get_choices()) +        self.fields['value'].widget.choices = list( +            instance.target.get_choices())          self.fields['key'].required = False          self.fields['value'].required = False @@ -146,11 +151,12 @@ class TargetKeyForm(forms.ModelForm):              self.associated_import = None              self.instance.save() +  class OrganizationForm(NewItemForm):      form_label = _(u"Organization") -    associated_models = {'organization_type':models.OrganizationType} -    name = forms.CharField(label=_(u"Name"), max_length=300, -                              validators=[name_validator]) +    associated_models = {'organization_type': models.OrganizationType} +    name = forms.CharField( +        label=_(u"Name"), max_length=300, validators=[name_validator])      organization_type = forms.ChoiceField(label=_(u"Organization type"),                                            choices=[])      address = forms.CharField(label=_(u"Address"), widget=forms.Textarea, @@ -170,20 +176,21 @@ class OrganizationForm(NewItemForm):      def __init__(self, *args, **kwargs):          super(OrganizationForm, self).__init__(*args, **kwargs)          self.fields['organization_type'].choices = \ -                                          models.OrganizationType.get_types() +            models.OrganizationType.get_types()          self.fields['organization_type'].help_text = \ -                                          models.OrganizationType.get_help() +            models.OrganizationType.get_help()          self.limit_fields()      def save(self, user):          dct = self.cleaned_data          dct['history_modifier'] = user          dct['organization_type'] = models.OrganizationType.objects.get( -                                                    pk=dct['organization_type']) +            pk=dct['organization_type'])          new_item = models.Organization(**dct)          new_item.save()          return new_item +  class OrganizationSelect(TableSelect):      name = forms.CharField(label=_(u"Name"), max_length=300)      organization_type = forms.ChoiceField(label=_(u"Type"), choices=[]) @@ -191,56 +198,65 @@ class OrganizationSelect(TableSelect):      def __init__(self, *args, **kwargs):          super(OrganizationSelect, self).__init__(*args, **kwargs)          self.fields['organization_type'].choices = \ -                                models.OrganizationType.get_types() +            models.OrganizationType.get_types() +  class OrganizationFormSelection(forms.Form):      form_label = _(u"Organization search") -    associated_models = {'pk':models.Organization} -    currents = {'pk':models.Organization} -    pk = forms.IntegerField(label="", -         widget=widgets.JQueryJqGrid(reverse_lazy('get-organization'), -                                     OrganizationSelect, models.Organization), -         validators=[models.valid_id(models.Organization)]) +    associated_models = {'pk': models.Organization} +    currents = {'pk': models.Organization} +    pk = forms.IntegerField( +        label="", +        widget=widgets.JQueryJqGrid(reverse_lazy('get-organization'), +                                    OrganizationSelect, models.Organization), +        validators=[models.valid_id(models.Organization)]) +  class BaseOrganizationForm(forms.ModelForm):      form_prefix = "orga" +      class Meta:          model = models.Organization          fields = ['name', 'organization_type', 'address', 'address_complement', -                  'town', 'postal_code',] +                  'town', 'postal_code'] +  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=75)      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)]) +    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)]) +    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 SimplePersonForm(NewItemForm):      form_label = _("Identity") -    associated_models = {'attached_to':models.Organization} +    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]) +                           validators=[name_validator])      address = forms.CharField(label=_(u"Address"), widget=forms.Textarea,                                required=False)      address_complement = forms.CharField(label=_(u"Address complement"), @@ -254,28 +270,31 @@ class SimplePersonForm(NewItemForm):      phone = forms.CharField(label=_(u"Phone"), max_length=18, required=False)      mobile_phone = forms.CharField(label=_(u"Town"), max_length=18,                                     required=False) -    attached_to = forms.IntegerField(label=_("Current organization"), +    attached_to = forms.IntegerField( +        label=_("Current organization"),          widget=widgets.JQueryAutoComplete( -                    reverse_lazy('autocomplete-organization'), -                    associated_model=models.Organization, new=True), +            reverse_lazy('autocomplete-organization'), +            associated_model=models.Organization, new=True),          validators=[models.valid_id(models.Organization)], required=False) +  class BasePersonForm(forms.ModelForm):      class Meta:          model = models.Person          fields = ['title', 'name', 'surname', 'address', 'address_complement',                    'town', 'postal_code'] +  class BaseOrganizationPersonForm(forms.ModelForm):      class Meta:          model = models.Person -        fields = ['attached_to', 'title', 'name', 'surname',] -        widgets = {'attached_to':widgets.JQueryPersonOrganization( -                reverse_lazy('autocomplete-organization'), -                reverse_lazy('organization_create'), -                model=models.Organization, -                attrs={'hidden':True}, -                new=True), +        fields = ['attached_to', 'title', 'name', 'surname'] +        widgets = {'attached_to': widgets.JQueryPersonOrganization( +            reverse_lazy('autocomplete-organization'), +            reverse_lazy('organization_create'), +            model=models.Organization, +            attrs={'hidden': True}, +            new=True),          }      def __init__(self, *args, **kwargs): @@ -293,14 +312,16 @@ class BaseOrganizationPersonForm(forms.ModelForm):                  person.save()          return person +  class PersonForm(SimplePersonForm): -    person_types = forms.MultipleChoiceField(label=_("Person type"), -                             choices=[], widget=forms.CheckboxSelectMultiple) +    person_types = forms.MultipleChoiceField( +        label=_("Person type"), choices=[], +        widget=forms.CheckboxSelectMultiple)      def __init__(self, *args, **kwargs):          super(PersonForm, self).__init__(*args, **kwargs)          self.fields['person_types'].choices = models.PersonType.get_types( -                                                         empty_first=False) +            empty_first=False)          self.fields['person_types'].help_text = models.PersonType.get_help()          self.limit_fields() @@ -309,48 +330,58 @@ class PersonForm(SimplePersonForm):          dct['history_modifier'] = user          if 'attached_to' in dct and dct['attached_to']:              dct['attached_to'] = models.Organization.objects.get( -                                                     pk=dct['attached_to']) +                pk=dct['attached_to'])          person_types = dct.pop('person_types')          new_item = models.Person.objects.create(**dct)          for pt in person_types:              new_item.person_types.add(pt)          return new_item + +class NoOrgaPersonForm(PersonForm): +    def __init__(self, *args, **kwargs): +        super(NoOrgaPersonForm, self).__init__(*args, **kwargs) +        self.fields.pop('attached_to') + +  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) +    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) +            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) +    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 = 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) +        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}) +                kwargs['initial'].update({'username': account.username, +                                          'email': account.email})              except ObjectDoesNotExist:                  pass          return super(AccountForm, self).__init__(*args, **kwargs) @@ -358,23 +389,25 @@ class AccountForm(forms.Form):      def clean(self):          cleaned_data = self.cleaned_data          password = cleaned_data.get("hidden_password") -        if password and password != cleaned_data.get("hidden_password_confirm"): +        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 "\ +                raise forms.ValidationError(_(u"You must provide a correct "                                                u"password."))          # check username unicity -        usernames = models.IshtarUser.objects.filter(username= -                                                  cleaned_data.get('username')) +        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") @@ -385,12 +418,14 @@ class FinalAccountForm(forms.Form):          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} +    associated_models = {'town': models.Town}      town = get_town_field(required=False) +  class TownFormSet(FormSet):      def clean(self):          """Checks that no towns are duplicated.""" @@ -400,9 +435,11 @@ class TownFormSet(FormSet):  TownFormset = formset_factory(TownForm, can_delete=True, formset=TownFormSet)  TownFormset.form_label = _("Towns") +  class MergeFormSet(BaseModelFormSet):      from_key = ''      to_key = '' +      def __init__(self, *args, **kwargs):          self._cached_list = []          super(MergeFormSet, self).__init__(*args, **kwargs) @@ -426,11 +463,11 @@ class MergeFormSet(BaseModelFormSet):          if self.is_bound and i < self.initial_form_count():              # Import goes here instead of module-level because importing              # django.db has side effects. -            from django.db import connections +            #  from django.db import connections              pk_key = "%s-%s" % (self.add_prefix(i), self.model._meta.pk.name)              pk = self.data[pk_key] -            pk_field = self.model._meta.pk -            """pk = pk_field.get_db_prep_lookup('exact', pk, +            """pk_field = self.model._meta.pk +            pk = pk_field.get_db_prep_lookup('exact', pk,                  connection=connections[self.get_queryset().db])"""              pk = self.get_restricted_queryset()[i].pk              if isinstance(pk, list): @@ -441,7 +478,8 @@ class MergeFormSet(BaseModelFormSet):          if i >= self.initial_form_count() and self.initial_extra:              # Set initial values for extra forms              try: -                kwargs['initial'] = self.initial_extra[i-self.initial_form_count()] +                kwargs['initial'] = \ +                    self.initial_extra[i-self.initial_form_count()]              except IndexError:                  pass          return super(BaseModelFormSet, self)._construct_form(i, **kwargs) @@ -464,8 +502,10 @@ class MergeFormSet(BaseModelFormSet):          self._cached_list = res          return res +  class MergeForm(forms.ModelForm): -    id = forms.IntegerField(label=u"", widget=forms.HiddenInput, required=False) +    id = forms.IntegerField( +        label=u"", widget=forms.HiddenInput, required=False)      a_is_duplicate_b = forms.BooleanField(required=False)      b_is_duplicate_a = forms.BooleanField(required=False)      not_duplicate = forms.BooleanField(required=False) @@ -492,13 +532,14 @@ class MergeForm(forms.ModelForm):          else:              return          try: -            reverse = self.instance.__class__.objects.get( -                **{self.TO_KEY:from_item, -                   self.FROM_KEY:to_item}).delete() +            self.instance.__class__.objects.get( +                **{self.TO_KEY: from_item, +                   self.FROM_KEY: to_item}).delete()          except ObjectDoesNotExist:              pass          self.instance.delete() +  class MergePersonForm(MergeForm):      class Meta:          model = models.Person @@ -507,6 +548,7 @@ class MergePersonForm(MergeForm):      FROM_KEY = 'from_person'      TO_KEY = 'to_person' +  class MergeOrganizationForm(MergeForm):      class Meta:          model = models.Organization @@ -521,12 +563,12 @@ class MergeOrganizationForm(MergeForm):  ######################  class SourceForm(forms.Form):      form_label = _(u"Documentation informations") -    associated_models = {'source_type':models.SourceType} +    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)")) +    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, @@ -536,12 +578,14 @@ class SourceForm(forms.Form):          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) +        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=[]) @@ -550,6 +594,7 @@ class SourceSelect(TableSelect):          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?") @@ -558,14 +603,16 @@ class SourceDeletionForm(FinalForm):  # Authors management #  ###################### +  class AuthorForm(NewItemForm):      form_label = _(u"Author") -    associated_models = {'person':models.Person, -                         'author_type':models.AuthorType} +    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")) +        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): @@ -576,7 +623,7 @@ class AuthorForm(NewItemForm):      def save(self, user):          dct = self.cleaned_data          dct['author_type'] = models.AuthorType.objects.get( -                                                     pk=dct['author_type']) +            pk=dct['author_type'])          dct['person'] = models.Person.objects.get(pk=dct['person'])          new_item = models.Author(**dct)          new_item.save() @@ -586,11 +633,13 @@ class AuthorForm(NewItemForm):  class AuthorFormSelection(forms.Form):      form_label = _(u"Author selection")      base_model = 'author' -    associated_models = {'author':models.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")) +        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): @@ -601,4 +650,3 @@ class AuthorFormSet(FormSet):  AuthorFormset = formset_factory(AuthorFormSelection, can_delete=True,                                  formset=AuthorFormSet)  AuthorFormset.form_label = _("Authors") - diff --git a/ishtar_common/templates/blocks/JQueryAutocomplete.js b/ishtar_common/templates/blocks/JQueryAutocomplete.js index eb365c38a..038acf1ba 100644 --- a/ishtar_common/templates/blocks/JQueryAutocomplete.js +++ b/ishtar_common/templates/blocks/JQueryAutocomplete.js @@ -1,8 +1,13 @@ +{% load replace_underscore %} +var base_source_{{field_id|replace_underscore}} = {{source}}; +var source_{{field_id|replace_underscore}} = base_source_{{field_id|replace_underscore}}; +  $("#id_select_{{field_id}}").autocomplete({ -    source: {{source}}, +    source: source_{{field_id|replace_underscore}},      select: function( event, ui ) {              if(ui.item){                  $('#id_{{field_id}}').val(ui.item.id); +                $('#id_{{field_id}}').change();              } else {                  $('#id_{{field_id}}').val(null);              } @@ -17,3 +22,17 @@ $('#id_select_{{field_id}}').live('click', function(){      $('#id_select_{{field_id}}').val(null);  }); + +{% if dynamic_limit %}{% for item_id in dynamic_limit %} +$('#{{item_id}}').change(function(){ +    $("#id_select_{{field_id}}").autocomplete( "option", "source", +        base_source_{{field_id|replace_underscore}} + $('#{{item_id}}').val() +        + '/'); +    if ($('#{{item_id}}').val()){ +        $("#id_select_{{field_id}}").prop("disabled", false); +    } else { +        $("#id_select_{{field_id}}").prop("disabled", true); +    } +}); +$('#{{item_id}}').change(); +{% endfor %}{% endif %} diff --git a/ishtar_common/templatetags/replace_underscore.py b/ishtar_common/templatetags/replace_underscore.py index 66931e6fe..d49fcf4fb 100644 --- a/ishtar_common/templatetags/replace_underscore.py +++ b/ishtar_common/templatetags/replace_underscore.py @@ -5,6 +5,7 @@ from django.template import Library  register = Library() +  @register.filter  def replace_underscore(value):      return value.replace('-', '_') diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py index bce968b51..eb0fe7ac2 100644 --- a/ishtar_common/urls.py +++ b/ishtar_common/urls.py @@ -18,7 +18,7 @@  # See the file COPYING for details.  from django.conf import settings -from django.conf.urls.defaults import * +from django.conf.urls.defaults import patterns, include, url  from django.conf.urls.static import static  from menus import menu @@ -29,53 +29,54 @@ urlpatterns, actions = [], []  # forms -urlpatterns = patterns('', -       # internationalization -       url(r'^i18n/', include('django.conf.urls.i18n')), -       # General -       url(r'person_search/(?P<step>.+)?$', -           views.person_search_wizard, name='person_search'), -       url(r'person_creation/(?P<step>.+)?$', -           views.person_creation_wizard, name='person_creation'), -       url(r'person_modification/(?P<step>.+)?$', -           views.person_modification_wizard, name='person_modification'), -       url(r'person_deletion/(?P<step>.+)?$', -           views.person_deletion_wizard, name='person_deletion'), -       url(r'^person-edit/$', -           views.PersonCreate.as_view(), name='person_create'), -       url(r'^person-edit/(?P<pk>\d+)$', -           views.PersonEdit.as_view(), name='person_edit'), -       url(r'organization_search/(?P<step>.+)?$', -           views.organization_search_wizard, name='organization_search'), -       url(r'organization_creation/(?P<step>.+)?$', -           views.organization_creation_wizard, name='organization_creation'), -       url(r'organization_modification/(?P<step>.+)?$', -           views.organization_modification_wizard, -           name='organization_modification'), -       url(r'organization_deletion/(?P<step>.+)?$', -           views.organization_deletion_wizard, name='organization_deletion'), -       url(r'organization-edit/$', -           views.OrganizationCreate.as_view(), name='organization_create'), -       url(r'organization-edit/(?P<pk>\d+)$', -           views.OrganizationEdit.as_view(), name='organization_edit'), -       url(r'organization-person-edit/$', -           views.OrganizationPersonCreate.as_view(), -           name='organization_person_create'), -       url(r'organization-person-edit/(?P<pk>\d+)$', -           views.OrganizationPersonEdit.as_view(), -           name='organization_person_edit'), -       url(r'account_management/(?P<step>.+)?$', -           views.account_management_wizard, name='account_management'), -       url(r'^import-new/$', views.NewImportView.as_view(), name='new_import'), -       url(r'^import-list/$', views.ImportListView.as_view(), -           name='current_imports'), -       url(r'^import-list-old/$', views.ImportOldListView.as_view(), -           name='old_imports'), -       url(r'^import-delete/(?P<pk>[0-9]+)/$', -           views.ImportDeleteView.as_view(), name='import_delete'), -       url(r'^import-link-unmatched/(?P<pk>[0-9]+)/$', -           views.ImportLinkView.as_view(), name='import_link_unmatched'), -       ) +urlpatterns = patterns( +    '', +    # internationalization +    url(r'^i18n/', include('django.conf.urls.i18n')), +    # General +    url(r'person_search/(?P<step>.+)?$', +        views.person_search_wizard, name='person_search'), +    url(r'person_creation/(?P<step>.+)?$', +        views.person_creation_wizard, name='person_creation'), +    url(r'person_modification/(?P<step>.+)?$', +        views.person_modification_wizard, name='person_modification'), +    url(r'person_deletion/(?P<step>.+)?$', +        views.person_deletion_wizard, name='person_deletion'), +    url(r'^person-edit/$', +        views.PersonCreate.as_view(), name='person_create'), +    url(r'^person-edit/(?P<pk>\d+)$', +        views.PersonEdit.as_view(), name='person_edit'), +    url(r'organization_search/(?P<step>.+)?$', +        views.organization_search_wizard, name='organization_search'), +    url(r'organization_creation/(?P<step>.+)?$', +        views.organization_creation_wizard, name='organization_creation'), +    url(r'organization_modification/(?P<step>.+)?$', +        views.organization_modification_wizard, +        name='organization_modification'), +    url(r'organization_deletion/(?P<step>.+)?$', +        views.organization_deletion_wizard, name='organization_deletion'), +    url(r'organization-edit/$', +        views.OrganizationCreate.as_view(), name='organization_create'), +    url(r'organization-edit/(?P<pk>\d+)$', +        views.OrganizationEdit.as_view(), name='organization_edit'), +    url(r'organization-person-edit/$', +        views.OrganizationPersonCreate.as_view(), +        name='organization_person_create'), +    url(r'organization-person-edit/(?P<pk>\d+)$', +        views.OrganizationPersonEdit.as_view(), +        name='organization_person_edit'), +    url(r'account_management/(?P<step>.+)?$', +        views.account_management_wizard, name='account_management'), +    url(r'^import-new/$', views.NewImportView.as_view(), name='new_import'), +    url(r'^import-list/$', views.ImportListView.as_view(), +        name='current_imports'), +    url(r'^import-list-old/$', views.ImportOldListView.as_view(), +        name='old_imports'), +    url(r'^import-delete/(?P<pk>[0-9]+)/$', +        views.ImportDeleteView.as_view(), name='import_delete'), +    url(r'^import-link-unmatched/(?P<pk>[0-9]+)/$', +        views.ImportLinkView.as_view(), name='import_link_unmatched'), +)  for section in menu.childs:      for menu_item in section.childs:          if hasattr(menu_item, 'childs'): @@ -86,50 +87,57 @@ for section in menu.childs:  actions = r"|".join(actions)  # other views -urlpatterns += patterns('ishtar_common.views', -     # General -     url(r'dashboard-main/$', 'dashboard_main', -           name='dashboard-main'), -     url(r'dashboard-main/(?P<item_name>[a-z-]+)/$', 'dashboard_main_detail', -           name='dashboard-main-detail'), -     url(r'update-current-item/$', 'update_current_item', -           name='update-current-item'), -     url(r'new-person/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$', -           'new_person', name='new-person'), -     url(r'autocomplete-person(?:/([0-9_]+))?/(user)?$', 'autocomplete_person', -           name='autocomplete-person'), -     url(r'get-person/(?P<type>.+)?$', 'get_person', -           name='get-person'), -     url(r'show-person(?:/(?P<pk>.+))?/(?P<type>.+)?$', -           'show_person', name='show-person'), -     url(r'department-by-state/(?P<state_id>.+)?$', 'department_by_state', -           name='department-by-state'), -     url(r'autocomplete-town/?$', 'autocomplete_town', -           name='autocomplete-town'), -     url(r'autocomplete-advanced-town/(?P<department_id>[0-9]+[ABab]?)?$', +urlpatterns += patterns( +    'ishtar_common.views', +    # General +    url(r'dashboard-main/$', 'dashboard_main', +        name='dashboard-main'), +    url(r'dashboard-main/(?P<item_name>[a-z-]+)/$', 'dashboard_main_detail', +        name='dashboard-main-detail'), +    url(r'update-current-item/$', 'update_current_item', +        name='update-current-item'), +    url(r'new-person/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$', +        'new_person', name='new-person'), +    url(r'new-person-noorga/' +        r'(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$', +        'new_person_noorga', name='new-person-noorga'), +    url(r'autocomplete-person(?:/([0-9_]+))?(?:/([0-9_]*))?/(user)?$', +        'autocomplete_person', name='autocomplete-person'), +    url(r'get-person/(?P<type>.+)?$', 'get_person', +        name='get-person'), +    url(r'show-person(?:/(?P<pk>.+))?/(?P<type>.+)?$', +        'show_person', name='show-person'), +    url(r'department-by-state/(?P<state_id>.+)?$', 'department_by_state', +        name='department-by-state'), +    url(r'autocomplete-town/?$', 'autocomplete_town', +        name='autocomplete-town'), +    url(r'autocomplete-advanced-town/(?P<department_id>[0-9]+[ABab]?)?$',          'autocomplete_advanced_town', name='autocomplete-advanced-town'), -     url(r'autocomplete-department/?$', 'autocomplete_department', -           name='autocomplete-department'), -     url(r'new-author/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$', -           'new_author', name='new-author'), -     url(r'autocomplete-author/$', 'autocomplete_author', -           name='autocomplete-author'), -     url(r'new-organization/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$', -           'new_organization', name='new-organization'), -     url(r'get-organization/(?P<type>.+)?$', 'get_organization', -           name='get-organization'), -     url(r'show-organization(?:/(?P<pk>.+))?/(?P<type>.+)?$', -           'show_organization', name='show-organization'), -     url(r'autocomplete-organization/([0-9_]+)?$', -           'autocomplete_organization', name='autocomplete-organization'), -     url(r'admin-globalvar/', views.GlobalVarEdit.as_view(), +    url(r'autocomplete-department/?$', 'autocomplete_department', +        name='autocomplete-department'), +    url(r'new-author/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$', +        'new_author', name='new-author'), +    url(r'autocomplete-author/$', 'autocomplete_author', +        name='autocomplete-author'), +    url(r'new-organization/(?:(?P<parent_name>[^/]+)/)?' +        r'(?:(?P<limits>[^/]+)/)?$', +        'new_organization', name='new-organization'), +    url(r'get-organization/(?P<type>.+)?$', 'get_organization', +        name='get-organization'), +    url(r'show-organization(?:/(?P<pk>.+))?/(?P<type>.+)?$', +        'show_organization', name='show-organization'), +    url(r'autocomplete-organization/([0-9_]+)?$', +        'autocomplete_organization', name='autocomplete-organization'), +    url(r'admin-globalvar/', views.GlobalVarEdit.as_view(),          name='admin-globalvar'), -     url(r'person_merge/(?:(?P<page>\d+)/)?$', 'person_merge', name='person_merge'), -     url(r'organization_merge/(?:(?P<page>\d+)/)?$', 'organization_merge', -         name='organization_merge'), -     url(r'reset/$', 'reset_wizards', name='reset_wizards'), -     url(r'(?P<action_slug>' + actions + r')/$', 'action', name='action'), +    url(r'person_merge/(?:(?P<page>\d+)/)?$', 'person_merge', +        name='person_merge'), +    url(r'organization_merge/(?:(?P<page>\d+)/)?$', 'organization_merge', +        name='organization_merge'), +    url(r'reset/$', 'reset_wizards', name='reset_wizards'), +    url(r'(?P<action_slug>' + actions + r')/$', 'action', name='action'),  )  if settings.DEBUG: -    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) +    urlpatterns += static(settings.STATIC_URL, +                          document_root=settings.STATIC_ROOT) diff --git a/ishtar_common/views.py b/ishtar_common/views.py index 0058821b2..fc8151d8d 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -19,14 +19,14 @@  from tidylib import tidy_document as tidy -import re  import csv -import json +import cStringIO as StringIO  import datetime +import ho.pisa as pisa +import json  import optparse -import cStringIO as StringIO +import re  from tempfile import NamedTemporaryFile -import ho.pisa as pisa  import unicodedata  from extra_views import ModelFormSetView @@ -34,17 +34,17 @@ from extra_views import ModelFormSetView  from django.conf import settings  from django.contrib.auth import logout  from django.contrib.auth.decorators import login_required -from django.core import serializers  from django.core.exceptions import ObjectDoesNotExist  from django.core.urlresolvers import reverse, NoReverseMatch -from django.db.models import Q, F, ImageField -from django.forms.models import model_to_dict, modelformset_factory -from django.http import HttpResponse, Http404, HttpResponseRedirect +from django.db.models import Q, ImageField +from django.forms.models import modelformset_factory +from django.http import HttpResponse, Http404, HttpResponseRedirect, \ +    HttpResponseBadRequest  from django.shortcuts import render_to_response, redirect  from django.template import RequestContext, loader  from django.utils.decorators import method_decorator  from django.utils.translation import ugettext, ugettext_lazy as _ -from django.views.generic import ListView, UpdateView, CreateView +from django.views.generic import ListView, UpdateView  from django.views.generic.edit import CreateView, DeleteView  from xhtml2odt import xhtml2odt @@ -56,11 +56,14 @@ from archaeological_operations.forms import DashboardForm as DashboardFormOpe  from ishtar_common.forms import FinalForm, FinalDeleteForm  from ishtar_common import forms_common as forms  from ishtar_common import wizards +from ishtar_common.models import HistoryError +  import models -CSV_OPTIONS = {'delimiter':';', 'quotechar':'"', 'quoting':csv.QUOTE_ALL} +CSV_OPTIONS = {'delimiter': ';', 'quotechar': '"', 'quoting': csv.QUOTE_ALL}  ENCODING = settings.ENCODING or 'utf-8' +  def index(request):      """      Main page @@ -68,69 +71,70 @@ def index(request):      dct = {}      try:          return render_to_response('index.html', dct, -                              context_instance=RequestContext(request)) +                                  context_instance=RequestContext(request))      except NoReverseMatch:          # probably rights exception (rights revoked)          logout(request)          return render_to_response('index.html', dct, -                              context_instance=RequestContext(request)) +                                  context_instance=RequestContext(request)) + +person_search_wizard = wizards.SearchWizard.as_view( +    [('general-person_search', forms.PersonFormSelection)], +    label=_(u"Person search"), +    url_name='person_search',) + +person_creation_wizard = wizards.PersonWizard.as_view( +    [('identity-person_creation', forms.SimplePersonForm), +     ('person_type-person_creation', forms.PersonTypeForm), +     ('final-person_creation', FinalForm)], +    label=_(u"New person"), +    url_name='person_creation') + +person_modification_wizard = wizards.PersonModifWizard.as_view( +    [('selec-person_modification', forms.PersonFormSelection), +     ('identity-person_modification', forms.SimplePersonForm), +     ('person_type-person_creation', forms.PersonTypeForm), +     ('final-person_modification', FinalForm)], +    label=_(u"Person modification"), +    url_name='person_modification') + +person_deletion_wizard = wizards.PersonDeletionWizard.as_view( +    [('selec-person_deletion', forms.PersonFormSelection), +     ('final-person_deletion', FinalDeleteForm)], +    label=_(u"Person deletion"), +    url_name='person_deletion',) + +organization_search_wizard = wizards.SearchWizard.as_view( +    [('general-organization_search', forms.OrganizationFormSelection)], +    label=_(u"Organization search"), +    url_name='organization_search',) + +organization_creation_wizard = wizards.OrganizationWizard.as_view( +    [('identity-organization_creation', forms.OrganizationForm), +     ('final-organization_creation', FinalForm)], +    label=_(u"New organization"), +    url_name='organization_creation') + +organization_modification_wizard = wizards.OrganizationModifWizard.as_view( +    [('selec-organization_modification', forms.OrganizationFormSelection), +     ('identity-organization_modification', forms.OrganizationForm), +     ('final-organization_modification', FinalForm)], +    label=_(u"Organization modification"), +    url_name='organization_modification') + +organization_deletion_wizard = wizards.OrganizationDeletionWizard.as_view( +    [('selec-organization_deletion', forms.OrganizationFormSelection), +     ('final-organization_deletion', FinalDeleteForm)], +    label=_(u"Organization deletion"), +    url_name='organization_deletion',) + +account_management_wizard = wizards.AccountWizard.as_view( +    [('selec-account_management', forms.PersonFormSelection), +     ('account-account_management', forms.AccountForm), +     ('final-account_management', forms.FinalAccountForm)], +    label=_(u"Account management"), +    url_name='account_management',) -person_search_wizard = wizards.SearchWizard.as_view([ -                        ('general-person_search', forms.PersonFormSelection)], -                        label=_(u"Person search"), -                        url_name='person_search',) - -person_creation_wizard = wizards.PersonWizard.as_view([ -                        ('identity-person_creation', forms.SimplePersonForm), -                        ('person_type-person_creation', forms.PersonTypeForm), -                        ('final-person_creation', FinalForm)], -                         label=_(u"New person"), -                         url_name='person_creation') - -person_modification_wizard = wizards.PersonModifWizard.as_view([ -                      ('selec-person_modification', forms.PersonFormSelection), -                      ('identity-person_modification', forms.SimplePersonForm), -                      ('person_type-person_creation', forms.PersonTypeForm), -                      ('final-person_modification', FinalForm)], -                       label=_(u"Person modification"), -                       url_name='person_modification') - -person_deletion_wizard = wizards.PersonDeletionWizard.as_view([ -          ('selec-person_deletion', forms.PersonFormSelection), -          ('final-person_deletion', FinalDeleteForm)], -                      label=_(u"Person deletion"), -                      url_name='person_deletion',) - -organization_search_wizard = wizards.SearchWizard.as_view([ -        ('general-organization_search', forms.OrganizationFormSelection)], -        label=_(u"Organization search"), -        url_name='organization_search',) - -organization_creation_wizard = wizards.OrganizationWizard.as_view([ -                    ('identity-organization_creation', forms.OrganizationForm), -                    ('final-organization_creation', FinalForm)], -                     label=_(u"New organization"), -                     url_name='organization_creation') - -organization_modification_wizard = wizards.OrganizationModifWizard.as_view([ -          ('selec-organization_modification', forms.OrganizationFormSelection), -          ('identity-organization_modification', forms.OrganizationForm), -          ('final-organization_modification', FinalForm)], -                       label=_(u"Organization modification"), -                       url_name='organization_modification') - -organization_deletion_wizard = wizards.OrganizationDeletionWizard.as_view([ -          ('selec-organization_deletion', forms.OrganizationFormSelection), -          ('final-organization_deletion', FinalDeleteForm)], -                      label=_(u"Organization deletion"), -                      url_name='organization_deletion',) - -account_management_wizard = wizards.AccountWizard.as_view([ -                    ('selec-account_management', forms.PersonFormSelection), -                    ('account-account_management', forms.AccountForm), -                    ('final-account_management', forms.FinalAccountForm)], -                     label=_(u"Account management"), -                     url_name='account_management',)  def update_current_item(request):      if not request.is_ajax() and not request.method == 'POST': @@ -139,15 +143,18 @@ def update_current_item(request):          request.session[request.POST['item']] = request.POST['value']      return HttpResponse('ok') +  def check_permission(request, action_slug, obj_id=None):      if action_slug not in menu.items: -        #! TODO +        # TODO          return True      if obj_id:          return menu.items[action_slug].is_available(request.user, obj_id)      return menu.items[action_slug].can_be_available(request.user) -def autocomplete_person(request, person_types=None, is_ishtar_user=None): + +def autocomplete_person(request, person_types=None, attached_to=None, +                        is_ishtar_user=None):      if not request.user.has_perm('ishtar_common.view_person', models.Person) and \         not request.user.has_perm('ishtar_common.view_own_person', models.Person) \         and not request.user.ishtaruser.has_right('person_search'): @@ -162,9 +169,13 @@ def autocomplete_person(request, person_types=None, is_ishtar_user=None):          return HttpResponseBadRequest()      query = Q()      for q in q.split(' '): -        query = query & (Q(name__icontains=q) | Q(surname__icontains=q) | \ -                 Q(email__icontains=q) | Q(attached_to__name__icontains=q)) -    if person_types and unicode(person_types) !=  '0': +        query = query & (Q(name__icontains=q) | Q(surname__icontains=q) | +                         Q(email__icontains=q) | +                         Q(attached_to__name__icontains=q)) +    if attached_to: +        query = query & Q(attached_to__pk__in=attached_to.split('_')) + +    if person_types and unicode(person_types) != '0':          try:              typs = [int(tp) for tp in person_types.split('_') if tp]              typ = models.PersonType.objects.filter(pk__in=typs).all() @@ -175,48 +186,51 @@ def autocomplete_person(request, person_types=None, is_ishtar_user=None):          query = query & Q(ishtaruser__isnull=False)      limit = 20      persons = models.Person.objects.filter(query)[:limit] -    data = json.dumps([{'id':person.pk, 'value':unicode(person)} -                                for person in persons if person]) +    data = json.dumps([{'id': person.pk, 'value': unicode(person)} +                       for person in persons if person])      return HttpResponse(data, mimetype='text/plain') +  def autocomplete_department(request):      if not request.GET.get('term'):          return HttpResponse(mimetype='text/plain')      q = request.GET.get('term') -    q = unicodedata.normalize("NFKD", q).encode('ascii','ignore') +    q = unicodedata.normalize("NFKD", q).encode('ascii', 'ignore')      query = Q()      for q in q.split(' '):          extra = (Q(label__icontains=q) | Q(number__istartswith=q))          query = query & extra      limit = 20      departments = models.Department.objects.filter(query)[:limit] -    data = json.dumps([{'id':department.pk, 'value':unicode(department)} -                                          for department in departments]) +    data = json.dumps([{'id': department.pk, 'value': unicode(department)} +                       for department in departments])      return HttpResponse(data, mimetype='text/plain') +  def autocomplete_town(request):      if not request.GET.get('term'):          return HttpResponse(mimetype='text/plain')      q = request.GET.get('term') -    q = unicodedata.normalize("NFKD", q).encode('ascii','ignore') +    q = unicodedata.normalize("NFKD", q).encode('ascii', 'ignore')      query = Q()      for q in q.split(' '):          extra = Q(name__icontains=q)          if settings.COUNTRY == 'fr': -            extra = (extra | Q(numero_insee__istartswith=q) | \ -                    Q(departement__label__istartswith=q)) +            extra = (extra | Q(numero_insee__istartswith=q) | +                     Q(departement__label__istartswith=q))          query = query & extra      limit = 20      towns = models.Town.objects.filter(query)[:limit] -    data = json.dumps([{'id':town.pk, 'value':unicode(town)} -                                          for town in towns]) +    data = json.dumps([{'id': town.pk, 'value': unicode(town)} +                       for town in towns])      return HttpResponse(data, mimetype='text/plain') +  def autocomplete_advanced_town(request, department_id=None, state_id=None):      if not request.GET.get('term'):          return HttpResponse(mimetype='text/plain')      q = request.GET.get('term') -    q = unicodedata.normalize("NFKD", q).encode('ascii','ignore') +    q = unicodedata.normalize("NFKD", q).encode('ascii', 'ignore')      query = Q()      for q in q.split(' '):          extra = Q(name__icontains=q) @@ -236,25 +250,24 @@ def autocomplete_advanced_town(request, department_id=None, state_id=None):          val = town.name          if hasattr(town, 'numero_insee'):              val += " (%s)" % town.numero_insee -        result.append({'id':town.pk, 'value':val}) +        result.append({'id': town.pk, 'value': val})      data = json.dumps(result)      return HttpResponse(data, mimetype='text/plain') +  def department_by_state(request, state_id=''):      if not state_id:          data = []      else:          departments = models.Department.objects.filter(state__number=state_id) -        data = json.dumps([{'id':department.pk, 'number':department.number, -                            'value':unicode(department)} -                                          for department in departments]) +        data = json.dumps([{'id': department.pk, 'number': department.number, +                            'value': unicode(department)} +                           for department in departments])      return HttpResponse(data, mimetype='text/plain') -from types import NoneType -  def format_val(val): -    if type(val) == NoneType: +    if val is None:          return u""      if type(val) == bool:          if val: @@ -267,33 +280,33 @@ HIERARCHIC_LEVELS = 5  HIERARCHIC_FIELDS = ['periods', 'period', 'unit', 'material_type',                       'conservatory_state']  PRIVATE_FIELDS = ('id', 'history_modifier', 'order') + +  def get_item(model, func_name, default_name, extra_request_keys=[], -            base_request={}, bool_fields=[], reversed_bool_fields=[], -            dated_fields=[], associated_models=[], relative_session_names={}, -            specific_perms=[]): +             base_request={}, bool_fields=[], reversed_bool_fields=[], +             dated_fields=[], associated_models=[], relative_session_names={}, +             specific_perms=[]):      """      Generic treatment of tables      """      def func(request, data_type='json', full=False, **dct):          # check rights -        own = True # more restrictive by default +        own = True  # more restrictive by default          allowed = False          for perm, lbl in model._meta.permissions:              # if not specific any perm is relevant (read right)              if specific_perms and perm not in specific_perms:                  continue              if request.user.has_perm(model._meta.app_label + '.' + perm) \ -             or (request.user.is_authenticated() -                 and request.user.ishtaruser.has_right(perm)): +                    or (request.user.is_authenticated() +                        and request.user.ishtaruser.has_right(perm)):                  allowed = True                  if "_own_" not in perm:                      own = False -                    break # max right reach -        EMPTY, mimetype = '', 'text/plain' +                    break  # max right reach +        EMPTY = ''          if 'type' in dct:              data_type = dct.pop('type') -            if data_type == 'csv': -               mimetype = 'text/csv'          if not data_type:              EMPTY = '[]'              data_type = 'json' @@ -301,18 +314,23 @@ def get_item(model, func_name, default_name, extra_request_keys=[],              return HttpResponse(EMPTY, mimetype='text/plain')          fields = [model._meta.get_field_by_name(k)[0]                    for k in model._meta.get_all_field_names()] -        request_keys = dict([(field.name, -            field.name + (hasattr(field, 'rel') and field.rel and '__pk' or '')) -                                for field in fields]) +        request_keys = dict([ +            (field.name, +             field.name + (hasattr(field, 'rel') and field.rel and '__pk' +                           or '')) +            for field in fields])          for associated_model, key in associated_models: -            associated_fields = [associated_model._meta.get_field_by_name(k)[0] -                          for k in associated_model._meta.get_all_field_names()] -            request_keys.update(dict([(key + "__" + field.name, -                key + "__" + field.name + (hasattr(field, 'rel') and -                                           field.rel and '__pk' or '')) -                                            for field in associated_fields])) +            associated_fields = [ +                associated_model._meta.get_field_by_name(k)[0] +                for k in associated_model._meta.get_all_field_names()] +            request_keys.update( +                dict([(key + "__" + field.name, +                       key + "__" + field.name + +                       (hasattr(field, 'rel') and field.rel and '__pk' or '')) +                      for field in associated_fields]))          request_keys.update(extra_request_keys) -        request_items = request.method == 'POST' and request.POST or request.GET +        request_items = request.method == 'POST' and request.POST \ +            or request.GET          dct = base_request.copy()          and_reqs, or_reqs = [], []          try: @@ -327,14 +345,15 @@ def get_item(model, func_name, default_name, extra_request_keys=[],          if not dct and 'submited' not in request_items:              if default_name in request.session and \                 request.session[default_name]: -                dct = {"pk":request.session[default_name]} +                dct = {"pk": request.session[default_name]}              else:                  for name in relative_session_names.keys():                      if name in request.session and request.session[name]:                          k = relative_session_names[name] -                        dct = {k:request.session[name]} +                        dct = {k: request.session[name]}                          break -            if (not dct or data_type == 'csv') and func_name in request.session: +            if (not dct or data_type == 'csv') \ +                    and func_name in request.session:                  dct = request.session[func_name]          else:              request.session[func_name] = dct @@ -351,7 +370,8 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                      if k.endswith('__isnull') and \                         isinstance(c_field, ImageField):                          if dct[k]: -                            or_reqs.append((k, {k.split('__')[0]+'__exact':''})) +                            or_reqs.append( +                                (k, {k.split('__')[0]+'__exact': ''}))                          else:                              dct[k.split('__')[0]+'__regex'] = '.{1}.*'          for k in dated_fields: @@ -362,8 +382,8 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                      items = dct[k].split('/')                      assert len(items) == 3                      dct[k] = datetime.date(*map(lambda x: int(x), -                                                reversed(items)) -                                            ).strftime('%Y-%m-%d') +                                                reversed(items)))\ +                                     .strftime('%Y-%m-%d')                  except AssertionError:                      dct.pop(k)          # manage hierarchic conditions @@ -374,18 +394,18 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                      q = None                      for idx, r in enumerate(req):                          if not idx: -                            q = Q(**{r:val}) +                            q = Q(**{r: val})                          else: -                            q = q | Q(**{r:val}) +                            q = q | Q(**{r: val})                      and_reqs.append(q)                      break                  elif req.endswith(k_hr + '__pk'):                      val = dct.pop(req) -                    reqs = Q(**{req:val}) +                    reqs = Q(**{req: val})                      req = req[:-2] + '__'                      for idx in xrange(HIERARCHIC_LEVELS):                          req = req[:-2] + 'parent__pk' -                        q = Q(**{req:val}) +                        q = Q(**{req: val})                          reqs = reqs | q                      and_reqs.append(reqs)                      break @@ -405,7 +425,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[],          # table cols          table_cols = full and [field.name for field in model._meta.fields                                 if field.name not in PRIVATE_FIELDS] \ -                     or model.TABLE_COLS +            or model.TABLE_COLS          # manage sort tables          manual_sort_key = None          order = request_items.get('sord') @@ -461,14 +481,15 @@ def get_item(model, func_name, default_name, extra_request_keys=[],                  for ky in k.split('.'):                      new_vals = []                      for val in vals: -                        if hasattr(val, 'all'): # manage related objects +                        if hasattr(val, 'all'):  # manage related objects                              val = list(val.all())                              for v in val:                                  new_vals.append(getattr(v, ky))                          elif val:                              new_vals.append(getattr(val, ky))                      vals = new_vals -                if vals and hasattr(vals[0], 'all'): # manage last related objects +                # manage last related objects +                if vals and hasattr(vals[0], 'all'):                      new_vals = []                      for val in vals:                          new_vals += list(val.all()) @@ -478,32 +499,33 @@ def get_item(model, func_name, default_name, extra_request_keys=[],          if manual_sort_key:              # +1 because the id is added as a first col              idx_col = table_cols.index(manual_sort_key) + 1 -            datas = sorted(datas, key=lambda x:x[idx_col]) +            datas = sorted(datas, key=lambda x: x[idx_col])              if sign == '-':                  datas = reversed(datas)              datas = list(datas)[start:end] -        link_template = "<a class='display_details' href='#' onclick='load_window(\"%%s\")'>%s</a>" % \ +        link_template = "<a class='display_details' href='#' "\ +                        "onclick='load_window(\"%%s\")'>%s</a>" % \                          (unicode(_("Details")))          if data_type == "json":              rows = []              for data in datas:                  try:                      lnk = link_template % reverse('show-'+default_name, -                                                      args=[data[0], '']) +                                                  args=[data[0], ''])                  except NoReverseMatch:                      print '"show-' + default_name + "\" args (" + \                            unicode(data[0]) + ") url not available"                      lnk = '' -                res = {'id':data[0], 'link':lnk} +                res = {'id': data[0], 'link': lnk}                  for idx, value in enumerate(data[1:]):                      if value:                          res[table_cols[idx].split('.')[-1]] = value                  rows.append(res)              data = json.dumps({ -                "records":items_nb, -                "rows":rows, -                "page":page_nb, -                "total":(items_nb/row_nb + 1) if row_nb else items_nb, +                "records": items_nb, +                "rows": rows, +                "page": page_nb, +                "total": (items_nb/row_nb + 1) if row_nb else items_nb,              })              return HttpResponse(data, mimetype='text/plain')          elif data_type == "csv": @@ -511,7 +533,8 @@ def get_item(model, func_name, default_name, extra_request_keys=[],              n = datetime.datetime.now()              filename = u'%s_%s.csv' % (default_name,                                         n.strftime('%Y%m%d-%H%M%S')) -            response['Content-Disposition'] = 'attachment; filename=%s'%filename +            response['Content-Disposition'] = 'attachment; filename=%s'\ +                                              % filename              writer = csv.writer(response, **CSV_OPTIONS)              col_names = []              for field_name in table_cols: @@ -529,6 +552,7 @@ def get_item(model, func_name, default_name, extra_request_keys=[],      return func +  def show_item(model, name, extra_dct=None):      def func(request, pk, **dct):          try: @@ -540,15 +564,15 @@ def show_item(model, name, extra_dct=None):                                       ).split('/')[:-2]) + u"/"          dct['current_window_url'] = url_name          date = 'date' in dct and dct.pop('date') -        dct['window_id'] = "%s-%d-%s" % (name, item.pk, -                                      datetime.datetime.now().strftime('%M%s')) +        dct['window_id'] = "%s-%d-%s" % ( +            name, item.pk, datetime.datetime.now().strftime('%M%s'))          if hasattr(item, 'history'):              if date:                  try:                      date = datetime.datetime.strptime(date,                                                        '%Y-%m-%dT%H:%M:%S.%f')                      item = item.get_previous(date=date) -                    assert item != None +                    assert item is not None                  except (ValueError, AssertionError):                      return HttpResponse(None, mimetype='text/plain')                  dct['previous'] = item._previous @@ -565,7 +589,6 @@ def show_item(model, name, extra_dct=None):              dct.update(extra_dct(request, item))          context_instance = RequestContext(request)          context_instance.update(dct) -        n = datetime.datetime.now()          filename = ""          if hasattr(item, 'history_object'):              filename = item.history_object.associated_filename @@ -575,9 +598,9 @@ def show_item(model, name, extra_dct=None):              tpl = loader.get_template('ishtar/sheet_%s.html' % name)              content = tpl.render(context_instance)              try: -                tidy_options = {'output-xhtml':1, 'indent':1, -                                'tidy-mark':0, 'doctype':'auto', -                                'add-xml-decl':1, 'wrap':1} +                tidy_options = {'output-xhtml': 1, 'indent': 1, +                                'tidy-mark': 0, 'doctype': 'auto', +                                'add-xml-decl': 1, 'wrap': 1}                  html, errors = tidy(content, options=tidy_options)                  html = html.encode('utf-8').replace(" ", " ")                  html = re.sub('<pre([^>]*)>\n', '<pre\\1>', html) @@ -602,12 +625,12 @@ def show_item(model, name, extra_dct=None):                  odtfile.open()                  odtfile.import_xhtml(html)                  odtfile = odtfile.save() -            except xhtml2odt.ODTExportError, ex: +            except xhtml2odt.ODTExportError:                  return HttpResponse(content, content_type="application/xhtml")              response = HttpResponse( -                            mimetype='application/vnd.oasis.opendocument.text') +                mimetype='application/vnd.oasis.opendocument.text')              response['Content-Disposition'] = 'attachment; filename=%s.odt' % \ -                                                                       filename +                                              filename              response.write(odtfile)              return response          elif doc_type == 'pdf': @@ -621,7 +644,7 @@ def show_item(model, name, extra_dct=None):              response = HttpResponse(result.getvalue(),                                      mimetype='application/pdf')              response['Content-Disposition'] = 'attachment; filename=%s.pdf' % \ -                                                                       filename +                                              filename              if not pdf.err:                  return response              return HttpResponse(content, content_type="application/xhtml") @@ -631,6 +654,7 @@ def show_item(model, name, extra_dct=None):              return HttpResponse(content, content_type="application/xhtml")      return func +  def revert_item(model):      def func(request, pk, date, **dct):          try: @@ -642,11 +666,12 @@ def revert_item(model):          return HttpResponse("True", mimetype='text/plain')      return func +  def autocomplete_organization(request, orga_type=None):      if (not request.user.has_perm('ishtar_common.view_organization', -                                 models.Organization) and \ -       not request.user.has_perm('ishtar_common.view_own_organization', -                                 models.Organization) +        models.Organization) and +        not request.user.has_perm('ishtar_common.view_own_organization', +                                  models.Organization)         and not request.user.ishtaruser.has_right('person_search')):          return HttpResponse(mimetype='text/plain')      if not request.GET.get('term'): @@ -665,14 +690,15 @@ def autocomplete_organization(request, orga_type=None):              pass      limit = 15      organizations = models.Organization.objects.filter(query)[:limit] -    data = json.dumps([{'id':org.pk, 'value':unicode(org)} -                                          for org in organizations]) +    data = json.dumps([{'id': org.pk, 'value': unicode(org)} +                       for org in organizations])      return HttpResponse(data, mimetype='text/plain') +  def autocomplete_author(request):      if not request.user.has_perm('ishtar_common.view_author', models.Author)\         and not request.user.has_perm('ishtar_common.view_own_author', -                                     models.Author) : +                                     models.Author):          return HttpResponse(mimetype='text/plain')      if not request.GET.get('term'):          return HttpResponse(mimetype='text/plain') @@ -680,23 +706,24 @@ def autocomplete_author(request):      query = Q()      for q in q.split(' '):          extra = Q(person__name__icontains=q) | \ -                Q(person__surname__icontains=q) | \ -                Q(person__email__icontains=q) | \ -                Q(author_type__label__icontains=q) +            Q(person__surname__icontains=q) | \ +            Q(person__email__icontains=q) | \ +            Q(author_type__label__icontains=q)          query = query & extra      limit = 15      authors = models.Author.objects.filter(query)[:limit] -    data = json.dumps([{'id':author.pk, 'value':unicode(author)} -                                          for author in authors]) +    data = json.dumps([{'id': author.pk, 'value': unicode(author)} +                       for author in authors])      return HttpResponse(data, mimetype='text/plain') +  def new_item(model, frm):      def func(request, parent_name, limits=''):          model_name = model._meta.object_name          if not check_permission(request, 'add_'+model_name.lower()):              not_permitted_msg = ugettext(u"Operation not permitted.")              return HttpResponse(not_permitted_msg) -        dct = {'title':unicode(_(u'New %s' % model_name.lower()))} +        dct = {'title': unicode(_(u'New %s' % model_name.lower()))}          if request.method == 'POST':              dct['form'] = frm(request.POST, limits=limits)              if dct['form'].is_valid(): @@ -708,8 +735,9 @@ def new_item(model, frm):                  if dct['parent_pk'] and '_select_' in dct['parent_pk']:                      parents = dct['parent_pk'].split('_')                      dct['parent_pk'] = "_".join([parents[0]] + parents[2:]) -                return render_to_response('window.html', dct, -                                  context_instance=RequestContext(request)) +                return render_to_response( +                    'window.html', dct, +                    context_instance=RequestContext(request))          else:              dct['form'] = frm(limits=limits)          return render_to_response('window.html', dct, @@ -717,24 +745,28 @@ def new_item(model, frm):      return func  new_person = new_item(models.Person, forms.PersonForm) +new_person_noorga = new_item(models.Person, forms.NoOrgaPersonForm)  new_organization = new_item(models.Organization, forms.OrganizationForm)  show_organization = show_item(models.Organization, 'organization') -get_organization = get_item(models.Organization, -        'get_organization', 'organization', -      extra_request_keys={ -                  'name':'name__icontains', -                  'organization_type':'organization_type__pk__in', -                  },) +get_organization = get_item( +    models.Organization, +    'get_organization', 'organization', +    extra_request_keys={ +        'name': 'name__icontains', +        'organization_type': 'organization_type__pk__in', +    })  new_author = new_item(models.Author, forms.AuthorForm)  show_person = show_item(models.Person, 'person') -get_person = get_item(models.Person, -        'get_person', 'person', -      extra_request_keys={ -                  'name':'name__icontains', -                  'surname':'surname__icontains', -                  'attached_to':'attached_to__pk', -                  'person_types':'person_types__pk__in', -                  },) +get_person = get_item( +    models.Person, +    'get_person', 'person', +    extra_request_keys={ +        'name': 'name__icontains', +        'surname': 'surname__icontains', +        'attached_to': 'attached_to__pk', +        'person_types': 'person_types__pk__in', +    }) +  def action(request, action_slug, obj_id=None, *args, **kwargs):      """ @@ -744,7 +776,6 @@ def action(request, action_slug, obj_id=None, *args, **kwargs):          not_permitted_msg = ugettext(u"Operation not permitted.")          return HttpResponse(not_permitted_msg)      request.session['CURRENT_ACTION'] = action_slug -    associated_wizard = action_slug + '_wizard'      dct = {}      globals_dct = globals()      if action_slug in globals_dct: @@ -752,6 +783,7 @@ def action(request, action_slug, obj_id=None, *args, **kwargs):      return render_to_response('index.html', dct,                                context_instance=RequestContext(request)) +  def dashboard_main(request, dct, obj_id=None, *args, **kwargs):      """      Main dashboard @@ -764,9 +796,9 @@ def dashboard_main(request, dct, obj_id=None, *args, **kwargs):          app_list.append((_(u"Context records"), 'contextrecords'))      if 'archaeological_finds' in settings.INSTALLED_APPS:          app_list.append((_(u"Finds"), 'finds')) -    dct = {'app_list':app_list} +    dct = {'app_list': app_list}      return render_to_response('ishtar/dashboards/dashboard_main.html', dct, -                               context_instance=RequestContext(request)) +                              context_instance=RequestContext(request))  DASHBOARD_FORMS = {}  if 'archaeological_files' in settings.INSTALLED_APPS: @@ -775,20 +807,21 @@ if 'archaeological_files' in settings.INSTALLED_APPS:  DASHBOARD_FORMS['operations'] = DashboardFormOpe +  def dashboard_main_detail(request, item_name):      """      Specific tab of the main dashboard      """      if item_name == 'users': -        dct = {'ishtar_users':models.UserDashboard()} +        dct = {'ishtar_users': models.UserDashboard()}          return render_to_response( -                    'ishtar/dashboards/dashboard_main_detail_users.html', -                            dct, context_instance=RequestContext(request)) +            'ishtar/dashboards/dashboard_main_detail_users.html', +            dct, context_instance=RequestContext(request))      form = None -    slicing, date_source, fltr, show_detail  = 'year', None, {}, False -    if (item_name == 'files' and \ -      'archaeological_files' in settings.INSTALLED_APPS) \ -      or item_name == 'operations': +    slicing, date_source, fltr, show_detail = 'year', None, {}, False +    if (item_name == 'files' and +        'archaeological_files' in settings.INSTALLED_APPS) \ +            or item_name == 'operations':          slicing = 'month'      if item_name in DASHBOARD_FORMS:          if request.method == 'POST': @@ -803,16 +836,16 @@ def dashboard_main_detail(request, item_name):          else:              form = DASHBOARD_FORMS[item_name]()      lbl, dashboard = None, None -    if (item_name == 'files' and \ -      'archaeological_files' in settings.INSTALLED_APPS) \ -      or item_name == 'operations': -        dashboard_kwargs = {'slice':slicing, 'fltr':fltr, -                            'show_detail':show_detail} +    if (item_name == 'files' and +        'archaeological_files' in settings.INSTALLED_APPS) \ +            or item_name == 'operations': +        dashboard_kwargs = {'slice': slicing, 'fltr': fltr, +                            'show_detail': show_detail}          # date_source is only relevant when the form has set one          if date_source:              dashboard_kwargs['date_source'] = date_source      if item_name == 'files' and \ -      'archaeological_files' in settings.INSTALLED_APPS: +            'archaeological_files' in settings.INSTALLED_APPS:          from archaeological_files.models import File          lbl, dashboard = (_(u"Archaeological files"),                            models.Dashboard(File, **dashboard_kwargs)) @@ -821,26 +854,29 @@ def dashboard_main_detail(request, item_name):          lbl, dashboard = (_(u"Operations"),                            models.Dashboard(Operation, **dashboard_kwargs))      if item_name == 'contextrecords' and \ -      'archaeological_context_records' in settings.INSTALLED_APPS: +            'archaeological_context_records' in settings.INSTALLED_APPS:          from archaeological_context_records.models import ContextRecord -        lbl, dashboard = (_(u"Context records"), models.Dashboard(ContextRecord, -                                                    slice=slicing, fltr=fltr)) +        lbl, dashboard = ( +            _(u"Context records"), +            models.Dashboard(ContextRecord, slice=slicing, fltr=fltr))      if item_name == 'finds' and \ -       'archaeological_finds' in settings.INSTALLED_APPS: +            'archaeological_finds' in settings.INSTALLED_APPS:          from archaeological_finds.models import Find          lbl, dashboard = (_(u"Finds"), models.Dashboard(Find, -                                                    slice=slicing, fltr=fltr)) +                                                        slice=slicing, +                                                        fltr=fltr))      if not lbl:          raise Http404 -    dct = {'lbl':lbl, 'dashboard':dashboard, -           'item_name':item_name.replace('-', '_'), +    dct = {'lbl': lbl, 'dashboard': dashboard, +           'item_name': item_name.replace('-', '_'),             'VALUE_QUOTE': '' if slicing == "year" else "'", -           'form':form, 'slicing':slicing} +           'form': form, 'slicing': slicing}      n = datetime.datetime.now()      dct['unique_id'] = dct['item_name'] + "_" + \ -                '%d_%d_%d' % (n.minute, n.second, n.microsecond) +        '%d_%d_%d' % (n.minute, n.second, n.microsecond)      return render_to_response('ishtar/dashboards/dashboard_main_detail.html', -                            dct, context_instance=RequestContext(request)) +                              dct, context_instance=RequestContext(request)) +  def reset_wizards(request):      # dynamicaly execute each reset_wizards of each ishtar app @@ -857,18 +893,21 @@ def reset_wizards(request):      return redirect(reverse('start'))  ITEM_PER_PAGE = 20 + +  def merge_action(model, form, key):      def merge(request, page=1):          current_url = key + '_merge'          if not page:              page = 1          page = int(page) -        FormSet = modelformset_factory(model.merge_candidate.through, -                                 form=form, formset=forms.MergeFormSet ,extra=0) +        FormSet = modelformset_factory( +            model.merge_candidate.through, form=form, +            formset=forms.MergeFormSet, extra=0)          q = model.merge_candidate.through.objects -        context = {'current_url':current_url, -                   'current_page':page, -                   'max_page':q.count()/ITEM_PER_PAGE} +        context = {'current_url': current_url, +                   'current_page': page, +                   'max_page': q.count()/ITEM_PER_PAGE}          if page < context["max_page"]:              context['next_page'] = page + 1          if page > 1: @@ -885,25 +924,32 @@ def merge_action(model, form, key):              context['formset'] = FormSet(request.POST, queryset=queryset)              if context['formset'].is_valid():                  context['formset'].merge() -                return redirect(reverse(current_url, kwargs={'page':page})) +                return redirect(reverse(current_url, kwargs={'page': page}))          else:              context['formset'] = FormSet(queryset=queryset) -        return render_to_response('ishtar/merge_'+key+'.html', context, -                              context_instance=RequestContext(request)) +        return render_to_response( +            'ishtar/merge_'+key+'.html', context, +            context_instance=RequestContext(request))      return merge  person_merge = merge_action(models.Person, forms.MergePersonForm, 'person') -organization_merge = merge_action(models.Organization, forms.MergeOrganizationForm, -                            'organization') +organization_merge = merge_action( +    models.Organization, +    forms.MergeOrganizationForm, +    'organization' +) +  class IshtarMixin(object):      page_name = u"" +      def get_context_data(self, **kwargs):          context = super(IshtarMixin, self).get_context_data(**kwargs)          context['page_name'] = self.page_name          return context +  class LoginRequiredMixin(object):      @method_decorator(login_required)      def dispatch(self, request, *args, **kwargs): @@ -915,12 +961,14 @@ class LoginRequiredMixin(object):          return super(LoginRequiredMixin, self).dispatch(request, *args,                                                          **kwargs) +  class AdminLoginRequiredMixin(LoginRequiredMixin):      def dispatch(self, request, *args, **kwargs):          if not request.user.is_staff:              return redirect(reverse('start')) -        return super(AdminLoginRequiredMixin, self).dispatch(request, *args, -                                                        **kwargs) +        return super(AdminLoginRequiredMixin, self).dispatch( +            request, *args, **kwargs) +  class GlobalVarEdit(IshtarMixin, AdminLoginRequiredMixin, ModelFormSetView):      template_name = 'ishtar/formset.html' @@ -930,6 +978,7 @@ class GlobalVarEdit(IshtarMixin, AdminLoginRequiredMixin, ModelFormSetView):      page_name = _(u"Global variables")      fields = ['slug', 'value', 'description'] +  class NewImportView(IshtarMixin, LoginRequiredMixin, CreateView):      template_name = 'ishtar/form.html'      model = models.Import @@ -944,6 +993,7 @@ class NewImportView(IshtarMixin, LoginRequiredMixin, CreateView):          self.object = form.save(user=user)          return HttpResponseRedirect(self.get_success_url()) +  class ImportListView(IshtarMixin, LoginRequiredMixin, ListView):      template_name = 'ishtar/import_list.html'      model = models.Import @@ -952,8 +1002,8 @@ class ImportListView(IshtarMixin, LoginRequiredMixin, ListView):      def get_queryset(self):          user = models.IshtarUser.objects.get(pk=self.request.user.pk) -        return self.model.objects.filter(user=user).exclude(state='AC' -                                        ).order_by('-creation_date') +        return self.model.objects.filter(user=user).exclude( +            state='AC').order_by('-creation_date')      def post(self, request, *args, **kwargs):          for field in request.POST: @@ -972,7 +1022,7 @@ class ImportListView(IshtarMixin, LoginRequiredMixin, ListView):              action = request.POST[field]              if action == 'D':                  return HttpResponseRedirect(reverse('import_delete', -                                                    kwargs={'pk':imprt.pk})) +                                                    kwargs={'pk': imprt.pk}))              elif action == 'A':                  imprt.initialize()              elif action == 'I': @@ -981,12 +1031,15 @@ class ImportListView(IshtarMixin, LoginRequiredMixin, ListView):                  imprt.archive()          return HttpResponseRedirect(reverse(self.current_url)) +  class ImportOldListView(ImportListView):      current_url = 'old_imports' +      def get_queryset(self):          user = models.IshtarUser.objects.get(pk=self.request.user.pk) -        return self.model.objects.filter(user=user, state='AC' -                                        ).order_by('-creation_date') +        return self.model.objects.filter( +            user=user, state='AC').order_by('-creation_date') +  class ImportLinkView(IshtarMixin, LoginRequiredMixin, ModelFormSetView):      template_name = 'ishtar/formset.html' @@ -996,12 +1049,13 @@ class ImportLinkView(IshtarMixin, LoginRequiredMixin, ModelFormSetView):      form_class = forms.TargetKeyForm      def get_queryset(self): -        return self.model.objects.filter(is_set=False, -                   associated_import=self.kwargs['pk']) +        return self.model.objects.filter( +            is_set=False, associated_import=self.kwargs['pk'])      def get_success_url(self):          return reverse('current_imports') +  class ImportDeleteView(IshtarMixin, LoginRequiredMixin, DeleteView):      template_name = 'ishtar/import_delete.html'      model = models.Import @@ -1010,6 +1064,7 @@ class ImportDeleteView(IshtarMixin, LoginRequiredMixin, DeleteView):      def get_success_url(self):          return reverse('current_imports') +  class PersonCreate(LoginRequiredMixin, CreateView):      model = models.Person      form_class = forms.BasePersonForm @@ -1018,6 +1073,7 @@ class PersonCreate(LoginRequiredMixin, CreateView):      def get_success_url(self):          return reverse('person_edit', args=[self.object.pk]) +  class PersonEdit(LoginRequiredMixin, UpdateView):      model = models.Person      form_class = forms.BasePersonForm @@ -1026,6 +1082,7 @@ class PersonEdit(LoginRequiredMixin, UpdateView):      def get_success_url(self):          return reverse('person_edit', args=[self.object.pk]) +  class OrganizationCreate(LoginRequiredMixin, CreateView):      model = models.Organization      form_class = forms.BaseOrganizationForm @@ -1038,6 +1095,7 @@ class OrganizationCreate(LoginRequiredMixin, CreateView):              kwargs.update({'prefix': self.form_class.form_prefix})          return kwargs +  class OrganizationEdit(LoginRequiredMixin, UpdateView):      model = models.Organization      form_class = forms.BaseOrganizationForm @@ -1049,6 +1107,7 @@ class OrganizationEdit(LoginRequiredMixin, UpdateView):              kwargs.update({'prefix': self.form_class.form_prefix})          return kwargs +  class OrganizationPersonCreate(LoginRequiredMixin, CreateView):      model = models.Person      form_class = forms.BaseOrganizationPersonForm @@ -1064,6 +1123,7 @@ class OrganizationPersonCreate(LoginRequiredMixin, CreateView):      def get_success_url(self):          return reverse('organization_person_edit', args=[self.object.pk]) +  class OrganizationPersonEdit(LoginRequiredMixin, UpdateView):      model = models.Person      form_class = forms.BaseOrganizationPersonForm @@ -1072,7 +1132,7 @@ class OrganizationPersonEdit(LoginRequiredMixin, UpdateView):      def get_context_data(self, *args, **kwargs):          data = super(OrganizationPersonEdit, self).get_context_data(*args, -                                                                      **kwargs) +                                                                    **kwargs)          data['relative_label'] = self.relative_label          return data diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index ba7e61e46..efafa38e2 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2014 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2015 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet>  # Copyright (C) 2007  skam <massimo dot scamarcia at gmail.com>  #                          (http://djangosnippets.org/snippets/233/) @@ -21,7 +21,7 @@  from django import forms  from django.conf import settings -from django.core.urlresolvers import resolve, reverse +from django.core.urlresolvers import reverse  from django.db.models import fields  from django.forms import ClearableFileInput  from django.forms.widgets import flatatt @@ -44,7 +44,7 @@ class Select2Multiple(forms.SelectMultiple):          css = {              'all': ('select2/css/select2.css',)          } -        js = ('select2/js/select2.min.js',  +        js = ('select2/js/select2.min.js',                'select2/js/init.js')      def render(self, name, value, attrs=None, choices=()): @@ -54,7 +54,8 @@ class Select2Multiple(forms.SelectMultiple):              attrs = {}          attrs['class'] = klass          return super(Select2Multiple, self).render(name, value, attrs, -                                                              choices) +                                                   choices) +  class MultipleAutocompleteField(forms.MultipleChoiceField):      def __init__(self, *args, **kwargs): @@ -65,10 +66,10 @@ class MultipleAutocompleteField(forms.MultipleChoiceField):              kwargs['choices'] = []          new = kwargs.pop('new') if 'new' in kwargs else None          if 'widget' not in kwargs and self.model: -            kwargs['widget'] = JQueryAutoComplete(reverse_lazy( -                    'autocomplete-'+self.model.__name__.lower()), -                    associated_model=self.model, new=new, -                    multiple=True) +            kwargs['widget'] = JQueryAutoComplete( +                reverse_lazy('autocomplete-'+self.model.__name__.lower()), +                associated_model=self.model, new=new, +                multiple=True)          super(MultipleAutocompleteField, self).__init__(*args, **kwargs)      def get_choices(self): @@ -89,17 +90,18 @@ class MultipleAutocompleteField(forms.MultipleChoiceField):                      val = value                      value = []                      for v in val: -                        v = unicode(v).strip('[').strip(']' -                                     ).strip('u').strip("'").strip('"') -                        value += [int(v.strip()) -                                            for v in list(set(v.split(','))) -                                                                if v.strip()] +                        v = unicode(v).strip('[').strip(']')\ +                                      .strip('u').strip("'").strip('"') +                        value += [int(va.strip()) +                                  for va in list(set(v.split(','))) +                                  if va.strip()]              except (TypeError, ValueError):                  value = []          else:              value = []          return super(MultipleAutocompleteField, self).clean(value) +  class DeleteWidget(forms.CheckboxInput):      def render(self, name, value, attrs=None):          final_attrs = flatatt(self.build_attrs(attrs, name=name, @@ -109,28 +111,31 @@ class DeleteWidget(forms.CheckboxInput):          output.append('</td></tr>')          return mark_safe('\n'.join(output)) +  class ImageFileInput(ClearableFileInput):      template_with_initial = u'<span class="prettyPhoto">%(initial)s</span>'\ -                      u' %(clear_template)s<br />%(input_text)s: %(input)s' +        u' %(clear_template)s<br />%(input_text)s: %(input)s' +  class SquareMeterWidget(forms.TextInput):      def render(self, name, value, attrs=None):          if not value:              value = u""          final_attrs = flatatt(self.build_attrs(attrs, name=name, value=value)) -        dct = {'final_attrs':final_attrs, -               'unit':settings.SURFACE_UNIT_LABEL, -               'id':attrs['id'], -               "safe_id":attrs['id'].replace('-', '_')} +        dct = {'final_attrs': final_attrs, +               'unit': settings.SURFACE_UNIT_LABEL, +               'id': attrs['id'], +               "safe_id": attrs['id'].replace('-', '_')}          t = loader.get_template('blocks/SquareMeterWidget.html')          rendered = t.render(Context(dct))          return mark_safe(rendered)  AreaWidget = forms.TextInput +  if settings.SURFACE_UNIT == 'square-metre': -    #global AreaWidget      AreaWidget = SquareMeterWidget +  class JQueryDate(forms.TextInput):      def __init__(self, *args, **kwargs):          super(JQueryDate, self).__init__(*args, **kwargs) @@ -166,12 +171,14 @@ class JQueryDate(forms.TextInput):      }      $(window).load(load_jquerydate_%(var_name)s);  //--></script> -""" % {"name":name, "var_name":var_name, "country":settings.COUNTRY} +""" % {"name": name, "var_name": var_name, "country": settings.COUNTRY}          return rendered +  class JQueryAutoComplete(forms.TextInput):      def __init__(self, source, associated_model=None, options={}, attrs={}, -                 new=False, multiple=False, limit={}): +                 new=False, url_new='', multiple=False, limit={}, +                 dynamic_limit=[]):          """          Source can be a list containing the autocomplete values or a          string containing the url used for the request. @@ -184,8 +191,10 @@ class JQueryAutoComplete(forms.TextInput):              self.options = JSONEncoder().encode(options)          self.attrs.update(attrs)          self.new = new +        self.url_new = url_new          self.multiple = multiple          self.limit = limit +        self.dynamic_limit = dynamic_limit      def value_from_datadict(self, data, files, name):          if self.multiple: @@ -203,8 +212,14 @@ class JQueryAutoComplete(forms.TextInput):                  source = "'" + unicode(self.source) + "'"              except:                  raise ValueError('source type is not valid') -        dct = {'source':mark_safe(source), -               'field_id':field_id,} +        dynamic_limit = [ +            'id_' + lim.replace('_', '') + '-' + +            '-'.join(field_id.split('-')[1:-1]) + '-' + lim +            for lim in self.dynamic_limit +        ] +        dct = {'source': mark_safe(source), +               'field_id': field_id, +               'dynamic_limit': dynamic_limit}          if self.options:              dct['options'] = mark_safe('%s' % self.options) @@ -253,7 +268,7 @@ class JQueryAutoComplete(forms.TextInput):                  if hiddens and selects:                      attrs_hidden['value'] = hiddens[0]                      attrs_select['value'] = selects[0] -        if not self.attrs.has_key('id'): +        if 'id' not in self.attrs:              attrs_hidden['id'] = 'id_%s' % name              attrs_select['id'] = 'id_select_%s' % name          if 'class' not in attrs_select: @@ -264,11 +279,14 @@ class JQueryAutoComplete(forms.TextInput):              limits = []              for k in self.limit:                  limits.append(k + "__" + "-".join( -                            [unicode(v) for v in self.limit[k]])) +                              [unicode(v) for v in self.limit[k]]))              args = [attrs_select['id']]              if limits:                  args.append(';'.join(limits)) -            url_new = reverse('new-' + model_name, args=args) +            url_new = 'new-' + model_name +            if self.url_new: +                url_new = self.url_new +            url_new = reverse(url_new, args=args)              new = u'  <a href="#" class="add-button" '\                    u'onclick="open_window(\'%s\');">+</a>' % url_new          html = u'''<input%(attrs_select)s/>%(new)s\ @@ -276,13 +294,14 @@ class JQueryAutoComplete(forms.TextInput):          <script type="text/javascript"><!--//          $(function() {%(js)s});//--></script>          ''' % { -            'attrs_select' : flatatt(attrs_select), -            'attrs_hidden' : flatatt(attrs_hidden), -            'js' : self.render_js(name), -            'new':new +            'attrs_select': flatatt(attrs_select), +            'attrs_hidden': flatatt(attrs_hidden), +            'js': self.render_js(name), +            'new': new          }          return html +  class JQueryTown(forms.TextInput):      """      Town fields whith state and department pre-selections @@ -305,7 +324,7 @@ class JQueryTown(forms.TextInput):          if isinstance(source, list):              encoded_src = JSONEncoder().encode(source)          elif isinstance(source, str) \ -           or isinstance(source, unicode): +                or isinstance(source, unicode):              src = escape(source)              if not src.endswith('/'):                  src += "/" @@ -357,31 +376,32 @@ class JQueryTown(forms.TextInput):              if hiddens and selects:                  attrs_hidden['value'] = hiddens[0]                  attrs_select['value'] = selects[0] -        if not self.attrs.has_key('id'): +        if 'id' not in self.attrs:              attrs_hidden['id'] = 'id_%s' % name              attrs_select['id'] = 'id_select_%s' % name          if 'class' not in attrs_select:              attrs_select['class'] = 'autocomplete'          source = self.encode_source(self.source) -        dct = {'source':mark_safe(source), -               'selected':selected, -               'safe_field_id':slugify(name).replace('-', '_'), -               'field_id':name} +        dct = {'source': mark_safe(source), +               'selected': selected, +               'safe_field_id': slugify(name).replace('-', '_'), +               'field_id': name}          if self.options:              dct['options'] = mark_safe('%s' % self.options) -        dct.update({'attrs_select':mark_safe(flatatt(attrs_select)), -               'attrs_hidden':mark_safe(flatatt(attrs_hidden)), -               'name':name, -               'states':models.State.objects.all().order_by('label'), -               'selected_department':selected_department, -               'selected_state':selected_state -               }) -        html = loader.get_template('blocks/JQueryAdvancedTown.html').render( -                                                                Context(dct)) +        dct.update({'attrs_select': mark_safe(flatatt(attrs_select)), +                    'attrs_hidden': mark_safe(flatatt(attrs_hidden)), +                    'name': name, +                    'states': models.State.objects.all().order_by('label'), +                    'selected_department': selected_department, +                    'selected_state': selected_state} +                   ) +        html = loader.get_template('blocks/JQueryAdvancedTown.html')\ +                     .render(Context(dct))          return html +  class JQueryPersonOrganization(forms.TextInput):      """      Complex widget which manage: @@ -392,7 +412,7 @@ class JQueryPersonOrganization(forms.TextInput):      def __init__(self, source, edit_source, model, options={},                   attrs={}, new=False, limit={}, -                 html_template = 'blocks/PersonOrganization.html', +                 html_template='blocks/PersonOrganization.html',                   js_template='blocks/JQueryPersonOrganization.js'):          self.options = None          self.attrs = {} @@ -413,7 +433,7 @@ class JQueryPersonOrganization(forms.TextInput):          if isinstance(source, list):              encoded_src = JSONEncoder().encode(source)          elif isinstance(source, str) \ -           or isinstance(source, unicode): +                or isinstance(source, unicode):              encoded_src = "'%s'" % escape(source)          else:              try: @@ -425,11 +445,11 @@ class JQueryPersonOrganization(forms.TextInput):      def render_js(self, field_id, selected=''):          source = self.encode_source(self.source)          edit_source = self.encode_source(self.edit_source) -        dct = {'source':mark_safe(source), -               'edit_source':mark_safe(edit_source), -               'selected':selected, -               'safe_field_id':slugify(field_id).replace('-', '_'), -               'field_id':field_id} +        dct = {'source': mark_safe(source), +               'edit_source': mark_safe(edit_source), +               'selected': selected, +               'safe_field_id': slugify(field_id).replace('-', '_'), +               'field_id': field_id}          if self.options:              dct['options'] = mark_safe('%s' % self.options)          js = loader.get_template(self.js_template).render(Context(dct)) @@ -467,33 +487,33 @@ class JQueryPersonOrganization(forms.TextInput):              if hiddens and selects:                  attrs_hidden['value'] = hiddens[0]                  attrs_select['value'] = selects[0] -        if not self.attrs.has_key('id'): +        if 'id' not in self.attrs:              attrs_hidden['id'] = 'id_%s' % name              attrs_select['id'] = 'id_select_%s' % name          if 'class' not in attrs_select:              attrs_select['class'] = 'autocomplete'          new = '' -        dct = {'attrs_select':mark_safe(flatatt(attrs_select)), -               'attrs_hidden':mark_safe(flatatt(attrs_hidden)), -               'name':name, -               'js':self.render_js(name, selected), -               'new':mark_safe(new)} +        dct = {'attrs_select': mark_safe(flatatt(attrs_select)), +               'attrs_hidden': mark_safe(flatatt(attrs_hidden)), +               'name': name, +               'js': self.render_js(name, selected), +               'new': mark_safe(new)}          html = loader.get_template(self.html_template).render(Context(dct))          return html +  class JQueryJqGrid(forms.RadioSelect):      COL_TPL = "{name:'%(idx)s', index:'%(idx)s', sortable:true}" +      class Media:          js = ['%s/js/i18n/grid.locale-%s.js' % (settings.STATIC_URL,                                                  settings.COUNTRY), -              '%s/js/jquery.jqGrid.min.js' % settings.STATIC_URL, -             ] -        css = {'all':['%s/media/ui.jqgrid.css' % settings.STATIC_URL, -                     ]} +              '%s/js/jquery.jqGrid.min.js' % settings.STATIC_URL] +        css = {'all': ['%s/media/ui.jqgrid.css' % settings.STATIC_URL]}      def __init__(self, source, form, associated_model, attrs={}, -         table_cols='TABLE_COLS', multiple=False, multiple_cols=[2], new=False, -         new_message="", source_full=None): +                 table_cols='TABLE_COLS', multiple=False, multiple_cols=[2], +                 new=False, new_message="", source_full=None):          self.source = source          self.form = form          self.attrs = attrs @@ -507,7 +527,7 @@ class JQueryJqGrid(forms.RadioSelect):      def render(self, name, value=None, attrs=None):          t = loader.get_template('blocks/form_snippet.html')          form = self.form() -        rendered = t.render(Context({'form':form})) +        rendered = t.render(Context({'form': form}))          dct = {}          if self.new:              model_name = self.associated_model._meta.object_name.lower() @@ -516,7 +536,6 @@ class JQueryJqGrid(forms.RadioSelect):          extra_cols = []          col_names, col_idx = [], []          for k in form.get_input_ids(): -            #field = form.fields[k]              col_idx.append(u'"%s"' % k)          for field_name in getattr(self.associated_model, self.table_cols):              field = self.associated_model @@ -536,7 +555,7 @@ class JQueryJqGrid(forms.RadioSelect):                      else:                          continue              col_names.append(u'"%s"' % field_verbose_name) -            extra_cols.append(self.COL_TPL % {'idx':field_name}) +            extra_cols.append(self.COL_TPL % {'idx': field_name})          col_names = col_names and ", ".join(col_names) or ""          col_idx = col_idx and ", ".join(col_idx) or ""          extra_cols = extra_cols and ", ".join(extra_cols) or "" @@ -544,19 +563,18 @@ class JQueryJqGrid(forms.RadioSelect):          dct['source'] = unicode(self.source)          if unicode(self.source_full) and unicode(self.source_full) != 'None':              dct['source_full'] = unicode(self.source_full) -        dct.update({'name':name, -               'col_names':col_names, -               'extra_cols':extra_cols, -               'source':unicode(self.source), -               'col_idx':col_idx, -               'no_result':unicode(_("No results")), -               'loading':unicode(_("Loading...")), -               'remove':unicode(_(u"Remove")), -               'sname':name.replace('-', ''), -               'multiple':self.multiple, -               'multi_cols': ",".join((u'"%d"' % col \ -                                       for col in self.multiple_cols)) -              }) +        dct.update({'name': name, +                    'col_names': col_names, +                    'extra_cols': extra_cols, +                    'source': unicode(self.source), +                    'col_idx': col_idx, +                    'no_result': unicode(_("No results")), +                    'loading': unicode(_("Loading...")), +                    'remove': unicode(_(u"Remove")), +                    'sname': name.replace('-', ''), +                    'multiple': self.multiple, +                    'multi_cols': ",".join((u'"%d"' % col +                                           for col in self.multiple_cols))})          t = loader.get_template('blocks/JQueryJqGrid.html')          rendered += t.render(Context(dct))          return mark_safe(rendered) diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index af236504c..7da654b80 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -23,13 +23,15 @@ from django.conf import settings  from django.contrib.formtools.wizard.storage import get_storage  from django.contrib.formtools.wizard.views import NamedUrlWizardView, \      normalize_name +from django.contrib.sites.models import Site  from django.core.exceptions import ObjectDoesNotExist  from django.core.files.images import ImageFile +from django.core.mail import send_mail  from django.db.models.fields.files import FileField  from django.db.models.fields.related import ManyToManyField  from django.forms import ValidationError  from django.shortcuts import render_to_response -from django.template import RequestContext +from django.template import Context, RequestContext, loader  from django.utils.datastructures import MultiValueDict as BaseMultiValueDict  from django.utils.translation import ugettext_lazy as _  import models @@ -216,12 +218,13 @@ class Wizard(NamedUrlWizardView):                  if form_datas:                      form_datas.append(("", "", "spacer"))                  items = hasattr(base_form, 'fields') and \ -                        base_form.fields.keyOrder or cleaned_data.keys() +                    base_form.fields.keyOrder or cleaned_data.keys()                  for key in items:                      lbl = None                      if key.startswith('hidden_'):                          continue -                    if hasattr(base_form, 'fields') and key in base_form.fields: +                    if hasattr(base_form, 'fields') \ +                            and key in base_form.fields:                          lbl = base_form.fields[key].label                          if hasattr(base_form, 'associated_labels') \                             and key in base_form.associated_labels: @@ -229,22 +232,22 @@ class Wizard(NamedUrlWizardView):                      if not lbl:                          continue                      value = cleaned_data[key] -                    if not value and value != False: +                    if value is None or value == '':                          continue                      if key in self.translated_keys:                          value = _(value)                      if type(value) == bool: -                        if value == True: +                        if value:                              value = _(u"Yes") -                        elif value == False: +                        else:                              value = _(u"No")                      elif key in associated_models:                          values = []                          if type(value) in (tuple, list):                              values = value                          elif "," in unicode(value): -                            values = unicode(value -                                            ).strip('[').strip(']').split(",") +                            values = unicode( +                                value).strip('[').strip(']').split(",")                          else:                              values = [value]                          rendered_values = [] @@ -274,7 +277,7 @@ class Wizard(NamedUrlWizardView):                  return self.render(form)              base_form = hasattr(form, 'forms') and form.forms[0] or form              associated_models = hasattr(base_form, 'associated_models') and \ -                                base_form.associated_models or {} +                base_form.associated_models or {}              if hasattr(form, 'forms'):                  multi = False                  if form.forms: @@ -289,7 +292,8 @@ class Wizard(NamedUrlWizardView):                      multi = len(fields) > 1                      if multi:                          assert hasattr(frm, 'base_model'), \ -                       u"Must define a base_model for " + unicode(frm.__class__) +                            u"Must define a base_model for " + \ +                            unicode(frm.__class__)                  for frm in form.forms:                      if not frm.is_valid():                          continue @@ -300,10 +304,11 @@ class Wizard(NamedUrlWizardView):                          frm.cleaned_data.pop('DELETE')                      for key in frm.cleaned_data:                          value = frm.cleaned_data[key] -                        if not value and value != False: +                        if value is None or value == '':                              continue                          if key in associated_models: -                            value = associated_models[key].objects.get(pk=value) +                            value = associated_models[key].objects.get( +                                pk=value)                          if multi:                              vals[key] = value                          else: @@ -319,10 +324,10 @@ class Wizard(NamedUrlWizardView):                          if value:                              model = associated_models[key]                              if isinstance(value, unicode) \ -                             or isinstance(value, str) and "," in value: +                                    or isinstance(value, str) and "," in value:                                  value = value.split(",")                              if isinstance(value, list) \ -                             or isinstance(value, tuple): +                                    or isinstance(value, tuple):                                  value = [model.objects.get(pk=val)                                           for val in value if val]                                  if len(value) == 1: @@ -346,11 +351,11 @@ class Wizard(NamedUrlWizardView):                                 return_object)      def get_saved_model(self): -        """Permit a distinguo when saved model is not the base selected model""" +        "Permit a distinguo when saved model is not the base selected model"          return self.model      def get_current_saved_object(self): -        """Permit a distinguo when saved model is not the base selected model""" +        "Permit a distinguo when saved model is not the base selected model"          return self.get_current_object()      def save_model(self, dct, m2m, whole_associated_models, form_list, @@ -363,7 +368,8 @@ class Wizard(NamedUrlWizardView):              if '__' not in k:                  continue              vals = k.split('__') -            assert len(vals) == 2, "Only one level of dependant item is managed" +            assert len(vals) == 2, \ +                "Only one level of dependant item is managed"              dependant_item, key = vals              if dependant_item not in other_objs:                  other_objs[dependant_item] = {} @@ -388,7 +394,7 @@ class Wizard(NamedUrlWizardView):                  setattr(obj, k, dct[k])              try:                  obj.full_clean() -            except ValidationError, msg: +            except ValidationError:                  return self.render(form_list[-1])              for dependant_item in other_objs:                  c_item = getattr(obj, dependant_item) @@ -429,7 +435,7 @@ class Wizard(NamedUrlWizardView):              obj = self.get_saved_model()(**dct)              try:                  obj.full_clean() -            except ValidationError, msg: +            except ValidationError:                  return self.render(form_list[-1])              obj.save()              for k in adds: @@ -463,13 +469,13 @@ class Wizard(NamedUrlWizardView):                  # necessary to manage interaction between models like                  # material_index management for baseitems                  obj.save() -        dct = {'item':obj} +        dct = {'item': obj}          # force evaluation of lazy urls          wizard_done_window = unicode(self.wizard_done_window)          if wizard_done_window:              dct['wizard_done_window'] = wizard_done_window          res = render_to_response(self.wizard_done_template, dct, -                                  context_instance=RequestContext(self.request)) +                                 context_instance=RequestContext(self.request))          return return_object and (obj, res) or res      def get_deleted(self, keys): @@ -494,8 +500,6 @@ class Wizard(NamedUrlWizardView):      def get_form(self, step=None, data=None, files=None):          """Manage formset""" -        request = self.request -        storage = self.storage          if data:              data = data.copy()              if not step: @@ -513,7 +517,7 @@ class Wizard(NamedUrlWizardView):                  if to_delete:                      # reorganize                      for idx, number in enumerate(sorted(not_to_delete, -                                                        key=lambda x:int(x))): +                                                        key=lambda x: int(x))):                          idx = unicode(idx)                          if idx == number:                              continue @@ -527,8 +531,8 @@ class Wizard(NamedUrlWizardView):                  frm = form.form                  if callable(frm):                      frm = frm() -                required_fields = [k for k in frm.fields -                                   if frm.fields[k].required] +                required_fields = [ki for ki in frm.fields +                                   if frm.fields[ki].required]                  base_key = None                  if required_fields:                      base_key = required_fields[-1] @@ -538,8 +542,8 @@ class Wizard(NamedUrlWizardView):                  total_field = 0                  if base_key:                      total_field = len([key for key in data.keys() -                                        if base_key in key.split('-') -                                           and data[key]]) +                                       if base_key in key.split('-') +                                       and data[key]])                  if init and not to_delete and (                     not hasattr(self, 'form_initialized') or                     not self.form_initialized): @@ -548,7 +552,8 @@ class Wizard(NamedUrlWizardView):                  data[step + u'-TOTAL_FORMS'] = unicode(total_field + 1)                  # TODO:remove form_initialized?                  # update initialization -                #if request.POST and init and hasattr(self, 'form_initialized') \ +                # if request.POST and init and hasattr(self, +                #                                      'form_initialized') \                  #   and self.form_initialized:                  #    for k in init[0]:                  #        data[step + '-' + unicode(total_field) + '-' + k] = \ @@ -560,15 +565,15 @@ class Wizard(NamedUrlWizardView):          if hasattr(form, 'fields') and form.fields.keys():              frm = form          elif hasattr(form, 'extra_form') and hasattr(form.extra_form, 'fields')\ -           and form.extra_form.fields.keys(): +                and form.extra_form.fields.keys():              frm = form.extra_form          elif hasattr(form, 'forms') and form.forms \ -           and form.forms[0].fields.keys(): +                and form.forms[0].fields.keys():              frm = form.forms[0]          if frm:              first_field = frm.fields[frm.fields.keyOrder[0]]              attrs = first_field.widget.attrs -            attrs.update({'autofocus':"autofocus"}) +            attrs.update({'autofocus': "autofocus"})              first_field.widget.attrs = attrs          return form @@ -584,10 +589,11 @@ class Wizard(NamedUrlWizardView):             or [key for key in request.POST.keys()                 if key.endswith('DELETE') and request.POST[key]]:              return self.render(form) -        elif request.POST.has_key('validate_and_end') \ -           and request.POST['validate_and_end']: +        elif 'validate_and_end' in request.POST \ +                and request.POST['validate_and_end']:              last_step = self.steps.last -            new_form = self.get_form(last_step, +            new_form = self.get_form( +                last_step,                  data=self.storage.get_step_data(last_step),                  files=self.storage.get_step_files(last_step))              self.storage.current_step = last_step @@ -668,9 +674,8 @@ class Wizard(NamedUrlWizardView):          vals = []          for k in request.session[storage.prefix]['step_data'][form_key]:              if k.startswith(form_key) and k.endswith(key) and \ -               request.session[storage.prefix]['step_data'][form_key][k]: -                val = request.session[storage.prefix]['step_data']\ -                                                     [form_key][k] +                    request.session[storage.prefix]['step_data'][form_key][k]: +                val = request.session[storage.prefix]['step_data'][form_key][k]                  if type(val) in (list, tuple):                      val = val[0]                  vals.append(val) @@ -694,13 +699,13 @@ class Wizard(NamedUrlWizardView):          request = self.request          if step.startswith('selec-') and step in self.form_list \             and 'pk' in self.form_list[step].associated_models: -            model_name = self.form_list[step].associated_models['pk' -                                              ].__name__.lower() +            model_name = self.form_list[step]\ +                             .associated_models['pk'].__name__.lower()              if step == current_step:                  self.storage.reset()              val = model_name in request.session and request.session[model_name]              if val: -                return MultiValueDict({'pk':val}) +                return MultiValueDict({'pk': val})          elif current_obj:              return self.get_instanced_init(current_obj, step)          current_form = self.form_list[current_step] @@ -709,7 +714,7 @@ class Wizard(NamedUrlWizardView):              for key in current_form.currents:                  model_name = current_form.currents[key].__name__.lower()                  val = model_name in request.session and \ -                      request.session[model_name] +                    request.session[model_name]                  if val:                      initial[key] = val              if initial: @@ -729,8 +734,8 @@ class Wizard(NamedUrlWizardView):          self.request.session[obj_name] = unicode(obj.pk)          initial = MultiValueDict()          if self.request.POST or \ -          (step in self.request.session[self.storage.prefix] and\ -           self.request.session[self.storage.prefix]['step_data'][step]): +                (step in self.request.session[self.storage.prefix] and +                 self.request.session[self.storage.prefix]['step_data'][step]):              return initial          if hasattr(c_form, 'base_fields'):              for base_field in c_form.base_fields.keys(): @@ -738,13 +743,13 @@ class Wizard(NamedUrlWizardView):                  if hasattr(c_form, 'base_model') and \                     base_field == c_form.base_model:                      key = c_form.base_model + 's' -                    initial.setlist(base_field, [unicode(val.pk) -                                        for val in getattr(obj, key).all()]) +                    initial.setlist(base_field, [ +                        unicode(val.pk) for val in getattr(obj, key).all()])                  else:                      fields = base_field.split('__')                      for field in fields:                          if not hasattr(value, field) or \ -                           getattr(value, field) == None: +                                getattr(value, field) is None:                              value = obj                              break                          value = getattr(value, field) @@ -762,7 +767,7 @@ class Wizard(NamedUrlWizardView):                     isinstance(value, FileField) or \                     isinstance(value, ImageFile):                      initial[base_field] = value -                elif value != None: +                elif value is not None:                      initial[base_field] = unicode(value)          elif hasattr(c_form, 'management_form'):              initial = [] @@ -789,7 +794,7 @@ class Wizard(NamedUrlWizardView):                              value = getattr(child_obj, field)                              if hasattr(value, 'pk'):                                  value = value.pk -                            if value != None: +                            if value is not None:                                  vals[field] = unicode(value)                  if vals:                      initial.append(vals) @@ -799,8 +804,9 @@ class Wizard(NamedUrlWizardView):  class SearchWizard(NamedUrlWizardView):      model = None      label = '' -    modification = None # True when the wizard modify an item -    storage_name = 'django.contrib.formtools.wizard.storage.session.SessionStorage' +    modification = None  # True when the wizard modify an item +    storage_name = \ +        'django.contrib.formtools.wizard.storage.session.SessionStorage'      def get_wizard_name(self):          """ @@ -812,7 +818,7 @@ class SearchWizard(NamedUrlWizardView):          """As the class name can interfere when reused prefix with the url_name          """          return self.url_name + super(SearchWizard, self).get_prefix(*args, -                                                              **kwargs) +                                                                    **kwargs)      def get_template_names(self):          templates = ['ishtar/wizard/search.html'] @@ -822,8 +828,8 @@ class SearchWizard(NamedUrlWizardView):          context = super(SearchWizard, self).get_context_data(form)          self.request.session['CURRENT_ACTION'] = self.get_wizard_name()          current_step = self.steps.current -        context.update({'current_step':self.form_list[current_step], -                        'wizard_label':self.label}) +        context.update({'current_step': self.form_list[current_step], +                        'wizard_label': self.label})          return context @@ -843,7 +849,8 @@ class DeletionWizard(Wizard):              for key in form.cleaned_data:                  if key == 'pk':                      model = form.associated_models['pk'] -                    self.current_obj = model.objects.get(pk=form.cleaned_data['pk']) +                    self.current_obj = model.objects.get( +                        pk=form.cleaned_data['pk'])          if not self.current_obj:              return datas          res = {} @@ -873,8 +880,9 @@ class DeletionWizard(Wizard):              obj.delete()          except ObjectDoesNotExist:              pass -        return render_to_response('ishtar/wizard/wizard_delete_done.html', {}, -                                  context_instance=RequestContext(self.request)) +        return render_to_response( +            'ishtar/wizard/wizard_delete_done.html', {}, +            context_instance=RequestContext(self.request))  class ClosingWizard(Wizard): @@ -893,7 +901,7 @@ class ClosingWizard(Wizard):                  if key == 'pk':                      model = form.associated_models['pk']                      self.current_obj = model.objects.get( -                                                  pk=form.cleaned_data['pk']) +                        pk=form.cleaned_data['pk'])          if not self.current_obj:              return datas          res = {} @@ -921,11 +929,13 @@ class ClosingWizard(Wizard):          obj = self.get_current_object()          for form in form_list:              if form.is_valid(): -                if 'end_date' in form.cleaned_data and hasattr(obj, 'end_date'): +                if 'end_date' in form.cleaned_data \ +                        and hasattr(obj, 'end_date'):                      obj.end_date = form.cleaned_data['end_date']                      obj.save() -        return render_to_response('ishtar/wizard/wizard_closing_done.html', {}, -                                  context_instance=RequestContext(self.request)) +        return render_to_response( +            'ishtar/wizard/wizard_closing_done.html', {}, +            context_instance=RequestContext(self.request))  class PersonWizard(Wizard): @@ -940,7 +950,7 @@ class PersonDeletionWizard(DeletionWizard):      model = models.Person      fields = model.TABLE_COLS      wizard_templates = { -        'final-person_deletion':'ishtar/wizard/wizard_person_deletion.html'} +        'final-person_deletion': 'ishtar/wizard/wizard_person_deletion.html'}  class OrganizationWizard(Wizard): @@ -955,12 +965,13 @@ class OrganizationDeletionWizard(DeletionWizard):      model = models.Organization      fields = model.TABLE_COLS      wizard_templates = { -        'final-organization_deletion':\ -            'ishtar/wizard/wizard_organization_deletion.html'} +        'final-organization_deletion': +        'ishtar/wizard/wizard_organization_deletion.html'}  class AccountWizard(Wizard):      model = models.Person +      def get_formated_datas(self, forms):          datas = super(AccountWizard, self).get_formated_datas(forms)          for form in forms: @@ -980,7 +991,7 @@ class AccountWizard(Wizard):              if not form.is_valid():                  return self.render(form)              associated_models = hasattr(form, 'associated_models') and \ -                                form.associated_models or {} +                form.associated_models or {}              if type(form.cleaned_data) == dict:                  for key in form.cleaned_data:                      if key == 'pk': @@ -1001,10 +1012,11 @@ class AccountWizard(Wizard):              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) +            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() @@ -1014,20 +1026,21 @@ class AccountWizard(Wizard):              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 "" -                              }) +                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} +                "app_name": app_name}              send_mail(subject, msg, settings.ADMINS[0][1],                        [dct['email']], fail_silently=True)          res = render_to_response('ishtar/wizard/wizard_done.html', {}, -                                  context_instance=RequestContext(self.request)) +                                 context_instance=RequestContext(self.request))          return res      def get_form(self, step=None, data=None, files=None): @@ -1045,6 +1058,7 @@ class AccountWizard(Wizard):  class SourceWizard(Wizard):      model = None +      def get_extra_model(self, dct, form_list):          dct = super(SourceWizard, self).get_extra_model(dct, form_list)          if 'history_modifier' in dct: | 
