hobo/hobo/multitenant/models.py

92 lines
3.5 KiB
Python

import json
import os
import urllib.parse
from shutil import rmtree
from django.conf import settings
from django.db import connection
from django.utils import timezone
from tenant_schemas.models import TenantMixin
from tenant_schemas.postgresql_backend.base import _check_schema_name
from tenant_schemas.utils import django_is_in_test_mode, get_public_schema_name, schema_exists
class Tenant(TenantMixin):
# default true, schema will be automatically created and synced when it is saved
auto_create_schema = False
__hobo_json = None
def save(self):
pass
def __unicode__(self):
return 'Tenant %s (%s)' % (self.domain_url, self.schema_name)
def __str__(self):
return 'Tenant %s (%s)' % (self.domain_url, self.schema_name)
@classmethod
def base(cls):
return settings.TENANT_BASE
def get_directory(self):
return os.path.join(self.base(), self.domain_url)
def get_hobo_json(self):
if not self.__hobo_json:
self.__hobo_json = json.load(open(os.path.join(self.get_directory(), 'hobo.json')))
return self.__hobo_json
def get_service(self):
for service in self.get_hobo_json()['services']:
if service.get('this'):
return service
def get_base_url(self):
if os.path.exists(os.path.join(self.get_directory(), 'base_url')):
return open(os.path.join(self.get_directory(), 'base_url')).read().strip().strip('/')
return 'https://%s' % self.domain_url
def build_absolute_uri(self, location):
return urllib.parse.urljoin(self.get_base_url(), location)
def create_schema(self, check_if_exists=False, sync_schema=True, verbosity=1, legacy_schema_name=None):
if not legacy_schema_name:
return super().create_schema(check_if_exists, sync_schema, verbosity)
# safety check
_check_schema_name(self.schema_name)
_check_schema_name(legacy_schema_name)
if check_if_exists and schema_exists(self.schema_name):
return False
if not schema_exists(legacy_schema_name):
return False
# rename schema
cursor = connection.cursor()
cursor.execute('ALTER SCHEMA %s RENAME TO %s' % (legacy_schema_name, self.schema_name))
connection.set_schema_to_public()
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 force_drop:
rmtree(self.get_directory())
else:
deletion_date = timezone.now().strftime('%Y%m%d_%H%M%S_%f')
os.rename(self.get_directory(), self.get_directory() + '.removed_%s.invalid' % deletion_date)
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)
if schema_exists(self.schema_name) and (not self.auto_drop_schema and not force_drop):
cursor = connection.cursor()
schema_new_name = 'removed_%s_%s' % (deletion_date, self.schema_name)
cursor.execute('ALTER SCHEMA %s RENAME TO %s' % (self.schema_name, schema_new_name[:63]))