diff --git a/apps/main/__init__.py b/apps/main/__init__.py index f2d5cf7fbb..3575666e30 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -7,7 +7,8 @@ from navigation.api import register_links from history import history_list from converter import formats_list from documents import document_type_views -from metadata import setup_metadata_type_list, metadata_setup_view +from metadata import setup_metadata_type_list, metadata_type_setup_views +from metadata import setup_metadata_set_list, metadata_set_setup_views from main.conf.settings import SIDE_BAR_SEARCH @@ -46,12 +47,13 @@ register_top_menu('about', link={'text': _(u'about'), 'view': 'about', 'famfam': register_links(['tools_menu', 'statistics', 'history_list', 'history_view', 'formats_list'], [tools_menu, statistics, history_list, formats_list, sentry], menu_name='secondary_menu') -setup_links = [check_settings, role_list, user_list, group_list, document_types, setup_metadata_type_list, admin_site] +setup_links = [check_settings, role_list, user_list, group_list, document_types, setup_metadata_type_list, setup_metadata_set_list, admin_site] register_links(['setting_list'], setup_links, menu_name='secondary_menu') register_links(permission_views, setup_links, menu_name='secondary_menu') register_links(user_management_views, setup_links, menu_name='secondary_menu') register_links(document_type_views, setup_links, menu_name='secondary_menu') -register_links(metadata_setup_view, setup_links, menu_name='secondary_menu') +register_links(metadata_type_setup_views, setup_links, menu_name='secondary_menu') +register_links(metadata_set_setup_views, setup_links, menu_name='secondary_menu') def get_version(): diff --git a/apps/metadata/__init__.py b/apps/metadata/__init__.py index 1fd0489617..c28c2ea6ff 100644 --- a/apps/metadata/__init__.py +++ b/apps/metadata/__init__.py @@ -3,7 +3,7 @@ from django.utils.translation import ugettext_lazy as _ from navigation.api import register_links, register_multi_item_links from permissions.api import register_permission, set_namespace_title from documents.models import Document -from metadata.models import MetadataType +from metadata.models import MetadataType, MetadataSet PERMISSION_METADATA_DOCUMENT_EDIT = {'namespace': 'metadata', 'name': u'metadata_document_edit', 'label': _(u'Edit a document\'s metadata')} PERMISSION_METADATA_DOCUMENT_ADD = {'namespace': 'metadata', 'name': u'metadata_document_add', 'label': _(u'Add metadata to a document')} @@ -14,6 +14,11 @@ PERMISSION_METADATA_TYPE_CREATE = {'namespace': 'metadata_setup', 'name': u'meta PERMISSION_METADATA_TYPE_DELETE = {'namespace': 'metadata_setup', 'name': u'metadata_type_delete', 'label': _(u'Delete metadata types')} PERMISSION_METADATA_TYPE_VIEW = {'namespace': 'metadata_setup', 'name': u'metadata_type_view', 'label': _(u'View metadata types')} +PERMISSION_METADATA_SET_EDIT = {'namespace': 'metadata_setup', 'name': u'metadata_set_edit', 'label': _(u'Edit metadata sets')} +PERMISSION_METADATA_SET_CREATE = {'namespace': 'metadata_setup', 'name': u'metadata_set_create', 'label': _(u'Create new metadata sets')} +PERMISSION_METADATA_SET_DELETE = {'namespace': 'metadata_setup', 'name': u'metadata_set_delete', 'label': _(u'Delete metadata sets')} +PERMISSION_METADATA_SET_VIEW = {'namespace': 'metadata_setup', 'name': u'metadata_set_view', 'label': _(u'View metadata sets')} + set_namespace_title('metadata', _(u'Metadata')) register_permission(PERMISSION_METADATA_DOCUMENT_EDIT) register_permission(PERMISSION_METADATA_DOCUMENT_ADD) @@ -25,6 +30,11 @@ register_permission(PERMISSION_METADATA_TYPE_CREATE) register_permission(PERMISSION_METADATA_TYPE_DELETE) register_permission(PERMISSION_METADATA_TYPE_VIEW) +register_permission(PERMISSION_METADATA_SET_EDIT) +register_permission(PERMISSION_METADATA_SET_CREATE) +register_permission(PERMISSION_METADATA_SET_DELETE) +register_permission(PERMISSION_METADATA_SET_VIEW) + metadata_edit = {'text': _(u'edit metadata'), 'view': 'metadata_edit', 'args': 'object.id', 'famfam': 'xhtml_go', 'permissions': [PERMISSION_METADATA_DOCUMENT_EDIT]} metadata_multiple_edit = {'text': _(u'edit metadata'), 'view': 'metadata_multiple_edit', 'famfam': 'xhtml_go', 'permissions': [PERMISSION_METADATA_DOCUMENT_EDIT]} metadata_add = {'text': _(u'add metadata'), 'view': 'metadata_add', 'args': 'object.id', 'famfam': 'xhtml_add', 'permissions': [PERMISSION_METADATA_DOCUMENT_ADD]} @@ -37,10 +47,19 @@ setup_metadata_type_edit = {'text': _(u'edit'), 'view': 'setup_metadata_type_edi setup_metadata_type_delete = {'text': _(u'delete'), 'view': 'setup_metadata_type_delete', 'args': 'object.id', 'famfam': 'xhtml_delete', 'permissions': [PERMISSION_METADATA_TYPE_DELETE]} setup_metadata_type_create = {'text': _(u'create new'), 'view': 'setup_metadata_type_create', 'famfam': 'xhtml_add', 'permissions': [PERMISSION_METADATA_TYPE_CREATE]} +setup_metadata_set_list = {'text': _(u'metadata sets'), 'view': 'setup_metadata_set_list', 'famfam': 'application_form', 'permissions': [PERMISSION_METADATA_SET_VIEW]} +setup_metadata_set_edit = {'text': _(u'edit'), 'view': 'setup_metadata_set_edit', 'args': 'object.id', 'famfam': 'application_form_edit', 'permissions': [PERMISSION_METADATA_SET_EDIT]} +setup_metadata_set_delete = {'text': _(u'delete'), 'view': 'setup_metadata_set_delete', 'args': 'object.id', 'famfam': 'application_form_delete', 'permissions': [PERMISSION_METADATA_SET_DELETE]} +setup_metadata_set_create = {'text': _(u'create new'), 'view': 'setup_metadata_set_create', 'famfam': 'application_form_add', 'permissions': [PERMISSION_METADATA_SET_CREATE]} + register_links(Document, [metadata_add, metadata_edit, metadata_remove]) register_multi_item_links(['document_type_document_list', 'search', 'results', 'document_group_view', 'document_list', 'document_list_recent'], [metadata_multiple_add, metadata_multiple_edit, metadata_multiple_remove]) register_links(MetadataType, [setup_metadata_type_edit, setup_metadata_type_delete]) register_links(['setup_metadata_type_delete', 'setup_metadata_type_edit', 'setup_metadata_type_list', 'setup_metadata_type_create'], [setup_metadata_type_create], menu_name='sidebar') -metadata_setup_view = ['setup_metadata_type_list', 'setup_metadata_type_edit', 'setup_metadata_type_delete', 'setup_metadata_type_create'] +register_links(MetadataSet, [setup_metadata_set_edit, setup_metadata_set_delete]) +register_links(['setup_metadata_set_delete', 'setup_metadata_set_edit', 'setup_metadata_set_list', 'setup_metadata_set_create'], [setup_metadata_set_create], menu_name='sidebar') + +metadata_type_setup_views = ['setup_metadata_type_list', 'setup_metadata_type_edit', 'setup_metadata_type_delete', 'setup_metadata_type_create'] +metadata_set_setup_views = ['setup_metadata_set_list', 'setup_metadata_set_edit', 'setup_metadata_set_delete', 'setup_metadata_set_create'] diff --git a/apps/metadata/forms.py b/apps/metadata/forms.py index 4a44c723a8..4b663392d5 100644 --- a/apps/metadata/forms.py +++ b/apps/metadata/forms.py @@ -99,3 +99,8 @@ MetadataRemoveFormSet = formset_factory(MetadataRemoveForm, extra=0) class MetadataTypeForm(forms.ModelForm): class Meta: model = MetadataType + + +class MetadataSetForm(forms.ModelForm): + class Meta: + model = MetadataSet diff --git a/apps/metadata/models.py b/apps/metadata/models.py index f3afd83b66..0b652f11b6 100644 --- a/apps/metadata/models.py +++ b/apps/metadata/models.py @@ -11,6 +11,9 @@ available_functions_string = (_(u' Available functions: %s') % u','.join([u'%s() class MetadataType(models.Model): + """ + Define a type of metadata + """ 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, @@ -25,6 +28,7 @@ class MetadataType(models.Model): return self.title if self.title else self.name class Meta: + ordering = ('title',) verbose_name = _(u'metadata type') verbose_name_plural = _(u'metadata types') @@ -39,6 +43,7 @@ class MetadataSet(models.Model): return self.title if self.title else self.name class Meta: + ordering = ('title',) verbose_name = _(u'metadata set') verbose_name_plural = _(u'metadata set') @@ -78,6 +83,10 @@ class DocumentMetadata(models.Model): class DocumentTypeDefaults(models.Model): + """ + Default preselected metadata types and metadata set per document + type + """ document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type')) default_metadata_sets = models.ManyToManyField(MetadataSet, blank=True, verbose_name=_(u'default metadata sets')) default_metadata = models.ManyToManyField(MetadataType, blank=True, verbose_name=_(u'default metadata')) diff --git a/apps/metadata/urls.py b/apps/metadata/urls.py index 3d45d5382a..2dcdbb4fa3 100644 --- a/apps/metadata/urls.py +++ b/apps/metadata/urls.py @@ -12,4 +12,9 @@ urlpatterns = patterns('metadata.views', url(r'^setup/type/create/$', 'setup_metadata_type_create', (), 'setup_metadata_type_create'), url(r'^setup/type/(?P\d+)/edit/$', 'setup_metadata_type_edit', (), 'setup_metadata_type_edit'), url(r'^setup/type/(?P\d+)/delete/$', 'setup_metadata_type_delete', (), 'setup_metadata_type_delete'), + + url(r'^setup/set/list/$', 'setup_metadata_set_list', (), 'setup_metadata_set_list'), + url(r'^setup/set/create/$', 'setup_metadata_set_create', (), 'setup_metadata_set_create'), + url(r'^setup/set/(?P\d+)/edit/$', 'setup_metadata_set_edit', (), 'setup_metadata_set_edit'), + url(r'^setup/set/(?P\d+)/delete/$', 'setup_metadata_set_delete', (), 'setup_metadata_set_delete'), ) diff --git a/apps/metadata/views.py b/apps/metadata/views.py index d272135a48..e1ce3f4b55 100644 --- a/apps/metadata/views.py +++ b/apps/metadata/views.py @@ -11,14 +11,20 @@ from documents.models import Document, RecentDocument from permissions.api import check_permissions from document_indexing.api import update_indexes, delete_indexes +from common.utils import generate_choices_w_labels#, two_state_template +from common.views import assign_remove + from metadata import PERMISSION_METADATA_DOCUMENT_EDIT, \ PERMISSION_METADATA_DOCUMENT_ADD, PERMISSION_METADATA_DOCUMENT_REMOVE, \ PERMISSION_METADATA_TYPE_EDIT, PERMISSION_METADATA_TYPE_CREATE, \ - PERMISSION_METADATA_TYPE_DELETE, PERMISSION_METADATA_TYPE_VIEW + PERMISSION_METADATA_TYPE_DELETE, PERMISSION_METADATA_TYPE_VIEW, \ + PERMISSION_METADATA_SET_EDIT, PERMISSION_METADATA_SET_CREATE, \ + PERMISSION_METADATA_SET_DELETE, PERMISSION_METADATA_SET_VIEW from metadata.forms import MetadataFormSet, AddMetadataForm, \ - MetadataRemoveFormSet, MetadataTypeForm + MetadataRemoveFormSet, MetadataTypeForm, MetadataSetForm from metadata.api import save_metadata_list -from metadata.models import DocumentMetadata, MetadataType +from metadata.models import DocumentMetadata, MetadataType, MetadataSet, \ + MetadataSetItem def metadata_edit(request, document_id=None, document_id_list=None): @@ -357,9 +363,122 @@ def setup_metadata_type_delete(request, metadatatype_id): 'next': next, 'previous': previous, 'object': metadata_type, - 'title': _(u'Are you sure you with to delete the metadata type: %s?') % metadata_type, + 'title': _(u'Are you sure you wish to delete the metadata type: %s?') % metadata_type, 'form_icon': u'xhtml_delete.png', } return render_to_response('generic_confirm.html', context, context_instance=RequestContext(request)) + + +def setup_metadata_set_list(request): + check_permissions(request.user, [PERMISSION_METADATA_SET_VIEW]) + + context = { + 'object_list': MetadataSet.objects.all(), + 'title': _(u'metadata sets'), + 'hide_link': True, + 'extra_columns': [ + { + 'name': _(u'members'), + 'attribute': lambda x: x.metadatasetitem_set.count(), + }, + ] + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) + + +def get_set_members(metadata_set): + return [item.metadata_type for item in metadata_set.metadatasetitem_set.all()] + + +def get_non_set_members(metadata_set): + return MetadataType.objects.exclude(pk__in=[member.pk for member in get_set_members(metadata_set)]) + + +def add_set_member(metadata_set, selection): + model, pk = selection.split(u',') + metadata_type = get_object_or_404(MetadataType, pk=pk) + new_member, created = MetadataSetItem.objects.get_or_create(metadata_set=metadata_set, metadata_type=metadata_type) + if not created: + raise Exception + + +def remove_set_member(metadata_set, selection): + model, pk = selection.split(u',') + metadata_type = get_object_or_404(MetadataType, pk=pk) + member = MetadataSetItem.objects.get(metadata_type=metadata_type, metadata_set=metadata_set) + member.delete() + + +def setup_metadata_set_edit(request, metadata_set_id): + check_permissions(request.user, [PERMISSION_METADATA_SET_EDIT]) + + metadata_set = get_object_or_404(MetadataSet, pk=metadata_set_id) + + return assign_remove( + request, + left_list=lambda: generate_choices_w_labels(get_non_set_members(metadata_set)), + right_list=lambda: generate_choices_w_labels(get_set_members(metadata_set)), + add_method=lambda x: add_set_member(metadata_set, x), + remove_method=lambda x: remove_set_member(metadata_set, x), + left_list_title=_(u'non members of metadata set: %s') % metadata_set, + right_list_title=_(u'members of metadata set: %s') % metadata_set, + obj=metadata_set, + object_name=_(u'metadata set'), + ) + + +def setup_metadata_set_create(request): + check_permissions(request.user, [PERMISSION_METADATA_SET_CREATE]) + + if request.method == 'POST': + form = MetadataSetForm(request.POST) + if form.is_valid(): + form.save() + messages.success(request, _(u'Metadata set created successfully')) + return HttpResponseRedirect(reverse('setup_metadata_set_list')) + else: + form = MetadataSetForm() + + return render_to_response('generic_form.html', { + 'title': _(u'create metadata set'), + 'form': form, + }, + context_instance=RequestContext(request)) + + +def setup_metadata_set_delete(request, metadata_set_id): + check_permissions(request.user, [PERMISSION_METADATA_SET_DELETE]) + + metadata_set = get_object_or_404(MetadataSet, pk=metadata_set_id) + + post_action_redirect = reverse('setup_metadata_set_list') + + previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', post_action_redirect))) + next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', post_action_redirect))) + + if request.method == 'POST': + try: + metadata_set.delete() + messages.success(request, _(u'Metadata set: %s deleted successfully.') % metadata_set) + except Exception, e: + messages.error(request, _(u'Folder: %(metadata_set)s delete error: %(error)s') % { + 'metadata_set': metadata_set, 'error': e}) + + return HttpResponseRedirect(next) + + context = { + 'object_name': _(u'metadata set'), + 'delete_view': True, + 'next': next, + 'previous': previous, + 'object': metadata_set, + 'title': _(u'Are you sure you wish to delete the metadata set: %s?') % metadata_set, + 'form_icon': u'application_form_delete.png', + } + + return render_to_response('generic_confirm.html', context, + context_instance=RequestContext(request)) diff --git a/site_media/images/icons/application_form_delete.png b/site_media/images/icons/application_form_delete.png new file mode 100644 index 0000000000..c8990b2fa0 Binary files /dev/null and b/site_media/images/icons/application_form_delete.png differ