diff options
-rw-r--r-- | example_project/settings.py | 3 | ||||
-rw-r--r-- | ishtar_common/admin.py | 4 | ||||
-rw-r--r-- | ishtar_common/migrations/0010_auto__del_wizardstep__del_wizard__add_globalvar__chg_field_person_atta.py | 236 | ||||
-rw-r--r-- | ishtar_common/models.py | 52 | ||||
-rw-r--r-- | ishtar_common/ooo_replace.py | 38 | ||||
-rw-r--r-- | ishtar_common/tests.py | 36 | ||||
-rw-r--r-- | ishtar_common/tests/test-file.odt | bin | 0 -> 9571 bytes | |||
-rw-r--r-- | requirements.txt | 1 |
8 files changed, 347 insertions, 23 deletions
diff --git a/example_project/settings.py b/example_project/settings.py index d276ef6bf..27b040874 100644 --- a/example_project/settings.py +++ b/example_project/settings.py @@ -121,7 +121,7 @@ INSTALLED_APPS = [ 'django.contrib.formtools', 'south', 'registration', - #'geodjangofla', + 'geodjangofla', 'ishtar_common', 'archaeological_operations', # mandatory app to run ishtar #'django_extensions', @@ -174,6 +174,7 @@ LOGGING = {'version': 1, # Ishtar custom SRID = 27572 ENCODING = 'windows-1252' +ALT_ENCODING = 'ISO-8859-15' APP_NAME = "SRA - Pays de la Loire" SURFACE_UNIT = 'square-metre' SURFACE_UNIT_LABEL = u'm²' diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py index cfbed2f66..9d164a626 100644 --- a/ishtar_common/admin.py +++ b/ishtar_common/admin.py @@ -81,6 +81,10 @@ class PersonTypeAdmin(admin.ModelAdmin): admin.site.register(models.PersonType, PersonTypeAdmin) +class GlobalVarAdmin(admin.ModelAdmin): + list_display = ['slug', 'description', 'value'] +admin.site.register(models.GlobalVar, GlobalVarAdmin) + class GeneralTypeAdmin(admin.ModelAdmin): list_display = ['label', 'txt_idx', 'available'] diff --git a/ishtar_common/migrations/0010_auto__del_wizardstep__del_wizard__add_globalvar__chg_field_person_atta.py b/ishtar_common/migrations/0010_auto__del_wizardstep__del_wizard__add_globalvar__chg_field_person_atta.py new file mode 100644 index 000000000..4bba74da9 --- /dev/null +++ b/ishtar_common/migrations/0010_auto__del_wizardstep__del_wizard__add_globalvar__chg_field_person_atta.py @@ -0,0 +1,236 @@ +# -*- coding: 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 model 'WizardStep' + db.delete_table('ishtar_common_wizardstep') + + # Deleting model 'Wizard' + db.delete_table('ishtar_common_wizard') + + # Adding model 'GlobalVar' + db.create_table('ishtar_common_globalvar', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=50)), + ('description', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), + ('value', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), + )) + db.send_create_signal('ishtar_common', ['GlobalVar']) + + + # Changing field 'Person.attached_to' + db.alter_column('ishtar_common_person', 'attached_to_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, on_delete=models.SET_NULL, to=orm['ishtar_common.Organization'])) + + def backwards(self, orm): + # Adding model 'WizardStep' + db.create_table('ishtar_common_wizardstep', ( + ('url_name', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=128)), + ('wizard', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['ishtar_common.Wizard'])), + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('order', self.gf('django.db.models.fields.IntegerField')()), + )) + db.send_create_signal('ishtar_common', ['WizardStep']) + + # Adding model 'Wizard' + db.create_table('ishtar_common_wizard', ( + ('url_name', self.gf('django.db.models.fields.CharField')(max_length=128, unique=True)), + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + )) + db.send_create_signal('ishtar_common', ['Wizard']) + + # Deleting model 'GlobalVar' + db.delete_table('ishtar_common_globalvar') + + + # Changing field 'Person.attached_to' + db.alter_column('ishtar_common_person', 'attached_to_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, to=orm['ishtar_common.Organization'])) + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'ishtar_common.arrondissement': { + 'Meta': {'object_name': 'Arrondissement'}, + 'department': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Department']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '30'}) + }, + 'ishtar_common.author': { + 'Meta': {'object_name': 'Author'}, + 'author_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.AuthorType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'person': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'author'", 'to': "orm['ishtar_common.Person']"}) + }, + 'ishtar_common.authortype': { + 'Meta': {'object_name': 'AuthorType'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'ishtar_common.canton': { + 'Meta': {'object_name': 'Canton'}, + 'arrondissement': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Arrondissement']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '30'}) + }, + 'ishtar_common.department': { + 'Meta': {'ordering': "['number']", 'object_name': 'Department'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '30'}), + 'number': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '3'}) + }, + 'ishtar_common.documenttemplate': { + 'Meta': {'ordering': "['associated_object_name']", 'object_name': 'DocumentTemplate'}, + 'associated_object_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'template': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}) + }, + 'ishtar_common.globalvar': { + 'Meta': {'ordering': "['slug']", 'object_name': 'GlobalVar'}, + 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'}), + 'value': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}) + }, + 'ishtar_common.historicalorganization': { + 'Meta': {'ordering': "('-history_date', '-history_id')", 'object_name': 'HistoricalOrganization'}, + 'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'history_creator_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'history_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'history_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'history_modifier_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'history_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'history_user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), + 'id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}), + 'mobile_phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '300'}), + 'organization_type_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), + 'town': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}) + }, + 'ishtar_common.ishtaruser': { + 'Meta': {'object_name': 'IshtarUser', '_ormbases': ['auth.User']}, + 'person': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ishtaruser'", 'unique': 'True', 'to': "orm['ishtar_common.Person']"}), + 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}) + }, + 'ishtar_common.organization': { + 'Meta': {'object_name': 'Organization'}, + 'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['auth.User']"}), + 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mobile_phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '300'}), + 'organization_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.OrganizationType']"}), + 'phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), + 'town': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}) + }, + 'ishtar_common.organizationtype': { + 'Meta': {'ordering': "('label',)", 'object_name': 'OrganizationType'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'ishtar_common.person': { + 'Meta': {'object_name': 'Person'}, + 'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'attached_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'members'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['ishtar_common.Organization']"}), + 'country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), + 'history_creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['auth.User']"}), + 'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mobile_phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '30'}), + 'person_types': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['ishtar_common.PersonType']", 'symmetrical': 'False'}), + 'phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), + 'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), + 'surname': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '2'}), + 'town': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}) + }, + 'ishtar_common.persontype': { + 'Meta': {'ordering': "('label',)", 'object_name': 'PersonType'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.Group']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'ishtar_common.sourcetype': { + 'Meta': {'object_name': 'SourceType'}, + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'ishtar_common.town': { + 'Meta': {'ordering': "['numero_insee']", 'object_name': 'Town'}, + 'canton': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Canton']", 'null': 'True', 'blank': 'True'}), + 'center': ('django.contrib.gis.db.models.fields.PointField', [], {'srid': '27572', 'null': 'True', 'blank': 'True'}), + 'departement': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Department']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'numero_insee': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '6'}), + 'surface': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + } + } + + complete_apps = ['ishtar_common'] diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 460612e17..6c4ec2e49 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -28,6 +28,7 @@ import tempfile import copy from django.conf import settings +from django.core.cache import cache from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.files.uploadedfile import SimpleUploadedFile from django.core.validators import validate_slug @@ -45,7 +46,8 @@ from django.contrib import admin from simple_history.models import HistoricalRecords as BaseHistoricalRecords -from ooo_replace import ooo_replace +from ishtar_common.ooo_replace import ooo_replace +from ishtar_common.utils import get_cache def post_save_user(sender, **kwargs): user = kwargs['instance'] @@ -85,6 +87,8 @@ class ValueGetter(object): values['VALUES'] = u'\n'.join( [u"%s: %s" % (k, v) for k, v in sorted(value_list, key=lambda x:x[0])]) + for global_var in GlobalVar.objects.all(): + values[global_var.slug] = global_var.value or "" return values @classmethod @@ -525,7 +529,6 @@ class BaseHistorizedItem(models.Model): items.append('00000000') return u"-".join([unicode(item) for item in items]) - class ShortMenuItem(object): def get_short_menu_class(self): return '' @@ -539,26 +542,39 @@ class LightHistorizedItem(BaseHistorizedItem): super(LightHistorizedItem, self).save(*args, **kwargs) return True -class Wizard(models.Model): - url_name = models.CharField(_(u"URL name"), max_length=128, unique=True) +class GlobalVar(models.Model): + slug = models.SlugField(_(u"Variable name"), unique=True) + description = models.TextField(_(u"Description of the variable"), + null=True, blank=True) + value = models.TextField(_(u"Value"), null=True, blank=True) class Meta: - verbose_name = _(u"Wizard") - ordering = ['url_name'] + verbose_name = _(u"Global variable") + verbose_name_plural = _(u"Global variables") + ordering = ['slug'] def __unicode__(self): - return unicode(self.url_name) - -class WizardStep(models.Model): - order = models.IntegerField(_(u"Order")) - wizard = models.ForeignKey(Wizard, verbose_name=_(u"Wizard")) - url_name = models.CharField(_(u"URL name"), max_length=128) - name = models.CharField(_(u"Label"), max_length=128) - class Meta: - verbose_name = _(u"Wizard step") - ordering = ['wizard', 'order'] + return unicode(self.slug) - def __unicode__(self): - return u"%s » %s" % (unicode(self.wizard), unicode(self.name)) + @classmethod + def get_cache(cls, slug): + cache_key, value = get_cache(cls, slug) + if value: + return value + try: + obj = cls.objects.get(slug=slug) + cache.set(cache_key, obj.value, settings.CACHE_TIMEOUT) + return obj.value + except cls.DoesNotExist: + return None + +def cached_globalvar_changed(sender, **kwargs): + if not kwargs['instance']: + return + var = kwargs['instance'] + cache_key, value = get_cache(GlobalVar, var.slug) + cache.set(cache_key, var.value, settings.CACHE_TIMEOUT) + +post_save.connect(cached_globalvar_changed, sender=GlobalVar) class UserDashboard: def __init__(self): diff --git a/ishtar_common/ooo_replace.py b/ishtar_common/ooo_replace.py index 346ef75a4..2fb01724b 100644 --- a/ishtar_common/ooo_replace.py +++ b/ishtar_common/ooo_replace.py @@ -17,7 +17,7 @@ # See the file COPYING for details. -import locale +import locale, re from zipfile import ZipFile, ZIP_DEFLATED from cStringIO import StringIO from xml.etree.cElementTree import ElementTree, fromstring @@ -78,9 +78,34 @@ def _format_value(value, default_value): value = unicode(value) if value else default_value return value +VAR_EXPR = u"###VAR %s###" +RE_VAR = re.compile(u"###VAR %s###" % u"([-a-zA-Z0-9_]+)") +IF_EXPR = u"###IF %s###(.*)###ENDIF###" +RE_IF = re.compile(IF_EXPR % u"([-a-zA-Z0-9_]+)") + +def _ishtar_parsing(context, value): + """ + ###VAR nom_var### for displaying a variable name + ###IF nom_var### ###ENDIF### for conditionnal display + Be carreful nested condition are not yet managed! + """ + for key, val in RE_IF.findall(value): + v = "" + if key in context and context[key]: + v = _ishtar_parsing(context, val) + value = re.sub(IF_EXPR % key, v, value) + for key in RE_VAR.findall(value): + v = "" + if key in context and context[key]: + v = unicode(context[key]) + value = re.sub(VAR_EXPR % key, v, value) + return value + def ooo_replace(infile, outfile, context, default_value=''): inzip = ZipFile(infile, 'r', ZIP_DEFLATED) outzip = ZipFile(outfile, 'w', ZIP_DEFLATED) + + # regular ooo parsing content = ElementTree(fromstring(inzip.read('content.xml'))) missing_keys = set() for xp in ('variable-set', 'variable-get'): @@ -102,11 +127,16 @@ def ooo_replace(infile, outfile, context, default_value=''): if value.strip() in context: value = context[value.strip()] p.text = value + + # raw content parsing + str_io = StringIO() + content.write(str_io) + value = str_io.getvalue() + value = _ishtar_parsing(context, value).encode('utf-8') + for f in inzip.infolist(): if f.filename == 'content.xml': - s = StringIO() - content.write(s) - outzip.writestr('content.xml', s.getvalue()) + outzip.writestr('content.xml', value) else: outzip.writestr(f, inzip.read(f.filename)) inzip.close() diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py new file mode 100644 index 000000000..cdcb42103 --- /dev/null +++ b/ishtar_common/tests.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2014 É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 tempfile +from zipfile import ZipFile, ZIP_DEFLATED + +from django.test import TestCase + +from ishtar_common import models, ooo_replace +from ishtar_common.ooo_replace import ooo_replace + +class OOOGenerationTest(TestCase): + def testGeneration(self): + context = {'test-var':u"Testé", 'test-var2':u""} + tmp = tempfile.TemporaryFile() + ooo_replace("../ishtar_common/tests/test-file.odt", tmp, context) + inzip = ZipFile(tmp, 'r', ZIP_DEFLATED) + value = inzip.read('content.xml') + self.assertTrue("Testé" in value) + self.assertTrue("testé 2" not in value) diff --git a/ishtar_common/tests/test-file.odt b/ishtar_common/tests/test-file.odt Binary files differnew file mode 100644 index 000000000..2e73fe0ee --- /dev/null +++ b/ishtar_common/tests/test-file.odt diff --git a/requirements.txt b/requirements.txt index 478800dc5..f10f8cdb6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,6 +8,7 @@ pisa==3.0.33 reportlab==2.5 dbf python-memcached +unicodecsv # for xhtml2odt pytidylib |