From debec7b4a2c1b4af4ba5500688a777e52fe25e71 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 24 Jun 2016 04:22:49 -0400 Subject: [PATCH] Update the django_gpg app to support organizations. --- mayan/apps/django_gpg/managers.py | 5 ++ .../migrations/0006_auto_20160510_0025.py | 5 +- .../migrations/0007_key_organization.py | 21 +++++ mayan/apps/django_gpg/models.py | 16 ++-- mayan/apps/django_gpg/tests/test_models.py | 5 +- .../tests/test_organization_views.py | 83 +++++++++++++++++++ mayan/apps/django_gpg/tests/test_views.py | 4 +- mayan/apps/django_gpg/views.py | 28 +++++-- 8 files changed, 147 insertions(+), 20 deletions(-) create mode 100644 mayan/apps/django_gpg/migrations/0007_key_organization.py create mode 100644 mayan/apps/django_gpg/tests/test_organization_views.py diff --git a/mayan/apps/django_gpg/managers.py b/mayan/apps/django_gpg/managers.py index 4247529e49..462b7b7def 100644 --- a/mayan/apps/django_gpg/managers.py +++ b/mayan/apps/django_gpg/managers.py @@ -10,6 +10,7 @@ import gnupg from django.db import models from common.utils import mkdtemp, mkstemp +from organizations.managers import CurrentOrganizationManager from .classes import KeyStub, SignatureVerification from .exceptions import ( @@ -193,3 +194,7 @@ class KeyManager(models.Manager): else: logger.debug('file not signed') raise VerificationError('File not signed') + + +class OrganizationKeyManager(KeyManager, CurrentOrganizationManager): + pass diff --git a/mayan/apps/django_gpg/migrations/0006_auto_20160510_0025.py b/mayan/apps/django_gpg/migrations/0006_auto_20160510_0025.py index b2a65a9abd..be851a2296 100644 --- a/mayan/apps/django_gpg/migrations/0006_auto_20160510_0025.py +++ b/mayan/apps/django_gpg/migrations/0006_auto_20160510_0025.py @@ -14,6 +14,9 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='key', name='key_data', - field=models.TextField(help_text='ASCII armored version of the key.', verbose_name='Key data'), + field=models.TextField( + help_text='ASCII armored version of the key.', + verbose_name='Key data' + ), ), ] diff --git a/mayan/apps/django_gpg/migrations/0007_key_organization.py b/mayan/apps/django_gpg/migrations/0007_key_organization.py new file mode 100644 index 0000000000..baf7d6edb7 --- /dev/null +++ b/mayan/apps/django_gpg/migrations/0007_key_organization.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import organizations.shortcuts + + +class Migration(migrations.Migration): + + dependencies = [ + ('organizations', '0002_add_data_default_organization'), + ('django_gpg', '0006_auto_20160510_0025'), + ] + + operations = [ + migrations.AddField( + model_name='key', + name='organization', + field=models.ForeignKey(default=organizations.shortcuts.get_current_organization, to='organizations.Organization'), + ), + ] diff --git a/mayan/apps/django_gpg/models.py b/mayan/apps/django_gpg/models.py index 075d11e249..ae53507737 100644 --- a/mayan/apps/django_gpg/models.py +++ b/mayan/apps/django_gpg/models.py @@ -14,6 +14,8 @@ from django.utils.encoding import python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ from common.utils import mkdtemp +from organizations.models import Organization +from organizations.shortcuts import get_current_organization from .exceptions import NeedPassphrase, PassphraseError from .literals import ( @@ -21,7 +23,7 @@ from .literals import ( ERROR_MSG_GOOD_PASSPHRASE, KEY_TYPE_CHOICES, KEY_TYPE_SECRET, OUTPUT_MESSAGE_CONTAINS_PRIVATE_KEY ) -from .managers import KeyManager +from .managers import KeyManager, OrganizationKeyManager from .settings import setting_gpg_path logger = logging.getLogger(__name__) @@ -44,6 +46,9 @@ def gpg_command(function): @python_2_unicode_compatible class Key(models.Model): + organization = models.ForeignKey( + Organization, default=get_current_organization + ) key_data = models.TextField( help_text=_('ASCII armored version of the key.'), verbose_name=_('Key data') @@ -72,11 +77,15 @@ class Key(models.Model): ) objects = KeyManager() + on_organization = OrganizationKeyManager() class Meta: verbose_name = _('Key') verbose_name_plural = _('Keys') + def __str__(self): + return '{} - {}'.format(self.key_id, self.user_id) + def clean(self): def import_key(gpg): return gpg.import_keys(key_data=self.key_data) @@ -86,7 +95,7 @@ class Key(models.Model): if not import_results.count: raise ValidationError(_('Invalid key data')) - if Key.objects.filter(fingerprint=import_results.fingerprints[0]).exists(): + if Key.on_organization.filter(fingerprint=import_results.fingerprints[0]).exists(): raise ValidationError(_('Key already exists.')) def get_absolute_url(self): @@ -123,9 +132,6 @@ class Key(models.Model): super(Key, self).save(*args, **kwargs) - def __str__(self): - return '{} - {}'.format(self.key_id, self.user_id) - def sign_file(self, file_object, passphrase=None, clearsign=False, detached=False, binary=False, output=None): # WARNING: using clearsign=True and subsequent decryption corrupts the # file. Appears to be a problem in python-gnupg or gpg itself. diff --git a/mayan/apps/django_gpg/tests/test_models.py b/mayan/apps/django_gpg/tests/test_models.py index 019fe4ba7c..291baca14b 100644 --- a/mayan/apps/django_gpg/tests/test_models.py +++ b/mayan/apps/django_gpg/tests/test_models.py @@ -5,9 +5,8 @@ import StringIO import gnupg import mock -from django.test import TestCase - from common.utils import TemporaryFile +from organizations.tests import OrganizationTestCase from ..exceptions import ( DecryptionError, KeyDoesNotExist, NeedPassphrase, PassphraseError, @@ -44,7 +43,7 @@ def mock_recv_keys(self, keyserver, *keyids): return ImportResult() -class KeyTestCase(TestCase): +class KeyTestCase(OrganizationTestCase): def test_key_instance_creation(self): # Creating a Key instance is analogous to importing a key key = Key.objects.create(key_data=TEST_KEY_DATA) diff --git a/mayan/apps/django_gpg/tests/test_organization_views.py b/mayan/apps/django_gpg/tests/test_organization_views.py new file mode 100644 index 0000000000..fe7384cd82 --- /dev/null +++ b/mayan/apps/django_gpg/tests/test_organization_views.py @@ -0,0 +1,83 @@ +from __future__ import unicode_literals + +from django.test import override_settings + +from django_downloadview.test import assert_download_response + +from organizations.tests.test_organization_views import OrganizationViewTestCase + +from ..models import Key + +from .literals import TEST_KEY_DATA, TEST_KEY_FINGERPRINT + + +@override_settings(OCR_AUTO_OCR=False) +class OrganizationKeyViewsTestCase(OrganizationViewTestCase): + def create_key(self): + with self.settings(ORGANIZATION_ID=self.organization_a.pk): + self.key = Key.on_organization.create(key_data=TEST_KEY_DATA) + + def test_key_delete_view(self): + self.create_key() + + with self.settings(ORGANIZATION_ID=self.organization_b.pk): + response = self.post( + 'django_gpg:key_delete', + args=(self.key.pk,), follow=True + ) + self.assertEqual(response.status_code, 404) + + def test_key_download_view(self): + self.create_key() + + with self.settings(ORGANIZATION_ID=self.organization_b.pk): + response = self.get( + viewname='django_gpg:key_download', args=(self.key.pk,) + ) + + self.assertEqual(response.status_code, 404) + + with self.settings(ORGANIZATION_ID=self.organization_a.pk): + response = self.get( + viewname='django_gpg:key_download', args=(self.key.pk,) + ) + + assert_download_response( + self, response=response, content=self.key.key_data, + basename=self.key.key_id, + ) + + def test_key_upload_view(self): + with self.settings(ORGANIZATION_ID=self.organization_a.pk): + response = self.post( + viewname='django_gpg:key_upload', + data={'key_data': TEST_KEY_DATA}, follow=True + ) + self.assertContains(response, 'created', status_code=200) + self.assertEqual(Key.on_organization.count(), 1) + self.assertEqual( + Key.on_organization.first().fingerprint, TEST_KEY_FINGERPRINT + ) + + with self.settings(ORGANIZATION_ID=self.organization_b.pk): + self.assertEqual(Key.on_organization.count(), 0) + + with self.settings(ORGANIZATION_ID=self.organization_a.pk): + self.assertEqual(Key.on_organization.count(), 1) + + def test_key_private_list_view(self): + self.create_key() + + with self.settings(ORGANIZATION_ID=self.organization_b.pk): + response = self.get(viewname='django_gpg:key_private_list') + + self.assertNotContains( + response, text=self.key.key_id, status_code=200 + ) + + with self.settings(ORGANIZATION_ID=self.organization_a.pk): + response = self.get(viewname='django_gpg:key_private_list') + + self.assertContains( + response, text=self.key.key_id, status_code=200 + ) diff --git a/mayan/apps/django_gpg/tests/test_views.py b/mayan/apps/django_gpg/tests/test_views.py index 7f65c1329e..196b0c7c14 100644 --- a/mayan/apps/django_gpg/tests/test_views.py +++ b/mayan/apps/django_gpg/tests/test_views.py @@ -3,9 +3,7 @@ from __future__ import absolute_import, unicode_literals from django_downloadview.test import assert_download_response from common.tests.test_views import GenericViewTestCase -from user_management.tests import ( - TEST_USER_USERNAME, TEST_USER_PASSWORD -) +from user_management.tests import TEST_USER_USERNAME, TEST_USER_PASSWORD from ..models import Key from ..permissions import permission_key_download, permission_key_upload diff --git a/mayan/apps/django_gpg/views.py b/mayan/apps/django_gpg/views.py index 4e6591640a..4c0e75b909 100644 --- a/mayan/apps/django_gpg/views.py +++ b/mayan/apps/django_gpg/views.py @@ -25,7 +25,6 @@ logger = logging.getLogger(__name__) class KeyDeleteView(SingleObjectDeleteView): - model = Key object_permission = permission_key_delete def get_post_action_redirect(self): @@ -37,10 +36,12 @@ class KeyDeleteView(SingleObjectDeleteView): def get_extra_context(self): return {'title': _('Delete key: %s') % self.get_object()} + def get_queryset(self): + return Key.on_organization.all() + class KeyDetailView(SingleObjectDetailView): form_class = KeyDetailForm - model = Key object_permission = permission_key_view def get_extra_context(self): @@ -48,9 +49,11 @@ class KeyDetailView(SingleObjectDetailView): 'title': _('Details for key: %s') % self.get_object(), } + def get_queryset(self): + return Key.on_organization.all() + class KeyDownloadView(SingleObjectDownloadView): - model = Key object_permission = permission_key_download def get_file(self): @@ -58,6 +61,9 @@ class KeyDownloadView(SingleObjectDownloadView): return ContentFile(key.key_data, name=key.key_id) + def get_queryset(self): + return Key.on_organization.all() + class KeyReceive(ConfirmView): post_action_redirect = reverse_lazy('django_gpg:key_public_list') @@ -71,7 +77,7 @@ class KeyReceive(ConfirmView): def view_action(self): try: - Key.objects.receive_key(key_id=self.kwargs['key_id']) + Key.on_organization.receive_key(key_id=self.kwargs['key_id']) except Exception as exception: messages.error( self.request, @@ -122,14 +128,13 @@ class KeyQueryResultView(SingleObjectListView): def get_queryset(self): term = self.request.GET.get('term') if term: - return Key.objects.search(query=term) + return Key.on_organization.search(query=term) else: return () class KeyUploadView(SingleObjectCreateView): fields = ('key_data',) - model = Key post_action_redirect = reverse_lazy('django_gpg:key_public_list') view_permission = permission_key_upload @@ -138,10 +143,12 @@ class KeyUploadView(SingleObjectCreateView): 'title': _('Upload new key'), } + def get_queryset(self): + return Key.on_organization.all() + class PublicKeyListView(SingleObjectListView): object_permission = permission_key_view - queryset = Key.objects.public_keys() def get_extra_context(self): return { @@ -149,13 +156,18 @@ class PublicKeyListView(SingleObjectListView): 'title': _('Public keys') } + def get_queryset(self): + return Key.on_organization.public_keys() + class PrivateKeyListView(SingleObjectListView): object_permission = permission_key_view - queryset = Key.objects.private_keys() def get_extra_context(self): return { 'hide_object': True, 'title': _('Private keys') } + + def get_queryset(self): + return Key.on_organization.private_keys()