summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@peacefrogs.net>2012-03-29 16:55:17 +0200
committerÉtienne Loks <etienne.loks@peacefrogs.net>2012-03-29 16:55:17 +0200
commit953310b7e18bdb012dae2fcc0184bc63f1c30c0c (patch)
tree98c7b6d2460060dd1a2a71c3b303e221d4fa258c
parenta46efae7bf7a9a0f8a2ccaffdfe0d18ffcb2a0d2 (diff)
downloadChimère-953310b7e18bdb012dae2fcc0184bc63f1c30c0c.tar.bz2
Chimère-953310b7e18bdb012dae2fcc0184bc63f1c30c0c.zip
Work on OSM export - simplify KML import
-rw-r--r--chimere/__init__.py7
-rw-r--r--chimere/admin.py20
l---------chimere/external_utils1
-rw-r--r--chimere/migrations/0011_auto__del_field_importer_source_url__add_field_importer_source.py195
-rw-r--r--chimere/models.py27
-rw-r--r--chimere/tasks.py49
-rw-r--r--chimere/tests.py14
-rw-r--r--chimere/utils.py106
-rw-r--r--debian/control2
-rw-r--r--example_project/settings.py.example12
-rw-r--r--requirements.txt1
11 files changed, 393 insertions, 41 deletions
diff --git a/chimere/__init__.py b/chimere/__init__.py
index 1b2fc61..a7083c7 100644
--- a/chimere/__init__.py
+++ b/chimere/__init__.py
@@ -7,3 +7,10 @@ from django.utils.translation import ugettext as _
# templates/chimere/edit.html, templates/chimere/edit_route.html
_(u"Multimedia files")
_(u"Picture files")
+
+VERSION = (2, 0)
+
+def get_version():
+ return u'.'.join((unicode(num) for num in VERSION))
+
+__version__ = get_version()
diff --git a/chimere/admin.py b/chimere/admin.py
index afc818c..42d536e 100644
--- a/chimere/admin.py
+++ b/chimere/admin.py
@@ -152,10 +152,24 @@ def cancel_import(modeladmin, request, queryset):
importer.save()
cancel_import.short_description = _(u"Cancel import")
+def cancel_export(modeladmin, request, queryset):
+ for importer in queryset:
+ importer.state = tasks.IMPORT_MESSAGES['export_cancel'][0]
+ importer.save()
+cancel_export.short_description = _(u"Cancel export")
+
+def export_to_osm(modeladmin, request, queryset):
+ importers = modeladmin.model.objects.filter(importer_type='OSM')
+ for importer in queryset:
+ importer.state = unicode(tasks.IMPORT_MESSAGES['export_pending'][0])
+ importer.save()
+ tasks.exporting(importer.pk)
+export_to_osm.short_description = _(u"Export to osm")
+
class ImporterAdmin(admin.ModelAdmin):
- list_display = ('importer_type', 'source_url', 'state', 'filtr')
- list_filter = ('importer_type', 'source_url')
- actions = [importing, cancel_import]
+ list_display = ('importer_type', 'source', 'state', 'filtr')
+ list_filter = ('importer_type', 'source')
+ actions = [importing, cancel_import, cancel_export]
class NewsAdmin(admin.ModelAdmin):
"""
diff --git a/chimere/external_utils b/chimere/external_utils
new file mode 120000
index 0000000..19985ba
--- /dev/null
+++ b/chimere/external_utils
@@ -0,0 +1 @@
+../utils/ \ No newline at end of file
diff --git a/chimere/migrations/0011_auto__del_field_importer_source_url__add_field_importer_source.py b/chimere/migrations/0011_auto__del_field_importer_source_url__add_field_importer_source.py
new file mode 100644
index 0000000..31ce4d8
--- /dev/null
+++ b/chimere/migrations/0011_auto__del_field_importer_source_url__add_field_importer_source.py
@@ -0,0 +1,195 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Deleting field 'Importer.source_url'
+ db.delete_column('chimere_importer', 'source_url')
+
+ # Adding field 'Importer.source'
+ db.add_column('chimere_importer', 'source', self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Adding field 'Importer.source_url'
+ db.add_column('chimere_importer', 'source_url', self.gf('django.db.models.fields.CharField')(max_length=200, null=True, blank=True), keep_default=False)
+
+ # Deleting field 'Importer.source'
+ db.delete_column('chimere_importer', 'source')
+
+
+ models = {
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'unique': 'True', 'max_length': '50', 'blank': 'True'})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '6'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'filtr': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'multimedia_files': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'marker'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['chimere.MultimediaFile']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'pictures': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'marker'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['chimere.PictureFile']"}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'object_name': 'News'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150', 'null': 'True', 'blank': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'areas': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'to': "orm['chimere.Area']"}),
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ }
+ }
+
+ complete_apps = ['chimere']
diff --git a/chimere/models.py b/chimere/models.py
index c93d271..3556e52 100644
--- a/chimere/models.py
+++ b/chimere/models.py
@@ -204,8 +204,8 @@ class Importer(models.Model):
importer_type = models.CharField(_(u"Importer type"), max_length=4,
choices=IMPORTER_CHOICES)
# URL of a KML file or a XAPI service for OSM
- source_url = models.CharField(_(u"Source URL"), max_length=200,
- blank=True, null=True)
+ source = models.CharField(_(u"Source"), max_length=200,
+ blank=True, null=True)
filtr = models.CharField(_(u"Filter"), max_length=200,
blank=True, null=True)
categories = SelectMultipleField(SubCategory,
@@ -253,6 +253,29 @@ class GeographicItem(models.Model):
class Meta:
abstract = True
+ def get_key(self, key):
+ key_vals = self.import_key.split(';')
+ for k_v in key_vals:
+ if k_v.startswith(key+':'):
+ return k_v.split(':')[1]
+
+ def set_key(self, key, value):
+ new_keys, _set = '', None
+ key_vals = self.import_key.split(';') if self.import_key else []
+ for k_v in key_vals:
+ if ':' not in k_v:
+ continue
+ k, v = k_v.split(':')
+ if k == key:
+ _set = True
+ new_keys += '%s:%s;' % (k, value)
+ else:
+ new_keys += '%s:%s;' % (k, v)
+ if not _set:
+ new_keys += '%s:%s;' % (key, value)
+ self.import_key = new_keys
+ self.save()
+
class Marker(GeographicItem):
'''Marker for a POI
'''
diff --git a/chimere/tasks.py b/chimere/tasks.py
index ba88304..58af162 100644
--- a/chimere/tasks.py
+++ b/chimere/tasks.py
@@ -24,12 +24,33 @@ from django.utils.translation import ugettext_lazy as _
from chimere.models import Importer
-IMPORT_MESSAGES = {'import_pending':[_(u"Import pending")],
+def single_instance_task(timeout):
+ def task_exc(func):
+ def wrapper(*args, **kwargs):
+ lock_id = "celery-single-instance-" + func.__name__
+ acquire_lock = lambda: cache.add(lock_id, "true", timeout)
+ release_lock = lambda: cache.delete(lock_id)
+ if acquire_lock():
+ try:
+ func()
+ finally:
+ release_lock()
+ return wrapper
+ return task_exc
+
+IMPORT_MESSAGES = {
+ 'import_pending':[_(u"Import pending")],
'import_process':[_(u"Import processing")],
'import_done':[_(u"Import successfuly done"),
_(u" %(new)d new item(s), %(updated)d updated item(s)")],
'import_failed':[_(u"Import failed"), "%s"],
- 'import_cancel':[_(u"Import canceled")]
+ 'import_cancel':[_(u"Import canceled")],
+ 'export_pending':[_(u"Export pending")],
+ 'export_process':[_(u"Export processing")],
+ 'export_done':[_(u"Export successfuly done"),
+ _(u" %(updated)d updated item(s)")],
+ 'export_failed':[_(u"Export failed"), "%s"],
+ 'export_cancel':[_(u"Export canceled")]
}
@task()
@@ -55,3 +76,27 @@ def importing(importer_pk):
'updated':updated_item}
importer.save()
return True
+
+@task()
+@single_instance_task(60*10)
+def exporting(importer_pk):
+ try:
+ importer = Importer.objects.get(pk=importer_pk)
+ except ObjectDoesNotExist:
+ # importer doesn't exists anymore: too late!
+ return
+ if importer.state != IMPORT_MESSAGES['export_pending'][0]:
+ # import canceled or done
+ return
+ importer.state = unicode(IMPORT_MESSAGES['export_process'][0])
+ importer.save()
+ updated_item, error = importer.manager.put()
+ if error:
+ importer.state = unicode(IMPORT_MESSAGES['export_failed'][0]) \
+ + u" - " + unicode(IMPORT_MESSAGES['export_failed'][1]) % error
+ importer.save()
+ return
+ importer.state = unicode(IMPORT_MESSAGES['export_done'][0]) + u" - " \
+ + unicode(IMPORT_MESSAGES['export_done'][1]) % {'updated':updated_item}
+ importer.save()
+ return True
diff --git a/chimere/tests.py b/chimere/tests.py
index 7a3960f..7d84394 100644
--- a/chimere/tests.py
+++ b/chimere/tests.py
@@ -65,19 +65,19 @@ class KMLImporterTest(TestCase, ImporterTest):
def setUp(self):
subcategory_1, subcategory_2 = self._baseSetUp()
importer1 = Importer.objects.create(importer_type='KML',
- source_url=test_dir_path+'sample.kml',
- filtr="//kml:Folder/kml:name[text()='Category 1']/../kml:Placemark")
+ source=test_dir_path+'sample.kml',
+ filtr="Category 1")
importer1.categories.add(subcategory_1)
importer2 = Importer.objects.create(importer_type='KML',
- source_url=test_dir_path+'sample.kml',
- filtr="//kml:Folder/kml:name[text()='Subcategory 1']/../kml:Placemark")
+ source=test_dir_path+'sample.kml',
+ filtr="Subcategory 1")
importer2.categories.add(subcategory_1)
importer2.categories.add(subcategory_2)
importer3 = Importer.objects.create(importer_type='KML',
- source_url=test_path+'sample.kml',
- filtr="//kml:Folder/kml:name[text()='Subcategory 3']/../kml:Placemark")
+ source=test_path+'sample.kml',
+ filtr="Subcategory 3")
importer3.categories.add(subcategory_2)
self.marker_importers = [(importer1, 1), (importer2, 2), (importer3, 0)]
@@ -86,7 +86,7 @@ class OSMImporterTest(TestCase, ImporterTest):
def setUp(self):
subcategory_1, subcategory_2 = self._baseSetUp()
importer1 = Importer.objects.create(importer_type='OSM',
- source_url=settings.CHIMERE_XAPI_URL,
+ source='OSM',
filtr="node[amenity=pub]"\
"[bbox=-77.041579,38.885851,-77.007247,38.900881]")
importer1.categories.add(subcategory_1)
diff --git a/chimere/utils.py b/chimere/utils.py
index 62d3786..b2c8ccc 100644
--- a/chimere/utils.py
+++ b/chimere/utils.py
@@ -21,10 +21,14 @@
Utilitaries
"""
-import urllib2
+import urllib2, re
+from external_utils import OsmApi
from lxml import etree
+from chimere import get_version
+from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
+from django.utils.translation import ugettext_lazy as _
class ImportManager:
u"""
@@ -42,11 +46,10 @@ class ImportManager:
class KMLManager(ImportManager):
u"""
KML importer
- The filtr argument has to be defined as a correct Xpath string pointing
- to Placemark nodes.
- A typical XPath string looks like:
- "//kml:Folder/kml:name[text()='Subcategory 1']/../kml:Placemark"
+ The filtr argument has to be defined as the exact name of the folder to be
+ imported
"""
+ XPATH = '//kml:Folder/kml:name[text()="%s"]/../kml:Placemark'
def __init__(self, importer_instance, ns=''):
self.importer_instance = importer_instance
self.ns = ns
@@ -62,11 +65,11 @@ class KMLManager(ImportManager):
from models import Marker
new_item, updated_item, msg = 0, 0, ''
try:
- source = urllib2.urlopen(self.importer_instance.source_url)
+ source = urllib2.urlopen(self.importer_instance.source)
except ValueError:
# assume it is a local file
try:
- source = open(self.importer_instance.source_url)
+ source = open(self.importer_instance.source)
except IOError, msg:
return (new_item, updated_item, msg)
except urllib2.URLError as error:
@@ -75,10 +78,11 @@ class KMLManager(ImportManager):
# try to get default namespace
if not self.ns:
self.ns = tree.getroot().nsmap[None]
- for placemark in tree.xpath(self.importer_instance.filtr,
+ for placemark in tree.xpath(self.XPATH % self.importer_instance.filtr,
namespaces={'kml':self.ns}):
name, point, linestring = None, None, None
pl_id = placemark.attrib.get('id')
+ pl_key = 'kml-%d' % self.importer_instance.pk
ns = '{%s}' % self.ns
for item in placemark:
if item.tag == ns + 'name':
@@ -97,8 +101,8 @@ class KMLManager(ImportManager):
m = None
if pl_id:
dct_import = {
- 'import_key':pl_id,
- 'import_source':self.importer_instance.source_url}
+ 'import_key__icontains':'%s:%s;' % (pl_key, pl_id),
+ 'import_source':self.importer_instance.source}
try:
m = Marker.objects.get(**dct_import)
for k in dct:
@@ -107,16 +111,23 @@ class KMLManager(ImportManager):
updated_item += 1
except ObjectDoesNotExist:
m = None
- dct.update(dct_import)
+ dct.update({
+ 'import_source':self.importer_instance.source})
if not m:
dct['status'] = 'I'
m = Marker.objects.create(**dct)
new_item += 1
+ if pl_id:
+ m.set_key(pl_key, pl_id)
m.categories.clear()
for cat in self.importer_instance.categories.all():
m.categories.add(cat)
return (new_item, updated_item, msg)
+RE_NODE = re.compile('node\[([^\]]*)\]')
+
+# manage deleted item from OSM
+
class OSMManager(ImportManager):
u"""
OSM importer
@@ -124,23 +135,25 @@ class OSMManager(ImportManager):
The filtr argument is XAPI args or empty if it is an OSM file.
"""
- def get(self):
+ def get(self, get_items=None):
u"""
Get data from the source
Return a tuple with:
- - number of new item ;
- - number of item updated ;
+ - new items or number of new items if nb_only = True;
+ - updated items or number of updated items if nb_only = True;
- error detail on error
"""
from models import Marker
- new_item, updated_item, msg = 0, 0, ''
+ new_item, updated_item = 0 , 0
+ items = []
+ msg = ''
try:
- source = urllib2.urlopen(self.importer_instance.source_url+
+ source = urllib2.urlopen(settings.CHIMERE_XAPI_URL+
self.importer_instance.filtr)
except ValueError:
# assume it is a local file
try:
- source = open(self.importer_instance.source_url)
+ source = open(self.importer_instance.source)
except IOError, msg:
return (new_item, updated_item, msg)
except urllib2.URLError as error:
@@ -163,10 +176,11 @@ class OSMManager(ImportManager):
m = None
if node_id:
dct_import = {
- 'import_key':node_id,
- 'import_source':self.importer_instance.source_url}
+ 'import_key__icontains':'OSM:%s;' % (node_id),
+ 'import_source':self.importer_instance.source}
try:
m = Marker.objects.get(**dct_import)
+ items.append(m)
if version and m.import_version == int(version):
# no update since the last import
continue
@@ -176,12 +190,62 @@ class OSMManager(ImportManager):
updated_item += 1
except ObjectDoesNotExist:
m = None
- dct.update(dct_import)
+ dct.update({
+ 'import_source':self.importer_instance.source})
if not m:
dct['status'] = 'I'
m = Marker.objects.create(**dct)
new_item += 1
+ items.append(m)
+ if node_id:
+ m.set_key('OSM', node_id)
m.categories.clear()
for cat in self.importer_instance.categories.all():
m.categories.add(cat)
- return (new_item, updated_item, msg)
+ if not get_items:
+ return (new_item, updated_item, msg)
+ return (items, new_item, updated_item, msg)
+
+ def put(self):
+ # first of all: reimport in order to verify that no changes has been
+ # made since the last import
+ from models import Marker
+ items, new_item, updated_item, msg = self.get(get_items=True)
+ # check if import is possible
+ if msg:
+ return 0, msg
+ if new_item:
+ return 0, _(u"New items imported - validate them before exporting")
+ if Marker.objects.filter(status='I').count():
+ return 0, _(u"There are items from a former import not yet "
+ u"validated - validate them before exporting")
+ # start import
+ api = OsmApi.OsmApi(api=settings.CHIMERE_OSM_API_URL,
+ username=settings.CHIMERE_OSM_USER,
+ password=settings.CHIMERE_OSM_PASSWORD)
+ api.ChangesetCreate({u"comment": u"Import from Chimère %s" % \
+ get_version()})
+ tag = RE_NODE.finddall(self.importer_instance.filtr)
+ if not tag:
+ return 0, _(u"Bad param")
+ tag = tag[0].split('=')
+ default_dct = {'tag':{tag[0]:tag[1]},
+ 'import_source':self.importer_instance.source}
+ for idx, item in Marker.objects.filter(status='A',
+ categories=self.importer_instance.categories.all()):
+ dct = default_dct.update({
+ 'name':item.name,
+ 'lon':item.point.lon,
+ 'lat':item.point.lat})
+ node = None
+ import_key = marker.get_key('OSM')
+ if not import_key:
+ node = OsmApi.NodeCreate(dct)
+ item.set_key('OSM', node['id'])
+ else:
+ dct['id'] = import_key
+ node = OsmApi.NodeUpdate(dct)
+ item.import_version = node['version']
+ item.save()
+ api.ChangesetClose()
+ return idx+1, None
diff --git a/debian/control b/debian/control
index 9fe58d9..b3cd3dc 100644
--- a/debian/control
+++ b/debian/control
@@ -5,5 +5,5 @@ Depends: python-django (>=1.3), python-gdal, python-psycopg2,
libjs-jquery-ui, libjs-jquery-ui-theme-base,
postgresql-9.1, postgresql-9.1-postgis, gettext,
python-simplejson
-Recommends: tinymce, gpsbabel, python-django-celery, rabbitmq-server
+Recommends: tinymce, gpsbabel, python-django-celery, python-kombu
Suggests: libjs-jquery-ui-theme-south-street
diff --git a/example_project/settings.py.example b/example_project/settings.py.example
index dc49768..d9afa6e 100644
--- a/example_project/settings.py.example
+++ b/example_project/settings.py.example
@@ -96,11 +96,12 @@ DATABASES = {
# celery
import djcelery
djcelery.setup_loader()
-BROKER_HOST = "localhost"
-BROKER_PORT = 5672
-BROKER_USER = "guest"
-BROKER_PASSWORD = "guest"
-BROKER_VHOST = "/"
+BROKER_URL = 'django://'
+#BROKER_HOST = "localhost"
+#BROKER_PORT = 5672
+#BROKER_USER = "guest"
+#BROKER_PASSWORD = "guest"
+#BROKER_VHOST = "/"
# Local time zone for this installation. Choices can be found here:
# http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
@@ -191,6 +192,7 @@ INSTALLED_APPS = (
'django.contrib.sites',
'django.contrib.gis',
'django.contrib.staticfiles',
+ 'kombu.transport.django',
'djcelery',
'south',
'chimere',
diff --git a/requirements.txt b/requirements.txt
index 8ca59a9..f976fb9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,3 +6,4 @@ lxml
south==0.7.3
simplejson
django-celery==2.4.2
+kombu