summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.md18
-rw-r--r--archaeological_files/tests.py31
-rw-r--r--archaeological_finds/models_finds.py6
-rw-r--r--archaeological_finds/tests.py15
-rw-r--r--archaeological_finds/urls.py2
-rw-r--r--archaeological_finds/views.py5
-rw-r--r--archaeological_operations/models.py29
-rw-r--r--archaeological_operations/tests.py36
-rw-r--r--install/install-ishtar.sh2
-rwxr-xr-xinstall/install.sh2
-rw-r--r--ishtar_common/admin.py7
-rw-r--r--ishtar_common/data_importer.py5
-rw-r--r--ishtar_common/fixtures/initial_importtypes-fr.json404
-rw-r--r--ishtar_common/management/commands/clean_ishtar.py35
-rw-r--r--ishtar_common/models.py12
-rw-r--r--ishtar_common/templates/blocks/inline_formset.html2
-rw-r--r--ishtar_common/templates/ishtar/display_item.html7
-rw-r--r--ishtar_common/templates/ishtar/formset.html2
-rw-r--r--ishtar_common/templates/welcome.html2
-rw-r--r--ishtar_common/tests.py18
-rw-r--r--ishtar_common/views.py9
-rw-r--r--ishtar_common/wizards.py13
-rw-r--r--version.py2
23 files changed, 481 insertions, 183 deletions
diff --git a/CHANGES.md b/CHANGES.md
index d41f7aa44..466d91d1d 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,6 +1,24 @@
Ishtar changelog
================
+0.99.4 (2017-01-24)
+-------------------
+
+### Features ###
+
+- New specific view to display items (available for finds)
+- Add a command to clean Ishtar DB
+- Import: new formater types - new fixture
+- Admin: add item key
+
+### Bug fixes ###
+
+- Operations: fix deletion of sym-linked operations
+- Parcels: on associated operation or file detachment remove the parcel
+- Fix inline_formset id in template
+- Imports: fix attached files imports
+
+
0.99.3 (2017-01-20)
-------------------
diff --git a/archaeological_files/tests.py b/archaeological_files/tests.py
index f3419013a..8a4c105c6 100644
--- a/archaeological_files/tests.py
+++ b/archaeological_files/tests.py
@@ -44,9 +44,9 @@ class FileInit(object):
self.user.set_password('tralala')
self.user.save()
self.o_user, created = User.objects.get_or_create(username='ousername')
- person_type = PersonType(label=u'Test person type',
- txt_idx='test_person', available=True)
- person_type.save()
+ person_type, created = PersonType.objects.get_or_create(
+ label=u'Test ' u'person type', txt_idx='test_person',
+ available=True)
self.extra_models['person_type'] = person_type
self.model_list.append(person_type)
@@ -56,9 +56,8 @@ class FileInit(object):
self.extra_models['person'] = person
self.model_list.append(person)
- file_type = models.FileType(label=u'Test file type',
- txt_idx='test_file', available=True)
- file_type.save()
+ file_type, created = models.FileType.objects.get_or_create(
+ label=u'Test file type', txt_idx='test_file', available=True)
self.extra_models['file_type'] = file_type
self.model_list.append(file_type)
@@ -205,6 +204,26 @@ class FileTest(TestCase, FileInit):
self.assertTrue(data['records'] == 1)
self.assertEqual(data['rows'][0]['internal_reference'], initial_ref)
+ def testPostDeleteParcels(self):
+ fle = self.item
+ town = Town.objects.create(name='plouf', numero_insee='20000')
+ parcel = Parcel.objects.create(town=town)
+ parcel_nb = Parcel.objects.count()
+ fle.parcels.add(parcel)
+ fle.delete()
+ # our parcel has no operation attached and should be deleted
+ self.assertEqual(parcel_nb - 1, Parcel.objects.count())
+
+ self.create_file()
+ fle = self.item
+ parcel = Parcel.objects.create(town=town)
+ parcel_nb = Parcel.objects.count()
+ fle.parcels.add(parcel)
+ fle.parcels.clear() # no signal raised... should resave
+ Parcel.objects.filter(pk=parcel.pk).all()[0].save()
+ # our parcel has no operation attached and should be deleted
+ self.assertEqual(parcel_nb - 1, Parcel.objects.count())
+
# class ImporterTest(TestCase):
# def testFormaters(self):
# from archaeological_files import data_importer
diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py
index 45c750f66..e8b6135a8 100644
--- a/archaeological_finds/models_finds.py
+++ b/archaeological_finds/models_finds.py
@@ -551,9 +551,9 @@ class Find(BaseHistorizedItem, ImageModel, OwnPerms, ShortMenuItem):
def _get_treatments(self, model, rel='upstream', limit=None):
treatments, findtreats = [], []
q = model.objects.filter(
- find_id=self.pk).order_by(
- 'treatment_nb', 'treatment__start_date',
- 'treatment__end_date')
+ find_id=self.pk).order_by(
+ 'treatment_nb', 'treatment__start_date',
+ 'treatment__end_date')
for findtreat in q.distinct().all():
if findtreat.pk in findtreats:
continue
diff --git a/archaeological_finds/tests.py b/archaeological_finds/tests.py
index 18744ea3d..2d1367c58 100644
--- a/archaeological_finds/tests.py
+++ b/archaeological_finds/tests.py
@@ -20,8 +20,11 @@
import datetime
from django.conf import settings
+from django.contrib.auth.models import User
from django.core.files.uploadedfile import SimpleUploadedFile
+from django.core.urlresolvers import reverse
from django.test import TestCase
+from django.test.client import Client
from ishtar_common.models import ImporterType, IshtarUser, ImporterColumn,\
FormaterType, ImportTarget
@@ -294,6 +297,11 @@ class FindTest(FindInit, TestCase):
def setUp(self):
self.create_finds(force=True)
+ password = 'mypassword'
+ my_admin = User.objects.create_superuser(
+ 'myuser', 'myemail@test.com', password)
+ self.client = Client()
+ self.client.login(username=my_admin.username, password=password)
def testExternalID(self):
find = self.finds[0]
@@ -309,6 +317,13 @@ class FindTest(FindInit, TestCase):
base_find.context_record.external_id,
base_find.label))
+ def testShowFind(self):
+ find = self.finds[0]
+ response = self.client.get(reverse('display-find', args=[find.pk]))
+ self.assertEqual(response.status_code, 200)
+ self.assertIn('load_window("/show-find/{}/");'.format(find.pk),
+ response.content)
+
class PackagingTest(FindInit, TestCase):
fixtures = [settings.ROOT_PATH +
diff --git a/archaeological_finds/urls.py b/archaeological_finds/urls.py
index 7be07d015..4a8dec030 100644
--- a/archaeological_finds/urls.py
+++ b/archaeological_finds/urls.py
@@ -269,6 +269,8 @@ urlpatterns += patterns(
name='show-findbasket'),
url(r'^show-find(?:/(?P<pk>.+))?/(?P<type>.+)?$', 'show_find',
name=models.Find.SHOW_URL),
+ url(r'^display-find/(?P<pk>.+)/$', 'display_find',
+ name='display-' + models.Find.SLUG),
url(r'^show-historized-find/(?P<pk>.+)?/(?P<date>.+)?$',
'show_find', name='show-historized-find'),
url(r'^revert-find/(?P<pk>.+)/(?P<date>.+)$',
diff --git a/archaeological_finds/views.py b/archaeological_finds/views.py
index 01e88c1b7..084f15d13 100644
--- a/archaeological_finds/views.py
+++ b/archaeological_finds/views.py
@@ -38,8 +38,8 @@ from archaeological_operations.forms import FinalAdministrativeActDeleteForm
from archaeological_context_records.forms \
import RecordFormSelection as RecordFormSelectionTable
-from ishtar_common.views import get_item, show_item, revert_item, \
- get_autocomplete_generic, IshtarMixin, LoginRequiredMixin
+from ishtar_common.views import get_item, show_item, display_item, \
+ revert_item, get_autocomplete_generic, IshtarMixin, LoginRequiredMixin
from ishtar_common.wizards import SearchWizard
from archaeological_operations.wizards import AdministrativeActDeletionWizard
@@ -108,6 +108,7 @@ show_findsource = show_item(models.FindSource, 'findsource')
get_findsource = get_item(models.FindSource, 'get_findsource', 'findsource')
show_find = show_item(models.Find, 'find')
+display_find = display_item(models.Find, 'find')
revert_find = revert_item(models.Find)
show_findbasket = show_item(models.FindBasket, 'findbasket')
diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py
index c8c291752..4a900c276 100644
--- a/archaeological_operations/models.py
+++ b/archaeological_operations/models.py
@@ -557,14 +557,6 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms,
def is_active(self):
return not bool(self.end_date)
- def save(self, *args, **kwargs):
- # put a default year if start_date is defined
- if self.start_date and not self.year:
- self.year = self.start_date.year
- if self.operation_code is None:
- self.operation_code = self.get_available_operation_code(self.year)
- return super(Operation, self).save(*args, **kwargs)
-
@property
def nb_parcels(self):
_(u"Number of parcels")
@@ -767,6 +759,14 @@ class Operation(ClosedItem, BaseHistorizedItem, ImageModel, OwnPerms,
res['mode'] = u" ; ".join([str(m) for m in mode(finds)])
return res
+ def save(self, *args, **kwargs):
+ # put a default year if start_date is defined
+ if self.start_date and not self.year:
+ self.year = self.start_date.year
+ if self.operation_code is None:
+ self.operation_code = self.get_available_operation_code(self.year)
+ return super(Operation, self).save(*args, **kwargs)
+
m2m_changed.connect(cached_label_changed, sender=Operation.towns.through)
@@ -1193,10 +1193,10 @@ class Parcel(LightHistorizedItem):
associated_file = models.ForeignKey(
'archaeological_files.File',
related_name='parcels', verbose_name=_(u"File"),
- blank=True, null=True)
+ blank=True, null=True, on_delete=models.CASCADE)
operation = models.ForeignKey(
Operation, related_name='parcels', blank=True, null=True,
- verbose_name=_(u"Operation"))
+ verbose_name=_(u"Operation"), on_delete=models.CASCADE)
year = models.IntegerField(_(u"Year"), blank=True, null=True)
town = models.ForeignKey(Town, related_name='parcels',
verbose_name=_(u"Town"))
@@ -1356,6 +1356,13 @@ def parcel_post_save(sender, **kwargs):
if not kwargs['instance']:
return
parcel = kwargs['instance']
+ created = kwargs.get('created', None)
+
+ # remove when the parcel is linked to nothing
+ if not getattr(parcel, '_updated_id', None) and not created and not \
+ parcel.operation and not parcel.associated_file:
+ parcel.delete()
+ return
updated = False
if not parcel.external_id or parcel.auto_external_id:
@@ -1365,6 +1372,7 @@ def parcel_post_save(sender, **kwargs):
parcel.auto_external_id = True
parcel.external_id = external_id
if updated:
+ parcel._updated_id = True
parcel.save()
return
@@ -1378,6 +1386,7 @@ def parcel_post_save(sender, **kwargs):
if parcel.operation and parcel.associated_file:
# parcels are copied between files and operations
parcel.copy_to_operation()
+
post_save.connect(parcel_post_save, sender=Parcel)
diff --git a/archaeological_operations/tests.py b/archaeological_operations/tests.py
index d8399eedb..33199dd04 100644
--- a/archaeological_operations/tests.py
+++ b/archaeological_operations/tests.py
@@ -35,7 +35,7 @@ import models
from archaeological_operations import views
from ishtar_common.models import OrganizationType, Organization, \
- ImporterType, IshtarUser, TargetKey, IshtarSiteProfile
+ ImporterType, IshtarUser, TargetKey, IshtarSiteProfile, Town
from ishtar_common import forms_common
from ishtar_common.tests import WizardTest, WizardTestFormData as FormData, \
@@ -578,8 +578,7 @@ class OperationTest(TestCase, OperationInitTest):
{'operator': self.orgas[0].pk})
self.assertTrue(json.loads(response.content)['total'] == 2)
- def testRelatedSearch(self):
- c = Client()
+ def create_relations(self):
rel1 = models.RelationType.objects.create(
symmetrical=True, label='Include', txt_idx='include')
rel2 = models.RelationType.objects.create(
@@ -589,6 +588,11 @@ class OperationTest(TestCase, OperationInitTest):
left_record=self.operations[0],
right_record=self.operations[1],
relation_type=rel1)
+ return rel1, rel2
+
+ def testRelatedSearch(self):
+ c = Client()
+ rel1, rel2 = self.create_relations()
self.operations[1].year = 2011
self.operations[1].save()
search = {'year': '2010', 'relation_types_0': rel2.pk}
@@ -599,6 +603,28 @@ class OperationTest(TestCase, OperationInitTest):
response = c.get(reverse('get-operation'), search)
self.assertTrue(json.loads(response.content)['total'] == 2)
+ def testPostDeleteRelations(self):
+ self.create_relations()
+ self.operations[0].delete()
+
+ def testPostDeleteParcels(self):
+ ope = self.operations[0]
+ town = Town.objects.create(name='plouf', numero_insee='20000')
+ parcel = models.Parcel.objects.create(town=town)
+ parcel_nb = models.Parcel.objects.count()
+ ope.parcels.add(parcel)
+ ope.delete()
+ # our parcel has no operation attached and should be deleted
+ self.assertEqual(parcel_nb - 1, models.Parcel.objects.count())
+ ope = self.operations[1]
+ parcel = models.Parcel.objects.create(town=town)
+ parcel_nb = models.Parcel.objects.count()
+ ope.parcels.add(parcel)
+ ope.parcels.clear() # no signal raised... should resave
+ models.Parcel.objects.filter(pk=parcel.pk).all()[0].save()
+ # our parcel has no operation attached and should be deleted
+ self.assertEqual(parcel_nb - 1, models.Parcel.objects.count())
+
def testOwnSearch(self):
c = Client()
response = c.get(reverse('get-operation'), {'year': '2010'})
@@ -718,6 +744,8 @@ class OperationWizardDeleteTest(OperationWizardCreationTest):
def pre_wizard(self):
self.ope = self.get_default_operation(force=True)
+ self.ope.parcels.add(self.create_parcel()[0])
+ self.parcel_nb = models.Parcel.objects.count()
self.form_datas[0].form_datas['selec-operation_deletion']['pk'] = \
self.ope.pk
self.operation_number = models.Operation.objects.count()
@@ -726,6 +754,8 @@ class OperationWizardDeleteTest(OperationWizardCreationTest):
def post_wizard(self):
self.assertEqual(self.operation_number - 1,
models.Operation.objects.count())
+ # associated parcel removed
+ self.assertEqual(self.parcel_nb - 1, models.Parcel.objects.count())
class OperationWizardClosingTest(OperationWizardCreationTest):
diff --git a/install/install-ishtar.sh b/install/install-ishtar.sh
index 214813406..4c5995ca0 100644
--- a/install/install-ishtar.sh
+++ b/install/install-ishtar.sh
@@ -327,7 +327,7 @@ EOF
mkdir -p $full_install_path
cd $full_install_path
( set -x; git clone git://git.proxience.com/git/oook_replace.git 2> /dev/null )
- ( set -x; git clone https://gitlab.com/ishtar/ishtar.git 2> /dev/null )
+ ( set -x; git clone https://gitlab.com/iggdrasil/ishtar.git 2> /dev/null )
cd ishtar
git fetch 2> /dev/null
git checkout $version 2> /dev/null
diff --git a/install/install.sh b/install/install.sh
index e80730f9d..1556306c6 100755
--- a/install/install.sh
+++ b/install/install.sh
@@ -133,7 +133,7 @@ mkdir $INSTALL_PATH'/conf'
cd $INSTALL_PATH
echo ' * ishtar'
-git clone https://gitlab.com/ishtar/ishtar.git 2> /dev/null
+git clone https://gitlab.com/iggdrasil/ishtar.git 2> /dev/null
# echo ' * oook!'
# git clone git://git.proxience.com/git/oook_replace.git 2> /dev/null
# ln -s $INSTALL_PATH'/oook_replace/oook_replace' $INSTALL_PATH'/ishtar/'
diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py
index efb452e74..b3e0763b5 100644
--- a/ishtar_common/admin.py
+++ b/ishtar_common/admin.py
@@ -246,6 +246,13 @@ class IshtarUserAdmin(admin.ModelAdmin):
admin.site.register(models.IshtarUser, IshtarUserAdmin)
+
+class ItemKeyAdmin(admin.ModelAdmin):
+ list_display = ('content_type', 'key', 'content_object', 'importer')
+ search_fields = ('key', )
+admin.site.register(models.ItemKey, ItemKeyAdmin)
+
+
basic_models = [models.DocumentTemplate]
if settings.COUNTRY == 'fr':
basic_models += [models.Arrondissement, models.Canton]
diff --git a/ishtar_common/data_importer.py b/ishtar_common/data_importer.py
index b669995e3..49705f0df 100644
--- a/ishtar_common/data_importer.py
+++ b/ishtar_common/data_importer.py
@@ -1311,11 +1311,14 @@ class Importer(object):
self.get_field(cls, attribute, data, m2ms, c_c_path,
new_created)
- # filter uncessary default values
create_dict = copy.deepcopy(data)
for k in create_dict.keys():
+ # filter unnecessary default values
if type(create_dict[k]) == dict:
create_dict.pop(k)
+ # File doesn't like deepcopy
+ if type(create_dict[k]) == File:
+ create_dict[k] = copy.copy(data[k])
# default values
path = tuple(path)
diff --git a/ishtar_common/fixtures/initial_importtypes-fr.json b/ishtar_common/fixtures/initial_importtypes-fr.json
index 0592ca60f..342367f2b 100644
--- a/ishtar_common/fixtures/initial_importtypes-fr.json
+++ b/ishtar_common/fixtures/initial_importtypes-fr.json
@@ -7,6 +7,7 @@
"is_template": true,
"unicity_keys": "code_patriarche",
"users": [
+ 2
],
"slug": "operatio",
"associated_models": "archaeological_operations.models.Operation",
@@ -21,6 +22,7 @@
"is_template": true,
"unicity_keys": null,
"users": [
+ 2
],
"slug": null,
"associated_models": "archaeological_operations.models.Operation",
@@ -35,6 +37,7 @@
"is_template": true,
"unicity_keys": null,
"users": [
+ 2
],
"slug": null,
"associated_models": "archaeological_context_records.models.ContextRecord",
@@ -3136,7 +3139,7 @@
"description": "Chronologies associ\u00e9es (plusieurs possibles s\u00e9par\u00e9es par &), exemple : \"Gallo-romain & M\u00e9di\u00e9val\", \"GR&MED\", \"M\u00e9solithique final & M\u00e9so moyen & Epipal\", etc.",
"regexp_pre_filter": null,
"required": false,
- "label": null,
+ "label": "Periodes",
"importer_type": 18
}
},
@@ -3421,7 +3424,7 @@
"model": "ishtar_common.importercolumn",
"fields": {
"col_number": 7,
- "description": "R\u00e9f\u00e9rence du point topo, d'ordinaire un entier mais peut \u00eatre autre chose. Champ texte, max. 120 caract\u00e8res. Exemple : \"7220\", \"pt. 72\", etc.\r\n\r\nNON LI\u00c9 POUR L'INSTANT.",
+ "description": "R\u00e9f\u00e9rence du point topo, d'ordinaire un entier mais peut \u00eatre autre chose. Champ texte, max. 120 caract\u00e8res. Exemple : \"7220\", \"pt. 72\", etc.\r\n",
"regexp_pre_filter": null,
"required": false,
"label": "Ref. point topo",
@@ -3505,7 +3508,7 @@
"model": "ishtar_common.importercolumn",
"fields": {
"col_number": 14,
- "description": "Type(s) d'objet(s), s\u00e9par\u00e9s par des \"&\". Exemple : \"tesson & charbon\", \"os & m\u00e9tal\", \"faune\", \"fibule & bague\", \"lame & lamelle\", \"\u00e9clat & nucl\u00e9us\", etc.",
+ "description": "Type(s) d'objet(s), s\u00e9par\u00e9s par des \"&\". Exemple : \"tesson & charbon\", \"vase\", \"scapula\", \"fibule & bague\", \"lame & lamelle\", \"\u00e9clat & nucl\u00e9us\", etc.",
"regexp_pre_filter": null,
"required": false,
"label": "Type(s) d'objet(s)",
@@ -3693,6 +3696,54 @@
}
},
{
+ "pk": 365,
+ "model": "ishtar_common.importercolumn",
+ "fields": {
+ "col_number": 30,
+ "description": "Coordonn\u00e9e X pour cet objet",
+ "regexp_pre_filter": null,
+ "required": false,
+ "label": "Coordonn\u00e9e X",
+ "importer_type": 20
+ }
+ },
+ {
+ "pk": 366,
+ "model": "ishtar_common.importercolumn",
+ "fields": {
+ "col_number": 31,
+ "description": "Coordonn\u00e9e Y pour cet objet",
+ "regexp_pre_filter": null,
+ "required": false,
+ "label": "Coordonn\u00e9e Y",
+ "importer_type": 20
+ }
+ },
+ {
+ "pk": 367,
+ "model": "ishtar_common.importercolumn",
+ "fields": {
+ "col_number": 32,
+ "description": "Coordonn\u00e9e Z pour cet objet (altitude NGF ou arbitraire)",
+ "regexp_pre_filter": null,
+ "required": false,
+ "label": "Coordonn\u00e9e Z",
+ "importer_type": 20
+ }
+ },
+ {
+ "pk": 368,
+ "model": "ishtar_common.importercolumn",
+ "fields": {
+ "col_number": 33,
+ "description": "Code permettant de qualifi\u00e9 le mode de projection des donnes (SRS /EPSG). Exemple : \"EPSG:2154\" pour le Lambert 93",
+ "regexp_pre_filter": null,
+ "required": false,
+ "label": "Syst\u00e8me de r\u00e9f\u00e9rence spatiale",
+ "importer_type": 20
+ }
+ },
+ {
"pk": 46,
"model": "ishtar_common.importtarget",
"fields": {
@@ -4505,6 +4556,20 @@
}
},
{
+ "pk": 38,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "label",
+ "column": 37,
+ "formater_type": 3,
+ "concat_str": null,
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": false
+ }
+ },
+ {
"pk": 305,
"model": "ishtar_common.importtarget",
"fields": {
@@ -4673,20 +4738,6 @@
}
},
{
- "pk": 335,
- "model": "ishtar_common.importtarget",
- "fields": {
- "comment": "",
- "target": "parcel__external_id",
- "column": 311,
- "formater_type": 28,
- "concat_str": "",
- "regexp_filter": null,
- "concat": false,
- "force_new": false
- }
- },
- {
"pk": 338,
"model": "ishtar_common.importtarget",
"fields": {
@@ -4757,20 +4808,6 @@
}
},
{
- "pk": 350,
- "model": "ishtar_common.importtarget",
- "fields": {
- "comment": "",
- "target": "datings__period",
- "column": 325,
- "formater_type": 6,
- "concat_str": "",
- "regexp_filter": null,
- "concat": false,
- "force_new": false
- }
- },
- {
"pk": 353,
"model": "ishtar_common.importtarget",
"fields": {
@@ -4813,20 +4850,6 @@
}
},
{
- "pk": 362,
- "model": "ishtar_common.importtarget",
- "fields": {
- "comment": "",
- "target": "context_record__external_id",
- "column": 337,
- "formater_type": 28,
- "concat_str": "",
- "regexp_filter": null,
- "concat": false,
- "force_new": false
- }
- },
- {
"pk": 365,
"model": "ishtar_common.importtarget",
"fields": {
@@ -4841,20 +4864,6 @@
}
},
{
- "pk": 368,
- "model": "ishtar_common.importtarget",
- "fields": {
- "comment": "",
- "target": "is_isolated",
- "column": 344,
- "formater_type": 19,
- "concat_str": "",
- "regexp_filter": null,
- "concat": false,
- "force_new": false
- }
- },
- {
"pk": 371,
"model": "ishtar_common.importtarget",
"fields": {
@@ -4953,34 +4962,6 @@
}
},
{
- "pk": 388,
- "model": "ishtar_common.importtarget",
- "fields": {
- "comment": "",
- "target": "find__datings__period",
- "column": 364,
- "formater_type": 6,
- "concat_str": "",
- "regexp_filter": null,
- "concat": false,
- "force_new": false
- }
- },
- {
- "pk": 38,
- "model": "ishtar_common.importtarget",
- "fields": {
- "comment": "",
- "target": "label",
- "column": 37,
- "formater_type": 3,
- "concat_str": null,
- "regexp_filter": null,
- "concat": false,
- "force_new": false
- }
- },
- {
"pk": 3,
"model": "ishtar_common.importtarget",
"fields": {
@@ -5191,20 +5172,6 @@
}
},
{
- "pk": 336,
- "model": "ishtar_common.importtarget",
- "fields": {
- "comment": "",
- "target": "parcel__external_id",
- "column": 312,
- "formater_type": 11,
- "concat_str": "",
- "regexp_filter": null,
- "concat": false,
- "force_new": false
- }
- },
- {
"pk": 339,
"model": "ishtar_common.importtarget",
"fields": {
@@ -5317,20 +5284,6 @@
}
},
{
- "pk": 363,
- "model": "ishtar_common.importtarget",
- "fields": {
- "comment": "",
- "target": "context_record__external_id",
- "column": 338,
- "formater_type": 35,
- "concat_str": "",
- "regexp_filter": null,
- "concat": false,
- "force_new": false
- }
- },
- {
"pk": 366,
"model": "ishtar_common.importtarget",
"fields": {
@@ -6115,6 +6068,76 @@
}
},
{
+ "pk": 336,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "parcel__external_id",
+ "column": 312,
+ "formater_type": 11,
+ "concat_str": "-",
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": false
+ }
+ },
+ {
+ "pk": 335,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "parcel__external_id",
+ "column": 311,
+ "formater_type": 28,
+ "concat_str": "-",
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": false
+ }
+ },
+ {
+ "pk": 362,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "context_record__external_id",
+ "column": 337,
+ "formater_type": 28,
+ "concat_str": "-",
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": false
+ }
+ },
+ {
+ "pk": 363,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "context_record__external_id",
+ "column": 338,
+ "formater_type": 35,
+ "concat_str": "-",
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": false
+ }
+ },
+ {
+ "pk": 388,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "find__datings__period",
+ "column": 364,
+ "formater_type": 6,
+ "concat_str": "",
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": true
+ }
+ },
+ {
"pk": 99,
"model": "ishtar_common.importtarget",
"fields": {
@@ -7445,34 +7468,6 @@
}
},
{
- "pk": 361,
- "model": "ishtar_common.importtarget",
- "fields": {
- "comment": "",
- "target": "context_record__external_id",
- "column": 336,
- "formater_type": 11,
- "concat_str": "",
- "regexp_filter": null,
- "concat": false,
- "force_new": false
- }
- },
- {
- "pk": 364,
- "model": "ishtar_common.importtarget",
- "fields": {
- "comment": "",
- "target": "context_record__external_id",
- "column": 339,
- "formater_type": 3,
- "concat_str": "",
- "regexp_filter": null,
- "concat": false,
- "force_new": false
- }
- },
- {
"pk": 367,
"model": "ishtar_common.importtarget",
"fields": {
@@ -7529,6 +7524,20 @@
}
},
{
+ "pk": 364,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "context_record__external_id",
+ "column": 339,
+ "formater_type": 3,
+ "concat_str": "-",
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": false
+ }
+ },
+ {
"pk": 381,
"model": "ishtar_common.importtarget",
"fields": {
@@ -7557,6 +7566,104 @@
}
},
{
+ "pk": 389,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "topographic_localisation",
+ "column": 343,
+ "formater_type": 3,
+ "concat_str": "",
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": false
+ }
+ },
+ {
+ "pk": 390,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "x",
+ "column": 365,
+ "formater_type": 21,
+ "concat_str": "",
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": false
+ }
+ },
+ {
+ "pk": 391,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "y",
+ "column": 366,
+ "formater_type": 21,
+ "concat_str": "",
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": false
+ }
+ },
+ {
+ "pk": 392,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "z",
+ "column": 367,
+ "formater_type": 21,
+ "concat_str": "",
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": false
+ }
+ },
+ {
+ "pk": 350,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "datings__period",
+ "column": 325,
+ "formater_type": 6,
+ "concat_str": "",
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": true
+ }
+ },
+ {
+ "pk": 393,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "spatial_reference_system",
+ "column": 368,
+ "formater_type": 46,
+ "concat_str": "",
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": false
+ }
+ },
+ {
+ "pk": 361,
+ "model": "ishtar_common.importtarget",
+ "fields": {
+ "comment": "",
+ "target": "context_record__external_id",
+ "column": 336,
+ "formater_type": 11,
+ "concat_str": "-",
+ "regexp_filter": null,
+ "concat": false,
+ "force_new": false
+ }
+ },
+ {
"pk": 25,
"model": "ishtar_common.formatertype",
"fields": {
@@ -7764,6 +7871,15 @@
}
},
{
+ "pk": 46,
+ "model": "ishtar_common.formatertype",
+ "fields": {
+ "formater_type": "TypeFormater",
+ "many_split": "",
+ "options": "SpatialReferenceSystem"
+ }
+ },
+ {
"pk": 13,
"model": "ishtar_common.formatertype",
"fields": {
@@ -8449,4 +8565,4 @@
"force_new": false
}
}
-]
+] \ No newline at end of file
diff --git a/ishtar_common/management/commands/clean_ishtar.py b/ishtar_common/management/commands/clean_ishtar.py
new file mode 100644
index 000000000..d3da40fd8
--- /dev/null
+++ b/ishtar_common/management/commands/clean_ishtar.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (C) 2017 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# See the file COPYING for details.
+
+import sys
+
+from django.core.management.base import BaseCommand
+
+from archaeological_operations.models import Parcel
+
+
+class Command(BaseCommand):
+ args = ''
+ help = 'Clean unused items'
+
+ def handle(self, *args, **options):
+ for parcel in Parcel.objects.all():
+ parcel.skip_history_when_saving = True
+ parcel.save()
+ self.stdout.write('Parcel cleaned.\n')
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index d58d549c8..d1d58f184 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -959,11 +959,12 @@ def post_delete_record_relation(sender, instance, **kwargs):
# no symetric/inverse is defined
if not sym_rel_type:
return
-
- dct = {'right_record': instance.left_record,
- 'left_record': instance.right_record,
+ dct = {'right_record_id': instance.left_record_id,
+ 'left_record_id': instance.right_record_id,
'relation_type': sym_rel_type}
- instance.__class__.objects.filter(**dct).delete()
+ q = instance.__class__.objects.filter(**dct)
+ if q.count():
+ q.delete()
class ShortMenuItem(object):
@@ -2048,10 +2049,13 @@ TARGET_MODELS = [
_(u"Conservatory state")),
('archaeological_finds.models.PreservationType', _(u"Preservation type")),
('archaeological_finds.models.ObjectType', _(u"Object type")),
+ ('archaeological_finds.models.IntegrityType', _(u"Integrity type")),
+ ('archaeological_finds.models.RemarkabilityType', _(u"Remarkability type")),
('archaeological_context_records.models.IdentificationType',
_("Identification type")),
('archaeological_context_records.models.RelationType',
_(u"Context record relation type")),
+ ('SpatialReferenceSystem', _(u"Spatial reference system")),
('SupportType', _(u"Support type")),
]
diff --git a/ishtar_common/templates/blocks/inline_formset.html b/ishtar_common/templates/blocks/inline_formset.html
index 4d4042985..9c1daad28 100644
--- a/ishtar_common/templates/blocks/inline_formset.html
+++ b/ishtar_common/templates/blocks/inline_formset.html
@@ -1,6 +1,6 @@
{% load i18n %}
{% if extra_formset.non_form_errors %}<div class='errors'>{{extra_formset.non_form_errors.as_ul}}</div>{% endif %}
- {% if header %}<table class='inline-table' id='{{formset}}'>
+ {% if header %}<table class='inline-table' id='{{formset.prefix}}'>
<caption>{% trans caption %}</caption>
<thead>
<tr>{% for field in formset.0.visible_fields%}
diff --git a/ishtar_common/templates/ishtar/display_item.html b/ishtar_common/templates/ishtar/display_item.html
index 87dda6dcf..e00fef05b 100644
--- a/ishtar_common/templates/ishtar/display_item.html
+++ b/ishtar_common/templates/ishtar/display_item.html
@@ -1,11 +1,10 @@
{% extends "base.html" %}
{% load i18n %}
-{% load url from future %}
{% block content %}
-<h2>{{page_name}}</h2>
<script type='text/javascript'>
-$(function() {
- load_window("{% url item_url pk %}");
+$(document).ready(
+function(){
+ load_window("/show-{{item_type}}/{{pk}}/");
});
</script>
{% endblock %}
diff --git a/ishtar_common/templates/ishtar/formset.html b/ishtar_common/templates/ishtar/formset.html
index c8a92165e..5454ae7e5 100644
--- a/ishtar_common/templates/ishtar/formset.html
+++ b/ishtar_common/templates/ishtar/formset.html
@@ -5,7 +5,7 @@
<div class='form' id='global-vars'>
<form action="." method="post">{% csrf_token %}
{% inline_formset ' ' formset %}
-<input type="submit" value="{% trans "Validate" %}"/>
+<input type="submit" value="{% trans 'Validate' %}"/>
</form>
</div>
{% endblock %}
diff --git a/ishtar_common/templates/welcome.html b/ishtar_common/templates/welcome.html
index eb9de475e..508f7be02 100644
--- a/ishtar_common/templates/welcome.html
+++ b/ishtar_common/templates/welcome.html
@@ -8,5 +8,5 @@
<li><a href='https://ishtar-archeo.net' target="_blank">{% trans "Presentation site and blog" %}</a>{% trans ":"%} {% trans "stay tuned with Ishtar news!" %}</li>
<li><a href='{% url 'admin:index' %}' target="_blank">{% trans "Admin interface" %}</a>{% trans ":"%} {% trans "for admin only." %}</li>
<li><a href="https://forum.ishtar-archeo.net/" target="_blank">{% trans "Forum" %}</a>{% trans ":"%} {% trans "need help? find a new bug? a fantastic feature to propose? Here is the place to go." %}</li>
- <li><a href="https://gitlab.com/ishtar/ishtar" target="_blank">{% trans "Source code" %}</a> &ndash; <a href="https://tickets.iggdrasil.net/projects/ishtar" target="_blank">{% trans "tickets" %}</a>{% trans ":"%} {% trans "where the magic happens." %}</li>
+ <li><a href="https://gitlab.com/iggdrasil/ishtar" target="_blank">{% trans "Source code" %}</a> &ndash; <a href="https://tickets.iggdrasil.net/projects/ishtar" target="_blank">{% trans "tickets" %}</a>{% trans ":"%} {% trans "where the magic happens." %}</li>
</ul>
diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py
index f22e42e38..10584e4f2 100644
--- a/ishtar_common/tests.py
+++ b/ishtar_common/tests.py
@@ -17,6 +17,7 @@
# See the file COPYING for details.
+from StringIO import StringIO
from bs4 import BeautifulSoup as Soup
from django.conf import settings
@@ -25,6 +26,7 @@ from django.contrib.contenttypes.models import ContentType
from django.core.cache import cache
from django.core.exceptions import ValidationError
from django.core.files.base import File as DjangoFile
+from django.core.management import call_command
from django.core.urlresolvers import reverse
from django.template.defaultfilters import slugify
from django.test import TestCase
@@ -76,6 +78,22 @@ def create_user():
return username, password, user
+class CommandsTestCase(TestCase):
+ def test_clean_ishtar(self):
+ """
+ Clean ishtar db
+ """
+ from archaeological_operations.models import Parcel
+ p = Parcel.objects.create(
+ town=models.Town.objects.create(name='test', numero_insee='25000'))
+ parcel_nb = Parcel.objects.count()
+ out = StringIO()
+ call_command('clean_ishtar', stdout=out)
+ # no operation or file attached - the parcel should have disappear
+ self.assertEqual(parcel_nb - 1, Parcel.objects.count())
+ self.assertEqual(Parcel.objects.filter(pk=p.pk).count(), 0)
+
+
class WizardTestFormData(object):
"""
Test set to simulate wizard steps
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index 42ebdf277..b0817fc59 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -1112,6 +1112,15 @@ def get_by_importer(request, slug, data_type='json', full=False,
)(request, data_type, full, force_own, **dct)
+def display_item(model, name, extra_dct=None):
+ def func(request, pk, **dct):
+ dct['item_type'] = name
+ dct['pk'] = pk
+ return render_to_response('ishtar/display_item.html', dct,
+ context_instance=RequestContext(request))
+ return func
+
+
def show_item(model, name, extra_dct=None):
def func(request, pk, **dct):
try:
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index 18336cff5..735ad62fd 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.py
@@ -31,6 +31,7 @@ from django.core.files.storage import default_storage
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.http import HttpResponseRedirect
from django.forms import ValidationError
from django.shortcuts import render_to_response, redirect
@@ -679,6 +680,18 @@ class Wizard(NamedUrlWizardView):
# material_index management for baseitems
obj._cached_label_checked = False
obj.save()
+
+ # force post_save for old related m2ms (which can have been detached
+ # from the current object)
+ for model in old_m2ms:
+ for item in old_m2ms[model]:
+ # verify it hasn't been deleted
+ q = item.__class__.objects.filter(pk=item.pk)
+ if q.count():
+ item = q.all()[0]
+ item.skip_history_when_saving = True
+ item.save()
+
# make the new object a default
if self.current_obj_slug:
self.request.session[self.current_obj_slug] = unicode(obj.pk)
diff --git a/version.py b/version.py
index 128b5c14a..2092b9c8f 100644
--- a/version.py
+++ b/version.py
@@ -1,4 +1,4 @@
-VERSION = (0, 99, 3)
+VERSION = (0, 99, 4)
def get_version():