diff --git a/mayan/apps/django_gpg/apps.py b/mayan/apps/django_gpg/apps.py index 7490aa6d21..791df1c8be 100644 --- a/mayan/apps/django_gpg/apps.py +++ b/mayan/apps/django_gpg/apps.py @@ -13,11 +13,12 @@ from navigation import SourceColumn from .classes import KeyStub from .links import ( - link_key_delete, link_key_detail, link_key_query, link_key_receive, - link_key_setup, link_private_keys, link_public_keys + link_key_delete, link_key_detail, link_key_download, link_key_query, + link_key_receive, link_key_setup, link_private_keys, link_public_keys ) from .permissions import ( - permission_key_delete, permission_key_sign, permission_key_view + permission_key_delete, permission_key_download, permission_key_sign, + permission_key_view ) @@ -35,7 +36,8 @@ class DjangoGPGApp(MayanAppConfig): ModelPermission.register( model=Key, permissions=( permission_acl_edit, permission_acl_view, - permission_key_delete, permission_key_sign, permission_key_view + permission_key_delete, permission_key_download, + permission_key_sign, permission_key_view ) ) @@ -89,7 +91,8 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. menu_object.bind_links(links=(link_key_receive,), sources=(KeyStub,)) menu_object.bind_links( - links=(link_acl_list, link_key_delete,), sources=(Key,) + links=(link_acl_list, link_key_delete, link_key_download,), + sources=(Key,) ) menu_setup.bind_links(links=(link_key_setup,)) menu_facet.bind_links( diff --git a/mayan/apps/django_gpg/links.py b/mayan/apps/django_gpg/links.py index 3a6cda3ee0..22771fe351 100644 --- a/mayan/apps/django_gpg/links.py +++ b/mayan/apps/django_gpg/links.py @@ -5,8 +5,8 @@ from django.utils.translation import ugettext_lazy as _ from navigation import Link from .permissions import ( - permission_key_delete, permission_key_receive, permission_key_view, - permission_keyserver_query + permission_key_delete, permission_key_download, permission_key_receive, + permission_key_view, permission_keyserver_query ) link_private_keys = Link( @@ -25,6 +25,10 @@ link_key_detail = Link( permissions=(permission_key_view,), text=_('Details'), view='django_gpg:key_detail', args=('resolved_object.pk',) ) +link_key_download = Link( + permissions=(permission_key_download,), text=_('Download'), + view='django_gpg:key_download', args=('resolved_object.pk',) +) link_key_query = Link( permissions=(permission_keyserver_query,), text=_('Query keyservers'), view='django_gpg:key_query' diff --git a/mayan/apps/django_gpg/permissions.py b/mayan/apps/django_gpg/permissions.py index 5603010405..2b224a5348 100644 --- a/mayan/apps/django_gpg/permissions.py +++ b/mayan/apps/django_gpg/permissions.py @@ -9,6 +9,9 @@ namespace = PermissionNamespace('django_gpg', _('Key management')) permission_key_delete = namespace.add_permission( name='key_delete', label=_('Delete keys') ) +permission_key_download = namespace.add_permission( + name='key_download', label=_('Download keys') +) permission_key_receive = namespace.add_permission( name='key_receive', label=_('Import keys from keyservers') ) diff --git a/mayan/apps/django_gpg/tests/test_views.py b/mayan/apps/django_gpg/tests/test_views.py new file mode 100644 index 0000000000..ac281526ca --- /dev/null +++ b/mayan/apps/django_gpg/tests/test_views.py @@ -0,0 +1,50 @@ +from __future__ import absolute_import, unicode_literals + +from django.core.files import File + +from django_downloadview.test import assert_download_response + +from documents.models import Document, DocumentVersion +from documents.tests.literals import TEST_DOCUMENT_PATH +from documents.tests.test_views import GenericDocumentViewTestCase +from user_management.tests import ( + TEST_USER_USERNAME, TEST_USER_PASSWORD +) + +from ..models import Key +from ..permissions import permission_key_download + +from .literals import ( + TEST_DETACHED_SIGNATURE, TEST_FILE, TEST_KEY_DATA, TEST_KEY_FINGERPRINT, + TEST_KEY_PASSPHRASE, TEST_SEARCH_FINGERPRINT, TEST_SEARCH_UID, + TEST_SIGNED_FILE, TEST_SIGNED_FILE_CONTENT +) + + +class KeyViewTestCase(GenericDocumentViewTestCase): + def test_key_download_view_no_permission(self): + key = Key.objects.create(key_data=TEST_KEY_DATA) + + self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD) + + response = self.get( + viewname='django_gpg:key_download', args=(key.pk,) + ) + + self.assertEqual(response.status_code, 403) + + def test_key_download_view_with_permission(self): + key = Key.objects.create(key_data=TEST_KEY_DATA) + + self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD) + + self.role.permissions.add(permission_key_download.stored_permission) + + response = self.get( + viewname='django_gpg:key_download', args=(key.pk,) + ) + + assert_download_response( + self, response=response, content=key.key_data, + basename=key.key_id, + ) diff --git a/mayan/apps/django_gpg/urls.py b/mayan/apps/django_gpg/urls.py index 47126ee413..e9530136fb 100644 --- a/mayan/apps/django_gpg/urls.py +++ b/mayan/apps/django_gpg/urls.py @@ -3,8 +3,8 @@ from __future__ import unicode_literals from django.conf.urls import patterns, url from .views import ( - KeyDeleteView, KeyDetailView, KeyQueryView, KeyQueryResultView, KeyReceive, - PrivateKeyListView, PublicKeyListView + KeyDeleteView, KeyDetailView, KeyDownloadView, KeyQueryView, + KeyQueryResultView, KeyReceive, PrivateKeyListView, PublicKeyListView ) urlpatterns = patterns( @@ -13,7 +13,11 @@ urlpatterns = patterns( r'^(?P\d+)/$', KeyDetailView.as_view(), name='key_detail' ), url( - r'^delete/(?P\d+)/$', KeyDeleteView.as_view(), name='key_delete' + r'^(?P\d+)/delete/$', KeyDeleteView.as_view(), name='key_delete' + ), + url( + r'^(?P\d+)/download/$', KeyDownloadView.as_view(), + name='key_download' ), url( r'^list/private/$', PrivateKeyListView.as_view(), diff --git a/mayan/apps/django_gpg/views.py b/mayan/apps/django_gpg/views.py index bc0c602265..8a40f822d0 100644 --- a/mayan/apps/django_gpg/views.py +++ b/mayan/apps/django_gpg/views.py @@ -3,20 +3,21 @@ from __future__ import absolute_import, unicode_literals import logging from django.contrib import messages +from django.core.files.base import ContentFile from django.core.urlresolvers import reverse, reverse_lazy from django.utils.translation import ugettext_lazy as _ from common.generics import ( ConfirmView, SimpleView, SingleObjectDeleteView, SingleObjectDetailView, - SingleObjectListView + SingleObjectDownloadView, SingleObjectListView ) from .forms import KeyDetailForm, KeySearchForm from .literals import KEY_TYPE_PUBLIC from .models import Key from .permissions import ( - permission_key_delete, permission_key_receive, permission_key_view, - permission_keyserver_query + permission_key_delete, permission_key_download, permission_key_receive, + permission_key_view, permission_keyserver_query ) logger = logging.getLogger(__name__) @@ -47,6 +48,16 @@ class KeyDetailView(SingleObjectDetailView): } +class KeyDownloadView(SingleObjectDownloadView): + model = Key + object_permission = permission_key_download + + def get_file(self): + key = self.get_object() + + return ContentFile(key.key_data, name=key.key_id) + + class KeyReceive(ConfirmView): post_action_redirect = reverse_lazy('django_gpg:key_public_list') view_permission = permission_key_receive