def test_auto_drop_schema_bulk_delete(self):
        """
        When bulk deleting tenants, it should also drop the schemas of
        tenants that have auto_drop_schema set to True.
        """
        Tenant.auto_drop_schema = True
        schemas = ['auto_drop_schema1', 'auto_drop_schema2']
        for schema in schemas:
            self.assertFalse(schema_exists(schema))
            tenant = Tenant(
                domain_url='%s.test.com' % schema,
                schema_name=schema
            )
            tenant.save(verbosity=BaseTestCase.get_verbosity())
            self.assertTrue(schema_exists(tenant.schema_name))

        # Force pending trigger events to be executed
        cursor = connection.cursor()
        cursor.execute('SET CONSTRAINTS ALL IMMEDIATE')

        # get a queryset of our 2 tenants and do a bulk delete
        Tenant.objects.filter(schema_name__in=schemas).delete()

        # verify that the schemas where deleted
        for schema in schemas:
            self.assertFalse(schema_exists(schema))

        Tenant.auto_drop_schema = False
示例#2
0
    def test_auto_drop_schema_bulk_delete(self):
        """
        When bulk deleting tenants, it should also drop the schemas of
        tenants that have auto_drop_schema set to True.
        """
        Tenant.auto_drop_schema = True
        schemas = ['auto_drop_schema1', 'auto_drop_schema2']
        for schema in schemas:
            self.assertFalse(schema_exists(schema))
            tenant = Tenant(domain_url='%s.test.com' % schema,
                            schema_name=schema)
            tenant.save(verbosity=BaseTestCase.get_verbosity())
            self.assertTrue(schema_exists(tenant.schema_name))

        # Force pending trigger events to be executed
        cursor = connection.cursor()
        cursor.execute('SET CONSTRAINTS ALL IMMEDIATE')

        # get a queryset of our 2 tenants and do a bulk delete
        Tenant.objects.filter(schema_name__in=schemas).delete()

        # verify that the schemas where deleted
        for schema in schemas:
            self.assertFalse(schema_exists(schema))

        Tenant.auto_drop_schema = False
示例#3
0
    def test_create_template_schema(self):
        """
        Test that the template schema can be created directly or indirectly
        """
        Tenant.objects.filter(schema_name=Tenant._TEMPLATE_SCHEMA).delete()
        self.assertFalse(schema_exists(Tenant._TEMPLATE_SCHEMA))

        # Also validate that the template will be created using migrations
        expected = f'INFO:api.iam.models:Using superclass for "{Tenant._TEMPLATE_SCHEMA}" schema creation'
        with self.assertLogs("api.iam.models", level="INFO") as _logger:
            Tenant(schema_name=Tenant._TEMPLATE_SCHEMA).save()
            self.assertIn(expected, _logger.output)
        self.assertTrue(schema_exists(Tenant._TEMPLATE_SCHEMA))

        Tenant.objects.filter(schema_name=Tenant._TEMPLATE_SCHEMA).delete()
        self.assertFalse(schema_exists(Tenant._TEMPLATE_SCHEMA))

        test_schema = "acct90909090"
        # Also validate that the customer tenant schema will be created using the clone function
        expected1 = (
            f'INFO:api.iam.models:Cloning template schema "{Tenant._TEMPLATE_SCHEMA}" to "{test_schema}" with data'
        )
        expected2 = f'INFO:api.iam.models:Successful clone of "{Tenant._TEMPLATE_SCHEMA}" to "{test_schema}"'
        with self.assertLogs("api.iam.models", level="INFO") as _logger:
            Tenant(schema_name=test_schema).save()
            self.assertIn(expected1, _logger.output)
            self.assertIn(expected2, _logger.output)
        self.assertTrue(schema_exists(Tenant._TEMPLATE_SCHEMA))
        self.assertTrue(schema_exists(test_schema))
 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_url='something.test.com',
                                schema_name='non_auto_sync_tenant')
     tenant.save(verbosity=BaseTestCase.get_verbosity())
     self.assertFalse(schema_exists(tenant.schema_name))
示例#5
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_url='something.test.com',
                                schema_name='non_auto_sync_tenant')
     tenant.save(verbosity=BaseTestCase.get_verbosity())
     self.assertFalse(schema_exists(tenant.schema_name))
    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_url='test.com', schema_name='test')
        tenant.save()

        self.assertFalse(schema_exists(tenant.schema_name))
示例#7
0
    def test_clone_schema_missing_clone_func(self):
        """
        Test that the clone function will be applied if it is missing and the clone will succeed
        """
        _drop_clone_func()
        self.assertFalse(_verify_clone_func())

        test_schema = "acct90909091"
        self.assertFalse(schema_exists(test_schema))
        Tenant(schema_name=test_schema).save()
        self.assertTrue(_verify_clone_func())
        self.assertTrue(schema_exists(test_schema))
示例#8
0
    def test_tenant_object_delete_leaves_template(self):
        """
        Test that deleting a customer schema will leave the template schema untouched
        """
        cust_tenant = "acct90909093"
        self.assertFalse(schema_exists(cust_tenant))
        self.assertTrue(schema_exists(Tenant._TEMPLATE_SCHEMA))

        Tenant(schema_name=cust_tenant).save()
        self.assertTrue(schema_exists(cust_tenant))

        Tenant.objects.filter(schema_name=cust_tenant).delete()
        self.assertFalse(schema_exists(cust_tenant))
        self.assertTrue(schema_exists(Tenant._TEMPLATE_SCHEMA))
示例#9
0
    def test_has_template_rec_missing_template_schema(self):
        """
        Test that am existing template tenant record with a missing tenant schema will throw an exception
        """
        _drop_template_schema()
        self.assertFalse(schema_exists(Tenant._TEMPLATE_SCHEMA))

        test_schema = "acct90909092"
        with self.assertRaises(CloneSchemaTemplateMissing):
            Tenant(schema_name=test_schema).save()

        Tenant.objects.filter(schema_name=Tenant._TEMPLATE_SCHEMA).delete()
        Tenant(schema_name=test_schema).save()
        self.assertTrue(schema_exists(test_schema))
        self.assertTrue(schema_exists(Tenant._TEMPLATE_SCHEMA))
示例#10
0
    def process_exception(self, request, exception):
        if isinstance(exception, (Tenant.DoesNotExist, ProgrammingError)):
            if (settings.ROOT_URLCONF == "koku.urls"
                    and request.path in reverse("settings")
                    and (not schema_exists(request.tenant.schema_name)
                         or request.tenant.schema_name == "public")):

                doc_link = generate_doc_link("/")

                err_page = {
                    "name":
                    "middleware.settings.err",
                    "component":
                    "error-state",
                    "errorTitle":
                    "Configuration Error",
                    "errorDescription":
                    f"Before adding settings you must create a Source for Cost Management. "
                    f"<br /><span><a href={doc_link}>[Learn more]</a></span>",
                }

                return JsonResponse([{
                    "fields": [err_page],
                    "formProps": {
                        "showFormControls": False
                    }
                }],
                                    safe=False,
                                    status=200)

            paginator = EmptyResultsSetPagination([], request)
            return paginator.get_paginated_response()
示例#11
0
    def handle(self, *args, **options):
        super(migrate_schemas.Command, self).handle(*args, **options)
        self.PUBLIC_SCHEMA_NAME = get_public_schema_name()

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

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

        if self.sync_public:
            executor.run_migrations(tenants=[self.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):
                    msg = f"Schema {self.schema_name} does not exist, skipping."
                    LOG.info(msg)
                else:
                    tenants = [self.schema_name]
            else:
                from django.db.models.expressions import RawSQL

                tenant_model = get_tenant_model()
                tenants = list(
                    tenant_model.objects.filter(schema_name__in=RawSQL(
                        """
                                SELECT nspname::text
                                FROM pg_catalog.pg_namespace
                                WHERE nspname = %s
                                    OR nspname ~ '^acct'
                            """,
                        (tenant_model._TEMPLATE_SCHEMA, ),
                    )).values_list("schema_name", flat=True))
            executor.run_migrations(tenants=tenants)
    def handle(self, *args, **options):
        super(Command, self).handle(*args, **options)
        self.PUBLIC_SCHEMA_NAME = get_public_schema_name()

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

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

        if self.sync_public:
            executor.run_migrations(tenants=[self.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 MigrationSchemaMissing(
                        'Schema "{}" does not exist'.format(self.schema_name)
                    )
                else:
                    tenants = [self.schema_name]
            else:
                tenants = (
                    get_tenant_model()
                        .objects.exclude(schema_name=get_public_schema_name())
                        .values_list("schema_name", flat=True)
                )
            executor.run_migrations(tenants=tenants)
示例#13
0
 def post(self, request):
     kwargs = {
         'active_menu': self.active_menu,
         'url_login_new_schema': None,
         'form_data': request.POST
     }
     tenant_name = request.POST.get('subdomain')
     email = request.POST.get('email')
     password = request.POST.get('password')
     if schema_exists(tenant_name):
         kwargs['tenant_exist'] = True
     else:
         if settings["USE_SSL"]:
             kwargs["protocolo"] = "https"
         else:
             kwargs["protocolo"] = "http"
         client = Client()
         client.domain_url = '{0}.{1}'.format(tenant_name,
                                              request.tenant.domain_url)
         client.name = tenant_name
         client.schema_name = tenant_name
         client.save()  # Ejecutar las migraciones
         with schema_context(tenant_name):
             user = User()
             user.email = email
             user.set_password(password)
             user.is_active = True
             user.is_superuser = True
             user.save()
         url_redirect = "{0}.{1}{2}".format(tenant_name,
                                            request.META['HTTP_HOST'],
                                            reverse('security:login'))
         kwargs['tenant_exist'] = False
         kwargs['url_login_new_schema'] = url_redirect
     return render(request, self.template_name, kwargs)
示例#14
0
def clone_schema(schema_name, clone_schema_name, set_connection=True):
    """
    Creates a full clone of an existing schema.
    """
    # check the clone_schema_name like we usually would
    _check_schema_name(clone_schema_name)
    if schema_exists(clone_schema_name):
        raise ValidationError("Schema name already exists")

    # The schema is changed to public because the clone function should live there.
    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:
        _create_clone_schema_function()
        transaction.commit()

    sql = 'SELECT clone_schema(%(schema_name)s, %(clone_schema_name)s, true, false)'
    cursor.execute(sql, {
        'schema_name': schema_name,
        'clone_schema_name': clone_schema_name
    })
    cursor.close()
示例#15
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()
示例#16
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_identifier(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('sync_schemas',
                         schema_name=self.schema_name,
                         tenant=True,
                         public=False,
                         interactive=False,  # don't ask to create an admin user
                         migrate_all=True,  # migrate all apps directly to last version
                         verbosity=verbosity,
                         )

            # fake all migrations
            if 'south' in settings.INSTALLED_APPS and not django_is_in_test_mode():
                call_command('migrate_schemas', fake=True, schema_name=self.schema_name, verbosity=verbosity)

        connection.set_schema_to_public()
        return True
示例#17
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_identifier(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('sync_schemas',
                schema_name=self.schema_name,
                interactive=False, # don't ask to create an admin user
                migrate_all=True, # migrate all apps directly to last version
                verbosity=verbosity,
            )

            # fake all migrations
            if 'south' in settings.INSTALLED_APPS and not django_is_in_test_mode():
                call_command('migrate_schemas', fake=True, schema_name=self.schema_name, verbosity=verbosity)

        return True
示例#18
0
    def test_nuevo_cliente(self):

        tenant = TenantBuilder(email='*****@*****.**',
                               owner_name='El nombre de la persona',
                               client_name='mi empresa',
                               domain_url='localhost',
                               password='******')
        cliente = tenant.crear()

        self.assertTrue(schema_exists('miempresa'))
        self.assertEqual(cliente.email, '*****@*****.**')
        self.assertEqual(cliente.name, 'mi empresa')
        self.assertEqual(cliente.owner_name, 'El nombre de la persona')
        self.assertEqual(cliente.schema_name, 'miempresa')
        self.assertEqual(cliente.domain_url, 'miempresa.localhost')
        self.assertEqual(cliente.is_active, True)

        self.assertTrue(tenant.usuario_principal)
        self.assertEqual(tenant.get_numero_usuarios(), 1)
        self.assertEqual(tenant.usuario_principal.email,
                         '*****@*****.**')
        self.assertEqual(tenant.usuario_principal.first_name,
                         'El nombre de la persona')
        self.assertEqual(tenant.usuario_principal.last_name, '')
        self.assertTrue(
            check_password('1234', tenant.usuario_principal.password))
示例#19
0
    def create_schema(self, check_if_exists=True, sync_schema=True, verbosity=1):
        """
        If schema is "public" or matches _TEMPLATE_SCHEMA, then use the superclass' create_schema() method.
        Else, verify the template and inputs and use the database clone function.
        """
        if self.schema_name in ("public", self._TEMPLATE_SCHEMA):
            LOG.info(f'Using superclass for "{self.schema_name}" schema creation')
            return super().create_schema(check_if_exists=True, sync_schema=sync_schema, verbosity=verbosity)

        db_exc = None
        # Verify name structure
        if not _is_valid_schema_name(self.schema_name):
            exc = ValidationError(f'Invalid schema name: "{self.schema_name}"')
            LOG.error(f"{exc.__class__.__name__}:: {''.join(exc)}")
            raise exc

        with transaction.atomic():
            # Make sure all of our special pieces are in play
            ret = self._check_clone_func()
            if not ret:
                errmsg = "Missing clone_schema function even after re-applying the function SQL file."
                LOG.critical(errmsg)
                raise CloneSchemaFuncMissing(errmsg)

            ret = self._verify_template(verbosity=verbosity)
            if not ret:
                errmsg = f'Template schema "{self._TEMPLATE_SCHEMA}" does not exist'
                LOG.critical(errmsg)
                raise CloneSchemaTemplateMissing(errmsg)

            # Always check to see if the schema exists!
            LOG.info(f"Check if target schema {self.schema_name} already exists")
            if schema_exists(self.schema_name):
                LOG.warning(f'Schema "{self.schema_name}" already exists. Exit with False.')
                return False

            # Clone the schema. The database function will check
            # that the source schema exists and the destination schema does not.
            try:
                self._clone_schema()
            except Exception as dbe:
                db_exc = dbe
                LOG.error(
                    f"""Exception {dbe.__class__.__name__} cloning"""
                    + f""" "{self._TEMPLATE_SCHEMA}" to "{self.schema_name}": {str(dbe)}"""
                )
                LOG.info("Setting transaction to exit with ROLLBACK")
                transaction.set_rollback(True)  # Set this transaction context to issue a rollback on exit
            else:
                LOG.info(f'Successful clone of "{self._TEMPLATE_SCHEMA}" to "{self.schema_name}"')

        # Set schema to public (even if there was an exception)
        with transaction.atomic():
            LOG.info("Reset DB search path to public")
            conn.set_schema_to_public()

        if db_exc:
            raise db_exc

        return True
    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()
示例#21
0
 def _tenant_for_schema(self, schema_name):
     """Get or create tenant for schema."""
     tenant, created = Tenant.objects.get_or_create(schema_name=schema_name)
     if not schema_exists(schema_name):
         tenant.create_schema()
         msg = f"Created tenant {schema_name}"
         LOG.info(msg)
     return tenant
示例#22
0
 def process_exception(self, request, exception):
     if isinstance(exception, (Tenant.DoesNotExist, ProgrammingError)):
         if (settings.ROOT_URLCONF == "koku.urls"
                 and request.path in reverse("settings")
                 and not schema_exists(request.tenant.schema_name)):
             return JsonResponse([{}], safe=False)
         paginator = EmptyResultsSetPagination([], request)
         return paginator.get_paginated_response()
示例#23
0
    def test_tenant_schema_is_created(self):
        """
        when saving a tenant, it's schema should be created
        """
        tenant = Tenant(domain_url='test.com', schema_name='test_tenant')
        tenant.save()

        self.assertTrue(schema_exists(tenant.schema_name))
    def test_tenant_schema_is_created(self):
        """
        When saving a tenant, it's schema should be created.
        """
        tenant = Tenant(domain_url='something.test.com', schema_name='test')
        tenant.save()

        self.assertTrue(schema_exists(tenant.schema_name))
示例#25
0
    def test_tenant_schema_is_created(self):
        """
        When saving a tenant, it's schema should be created.
        """
        tenant = Tenant(domain_url='something.test.com', schema_name='test')
        tenant.save(verbosity=BaseTestCase.get_verbosity())

        self.assertTrue(schema_exists(tenant.schema_name))
def drop_schema(sender, instance, **kwargs):
    """
    Called in post_delete signal.
    Drops the schema related to the tenant instance. Just drop the schema if the parent
    class model has the attribute auto_drop_schema set to True.
    """
    if schema_exists(instance.schema_name) and instance.auto_drop_schema:
        cursor = connection.cursor()
        cursor.execute('DROP SCHEMA %s CASCADE' % instance.schema_name)
示例#27
0
    def test_auto_drop_schema(self):
        """
        When deleting a tenant with auto_drop_schema=True, it should delete
        the schema associated with the tenant.
        """
        self.assertFalse(schema_exists('auto_drop_tenant'))
        Tenant.auto_drop_schema = True
        tenant = Tenant(domain_url='something.test.com',
                        schema_name='auto_drop_tenant')
        tenant.save(verbosity=BaseTestCase.get_verbosity())
        self.assertTrue(schema_exists(tenant.schema_name))
        cursor = connection.cursor()

        # Force pending trigger events to be executed
        cursor.execute('SET CONSTRAINTS ALL IMMEDIATE')

        tenant.delete()
        self.assertFalse(schema_exists(tenant.schema_name))
        Tenant.auto_drop_schema = False
    def test_auto_drop_schema(self):
        """
        When deleting a tenant with auto_drop_schema=True, it should delete
        the schema associated with the tenant.
        """
        self.assertFalse(schema_exists('auto_drop_tenant'))
        Tenant.auto_drop_schema = True
        tenant = Tenant(domain_url='something.test.com',
                        schema_name='auto_drop_tenant')
        tenant.save(verbosity=BaseTestCase.get_verbosity())
        self.assertTrue(schema_exists(tenant.schema_name))
        cursor = connection.cursor()

        # Force pending trigger events to be executed
        cursor.execute('SET CONSTRAINTS ALL IMMEDIATE')

        tenant.delete()
        self.assertFalse(schema_exists(tenant.schema_name))
        Tenant.auto_drop_schema = False
 def  test_tenant_schema_creation_in_specified_db(self):
     """
     When saving a tenant using a db, its schema should be created in 
     that db
     """
     db = random.choice(get_all_dbs())
     tenant = Tenant(domain_url='something1.test.com', 
                                 schema_name='test1')
     tenant.save(
         verbosity=BaseTestCase.get_verbosity(),
         using=db)
     for d in get_all_dbs():
         if d == db:
             self.assertTrue(schema_exists(
                                     tenant.schema_name,
                                     db=d))
         else:
             self.assertFalse(schema_exists(
                                     tenant.schema_name,
                                     db=d))
示例#30
0
    def run_migrations(self, schema_name, included_apps):
        if int(self.options.get('verbosity', 1)) >= 1:
            self._notice("=== Running migrate for schema %s" % schema_name)

        if not schema_exists(schema_name):
            raise MigrationSchemaMissing(
                'Schema "{}" does not exist'.format(schema_name))

        connection.set_schema(schema_name)
        command = MigrateCommand()
        command.execute(*self.args, **self.options)
        connection.set_schema_to_public()
示例#31
0
文件: models.py 项目: xJustin/koku
    def _verify_template(self, verbosity=1):
        LOG.info(
            f'Verify that template schema "{self._TEMPLATE_SCHEMA}" exists')
        # This is using the teanant table data as the source of truth which can be dangerous.
        # If this becomes unreliable, then the database itself should be the source of truth
        # and extra code must be written to handle the sync of the table data to the state of
        # the database.
        template_schema = self.__class__.objects.get_or_create(
            schema_name=self._TEMPLATE_SCHEMA)

        # Strict check here! Both the record and the schema *should* exist!
        return template_schema and schema_exists(self._TEMPLATE_SCHEMA)
    def run_migrations(self, schema_name, included_apps):
        if int(self.options.get('verbosity', 1)) >= 1:
            self._notice("=== Running migrate for schema %s" % schema_name)

        if not schema_exists(schema_name):
            raise MigrationSchemaMissing('Schema "{}" does not exist'.format(
                schema_name))

        connection.set_schema(schema_name)
        command = MigrateCommand()
        command.execute(*self.args, **self.options)
        connection.set_schema_to_public()
示例#33
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:
            if django.VERSION >= (
                    1,
                    7,
                    0,
            ):
                call_command('migrate_schemas',
                             schema_name=self.schema_name,
                             interactive=False,
                             verbosity=verbosity)
            else:
                # default is faking all migrations and syncing directly to the current models state
                fake_all_migrations = getattr(
                    settings, 'TENANT_CREATION_FAKES_MIGRATIONS', True)
                call_command('sync_schemas',
                             schema_name=self.schema_name,
                             tenant=True,
                             public=False,
                             interactive=False,
                             migrate_all=fake_all_migrations,
                             verbosity=verbosity)

                # run/fake all migrations
                if 'south' in settings.INSTALLED_APPS and not django_is_in_test_mode(
                ):
                    call_command('migrate_schemas',
                                 fake=fake_all_migrations,
                                 schema_name=self.schema_name,
                                 verbosity=verbosity)

        connection.set_schema_to_public()
        post_schema_sync.send(sender=TenantMixin, tenant=self)
示例#34
0
    def delete(self, *args, **kwargs):
        """
        Drops the schema related to the tenant instance. Just drop the schema if the parent
        class model has the attribute auto_drop_schema set to True.
        """
        if connection.get_schema() 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.get_schema())

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

        super(TenantMixin, self).delete(*args, **kwargs)
示例#35
0
def rename_schema(*, schema_name, new_schema_name):
    """
    This renames a schema to a new name. It checks to see if it exists first
    """
    cursor = connection.cursor()

    if schema_exists(new_schema_name):
        raise ValidationError("New schema name already exists")
    if not _is_valid_schema_name(new_schema_name):
        raise ValidationError("Invalid string used for the schema name.")

    sql = 'ALTER SCHEMA {0} RENAME TO {1}'.format(schema_name, new_schema_name)
    cursor.execute(sql)
    cursor.close()
示例#36
0
    def post(self, request):
        kwargs = {'url_login_new_schema': None, 'form_data': request.POST}

        tenant_name = request.POST.get('subdomain', None)
        name_fantasy = request.POST.get('name_fantasy', None)
        email = request.POST.get('email', None)
        phone_number = request.POST.get('phone_number', None)
        area_code = phone_number[1:3]
        phone = phone_number[5:15]
        phone = phone.replace('-', '')
        password = request.POST.get('password', None)
        plan = request.POST.get('plan', None)

        if schema_exists(tenant_name):
            print('O inquilino já foi criado!')
            kwargs['tenant_exist'] = True
        else:
            print('Criando inquilino para o provarme')
            client = Client()
            site_url = request.tenant.domain_url.replace('www.', '')
            client.domain_url = '{0}.{1}'.format(tenant_name, site_url)
            client.name = tenant_name
            client.name_fantasy = name_fantasy
            client.is_active = False
            client.schema_name = 'provarme_' + tenant_name
            client.save()

            # Executando as migrações
            with schema_context('provarme_' + tenant_name):
                print('Rodando as migrações com o Cliente que foi criado!')
                user = User()
                user.email = email
                user.username = name_fantasy
                user.set_password(password)
                user.is_active = True
                user.is_staff = False
                user.is_superuser = False
                user.save()
                # Lógica para o pagamento do plano e assinatura
                url_payment = "https://upnid.com/go/p9854?p=n4kj"

                mail_admins(
                    'Notificação - Nova contratação do sistema',
                    'O sistema acabou de criar e aguarda pagamento da instancia: %s'
                    % tenant_name,
                    fail_silently=False)

                print('Criação de instância finalizada!')
                print("Redirecionando usuário para o pagamento.....")
        return HttpResponseRedirect(url_payment)
示例#37
0
    def delete(self, *args, **kwargs):
        """
        Drops the schema related to the tenant instance. Just drop the schema if the parent
        class model has 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:
            cursor = connection.cursor()
            cursor.execute('DROP SCHEMA %s CASCADE' % self.schema_name)
            transaction.commit_unless_managed()

        super(TenantMixin, self).delete(*args, **kwargs)
示例#38
0
 def get(self, request):
     if request.GET.get('tenant_name', False) and schema_exists(
             request.GET.get('tenant_name')):
         protocol = "https" if settings['USE_SSL'] else "http"
         url_redirect = "{0}://{1}.{2}{3}".format(
             protocol, request.GET.get('tenant_name'),
             request.META['HTTP_HOST'], reverse_lazy('security:login'))
         return HttpResponseRedirect(url_redirect)
     if request.user.is_authenticated:
         return HttpResponseRedirect(reverse('flow:dashboard'))
     else:
         ctx = {'form': self.form}
         if 'next' in request.GET:
             ctx['next'] = request.GET['next']
         return render(request, self.template_name, ctx)
示例#39
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)
    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 IF EXISTS %s CASCADE' % self.schema_name)

        return super(TenantMixin, self).delete(*args, **kwargs)
def drop_schema(sender, instance, **kwargs):
    """
    Called in post_delete signal.
    Drops the schema related to the tenant instance. Just drop the schema if the parent
    class model has the attribute auto_drop_schema setted to True.

    """

    # this function is called each time some model object is deleted, even if it is not a
    # tenant. So we check that a tenant is being deleted:
    if isinstance(instance, TenantMixin):
        cursor = connection.cursor()

        if schema_exists(instance.schema_name) and instance.auto_drop_schema:
            # remove the schema
            cursor.execute('DROP SCHEMA %s CASCADE' % instance.schema_name)
    def handle(self, *args, **options):
        self.non_tenant_schemas = settings.PG_EXTRA_SEARCH_PATHS + ['public']
        self.sync_tenant = options.get('tenant')
        self.sync_public = options.get('shared')
        self.schema_name = options.get('schema_name')
        self.args = args
        self.options = options
        self.PUBLIC_SCHEMA_NAME = get_public_schema_name()

        if self.schema_name:
            if self.sync_public:
                raise CommandError("schema should only be used "
                                   "with the --tenant switch.")
            elif self.schema_name == self.PUBLIC_SCHEMA_NAME:
                self.sync_public = True
            else:
                self.sync_tenant = True
        elif not self.sync_public and not self.sync_tenant:
            # no options set, sync both
            self.sync_tenant = True
            self.sync_public = True

        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)
        if self.sync_tenant:
            if self.schema_name and \
                    (self.schema_name != self.PUBLIC_SCHEMA_NAME):
                # Make sure the tenant exists and the schema belongs to
                # a tenant; We don't want to sync to extensions schema by
                # mistake
                if not schema_exists(self.schema_name):
                    raise RuntimeError('Schema "{}" does not exist'.format(
                        self.schema_name))
                elif self.schema_name in self.non_tenant_schemas:
                    raise RuntimeError(
                        'Schema "{}" does not belong to any tenant'.format(
                            self.schema_name))
                else:
                    self.run_migrations(self.schema_name, settings.TENANT_APPS)
            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)
示例#43
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:
            if django.VERSION >= (1, 7, 0,):
                call_command('migrate_schemas',
                             schema_name=self.schema_name,
                             interactive=False,
                             verbosity=verbosity)
            else:
                # default is faking all migrations and syncing directly to the current models state
                fake_all_migrations = getattr(settings, 'TENANT_CREATION_FAKES_MIGRATIONS', True)
                call_command('sync_schemas',
                             schema_name=self.schema_name,
                             tenant=True,
                             public=False,
                             interactive=False,
                             migrate_all=fake_all_migrations,
                             verbosity=verbosity)

                # run/fake all migrations
                if 'south' in settings.INSTALLED_APPS and not django_is_in_test_mode():
                    call_command('migrate_schemas',
                                 fake=fake_all_migrations,
                                 schema_name=self.schema_name,
                                 verbosity=verbosity)

        connection.set_schema_to_public()
        post_schema_sync.send(sender=TenantMixin, tenant=self)
    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)
        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)
            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)
示例#45
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_identifier(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)
        transaction.commit_unless_managed()

        if sync_schema:
            # default is faking all migrations and syncing directly to the current models state
            fake_all_migrations = getattr(settings, "TENANT_CREATION_FAKES_MIGRATIONS", True)

            call_command(
                "sync_schemas",
                schema_name=self.schema_name,
                tenant=True,
                public=False,
                interactive=False,  # don't ask to create an admin user
                migrate_all=fake_all_migrations,
                verbosity=verbosity,
            )

            # run/fake all migrations
            if "south" in settings.INSTALLED_APPS and not django_is_in_test_mode():
                call_command(
                    "migrate_schemas", fake=fake_all_migrations, schema_name=self.schema_name, verbosity=verbosity
                )

        connection.set_schema_to_public()
        return True
    def handle(self, *args, **options):
        super(Command, self).handle(*args, **options)
        self.PUBLIC_SCHEMA_NAME = get_public_schema_name()

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

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

        if self.sync_public:
            executor.run_migrations(tenants=[self.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 MigrationSchemaMissing('Schema "{}" does not exist'.format(
                        self.schema_name))
                else:
                    tenants = [self.schema_name]
            else:
                tenants = get_tenant_model().objects.exclude(schema_name=get_public_schema_name()).values_list(
                    'schema_name', flat=True)
            executor.run_migrations(tenants=tenants)