Merge branch 'development' into feature/document_states
This commit is contained in:
@@ -17,16 +17,26 @@
|
||||
{% endif %}
|
||||
|
||||
{% if form_display_mode_table %}
|
||||
<div class="flash">
|
||||
{% for field in form.visible_fields %}
|
||||
{% for error in field.errors %}
|
||||
<div class="message error">
|
||||
<p>{{ error }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% for field in form.hidden_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<tr class="{% cycle 'odd' 'even2' %}">
|
||||
{% for field in form.visible_fields %}
|
||||
<td title="{% if field.errors %}{% for error in field.errors %}{{ error }}{% if not forloop.last %} | {% endif %}{% endfor %}{% else %}{{ field.help_text }}{% endif %}">
|
||||
{% if field.errors %}<div class="flash"><div class="error">{% endif %}
|
||||
<td title="{% if field.errors %}{% for error in field.errors %}{{ error }}{% if not forloop.last %} | {% endif %}{% endfor %}{% else %}{{ field.help_text }}{% endif %}">
|
||||
{% if field.errors %}<div class="error">{% endif %}
|
||||
{{ field }}
|
||||
{% if field.errors %}</div></div>{% endif %}
|
||||
</td>
|
||||
{% if field.errors %}</div>{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% else %}
|
||||
|
||||
@@ -6,7 +6,7 @@ from .models import MetadataType
|
||||
|
||||
|
||||
class MetadataTypeAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'title', 'default', 'lookup')
|
||||
list_display = ('name', 'title', 'default', 'lookup', 'validation')
|
||||
|
||||
|
||||
admin.site.register(MetadataType, MetadataTypeAdmin)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.forms.formsets import formset_factory
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
@@ -11,15 +12,42 @@ from .settings import AVAILABLE_FUNCTIONS, AVAILABLE_MODELS, AVAILABLE_VALIDATOR
|
||||
class MetadataForm(forms.Form):
|
||||
|
||||
def clean_value(self):
|
||||
value = self.cleaned_data['value']
|
||||
metadata_id = self.cleaned_data['id']
|
||||
metadata_type = MetadataType.objects.get(pk=metadata_id)
|
||||
if metadata_type.lookup and metadata_type.lookup in AVAILABLE_VALIDATORS:
|
||||
val_func = AVAILABLE_VALIDATORS[metadata_type.lookup]
|
||||
new_value = val_func(value)
|
||||
if new_value:
|
||||
value = new_value
|
||||
return value
|
||||
metadata_type = MetadataType.objects.get(pk=self.cleaned_data['id'])
|
||||
|
||||
try:
|
||||
validation_function = AVAILABLE_VALIDATORS[metadata_type.validation]
|
||||
except KeyError:
|
||||
# User entered a validation function name, but was not found
|
||||
# Return value entered as is
|
||||
return self.cleaned_data['value']
|
||||
else:
|
||||
try:
|
||||
# If it is a parsing function we should get a value
|
||||
# If it is a validation function we get nothing on success
|
||||
result = validation_function(self.cleaned_data['value'])
|
||||
except Exception as exception:
|
||||
# If it is a validation function and an exception is raise
|
||||
# we wrap that into a new ValidationError exception
|
||||
# If the function exception is a ValidationError itself the
|
||||
# error messages will be in a 'messages' property, so we
|
||||
# contatenate them.
|
||||
# Otherwise we extract whatever single message the exception
|
||||
# included.
|
||||
try:
|
||||
message = u', '.join(exception.messages)
|
||||
except AttributeError:
|
||||
message = unicode(exception)
|
||||
|
||||
raise ValidationError(_('Invalid value: %(message)s'), params={'message': message}, code='invalid')
|
||||
else:
|
||||
# Return the result if it was a parsing function
|
||||
# If it was a validation function and passed correctly we return
|
||||
# the original input value
|
||||
return result or self.cleaned_data['value']
|
||||
|
||||
# If a validation function was never specified we return the original
|
||||
# value
|
||||
return self.cleaned_data['value']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MetadataForm, self).__init__(*args, **kwargs)
|
||||
@@ -39,7 +67,7 @@ class MetadataForm(forms.Form):
|
||||
self.fields['name'].initial = '%s%s' % ((self.metadata_type.title if self.metadata_type.title else self.metadata_type.name), required_string)
|
||||
self.fields['id'].initial = self.metadata_type.pk
|
||||
|
||||
if self.metadata_type.lookup and self.metadata_type.lookup not in AVAILABLE_VALIDATORS:
|
||||
if self.metadata_type.lookup:
|
||||
try:
|
||||
choices = eval(self.metadata_type.lookup, AVAILABLE_MODELS)
|
||||
self.fields['value'] = forms.ChoiceField(label=self.fields['value'].label)
|
||||
@@ -68,22 +96,26 @@ MetadataFormSet = formset_factory(MetadataForm, extra=0)
|
||||
|
||||
|
||||
class AddMetadataForm(forms.Form):
|
||||
metadata_type = forms.ModelChoiceField(queryset=MetadataType.objects.all(), label=_(u'Metadata type'))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
document_type = kwargs.pop('document_type')
|
||||
super(AddMetadataForm, self).__init__(*args, **kwargs)
|
||||
self.fields['metadata_type'].queryset = document_type.metadata.all()
|
||||
|
||||
metadata_type = forms.ModelChoiceField(queryset=MetadataType.objects.all(), label=_(u'Metadata type'))
|
||||
|
||||
|
||||
class MetadataRemoveForm(MetadataForm):
|
||||
update = forms.BooleanField(initial=False, label=_(u'Remove'), required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MetadataRemoveForm, self).__init__(*args, **kwargs)
|
||||
self.fields.pop('value')
|
||||
|
||||
|
||||
MetadataRemoveFormSet = formset_factory(MetadataRemoveForm, extra=0)
|
||||
|
||||
|
||||
class MetadataTypeForm(forms.ModelForm):
|
||||
class Meta:
|
||||
fields = ('name', 'title', 'default', 'lookup')
|
||||
fields = ('name', 'title', 'default', 'lookup', 'validation')
|
||||
model = MetadataType
|
||||
|
||||
@@ -7,6 +7,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from documents.models import Document, DocumentType
|
||||
|
||||
from .managers import MetadataTypeManager
|
||||
from .settings import AVAILABLE_VALIDATORS
|
||||
|
||||
|
||||
class MetadataType(models.Model):
|
||||
@@ -24,7 +25,7 @@ class MetadataType(models.Model):
|
||||
lookup = models.TextField(blank=True, null=True,
|
||||
verbose_name=_(u'Lookup'),
|
||||
help_text=_(u'Enter a string to be evaluated that returns an iterable.'))
|
||||
# TODO: Add datatype choice: Date, Time, String, Number
|
||||
validation = models.CharField(blank=True, choices=zip(AVAILABLE_VALIDATORS, AVAILABLE_VALIDATORS), max_length=64, verbose_name=_(u'Validation function name'))
|
||||
# TODO: Find a different way to let users know what models and functions are
|
||||
# available now that we removed these from the help_text
|
||||
objects = MetadataTypeManager()
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
"""Configuration options for the metadata app"""
|
||||
|
||||
from dateutil.parser import parse
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils.timezone import now
|
||||
|
||||
from smart_settings.api import register_settings
|
||||
|
||||
|
||||
default_available_functions = {
|
||||
'current_date': now().date,
|
||||
}
|
||||
@@ -15,6 +16,7 @@ default_available_models = {
|
||||
}
|
||||
|
||||
default_available_validators = {
|
||||
'parse_date': lambda input: parse(input).isoformat()
|
||||
}
|
||||
|
||||
register_settings(
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding field 'MetadataType.validation'
|
||||
db.add_column(u'metadata_metadatatype', 'validation',
|
||||
self.gf('django.db.models.fields.CharField')(default='', max_length=64),
|
||||
keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting field 'MetadataType.validation'
|
||||
db.delete_column(u'metadata_metadatatype', 'validation')
|
||||
|
||||
|
||||
models = {
|
||||
u'documents.document': {
|
||||
'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'},
|
||||
'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'document_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'documents'", 'to': u"orm['documents.DocumentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'label': ('django.db.models.fields.CharField', [], {'default': "u'Uninitialized document'", 'max_length': '255', 'db_index': 'True'}),
|
||||
'language': ('django.db.models.fields.CharField', [], {'default': "u'eng'", 'max_length': '8'}),
|
||||
'uuid': ('django.db.models.fields.CharField', [], {'default': "u'8fd13d23-fcd0-438c-a1b3-7421a1d0eed5'", 'max_length': '48'})
|
||||
},
|
||||
u'documents.documenttype': {
|
||||
'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
|
||||
'ocr': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
u'metadata.documentmetadata': {
|
||||
'Meta': {'unique_together': "(('document', 'metadata_type'),)", 'object_name': 'DocumentMetadata'},
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'metadata'", 'to': u"orm['documents.Document']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'metadata_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['metadata.MetadataType']"}),
|
||||
'value': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
u'metadata.documenttypemetadatatype': {
|
||||
'Meta': {'unique_together': "(('document_type', 'metadata_type'),)", 'object_name': 'DocumentTypeMetadataType'},
|
||||
'document_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'metadata'", 'to': u"orm['documents.DocumentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'metadata_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['metadata.MetadataType']"}),
|
||||
'required': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
|
||||
},
|
||||
u'metadata.metadatatype': {
|
||||
'Meta': {'ordering': "('title',)", 'object_name': 'MetadataType'},
|
||||
'default': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'lookup': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '48'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '48'}),
|
||||
'validation': ('django.db.models.fields.CharField', [], {'max_length': '64'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['metadata']
|
||||
@@ -156,10 +156,13 @@ def metadata_add(request, document_id=None, document_id_list=None):
|
||||
metadata_type = form.cleaned_data['metadata_type']
|
||||
for document in documents:
|
||||
try:
|
||||
document_metadata, created = DocumentMetadata.objects.get_or_create(document=document, metadata_type=metadata_type, defaults={'value': u''})
|
||||
document_metadata, created = DocumentMetadata.objects.get_or_create(document=document, metadata_type=metadata_type.metadata_type, defaults={'value': u''})
|
||||
except Exception as exception:
|
||||
messages.error(request, _(u'Error adding metadata type "%(metadata_type)s" to document: %(document)s; %(exception)s') % {
|
||||
'metadata_type': metadata_type, 'document': document, 'exception': ', '.join(exception.messages)})
|
||||
if getattr(settings, 'DEBUG', False):
|
||||
raise
|
||||
else:
|
||||
messages.error(request, _(u'Error adding metadata type "%(metadata_type)s" to document: %(document)s; %(exception)s') % {
|
||||
'metadata_type': metadata_type, 'document': document, 'exception': ', '.join(getattr(exception, 'messages', exception))})
|
||||
else:
|
||||
if created:
|
||||
messages.success(request, _(u'Metadata type: %(metadata_type)s successfully added to document %(document)s.') % {
|
||||
|
||||
@@ -23,6 +23,7 @@ pdfminer==20110227
|
||||
psutil==2.1.3
|
||||
pycountry==1.8
|
||||
pytz==2014.4
|
||||
python-dateutil==2.4.0
|
||||
python-gnupg==0.3.6
|
||||
python-hkp==0.1.3
|
||||
python-magic==0.4.6
|
||||
|
||||
Reference in New Issue
Block a user