U
    %e                    @   s@  d dl 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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 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"G dd de"j*j+Z,G dd de"j*j+Z-dZ.e/0dZ1i Z2dd Z3dd Z4G dd de5Z6e7dddZ8G dd de6d Z9G d!d" d"e9Z:G d#d$ d$e9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.Z@ejG d/d0 d0ZAejG d1d2 d2eAZBG d3d4 d4ZCdS )5    N)	dataclass)OrderedDictdefaultdict)Mapping)deepcopy)	lru_cache)ListDictOptional)
MethodType)	LockError)desc)aliased)translit)*)imutable_deep_copymutable_deep_copy)cmfutilc                   @   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   captionr.   fields)reversedr   r,   r/   r   typetupler.   listZ	FieldDataupdatekwargsbaseCmfTypeMetasuper__new__)clsnamebases	namespacer/   base_cls
field_name	field_clsr$   r%   Znew_type_namespace	__class__r   r   r9   @   s4    




zBaseModelMeta.__new__c                 C   s<   | j D ]&}t|tr|j| }r|  S qt|| d S N)__mro__r   r,   r/   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 )Nr/   )ui_name	ui_modulecode_prefixu   Заполните поле     в классе )rJ   rL   r-   r&   )r+   r   	tablename
class_nameprimary_key__dp__ui_metaabstract
issubclass	CmfEntityhasattr
ValueError_unique_fields_cache
setdefaultdictgetattrr/   r   Zinstance_classclass_full_nameappenddir
startswithui_meta_skipr   propertycallable)r:   argsr5   r/   rH   Z_unique_field_cachevalueZ_cached_clsr?   r@   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.baserf   data_sourcesDEFAULT_DATASOURCErQ   r!   )r:   rf   rg   Zdp_r   r   r   dp   s    
zBaseModelMeta.dpc                 C   s   | j j| S rC   )rk   data_driverdp_modelr:   r   r   r   rm      s    zBaseModelMeta.dp_modelc                 C   s
   t | jS )u!   метаданные модели)r+   r   rn   r   r   r   	snakename   s    zBaseModelMeta.snakename)r   r   r   r   r9   rI   re   ra   rk   rm   ro   __classcell__r   r   rA   r   r,   ;   s   !3

r,   BM	BaseModel)Zboundc                   @   sD  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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dZdZdZdZ dZ!dZ"e#dd Z$dddZ%dd Z&dd Z'dd Z(dddZ)dd Z*dd Z+dd Z,e-dd Z.e#d d! Z/dd"d#Z0dd$d%Z1dd&d'Z2d(d) Z3d*d+ Z4e#eed,d-d.Z5e#dd0d1Z6e#dd2d3Z7e#d4d5 Z8d6d7 Z9e#d8d9 Z:e#dd:d;Z;dd<d=Z<e#dd>d?Z=e#de>d@dAdBZ?e#e>d@dCdDZ@e#deAd@dEdFZBe#e>dGdHdIZCddJdKZDddLdMZEe#eFdNdOeGd@dPdQZHe#e>d@dRdSZIe#ddTdUZJe#dd@eKeL eLdVdWdXZMe#dd@eKeL eLdVdYdZZNe#d[d\ ZOe#dd@eKeL eLdVd]d^ZPe#ddd_d`daZQe#dd@eKeL eReL dVdbdcZAe#dd@eKeL eRdVdddeZSe#ddGdfdgZTe#dd@dhdiZUe#ddGdjdkZVe#dldm ZWe#ddndoZXe#dee>edpdqdrZYe#dsdt ZZe#ddudvZ[e#dwdx Z\ddzd{Z]d|d} Z^d~d Z_dd Z`dd Zadd Zbdd Zcdd ZddddddZedd Zfdd ZgdddZhdd ZidyddddZjdd Zkdd ZlemdddZndd ZodddZpdd ZqdddZrdddddddZsddddZtdd Zudd Zvdd Zwdd Zxdd ZydddZze#ddddddZ{e#dd Z|dZ}e#dd Z~e#dd ZddddÄZe#dddĜddƄZddȄ Zemddʄ Zddd̄Ze#ddd΄ZddЄ ZdS )rr   NTFr   r   acl_typeacl_allow_createacl_static_user_write_fieldsacl_static_owner_write_fieldsacl_static_self_write_fields)Z$menu_tree_parent_idmenu_tree_ordernomenu_tree_node_is_branchrR   r`   rN   r/   ri   rS   rk   rm   ro   valuesZvalues_dictrP   db_nameis_recursion_savedisable_simpleno_aclacl_default_user_policyrt   Z
acl_staticru   rv   rw   essential_child_modelsdisable_auditc                 c   s<   ddl m} t| D ]}t|trt|| r|V  qd S )Nr   models)cmf.includer   varsry   r   r1   rT   )r:   r   rh   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 rC   )r/   rO   instance__dict__datetimenowtimezoneutcr   CmfDateauto_nowauto_now_adddate_value_oldCmfDateTimer   r   __func__r3   rZ   copy)rF   r?   r@   emptyrH   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   )
r/   r!   simple_objectrV   r[   virtualZCmfOrmImplicitLazyLoadrO   r   rE   )rF   rG   r@   r   r   r   rI     s    zBaseModel.__getattr__c                 C   sV   | j |}|rD| j|d }dkr6| j||dd}|| | nt| || d S )N.Tr   )r/   r!   r   r   setobject__setattr__)rF   r$   r%   r@   rH   r   r   r   r   &  s    zBaseModel.__setattr__c                 C   s
   d| _ dS )u   
        Помечаем что обьект уже создан в бд
        Эту опцию нельзя использовать в бизнес логике
        TN)_BaseModel__exists_in_dbrF   r   r   r   mark_exists_in_db/  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   cmf
base_errorCmfOrmError	wrap_saverY   gen_idr[   gr/   r   r   
is_changedr{   setattr)rF   r   r   r5   ir$   r%   r   r   r   re   6  s2      zBaseModel.__init__c                 C   s   | j  }|d= |S )Nsave)r   r   )rF   r"   r   r   r   __getstate__V  s    
zBaseModel.__getstate__c                 C   s   || _ |   d S rC   )r   r   )rF   stater   r   r   __setstate__[  s    zBaseModel.__setstate__c                 C   s
   t | jS rC   )hashr   r   r   r   r   __hash___  s    zBaseModel.__hash__c                 C   s
   t | jS rC   )r1   rk   r   r   r   r   rk   b  s    zBaseModel.dpc                 C   s6   t |tks|j}n|}|dd }ttjj| S )N:r   )r1   strrd   splitr   r   includer   )r:   r   ZtuuidrO   r   r   r   get_model_by_idf  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>t  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   v  s     
  N)r/   r3   rF   r   r   r   r   r   keyso  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   z  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   ry     s    zBaseModel.valuesc              
   C   s:   zt | |W S  tk
r4 } z
t|W 5 d }~X Y nX d S rC   )r[   rE   KeyError)rF   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 rC   )r   rE   r   )rF   r   rd   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   bqlr   r   r   r     s    zBaseModel.ubql2bql   c                 C   s   ddl m} ddg}	|s|r.tj||	dd}nP|rr|rrt|}
|
sT|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parentTr/   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   rJ   coderK   	parent_idrupobjr   r/   rO   rh   r   r   r   _get_ui_full_path_obj  s     

zBaseModel._get_ui_full_path_objc                 C   sb  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|
 d|j d| d| d|j d|j | dt|jjd }|S )Nr   r   r   r   )r   rJ   r   rK   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   rO   check_project_role_access_acl_check_readCmfPermissionErrorr   r   r   rK   is_not_nullr/   r   rJ   r)   r   r   Ztranslit_stripr;   rd   )r:   r   rJ   r   rK   r   r   r   r   r/   Ztmp_ui_moduleZtranslit_nameZtmp_parent_idZrup_txtr   urlr   r   r   get_ui_full_path  s0    
 $D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   rO   r   rJ   r   r   )r:   rc   r5   r   r   r   r   r   public_get_ui_full_path  s
    
z!BaseModel.public_get_ui_full_pathc                 O   s   d S rC   r   rF   rc   r5   r   r   r   public_none  s    zBaseModel.public_nonec                 O   s   d S rC   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   r3   r2   lenrT   r1   r   r   rr   
CmfRelBaser   r   r   r   is_model_obj  s    0z&BaseModel.asdict.<locals>.is_model_objr/   c                    s   g | ]}|j f  qS r   get_values_dictr   r   paramsr   r   r     s     z$BaseModel.asdict.<locals>.<listcomp>)rZ   r   r3   r2   rT   r1   r   r   rr   r   r/   CmfTypeasdict)rF   r   r/   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   rZ   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   0  s     z-BaseModel.get_values_dict.<locals>.<listcomp>.rO   )r   )r   r	  r   rZ   r!   r   r   r/   
CmfM2MBaseCmfBackrefBaserd   CmfRelationBaser   r   rO   )rF   r/   r	  rr  r?   Z	field_val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visiblerO   fr  r   r   filter_visibleE  s
    

z-BaseModel.meta_fields.<locals>.filter_visible)r/   ry   filter)r:   r  r/   r  r   r  r   meta_fields?  s
    

zBaseModel.meta_fieldsr   c              	      s  t t}t t}g }d|kr d}t t}	|si |	d< |rt| trRi |	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r4d}|t	|
k r|
|d   dkrq|d7 }q|
d|  }||||f< t
|| |||< ||
= qq|
drRt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r>| 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sl|rR|j|rR|dkrR||ji }t|||df  t|||df  qRnL| D ]B\}}|jdks|r|j|r|dkr||ji  qĐq|D ]}
|
|kr||
= q|	 D ] \}
}||
i }t|| q0| D ]\}
}| j|
}|rZt|trZ| }|stg}i }|D ],}t|}|j|||
||d t|| q|  t|| qZ fd d!  |}|d"krtjj d#| d$dd% dS )&u  
        Разворачиваем мета-правила
        - вначале *, **, ***, включая <prefix>*, ... - пока маски только для префиксов
        - затем -field_name
        - затем +fild_name - deprecated
        --Fr   r   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   intrZ   rT   CmfModelrU   r3   r   endswithr   maxr_   ZCmfDeprecatedErrorr]   r   r/   ry   	load_moderO   rY   r
  r  r    r  r!   r   related_modelsr   _fields_load_expandclearr   r   r   )r:   r/   r$  r%  r&  r'  Zfields_prefixesZasterisk_specsZminus_fieldsZplus_fieldsr?   
field_specZcntprefixrH   Zasterisk_cntZplus_field_specrelated_model_listZfield_spec_newrelated_modelZfield_spec_subZfield_countr   r)  r   r1  O  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)r3   r   	partitionrY   r4   ry   _fields_split)r:   r/   Zfull_field_namer3  r?   r&   Zsub_field_namer   r   r   r8    s    zBaseModel._fields_splitc                 C   s   ddl }|  }|rg }ntj}dd |p,|D }| | | j||d |  | }|dkr|t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_FIELDSr8  r1  r   debug)r:   r/   r$  r:  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)r/   ry   rO   extendZget_required_fieldsr	  r    r   r!   rT   r   r0  rU   _enrich_load_plan)
r:   r	  required_fieldsrH   Zrequired_fflr?   r3  Z	field_fflr5  r6  r   r   r   r?    s$    



zBaseModel._enrich_load_planc                 K   s   | j | |f|S rC   )_load_fields_build_load_plan)rF   r/   forcer5   r   r   r   load_fields5  s    zBaseModel.load_fieldsc                    s   ddl m} | jstd dS t|}ttdfdd| |rHdS | jsZtd dS t|| j j	| j
d||d	}|ftttd
 fdd  | | | S )u   
        Прогрузим поля по правилам fields
        Вложенные объекты уже могут быть прогруженны, важно догрузить только то, чего не хватает.
        r   r   u=   SKIP!!! попытка _load_fields при not __exists_in_dbN)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  rd   r
  r  r   r   AssertionError)r   rE  Zloadedr?   rH   Zlist_loadedZrel_instance)	strip_fflr   r   rG  F  s(    


z)BaseModel._load_fields.<locals>.strip_fflT)include_deleted_oncer	  r   )dst_instancesrc_instancerE  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 поля запросили для загрузки, но не загружены: .)rE  c                 S   s   i | ]}|j j|qS r   )r   rd   )r   Zsrc_ir   r   r   r9    s      z@BaseModel._load_fields.<locals>.merge_fields.<locals>.<dictcomp>N)r   r   printr   rd   r   r   r3   rZ   r   r
  apply_changesr  r   rA  r!   r  r   r   rF  )	rI  rJ  rE  Zmissing_fieldsr?   Z	src_fieldZ	dst_fieldZsrc_instancesZdst_i)merge_fieldsr   r   rM  t  sR    



 

 

z,BaseModel._load_fields.<locals>.merge_fields)r   r   r   rK  r   rr   rZ   r   rO   _getr   )rF   r	  r   r5   r   Znew_instancer   )rM  rG  r   rA  9  s2     
    4
zBaseModel._load_fieldsi  )maxsizec                 C   s    |  |pi }| | t|S rC   )r	  r?  r   )r:   r/   r	  r   r   r   _build_load_plan_for_tuple  s    
z$BaseModel._build_load_plan_for_tuplec                 C   s   t |}| | |S rC   )r   r?  r:   r/   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   rZ   rR  rP  r2   sortedrQ  r   r   r   rB    s    

zBaseModel._build_load_plan)r:   r   c                O   s   |  |}| j|d|i|S x   
        fields - список мета-правил для указания какие поля грузить
        r	  )rB  rN  r:   r/   rc   r5   r	  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 rU  Nr   Fvirtual_cache_timelifer/   simple)r	  mapper)rB  r   r[   r!   rN  r:   r/   rc   r5   r	  r?   rH   r   r   r   sget  s    
zBaseModel.sgetc             	   O   sP  | j }d}	d}
|jr|jjdkr|jjrtjjdgdd|jjggddd|j	jgddd ggd	d|gd
d|gdd|jjjggd}|r|j
j}|j
j}
|j
j}	t|pg }|d |r|dg }|D ]}||dg  q| |}| j||d|d|}|rL|jrd|j |_||_|
|_|	|_|jsLttdrLtj|}|S )Nr   r   ztarget.ui_form_jsonZlogic_typesINORactivity=is_public_formr   ui_form_schemer/   r  cmf_deletedui_group_fieldsr/   rY  )r	  rZ  r   zDELETED CmfAutomationUiForm)ui_formr   rO   rb  r   ZCmfUiFormSchemeRuler\  
logic_typer   r_  targetui_form_jsonr;   r   r   addr!   r4   rB  rN  rd  ui_form_nameui_form_coderV   rf  Zui_get_hook)r:   r/   tmp_objtmp_is_public_formtmp_ui_view_formtmp_include_deletedrc   r5   rj  rm  rl  Zui_form_scheme_ruleZ
fields_setgroupsZ
group_datar	  retr   r   r   _ui_form_get  sH    


zBaseModel._ui_form_getc          	      O   s   | dd}| d| j }d}d|kr8|d }|d= | j|ddddd	gd
d|}|rj|jd
krjd
}| j||||||d|}|S )rU  ra  Fr   r   rh  r_  zparent.ui_form_schemezparent.logic_prefixrd  Tr   )r/   rn  ro  rp  rq  )r!   rJ   r)   r\  rd  rt  )	r:   r/   rc   r5   ro  rp  rq  rn  rs  r   r   r   ui_get  s(         zBaseModel.ui_get)r	  rH  c                O   s~  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|}|szd|krz|	d}t
|tr|j}|dk	rzd|krz| tjkrttd	rtjj|d
gd}	|	rzdd|	jg|d< | jj|d|i|}nd| tjkr$nV|sz|dd }
|
 rzt|
dkrzd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
        rd  r   FNrX  r	  r   r   CmfTaskCodeHistorytask_id)r   r/   r   r`  r  r"  LIKEz%-)r/   r!   rY   r[   r   jscache_timeliferX  minrk   popr   r  rd   r   r   rV   rv  r\  rw  r   isdigitr   )r:   r	  rH  rc   r5   r?   rH   instr   Ztask_code_historyZcode_numberr   r   r   rN  1  sD    


zBaseModel._getc                O   s   |  |}| j|d|i|S rT  )rB  _listrV  r   r   r   r3   d  s    
zBaseModel.listc                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 rW  )rB  r   r[   r3   r  r[  r   r   r   slistl  s    
zBaseModel.slistc                O   s   t | dr |ds |dd t | drJ|dsJ|dsJ|dd |r|D ]<}t| |d}t|ddrRtjs~|jt_qRttj|jt_qR| jj	| f|d|i|}|S )	   
        Т.к. по show definition люди придут за гайдом по использованию filter именно сюда, дублирую доку
        https://bcrm.carbonsoft.ru/project/Document/DOC-000282
        rd  r   Fcmf_archivedZinclude_archivedNrX  r	  )
rV   r!   rY   r[   r   rz  rX  r{  rk   r3   )r:   r	  rc   r5   r?   rH   Z	inst_listr   r   r   r  z  s    
zBaseModel._listc                O   s"   |  ddg}| j|d|i|S )rU  r  r   r	  )rB  _countrV  r   r   r   count  s    zBaseModel.countc                O   s@   t | dr |ds |dd | jj| f|d|i|}|S )r  rd  r   Fr	  )rV   r!   rY   rk   r  )r:   r	  rc   r5   rs  r   r   r   r    s    zBaseModel._countc                 O   s   | j j| jf| S rC   )rk   query_deprecatedrm   r:   rc   r5   r   r   r   r    s    zBaseModel.query_deprecatedc                 K   s   | j |f|S )u  
        Метод-обёртка field_options_list для вызова с подстрокой поиска, чтобы избежать кеширования на фронте.
        Сейчас фильтрация идёт на фронте, строка поиска не передаётся. Вероятно этот метод никогда не понадобится.
        )field_options_list)r:   r%  searchr5   r   r   r   field_options_search  s    zBaseModel.field_options_search)all_optionsmodels_filtersr  c              
   K   s  | j |}|s(td| d|  | ||	s0g }	g }|r@d|d< t|tj jr|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}|st|dr|dddgg}|rt|dk rLd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|rd |ksttd!d" |rd|d d#|gg}||g}|jf d$|i|}t|
d	 | d	}t|
d% |
d	  t| |}||| g}||7 }|d	 |krbq||jf ||||d&| t||
d% |
d	  kr qqn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   Не нашел поле rM   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, показали первые 100Z
cmf_hiddenr`  Fr"  r^  r;   ILIKE%z% r   r   Zparent_taskANDzparent_task.namer   r]  z	task.epicztask.subproject	CmfPersonZrolesc                 S   s
   |  dS )Nzroles.r_   r  r   r   r   <lambda>      z.BaseModel.field_options_list.<locals>.<lambda>EXISTSr  r   )r/   r  sliceorder_byu)   Некорректный тип поля )r/   r!   rW   rT   r   r   r[   r0  r   r   rO   default_options_filterrV   r   anybuiltinsr  r  r.  r{  r>  r3   )r:   r%  	object_idZobject_fieldsmodels_listr  r/   r  r  r  r  r  Zinclude_hiddenr5   rH   resultsr  r0  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   rH   rG   Zitem_objr   r   r   m2m_add_values  s    

zBaseModel.m2m_add_valuesc              	   C   sv   | j pg }| }|r|}|r,|r,|dg7 }|D ]@}|dr^|tt| j|dd  }q0|t| j|}q0|S )Nr   r   r   )orderingr   r_   r  r   r[   rm   )r:   queryr  r  Zorder_fieldsr   r   r   r   order_query  s    


 zBaseModel.order_queryc                 C   s   | j  dt  S )Nr   )rO   Zuuid1rn   r   r   r   r   7  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   ry   r   r   rd   rr   r[   flush)rF   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   O  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   P  s      )r   r   rD  )rF   r/   r   r   r   _load_changed_fieldsJ  s    zBaseModel._load_changed_fieldsc                 K   s   d S rC   r   rF   _kwargsr   r   r   before_save_hookT  s    zBaseModel.before_save_hookc                 K   s   d S rC   r   r  r   r   r   before_save_data_hookW  s    zBaseModel.before_save_data_hookc                 C   s   g S rC   r   r   r   r   r   save_preload_fields[  s    zBaseModel.save_preload_fieldsc                 C   s   |   }|r| | d S rC   )r  rD  )rF   r  r   r   r   save_preparea  s    zBaseModel.save_preparec                 C   s   d S rC   r   r   r   r   r   check_simple_permf  s    zBaseModel.check_simple_permc                 C   s   d S rC   r   r   r   r   r   _check_project_permi  s    zBaseModel._check_project_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  )ry   r   r   r   r   r   r   r   r   r   rd   r   r   r   r[   r   r/   cmf_modified_by_idis_nullr   r   cmf_author_idr   r  
_save_data)rF   r  r  rc   r5   rH   r   r   r   r   r   _save_importl  s.    



zBaseModel._save_importc                    s   ddd fdd
}|S )NF)r  save_importc                    s  d _  jddD ]D} | jr"qt | jtjjs8q | j | j	krd | _qt
jrbd} t
jsp| sp|rdt
_t j f|dt
ji|}| rdt
_|ddrt trĈ jrĈ   |rdt
_    jrd _   nt j f|ddd|    t
jdkrL   t trD jrD       jf | t j f|d| i| d _d _     S )NTr  Fr  r  )r  Z
invalidate)r{   r   r   rT   rB   r   r/   CmfJsonr   r   r   Zsave_only_data_hackr1   r  r!   r   rU   r  r  r   import_originalr  disable_permissionsr  _calc_root_parentr  r  r   r  )r  r  rc   r5   r$   r  r   r   r   save_with_flush  sH    	
 
 z5BaseModel.save_flush_wrapper.<locals>.save_with_flushr   )rF   r  r  r   r   r   save_flush_wrapper  s    NzBaseModel.save_flush_wrapperc                 C   s   |  | j| _d S rC   )r  r   r   r   r   r   r     s    zBaseModel.wrap_savec                 C   sN   | j j|d}| jddD ].}|jdkr*q|jdr8qt||j|j q|S )Nr   Tr  )r   r   cmf_created_atr   r   _id)rk   rh   ry   rO   r-  r   rd   )rF   r   resrH   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  )ry   r   )r  r  Z	max_depthrH   r5   rF   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, (, r   ))r:  _acl_check_writeverbose_namer   r1   rk   creater  r4   ZCmfOrmUniqueErrorr   r   r   logging	exceptionZCmfOrmIntegrityErrorr   r<  rK  rO   r   r/   )rF   r  r  rc   r5   r  r:  startr  r   r   r=  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   )ry   r   r   import_moder   r   r   r   r   r   r   r   rd   r   r   r   r[   r/   r  r  r   r   r  r   r  r  r  )rF   rc   r5   rH   r   r   r   r   r   r   "  s4    



"zBaseModel.savec                 C   s   |    | j  | S rC   )r   rk   Zcommitr   r   r   r   _test_save_commitC  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)r/   TECHCOM_nocacher   r  N)r   r   r   r   r   CmfAccessListZCmfAccessRule
CmfCommentr,  r   r  r[   sysinternr   rk  r   r  )r   r  r5   resultZskip_modelsrh   Zobj_datar   r   r   _build_relation_cacheH  s"     
"zBaseModel._build_relation_cachec                 K   s   t  }tjj| jkr|  d}zLz(td|  |j	f ddi| W n t
k
rj   t } Y nX W 5 tjj| jkr|j|  X d S )NNNNu-   Удаляем дочерний обьект rC  T)r   disable_aclr   r   r   r  	__enter____exit__r<  deleter  r  exc_inforF   r   r5   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)r/   r  r  r  r   r   )r  r   r   rd   rk  r   r   r   r  r3   r  r   r   )rF   r  r   r  r5   relation_cachechildren_id_setlevel
next_levelr   child_idcommentchildr   r   r   _children_recursion_deleteq  s4    


   
z$BaseModel._children_recursion_deletec                 K   sF   | j D ]:}t|}|jdgdd| gddD ]}| j|f| q,qd S )Nr   r   r`  T)r/   r  r  )r   r   r   r3   r  rF   r5   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   )rF   group_by_modelsr  r   r   r   list_children  s    zBaseModel.list_children)	recursiverC  r  r  c                O   sH  | 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| f||}
|   |
S )Nr   r   r  	CmfNotifyCmfAttachmentr  Fr  T)	skip_subsu   Нельзя удалить u1   , на него ссылаются потомкиr  r   )rD  rO   r!   r  r  ZCmfOrmHasReferenceErrorr  r   r,  logical_deleterd  rY   r   r  r/   rT   r   r
  r]   r[   r   r1   rk   r  r  )rF   r  rC  r  r  rc   r5   ZchildrenZ
m2m_fieldsr?   r  r   r   r   r    s4    


zBaseModel.deleter  c                O   sL   d| _ d| _|dd | j||}| jdkrH|r@| jf | n|   |S )uy   
        Восстановление из корзины логически удаленного объекта
        Fr  Tr  )rd  tree_node_is_branchrY   r   rO   _children_recursion_restore_essential_children_restore)rF   r  rc   r5   r  r   r   r   restore  s    
zBaseModel.restorec                 C   s   d S rC   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r/   r  r  r   N)r   r   r   r3   _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}|rjt }|D ]8}||kr*|| D ]"}||krLq>|| || q>q*|}qtjjjj	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   rd   rk  r   r   r   r  r3   r  r   r   )
rF   r5   r  r  r  r  r   r  r  r  r   r   r   r     s.    


 
z%BaseModel._children_recursion_restorec                 C   s  | j dkrd S | j dkrJtjtjkrJtjjd| j| dd td| j	 t
| toZ| jj}t
| tol| jj}| jrt
| to| jr| jjn| jj}nt
| to| jj}| j}| j dkr&t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rVd
}| jddD ]*\}}|jdkrB|dkrBd} qnqB|sxd S tjstjrd S tjtjkrd S tjjdd
drd S tjjdddgd}	|	j	jtjkr| js|tjj	krt| dr| j rt!| | j " #  d S tjjd|| dd | jr@tdntd| j	 d| zft
| t$jjon| j%j}
| jddD ]<\}}|jrq|tjj&d||||| j	j|| | j|
d
 q|W nR tk
r } z2|j'd| j	 f |_'tjjd| j| dd  W 5 d }~X Y nX d S )Nr}   systemr4   failoperatecmf_model_namer   Zresult_statusuO   Отказано в модификации системного объекта ZadminmessageZproject_adminFTr  r  r   )r   r   ==ZProjectAdminsr  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)(rs   r   r   system_personr   CmfAuditaudit_eventrO   r   r   r   rU   r  oldr,  r   rt   r   r  newr  check_admin_moder   r}   r  Zacl_admin_modeCmfPersonGroupr!   rd   Zcurrent_person__member_ofcurrent_userrV   r  r[   loadr  r   r  check_accessrc   )rF   r  obj_parent_idZobj_owner_idrO   r   Z
need_checkZchanged_field_nameZchanged_fieldZproject_admins_groupr  r?   rH   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)	r  r  r  r  r  r  r  r   r  u0   Отказано в чтении объекта r  r  )rs   r   rU   r  rd   r,  r   r   r   r  r  rO   r   r}   r  r"  r   r   r   rc   r  r  )
rF   r   r  r#  r  rO   r?   rH   rulesr   r   r   r   r   u  s6        
zBaseModel._acl_check_read)r/   save_kwargsr  c                O   sF   | ||}|si }| d||d< |jf | |rB| j |j|dS |S )Nr  r   )r!   r   r   )r:   r/   r&  r  rc   r5   r   r   r   r   r    s    
zBaseModel.createc                 C   s   | j S rC   )rR   rn   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   r?   Z
field_metar   r   r   r9    s   
 z-BaseModel.all_models_meta.<locals>.<dictcomp>r/   )rO   re  rg  r/   )	_all_models_metar   rS   rR   r   rg  r]   rO   re  )r:   _argsr  r  ZmodelClsZcustom_fields_metar   r   r   all_models_meta  s"    


zBaseModel.all_models_metac                 O   s4   t | dr |ds |dd | jj| f||S )Nrd  r   F)rV   r!   rY   rk   bulk_updater  r   r   r   r,    s    zBaseModel.bulk_update)r&  c                O   s   |    | j D ]}||kr qt| |}t|tjjtjjfrBqt|tr|j	s\|j
dkr|d d |krt| |d d ||  qt| |||  q|si }| jst| j t| drt| j | jf |S )Nr   r   )r  r/   r   r[   r   r   Z
CmfBackrefCmfGenericBackrefCmfTUUIDZforeign_keyrO   r   no_cacher   Zcache_obj_lock_getr   rV   r   r   )rF   r&  r*  r5   r?   	field_objr   r   r   r4     s&    

zBaseModel.update)r  r&  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   r3   r   r   r   r   r/   )Z
sub_filterZsub_sub_filtercheck_simple_filterr:   r  Z
key_valuesr   r   r3    s     z-BaseModel.upsert.<locals>.check_simple_filterT)r   r#  )
for_updater  r   u9   Ключ в фильтре upsert не уникален: r  r   r   r&  )r3   r   r   r   r   r4   )r:   r  r&  r*  r5   Zobj_listr   r2  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   r  : r  )rV   r1   r   r   r   r;   r   r   r   r   r   r   __repr__  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   rr   	from_jsonr   r   r   r   r     s     z'BaseModel.from_json.<locals>.<listcomp>r   c                 S   s   i | ]\}}|t |qS r   r8  )r   r$   r%   r   r   r   r9  $  s      z'BaseModel.from_json.<locals>.<dictcomp>r   T)r   r3   rZ   r/  Zget_cls_by_tuuid_strr   )r   r  r:   r/   r   r   r   r9    s    

zBaseModel.from_jsonc                 C   s:   |sg }i }| j ddD ]\}}||kr*q|j||< q|S )NTr  )r   r   )rF   r/   rs  Z	fieldnamerH   r   r   r   to_json)  s    zBaseModel.to_jsonc           
      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   r3   r	  rk   Z_load_extra_fieldsr   r/   r   rT   r  r  r!   CmfRelationZCmfM2Mrh   r   r   dump_data_dictCmfGenericRelationCmfGenericM2MrK  r]   )
r:   Z	upper_resr  r	  rG   Z	item_dictr?   r@   Zfk_modelr  r   r   r   r<  7  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   rr   r   r  r  )rF   otherr   r   r   __eq__t  s    

zBaseModel.__eq__)NNF)FN)NN)NN)NN)NNNNNr   N)NNNNNr   N)N)NN)N)NNTF)NN)NF)F)N)N)NNNNNFNNNNF)NN)r   )N)FN)FFF)T)N)N)N)r   r   r   ri   rS   Zfields_orderr  r  Zverbose_name_pluralr   re  rg  r0  r  r   customsmart_notifyZcache_inmemoryrs   r   __annotations__r~   rt   boolru   r   rv   rw   rN   r/   rP   r{   r|   iconr`   classmethodr   r   rI   r   r   re   r   r   r   ra   rk   r   r   r   ry   r   r   r   r   r   r   r   r   r  r   r  rZ   r1  r8  r3   r	  r?  rD  rA  r   r2   rP  rR  rB  Typerq   r!   r\  rt  ru  rN  r   r  r  r  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'  r)  r+  r,  r4   r5  r7  r9  r:  r<  r@  r   r   r   r   rr      sd  



	
 




'

"
0 "

 
/2 

                      e




Q

6!

*![
-



+

<)	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	gd
Z
ee	dddd	gd
ZejjejjddddZee	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d;d%d&Ze d<d'd(Z!e  fd)d*Z"e d= fd+d,	Z#d-d. Z$ fd/d0Z%d1d2 Z&d3d4 Z' fd5d6Z(d>d7d8Z)d9d: Z*  Z+S )?r,  us   Базовый класс, содержит стандартные поля для типовых объектов.T)r  )   Идентификатор объекта3   Автоматически генерируетсяFr.   r  nullablerP   readonlyr  u
   Авторr  r.   r  rN  r   u   Владелецu   РодительrU   r.   
base_modelr  u'   Последний изменивший)r.   r  rN  r   autor}   u   Кто захватил r!  )r.   r  rN  r   r/  r}   u   Дата захвата)r.   r  rN  indexr}   u   Дата создания)r.   rR  r   r  rN  rS  rM  u   Дата изменения)r.   rR  r   r  rN  rS  rM  r}   u   Дата просмотра)rR  r.   r   r  rN  rS  r}   u   Удален)r.   r  rN  r   rM  rS  u   Номер версииZ
CmfVersion)r.   r  rN  rS  r}   widgetr   c                 C   s
   t | jS rC   )r1   rz   r   r   r   r   rz     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   rV  r-   r   )r]   rD  r   r   
user_localrk  r[   r3   )	rF   r/   rW  r5   Zself_fieldsZperson_field_namer  r  ownerr   r   r   all_relation_persons  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 ].}| |j|j|j|jo|j| j	| j
d qj|S )N)r   r   rd  cmf_versionr  
cmf_importr  import_raw_jsonext_idr  )r.   r?   Zfield_qualnamerequiredr  rE  )r]   r/   ry   rO   r-  r.   r   rM  r  r  rE  )r:   fields_namer  r/   r?   rH   r   r   r   import_shop_fields	  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 )Nr  r   z:Classr   r   )rZ   r   r-  rV   r   r   r   r   r   r!   r8   r  )r:   rc   r5   r$   r%   rA   r   r   r   	  s    
zCmfModel.createc                    s6   |dkr|sg }|dddgg}t  j|fd|i|S )N)r   r   rV  rW  r  Tr  )r8   r  )r:   r%  r  r5   rA   r   r   r  -	  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%fr-  )rZ  r   r+  r   r   r   r   strftimer   r   r   r   _increment_version6	  s    zCmfModel._increment_versionc                    s   |    t j||S rC   )rc  r8   r   r   rA   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_ownerrV  r   )
rD  r   r  r   r   r  r   r]   rV   rV  )rF   r  perm_parentrX  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   rV  rd  re  c                 S   s   g | ]}|r|qS r   r   r   rX  r   r   r   r   o	  s      z'CmfModel.get_owners.<locals>.<listcomp>)rD  r   r  r   r   r]   r  rV   rV  r   r>  rg  )rF   rc   r5   ZownersrX  r   r   r   
get_ownersX	  s"     

zCmfModel.get_ownersc                    s*   | j s | jjr tj|  kr d S t  S rC   )r   r   r   r   r   rg  r8   r  r   rA   r   r   r  q	  s    zCmfModel._acl_check_writec           	      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`  )r  r^  tree_parentr  r  r/   )r,  r   rT   r   r   r/   r=  rO   r   rh   rU   rj  r   r  r>  r3   )	rF   r  r  r  r  rh   ZlinkedZfilter_r  r   r   r   r  x	  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   r!  r;   rd   r  r   r   r   get_project_name	  s    zCmfModel.get_project_name)NT)N)N)TF),r   r   r   r   r  r   Fieldr/  r   r=  r   r   r   r/   CmfSubclassedGenericRelationr   r   cmf_locked_byr   cmf_locked_atZCmfCreateDateTimer  cmf_modified_atcmf_viewed_atCmfBoolrd  Z	CmfBigIntrZ  ra   r   rz   rY  rF  r`  r  r  rc  r   rg  ri  r  r  rm  rp   r   r   rA   r   r,  ~  s   
   	
     

      

0r,  c                	   @   sB   e 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 )
BaseM2MModelTrJ  rK  FrL  u%   Родительская запись)r.   rS  u   Корневая записьN)
r   r   r   r}   rn  ZCmfM2MTUUIDr   r/  r   Zroot_idr   r   r   r   ru  	  s   
ru  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   r.   rM  r   r   r   r   description	  s   ry  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r8   re   rV   r;   Zleft_name_cacheZright_name_cacher   rA   r   r   re   	  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)rk   rl   r{  r0  rm   r1   r   r  joinright_idr   left_idr  r   rd   r  allr>  r  )r:   r   r  r*  r  rk   dd	model_clsdp_right_modeldp_left_modeldp_m2m_modelZdp_left_model_aliasedr  Zdp_right_model_aliasedr   r   r   select_related	  sJ    









zCmfGM2MModel.select_related
r   r   r   r   Z
CmfStr4096ry  re   rF  r  rp   r   r   rA   r   rv  	  s
   rv  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.descriptionrw  TNrx  r   r   r   r   ry  	  s   ry  c                    sV   t  j|| d|kr0t|d dr0|d j| _d|krRt|d drR|d j| _d S rz  r|  r   rA   r   r   re   
  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  )rk   rl   r   r   r  rh   r   r1   r{  rm   r  r}  r~  r   r  r  rd   r  r  )r:   r   r  rk   r  r}  Zleft_clsZ	right_clsr  r  r  r  r   r   r   r  

  s.    





zCmfM2MModel.select_related)Tr  r   r   rA   r   r  	  s
   r  c                	       s  e Zd ZU dZdZeed< 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dddddd Zeed!dd"dd#Zej jej j!d$ddd%Z"ee#d&ddd'Z$eed(dddd)Z%ee&d*dd+d,ddd-Z'ej jej jdd.dd/Z(ej jej j)d0ddg d1Z*ej jej jd2d3ddg d4Z+ej jej jd5ddd6Z,ej jej jd7dddd8Z-ej jej jd9ddd6Z.ej jej j/d:d dd;Z0dZ1g Z2d<gZ3ej jej j4d=dddd>d?Z5d@dA Z6dBdC Z7dDdE Z8 fdFdGZ9e:ddIdJZ;e<e=> dedKdLdMZ?e:dNdO Z@e:dPdQ ZAdRdS ZBe:ddTdUZCe:ddVdWZDe:ddXdYZEe:ddZd[ZFe:dd\d]ZGe:dd^d_ZHd`da ZIdbdc ZJeKddde ZLdfdg ZMdhdi ZNdjdk ZOdldm ZPdndo ZQdpdq ZRdrds ZSdtdu ZTddvdwZUd>dxeVdKdydzZWd{d| ZXd}d~ ZYdd fdd
ZZdd Z[ fddZ\d>dd fdd
Z]dddZ^dd Z_e:dd Z`e:dddddddZadd Zbdd Zcdd Zddd Zeddd fdd
Zfdd fdd
Zgdd Zhe:ddddZidddZjdddZke:dd Zlej jej jddddZmej jej jdddZnej jej jdddddZoej jej jdddd/Zpej jej j/ddd ddZqej jej jrdddd"dZsej jej jrddd"ddZtej jej jrddddZuej jej j!ddZvej jej jdddddZwdd ZxddĄ ZyddƄ ZzddȄ Z{dddʄZ|dd̄ Z}dd΄ Z~ddЄ Zddd҄ZddԄ Zddք Zdd؄ Z fddڄZ  ZS )rU   u   CmfEntity - базовый класс для типичных моделей подлежащих автоматизации на преприятии.

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

    class Task(CmfEntity): pass
    Nacl_parent_fieldz^DEL[0-9]+\s)delete_prefix_patternu   Имя объектаu   object.name - статичное поле для представления в ui, аналог repr, генерируем методом если не заданоT)r.   r  rS  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   Код в реальном мире из жизниrC   rx  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_encr8   cast)rF   rd   r  rA   r   r   r  H
  s    $zCmfEntity.code.cast)r   r   r   r.   rS  uniquerN  r  r  	log_levelr  rp   r   r   rA   r   r   @
  s   r   u   Системный объектu   Нельзя удалятьF)r.   r  rM  r   r  u
   Текстu   Текст сущностиu!   Добавить описание)r.   r  Zplaceholderu   Задачи сущностиr   r   )r.   r   backrefr  u#   Документы сущностиr   u'   Комментарии сущностиr  r!  	CmfImportu   ИмпортированZimport_objects)r/  rh   r.   r  r  u,   Исходная версия импортаr  )r.   r  r/  r}   u&   Сырые данные импорта)r.   rM  r  u"   Ид внешней системы)r.   rN  r  u   Объект в архиве)r.   rM  r   r  u   Избранный дляZCmfPersonVarZ	favorites)r.   r{  rh   r  r  r}   u3   В избранное всем участникам)r   r.   r  u!   Родительская нодаrO  u   Ветви дереваrj  )r.   r  r  rN  r   u(   Есть вложенные узлы old)r.   r  rN  u$   Есть вложенные узлы)r.   r   r  rN  u)   Не отображать в деревеu!   Корневой РодительrP  ordernou   Сортировкаr   )r.   rS  r  rM  r   c                 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   s   t  }d}|dsdS |dkrFd}| dddg | jrF|| j |d	krxd}| d
ddg | j rx|| j |dkrtjgS |dkrd}|	| 
  |dkrd}|	| jddgd dd |D }|r|S dS )u?  
        Получение значение по шаблонным объектам.

        Возвращает список (в том числе пустой), если передан шаблонный объект
            или None, если объект не является шаблонным
        Fzvar:Nz	var:ownerTr   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_usersrd  does_not_workr   c                 S   s   g | ]}|j s|js|qS r   )rd  r  )r   Zvar_userr   r   r   r   
  s     z-CmfEntity.extract_var_obj.<locals>.<listcomp>)r3   r_   rD  r   r]   r   r!  r   r   r>  get_all_followersrY  )rF   Zobj_codeZ	var_usersZis_var_userr   r   r   extract_var_obj
  s0    

zCmfEntity.extract_var_objc                    sN   |    |   |   |   |   |   |   |   t j	||S )u   
        Функция сохранения при импорте, чтобы ускорить исключив лишние логики и защиты
        )
_calc_perm_parent_calc_perm_inherit_acl_id_calc_perm_has_acl_calc_perm_acl_calc_perm_effective_acl_calc_tree_parentr  
_calc_coder8   r  r   rA   r   r   r  
  s    zCmfEntity._save_importcsvc           
      C   s   ddl m} dd l}ddlm} |j }|d}|tj	dt
jj d| d| }	|	jjdd || j| jt|	||gd	 t|	tjd
S )Nr   Path)cmf_deferred_task%Y%m%d%H%M%SZexportr-   Texist_ok)rc   z/files/)pathlibr  r   r   r  r   rb  r;  
UPLOAD_DIRZjoinpathr   r   r   r   mkdirexport2file_taskrO   r   replace)
r:   field_namesr   format_filer  r   r  r   Zformatted_time	file_pathr   r   r   export2file  s    

&zCmfEntity.export2filerU  c           *         s  ddl }ddl}tt|   fdd}fdddd }	td	fd
d}
|shdd j D }t }|D ]4}j|rtj|t	r|d7 }|
| qr|}|
|}t }|dkr| d}t|ddd}ddl}|j|dd|jd}g }t||D ]\}}g }|D ]}|dkr^|
|| |dkr^|
|| d |
|	|| |dkr ||	||d}|
|j q |dkr|| || qW 5 Q R X n|dkrddlm} ddlm} ||d}|d}|dd  |d!}|
| |d"}d#|_|
| |d$}tj|_|
| |d%}d&|_|
| |d'}d(|_|
| |d)} | d*d+ |
|  |d,}!|
|! t||D ]\}}|d-}"t }#|
|" |D ]`}|d.}$j|$d }|$d |#krP||$d |#|$d < |"
|#|$d   |#|$d }%t||$d }&t|t r|&rZtt|&j! jD ]>}'|'d/kr|&j"|%_qt#|&|'r|%|'t$t|&|' q|%d0|j% n|t|t&t'fr:|&rZ|%d0|j% |&D ]0}(|d1})|)d2|(j( |(j"|)_|%
|) qn t$|	|||%_|%d0||  qq| d3t$| | d4t$| |)|*| nt+d5| |,|| W 5 Q R X dS )6zV
        https://bcrm.carbonsoft.ru/project/Document/DOC-007693#spec-007668-b
        r   Nc                 3   sV   d}d}d| krdg|  } j  ||| g| d}|s8qR||7 }|D ]
}|V  qDqd S )Nr   iP  r  )r  r  r/   )r  )r/   r  stepdatarow)r   r:   r   r   paginate_data  s    
z1CmfEntity.export2file_task.<locals>.paginate_datac                    s^   | sdS t | drt| jS t | dr0t| jS t| trRd fdd| D S t| S d S )Nr   r;   r   ,c                    s   g | ]} |qS r   r   r   r  convert_valr   r   r   /  s     zCCmfEntity.export2file_task.<locals>.convert_val.<locals>.<listcomp>)rV   r   r;   r   r   r3   r}  )valr  r   r   r  '  s    




z/CmfEntity.export2file_task.<locals>.convert_valc                 S   s(   | dD ]}t| |r
t| |} q
| S )u   
            Получить поле объекта. Как getattr, только работает с вложенными полями
            Например: get_included_attr(doc, 'person.second_name')
            r-   )r   rV   r[   )r   Z	field_strrH   r   r   r   get_included_attr3  s    
z5CmfEntity.export2file_task.<locals>.get_included_attr)r_  c                    s,    fdd i }| D ]} |||< q|S )Nc              	      s   | d}| j|d }|}ttt}t|d< |r|j}t|dkrt	|drd|jrd|jd }n|j
}| d || d|dd   }|S )Nr-   r   rU   r   r   )r   r/   r!   r   r   r   rU   r.   r   rV   rh   r}  )Z	class_objr?   pural_namesrH   r  Z
models_clsr  get_captionr   r   r  ?  s    
&zECmfEntity.export2file_task.<locals>.get_captions.<locals>.get_captionr   )r_  r  r?   rn   r  r   get_captions>  s
    z0CmfEntity.export2file_task.<locals>.get_captionsc                 S   s   g | ]}|j r|jqS r   r  )r   rH   r   r   r   r   U  s      z.CmfEntity.export2file_task.<locals>.<listcomp>z.namer  z/export.csvzw+r   )newline;")Z	delimiterZ	quotecharZquoting)textZresult_textu    без htmlZlxmlZxml)ElementTreer  z
export.xmlrssversionz0.92channeltitleZEvaTeamlinkry  u+   XML представление данныхlanguagezru-rutaskr  0
build_inforG   r-   r;   r.   rd   r   endtotalu7   Это формат не поддерживается: )-shutilbs4r   r   r3   r/   ry   r!   rT   r   r]   tempfileZTemporaryDirectoryopenr  writerZQUOTE_MINIMAL	enumerateZBeautifulSoupr  ZwriterowZ	xml.etreer  r  r  ZElementr   Zrequestr   rZ   r   r[   r  rO   r;   rV   r   r.   r
  r  r   Zwrite_bytesZtostringr  move)*rO   Zres_file_pathr  r   r  r5   r  r  r  r  r  Z
new_fieldsr?   ZcaptionsZtmpdirr  Zcsvfiler  r  Zcsv_headr   r  Zcsv_rowrH   ZsoupZETr  r  r  r  r  ry  r  r  rG   elementsr  Z
field_infor  r   r%   rd   r   )r   r:   r  r   r    s    

 



























zCmfEntity.export2file_taskc                 C   s   | j od| j kS )N-ordernor  rn   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   r?   r   r   r   r     s   z.CmfEntity._revers_ordering.<locals>.<listcomp>r  rn   r   r   r   _revers_ordering  s
    zCmfEntity._revers_orderingc              	   C   s   t jr
d S | jrd S |  }t j|krd}| jr8| jj}d}| jrT| jjrT| jjj}d}| jrt| jdr| jj	rd
dd | jj	D }d| j d| d| d	| d
	}tjj|d d S )Nr   rV  r  c                 S   s   g | ]}t |jqS r   )r   r;   rh  r   r   r   r     s     z/CmfEntity.check_owner_perms.<locals>.<listcomp>u   Это действие над uC    разрешено только Владельцу объекта(u+   ) или Владельцу проекта(uD   ) или Заместителям владельца проекта(u5   ) или Администратору системы.r  )r   r  r   ri  r   r   r;   r   rV   rV  r}  r   r   r  r  )rF   Z
all_ownersZ
owner_nameZparent_owner_nameZparent_owner_assistant_namemsgr   r   r   check_owner_perms  s"    

 zCmfEntity.check_owner_permsc              	   K   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, t
jj|j|ddst
j||d	  W 5 Q R X d S )
NzKDEV: FATAL self.id != g.current_person.id and self.id != g.system_person.idTr   zCmfEntity.mark_viewed:r      timeout)	person_idobj_idr4  )personr   )r   r   r   r  r   r   r   r   r   ZCmfLockr   ZCmfPersonViewr!   r   )r:   r  r  r5   r  r   r   r   mark_viewed  s     zCmfEntity.mark_viewedc                 K   s   |d kr|   }dg| j }| j||d}| j||d}| g}	|rP|	| |	d|r^dnd|jg | j|rvd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*  Tr  r  orderno_partition_byr!   _orderno_filterr]   r  r+  r   )r:   r  Z	before_idr  reversr  r/   beforer   orderno_filterZ	prev_itemdeltar   r   r   
move_above  s$    

zCmfEntity.move_abovec                 K   s   |d kr|   }dg| j }| j||d}| j||d}| g}	|rP|	| |	d|r^dnd|jg | j|rvd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*  Tr  r  )r:   r  Zafter_idr  r  r  r/   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   rc  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  r/   r  r  )r!   r  r   r  )r:   r  r  r  r   r   r   	move_down1  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   r/   r  r  r   )r  r3   r   r   r  )r:   r  r  Z
count_objsZ	half_objsZbefore_listr  r   r   r   move_middle9  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]   rD  r[   )rF   r  Zpartition_filterr?   r   r   r   r  H  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  r/   r*  )r   r  r  r   r  r!   )rF   r  Zmax_itemr   r   r   _calc_ordernoR  s    

zCmfEntity._calc_ordernoc                 C   s   d| j  d| j d| j S )Nr   z/?obj=r   )rK   rJ   r   r   r   r   r   hrefe  s    zCmfEntity.hrefc                 C   s   d S rC   r   r   r   r   r   r  i  s    zCmfEntity._calc_tree_parentc                 C   s   | j s|  | _ d S rC   )r   gen_coder   r   r   r   r  l  s    zCmfEntity._calc_codec                 C   s  | 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 sDt	d| d| j
 dqD| | }|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  T)r  r   r   u8   Превышен лимит поиска кода limit=z model=uA   , возможно надо отключить def gen_code: passz$!!! --- gen_code::duration too long r  r  r  r  r  )root_parent_idr  r   r  r:  get_code_prefixnext_code_numberr\  r   rF  rO   rK  r/   r   )rF   r:  r  r   limitr   r=  r   r   r   r  p  s$    
 ".zCmfEntity.gen_codec                 C   s   | j S rC   )rL   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   rx  )r\  r+  r   r   )rF   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_DBrO   redislockacquirerelease
exceptionsr   r   r<  r;   r  existsZincrr	  r   )rF   Zredis_dbr   Zlock_keyr  r   r  r   r   r   r    s    
4zCmfEntity.next_code_numberc                 C   s   d S rC   r   r   r   r   r   gen_name  s    zCmfEntity.gen_namec                 O   s
   | | j S rC   )r  )rF   r?   rc   r5   r   r   r   _get_field_log_level  s    zCmfEntity._get_field_log_levelc              
   C   sN  | j r
d S |sd S i }g }| jddD ]\}}|dkr8q&|drDq&|drPq&|jdkrntd|j d |jdk	r|j|j	krq&| 
|}|d	krq&| }|sq&|||< | }|s|d
kr|j}|r&|| d|  q&|sd S d}	| jrd}	| j}
| jdkr"| jr"| jdd }
tjj|	| jtj| t|
|d|d d S )NTr  )
rs  Zcache_fieldsr   rr  rZ  ZviewsZlikesZstatus_closed_atZstatus_modified_atZstatus_in_progress_endr  Zcache_.u&   DEV: INFO. Возможно, поле uI    не попало в аудит, т.к. его old не загруженr  r6  r4   r  r  r      z<br>)r	  r
  r   r   parent_name
audit_dataZhtml_diff_data)r   r   r-  r_   r   r   r<  r\   rd   r  r  Z
audit_diff	html_diffr]   r   r;   rO   r  r   r  r  r   r   r}  )rF   auditr  r  r?   r1  r  Z_audit_diffZ
_html_diffr	  tmp_namer   r   r   _system_audit  s`    



zCmfEntity._system_audit)	recursionc                O   s   t  S rC   )r   )rF   r  rc   r5   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_notify)rF   r5   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_executorsr/   )is_favoriter   favorite_forr!  rY  r  r]   remove)rF   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   )r8   re   r   r   r  )rF   r   rc   r5   rA   r   r   re     s    
zCmfEntity.__init__c                 C   s   | j r4| j dr4| js4| dddg | j| _d S | jrR| jjjsR| jdg | jrb| jj}n| jdkrt| j}nd }| j|kr|r| j	  t
|| _d S )NzCmfProject:zparent.task_code_prefixz&parent.task_code_use_logic_type_prefixzlogic_type.obj_code_prefixr  r   )r   r_   r  rD  r   root_parentr   rO   r   r!  r   r   )rF   r  r   r   r   r    s"    


zCmfEntity._calc_root_parentc                    s   t   dddg S )Nr  zparent.root_parent_idr  )r8   r  r   rA   r   r   r  #  s    zCmfEntity.save_preload_fieldsr  r  c                   sX  | 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_| jjdd | 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  Fr%  r  )r  )$r  r   r   r   r;   r   r   r   r   r#  r  rj  rD  r   r  r   r  tree_child_deleter  r  r  r  r  r  r  r  r  r  r   r  r  r8   _acl_spread_inheritancer  r!   r  )rF   r  r  rc   r5   r  rA   r   r   r   )  sB    

zCmfEntity.savec                 C   sJ  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|r0|tj|}|jjdd ||| | d}tj|r|||j tjjd	d
| gdddgdD ]>}	|	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|rB|tj|}t|S )Nr   r  r   r   r  Tr  z.metar   r  r   url_preview_imgurl_previewrk  r  ) r  urllibr  r  ospathr}  r;  r  r   r   r   r   rO   r  r   r  r  r   r  r3   r   rd   r(  r)  r   r  r  parsequoteZ
quote_plusr   )rF   Zabsoluter  r*  r  Zold_pathr,  new_pathZold_meta_pathZattachZold_urlZold_url_preview_imgZold_url_previewr   r   r   get_files_dirc  s@    &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  placerO   Zrelation_personsZchanged_fieldschanged_relationsactionTr  )rr  r   rs  Zcmf_viewed_byrq  rp  .zemit: FIXME is changed bug r-   uR   DEV: INFO Могла не прийти инвалидация для old-поля r4   insertr  jsurlr   session_tab_id)'collectionsr   rO   r   r  r   r2  r   r   r!   r4  rd   rV   r   r   r  r5  rY  r]   r   r   r[   r   r  r<  r   r   r/   r   r
  Z_changesr3   r\   r>  r   rd  r   r9  r:  )rF   r   r2  r4  Zbodypr6  r$   r%   rH   r7  r   r&   r   r   r   r   r    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  r/   r  r  c                O   s   | j |d}ddd|gg}d|krD|dD ]}	||	d|g q,nBdD ]}	||	d|g qH|| jrt|dkr|d	d|g |r||g}| j|||d
}
|
S )N)r  r^  r   r  Zfields_filterr  )r;   r  r   ,   r   r  )r?  r!   r]   r_   rO   r   r3   )r:   r  r/   r  r  rc   r5   Zstemmed_query_filterr  r  r   r   r   r    s    zCmfEntity.searchc                 C   s   | j stdt| j S )NK   Блокировка объектов без id не реализована)r   rW   r   	lock_pingr   r   r   r   rC    s    zCmfEntity.lock_pingc                 C   s   | j stdt| j S )ut   
        Из редиса заберём структуру, где есть данные
        :return:
        rB  )r   rW   r   	lock_infor   r   r   r   rD    s    zCmfEntity.lock_infoc                 C   s<   | j std|   | jdkr.| jd| d t| j dS )u`   
        Захват объекта на редактирование
        :return:
        rB  r   zPPP-PR-ADMINr   i  )r   rW   r  rO   r   r   r  r   r   r   r   r    s    
zCmfEntity.lockc                 C   s   | j stdt| j S )u>   
        Снятие захвата
        :return:
        rB  )r   rW   r   unlockr   r   r   r   rE  .  s    zCmfEntity.unlock)rC  skip_owner_checkc                   s  |    | ddg | jr<|s<tjjd| j dd d S |sH|   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sx| j}| jdkrN| j  | jrN| jdd }tjjd| jtj| t |d | j!|| t" j#|d|i|S )Nr  r   u<   Нельзя удалять системный объект Tr   ZDELr  z[A-Z]+-\d{4,}\Zr  loginemailr   r&   r  r   r  r  )r	  r
  r   r   r  rC  )$r  rD  r  r   r   r   r   r  r   r   rb  r   rematchrd   r  r;   rV   rG  deleted_loginrH  rj  r!  r&  r   rO   r  r   r  r  r   r   r   r  r8   r  )rF   rC  rF  rc   r5   r4  r  rA   r   r   r  8  sD    



zCmfEntity.deleter  c                   s   |  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| _t j|d|i|S )Nr  r   Trd  r  )r   r/   r   rG  rH  rK  r   r  )rD  r  r   r   r   rd  r   rj  r  r;   rI  rJ  r  rd   r(   r   rV   rG  rK  rH  r8   r  )rF   r  rc   r5   rj  rA   r   r   r  j  s&    


zCmfEntity.restorec                 C   sP   | j  D ].}|jdd| jgdd|jggd}|r
 dS q
d| _| jdd	 dS )
u    Убирает метку дерева у объекта при удалении узлов, при перемещении узлов r  r  r   r  r  NFTr  )
tree_nodesr0  r\  r   r  r   )rF   r  rh   r   r   r   r   r&    s     zCmfEntity.tree_child_deleteskip_choice_data_syncc                O   s.  ddl m} |jjdddd}| s6tjjddd zt }t	j
jd	d
| jgdddggdgdD ]&}|jd D ]}|jd | ||< qpqbt| d}	g }
| D ]}|
tj|| d q|	|
 |	j|d |	  W nN   z|  W n4 tk
r" } ztd|  W 5 d}~X Y nX Y nX dS )uD  
        Синхронизируем настройки полей с фронта
        Получаем список полей с фронта, в нужном порядке для ui_group.
        Приводим в соответствие модель, БД, и запрашиваемый список.
        Поля которые удалили(нет в fields) убираем из ui_group, но оставляем в базе(!!! важно) и в модели
        (в модели поля может не быть, если её удаляли).
        r   )r  z(lock::cmf__base_model__custom_field_synci  )r  Zblocking_timeoutu   Невозможно изменить список полей, так как уже запущен процесс изменения.Tr   r
  r  rj  r  Nrk  	ui_fieldsr  )rh   rM  z'custom_field_sync:: release lock error )cmf.appr  r  r  r  r   r   r   rZ   r   Z	CmfUiFormr3   rO   rj  CmfCustomClassry   r]   CmfCustomField	from_dictrM  save_changesrL  r  r   r   r<  )r:   rN  rc   r5   r  Z
redis_lockrO  Zui_form_rowr   custom_classcustom_fieldsZcustom_field_datar   r   r   r   custom_field_sync  s0    	


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   r1  ztask-comment-)r3  zaudit-task-comment-)rQ  r2  r  r   rY  )rF   r  rc   r5   r2  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  r  r  r  rk  )r   r]   rV   r   r  r3   r   r   )rF   r  r5   rA  _fieldsr$   r  r  r   r   r   _update_opened_notifies  s    z!CmfEntity._update_opened_notifiesc                 C   s   dS )uE    Базовый шаблон почтовых уведомлений zmail_notification.htmlr   rn   r   r   r   +get_default_mail_notification_template_name  s    z5CmfEntity.get_default_mail_notification_template_nameu8   Разрешить публичный доступ DELME)r  r.   r   u-   Задать права для объекта)r  r.   r  u<   Список для проверки прав доступа)rh   rN  r  r.   u!   Наследовать праваu#   Наследуем права от )r  rN  rQ  r.   u*   Кеш Владельца Родителя)rN  r  r.   r/  u;   Наследуемый список прав доступа)rN  r.   r/  r  u;   Эффективный список прав доступа)rN  r  r.   u   Кеш неразвернутых записей Уровней безопасности, которым разрешен доступr.   u   Шифрованныйu5   Для просмотра требуется ключ)r   r  r.   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_inheritrf  r  r  r   )rD  r   r   r   r   _load_perm_fields  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 rC   )r   rj  r   r   r`  rf  )rF   rf  r   r   r   r     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  )rf  r   r`  rD  r  r  r  r  r   r   r   r   r  ,  s    
z#CmfEntity._calc_perm_inherit_acl_idc                 C   s   d S rC   r   r   r   r   r   r  9  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   r  disabledZobject_ownerperm_inheritZinherit_acl_idrd   r   r   r   r   r  Zclear_auto_acl_acl_scaffold)rF   rC  r   r   r   r  <  s.    


zCmfEntity._calc_perm_aclc                 C   s   d S rC   r   r   r   r   r   re  T  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policyrc  zrules.disabledzrules.sys_typeTrR  r  )
r  r`  rb  rD  rc  r%  sys_typer  r   rd   )rF   r  Zruler   r   r   r  W  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_idrd  r  r  )r_  r   rd  rb  r  rD  r   r  )rF   r  r   r   r   r  j  s$    
z"CmfEntity._calc_perm_effective_aclc                 C   s@  ddl }| jrdS | jjs&| jjs&dS td | jjrtd|   |}|dkr\t }|D ]j}t	j
jj d|j | jj| jjd}t|}|jj|jdd |D  td	tt|  q`td
 | jj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}
|jj|jdd |D  |D ]\}|
d7 }
|d |krtd|d  d qt|d dkrАq||d  qq.|| }tdt| dt|  qtdt|  td |rd}	|d|	 }||	d }|}|dkrdt }|D ]}t	j
jj d|j | jj|d}|jj|jdd |D  t	j
jj d|j | jj|d}t|}|jj|jdd |D  qhtdt| dt|  q,td td t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   Nua   Шаг 1. Если изменился owner_id, апдейтим его всем потомкамu9   Обновляем 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 ra  r   r  r   r   r   	<setcomp>  s     z4CmfEntity._acl_spread_inheritance.<locals>.<setcomp>z... update count: uK   Шаг 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_listc                 S   s   h | ]}|d  qS ra  r   r  r   r   r   rg    s     r   r   u   Ошибка! u!    уже был обработанr  u   Уже обработано: u   , к обработке: u!   Всего обработано: ug   Шаг 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 ra  r   r  r   r   r   rg    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 ra  r   r  r   r   r   rg    s     ZDoneu/   Шаг 3. Перезагружаем кеш ACL)rQ  r   r  r   r  r   r<  rU   r   r   r  rk   Z_ddZSessionZexecuterN   rd   r   r3   Zapp	CMF_CACHEZinvalidate_idsrO   r   r   rl  r]   )rF   Zspread_modelsr   Z_spread_modelsZchild_modelr  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_inheritancec                 C   s&   | j jrdS t| dr"| jjr"dS dS )NTrV  F)r   r   rV   rV  r   r   r   r   ra  %  s
    z"CmfEntity._acl_subjects_is_changedc                 C   s:   g }| j r|| j  t| dr6| jD ]}|| q&|S )NrV  )r   r]   rV   rV  )rF   r  rX  r   r   r   _acl_subjects_list_level_write-  s    

z(CmfEntity._acl_subjects_list_level_writec                 C   s   g S rC   r   r   r   r   r   _acl_subjects_list_level_read7  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  S )Nr   r   r   r  )	r  r  r  r  r  r  r  r  r   )r   r   r  r  rd   r7  r[   r/   r!   r   r,  r   r  r}   r  r"  r  r  r   r   r8   r  )rF   r   Zparent_class_nameZparent_modelZparent_fieldr#  rA   r   r   r  ;  s&    
    zCmfEntity._acl_check_write)NNr  )NNr  )N)NN)NN)N)N)N)T)F)N)N)F)N)r   r   r   r   r  r   rC  Zmenu_tree_parent_idZmenu_tree_ordernorx   rI  compiler  r,  r`   rn  Z	CmfStr256r;   ZCmfStr64r   rt  r  Z	CmfMarkupr  r.  ZtasksZ	documentsZcommentsr;  r[  r  r   r/   r  r\  ZCmfStrr]  r  r>  r   r  r=  rj  rL  Zhas_tree_nodesr  Ztree_hiddenro  r$  rB  r  r  ZCmfIntr  r  r  r  r  rF  r  rH  Z
celery_appr  r  r  r  r  r  r  r  r  r  r  r  r  ra   r   r  r  r  r  r	  r  r  r  r  r   r  r  r#  re   r  r  r   r0  r  r?  r  rC  rD  r  rE  r  r  r&  rX  rY  r\  r]  Zperm_publicr_  rb  rd  rf  r/  r  r  r  r  Zperm_encryptr`  r  r  r  r  re  r  r  r'  ra  ri  rj  r  rp   r   r   rA   r   rU   &
  s"  


	  
                       % +



		
<:
&b



2
&


             	   
      

 +
rU   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 )rS  NrO   
field_typeui_group_name	ui_groupsrR   r.   rA  db_typedb_column_namedb_table_namerT  rh   r   choicesF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 )Nrr  c                 S   s   i | ]}t ||qS r   )rR  caption_to_name)r   choicer   r   r   r9  o  s      z,CmfCustomField.from_dict.<locals>.<dictcomp>)rl  rm  rn  rR   ro  rp  rq  r@  rR   )r   r   r   r3   Z__dataclass_fields___calc_db_choice_table_name)	r:   ru  rh   rR   Zui_meta_nativer5   r$   r%   r  r   r   r   rT  g  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   r<  r   r   r   r   }  s     z;CmfCustomField.gen_db_choice_table_name.<locals>.<listcomp>r&   ZCh@   u8   Имя поля не должно быть больше    u    символовTr   )r}  rO   r   r   r   r   r   )rF   rh   rt  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 )Nrh   ZCUSTOM_CHOICE_MODELT)r[   rs  r|  rt  rh   rR   )rF   rh   Z	rel_modelr   r   r   rx    s    z)CmfCustomField._calc_db_choice_table_name)N)r   r   r   rO   r   rC  rl  rm  rn  r   rR   rZ   r.   rA  rD  ro  rp  r
   rq  rT  rh   r   rr  rs  rt  rF  rT  r|  rx  r   r   r   r   rS  T  s(   
rS  c                   @   s   e Zd Zee dddZee dddZd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 )rR  rP  c           
      C   st  || _ d | _g | _d | _d | _g | _d | _|  | _| j	d| _
d| _dd | j jj| j jD | _| j }tt}| j j D ]}|jr||j}d }d }t|ttfrnt|tr|j d}n|j}||kr||nd }t|j| |||o|d |j|j|j|j |o |d |d |j dd d	}	|	!| j  |rV| j"|	 qd
| _qdd | jD | _d S )N.bkFc                 S   s$   i | ]}|d   dr|d  |qS )r;   r(  r  )r   columnr   r   r   r9    s    z+CmfCustomClass.__init__.<locals>.<dictcomp>r  r   r1   rh   )rO   rl  rn  rm  r.   rA  rT  rR   ro  rp  rq  rh   Tc                 S   s   i | ]}|j |qS r   )rO   )r   
field_datar   r   r   r9    s      )#r  Zcurrent_fieldsrW  
db_columnsr   add_to_db_fieldsZcustom_fields_index_get_model_file_pathmodel_file_pathwith_suffixmodel_bk_pathrk   rl   Zinspect_table_columnsrN   r   r   r3   r/   ry   rA  r!   rO   rT   r  r
  r  r|  rS  _field_type_namer.   rT  rR   rx  r]   )
rF   r  r  Zfields_ui_groupsr@   rn  rp  Z_db_table_nameZdb_field_infor  r   r   r   re     sZ    


zCmfCustomClass.__init__r   c                 C   s   |D ]~}|j r| j| |j| jjkrX|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 удалять, если данных нет.
        r  Trr  N)rA  rW  r]   rO   r  r/   r  r  r   rV   rr  )rF   r/   r  rH   r   r   r   rM    s    zCmfCustomClass.merge_fieldsFc                 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&   r  r}  N)r  r[   r   r/   rl  rT   r  NotImplementedrt  rs  r  rk   rl   Zadd_custom_choice_modelrO   Zadd_custom_m2m_modelr
  rN   ry  r  r/  Zadd_custom_columnr  r  r  renamer  _write_custom_model_file)rF   rN  r  rl  r  Z
table_nameZcolumn_nameZmodel_tmp_pathr   r   r   rU    s2    





zCmfCustomClass.save_changesc                    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  fdd	}tjr | |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)r  r  r;  PROJECT_DIRr  unlink
subprocessrun)Zproject_pathZautogen_filenameZautogen_file_pathr   r   r   apply  s    
z+CmfCustomClass.apply_changes.<locals>.applyuG   Ошибка применения новой кастом модели.u=   Есть backup file попробуем откатиться.uA   Попробуем откатиться удалив custom file.c                     s^     d tdtjd  r>ddddd tjD g} n
dtj} t|   t	|  d S )Nr   z/etc/init.dr   z	/bin/bashz-cr  c                 s   s   | ]}d | dV  qdS )z/etc/init.d/z restartNr   )r   Zsvcr   r   r   	<genexpr>,  s     zICmfCustomClass.apply_changes.<locals>.restart_services.<locals>.<genexpr>/bin/systemctlrestart)r  r  )
sleepr  r  r;  SERVICESr  r}  rK  r  Popen)Zcommandgeventr   r   restart_services(  s    

z6CmfCustomClass.apply_changes.<locals>.restart_serviceszBaseModel:custom_field_syncr
  )r   r  r  r  ZSubprocessErrorr  r  r  r  infor  r  r  r;  r  Zspawnr  rO   )rF   r  r  r  r   r  r   rL    s(    




zCmfCustomClass.apply_changesc           	      C   sF  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 ]2}|| jj rtt|dstt|t|| q|  dt_| jjjj !| jjr8| jjjj | jj= tj"#  dS )u   
        без перезагрузки обновляем в памяти модели и поля, добавляя кастомные
        r   )rh  r   r   r-   Nr-  custom_modelsz /opt/eva-app/__autogen_models.pyr(  )$rQ  rh  r   r  r  r;  r  	importlibreloadimport_moduleutilspec_from_file_locationmodule_from_specr  modulesloaderexec_moduler[   r  rO   r/   r_   rR   re  r   r   r   Zflushdbrr   r)  rk   rl   Zmodels_registryr!   ZRelationCacheZbuild_fields_cache)	rF   rh  Zmodule_pathZmodule_namespecr  Zcustom_modelr?   r  r   r   r   reload_models_and_fields9  s.    *




z'CmfCustomClass.reload_models_and_fields)r.   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  r(  r  r&   u#   Такое имя уже есть: r  r  )r   r   r   rv  ranger-  r  )rV  r.   Z	name_basennr?   r   r   r   calc_field_namee  s    



zCmfCustomClass.calc_field_namer^  c                 C   s&   t | ddd}ddd |D }|S )NruT)Zlanguage_coder0   r   c                 s   s"   | ]}|  r| nd V  qdS )r&   N)isalnumr)   )r   r(  r   r   r   r  v  s     z1CmfCustomClass.caption_to_name.<locals>.<genexpr>)r   r}  )r.   r;   r   r   r   rv  s  s    zCmfCustomClass.caption_to_name)r@   c                 C   s8   | j D ],}t|dd }t|tr|dr|  S qd S )NrO   ZCmf)rD   r[   r   r   r_   )r@   r>   Zbase_class_namer   r   r   r  y  s    
zCmfCustomClass._field_type_name)r  c              	   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   r=  r  )xr   r   r   r    r  z9CmfCustomClass._write_custom_model_file.<locals>.<lambda>r.  zcmf_model.tmpltcustom.Nr>  )rA  rQ  )Zjinja2ZEnvironmentZFileSystemLoaderr+  r,  r}  r;  r  filtersZget_templater  	__bases__r   r_   r  r  Zrender)rF   r  Z	jinja_envtemplaterQ  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__.pyr>  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)r  r  r;  r  r  rK   r  r   r_   r}  r   r  r  r  rK  rI  rk  findallrO   )rF   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)F)r   r   r   rG  rU   re   r   rS  rM  rU  rL  r  rH  r   r  rv  r7   r  r  r  r  r  r   r   r   r   rR    s   <
!2,rR  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   rK   r   rJ   r   sharelink_hashvfr;   )r   r   r   r   r   rC  rK   r   rJ   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_factoryrL  r  T
allow_movechildren_countr  rf  )r   r   r   r  r   rC  r  rD  dataclassesrH   r3   rL  r  r+  r  r  r  rf  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    не найдено поле rx  FTu0   Не найдено поле у моделей: )	itertoolsrV   r  rO   r[   rT   r   r/   r   r0  r   r   chainr   rU   r   ZCmfGanttTaskr4   r3   )r:   rh   Z
field_pathr  rH   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  r  Z
CmfOrgUnitZCmfRoleZCmfWorkflowZCmfTagZCmfRelationOptionZCmfLogicTyper   Z
CmfCompanyZCmfActivityr!   r   rd   )r:   r   
model_listrh   r   r   r   r   _convert_code_to_uuid  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]  zNOT INry  zNOT LIKEr  z	NOT ILIKEr  zNOT SIMILAR TOr  z
NOT EXISTSr^  r  r  z([^"'])z\1"z"\2)flagsr   []r   rx  r  )r  ')r  r  r  )r  r  )g.current_userg.now()g.date())TrueFalseNoner  )rI  r(   Ir  upper)r   r  Z	cur_tokenZcur_string_symbolZorm_operatorsZoperr(  r   r   r   
quote_ubql  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:    Должно быть:   ОШИБКА!!!)rK  r   r  )
test_casesr   Zubql_convertedr  r   r   r   test_quote_ubqll  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   r2   r3   r   r   r)   r  r]   r  )r   Zskip_orderbyZblqr?   r  r  Zexists_filterZ_valZ
tuuid_valsr   r   )_recursive_ubql_processr:   rh   r   r   r    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   r3   r>  r]   r)   )Z
field_listZ_resr?   rec_parse_order_byr   r   r  @  s    
zTUbqlConverter.ubql2bql.<locals>._recursive_ubql_order_by.<locals>.rec_parse_order_byr`  )r   r2   r3   r   r   r)   r]   )r   r  r   r   )_recursive_ubql_order_byr  r   r  (  s$    

**
z8UbqlConverter.ubql2bql.<locals>._recursive_ubql_order_byu&   Ошибка обработки UBQL: r   u   . UBQL отключен)r   r  r  astZliteral_evalr3   r  r   r   r   rc   )r:   r   rh   Zfilter_ubqlZ
filter_bqlr   r   )r  r  r:   rh   r   r     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()]rr  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  rK  r   r   r   r:   r  r   r   r  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  rF  r  r  rH  r   r  r  r3   r   r  r  r   r   r   r   r     s   

Z
wz
7r   )Dr  r  r  r  r  r   r;  r   r   Zcollections.abcr   r   r   	functoolsr   typingr   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   rj   rI  rk  r'   rX   r    r+   r1   r,   ZTypeVarrq   rr   r,  ru  rv  r  rU   rS  rR  r  r  r   r   r   r   r   <module>   s   

v               Y  4;*            :B  