
    Bhp<                        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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"  ed      Z#d Z$d Z% G d d      Z& G d d      Z' e'       Z(y)    )partial)	getLogger)messages)Site)cache)ValidationError)NoReverseMatch)cached_property)autodiscover_modules)get_language_from_requestgettext_lazy)get_current_site)get_cms_setting)get_default_language_for_site is_language_prefix_patterns_usedMenu)NamespaceAlreadyRegistered)CacheKeymenusc                 v   i }g }t        |       }| r&d}| j                  d      }t        |dd      dz   |_        |j                  s||_        |j                  |vri ||j                  <   |j
                  ||j                     v rR|j                  s||_        ||j                     |j
                     }|j                  j                  |       ||_	        n.|j
                  r"|j                  |k  r| j                  |       d}|r-|j                  |       |||j                     |j                  <   | r&|S )z{
    This is an easier to test "inner loop" building the menu tree structure
    for one menu (one language, one site)
    Tr   _counter   F)lenpopgetattrr   	namespace	parent_idparent_namespacechildrenappendparentid)nodesmenu_class_name
done_nodesfinal_nodeslist_total_lengthshould_add_to_final_listnoder"   s           ?/home/dcms/DCMS/lib/python3.12/site-packages/menus/menu_pool.py_build_nodes_inner_for_one_menur,      s,   
 JK
 E

 $( yy|  j!4q8 ~~,DN>>+)+Jt~~& >>Z77(((7%/?FOO""4( DK^^ }}00T" (-$#t$26Jt~~&tww/M N     c                 N    d|i}| j                   }t        |       } ||| f|      S )z
    Returns a new menu class that subclasses
    menu_class but is bound to instance.
    This means it sets the "instance" attribute of the class.
    instance)__name__type)
menu_classr/   attrs
class_name
meta_classs        r+   _get_menu_class_for_instancer6   T   s4     "E$$Jj!Jj:-77r-   c                   f    e Zd Zd Zed        Zed        Zd Zd Z	d Z
d Zd Zdd
ZddZd Zy	)MenuRendererc                    || _         |j                  d      | _        || _        t        j
                  j                  |      | _        d | _        t        |d      r|j                  | _        | j                  s$t        | j                  j                        | _        t        |dd       }|r |j                  xs |j                  | _        y d| _        y )NTfor_renderingLANGUAGE_CODEtoolbarF)poolget_registered_menusr   requestr   objectsget_currentsiterequest_languagehasattrr<   r   pkr   edit_mode_activepreview_mode_activeedit_or_preview)selfr>   r@   r=   s       r+   __init__zMenuRenderer.__init__f   s    	
 ..T.B
LL,,W5	 $7O,$+$9$9D!$$$A$)),,$OD!'9d3Zaw77V7;V;Vglr-   c                 *   t        d      }| d| j                   d| j                  j                   }| j                  j
                  j                  r'|d| j                  j
                  j                   dz  }| j                  r|dz  }|S |dz  }|S )NCACHE_PREFIXmenu_nodes___userz:editz:public)r   rD   rC   rF   r@   useris_authenticatedrI   )rJ   prefixkeys      r+   	cache_keyzMenuRenderer.cache_keyx   s     0D$9$9#:!DIILL>J<<--Qt||((++,E22C7NC 
 9C
r-   c                     t         j                  j                  | j                  | j                  | j
                  j                        }|j                         S )NrT   languagerC   )r   rA   filterrU   rD   rC   rF   exists)rJ   db_cache_key_lookups     r+   	is_cachedzMenuRenderer.is_cached   sJ    &..55** 6 

 #))++r-   c                    | j                   }t        j                  |d      }|r| j                  r|S g }t	        | j
                  dd      }| j                  D ]>  }| j                  |      }	 |j                  | j
                        }|t        ||      z  }@ t        j                   ||t#        d      d          | j                  sOd| j$                  d	<   t&        j(                  j+                  || j,                  | j.                  j0                  
       |S # t        $ rY g }|r8|j                  r,t        j                  | j
                  t        d      |z         t        j                  d|z  d       Y w xY w)a  
        This is slow. Caching must be used.
        One menu is built per language and per site.

        Namespaces: they are ID prefixes to avoid node ID clashes when plugging
        multiple trees together.

        - We iterate on the list of nodes.
        - We store encountered nodes in a dict (with namespaces):
            done_nodes[<namespace>][<node's id>] = node
        - When a node has a parent defined, we lookup that parent in done_nodes
            if it's found:
                set the node as the node's parent's child (re-read this)
            else:
                the node is put at the bottom of the list
        Nr=   zSMenu %s cannot be loaded. Please, make sure all its urls exist and can be resolved.zMenu %s could not be loaded.T)exc_infoCACHE_DURATIONSr   r\   rW   )rU   r   getr\   r   r@   r   get_menu	get_nodesr	   is_staffr   errorrO   loggerr,   setr   __dict__r   rA   createrD   rC   rF   )rJ   rT   cached_nodesr'   r=   r%   menur$   s           r+   _build_nodeszMenuRenderer._build_nodes   s`   " nnyyd+DNN  $,,	48#zz 	SO==1D^t||4 :5/RRK#	S& 			#{O4E$Fw$OP~~ *.DMM+& ##d6K6KRVR[R[R^R^#_5 " 
^ w//NNop'(
 ;oMX\]
^s   -DAE;:E;c                      t         fd|D        d      }|rDd|_         j                  |        j                  |       d |D        } j	                  ||       |S )zCMark the selected node and its ancestors, descendants and siblings.c              3   Z   K   | ]"  }|j                  j                        s| $ y wN)is_selectedr@   ).0r*   rJ   s     r+   	<genexpr>z.MenuRenderer._mark_selected.<locals>.<genexpr>   s"     R$43C3CDLL3QRs    ++NTc              3   :   K   | ]  }|j                   r|  y wrn   )r"   )rp   r*   s     r+   rq   z.MenuRenderer._mark_selected.<locals>.<genexpr>   s     D4$Ds   )nextselected_mark_ancestors_mark_descendants_mark_siblings)rJ   r$   rt   
root_nodess   `   r+   _mark_selectedzMenuRenderer._mark_selected   s\    R%RTXY $H  *""8,D5DJ*5r-   c                 ^    |j                   r!|j                   }d|_        |j                   r yy)z)Marks the ancestors of the selected node.TN)r"   ancestor)rJ   r*   s     r+   ru   zMenuRenderer._mark_ancestors   s"    kk;;D DM kkr-   c                 V    |j                   D ]  }d|_        | j                  |        y)z+Marks the descendants of the selected node.TN)r    
descendantrv   )rJ   r*   childs      r+   rv   zMenuRenderer._mark_descendants   s+    ]] 	*E#E""5)	*r-   c                     |j                   r)|j                   j                  D ]  }||k7  s	d|_         y|D ]  }||k7  s	d|_         y)zTMarks the siblings of the selected node. All root nodes are siblings of a root node.TN)r"   r    sibling)rJ   r*   rx   r   s       r+   rw   zMenuRenderer._mark_siblings   sO    ;;;;// +d?&*GO+ & +d?&*GO+r-   Nc           	          |s| j                  |      }| j                  j                         D ]+  } ||       }|j                  | j                  |||||      }- |S N)renderer)ry   r>   get_registered_modifiersmodifyr@   )rJ   r$   r   root_idpost_cut
breadcrumbclsinsts           r+   apply_modifierszMenuRenderer.apply_modifiers   sf    ''.E
 99557 	OC%DKKeY:OE	O r-   c                 R    | j                         }| j                  |||d|      }|S )NF)r$   r   r   r   r   )rk   r   )rJ   r   r   r   r$   s        r+   rb   zMenuRenderer.get_nodes   s;    !!#$$! % 
 r-   c                 2    | j                   |   } ||       S r   )r   )rJ   	menu_name	MenuClasss      r+   ra   zMenuRenderer.get_menu	  s    JJy)	$''r-   )NNFFNNF)r0   
__module____qualname__rK   propertyrU   r
   r\   rk   ry   ru   rv   rw   r   rb   ra    r-   r+   r8   r8   `   sY    m$   , ,=~	!*	+	(r-   r8   c                   L    e Zd Zd Zd Zd ZddZd ZddZd Z	d	 Z
d
 Zd Zy)MenuPoolc                 .    i | _         g | _        d| _        y )NF)r   	modifiers
discoveredrJ   s    r+   rK   zMenuPool.__init__  s    
r-   c                 <    | j                          t        | |      S )N)r>   r@   )discover_menusr8   )rJ   r@   s     r+   get_rendererzMenuPool.get_renderer  s     w77r-   c                 \    | j                   ry t        d       ddlm}  |        d| _         y )N	cms_menusr   )registerT)r   r   menus.modifiersr   )rJ   r   s     r+   r   zMenuPool.discover_menus  s#    ??[),
r-   c                    | j                          i }| j                  j                         D ]  \  }}t        |t              r|j
                  }t        |d      rSt        t        |      }|j                         xs g }|D ]  }| d|j                   } ||      ||<     |rx|r{|||<   t        |d      r|||<   t        d       |S )z
        Returns all registered menu classes.

        :param for_rendering: Flag that when True forces us to include
            all CMSAttachMenu subclasses, even if they're not attached.
        get_instances:rb   z.Something was registered as a menu, but isn't.)r   r   items
isinstancer   	__class__rE   r   r6   r   rF   r   )	rJ   r;   registered_menusr%   menu_cls_get_menu_class	instancesr/   r   s	            r+   r?   zMenuPool.get_registered_menus$  s     	)-)9)9); "	F%OX(D) $--x1 #**F"Q$224:	 ) LH $3"31X[[M BI2A(2K$Y/L !
 9A$_5;/ 5= 1%DF FC"	FF  r-   c                     | j                   S rn   )r   r   s    r+   r   z!MenuPool.get_registered_modifiersS  s    ~~r-   Nc                    |rt         j                  j                         }n t         j                  j                  ||      }|j                         j	                  dd      }|r&t        j                  |       |j                          yy)zT
        This invalidates the cache for a given menu (site_id and language)
        rT   T)flatN)r   rA   get_keysdistinctvalues_listr   delete_manydelete)rJ   site_idrX   all
cache_keysto_be_deleteds         r+   clearzMenuPool.clearV  ss     !))224J!))227HEJ"++-99%d9Km, r-   c                     ddl m} t        ||      sJ |j                  | j                  v rt        d|j                   d      || j                  |j                  <   y )Nr   r   [z-] a menu with this name is already registered)
menus.baser   
issubclassr0   r   r   )rJ   r   r   s      r+   register_menuzMenuPool.register_menue  s`    #(D)))

*,H%%&&STV V )1

8$$%r-   c                     ddl m} t        ||      sJ || j                  vr| j                  j	                  |       y y )Nr   )Modifier)r   r   r   r   r!   )rJ   modifier_classr   s      r+   register_modifierzMenuPool.register_modifiern  s8    '.(333/NN!!.1 0r-   c                     | j                  d      }t        |j                         D ch c]-  \  }}t        ||d      |k(  r|j                  |j
                  f/ c}}      S c c}}w )zX
        Returns the list of menus that match the name/value criteria provided.
        Fr:   N)r?   sortedr   r   r0   name)rJ   r   valuer   r%   rj   s         r+   get_menus_by_attributezMenuPool.get_menus_by_attributet  sg     )))>EJ[[] 4,AOTdD)U2 mmTYY' 4
 	
4s   2A%
c                 l    |D cg c]$  }|j                   j                  |d       |k(  s#|& c}S c c}w rn   )attrr`   )rJ   r$   r   r   r*   s        r+   get_nodes_by_attributezMenuPool.get_nodes_by_attribute  s,    !&M$))--d*Cu*LMMMs   $11)Fr   )r0   r   r   rK   r   r   r?   r   r   r   r   r   r   r   r-   r+   r   r     s6     
8- ^ 12
"Nr-   r   N))	functoolsr   loggingr   django.contribr   django.contrib.sites.modelsr   django.core.cacher   django.core.exceptionsr   django.urlsr	   django.utils.functionalr
   django.utils.module_loadingr   django.utils.translationr   r   rO   	cms.utilsr   cms.utils.confr   cms.utils.i18nr   r   r   r   menus.exceptionsr   menus.modelsr   re   r,   r6   r8   r   	menu_poolr   r-   r+   <module>r      sw      # , # 2 & 3 <
 ' *  7 !	7	4n	8k( k(\xN xNv J	r-   