Remove concept of ownership from folders by removing the user field.

"Ownership" now is now determined by ACL of a folder, like the rest of the objects in the system.
This commit is contained in:
Roberto Rosario
2016-03-08 01:20:10 -04:00
parent 74fd47d86e
commit 1c65b389ee
11 changed files with 91 additions and 134 deletions

View File

@@ -8,5 +8,4 @@ from .models import Folder
@admin.register(Folder) @admin.register(Folder)
class FolderAdmin(admin.ModelAdmin): class FolderAdmin(admin.ModelAdmin):
filter_horizontal = ('documents',) filter_horizontal = ('documents',)
list_display = ('label', 'user', 'datetime_created') list_display = ('label', 'datetime_created')
list_filter = ('user',)

View File

@@ -67,7 +67,6 @@ class FoldersApp(MayanAppConfig):
SourceColumn( SourceColumn(
source=Folder, label=_('Created'), attribute='datetime_created' source=Folder, label=_('Created'), attribute='datetime_created'
) )
SourceColumn(source=Folder, label=_('User'), attribute='user')
SourceColumn( SourceColumn(
source=Folder, label=_('Documents'), source=Folder, label=_('Documents'),
func=lambda context: context['object'].get_document_count( func=lambda context: context['object'].get_document_count(

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
def merge_label_and_user(apps, schema_editor):
Folder = apps.get_model('folders', 'Folder')
for folder in Folder.objects.all():
folder.label = '{}-{}'.format(folder.user.username, folder.label)
folder.save()
class Migration(migrations.Migration):
dependencies = [
('folders', '0004_documentfolder'),
]
operations = [
migrations.RunPython(merge_label_and_user),
]

View File

@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('folders', '0005_auto_20160308_0437'),
]
operations = [
migrations.AlterUniqueTogether(
name='folder',
unique_together=set([('label',)]),
),
migrations.RemoveField(
model_name='folder',
name='user',
),
]

View File

@@ -1,6 +1,5 @@
from __future__ import absolute_import, unicode_literals from __future__ import absolute_import, unicode_literals
from django.contrib.auth.models import User
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import models from django.db import models
@@ -20,7 +19,6 @@ class Folder(models.Model):
label = models.CharField( label = models.CharField(
db_index=True, max_length=128, verbose_name=_('Label') db_index=True, max_length=128, verbose_name=_('Label')
) )
user = models.ForeignKey(User, verbose_name=_('User'))
datetime_created = models.DateTimeField( datetime_created = models.DateTimeField(
auto_now_add=True, verbose_name=_('Datetime created') auto_now_add=True, verbose_name=_('Datetime created')
) )
@@ -42,7 +40,7 @@ class Folder(models.Model):
class Meta: class Meta:
ordering = ('label',) ordering = ('label',)
unique_together = ('label', 'user') unique_together = ('label', )
verbose_name = _('Folder') verbose_name = _('Folder')
verbose_name_plural = _('Folders') verbose_name_plural = _('Folders')

View File

@@ -18,16 +18,14 @@ class FolderSerializer(serializers.HyperlinkedModelSerializer):
view_name='rest_api:folder-document-list' view_name='rest_api:folder-document-list'
) )
documents_count = serializers.SerializerMethodField() documents_count = serializers.SerializerMethodField()
user = UserSerializer(read_only=True)
class Meta: class Meta:
extra_kwargs = { extra_kwargs = {
'url': {'view_name': 'rest_api:folder-detail'}, 'url': {'view_name': 'rest_api:folder-detail'},
'user': {'view_name': 'rest_api:user-detail'}
} }
fields = ( fields = (
'datetime_created', 'documents', 'documents_count', 'id', 'label', 'datetime_created', 'documents', 'documents_count', 'id', 'label',
'url', 'user' 'url'
) )
model = Folder model = Folder
@@ -41,7 +39,6 @@ class NewFolderSerializer(serializers.Serializer):
def create(self, validated_data): def create(self, validated_data):
try: try:
data = validated_data.copy() data = validated_data.copy()
data.update({'user': self.context['request'].user})
return Folder.objects.create(**data) return Folder.objects.create(**data)
except Exception as exception: except Exception as exception:
raise ValidationError(exception) raise ValidationError(exception)

View File

@@ -42,12 +42,9 @@ class FolderAPITestCase(APITestCase):
self.assertEqual(Folder.objects.count(), 1) self.assertEqual(Folder.objects.count(), 1)
self.assertEqual(folder.label, TEST_FOLDER_LABEL) self.assertEqual(folder.label, TEST_FOLDER_LABEL)
self.assertEqual(folder.user, self.admin_user)
def test_folder_delete(self): def test_folder_delete(self):
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.admin_user
)
self.client.delete( self.client.delete(
reverse('rest_api:folder-detail', args=(folder.pk,)) reverse('rest_api:folder-detail', args=(folder.pk,))
@@ -56,9 +53,7 @@ class FolderAPITestCase(APITestCase):
self.assertEqual(Folder.objects.count(), 0) self.assertEqual(Folder.objects.count(), 0)
def test_folder_edit(self): def test_folder_edit(self):
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.admin_user
)
self.client.put( self.client.put(
reverse('rest_api:folder-detail', args=(folder.pk,)), reverse('rest_api:folder-detail', args=(folder.pk,)),
@@ -71,9 +66,7 @@ class FolderAPITestCase(APITestCase):
@override_settings(OCR_AUTO_OCR=False) @override_settings(OCR_AUTO_OCR=False)
def test_folder_add_document(self): def test_folder_add_document(self):
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.admin_user
)
document_type = DocumentType.objects.create( document_type = DocumentType.objects.create(
label=TEST_DOCUMENT_TYPE label=TEST_DOCUMENT_TYPE
@@ -93,9 +86,7 @@ class FolderAPITestCase(APITestCase):
@override_settings(OCR_AUTO_OCR=False) @override_settings(OCR_AUTO_OCR=False)
def test_folder_remove_document(self): def test_folder_remove_document(self):
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.admin_user
)
document_type = DocumentType.objects.create( document_type = DocumentType.objects.create(
label=TEST_DOCUMENT_TYPE label=TEST_DOCUMENT_TYPE

View File

@@ -12,6 +12,8 @@ from user_management.tests.literals import (
from ..models import Folder from ..models import Folder
from .literals import TEST_FOLDER_LABEL
class FolderTestCase(TestCase): class FolderTestCase(TestCase):
def setUp(self): def setUp(self):
@@ -32,23 +34,21 @@ class FolderTestCase(TestCase):
def tearDown(self): def tearDown(self):
self.document_type.delete() self.document_type.delete()
def test_creation_of_folder(self): def test_folder_creation(self):
folder = Folder.objects.create(label='test', user=self.user) folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
self.assertEqual(Folder.objects.all().count(), 1) self.assertEqual(Folder.objects.all().count(), 1)
self.assertEqual(list(Folder.objects.all()), [folder]) self.assertEqual(list(Folder.objects.all()), [folder])
folder.delete()
def test_addition_of_documents(self): def test_addition_of_documents(self):
folder = Folder.objects.create(label='test', user=self.user) folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
folder.documents.add(self.document) folder.documents.add(self.document)
self.assertEqual(folder.documents.count(), 1) self.assertEqual(folder.documents.count(), 1)
self.assertEqual(list(folder.documents.all()), [self.document]) self.assertEqual(list(folder.documents.all()), [self.document])
folder.delete()
def test_addition_and_deletion_of_documents(self): def test_addition_and_deletion_of_documents(self):
folder = Folder.objects.create(label='test', user=self.user) folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
folder.documents.add(self.document) folder.documents.add(self.document)
self.assertEqual(folder.documents.count(), 1) self.assertEqual(folder.documents.count(), 1)
@@ -58,5 +58,3 @@ class FolderTestCase(TestCase):
self.assertEqual(folder.documents.count(), 0) self.assertEqual(folder.documents.count(), 0)
self.assertEqual(list(folder.documents.all()), []) self.assertEqual(list(folder.documents.all()), [])
folder.delete()

View File

@@ -43,12 +43,9 @@ class FolderViewTestCase(GenericDocumentViewTestCase):
self.assertContains(response, text='created', status_code=200) self.assertContains(response, text='created', status_code=200)
self.assertEqual(Folder.objects.count(), 1) self.assertEqual(Folder.objects.count(), 1)
self.assertEqual(Folder.objects.first().label, TEST_FOLDER_LABEL) self.assertEqual(Folder.objects.first().label, TEST_FOLDER_LABEL)
self.assertEqual(Folder.objects.first().user, self.user)
def test_folder_create_duplicate_view_with_permission(self): def test_folder_create_duplicate_view_with_permission(self):
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.user
)
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD) self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
@@ -62,16 +59,14 @@ class FolderViewTestCase(GenericDocumentViewTestCase):
} }
) )
self.assertContains(response, text='Error', status_code=200) self.assertContains(response, text='exists', status_code=200)
self.assertEqual(Folder.objects.count(), 1) self.assertEqual(Folder.objects.count(), 1)
self.assertEqual(Folder.objects.first().pk, folder.pk) self.assertEqual(Folder.objects.first().pk, folder.pk)
def test_folder_delete_view_no_permission(self): def test_folder_delete_view_no_permission(self):
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD) self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.admin_user
)
response = self.post('folders:folder_delete', args=(folder.pk,)) response = self.post('folders:folder_delete', args=(folder.pk,))
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
@@ -84,9 +79,7 @@ class FolderViewTestCase(GenericDocumentViewTestCase):
permission_folder_delete.stored_permission permission_folder_delete.stored_permission
) )
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.admin_user
)
response = self.post( response = self.post(
'folders:folder_delete', args=(folder.pk,), follow=True 'folders:folder_delete', args=(folder.pk,), follow=True
@@ -98,9 +91,7 @@ class FolderViewTestCase(GenericDocumentViewTestCase):
def test_folder_edit_view_no_permission(self): def test_folder_edit_view_no_permission(self):
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD) self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.user
)
response = self.post( response = self.post(
'folders:folder_edit', args=(folder.pk,), data={ 'folders:folder_edit', args=(folder.pk,), data={
@@ -118,9 +109,7 @@ class FolderViewTestCase(GenericDocumentViewTestCase):
permission_folder_edit.stored_permission permission_folder_edit.stored_permission
) )
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.user
)
response = self.post( response = self.post(
'folders:folder_edit', args=(folder.pk,), data={ 'folders:folder_edit', args=(folder.pk,), data={
@@ -129,7 +118,7 @@ class FolderViewTestCase(GenericDocumentViewTestCase):
) )
folder = Folder.objects.get(pk=folder.pk) folder = Folder.objects.get(pk=folder.pk)
self.assertContains(response, text='saved', status_code=200) self.assertContains(response, text='update', status_code=200)
self.assertEqual(folder.label, TEST_FOLDER_EDITED_LABEL) self.assertEqual(folder.label, TEST_FOLDER_EDITED_LABEL)
def test_folder_add_document_view_no_permission(self): def test_folder_add_document_view_no_permission(self):
@@ -137,9 +126,7 @@ class FolderViewTestCase(GenericDocumentViewTestCase):
self.role.permissions.add(permission_folder_view.stored_permission) self.role.permissions.add(permission_folder_view.stored_permission)
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.admin_user
)
response = self.post( response = self.post(
'folders:folder_add_document', args=(self.document.pk,), data={ 'folders:folder_add_document', args=(self.document.pk,), data={
@@ -163,9 +150,7 @@ class FolderViewTestCase(GenericDocumentViewTestCase):
permission_document_view.stored_permission permission_document_view.stored_permission
) )
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.admin_user
)
response = self.post( response = self.post(
'folders:folder_add_document', args=(self.document.pk,), data={ 'folders:folder_add_document', args=(self.document.pk,), data={
@@ -185,9 +170,7 @@ class FolderViewTestCase(GenericDocumentViewTestCase):
self.role.permissions.add(permission_folder_view.stored_permission) self.role.permissions.add(permission_folder_view.stored_permission)
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.admin_user
)
response = self.post( response = self.post(
'folders:folder_add_multiple_documents', data={ 'folders:folder_add_multiple_documents', data={
@@ -207,9 +190,7 @@ class FolderViewTestCase(GenericDocumentViewTestCase):
permission_folder_add_document.stored_permission permission_folder_add_document.stored_permission
) )
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.admin_user
)
response = self.post( response = self.post(
'folders:folder_add_multiple_documents', data={ 'folders:folder_add_multiple_documents', data={
@@ -227,9 +208,7 @@ class FolderViewTestCase(GenericDocumentViewTestCase):
def test_folder_remove_document_view_no_permission(self): def test_folder_remove_document_view_no_permission(self):
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD) self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.user
)
folder.documents.add(self.document) folder.documents.add(self.document)
@@ -254,9 +233,7 @@ class FolderViewTestCase(GenericDocumentViewTestCase):
permission_folder_remove_document.stored_permission permission_folder_remove_document.stored_permission
) )
folder = Folder.objects.create( folder = Folder.objects.create(label=TEST_FOLDER_LABEL)
label=TEST_FOLDER_LABEL, user=self.user
)
folder.documents.add(self.document) folder.documents.add(self.document)
self.assertEqual(folder.documents.count(), 1) self.assertEqual(folder.documents.count(), 1)

View File

@@ -7,8 +7,8 @@ from .api_views import (
APIFolderDocumentView, APIFolderListView, APIFolderView APIFolderDocumentView, APIFolderListView, APIFolderView
) )
from .views import ( from .views import (
DocumentFolderListView, FolderCreateView, FolderDetailView, FolderEditView, DocumentFolderListView, FolderCreateView, FolderDeleteView,
FolderListView FolderDetailView, FolderEditView, FolderListView
) )
urlpatterns = patterns( urlpatterns = patterns(
@@ -17,7 +17,8 @@ urlpatterns = patterns(
url(r'^create/$', FolderCreateView.as_view(), name='folder_create'), url(r'^create/$', FolderCreateView.as_view(), name='folder_create'),
url(r'^(?P<pk>\d+)/edit/$', FolderEditView.as_view(), name='folder_edit'), url(r'^(?P<pk>\d+)/edit/$', FolderEditView.as_view(), name='folder_edit'),
url( url(
r'^(?P<folder_id>\d+)/delete/$', 'folder_delete', name='folder_delete' r'^(?P<pk>\d+)/delete/$', FolderDeleteView.as_view(),
name='folder_delete'
), ),
url(r'^(?P<pk>\d+)/$', FolderDetailView.as_view(), name='folder_view'), url(r'^(?P<pk>\d+)/$', FolderDetailView.as_view(), name='folder_view'),
url( url(

View File

@@ -13,7 +13,8 @@ from django.utils.translation import ugettext_lazy as _, ungettext
from acls.models import AccessControlList from acls.models import AccessControlList
from common.views import ( from common.views import (
SingleObjectCreateView, SingleObjectEditView, SingleObjectListView SingleObjectCreateView, SingleObjectDeleteView, SingleObjectEditView,
SingleObjectListView
) )
from documents.permissions import permission_document_view from documents.permissions import permission_document_view
from documents.models import Document from documents.models import Document
@@ -40,11 +41,13 @@ class FolderEditView(SingleObjectEditView):
def get_extra_context(self): def get_extra_context(self):
return { return {
'object': self.get_object(), 'object': self.get_object(),
'object_name': _('Folder'),
'title': _('Edit folder: %s') % self.get_object(), 'title': _('Edit folder: %s') % self.get_object(),
} }
class FolderListView(SingleObjectListView): class FolderListView(SingleObjectListView):
model = Folder
object_permission = permission_folder_view object_permission = permission_folder_view
def get_extra_context(self): def get_extra_context(self):
@@ -53,81 +56,30 @@ class FolderListView(SingleObjectListView):
'title': _('Folders'), 'title': _('Folders'),
} }
def get_folder_queryset(self):
return Folder.objects.all()
def get_queryset(self):
self.queryset = self.get_folder_queryset()
return super(FolderListView, self).get_queryset()
class FolderCreateView(SingleObjectCreateView): class FolderCreateView(SingleObjectCreateView):
fields = ('label',) fields = ('label',)
model = Folder model = Folder
view_permission = permission_folder_create view_permission = permission_folder_create
def form_valid(self, form):
try:
Folder.objects.get(
label=form.cleaned_data['label'], user=self.request.user
)
except Folder.DoesNotExist:
instance = form.save(commit=False)
instance.user = self.request.user
instance.save()
return super(FolderCreateView, self).form_valid(form)
else:
messages.error(
self.request,
_(
'A folder named: %s, already exists.'
) % form.cleaned_data['label']
)
return super(FolderCreateView, self).form_invalid(form)
def get_extra_context(self): def get_extra_context(self):
return { return {
'object_name': _('Folder'),
'title': _('Create folder'), 'title': _('Create folder'),
} }
def folder_delete(request, folder_id): class FolderDeleteView(SingleObjectDeleteView):
folder = get_object_or_404(Folder, pk=folder_id) model = Folder
object_permission = permission_folder_delete
post_action_redirect = reverse_lazy('folders:folder_list')
try: def get_extra_context(self):
Permission.check_permissions(request.user, (permission_folder_delete,)) return {
except PermissionDenied: 'object_name': _('Folder'),
AccessControlList.objects.check_access( 'object': self.get_object(),
permission_folder_delete, request.user, folder 'title': _('Delete the folder: %s?') % self.get_object(),
) }
post_action_redirect = reverse('folders:folder_list')
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
next = request.POST.get('next', request.GET.get('next', post_action_redirect if post_action_redirect else request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
if request.method == 'POST':
try:
folder.delete()
messages.success(request, _('Folder: %s deleted successfully.') % folder)
except Exception as exception:
messages.error(request, _('Folder: %(folder)s delete error: %(error)s') % {
'folder': folder, 'error': exception})
return HttpResponseRedirect(next)
context = {
'delete_view': True,
'previous': previous,
'next': next,
'object': folder,
'title': _('Delete the folder: %s?') % folder,
}
return render_to_response(
'appearance/generic_confirm.html', context,
context_instance=RequestContext(request)
)
class FolderDetailView(DocumentListView): class FolderDetailView(DocumentListView):
@@ -260,7 +212,7 @@ class DocumentFolderListView(FolderListView):
'title': _('Folders containing document: %s') % self.document, 'title': _('Folders containing document: %s') % self.document,
} }
def get_folder_queryset(self): def get_queryset(self):
return self.document.document_folders().all() return self.document.document_folders().all()