
    Bh=T                        d dl Z d dlZd dlZd dlmZmZmZ d dlmZ d dl	m
Z
 d dlmZmZ d dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZ d dlmZ d dlmZ d dlmZ d dlm Z  d dl!m"Z" d dl#m$Z$ d dl%m&Z& d dl'm(Z( d dl)m*Z*  e jV                  e,      Z-ede.de/e"   fd       Z0de.de fdZ1d&dZ2d'dZ3d Z4d Z5d'dZ6d Z7d(dZ8d Z9	 	 	 d)d ee    d!ee:   d"e;d#ee   dee    f
d$Z<d&d%Z=y)*    N)OrderedDictdefaultdictdeque)Iterable)deepcopy)cache	lru_cache)starmap)
itemgetter)Optional)models)HttpRequest)	force_str)gettext)PluginLimitReached)	CMSPlugin)CMSPluginBase)plugin_pool)get_language_from_request)has_plugin_permission)get_placeholder_confplugin_typereturnc                 ,    t        j                  |       S )z6Returns the plugin class for a given plugin_type (str))r   
get_pluginr   s    A/home/dcms/DCMS/lib/python3.12/site-packages/cms/utils/plugins.pyget_plugin_classr      s     !!+..    c                 ,    t        |       j                  S )z<Returns the plugin model class for a given plugin_type (str))r   modelr   s    r   get_plugin_modelr"   "   s    K(...r   c                 X    |sg S t        |d      st        | |g||       |j                  S )aP  
    Get a list of plugins for a placeholder in a specified template. Respects the placeholder's cache.

    :param request: (HttpRequest) The HTTP request object.
    :param placeholder: (Placeholder) The placeholder object for which to retrieve plugins.
    :param template: (Template) The template object in which the placeholder resides (not used).
    :param lang: (str, optional) The language code for localization. Defaults to None.

    Returns:
        list: A list of plugins for the specified placeholder in the template.

    Raises:
        None.

    Examples::

        # Get plugins for a placeholder in a template
        plugins = get_plugins(request, placeholder, template)

        # Get plugins for a placeholder in a template with specific language
        plugins = get_plugins(request, placeholder, template, lang="en")
    _plugins_cache)hasattrassign_pluginsr$   )requestplaceholdertemplatelangs       r   get_pluginsr+   '   s3    . 	; 01wx>%%%r   c                    |syt        |      }|xs t        |       }t        t        j                  j                  ||            }|st        | |||      }nt        |||       }t        t              }|D ]   }||j                     j                  |       " |D ]/  }||j                     }|rt        |      }	ng }	||_        |	|_        1 y)a"  
    Fetch all plugins for the given ``placeholders`` and
    cast them down to the concrete instances in one query
    per type.

    :param request: The current request.
    :param placeholders: An iterable of placeholder objects.
    :param template: (optional) The template object.
    :param lang: (optional) The language code.

    This method assigns plugins to the given placeholders. It retrieves the plugins from the database based on the
    placeholders and the language. The plugins are then downcasted to their specific plugin types.

    The plugins are split up by placeholder and stored in a dictionary where the key is the placeholder ID and the
    value is a list of plugins.

    For each placeholder, if there are plugins assigned to it, the plugins are organized as a layered tree structure.
    Otherwise, an empty list is assigned.

    The list of all plugins for each placeholder is stored in the `_all_plugins_cache` attribute of the placeholder,
    while the list of root plugins is stored in the `_plugins_cache` attribute
    N)placeholder__inlanguage)r'   )tupler   listr   objectsfiltercreate_default_pluginsdowncast_pluginsr   placeholder_idappendpkget_plugins_as_layered_tree_all_plugins_cacher$   )
r'   placeholdersr)   r*   pluginsplugins_by_placeholderpluginr(   all_pluginslayered_pluginss
             r   r&   r&   E   s    . &L5,W5D9$$++LSW+XYG(,$O"7L'J ). Ev445<<VDE $ 
5,[^^<9+FO O)4&%4"
5r   c                      ddl m d fd	fd|D        } fdt        t        d      |      D        }t	        t        |      g       S )z
    Create all default plugins for the given ``placeholders`` if they have
    a "default_plugins" configuration value in settings.
    return all plugins, children, grandchildren (etc.) created
    r   )
add_pluginc                     g g }}fd|D        }|D ]L  } 
| |d   fd|i|d   }d|v r| |d   |f}| 	| z  }|j                  |       |j                  |       N |r|j                  |       ||z   S )z
        Auxiliary function that builds all of a placeholder's default plugins
        at the current level and drives the recursion down the tree.
        Returns the plugins at the current level along with all descendants.
        c              3   X   K   | ]!  }t        j                  |d    d      s| # yw)r   addN)r   user).0confr'   s     r   	<genexpr>zJcreate_default_plugins.<locals>._create_default_plugins.<locals>.<genexpr>   s)     s$3HW[\iWjlq3rss   **r   targetvalueschildren)notify_on_autoaddr6   notify_on_autoadd_children)r(   confsparentr;   descendantsaddable_confsrG   r=   args_create_default_pluginsrA   r*   r'   s            r   rS   z7create_default_plugins.<locals>._create_default_plugins   s      "2s%s! 	#DT--@$hvhY]^fYghFT!"D$4f<6==$$Wd3NN6"	# --gtWE$$r   c              3   P   K   | ]  }|t        d |j                        f  yw)default_pluginsN)r   slot)rF   phr)   s     r   rH   z)create_default_plugins.<locals>.<genexpr>   s&     p]_12CRWWhWXps   #&c              3   b   K   | ]&  \  }}|j                  j                        r||f ( y wN)has_change_permissionrE   )rF   rW   default_plugin_confsr'   s      r   rH   z)create_default_plugins.<locals>.<genexpr>   s6      $B$##GLL1 
!"s   ,/   rY   )cms.apirA   r2   r   sumr
   )r'   r:   r)   r*   unfiltered_confsmutable_confsrS   rA   s   ` ``  @@r   r3   r3   z   sS     #% %& qcop(.z!}>N(OM
 w.>CCr   c                     t        t              }t               }t        |       D ]R  }||j                     |_        |j
                  r||j
                     j                  |       B|j                  |       T |S )z
    Given an iterable of plugins ordered by position,
    returns a deque of root plugins with their respective
    children set in the child_plugin_instances attribute.
    )r   r   reversedr7   child_plugin_instances	parent_id
appendleft)r;   delayedroot_pluginsr=   s       r   r8   r8      sr     % G7L7# ,(/		(:%F$$%008##F+, r   c                 "   |i }| j                   }t        | j                         }t        j                  || |      } |j                  di       } |j                  di       }	 ||   }|j                  r	|xs g ||<   g }	|j                  r8	 ||   }	|j                  | j                  j                  || d      }
|	|
z   }	|	|fS |	|fS # t
        $ r+ |j                  | j                  j                  ||       }Y w xY w# t
        $ r |j                  | j                  j                  || d      }	|j                  rJ|	xs g D  cg c]$  } t        j                  |       j                  s#| & nc c} w c} ||<   ||   s|	rdg||<   Y |	|fS w xY w)	N)pageplugin_parentsplugin_children)rV   ri   instanceT)rV   ri   rl   only_uncachedF )r   r   r   get_restrictions_cache
setdefaultKeyErrorget_parent_classesr(   rV   cache_parent_classesallow_childrenget_child_classescache_child_classesr   )r=   ri   restrictions_cacher   plugin_classr   parents_cachechildren_cacheparent_classeschild_classesuncached_child_classess              r   get_plugin_restrictionsr~      s   !$$K#F$6$67L../A6PTUE$E$$%5r:M%U%%&7<N
&{3 ((%3%9rk"M""	7*;7M%1%C%C'',,"	 &D &" *,BBM$ .((=.((Q  
%88##(( 9 

0  	7(::'',,#	 ; M // +8*=2/%+BXBXY_B`BuBuF/ /{+ &k2}35$N;/.((!	7s7   %C	 3D  	1C=<C= AF$E0+E0/FFc                 p    |D ]1  \  }}|j                  ||       }|s||_        |j                          3 y)a  
    Handle plugins where the parent hasn't yet been copied (child seen before the parent)

    CAVEAT: The only reason this exists is because the plugin position is not
           sequential through children when the user nests plugins.
           It's now too late as content already has this issue, it would be a very expensive
           calculation to recalculate every placeholders positions, needs to be handled gracefully
           so that it doesn't actually matter :-).
    N)getrO   save)root_pluginorphaned_plugin_listplugins_by_idold_plugin_parent_id
new_plugin
new_parents         r   -_reunite_orphaned_placeholder_plugin_childrenr      sB     -A (j"&&';[I
 *JOO	r   c                 r   g }t               }i }g }|r|j                  |       |r|j                  }t        |       D ];  }	|j	                  |	j
                  |      }
|	j                  }|t        ur=t        |	      }d|_	        d|_
        |xs |j                  |_        ||_        |
|_        n't        |xs |	j                  |
|	j                  |      }	 ||j                     }||_        |j'                          |dz   ||j                  <   |t        k7  r$|j)                  |	       |j+                  ||	f       |||	j                  <   |
r|	j
                  s|j+                  |	j
                  |f       > |rt-        |||       |D ]  \  }}|j/                  ||        |D ]  }|j1                  |        t3        |j5                               S # t        $ rU |j                  |      xs d}|j!                  |j                  |j                  d      }|j#                  |||       Y Pw xY w)a  Copies an iterable of plugins to a placeholder

    :param iterable plugins: Plugins to be copied
    :param placeholder: Target placeholder
    :type placeholder: :class:`cms.models.placeholdermodel.Placeholder` instance
    :param str language: target language (if no root plugin is given)
    :param root_plugin:
    :type placeholder: :class:`cms.models.pluginmodel.CMSPlugin` instance
    :param int start_positions: Cache for start positions by language

    The logic of this method is the following:

    #. Get bound plugins for each source plugin
    #. Get the parent plugin (if it exists)
    #. then get a copy of the source plugin instance
    #. Set the id/pk to None to it the id of the generic plugin instance above;
       this will effectively change the generic plugin created above
       into a concrete one
    #. find the position in the new placeholder
    #. save the concrete plugin (which creates a new plugin in the database)
    #. trigger the copy relations
    #. return the plugin ids
    N)r.   rO   r   r(   r   last)r.   rO   insert_order)startoffsetr\   )r   updater.   get_bound_pluginsr   rd   	__class__r   r   r7   idr(   rO   r   rq   get_last_plugin_positionget_next_plugin_position_shift_plugin_positionspositionr   copy_relationsr6   r   	post_copy_recalculate_plugin_positionsr0   rJ   )r;   r(   r.   r   start_positionsplugin_pairsr   positions_by_languager   source_pluginrO   plugin_modelr   r   r   
old_plugins                   r   copy_plugins_to_placeholderr      sZ   0 LMM$$_5''*73 0O""=#:#:KH$..y(!-0J JM JM"*"Aj.A.AJ%0J" &J""<m&<&<)55'	J	,Z-@-@AH" '
5=\j1129$%%m4] ;<*4m&&' -11 '')@)@*(MNa0Of 5kCWYfg
 #/ 7
JZ67 * <11(;< $$&''U  	 99(CHqF";;#,,!((# < H // 0 	s   GAH65H6c              #     K   t        t              }g }i }| D ]|  }|j                  |j                         t	        |j
                        j                  j                  }|t        u r|||j                  <   _||   j                  |j                         ~ |j                         D ]a  \  }}|j                  j                  |      }|j                         D ]-  }t	        |j
                        }	|	|_        |||j                  <   / c | D ]h  }|j                   xs |j                  |v}
|
xs |j                  |v }|s5|j                  |v sD||j                     |_        ||j                      j yw)aY  
    Get the bound plugins by downcasting the plugins to their respective classes. Raises a KeyError if the plugin type
    is not available.

    Creates a map of plugin types and their corresponding plugin IDs for later use in downcasting.
    Then, retrieves the plugin instances from the plugin model using the mapped plugin IDs.
    Finally, iterates over the plugins and yields the downcasted versions if they have a valid parent.
    Does not affect caching.

    :param plugins:  List of ``CMSPlugin`` instances.
    :type plugins: List[CMSPlugin]
    :return: Generator that yields the downcasted plugins.
    :rtype: Generator[CMSPlugin, None, None]

    Example::

        plugins = [plugin_instance1, plugin_instance2]
        for bound_plugin in get_bound_plugins(plugins):
            # Do something with the bound_plugin
            pass
    pk__inN)r   r0   r6   r7   r"   r   _metaconcrete_modelr   itemsr1   r2   iteratorr   rd   _inst)r;   plugin_types_map
plugin_idsplugin_lookupr=   
base_modelpksplugin_querysetrl   r!   parent_not_availablevalid_parents               r   r   r   `  sr    , #4(JM  ;&))$%f&8&89??NN
"'-M&))$Z(//		:; ,113 2
C$,,3333? (002 	2H$X%9%9:E!&H)1M(++&	2	2  +#)#3#33Yv7G7Gz7Y+Pv/?/?=/PFII6(3FL		**+s   D?E9E9(E9r;   r:   select_placeholderr'   c           	   #   >  K   t        t              }i }g }| D ]}  }	 t        |j                        j                  j
                  }|j                  |j                         |t        u r|||j                  <   `||   j                  |j                          |xs g }|D 	ci c]  }	|	j                  |	 }
}	|j                         D ]~  \  }}|j                  j!                  |      }|r|j#                  d      }|j%                         D ]7  }t'        |j                        }|j(                  |_        |||j                  <   9  | D ]  }|j,                   xs |j,                  |v}|xs |j,                  |v }|s5|j                  |v sD||j                     }|j,                  |v r&||j,                     |j.                  j0                  d<   |
j3                  |j4                        }	|	rG|	|_        t'        |j                        }|j8                  s |       j;                  |||	      sd|	_        ||_        |  y	# t        $ rH t        j                  d|j                   d|j                   dt        j                                Y |w xY wc c}	w w)
a  
    Downcasts the given list of plugins to their respective classes. Ignores any plugins
    that are not available.

    :param plugins: List of plugins to downcast.
    :type plugins: List[CMSPlugin]
    :param placeholders: List of placeholders associated with the plugins.
    :type placeholders: Optional[List[Placeholder]]
    :param select_placeholder: If True, select_related the plugin queryset with placeholder.
    :type select_placeholder: bool
    :param request: The current request.
    :type request: Optional[HttpRequest]
    :return: Generator that yields the downcasted plugins.
    :rtype: Generator[CMSPlugin, None, None]
    zPlugin not installed: z (pk=))exc_infor   r(   rO   FN) r   r0   r"   r   r   r   rq   loggererrorr7   sysr   r6   r   r   r1   r2   select_relatedr   r   r!   r   rd   _statefields_cacher   r5   r(   r   get_cache_expirationcache_placeholderr   )r;   r:   r   r'   r   r   r   r=   r   r(   placeholders_by_idr   r   	plugin_qsrl   clsr   r   s                     r   r4   r4     s    * #4(MJ  ;	)&*<*<=CCRRJ
 	&))$"'-M&))$Z(//		:;  %2LIUV++..+5VV-335 2c ((//s/;	!00?I "**, 	2H"8#7#78C!$H)1M(++&	22  #)#3#33Yv7G7Gz7Y+Pv/?/?=/PFII6$VYY/H!!]29FxGYGY9Z,,X6,001H1HIK'2$&x';';<yy)C)CGXWb)c49K1#FLN#7  	LL1&2D2D1EU699+UVWbebnbnbpLq	 WsD   J)IAJ"J6C	J JB5JAJJJJc           	      |   t        d| j                  |      }|sy|j                  d      }|j                  |      }| j                  |      j	                  t        j                  d      t        j                  dt        j                  |                  }|j                  d	      xs d
}|j                  d      xs d
}	|j                  d      }|j                  |      }|r||k\  rt        t        d      |z        |r5|	|k\  r/t        |      j                  }
t        t        d      ||
dz        yy)aE  
    Checks if the global maximum limit for plugins in a placeholder has been reached.
    If not then it checks if it has reached its maximum plugin_type limit.

    Parameters:
    - placeholder: The placeholder object to check the limit for.
    - plugin_type: The type of plugin to check the limit for.
    - language: The language code for the plugins.
    - template: The template object for the placeholder. Optional.

    Returns:
    - False if the limit has not been reached.

    Raises:
    - PluginLimitReached: If the limit has been reached for the placeholder.

    limitsFglobal)r.   r7   r   )r2   )total_count
type_countr   r   r   z@This placeholder already has the maximum number of plugins (%s).z_This placeholder already has the maximum number (%(limit)s) of allowed %(plugin_name)s plugins.)limitplugin_nameN)r   rV   r   r+   	aggregater   CountQr   _r   name)r(   r   r.   r)   r   global_limit
type_limitcountsr   r   r   s              r   has_reached_plugin_limitr     s/   $ "(K,<,<hGF::h'LK(J$$h$7AALL&<<VXX+-NO B F
 **]+0qKL).QJ::h'LK(J|3 #e!fiu!uvvjJ.&{388 q #;?@
 	
 /zr   rY   )NN)NNN)NFN)>loggingosr   collectionsr   r   r   collections.abcr   copyr   	functoolsr   r	   	itertoolsr
   operatorr   typingr   	django.dbr   django.httpr   django.utils.encodingr   django.utils.translationr   r   cms.exceptionsr   cms.models.pluginmodelr   cms.plugin_baser   cms.plugin_poolr   	cms.utilsr   cms.utils.permissionsr   cms.utils.placeholderr   	getLogger__name__r   strtyper   r"   r+   r&   r3   r8   r~   r   r   r   r0   boolr4   r    r   r   <module>r      s    	 
 7 7 $  &     # + 1 - , ) ' / 7 6			8	$ /# /$}*= / /
/# /) /
&<25j"DJ&4)n"c(L3+p $($%)	Ji J4.J J k"	J
 iJZ.
r   