U
    .,f\                    @   sH  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 d dlm	Z	 d dl
mZ d dlmZ d dlmZmZmZmZ d dlmZ 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 d dlmZ d dlm Z  d dl!Z"d dl!T d dl#Z"d dl#T d dl$m%Z%m&Z& d dl'm(Z( d dl)Z"d dl'm*Z* G dd de"j+j,Z-G dd de"j+j,Z.dZ/e01dZ2i Z3dd Z4dd Z5G dd de6Z7e8dddZ9G d d de7d!Z:G d"d# d#e:Z;G d$d% d%e:Z<G d&d' d'e<Z=G d(d) d)e<Z>G d*d+ d+e;Z?eG d,d- d-Z@G d.d/ d/ZAejG d0d1 d1ZBejG d2d3 d3eBZCG d4d5 d5ZDdS )6    N)	dataclass)OrderedDictdefaultdict)Mapping)deepcopy)	lru_cache)IterableListDictOptional)
MethodType)	LockError)desc)aliased)translit)*)imutable_deep_copymutable_deep_copy)cmfutil)
cmf_exportc                   @   s   e Zd ZdZdS )CmfOrmFieldsSpecErroruC   Недопустимые правила загрузки полейN__name__
__module____qualname____doc__ r   r   ./cmf/models/base_model.pyr      s   r   c                   @   s   e Zd ZdZdS )CmfOrmNotLoadedErroru"   Объект не загруженNr   r   r   r   r   r   #   s   r   defaultz(?<!^)(?=[A-Z])c                 C   s@   |  D ]2\}}t|tr2t| |i || |< q|| |< q| S )zupdate nested dicts)items
isinstancer   _dict_mergeget)dukvr   r   r   r"   -   s
    

r"   c                 C   s   t d|  S )N_)_camel_to_snake_regexsublower)sr   r   r   camel2snake7   s    r-   c                       sT   e Zd ZdZ fddZdd Zdd Zedd	 Zed
d Z	edd Z
  ZS )BaseModelMetau,   
    Метаданные модели.
    c              	      s  i }t |D ]T}t|tr|j D ]:\}}t|t|g|d |d  d| |jd||< q$qt| D ]\}}	t|	t	ri }
|d |
d< |d d | |
d< |	j|
d< |

|	j t|t|	jg|
||< ||= qnt|	trn|	||< ||= qn||d< t | |||S )u%   преобразуем Field в classr   r   .)r   r   captionr0   fields)reversedr!   r.   r1   r    typetupler0   listZ	FieldDataupdatekwargsbaseCmfTypeMetasuper__new__)clsnamebases	namespacer1   base_cls
field_name	field_clsr&   r'   Znew_type_namespace	__class__r   r   r;   @   s4    




zBaseModelMeta.__new__c                 C   s<   | j D ]&}t|tr|j| }r|  S qt|| d S N)__mro__r!   r.   r1   r#   AttributeError)selfitemr<   fieldr   r   r   __getattr__a   s
    


zBaseModelMeta.__getattr__c                 O   sf  t | j| _| j| _g | _i | _di i| _| jst| t	rd}|D ]$}t
| |sBtd| d| j qBd}|D ]<}t|t  t| }t| |}||kr|| }| ||< qp| j D ]F\}}	| |	_| j d|	j |	_|	j| jd |< |	jr| j|	j qt| D ]X}
|
drq|
| jkr,qt| |
}t|trFqt|rTq|| j|
< qd S )Nr1   )ui_name	ui_modulecode_prefixu   Заполните поле     в классе )rL   rN   r/   r(   )r-   r   	tablename
class_nameprimary_key__dp__ui_metaabstract
issubclass	CmfEntityhasattr
ValueError_unique_fields_cache
setdefaultdictgetattrr1   r    Zinstance_classclass_full_nameappenddir
startswithui_meta_skipr!   propertycallable)r<   argsr7   r1   rJ   Z_unique_field_cachevalueZ_cached_clsrA   rB   r&   r'   r   r   r   __init__h   sF    





zBaseModelMeta.__init__c                 C   sJ   ddl m} | jr| jd nt}| j|}|sF||| d}|| j|< |S )u9   Доступ к датапровайдеру моделиr   )DataProvider)data_sourcemodel)Zcmf.data_providers.baserh   data_sourcesDEFAULT_DATASOURCErS   r#   )r<   rh   ri   Zdp_r   r   r   dp   s    
zBaseModelMeta.dpc                 C   s   | j j| S rE   )rm   data_driverdp_modelr<   r   r   r   ro      s    zBaseModelMeta.dp_modelc                 C   s
   t | jS )u!   метаданные модели)r-   r   rp   r   r   r   	snakename   s    zBaseModelMeta.snakename)r   r   r   r   r;   rK   rg   rc   rm   ro   rq   __classcell__r   r   rC   r   r.   ;   s   !3

r.   BM	BaseModel)Zboundc                   @   s  e Zd ZU dZdZdZdZdZdZdZ	dZ
dZdZdZdZdZdZdZdZdZeed< dZ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< dZdZdZ dZ!dZ"dZ#dZ$dZ%g Z&dZ'e(dddZ)e(dd Z*dddZ+dd Z,dd Z-dd Z.dddZ/dd Z0dd Z1d d! Z2e3d"d# Z4e(d$d% Z5dd&d'Z6dd(d)Z7dd*d+Z8d,d- Z9d.d/ Z:e(eed0d1d2Z;e(dd4d5Z<e(dd6d7Z=e(d8d9 Z>d:d; Z?e(d<d= Z@e(dd>d?ZAdd@dAZBe(ddBdCZCe(deDdDdEdFZEe(eDdDdGdHZFe(deGdDdIdJZHe(eDdKdLdMZIddNdOZJddPdQZKe(eLdRdSeMdDdTdUZNe(eDdDdVdWZOe(ddXdYZPe(ddDeQeR eRdZd[d\ZSe(ddDeQeR eRdZd]d^ZTe(ddd_d`daZUe(eQeR dbdcddZVe(dedf ZWe(dgdh ZXe(dddieQeR eYeR dZdjdkZGe(dddieQeR eYdZdldmZZe(dndo Z[e(ddKdpdqZ\e(drds Z]e(ddDdtduZ^e(ddKdvdwZ_e(dxdy Z`e(ddzd{Zae(deeDed|d}d~Zbe(dd Zce(dddZde(dd ZedddZfdd Zgdd Zhdd Zidd Zjdd Zkdd Zldd ZmdddddZndd Zodd ZpdddZqdd ZrdddddZsdd Ztdd ZuevdddZwdd ZxdddZydddZzdd Z{dddZ|dddddddZ}ddddZ~dd Zdd Zdd ZdddZdddÄZdddńZe(ddddƜddȄZe(ddʄ ZdZe(dd̄ Ze(dd΄ Ze(ddЄ ZddќddӄZe(dddԜddքZdd؄ Zevddڄ Zd dd܄Zddd߄Ze(dddZdd ZdS (  rt   NTFr   r   acl_typeacl_allow_createacl_static_user_write_fieldsacl_static_owner_write_fieldsacl_static_self_write_fields	api_allow)Z$menu_tree_parent_idmenu_tree_ordernomenu_tree_node_is_branchrT   rb   rP   r1   rk   rU   rm   ro   rq   valuesZvalues_dictrR   db_nameis_recursion_savedisable_simpleru   acl_default_user_policyrv   rw   rx   ry   essential_child_modelsdisable_auditrz   csvc                 C   s   | j }tj||||dS )N)rQ   field_namesbqlformat_file)rQ   r   export2file)r<   r   r   r   rQ   r   r   r   r     s    zBaseModel.export2filec                 c   s<   ddl m} t| D ]}t|trt|| r|V  qd S )Nr   models)cmf.includer   varsr|   r!   r3   rV   )r<   r   rj   r   r   r   iter_subclasses	  s    zBaseModel.iter_subclassesc                 C   s   |s| j | }|s|j}| }| |_|| j|< |sttj}t|t	rj|j
sT|jrj| |_| |_nt|tr|j
s|jr||_||_n`t|jtr|j |_|j |_n:t|jttfrt|j|_t|j|_n|j|_|j|_|S rE   )r1   rQ   instance__dict__datetimenowtimezoneutcr!   CmfDateauto_nowauto_now_adddate_value_oldCmfDateTimer   r   __func__r5   r\   copy)rH   rA   rB   emptyrJ   r   r   r   r   
init_field  s0    


zBaseModel.init_fieldc                 C   sl   | j | }r^| jrNt| j|r.t| j|S |jsNt| j d| d| || j||ddS t	|| d S )Nr/   u&    для тонкого объекта.Tr   )
r1   r#   simple_objectrX   r]   virtualZCmfOrmImplicitLazyLoadrQ   r   rG   )rH   rI   rB   r   r   r   rK   .  s    zBaseModel.__getattr__c                 C   sz   | j |}|rh| jr4tjd|  d| d| | j|d }dkrZ| j||dd}|| | nt	
| || d S )NERROR: Object z is readonly, try set =.Tr   )r1   r#   readonlycmf
base_errorCmfOrmReadonlyModifyErrorr   r   setobject__setattr__)rH   r&   r'   rB   rJ   r   r   r   r   9  s    zBaseModel.__setattr__c                 C   s
   d| _ dS )u   
        Помечаем что обьект уже создан в бд
        Эту опцию нельзя использовать в бизнес логике
        TN)_BaseModel__exists_in_dbrH   r   r   r   mark_exists_in_dbD  s    zBaseModel.mark_exists_in_dbc                 K   s   d| _ d| _|| _| jr6d| _ d}|r6tjd| ||   |s|d|   dD ]}||krdqVt	t
dd ||< qV| j D ]\}}| j|||d qd| _d| _| D ]\}}t| || qd S )NTFuh   Нелья передавать поля для инициализации вместе с simple_objectid)
cmf_author	cmf_ownercmf_modified_bycurrent_personr   )is_newr   r   r   r   CmfOrmError	wrap_saver[   gen_idr]   gr1   r    r   
is_changedr~   setattr)rH   r   r   r7   ir&   r'   r   r   r   rg   K  s2      zBaseModel.__init__c                 C   s   | j  }|d= |S )Nsave)r   r   )rH   r$   r   r   r   __getstate__k  s    
zBaseModel.__getstate__c                 C   s   || _ |   d S rE   )r   r   )rH   stater   r   r   __setstate__p  s    zBaseModel.__setstate__c                 C   s
   t | jS rE   )hashr   r   r   r   r   __hash__t  s    zBaseModel.__hash__c                 C   s
   t | jS rE   )r3   rm   r   r   r   r   rm   w  s    zBaseModel.dpc                 C   s6   t |tks|j}n|}|dd }ttjj| S )N:r   )r3   strrf   splitr   r   includer   )r<   r   ZtuuidrQ   r   r   r   get_model_by_id{  s
    zBaseModel.get_model_by_idc                    sF   |dkr fdd j D S |dkr8 fdd j D S t j S dS )uP   
            Ключи инициализированных полей
        Tc                    s&   g | ]}| j kr j | jr|qS r   )r   r   .0r&   r   r   r   
<listcomp>  s     
  z"BaseModel.keys.<locals>.<listcomp>c                    s&   g | ]}| j kr j | jr|qS r   )r   
is_definedr   r   r   r   r     s     
  N)r1   r5   rH   r   r   r   r   r   keys  s
    zBaseModel.keysc                    s    fdd j ||dD S )uo   
            пары ключ:значение для инициализированных полей
        c                    s   g | ]}|t  |fqS r   r]   r   r   r   r   r     s     z#BaseModel.items.<locals>.<listcomp>r   r   r   r   r   r   r   r      s    zBaseModel.itemsc                    s    fdd j ||dD S )ug   
            возвращает списком инициализированные поля
        c                    s   g | ]}t  |qS r   r   r   r   r   r   r     s     z$BaseModel.values.<locals>.<listcomp>r   r   r   r   r   r   r|     s    zBaseModel.valuesc              
   C   s:   zt | |W S  tk
r4 } z
t|W 5 d }~X Y nX d S rE   )r]   rG   KeyError)rH   keyer   r   r   __getitem__  s    zBaseModel.__getitem__c              
   C   s<   zt | ||W S  tk
r6 } z
t|W 5 d }~X Y nX d S rE   )r   rG   r   )rH   r   rf   r   r   r   r   __setitem__  s    zBaseModel.__setitem__ubqlreturnc                 C   s   t || }tj|ddS )NF)Zensure_ascii)UbqlConverterubql2bqljsondumps)r<   r   r   r   r   r   r     s    zBaseModel.ubql2bql   c                 C   s   ddl m} dddg}	|s|r0tj||	dd}nP|rt|rtt|}
|
sV|ddd	 d S t|
}tj|||	dd}n|d
dd	 |s|ddd	 |S )Nr   	cmf_alertui_view_formparentprojectTr1   include_deletedz+DEV: FATAL get_ui_full_path class_name=Noneabortz3DEV: FATAL get_ui_full_path ui_name=None, code=NoneuC   Объект не найден или возможно удален)r   r   r   get_obj_by_idZget_class_name_by_ui_nameget_model_by_nameZget_obj_by_code)r<   r   rL   coderM   	parent_idrupobjr   r1   rQ   rj   r   r   r   _get_ui_full_path_obj  s     


zBaseModel._get_ui_full_path_objc                 C   sr  ddl m} dg}	|s.| j|||||d|d}|jdkrh|jd|dd	s|d
|d|d|dd nLz|jddddgd W n2 tk
r   |d
|d|d|dd Y nX |jrt	|jj
n|j
}
t}|jjr|j}n|}|r|}
d}|dkrd}d|jkr|jn|j }d}|jr6t|jjd}d|
 d|j d| d| d|j d|j | d| }|S )Nr   r   r   r   )r   rL   r   rM   r   r   r   
CmfProjectzPPP-PR-BROWSEF)r   raise_error$   Объект не найден id =  ui_name =  code = Tr   r   r=   r   r   )check_fields z&rup=0-/z/?parent_id=z&vf=z&code=z	&ui_name=#)r   r   r   rQ   check_project_role_access_acl_check_readCmfPermissionErrorr   r   r   rM   is_not_nullr1   r   rL   r+   r=   Ztranslit_striprf   r   r   )r<   r   rL   r   rM   r   r   r   r   r1   Ztmp_ui_moduleZtranslit_nameZtmp_parent_idZrup_txtr   Ztranslit_name_for_urlurlr   r   r   get_ui_full_path  s6    
 $8zBaseModel.get_ui_full_pathc                 O   sT   ddl m} | j||}|jdkr@|dtdtdtdd | j||d	|iS )
Nr   r   )r   CmfDocument	CmfFolderCmfTaskr   r   r   Tr   r   )r   r   r   rQ   r   rL   r   r   )r<   re   r7   r   r   r   r   r   public_get_ui_full_path  s
    
z!BaseModel.public_get_ui_full_pathc                 O   s   d S rE   r   rH   re   r7   r   r   r   public_none  s    zBaseModel.public_nonec                 O   s   d S rE   r   r   r   r   r   public_none_classmethod  s    z!BaseModel.public_none_classmethodc                    s   dd }|s|S t |d ||rbt|ttfrB fdd|D S tt|tjjr|j	f  S n,t|ttfrt|S tt|tj
jr| S |S )u   
        Конвертация в дикты с последующей серилизацией
        :param relation_load_only:
        :param relation_load:
        :param obj:
        :param filter_fields:
        :return:
        c                 S   s`   t | ttfrBt| dkrBtt| d tjjs>t | d t	rBdS tt| tjjrXdS dS d S )Nr   TF)
r!   r5   r4   lenrV   r3   r   r   rt   
CmfRelBaser   r   r   r   is_model_obj  s    0z&BaseModel.asdict.<locals>.is_model_objr1   c                    s   g | ]}|j f  qS r   get_values_dictr   r   paramsr   r   r     s     z$BaseModel.asdict.<locals>.<listcomp>)r\   r!   r5   r4   rV   r3   r   r   rt   r  r1   CmfTypeasdict)rH   r   r1   r  r   r
  r   r    s    

zBaseModel.asdictc                    s   t  }ddd}|  |dkr,|r,| |}| jddD ]\}}t|rP||pR|d |rf||krfq8t|tjjtjj	fr fdd	|j
D }n*t|tjjr|j
r|j
jf  }n|j}|d
krd}|||< q8| j|d< |S )uy   
        Функция превращает instance в dict для дальнейшей серилизации
        r   c              
   S   sj   zdt krt t _W n( tk
r< } z
W Y d S d }~X Y nX dt jkrT| t jd< nt jd  | 7  < d S )Nprofiler_dataZ	obj_count)r   r\   r  	Exception)nr   r   r   r   inc_obj_count.  s    
z0BaseModel.get_values_dict.<locals>.inc_obj_countNTr   full_fields_loadc                    s   g | ]}|j f  qS r   r  )r   r   r
  r   r   r   H  s     z-BaseModel.get_values_dict.<locals>.<listcomp>.rQ   )r   )r   r  r    r\   r#   r!   r   r1   
CmfM2MBaseCmfBackrefBaserf   CmfRelationBaser  r   rQ   )rH   r1   r  rr  rA   Z	field_valZfield_valuer   r
  r   r  '  s.    

 

zBaseModel.get_values_dictc                    s,   | j  } d k	r( fdd}t||}|S )Nc                    s    | j  krdS | jdkrdS dS )NTr   F)visiblerQ   fr  r   r   filter_visible]  s
    

z-BaseModel.meta_fields.<locals>.filter_visible)r1   r|   filter)r<   r  r1   r  r   r  r   meta_fieldsW  s
    

zBaseModel.meta_fieldsr  c              	      s(  t t}t t}g }d|kr d}t t}	|si |	d< |rt| trZi |	d< i |	d< i |	d< t| tri |	d< i |	d< i |	d	< i |	d
< i |	d< i |	d< i |	d< i |	d< i |	d< |dkrd}t| D ]\}
}|
drBd}|t	|
k r|
|d   dkrq|d7 }q|
d|  }||||f< t
|| |||< ||
= qq|
dr`td|
 dq|
dr||
= |
dd }
||
 |rtd|
||q| j D ]r}|jdkr|r|r|jdkr||ji  t|ttfrL| D ]T\}}|jdks|r|j|r|dkr||ji }t|||df  qnt|tr| D ]f\}}|jdksz|r`|j|r`|dkr`||ji }t|||df  t|||df  q`nL| D ]B\}}|jdks|r|j|r|dkr||ji  qҐq|D ]}
|
|kr||
= q|	 D ] \}
}||
i }t|| q>| D ]\}
}| j|
}|rht|trh| }|stg}i }|D ],}t|}|j|||
||d  t|| q|  t|| qh fd!d"  |}|d#kr$tjj d$| d%dd& dS )'u  
        Разворачиваем мета-правила
        - вначале *, **, ***, включая <prefix>*, ... - пока маски только для префиксов
        - затем -field_name
        - затем +fild_name - deprecated
        --Fr   r   
project_idcmf_owner_idr=   r   Zworkflow_idZcache_cluster_idperm_effective_acl_idperm_inherit_acl_idperm_parent_idperm_parent_owner_id%perm_security_level_allowed_ids_cacher   Tr   r   r   N+u   Синтаксис +field u)    устарел, используй fieldr   u=   У "-" не может быть вложенных полейalwayslogic_prefixlazy      )fields_is_lazyrelation_field_nameauto_fieldshack_parent_noalwaysc                    s2   d}|   D ] \}}|d7 }|r| |7 }q|S )Nr   r   )r    )Z_BaseModel__fieldscr&   r'   Z_BaseModel__field_countr   r   Z__field_count  s    z4BaseModel._fields_load_expand.<locals>.__field_count  u_   DEV: WARNING. В запросе используется слишком много полей: u;   . Возможно, где-то используется **)Z
debug_only)!r   intr\   rV   CmfModelrW   r5   r    endswithr  maxra   ZCmfDeprecatedErrorr_   r   r1   r|   	load_moderQ   r[   r  r  r"   r  r#   r  related_modelsr   _fields_load_expandclearr   r   r   )r<   r1   r.  r/  r0  r1  Zfields_prefixesZasterisk_specsZminus_fieldsZplus_fieldsrA   
field_specZcntprefixrJ   Zasterisk_cntZplus_field_specrelated_model_listZfield_spec_newrelated_modelZfield_spec_subZfield_countr   r3  r   r;  g  s    




	$





zBaseModel._fields_load_expandc                 C   sn   t | D ]@\}}|d\}}}||kr||i |i | ||= q| D ]}|rV| | qVdS )u   
        Структурируем плоские имена полей.
        Например: {field.sub_field...: {}} => {field: {sub_field: {...}}}
        r/   N)r5   r    	partitionr[   r6   r|   _fields_split)r<   r1   Zfull_field_namer=  rA   r(   Zsub_field_namer   r   r   rB    s    zBaseModel._fields_splitc           	      C   s   ddl }|  }|rg }ntj}dd |p,|D }| | |sN| j||d |  | }|dkrtd| d|d	d
|   |S )u  
        Преобразуем список правил загрузки полей, во вложенную структуру,
         которая содержит имена полей для каждого уровня.

        fixme Правильно ли?
        Структура будет у всех вложенных объектов одна. Первый объект разворачивает свои мета команды, другие используют.
        Так быстрее, но могут быть проблемы со * в generic полях, т.к. они должны разворачиваться по-разному.

        :param fields_is_lazy: признак, что список ленивых полей
        :param fields: Список правил загрузки полей.
        :type fields: list

        :return: Структура загружаемых полей.
        :rtype: dict
        r   Nc                 S   s   i | ]
}|i qS r   r   )r   Z
field_ruler   r   r   
<dictcomp>(  s      z.BaseModel.full_fields_load.<locals>.<dictcomp>)r.  g?z!!! full_fields_load(z): duration z.3fz too long! Model: )timeconfigZORM_DEFAULT_FIELDSrB  r;  r   debug)	r<   r1   r.  group_byrD  Zstart_tsZdefault_fieldsZtree_fieldsdurationr   r   r   r    s    
zBaseModel.full_fields_loadr  c           
      C   s   g }| j  D ]}|j|kr||  q|rD| |}t|| | D ]X\}}||}|sdqL| j |}|rLt	|t
rL| }|stg}|D ]}	|	| qqLdS )uF   Рекурсивно добавим _id поля, если нужно.N)r1   r|   rQ   extendZget_required_fieldsr  r"   r    r#   rV   r  r:  rW   _enrich_load_plan)
r<   r  required_fieldsrJ   Zrequired_fflrA   r=  Z	field_fflr?  r@  r   r   r   rJ  5  s$    



zBaseModel._enrich_load_planc                 K   s   | j | |f|S rE   )_load_fields_build_load_plan)rH   r1   forcer7   r   r   r   load_fieldsP  s    zBaseModel.load_fieldsc                    s   ddl m} | js&td| j  dS t|}ttdfdd| |rPdS | jsbtd dS t|| j	 j
| jd	||d
}|ftttd fdd  | | | S )u   
        Прогрузим поля по правилам fields
        Вложенные объекты уже могут быть прогруженны, важно догрузить только то, чего не хватает.
        r   r   uB   SKIP!!! попытка _load_fields при not __exists_in_db. id=N)r   fflc                    s   d}|   D ]}||kr| | }|jdkr0d}qt|tr^|jr |j|| rX||= qd}qt|ttfrd}|jD ]} |t|| svd} qqvqt|trt	q|S )u   
            Проверим всё ли загружено рекурсивно. Уберём из ffl, что грузить не требуется.
            Вернём True, если всё загружено
            T.FN)
r   r   r!   r  rf   r  r  r   r  AssertionError)r   rP  ZloadedrA   rJ   Zlist_loadedZrel_instance)	strip_fflr   r   rR  a  s(    


z)BaseModel._load_fields.<locals>.strip_ffluL   fSKIP2!!! попытка _load_fields при not __exists_in_db id={self.id}T)include_deleted_oncer  r   )dst_instancesrc_instancerP  c           	   	      s  t | t |jdd }|t | @ }|r:td| |jddD ]n}|| }| | }|jdkrn|j|_|jdkrt|jttfrt	|j|_n|j|_t|t
rF|  qFt|tr&|jr|r|||i  nH|r|j|jkr |j|j||i d n|r|||i  qFt|t
tfrdd |jD }|jD ]X}|jj|kr |||jj ||i d ||jj= n|jrL|||i  qLqFt|trFtqFdS )	un   Если поле изменилось, то доводим новое значение до кондиции.Tr  ue   DEV: merge_fields поля запросили для загрузки, но не загружены: .)rP  c                 S   s   i | ]}|j j|qS r   )r   rf   )r   Zsrc_ir   r   r   rC    s      z@BaseModel._load_fields.<locals>.merge_fields.<locals>.<dictcomp>N)r   r   printr   rf   r   r!   r5   r\   r   r  apply_changesr  r   rL  r#   r  r   r  rQ  )	rT  rU  rP  Zmissing_fieldsrA   Z	src_fieldZ	dst_fieldZsrc_instancesZdst_i)merge_fieldsr   r   rX    sR    



 

 

z,BaseModel._load_fields.<locals>.merge_fields)r   r   r   rV  r   r   rt   r\   r   rQ   _get)rH   r  r   r7   r   Znew_instancer   )rX  rR  r   rL  T  s2     
    4
zBaseModel._load_fieldsi  )maxsizec                 C   s    |  |pi }| | t|S rE   )r  rJ  r   )r<   r1   r  r   r   r   _build_load_plan_for_tuple  s    
z$BaseModel._build_load_plan_for_tuplec                 C   s   t |}| | |S rE   )r   rJ  r<   r1   r   r   r   _build_load_plan_for_dict  s    
z#BaseModel._build_load_plan_for_dictc                 C   s.   t |tr| |S | tt|p"g S dS )u7   Готовим и возвращаем full_fields_loadN)r!   r\   r]  r[  r4   sortedr\  r   r   r   rM    s    

zBaseModel._build_load_plan)r<   r   c                O   sr   d}|r,|D ]}d|kr|  |rd} q,q|rT| j|d|i|}|rP|d S dS | |}| j|d|i|S )x   
        fields - список мета-правил для указания какие поля грузить
        F__Tr1   r   Nr  )_allowed_field_funcsr5   rM  rY  )r<   r1   re   r7   aggregate_selectrA   resr  r   r   r   r#     s    

zBaseModel.getc                O   sp   |  |}| D ]F}t| |d}|s(qt|ddrt|ddr| j|d|i|  S q| j||dd|S )r_  Nr   Fvirtual_cache_timelifer1   simple)r  mapper)rM  r   r]   r#   rY  )r<   r1   re   r7   r  rA   rJ   r   r   r   sget  s    
zBaseModel.sget)r  rS  c                O   s6  d| j kr$|ds$|s$|dd |rj|D ]<}t| |d}t|ddr,tjsX|jt_q,ttj|jt_q,| jj|d|i|}|s6d|kr6t	|d dkr6|d d	 d
kr6|d d }t
|tr|j}|r6d|kr6| tjkr6ttdr6tjj|dgd}	|	r6dd|	jg|d< | jj|d|i|}|s2d
|kr2|d
}t
|trb|j}|dk	r2d|kr2| tjkrttdrtjj|dgd}	|	r2dd|	jg|d< | jj|d|i|}nd| tjkrnV|s2|dd }
|
 r2t	|
dkr2d
dd|
 g|d< | jj|d|i|}|S )u  
        Прогружаем поля которые не знает как прогрузить драйвер базы
        например м2м поля, виртуальные поля.

        full_fields_load - иерархия полученная из fields

        Т.к. по show definition люди придут за гайдом по использованию filter именно сюда, дублирую доку
        https://bcrm.carbonsoft.ru/project/Document/DOC-000282
        cmf_deletedr   FNrd  r  r  r,  r   r   r-  r   CmfTaskCodeHistorytask_id)r   r1   r   r   LIKEz%-)r1   r#   r[   r]   r   jscache_timeliferd  minrm   r  r!   r  rf   r   r   rX   ri  rg  rj  popr   isdigit)r<   r  rS  re   r7   rA   rJ   instr   Ztask_code_historyZcode_numberr   r   r   rY    sX    
4

zBaseModel._getrp   c                 C   sP   t  }|s|S |D ]8}d|kr|d\}}||kr<g ||< || | q|S )Nr`  )r\   r   r_   )r<   r1   resultrA   funcr   r   r   _parse_aggregate_fieldsU  s    z!BaseModel._parse_aggregate_fieldsc                 C   s,   dddddg}| d\}}||kr(dS dS )	NsumZavgcountrn  r8  r`  TF)r   )r<   rA   Zallowed_funcsrs  r   r   r   ra  b  s
    zBaseModel._allowed_field_funcsc                 C   s   t jjddstjtjkrd S d|kr4|d\}}d }|drTt| |	dd }|sdt| |d }|r|j
std|j d|j dd S )	NFr   r`  r   _idu%   Группировка по полю (u   ) запрещена)r   CmfAccessListcheck_admin_moder   r   system_personr   r7  r]   rstripZTEXKOM_group_by_allowrQ  rQ   r0   )r<   rA   Z	func_namerJ   r   r   r   _check_group_by_aclj  s    
zBaseModel._check_group_by_acl)r1   rG  c                O   s   |}|s0|r0|D ]}d|kr|  |rd} q0q|rd|krF|d |rf|D ]}||krN|| qN|D ]}| | qj| |}|d= n
| |}| j||||d|S )r_  r`  Tr   r   )r  rG  rb  )ra  r_   r~  r  rM  _list)r<   r1   rG  re   r7   rb  rA   r  r   r   r   r5   y  s(    



zBaseModel.listc          	      O   s   |}|s0|r0|D ]}d|kr|  |rd} q0q|rd|krF|d |rf|D ]}||krN|| qN|D ]}| | qj| |}|d= n
| |}| D ]F}t| |d}|sqt|ddrt|ddr| j|d	|i|  S q| j||||d
d|S )r_  r`  Tr   r   Nr   Frd  r1   re  )r  rG  rb  rf  )	ra  r_   r~  r  rM  r   r]   r5   r  )	r<   r1   rG  re   r7   rb  rA   r  rJ   r   r   r   slist  s4    



zBaseModel.slistc                 C   sd   t | dr |ds |dd t | drJ|dsJ|dsJ|dd t | dr`|dd |S )Nrh  r   Fcmf_archivedZinclude_archivedis_dummy)rX   r#   r[   )r<   _kwargsr   r   r   _default_kwargs  s    
zBaseModel._default_kwargsc                O   sp   |  |}|rP|D ]<}t| |d}t|ddrtjs>|jt_qttj|jt_q| jj| f|d|i|}|S )   
        Т.к. по show definition люди придут за гайдом по использованию filter именно сюда, дублирую доку
        https://bcrm.carbonsoft.ru/project/Document/DOC-000282
        Nrd  r  )r  r]   r   rm  rd  rn  rm   r5   )r<   r  re   r7   rA   rJ   Z	inst_listr   r   r   r    s    

zBaseModel._listc                 O   s   t | j||S rE   )boolrv  r<   re   r7   r   r   r   exists  s    zBaseModel.existsc                O   s"   |  ddg}| j|d|i|S )r_  r   r   r  )rM  _count)r<   r1   re   r7   r  r   r   r   rv    s    zBaseModel.countc                O   s*   |  |}| jj| f|d|i|}|S )r  r  )r  rm   rv  )r<   r  re   r7   retr   r   r   r    s    
zBaseModel._countc                 O   s   | j j| jf| S rE   )rm   query_deprecatedro   r  r   r   r   r    s    zBaseModel.query_deprecatedc                 K   s   | j |f|S )u  
        Метод-обёртка field_options_list для вызова с подстрокой поиска, чтобы избежать кеширования на фронте.
        Сейчас фильтрация идёт на фронте, строка поиска не передаётся. Вероятно этот метод никогда не понадобится.
        )field_options_list)r<   r/  searchr7   r   r   r   field_options_search  s    zBaseModel.field_options_search)all_optionsmodels_filtersr  c                 K   sr  | j |}|s(td| d|  | ||	s0g }	g }|r@d|d< t|tj jrV|p^t|dd}|rtdd |D }n| }|
sd	d
g}
tj	d| d d	}|D ]}|pi |j
}|dkr|jpg }|	r||	g}|st|dr|ddddgdddggg}|rt|dk r\ddd| dgddd| dgdd| dgddd| dgg}n&dddd| dgddd| dgg}|j
dkr|dkrd|dddd| dgddddgggg}|j
dkr|rd |ksttd!d" |rd|d d#|gg}|j
d$kr|d%krd|d&dd| dgd'dd| dgd(d| dgd)d| dgd*dd| dgd+dd| dgd,dd| dgd-dd| dgd.dd| dgd/dd| dgd0d| dgd1dd| dgd2d| dgd3d| dgd4d| dgd5dd| dgg}|j
dkrt|dk rxd|dd6d| dgd6dd| dgd7d| dgd7dd| dggg}n,d|dd6dd| dgd7dd| dggg}||g}|jf d8|i|}t|
d	 | d	}t|
d9 |
d	  t| |}||| g}||7 }|d	 |krq||jf ||||d:| t||
d9 |
d	  kr qnqntd;| d|  || |S )<u  
        Метод для получения списка значений для выбора во фронтенде
        :param relation_field_name:
        :param object_id: в некоторых случаях для фильтрации передаётся id объекта - параметра фильтра, но он портит кеш
        :param object_fields: в некоторых случаях для фильтрации передаётся поля объекта - параметры фильтра
        :param all_options: Все возможные значения, используется в т.ч. для фильтрации на фронте.
        :param slice: диапазон значений для пагинации. !! Есть риск зацикливания, если бэк не будет поддерживать.
        :param search: строка поиска для фильтрации значений. no_cache? обсудить.
        :param kwargs:
        :return:
        u   Не нашел поле rO   Tinclude_systemfield_options_list_limitNc                 S   s   g | ]}t t|qS r   )r]   r   )r   
model_namer   r   r   r     s     z0BaseModel.field_options_list.<locals>.<listcomp>r   d   zfield_options_list u0    без slice, показали первые 100
cmf_hiddenORr   Fr,  r=   ILIKE%z% r   r   Zparent_taskANDzparent_task.namer*  INz	task.epicztask.subproject	CmfPersonZrolesc                 S   s
   |  dS )Nzroles.ra   r  r   r   r   <lambda>H      z.BaseModel.field_options_list.<locals>.<lambda>EXISTSZCmfAssetZassetszlocation.nameZ	asset_tagZserial_numberZ	po_numberZinvoice_numberZlease_contractZmaintenance_contractZownership_typeZdevice_typeZ
os_versionZimeiZphone_numberZ	ip_adressZdomain_nameZmarkcodeZinv_noemailloginr  r   )r1   r  sliceorder_byu)   Некорректный тип поля )r1   r#   rY   rV   r   r  r]   r:  r   r   rQ   default_options_filterrX   r  anybuiltinsr  rv  r8  rn  rI  r5   )r<   r/  	object_idobject_fieldsmodels_listr  r1   r  r  r  r  r  Zinclude_hiddenr7   rJ   resultsr  r:  Zprocessed_countmZmodel_filterZsearch_filtermodel_countZmodel_startZmodel_lengthZmodel_slicer   r   r   r    s    



zBaseModel.field_options_listc                 C   sd   |  |d }t||}|D ]B}ttjj|d dd   |d }|| |jdd qd S )Nr   r   r   r   depth)	r#   r]   r   r   r   r   r   r_   r   )r<   leftr/  Z
right_listr   rJ   rI   Zitem_objr   r   r   m2m_add_values  s    

zBaseModel.m2m_add_valuesc           
      C   s   g }|s| j pg }| }|r"|}|r8|r8|s8|dg7 }|D ]v}d}|dr^|dd  }d}t| j|rxt| j|}n$|jD ]}	|	d |kr~|	d } qq~|rt|}||}q<|S )Nr   Fr   r   Tr=   expr)	orderingr   ra   rX   ro   r]   Zcolumn_descriptionsr   r  )
r<   queryr  r  rb  Zorder_fieldsr   Z
order_descZ	order_colZcdr   r   r   order_query  s.    



zBaseModel.order_queryc                 C   s   | j  dt  S )Nr   )rQ   Zuuid1rp   r   r   r   r     s    zBaseModel.gen_idr   c                 C   s`   |dks| j sdS d| _ | jddD ]6}|jsJt|jtrJt|jddrJq$|j|d d q$dS )ub   
            сброс состояния объекта после сохранения
        r   NFTr  r~   r  )r   r|   r   r!   rf   rt   r]   flush)rH   r  r'   r   r   r   r    s     zBaseModel.flushc                    sH    j r
d S  fdd jddD } fdd|D }|rD | d S )Nc                    s    g | ]}t  |jd kr|qS ).)r]   r   r   r   r   r   r     s      z2BaseModel._load_changed_fields.<locals>.<listcomp>Tr   c                    s    g | ]}t t |ts|qS r   )r!   r]   r  r   r   r   r   r     s      )r   r   rO  )rH   r1   r   r   r   _load_changed_fields  s    zBaseModel._load_changed_fieldsc                 K   s   d S rE   r   rH   r  r   r   r   before_save_hook  s    zBaseModel.before_save_hookc                 K   s   d S rE   r   r  r   r   r   before_save_data_hook  s    zBaseModel.before_save_data_hookc                 C   s   g S rE   r   r   r   r   r   save_preload_fields  s    zBaseModel.save_preload_fieldsc                 C   s   |   }|r| | d S rE   )r  rO  )rH   r  r   r   r   save_prepare  s    zBaseModel.save_preparec                 C   s   d S rE   r   r   r   r   r   check_edit_perm  s    zBaseModel.check_edit_permc                 C   s   d S rE   r   r   r   r   r   check_delete_perm  s    zBaseModel.check_delete_perm)	only_dataemitc                O   s  |   D ]}|jdk	rqttj}t|tr>|jr>|	 |_
t|trT|jrT||_
| jrt|trt|jrt|	 |_
t|tr|jr||_
qttdd }|rd| jkr| jjr|j| _| jrd| jkr| jjdkr|j| _| jrd| jkr| jjdkr|j| _| j|d|i|S )N.r   r   r   r   r  )r|   r   r   r   r   r   r!   r   r   r   rf   r   r   r   r]   r   r1   cmf_modified_by_idis_nullr   r   cmf_author_idr   r"  
_save_data)rH   r  r  re   r7   rJ   r   r   r   r   r   _save_import  s.    



zBaseModel._save_importc                    s   ddd fdd
}|S )NF)r  save_importc                    s   j rtjd  dd _ jddD ]D} | jr<q,t | jtj	j
sRq, | j | jkr,d | _q,tjr|d} tjs| s|rddt_t j f|dtji|}| r8dt_|ddrt tr jr   t tr t dr js  jr jd	d
 n   t tr8 jdd |rdt_    jrZd _   nt j f|ddd|    tjdkrt tr js jjr     !   j"f | t j# f|d| i| d _d _ $   S )Nr   z is readonly, try save()Tr  Fr  r  r  insertinitiator_actioncelery)r  Z
invalidate)%r   r   r   r   r~   r   r   rV   rD   r1   CmfJsonr   r   r   Zsave_only_data_hackr3   r  r#   r!   rW   r  r6  rX   r  r   project_notifymark_full_searchr  import_originalr  disable_permissionsr   _calc_projectr  r  r   r  )r  r  re   r7   r&   r  r   r   r   save_with_flush  sV    	
  
 z5BaseModel.save_flush_wrapper.<locals>.save_with_flushr   )rH   r  r  r   r   r   save_flush_wrapper  s    \zBaseModel.save_flush_wrapperc                 C   s   |  | j| _d S rE   )r  r   r   r   r   r   r   |  s    zBaseModel.wrap_savec                 C   s~   | j j|d}| jddD ]^}|jdks|jdr6q|jdrZ|jdsZ|jdksZq|jdrhqt||j|j q|S )	Nr   Tr  )r   r   cmf_created_atr   r   systemZperm_Zperm_policyperm_encryptrx  )rm   rj   r|   rQ   ra   r7  r   rf   )rH   r   rc  rJ   r   r   r   clone  s    

zBaseModel.clonec                 C   s   dS )u4   
        Вычисляем кеш поля
        Nr   r   r   r   r   _update_cache_fields  s    zBaseModel._update_cache_fieldsr  r  c             
      s  d|f fdd	}ddl }|  }  jr8jnd}zbjspd_tjjf|  |||d n,  |||d tjjf|  W n t	k
r }	 z6dd	l
m}
 |
d
| dj ddd t|	 W 5 d}	~	X Y nF tk
r6 }	 z&dd	l
m}
 t|	 |
ddd W 5 d}	~	X Y nX |  | }|dkrtd|ddj dj ddjkozj d	 S )u)  
            Финальное низкоуровневое сохранение в базу
            Умышленно не разделяем save() на update() и create(), т.к.
            обычно в бизнес-логике очень много общего кода.
        Fc                    sN   d}||k rJj ddD ]0}d kr:|j||  d d q|j|| d qd S )Nr   Tr  notify)r  r  r  r  )r|   r   )r  r  Z	max_depthrJ   r7   rH   r   r   check_relations  s    z-BaseModel._save_data.<locals>.check_relationsr   Nu   объектаT)r  r  r   u   Код  uS    уже существует. Укажите уникальное значение.r   uA   Нарушение ограничения целостности.r   z&!!! --- _save_data::duration too long .1f sec, ry  , r   ))rD  _acl_check_writeverbose_namer   r3   rm   creater  r6   ZCmfOrmUniqueErrorr   r   r   logging	exceptionZCmfOrmIntegrityErrorr   rF  rV  rQ   r   r1   )rH   r  r  re   r7   r  rD  startr  r   r   rH  r   r  r   r    s6    

0zBaseModel._save_datac                 O   s<  |   D ]}|jdk	rtjrqttj}t|t	rD|j
rD| |_t|trZ|j
rZ||_| jr|jdk	rlqt|t	r|jr| |_t|tr|jr||_qttdd}|r$d| jkrtjrtjr| jjr|j| _| jrd| jkr| jjdkr|j| _| jr$d| jkr$| jjdkr$|j| _| jf | | j||S )uA   
        Супер общая бизнес логика
        .r   Nr   r   r   )r|   r   r   import_moder   r   r   r   r!   r   r   r   rf   r   r   r   r]   r1   r  r  r   r   r  r   r"  r  r  )rH   re   r7   rJ   r   r   r   r   r   r     s4    



"zBaseModel.savec                 C   s   |    | j  | S rE   )r   rm   Zcommitr   r   r   r   _test_save_commit  s    
zBaseModel._test_save_commitc                 K   s   t t}tjjjtjjjtjjjf}t	 D ]}||kr:q,|j
ddddgd| |dD ]X}t|ddr|t|j t|j t|ddrT|t|j t|j qTq,|S )uw   
        Формируем кеш словарь связи объектов по parent_id и tree_parent_id
        r   r   r   tree_parent_idT)r1   TECHCOM_nocacher   r  N)r   r   r   r   r   rz  CmfAccessRule
CmfCommentr6  r   r  r]   sysinternr   addr   r  )r   r  r7   rr  skip_modelsrj   obj_datar   r   r   _build_relation_cache  s"     
"zBaseModel._build_relation_cachec                 K   s   t  }tjj| jkr|  d}|j| jkr6d|d< zLz(t
d|  |jf ddi| W n tk
r~   t } Y nX W 5 tjj| jkr|j	|  X d S )NNNNTskip_owner_checku-   Удаляем дочерний обьект rN  )r   disable_aclr   r   r   r"  	__enter__rQ   r   __exit__rF  deleter  r  exc_inforH   r   r7   r  r  r   r   r   _delete_child_object  s    zBaseModel._delete_child_objectc                 K   s
  |p|}|p|}| j f |||d|}t }| jjh}|rt }|D ]8}	|	|krF||	 D ]"}
|
|krhqZ||
 ||
 qZqF|}q8tjjjj	dgdd|gddddD ]}| j
|f|||d| q|D ]8}
tjjj|
dg|d }r| j
|f|||d| qd S )Nr   TEXKOM_db_deleter  r   r   r  Tr1   r  r  r  r   r   )r  r   r   rf   r  r   r   r   r  r5   r  r   r   )rH   r  r   r  r7   relation_cachechildren_id_setlevel
next_levelr   child_idcommentchildr   r   r   %_depricated_children_recursion_delete"  s4    


   
z/BaseModel._depricated_children_recursion_deletec              
      s    p pddfdddd fddd
t t d fdd	jjf jjg}| d S )Nr   )id_listc                    s   t  }tjjjtjjjtjjjf}t D ]}g }||kr<q*t	|drV|
dd| g t	|dr|rp|dd |
dd| g |sq*|jddddgd |d	D ]@}t|dd r|t|j t|dd r|t|j qq*|S )
Nr   r  r  r   r  r   r   T)r1   r  r   r  r  )r   r   r   r   rz  r  r  r6  r   rX   r_   r  r  r]   r  r  r  r   )r	  new_id_listr  rj   _filterr  r   r  r   r   list_children_idsE  s6    

  
z?BaseModel._children_recursion_delete.<locals>.list_children_idsc                    sF   t jjjjdgdd| gddddD ]}j|f d q"d S )Nr   r   r  Tr   r  )r   r   r   r  r5   r  )r	  r  )r  r   r  r7   rH   r   r   delete_commentsb  s     

z=BaseModel._children_recursion_delete.<locals>.delete_comments)r	  id_setc                    s   |d krt  }| }|r:tdt| d || |  | D ]@}||krFtjjj|dgd }rFj|f d qF|	|  d S )Nu   Удаляем u    обьектовr   r   r  )
r   r   rF  r  r   r   r   r   r  union)r	  r  r
  r  r  r  r  r   r  r7   level_deleter  rH   r   r   r  s  s    
z:BaseModel._children_recursion_delete.<locals>.level_delete)N)r   r   rf   )rH   r  r   r  r7   Zchildren_idsr   r  r   _children_recursion_deleteA  s    $z$BaseModel._children_recursion_deletec                 K   sN   | j D ]B}t|}|jdgdd| gddD ]}| j|fddi| q,qd S )Nr   r   r   T)r1   r  r  r  )r   r   r   r5   r  rH   r7   Zessential_child_model_nameZessential_child_modelr  r   r   r   _essential_children_delete  s    

z$BaseModel._essential_children_deletec                 K   s   |ri S g S )u(   Получим всех потомковr   )rH   group_by_modelsr  r   r   r   list_children  s    zBaseModel.list_children)	recursiverN  r  r  c                O   sZ  | j dgd | jdkrz|s |rJ|ddo.||d< | jf d|i| n0|sr| jdd }rrtd	|  d
|n|   t| tr| j	r|sd| _
|dd | j||S |   g }| jD ]"}	t| j|	 tjjr||	 q|r$| j |dd |D ](}	t| |	rt| |	g  t| |	  qtj| jjd t| jj| f||}
|   |
S )Nr   r  r  	CmfNotifyCmfAttachmentr  Fr  T)	skip_subsu   Нельзя удалить u1   , на него ссылаются потомкиr  )r   r   )rO  rQ   r#   r  r  ZCmfOrmHasReferenceErrorr  r!   r6  logical_deleterh  r[   r   r  r1   rV   r   r  r_   r]   r   r   CmfFullSearchZ_text_search_sql_delete_partnor   rf   r3   rm   r  r  )rH   r  rN  r  r  re   r7   ZchildrenZ
m2m_fieldsrA   rc  r   r   r   r    s6    


zBaseModel.deleter  c                O   sL   d| _ d| _|dd | j||}| jdkrH|r@| jf | n|   |S )uy   
        Восстановление из корзины логически удаленного объекта
        Fr  Tr  )rh  tree_node_is_branchr[   r   rQ   _children_recursion_restore_essential_children_restore)rH   r  re   r7   rc  r   r   r   restore  s    
zBaseModel.restorec                 C   s   d S rE   r   r   r   r   r   tree_child_restore_hook  s    z!BaseModel.tree_child_restore_hookc                 K   sH   | j D ]<}t|}|jdgdd| gdddD ]}| j|f| q.qdS )u   
        Восстановление дочерних объектов которые являются неотьемлемой частью объекта
        Вложения, комментарии и т.д.
        r   r   r   Tr1   r  r  r   N)r   r   r   r5   _restore_child_objectr  r   r   r   r"    s    


z%BaseModel._essential_children_restorec                 K   sv   t  }tjj| jkr|  d}z4z|jf | W n t	k
rR   t
 } Y nX W 5 tjj| jkrp|j|  X dS )uP   
        Восстановление дочернего объекта
        r  N)r   r  r   r   r   r"  r  r  r#  r  r  r  r  r   r   r   r&    s    zBaseModel._restore_child_objectc                 K   s   | j d|d}t }| jjh}|rlt }|D ]8}||kr,|| D ]"}||krNq@|| || q@q,|}qtjjjj	ddgddd|gdd| ggddd	D ]}	| j
|	f| q|D ],}tjjj|dgdd
 }
r| j
|
f| qdS )ul   
        Рекурсивно восстанавливаем все дочерние объекты
        Tr  r   r   r  r   r  r   r%  r   N)r  r   r   rf   r  r   r   r   r  r5   r&  r   r   )rH   r  r7   r  r  r  r  r   r  r  r  r   r   r   r!    s.    


 
z%BaseModel._children_recursion_restorec                 C   sh  t jr
d S | jdkrd S | jdkrTt jt jkrTtjjd| j| dd t	d| j
 t| tod| jj}t| tov| jj}| jrt| to| jr| jjn| jj}nt| to| jj}| j}| jdkr0t jt jkrd S ztjjd| j
 d W n< t	k
r* } ztjjd|| dd |W 5 d }~X Y nX d S | jd	kr"d
}| jddD ]*\}}	|	jdkrL|dkrLd} qxqLd}
tt| drt| jr| jddD ]*\}}	|	jrq|t| jkrd
}
q|sd S t jst jrd S t jt jkr d S tjjdd
drd S tjjdddgdd}| jdkrl| joL|j
jt j k}| j oh|t j!j
koh|
}nB| jo|j
jt j k}| j o|t j!j
ko|j
jt j ko|
}|s|rt| dr| j"rt#| | j"$ %  d S tjjd|| dd | jrt	dnt	d| j
 d| zt| t&jjo:| j'j}t( }|rPt(|}| jddD ]P\}}||krx|)| |jrq\tjj*d||||| j
j|| | j|d
 q\|r|D ]@}| | }|jrАqtjj*d||||| j
j|| | j|d
 qW nf t	k
rb } zF|j+d| j
 f |_+t,-  tjjd| j| dd  W 5 Q R X W 5 d }~X Y nX d S )Nno_aclr  r6   failoperatecmf_model_namer   Zresult_statusuO   Отказано в модификации системного объекта ZadminmessageZproject_adminFTr  r  rx   r   rw  r   ==ZProjectAdmins)r  cache_inmemoryCmfPersonGroupacl_self_parent_link_depricatedu   Отказано в создании объекта. Разрешено только Администраторам системы и членам группы Создатели проектовu:   Отказано в модификации объекта uu   . Разрешено только Администраторам системы и Владельцу объекта write)
access_levelinitial_acl_keyobject_modelobject_owner_idobject_fieldr  object_parent_idobject_instancer   perm_security_level_allowed_ids).r   r  ru   r   r|  r   CmfAuditaudit_eventrQ   r   r   r!   rW   r#  oldr6  r   rv   r   r"  newrz  r{  r    r'  rX   r3   rx   Zacl_admin_moder0  r#   rf   current_person__member_ofcurrent_userr1  r]   loadr  r   r'  r   removecheck_accessre   r   r  )rH   Zforce_check_fieldsr4  obj_parent_idZobj_owner_idrQ   r   
need_checkZchanged_field_nameZchanged_fieldZowner_write_fields_allowZproject_admins_groupZaccept_creationZaccept_editr'  Zforce_check_fields_setrA   rJ   r   r   r   r    s    





      
      
zBaseModel._acl_check_writec           
      C   s   | j dks| j dkrdS t| to(| jj}t| to8| j}t| tjjoN| j	j
}| j}zR| jddD ]@\}}|jrtqdtjjd|||| jj|| | j|d	}d|krdtqdW nR tk
r }	 z4|	jd| j f |	_tjjd| j| d	d
 |	W 5 d}	~	X Y nX dS )u   
        check_fields - если контретные филды проверить, передать явно список
        Дефолт - загруженные (is_defined) поля
        r'  Zpublic_readNTr  read)	r3  r4  r5  r7  r  r8  r9  r   r:  u0   Отказано в чтении объекта r(  r)  )ru   r!   rW   r#  rf   r6  r   r   r   r'  r=  rQ   r    r'  rz  rC  r   r   r   re   r;  r<  )
rH   r   r4  rD  r'  rQ   rA   rJ   rulesr   r   r   r   r     s6        
zBaseModel._acl_check_read)r1   save_kwargsr  c                O   sF   | ||}|si }| d||d< |jf | |rB| j |j|dS |S )Nr  r  )r#   r   r   )r<   r1   rH  r  re   r7   r   r   r   r   r    s    
zBaseModel.createc                 C   s   | j S rE   )rT   rp   r   r   r   get_meta  s    zBaseModel.get_metac                 O   sl   | j d krfg }|  D ]H}|jr"qdd |jd  D }|sD|jr||j|j|j|d q|| _ | j S )Nc                 S   s    i | ]\}}| d r||qS cf_r  )r   rA   Z
field_metar   r   r   rC    s   
 z-BaseModel.all_models_meta.<locals>.<dictcomp>r1   )rQ   ui_group_fieldsui_formr1   )	_all_models_metar   rU   rT   r    rM  r_   rQ   rL  )r<   _argsr  rr  ZmodelClsZcustom_fields_metar   r   r   all_models_meta  s"    


zBaseModel.all_models_metac                 O   sJ   t | dr |ds |dd t | dr6|dd | jj| f||S Nrh  r   Fr  )rX   r#   r[   rm   bulk_deleter  r   r   r   rR    s
    
zBaseModel.bulk_deletec                 O   sJ   t | dr |ds |dd t | dr6|dd | jj| f||S rQ  )rX   r#   r[   rm   bulk_updater  r   r   r   rS    s
    
zBaseModel.bulk_update)rH  c                O   s   | j s(t| j t| dr(t| j |   | j D ]}||krHq:t	| |}t
|tjjtjjfrjq:t
|tr|js|jdkr|d d |kr:t| |d d ||  q:t| |||  q:|si }| jf |S )Nr   r   )TEXKOM_no_cacher   Zcache_obj_lock_getr   rX   r   r  r1   r   r]   r!   r   Z
CmfBackrefCmfGenericBackrefCmfTUUIDZforeign_keyrQ   r   r   )rH   rH  rO  r7   rA   	field_objr   r   r   r6     s&    

zBaseModel.update)r  rH  c                   s   i  fdd   j f ddd}|s@ g}t|dkrhtjjd| d dd	 |d
 jf d|i| |d
 S )u  
        update or insert: Создаём новый объект или изменяем уже существубщий.
        fixme т.к. фильтр работает по _id, а присваивание по релейшен, то используем filter только для поиска,
          а в kwargs нужно дублировать поля ключа. Пример: upsert(filter=[person_id, =, '...'], person={id: '...'}, ...)
        :param filter: фильтр по ключевому значению, используется для поиска объекта.
         Только простой фильтр на равенство: [field, ==, value] или [[field1, ==, value1], [field2, ==, value2]]
        :param save_kwargs: параметры вызова .save
        :param kwargs: поля которые нужно изменить: {field: value, ...}
        :return:
        c                    s   | rt | d tr&| D ]} | qqt| dks>| d dkrZtjjd|  d dd | d jkrtjjd	| d  d d
dd | d | d < ntjjd|  d dd dS )u   Соберём в key_values значения полей из фильтра, и проверим, что фильтр простой.r   r,  r   )r   r.  ud   Фильтр для upsert должен быть простой: [field, =, value], передан: r  Tr   u8   В фильтре upsert неизвестно поле: u6   , допустимый фильтр: [field, =, value]r-  u2   Указан пустой фильтр в upsert: N)r!   r5   r  r   r   r   r1   )Z
sub_filterZsub_sub_filtercheck_simple_filterr<   r  Z
key_valuesr   r   rZ  (	  s     z-BaseModel.upsert.<locals>.check_simple_filterT)r   r-  )
for_updater  r   u9   Ключ в фильтре upsert не уникален: r  r   r   rH  )r5   r  r   r   r   r6   )r<   r  rH  rO  r7   Zobj_listr   rY  r   upsert	  s    zBaseModel.upsertc                 C   s^   t | dr8t | dr8t| j d| jj d| jj dS t| j d| jrR| jjn| j dS )Nr=   r   ry  : r  )rX   r3   r   r   r   r=   r   r   r   r   r   r   __repr__F	  s    $zBaseModel.__repr__c                 C   sd   t | trdd | D S t | tr`d| kr`| d }t|}dd |  D }|f |ddiS | S )Nc                 S   s   g | ]}t |qS r   rt   	from_jsonr	  r   r   r   r   O	  s     z'BaseModel.from_json.<locals>.<listcomp>r   c                 S   s   i | ]\}}|t |qS r   r_  )r   r&   r'   r   r   r   rC  T	  s      z'BaseModel.from_json.<locals>.<dictcomp>r   T)r!   r5   r\   rW  Zget_cls_by_tuuid_strr    )r   rx  r<   r1   r   r   r   r`  L	  s    

zBaseModel.from_jsonc                 C   s:   |sg }i }| j ddD ]\}}||kr*q|j||< q|S )NTr  )r    r   )rH   r1   r  Z	fieldnamerJ   r   r   r   to_jsonY	  s    zBaseModel.to_jsonr   c                 C   s.   |dkrt | S |dkr$t | S t d S )Nr\   r   )r   Z
dumps_dictZ
dumps_jsonNotImplemented)rH   r3   r   r   r   r   g	  s
    

zBaseModel.dumpsc           
      C   s  t  }|r| j|kr|S |r4t f | jt i|}nt || j< | dg}| jj|dD ]T}| || | }| j D ]\}}t	|t
tfr||kr||= ||rt	|ttfr|r|j|krq~|j|krq~|j| jkrq~tt|j }||}q~||r~t	|ttfr~|js6td| d q~|jD ]`}	|rT|	|krTq<|	|krbq<|	| jkrrq<|	ttkrq<tt|	 }||}q<q~|| j | qZ|S )uT  
        Дампим все обьекты класса и ссылки в dict для последующей серилизации
        :param upper_res: предыдущий дамп для исключения повторений и правильной последовательности
        :return: словарь
        r   r  u   WARNING: поле u    без models)r   r   r5   r  rm   Z_load_extra_fieldsr  r1   r    rV   r  r  r#   CmfRelationZCmfM2Mrj   r   r   dump_data_dictCmfGenericRelationCmfGenericM2MrV  r_   )
r<   Z	upper_resrc  r  rI   Z	item_dictrA   rB   Zfk_modelr  r   r   r   rd  n	  sT    


zBaseModel.dump_data_dictc                 C   s<   t |tr| j|jkS t |tr8|jjr,dS | j|jkS dS )NF)r!   rt   r   r  r  )rH   otherr   r   r   __eq__	  s    

zBaseModel.__eq__)NNr   )NNF)FN)NN)NN)NN)NNNNNr   N)NNNNNr   N)N)NN)N)NNTF)NNN)NF)F)N)N)NNNNNFNNNNF)NNN)r   )N)FN)FFF)FFF)T)F)N)N)N)r   )N)r   r   r   rk   rU   Zfields_orderr  r  Zverbose_name_pluralr   rL  rM  rU  r  r   customsmart_notifyr/  r   ru   r   __annotations__r   rv   r  rw   r   rx   ry   rz   enable_edit_permenable_delete_permrP   r1   rR   r~   r   iconZcache_cluster_fieldsrb   classmethodr   r   r   rK   r   r   rg   r   r   r   rc   rm   r   r   r    r|   r   r   r   r   r   r   r   r  r  r  r  r\   r;  rB  r5   r  rJ  rO  rL  r   r4   r[  r]  rM  Typers   r#   rg  rY  rt  ra  r~  r	   r  r  r  r  rv  r  r  r  r  r  r  r   r  r  r  r  r  r  r  r  r  r  r   r  r  r  r   r  staticmethodr  r  r  r  r  r  r  r#  r$  r"  r&  r!  r  r   r  rI  rN  rP  rR  rS  r6   r\  r^  r`  ra  r   rd  rh  r   r   r   r   rt      s  




 




*

"
0 $

 @

"&
	
	
                       

$


_
:!

J	
*
!
 
-




+
<)	metaclassc                       s  e Zd ZdZdZdZeedddddddZee	ddddd	gd
Z
ee	ddddd	gdZejjejjdddddZee	ddddd	gdddZee	dddd	gdddZeeddddddZeeddddddddZeeddddddddd	ZeeddddddddZeedddddddZeedddddd d!Zeed"d#d$ZdCd&d'Ze dDd(d)Z!e  fd*d+Z"e dE fd,d-	Z#d.d/ Z$dFd1d2Z% fd3d4Z&d5d6 Z'd7d8 Z( fd9d:Z)dGd;d<Z*d=d> Z+dHd?d@Z,dAdB Z-  Z.S )Ir6  us   Базовый класс, содержит стандартные поля для типовых объектов.T)r  )   Идентификатор объекта3   Автоматически генерируетсяFr0   r  nullablerR   r   r  u
   Авторr  )r0   r  linkabler   r   u   Владелец)r0   r  r   rw  r   u   РодительrW   )r0   
base_modelrw  r  u'   Последний изменивший)r0   r  r   rw  r   autor'  u$   DEPRICATED. Кто захватил r+  )r0   r  r   r   r9  r'  u#   DEPRICATED. Дата захвата)r0   r  r   indexr'  u   Дата создания)r0   ry  r   r  r   rz  rv  u   Дата изменения)r0   ry  r   r  r   rz  rv  r'  u   Дата просмотра)ry  r0   r   r  r   rz  r'  u   Удален)r0   r  r   r   rv  rz  u   Номер версииZ
CmfVersion)r0   r  r   rz  r'  widgetr   c                 C   s
   t | jS rE   )r3   r}   r   r   r   r   r}   2
  s    zCmfModel.db_nameNc           	      K   s   ddddg}|r8dD ]"}|D ]}| | d|  qq| j|d t }| jrp|d ksd| jj|krp|| j t| dg D ] }|d ks|j|kr||| q|t|S )Nr   cmf_owner_assistantszcmf_owner.user_localzcmf_owner_assistants.user_local)r   r}  r/   r  )r_   rO  r   r   
user_localr  r]   r5   )	rH   r1   r~  r7   Zself_fieldsZperson_field_namer  rr  ownerr   r   r   all_relation_persons6
  s    zCmfModel.all_relation_personsc                 C   s   g }g }|r(|D ]}| | j|  qn>| j D ]2}|jdkrBq2|jdkrZ|jdrZq2| | q2|D ]2}| |j|j|j|jo|j| j	| j
|jd qj|S )N)r   r   rh  cmf_versionr  
cmf_importr  import_raw_jsonext_idrx  )r0   rA   Zfield_qualnamerequiredr  rn  r{  )r_   r1   r|   rQ   r7  r0   r   rv  r  r  rn  r{  )r<   Zfields_namerr  r1   rA   rJ   r   r   r   import_shop_fieldsF
  s(    
 
  
zCmfModel.import_shop_fieldsc                    s   t |  D ]b\}}|drt| |dd r|rd|krttjj|dd  j	|d||dd < qt
 j||S )Nrx  r   z:Classr   r   )r\   r    r7  rX   r   r   r   r   r   r#   r:   r  )r<   re   r7   r&   r'   rC   r   r   r  [
  s    
zCmfModel.createc                    s   |dkr|sg }|dkrx| dd rx|d  dd dkrx| dd rxd|krTi |d< dg i|d< t j|fd	|i|S |d
ddgg}t j|fd	|i|S )N)r   r   r}  r   r  Zparent_logic_prefixzproject.servicedeskr  r  r  r  r~  r.  T)r#   r:   r  )r<   r/  r  r7   rC   r   r   r  h
  s    
zCmfModel.field_options_listc                 C   s6   | j js| jsd S tttjdd d | _ d S )Nz%Y%m%d%H%M%S%frT  )r  r   r5  r   r   r   r   strftimer   r   r   r   _increment_version}
  s    zCmfModel._increment_versionr6   c                 C   s   d S rE   r   )rH   r  r   r   r   r  
  s    zCmfModel.project_notifyc                    s2   |    | jr| jdd n|   t j||S )Nr  r  )r  r   r  r:   r   r   rC   r   r   r   
  s
    zCmfModel.savec                 C   s   |  ddg tjg}| j}| jjr>| jj}|r>| ddg |sF|S |jjr^||jj n||j t|dr|j	jr|j	jD ]}|| qn|j	D ]}|| q|S )Nparent.cmf_owner_assistantsparent.cmf_ownerr}  r   )
rO  r   r|  r   r   r=  r   r_   rX   r}  )rH   rr  perm_parentr  r   r   r   get_parent_owners
  s&    

zCmfModel.get_parent_ownersc                 O   s   |  ddddg tjg}| jjr2|| jj n|| j t| dr| jjrj| jjD ]}|| qXn| jD ]}|| qp| j	r|
|   dd |D S )u   
        Все владельцы обьекта
        fixme метод используется для проверки прав доступа, но не для всех владельцев сейчас реализован доступ.
        r   r}  r  r  c                 S   s   g | ]}|r|qS r   r   )r   r  r   r   r   r   
  s      z'CmfModel.get_owners.<locals>.<listcomp>)rO  r   r|  r   r   r_   r=  rX   r}  r   rI  r  )rH   re   r7   Zownersr  r   r   r   
get_owners
  s"     

zCmfModel.get_ownersc                    s.   | j s | jjr tj|  kr d S t jf |S rE   )r   r   r   r   r   r  r:   r  rH   r7   rC   r   r   r  
  s    zCmfModel._acl_check_writec                 C   sV  | j s
d S tjrd S | js| jr$d S d}| jddD ].}|j|  kr4|jds4|j	ds4d}q4|r| 
 }tj|krttjtdd |D @ sd|  d	d
dd t|D  d}tjj|d d S | jr| jjd| d d S |s@t }| jddD ]>}|j|  kr |jds |j	ds ||j q d|krd| jjd| d |d d|ksxd|kr| jjr| jjr| jj| jjkr| jjd| d | jjs| jjr| jr| jjd| dd d|kr|d d|kr|d d|kr|d d|kr<| jjd| d |d |rR| jjd| d d S )NFTr  cache_rx  c                 S   s   g | ]
}|j qS r   r  r   or   r   r   r   
  s     z,CmfModel.check_edit_perm.<locals>.<listcomp>u   Это действие над v    разрешено только владельцам объекта и владельцам его родителя: r  c                 S   s   g | ]}|j jqS r   r=   rf   r  r   r   r   r   
  s     4    или Администратору системы.r,  zPPP-OBJ-CREATEr  ordernozPPP-OBJ-TREE-ORDERr   r   zPPP-OBJ-MOVE)r   Zuse_new_projecttree_parentzPPP-OBJ-TREEMOVEzPPP-OBJ-EDIT)rl  r   r  r   r   r|   rQ   project_perm_allow_fieldsra   r7  r  r   r   r?  joinr   rz  r{  r   r  rB  r   r=  r>  r   )rH   Zchanged_fields_to_checkrE  rJ   
all_ownersmsgr   r   r   r  
  sn    


&



&







zCmfModel.check_edit_permc                 C   s   | j s
d S tjrd S t| dr$| js|  }tj|krttjtdd |D @ sd| j	 dd
dd |D  d}tjj|d	 d S | jjd
| d d S )Nr   c                 S   s   g | ]
}|j qS r   r  r  r   r   r   r     s     z.CmfModel.check_delete_perm.<locals>.<listcomp>u   Удаление r  r  c                 S   s   g | ]}|j jqS r   r  r  r   r   r   r     s     r  r,  zPPP-OBJ-DELETEr  )rm  r   r  rX   r   r  r   r   r?  r   r  r   rz  r{  r   )rH   r  r  r   r   r   r    s    
$zCmfModel.check_delete_permc           	      K   s&  |ri ng }t  D ]
}d}t|jtjjrB| j|jjkrTd}n| j|jj	krTd}|st|t
rt|jtjjr| j|jjkrd}n| j|jj	krd}|sqdd| g}|r|j| jkrq|r|jdkrqt|t
rd|dd| gg}|r|j|d }r |||j< q||j|ddgd	 q|S )
ur  
        Получим всех потомков
        Пока только parent and tree_parent
        Может логику через модель надо определять, т.к. связи разные могут быть...
        Поддержка soft_link? Связи, которые надо разрывать при удалении.
        FTr   r   )rz  r  r  r  r  r1   )r6  r   rV   r   r   r1   re  rQ   r   rj   rW   r  r   rv  rI  r5   )	rH   r  r  r  rr  rj   ZlinkedZfilter_r  r   r   r   r  '  s8    

zCmfModel.list_childrenc                 K   s.   | j r*t| j dkr*| j o(| jjjS dS )u   
        Хак для доступ к имени проекта для опубликованных документов.
        r   N)r   r   get_class_name_by_idr   rA  r=   rf   r  r   r   r   get_project_nameW  s    zCmfModel.get_project_name)NT)N)N)r6   )N)TF)/r   r   r   r   r  r   FieldrW  r   re  r   r   r   r1   CmfSubclassedGenericRelationr   r   cmf_locked_byr   cmf_locked_atZCmfCreateDateTimer  cmf_modified_atcmf_viewed_atCmfBoolrh  Z	CmfBigIntr  rc   r   r}   r  ro  r  r  r  r  r  r   r  r  r  r  r  r  r  rr   r   r   rC   r   r6  	  s  
   

     

      

	
J
0r6  c                	   @   sF   e Zd ZdZdZeedddddddZeedddZ	eedddZ
d	S )
BaseM2MModelTFrs  rt  ru  u%   Родительская запись)r0   rz  u   Корневая записьN)r   r   r   r'  rz   r  ZCmfM2MTUUIDr   rW  r   Zroot_idr   r   r   r   r  _  s   
r  c                       sB   e Zd ZdZG dd deZ fddZedddd	Z  Z	S )
CmfGM2MModelu2   Базовый класс для GM2M Связейc                   @   s   e Zd ZdZdZdS )zCmfGM2MModel.description   Описание связиTNr   r   r   r0   rv  r   r   r   r   descriptiont  s   r  c                    sV   t  j|| d|kr0t|d dr0|d j| _d|krRt|d drR|d j| _d S Nr  r=   rightr:   rg   rX   r=   Zleft_name_cacheZright_name_cacher   rC   r   r   rg   x  s
    zCmfGM2MModel.__init__T)r  c                G   sr  g }| j }|j}|r| j D ]}||}|t|}	|| }
t|	}||}||
|
j	|j
k}|||
j|j
k}||
jdk}||j
|j
jk}||}| }|| qn| j D ]}|| }
||}	|t|}t|}||	}||
|
j|	j
k}|||
j	|j
k}||
jdk}||j
|j
jk}||}| }|| q|S )u*  
        Получаем список обьектов через связанную таблицу с проверкой существования обьектов по обе стороны
        TODO TODO1 перенести в драйвер и прожать по full_fields_load
        N)rm   rn   r  r:  ro   r3   r   r  r  right_idr   left_idr  r   rf   r  allrI  r  )r<   r   r  rO  r  rm   dd	model_clsdp_right_modeldp_left_modeldp_m2m_modelZdp_left_model_aliasedrc  Zdp_right_model_aliasedr   r   r   select_related  sJ    









zCmfGM2MModel.select_related
r   r   r   r   Z
CmfStr4096r  rg   ro  r  rr   r   r   rC   r   r  q  s
   r  c                       s>   e Zd ZdZG dd deZ fddZed	ddZ  Z	S )
CmfM2MModelu1   Базовый класс для M2M Связейc                   @   s   e Zd ZdZdZdS )zCmfM2MModel.descriptionr  TNr  r   r   r   r   r    s   r  c                    sV   t  j|| d|kr0t|d dr0|d j| _d|krRt|d drR|d j| _d S r  r  r   rC   r   r   rg     s
    zCmfM2MModel.__init__Tc                 C   s  | j }|j}d}tt| jj }|jt|jkr4d}tt| jj }|	|}|	|}	|	| }
|dkr|
|	}||
|
j|	jk}|||
j|jk}||j|jjk}||}nP|
|}||
|
j|jk}||	|
j|	jk}||	j|jjk}||}| }|S )Nr  r  )rm   rn   r   r   r  rj   r   r3   r  ro   r  r  r  r   r  r  rf   r  r  )r<   r   r  rm   r  r  Zleft_clsZ	right_clsr  r  r  rc  r   r   r   r    s.    





zCmfM2MModel.select_related)Tr  r   r   rC   r   r    s
   r  c                       s  e Zd ZU dZdZeed< dZddddd	d
ddddddddddddddddddgZdZ	dZ
dZedZejd ZeeddddZG d d deZeed!d"dddd#Zeed$d%d&d'Zeed(d)gd*dd+Zeed,d-gd*dd+Zeed.d/gd*dd+Zeed0d1d2d3dd4Zeed5dd6dd7Z e!j"je!j"j#d8ddd9Z$ee%d:ddd;Z&eed<dddd=Z'ee(d>dd?d@dddAZ)e!j"je!j"jddBddCZ*e!j"je!j"j+dDddg dEZ,e!j"je!j"jdFdGddg dHZ-e!j"je!j"jdIdddJZ.e!j"je!j"jdKddddLZ/e!j"je!j"jdMdddJZ0e!j"je!j"j1dNd ddOZ2e!j"je!j"jdPdQdddRZ3dZ4g Z5dSgZ6e!j"je!j"j7dTddddUdVZ8e9dWdX Z:edYdZd[Z;d\d] Z<d^d_ Z=dd`daZ> fdbdcZ?e9ddde Z@e9dfdg ZAe9ddhdiZBe9ddjdkZCe9dldm ZDe9d	dndoZEe9d
dpdqZFe9ddrdsZGe9ddtduZHe9ddvdwZIe9ddxdyZJdzd{ ZKd|d} ZLeMd~d ZNdd ZOdd ZPdd ZQdd ZRdd ZSdd ZTdd ZUdd ZVdddZWdUdeXdddZYdd ZZdd Z[dd fdd
Z\dddZ]dd Z^ fddZ_dUdd fdd
Z`dddZaebecdddgdddd ZddddZedd Zfe9dd Zge9dddddddZhdd Zidd Zjdd Zkdd Zlddd fdd
Zmdd fddĄ
ZnddƄ Zoe9ddǜddɄZpddd˄Zqddd̈́Zre9ddτ Zsddф Zte!j"je!j"jddddӍZue!j"je!j"jdddՍZve!j"je!j"jddddd؍Zwe!j"je!j"jddddCZxe!j"je!j"j1ddd ddۍZye!j"je!j"jzdddd6dݍZ{e!j"je!j"jzddd6ddߍZ|e!j"je!j"jzddddZ}e!j"je!j"j#dddZ~e!j"je!j"jdddddZdd Zdd Zdd Zdd ZdddZdd Zdd Zdd ZdddZebecdddddgddddZdd Zd d Zdd Z fddZ  ZS (  rW   u   CmfEntity - базовый класс для типичных моделей подлежащих автоматизации на преприятии.

    Пример: Task, Invoice, SalesOrder, Bill

    class Task(CmfEntity): pass
    Nacl_parent_fieldFr   r=   textr  rh  r   zlogic_type.codezactivity.codezcmf_owner.namer!  r  r  r  zcomments.textzcomments.log_levelZresult_textzresponsible.namezexecutors.nameZcache_status_typez	tags.namer  z^DEL[0-9]+\s)delete_prefix_patternu   Имя объектаu   object.name - статичное поле для представления в ui, аналог repr, генерируем методом если не заданоT)r0   r  rz  c                       s8   e Zd ZdZdZdZdZdZdZdZ	 fddZ
  ZS )zCmfEntity.codeu   КодTu3   Код в реальном мире из жизниrE   rk  c                    sd   ddl m} |s|S | }| jdkrXt|| jkrX|d | jd   d||d }t |S )Nr   )cmf_hashlibr      r      )	cmf.utilr  striptruncater  
max_lengthZshort_str_encr:   cast)rH   rf   r  rC   r   r   r    s    $zCmfEntity.code.cast)r   r   r   r0   rz  uniquer   r  r  	log_levelr  rr   r   r   rC   r   r     s   u   Системный объектu   Нельзя удалять)r0   r  rv  r   r  u
   Текстu   Текст сущностиu!   Добавить описание)r0   r  placeholderu   Задачи сущностиr   r   )r0   r   backrefr  u#   Документы сущностиr   u'   Комментарии сущностиr  r+  	CmfImportu   ИмпортированZimport_objects)r9  rj   r0   r  r  u,   Исходная версия импортаr)  )r0   r  r9  r'  u&   Сырые данные импорта)r0   rv  r  u"   Ид внешней системы)r0   r   r  u   Объект в архиве)r0   rv  r   r  u   Избранный дляZCmfPersonVarZ	favorites)r0   r  rj   r  r  r'  u3   В избранное всем участникам)r   r0   r  u!   Родительская нода)r0   r  r   r   u   Ветви дереваr  )r0   r  r  r   r   u(   Есть вложенные узлы old)r0   r  r   u$   Есть вложенные узлы)r0   r   r  r   u)   Не отображать в деревеu-   DEPRICATED. Корневой Родитель)r0   rx  r  u   Проектr   )r0   rj   rw  rv  r  u   Сортировкаr   )r0   rz  r  rv  r   c                 O   s>   | j }|st }d|d< d|d< d |d< |dt |d< |S )Nr   r   r=   r   	ui_fields)rM  r\   r#   )r<   re   r7   Zui_form_jsonr   r   r   _build_ui_form  s    zCmfEntity._build_ui_form)r=   c                 O   s   |  dg |  }|D ]&}t||r|dkrt||||  q||_|  |  |  |  |	  |j
dd d|_|S )u/   
        Копируем обьект
        z**r   Tr  )rO  r  rX   r   r=   _calc_perm_parent_calc_perm_inherit_acl_id_calc_perm_has_acl_calc_perm_acl_calc_perm_effective_aclr   r   )rH   r=   re   r7   Zobj_copyr   r   r   r   r     s    zCmfEntity.copyc                 O   s8   | j rtjj| df|| ntjj| df|| d S )NZcreatedupdated)r   r   CmfEventdo_eventr   r   r   r   _do_event_save  s    zCmfEntity._do_event_savec                 O   s   t jj| df|| d S )Ndeleted)r   r  r  r   r   r   r   _do_event_deleted  s    zCmfEntity._do_event_deletedc                 C   s8  t  }|dkr"td| ddd |ds0dS |dkrZ| d	d
dg | jrZ|| j |dkr| dddg | j r|| j |dkrtj	gS |dkr|
|   |dkr|
| jddgd g }|D ]^}|jjdr|
| j|jj|d |d q|jrqt|dr(|jr(q|| q|S )u?  
        Получение значение по шаблонным объектам.

        Возвращает список (в том числе пустой), если передан шаблонный объект
            или None, если объект не является шаблонным
        
   un   Зацикливание рекурсии в раскрытии var-пользователя: extract_var_obj(r  Tr   zvar:Nz	var:ownerr   zcmf_owner.cmf_deletedzcmf_owner.does_not_workz
var:authorr   zcmf_author.cmf_deletedzcmf_author.does_not_workzvar:current_userzvar:followerszvar:all_related_usersrh  does_not_workr  r   )	recursionall_nested_persons)r5   r   ra   rO  r   r_   r   rA  r   r@  rI  get_all_followersr  r   rf   extract_var_objrh  rX   r  )rH   obj_coder  r  Z	var_usersZres_var_usersZvar_userr   r   r   r    s@    

zCmfEntity.extract_var_objc                    sf   |    |   |   |   |   |   |   |   |   t	 j
||}| jdd |S )u   
        Функция сохранения при импорте, чтобы ускорить исключив лишние логики и защиты
        Fr  )r  r  r  r  r  _calc_tree_parentr  
_calc_code_calc_ordernor:   r  r  )rH   re   r7   rc  rC   r   r   r    s    zCmfEntity._save_importc                 C   s   | j od| j kS )N-ordernor  rp   r   r   r   _is_orderno_descending_sort  s    z%CmfEntity._is_orderno_descending_sortc                 C   s   | j s| j S dd | j D S )Nc                 S   s,   g | ]$}| d r|dd nd | qS )r   r   Nr  )r   rA   r   r   r   r     s   z.CmfEntity._revers_ordering.<locals>.<listcomp>r  rp   r   r   r   _revers_ordering  s
    zCmfEntity._revers_orderingc                 C   s   | ds| dsd S |s$tjj}|s8t|}|j}t|tj	k	r^t
d| d d S t }||_d|_||_||_||_||_d|_|  d S )NCmfDocument:CmfTask:zproject_id "z-" is not a valid CmfProject obj_id, aborting;ZclickF)ra   r   r   r   r   r   r   r   r   r   rF  ZCmfSearchStatobj_idactionsearch_query	person_idr!  
aggregatedr   )r<   r  r  r  r!  r   r   statr   r   r   mark_clicked  s&    
zCmfEntity.mark_clickedc           
      K   sR  |s|sd S |s,|r,|D ]}| j ||d q|r<|  ||}|sF|g}|D ] }|dsn|dsn|drJtj|dgdd}|std| d	 qJ|s|dr|jr|jj}n|j}|sqJ|sqJt|t	j
k	rtd
| d qJ|s|j}|s|dr|j }t	 }	||	_d|	_||	_||	_||	_||	_d|	_|	  qJd S )N)r  r  r  r  zCmfAttachment:r   Tr   zobj is None for obj_id "z", skipping;zinvalid project_id "z+": it is not a CmfProject obj_id, skipping;r   viewF)mark_viewed_objra   r   r   r   rF  r   r   r   r   r   Zcur_workflow_version_idrA  ZCmfStatr  r  r  r!  
history_idr  r   )
r<   r  Zobj_id_listr  r!  r  r   r7   r   r  r   r   r   mark_viewed  sP    



zCmfEntity.mark_viewedc              	   C   s   |st jj}|t jjkr@t jt jkr4tjjddd t|}nt j}tj	d|j d| dd6 |
drtjj|j|dd	stj||d
  W 5 Q R X |S )NzKDEV: FATAL self.id != g.current_person.id and self.id != g.system_person.idTr   zCmfEntity.mark_viewed:r      timeout)r  r  zCmfComment:)r  r  r[  )personr   )r   r   r   r|  r   r   r   r   r   ZCmfLockra   r   ZCmfPersonViewr#   r   )r<   r  r  r  r   r   r   r  R  s      
zCmfEntity.mark_viewed_objc           	      C   s   | j s
d S dg| j  }| j||d}| g}|r<|| d}| jdg||ddgd}t|dkrttd|  d |D ]8}|j|k r||_|jdd	 |d7 }qxt	|jd }qxd S )
Nr  r  r4  r   )r  r  r1   r   u   Переиндексация ug   .orderno выполнена частично, так как объектов слишком много.Tr  )
orderno_partition_byr#   _orderno_filterr_   r5   r  r   r  r   r5  )	r<   r  r  r1   r   orderno_filterZcur_ordernoZfix_obj_listZfix_objr   r   r   _orderno_reindexd  s"    



zCmfEntity._orderno_reindexc                 K   s  |d kr|   }ddg| j }| j||d}| j||d}	|	jrl|dr\|	jjd|	d n|	jjd|	d |	 g}
|r|
| |s| j|
dd|j	ggd	d
kr| j
||d	 | j||f||dd|S |
d|rdnd|j	g | j|rdndg|
|d}|rht|j	|j	 d }|sxtt|j	|j	 d
krx| j
||d	 | j||f||dd|S n|rtd}nd}|j	| |	_	|	jdd |	j	S )Nr   r  r  r  PPP-TSK-ORDERr  PPP-OBJ-ORDERr   r  r   T)r  reversreindex><r  r  r  r1   r-  r4  r  )r  r  r#   r   ra   r   r  r_   rv  r  r  
move_abover5  absr   )r<   r  Z	before_idr  r  r  r  r1   beforer   r  Z	prev_itemdeltar   r   r   r  z  s8    


  zCmfEntity.move_abovec                 K   s   |d kr|   }ddg| j }| j||d}|jr^|drN|jjd|d n|jjd|d | j||d}| g}	|r|	| |	d|rdnd	|jg | j|rd
ndg|	|d}
|
rt	|
j|j d }n|rd}nd}|j| |_|j
dd |jS )Nr   r  r  r  r  r  r  r   r  r  r  r-  r  r4  Tr  )r  r  r#   r   ra   r   r  r_   r  r5  r   )r<   r  Zafter_idr  r  r  r1   r   afterr  Z	next_itemr  r   r   r   
move_below  s,    


zCmfEntity.move_belowc                 C   s2   | j ddg|d}|j|kr d S | j||j|dS )Nr   r   )r1   r  r  )r#   r   r  )r<   r  r  r  r   r   r   move_up  s    
zCmfEntity.move_upc                 C   s8   | j |  ddg|d}|j|kr&d S | j||j|dS )Nr   r   )r  r1   r  r  )r#   r  r   r  )r<   r  r  r  r   r   r   	move_down  s    
zCmfEntity.move_downc                 C   sd   | j |d}|d }| jddg|||d gd}t|s<d S |d }|j|krRd S | j||j|dS )Nr  r-  r   r   r   r1   r  r  r   )rv  r5   r  r   r  )r<   r  r  Z
count_objsZ	half_objsZbefore_listr  r   r   r   move_middle  s    
zCmfEntity.move_middlec                 C   sR   ddd gg}| j rNg }|| | | j  | j D ]}||dt| |g q2|S )Nr  !=r   )r  r_   rO  r]   )rH   r  Zpartition_filterrA   r   r   r   r    s    

zCmfEntity._orderno_filterc              	   C   sb   | j r| jrd S |  }t  | j|dgdgd}W 5 Q R X |rX|jrX|jd | _nd| _d S )Nr  r  )r  r  r1   r4  )r   r  r  r   r  r#   )rH   r  Zmax_itemr   r   r   r    s    

zCmfEntity._calc_ordernoc                 C   s   d| j  d| j d| j S )Nr   z/?obj=r   )rM   rL   r   r   r   r   r   href  s    zCmfEntity.hrefc                 C   s   d S rE   r   r   r   r   r   r    s    zCmfEntity._calc_tree_parentc                 C   s   | j s|  | _ d S rE   )r   gen_coder   r   r   r   r    s    zCmfEntity._calc_codec                 C   s  t | dr| js|   t  dd l}| }|  d |   }d}d}| jdd|gdd| j	ggd	d
r|d7 }|   d|   }||k sNt
d| d| j dqN| | }|dkrtd|dd| j d| j	 dd| jko| j d	 |W  5 Q R  S Q R X d S )Nr   r   r   '  r   r   r   r  T)r  r   r   u8   Превышен лимит поиска кода limit=z model=uA   , возможно надо отключить def gen_code: passz$!!! --- gen_code::duration too long r  r  ry  r  r  )rX   r!  r  r   r  rD  get_code_prefixnext_code_numberrg  r   rQ  rQ   rV  r1   r   )rH   rD  r  r   limitr   rH  r   r   r   r  
  s$    
 ".zCmfEntity.gen_codec                 C   s   | j S rE   )rN   r   r   r   r   r  "  s    zCmfEntity.get_code_prefixc                 C   s8   d}| j dddgdgdd}|r4t|jdd	 }|S )
Nr   r   
SIMILAR TOz[A-Z]+-[0-9]+\Z-cmf_created_atT)r  r  r   r   rk  )rg  r5  r   r   )rH   Z
max_numberZlastr   r   r    _get_current_code_number_from_db%  s    z*CmfEntity._get_current_code_number_from_dbc                 C   s   t j}d| j }| j d}|jj|dd}|  z2||rN||}n|  d	 }||| W 5 z|  W nF tjjk
r } z$t	
d| d|j d|j  W 5 d}~X Y nX X |d
S )uN    Высчитывает следующий номер для кода
        znext_code_number-z.lock   r  zlock release error z, lock_name z
, timeout Nr   Z06)ZAPPREDIS_DBrQ   redislockacquirerelease
exceptionsr   r   rF  r=   r  r  Zincrr  r   )rH   Zredis_dbr   Zlock_keyr  r   r  r   r   r   r  .  s    
4zCmfEntity.next_code_numberc                 C   s   d S rE   r   r   r   r   r   gen_nameE  s    zCmfEntity.gen_namec                 O   s
   | | j S rE   )r  )rH   rA   re   r7   r   r   r   _get_field_log_levelH  s    zCmfEntity._get_field_log_levelc                 C   s  | j r
d S |sd S i }g }| jddD ]\}}|dkr8q&|drDq&|drPq&t|tjjrh|jsq&n6|j	dkrt
d|j d |j	dk	r|j|jkrq&| |}|d	krq&| }|sq&|||< | }|s|d
kr|j}|r&|| d|  q&|sd S d}	| jrd}	| j}
| jdkr>| jr>| jdd }
|
sVt| drV| j}
tjj|	| jt
j| t|
t| j|d|d d S )NTr  )
r  Zcache_fieldsr   r  r  ZviewsZlikesZstatus_closed_atZstatus_modified_atZstatus_in_progress_endrx  r  .u&   DEV: INFO. Возможно, поле uI    не попало в аудит, т.к. его old не загруженr  r]  r6   r  r  r      r   z<br>)r*  r+  r   r   parent_nameparent_code
audit_dataZhtml_diff_data)r   r    r7  ra   r!   r   r1   r  _changesr   r   rF  r^   rf   r=  r  Z
audit_diff	html_diffr_   r   r=   rQ   r  rX   r   r   r;  r<  r   r   r  )rH   auditr$  r&  rA   rX  r  Z_audit_diffZ
_html_diffr*  tmp_namer   r   r   _system_auditQ  sl    



zCmfEntity._system_audit)r  r|  c                O   s   t  S rE   )r   )rH   r  re   r7   r   r   r   r    s    zCmfEntity.get_all_followersc                 K   s   t jjf d| i| d S )Nr   )r   r  Zplace_notifyr  r   r   r   _place_notify  s    zCmfEntity._place_notifyc                 C   sf   | j jrb| j  | jddgd}|D ]:}|j  |jD ]$}| j rR| j| q:| j| q:q&d S )NT
person_var)Zinherit_executorsr1   )is_favoriter   favorite_forrA  r  r+  r_   rB  )rH   Z	executorsexecutorr+  r   r   r   _calc_executors_favorites  s    


z#CmfEntity._calc_executors_favoritesr   c                   s4   t  j|d|i| |s0| js0| js0|  | _d S )Nr   )r:   rg   r   r   r  )rH   r   re   r7   rC   r   r   rg     s    
zCmfEntity.__init__c                 C   s   | j s@| jr@| jdr@| dddg | j| _|s<|   d S | jr^| jj js^| jdg | jrn| jj }n| jdkr| j	}nd }| j |kr|r| j
  tjj|ddgd	| _|s|   d S )
NzCmfProject:zparent.task_code_prefixz&parent.task_code_use_logic_type_prefixzlogic_type.obj_code_prefixr!  r   r*  Zui_form_scheme)r   r1   )r!  r   ra   rO  r   r   r  r   rQ   r   rA  r   r   r#   )rH   Zskip_project_perms_checkr!  r   r   r   r    s*    


zCmfEntity._calc_projectc                 C   s   dgS )Nr-  r   r   r   r   r   r    s    z#CmfEntity.project_perm_allow_fieldsc                    s   t   dddg S )Nr  zparent.project_idr!  )r:   r  r   rC   r   r   r    s    zCmfEntity.save_preload_fieldsr  r  c             	      st  | j r4| js4| jjs| jjr4tjjd| j dd | 	  | jsL| 
 | _| jjr| dg | jjr| jjsd| j_t  | jjdd W 5 Q R X | jjr| jj|  |   |   |   |   | jr|r|   |   |   |   |   |   tjrd| _ n| j r(d| _ t! j|||d|}| "  | j#|$ddd	 | j%|| | &  |S )
NuN   Запрещено редактировать системный объект Tr   ztree_parent.tree_node_is_branchr  Fr0  r'  )r'  )'r  r   r   r   r=   r   r   r   r   r/  r  r  rO  r   r   r   r  r   r=  tree_child_deleter  r  r  r  r  r  r  r  r  r  r   r  r  r:   _acl_spread_inheritancer)  r#   r  r  )rH   r  r  re   r7   rc  rC   r   r   r     sF    


zCmfEntity.savec                 C   sH   ddl m} | jsd S tj| jj |rD|tjj	d| jjidd d S )Nr   schedule_deferred_jobr  r  )r7   Z	countdown)
r   r4  full_searchr   r  Z
mark_dirtyr   rf   r  celery_full_search_index)rH   r  r4  r   r   r   r    s    zCmfEntity.mark_full_searchr  r  )
system_job	only_onceonly_once_argspriorityc                 O   sF   t d|   t| }tj| |jd}|  t d|   d S )NzStart celery_full_search_index r  zEnd celery_full_search_index )r   rF  r   r   r   full_search_fieldsfull_search_index)r  re   r7   rj   r   r   r   r   r6  %  s
    
z"CmfEntity.celery_full_search_indexc                 C   sn  dd l }dd l}ddlm} tjtjd| j	
dd t| j	}|d| j	
dd t| j	d t| jd  t| j	}tj|rT|tj|}| s|jjdd ||| n||| || | d}tj|r|||j tjjd	d
| gdddgdD ]B}	|	jj}
|	jj}|	jj}d |	_|	  |
|	jkr<| jj|
|	jj| _| jj|j|
|	jj| _| jj|j |
|	jj| _| jj||	jj| _| jj|j||	jj| _| jj|j ||	jj| _| jj||	jj| _| jj|j||	jj| _| jj|j ||	jj| _| j!r| jdd q|rf|tj|}t|S )Nr   )Pathr   r   r  T)exist_okz.metar   r.  r   url_preview_imgurl_previewr  r  )"shutilurllibpathlibr=  ospathr  rE  Z
UPLOAD_DIRr   r   r   r  rQ   r  r   mkdirmover   rmtreer   r  r5   r   rf   r?  r@  r   r  replaceparsequoteZ
quote_plusr   )rH   ZabsoluterA  rB  r=  Zold_pathrE  new_pathZold_meta_pathZattachZold_urlZold_url_preview_imgZold_url_previewr   r   r   get_files_dir.  sF    &8

"zCmfEntity.get_files_dirc                 C   s  ddl m} | jdkr tjr d S ddlm} |d| j ddtjgd t	d	}|s`i }i t_
|	| jj}|d kri }| jj|d
< tjotjjj|d< d |d< d |d< d |d< | j|d< g |d< g |d< g |d< g |d< t| dr| jjr| jj|d< t| dr| jjr| jj|d< t| dr>| jjr>| jj|d< |  D ]}|d |jj qF|	dpng }| jr| jddD ]\}}|dkrqt| |}	|	jdk	r|	j|jkrtd| j d|	j  qt|	tjjrxt|	tjjr"|	jD ]^}
}}||jj qnVt|	jtsN|	jd k	rN||	jjj n*t|	jtrx|	jD ]}||jj qb|	jdkrtd|	j   |	jdk	rt|	tjjrt|	jts|	jd k	r||	jjj n*t|	jtr|	jD ]}||jj q|d | q|d !| d}
| j"r8d}
| j#jrR| j#dkrRd}
|d |
 tt$|d |d< tt$|d |d< tt$|d |d< tt$|d |d< dtkrtj%|d< nd|d< d tkrtj&|d < nd|d < |tj
| jj< d S )!Nr   )r   r  cmf_emit_eventzevent-z1this event DEPRECATED, use is\_changed-class_namer   )r?   event_persons	emit_listr   Zevent_current_personr   r  placerQ   Zrelation_personsZchanged_fieldschanged_relationsr  Tr  )r  r   r  Zcmf_viewed_byr  r  .zemit: FIXME is changed bug r/   uR   DEV: INFO Могла не прийти инвалидация для old-поля r6   r  r  jsurlr   session_tab_id)'collectionsr   rQ   r   r  r   rO  r   r   r#   rQ  rf   rX   r   r   r  rR  r  r_   r   r    r]   r   r=  rF  r!   r   r1   r  r  r%  r5   r^   rI  r   rh  r   rT  rU  )rH   r   rO  rQ  ZbodyprS  r&   r'   rJ   r  r   r(   r   r   r   r   r  Z  s    







zCmfEntity.emitc              	   C   sj   g }|  d}|D ]<}t|dkrH|d|d t|d   q|| qdd| dS )Nr  r  z{}%r-  z%{}%r  )r  r   r  r_   formatr  )r<   r  Zstemmed_query_wordsZwordswr   r   r   _get_stemmed_query  s    "zCmfEntity._get_stemmed_queryr   )r  r1   r  r  c                O   s   | j |d}|d}ddd|gg}	d|krN|dD ]}
|	|
d|g q6nBdD ]}
|	|
d|g qR|| jrt|d	kr|	d
d|g |r|	|g}	|r|	d
d|g | j||	|d}|S )N)r  r   r  r   r.  Zfields_filterr  )r=   r  r   ,   r   r  r  )rZ  r#   r_   ra   rQ   r  r5   )r<   r  r1   r  r  re   r7   Zstemmed_queryr   r  r  rc  r   r   r   r    s$    
zCmfEntity.searchc                 C   s   | j stdt| j S )NK   Блокировка объектов без id не реализована)r   rY   r   	lock_pingr   r   r   r   r]    s    zCmfEntity.lock_pingc                 C   s   | j stdt| j S )ut   
        Из редиса заберём структуру, где есть данные
        :return:
        r\  )r   rY   r   	lock_infor   r   r   r   r^    s    zCmfEntity.lock_infoc                 C   s<   | j std|   | jdkr.| jd| d t| j dS )u`   
        Захват объекта на редактирование
        :return:
        r\  r   zPPP-PR-ADMINr  i  )r   rY   r  rQ   r   r   r  r   r   r   r   r    s    
zCmfEntity.lockc                 C   s   | j stdt| j S )u>   
        Снятие захвата
        :return:
        r\  )r   rY   r   unlockr   r   r   r   r_    s    zCmfEntity.unlock)rN  r  c                   s  |    | dddg | jr>|s>tjjd| j dd d S |sJ|   dt	 
d }| jrtd	| jjs| d
| j d | jj | _| d
| j d | jj | _t| drt| dr| jddgd | jr| jj| _| d| j | _| j| _| j r| j|  | js| j}| jdkrP| j  | jrP| jdd }tjjd| jtj| t |t | jj!d | j"|| | j#dd t$ j%|d|i|}| &  |S )Nr  r   r   u<   Нельзя удалять системный объект Tr   ZDELz%Y%m%d%H%M%Sz[A-Z]+-\d{4,}\Zr  r  r  r  r(   r  r   r!  r  r*  r+  r   r   r"  r#  r  rN  )'r  rO  r  r   r   r   r   r  r   r   r  r   rematchrf   r  r=   rX   r  deleted_loginr  r  rA  r1  r   rQ   r  r   r;  r<  r   r   r   r=  r  r  r:   r  r  )rH   rN  r  re   r7   r>  r(  rc  rC   r   r   r    sL    




	zCmfEntity.deleter  c                   sp  |  ddg | jjrHtj| jdddgd}|rH|jr@| j| _n|  | j	rvt
| j| j	jrvt
| jd| j	j| _	| jrt
| j| jjrt
| jd| jj| _t| drt| d	r| j dd	d
gd | jr| jj| _| j| _| jsZ| j	}| jdkr| j  | jr| jdd }tjjd| jtj| t|t| jjd tjj | df|| t! j"|d|i|S )Nr  r   Trh  r   )r   r1   r   r  r  rc  r  r  r   r!  r#  r`  Zrestoredr  )#rO  r  r   r   r   rh  r   r  r$  r=   ra  rb  r  rf   r*   r   rX   r  rc  r  r   rQ   r  rA  r   r;  r<  r   r   r   r=  r  r  r:   r#  )rH   r  re   r7   r  r(  rC   r   r   r#  E  sD    




	zCmfEntity.restorec              	   C   sd   | j  D ].}|jdd| jgdd|jggd}|r
 dS q
d| _t  | jdd	 W 5 Q R X dS )
u    Убирает метку дерева у объекта при удалении узлов, при перемещении узлов r  r.  r   r  r  NFTr  )
tree_nodesr:  rg  r   r   r   r  r   )rH   r  rj   r   r   r   r   r1  o  s     
zCmfEntity.tree_child_delete)rN  c                O   s  ddl m}m} |jjdddd}| s:|ddd d	S z*t
 }t| d}	dd| jgg}
|s|
ddddd |	jD gdddgg tjj|
dgdD ]~}t
|jjd||jj< |jj||jj d< |jj||jj d< ||jj d dr |jrd||jj d< nd||jj d< |jr<|jj||jj d< |jrX|jj||jj d< |jj||jj d< |jj||jj d< |jj||jj d < |jjs|jj||jj d!< |jjs|jj||jj d"< |jjs|jj||jj d#< |j j||jj d$< |j!rd%|_!|j"dd& q|rdg }|# D ]}|t$j%|| d' q.|	&| |	'  |	(  W 5 z|  W n4 tk
r } zt	d
|  W 5 d	}~X Y nX X d	S )(uD  
        Синхронизируем настройки полей с фронта
        Получаем список полей с фронта, в нужном порядке для ui_group.
        Приводим в соответствие модель, БД, и запрашиваемый список.
        Поля которые удалили(нет в fields) убираем из ui_group, но оставляем в базе(!!! важно) и в модели
        (в модели поля может не быть, если её удаляли).
        r   )r  r   z(lock::cmf__base_model__custom_field_synci  )r  Zblocking_timeoutu   Невозможно изменить список полей, так как уже запущен процесс изменения. Попробуйте снова через минуту.Tr   Nz'custom_field_sync:: release lock error r  r+  r.  r  r=   NOT INc                 S   s   g | ]
}|j qS r   rQ   )r   r  r   r   r   r     s     z/CmfEntity.custom_field_sync.<locals>.<listcomp>dirtyr   r  rg  r0   
field_typeZM2Mr  r  r  r  r   r  r   r   rj   choicesr{  Fr  )rj   ))cmf.appr  r   r  r  r  r  r   r   rF  r\   CmfCustomClassrQ   r_   custom_fieldsr   ZCmfCustFieldr5   r=   rf   r0   ri  r7  r  r  r  r   r  Zfield_readonlyr  rj   rj  r{  rh  r   r|   CmfCustomField	from_dictrX  save_changesrW  )r<   rN  re   r7   r  r   Z
redis_lockr   r  custom_classr  Z
cust_fieldrm  Zcustom_field_datar   r   r   custom_field_sync{  sd    	
(



zCmfEntity.custom_field_syncc                 O   sL   ddl m} |jdkr0|d| j |  d n|d| j |  d d S )Nr   rN  ztask-comment-)rP  zaudit-task-comment-)rk  rO  r  r   r  )rH   r  re   r7   rO  r   r   r   _comment_save_hook  s    
zCmfEntity._comment_save_hookc                 K   s   dddgdd| j gg}|r*|dd|g g }|D ]}ttj|r2|| q2tjj||dD ]&}|D ]}t||||  qf|  q^d S )Nstatusr.  openr  r  r  )r   r_   rX   r   r  r5   r   r   )rH   r  r7   r  _fieldsr&   r  r  r   r   r   _update_opened_notifies  s    z!CmfEntity._update_opened_notifiesc                 C   s   dS )uE    Базовый шаблон почтовых уведомлений zmail_notification.htmlr   rp   r   r   r   +get_default_mail_notification_template_name  s    z5CmfEntity.get_default_mail_notification_template_namec                 K   s  |  | j d|kr<t| jd tjt| jp0d |d< d|krd}| jD ],}|j	dkrN|dtjt|jppd 7 }qN||d< d|kr| jst
| j d tj| jj d	S | j|d
< | jj|d< |d| jj |d| jj |d| jj |d| jj |d| j |d| jj |d| jrF| jjjpHd	 |d| jj t| drx|d| jj |d| jj |d| jj tjjf | d	S )u   
        Медленный метод для вызова из celery или из массовых индексаций
        r  r  r   comments_textr   
r=   ud    Объект без имени в поиск добавлять бессмысленно mark_cleanNr  r  r  Zobj_archivedZobj_deletedZobj_hrefrD  Zobj_owner_nameZobj_tree_parent_idr!  Zobj_project_idZobj_created_atZobj_modified_at)rO  r;  r   r=   r   r  Z
strip_htmlr  commentsr  r   rF  r   Z
mark_cleanrf   rQ   r[   r   r  rh  r  r   r   r  rX   r!  r  r  Zindex_object)rH   r7   ry  r  r   r   r   r<    s8    (

 
 zCmfEntity.full_search_indexu8   Разрешить публичный доступ DELME)r  r0   r   u-   Задать права для объекта)r  r0   rz  u<   Список для проверки прав доступа)rj   r   r  r0   u!   Наследовать праваu#   Наследуем права от )r  r   rx  r0   u*   Кеш Владельца Родителя)r   r  r0   r9  u;   Наследуемый список прав доступа)r   r0   r9  r  u;   Эффективный список прав доступа)r   r  r0   u   Кеш неразвернутых записей Уровней безопасности, которым разрешен доступ)r0   r  u   Шифрованныйu5   Для просмотра требуется ключ)r   r  r0   r  c              
   C   s   |  ddddddddg d S )	Nperm_has_aclz
perm_acl.*zperm_acl.cmf_ownerz!perm_acl.object_ownerperm_inheritr  r$  r#  r   )rO  r   r   r   r   _load_perm_fieldsT  s         zCmfEntity._load_perm_fieldsc                 C   sJ   | j s| jjs| jjsd S |   d }| jr4| j}n| jr@| j}|| _d S rE   )r   r  r   r   r}  r  )rH   r  r   r   r   r  Z  s    zCmfEntity._calc_perm_parentc                 C   sP   | j jsd S |   | j r@| j ddg | j j| _| j j| _nd | _d | _d S )Nr#  r"  )r  r   r}  rO  r#  r$  r"  r&  r   r   r   r   r  f  s    
z#CmfEntity._calc_perm_inherit_acl_idc                 C   s   d S rE   r   r   r   r   r   r  s  s    zCmfEntity._calc_perm_has_aclc              	   C   s   | j js(| jjs(| jjs(|s(|  s(d S |   | j rJ| jsJtj| d| _| jr| j  | j_	| j| j_| j| j_
| jr|| jnd | j_| jj  tjj  | j  |   W 5 Q R X d S )N)r   )r|  r   r$  r   _acl_subjects_is_changedr}  perm_aclr   rz  disabledZobject_ownerperm_inheritZinherit_acl_idrf   r   r   r   r   r  Zclear_auto_acl_acl_scaffold)rH   rN  r   r   r   r  v  s.    


zCmfEntity._calc_perm_aclc                 C   s   d S rE   r   r   r   r   r   r    s    zCmfEntity._acl_scaffoldc                 K   s   |    |   | jrr| jddddg d| j_| jjD ]*}|jdkrR|  q:d|_|jdd q:| jj	  | jdd d S )NZpolicyr  zrules.disabledzrules.sys_typeTry  r  )
r  r}  r  rO  r  rG  sys_typer  r   rf   )rH   r  Zruler   r   r   r    s    

zCmfEntity.disable_aclc                 C   sb   | j js$| jjs$| jjs$| jjs$d S | dddddg d }| j rL| jj}n| jrX| j}|| _d S )Nr|  Zperm_acl_idr  r$  r#  )r|  r   r  r  r$  rO  r   r#  )rH   r#  r   r   r   r    s$    
z"CmfEntity._calc_perm_effective_aclc                 C   sz   ddl }| jrdS | jjs&| jjs&dS td ddlm} d}|rRdd |D }|t	j
j| j|| jj| jjdd dS )	u  
        При изменении эффективного ACL, нужно обновить все объекты и ACL, кто от нас наследуется.
        Наследование:
          child.perm_parent(рекурсивно) -> self, sub_child.perm_parent -> child
          child.perm_inherit_acl_id = self.perm_effective_acl_id
          child.perm_acl.inherit_acl_id = child.perm_inherit_acl_id if child.inherit
          if child.perm_effective_acl_id.is_change:
              do_recursion

        Операция может быть очень тяжёлой, нужно запускать как можно реже.
        !!! Потенциально можем изменять большое количество объектов, высок риск деадлоков.
         Можно разбить на небольшие транзакции, но тогда нужны дополнительные средства обеспечения
         целостности конфигурации. Может глобальный acl_lock в редисе.

        Возможна супер оптимизация, если все связи по perm_parent_id вынести в одну таблицу(модель).
          Тогда их можно получить одним рекурсивным запросом.

        TODO: force=True всё пересчитать без оптимизаций.
        r   NuG   _acl_spread_inheritance: запускаем _acl_spread_inheritance_jobr3  c                 S   s   g | ]
}|j qS r   rg  )r   r  r   r   r   r     s     z5CmfEntity._acl_spread_inheritance.<locals>.<listcomp>)r  spread_model_namescmf_owner_is_changedperm_effective_acl_is_changed)r7   )rk  r   r#  r   r"  r   rF  r   r4  r   r   _acl_spread_inheritance_jobr   )rH   spread_modelsr   r4  r  r   r   r   r2    s"    
z!CmfEntity._acl_spread_inheritancer  r  )r8  r7  r9  c                 C   s:  d }|rdd |D }t j| ddgd}td |rtd|  |}|d krZt }|D ]j}tjjj	
 d|j |jj|jjd	}t|}tjj|jd
d |D  tdtt|  q^td |r"g }	g }
|jjg}|rd}|d | }
||d  }|}|d kr$t }|D ]}tjjj	
 d|j |jj|
d}t|}d}tjj|jdd |D  |D ]\}|d7 }|d |	krtd|d  d q~t |d dkrʐq~||d  q~q(|	|
 }	tdt|	 dt|  qtdt|	  td |	rd}|	d | }|	|d  }	|}|d kr^t }|D ]}tjjj	
 d|j |jj|d}tjj|jdd |D  tjjj	
 d|j |jj|d}t|}tjj|jdd |D  qbtdt| dt|	  q&td  td! td  d S )"Nc                 S   s   g | ]}t |qS r   )r   r   )r   r  r   r   r   r     s     z9CmfEntity._acl_spread_inheritance_job.<locals>.<listcomp>r"  r#  r  uz   _acl_spread_inheritance: Шаг 1. Если изменился owner_id, апдейтим его всем потомкамuR   _acl_spread_inheritance: Обновляем perm_parent_owner_id потомкам ai  
                    UPDATE %s SET perm_parent_owner_id = :new_owner_id
                    WHERE
                    (
                        perm_parent_owner_id != :new_owner_id
                        OR perm_parent_owner_id is null
                    )
                    AND perm_parent_id = :parent_id
                    RETURNING id
                )Znew_owner_idr   c                 S   s   h | ]}|d  qS r  r   r   rowr   r   r   	<setcomp>  s     z8CmfEntity._acl_spread_inheritance_job.<locals>.<setcomp>z+_acl_spread_inheritance: ... update count: ud   _acl_spread_inheritance: Шаг 2. Рекурсивное обновление perm_effective_acl_idr  a  
                        UPDATE %s SET
                            perm_inherit_acl_id = :perm_effective_acl_id,
                            perm_effective_acl_id = :perm_effective_acl_id
                        WHERE perm_parent_id = ANY(:parent_id_list)
                        AND perm_inherit = 't'
                        AND (perm_has_acl = 'f' or perm_has_acl is null)
                        RETURNING id
                    )r#  Zparent_id_listr   c                 S   s   h | ]}|d  qS r  r   r  r   r   r   r  ,  s     r   r   u'   _acl_spread_inheritance: Ошибка! u!    уже был обработанr  u6   _acl_spread_inheritance: Уже обработано: u   , к обработке: u:   _acl_spread_inheritance: Всего обработано: u   _acl_spread_inheritance: Шаг 2.1. Рекурсивное обновление child.perm_acl.inherit_acl_id детям с ACLa  
                                            UPDATE cmf_access_list SET
                                                inherit_acl_id = :perm_effective_acl_id
                                            WHERE
                                            (
                                                inherit_acl_id != :perm_effective_acl_id
                                                OR inherit_acl_id is null
                                            )
                                            AND id in (
                                                SELECT perm_acl_id FROM %s WHERE
                                                perm_parent_id = ANY(:parent_id_list)
                                                AND perm_inherit = 't'
                                                AND (perm_acl_id is not null or perm_acl_id != '')
                                            )
                                            RETURNING id
                                        c                 S   s   h | ]}|d  qS r  r   r  r   r   r   r  W  s     a  
                                            UPDATE %s SET
                                                perm_inherit_acl_id = :perm_effective_acl_id
                                            WHERE perm_parent_id = ANY(:parent_id_list)
                                            AND (
                                                perm_inherit_acl_id != :perm_effective_acl_id
                                                OR perm_inherit_acl_id is null
                                                )
                                            AND perm_inherit = 't'
                                            AND perm_has_acl = 't'
                                            RETURNING id
                                            c                 S   s   h | ]}|d  qS r  r   r  r   r   r   r  i  s     z_acl_spread_inheritance: DoneuH   _acl_spread_inheritance: Шаг 3. Перезагружаем кеш ACL)r   r   r   rF  rW   r   r   r  rm   Z_ddZSessionZexecuterP   r"  rf   r   r5   r   Zapp	CMF_CACHEZinvalidate_idsrQ   r  r#  r  r_   )r  r  r  r  r  r   Z_spread_modelsZchild_modelrc  Z	processedZcur_stage_parent_id_listZnew_stage_parent_id_listZbatch_countZ	upd_countr  Zcur_parent_batchr   r   r   r    s    
	



	 

 "

z%CmfEntity._acl_spread_inheritance_jobc                 C   s&   | j jrdS t| dr"| jjr"dS dS )NTr}  F)r   r   rX   r}  r   r   r   r   r~  z  s
    z"CmfEntity._acl_subjects_is_changedc                 C   s:   g }| j r|| j  t| dr6| jD ]}|| q&|S )Nr}  )r   r_   rX   r}  )rH   rr  r  r   r   r   _acl_subjects_list_level_write  s    

z(CmfEntity._acl_subjects_list_level_writec                 C   s   g S rE   r   r   r   r   r   _acl_subjects_list_level_read  s    z'CmfEntity._acl_subjects_list_level_readc                    s   ddl m} | jr| jr| jjdd }t||d }|oF|j| j}t	| t
oX| jj}|rd|js|jjd| jj|| jj| j| jj|| | jd	 t jf |S )Nr   r   r   r2  )	r3  r4  r5  r6  r7  r  r8  r9  r   )r   r   r  r%  rf   rA  r]   r1   r#   r!   r6  r   r=  r'  rz  rC  r$  r&  r   r   r:   r  )rH   r7   r   Zparent_class_nameZparent_modelZparent_fieldrD  rC   r   r   r    s&    
    zCmfEntity._acl_check_write)r   F)NNN)NNNNNN)N)NNF)NN)N)N)N)T)F)T)F)N)N)F)N)NFF)r   r   r   r   r  r   rk  r5  r;  Zmenu_tree_parent_idZmenu_tree_ordernor{   ra  compiler  r6  rb   r  Z	CmfStr256r=   ZCmfStr64r   r  r  Z	CmfMarkupr  rV  ZtasksZ	documentsr{  rc  r  r  r   r1   r  r  ZCmfStrr  r  rf  r-  r,  re  r  rd  Zhas_tree_nodesr   Ztree_hiddenr  Zroot_parentr   rj  r  r  ZCmfIntr  ro  r  r   r  r  r  r  r  r  r  r  r  r  r  r  r	  r
  r  r  r  rc   r  r  r  r  r  r  r  r  r  r)  r   r  r*  r/  rg   r  r  r  r   r  rq  Zcmf_deferred_jobr6  rM  r  rZ  r  r]  r^  r  r_  r  r#  r1  rr  rs  rw  rx  r<  Zperm_publicr|  r  r  r  rW  r&  r$  r#  r'  r  r}  r  r  r  r  r  r  r  r2  r  r~  r  r  r  rr   r   r   rC   r   rW     s|  
            


	  
                  
     

,

;
(

		DA
,b



7*B
8             	   
      )
    
rW   c                   @   s  e Zd ZU dZeed< dZeed< dZeed< dZe	e ed< dZ
eed< dZeed< dZeed< dZeed	< dZee ed
< dZee ed< dZeed< dZeed< dZe	e ed< dZeed< dZeed< dZeed< ededddZdd Zdd ZdS )rn  NrQ   ri  ui_group_name	ui_groupsrT   r0   ri  db_typedb_column_namedb_table_namer{  rj   r   rj  Fdb_need_create_choice_tabledb_choice_table_name)
field_dictc           	      C   s   t |}i }d }i }| D ]V\}}|dkrDt|trDdd |D }|| jkrV|||< |dkrf|||< |dkr|}q| f d|p|i|}|| |S )Nrj  c                 S   s   i | ]}t ||qS r   )rl  caption_to_name)r   choicer   r   r   rC    s      z,CmfCustomField.from_dict.<locals>.<dictcomp>)ri  r  r  rT   r  r  r  rK  rT   )r   r    r!   r5   Z__dataclass_fields___calc_db_choice_table_name)	r<   r  rj   rT   Zui_meta_nativer7   r&   r'   rc  r   r   r   ro    s     

zCmfCustomField.from_dictc                 C   s^   d dd | jdD }|j | d}t|dkrZtjjddt|j  d	d
d |S )Nr   c                 S   s   g | ]}|  qS r   )
capitalize)r   rW  r   r   r   r     s     z;CmfCustomField.gen_db_choice_table_name.<locals>.<listcomp>r(   ZCh@   u8   Имя поля не должно быть больше    u    символовTr   )r  rQ   r   r  r   r   r   )rH   rj   r  r   r   r   gen_db_choice_table_name  s
    "z'CmfCustomField.gen_db_choice_table_namec                 C   s\   t | dd }|sd S |dkrDd| _| || _| j| _| j| jd< n|| |krX|| _d S )Nrj   ZCUSTOM_CHOICE_MODELT)r]   r  r  r  rj   rT   )rH   rj   Z	rel_modelr   r   r   r    s    z)CmfCustomField._calc_db_choice_table_name)N)r   r   r   rQ   r   rk  ri  r  r  r	   rT   r\   r0   ri  r  r  r  r   r  r{  rj   r   rj  r  r  ro  ro  r  r  r   r   r   r   rn    s(   
rn  c                   @   s   e Zd Zee dddZee dddZdd Z	d	d
 Z
dd ZeeedddZeedddZeedddZejdddZdd ZdS )rl  re  c                 C   s  || _ d | _g | _d | _d | _g | _d | _|  | _| j	d| _
d| _dd | j jj| j jD | _| j }tt}dd | j j D D ]}||j}d }d }t|ttfrtt|jd}|r| j jj|rt }	nPt|tr|j d}||kr||nd }	n|j}||kr6||nd }	t |j| !|||oV|d	 |j"|j#|j|	op|	d
|d |jdd d}
|
$| j  |	d k	r| j%|
 qd| _qdd | jD | _d S )N.bkFc                 S   s$   i | ]}|d   dr|d  |qS )r=   rK  r  )r   columnr   r   r   rC    s    z+CmfCustomClass.__init__.<locals>.<dictcomp>c                 S   s   g | ]}|j d r|qS rJ  )rQ   ra   )r   r'   r   r   r   r     s      z+CmfCustomClass.__init__.<locals>.<listcomp>rj   rx  r   r3   )rQ   ri  r  r  r0   r{  rT   r  r  r  rj   Tc                 S   s   i | ]}|j |qS r   rg  )r   
field_datar   r   r   rC  )  s      )&r  Zcurrent_fieldsrm  
db_columnsr   add_to_db_fieldsZcustom_fields_index_get_model_file_pathmodel_file_pathwith_suffixmodel_bk_pathrm   rn   Zinspect_table_columnsrP   r   r   r5   r1   r|   r#   rQ   rV   r  r  r   r   rT   Z	has_tabler\   r  ro  rn  _field_type_namer0   r{  r  r_   )rH   r  r  Zfields_ui_groupsrB   r  r  Z_db_table_nameZ	cmf_modelZdb_field_infor  r   r   r   rg     s\    


zCmfCustomClass.__init__r  c                 C   s   dd | j D }|D ]}||j}|s@| j | d| _|}n(|jD ] }t||rFt||t|| qF|j| j	j
kr|j| jkr|jd | jkr| j| d| _q| j	j
|j }t|dr|j|jkrd| _qdS )u  
        Получим список новых полей, которые надо создать.
        Соберём новые группы на основе системного значения и списка полей.
        Поля удалять нельзя, т.к. данные могут быть бесценны. TODO удалять, если данных нет.
        c                 S   s   i | ]}|j |qS r   rg  r  r   r   r   rC  1  s      z/CmfCustomClass.merge_fields.<locals>.<dictcomp>Trx  rj  N)rm  r#   rQ   r_   r   r   rX   r   r]   r  r1   r  r  rj  )rH   r1   Z
cur_fieldsr  Zcustom_fieldr   rJ   r   r   r   rX  +  s"    

zCmfCustomClass.merge_fieldsc                 C   s6  | j D ]}ttj|j}t|tr*t n|jrn|j	r| j
jj|j | j
j |j }| j
jj| qnnt|tr| j
j d|j }| j
j |j  }| j
jj| qn&t|tr|j d}tjj}n|j}| j
jj| j
j|| q| jd}| j r| j| j | | || j dS )uP   Создадим поля в базе и сохраним файл модели.r(   rx  r  N)r  r]   r   r1   ri  rV   r  rb  r  r  r  rm   rn   Zadd_custom_choice_modelrQ   Zadd_custom_m2m_modelr  rP   r  r  rW  Zadd_custom_columnr  r  r  renamer  _write_custom_model_file)rH   r  ri  r  Z
table_nameZcolumn_nameZmodel_tmp_pathr   r   r   rp  F  s2    





zCmfCustomClass.save_changesc                 C   s   ddl m} dd l}dd }z
|  W nz tjk
r   td | jrl| j rlt	d | j
| j n(| jr| j rt	d | j  n |   Y nX |dd	| jji d S )
Nr   )cmf_emit_server_eventc                  S   sN   t tj } dD ] }| d | }| r|  qtjddddgdd d S )	N)z__autogen_models.pyz__autogen_models_tmp.pyz__autogen_models.tsZtmpz/usr/bin/envpython3z	manage.pyZautogenT)check)rC  r=  rE  PROJECT_DIRr  unlink
subprocessrun)Zproject_pathZautogen_filenameZautogen_file_pathr   r   r   applyk  s    
z+CmfCustomClass.apply_changes.<locals>.applyuG   Ошибка применения новой кастом модели.u=   Есть backup file попробуем откатиться.uA   Попробуем откатиться удалив custom file.zBaseModel:custom_field_syncr+  )r   r  geventr  ZSubprocessErrorr  r  r  r  infor  r  r  r  rQ   )rH   r  r  r  r   r   r   rW  g  s"    



zCmfCustomClass.apply_changesc           	      C   s\  ddl m} t| jtj dddddd }tt	| d}tj
|d	}tj
|}|tj|< |j| t|| jj}|jD ] }|d
r|j| | jj|< q|j| j_|j| j_t|D ]H}|| jj ds|| jj | jj drtt|t|| q|  dt_| jjjj !| jjrN| jjjj | jj= tj"#  dS )u   
        без перезагрузки обновляем в памяти модели и поля, добавляя кастомные
        r   )r  r   r   r/   NrT  custom_modelsz /opt/eva-app/__autogen_models.pyrK  ZCf)$rk  r  r   r  rI  rE  r  	importlibreloadimport_moduleutilspec_from_file_locationmodule_from_specr  modulesloaderexec_moduler]   r  rQ   r1   ra   rT   rL  r   r   r   Zflushdbrt   rN  rm   rn   Zmodels_registryr#   ZRelationCacheZbuild_fields_cache)	rH   r  Zmodule_pathZmodule_namespecr  Zcustom_modelrA   r  r   r   r   reload_models_and_fields  s,    *




2z'CmfCustomClass.reload_models_and_fields)r0   r   c                 C   s   |st jjddd | |}tdD ]<}d| }|sB|drP|d| 7 }|| jkr&|  S q&t jjd| d	| d
dd d S )NuM   У настраиваемого поля не указано названиеTr   r  rK  rx  r(   u#   Такое имя уже есть: ry  r  )r   r   r   r  ranger7  r  )rq  r0   Z	name_basennrA   r   r   r   calc_field_name  s    



zCmfCustomClass.calc_field_name)r0   c                 C   s&   t | ddd}ddd |D }|S )NruT)Zlanguage_coder2   r   c                 s   s"   | ]}|  r| nd V  qdS )r(   N)isalnumr+   )r   r2  r   r   r   	<genexpr>  s     z1CmfCustomClass.caption_to_name.<locals>.<genexpr>)r   r  )r0   r=   r   r   r   r    s    zCmfCustomClass.caption_to_name)rB   c                 C   s8   | j D ],}t|dd }t|tr|dr|  S qd S )NrQ   ZCmf)rF   r]   r!   r   ra   )rB   r@   Zbase_class_namer   r   r   r    s    
zCmfCustomClass._field_type_name)	file_pathc              	   C   s   t jt tjtjdgd}dd |jd< |	d}| j
jD ]}|jds@ qZq@d}|d	}||j| |d
 W 5 Q R X dS )u^   Дампим кастомные поля в файл используя шаблон и jinja2zcmf/templates)r  c                 S   s    t | trd| ddS | S )Nz'''{}'''z'''z""")r!   r   rX  rI  )xr   r   r   r    r  z9CmfCustomClass._write_custom_model_file.<locals>.<lambda>rK  zcmf_model.tmpltcustom.NrY  )ri  rx  )Zjinja2ZEnvironmentZFileSystemLoaderrD  rE  r  rE  r  filtersZget_templater  	__bases__r   ra   ru  r2  Zrender)rH   r  Z	jinja_envtemplaterx  Z
model_filer   r   r   r    s    
z'CmfCustomClass._write_custom_model_filec              	   C   s  t tj d| jj d}| jjD ]~}|jdrld	|j
ddd }t tj d| d} qq$d	|j
ddd }t tj d| d} qq$|jd	d	d
 |d }| s|d W 5 Q R X td|  td}d	dd || jjD }|| d S )uY   Возвращает путь к файлу где будут кастомные поляz/custom/modules/z/fieldsr  r   r/   Nr   z/custom/T)parentsr>  z__init__.pyrY  u   Создан z[A-Z][a-z0-9]+r(   c                 S   s   g | ]}|  qS r   )r+   )r   Zwordr   r   r   r     s     z7CmfCustomClass._get_model_file_path.<locals>.<listcomp>z.py)rC  r=  rE  r  r  rM   r  r   ra   r  r   rF  r  ru  rV  ra  r  findallrQ   )rH   Zfields_dir_pathr<   ZpostfixZpkg_init_file_pathZname_word_reZmodel_filenamer   r   r   r    s$    

z#CmfCustomClass._get_model_file_pathN)r   r   r   rp  rW   rg   r	   rn  rX  rp  rW  r  rq  r   r  r  r9   r  rC  r=  r  r  r   r   r   r   rl    s   >!$+rl  c                   @   sn   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< dZ
eed< dZeed< dZeed	< dS )
CmfUiFullPathNr   rM   r   rL   r   sharelink_hashvfr=   )r   r   r   r   r   rk  rM   r   rL   r   r  r  r=   r   r   r   r   r    s   
r  c                   @   sv   e Zd ZU dZeed< dZeed< ej	e
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< dZeed< dS )CmfUiMenuNodeNr  Fr   )default_factoryrd  r  T
allow_movechildren_countr  r  )r   r   r   r  r   rk  r   r  dataclassesrJ   r5   rd  r  r5  r  r  r  r  r   r   r   r   r    s   
r  c                   @   s~   e Zd ZG dd deZedd Zedd Zee	ddd	Z
ed
d Zee	edddZedd Zedd ZdS )r   c                   @   s   e Zd ZdS )zUbqlConverter.UBQLParseErrorN)r   r   r   r   r   r   r   UBQLParseError)  s   r  c                 C   s   dd l }d|krVt||s2| d|j d| t||}t|tjjsNd S |	 S t
 }|dd }d}|tjj tjgD ]8}t||rd}t||}t|tjjr||	  q|s| d| t|S )	Nr   r/   u   У модели u    не найдено поле rk  FTu0   Не найдено поле у моделей: )	itertoolsrX   r  rQ   r]   rV   r   r1   r  r:  r   r   chainr   rW   r   ZCmfGanttTaskr6   r5   )r<   rj   Z
field_pathr  rJ   r  Zright_field_nameZfound_field_flagr   r   r   _get_field_model_list,  s(    



z#UbqlConverter._get_field_model_listc                 C   s   t jt jt jt jt jt jt jt jt j	t j
t jt jt jt jt jt jfD ]*}||krRqD|j|d}|rD|jj  S qD|D ] }|j|d}|rt|jj  S qt|S )Nr  )r   r   ZCmfListr   r   Z	CmfStatusr  r0  Z
CmfOrgUnitZCmfRoleZCmfWorkflowZCmfTagZCmfRelationOptionZCmfLogicTyper   Z
CmfCompanyZCmfActivityr#   r   rf   )r<   r   
model_listrj   r   r   r   r   _convert_code_to_uuidJ  s0             z#UbqlConverter._convert_code_to_uuid)r   c                 C   s  d}d}d}d}|D ]2}d|kr"qt jd| d d| d | t jd} q|  } | d d	krhd	|  d
} | D ]p}|r||7 }||krl|dd  |kr| }||7 }d}d}ql|dkrd}|dkr| r||7 }ql|}|}ql|dkr| }|sT|dkr$|d d
kr$|d dkr$ql|d	krJ|rJ|d d
krJ|d7 }||7 }ql|d dkrx||7 }||7 }d}ql|dks|dkr||7 }||7 }d}ql| |kr| }|d| d 7 }||7 }d}ql||7 }ql|S )uU   
        Расстановка кавычек в UBQL без кавычек
        r   )r  rf  rl  zNOT LIKEr  z	NOT ILIKEr  zNOT SIMILAR TOr  z
NOT EXISTSr  r  r  z([^"'])z\1"z"\2)flagsr   []r   rk  ,)"')r  r  r  )r  r  )g.current_userg.now()g.date())TrueFalseNoner  )ra  r*   Ir  upper)r   rc  Z	cur_tokenZcur_string_symbolZorm_operatorsZoperr2  r   r   r   
quote_ubqlb  sv    &

&

zUbqlConverter.quote_ubqlc                  C   s   ddgddgddgddgd	d
gddgddgddgddgddgddgddgddgddgddgddgddgd d!gd"d#gd$d#gg} t d% | D ]^\}}t|}t d& t | t d' t | ||krt d( t | t d) t   t   qd S )*Nu     [  OR  , ["alarm_date", <, g.now()  ], [name, like,    "Вася Пупкин    "], [parent.agile_story_points, ==, "None"], [cf_val, ==, True], [executors, IN, [n.krat@carbonsoft.ru, v.sdf@gmail.com]]]u   ["OR",["alarm_date","<",g.now(),],["name","LIKE","Вася Пупкин    "],["parent.agile_story_points","==","None"],["cf_val","==",True],["executors","IN",["n.krat@carbonsoft.ru","v.sdf@gmail.com"]]]z[]]][][][]][]]z[]]],[],[],[]],[]]z[name, =, "[qwe, =, 'test']"]z["name","=","[qwe, =, 'test']"]z[name, =, Valsya Poopkin's]z["name","=","Valsya Poopkin's"]u   [name, like, Вася]u   ["name","LIKE","Вася"]zname, =, "vasya"z["name","=","vasya"]z[name = "vasya"]z[name     =       "vasya"]z'    [    name    =   " ilike  "   ]    z["name","="," ilike  ",]z*[[ name = "ilike" ],[name = "ilike" ]]    z-[["name","=","ILIKE",],["name","=","ILIKE",]]uM   [OR, ["alarm_date", <, g.now()], [name, like, "Вася Пупкин    "]]  uM   ["OR",["alarm_date","<",g.now()],["name","LIKE","Вася Пупкин    "]]uC   ["alarm_date", <, g.now()][name, like, "Вася Пупкин    "]uF   ["alarm_date","<",g.now()],["name","LIKE","Вася Пупкин    "]u   [responsible.name like %Вася%] [epic IN [EPC-1624993444 EPC-1624993246 EPC-1624993221 EPC-1624993102 EPC-1624986171 EPC-16249628604 EPC-16249628009 EPC-16249627823]]u   ["responsible.name","LIKE","%Вася%"],["epic","IN",["EPC-1624993444","EPC-1624993246","EPC-1624993221","EPC-1624993102","EPC-1624986171","EPC-16249628604","EPC-16249628009","EPC-16249627823"]]zname like """qwe"s"""z["name","LIKE","""qwe""s""""]u   name "like" %Вася%u   ["name","LIKE","%Вася%"]z+cache_status_type NOT IN ['CLOSED', 'OPEN']z0["cache_status_type","NOT IN",['CLOSED','OPEN']]z-cache_status_type "NOT in" ['CLOSED', 'OPEN']z-cache_status_type 'NOT IN' ['CLOSED', 'OPEN']z0["cache_status_type",'NOT IN',['CLOSED','OPEN']]u,   name "like" %Вася% name2 like %Петя%u<   [["name","LIKE","%Вася%"],["name2","LIKE","%Петя%"]]u-   name "like" %Вася%, name2 like %Петя%%   Тесты конвертера UBQL:UBQL: RES:    Должно быть:   ОШИБКА!!!)rV  r   r  )
test_casesr   Zubql_convertedrc  r   r   r   test_quote_ubql  s    d
zUbqlConverter.test_quote_ubqlr   c              
      s   t |}|dd}|dd}|dd}t|}fddttd	 fd
d z|} |}W nB jk
r } z"tj	d|j
d  d d }W 5 d }~X Y nX |S )Nr  z'__G_CURRENT_USER'r  z	'__G_NOW'r  z
'__G_DATE'c                    s  t | trt| } t | ts | S d}t| dkrt | d tr| d  dkrRd}t | d tr| d  dkr| d  dkrd}t| d	krt | d tr| d d
kr|s| }| d }|}|r| d }|s|S t |tr| d dkr0g }|D ]}| | q| d | d |g}nNg }|D ]2}d| d krV|| n||| q8| d | d |g}n$d|kr| d | d ||g}|S |S g }	| D ]}
|	 |
 q|	S )NFr-  r   zorder byr  Tr   orderbyr,  )r  r  r  r   )	r!   r4   r5   r  r   r+   r  r_   r  )r   Zskip_orderbyZblqrA   r  valZexists_filterZ_valZ
tuuid_valsr   r   )_recursive_ubql_processr<   rj   r   r   r  A  sL    

.2
z7UbqlConverter.ubql2bql.<locals>._recursive_ubql_processr   c                    s   t | trt| } t | ts | S t| dkrzt | d trz| d  dkrzt | d trz| d  dkrzdg| dd  } t| dkrt | d tr| d  dkrʇ fd	d
  | dd }dd|gS g }| D ]}|| q|S )u  
            Вычленяем из ubql конструкции сортировки.
            Order by на выражение только один
            ["order by", "=", "-cmf_created_at"]
            ["order_by", "=", "name", "cmf_created_at"]
            ["order by", ["-cmf_created_at", "name"]]
            ["order", "by", "-cmf_created_at", "name"]
            ASC DESK - не поддерживаем! Специально уходим от SQL-формата
            r-  r   r  r   r  r  Nr  c                    sF   g }| D ]8}t |tr&| | q|dkr2qq||  q|S )Nr   )r!   r5   rI  r_   r+   )Z
field_listZ_resrA   rec_parse_order_byr   r   r    s    
zTUbqlConverter.ubql2bql.<locals>._recursive_ubql_order_by.<locals>.rec_parse_order_byr   )r!   r4   r5   r  r   r+   r_   )r   r  r   r   )_recursive_ubql_order_byr  r   r  y  s$    

**
z8UbqlConverter.ubql2bql.<locals>._recursive_ubql_order_byu&   Ошибка обработки UBQL: r   u   . UBQL отключен)r   r  rI  astZliteral_evalr5   r  r   r   r   re   )r<   r   rj   Zfilter_ubqlZ
filter_bqlr   r   )r  r  r<   rj   r   r   5  s    

8.zUbqlConverter.ubql2bqlc                 C   s  ddddgddddgddd	ggggd
dddgddddgddd	ggggddddgddddgddd	ggggddddgddddgddd	ggggddddgddddgddd	dgggggdd gddddgddddgddd	dgggggddddgdddddggddd	dgggggddddggddddggdddd ggg}t d! |D ]f\}}| |tj}t d" t | t d# t | ||krt d$ t | t d% t   t   q8d S )&NzZ[['name', '=', 'test'], ['OR', ['parent', '=', 'evateam'], ['parent.name', '=', 'test2']]]r=   r   Ztestr  r   z/CmfProject:6597795c-95ce-11ea-9023-6f4fdd48682bzparent.nameZtest2zh[['name', '=', 'test'], ['OR', ['parent.parent.parent', '=', 'evateam'], ['parent.name', '=', 'test2']]]zparent.parent.parentzf[['name', '=', 'test'], ['OR', ['parent.parent.name', '=', 'evateam'], ['parent.name', '=', 'test2']]]zparent.parent.nameZevateamzS[['name', '=', 'test'], ['OR', ['parent', '=', 'evateam'], ['name', '=', 'test2']]]z^[['name', '=', 'test'], ['OR', ['parent', '=', 'evateam'], ['name', '=', ['test2', 'test3']]]]Ztest3za[['name', '=', 'test'], ['OR', ['bad_field', '=', 'evateam'], ['name', '=', ['test2', 'test3']]]]zb[['name', '=', 'test'], ['OR', ['parent', '=', 'RANDOM CODE'], ['name', '=', ['test2', 'test3']]]]zRANDOM CODEzn[['name', '=', 'test'], ['OR', ['parent', 'IN', ['evateam', 'activecrm']], ['name', '=', ['test2', 'test3']]]]r  z/CmfProject:8e97dfe2-7113-11eb-b9c1-7571d63a6e0dz!['cmf_modified_at', '<', g.now()]r  r   Z__G_NOWz"['cmf_modified_at', '=', g.date()]Z__G_DATEz(['cmf_modified_by', '=', g.current_user]r   Z__G_CURRENT_USERr  r  r  r  r  rV  r   r   r   r<   r  r   r   rc  r   r   r   test_ubql2bql  s^    ""&%
zUbqlConverter.test_ubql2bqlc                 C   s   ddddgggdddddgggdddddgggd	ddddgggg}t d
 |D ]b\}}| |tj}t d t | t d t | ||krt d t | t d t   t   qNd S )Nz$["order by", "=", "-cmf_created_at"]r  r   r  z+["order_by", "=", "name", "cmf_created_at"]r=   r  z)["order by", ["-cmf_created_at", "name"]]z*["order", "by", "-cmf_created_at", "name"]u.   Тесты конвертера UBQL order by:r  r  r  r  r  r  r   r   r   test_ubql2bql_oreder_by  s4    
z%UbqlConverter.test_ubql2bql_oreder_byN)r   r   r   r  r  ro  r  r  rq  r   r  r  r5   r   r  r  r   r   r   r   r   (  s   

Z
wz
7r   )Er  r  rC  r  r   rV  r   r   Zcollections.abcr   r   r   	functoolsr   typingr   r	   r
   r   typesr   base64r  Zredis.exceptionsr  r  r   Z
sqlalchemyr   Zsqlalchemy.ormr   Ztransliterater   Z
cmf.fieldsr   r   Zcmf.util.immutablesr   r   r  r   Zcmf.base_errorr   r   r   r   r   rl   ra  r  r)   rZ   r"   r-   r3   r.   ZTypeVarrs   rt   r6  r  r  r  rW   rn  rl  r  r  r   r   r   r   r   <module>   s   

v                     -;*             `B  