diff options
| -rw-r--r-- | CHANGES.md | 10 | ||||
| -rw-r--r-- | archaeological_context_records/forms.py | 4 | ||||
| -rw-r--r-- | archaeological_context_records/models.py | 6 | ||||
| -rw-r--r-- | archaeological_files/forms.py | 6 | ||||
| -rw-r--r-- | archaeological_files/models.py | 7 | ||||
| -rw-r--r-- | archaeological_finds/forms.py | 15 | ||||
| -rw-r--r-- | archaeological_finds/forms_treatments.py | 9 | ||||
| -rw-r--r-- | archaeological_finds/models_finds.py | 9 | ||||
| -rw-r--r-- | archaeological_finds/models_treatments.py | 17 | ||||
| -rw-r--r-- | archaeological_operations/forms.py | 6 | ||||
| -rw-r--r-- | archaeological_operations/models.py | 13 | ||||
| -rw-r--r-- | archaeological_warehouse/forms.py | 4 | ||||
| -rw-r--r-- | archaeological_warehouse/models.py | 6 | ||||
| -rw-r--r-- | ishtar_common/forms.py | 24 | ||||
| -rw-r--r-- | ishtar_common/models.py | 17 | 
15 files changed, 115 insertions, 38 deletions
| diff --git a/CHANGES.md b/CHANGES.md index b3907be7f..821d79c04 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,7 @@  Ishtar changelog  ================ -v3.0.4 - 2020-XX-XX +v3.0.4 - 2020-03-11  -------------------  ### Features ###  - Quick actions - sheets: add duplicate for site, operation, document and context record @@ -17,6 +17,14 @@ v3.0.4 - 2020-XX-XX      - operation: town, scientist    - Warehouse:      - town +  - All document items: +    - has associated file +    - has associated image +    - has associated url +     +### Bug fixes ### +- Tables: fix display of links in columns +- Criteria search: manage empty field (but not NULL) multiple level search for file (including images) fields  v3.0.3 - 2020-02-24 diff --git a/archaeological_context_records/forms.py b/archaeological_context_records/forms.py index 87cad2c66..5ed9935e9 100644 --- a/archaeological_context_records/forms.py +++ b/archaeological_context_records/forms.py @@ -35,7 +35,7 @@ from archaeological_context_records import models  from ishtar_common.forms import FinalForm, FormSet, \      reverse_lazy, get_form_selection, ManageOldType, CustomForm, \      FieldType, CustomFormSearch, IshtarForm, FormHeader, HistorySelect, \ -    MultiSearchForm, LockForm +    MultiSearchForm, LockForm, DocumentItemSelect  from ishtar_common.forms_common import get_town_field  from archaeological_operations.forms import OperationSelect, ParcelField, \      RecordRelationsForm as OpeRecordRelationsForm, RecordRelationsFormSetBase @@ -60,7 +60,7 @@ class OperationFormSelection(CustomForm, forms.Form):          validators=[valid_id(Operation)]) -class RecordSelect(HistorySelect): +class RecordSelect(DocumentItemSelect):      _model = models.ContextRecord      form_admin_name = _(u"Context record - 001 - Search")      form_slug = "contextrecord-001-search" diff --git a/archaeological_context_records/models.py b/archaeological_context_records/models.py index 9b1483e0d..02b074706 100644 --- a/archaeological_context_records/models.py +++ b/archaeological_context_records/models.py @@ -362,6 +362,11 @@ class ContextRecord(BulkUpdatedItem, DocumentItem, BaseHistorizedItem,          'operation_id': 'operation_id',          'unit__label': "unit__label"      } +    REVERSED_BOOL_FIELDS = [ +        'documents__image__isnull', +        'documents__associated_file__isnull', +        'documents__associated_url__isnull', +    ]      RELATION_TYPES_PREFIX = {'ope_relation_types': 'operation__',                               'cr_relation_types': ''}      # alternative names of fields for searches @@ -416,6 +421,7 @@ class ContextRecord(BulkUpdatedItem, DocumentItem, BaseHistorizedItem,          ),      }      ALT_NAMES.update(BaseHistorizedItem.ALT_NAMES) +    ALT_NAMES.update(DocumentItem.ALT_NAMES)      PARENT_ONLY_SEARCH_VECTORS = ["operation", "archaeological_site", "parcel"]      BASE_SEARCH_VECTORS = [ diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py index 9a2f63a1d..a9936c47a 100644 --- a/archaeological_files/forms.py +++ b/archaeological_files/forms.py @@ -37,8 +37,8 @@ from archaeological_operations.models import ActType, AdministrativeAct, \  from . import models  from ishtar_common.forms import FinalForm, get_now, reverse_lazy, TableSelect, \ -    ManageOldType, CustomForm, FieldType, IshtarForm, HistorySelect, \ -    MultiSearchForm, LockForm, CustomFormSearch +    ManageOldType, CustomForm, FieldType, IshtarForm, \ +    MultiSearchForm, LockForm, CustomFormSearch, DocumentItemSelect  from ishtar_common.forms_common import get_town_field  from archaeological_operations.forms import AdministrativeActForm, \      AdministrativeActOpeFormSelection, SLICING, AdministrativeActModifForm, \ @@ -47,7 +47,7 @@ from ishtar_common import widgets  from bootstrap_datepicker.widgets import DatePicker -class FileSelect(HistorySelect): +class FileSelect(DocumentItemSelect):      _model = models.File      form_admin_name = _(u"File - 001 - Search")      form_slug = "file-001-search" diff --git a/archaeological_files/models.py b/archaeological_files/models.py index 018b5d429..310301c59 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -161,6 +161,12 @@ class File(ClosedItem, DocumentItem, BaseHistorizedItem, OwnPerms, ValueGetter,          'towns_label': _(u"Towns"),      } +    REVERSED_BOOL_FIELDS = [ +        'documents__image__isnull', +        'documents__associated_file__isnull', +        'documents__associated_url__isnull', +    ] +      # alternative names of fields for searches      ALT_NAMES = {          'year': SearchAltName( @@ -230,6 +236,7 @@ class File(ClosedItem, DocumentItem, BaseHistorizedItem, OwnPerms, ValueGetter,          ),      }      ALT_NAMES.update(BaseHistorizedItem.ALT_NAMES) +    ALT_NAMES.update(DocumentItem.ALT_NAMES)      POST_PROCESS_REQUEST = {          'towns__numero_insee__startswith': '_get_department_code', diff --git a/archaeological_finds/forms.py b/archaeological_finds/forms.py index 316253a7a..90805e656 100644 --- a/archaeological_finds/forms.py +++ b/archaeological_finds/forms.py @@ -56,7 +56,7 @@ from ishtar_common import widgets  from ishtar_common.forms import CustomForm, CustomFormSearch, FormSet, \      FloatField, reverse_lazy, TableSelect, get_now, FinalForm, \      ManageOldType, FieldType, IshtarForm, FormHeader, QAForm, HistorySelect, \ -    MultiSearchForm, LockForm +    MultiSearchForm, LockForm, DocumentItemSelect  from ishtar_common.forms_common import get_town_field  from ishtar_common.models import valid_id, valid_ids, get_current_profile, \      SpatialReferenceSystem, Area, OperationType, IshtarUser @@ -524,8 +524,8 @@ class ResultingFindsForm(CustomForm, ManageOldType):          label=_(u"Prefix label for resulting finds"),          validators=[validators.MaxLengthValidator(200)],          help_text=_( -            u'E.g.: with a prefix "item-", each resulting item will be named ' -            u'"item-1", "item-2", "item-3"') +            'E.g.: with a prefix "item-", each resulting item will be named ' +            '"item-1", "item-2", "item-3"')      )      resultings_start_number = forms.IntegerField(          label=_(u"Numbering starting from"), initial=1, min_value=0 @@ -908,9 +908,9 @@ DatingFormSet.form_admin_name = _(u"Find - 040 - Dating")  DatingFormSet.form_slug = "find-040-dating" -class FindSelect(HistorySelect): +class FindSelect(DocumentItemSelect):      _model = models.Find -    form_admin_name = _(u"Find - 001 - Search") +    form_admin_name = _("Find - 001 - Search")      form_slug = "find-001-search"      FORM_FILTERS = [          (_(u"Find origin"), [ @@ -1051,9 +1051,9 @@ class FindSelect(HistorySelect):              reverse_lazy('autocomplete-materialtype'),              associated_model=models.MaterialType),      ) -    material_type_quality = forms.ChoiceField(label=_(u"Material type quality"), +    material_type_quality = forms.ChoiceField(label=_("Material type quality"),                                                choices=[]) -    material_comment = forms.CharField(label=_(u"Comment on the material")) +    material_comment = forms.CharField(label=_("Comment on the material"))      object_types = forms.IntegerField(          label=_(u"Object type"),          widget=widgets.JQueryAutoComplete( @@ -1182,7 +1182,6 @@ class FindSelect(HistorySelect):      appraisal_date__before = forms.DateField(          label=_(u"Appraisal date before"), widget=DatePicker) -    documents__image__isnull = forms.NullBooleanField(label=_(u"Has an image?"))      loan = forms.NullBooleanField(label=_(u"Loan?"))      treatments_file_end_date = forms.DateField(          label=_(u"Treatment file end date before"), widget=DatePicker diff --git a/archaeological_finds/forms_treatments.py b/archaeological_finds/forms_treatments.py index f03dec18a..b80b6c0fe 100644 --- a/archaeological_finds/forms_treatments.py +++ b/archaeological_finds/forms_treatments.py @@ -33,8 +33,8 @@ from archaeological_warehouse.models import Warehouse, Container  from bootstrap_datepicker.widgets import DatePicker  from ishtar_common import widgets  from ishtar_common.forms import reverse_lazy, TableSelect, FinalForm, \ -    ManageOldType, CustomForm, FieldType, IshtarForm, HistorySelect, \ -    MultiSearchForm +    ManageOldType, CustomForm, FieldType, IshtarForm, \ +    DocumentItemSelect, MultiSearchForm  from ishtar_common.models import Person, valid_id, valid_ids, Organization, \      get_current_profile @@ -43,7 +43,7 @@ logger = logging.getLogger(__name__)  # Treatment -class TreatmentSelect(HistorySelect): +class TreatmentSelect(DocumentItemSelect):      _model = models.Treatment      form_admin_name = _(u"Treatment - 001 - Search")      form_slug = "treatment-001-search" @@ -63,7 +63,6 @@ class TreatmentSelect(HistorySelect):              associated_model=Person),          label=_(u"Scientific monitoring manager"))      treatment_types = forms.ChoiceField(label=_(u"Treatment type"), choices=[]) -    documents__image__isnull = forms.NullBooleanField(label=_(u"Has an image?"))      def __init__(self, *args, **kwargs):          super(TreatmentSelect, self).__init__(*args, **kwargs) @@ -662,7 +661,7 @@ class AdministrativeActTreatmentModifForm(  # treatment requests -class TreatmentFileSelect(HistorySelect): +class TreatmentFileSelect(DocumentItemSelect):      _model = models.TreatmentFile      form_admin_name = _(u"Treatment file - 001 - Search")      form_slug = "treatmentfile-001-search" diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py index ad5c803fa..328821386 100644 --- a/archaeological_finds/models_finds.py +++ b/archaeological_finds/models_finds.py @@ -880,7 +880,9 @@ class Find(BulkUpdatedItem, ValueGetter, DocumentItem, BaseHistorizedItem,      )      # search parameters -    REVERSED_BOOL_FIELDS = ['documents__image__isnull'] +    REVERSED_BOOL_FIELDS = ['documents__image__isnull', +                            'documents__associated_url__isnull', +                            'documents__associated_file__isnull']      BOOL_FIELDS = ['is_complete']      RELATION_TYPES_PREFIX = {          'ope_relation_types': @@ -1042,10 +1044,6 @@ class Find(BulkUpdatedItem, ValueGetter, DocumentItem, BaseHistorizedItem,              SearchAltName(                  pgettext_lazy("key for text search", "checked"),                  'checked_type__label__iexact'), -        'documents__image__isnull': -            SearchAltName( -                pgettext_lazy("key for text search", "has-image"), -                'documents__image__isnull'),          'container_ref__location':              SearchAltName(                  pgettext_lazy("key for text search", "location"), @@ -1364,6 +1362,7 @@ class Find(BulkUpdatedItem, ValueGetter, DocumentItem, BaseHistorizedItem,          ),      }      ALT_NAMES.update(BaseHistorizedItem.ALT_NAMES) +    ALT_NAMES.update(DocumentItem.ALT_NAMES)      DYNAMIC_REQUESTS = {          'current_division': DynamicRequest( diff --git a/archaeological_finds/models_treatments.py b/archaeological_finds/models_treatments.py index a8a06ae27..071d80af1 100644 --- a/archaeological_finds/models_treatments.py +++ b/archaeological_finds/models_treatments.py @@ -74,7 +74,11 @@ class Treatment(DashboardFormItem, ValueGetter, DocumentItem,                    'person__cached_label',                    'start_date', 'downstream_cached_label',                    'upstream_cached_label') -    REVERSED_BOOL_FIELDS = ['documents__image__isnull'] +    REVERSED_BOOL_FIELDS = [ +        'documents__image__isnull', +        'documents__associated_file__isnull', +        'documents__associated_url__isnull', +    ]      EXTRA_REQUEST_KEYS = {          "downstream_cached_label": "downstream__cached_label",          "upstream_cached_label": "upstream__cached_label", @@ -115,10 +119,6 @@ class Treatment(DashboardFormItem, ValueGetter, DocumentItem,              pgettext_lazy("key for text search", "index"),              'index'          ), -        'documents__image__isnull': SearchAltName( -            pgettext_lazy("key for text search", "has-image"), -            'documents__image__isnull' -        ),          'treatment_types': SearchAltName(              pgettext_lazy("key for text search", "type"),              'treatment_types__label__iexact' @@ -129,6 +129,7 @@ class Treatment(DashboardFormItem, ValueGetter, DocumentItem,          ),      }      ALT_NAMES.update(BaseHistorizedItem.ALT_NAMES) +    ALT_NAMES.update(DocumentItem.ALT_NAMES)      HISTORICAL_M2M = [          'treatment_types',      ] @@ -914,6 +915,11 @@ class TreatmentFile(DashboardFormItem, ClosedItem, DocumentItem,          "in_charge__pk": "in_charge__pk",  # used by dynamic_table_documents          "applicant__pk": "applicant__pk",  # used by dynamic_table_documents      } +    REVERSED_BOOL_FIELDS = [ +        'documents__image__isnull', +        'documents__associated_file__isnull', +        'documents__associated_url__isnull', +    ]      # alternative names of fields for searches      ALT_NAMES = {          'name': SearchAltName( @@ -966,6 +972,7 @@ class TreatmentFile(DashboardFormItem, ClosedItem, DocumentItem,          ),      }      ALT_NAMES.update(BaseHistorizedItem.ALT_NAMES) +    ALT_NAMES.update(DocumentItem.ALT_NAMES)      DATED_FIELDS = ['exhibition_start_date__lte',                      'exhibition_start_date__gte', diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index 9a3335df5..d665fc779 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -41,7 +41,7 @@ from ishtar_common import widgets  from ishtar_common.forms import FinalForm, FormSet, get_now, \      reverse_lazy, TableSelect, get_data_from_formset, QAForm, CustomFormSearch,\      ManageOldType, IshtarForm, CustomForm, FieldType, FormHeader, \ -    HistorySelect, LockForm, MultiSearchForm +    DocumentItemSelect, LockForm, MultiSearchForm  from ishtar_common.forms_common import TownFormSet, get_town_field, TownForm  from ishtar_common.models import valid_id, valid_ids, Person, Town, \      DocumentTemplate, Organization, get_current_profile, \ @@ -472,7 +472,7 @@ RecordRelationsFormSet.form_admin_name = _(u"Operation - 080 - Relations")  RecordRelationsFormSet.form_slug = "operation-080-relations" -class OperationSelect(HistorySelect): +class OperationSelect(DocumentItemSelect):      _model = models.Operation      form_admin_name = _(u"Operation - 001 - Search")      form_slug = "operation-001-search" @@ -1367,7 +1367,7 @@ class OperationDeletionForm(FinalForm):  ######### -class SiteSelect(HistorySelect): +class SiteSelect(DocumentItemSelect):      _model = models.ArchaeologicalSite      form_admin_name = _(u"Archaeological site - 001 - Search")      form_slug = "archaeological_site-001-search" diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index 8dd6568b8..8a415c0c5 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -180,6 +180,11 @@ class ArchaeologicalSite(DocumentItem, BaseHistorizedItem, QRCodeItem,      }      # alternative names of fields for searches +    REVERSED_BOOL_FIELDS = [ +        'documents__image__isnull', +        'documents__associated_file__isnull', +        'documents__associated_url__isnull', +    ]      ALT_NAMES = {          'reference': SearchAltName(              pgettext_lazy("key for text search", "reference"), @@ -264,6 +269,7 @@ class ArchaeologicalSite(DocumentItem, BaseHistorizedItem, QRCodeItem,          ),      }      ALT_NAMES.update(BaseHistorizedItem.ALT_NAMES) +    ALT_NAMES.update(DocumentItem.ALT_NAMES)      UP_MODEL_QUERY = {          "operation": (pgettext_lazy("key for text search", "operation"), @@ -694,6 +700,11 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem, QRCodeItem,      # search parameters      BOOL_FIELDS = ['end_date__isnull', 'virtual_operation',                     'documentation_received', 'finds_received'] +    REVERSED_BOOL_FIELDS = [ +        'documents__image__isnull', +        'documents__associated_file__isnull', +        'documents__associated_url__isnull', +    ]      DATED_FIELDS = [          'start_date__lte', 'start_date__gte', 'excavation_end_date__lte',          'excavation_end_date__gte', 'documentation_deadline__lte', @@ -951,6 +962,8 @@ class Operation(ClosedItem, DocumentItem, BaseHistorizedItem, QRCodeItem,          ),      }      ALT_NAMES.update(BaseHistorizedItem.ALT_NAMES) +    ALT_NAMES.update(DocumentItem.ALT_NAMES) +      QA_EDIT = QuickAction(          url="operation-qa-bulk-update", icon_class="fa fa-pencil",          text=_(u"Bulk update"), target="many", diff --git a/archaeological_warehouse/forms.py b/archaeological_warehouse/forms.py index 867761047..a7b6c575e 100644 --- a/archaeological_warehouse/forms.py +++ b/archaeological_warehouse/forms.py @@ -42,7 +42,7 @@ from bootstrap_datepicker.widgets import DatePicker  from ishtar_common.forms import name_validator, reverse_lazy, \      get_form_selection, ManageOldType, FinalForm, FormSet, \ -    CustomForm, FieldType, HistorySelect, FormHeader, TableSelect, \ +    CustomForm, FieldType, DocumentItemSelect, FormHeader, TableSelect, \      CustomFormSearch, MultiSearchForm, LockForm  from ishtar_common.forms_common import get_town_field  from archaeological_finds.forms import FindMultipleFormSelection, \ @@ -354,7 +354,7 @@ class ContainerModifyForm(ContainerForm):          return cleaned_data -class ContainerSelect(HistorySelect): +class ContainerSelect(DocumentItemSelect):      _model = models.Container      form_admin_name = _(u"Container - 001 - Search")      form_slug = "container-001-search" diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py index 325adce9e..63d4497ac 100644 --- a/archaeological_warehouse/models.py +++ b/archaeological_warehouse/models.py @@ -603,9 +603,15 @@ class Container(DocumentItem, LightHistorizedItem, QRCodeItem, GeoItem,          ),      } +    REVERSED_BOOL_FIELDS = [ +        'documents__image__isnull', +        'documents__associated_file__isnull', +        'documents__associated_url__isnull', +    ]      REVERSED_MANY_COUNTED_FIELDS = ['finds', 'finds_ref']      ALT_NAMES.update(LightHistorizedItem.ALT_NAMES) +    ALT_NAMES.update(DocumentItem.ALT_NAMES)      DYNAMIC_REQUESTS = {          'division': DynamicRequest( diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index 17ada982f..939563334 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -782,23 +782,39 @@ class HistorySelect(CustomForm, TableSelect):          label=_("Modified after"), widget=DatePicker,          required=False)      _explicit_ordering = True +    CURRENT_FIELDS = ["history_creator", "history_modifier", +                      "modified_before", "modified_after"]      def __init__(self, *args, **kwargs):          super(HistorySelect, self).__init__(*args, **kwargs)          field_order = self.fields.keys() -        current_fields = ["history_creator", "history_modifier", -                          "modified_before", "modified_after"]          fields = OrderedDict()          for k in field_order: -            if k in current_fields: +            if k in self.CURRENT_FIELDS:                  continue              fields[k] = self.fields[k] -        for k in current_fields: +        for k in self.CURRENT_FIELDS:              fields[k] = self.fields[k]          self.fields = fields          self.custom_form_ordering() +class DocumentItemSelect(HistorySelect): +    documents__image__isnull = forms.NullBooleanField(label=_("Has an image?")) +    documents__associated_file__isnull = forms.NullBooleanField( +        label=_("Has an attached file?")) +    documents__associated_url__isnull = forms.NullBooleanField( +        label=_("Has a web address?")) +    CURRENT_FIELDS = [ +        'documents__image__isnull', +        'documents__associated_file__isnull', +        'documents__associated_url__isnull', +        "history_creator", "history_modifier", +        "modified_before", "modified_after" +    ] +    _explicit_ordering = True + +  def get_now():      format = formats.get_format('DATE_INPUT_FORMATS')[0]      value = datetime.datetime.now().strftime(format) diff --git a/ishtar_common/models.py b/ishtar_common/models.py index dc2fef815..5fa668faf 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -1818,6 +1818,21 @@ class QRCodeItem(models.Model, ImageContainerModel):  class DocumentItem(object): +    ALT_NAMES = { +        'documents__image__isnull': +            SearchAltName( +                pgettext_lazy("key for text search", "has-image"), +                'documents__image__isnull'), +        'documents__associated_url__isnull': +            SearchAltName( +                pgettext_lazy("key for text search", "has-url"), +                'documents__associated_url__isnull'), +        'documents__associated_file__isnull': +            SearchAltName( +                pgettext_lazy("key for text search", "has-attached-file"), +                'documents__associated_file__isnull'), +    } +      def public_representation(self):          images = []          if getattr(self, "main_image", None): @@ -5600,6 +5615,8 @@ class Document(BaseHistorizedItem, QRCodeItem, OwnPerms, ImageModel,          no_path_change = 'no_path_change' in kwargs \                           and kwargs.pop('no_path_change')          self.set_index() +        if not self.associated_url: +            self.associated_url = None          super(Document, self).save(*args, **kwargs)          if self.image and not no_path_change and \ | 
