U
    -dz                     @   s  U d dl Z d dlZd dlZd dlZd dlmZ d dlmZmZm	Z	m
Z
mZmZ d dlZd dlT d dlZd dlZe jG dd dZe jG dd dZe jG d	d
 d
Zdai aeeef ed< d dddZedddhZG dd deZG dd dejjj Z dS )    N)OrderedDict)TupleDictOptionalListSetType)*c                   @   sF   e Zd ZU dZee ed< dZeed< dZee ed< dZ	eed< dS )AccessRuleDataNsubjectsobject_modelobject_fieldsaccess_level)
__name__
__module____qualname__r   r   str__annotations__r   r   r    r   r   ./models/cmf_access_list.pyr
      s   
r
   c                   @   sz   e Zd ZU dZeed< dZeed< dZeed< dZ	eed< dZ
eed< ejedZee ed< ejedZee ed	< dS )
AccessListDataNdisabledidcodeinherit_acl_idobject_owner_iddefault_factorycustom_rules
auto_rules)r   r   r   r   boolr   r   r   r   r   r   dataclassesfieldlistr   r   r
   r   r   r   r   r   r      s   
r   c                   @   s   e Zd ZU ejedZeee	f e
d< ejedZee e
d< ejedZeeeejj f e
d< ejedZeeef e
d< dS )AclDatar   aclused_fieldsstatic_access_control_modelscacheN)r   r   r   r!   r"   dictr%   r   r   r   r   setr&   r   r'   r   cmfmodels	BaseModelr(   r   r   r   r   r   r$   "   s   
$r$   F_acl_cache_granted_tuplesd      )defaultreadonlyZprivatefullwritereadc                   @   s   e Zd ZdS )_AclStopN)r   r   r   r   r   r   r   r6   <   s   r6   c                       s  e Zd ZU dZdZdZeed< dZdd Z	e
dd	 Ze
d
d Ze
d;ee ee ee ee ee ee eejj ee ee ee d
ddZed<ddZe
d=ddZed>ddZedd Ze
dd Ze
dd Zeedddd  Ze
d!d" Z fd#d$Z fd%d&Z d'd( Z! fd)d*Z"d+d, Z#d-d. Z$d/d0 Z%d1d2 Z&d? fd3d4	Z'd5d6 Z(d7d8 Z)e
d@d9d:Z*  Z+S )ACmfAccessList TN	_ACL_DATAi c                 C   s6   dd| j gdddgg}tjj|dD ]}|  q$d S )N	parent_id=sys_typeautofilter)r   r,   CmfAccessRuler#   delete)selfZ
acl_filterZacl_itemr   r   r   clear_auto_aclF   s    zCmfAccessList.clear_auto_aclc                 C   s  t dt  d t }dddddh}| jdd	d
gd}|D ]\}t|j|j|j|j	|j
d}t dt  d|j d|j d ||j|j< ||j|j< q>tjjddddgdddggddddddgd}|D ]Z}|jr|j|krt dt  d| d|j d|j d	 qdd |jD }|jr:d d |jD nd}	|	rP|j|	 t||joft|j|	t|jd!}
|j|j}|st dt  d| d"|j d|j d	 qt dt  d#|j d$|
j d%|
j d&|
j d'|
j d(|j d|j d |jd)kr|j|
 q|j|
 qtjj D ]}|j d*kr8||j!|j"< q8|t#_$t dt  d+t%| d,t%| d- dS ).u   
        TODO: что делаем, если загрузка acl падает??? Всё разрешаем или всё запрещаем?
        zload_acl_data(pid z): startr3   r5   r4   deny	denyWriter   r   r   fields)r   r   r   r   r   z): add acl(z, )ORr;   NFr:   r<   r   r   r   r   r?   rG   z): skip z due to empty subjects(z) or invalid access_level(c                 S   s   h | ]}t |jqS r   )sysinternr   ).0subjectr   r   r   	<setcomp>j   s     z.CmfAccessList.load_acl_data.<locals>.<setcomp>c                 S   s   h | ]}t |qS r   )rK   rL   )rM   Z
field_namer   r   r   rO   l   s     )r   r   r   r   z due to absent access_list(z): add rule(type=z, subjects=, model=z	, fields=z, level=z, acl=(r=   Zstaticz
): loaded z acl, z rules)&printosgetpidr$   slistr   r   r   r   r   r   r%   r,   r@   r   r   r   r&   updater
   r   rK   rL   getr:   r<   r   appendr   r+   r-   iter_subclassesZacl_typer'   
class_namer7   r9   len)clsacl_dataZvalid_access_levelsZaccess_listsZaccess_listZaccess_list_dataZaccess_rulesZaccess_ruleZsubjects_dataZobject_fields_dataZaccess_rule_datamodelr   r   r   load_acl_dataK   sn       $
$  
$FzCmfAccessList.load_acl_datac                 C   s   | j }|o|jS )u   Набор полей, по которым существуют правила, чтобы не проверять всё подряд.)r9   r&   )r[   r\   r   r   r   r&      s    zCmfAccessList.used_fields)
initial_acl_keyr   object_fieldr   r   	object_idobject_instanceobject_dictobject_parent_idis_newc                    s    
fdd}	f
dd}dt krDt t _t j}d|krhdD ]}||d qV|d  d	7  < d
}}|r|dg |jj|jtj	j
|dd|t jkrtj }|jj n>t jot jjjt jt jt jst jr|d  d	7  < t}|d
kr|	rrt|	dkr|sdt krzdd tjjddgdddgddgggdD t _|	t jkrt}|d
kr>| j  std j
r>totot
ot
otf} j |}|d
k	r(|d  d	7  < n|d  d	7  < | }|d
krlrlkrl|d  d	7  < t}|d
krz j!krd
tot
ot
otf} j |}|d
k	r|d  d	7  < n|d   d	7  < | }| j |< t" j | j#krzt$ j t" j t$|  }t%d!t" j  d"|d#  d$ d%d& t&' j ( | j#d' D  _ |r||krd(}|s|rt%d)t j d*| d+ d,| d- d.
 d/ d0| d1 d2otj) d3 t*
||S )4u  
        Проверка/получение прав доступа к объекту или его полю.
        Возвращает список доступных прав.
        Если raise_error == True, то генерирует стандартную ошибку о недостаточности прав доступа.
        Если текущий пользователь админ, или владелец объекта, или проверка прав отключена, то выдаём полные права.

        :param object_parent_id:
        TODO: object_instance может быть без филдов при sget и is_web_public
        :param object_instance:
        :param is_new:
        :param object_id:
        :param object_dict:
        :param initial_acl_key: id/code - списка доступа, по которому начинанать поиск.
        :param object_model: имя модели объекта, если пременимо
        :param object_field: поле объекта, если применимо
        :param access_level: если указан, то проверяется наличие конкретного уровня доступа.
        :param object_owner_id: владелец объекта, параметр для удобства,
            если указан и совпадает с текущим пользователем, то получаем полные права.
        :param raise_error: определяет: return False или raise CmfPermissionError
        :param checking_person - если указан, проверяются его права, а не сессионный g.current_person
        :return: Set[str]/False/raise CmfPermissionError
        c                     s  fdd  fddfddt  t  g z	rV	 d r
rtt} | j}|dkrn:|d	kr d
 tn$|dkrtntd d| d
rֈ d  d  d
 W n tk
r   Y nX t}t||}|S )Nc                    s   |  kr |  d S N)add)Zaccess_level_)deniedgrantedr   r   	add_grant   s    zBCmfAccessList.check_access.<locals>.calc_access.<locals>.add_grantc                    s   | j r| j kr| jr | jkr| j@ r| jdkrR d  d  d tn^| jdkrbtnN| jdkrd d n.| jdkr d  d n| jdkr d d S )Nr3   r4   r5   rD   rE   )r   r   r   r   r6   rg   )rule)rj   rh   r`   r   r   r   r   
check_rule   s2    






zCCmfAccessList.check_access.<locals>.calc_access.<locals>.check_rulec                    s    j | }|s<td|  d dt   td|  |jkrjtd|j d  td|  |j t	|j
|jD ]}| q|jr|jS d S )Nz.   !!!    CmfAccessList.check_access: acl_key z not found, processed z, pid=u   Не загружен ACL z0   !!!    CmfAccessList.check_access: recursion z in u+   !!! Кольцевые ссылки у ACL )r%   rV   rQ   rR   rS   CmfErrorr   rW   	itertoolschainr   r   r   )Zacl_keyr%   rk   )r\   	check_aclrl   processed_aclsr   r   rp      s    

zBCmfAccessList.check_access.<locals>.calc_access.<locals>.check_aclglobalr1   r2   r5   rD   zInvalid model acl policy z.acl_default_user_policy(z!), valid: default, readonly, denyr3   r4   )	r*   getattrr,   Zacl_default_user_policyr6   rm   tupler.   
setdefault)Z	model_clsZmodel_policyZgranted_tuple)r\   current_person__member_ofr_   is_local_userr`   r   )rj   rp   rl   rh   ri   rq   r   r   calc_access   sB    
z/CmfAccessList.check_access.<locals>.calc_accessc                     s   d} r	j rd} nkr2	jr2	jkr2d} nr krP	jrP	jkrPd} nTrj	jrj	jkrjd} n:r	tjkrrddrrrjsnjjsd} t	| rdddhndh}t
||S )NFT
user_localr3   r4   r5   )Zacl_allow_createZacl_static_owner_write_fieldsZacl_static_self_write_fieldsZacl_static_user_write_fieldsr,   	CmfPersonrV   ry   oldrt   r.   ru   )Zallow_writeZresult_)
rv   current_person_idrw   re   rc   r`   ra   rb   r   static_acl_modelr   r   calc_static  sF    


z/CmfAccessList.check_access.<locals>.calc_staticprofiler_data	acl_check)r   acl_check_skipacl_check_owner_skipacl_check_cacheacl_check_calcacl_check_cache_staticacl_check_calc_staticr      Nry   Tid_onlyr   
CmfProjectacl_owned_projectsc                 S   s   h | ]
}|j qS r   )r   )rM   Zprojectr   r   r   rO   \  s   z-CmfAccessList.check_access.<locals>.<setcomp>--r   rI   cmf_owner_idr;   Zcmf_owner_assistantsINrG   r?   u8   Система ACL не инициализированаr   r   r   r   r   z!CmfAccessList: shrink cache, len z, size i   z Kbc                 S   s   i | ]\}}||qS r   r   )rM   kvr   r   r   
<dictcomp>  s      z.CmfAccessList.check_access.<locals>.<dictcomp>   Fz   !!!   ACL access denied for z(or z)(z), request z	, to acl=rP   z, field=z
(requsted z), object_owner_id=(rH   )+gr   r   ru   Zload_fieldsr   valuery   r,   r7   subject_full_group_listZsharelink_anonymous_userCmfPersonGroupsharelink_grouprg   current_personrw   rv   disable_permissionsacl_admin_mode_full_accesscmfutilZget_class_name_by_idr   rT   r   r9   ZCmfACLNotInitializedErrorr'   rV   rK   rL   r(   r&   rZ   _CACHE_MAX_SIZE	getsizeofrQ   rn   isliceitemsrz   CmfPermissionError)r[   r_   r   r`   r   r   ra   rb   rc   rd   re   raise_errorZchecking_personrx   r~   statZstat_keyresultZrequested_object_fieldr   Z	cache_keyZ
cache_sizer   )r\   rv   r|   r_   rw   re   rc   r`   ra   rb   r   r   r}   r   check_access   s    %`




	





 $PzCmfAccessList.check_accessFc                    sz   |s| r| j j}tjjj}dd|gdd|gg}dd tjj|dgdD }|t	| |rb|S  fd	d|D }|S )
NZchild_idr;   Zparent_modelr   c                 S   s   h | ]}|j rt|j qS r   )r:   rK   rL   )rM   Zrelationr   r   r   rO     s   z8CmfAccessList.subject_full_group_list.<locals>.<setcomp>r:   rJ   c                    s"   h | ]}t j| d  rqS )rF   )r   Zget_obj_by_id)rM   Zgroup_idrG   objr   r   rO     s      )
r   r   r,   r@   r   ZRelationCacherT   rg   rK   rL   )rN   
subject_idr   rG   _kwargsZgroup_model_namesZrelation_filterr   r   r   r   r     s    
z%CmfAccessList.subject_full_group_listc           	      K   s\   | j ||dd}tjjdgddt|gd}|s4g }|dddd	 |D gg}| j|||d
S )NT)rN   r   r   r:   r   r   r   r   c                 S   s   g | ]
}|j qS r   )r:   )rM   rk   r   r   r   
<listcomp>  s     z2CmfAccessList.subject_list_acl.<locals>.<listcomp>)rG   r?   order_by)r   r,   r@   rT   r#   )	r[   rN   r   rG   r?   r   r   Z	member_ofZrelated_rulesr   r   r   subject_list_acl  s    zCmfAccessList.subject_list_aclcheck_admin_modec                 C   s    t jst jrdS |rt| d S )NT)r   r   r   r   )messager   r   r   r   r     s    zCmfAccessList.check_admin_modec                   C   s:   t j jtjjjddkr*tjs*t	ddt_
dt_d S )NTr   activate_admin_mode)r,   r   Zadmin_groupr   r   r   Zrg_member_ofZall_parentsZ
is_supportr   r   r   r   r   r   r   r     s    z!CmfAccessList.activate_admin_modec                 C   s   dt _dt _dt _dS )u   Первоначальная инициализация контекста, чтобы работали g.current_person, в т.ч. создание пользователей.TN)r   r   rv   r   r[   r   r   r   init_context  s    zCmfAccessList.init_contextc                 C   s   t tddt_tjr*tjs*dt_t t_n"tjtjkt_t	j
jtjddt_tjrXdt_tjr~tjr~t	j }tj|jj dS )u\   Сейчас уже должны быть рабочие g.current_person и g.system_personr   NTr   )rs   ZAPPr   r   Zsystem_personr   r*   rv   r   r,   r7   r   Zsharelink_access_requestZsharelink_access_grantedr   r   rg   r   r   )r[   r   r   r   r   setup_context  s    

zCmfAccessList.setup_contextCmfAccessList:changed)Zchannelc                  K   s"   dd }t d dat| d S )Nc                	   S   s~   t d td trrt d datj > tj	  t
jjdtt dddrftd	 t  W 5 Q R X nt d
 d S )Nzacl::reload handler spawnedr   zacl::reload handler do reloadFz!CmfAccessList::clear_jscache:lockTi  )ZnxZpxz0acl::reload handler do CMF_CACHE.flush_jscache()zacl::reload handler skip)rQ   timesleep_acl_changedr+   ZappZcmf_contextr,   r7   r^   ZREDIS_DBZredisr*   r   rR   rS   r   debugZ	CMF_CACHEZflush_jscacher   r   r   r   handler   s    


z,CmfAccessList.on_acl_change.<locals>.handlerzacl::reload spawn handlerT)rQ   r   geventZspawn)r   r   r   r   r   on_acl_change  s    zCmfAccessList.on_acl_changec                 C   s   t d tdd  d S )Nzacl::reload triggerr   )rQ   Zcmf_emit_server_eventr   r   r   r   trigger_reload  s    zCmfAccessList.trigger_reloadc                    s   t   dddg S )Nr   Zpolicyparent)supersave_preload_fieldsrB   	__class__r   r   r     s    z!CmfAccessList.save_preload_fieldsc                    s   |    t jf |S rf   )r   r   save)rB   kwargsr   r   r   r     s    zCmfAccessList.savec                 K   s   g }t jj D ]F}||jdddddddgddd	| jgdd	| jgdd	| jggd
 q|| jddddddgdd	| jgd
 |S )Nr   r   r   nameZperm_effective_acl_idZperm_inherit_acl_idZperm_acl_idrI   r;   r   r   )r+   r,   Z	CmfEntityrX   extendrT   r   )rB   r   r   r]   r   r   r   find_acl_usage   s    




zCmfAccessList.find_acl_usagec              	      sH   |   }|r2td|  dt| d|d d  |   t jf |S )Nu)   Не возможно удалить acl u,   , т.к. на него существует u    ссылок, 
   )r   ZCmfOrmIntegrityErrorrZ   r   r   rA   )rB   r   usager   r   r   rA   /  s     zCmfAccessList.deletec                 C   s   d S rf   r   r   r   r   r   _calc_perm_parent9  s    zCmfAccessList._calc_perm_parentc                 C   s   d S rf   r   r   r   r   r   _calc_perm_has_acl<  s    z CmfAccessList._calc_perm_has_aclc                 C   s   d S rf   r   r   r   r   r   _calc_perm_acl?  s    zCmfAccessList._calc_perm_aclc                 C   s   d S rf   r   r   r   r   r   _calc_perm_effective_aclB  s    z&CmfAccessList._calc_perm_effective_aclc                    s   |st jg}t j|dS )N)spread_models)r,   r@   r   _acl_spread_inheritance)rB   r   r   r   r   r   E  s    z%CmfAccessList._acl_spread_inheritancec                 C   s$   |    | jr d| _| jdd d S )NFTZ	only_data)save_preparer   r   )rB   Z_ruler   r   r   save_rule_hookJ  s    zCmfAccessList.save_rule_hookc                 C   sD   |    | js@tjjdd| gdd|jggds@d| _| jdd d S )Nr   r;   r   z!=r>   Tr   )r   r   r,   r@   rT   r   r   )rB   rk   r   r   r   delete_rule_hookP  s    zCmfAccessList.delete_rule_hookc                 C   s   | j ddrdS dd |jddD }|s.dS tj }|sBtd|r`|jr`tj|_tj|_dS |rp|t	|8 }|j
jtjjkr|r|t	|8 }|jtjkr|r|t	|8 }|sdS | j d| d	| d
 dS )z)deprecated method, due not API integratedF)r   Tc                 S   s   h | ]}|j s|jqS r   )Zno_aclrY   )rM   r"   r   r   r   rO   `  s   z:CmfAccessList.subject_model_check_write.<locals>.<setcomp>)Z
is_changedzAccess Prohibitedztry change fields z on )r   N)r   valuesr   Zpublic_accessr   re   r   Z	cmf_ownerZ
cmf_authorr*   r   r{   r   rv   )r[   rN   Zallow_createZallow_user_fieldsZallow_owner_fieldsZallow_self_fieldsZchanged_fieldsZis_userr   r   r   subject_model_check_writeX  s.    

z'CmfAccessList.subject_model_check_write)NNNNNNNNNNTN)NNFN)NNNNN)r   T)N)FNNN),r   r   r   __doc__Zno_cacher9   r$   r   r   rC   classmethodr^   r&   r   r   r+   r,   r-   r)   r    r   staticmethodr   r   r   r   r   r   Zon_server_eventr   r   r   r   r   rA   r   r   r   r   r   r   r   r   __classcell__r   r   r   r   r7   @   s   

A
            
   	




       r7   )!r!   rn   rK   r   collectionsr   typingr   r   r   r   r   r   r   Zcmf.includeZcmf.appr+   Zcmf.fields.cmf_access_listZ	dataclassr
   r   r$   r   r.   r   Z_policy_prioritiesrt   r   	Exceptionr6   rG   Zcmf_access_listr7   r   r   r   r   <module>   s2     
