diff options
| -rw-r--r-- | archaeological_operations/forms.py | 34 | ||||
| -rw-r--r-- | archaeological_operations/migrations/0034_archaeologicalsite_cached_label.py | 20 | ||||
| -rw-r--r-- | archaeological_operations/migrations/0035_auto_20180809_1152.py | 88 | ||||
| -rw-r--r-- | archaeological_operations/migrations/0036_auto_20180809_1242.py | 23 | ||||
| -rw-r--r-- | archaeological_operations/models.py | 121 | ||||
| -rw-r--r-- | ishtar_common/models.py | 1 | ||||
| -rw-r--r-- | ishtar_common/views_item.py | 18 | 
7 files changed, 258 insertions, 47 deletions
| diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index 63b350f28..20379e588 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -530,7 +530,7 @@ class OperationSelect(TableSelect):      abstract = forms.CharField(label=_(u"Abstract (full text search)"))      scientific_documentation_comment = forms.CharField(          label=_(u"Comment about scientific documentation")) -    record_quality = forms.ChoiceField(label=_(u"Record quality")) +    record_quality_type = forms.ChoiceField(label=_(u"Record quality"))      report_processing = forms.ChoiceField(label=_(u"Report processing"),                                            choices=[])      virtual_operation = forms.NullBooleanField(label=_(u"Virtual operation")) @@ -553,18 +553,27 @@ class OperationSelect(TableSelect):                           args=['0', 'user']),              associated_model=Person),          validators=[valid_id(Person)]) +    documentation_received = forms.NullBooleanField( +        label=_(u"Documentation received"))      documentation_deadline_before = DateField(          label=_(u"Documentation deadline before"))      documentation_deadline_after = DateField(          label=_(u"Documentation deadline after")) -    documentation_received = forms.NullBooleanField( -        label=_(u"Documentation received")) +    finds_received = forms.NullBooleanField( +        label=_(u"Finds received"))      finds_deadline_before = DateField(          label=_(u"Finds deadline before"))      finds_deadline_after = DateField(          label=_(u"Finds deadline after")) -    finds_received = forms.NullBooleanField( -        label=_(u"Finds received")) + +    TYPES = [ +        FieldType('operation_type', models.OperationType), +        FieldType('report_processing', models.ReportState), +        FieldType('remains', models.RemainType), +        FieldType('periods', models.Period), +        FieldType('record_quality_type', models.RecordQualityType), +        FieldType('relation_types', models.RelationType), +    ]      def __init__(self, *args, **kwargs):          super(OperationSelect, self).__init__(*args, **kwargs) @@ -575,25 +584,10 @@ class OperationSelect(TableSelect):              self.fields.pop('finds_deadline_before')              self.fields.pop('finds_deadline_after')              self.fields.pop('finds_received') -        self.fields['operation_type'].choices = \ -            models.OperationType.get_types() -        self.fields['operation_type'].help_text = \ -            models.OperationType.get_help() -        self.fields['report_processing'].choices = \ -            models.ReportState.get_types() -        self.fields['report_processing'].help_text = \ -            models.ReportState.get_help() -        self.fields['remains'].choices = models.RemainType.get_types() -        self.fields['remains'].help_text = models.RemainType.get_help() -        self.fields['periods'].choices = models.Period.get_types() -        self.fields['periods'].help_text = models.Period.get_help() -        self.fields['record_quality'].choices = \ -            [('', '--')] + list(models.QUALITY)          if settings.ISHTAR_DPTS:              k = 'towns__numero_insee__startswith'              self.fields[k].choices = [                  ('', '--')] + list(settings.ISHTAR_DPTS) -        self.fields['relation_types'].choices = models.RelationType.get_types()  class OperationFormSelection(IshtarForm): diff --git a/archaeological_operations/migrations/0034_archaeologicalsite_cached_label.py b/archaeological_operations/migrations/0034_archaeologicalsite_cached_label.py new file mode 100644 index 000000000..c4bd2e765 --- /dev/null +++ b/archaeological_operations/migrations/0034_archaeologicalsite_cached_label.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-08-08 18:58 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + +    dependencies = [ +        ('archaeological_operations', '0033_parcel_cached_label'), +    ] + +    operations = [ +        migrations.AddField( +            model_name='archaeologicalsite', +            name='cached_label', +            field=models.TextField(blank=True, db_index=True, null=True, verbose_name='Cached name'), +        ), +    ] diff --git a/archaeological_operations/migrations/0035_auto_20180809_1152.py b/archaeological_operations/migrations/0035_auto_20180809_1152.py new file mode 100644 index 000000000..cb88d6119 --- /dev/null +++ b/archaeological_operations/migrations/0035_auto_20180809_1152.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-08-09 11:52 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import ishtar_common.models +import re + + +def migrate_operation(apps, schema_editor): +    Operation = apps.get_model('archaeological_operations', 'Operation') +    RecordQualityType = apps.get_model('archaeological_operations', +                                       'RecordQualityType') + +    not_documented, c = RecordQualityType.objects.get_or_create( +        txt_idx=u"not-documented", +        defaults={ +            "label": u"Non documenté", +            "order": 10 +        } +    ) +    arbitrary, c = RecordQualityType.objects.get_or_create( +        txt_idx=u"arbitrary", +        defaults={ +            "label": u"Arbitraire", +            "order": 20 +        } +    ) +    reliable, c = RecordQualityType.objects.get_or_create( +        txt_idx=u"reliable", +        defaults={ +            "label": u"Fiable", +            "order": 30 +        } +    ) +    QUALITY = { +        'ND': not_documented, +        'A': arbitrary, +        'R': reliable +    } +    for operation in Operation.objects.all(): +        if not operation.record_quality: +            continue +        if operation.record_quality not in QUALITY: +            continue +        operation.record_quality_type = QUALITY[operation.record_quality] +        operation.skip_history_when_saving = True +        operation.save() + + +class Migration(migrations.Migration): + +    dependencies = [ +        ('archaeological_operations', '0034_archaeologicalsite_cached_label'), +    ] + +    operations = [ +        migrations.CreateModel( +            name='RecordQualityType', +            fields=[ +                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), +                ('label', models.TextField(verbose_name='Label')), +                ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')), +                ('comment', models.TextField(blank=True, null=True, verbose_name='Comment')), +                ('available', models.BooleanField(default=True, verbose_name='Available')), +                ('order', models.IntegerField(verbose_name='Order')), +            ], +            options={ +                'ordering': ('order',), +                'verbose_name': 'Type of record quality', +                'verbose_name_plural': 'Types of record quality', +            }, +            bases=(ishtar_common.models.Cached, models.Model), +        ), +        migrations.AddField( +            model_name='historicaloperation', +            name='record_quality_type', +            field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='archaeological_operations.RecordQualityType'), +        ), +        migrations.AddField( +            model_name='operation', +            name='record_quality_type', +            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='archaeological_operations.RecordQualityType', verbose_name='Record quality'), +        ), +        migrations.RunPython(migrate_operation), +    ] diff --git a/archaeological_operations/migrations/0036_auto_20180809_1242.py b/archaeological_operations/migrations/0036_auto_20180809_1242.py new file mode 100644 index 000000000..9e8d89fa2 --- /dev/null +++ b/archaeological_operations/migrations/0036_auto_20180809_1242.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-08-09 12:42 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + +    dependencies = [ +        ('archaeological_operations', '0035_auto_20180809_1152'), +    ] + +    operations = [ +        migrations.RemoveField( +            model_name='historicaloperation', +            name='record_quality', +        ), +        migrations.RemoveField( +            model_name='operation', +            name='record_quality', +        ), +    ] diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index 6f083fe7f..035235b51 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -79,14 +79,24 @@ class ReportState(GeneralType):          verbose_name_plural = _(u"Types of report state")          ordering = ('order',) -    def __unicode__(self): -        return self.label -  post_save.connect(post_save_cache, sender=ReportState)  post_delete.connect(post_save_cache, sender=ReportState) +class RecordQualityType(GeneralType): +    order = models.IntegerField(_(u"Order")) + +    class Meta: +        verbose_name = _(u"Type of record quality") +        verbose_name_plural = _(u"Types of record quality") +        ordering = ('order',) + + +post_save.connect(post_save_cache, sender=RecordQualityType) +post_delete.connect(post_save_cache, sender=RecordQualityType) + +  class ArchaeologicalSite(BaseHistorizedItem):      SHOW_URL = 'show-site'      TABLE_COLS = ['reference', 'name', 'towns', 'periods', 'remains'] @@ -95,7 +105,7 @@ class ArchaeologicalSite(BaseHistorizedItem):          "reference", "name", "oceanographic_service_localisation",          "shipwreck_code", "comment", "shipwreck_name", "discovery_area",      ] -    M2M_SEARCH_VECTORS = ["periods__name", "remains__name", "towns__name"] +    M2M_SEARCH_VECTORS = ["periods__label", "remains__label", "towns__name"]      PARENT_SEARCH_VECTORS = ['operations']      reference = models.CharField(_(u"Reference"), max_length=200, unique=True)      name = models.CharField(_(u"Name"), max_length=200, @@ -131,6 +141,8 @@ class ArchaeologicalSite(BaseHistorizedItem):      documents = models.ManyToManyField(          Document, related_name="sites", verbose_name=_(u"Documents"),          blank=True) +    cached_label = models.TextField(_(u"Cached name"), +                                    null=True, blank=True, db_index=True)      class Meta:          verbose_name = _(u"Archaeological site") @@ -149,6 +161,12 @@ class ArchaeologicalSite(BaseHistorizedItem):          )      def __unicode__(self): +        if self.cached_label: +            return self.cached_label +        self.save() +        return self.cached_label + +    def _generate_cached_label(self):          name = self.reference          if self.name:              name += u" %s %s" % (settings.JOINT, self.name) @@ -157,7 +175,7 @@ class ArchaeologicalSite(BaseHistorizedItem):          for k, lbl in keys:              if getattr(self, k).count():                  name += lbl.format(u", ".join([ -                    v.name for v in getattr(self, k).all() +                    unicode(v) for v in getattr(self, k).all()                  ]))          return name @@ -219,6 +237,9 @@ class ArchaeologicalSite(BaseHistorizedItem):              ) +post_save.connect(cached_label_changed, sender=ArchaeologicalSite) + +  def get_values_town_related(item, prefix, values):      values[prefix + 'parcellist'] = item.render_parcels()      values[prefix + 'towns'] = '' @@ -240,11 +261,6 @@ def get_values_town_related(item, prefix, values):      return values -QUALITY = (('ND', _(u"Not documented")), -           ('A', _(u"Arbitrary")), -           ('R', _(u"Reliable")),) - -  class ClosedItem(object):      def closing(self):          if self.is_active(): @@ -275,7 +291,6 @@ class ClosedItem(object):  class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter,                  ShortMenuItem, DashboardFormItem, RelationItem): -    QUALITY_DICT = dict(QUALITY)      SHOW_URL = 'show-operation'      TABLE_COLS = ['year', 'towns', 'common_name', 'operation_type',                    'start_date', 'excavation_end_date', 'remains'] @@ -309,8 +324,6 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter,          'history_creator__ishtaruser__person__pk',          'history_modifier':          'history_modifier__ishtaruser__person__pk', -        'archaeological_sites': -        'archaeological_sites__pk',          'documentation_deadline_before': 'documentation_deadline__lte',          'documentation_deadline_after': 'documentation_deadline__gte',          'finds_deadline_before': 'finds_deadline__lte', @@ -384,15 +397,15 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter,          ),          'common_name': (              pgettext_lazy(TXT_SEARCH_COMMENT, u"name"), -            'common_name' +            'common_name__icontains'          ),          'address': (              pgettext_lazy(TXT_SEARCH_COMMENT, u"address"), -            'address' +            'address__icontains'          ),          'operation_type': (              pgettext_lazy(TXT_SEARCH_COMMENT, u"type"), -            'operation_type__pk' +            'operation_type__label__iexact'          ),          'end_date': (              pgettext_lazy(TXT_SEARCH_COMMENT, u"is-open"), @@ -412,11 +425,11 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter,          ),          'remains': (              pgettext_lazy(TXT_SEARCH_COMMENT, u"remain"), -            'remains__pk' +            'remains__label__iexact'          ),          'periods': (              pgettext_lazy(TXT_SEARCH_COMMENT, u"period"), -            'periods__pk' +            'periods__label__iexact'          ),          'start_before': (              pgettext_lazy(TXT_SEARCH_COMMENT, u"start-before"), @@ -437,7 +450,71 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter,          'relation_types': (              pgettext_lazy(TXT_SEARCH_COMMENT, u"relation-types"),              'relation_types' -        ) +        ), +        'comment': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, u"comment"), +            'comment__icontains' +        ), +        'abstract': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, u"abstract"), +            'abstract__icontains' +        ), +        'scientific_documentation_comment': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, +                          u"scientific-documentation-comment"), +            'scientific_documentation_comment__icontains' +        ), +        'record_quality_type': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, u"record-quality"), +            'record_quality_type__label__iexact' +        ), +        'report_processing': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, +                          u"report-processing"), +            'report_processing__label__iexact' +        ), +        'virtual_operation': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, +                          u"virtual_operation"), +            'virtual_operation' +        ), +        'archaeological_sites': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, +                          u"site"), +            'archaeological_sites__cached_label__icontains' +        ), +        'history_creator': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, u"created-by"), +            'history_creator__ishtaruser__person__cached_label__iexact' +        ), +        'history_modifier': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, u"modified-by"), +            'history_modifier__ishtaruser__person__cached_label__iexact' +        ), +        'documentation_received': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, u"documentation-received"), +            'documentation_received' +        ), +        'documentation_deadline_before': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, u"documentation-deadline-before"), +            'documentation_deadline__lte' +        ), +        'documentation_deadline_after': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, u"documentation-deadline-after"), +            'documentation_deadline__gte' +        ), +        'finds_received': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, u"finds-received"), +            'finds_received' +        ), +        'finds_deadline_before': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, u"finds-deadline-before"), +            'finds_deadline__lte' +        ), +        'finds_deadline_after': ( +            pgettext_lazy(TXT_SEARCH_COMMENT, u"finds-deadline-after"), +            'finds_deadline__gte' +        ),      }      for v in ALT_NAMES.values():          EXTRA_REQUEST_KEYS[v[0]] = v[1] @@ -550,9 +627,9 @@ class Operation(ClosedItem, BaseHistorizedItem, OwnPerms, ValueGetter,          default=False, help_text=_(              u"If checked, it means that this operation have not been "              u"officialy registered.")) -    record_quality = models.CharField( -        _(u"Record quality"), max_length=2, null=True, blank=True, -        choices=QUALITY) +    record_quality_type = models.ForeignKey( +        RecordQualityType, verbose_name=_(u"Record quality"), +        null=True, blank=True,)      abstract = models.TextField(_(u"Abstract"), null=True, blank=True)      documentation_deadline = models.DateField(          _(u"Deadline for submission of the documentation"), blank=True, diff --git a/ishtar_common/models.py b/ishtar_common/models.py index e2b1d5b02..678e2ce41 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -652,6 +652,7 @@ class GeneralType(Cached, models.Model):      PREFIX_EMPTY = "  "      PREFIX_MEDIUM = "├ "      PREFIX_LAST = "└ " +    PREFIX_CODES = [u"\u2502", u"\u251C", u"\u2514"]      @classmethod      def _get_childs(cls, item, dct, prefix=0, instances=False, exclude=[], diff --git a/ishtar_common/views_item.py b/ishtar_common/views_item.py index 746d359c1..3b09bc7da 100644 --- a/ishtar_common/views_item.py +++ b/ishtar_common/views_item.py @@ -29,7 +29,7 @@ from weasyprint.fonts import FontConfiguration  from ishtar_common.utils import check_model_access_control, CSV_OPTIONS, \      get_all_field_names  from ishtar_common.models import HistoryError, get_current_profile, \ -    PRIVATE_FIELDS +    PRIVATE_FIELDS, GeneralType  from menus import Menu  import models @@ -492,6 +492,12 @@ def _manage_dated_fields(dated_fields, dct):                  dct.pop(k) +def _clean_type_val(val): +    for prefix in GeneralType.PREFIX_CODES: +        val = val.replace(prefix, u"") +    return val.strip() + +  def _manage_facet_search(model, dct, and_reqs):      general_types = model.general_types()      for base_k in general_types: @@ -501,7 +507,7 @@ def _manage_facet_search(model, dct, and_reqs):          if k not in dct or not dct[k].startswith(u'"') \                  or not dct[k].startswith(u'"'):              continue -        val = dct.pop(k) +        val = _clean_type_val(dct.pop(k))          if u";" in val:              # OR request              values = val.split(u";") @@ -533,7 +539,7 @@ def _manage_facet_search(model, dct, and_reqs):  def _manage_hierarchic_fields(dct, and_reqs):      for req in dct.copy():          if req.endswith('areas__pk'): -            val = dct.pop(req) +            val = _clean_type_val(dct.pop(req))              reqs = Q(**{req: val})              base_req = req[:-2] + '__'              req = base_req[:] @@ -550,7 +556,7 @@ def _manage_hierarchic_fields(dct, and_reqs):              continue          if req.endswith('town__pk') or req.endswith('towns__pk'): -            val = dct.pop(req) +            val = _clean_type_val(dct.pop(req))              reqs = Q(**{req: val})              base_req = req[:-2] + '__'              req = base_req[:] @@ -571,6 +577,7 @@ def _manage_hierarchic_fields(dct, and_reqs):                  val = dct.pop(req)                  q = None                  for idx, r in enumerate(req): +                    r = _clean_type_val(r)                      if not idx:                          q = Q(**{r: val})                      else: @@ -578,7 +585,7 @@ def _manage_hierarchic_fields(dct, and_reqs):                  and_reqs.append(q)                  break              elif req.endswith(k_hr + '__pk'): -                val = dct.pop(req) +                val = _clean_type_val(dct.pop(req))                  if u";" in val:                      # OR request @@ -619,6 +626,7 @@ def _manage_clean_search_field(dct):          # clean quoted search field          if type(dct[k]) == unicode:              dct[k] = dct[k].replace(u'"', '') +            dct[k] = _clean_type_val(dct[k])  def _manage_relation_types(relation_types, dct, query, or_reqs): | 
