diff --git a/apps/documents/admin.py b/apps/documents/admin.py index e63bfec2af..c1cb7d22e1 100644 --- a/apps/documents/admin.py +++ b/apps/documents/admin.py @@ -2,8 +2,8 @@ from django.contrib import admin from documents.models import MetadataType, DocumentType, Document, \ MetadataSet, MetadataSetItem, DocumentMetadata, \ - DocumentTypeFilename, MetadataIndex, DocumentPage, MetadataGroup, \ - MetadataGroupItem, DocumentPageTransformation, RecentDocument + DocumentTypeFilename, MetadataIndex, DocumentPage, DocumentGroup, \ + DocumentGroupItem, DocumentPageTransformation, RecentDocument from filesystem_serving.admin import DocumentMetadataIndexInline @@ -65,15 +65,15 @@ class DocumentAdmin(admin.ModelAdmin): list_display = ('uuid', 'file_filename', 'file_extension') -class MetadataGroupItemInline(admin.StackedInline): - model = MetadataGroupItem +class DocumentGroupItemInline(admin.StackedInline): + model = DocumentGroupItem extra = 1 classes = ('collapse-open',) allow_add = True -class MetadataGroupAdmin(admin.ModelAdmin): - inlines = [MetadataGroupItemInline] +class DocumentGroupAdmin(admin.ModelAdmin): + inlines = [DocumentGroupItemInline] filter_horizontal = ['document_type'] @@ -87,7 +87,6 @@ class RecentDocumentAdmin(admin.ModelAdmin): class MetadataSetAdmin(admin.ModelAdmin): inlines = [MetadataSetItemInline] - #filter_horizontal = ['document_type'] admin.site.register(MetadataType, MetadataTypeAdmin) diff --git a/apps/documents/classes.py b/apps/documents/classes.py new file mode 100644 index 0000000000..b8476a744f --- /dev/null +++ b/apps/documents/classes.py @@ -0,0 +1,12 @@ +from django.utils.translation import ugettext_lazy as _ + + +class MetadataObject(object): + def __init__(self, dictionary): + self.dictionary = dictionary + + def __getattr__(self, name): + if name in self.dictionary: + return self.dictionary.get(name) + else: + raise AttributeError(_(u'\'metadata\' object has no attribute \'%s\'') % name) diff --git a/apps/documents/metadata.py b/apps/documents/metadata.py index 4c891e2ede..9b5aaf5b1a 100644 --- a/apps/documents/metadata.py +++ b/apps/documents/metadata.py @@ -1,17 +1,16 @@ -'''Metadata handling commonalities -''' +"""Metadata handling commonalities""" from urllib import unquote_plus from django.shortcuts import get_object_or_404 from django.core.exceptions import ObjectDoesNotExist +from django.utils.translation import ugettext_lazy as _ from documents.models import DocumentMetadata, MetadataType def decode_metadata_from_url(url_dict): - '''Parses a URL query string to a list of metadata - ''' + """Parse a URL query string to a list of metadata""" metadata_dict = { 'id': {}, 'value': {} @@ -35,8 +34,9 @@ def decode_metadata_from_url(url_dict): def save_metadata_list(metadata_list, document): - '''Takes a list of metadata values and associates a document to it - ''' + """ + Take a list of metadata values and associate a document to it + """ for item in metadata_list: save_metadata(item, document) @@ -57,9 +57,8 @@ def save_metadata_list(metadata_list, document): def save_metadata(metadata_dict, document): - '''save metadata_dict - ''' - #Use matched metadata now to create document metadata + """save metadata_dict""" + # Use matched metadata now to create document metadata document_metadata, created = DocumentMetadata.objects.get_or_create( document=document, metadata_type=get_object_or_404( @@ -67,24 +66,24 @@ def save_metadata(metadata_dict, document): pk=metadata_dict['id'] ), ) - #Handle 'plus sign as space' in the url + # Handle 'plus sign as space' in the url - #unquote_plus handles utf-8?!? - #http://stackoverflow.com/questions/4382875/handling-iri-in-django + # unquote_plus handles utf-8?!? + # http://stackoverflow.com/questions/4382875/handling-iri-in-django #.decode('utf-8') document_metadata.value = unquote_plus(metadata_dict['value']) document_metadata.save() def metadata_repr(metadata_list): - '''Return a printable representation of a metadata list - ''' - return ', '.join(metadata_repr_as_list(metadata_list)) + """Return a printable representation of a metadata list""" + return u', '.join(metadata_repr_as_list(metadata_list)) def metadata_repr_as_list(metadata_list): - '''Turn a list of metadata into a list of printable representations - ''' + """ + Turn a list of metadata into a list of printable representations + """ output = [] for metadata_dict in metadata_list: try: diff --git a/apps/documents/models.py b/apps/documents/models.py index 355d4f70e9..8f023ff5f7 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -25,6 +25,7 @@ from documents.conf.settings import STORAGE_BACKEND from documents.conf.settings import AVAILABLE_TRANSFORMATIONS from documents.conf.settings import DEFAULT_TRANSFORMATIONS from documents.conf.settings import RECENT_COUNT +from documents.classes import MetadataObject def get_filename_from_uuid(instance, filename): @@ -352,8 +353,11 @@ class MetadataGroupManager(models.Manager): metadata_groups = {} metadata_dict = {} for document_metadata in document.documentmetadata_set.all(): - metadata_dict['metadata_%s' % document_metadata.metadata_type.name] = document_metadata.value - + metadata_dict[document_metadata.metadata_type.name] = document_metadata.value + eval_dict = {} + eval_dict['document'] = document + eval_dict['metadata'] = MetadataObject(metadata_dict) + if group_obj: groups_qs = MetadataGroup.objects.filter((Q(document_type=document.document_type) | Q(document_type=None)) & Q(enabled=True) & Q(pk=group_obj.pk)) else: @@ -363,7 +367,7 @@ class MetadataGroupManager(models.Manager): total_query = Q() for item in group.metadatagroupitem_set.filter(enabled=True): try: - value_query = Q(**{'value__%s' % item.operator: eval(item.expression, metadata_dict)}) + value_query = Q(**{'value__%s' % item.operator: eval(item.expression, eval_dict)}) if item.negated: query = (Q(metadata_type__id=item.metadata_type_id) & ~value_query) else: @@ -390,10 +394,10 @@ class MetadataGroupManager(models.Manager): return metadata_groups, errors -class MetadataGroup(models.Model): +class DocumentGroup(models.Model): document_type = models.ManyToManyField(DocumentType, null=True, blank=True, verbose_name=_(u'document type'), help_text=_(u'If left blank, all document types will be matched.')) - name = models.CharField(max_length=32, verbose_name=_(u'name')) + #name = models.CharField(max_length=32, verbose_name=_(u'name')) label = models.CharField(max_length=32, verbose_name=_(u'label')) enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) @@ -433,14 +437,17 @@ OPERATOR_CHOICES = ( (u'iregex', _(u'is in regular expression (case insensitive)')), ) +#LOCAL_SOURCE_CHOICES = ( +# (u' -class MetadataGroupItem(models.Model): - metadata_group = models.ForeignKey(MetadataGroup, verbose_name=_(u'metadata group')) +class DocumentGroupItem(models.Model): + metadata_group = models.ForeignKey(DocumentGroup, verbose_name=_(u'metadata group')) inclusion = models.CharField(default=INCLUSION_AND, max_length=16, choices=INCLUSION_CHOICES, help_text=_(u'The inclusion is ignored for the first item.')) - metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type'), help_text=_(u'This represents the metadata of all other documents.')) + foreign_metadata_type = models.ForeignKey(MetadataType, related_name='metadata_type_foreign', verbose_name=_(u'foreign metadata'), help_text=_(u'This represents the metadata of all other documents.')) operator = models.CharField(max_length=16, choices=OPERATOR_CHOICES) - expression = models.CharField(max_length=128, - verbose_name=_(u'expression'), help_text=_(u'This expression will be evaluated against the current selected document. The document metadata is available as variables of the same name but with the "metadata_" prefix added their name.')) + + local_metadata_type = models.ForeignKey(MetadataType, related_name='metadata_type_local', verbose_name=_(u'local metadata'), help_text=_(u'This represents the metadata of the current document.')) + expression = models.TextField(verbose_name=_(u'expression'), help_text=_(u'This expression will be evaluated against the current selected document. The document metadata is available as variables `metadata` and document properties under the variable `document`.')) negated = models.BooleanField(default=False, verbose_name=_(u'negated'), help_text=_(u'Inverts the logic of the operator.')) enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) diff --git a/apps/filesystem_serving/api.py b/apps/filesystem_serving/api.py index eda6b843bd..c003f3101c 100644 --- a/apps/filesystem_serving/api.py +++ b/apps/filesystem_serving/api.py @@ -5,6 +5,7 @@ from django.template.defaultfilters import slugify from django.utils.translation import ugettext_lazy as _ from documents.conf.settings import AVAILABLE_INDEXING_FUNCTIONS +from documents.classes import MetadataObject from filesystem_serving.conf.settings import FILESERVING_ENABLE from filesystem_serving.conf.settings import FILESERVING_PATH @@ -25,13 +26,15 @@ def document_create_fs_links(document): if FILESERVING_ENABLE: if not document.exists(): raise Exception(_(u'Not creating metadata indexing, document not found in document storage')) - metadata_dict = {'document': document} - metadata_dict.update(dict([(metadata.metadata_type.name, SLUGIFY_FUNCTION(metadata.value)) for metadata in document.documentmetadata_set.all() if metadata.value])) - + eval_dict = {} + eval_dict['document'] = document + metadata_dict = dict([(metadata.metadata_type.name, SLUGIFY_FUNCTION(metadata.value)) for metadata in document.documentmetadata_set.all() if metadata.value]) + eval_dict['metadata'] = MetadataObject(metadata_dict) + for metadata_index in document.document_type.metadataindex_set.all(): if metadata_index.enabled: try: - fabricated_directory = eval(metadata_index.expression, metadata_dict, AVAILABLE_INDEXING_FUNCTIONS) + fabricated_directory = eval(metadata_index.expression, eval_dict, AVAILABLE_INDEXING_FUNCTIONS) target_directory = os.path.join(FILESERVING_PATH, fabricated_directory) try: os.makedirs(target_directory) @@ -48,7 +51,7 @@ def document_create_fs_links(document): #This should be a warning not an error #pass except Exception, exc: - raise Exception(_(u'Unable to create metadata indexing directory: %s') % exc) + warnings.append(_(u'Unable to create metadata indexing directory: %s') % exc) return warnings