예제 #1
1
    def handle(self, *args, **options):
        all_tenants = get_tenant_model().objects.exclude(schema_name='public')

        for tenant in all_tenants:
            connection.set_tenant(tenant)
            logger.info(f'Set {tenant.schema_name}')
            call_command('loaddata', *args, **options)
예제 #2
0
    def test_switching_search_path(self):
        tenant1 = get_tenant_model()(schema_name='tenant1')
        tenant1.save()

        domain1 = get_tenant_domain_model()(tenant=tenant1, domain='something.test.com')
        domain1.save()

        connection.set_schema_to_public()

        tenant2 = get_tenant_model()(schema_name='tenant2')
        tenant2.save()

        domain2 = get_tenant_domain_model()(tenant=tenant2, domain='example.com')
        domain2.save()

        # go to tenant1's path
        connection.set_tenant(tenant1)

        # add some data, 2 DummyModels for tenant1
        DummyModel(name="Schemas are").save()
        DummyModel(name="awesome!").save()

        # switch temporarily to tenant2's path
        with tenant_context(tenant2):
            # add some data, 3 DummyModels for tenant2
            DummyModel(name="Man,").save()
            DummyModel(name="testing").save()
            DummyModel(name="is great!").save()

        # we should be back to tenant1's path, test what we have
        self.assertEqual(2, DummyModel.objects.count())

        # switch back to tenant2's path
        with tenant_context(tenant2):
            self.assertEqual(3, DummyModel.objects.count())
예제 #3
0
    def setUp(self):
        super(SharedAuthTest, self).setUp()

        settings.SHARED_APPS = ('django_tenants',
                                'customers',
                                'django.contrib.auth',
                                'django.contrib.contenttypes', )
        settings.TENANT_APPS = ('dts_test_app', )
        settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
        self.sync_shared()
        self.public_tenant = get_tenant_model()(schema_name=get_public_schema_name())
        self.public_tenant.save()
        self.public_domain = get_tenant_domain_model()(tenant=self.public_tenant, domain='test.com')
        self.public_domain.save()

        # Create a tenant
        self.tenant = get_tenant_model()(schema_name='tenant')
        self.tenant.save()
        self.domain = get_tenant_domain_model()(tenant=self.tenant, domain='tenant.test.com')
        self.domain.save()

        # Create some users
        with schema_context(get_public_schema_name()):  # this could actually also be executed inside a tenant
            self.user1 = User(username='******', email="*****@*****.**")
            self.user1.save()
            self.user2 = User(username='******', email="*****@*****.**")
            self.user2.save()

        # Create instances on the tenant that point to the users on public
        with tenant_context(self.tenant):
            self.d1 = ModelWithFkToPublicUser(user=self.user1)
            self.d1.save()
            self.d2 = ModelWithFkToPublicUser(user=self.user2)
            self.d2.save()
    def test_files_are_saved_under_subdirectories_per_tenant(self):
        storage = TenantFileSystemStorage()

        connection.set_schema_to_public()
        tenant1 = utils.get_tenant_model()(schema_name='tenant1')
        tenant1.save()

        domain1 = utils.get_tenant_domain_model()(tenant=tenant1, domain='something.test.com')
        domain1.save()

        connection.set_schema_to_public()
        tenant2 = utils.get_tenant_model()(schema_name='tenant2')
        tenant2.save()

        domain2 = utils.get_tenant_domain_model()(tenant=tenant2, domain='example.com')
        domain2.save()

        # this file should be saved on the public schema
        public_file_name = storage.save('hello_world.txt', ContentFile('Hello World'))
        public_os_path = storage.path(public_file_name)
        public_url = storage.url(public_file_name)

        # switch to tenant1
        with utils.tenant_context(tenant1):
            t1_file_name = storage.save('hello_from_1.txt', ContentFile('Hello T1'))
            t1_os_path = storage.path(t1_file_name)
            t1_url = storage.url(t1_file_name)

        # switch to tenant2
        with utils.tenant_context(tenant2):
            t2_file_name = storage.save('hello_from_2.txt', ContentFile('Hello T2'))
            t2_os_path = storage.path(t2_file_name)
            t2_url = storage.url(t2_file_name)

        # assert the paths are correct
        self.assertTrue(public_os_path.endswith('apps_dir/media/public/%s' % public_file_name))
        self.assertTrue(t1_os_path.endswith('apps_dir/media/tenant1/%s' % t1_file_name))
        self.assertTrue(t2_os_path.endswith('apps_dir/media/tenant2/%s' % t2_file_name))

        # assert urls are correct
        self.assertEqual(public_url, '/media/public/%s' % public_file_name)
        self.assertEqual(t1_url, '/media/tenant1/%s' % t1_file_name)
        self.assertEqual(t2_url, '/media/tenant2/%s' % t2_file_name)

        # assert contents are correct
        with open(public_os_path, 'r') as f:
            self.assertEqual(f.read(), 'Hello World')

        with open(t1_os_path, 'r') as f:
            self.assertEqual(f.read(), 'Hello T1')

        with open(t2_os_path, 'r') as f:
            self.assertEqual(f.read(), 'Hello T2')
예제 #5
0
 def handle(self, *args, **options):
     """
     Iterates a command over all registered schemata.
     """
     if options['schema_name']:
         # only run on a particular schema
         connection.set_schema_to_public()
         self.execute_command(get_tenant_model().objects.get(schema_name=options['schema_name']), self.COMMAND_NAME,
                              *args, **options)
     else:
         for tenant in get_tenant_model().objects.all():
             if not (options['skip_public'] and tenant.schema_name == get_public_schema_name()):
                 self.execute_command(tenant, self.COMMAND_NAME, *args, **options)
예제 #6
0
    def test_sync_tenant(self):
        """
        When editing an existing tenant, all data should be kept.
        """
        tenant = get_tenant_model()(schema_name='test')
        tenant.save()

        domain = get_tenant_domain_model()(tenant=tenant, domain='something.test.com')
        domain.save()

        # go to tenant's path
        connection.set_tenant(tenant)

        # add some data
        DummyModel(name="Schemas are").save()
        DummyModel(name="awesome!").save()

        # edit tenant
        connection.set_schema_to_public()
        tenant.domain_urls = ['example.com']
        tenant.save()

        connection.set_tenant(tenant)

        # test if data is still there
        self.assertEquals(DummyModel.objects.count(), 2)

        self.created = [domain, tenant]
예제 #7
0
    def test_tenant_apps_and_shared_apps_can_have_the_same_apps(self):
        """
        Tests that both SHARED_APPS and TENANT_APPS can have apps in common.
        In this case they should get synced to both tenant and public schemas.
        """
        settings.SHARED_APPS = ('django_tenants',  # 2 tables
                                'customers',
                                'django.contrib.auth',  # 6 tables
                                'django.contrib.contenttypes',  # 1 table
                                'django.contrib.sessions', )  # 1 table
        settings.TENANT_APPS = ('django.contrib.sessions', )  # 1 table
        settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
        self.sync_shared()
        tenant = get_tenant_model()(schema_name='test')
        tenant.save()

        domain = get_tenant_domain_model()(tenant=tenant, domain='arbitrary.test.com')
        domain.save()

        shared_tables = self.get_tables_list_in_schema(get_public_schema_name())
        tenant_tables = self.get_tables_list_in_schema(tenant.schema_name)
        self.assertEqual(2+6+1+1+self.MIGRATION_TABLE_SIZE, len(shared_tables))
        self.assertIn('django_session', shared_tables)
        self.assertEqual(1+self.MIGRATION_TABLE_SIZE, len(tenant_tables))
        self.assertIn('django_session', tenant_tables)
예제 #8
0
    def ready(self):
        # Test for configuration recommendations. These are best practices,
        # they avoid hard to find bugs and unexpected behaviour.
        if not hasattr(settings, "TENANT_APPS"):
            raise ImproperlyConfigured("TENANT_APPS setting not set")

        if not settings.TENANT_APPS:
            raise ImproperlyConfigured("TENANT_APPS is empty. " "Maybe you don't need this app?")

        if not hasattr(settings, "TENANT_MODEL"):
            raise ImproperlyConfigured("TENANT_MODEL setting not set")

        if "django_tenants.routers.TenantSyncRouter" not in settings.DATABASE_ROUTERS:
            raise ImproperlyConfigured(
                "DATABASE_ROUTERS setting must contain " "'django_tenants.routers.TenantSyncRouter'."
            )

        if hasattr(settings, "PG_EXTRA_SEARCH_PATHS"):
            if get_public_schema_name() in settings.PG_EXTRA_SEARCH_PATHS:
                raise ImproperlyConfigured(
                    "%s can not be included on PG_EXTRA_SEARCH_PATHS." % get_public_schema_name()
                )

            # make sure no tenant schema is in settings.PG_EXTRA_SEARCH_PATHS
            invalid_schemas = set(settings.PG_EXTRA_SEARCH_PATHS).intersection(
                get_tenant_model().objects.all().values_list("schema_name", flat=True)
            )
            if invalid_schemas:
                raise ImproperlyConfigured(
                    "Do not include tenant schemas (%s) on PG_EXTRA_SEARCH_PATHS." % list(invalid_schemas)
                )
예제 #9
0
    def test_tenant_schema_is_created_atomically(self):
        """
        When saving a tenant, it's schema should be created.
        This should work in atomic transactions too.
        """
        executor = get_executor()
        Tenant = get_tenant_model()

        schema_name = 'test'

        @transaction.atomic()
        def atomically_create_tenant():
            t = Tenant(schema_name=schema_name)
            t.save()

            self.created = [t]

        if executor == 'simple':
            atomically_create_tenant()

            self.assertTrue(schema_exists(schema_name))
        elif executor == 'multiprocessing':
            # Unfortunately, it's impossible for the multiprocessing executor
            # to assert atomic transactions when creating a tenant
            with self.assertRaises(transaction.TransactionManagementError):
                atomically_create_tenant()
예제 #10
0
    def handle(self, *args, **options):
        super(MigrateSchemasCommand, self).handle(*args, **options)
        self.PUBLIC_SCHEMA_NAME = get_public_schema_name()

        if self.sync_public and not self.schema_name:
            self.schema_name = self.PUBLIC_SCHEMA_NAME

        executor = get_executor(codename=self.executor)(self.args, self.options)

        if self.sync_public:
            executor.run_migrations(tenants=[self.PUBLIC_SCHEMA_NAME])
        if self.sync_tenant:
            if self.schema_name and self.schema_name != self.PUBLIC_SCHEMA_NAME:
                if not schema_exists(self.schema_name):
                    raise RuntimeError('Schema "{}" does not exist'.format(
                        self.schema_name))
                else:
                    tenants = [self.schema_name]
            else:
                tenants = get_tenant_model().objects.only(
                    'schema_name').exclude(
                    schema_name=self.PUBLIC_SCHEMA_NAME).values_list(
                    'schema_name', flat=True)

            executor.run_migrations(tenants=tenants)
예제 #11
0
 def store_tenant(self, **fields):
     try:
         tenant = get_tenant_model().objects.create(**fields)
         return tenant
     except exceptions.ValidationError as e:
         self.stderr.write("Error: %s" % '; '.join(e.messages))
         return None
     except IntegrityError:
         return None
예제 #12
0
 def get_tenant(self, domain_model, hostname):
     try:
         return super().get_tenant(domain_model, hostname)
     except domain_model.DoesNotExist:
         schema_name = self.DEFAULT_SCHEMA_NAME
         if not schema_name:
             schema_name = get_public_schema_name()
         tenant_model = get_tenant_model()
         return tenant_model.objects.get(schema_name=schema_name)
예제 #13
0
    def setUp(self):
        super(RoutesTestCase, self).setUp()
        self.factory = RequestFactory()
        self.tm = TenantMiddleware()

        self.tenant_domain = 'tenant.test.com'
        self.tenant = get_tenant_model()(schema_name='test')
        self.tenant.save()
        self.domain = get_tenant_domain_model()(tenant=self.tenant, domain=self.tenant_domain)
        self.domain.save()
예제 #14
0
    def setUp(self):
        super().setUp()
        self.factory = RequestFactory()
        self.tsf = TenantSubfolderMiddleware(noop_middleware)

        self.sync_shared()
        self.public_tenant = get_tenant_model()(
            schema_name=get_public_schema_name())
        self.public_tenant.save()
        self.public_domain = get_tenant_domain_model()(
            domain='test.com', tenant=self.public_tenant)
        self.public_domain.save()

        self.tenant_domain = 'tenant.test.com'
        self.tenant = get_tenant_model()(schema_name='test')
        self.tenant.save()
        self.domain = get_tenant_domain_model()(tenant=self.tenant,
                                                domain=self.tenant_domain)
        self.domain.save()
예제 #15
0
    def test_files_are_saved_under_subdirectories_per_tenant(self):
        storage = TenantFileSystemStorage()

        connection.set_schema_to_public()
        tenant2 = utils.get_tenant_model()(schema_name='tenant2',
                                           owner=UserFactory())
        tenant2.save()

        domain2 = utils.get_tenant_domain_model()(tenant=tenant2,
                                                  domain='example.com')
        domain2.save()

        # this file should be saved on the public schema
        public_file_name = storage.save('hello_world.txt',
                                        ContentFile('Hello World'))
        public_os_path = storage.path(public_file_name)
        public_url = storage.url(public_file_name)

        # switch to tenant1
        with utils.tenant_context(self.tenant):
            t1_file_name = storage.save('hello_from_1.txt',
                                        ContentFile('Hello T1'))
            t1_os_path = storage.path(t1_file_name)
            t1_url = storage.url(t1_file_name)

        # switch to tenant2
        with utils.tenant_context(tenant2):
            t2_file_name = storage.save('hello_from_2.txt',
                                        ContentFile('Hello T2'))
            t2_os_path = storage.path(t2_file_name)
            t2_url = storage.url(t2_file_name)

        # assert the paths are correct
        self.assertTrue(
            public_os_path.endswith('apps_dir/media/public/%s' %
                                    public_file_name))
        self.assertTrue(
            t1_os_path.endswith('apps_dir/media/test/%s' % t1_file_name))
        self.assertTrue(
            t2_os_path.endswith('apps_dir/media/tenant2/%s' % t2_file_name))

        # assert urls are correct
        self.assertEqual(public_url, '/media/public/%s' % public_file_name)
        self.assertEqual(t1_url, '/media/test/%s' % t1_file_name)
        self.assertEqual(t2_url, '/media/tenant2/%s' % t2_file_name)

        # assert contents are correct
        with open(public_os_path, 'r') as fobj:
            self.assertEqual(fobj.read(), 'Hello World')

        with open(t1_os_path, 'r') as fobj:
            self.assertEqual(fobj.read(), 'Hello T1')

        with open(t2_os_path, 'r') as fobj:
            self.assertEqual(fobj.read(), 'Hello T2')
예제 #16
0
    def test_switching_search_path(self):
        tenant1 = get_tenant_model()(schema_name='tenant1')
        tenant1.save()

        domain1 = get_tenant_domain_model()(tenant=tenant1,
                                            domain='something.test.com')
        domain1.save()

        connection.set_schema_to_public()

        tenant2 = get_tenant_model()(schema_name='tenant2')
        tenant2.save()

        domain2 = get_tenant_domain_model()(tenant=tenant2,
                                            domain='example.com')
        domain2.save()

        # go to tenant1's path
        connection.set_tenant(tenant1)

        # add some data, 2 DummyModels for tenant1
        DummyModel(name="Schemas are").save()
        DummyModel(name="awesome!").save()

        # switch temporarily to tenant2's path
        with self.assertNumQueries(6):
            with tenant_context(tenant2):
                # add some data, 3 DummyModels for tenant2
                DummyModel(name="Man,").save()
                DummyModel(name="testing").save()
                DummyModel(name="is great!").save()

        # we should be back to tenant1's path, test what we have
        with self.assertNumQueries(2):
            self.assertEqual(2, DummyModel.objects.count())

        # switch back to tenant2's path
        with self.assertNumQueries(2):
            with tenant_context(tenant2):
                self.assertEqual(3, DummyModel.objects.count())

        self.created = [domain2, domain1, tenant2, tenant1]
예제 #17
0
    def process_request(self, request):
        # Short circuit if tenant is already set by another middleware.
        # This allows for multiple tenant-resolving middleware chained together.
        if hasattr(request, "tenant"):
            return

        connection.set_schema_to_public()

        tenant = None
        urlconf = None

        TenantModel = get_tenant_model()
        hostname = self.hostname_from_request(request)
        subfolder_prefix_path = "/{}/".format(get_subfolder_prefix())

        # We are in the public tenant
        if not request.path.startswith(subfolder_prefix_path):
            try:
                tenant = TenantModel.objects.get(
                    schema_name=get_public_schema_name())
            except TenantModel.DoesNotExist:
                raise self.TENANT_NOT_FOUND_EXCEPTION(
                    "Unable to find public tenant")

            # Do we have a public-specific urlconf?
            if (hasattr(settings, "PUBLIC_SCHEMA_URLCONF")
                    and tenant.schema_name == get_public_schema_name()):
                urlconf = settings.PUBLIC_SCHEMA_URLCONF

        # We are in a specific tenant
        else:
            path_chunks = request.path[len(subfolder_prefix_path):].split("/")
            tenant_subfolder = path_chunks[0]

            try:
                tenant = TenantModel.objects.get(
                    domains__domain=tenant_subfolder)
            except TenantModel.DoesNotExist:
                raise self.TENANT_NOT_FOUND_EXCEPTION(
                    'No tenant for subfolder "%s"' % (tenant_subfolder or ""))

            tenant.domain_subfolder = tenant_subfolder
            urlconf = get_subfolder_urlconf(tenant)

        tenant.domain_url = hostname
        request.tenant = tenant

        connection.set_tenant(request.tenant)
        clear_url_caches(
        )  # Required to remove previous tenant prefix from cache, if present

        if urlconf:
            request.urlconf = urlconf
            set_urlconf(urlconf)
예제 #18
0
    def test_tenant_schema_is_created(self):
        """
        When saving a tenant, it's schema should be created.
        """
        tenant = get_tenant_model()(schema_name='test')
        tenant.save()

        domain = get_tenant_domain_model()(tenant=tenant, domain='something.test.com')
        domain.save()

        self.assertTrue(schema_exists(tenant.schema_name))
예제 #19
0
    def setup_test_tenant_and_domain(cls):
        cls.tenant = get_tenant_model()(schema_name=cls.get_test_schema_name())
        cls.setup_tenant(cls.tenant)
        cls.tenant.save(verbosity=cls.get_verbosity())

        # Set up domain
        tenant_domain = cls.get_test_tenant_domain()
        cls.domain = get_tenant_domain_model()(tenant=cls.tenant, domain=tenant_domain)
        cls.setup_domain(cls.domain)
        cls.domain.save()
        cls.use_new_tenant()
예제 #20
0
    def setUp(self):
        super(RoutesTestCase, self).setUp()
        self.factory = RequestFactory()
        self.tm = TenantMiddleware()

        self.tenant_domain = 'tenant.test.com'
        self.tenant = get_tenant_model()(schema_name='test')
        self.tenant.save()
        self.domain = get_tenant_domain_model()(tenant=self.tenant,
                                                domain=self.tenant_domain)
        self.domain.save()
예제 #21
0
    def process_request(self, request):
        try:
            connection.set_schema_to_public()
            hostname_without_port = remove_www_and_dev(
                request.get_host().split(':')[0])
            tenant_model = get_tenant_model()
            request.main_url = MAIN_URL
            request.login_url = LOGIN_URL
            request.protocol = PROTOCOL
            if hostname_without_port.startswith('login.'):
                hostname_without_port = hostname_without_port.replace(
                    'login.', '')

            tenant = tenant_model.objects.filter(
                domain_name=hostname_without_port)
            if tenant:
                tenant = tenant[0]
                request.tenant = tenant
                selected_schema_name = tenant.schema_name
            else:
                res = {
                    'error':
                    'Subdomain ' + hostname_without_port + ' does not exist',
                    'status': 'Invalid Client'
                }
                not_found = {
                    'error': 'This subdomain does not exist => ' +
                    hostname_without_port,
                    'error_code': 404
                }
                if hostname_without_port != server_domain:
                    return render(request, 'error.html', not_found)
                tenant = tenant_model.objects.filter(schema_name='public')
                if not tenant:
                    tenant = create_public_tenant(tenant_model)
                    if type(tenant) is not str:
                        request.tenant = tenant
                        selected_schema_name = tenant.schema_name
                    else:
                        return render(request, 'error.html', not_found)
                else:
                    tenant = tenant[0]
                    request.tenant = tenant
                    selected_schema_name = tenant.schema_name
        except utils.DatabaseError:
            request.urlconf = PUBLIC_SCHEMA_URLCONF
            return
        connection.set_tenant(request.tenant, False)
        ContentType.objects.clear_cache()
        if selected_schema_name == 'public':
            request.home_url = PROTOCOL + "://" + server_domain + SERVER_PORT_STR
            request.urlconf = PUBLIC_SCHEMA_URLCONF
        else:
            request.home_url = PROTOCOL + "://" + selected_schema_name + '.' + server_domain + SERVER_PORT_STR
예제 #22
0
    def setUpClass(cls):
        tenant_model = get_tenant_model()

        test_schema_name = cls.get_test_schema_name()
        if tenant_model.objects.filter(schema_name=test_schema_name).exists():
            cls.tenant = tenant_model.objects.filter(schema_name=test_schema_name).first()
            cls.use_existing_tenant()
        else:
            cls.setup_test_tenant_and_domain()

        connection.set_tenant(cls.tenant)
예제 #23
0
    def test_tenant_prefix(self):
        from django.db import connection

        tpp = TenantPrefixPattern()
        for tenant in get_tenant_model().objects.all():
            domain = tenant.domains.first()
            tenant.domain_subfolder = domain.domain  # Normally done by middleware
            connection.set_tenant(tenant)
            self.assertEqual(
                tpp.tenant_prefix, "clients/{}/".format(tenant.domain_subfolder)
            )
예제 #24
0
 def connect(realm, *args, **kwargs):
     if hasattr(realm, 'schema_name') and hasattr(connection, 'set_schema'):
         try:
             from django_tenants.utils import get_tenant_model
             connection.set_tenant(get_tenant_model().objects.get(
                 schema_name=realm.schema_name))
         except ImportError:
             raise ModuleNotFoundError(
                 'django-tenants package is not installed: pip install django-quickbooks[tenant]'
             )
     return func(realm, *args, **kwargs)
예제 #25
0
    def setUpClass(cls):
        cls.sync_shared()
        cls.tenant = get_tenant_model()(schema_name='test')
        cls.tenant.save(verbosity=0)  # todo: is there any way to get the verbosity from the test command here?

        # Set up domain
        tenant_domain = 'tenant.test.com'
        domain = get_tenant_domain_model()(tenant=cls.tenant, domain=tenant_domain)
        domain.save()

        connection.set_tenant(cls.tenant)
예제 #26
0
    def setUpClass(cls):
        super().setUpClass()

        with utils.schema_context('public'):
            cls.tenant2 = django_tenant_utils.get_tenant_model()(
                schema_name='other2', owner=cls.tester)
            cls.tenant2.save()

            cls.domain2 = django_tenant_utils.get_tenant_domain_model()(
                tenant=cls.tenant2, domain='other2.example.com')
            cls.domain2.save()
예제 #27
0
    def setup_test_tenant_and_domain(cls):
        cls.tenant = get_tenant_model()(schema_name=cls.get_test_schema_name())
        cls.setup_tenant(cls.tenant)
        cls.tenant.save(verbosity=cls.get_verbosity())

        # Set up domain
        tenant_domain = cls.get_test_tenant_domain()
        cls.domain = get_tenant_domain_model()(tenant=cls.tenant, domain=tenant_domain)
        cls.setup_domain(cls.domain)
        cls.domain.save()
        cls.use_new_tenant()
예제 #28
0
    def setUpClass(cls):
        cls.sync_shared()
        cls.tenant = get_tenant_model()(schema_name='test')
        cls.tenant.save(verbosity=0)  # todo: is there any way to get the verbosity from the test command here?

        # Set up domain
        tenant_domain = 'tenant.test.com'
        domain = get_tenant_domain_model()(domain=tenant_domain, tenant=cls.tenant)
        domain.save()

        connection.set_tenant(cls.tenant)
예제 #29
0
    def setUpClass(cls):
        tenant_model = get_tenant_model()

        test_schema_name = cls.get_test_schema_name()
        if tenant_model.objects.filter(schema_name=test_schema_name).exists():
            cls.tenant = tenant_model.objects.filter(schema_name=test_schema_name).first()
            cls.use_existing_tenant()
        else:
            cls.setup_test_tenant_and_domain()

        connection.set_tenant(cls.tenant)
예제 #30
0
    def setUp(self):
        self.sync_shared()
        self.tenant = get_tenant_model()(schema_name='test')
        self.tenant.save(verbosity=0)  # todo: is there any way to get the verbosity from the test command here?

        # Set up domain
        tenant_domain = 'tenant.test.com'
        self.domain = get_tenant_domain_model()(tenant=self.tenant, domain=tenant_domain)
        self.domain.save()

        connection.set_tenant(self.tenant)
예제 #31
0
    def setUp(self):
        super(SharedAuthTest, self).setUp()

        settings.SHARED_APPS = (
            'django_tenants',
            'abi_back.tenant_configuration',
            'django.contrib.auth',
            'django.contrib.contenttypes',
        )
        settings.TENANT_APPS = (
            'abi_back.tenant_configuration.custom_dts_test_app', )
        settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
        self.sync_shared()
        self.public_tenant = get_tenant_model()(
            schema_name=get_public_schema_name())
        self.public_tenant.save()
        self.public_domain = get_tenant_domain_model()(
            tenant=self.public_tenant, domain='test.com')
        self.public_domain.save()

        # Create a tenant
        self.tenant = get_tenant_model()(schema_name='tenant')
        self.tenant.save()
        self.domain = get_tenant_domain_model()(tenant=self.tenant,
                                                domain='tenant.test.com')
        self.domain.save()

        # Create some users
        with schema_context(get_public_schema_name(
        )):  # this could actually also be executed inside a tenant
            self.user1 = User(username='******', email="*****@*****.**")
            self.user1.save()
            self.user2 = User(username='******', email="*****@*****.**")
            self.user2.save()

        # Create instances on the tenant that point to the users on public
        with tenant_context(self.tenant):
            self.d1 = ModelWithFkToPublicUser(user=self.user1)
            self.d1.save()
            self.d2 = ModelWithFkToPublicUser(user=self.user2)
            self.d2.save()
예제 #32
0
    def store_tenant(self, clone_schema_from, clone_tenant_fields, **fields):

        connection.set_schema_to_public()
        try:
            if clone_tenant_fields:
                tenant = get_tenant_model().objects.get(schema_name=clone_schema_from)
                tenant.pk = None
                tenant.schema_name = fields['schema_name']
            else:
                tenant = get_tenant_model()(**fields)
            tenant.auto_create_schema = False
            tenant.save()
            clone_schema = CloneSchema()
            clone_schema.clone_schema(clone_schema_from, tenant.schema_name, set_connection=False)
            return tenant
        except exceptions.ValidationError as e:
            self.stderr.write("Error: %s" % '; '.join(e.messages))
            return None
        except IntegrityError as e:
            self.stderr.write("Error: " + str(e))
            return None
예제 #33
0
 def test_rename_schema_ok(self):
     Client = get_tenant_model()
     tenant = Client(schema_name='test')
     tenant.save()
     self.assertTrue(schema_exists(tenant.schema_name))
     domain = get_tenant_domain_model()(tenant=tenant,
                                        domain='something.test.com')
     domain.save()
     schema_rename(tenant=Client.objects.filter(pk=tenant.pk).first(),
                   new_schema_name='new_name')
     self.assertFalse(schema_exists('test'))
     self.assertTrue(schema_exists('new_name'))
예제 #34
0
파일: views.py 프로젝트: humblesami/tenants
def create_tenant(email, subscription_id, request):
    res = 'Unknown issue'
    req_data = request.POST
    sub_domain = req_data['sub_domain']
    company = req_data['company']
    password = req_data['password']
    plan_id = req_data['plan_id']
    public_tenant = request.tenant
    try:
        tenant_model = get_tenant_model()
        with transaction.atomic():
            if not tenant_model.objects.filter(schema_name=sub_domain):

                schema_owner = User.objects.create(username='******' +
                                                   sub_domain + '.com')
                schema_owner.save()

                domain_name = sub_domain + '.' + server_domain
                company = tenant_model(schema_name=sub_domain,
                                       name=company,
                                       owner_id=schema_owner.id,
                                       domain_name=domain_name)
                company.subscription_id = subscription_id
                company.plan_id = plan_id
                company.save()

                create_public_user(company, email, password)

                request.tenant = company
                connection.set_tenant(request.tenant, False)
                ContentType.objects.clear_cache()
                try:
                    tenant_user = AuthUser(username=email,
                                           is_superuser=True,
                                           is_staff=True,
                                           is_active=True)
                    tenant_user.on_schema_creating = True
                    tenant_user.email = email
                    tenant_user.save()
                    tenant_user.set_password(password)
                    tenant_user.save()
                    print('\n\n\n Success while creating user\n\n\n')
                except:
                    print('\n\n\n Error while creating user\n\n\n')
                res = 'done'
            else:
                res = 'Client with name "' + sub_domain + '" already exists'
    except:
        res = ws_methods.produce_exception()
    request.tenant = public_tenant
    connection.set_tenant(request.tenant, False)
    ContentType.objects.clear_cache()
    return res
예제 #35
0
    def test_prefixed_reverse(self):
        from django.db import connection

        for tenant in get_tenant_model().objects.all():
            domain = tenant.domains.first()
            tenant.domain_subfolder = domain.domain  # Normally done by middleware
            connection.set_tenant(tenant)
            for name, path in self.paths.items():
                self.assertEqual(
                    self.reverser(name, tenant),
                    "/clients/{}{}".format(domain.domain, path),
                )
예제 #36
0
def provision_tenant(tenant_name, tenant_slug, user_email, is_staff=False):
    """
    Create a tenant with default roles and permissions

    Returns:
    The Fully Qualified Domain Name(FQDN) for the tenant.
    """
    tenant = None

    UserModel = get_user_model()
    TenantModel = get_tenant_model()

    user = UserModel.objects.get(email=user_email)
    if not user.is_active:
        raise InactiveError("Inactive user passed to provision tenant")

    tenant_domain = '{}.{}'.format(tenant_slug, settings.TENANT_USERS_DOMAIN)

    if get_tenant_domain_model().objects.filter(domain=tenant_domain).first():
        raise ExistsError("Tenant URL already exists.")

    time_string = str(int(time.time()))
    # Must be valid postgres schema characters see:
    # https://www.postgresql.org/docs/9.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
    # We generate unique schema names each time so we can keep tenants around without
    # taking up url/schema namespace.
    schema_name = '{}_{}'.format(tenant_slug, time_string)
    domain = None

    # noinspection PyBroadException
    try:
        # Wrap it in public schema context so schema consistency is maintained
        # if any error occurs
        with schema_context(get_public_schema_name()):
            tenant = TenantModel.objects.create(name=tenant_name,
                                                slug=tenant_slug,
                                                schema_name=schema_name,
                                                owner=user)

            # Add one or more domains for the tenant
            domain = get_tenant_domain_model().objects.create(
                domain=tenant_domain, tenant=tenant, is_primary=True)
            # Add user as a superuser inside the tenant
            tenant.add_user(user, is_superuser=True, is_staff=is_staff)
    except:  # noqa
        if domain is not None:
            domain.delete()
        if tenant is not None:
            # Flag is set to auto-drop the schema for the tenant
            tenant.delete(True)
        raise

    return tenant
예제 #37
0
    def test_manager_method_deletes_schema(self):
        Client = get_tenant_model()
        Client.auto_drop_schema = True
        tenant = Client(schema_name='test')
        tenant.save()
        self.assertTrue(schema_exists(tenant.schema_name))

        domain = get_tenant_domain_model()(tenant=tenant, domain='something.test.com')
        domain.save()

        Client.objects.filter(pk=tenant.pk).delete()
        self.assertFalse(schema_exists(tenant.schema_name))
예제 #38
0
    def test_tenant_schema_is_created(self):
        """
        When saving a tenant, it's schema should be created.
        """
        tenant = get_tenant_model()(schema_name='test')
        tenant.save()

        domain = get_tenant_domain_model()(tenant=tenant,
                                           domain='something.test.com')
        domain.save()

        self.assertTrue(schema_exists(tenant.schema_name))
예제 #39
0
    def handle(self, *args, **options):
        super().handle(*args, **options)
        self.PUBLIC_SCHEMA_NAME = get_public_schema_name()

        if self.sync_public and not self.schema_name:
            self.schema_name = self.PUBLIC_SCHEMA_NAME

        executor = get_executor(codename=self.executor)(self.args,
                                                        self.options)

        if self.sync_public:
            executor.run_migrations(tenants=[self.PUBLIC_SCHEMA_NAME])
        if self.sync_tenant:
            if self.schema_name and self.schema_name != self.PUBLIC_SCHEMA_NAME:
                if not schema_exists(self.schema_name,
                                     self.options.get('database', None)):
                    raise RuntimeError('Schema "{}" does not exist'.format(
                        self.schema_name))
                elif has_multi_type_tenants():
                    type_field_name = get_multi_type_database_field_name()
                    tenants = get_tenant_model().objects.only('schema_name', type_field_name)\
                        .filter(schema_name=self.schema_name)\
                        .values_list('schema_name', type_field_name)
                    executor.run_multi_type_migrations(tenants=tenants)
                else:
                    tenants = [self.schema_name]
                    executor.run_migrations(tenants=tenants)
            else:
                if has_multi_type_tenants():
                    type_field_name = get_multi_type_database_field_name()
                    tenants = get_tenant_model().objects.only('schema_name', type_field_name)\
                        .exclude(schema_name=self.PUBLIC_SCHEMA_NAME)\
                        .values_list('schema_name', type_field_name)
                    executor.run_multi_type_migrations(tenants=tenants)
                else:
                    tenants = get_tenant_model().objects.only(
                        'schema_name').exclude(
                            schema_name=self.PUBLIC_SCHEMA_NAME).values_list(
                                'schema_name', flat=True)
                    executor.run_migrations(tenants=tenants)
예제 #40
0
    def ready(self):
        from django.db import connections

        # Test for configuration recommendations. These are best practices,
        # they avoid hard to find bugs and unexpected behaviour.
        if not hasattr(settings, 'TENANT_APPS'):
            raise ImproperlyConfigured('TENANT_APPS setting not set')

        if not settings.TENANT_APPS:
            raise ImproperlyConfigured("TENANT_APPS is empty. "
                                       "Maybe you don't need this app?")

        if not hasattr(settings, 'TENANT_MODEL'):
            raise ImproperlyConfigured('TENANT_MODEL setting not set')

        if not hasattr(settings, 'TENANT_SESSION_KEY'):
            setattr(settings, 'TENANT_SESSION_KEY', 'tenant_schema')

        if not hasattr(settings, 'TENANT_SELECTION_METHOD'):
            setattr(settings, 'TENANT_SELECTION_METHOD', 'domain')

        if not hasattr(settings, 'TENANT_DATABASE'):
            setattr(settings, 'TENANT_DATABASE', 'default')

        if 'django_tenants.routers.TenantSyncRouter' not in settings.DATABASE_ROUTERS:
            raise ImproperlyConfigured(
                "DATABASE_ROUTERS setting must contain "
                "'django_tenants.routers.TenantSyncRouter'.")

        if hasattr(settings, 'PG_EXTRA_SEARCH_PATHS'):
            if get_public_schema_name() in settings.PG_EXTRA_SEARCH_PATHS:
                raise ImproperlyConfigured(
                    "%s can not be included on PG_EXTRA_SEARCH_PATHS." %
                    get_public_schema_name())

            # make sure no tenant schema is in settings.PG_EXTRA_SEARCH_PATHS

            # first check that the model table is created
            model = get_tenant_model()
            c = connections[DEFAULT_DB_ALIAS].cursor()
            c.execute(
                'SELECT 1 FROM information_schema.tables WHERE table_name = %s;',
                [model._meta.db_table])
            if c.fetchone():
                invalid_schemas = set(
                    settings.PG_EXTRA_SEARCH_PATHS).intersection(
                        model.objects.all().values_list('schema_name',
                                                        flat=True))
                if invalid_schemas:
                    raise ImproperlyConfigured(
                        "Do not include tenant schemas (%s) on PG_EXTRA_SEARCH_PATHS."
                        % list(invalid_schemas))
예제 #41
0
    def setup_test_tenant_and_domain(cls):
        cls.tenant, created_tenant = get_tenant_model().objects.get_or_create(
            schema_name=cls.get_test_schema_name())
        cls.setup_tenant(cls.tenant)
        # cls.tenant.save(verbosity=cls.get_verbosity())

        # Set up domain
        tenant_domain = cls.get_test_tenant_domain()
        cls.domain, created_domain = get_tenant_domain_model(
        ).objects.get_or_create(tenant=cls.tenant, domain=tenant_domain)
        cls.setup_domain(cls.domain)
        # cls.domain.save()
        cls.use_new_tenant()
예제 #42
0
 def get_tenant(self, tenant_model, user):
     try:
         return super(DefaultTenantMiddleware,
                      self).get_tenant(tenant_model, user)
     except self.TENANT_NOT_FOUND_EXCEPTION or self.NO_TENANT_EXCEPTION:
         schema_name = self.DEFAULT_SCHEMA_NAME
         if not schema_name:
             schema_name = get_public_schema_name()
         tenant_model = get_tenant_model()
         return tenant_model.objects.get(schema_name=schema_name)
     except Exception as e:
         print(e)
         print(e.message)
예제 #43
0
    def setUp(self):
        self.sync_shared()
        self.tenant = get_tenant_model()(schema_name=self.get_test_schema_name())
        self.setup_tenant(self.tenant)
        self.tenant.save(verbosity=0)  # todo: is there any way to get the verbosity from the test command here?

        # Set up domain
        tenant_domain = self.get_test_tenant_domain()
        self.domain = get_tenant_domain_model()(tenant=self.tenant, domain=tenant_domain)
        self.setup_domain(self.domain)
        self.domain.save()

        connection.set_tenant(self.tenant)
예제 #44
0
 def setUpClass(cls):
     super(RoutesTestCase, cls).setUpClass()
     settings.SHARED_APPS = ('django_tenants',
                             'customers')
     settings.TENANT_APPS = ('dts_test_app',
                             'django.contrib.contenttypes',
                             'django.contrib.auth', )
     settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
     cls.sync_shared()
     cls.public_tenant = get_tenant_model()(schema_name=get_public_schema_name())
     cls.public_tenant.save()
     cls.public_domain = get_tenant_domain_model()(domain='test.com', tenant=cls.public_tenant)
     cls.public_domain.save()
예제 #45
0
    def setUpClass(cls):
        super(SharedAuthTest, cls).setUpClass()

        settings.SHARED_APPS = (
            'django_tenants',
            'customers',
            'django.contrib.auth',
            'django.contrib.contenttypes',
        )
        settings.TENANT_APPS = ('dts_test_app', )
        settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
        cls.sync_shared()
        tenant = get_tenant_model()(schema_name=get_public_schema_name())
        tenant.save()
        domain = get_tenant_domain_model()(tenant=tenant, domain='test.com')
        domain.save()

        # Create a tenant
        cls.tenant = get_tenant_model()(schema_name='tenant')
        cls.tenant.save()
        cls.domain = get_tenant_domain_model()(tenant=cls.tenant,
                                               domain='tenant.test.com')
        cls.domain.save()

        # Create some users
        with schema_context(get_public_schema_name(
        )):  # this could actually also be executed inside a tenant
            cls.user1 = User(username='******', email="*****@*****.**")
            cls.user1.save()
            cls.user2 = User(username='******', email="*****@*****.**")
            cls.user2.save()

        # Create instances on the tenant that point to the users on public
        with tenant_context(cls.tenant):
            cls.d1 = ModelWithFkToPublicUser(user=cls.user1)
            cls.d1.save()
            cls.d2 = ModelWithFkToPublicUser(user=cls.user2)
            cls.d2.save()
예제 #46
0
    def setUpClass(cls):
        super().setUpClass()
        settings.SHARED_APPS = ('django_tenants',
                                'customers')
        settings.TENANT_APPS = ('dts_test_app',
                                'django.contrib.contenttypes',
                                'django.contrib.auth', )
        settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
        cls.sync_shared()

        cls.public_tenant = get_tenant_model()(schema_name=get_public_schema_name())
        cls.public_tenant.save()
        cls.public_domain = get_tenant_domain_model()(tenant=cls.public_tenant, domain='test.com')
        cls.public_domain.save()
예제 #47
0
    def setUpClass(cls):
        super(TenantDataAndSettingsTest, cls).setUpClass()
        settings.SHARED_APPS = ('django_tenants',
                                'customers')
        settings.TENANT_APPS = ('dts_test_app',
                                'django.contrib.contenttypes',
                                'django.contrib.auth', )
        settings.INSTALLED_APPS = settings.SHARED_APPS + settings.TENANT_APPS
        cls.sync_shared()

        tenant = get_tenant_model()(schema_name=get_public_schema_name())
        tenant.save()
        domain = get_tenant_domain_model()(tenant=tenant, domain='test.com')
        domain.save()
예제 #48
0
    def test_switching_tenant_without_previous_tenant(self):
        tenant = get_tenant_model()(schema_name='test')
        tenant.save()

        domain = get_tenant_domain_model()(tenant=tenant, domain='something.test.com')
        domain.save()

        connection.tenant = None
        with tenant_context(tenant):
            DummyModel(name="No exception please").save()

        connection.tenant = None
        with schema_context(tenant.schema_name):
            DummyModel(name="Survived it!").save()
예제 #49
0
    def setUp(self):
        super().setUp()
        self.factory = RequestFactory()
        self.tm = TenantMainMiddleware(lambda r: r)
        print(settings.INSTALLED_APPS)
        self.public_tenant = get_tenant_model()(schema_name=get_public_schema_name(),
                                                type='public')
        self.public_tenant.save()
        self.public_domain = get_tenant_domain_model()(domain='test.com',
                                                       tenant=self.public_tenant)
        self.public_domain.save()
        self.tenant_domain = 'tenant.test.com'
        self.tenant = get_tenant_model()(schema_name='test')
        self.tenant.save()
        self.domain = get_tenant_domain_model()(tenant=self.tenant, domain=self.tenant_domain)
        self.domain.save()

        self.tenant_domain2 = 'tenant2.test.com'
        self.tenant2 = get_tenant_model()(schema_name='test2',
                                          type='type2')
        self.tenant2.save()
        self.domain2 = get_tenant_domain_model()(tenant=self.tenant2, domain=self.tenant_domain2)
        self.domain2.save()
예제 #50
0
    def test_non_auto_sync_tenant(self):
        """
        When saving a tenant that has the flag auto_create_schema as
        False, the schema should not be created when saving the tenant.
        """

        tenant = get_tenant_model()(schema_name='test')
        tenant.auto_create_schema = False
        tenant.save()

        domain = get_tenant_domain_model()(tenant=tenant, domain='something.test.com')
        domain.save()

        self.assertFalse(schema_exists(tenant.schema_name))
예제 #51
0
    def setUpClass(cls):
        cls.sync_shared()
        cls.add_allowed_test_domain()
        cls.tenant = get_tenant_model()(schema_name=cls.get_test_schema_name())
        cls.setup_tenant(cls.tenant)
        cls.tenant.save(verbosity=cls.get_verbosity())

        # Set up domain
        tenant_domain = cls.get_test_tenant_domain()
        cls.domain = get_tenant_domain_model()(tenant=cls.tenant, domain=tenant_domain)
        cls.setup_domain(cls.domain)
        cls.domain.save()

        connection.set_tenant(cls.tenant)
예제 #52
0
    def __call__(self, request):
        # Short circuit if tenant is already set by another middleware.
        # This allows for multiple tenant-resolving middleware chained together.
        if hasattr(request, "tenant"):
            return

        connection.set_schema_to_public()

        urlconf = None

        tenant_model = get_tenant_model()
        domain_model = get_tenant_domain_model()
        hostname = self.hostname_from_request(request)
        subfolder_prefix_path = "/{}/".format(get_subfolder_prefix())

        # We are in the public tenant
        if not request.path.startswith(subfolder_prefix_path):
            try:
                tenant = tenant_model.objects.get(
                    schema_name=get_public_schema_name())
            except tenant_model.DoesNotExist:
                raise self.TENANT_NOT_FOUND_EXCEPTION(
                    "Unable to find public tenant")

            request.urlconf = settings.PUBLIC_SCHEMA_URLCONF

        # We are in a specific tenant
        else:
            path_chunks = request.path[len(subfolder_prefix_path):].split("/")
            tenant_subfolder = path_chunks[0]
            try:
                tenant = self.get_tenant(domain_model=domain_model,
                                         hostname=tenant_subfolder)
            except domain_model.DoesNotExist:
                return self.no_tenant_found(request, hostname)

            tenant.domain_subfolder = tenant_subfolder
            urlconf = get_subfolder_urlconf(tenant)

        tenant.domain_url = hostname
        request.tenant = tenant

        connection.set_tenant(request.tenant)
        clear_url_caches(
        )  # Required to remove previous tenant prefix from cache, if present

        if urlconf:
            request.urlconf = urlconf
            set_urlconf(urlconf)
        return self.get_response(request)
예제 #53
0
    def setUpClass(cls):
        cls.sync_shared()
        cls.add_allowed_test_domain()
        cls.tenant = get_tenant_model()(schema_name=cls.get_test_schema_name())
        cls.setup_tenant(cls.tenant)
        cls.tenant.save(verbosity=cls.get_verbosity())

        # Set up domain
        tenant_domain = cls.get_test_tenant_domain()
        cls.domain = get_tenant_domain_model()(tenant=cls.tenant, domain=tenant_domain)
        cls.setup_domain(cls.domain)
        cls.domain.save()

        connection.set_tenant(cls.tenant)
예제 #54
0
    def ready(self):
        from django.db import connections

        # Test for configuration recommendations. These are best practices,
        # they avoid hard to find bugs and unexpected behaviour.
        if not hasattr(settings, 'TENANT_APPS'):
            raise ImproperlyConfigured('TENANT_APPS setting not set')

        if not settings.TENANT_APPS:
            raise ImproperlyConfigured("TENANT_APPS is empty. "
                                       "Maybe you don't need this app?")

        if not hasattr(settings, 'TENANT_MODEL'):
            raise ImproperlyConfigured('TENANT_MODEL setting not set')

        if not hasattr(settings, 'TENANT_SESSION_KEY'):
            setattr(settings, 'TENANT_SESSION_KEY', 'tenant_schema')

        if not hasattr(settings, 'TENANT_SELECTION_METHOD'):
            setattr(settings, 'TENANT_SELECTION_METHOD', 'domain')

        if not hasattr(settings, 'TENANT_DATABASE'):
            setattr(settings, 'TENANT_DATABASE', 'default')

        if 'django_tenants.routers.TenantSyncRouter' not in settings.DATABASE_ROUTERS:
            raise ImproperlyConfigured("DATABASE_ROUTERS setting must contain "
                                       "'django_tenants.routers.TenantSyncRouter'.")

        if hasattr(settings, 'PG_EXTRA_SEARCH_PATHS'):
            if get_public_schema_name() in settings.PG_EXTRA_SEARCH_PATHS:
                raise ImproperlyConfigured(
                    "%s can not be included on PG_EXTRA_SEARCH_PATHS."
                    % get_public_schema_name())

            # make sure no tenant schema is in settings.PG_EXTRA_SEARCH_PATHS

            # first check that the model table is created
            model = get_tenant_model()
            c = connections[DEFAULT_DB_ALIAS].cursor()
            c.execute(
                'SELECT 1 FROM information_schema.tables WHERE table_name = %s;',
                [model._meta.db_table]
            )
            if c.fetchone():
                invalid_schemas = set(settings.PG_EXTRA_SEARCH_PATHS).intersection(
                    model.objects.all().values_list('schema_name', flat=True))
                if invalid_schemas:
                    raise ImproperlyConfigured(
                        "Do not include tenant schemas (%s) on PG_EXTRA_SEARCH_PATHS."
                        % list(invalid_schemas))
예제 #55
0
    def test_content_types_is_not_mandatory(self):
        """
        Tests that even if content types is in SHARED_APPS, it's
        not required in TENANT_APPS.
        """
        tenant = get_tenant_model()(schema_name='test')
        tenant.save()
        domain = get_tenant_domain_model()(tenant=tenant, domain='something.test.com')
        domain.save()

        shared_tables = self.get_tables_list_in_schema(get_public_schema_name())
        tenant_tables = self.get_tables_list_in_schema(tenant.schema_name)
        self.assertEqual(2+1 + self.MIGRATION_TABLE_SIZE, len(shared_tables))
        self.assertIn('django_session', tenant_tables)
        self.assertEqual(1+self.MIGRATION_TABLE_SIZE, len(tenant_tables))
        self.assertIn('django_session', tenant_tables)
예제 #56
0
    def handle(self, *args, **options):
        if not options.get('schema_name'):
            TenantModel = get_tenant_model()
            all_tenants = TenantModel.objects.all().order_by("schema_name")
            schema_name_start = options.get('schema_name_start')
            execute = False
            for tenant in all_tenants:
                if schema_name_start and schema_name_start != tenant.schema_name and execute is False:
                    # print "skipe: {}".format(tenant.schema_name)
                    continue
                else:
                    execute = True

                if execute:
                    self.on_execute_command(tenant, args, options)
        else:
            super(SingleOrAllTenantWrappedCommand, self).handle(*args, **options)
예제 #57
0
    def store_tenant(self, clone_schema_from, **fields):
        connections[DEFAULT_DB_ALIAS].set_schema_to_public()
        cursor = connections[settings.TENANT_DATABASE].cursor()

        try:
            tenant = get_tenant_model()(**fields)
            tenant.auto_create_schema = False
            tenant.save()

            clone_schema = CloneSchema(cursor)
            clone_schema.clone(clone_schema_from, tenant.schema_name)
            return tenant
        except exceptions.ValidationError as e:
            self.stderr.write("Error: %s" % '; '.join(e.messages))
            return None
        except IntegrityError:
            return None
예제 #58
0
    def test_tenant_apps_and_shared_apps_can_have_the_same_apps(self):
        """
        Tests that both SHARED_APPS and TENANT_APPS can have apps in common.
        In this case they should get synced to both tenant and public schemas.
        """
        tenant = get_tenant_model()(schema_name='test')
        tenant.save()

        domain = get_tenant_domain_model()(tenant=tenant, domain='arbitrary.test.com')
        domain.save()

        shared_tables = self.get_tables_list_in_schema(get_public_schema_name())
        tenant_tables = self.get_tables_list_in_schema(tenant.schema_name)
        self.assertEqual(2+6+1+1+self.MIGRATION_TABLE_SIZE, len(shared_tables))
        self.assertIn('django_session', shared_tables)
        self.assertEqual(1+self.MIGRATION_TABLE_SIZE, len(tenant_tables))
        self.assertIn('django_session', tenant_tables)
예제 #59
0
    def test_tenant_apps_does_not_sync_shared_apps(self):
        """
        Tests that if an app is in TENANT_APPS, it does not get synced to
        the public schema.
        """
        tenant = get_tenant_model()(schema_name='test')
        tenant.save()

        domain = get_tenant_domain_model()(tenant=tenant, domain='arbitrary.test.com')
        domain.save()

        tenant_tables = self.get_tables_list_in_schema(tenant.schema_name)
        self.assertEqual(1+self.MIGRATION_TABLE_SIZE, len(tenant_tables))
        self.assertIn('django_session', tenant_tables)

        connection.set_schema_to_public()
        domain.delete()
        tenant.delete(force_drop=True)
예제 #60
0
파일: cases.py 프로젝트: unicef/etools
    def setUpClass(cls):
        # This replaces TestCase.setUpClass so that we can do some setup in
        # different schemas.
        # It also drops the check whether the database supports transactions.
        cls.sync_shared()

        EmailTemplate.objects.get_or_create(name='audit/staff_member/invite')
        EmailTemplate.objects.get_or_create(name='audit/engagement/submit_to_auditor')

        TenantModel = get_tenant_model()
        try:
            cls.tenant = TenantModel.objects.get(schema_name=SCHEMA_NAME)
        except TenantModel.DoesNotExist:
            cls.tenant = TenantModel(schema_name=SCHEMA_NAME)
            cls.tenant.save(verbosity=0)

        cls.tenant.business_area_code = 'ZZZ'
        # Make sure country has a short code, it affects some results
        cls.tenant.country_short_code = 'TST'
        cls.tenant.save(verbosity=0)

        cls.domain = get_tenant_domain_model().objects.get_or_create(domain=TENANT_DOMAIN, tenant=cls.tenant)

        try:
            cls.tenant.counters
        except ObjectDoesNotExist:
            WorkspaceCounter.objects.create(workspace=cls.tenant)

        cls.cls_atomics = cls._enter_atomics()

        # Load fixtures for shared schema
        cls._load_fixtures()

        connection.set_tenant(cls.tenant)

        # Load fixtures for tenant schema
        cls._load_fixtures()

        try:
            cls.setUpTestData()
        except Exception:
            cls._rollback_atomics(cls.cls_atomics)
            raise