Initial set of changes to support user document folders
This commit is contained in:
43
apps/folders/__init__.py
Normal file
43
apps/folders/__init__.py
Normal file
@@ -0,0 +1,43 @@
|
||||
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
|
||||
from permissions.api import register_permissions
|
||||
|
||||
from models import Folder
|
||||
|
||||
folder_list = {'text': _(u'folder list'), 'view': 'folder_list', 'famfam': 'folder'}
|
||||
folder_create = {'text': _('create folder'), 'view': 'folder_create', 'famfam': 'folder_add'}
|
||||
folder_edit = {'text': _('edit'), 'view': 'folder_edit', 'args': 'object.id', 'famfam': 'folder_edit'}
|
||||
folder_delete = {'text': _('delete'), 'view': 'folder_delete', 'args': 'object.id', 'famfam': 'folder_delete'}
|
||||
|
||||
#document_create_multiple = {'text': _('upload multiple new documents'), 'view': 'document_create_multiple', 'famfam': 'page_add', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_CREATE]}}
|
||||
#document_create_sibling = {'text': _('upload new document using same metadata'), 'view': 'document_create_sibling', 'args': 'object.id', 'famfam': 'page_copy', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_CREATE]}}
|
||||
#document_view = {'text': _('details (advanced)'), 'view': 'document_view', 'args': 'object.id', 'famfam': 'page', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_VIEW]}}
|
||||
#document_view_simple = {'text': _('details (simple)'), 'view': 'document_view_simple', 'args': 'object.id', 'famfam': 'page', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_VIEW]}}
|
||||
#document_multiple_delete = {'text': _('delete'), 'view': 'document_multiple_delete', 'famfam': 'page_delete', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_DELETE]}}
|
||||
#document_edit_metadata = {'text': _('edit metadata'), 'view': 'document_edit_metadata', 'args': 'object.id', 'famfam': 'page_edit', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_METADATA_EDIT]}}
|
||||
#document_multiple_edit_metadata = {'text': _('edit metadata'), 'view': 'document_multiple_edit_metadata', 'famfam': 'page_edit', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_METADATA_EDIT]}}
|
||||
#document_preview = {'text': _('preview'), 'class': 'fancybox', 'view': 'document_preview', 'args': 'object.id', 'famfam': 'magnifier', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_VIEW]}}
|
||||
#document_download = {'text': _('download'), 'view': 'document_download', 'args': 'object.id', 'famfam': 'page_save', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]}}
|
||||
#document_find_duplicates = {'text': _('find duplicates'), 'view': 'document_find_duplicates', 'args': 'object.id', 'famfam': 'page_refresh', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_VIEW]}}
|
||||
#document_find_all_duplicates = {'text': _('find all duplicates'), 'view': 'document_find_all_duplicates', 'famfam': 'page_refresh', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_VIEW]}}
|
||||
#document_clear_transformations = {'text': _('clear all transformations'), 'view': 'document_clear_transformations', 'args': 'object.id', 'famfam': 'page_paintbrush', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]}}
|
||||
#document_multiple_clear_transformations = {'text': _('clear all transformations'), 'view': 'document_multiple_clear_transformations', 'famfam': 'page_paintbrush', 'permissions': {'namespace': 'documents', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]}}
|
||||
|
||||
#register_links(Document, [document_view_simple, document_view, document_edit, document_edit_metadata, document_delete, document_download, document_find_duplicates, document_clear_transformations], menu_name='sidebar')
|
||||
#register_links(Document, [document_list_recent, document_list, document_create, document_create_multiple, document_create_sibling], menu_name='sidebar')
|
||||
#register_multi_item_links(['document_list'], [document_multiple_clear_transformations, document_multiple_edit_metadata, document_multiple_delete])
|
||||
|
||||
#####register_links(['folder_list', 'document_list_recent', 'document_list', 'document_create', 'document_create_multiple', 'upload_document_with_type', 'upload_multiple_documents_with_type'], [folder_list, folder_create], menu_name='sidebar')
|
||||
|
||||
register_links(Folder, [folder_edit, folder_delete])
|
||||
|
||||
register_links(['folder_edit', 'folder_delete', 'folder_list', 'folder_create'], [folder_list, folder_create], menu_name='sidebar')
|
||||
|
||||
|
||||
register_menu([
|
||||
{'text': _('folders'), 'view': 'folder_list', 'links': [
|
||||
folder_list, folder_create
|
||||
], 'famfam': 'folder', 'position': 2}])
|
||||
17
apps/folders/admin.py
Normal file
17
apps/folders/admin.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from models import Folder, FolderDocument
|
||||
|
||||
|
||||
class FolderDocumentInline(admin.StackedInline):
|
||||
model = FolderDocument
|
||||
extra = 1
|
||||
classes = ('collapse-open',)
|
||||
allow_add = True
|
||||
|
||||
|
||||
class FolderAdmin(admin.ModelAdmin):
|
||||
inlines = [FolderDocumentInline]
|
||||
|
||||
|
||||
admin.site.register(Folder, FolderAdmin)
|
||||
11
apps/folders/forms.py
Normal file
11
apps/folders/forms.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext as _
|
||||
#from django.template.defaultfilters import capfirst
|
||||
|
||||
from models import Folder
|
||||
|
||||
|
||||
class FolderForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Folder
|
||||
fields = ('title',)
|
||||
43
apps/folders/models.py
Normal file
43
apps/folders/models.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from datetime import datetime
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from documents.models import Document
|
||||
|
||||
|
||||
class Folder(models.Model):
|
||||
title = models.CharField(max_length=32, verbose_name=_(u'title'), db_index=True)
|
||||
user = models.ForeignKey(User, verbose_name=_(u'user'))
|
||||
datetime_created = models.DateTimeField(verbose_name=_(u'datetime created'))
|
||||
|
||||
def __unicode__(self):
|
||||
return self.title
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.pk:
|
||||
self.datetime_created = datetime.now()
|
||||
super(Folder, self).save(*args, **kwargs)
|
||||
|
||||
@models.permalink
|
||||
def get_absolute_url(self):
|
||||
return ('folder_view', [self.pk])
|
||||
|
||||
class Meta:
|
||||
unique_together = ('title', 'user')
|
||||
ordering = ('title',)
|
||||
verbose_name = _(u'folder')
|
||||
verbose_name_plural = _(u'folders')
|
||||
|
||||
|
||||
class FolderDocument(models.Model):
|
||||
folder = models.ForeignKey(Folder, verbose_name=_('folder'))
|
||||
document = models.ForeignKey(Document, verbose_name=_('document'))
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.document)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _(u'folder document')
|
||||
verbose_name_plural = _(u'folders documents')
|
||||
23
apps/folders/tests.py
Normal file
23
apps/folders/tests.py
Normal 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
apps/folders/urls.py
Normal file
10
apps/folders/urls.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
|
||||
|
||||
urlpatterns = patterns('folders.views',
|
||||
url(r'^list/$', 'folder_list', (), 'folder_list'),
|
||||
url(r'^create/$', 'folder_create', (), 'folder_create'),
|
||||
url(r'^(?P<folder_id>\d+)/edit/$', 'folder_edit', (), 'folder_edit'),
|
||||
url(r'^(?P<folder_id>\d+)/delete/$', 'folder_delete', (), 'folder_delete'),
|
||||
url(r'^(?P<folder_id>\d+)/$', 'folder_view', (), 'folder_view'),
|
||||
)
|
||||
135
apps/folders/views.py
Normal file
135
apps/folders/views.py
Normal file
@@ -0,0 +1,135 @@
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import render_to_response, get_object_or_404
|
||||
from django.template import RequestContext
|
||||
from django.contrib import messages
|
||||
from django.views.generic.list_detail import object_detail, object_list
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.views.generic.create_update import create_object, delete_object, update_object
|
||||
|
||||
from documents import PERMISSION_DOCUMENT_VIEW
|
||||
from documents.models import Document
|
||||
from permissions.api import check_permissions
|
||||
|
||||
from models import Folder, FolderDocument
|
||||
from forms import FolderForm
|
||||
|
||||
|
||||
def folder_list(request):
|
||||
return object_list(
|
||||
request,
|
||||
queryset=Folder.objects.filter(user=request.user),
|
||||
template_name='generic_list.html',
|
||||
extra_context={
|
||||
'title': _(u'folders'),
|
||||
'multi_select_as_buttons': True,
|
||||
'extra_columns': [
|
||||
{'name': _(u'created'), 'attribute': 'datetime_created'},
|
||||
{'name': _(u'documents'), 'attribute': lambda x: x.folderdocument_set.count()}
|
||||
]
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def folder_create(request):
|
||||
if request.method == 'POST':
|
||||
form = FolderForm(request.POST)
|
||||
if form.is_valid():
|
||||
folder, created = Folder.objects.get_or_create(user=request.user, title=form.cleaned_data['title'])
|
||||
if created:
|
||||
messages.success(request, _(u'Folder created successfully'))
|
||||
return HttpResponseRedirect(reverse('folder_list'))
|
||||
else:
|
||||
messages.error(request, _(u'A folder named: %s, already exists.') % form.cleaned_data['title'])
|
||||
else:
|
||||
form = FolderForm()
|
||||
|
||||
return render_to_response('generic_form.html', {
|
||||
'title': _(u'create folder'),
|
||||
'form': form,
|
||||
},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def folder_edit(request, folder_id):
|
||||
folder = get_object_or_404(Folder, pk=folder_id)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = FolderForm(request.POST)
|
||||
if form.is_valid():
|
||||
folder.title=form.cleaned_data['title']
|
||||
try:
|
||||
folder.save()
|
||||
messages.success(request, _(u'Folder edited successfully'))
|
||||
return HttpResponseRedirect(reverse('folder_list'))
|
||||
except Exception, e:
|
||||
messages.error(request, _(u'Error editing folder; %s') % e)
|
||||
else:
|
||||
form = FolderForm(instance=folder)
|
||||
|
||||
return render_to_response('generic_form.html', {
|
||||
'title': _(u'edit folder: %s') % folder,
|
||||
'form': form,
|
||||
'object': folder,
|
||||
},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def folder_delete(request, folder_id):
|
||||
folder = get_object_or_404(Folder, pk=folder_id)
|
||||
|
||||
post_action_redirect = reverse('folder_list')
|
||||
|
||||
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/')))
|
||||
next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', '/')))
|
||||
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
folder.delete()
|
||||
messages.success(request, _(u'Folder: %s deleted successfully.') % folder)
|
||||
except Exception, e:
|
||||
messages.error(request, _(u'Folder: %(folder)s delete error: %(error)s') % {
|
||||
'folder': folder, 'error': e})
|
||||
|
||||
return HttpResponseRedirect(next)
|
||||
|
||||
context = {
|
||||
'object_name': _(u'folder'),
|
||||
'delete_view': True,
|
||||
'previous': previous,
|
||||
'next': next,
|
||||
'object': folder,
|
||||
'title': _(u'Are you sure you with to delete the folder: %s?') % folder
|
||||
}
|
||||
|
||||
return render_to_response('generic_confirm.html', context,
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def folder_view(request, folder_id):
|
||||
folder = get_object_or_404(Folder, pk=folder_id)
|
||||
|
||||
return render_to_response('generic_list.html', {
|
||||
'object_list': [folder_document.document for folder_document in folder.folderdocument_set.all()],
|
||||
'title': _(u'documents in folder: %s') % folder,
|
||||
'multi_select_as_buttons': True,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def folder_add_document(request, folder_id, document_id):
|
||||
folder = get_object_or_404(Folder, pk=folder_id)
|
||||
document = get_object_or_404(Document, pk=document_id)
|
||||
check_permissions(request.user, 'documents', [PERMISSION_DOCUMENT_VIEW])
|
||||
|
||||
if request.method == 'POST':
|
||||
previous = request.META.get('HTTP_REFERER', '/')
|
||||
|
||||
folder_document, created = FolderDocument.objects.get_or_create(folder=folder, document=document)
|
||||
if created:
|
||||
messages.success(request, _(u'Document: %(document)s added to folder: %(folder)s successfully.') % {
|
||||
'document': document, 'folder': folder})
|
||||
else:
|
||||
messages.warning(request, _(u'Document: %(document)s is already in folder: %(folder)s.') % {
|
||||
'document': document, 'folder': folder})
|
||||
|
||||
return HttpResponseRedirect(previous)
|
||||
@@ -138,6 +138,7 @@ INSTALLED_APPS = (
|
||||
'sentry.client.celery',
|
||||
'filesystem_serving',
|
||||
'storage',
|
||||
'folders',
|
||||
)
|
||||
|
||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
|
||||
1
urls.py
1
urls.py
@@ -10,6 +10,7 @@ urlpatterns = patterns('',
|
||||
(r'^', include('common.urls')),
|
||||
(r'^', include('main.urls')),
|
||||
(r'^documents/', include('documents.urls')),
|
||||
(r'^folders/', include('folders.urls')),
|
||||
(r'^filesystem_serving/', include('filesystem_serving.urls')),
|
||||
(r'^search/', include('dynamic_search.urls')),
|
||||
(r'^ocr/', include('ocr.urls')),
|
||||
|
||||
Reference in New Issue
Block a user