Convert sources app to use organizations.

This commit is contained in:
Roberto Rosario
2016-05-30 15:37:58 -04:00
parent 2dcad10805
commit db1673dd0a
13 changed files with 263 additions and 83 deletions

View File

@@ -40,7 +40,7 @@ class APIStagingSourceListView(generics.ListAPIView):
""" """
serializer_class = StagingFolderSerializer serializer_class = StagingFolderSerializer
queryset = StagingFolderSource.objects.all() queryset = StagingFolderSource.on_organization.all()
class APIStagingSourceView(generics.RetrieveAPIView): class APIStagingSourceView(generics.RetrieveAPIView):
@@ -48,7 +48,7 @@ class APIStagingSourceView(generics.RetrieveAPIView):
Details of the selected staging folders and the files it contains. Details of the selected staging folders and the files it contains.
""" """
serializer_class = StagingFolderSerializer serializer_class = StagingFolderSerializer
queryset = StagingFolderSource.objects.all() queryset = StagingFolderSource.on_organization.all()
class APIStagingSourceFileImageView(generics.GenericAPIView): class APIStagingSourceFileImageView(generics.GenericAPIView):

View File

@@ -56,7 +56,7 @@ class SourcesApp(MayanAppConfig):
'feed to Mayan EDMS, create at least a web form source to ' 'feed to Mayan EDMS, create at least a web form source to '
'be able to upload documents from a browser.' 'be able to upload documents from a browser.'
), ),
condition=lambda: not Source.objects.exists(), condition=lambda: not Source.on_organization.exists(),
view='sources:setup_source_list' view='sources:setup_source_list'
) )

View File

@@ -9,8 +9,8 @@ from django.utils.translation import ugettext_lazy as _
from documents.forms import DocumentForm from documents.forms import DocumentForm
from .models import ( from .models import (
IMAPEmail, POP3Email, StagingFolderSource, WebFormSource, IMAPEmail, POP3Email, StagingFolderSource, WatchFolderSource,
WatchFolderSource WebFormSource
) )
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -80,6 +80,9 @@ class WebFormUploadFormHTML5(WebFormUploadForm):
class WebFormSetupForm(forms.ModelForm): class WebFormSetupForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(WebFormSetupForm, self).__init__(*args, **kwargs)
class Meta: class Meta:
fields = ('label', 'enabled', 'uncompress') fields = ('label', 'enabled', 'uncompress')
model = WebFormSource model = WebFormSource

View File

@@ -9,8 +9,8 @@ from .literals import SOURCE_UNCOMPRESS_CHOICE_ASK
def create_default_document_source(sender, **kwargs): def create_default_document_source(sender, **kwargs):
WebFormSource = get_model('sources', 'WebFormSource') WebFormSource = get_model('sources', 'WebFormSource')
if not WebFormSource.objects.count(): if not WebFormSource.on_organization.count():
WebFormSource.objects.create( WebFormSource.on_organization.create(
label=_('Default'), uncompress=SOURCE_UNCOMPRESS_CHOICE_ASK label=_('Default'), uncompress=SOURCE_UNCOMPRESS_CHOICE_ASK
) )
@@ -32,11 +32,11 @@ def initialize_periodic_tasks(sender, **kwargs):
IMAPEmail = get_model('sources', 'IMAPEmail') IMAPEmail = get_model('sources', 'IMAPEmail')
WatchFolderSource = get_model('sources', 'WatchFolderSource') WatchFolderSource = get_model('sources', 'WatchFolderSource')
for source in POP3Email.objects.filter(enabled=True): for source in POP3Email.on_organization.filter(enabled=True):
source.save() source.save()
for source in IMAPEmail.objects.filter(enabled=True): for source in IMAPEmail.on_organization.filter(enabled=True):
source.save() source.save()
for source in WatchFolderSource.objects.filter(enabled=True): for source in WatchFolderSource.on_organization.filter(enabled=True):
source.save() source.save()

View File

@@ -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'),
('sources', '0010_auto_20151001_0055'),
]
operations = [
migrations.AddField(
model_name='source',
name='organization',
field=models.ForeignKey(default=organizations.shortcuts.get_current_organization, to='organizations.Organization'),
),
]

View File

@@ -11,6 +11,7 @@ import poplib
import yaml import yaml
from django.conf import settings
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.files import File from django.core.files import File
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
@@ -18,7 +19,7 @@ from django.db import models, transaction
from django.utils.encoding import python_2_unicode_compatible from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from model_utils.managers import InheritanceManager from model_utils.managers import InheritanceManager, InheritanceQuerySet
from common.compressed_files import CompressedFile, NotACompressedFile from common.compressed_files import CompressedFile, NotACompressedFile
from converter.literals import DIMENSION_SEPARATOR from converter.literals import DIMENSION_SEPARATOR
@@ -28,7 +29,9 @@ from documents.models import Document, DocumentType
from documents.settings import setting_language from documents.settings import setting_language
from metadata.api import save_metadata_list, set_bulk_metadata from metadata.api import save_metadata_list, set_bulk_metadata
from metadata.models import MetadataType from metadata.models import MetadataType
from tags.models import Tag from organizations.models import Organization
from organizations.managers import CurrentOrganizationManager
from organizations.shortcuts import get_current_organization
from .classes import Attachment, SourceUploadedFile, StagingFile from .classes import Attachment, SourceUploadedFile, StagingFile
from .literals import ( from .literals import (
@@ -43,12 +46,24 @@ from .literals import (
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class OrganizationSourceManager(InheritanceManager, CurrentOrganizationManager):
def get_queryset(self):
return InheritanceQuerySet(self.model).filter(
**{self._get_field_name() + '__id': settings.ORGANIZATION_ID}
)
@python_2_unicode_compatible @python_2_unicode_compatible
class Source(models.Model): class Source(models.Model):
organization = models.ForeignKey(
Organization, default=get_current_organization
)
label = models.CharField(max_length=64, verbose_name=_('Label')) label = models.CharField(max_length=64, verbose_name=_('Label'))
enabled = models.BooleanField(default=True, verbose_name=_('Enabled')) enabled = models.BooleanField(default=True, verbose_name=_('Enabled'))
objects = InheritanceManager() objects = InheritanceManager()
on_organization = OrganizationSourceManager()
@classmethod @classmethod
def class_fullname(cls): def class_fullname(cls):
@@ -63,7 +78,7 @@ class Source(models.Model):
def upload_document(self, file_object, document_type, description=None, label=None, language=None, metadata_dict_list=None, metadata_dictionary=None, tag_ids=None, user=None): def upload_document(self, file_object, document_type, description=None, label=None, language=None, metadata_dict_list=None, metadata_dictionary=None, tag_ids=None, user=None):
try: try:
with transaction.atomic(): with transaction.atomic():
document = Document.objects.create( document = Document.on_organization.create(
description=description or '', document_type=document_type, description=description or '', document_type=document_type,
label=label or file_object.name, label=label or file_object.name,
language=language or setting_language.value language=language or setting_language.value
@@ -93,7 +108,7 @@ class Source(models.Model):
) )
if tag_ids: if tag_ids:
for tag in Tag.objects.filter(pk__in=tag_ids): for tag in Tag.on_organization.filter(pk__in=tag_ids):
tag.documents.add(document) tag.documents.add(document)
except Exception as exception: except Exception as exception:
@@ -147,6 +162,7 @@ class Source(models.Model):
class InteractiveSource(Source): class InteractiveSource(Source):
objects = InheritanceManager() objects = InheritanceManager()
on_organization = OrganizationSourceManager()
class Meta: class Meta:
verbose_name = _('Interactive source') verbose_name = _('Interactive source')
@@ -183,6 +199,9 @@ class StagingFolderSource(InteractiveSource):
verbose_name=_('Delete after upload') verbose_name=_('Delete after upload')
) )
objects = InheritanceManager()
on_organization = OrganizationSourceManager()
def get_preview_size(self): def get_preview_size(self):
dimensions = [] dimensions = []
dimensions.append(unicode(self.preview_width)) dimensions.append(unicode(self.preview_width))
@@ -248,6 +267,12 @@ class WebFormSource(InteractiveSource):
def get_upload_file_object(self, form_data): def get_upload_file_object(self, form_data):
return SourceUploadedFile(source=self, file=form_data['file']) return SourceUploadedFile(source=self, file=form_data['file'])
# Custom model managers are not inherited is base class is not abstract.
# This will change in Django 1.10
# https://docs.djangoproject.com/en/1.8/topics/db/managers/#custom-managers-and-model-inheritance
objects = InheritanceManager()
on_organization = OrganizationSourceManager()
class Meta: class Meta:
verbose_name = _('Web form') verbose_name = _('Web form')
verbose_name_plural = _('Web forms') verbose_name_plural = _('Web forms')
@@ -256,6 +281,11 @@ class WebFormSource(InteractiveSource):
class OutOfProcessSource(Source): class OutOfProcessSource(Source):
is_interactive = False is_interactive = False
# Custom model managers are not inherited is base class is not abstract.
# This will change in Django 1.10
# https://docs.djangoproject.com/en/1.8/topics/db/managers/#custom-managers-and-model-inheritance
on_organization = OrganizationSourceManager()
class Meta: class Meta:
verbose_name = _('Out of process') verbose_name = _('Out of process')
verbose_name_plural = _('Out of process') verbose_name_plural = _('Out of process')
@@ -280,6 +310,12 @@ class IntervalBaseModel(OutOfProcessSource):
max_length=1, verbose_name=_('Uncompress') max_length=1, verbose_name=_('Uncompress')
) )
# Custom model managers are not inherited is base class is not abstract.
# This will change in Django 1.10
# https://docs.djangoproject.com/en/1.8/topics/db/managers/#custom-managers-and-model-inheritance
objects = InheritanceManager()
on_organization = OrganizationSourceManager()
def _get_periodic_task_name(self, pk=None): def _get_periodic_task_name(self, pk=None):
return 'check_interval_source-%i' % (pk or self.pk) return 'check_interval_source-%i' % (pk or self.pk)
@@ -368,6 +404,12 @@ class EmailBaseModel(IntervalBaseModel):
), verbose_name=_('Store email body') ), verbose_name=_('Store email body')
) )
# Custom model managers are not inherited is base class is not abstract.
# This will change in Django 1.10
# https://docs.djangoproject.com/en/1.8/topics/db/managers/#custom-managers-and-model-inheritance
objects = InheritanceManager()
on_organization = OrganizationSourceManager()
def clean(self): def clean(self):
if self.subject_metadata_type: if self.subject_metadata_type:
if self.subject_metadata_type.pk not in self.document_type.metadata.values_list('metadata_type', flat=True): if self.subject_metadata_type.pk not in self.document_type.metadata.values_list('metadata_type', flat=True):
@@ -488,6 +530,12 @@ class POP3Email(EmailBaseModel):
default=DEFAULT_POP3_TIMEOUT, verbose_name=_('Timeout') default=DEFAULT_POP3_TIMEOUT, verbose_name=_('Timeout')
) )
# Custom model managers are not inherited is base class is not abstract.
# This will change in Django 1.10
# https://docs.djangoproject.com/en/1.8/topics/db/managers/#custom-managers-and-model-inheritance
objects = InheritanceManager()
on_organization = OrganizationSourceManager()
def check_source(self): def check_source(self):
logger.debug('Starting POP3 email fetch') logger.debug('Starting POP3 email fetch')
logger.debug('host: %s', self.host) logger.debug('host: %s', self.host)
@@ -535,6 +583,12 @@ class IMAPEmail(EmailBaseModel):
max_length=64, verbose_name=_('Mailbox') max_length=64, verbose_name=_('Mailbox')
) )
# Custom model managers are not inherited is base class is not abstract.
# This will change in Django 1.10
# https://docs.djangoproject.com/en/1.8/topics/db/managers/#custom-managers-and-model-inheritance
objects = InheritanceManager()
on_organization = OrganizationSourceManager()
# http://www.doughellmann.com/PyMOTW/imaplib/ # http://www.doughellmann.com/PyMOTW/imaplib/
def check_source(self): def check_source(self):
logger.debug('Starting IMAP email fetch') logger.debug('Starting IMAP email fetch')
@@ -579,6 +633,12 @@ class WatchFolderSource(IntervalBaseModel):
verbose_name=_('Folder path') verbose_name=_('Folder path')
) )
# Custom model managers are not inherited is base class is not abstract.
# This will change in Django 1.10
# https://docs.djangoproject.com/en/1.8/topics/db/managers/#custom-managers-and-model-inheritance
objects = InheritanceManager()
on_organization = OrganizationSourceManager()
def check_source(self): def check_source(self):
# Force self.folder_path to unicode to avoid os.listdir returning # Force self.folder_path to unicode to avoid os.listdir returning
# str for non-latin filenames, gh-issue #163 # str for non-latin filenames, gh-issue #163

View File

@@ -21,7 +21,7 @@ def task_check_interval_source(source_id):
app_label='sources', model_name='Source' app_label='sources', model_name='Source'
) )
source = Source.objects.get_subclass(pk=source_id) source = Source.on_organization.get_subclass(pk=source_id)
if source.enabled: if source.enabled:
try: try:
source.check_source() source.check_source()
@@ -49,14 +49,14 @@ def task_upload_document(self, source_id, document_type_id, shared_uploaded_file
) )
try: try:
document_type = DocumentType.objects.get(pk=document_type_id) document_type = DocumentType.on_organization.get(pk=document_type_id)
source = Source.objects.get_subclass(pk=source_id) source = Source.on_organization.get_subclass(pk=source_id)
shared_upload = SharedUploadedFile.objects.get( shared_upload = SharedUploadedFile.objects.get(
pk=shared_uploaded_file_id pk=shared_uploaded_file_id
) )
if user_id: if user_id:
user = get_user_model().objects.get(pk=user_id) user = get_user_model().on_organization.get(pk=user_id)
else: else:
user = None user = None
@@ -96,7 +96,7 @@ def task_source_handle_upload(self, document_type_id, shared_uploaded_file_id, s
) )
try: try:
document_type = DocumentType.objects.get(pk=document_type_id) document_type = DocumentType.on_organization.get(pk=document_type_id)
shared_upload = SharedUploadedFile.objects.get( shared_upload = SharedUploadedFile.objects.get(
pk=shared_uploaded_file_id pk=shared_uploaded_file_id
) )

View File

@@ -0,0 +1,6 @@
from __future__ import unicode_literals
TEST_SOURCE_LABEL = 'test source label'
TEST_SOURCE_EDITED_LABEL = 'test source label edited'
TEST_SOURCE_UNCOMPRESS_N = 'n'
TEST_STAGING_PREVIEW_WIDTH = 640

View File

@@ -14,6 +14,8 @@ from documents.tests import (
TEST_NON_ASCII_DOCUMENT_FILENAME, TEST_NON_ASCII_DOCUMENT_PATH, TEST_NON_ASCII_DOCUMENT_FILENAME, TEST_NON_ASCII_DOCUMENT_PATH,
TEST_NON_ASCII_COMPRESSED_DOCUMENT_PATH TEST_NON_ASCII_COMPRESSED_DOCUMENT_PATH
) )
from organizations.models import Organization
from organizations.utils import create_default_organization
from user_management.tests import ( from user_management.tests import (
TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME
) )
@@ -29,7 +31,8 @@ class UploadDocumentTestCase(TestCase):
""" """
def setUp(self): def setUp(self):
self.document_type = DocumentType.objects.create( create_default_organization()
self.document_type = DocumentType.on_organization.create(
label=TEST_DOCUMENT_TYPE label=TEST_DOCUMENT_TYPE
) )
@@ -43,6 +46,9 @@ class UploadDocumentTestCase(TestCase):
self.document_type.delete() self.document_type.delete()
self.admin_user.delete() self.admin_user.delete()
Organization.objects.all().delete()
Organization.objects.clear_cache()
def test_issue_gh_163(self): def test_issue_gh_163(self):
""" """
Non-ASCII chars in document name failing in upload via watch folder Non-ASCII chars in document name failing in upload via watch folder
@@ -52,15 +58,15 @@ class UploadDocumentTestCase(TestCase):
temporary_directory = tempfile.mkdtemp() temporary_directory = tempfile.mkdtemp()
shutil.copy(TEST_NON_ASCII_DOCUMENT_PATH, temporary_directory) shutil.copy(TEST_NON_ASCII_DOCUMENT_PATH, temporary_directory)
watch_folder = WatchFolderSource.objects.create( watch_folder = WatchFolderSource.on_organization.create(
document_type=self.document_type, folder_path=temporary_directory, document_type=self.document_type, folder_path=temporary_directory,
uncompress=SOURCE_UNCOMPRESS_CHOICE_Y uncompress=SOURCE_UNCOMPRESS_CHOICE_Y
) )
watch_folder.check_source() watch_folder.check_source()
self.assertEqual(Document.objects.count(), 1) self.assertEqual(Document.on_organization.count(), 1)
document = Document.objects.first() document = Document.on_organization.first()
self.assertEqual(document.exists(), True) self.assertEqual(document.exists(), True)
self.assertEqual(document.size, 17436) self.assertEqual(document.size, 17436)
@@ -77,9 +83,9 @@ class UploadDocumentTestCase(TestCase):
) )
watch_folder.check_source() watch_folder.check_source()
document = Document.objects.all()[1] document = Document.on_organization.all()[1]
self.assertEqual(Document.objects.count(), 2) self.assertEqual(Document.on_organization.count(), 2)
self.assertEqual(document.exists(), True) self.assertEqual(document.exists(), True)
self.assertEqual(document.size, 17436) self.assertEqual(document.size, 17436)
@@ -95,12 +101,16 @@ class UploadDocumentTestCase(TestCase):
@override_settings(OCR_AUTO_OCR=False) @override_settings(OCR_AUTO_OCR=False)
class CompressedUploadsTestCase(TestCase): class CompressedUploadsTestCase(TestCase):
def setUp(self): def setUp(self):
self.document_type = DocumentType.objects.create( create_default_organization()
self.document_type = DocumentType.on_organization.create(
label=TEST_DOCUMENT_TYPE label=TEST_DOCUMENT_TYPE
) )
def tearDown(self): def tearDown(self):
self.document_type.delete() self.document_type.delete()
Organization.objects.all().delete()
Organization.objects.clear_cache()
def test_upload_compressed_file(self): def test_upload_compressed_file(self):
source = WebFormSource( source = WebFormSource(
@@ -114,14 +124,14 @@ class CompressedUploadsTestCase(TestCase):
expand=(source.uncompress == SOURCE_UNCOMPRESS_CHOICE_Y) expand=(source.uncompress == SOURCE_UNCOMPRESS_CHOICE_Y)
) )
self.assertEqual(Document.objects.count(), 2) self.assertEqual(Document.on_organization.count(), 2)
self.assertTrue( self.assertTrue(
'first document.pdf' in Document.objects.values_list( 'first document.pdf' in Document.on_organization.values_list(
'label', flat=True 'label', flat=True
) )
) )
self.assertTrue( self.assertTrue(
'second document.pdf' in Document.objects.values_list( 'second document.pdf' in Document.on_organization.values_list(
'label', flat=True 'label', flat=True
) )
) )

View File

@@ -0,0 +1,71 @@
from __future__ import unicode_literals
from organizations.tests.test_organization_views import OrganizationViewTestCase
from ..models import WebFormSource
from ..utils import get_class, get_form_class, get_upload_form_class
from .literals import (
TEST_SOURCE_LABEL, TEST_SOURCE_EDITED_LABEL, TEST_SOURCE_UNCOMPRESS_N
)
class SourceOrganizationViewTestCase(OrganizationViewTestCase):
def create_source(self):
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
self.source = WebFormSource.on_organization.create(
enabled=True, label=TEST_SOURCE_LABEL,
uncompress=TEST_SOURCE_UNCOMPRESS_N
)
def test_source_create_view(self):
# Create a source for organization A
with self.settings(ORGANIZATION_ID=self.organization_a.pk):
response = self.post(
'sources:setup_source_create',
args=(WebFormSource.source_type,), data={
'label': TEST_SOURCE_LABEL,
'uncompress': TEST_SOURCE_UNCOMPRESS_N
}
)
self.assertNotContains(response, text='danger', status_code=302)
self.assertEqual(WebFormSource.on_organization.count(), 1)
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
self.assertEqual(WebFormSource.on_organization.count(), 0)
def test_source_delete_view(self):
self.create_source()
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
response = self.post(
'sources:setup_source_delete', args=(self.source.pk,)
)
self.assertEqual(response.status_code, 404)
def test_source_edit_view(self):
self.create_source()
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
# Make sure admin for organization B cannot edit the source
response = self.post(
'sources:setup_source_edit', args=(self.source.pk,), data={
'label': TEST_SOURCE_EDITED_LABEL
}
)
self.assertEqual(response.status_code, 404)
def test_source_list_view(self):
self.create_source()
with self.settings(ORGANIZATION_ID=self.organization_b.pk):
# Make sure admin for organization B cannot find the source for
# organization A
response = self.get(
'sources:setup_source_list',
)
self.assertNotContains(
response, text=self.source.label, status_code=200
)

View File

@@ -18,6 +18,8 @@ from documents.tests import (
TEST_DOCUMENT_TYPE TEST_DOCUMENT_TYPE
) )
from documents.tests.test_views import GenericDocumentViewTestCase from documents.tests.test_views import GenericDocumentViewTestCase
from organizations.models import Organization
from organizations.utils import create_default_organization
from user_management.tests import ( from user_management.tests import (
TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME,
TEST_USER_PASSWORD, TEST_USER_USERNAME TEST_USER_PASSWORD, TEST_USER_USERNAME
@@ -30,15 +32,15 @@ from ..permissions import (
permission_sources_setup_view, permission_staging_file_delete permission_sources_setup_view, permission_staging_file_delete
) )
TEST_SOURCE_LABEL = 'test source' from .literals import (
TEST_SOURCE_UNCOMPRESS_N = 'n' TEST_SOURCE_LABEL, TEST_SOURCE_UNCOMPRESS_N, TEST_STAGING_PREVIEW_WIDTH
TEST_STAGING_PREVIEW_WIDTH = 640 )
class DocumentUploadTestCase(GenericDocumentViewTestCase): class DocumentUploadTestCase(GenericDocumentViewTestCase):
def setUp(self): def setUp(self):
super(DocumentUploadTestCase, self).setUp() super(DocumentUploadTestCase, self).setUp()
self.source = WebFormSource.objects.create( self.source = WebFormSource.on_organization.create(
enabled=True, label=TEST_SOURCE_LABEL, enabled=True, label=TEST_SOURCE_LABEL,
uncompress=TEST_SOURCE_UNCOMPRESS_N uncompress=TEST_SOURCE_UNCOMPRESS_N
) )
@@ -61,7 +63,7 @@ class DocumentUploadTestCase(GenericDocumentViewTestCase):
) )
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
self.assertEqual(Document.objects.count(), 0) self.assertEqual(Document.on_organization.count(), 0)
def test_upload_wizard_with_permission(self): def test_upload_wizard_with_permission(self):
self.client.login( self.client.login(
@@ -83,7 +85,7 @@ class DocumentUploadTestCase(GenericDocumentViewTestCase):
) )
self.assertTrue(b'queued' in response.content) self.assertTrue(b'queued' in response.content)
self.assertEqual(Document.objects.count(), 1) self.assertEqual(Document.on_organization.count(), 1)
def test_upload_wizard_with_document_type_access(self): def test_upload_wizard_with_document_type_access(self):
""" """
@@ -97,7 +99,7 @@ class DocumentUploadTestCase(GenericDocumentViewTestCase):
# Create an access control entry giving the role the document # Create an access control entry giving the role the document
# create permission for the selected document type. # create permission for the selected document type.
acl = AccessControlList.objects.create( acl = AccessControlList.on_organization.create(
content_object=self.document_type, role=self.role content_object=self.document_type, role=self.role
) )
acl.permissions.add(permission_document_create.stored_permission) acl.permissions.add(permission_document_create.stored_permission)
@@ -113,13 +115,14 @@ class DocumentUploadTestCase(GenericDocumentViewTestCase):
) )
self.assertTrue(b'queued' in response.content) self.assertTrue(b'queued' in response.content)
self.assertEqual(Document.objects.count(), 1) self.assertEqual(Document.on_organization.count(), 1)
@override_settings(OCR_AUTO_OCR=False) @override_settings(OCR_AUTO_OCR=False)
class DocumentUploadIssueTestCase(TestCase): class DocumentUploadIssueTestCase(TestCase):
def setUp(self): def setUp(self):
self.document_type = DocumentType.objects.create( create_default_organization()
self.document_type = DocumentType.on_organization.create(
label=TEST_DOCUMENT_TYPE label=TEST_DOCUMENT_TYPE
) )
@@ -131,6 +134,8 @@ class DocumentUploadIssueTestCase(TestCase):
def tearDown(self): def tearDown(self):
self.document_type.delete() self.document_type.delete()
Organization.objects.all().delete()
Organization.objects.clear_cache()
def test_issue_25(self): def test_issue_25(self):
# Login the admin user # Login the admin user
@@ -146,7 +151,7 @@ class DocumentUploadIssueTestCase(TestCase):
'sources:setup_source_create', args=(SOURCE_CHOICE_WEB_FORM,) 'sources:setup_source_create', args=(SOURCE_CHOICE_WEB_FORM,)
), {'label': 'test', 'uncompress': 'n', 'enabled': True} ), {'label': 'test', 'uncompress': 'n', 'enabled': True}
) )
self.assertEqual(WebFormSource.objects.count(), 1) self.assertEqual(WebFormSource.on_organization.count(), 1)
# Upload the test document # Upload the test document
with open(TEST_SMALL_DOCUMENT_PATH) as file_descriptor: with open(TEST_SMALL_DOCUMENT_PATH) as file_descriptor:
@@ -157,9 +162,9 @@ class DocumentUploadIssueTestCase(TestCase):
'document_type_id': self.document_type.pk 'document_type_id': self.document_type.pk
} }
) )
self.assertEqual(Document.objects.count(), 1) self.assertEqual(Document.on_organization.count(), 1)
document = Document.objects.first() document = Document.on_organization.first()
# Test for issue 25 during creation # Test for issue 25 during creation
# ** description fields was removed from upload from ** # ** description fields was removed from upload from **
self.assertEqual(document.description, '') self.assertEqual(document.description, '')
@@ -178,7 +183,7 @@ class DocumentUploadIssueTestCase(TestCase):
} }
) )
# Fetch document again and test description # Fetch document again and test description
document = Document.objects.first() document = Document.on_organization.first()
self.assertEqual(document.description, TEST_DOCUMENT_DESCRIPTION) self.assertEqual(document.description, TEST_DOCUMENT_DESCRIPTION)
@@ -240,7 +245,7 @@ class StagingFolderTestCase(GenericViewTestCase):
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
) )
staging_folder = StagingFolderSource.objects.create( staging_folder = StagingFolderSource.on_organization.create(
label=TEST_SOURCE_LABEL, label=TEST_SOURCE_LABEL,
folder_path=self.temporary_directory, folder_path=self.temporary_directory,
preview_width=TEST_STAGING_PREVIEW_WIDTH, preview_width=TEST_STAGING_PREVIEW_WIDTH,
@@ -269,7 +274,7 @@ class StagingFolderTestCase(GenericViewTestCase):
permission_staging_file_delete.stored_permission permission_staging_file_delete.stored_permission
) )
staging_folder = StagingFolderSource.objects.create( staging_folder = StagingFolderSource.on_organization.create(
label=TEST_SOURCE_LABEL, label=TEST_SOURCE_LABEL,
folder_path=self.temporary_directory, folder_path=self.temporary_directory,
preview_width=TEST_STAGING_PREVIEW_WIDTH, preview_width=TEST_STAGING_PREVIEW_WIDTH,
@@ -292,7 +297,7 @@ class StagingFolderTestCase(GenericViewTestCase):
class SourcesTestCase(GenericDocumentViewTestCase): class SourcesTestCase(GenericDocumentViewTestCase):
def create_web_source(self): def create_web_source(self):
self.source = WebFormSource.objects.create( self.source = WebFormSource.on_organization.create(
enabled=True, label=TEST_SOURCE_LABEL, enabled=True, label=TEST_SOURCE_LABEL,
uncompress=TEST_SOURCE_UNCOMPRESS_N uncompress=TEST_SOURCE_UNCOMPRESS_N
) )
@@ -343,7 +348,7 @@ class SourcesTestCase(GenericDocumentViewTestCase):
} }
) )
webform_source = WebFormSource.objects.first() webform_source = WebFormSource.on_organization.first()
self.assertEqual(webform_source.label, TEST_SOURCE_LABEL) self.assertEqual(webform_source.label, TEST_SOURCE_LABEL)
self.assertEqual(webform_source.uncompress, TEST_SOURCE_UNCOMPRESS_N) self.assertEqual(webform_source.uncompress, TEST_SOURCE_UNCOMPRESS_N)
@@ -368,7 +373,7 @@ class SourcesTestCase(GenericDocumentViewTestCase):
) )
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
self.assertEqual(WebFormSource.objects.count(), 0) self.assertEqual(WebFormSource.on_organization.count(), 0)
def test_source_delete_view_with_permission(self): def test_source_delete_view_with_permission(self):
self.create_web_source() self.create_web_source()
@@ -390,7 +395,7 @@ class SourcesTestCase(GenericDocumentViewTestCase):
) )
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(WebFormSource.objects.count(), 0) self.assertEqual(WebFormSource.on_organization.count(), 0)
def test_source_delete_view_no_permission(self): def test_source_delete_view_no_permission(self):
self.create_web_source() self.create_web_source()
@@ -409,4 +414,4 @@ class SourcesTestCase(GenericDocumentViewTestCase):
) )
self.assertEqual(response.status_code, 403) self.assertEqual(response.status_code, 403)
self.assertEqual(WebFormSource.objects.count(), 1) self.assertEqual(WebFormSource.on_organization.count(), 1)

View File

@@ -23,6 +23,7 @@ from documents.permissions import (
from documents.tasks import task_upload_new_version from documents.tasks import task_upload_new_version
from metadata.api import decode_metadata_from_url from metadata.api import decode_metadata_from_url
from navigation import Link from navigation import Link
from organizations.models import Organization
from permissions import Permission from permissions import Permission
from .forms import ( from .forms import (
@@ -49,14 +50,6 @@ from .utils import get_class, get_form_class, get_upload_form_class
class SourceLogListView(SingleObjectListView): class SourceLogListView(SingleObjectListView):
view_permission = permission_sources_setup_view view_permission = permission_sources_setup_view
def get_source(self):
return get_object_or_404(
Source.objects.select_subclasses(), pk=self.kwargs['pk']
)
def get_queryset(self):
return self.get_source().logs.all()
def get_extra_context(self): def get_extra_context(self):
return { return {
'hide_object': True, 'hide_object': True,
@@ -64,6 +57,14 @@ class SourceLogListView(SingleObjectListView):
'title': _('Log entries for source: %s') % self.get_source(), 'title': _('Log entries for source: %s') % self.get_source(),
} }
def get_queryset(self):
return self.get_source().logs.all()
def get_source(self):
return get_object_or_404(
Source.on_organization.select_subclasses(), pk=self.kwargs['pk']
)
class UploadBaseView(MultiFormView): class UploadBaseView(MultiFormView):
template_name = 'appearance/generic_form.html' template_name = 'appearance/generic_form.html'
@@ -91,13 +92,13 @@ class UploadBaseView(MultiFormView):
def get_active_tab_links(document=None): def get_active_tab_links(document=None):
tab_links = [] tab_links = []
web_forms = WebFormSource.objects.filter(enabled=True) web_forms = WebFormSource.on_organization.filter(enabled=True)
for web_form in web_forms: for web_form in web_forms:
tab_links.append( tab_links.append(
UploadBaseView.get_tab_link_for_source(web_form, document) UploadBaseView.get_tab_link_for_source(web_form, document)
) )
staging_folders = StagingFolderSource.objects.filter(enabled=True) staging_folders = StagingFolderSource.on_organization.filter(enabled=True)
for staging_folder in staging_folders: for staging_folder in staging_folders:
tab_links.append( tab_links.append(
UploadBaseView.get_tab_link_for_source( UploadBaseView.get_tab_link_for_source(
@@ -114,15 +115,15 @@ class UploadBaseView(MultiFormView):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if 'source_id' in kwargs: if 'source_id' in kwargs:
self.source = get_object_or_404( self.source = get_object_or_404(
Source.objects.filter(enabled=True).select_subclasses(), Source.on_organization.filter(enabled=True).select_subclasses(),
pk=kwargs['source_id'] pk=kwargs['source_id']
) )
else: else:
self.source = InteractiveSource.objects.filter( self.source = InteractiveSource.on_organization.filter(
enabled=True enabled=True
).select_subclasses().first() ).select_subclasses().first()
if not InteractiveSource.objects.filter(enabled=True).exists(): if not InteractiveSource.on_organization.filter(enabled=True).exists():
messages.error( messages.error(
request, request,
_( _(
@@ -450,9 +451,6 @@ class SetupSourceCreateView(SingleObjectCreateView):
post_action_redirect = reverse_lazy('sources:setup_source_list') post_action_redirect = reverse_lazy('sources:setup_source_list')
view_permission = permission_sources_setup_create view_permission = permission_sources_setup_create
def get_form_class(self):
return get_form_class(self.kwargs['source_type'])
def get_extra_context(self): def get_extra_context(self):
return { return {
'object': self.kwargs['source_type'], 'object': self.kwargs['source_type'],
@@ -461,48 +459,54 @@ class SetupSourceCreateView(SingleObjectCreateView):
) % get_class(self.kwargs['source_type']).class_fullname(), ) % get_class(self.kwargs['source_type']).class_fullname(),
} }
def get_form_class(self):
return get_form_class(self.kwargs['source_type'])
def get_instance_extra_data(self):
return {'organization': Organization.objects.get_current()}
class SetupSourceDeleteView(SingleObjectDeleteView): class SetupSourceDeleteView(SingleObjectDeleteView):
post_action_redirect = reverse_lazy('sources:setup_source_list') post_action_redirect = reverse_lazy('sources:setup_source_list')
view_permission = permission_sources_setup_delete view_permission = permission_sources_setup_delete
def get_object(self):
return get_object_or_404(
Source.objects.select_subclasses(), pk=self.kwargs['pk']
)
def get_form_class(self):
return get_form_class(self.get_object().source_type)
def get_extra_context(self): def get_extra_context(self):
return { return {
'object': self.get_object(), 'object': self.get_object(),
'title': _('Delete the source: %s?') % self.get_object(), 'title': _('Delete the source: %s?') % self.get_object(),
} }
def get_form_class(self):
return get_form_class(self.get_object().source_type)
def get_object(self):
return get_object_or_404(
Source.on_organization.select_subclasses(), pk=self.kwargs['pk']
)
class SetupSourceEditView(SingleObjectEditView): class SetupSourceEditView(SingleObjectEditView):
post_action_redirect = reverse_lazy('sources:setup_source_list') post_action_redirect = reverse_lazy('sources:setup_source_list')
view_permission = permission_sources_setup_edit view_permission = permission_sources_setup_edit
def get_object(self):
return get_object_or_404(
Source.objects.select_subclasses(), pk=self.kwargs['pk']
)
def get_form_class(self):
return get_form_class(self.get_object().source_type)
def get_extra_context(self): def get_extra_context(self):
return { return {
'object': self.get_object(), 'object': self.get_object(),
'title': _('Edit source: %s') % self.get_object(), 'title': _('Edit source: %s') % self.get_object(),
} }
def get_form_class(self):
return get_form_class(self.get_object().source_type)
def get_object(self):
return get_object_or_404(
Source.on_organization.select_subclasses(), pk=self.kwargs['pk']
)
class SetupSourceListView(SingleObjectListView): class SetupSourceListView(SingleObjectListView):
queryset = Source.on_organization.select_subclasses()
view_permission = permission_sources_setup_view view_permission = permission_sources_setup_view
queryset = Source.objects.select_subclasses()
extra_context = { extra_context = {
'extra_columns': ( 'extra_columns': (

View File

@@ -42,7 +42,7 @@ class DocumentCreateWizard(ViewPermissionCheckMixin, SessionWizardView):
template_name = 'appearance/generic_wizard.html' template_name = 'appearance/generic_wizard.html'
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if not InteractiveSource.objects.filter(enabled=True).exists(): if not InteractiveSource.on_organization.filter(enabled=True).exists():
messages.error( messages.error(
request, request,
_( _(