示例#1
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'))
示例#2
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.
        """
        self.assertFalse(schema_exists('non_auto_sync_tenant'))

        tenant = NonAutoSyncTenant(domain_urls=['something.test.com'],
                                   schema_name='test')
        tenant.save()

        self.assertFalse(schema_exists(tenant.schema_name))
示例#3
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.
        """
        self.assertFalse(schema_exists('non_auto_sync_tenant'))

        tenant = NonAutoSyncTenant(domain_urls=['something.test.com'],
                                   schema_name='test')
        tenant.save()

        self.assertFalse(schema_exists(tenant.schema_name))
示例#4
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))
示例#5
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()
示例#6
0
    def test_tenant_schema_creation_with_only_numbers_name(self):
        tenant = get_tenant_model()(schema_name='123')
        tenant.save()

        self.assertTrue(schema_exists(tenant.schema_name))

        self.created = [tenant]
示例#7
0
    def test_tenant_schema_creation_with_sql_keyword_name(self):
        tenant = get_tenant_model()(schema_name='select')
        tenant.save()

        self.assertTrue(schema_exists(tenant.schema_name))

        self.created = [tenant]
    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)
            tenant_objects = get_tenant_model().objects.filter(schema_name__in=tenants)

            for tenant in tenant_objects:
                if not isinstance(tenant, TenantMixin):
                    continue
                post_schema_migrate.send(sender=TenantMixin, tenant=tenant.serializable_fields())
示例#9
0
    def clone_schema(self,
                     base_schema_name,
                     new_schema_name,
                     set_connection=True):
        """
        Creates a new schema `new_schema_name` as a clone of an existing schema
        `old_schema_name`.
        """
        if set_connection:
            connection.set_schema_to_public()
        cursor = connection.cursor()

        # check if the clone_schema function already exists in the db
        try:
            cursor.execute("SELECT 'clone_schema'::regproc")
        except ProgrammingError:
            self._create_clone_schema_function()
            transaction.commit()

        if schema_exists(new_schema_name):
            raise ValidationError("New schema name already exists")

        sql = 'SELECT clone_schema(%(base_schema)s, %(new_schema)s, true, false)'
        cursor.execute(sql, {
            'base_schema': base_schema_name,
            'new_schema': new_schema_name
        })
        cursor.close()
示例#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 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()
示例#12
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)
示例#13
0
    def create_schema(self, check_if_exists=False, sync_schema=True,
                      verbosity=1):
        """
        Creates the schema 'schema_name' for this tenant. Optionally checks if
        the schema already exists before creating it. Returns true if the
        schema was created, false otherwise.
        """

        # safety check
        _check_schema_name(self.schema_name)
        cursor = connection.cursor()

        if check_if_exists and schema_exists(self.schema_name):
            return False

        # create the schema
        cursor.execute('CREATE SCHEMA %s' % self.schema_name)

        if sync_schema:
            call_command('migrate_schemas',
                         schema_name=self.schema_name,
                         interactive=False,
                         verbosity=verbosity)

        connection.set_schema_to_public()
示例#14
0
    def test_tenant_schema_is_created(self):
        """
        When saving a tenant, it's schema should be created.
        """
        tenant = Tenant(domain_urls=['something.test.com'], schema_name='test')
        tenant.save()

        self.assertTrue(schema_exists(tenant.schema_name))
示例#15
0
    def test_tenant_schema_is_created(self):
        """
        When saving a tenant, it's schema should be created.
        """
        tenant = Tenant(domain_urls=['something.test.com'], schema_name='test')
        tenant.save()

        self.assertTrue(schema_exists(tenant.schema_name))
示例#16
0
    def test_tenant_schema_creation_with_special_chars(self):
        """Tests using special characters in schema name."""
        schema_names = ('test-hyphen', 'test@at', 'test`backtick')

        Client = get_tenant_model()
        for schema_name in schema_names:
            tenant = Client(schema_name=schema_name)
            tenant.save()
            self.assertTrue(schema_exists(tenant.schema_name))
示例#17
0
    def handle(self, *args, **options):
        tenants = get_tenant_model().objects.all()
        for tenant in tenants:
            if not schema_exists(schema_name=tenant.schema_name):
                self.stdout.write(
                    self.style.NOTICE("Missing '%s' schema lets create it" %
                                      tenant.schema_name))
                tenant.create_schema()

        self.stdout.write("Done")
示例#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 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))
示例#20
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))
示例#21
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:
                migration_order = get_tenant_migration_order()

                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)

                    if migration_order is not None:
                        tenants = tenants.order_by(*migration_order)

                    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)

                    if migration_order is not None:
                        tenants = tenants.order_by(*migration_order)

                    executor.run_migrations(tenants=tenants)
示例#22
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))
示例#23
0
    def delete(self, force_drop=False, *args, **kwargs):
        """
        Deletes this row. Drops the tenant's schema if the attribute
        auto_drop_schema set to True.
        """
        if connection.schema_name not in (self.schema_name, get_public_schema_name()):
            raise Exception("Can't delete tenant outside it's own schema or "
                            "the public schema. Current schema is %s."
                            % connection.schema_name)

        if schema_exists(self.schema_name) and (self.auto_drop_schema or force_drop):
            cursor = connection.cursor()
            cursor.execute('DROP SCHEMA %s CASCADE' % self.schema_name)

        super(TenantMixin, self).delete(*args, **kwargs)
示例#24
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

        if self.sync_public:
            self.run_migrations(self.schema_name, settings.SHARED_APPS, options)
        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:
                    self.run_migrations(self.schema_name, settings.TENANT_APPS, options)
            else:
                all_tenants = get_tenant_model().objects.exclude(schema_name=get_public_schema_name())
                for tenant in all_tenants:
                    self.run_migrations(tenant.schema_name, settings.TENANT_APPS, options)
示例#25
0
    def store_tenant(self, clone_schema_from, **fields):
        connection.set_schema_to_public()
        cursor = connection.cursor()

        tm = get_tenant_model()

        try:
            if schema_exists(fields["schema_name"]):
                raise exceptions.ValidationError(
                    "Error: Schema %s already exists." % fields["schema_name"])
            try:
                tenant = tm.objects.get(schema_name=fields["schema_name"])
                # IMPORTANT: Enter here, only if the row in table 'Tenant Model' exists
                # and the Schema Postgre not.
                # If the schema exists one exception will be thrown and
                # one new row on table 'Tenants' will be created.
                tm.objects.filter(id=tenant.id).update(**fields)
            except tm.DoesNotExist:
                tenant = tm(**fields)
                tenant.auto_create_schema = False
                tenant.save()

            clone_schema = CloneSchema(cursor)
            clone_schema.clone(clone_schema_from, tenant.schema_name)
            return tenant

        # 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 as e:
            self.stderr.write("Error: %s" % e.message)
            return None
示例#26
0
    def store_tenant(self, clone_schema_from, **fields):
        connection.set_schema_to_public()
        cursor = connection.cursor()

        tm = get_tenant_model()

        try:
            if schema_exists(fields["schema_name"]):
                raise exceptions.ValidationError("Error: Schema %s already exists." %
                                                 fields["schema_name"])
            try:
                tenant = tm.objects.get(schema_name=fields["schema_name"])
                # IMPORTANT: Enter here, only if the row in table 'Tenant Model' exists
                # and the Schema Postgre not.
                # If the schema exists one exception will be thrown and
                # one new row on table 'Tenants' will be created.
                tm.objects.filter(id=tenant.id).update(**fields)
            except tm.DoesNotExist:
                tenant = tm(**fields)
                tenant.auto_create_schema = False
                tenant.save()

            clone_schema = CloneSchema(cursor)
            clone_schema.clone(clone_schema_from, tenant.schema_name)
            return tenant

        # 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 as e:
            self.stderr.write("Error: %s" % e.message)
            return None
示例#27
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

        if self.sync_public:
            self.run_migrations(self.schema_name, settings.SHARED_APPS,
                                options)
        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:
                    self.run_migrations(self.schema_name, settings.TENANT_APPS,
                                        options)
            else:
                all_tenants = get_tenant_model().objects.exclude(
                    schema_name=get_public_schema_name())
                for tenant in all_tenants:
                    self.run_migrations(tenant.schema_name,
                                        settings.TENANT_APPS, options)
示例#28
0
def tenant_delete_callback(sender, instance, **kwargs):
    if not isinstance(instance, get_tenant_model()):
        return

    if instance.auto_drop_schema and schema_exists(instance.schema_name):
        instance._drop_schema(True)
def school_add_save(request):
    if request.is_ajax():
        if request.method == "POST":
            form = SchoolAddForm(request.POST)
            if form.is_valid():
                data = form.cleaned_data
                #tenant related data
                school_name = data.get('school_name')
                subdomain = data.get('subdomain')
                description = data.get('description')
                on_trial = data.get('ontrial')
                active_until = data.get('active_until')

                # user related data
                admin_email = data.get('email')
                phone = data.get('phone')
                username = data.get('username')
                password = data.get('password')

                if not special_match(subdomain):
                    return HttpResponse(2)  # special character is found

                if schema_exists(subdomain):
                    return HttpResponse(3)  # client already exist
                else:
                    tenant = Client(schema_name=subdomain,
                                    name=subdomain,
                                    description=description,
                                    on_trial=False,
                                    active_until=active_until)
                    tenant.save(
                    )  # migrate_schemas will automatically be called

                    # Create Domain
                    domain = Domain()
                    domain.domain = '{}.bitpoint.com'.format(subdomain)
                    domain.tenant = tenant
                    domain.is_primary = True
                    domain.save()

                    with schema_context(tenant.schema_name):
                        admin = User.objects.create_superuser(
                            username=username,
                            password=password,
                            email=admin_email,
                            phone=phone)
                        Setting.objects.create(school_name=school_name,
                                               business_email=admin_email,
                                               business_phone1=phone).save()
                        Notification.objects.create(
                            user=admin,
                            title='Welcome to Bitpoint inc.',
                            body='Hello {} and  Welcome to Bitpoint Inc., \
                                  we wish you and the entire a happy schooling. \
                                  Thank you for choosing bitpoint',
                            message_type='Info')
                        message = 'Dear {}, Welcome to Bitpoint inc.,\
                                    please login to http://{}/app\
                                    using username: {} and password: {}\
                                    '.format(school_name, domain.domain,
                                             username, password)
                        send_sms(phone=phone, msg=message)
                    tenant.school_admin = admin
                    tenant.save()
                    return HttpResponse('success')
            else:
                form = SchoolAddForm(request.POST)
                template = "authenticated/ajax/school_add_form_not_valid.html"
                context = {
                    "form": form,
                }
                return render(request, template, context)
        else:
            return HttpResponse('Get')