Created new metadata app and move all code relating metadata to it

This commit is contained in:
Roberto Rosario
2011-05-10 03:41:35 -04:00
parent b4daa2d52b
commit ea20cde597
20 changed files with 601 additions and 320 deletions
+28
View File
@@ -0,0 +1,28 @@
from django.utils.translation import ugettext_lazy as _
from navigation.api import register_links, register_menu, \
register_model_list_columns, register_multi_item_links
from main.api import register_diagnostic, register_tool
from permissions.api import register_permissions
from documents.models import Document
PERMISSION_METADATA_DOCUMENT_EDIT = u'metadata_document_edit'
PERMISSION_METADATA_DOCUMENT_ADD = u'metadata_document_add'
PERMISSION_METADATA_DOCUMENT_REMOVE = u'metadata_document_remove'
register_permissions('metadata', [
{'name': PERMISSION_METADATA_DOCUMENT_EDIT, 'label': _(u'Edit a document\'s metadata')},
{'name': PERMISSION_METADATA_DOCUMENT_ADD, 'label': _(u'Add metadata to a document')},
{'name': PERMISSION_METADATA_DOCUMENT_REMOVE, 'label': _(u'Remove metadata from a document')},
])
metadata_edit = {'text': _(u'edit metadata'), 'view': 'metadata_edit', 'args': 'object.id', 'famfam': 'xhtml_go', 'permissions': {'namespace': 'metadata', 'permissions': [PERMISSION_METADATA_DOCUMENT_EDIT]}}
metadata_multiple_edit = {'text': _(u'edit metadata'), 'view': 'metadata_multiple_edit', 'famfam': 'xhtml_go', 'permissions': {'namespace': 'metadata', 'permissions': [PERMISSION_METADATA_DOCUMENT_EDIT]}}
metadata_add = {'text': _(u'add metadata'), 'view': 'metadata_add', 'args': 'object.id', 'famfam': 'xhtml_add', 'permissions': {'namespace': 'metadata', 'permissions': [PERMISSION_METADATA_DOCUMENT_ADD]}}
metadata_multiple_add = {'text': _(u'add metadata'), 'view': 'metadata_multiple_add', 'famfam': 'xhtml_add', 'permissions': {'namespace': 'metadata', 'permissions': [PERMISSION_METADATA_DOCUMENT_ADD]}}
metadata_remove = {'text': _(u'remove metadata'), 'view': 'metadata_remove', 'args': 'object.id', 'famfam': 'xhtml_delete', 'permissions': {'namespace': 'metadata', 'permissions': [PERMISSION_METADATA_DOCUMENT_REMOVE]}}
metadata_multiple_remove = {'text': _(u'remove metadata'), 'view': 'metadata_multiple_remove', 'famfam': 'xhtml_delete', 'permissions': {'namespace': 'metadata', 'permissions': [PERMISSION_METADATA_DOCUMENT_REMOVE]}}
register_links(Document, [metadata_add, metadata_edit, metadata_remove])
register_multi_item_links(['metadatagroup_view', 'document_list', 'document_list_recent'], [metadata_multiple_add, metadata_multiple_edit, metadata_multiple_remove])
+30
View File
@@ -0,0 +1,30 @@
from django.contrib import admin
from metadata.models import MetadataType, MetadataSet, MetadataSetItem, \
DocumentMetadata
class MetadataTypeAdmin(admin.ModelAdmin):
list_display = ('name', 'title', 'default', 'lookup')
class MetadataSetItemInline(admin.StackedInline):
model = MetadataSetItem
extra = 1
classes = ('collapse-open',)
allow_add = True
class DocumentMetadataInline(admin.StackedInline):
model = DocumentMetadata
extra = 0
classes = ('collapse-open',)
allow_add = False
class MetadataSetAdmin(admin.ModelAdmin):
inlines = [MetadataSetItemInline]
admin.site.register(MetadataType, MetadataTypeAdmin)
admin.site.register(MetadataSet, MetadataSetAdmin)
+11 -3
View File
@@ -3,10 +3,9 @@
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
from metadata.models import DocumentMetadata, MetadataType
def decode_metadata_from_url(url_dict):
@@ -59,13 +58,22 @@ def save_metadata_list(metadata_list, document):
def save_metadata(metadata_dict, document):
"""save metadata_dict"""
# Use matched metadata now to create document metadata
document_metadata, created = DocumentMetadata.objects.get_or_create(
#document_metadata, created = DocumentMetadata.objects.get_or_create(
# document=document,
# metadata_type=get_object_or_404(
# MetadataType,
# pk=metadata_dict['id']
# ),
#)
document_metadata = DocumentMetadata.objects.get(
document=document,
metadata_type=get_object_or_404(
MetadataType,
pk=metadata_dict['id']
),
)
# Handle 'plus sign as space' in the url
# unquote_plus handles utf-8?!?
+1
View File
@@ -0,0 +1 @@
+27
View File
@@ -0,0 +1,27 @@
"""Configuration options for the metadata app"""
import datetime
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
from smart_settings.api import register_settings
default_available_functions = {
'current_date': datetime.datetime.now().date,
}
default_available_models = {
'User': User
}
register_settings(
namespace=u'metadata',
module=u'metadata.conf.settings',
settings=[
# Definition
{'name': u'AVAILABLE_FUNCTIONS', 'global_name': u'METADATA_AVAILABLE_FUNCTIONS', 'default': default_available_functions},
{'name': u'AVAILABLE_MODELS', 'global_name': u'METADATA_AVAILABLE_MODELS', 'default': default_available_models},
]
)
+67
View File
@@ -0,0 +1,67 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.forms.formsets import formset_factory
from metadata.conf.settings import AVAILABLE_MODELS
from metadata.conf.settings import AVAILABLE_FUNCTIONS
from metadata.models import MetadataType, DocumentMetadata
class MetadataForm(forms.Form):
def __init__(self, *args, **kwargs):
super(MetadataForm, self).__init__(*args, **kwargs)
#Set form fields initial values
if 'initial' in kwargs:
self.metadata_type = kwargs['initial'].pop('metadata_type', None)
#self.document_type = kwargs['initial'].pop('document_type', None)
# FIXME:
#required = self.document_type.documenttypemetadatatype_set.get(metadata_type=self.metadata_type).required
required = False
required_string = u''
if required:
self.fields['value'].required = True
required_string = ' (%s)' % _(u'required')
else:
#TODO: FIXME: not working correctly
self.fields['value'].required = False
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.default:
try:
self.fields['value'].initial = eval(self.metadata_type.default, AVAILABLE_FUNCTIONS)
except Exception, err:
self.fields['value'].initial = err
if self.metadata_type.lookup:
try:
choices = eval(self.metadata_type.lookup, AVAILABLE_MODELS)
self.fields['value'] = forms.ChoiceField(label=self.fields['value'].label)
choices = zip(choices, choices)
if not required:
choices.insert(0, ('', '------'))
self.fields['value'].choices = choices
self.fields['value'].required = required
except Exception, err:
self.fields['value'].initial = err
self.fields['value'].widget = forms.TextInput(attrs={'readonly': 'readonly'})
id = forms.CharField(label=_(u'id'), widget=forms.HiddenInput)
name = forms.CharField(label=_(u'Name'),
required=False, widget=forms.TextInput(attrs={'readonly': 'readonly'}))
value = forms.CharField(label=_(u'Value'), required=False)
update = forms.BooleanField(initial=True, label=_(u'Update'), required=False)
MetadataFormSet = formset_factory(MetadataForm, extra=0)
class AddMetadataForm(forms.Form):
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)
MetadataRemoveFormSet = formset_factory(MetadataRemoveForm, extra=0)
+74
View File
@@ -0,0 +1,74 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from documents.models import Document
from metadata.conf.settings import AVAILABLE_MODELS
from metadata.conf.settings import AVAILABLE_FUNCTIONS
available_models_string = (_(u' Available models: %s') % u','.join([name for name, model in AVAILABLE_MODELS.items()])) if AVAILABLE_MODELS else u''
available_functions_string = (_(u' Available functions: %s') % u','.join([u'%s()' % name for name, function in AVAILABLE_FUNCTIONS.items()])) if AVAILABLE_FUNCTIONS else u''
class MetadataType(models.Model):
name = models.CharField(unique=True, max_length=48, verbose_name=_(u'name'), help_text=_(u'Do not use python reserved words, or spaces.'))
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)
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)
#TODO: datatype?
def __unicode__(self):
return self.title if self.title else self.name
class Meta:
verbose_name = _(u'metadata type')
verbose_name_plural = _(u'metadata types')
class MetadataSet(models.Model):
title = models.CharField(max_length=48, verbose_name=_(u'title'))
def __unicode__(self):
return self.title if self.title else self.name
class Meta:
verbose_name = _(u'metadata set')
verbose_name_plural = _(u'metadata set')
class MetadataSetItem(models.Model):
"""
Define the set of metadata that relates to a set or group of
metadata fields
"""
metadata_set = models.ForeignKey(MetadataSet, verbose_name=_(u'metadata set'))
metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'metadata type'))
#required = models.BooleanField(default=True, verbose_name=_(u'required'))
def __unicode__(self):
return unicode(self.metadata_type)
class Meta:
verbose_name = _(u'metadata set item')
verbose_name_plural = _(u'metadata set items')
class DocumentMetadata(models.Model):
"""
Link a document to a specific instance of a metadata type with it's
current value
"""
document = models.ForeignKey(Document, verbose_name=_(u'document'))
metadata_type = models.ForeignKey(MetadataType, verbose_name=_(u'type'))
value = models.TextField(blank=True, null=True, verbose_name=_(u'value'), db_index=True)
def __unicode__(self):
return unicode(self.metadata_type)
class Meta:
verbose_name = _(u'document metadata')
verbose_name_plural = _(u'document metadata')
+23
View File
@@ -0,0 +1,23 @@
"""
This file demonstrates two different styles of tests (one doctest and one
unittest). These will both pass when you run "manage.py test".
Replace these with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.failUnlessEqual(1 + 1, 2)
__test__ = {"doctest": """
Another way to test that 1 + 1 is equal to 2.
>>> 1 + 1 == 2
True
"""}
+10
View File
@@ -0,0 +1,10 @@
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('metadata.views',
url(r'^(?P<document_id>\d+)/edit/$', 'metadata_edit', (), 'metadata_edit'),
url(r'^multiple/edit/$', 'metadata_multiple_edit', (), 'metadata_multiple_edit'),
url(r'^(?P<document_id>\d+)/add/$', 'metadata_add', (), 'metadata_add'),
url(r'^multiple/add/$', 'metadata_multiple_add', (), 'metadata_multiple_add'),
url(r'^(?P<document_id>\d+)/remove/$', 'metadata_remove', (), 'metadata_remove'),
url(r'^multiple/remove/$', 'metadata_multiple_remove', (), 'metadata_multiple_remove'),
)
+251
View File
@@ -0,0 +1,251 @@
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _
from django.shortcuts import get_object_or_404
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.utils.http import urlencode
from documents.models import Document, RecentDocument
from permissions.api import check_permissions
from filesystem_serving.api import document_create_fs_links, document_delete_fs_links
from metadata import PERMISSION_METADATA_DOCUMENT_EDIT, \
PERMISSION_METADATA_DOCUMENT_ADD, PERMISSION_METADATA_DOCUMENT_REMOVE
from metadata.forms import MetadataFormSet, AddMetadataForm, MetadataRemoveFormSet
from metadata.api import save_metadata_list
from metadata.models import DocumentMetadata, MetadataType
def metadata_edit(request, document_id=None, document_id_list=None):
check_permissions(request.user, 'metadata', [PERMISSION_METADATA_DOCUMENT_EDIT])
if document_id:
documents = [get_object_or_404(Document, pk=document_id)]
if documents[0].documentmetadata_set.count() == 0:
messages.warning(request, _(u'The selected document doesn\'t have any metadata.'))
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
elif document_id_list:
documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')]
else:
messages.error(request, _(u'Must provide at least one document.'))
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
metadata = {}
for document in documents:
RecentDocument.objects.add_document_for_user(request.user, document)
for item in document.documentmetadata_set.all():
value = item.value
if item.metadata_type in metadata:
if value not in metadata[item.metadata_type]:
metadata[item.metadata_type].append(value)
else:
metadata[item.metadata_type] = [value] if value else u''
initial = []
for key, value in metadata.items():
initial.append({
'metadata_type': key,
'value': u', '.join(value)
})
formset = MetadataFormSet(initial=initial)
if request.method == 'POST':
formset = MetadataFormSet(request.POST)
if formset.is_valid():
for document in documents:
try:
document_delete_fs_links(document)
except Exception, e:
messages.error(request, _(u'Error deleting filesystem links for document: %(document)s; %(error)s') % {
'document': document, 'error': e})
for form in formset.forms:
if form.cleaned_data['update']:
try:
save_metadata_list([form.cleaned_data], document)
messages.success(request, _(u'Metadata for document %s edited successfully.') % document)
except Exception, e:
messages.error(request, _(u'Error editing metadata for document %(document)s; %(error)s.') % {
'document': document, 'error': e})
try:
warnings = document_create_fs_links(document)
if request.user.is_staff or request.user.is_superuser:
for warning in warnings:
messages.warning(request, warning)
messages.success(request, _(u'Filesystem links updated successfully for document: %s.') % document)
except Exception, e:
messages.error(request, _('Error creating filesystem links for document: %(document)s; %(error)s') % {
'document': document, 'error': e})
if len(documents) == 1:
return HttpResponseRedirect(document.get_absolute_url())
elif len(documents) > 1:
return HttpResponseRedirect(reverse('document_list_recent'))
context = {
'form_display_mode_table': True,
'form': formset,
}
if len(documents) == 1:
context['object'] = documents[0]
context['title'] = _(u'Edit metadata for document: %s') % ', '.join([unicode(d) for d in documents])
elif len(documents) > 1:
context['title'] = _(u'Edit metadata for documents: %s') % ', '.join([unicode(d) for d in documents])
return render_to_response('generic_form.html', context,
context_instance=RequestContext(request))
def metadata_multiple_edit(request):
return metadata_edit(request, document_id_list=request.GET.get('id_list', []))
def metadata_add(request, document_id=None, document_id_list=None):
check_permissions(request.user, 'metadata', [PERMISSION_METADATA_DOCUMENT_ADD])
if document_id:
documents = [get_object_or_404(Document, pk=document_id)]
elif document_id_list:
documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')]
else:
messages.error(request, _(u'Must provide at least one document.'))
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
metadata = {}
for document in documents:
RecentDocument.objects.add_document_for_user(request.user, document)
if request.method == 'POST':
form = AddMetadataForm(request.POST)
if form.is_valid():
metadata_type = form.cleaned_data['metadata_type']
for document in documents:
document_metadata, created = DocumentMetadata.objects.get_or_create(document=document, metadata_type=metadata_type, defaults={'value': u''})
if created:
messages.success(request, _(u'Metadata type: %(metadata_type)s successfully added to document %(document)s.') % {
'metadata_type': metadata_type, 'document': document})
else:
messages.warning(request, _(u'Metadata type: %(metadata_type)s already present in document %(document)s.') % {
'metadata_type': metadata_type, 'document': document})
if len(documents) == 1:
return HttpResponseRedirect(reverse(metadata_edit, args=[document.pk]))
elif len(documents) > 1:
return HttpResponseRedirect(u'%s?%s' % (reverse('metadata_multiple_edit'), urlencode({'id_list': document_id_list})))
else:
form = AddMetadataForm()
context = {
#'form_display_mode_table': True,
'form': form,
}
if len(documents) == 1:
context['object'] = documents[0]
context['title'] = _(u'Add metadata type to document: %s') % ', '.join([unicode(d) for d in documents])
elif len(documents) > 1:
context['title'] = _(u'Add metadata type to documents: %s') % ', '.join([unicode(d) for d in documents])
return render_to_response('generic_form.html', context,
context_instance=RequestContext(request))
def metadata_multiple_add(request):
return metadata_add(request, document_id_list=request.GET.get('id_list', []))
def metadata_remove(request, document_id):
check_permissions(request.user, 'metadata', [PERMISSION_METADATA_DOCUMENT_REMOVE])
if document_id:
documents = [get_object_or_404(Document, pk=document_id)]
if documents[0].documentmetadata_set.count() == 0:
messages.warning(request, _(u'The selected document doesn\'t have any metadata.'))
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
elif document_id_list:
documents = [get_object_or_404(Document, pk=document_id) for document_id in document_id_list.split(',')]
else:
messages.error(request, _(u'Must provide at least one document.'))
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
metadata = {}
for document in documents:
RecentDocument.objects.add_document_for_user(request.user, document)
for item in document.documentmetadata_set.all():
value = item.value
if item.metadata_type in metadata:
if value not in metadata[item.metadata_type]:
metadata[item.metadata_type].append(value)
else:
metadata[item.metadata_type] = [value] if value else u''
initial = []
for key, value in metadata.items():
initial.append({
'metadata_type': key,
'value': u', '.join(value)
})
formset = MetadataRemoveFormSet(initial=initial)
if request.method == 'POST':
formset = MetadataRemoveFormSet(request.POST)
if formset.is_valid():
for document in documents:
try:
document_delete_fs_links(document)
except Exception, e:
messages.error(request, _(u'Error deleting filesystem links for document: %(document)s; %(error)s') % {
'document': document, 'error': e})
for form in formset.forms:
if form.cleaned_data['update']:
metadata_type = get_object_or_404(MetadataType, pk=form.cleaned_data['id'])
try:
document_metadata = DocumentMetadata.objects.get(document=document, metadata_type=metadata_type)
document_metadata.delete()
messages.success(request, _(u'Successfully remove metadata type: %(metadata_type)s from document: %(document)s.') % {
'metadata_type': metadata_type, 'document': document})
except:
messages.error(request, _(u'Error removing metadata type: %(metadata_type)s from document: %(document)s.') % {
'metadata_type': metadata_type, 'document': document})
try:
warnings = document_create_fs_links(document)
if request.user.is_staff or request.user.is_superuser:
for warning in warnings:
messages.warning(request, warning)
messages.success(request, _(u'Filesystem links updated successfully for document: %s.') % document)
except Exception, e:
messages.error(request, _('Error creating filesystem links for document: %(document)s; %(error)s') % {
'document': document, 'error': e})
if len(documents) == 1:
return HttpResponseRedirect(document.get_absolute_url())
elif len(documents) > 1:
return HttpResponseRedirect(reverse('document_list_recent'))
context = {
'form_display_mode_table': True,
'form': formset,
}
if len(documents) == 1:
context['object'] = documents[0]
context['title'] = _(u'Remove metadata types to document: %s') % ', '.join([unicode(d) for d in documents])
elif len(documents) > 1:
context['title'] = _(u'Remove metadata types to documents: %s') % ', '.join([unicode(d) for d in documents])
return render_to_response('generic_form.html', context,
context_instance=RequestContext(request))
def metadata_multiple_remove(request):
return metadata_remove(request, document_id_list=request.GET.get('id_list', []))