diff options
Diffstat (limited to 'archaeological_operations')
9 files changed, 262 insertions, 7 deletions
diff --git a/archaeological_operations/admin.py b/archaeological_operations/admin.py index f1deac188..bf1415989 100644 --- a/archaeological_operations/admin.py +++ b/archaeological_operations/admin.py @@ -40,7 +40,7 @@ class AdministrativeActAdmin(HistorizedObjectAdmin): search_fields = ('year', 'index') readonly_fields = HistorizedObjectAdmin.readonly_fields + [ 'in_charge', 'operator', 'scientist', 'signatory', 'associated_file', - 'imports', 'departments_label', 'towns_label'] + 'departments_label', 'towns_label'] model = models.AdministrativeAct form = make_ajax_form( models.AdministrativeAct, {'operation': 'operation'} @@ -69,7 +69,6 @@ class ArchaeologicalSiteAdmin(HistorizedObjectAdmin): list_display = ('name', 'reference') search_fields = ('name', 'reference') model = models.ArchaeologicalSite - readonly_fields = HistorizedObjectAdmin.readonly_fields + ['imports'] inlines = [OperationInline] admin_site.register(models.ArchaeologicalSite, ArchaeologicalSiteAdmin) @@ -112,7 +111,7 @@ class OperationAdmin(HistorizedObjectAdmin): search_fields += ['code_patriarche'] model = models.Operation readonly_fields = HistorizedObjectAdmin.readonly_fields + [ - 'imports', 'cached_label'] + 'cached_label'] form = AdminOperationForm inlines = [ArchaeologicalSiteInline] @@ -144,7 +143,7 @@ class ParcelAdmin(HistorizedObjectAdmin): 'town': 'town'} ) readonly_fields = HistorizedObjectAdmin.readonly_fields + [ - 'imports', 'history_date' + 'history_date' ] admin_site.register(models.Parcel, ParcelAdmin) @@ -196,7 +195,7 @@ class ParcelOwnerAdmin(HistorizedObjectAdmin): 'parcel': 'parcel'} ) readonly_fields = HistorizedObjectAdmin.readonly_fields + [ - 'imports', 'history_date' + 'history_date' ] admin_site.register(models.ParcelOwner, ParcelOwnerAdmin) diff --git a/archaeological_operations/forms.py b/archaeological_operations/forms.py index 651cd740f..841131da6 100644 --- a/archaeological_operations/forms.py +++ b/archaeological_operations/forms.py @@ -480,6 +480,7 @@ RecordRelationsFormSet.form_label = _(u"Relations") class OperationSelect(TableSelect): + search_vector = forms.CharField(label=_(u"Full text search")) year = forms.IntegerField(label=_("Year")) operation_code = forms.IntegerField(label=_(u"Numeric reference")) if settings.COUNTRY == 'fr': diff --git a/archaeological_operations/migrations/0009_auto_20171011_1644.py b/archaeological_operations/migrations/0009_auto_20171011_1644.py new file mode 100644 index 000000000..18a284a21 --- /dev/null +++ b/archaeological_operations/migrations/0009_auto_20171011_1644.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-10-11 16:44 +from __future__ import unicode_literals + +import django.contrib.postgres.search +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_operations', '0008_auto_20170829_1639'), + ] + + operations = [ + migrations.AddField( + model_name='administrativeact', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto filled at save', null=True, verbose_name='Search vector'), + ), + migrations.AddField( + model_name='archaeologicalsite', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto filled at save', null=True, verbose_name='Search vector'), + ), + migrations.AddField( + model_name='historicaladministrativeact', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto filled at save', null=True, verbose_name='Search vector'), + ), + migrations.AddField( + model_name='historicaloperation', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto filled at save', null=True, verbose_name='Search vector'), + ), + migrations.AddField( + model_name='operation', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto filled at save', null=True, verbose_name='Search vector'), + ), + migrations.AddField( + model_name='parcel', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto filled at save', null=True, verbose_name='Search vector'), + ), + migrations.AddField( + model_name='parcelowner', + name='search_vector', + field=django.contrib.postgres.search.SearchVectorField(blank=True, help_text='Auto filled at save', null=True, verbose_name='Search vector'), + ), + ] diff --git a/archaeological_operations/migrations/0010_auto_20171012_1316.py b/archaeological_operations/migrations/0010_auto_20171012_1316.py new file mode 100644 index 000000000..3a847a803 --- /dev/null +++ b/archaeological_operations/migrations/0010_auto_20171012_1316.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-10-12 13:16 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_operations', '0009_auto_20171011_1644'), + ] + + operations = [ + migrations.AlterField( + model_name='historicaloperation', + name='cached_label', + field=models.CharField(blank=True, db_index=True, max_length=500, null=True, verbose_name='Cached name'), + ), + migrations.AlterField( + model_name='operation', + name='cached_label', + field=models.CharField(blank=True, db_index=True, max_length=500, null=True, verbose_name='Cached name'), + ), + ] diff --git a/archaeological_operations/migrations/0011_auto_20171017_1840.py b/archaeological_operations/migrations/0011_auto_20171017_1840.py new file mode 100644 index 000000000..cd169957a --- /dev/null +++ b/archaeological_operations/migrations/0011_auto_20171017_1840.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-10-17 18:40 +from __future__ import unicode_literals + +import django.contrib.postgres.fields.jsonb +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('archaeological_operations', '0010_auto_20171012_1316'), + ] + + operations = [ + migrations.AddField( + model_name='administrativeact', + name='data', + field=django.contrib.postgres.fields.jsonb.JSONField(db_index=True, default={}), + ), + migrations.AddField( + model_name='archaeologicalsite', + name='data', + field=django.contrib.postgres.fields.jsonb.JSONField(db_index=True, default={}), + ), + migrations.AddField( + model_name='historicaladministrativeact', + name='data', + field=django.contrib.postgres.fields.jsonb.JSONField(db_index=True, default={}), + ), + migrations.AddField( + model_name='historicaloperation', + name='data', + field=django.contrib.postgres.fields.jsonb.JSONField(db_index=True, default={}), + ), + migrations.AddField( + model_name='operation', + name='data', + field=django.contrib.postgres.fields.jsonb.JSONField(db_index=True, default={}), + ), + migrations.AddField( + model_name='parcel', + name='data', + field=django.contrib.postgres.fields.jsonb.JSONField(db_index=True, default={}), + ), + migrations.AddField( + model_name='parcelowner', + name='data', + field=django.contrib.postgres.fields.jsonb.JSONField(db_index=True, default={}), + ), + ] diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index bc03ee387..70c1c02ba 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -248,6 +248,10 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms, 'archaeological_sites__reference': _(u"Archaeological sites (" u"reference)"), } + BASE_SEARCH_VECTORS = ["scientist__raw_name", "cached_label", + "common_name", "comment", "address", "old_code"] + INT_SEARCH_VECTORS = ["year"] + M2M_SEARCH_VECTORS = ["towns__name"] # fields definition creation_date = models.DateField(_(u"Creation date"), @@ -309,6 +313,7 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms, code_patriarche = models.TextField(u"Code PATRIARCHE", null=True, blank=True, unique=True) TABLE_COLS = ['full_code_patriarche'] + TABLE_COLS + BASE_SEARCH_VECTORS = ['code_patriarche'] + BASE_SEARCH_VECTORS # preventive fnap_financing = models.FloatField(u"Financement FNAP (%)", blank=True, null=True) @@ -340,7 +345,7 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms, scientific_documentation_comment = models.TextField( _(u"Comment about scientific documentation"), null=True, blank=True) cached_label = models.CharField(_(u"Cached name"), max_length=500, - null=True, blank=True) + null=True, blank=True, db_index=True) archaeological_sites = models.ManyToManyField( ArchaeologicalSite, verbose_name=_(u"Archaeological sites"), blank=True, related_name='operations') diff --git a/archaeological_operations/templates/ishtar/sheet_operation.html b/archaeological_operations/templates/ishtar/sheet_operation.html index 5a02236a3..e46db74c7 100644 --- a/archaeological_operations/templates/ishtar/sheet_operation.html +++ b/archaeological_operations/templates/ishtar/sheet_operation.html @@ -71,6 +71,8 @@ {% field "Abstract" item.abstract "<pre>" "</pre>" %} {% field "Comment about scientific documentation" item.scientific_documentation_comment "<pre>" "</pre>" %} +{% include "ishtar/blocks/sheet_json.html" %} + {% if not next %} {% if item.towns.count %} <h3>{% trans "Localisation"%}</h3> diff --git a/archaeological_operations/tests.py b/archaeological_operations/tests.py index 0d6908374..67b89ce11 100644 --- a/archaeological_operations/tests.py +++ b/archaeological_operations/tests.py @@ -23,6 +23,7 @@ import StringIO import zipfile from django.conf import settings +from django.contrib.contenttypes.models import ContentType from django.core.files.uploadedfile import SimpleUploadedFile from django.core.urlresolvers import reverse from django.db.models import Q @@ -37,7 +38,8 @@ from archaeological_operations import views from ishtar_common.models import OrganizationType, Organization, ItemKey, \ ImporterType, IshtarUser, TargetKey, ImporterModel, IshtarSiteProfile, \ Town, ImporterColumn, Person, Author, SourceType, AuthorType, \ - DocumentTemplate, PersonType, TargetKeyGroup + DocumentTemplate, PersonType, TargetKeyGroup, JsonDataField, \ + JsonDataSection, ImportTarget, FormaterType from archaeological_files.models import File, FileType from archaeological_context_records.models import Unit @@ -453,6 +455,24 @@ class ImportOperationTest(ImportTest, TestCase): impt.delete() self.assertEqual(parcel_count - 3, models.Parcel.objects.count()) + def test_json_fields(self): + importer, form = self.init_ope_import("operations-with-json-fields.csv") + col = ImporterColumn.objects.create(importer_type=importer, + col_number=11) + formater_type = FormaterType.objects.get( + formater_type='IntegerFormater') + ImportTarget.objects.create( + column=col, target='data__autre_refs__arbitraire', + formater_type=formater_type) + impt = form.save(self.ishtar_user) + impt.initialize() + self.init_ope_targetkey(imp=impt) + impt.importation() + ope1 = models.Operation.objects.get(code_patriarche='4200') + self.assertEqual(ope1.data, {u'autre_refs': {u'arbitraire': 789}}) + ope2 = models.Operation.objects.get(code_patriarche='4201') + self.assertEqual(ope2.data, {u'autre_refs': {u'arbitraire': 456}}) + class ParcelTest(ImportTest, TestCase): fixtures = OPERATION_TOWNS_FIXTURES @@ -895,6 +915,21 @@ class OperationTest(TestCase, OperationInitTest): self.assertEqual(ope_id, 'OP2011-1') self.assertEqual(town, self.towns[0].name) + def test_search_vector_update(self): + operation = self.operations[0] + town = self.create_towns({'numero_insee': '12346', 'name': 'Daisy'})[-1] + operation.towns.add(town) + town = self.create_towns( + {'numero_insee': '12347', 'name': 'Dirty old'})[-1] + operation.towns.add(town) + operation = models.Operation.objects.get(pk=operation.pk) + operation.comment = u"Zardoz" + operation.code_patriarche = u"HUIAAA5" + operation.save() + for key in ('old', 'op2010', 'dirty', 'daisy', "'2010'", "zardoz", + "huiaaa5"): + self.assertIn(key, operation.search_vector) + def test_cache_bulk_update(self): if settings.USE_SPATIALITE_FOR_TESTS: # using views - can only be tested with postgresql @@ -1015,6 +1050,53 @@ class OperationTest(TestCase, OperationInitTest): z = zipfile.ZipFile(f) self.assertIsNone(z.testzip()) + def test_json(self): + operation = self.operations[0] + operation.data = {"groundhog": {"number": 53444, + "awake_state": u"réveillée", + "with_feather": "Oui"}, + "frog_number": 32303} + operation.save() + + content_type = ContentType.objects.get_for_model(operation) + groundhog_section = JsonDataSection.objects.create( + name="Marmotte", content_type=content_type) + JsonDataField.objects.create(name=u"État d'éveil", + key='groundhog__awake_state', + content_type=content_type, + section=groundhog_section) + JsonDataField.objects.create(name=u"Avec plume", + key='groundhog__with_feather', + content_type=content_type, + section=groundhog_section) + JsonDataField.objects.create(name=u"Zzzzzzzz", + key='groundhog__zzz', + content_type=content_type, + section=groundhog_section) + JsonDataField.objects.create(name=u"Grenouille", + key='frog_number', + content_type=content_type) + + c = Client() + c.login(username=self.username, password=self.password) + response = c.get(reverse('show-operation', kwargs={'pk': operation.pk})) + self.assertEqual(response.status_code, 200) + self.assertIn('class="sheet"', response.content) + self.assertIn(u"Marmotte".encode('utf-8'), response.content) + self.assertIn(u"État d'éveil".encode('utf-8'), response.content) + self.assertIn(u"réveillée".encode('utf-8'), response.content) + self.assertIn(u"Grenouille".encode('utf-8'), response.content) + self.assertIn(u"32303".encode('utf-8'), response.content) + self.assertNotIn(u"53444".encode('utf-8'), response.content) + self.assertNotIn(u"Zzzzzzzz".encode('utf-8'), response.content) + + operation.data = {} + operation.save() + response = c.get(reverse('show-operation', kwargs={'pk': operation.pk})) + self.assertEqual(response.status_code, 200) + self.assertIn('class="sheet"', response.content) + self.assertNotIn(u"Marmotte".encode('utf-8'), response.content) + class OperationSearchTest(TestCase, OperationInitTest): fixtures = FILE_FIXTURES @@ -1104,6 +1186,42 @@ class OperationSearchTest(TestCase, OperationInitTest): self.assertEqual(response.status_code, 200) self.assertEqual(json.loads(response.content)['total'], 1) + def test_town_search(self): + c = Client() + c.login(username=self.username, password=self.password) + + data = {'numero_insee': '98989', 'name': 'base_town'} + base_town = self.create_towns(datas=data)[-1] + + data = {'numero_insee': '56789', 'name': 'parent_town'} + parent_town = self.create_towns(datas=data)[-1] + parent_town.children.add(base_town) + + data = {'numero_insee': '01234', 'name': 'child_town'} + child_town = self.create_towns(datas=data)[-1] + base_town.children.add(child_town) + + ope = self.operations[1] + ope.towns.add(base_town) + + # simple search + search = {'towns': base_town.pk} + response = c.get(reverse('get-operation'), search) + self.assertEqual(response.status_code, 200) + self.assertEqual(json.loads(response.content)['total'], 1) + + # parent search + search = {'towns': parent_town.pk} + response = c.get(reverse('get-operation'), search) + self.assertEqual(response.status_code, 200) + self.assertEqual(json.loads(response.content)['total'], 1) + + # child search + search = {'towns': child_town.pk} + response = c.get(reverse('get-operation'), search) + self.assertEqual(response.status_code, 200) + self.assertEqual(json.loads(response.content)['total'], 1) + def testOwnSearch(self): c = Client() response = c.get(reverse('get-operation'), {'year': '2010'}) diff --git a/archaeological_operations/tests/operations-with-json-fields.csv b/archaeological_operations/tests/operations-with-json-fields.csv new file mode 100644 index 000000000..015497b4c --- /dev/null +++ b/archaeological_operations/tests/operations-with-json-fields.csv @@ -0,0 +1,3 @@ +code OA,region,type operation,intitule operation,operateur,responsable operation,date debut terrain,date fin terrain,chronologie generale,identifiant document georeferencement,notice scientifique,numéro arbitraire +4201,Bourgogne,Fouille programmée,Oppìdum de Paris 2,L'opérateur,,2000/01/31,2002/12/31,Age du Fer,,456 +4200,Bourgogne,Fouille programmée,Oppìdum de Paris,L'opérateur,Jean Sui-Resp'on Sablé,2000/01/22,2002/12/31,Age du Fer & Gallo-Romain & Néolithik & Moderne,,789 |
