
    h0+                        S SK r S SKJr  S SKJrJr  S SKJr  S SKJ	r	  S SK
JrJr  S SKJrJrJr  S SKJr   S S	KJr  \R*                  rS SKJr  S rS rS rS rS rS rS r S r!S r"S r#S r$S r%S r&S r'S r( " S S\5      r) " S S\5      r*S r+S  r,S! r-S" r.\" 5       4S# jr/\" 5       S$4S% jr0\" S&S'9S( 5       r1S) r2S* r3S+ r4S$S,S-.S. jr5S/ r6g! \ a	    S S
KJr   Nf = f)0    N)ContextDecorator)	lru_cachewraps)
ModuleType)settings)ImproperlyConfiguredValidationError)DEFAULT_DB_ALIAS
connectionconnections)import_stringapps)	get_model)mailc                  4    [        [        R                  5      $ N)r   r   TENANT_MODEL     F/var/www/html/env/lib/python3.13/site-packages/django_tenants/utils.pyget_tenant_modelr      s    X**++r   c                  4    [        [        R                  5      $ r   )r   r   TENANT_DOMAIN_MODELr   r   r   get_tenant_domain_modelr      s    X1122r   c                  ,    [        [        S[        5      $ )NTENANT_DB_ALIAS)getattrr   r
   r   r   r   get_tenant_database_aliasr      s    8.0@AAr   c                  $    [        [        SS5      $ )NPUBLIC_SCHEMA_NAMEpublicr   r   r   r   r   get_public_schema_namer$       s    818<<r   c                  $    [        [        S0 5      $ )NTENANT_TYPESr#   r   r   r   get_tenant_typesr'   $   s    8^R00r   c                  :    [        [        SS5      n [        U 5      $ )NTENANT_BASE_MIGRATE_COMMANDz/django.core.management.commands.migrate.Command)r   r   r   )
class_paths    r   %get_tenant_base_migrate_command_classr+   (   s"    %9J
 $$r   c                  $    [        [        SS5      $ )NHAS_MULTI_TYPE_TENANTSFr#   r   r   r   has_multi_type_tenantsr.   1       85u==r   c                  $    [        [        SS5      $ )NMULTI_TYPE_DATABASE_FIELD r#   r   r   r   "get_multi_type_database_field_namer3   5   s    88"==r   c                  r    [        5       (       a  [        5       [        5          S   $ [        [        SS5      $ )NURLCONFPUBLIC_SCHEMA_URLCONFurls_public)r.   r'   r$   r   r   r   r   r   get_public_schema_urlconfr8   9   s2    !"8":;IFFx!8-HHr   c                      [        5       (       d   S5       e[        5       n U R                  5        Vs/ s H  oU4PM     sn$ s  snf )z6This is to allow a choice field for the type of tenantzBget_tenant_type_choices should only be used for multi type tenants)r.   r'   keys)tenant_typesks     r   get_tenant_type_choicesr=   @   sC    !##ZZZu#%L(--/0/qF/000s   Ac                  $    [        [        SS5      $ )NTENANT_LIMIT_SET_CALLSFr#   r   r   r   get_limit_set_callsr@   J   r/   r   c                  X    [        [        SS5      =(       d    Sn U R                  S5      $ )NTENANT_SUBFOLDER_PREFIXr2   z/ )r   r   strip)subfolder_prefixs    r   get_subfolder_prefixrE   N   s(    x)BBGM2!!$''r   c                  x    [        [        SS5      n U (       a!  [        [        SS5      (       d  [        S5      eU $ )|
If TENANT_CREATION_FAKES_MIGRATIONS, tenants will be created by cloning an
existing schema specified by TENANT_CLONE_BASE.
 TENANT_CREATION_FAKES_MIGRATIONSFTENANT_BASE_SCHEMAzdYou must specify a schema name in TENANT_BASE_SCHEMA if TENANT_CREATION_FAKES_MIGRATIONS is enabled.r   r   r   )fakeds    r   get_creation_fakes_migrationsrL   S   s?    
 H@%HEx!5u==&?  Lr   c                  x    [        [        SS5      n U (       a!  [        [        SS5      (       d  [        S5      eU $ )rG   rI   FrH   z\TENANT_CREATION_FAKES_MIGRATIONS setting must be True to use TENANT_BASE_SCHEMA for cloning.rJ   )schemas    r   get_tenant_base_schemarO   b   s?    
 X3U;Fx!CUKK&2  Mr   c                  $    [        [        SS 5      $ )NTENANT_MIGRATION_ORDERr#   r   r   r   get_tenant_migration_orderrR   q   s    85t<<r   c                   4   ^  \ rS rSrU 4S jrS rS rSrU =r$ )schema_contextu   c                 6   > US   U l         [        TU ]	  5         g Nr   )schema_namesuper__init__selfargskwargs	__class__s      r   rZ   schema_context.__init__w   s    7r   c                     [         [        5          U l        [        R                  U l        U R                  R                  U R                  5        g r   )r   r   r   tenantprevious_tenant
set_schemarX   r\   s    r   	__enter__schema_context.__enter__{   s8    %&?&AB)00""4#3#34r   c                     U R                   c  U R                  R                  5         g U R                  R                  U R                   5        g r   rc   r   set_schema_to_public
set_tenantr\   excs     r   __exit__schema_context.__exit__   6    'OO002OO&&t';';<r   )r   rc   rX   	__name__
__module____qualname____firstlineno__rZ   rf   rn   __static_attributes____classcell__r_   s   @r   rT   rT   u   s    5
= =r   rT   c                   4   ^  \ rS rSrU 4S jrS rS rSrU =r$ )tenant_context   c                 6   > US   U l         [        TU ]	  5         g rW   )rb   rY   rZ   r[   s      r   rZ   tenant_context.__init__   s    1gr   c                     [         [        5          U l        [        R                  U l        U R                  R                  U R                  5        g r   )r   r   r   rb   rc   rk   re   s    r   rf   tenant_context.__enter__   s6    %&?&AB)00""4;;/r   c                     U R                   c  U R                  R                  5         g U R                  R                  U R                   5        g r   ri   rl   s     r   rn   tenant_context.__exit__   rp   r   )r   rc   rb   rq   rx   s   @r   rz   rz      s    0
= =r   rz   c                     [        [        S5      (       aU  [        R                  (       a@  U R                  [        R                  5      (       a  U [	        [        R                  5      S n U $ )z3
Removes the TENANT_TOKEN from a particular string
r6   N)hasattrr   r6   
startswithlen)
url_strings    r   clean_tenant_urlr      sP     x011**%%h&D&DEE#C(F(F$G$HIJr   c                     [        U 5      $ )zD
Legacy function - just in case someone is still using the old name
)
remove_wwwhostnames    r   remove_www_and_devr      s     hr   c                 <    U R                  S5      (       a  U SS $ U $ )z
Removes www. from the beginning of the address. Only for
routing purposes. www.test.com/login/ and test.com/login/ should
find the same tenant.
zwww.   N)r   r   s    r   r   r      s&     6""|Or   c                  "    [        [        S5      $ )z
I know this is very ugly! I'm looking for more elegant solutions.
See: http://stackoverflow.com/questions/6957016/detect-django-testing-mode
outbox)r   r   r   r   r   django_is_in_test_moder      s    
 4""r   c                     [         U   nUR                  5       nSnUR                  X@45        UR                  5       nU(       a  US   nOSnUR	                  5         U$ )NzUSELECT EXISTS(SELECT 1 FROM pg_catalog.pg_namespace WHERE LOWER(nspname) = LOWER(%s))r   F)r   cursorexecutefetchoneclose)rX   database_connectionr   sqlrowexistss          r   schema_existsr      s[    h'K!F bC
NN3(
//
C
Q
LLNMr   Tc                    SSK Jn  [        U   nUR                  5       n[	        U5      (       a  [        S5      eU" U5      (       d  [        S5      eSR                  [        R                  R                  U R                  5      [        R                  R                  U5      5      nUR                  U5        UR                  5         Xl
        U(       a  U R                  5         gg)zJ
This renames a schema to a new name. It checks to see if it exists first
r   )is_valid_schema_namezNew schema name already existsz(Invalid string used for the schema name.zALTER SCHEMA {0} RENAME TO {1}N)&django_tenants.postgresql_backend.baser   r   r   r   r	   formatr   ops
quote_namerX   r   r   save)rb   new_schema_namer   r   r   r   r   r   s           r   schema_renamer      s     Lh'K!F_%%>??00HII
*
1
1*..2K2KFL^L^2_2<..2K2KO2\^C
NN3
LLN( r      )maxsizec                 h   SSK Jn  U R                  S5      S   n [        U 5      n[        U[        5      (       a  U OUR                  nUR                  " 5        Vs/ s H!  nUR                  U:X  d  M  UR                  PM#     nn[        U5      S:w  a  U$ US   $ ! [         a    Us $ f = fs  snf )Nr   r   .   )django.appsr   splitr   ImportError
isinstancer   nameget_app_configslabelr   )appr   	candidateimported_appapp_name
app_config	app_labels          r   get_app_labelr      s     		#r"I$S) !z::s@Q@QH ..00J??h& 	
0   9~Q<  
s   B B/5B/B,+B,c                 D    U  Vs/ s H  n[        U5      PM     sn$ s  snf )z5
Returns a list of app labels of the given apps_list
)r   )	apps_listr   s     r   
app_labelsr      s!     +44)3M#)444s   c                      U [         R                  -  $ ! [        [        4 a1    [        R
                  R                  U [         R                  5      s $ f = f)a  
Convenience function for parsing django-tenants' path configuration strings.

If the string contains '%s', then the current tenant's schema name will be inserted at that location. Otherwise
the schema name will be appended to the end of the string.

:param config_path: A configuration path string that optionally contains '%s' to indicate where the tenant
schema name should be inserted.

:return: The formatted string containing the schema name
)r   rX   	TypeError
ValueErrorospathjoin)config_paths    r   parse_tenant_config_pathr     sJ    AZ3333z" Aww||K)?)?@@As    >AAc                     [        [        SS5      n [        [        S/ 5      nU (       Gd  U(       a  [        5       U;   a  [        S[        5       -  5      e[	        5       n[
        R                  " 5        nUR                  SUR                  R                  /5        UR                  5       (       a^  [        U5      R                  UR                  R                  5       R                  SSS95      nU(       a  [        S	[!        U5      -  5      eS S S 5        [
        R"                  " 5         g g g ! , (       d  f       N&= f)
NSKIP_PG_EXTRA_VALIDATIONFPG_EXTRA_SEARCH_PATHSz0%s can not be included on PG_EXTRA_SEARCH_PATHS.z>SELECT 1 FROM information_schema.tables WHERE table_name = %s;rX   T)flatz<Do not include tenant schemas (%s) on PG_EXTRA_SEARCH_PATHS.)r   r   r$   r   r   r   r   r   _metadb_tabler   setintersectionobjectsallvalues_listlistr   )skip_validationextra_extensionsmodelr   invalid_schemass        r   validate_extra_extensionsr     s   h(BEJOx)@"E/!#'77&B(*+, , !" FNNP%%&   "%&6"7"D"DMM%%'33M3M#O".V/01 1 ! 	1  0? ! s   5BD00
D>F)tenant_schemapublic_schemac                 r   ^ ^ UU 4S jn[        U5      S:X  a  [        US   5      (       a  U" US   5      $ U$ )a  
Decorator to control which schemas a data migration will execute on.

:param tenant_schema: If True (default), the data migration will execute on the tenant schema(s).
:param public_schema: If True, the data migration will execute on the public schema.

:return: None
c                 6   >^  [        T 5      U UU4S j5       nU$ )Nc                    >  U u  p#T(       a"  UR                  R                  [        5       :w  d)  T(       a,  UR                  R                  [        5       :X  a	  T" U 0 UD6  g g g ! [          a  n[        SU 35      eS nAff = f)NzADecorator requires apps & schema_editor as positional arguments: )	Exceptionr   rX   r$   )_argsr^   _schema_editorexcpfuncr   r   s        r   wrapper<tenant_migration.<locals>._tenant_migration.<locals>.wrapperE  s    l#(  =#;#;#G#GKaKc#c"}'?'?'K'KOeOg'ge&v& (h]	  l"cdhci jkkls   A$ $
B.A<<B)r   )r   r   r   r   s   ` r   _tenant_migration+tenant_migration.<locals>._tenant_migrationD  s     	t	' 
	' r   r   r   )r   callable)r   r   r]   r   s   ``  r   tenant_migrationr   :  s8     4yA~(47++ a))r   c                 >    [        U S5      (       a  U R                  $ g)z,This gets the tenant object from the requestrb   N)r   rb   )requests    r   
get_tenantr   X  s    w!!~~r   )7r   
contextlibr   	functoolsr   r   typesr   django.confr   django.core.exceptionsr   r	   	django.dbr
   r   r   django.utils.module_loadingr   r   r   r   r   django.db.models.loadingdjango.corer   r   r   r   r$   r'   r+   r.   r3   r8   r=   r@   rE   rL   rO   rR   rT   rz   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>r      s   	 ' &    H ? ? 53 I ,3B=1%>>I1>(
==% =$=% =$ 	# )B(C & 5N4OVZ * 3 05A(> +/e <U
  323s   C C&%C&