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)
     connection.set_schema(schema_name)
     command = MigrateCommand()
     command.execute(*self.args, **self.options)
     connection.set_schema_to_public()
    def process_request(self, request):
        # Connection needs first to be at the public schema, as this is where
        # the tenant metadata is stored.
        connection.set_schema_to_public()

        hostname = self.hostname_from_request(request)
        TenantModel = get_tenant_model()

        try:
            # get_tenant must be implemented by extending this class.
            tenant = self.get_tenant(TenantModel, hostname, request)
            assert isinstance(tenant, TenantModel)
        except TenantModel.DoesNotExist:
            raise self.TENANT_NOT_FOUND_EXCEPTION(
                'No tenant for {!r}'.format(request.get_host()))
        except AssertionError:
            raise self.TENANT_NOT_FOUND_EXCEPTION(
                'Invalid tenant {!r}'.format(request.tenant))

        request.tenant = tenant
        connection.set_tenant(request.tenant)

        # Content type can no longer be cached as public and tenant schemas
        # have different models. If someone wants to change this, the cache
        # needs to be separated between public and shared schemas. If this
        # cache isn't cleared, this can cause permission problems. For example,
        # on public, a particular model has id 14, but on the tenants it has
        # the id 15. if 14 is cached instead of 15, the permissions for the
        # wrong model will be fetched.
        ContentType.objects.clear_cache()

        # Do we have a public-specific urlconf?
        if hasattr(settings, 'PUBLIC_SCHEMA_URLCONF') and request.tenant.schema_name == get_public_schema_name():
            request.urlconf = settings.PUBLIC_SCHEMA_URLCONF
    def setUp(self):
        kwargs1 = {}
        kwargs2 = {}

        try:
            Client._meta.get_field('domain_url')
        except FieldDoesNotExist:
            pass
        else:
            kwargs1 = {'domain_url': 'test1.test.com'}
            kwargs2 = {'domain_url': 'test2.test.com'}

        self.tenant1 = Client(name='test1', schema_name='test1', **kwargs1)
        self.tenant1.save()

        self.tenant2 = Client(name='test2', schema_name='test2', **kwargs2)
        self.tenant2.save()

        connection.set_tenant(self.tenant1)
        self.dummy1 = DummyModel.objects.create(name='test1')

        connection.set_tenant(self.tenant2)
        self.dummy2 = DummyModel.objects.create(name='test2')

        connection.set_schema_to_public()
    def tearDownClass(cls):
        connection.set_schema_to_public()
        cls.tenant.delete()

        cls.remove_allowed_test_domain()
        cursor = connection.cursor()
        cursor.execute('DROP SCHEMA IF EXISTS test CASCADE')
Example #5
0
    def test_switching_search_path(self):
        tenant1 = Tenant(domain_urls=['something.test.com'],
                         schema_name='tenant1')
        tenant1.save()

        connection.set_schema_to_public()
        tenant2 = Tenant(domain_urls=['example.com'], schema_name='tenant2')
        tenant2.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())
    def process_request(self, request):
        # Connection needs first to be at the public schema, as this is where
        # the tenant metadata is stored.
        connection.set_schema_to_public()
        hostname = self.hostname_from_request(request)

        tenant_model = get_tenant_model()
        try:
            request.tenant = tenant_model.objects.get(domain_url=hostname)
            connection.set_tenant(request.tenant)
        except tenant_model.DoesNotExist:
            pass

        # Content type can no longer be cached as public and tenant schemas
        # have different models. If someone wants to change this, the cache
        # needs to be separated between public and shared schemas. If this
        # cache isn't cleared, this can cause permission problems. For example,
        # on public, a particular model has id 14, but on the tenants it has
        # the id 15. if 14 is cached instead of 15, the permissions for the
        # wrong model will be fetched.
        ContentType.objects.clear_cache()

        # Do we have a public-specific urlconf?
        if hasattr(settings, 'PUBLIC_SCHEMA_URLCONF') and request.tenant.schema_name == get_public_schema_name():
            request.urlconf = settings.PUBLIC_SCHEMA_URLCONF
Example #7
0
def switch_schema(task, kwargs, **kw):
    """ Switches schema of the task, before it has been run. """
    # Lazily load needed functions, as they import django model functions which
    # in turn load modules that need settings to be loaded and we can't
    # guarantee this module was loaded when the settings were ready.
    from .compat import get_public_schema_name, get_tenant_model

    old_schema = (connection.schema_name, connection.include_public_schema)
    setattr(task, '_old_schema', old_schema)

    schema = (
        get_schema_name_from_task(task, kwargs) or
        get_public_schema_name()
    )

    # If the schema has not changed, don't do anything.
    if connection.schema_name == schema:
        return

    if connection.schema_name != get_public_schema_name():
        connection.set_schema_to_public()

    if schema == get_public_schema_name():
        return

    tenant = get_tenant_model().objects.get(schema_name=schema)
    connection.set_tenant(tenant, include_public=True)
    def process_request(self, request):
        """
        Resets to public schema

        Some nasty weird bugs happened at the production environment without this call.
        connection.pg_thread.schema_name would already be set and then terrible errors
        would occur. Any idea why? My theory is django implements connection as some sort
        of threading local variable.
        """
        connection.set_schema_to_public()
        hostname_without_port = remove_www_and_dev(request.get_host().split(':')[0])

        TenantModel = get_tenant_model()
        request.tenant = get_object_or_404(TenantModel, domain_url=hostname_without_port)
        connection.set_tenant(request.tenant)

        # content type can no longer be cached as public and tenant schemas have different
        # models. if someone wants to change this, the cache needs to be separated between
        # public and shared schemas. if this cache isn't cleared, this can cause permission
        # problems. for example, on public, a particular model has id 14, but on the tenants
        # it has the id 15. if 14 is cached instead of 15, the permissions for the wrong
        # model will be fetched.
        ContentType.objects.clear_cache()

        # do we have a public-specific token?
        if hasattr(settings, 'PUBLIC_SCHEMA_URL_TOKEN') and request.tenant.schema_name == get_public_schema_name():
            request.path_info = settings.PUBLIC_SCHEMA_URL_TOKEN + request.path_info
    def process_request(self, request):
        """
        Resets to public schema

        Some nasty weird bugs happened at the production environment without this call.
        connection.pg_thread.schema_name would already be set and then terrible errors
        would occur. Any idea why? My theory is django implements connection as some sort
        of threading local variable.
        """
        connection.set_schema_to_public()
        request.tenant = self.set_tenant(request.get_host())

        # do we have tenant-specific URLs?
        if (
            hasattr(settings, "PUBLIC_SCHEMA_URL_TOKEN")
            and request.tenant.schema_name == get_public_schema_name()
            and request.path_info[-1] == "/"
        ):
            # we are not at the public schema, manually alter routing to schema-dependent urls
            request.path_info = settings.PUBLIC_SCHEMA_URL_TOKEN + request.path_info

        if SET_TENANT_SITE_DYNAMICALLY and hasattr(request.tenant, "site") and request.tenant.site:
            SITE_THREAD_LOCAL.SITE_ID = request.tenant.site_id
            # dynamically set the site
        else:
            SITE_THREAD_LOCAL.SITE_ID = DEFAULT_SITE_ID
Example #10
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]
    def migrate_tenant_apps(self, schema_name=None):
        self._save_south_settings()

        apps = self.tenant_apps or self.installed_apps
        self._set_managed_apps(included_apps=apps, excluded_apps=self.shared_apps)

        syncdb_command = MigrateCommand()
        if schema_name:
            print self.style.NOTICE("=== Running migrate for schema: %s" % schema_name)
            connection.set_schema_to_public()
            sync_tenant = get_tenant_model().objects.filter(schema_name=schema_name).get()
            connection.set_tenant(sync_tenant, include_public=False)
            syncdb_command.execute(**self.options)
        else:
            public_schema_name = get_public_schema_name()
            tenant_schemas_count = get_tenant_model().objects.exclude(schema_name=public_schema_name).count()
            if not tenant_schemas_count:
                print self.style.NOTICE("No tenants found")

            for tenant_schema in get_tenant_model().objects.exclude(schema_name=public_schema_name).all():
                Migrations._dependencies_done = False  # very important, the dependencies need to be purged from cache
                print self.style.NOTICE("=== Running migrate for schema %s" % tenant_schema.schema_name)
                connection.set_tenant(tenant_schema, include_public=False)
                syncdb_command.execute(**self.options)

        self._restore_south_settings()
Example #12
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()
    def run_migrations(self, schema_name, included_apps, options):
        self._notice("=== Running migrate for schema %s" % schema_name)
        connection.set_schema(schema_name)
        command = MigrateCommand()

        command.execute(*self.args, **options)
        connection.set_schema_to_public()
Example #14
0
def run_migrations(args, options, executor_codename, schema_name, allow_atomic=True):
    from django.core.management import color
    from django.core.management.base import OutputWrapper
    from django.db import connection

    style = color.color_style()

    def style_func(msg):
        return '[%s:%s] %s' % (
            style.NOTICE(executor_codename),
            style.NOTICE(schema_name),
            msg
        )

    connection.set_schema(schema_name)
    stdout = OutputWrapper(sys.stdout)
    stdout.style_func = style_func
    stderr = OutputWrapper(sys.stderr)
    stderr.style_func = style_func
    if int(options.get('verbosity', 1)) >= 1:
        stdout.write(style.NOTICE("=== Starting migration"))
    MigrateCommand(stdout=stdout, stderr=stderr).execute(*args, **options)

    try:
        transaction.commit()
        connection.close()
        connection.connection = None
    except transaction.TransactionManagementError:
        if not allow_atomic:
            raise

        # We are in atomic transaction, don't close connections
        pass

    connection.set_schema_to_public()
Example #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_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
    def test_switching_search_path(self):
        dummies_tenant1_count, dummies_tenant2_count = 0, 0

        tenant1 = Tenant(domain_url='test.com', schema_name='tenant1')
        tenant1.save()

        connection.set_schema_to_public()
        tenant2 = Tenant(domain_url='example.com', schema_name='tenant2')
        tenant2.save()

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

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

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

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

        # switch back to tenant2's path
        with tenant_context(tenant2):
            self.assertEqual(DummyModel.objects.count(), dummies_tenant2_count)
Example #17
0
def setup_tenant_test(transactional_db):
    kwargs1 = {}
    kwargs2 = {}

    data = {}

    try:
        Client._meta.get_field('domain_url')
    except FieldDoesNotExist:
        pass
    else:
        kwargs1 = {'domain_url': 'test1.test.com'}
        kwargs2 = {'domain_url': 'test2.test.com'}

    tenant1 = data['tenant1'] = Client(name='test1', schema_name='test1', **kwargs1)
    tenant1.save()

    tenant2 = data['tenant2'] = Client(name='test2', schema_name='test2', **kwargs2)
    tenant2.save()

    connection.set_tenant(tenant1)
    DummyModel.objects.all().delete()
    data['dummy1'] = DummyModel.objects.create(name='test1')

    connection.set_tenant(tenant2)
    DummyModel.objects.all().delete()
    data['dummy2'] = DummyModel.objects.create(name='test2')

    connection.set_schema_to_public()

    try:
        yield data

    finally:
        connection.set_schema_to_public()
Example #18
0
    def tearDownClass(cls):
        # delete tenant
        connection.set_schema_to_public()
        cls.tenant.delete()

        cursor = connection.cursor()
        cursor.execute('DROP SCHEMA test CASCADE')
Example #19
0
    def setUp(self):
        super(TestMultiTenant, self).setUp()

        now = timezone.now()

        self.init_projects()
        self.tenant1 = connection.tenant
        status_running = ProjectPhase.objects.get(slug='campaign')

        # Create a project for the main tenant
        self.project = ProjectFactory.create(status=ProjectPhase.objects.get(slug='campaign'),
                                             deadline=now - timezone.timedelta(days=5),
                                             amount_asked=0)

        # Create a second tenant
        connection.set_schema_to_public()
        tenant_domain = 'testserver2'
        self.tenant2 = get_tenant_model()(
            domain_url=tenant_domain,
            schema_name='test2',
            client_name='test2')

        self.tenant2.save(verbosity=0)
        connection.set_tenant(self.tenant2)

        self.init_projects()
        self.project2 = ProjectFactory.create(status=ProjectPhase.objects.get(slug='campaign'),
                                              deadline=now - timezone.timedelta(days=5),
                                              amount_asked=0)
Example #20
0
def get_current_tenant():
    """ Return current tenant
    Determine based on connection schema_name """
    schema_name = connection.schema_name
    connection.set_schema_to_public()
    tenant = get_tenant_model().objects.get(schema_name=schema_name)
    connection.set_tenant(tenant)
    return tenant
Example #21
0
    def tearDown(self):
        connection.set_schema_to_public()
        self.public_domain.delete()
        self.public_tenant.delete()
        self.domain.delete()
        self.tenant.delete(force_drop=True)

        super(SharedAuthTest, self).tearDown()
Example #22
0
    def tearDown(self):
        from django.db import connection

        connection.set_schema_to_public()

        self.domain.delete()
        self.tenant.delete(force_drop=True)

        super(RoutesTestCase, self).tearDown()
Example #23
0
    def tearDownClass(cls):
        from django.db import connection

        connection.set_schema_to_public()

        cls.public_domain.delete()
        cls.public_tenant.delete()

        super(RoutesTestCase, cls).tearDownClass()
Example #24
0
    def deactivate(cls):
        """
        Syntax sugar, return to public schema

        Usage:
            test_tenant.deactivate()
            # or simpler
            Tenant.deactivate()
        """
        connection.set_schema_to_public()
Example #25
0
def tenant_context(tenant):
    previous_tenant = connection.tenant
    try:
        connection.set_tenant(tenant)
        yield
    finally:
        if previous_tenant is None:
            connection.set_schema_to_public()
        else:
            connection.set_tenant(previous_tenant)
Example #26
0
    def setUp(self):
        super(BaseSyncTest, self).setUp()
        # Django calls syncdb by default for the test database, but we want
        # a blank public schema for this set of tests.
        connection.set_schema_to_public()
        with connection.cursor() as cursor:
            cursor.execute('DROP SCHEMA %s CASCADE; CREATE SCHEMA %s;'
                           % (get_public_schema_name(), get_public_schema_name(), ))

        self.sync_shared()
Example #27
0
def schema_context(schema_name):
    from django.db import connection
    previous_tenant = connection.tenant
    try:
        connection.set_schema(schema_name)
        yield
    finally:
        if previous_tenant is None:
            connection.set_schema_to_public()
        else:
            connection.set_tenant(previous_tenant)
    def setUp(self):
        # settings needs some patching
        settings.TENANT_MODEL = 'tenant_schemas.Tenant'

        # add the public tenant
        self.public_tenant_domain = 'test.com'
        self.public_tenant = Tenant(domain_url=self.public_tenant_domain,
                                    schema_name='public')
        self.public_tenant.save()

        connection.set_schema_to_public()
 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():
             self.execute_command(tenant, self.COMMAND_NAME, *args, **options)
Example #30
0
    def tearDown(self):
        from django_tenants.models import TenantMixin

        connection.set_schema_to_public()

        for c in self.created:
            if isinstance(c, TenantMixin):
                c.delete(force_drop=True)
            else:
                c.delete()

        super(TenantDataAndSettingsTest, self).tearDown()
Example #31
0
    def process_request(self, request):
        # add request id
        request.request_id = str(uuid.uuid4())

        connection.set_schema_to_public()

        logger.info('incoming request')
        user = getattr(request, 'user', None)

        # Attempt to set tenant
        print("user: {}".format(user))
        if user and not user.is_anonymous():
            logging.info("try to find user profile")

            email = user.email
            domain = email.split("@")[1]

            if (CREATE_MISSING_TENANT):
                tenant, created = models.Tenant.objects.update_or_create(
                    name=domain, defaults={
                        'name': domain,
                        'email': email
                    })
            else:
                tenant = models.Tenant.objects.get(name=domain)

            set_current_tenant(tenant)

            try:
                profile = user.userprofile
                logger.debug("profile {}".format(profile.tenant.pk))
                if profile:
                    logger.info("setting tenant")
                    tenant = getattr(profile, 'tenant', None)
                else:
                    models.UserProfile.objects.create(user=user, tenant=tenant)

            except djangoexceptions.ObjectDoesNotExist:
                logger.debug(domain)

                userprofile = models.UserProfile(user=user, tenant=tenant)

                setattr(user, 'userprofile', userprofile)

                userprofile.save()
            except:
                # If the profile lookup failed, we're in deep doodoo.  It's not
                # safe to set a default tenant for this User - it might give access
                # to the base tenant which is cloned to create all new tenants.
                raise ValueError(
                    """A User was created with no profile.  For security reasons, 
                    we cannot allow the request to be processed any further.
                    Try deleting this User and creating it again to ensure a 
                    UserProfile gets attached, or link a UserProfile 
                    to this User.""")
        else:
            # It's important that we hit the db once to set the tenant, even if
            # it's an anonymous user.  That way we get fresh values from the db,
            # including the tenant options.
            #
            # An anonymous user, for example, still has access to the login page,
            # so he will see the primary navigation tabs.  To decide which primary
            # navigation tabs to show, we need the tenant to be set.
            #
            # Not: If we simply set the tenant once and left it in a module-level
            # variable, it would stay latched between page requests which is NOT
            # what we want.
            logging.info("default tenant")
            set_tenant_to_default()
Example #32
0
    def run_backlog(self, models, force, update):
        """Installs the list of models given from the previous backlog

        If the correct dependent views have not been installed, the view
        will be added to the backlog.

        Eventually we get to a point where all dependencies are sorted.
        """
        backlog = []
        for view_cls in models:
            skip = False
            name = "{}.{}".format(view_cls._meta.app_label, view_cls.__name__)
            for dep in view_cls._dependencies:
                if dep not in self.synced:
                    skip = True
            if skip is True:
                backlog.append(view_cls)
                log.info("Putting pgview at back of queue: %s", name)
                continue  # Skip

            try:
                app_label = ContentType.objects.get_for_model(
                    view_cls).app_label
                if hasattr(
                        settings,
                        "TENANT_APPS") and app_label in settings.TENANT_APPS:
                    from tenant_schemas.utils import get_public_schema_name, get_tenant_model, schema_exists

                    tenants = (get_tenant_model().objects.exclude(
                        schema_name=get_public_schema_name()).values_list(
                            "schema_name", flat=True))
                else:
                    tenants = ["public"]
                status = "EXISTS"
                for tenant in tenants:
                    try:
                        connection.set_schema(tenant)
                        log.info("Switched to %s schema for %s", tenant,
                                 view_cls._meta.db_table)
                    except:
                        pass
                    status = create_view(
                        connection,
                        view_cls._meta.db_table,
                        string.Template(
                            view_cls.sql).safe_substitute(tenant=tenant),
                        update=update,
                        force=force,
                        materialized=isinstance(view_cls(), MaterializedView),
                        index=view_cls._concurrent_index,
                        column_indexes=view_cls._column_indexes,
                        tenant_schema=tenant,
                        is_function=isinstance(view_cls(), PLPGSQLFunction),
                        function_signature=view_cls._function_signature)
                    try:
                        connection.set_schema_to_public()
                    except:
                        pass

                view_synced.send(
                    sender=view_cls,
                    update=update,
                    force=force,
                    status=status,
                    has_changed=status not in ("EXISTS", "FORCE_REQUIRED"),
                )
                self.synced.append(name)
            except Exception as exc:
                exc.view_cls = view_cls
                exc.python_name = name
                msg = "failer, skipping"
                raise
            else:
                if status == "CREATED":
                    msg = "created"
                elif status == "UPDATED":
                    msg = "updated"
                elif status == "EXISTS":
                    msg = "already exists, skipping"
                elif status == "FORCED":
                    msg = "forced overwrite of existing schema"
                elif status == "FORCE_REQUIRED":
                    msg = "exists with incompatible schema, " "--force required to update"
                log.info("pgview %(python_name)s %(msg)s" % {
                    "python_name": name,
                    "msg": msg
                })
        return backlog
Example #33
0
    def handle(self, *args, **options):
        # Get the user inputs.
        schema_name = options['schema_name'][0]
        name = options['name'][0]
        alternate_name = options['alternate_name'][0]
        description = options['description'][0]
        country = options['country'][0]
        city = options['city'][0]
        province = options['province'][0]
        try:
            street_number = int(self.get(options, 'street_number'))
        except Exception as e:
            raise CommandError(_('Street # needs to be integer value. Please see `organization.py` file.'))
        street_name = self.get(options, 'street_name')
        try:
            apartment_unit = int(self.get(options, 'apartment_unit'))
        except Exception as e:
            raise CommandError(_('Apt # needs to be integer value. Please see `organization.py` file.'))
        try:
            street_type = int(self.get(options, 'street_type'))
        except Exception as e:
            street_type = SharedOrganization.STREET_TYPE.UNSPECIFIED
        street_type_other = self.get(options, 'street_type_other')
        try:
            street_direction = int(self.get(options, 'street_direction'))
        except Exception as e:
            street_direction = SharedOrganization.STREET_DIRECTION.NONE
        postal_code = self.get(options, 'postal_code')
        timezone_name = self.get(options, 'timezone_name')
        police_report_url = self.get(options, 'police_report_url')

        # For debugging purposes only.
        self.stdout.write(
            self.style.SUCCESS(_(
            '''
            Schema: %(schema_name)s
            Name: %(name)s
            Alternate Name: %(alternate_name)s
            Description: %(description)s
            Country: %(country)s
            Province: %(province)s
            City: %(city)s
            Street #: %(street_number)s
            Street Name: %(street_name)s
            Apt #: %(apartment_unit)s
            Street Type: %(street_type)s
            Street Type (Other): %(street_type_other)s
            Street Direction: %(street_direction)s
            Postal Code: %(postal_code)s
            Timezone: %(timezone_name)s
            Police Report URL: %(police_report_url)s
            '''
            ) % {
                'schema_name': schema_name,
                'name': name,
                'alternate_name': alternate_name,
                'description': description,
                'country': country,
                'province': province,
                'city': city,
                'street_number': street_number,
                'street_name': street_name,
                'apartment_unit': apartment_unit,
                'street_type': street_type,
                'street_type_other': street_type_other,
                'street_direction': street_direction,
                'postal_code': postal_code,
                'timezone_name': timezone_name,
                'police_report_url': police_report_url,
            })
        )

        # Connection needs first to be at the public schema, as this is where
        # the database needs to be set before creating a new tenant. If this is
        # not done then django-tenants will raise a "Can't create tenant outside
        # the public schema." error.
        connection.set_schema_to_public() # Switch to Public.

        # Check to confirm that we already do not have a `Franchise` with this
        # name in our database.
        organization_does_exist = SharedOrganization.objects.filter(schema_name=schema_name).exists()
        if organization_does_exist:
            raise CommandError(_('Organization already exists!'))

        # Create our tenant.
        self.begin_processing(schema_name, name, alternate_name, description,
                             country, city, province, street_number, street_name,
                             apartment_unit, street_type, street_type_other,
                             street_direction, postal_code, timezone_name,
                             police_report_url)

        # Used for debugging purposes.
        self.stdout.write(
            self.style.SUCCESS(_('Successfully setup organization.'))
        )
Example #34
0
def cambiar_de_empresa(empresa=None):
    from django.db import connection
    if empresa:
        connection.set_tenant(empresa)
    else:
        connection.set_schema_to_public()
Example #35
0
    def handle(self, *args, **options):
        # Connection needs first to be at the public schema, as this is where
        # the database needs to be set before creating a new tenant. If this is
        # not done then django-tenants will raise a "Can't create tenant outside
        # the public schema." error.
        connection.set_schema_to_public()  # Switch to Public.
        # Get the user inputs.
        schema_name = options['schema_name'][0]

        try:
            franchise = SharedFranchise.objects.get(schema_name=schema_name)
        except SharedFranchise.DoesNotExist:
            raise CommandError(_('Franchise does not exist!'))

        # Connection will set it back to our tenant.
        connection.set_schema(franchise.schema_name, True)  # Switch to Tenant.

        #----------------------------------------------------------------------#
        # ALGORITHM:
        # WE WANT TO FREEZE TIME TO THE `LAST_MODIFIED` DATETIME SO THE RECORD
        # DOES NOT LOOKED LIKE IT WAS MODIFIED. SPECIAL THANKS TO LINK:
        # https://stackoverflow.com/a/40423482
        #----------------------------------------------------------------------#

        self.stdout.write(
            self.style.SUCCESS(_('Starting updating associates...')))
        for associate in Associate.objects.all().iterator(chunk_size=250):
            try:
                with freeze_time(associate.last_modified):
                    associate.save()
                    self.stdout.write(
                        self.style.SUCCESS(
                            _('Updated associate %s.') % str(associate.id)))
            except Exception as e:
                print(e)

        self.stdout.write(self.style.SUCCESS(
            _('Starting updating clients...')))
        for client in Customer.objects.all().iterator(chunk_size=250):
            try:
                with freeze_time(client.last_modified):
                    client.save()
                    self.stdout.write(
                        self.style.SUCCESS(
                            _('Updated client %s.') % str(client.id)))
            except Exception as e:
                print(e)

        self.stdout.write(
            self.style.SUCCESS(_('Starting updating partners...')))
        for partner in Partner.objects.all().iterator(chunk_size=250):
            try:
                with freeze_time(partner.last_modified):
                    partner.save()
                    self.stdout.write(
                        self.style.SUCCESS(
                            _('Updated partner %s.') % str(partner.id)))
            except Exception as e:
                print(e)

        self.stdout.write(self.style.SUCCESS(_('Starting updating staff...')))
        for staff in Staff.objects.all().iterator(chunk_size=250):
            try:
                with freeze_time(staff.last_modified):
                    staff.save()
                    self.stdout.write(
                        self.style.SUCCESS(
                            _('Updated staff %s.') % str(staff.id)))
            except Exception as e:
                print(e)

        self.stdout.write(self.style.SUCCESS(_('Starting updating orders...')))
        for order in WorkOrder.objects.all().iterator(chunk_size=250):
            try:
                with freeze_time(order.last_modified):
                    order.save()
                    self.stdout.write(
                        self.style.SUCCESS(
                            _('Updated order %s.') % str(order.id)))
            except Exception as e:
                print(e)

        self.stdout.write(
            self.style.SUCCESS(
                _('Successfully updated all unassigned associates.')))
Example #36
0
 def tearDownClass(cls):
     connection.set_schema_to_public()
     cls.remove_allowed_test_domain()
Example #37
0
 def tearDownClass(cls):
     TenantModel = get_tenant_model()
     test_schema_name = cls.get_test_schema_name()
     TenantModel.objects.filter(schema_name=test_schema_name).delete()
     connection.set_schema_to_public()
Example #38
0
 def tearDownClass(cls):
     cls._rollback_atomics(cls.cls_atomics)
     connection.set_schema_to_public()
Example #39
0
    def tearDownClass(cls):
        connection.set_schema_to_public()

        for schema_name, tenant in cls.tenants.items():
            tenant.delete(force_drop=True)
Example #40
0
    def get_context_data(self, **kwargs):
        context = super(ReporteProductosView, self).get_context_data(**kwargs)
        reporte = []
        tenants = Productor.objects.exclude(schema_name='public')
        dominio = "localhost:8080"

        #Reportes gráficos
        productoPorAltura = {}
        productoPorTemperatura = {}
        productosTotales = {}

        for tenant in tenants:
            connection.set_tenant(tenant)

            listaNombreFrutas = Fruta.objects.values_list('nombre')
            listamsnmFrutas = Fruta.objects.values_list('msnm')
            listaTemperaturaFrutas = Fruta.objects.values_list('temperatura')

            for fruta in listaNombreFrutas:

                f = str(fruta[0]).capitalize()

                if f in productosTotales:
                    productosTotales[f] = productosTotales[f] + 1
                else:
                    productosTotales[f] = 1

            for fruta in listamsnmFrutas:

                f = fruta[0]
                if f in productoPorAltura:
                    productoPorAltura[f] = productoPorAltura[f] + 1
                else:
                    productoPorAltura[f] = 1

            for fruta in listaTemperaturaFrutas:

                f = fruta[0]
                if f in productoPorTemperatura:
                    productoPorTemperatura[f] = productoPorTemperatura[f] + 1
                else:
                    productoPorTemperatura[f] = 1

            reporte_actual = {
                'url': tenant.schema_name + '.' + dominio,
                'info': serializers.serialize("python", Fruta.objects.all())
            }

            reporte.append(reporte_actual)

        reportesGenerados = {
            'reporteTotalNombre': productosTotales,
            'reporteTotalAltura': productoPorAltura,
            'reporteTotalTemperatura': productoPorTemperatura,
        }

        connection.set_schema_to_public()

        contexto = {
            'reporte': reporte,
            'reportesGenerados': reportesGenerados,
        }

        context.update(contexto)
        return context
Example #41
0
    def handle(self, *args, **options):
        # Connection needs first to be at the public schema, as this is where
        # the database needs to be set before creating a new tenant. If this is
        # not done then django-tenants will raise a "Can't create tenant outside
        # the public schema." error.
        connection.set_schema_to_public()  # Switch to Public.
        # Get the user inputs.
        schema_name = options['schema_name'][0]

        try:
            franchise = SharedFranchise.objects.get(schema_name=schema_name)
        except SharedFranchise.DoesNotExist:
            raise CommandError(_('Franchise does not exist!'))

        # Connection will set it back to our tenant.
        connection.set_schema(franchise.schema_name, True)  # Switch to Tenant.

        customers = Customer.objects.all()
        for customer in customers.all():
            how_hear_text = customer.how_hear
            if how_hear_text:

                how_hear = 1
                how_hear_other = how_hear_text

                how_hear_text = how_hear_text.lower()
                if "friend" in how_hear_text:
                    how_hear = 2

                elif "google" in how_hear_text:
                    how_hear = 3

                elif "online" in how_hear_text:
                    how_hear = 3

                elif "internet" in how_hear_text:
                    how_hear = 3

                elif "inernet" in how_hear_text:
                    how_hear = 3

                elif "www" in how_hear_text:
                    how_hear = 3

                elif "website" in how_hear_text:
                    how_hear = 3

                elif "on line" in how_hear_text:
                    how_hear = 3

                elif "on-line" in how_hear_text:
                    how_hear = 3

                elif "computer" in how_hear_text:
                    how_hear = 3

                elif "associate" in how_hear_text:
                    how_hear = 5

                elif "facebook" in how_hear_text:
                    how_hear = 6

                elif "twitter" in how_hear_text:
                    how_hear = 7

                elif "instagram" in how_hear_text:
                    how_hear = 8

                elif "magazine" in how_hear_text:
                    how_hear = 9

                elif "event" in how_hear_text:
                    how_hear = 10

                customer.how_hear = int(how_hear)
                customer.how_hear_other = how_hear_other
                customer.save()

        # For debugging purposes.
        self.stdout.write(self.style.SUCCESS(_('Successfully updated.')))
Example #42
0
 def setUp(self):
     connection.set_schema_to_public()
     super(BaseTestCase, self).setUp()
Example #43
0
    def process_request(self, request):
        # Connection needs first to be at the public schema, as this is where
        # the tenant metadata is stored.
        connection.set_schema_to_public()
        hostname = self.hostname_from_request(request)
        print('IN PROCESS REQUEST - METHOD = ', request.method)
        print('IN PROCESS REQUEST - META = ', request.META)
        print('IN PROCESS REQUEST - HEADERS = ', request.headers)

        tenant_id = request.headers.get('x-tenant-id')
        print('X TENTANT = ', tenant_id)

        domain_model = get_tenant_domain_model()

        if request.method != 'OPTIONS' and request.method != 'GET':
            try:
                tenant_id = request.headers.get('X-TENANT-ID')
                print('TENANT ID = ', tenant_id)
                tenant_model = get_tenant_model()
                if tenant_model.objects.filter(tenant_id=tenant_id).exists():
                    tenant = tenant_model.objects.get(tenant_id=tenant_id)
                    print('TENANT = ', tenant.__dict__)
                    tenant.domain_url = hostname
                    request.tenant = tenant

                    connection.set_tenant(request.tenant)
                else:
                    print('NO TENANT')
                    return HttpResponse('Unauthorized - Invalid Tenant Id',
                                        status=401)
            except domain_model.DoesNotExist:
                raise self.TENANT_NOT_FOUND_EXCEPTION('No tenant for id "%s"' %
                                                      tenant_id)

        # if request.method != 'OPTIONS':
        #     try:
        #         tenant_id = request.headers.get('X-TENANT-ID')
        #         print('TENANT ID = ', tenant_id)
        #         tenant_model = get_tenant_model()
        #         tenant = tenant_model.objects.get(tenant_id=tenant_id)
        #         print('TENANT = ', tenant.__dict__)
        #     except domain_model.DoesNotExist:
        #         raise self.TENANT_NOT_FOUND_EXCEPTION(
        #             'No tenant for id "%s"' % tenant_id)

        #     tenant.domain_url = hostname
        #     request.tenant = tenant

        #     connection.set_tenant(request.tenant)

        # ** OLD DOMAIN METHOD***
        # try:
        #     tenant = self.get_tenant(domain_model, hostname)
        #     print('TENANT = ', tenant)
        # except domain_model.DoesNotExist:
        #     raise self.TENANT_NOT_FOUND_EXCEPTION('No tenant for hostname "%s"' % hostname)

        # tenant.domain_url = hostname
        # request.tenant = tenant

        # connection.set_tenant(request.tenant)
        # ***************

        # Do we have a public-specific urlconf?
        if hasattr(
                settings, 'PUBLIC_SCHEMA_URLCONF'
        ) and request.tenant.schema_name == get_public_schema_name():
            request.urlconf = settings.PUBLIC_SCHEMA_URLCONF
            set_urlconf(request.urlconf)
    def handle(self, *args, **options):
        # Connection needs first to be at the public schema, as this is where
        # the database needs to be set before creating a new tenant. If this is
        # not done then django-tenants will raise a "Can't create tenant outside
        # the public schema." error.
        connection.set_schema_to_public()  # Switch to Public.

        # Get the user inputs.
        schema_name = options['schema_name'][0]
        length = options['length'][0]

        try:
            organization = SharedOrganization.objects.get(
                schema_name=schema_name)
        except SharedOrganization.DoesNotExist:
            raise CommandError(_('Organization does not exist!'))

        # Connection will set it back to our tenant.
        connection.set_schema(organization.schema_name,
                              True)  # Switch to Tenant.

        members = Member.seed(organization, length)

        # Iterate through all the randomly generated members
        for member in members:
            freezer = freeze_time(member.last_modified_at)
            freezer.start()

            # Run the following which will save our searchable content.
            indexed_text = Member.get_searchable_content(member)
            member.indexed_text = Truncator(indexed_text).chars(1023)
            member.save()

            # Promote the `member` to be an `area coordinator`.
            area_coordinator = member.promote_to_area_coordinator(
                defaults={
                    'has_signed_area_coordinator_agreement': True,
                    'has_signed_conflict_of_interest_agreement': True,
                    'has_signed_code_of_conduct_agreement': True,
                    'has_signed_confidentiality_agreement': True,
                    'police_check_date': timezone.now(),
                    'created_by': None,
                    'created_from': None,
                    'created_from_is_public': False,
                    'last_modified_by': None,
                    'last_modified_from': None,
                    'last_modified_from_is_public': False,
                })

            # For debugging purposes.
            self.stdout.write(
                self.style.SUCCESS(
                    _('Promoted member slug %(slug)s to area coordinator.') % {
                        'slug': member.user.slug,
                    }))

            freezer.stop()

        # For debugging purposes.
        self.stdout.write(
            self.style.SUCCESS(
                _('Successfully seed the following member(s):')))

        for member in members:
            self.stdout.write(
                self.style.SUCCESS(
                    _('Slug %(slug)s.') % {
                        'slug': member.user.slug,
                    }))
Example #45
0
def member_logout(request):
    connection.set_schema_to_public()
    logout(request)
    return redirect('member-login')
Example #46
0
    def process_request(self, request):  # noqa: C901
        """Process request for csrf checks.
        Args:
            request (object): The request object
        """
        connection.set_schema_to_public()

        if is_no_auth(request):
            request.user = User("", "")
            return

        try:
            rh_auth_header, json_rh_auth = extract_header(request, self.header)
        except (KeyError, JSONDecodeError):
            LOG.warning("Could not obtain identity on request.")
            return
        except binascii.Error as error:
            LOG.error("Error decoding authentication header: %s", str(error))
            raise PermissionDenied()

        is_cost_management = json_rh_auth.get("entitlements", {}).get("cost_management", {}).get("is_entitled", False)
        skip_entitlement = is_no_entitled(request)
        if not skip_entitlement and not is_cost_management:
            LOG.warning("User is not entitled for Cost Management.")
            raise PermissionDenied()

        account = json_rh_auth.get("identity", {}).get("account_number")
        user = json_rh_auth.get("identity", {}).get("user", {})
        username = user.get("username")
        email = user.get("email")
        is_admin = user.get("is_org_admin")
        req_id = None

        if username and email and account:
            # Get request ID
            req_id = request.META.get("HTTP_X_RH_INSIGHTS_REQUEST_ID")
            # Check for customer creation & user creation
            query_string = ""
            if request.META["QUERY_STRING"]:
                query_string = "?{}".format(request.META["QUERY_STRING"])
            stmt = {
                "method": request.method,
                "path": request.path + query_string,
                "request_id": req_id,
                "account": account,
                "username": username,
                "is_admin": is_admin,
            }
            LOG.info(stmt)
            try:
                if account not in IdentityHeaderMiddleware.customer_cache:
                    IdentityHeaderMiddleware.customer_cache[account] = Customer.objects.filter(
                        account_id=account
                    ).get()
                    LOG.debug(f"Customer added to cache: {account}")
                customer = IdentityHeaderMiddleware.customer_cache[account]
            except Customer.DoesNotExist:
                customer = IdentityHeaderMiddleware.create_customer(account)
            except OperationalError as err:
                LOG.error("IdentityHeaderMiddleware exception: %s", err)
                DB_CONNECTION_ERRORS_COUNTER.inc()
                return HttpResponseFailedDependency({"source": "Database", "exception": err})

            try:
                if username not in USER_CACHE:
                    user = User.objects.get(username=username)
                    USER_CACHE[username] = user
                    LOG.debug(f"User added to cache: {username}")
                else:
                    user = USER_CACHE[username]
            except User.DoesNotExist:
                user = IdentityHeaderMiddleware.create_user(username, email, customer, request)

            user.identity_header = {"encoded": rh_auth_header, "decoded": json_rh_auth}
            user.admin = is_admin
            user.req_id = req_id

            cache = caches["rbac"]
            user_access = cache.get(user.uuid)

            if not user_access:
                if settings.DEVELOPMENT and request.user.req_id == "DEVELOPMENT":
                    # passthrough for DEVELOPMENT_IDENTITY env var.
                    LOG.warning("DEVELOPMENT is Enabled. Bypassing access lookup for user: %s", json_rh_auth)
                    user_access = request.user.access
                else:
                    try:
                        user_access = self._get_access(user)
                    except RbacConnectionError as err:
                        return HttpResponseFailedDependency({"source": "Rbac", "exception": err})
                cache.set(user.uuid, user_access, self.rbac.cache_ttl)
            user.access = user_access
            request.user = user
Example #47
0
 def tearDownClass(cls):
     connection.set_schema_to_public()
     cls.tenant.delete()
Example #48
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
        with transaction.atomic():
            # Verify name structure
            _check_schema_name(self.schema_name)

            # 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!
            if schema_exists(self.schema_name):
                LOG.warning(f'Schema "{self.schema_name}" already exists.')
                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 DBError as dbe:
                db_exc = dbe
                LOG.error(
                    f"""Exception {dbe.__class__.__name__} cloning""" +
                    f""" "{self._TEMPLATE_SCHEMA}" to "{self.schema_name}": {str(dbe)}"""
                )
                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():
            conn.set_schema_to_public()

        if db_exc:
            raise db_exc

        return True
Example #49
0
 def tearDown(self):
     connection.set_schema_to_public()
     self.domain.delete()
     self.tenant.delete(force_drop=True)
Example #50
0
 def tearDown(self):
     connection.set_schema_to_public()
Example #51
0
    def test_command_with_multiple_success(self):
        call_command(
            "create_franchise",
            "london_test",
            "Over55",
            "Over55 (London) Inc.",
            "Located at the Forks of the Thames in downtown London Ontario, Over 55 is a non profit charitable organization that applies business strategies to achieve philanthropic goals. The net profits realized from the services we provide will help fund our client and community programs. When you use our services and recommended products, you are helping to improve the quality of life of older adults and the elderly in our community.",
            "CA",
            "London",
            "Ontario",
            "", # Post Offic #
            "N6H 1B4",
            "78 Riverside Drive",
            "", # Extra line.
            "America/Toronto",
            verbosity=0
        )
        call_command(
           'create_tenant_account',
           "london_test",
           constants.MANAGEMENT_GROUP_ID,
           TEST_USER_EMAIL,
           TEST_USER_PASSWORD,
           "Bart",
           "Mika",
           TEST_USER_TEL_NUM,
           TEST_USER_TEL_EX_NUM,
           TEST_USER_CELL_NUM,
           "CA",
           "London",
           "Ontario",
           "", # Post Offic #
           "N6H 1B4",
           "78 Riverside Drive",
           "", # Extra line.
           verbosity=0
        )
        call_command(
           'create_tenant_account',
           "london_test",
           constants.MANAGEMENT_GROUP_ID,
           "*****@*****.**",
           "123password",
           "Rodolfo",
           "Martinez",
           TEST_USER_TEL_NUM,
           TEST_USER_TEL_EX_NUM,
           TEST_USER_CELL_NUM,
           "CA",
           "London",
           "Ontario",
           "", # Post Offic #
           "N6H 1B4",
           "78 Riverside Drive",
           "", # Extra line.
           verbosity=0
        )

        # Connection needs to be the public schema as the user is in the shared database.
        connection.set_schema_to_public() # Switch to Public.

        # Verify the account works.
        from django.contrib.auth.hashers import check_password
        user = SharedUser.objects.filter(email__iexact=TEST_USER_EMAIL).first()
        self.assertIsNotNone(user)
        is_authenticated = check_password(TEST_USER_PASSWORD, user.password)
        self.assertTrue(is_authenticated)
Example #52
0
 def setUp(self):
     connection.set_schema_to_public()
     super().setUp()
Example #53
0
 def tearDown(self):
     connection.set_schema_to_public()
     self.remove_allowed_test_domain()
 def tearDownClass(cls):
     """Tear down the class."""
     connection.set_schema_to_public()
     cls.tenant.delete()
     super().tearDownClass()
Example #55
0
 def tearDownClass(cls):
     connection.set_schema_to_public()
     super(FastTenantTestCase, cls).tearDownClass()
Example #56
0
    def tearDownClass(cls):
        connection.set_schema_to_public()
        cls.tenant.delete()

        cursor = connection.cursor()
        cursor.execute('DROP SCHEMA IF EXISTS test CASCADE')
Example #57
0
 def tearDownClass(cls):
     connection.set_schema_to_public()
     cls.domain.delete()
     cls.tenant.delete(force_drop=True)
     cls.remove_allowed_test_domain()
Example #58
0
 def tearDownClass(self):
     connection.set_schema_to_public()
     self.tenant.delete()
     super().tearDownClass()
Example #59
0
 def tearDownClass(cls):
     connection.set_schema_to_public()
Example #60
0
    def handle(self, *args, **options):
        # Get the user inputs.
        schema_name = options['schema_name'][0]
        group_id = int(options['group_id'][0])
        email = options['email'][0]
        password = options['password'][0]
        first_name = options['first_name'][0]
        last_name = options['last_name'][0]
        telephone = options['telephone'][0]
        telephone_extension = options['telephone_extension'][0]
        other_telephone = options['other_telephone'][0]
        address_country = options['address_country'][0]
        address_locality = options['address_locality'][0]
        address_region = options['address_region'][0]
        post_office_box_number = options['post_office_box_number'][0]
        postal_code = options['postal_code'][0]
        street_address = options['street_address'][0]
        street_address_extra = options['street_address_extra'][0]

        # Connection needs first to be at the public schema, as this is where
        # the database needs to be set before creating a new tenant. If this is
        # not done then django-tenants will raise a "Can't create tenant outside
        # the public schema." error.
        connection.set_schema_to_public()  # Switch to Public.

        # Defensive Code: Prevent continuing if the email already exists.
        if SharedUser.objects.filter(email=email).exists():
            raise CommandError(
                _('Email already exists, please pick another email.'))

        try:
            franchise = SharedFranchise.objects.get(schema_name=schema_name)
        except SharedFranchise.DoesNotExist:
            raise CommandError(_('Franchise does not exist!'))

        # Create the user.
        user = SharedUser.objects.create(first_name=first_name,
                                         last_name=last_name,
                                         email=email,
                                         is_active=True,
                                         franchise=franchise,
                                         was_email_activated=True)
        self.stdout.write(
            self.style.SUCCESS(_('Created a "SharedUser" object.')))

        # Generate and assign the password.
        user.set_password(password)
        user.save()

        # Generate the private access key.
        token = Token.objects.create(user=user)

        self.stdout.write(self.style.SUCCESS(_('Created a "Token" object.')))

        # Attach our user to the group.
        user.groups.add(group_id)

        # Connection will set it back to our tenant.
        connection.set_schema(franchise.schema_name, True)  # Switch to Tenant.

        # Create `Manager` or `Frontline Staff`.
        if group_id == constants.MANAGEMENT_GROUP_ID or group_id == constants.FRONTLINE_GROUP_ID:
            Staff.objects.create(
                owner=user,
                given_name=first_name,
                last_name=last_name,
                email=email,
                telephone=telephone,
                telephone_extension=telephone_extension,
                other_telephone=other_telephone,
                address_country=address_country,
                address_locality=address_locality,
                address_region=address_region,
                post_office_box_number=post_office_box_number,
                postal_code=postal_code,
                street_address=street_address,
                street_address_extra=street_address_extra,
            )
            self.stdout.write(
                self.style.SUCCESS(_('Created a "Staff" object.')))

        # Create `Associate`.
        if group_id == constants.ASSOCIATE_GROUP_ID:
            Associate.objects.create(
                owner=user,
                given_name=first_name,
                last_name=last_name,
                email=email,
                telephone=telephone,
                telephone_extension=telephone_extension,
                other_telephone=other_telephone,
                address_country=address_country,
                address_locality=address_locality,
                address_region=address_region,
                post_office_box_number=post_office_box_number,
                postal_code=postal_code,
                street_address=street_address,
                street_address_extra=street_address_extra,
            )
            self.stdout.write(
                self.style.SUCCESS(_('Created an "Associate" object.')))

        # Create `Customer`.
        if group_id == constants.CUSTOMER_GROUP_ID:
            Customer.objects.create(
                owner=user,
                given_name=first_name,
                last_name=last_name,
                email=email,
                telephone=telephone,
                telephone_extension=telephone_extension,
                other_telephone=other_telephone,
                address_country=address_country,
                address_locality=address_locality,
                address_region=address_region,
                post_office_box_number=post_office_box_number,
                postal_code=postal_code,
                street_address=street_address,
                street_address_extra=street_address_extra,
            )
            self.stdout.write(
                self.style.SUCCESS(_('Created a "Customer" object.')))

        # For debugging purposes.
        self.stdout.write(
            self.style.SUCCESS(_('Successfully created a tenant account.')))