diff --git a/apps/documents/admin.py b/apps/documents/admin.py index 1f8b6248b8..99e07d83bc 100644 --- a/apps/documents/admin.py +++ b/apps/documents/admin.py @@ -1,13 +1,20 @@ from django.contrib import admin from models import MetadataType, DocumentType, Document, \ - DocumentTypeMetadataType, DocumentMetadata, DocumentTypeFilename#, \ -# DocumentFile + DocumentTypeMetadataType, DocumentMetadata, DocumentTypeFilename, \ + MetadataIndex, DocumentMetadataIndex class MetadataTypeAdmin(admin.ModelAdmin): - list_display = ('name', 'default', 'lookup') - + list_display = ('name', 'title', 'default', 'lookup') + + +class MetadataIndexInline(admin.StackedInline): + model = MetadataIndex + extra = 1 + classes = ('collapse-open',) + allow_add = True + class DocumentTypeMetadataTypeInline(admin.StackedInline): model = DocumentTypeMetadataType @@ -24,7 +31,7 @@ class DocumentTypeFilenameInline(admin.StackedInline): class DocumentTypeAdmin(admin.ModelAdmin): - inlines = [DocumentTypeMetadataTypeInline, DocumentTypeFilenameInline] + inlines = [DocumentTypeFilenameInline, DocumentTypeMetadataTypeInline, MetadataIndexInline] class DocumentMetadataInline(admin.StackedInline): @@ -34,17 +41,17 @@ class DocumentMetadataInline(admin.StackedInline): allow_add = True -#class DocumentFileInline(admin.StackedInline): -# model = DocumentFile -# extra = 1 -# classes = ('collapse-open',) -# allow_add = True +class DocumentMetadataIndexInline(admin.StackedInline): + model = DocumentMetadataIndex + extra = 1 + classes = ('collapse-open',) + allow_add = True + readonly_fields = ('metadata_indexing', 'filename') class DocumentAdmin(admin.ModelAdmin): - #inlines = [DocumentFileInline]#, DocumentMetadataInline,] - inlines = [DocumentMetadataInline] - list_display = ('uuid',) + inlines = [DocumentMetadataInline, DocumentMetadataIndexInline] + list_display = ('uuid', 'file_filename', 'file_extension') diff --git a/apps/documents/forms.py b/apps/documents/forms.py index e3c2529db5..561d07c481 100644 --- a/apps/documents/forms.py +++ b/apps/documents/forms.py @@ -84,7 +84,7 @@ class MetadataForm(forms.Form): self.document_type = kwargs['initial'].pop('document_type', None) self.metadata_options = kwargs['initial'].pop('metadata_options', None) - self.fields['name'].initial=self.metadata_type.name + self.fields['name'].initial=self.metadata_type.title if self.metadata_type.title else self.metadata_type.name self.fields['id'].initial=self.metadata_type.id if self.metadata_type.default: try: diff --git a/apps/documents/models.py b/apps/documents/models.py index 14d4c29f65..40d17bd7c3 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -2,6 +2,7 @@ import errno import os import mimetypes from datetime import datetime +import sys from django.conf import settings from django.db import models @@ -42,12 +43,33 @@ def populate_file_extension_and_mimetype(instance, filename): instance.file_extension = extension[1:] +def custom_eval(format, dictionary): + try: + #Do a normal substitution + return format % dictionary + except: + #Use exception to catch unknown elements + (exc_type, exc_info, tb) = sys.exc_info() + key = unicode(exc_info)[2:-1] + try: + #Resolve unknown element + dictionary[key] = eval(key, dictionary) + #Call itself again, but with an additional resolved element in + #the dictionary + return custom_eval(format, dictionary) + except Exception, e: + #Can't resolve elemtent, give up + (exc_type, exc_info, tb) = sys.exc_info() + print exc_info + raise Exception(e) + + class DocumentType(models.Model): name = models.CharField(max_length=32, verbose_name=_(u'name')) def __unicode__(self): return self.name - + class Document(models.Model): """ Minimum fields for a document entry. @@ -57,6 +79,7 @@ class Document(models.Model): file = models.FileField(upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'file')) uuid = models.CharField(max_length=48, default=UUID_FUNCTION(), blank=True, editable=False) file_mimetype = models.CharField(max_length=64, default='', editable=False) + #FAT filename can be up to 255 using LFN file_filename = models.CharField(max_length=64, default='', editable=False) file_extension = models.CharField(max_length=16, default='', editable=False) date_added = models.DateTimeField(verbose_name=_(u'added'), auto_now_add=True) @@ -89,16 +112,31 @@ class Document(models.Model): super(Document, self).save(*args, **kwargs) def delete(self, *args, **kwargs): + #TODO: Might not execute when done in bulk from a queryset + #topics/db/queries.html#topics-db-queries-delete self.delete_fs_links() super(Document, self).delete(*args, **kwargs) def calculate_fs_links(self): - targets = [] - for metadata in self.documentmetadata_set.all(): - if metadata.metadata_type.documenttypemetadatatype_set.all()[0].create_directory_link: - target_directory = os.path.join(FILESYSTEM_FILESERVING_PATH, slugify(metadata.metadata_type.name), slugify(metadata.value)) - targets.append(os.path.join(target_directory, os.extsep.join([slugify(self.file_filename), slugify(self.file_extension)]))) - return targets + metadata_dict = {'document':self} + metadata_dict.update(dict([(metadata.metadata_type.name, slugify(metadata.value)) for metadata in self.documentmetadata_set.all()])) + + for metadata_index in self.document_type.metadataindex_set.all(): + if metadata_index.enabled: + #print eval(metadata_index.expression, metadata_dict) + fabricated_directory = custom_eval(metadata_index.expression, metadata_dict) + target_directory = os.path.join(FILESYSTEM_FILESERVING_PATH, fabricated_directory) + #print target_directory + + + final_path = os.path.join(target_directory, os.extsep.join([slugify(self.file_filename), slugify(self.file_extension)])) + print final_path + #targets = [] + #for metadata in self.documentmetadata_set.all(): + # if metadata.metadata_type.documenttypemetadatatype_set.all()[0].create_directory_link: + # target_directory = os.path.join(FILESYSTEM_FILESERVING_PATH, slugify(metadata.metadata_type.name), slugify(metadata.value)) + # targets.append(os.path.join(target_directory, os.extsep.join([slugify(self.file_filename), slugify(self.file_extension)]))) + #return targets def create_fs_links(self): if FILESYSTEM_FILESERVING_ENABLE: @@ -128,22 +166,25 @@ class Document(models.Model): pass else: raise OSError(ugettext(u'Unable to delete metadata indexing symbolic link: %s') % exc) - + + available_functions_string = (_(u' Available functions: %s') % ','.join(['%s()' % name for name, function in AVAILABLE_FUNCTIONS.items()])) if AVAILABLE_FUNCTIONS else '' available_models_string = (_(u' Available models: %s') % ','.join([name for name, model in AVAILABLE_MODELS.items()])) if AVAILABLE_MODELS else '' class MetadataType(models.Model): name = models.CharField(max_length=48, verbose_name=_(u'name')) -# title = models.CharField(max_length=48, verbose_name=_(u'title'), blank=True, null=True) + title = models.CharField(max_length=48, verbose_name=_(u'title'), blank=True, null=True) default = models.CharField(max_length=128, blank=True, null=True, - verbose_name=_(u'default'), help_text=_(u'Enter a string to be evaluated.%s') % available_functions_string) + verbose_name=_(u'default'), + help_text=_(u'Enter a string to be evaluated.%s') % available_functions_string) lookup = models.CharField(max_length=128, blank=True, null=True, - verbose_name=_(u'lookup'), help_text=_(u'Enter a string to be evaluated. Example: [user.get_full_name() for user in User.objects.all()].%s') % available_models_string) - #datatype = models. + verbose_name=_(u'lookup'), + help_text=_(u'Enter a string to be evaluated. Example: [user.get_full_name() for user in User.objects.all()].%s') % available_models_string) + #TODO: datatype? def __unicode__(self): -# return self.title if self.title else self.name + #return '%s - %s' % (self.name, self.title if self.title else self.name) return self.name class Meta: @@ -151,25 +192,12 @@ class MetadataType(models.Model): verbose_name_plural = _(u'metadata types') -#class MetadataIndexing(models.Model): -# metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type')) -# indexing_string = models.CharField( -# -# -# def __unicode__(self): -# return unicode(self.metadata_type) -# -# class Meta: -# verbose_name = _(u'metadata type') -# verbose_name_plural = _(u'metadata types') - - class DocumentTypeMetadataType(models.Model): document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type')) metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type')) - create_directory_link = models.BooleanField(verbose_name=_(u'create directory link')) - #override default - #required? -bool + #create_directory_link = models.BooleanField(verbose_name=_(u'create directory link')) + #TODO: override default for this document type + #TODO: required? -bool def __unicode__(self): return unicode(self.metadata_type) @@ -179,6 +207,34 @@ class DocumentTypeMetadataType(models.Model): verbose_name_plural = _(u'document type metadata type connectors') +class MetadataIndex(models.Model): + document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type')) + expression = models.CharField(max_length=128, + verbose_name=_(u'indexing expression'), + help_text=_(u'Enter a python string expression to be evaluated. The slash caracter "/" acts as a directory delimiter.')) + enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) + + def __unicode__(self): + return unicode(self.expression) + + class Meta: + verbose_name = _(u'metadata index') + verbose_name_plural = _(u'metadata indexes') + + +class DocumentMetadataIndex(models.Model): + document = models.ForeignKey(Document, verbose_name=_(u'document')) + metadata_indexing = models.ForeignKey(MetadataIndex, verbose_name=_(u'metadata indexing')) + filename = models.CharField(max_length=128) + + def __unicode__(self): + return unicode(self.filename) + + class Meta: + verbose_name = _(u'document metadata index') + verbose_name_plural = _(u'document metadata indexes') + + class DocumentMetadata(models.Model): document = models.ForeignKey(Document, verbose_name=_(u'document')) metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type')) diff --git a/apps/documents/views.py b/apps/documents/views.py index a2bb9430f7..9d84b5804b 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -178,6 +178,8 @@ def upload_document_with_type(request, document_type_id, multiple=True): def document_view(request, document_id): document = get_object_or_404(Document, pk=document_id) + ##############TEST############ + document.calculate_fs_links() form = DocumentForm_view(instance=document, extra_fields=[ {'label':_(u'Filename'), 'field':'file_filename'}, {'label':_(u'File extension'), 'field':'file_extension'},