U
    gyd                    @   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   ./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   s  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|| }t|t| kr| jdkrtd| d| j d	t|  d
|j d	t| d| ||< qp| j D ]J\}}	| |	_| j d|	j |	_|	j| jd |< |	jr| j|	j qt| D ]X}
|
drnqZ|
| jkr~qZt| |
}t|trqZt|rqZ|| j|
< qZd S )Nr/   )ui_name	ui_modulecode_prefixu   Заполните поле     в классе )rJ   rL   customu   Значение поля u    класса (u)   ) дублируется в классе )r-   r&   )r+   r   	tablename
class_nameprimary_key__dp__ui_metaabstract
issubclass	CmfEntityhasattr
ValueError_unique_fields_cache
setdefaultdictgetattrreprr   r/   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   sN    


.


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.baserj   data_sourcesDEFAULT_DATASOURCErT   r!   )r:   rj   rk   Zdp_r   r   r   dp   s    
zBaseModelMeta.dpc                 C   s   | j j| S rC   )ro   data_driverdp_modelr:   r   r   r   rq      s    zBaseModelMeta.dp_modelc                 C   s
   t | jS )u!   метаданные модели)r+   r   rr   r   r   r   	snakename   s    zBaseModelMeta.snakename)r   r   r   r   r9   rI   ri   re   ro   rq   rs   __classcell__r   r   rA   r   r,   ;   s   !2

r,   BM	BaseModel)Zboundc                   @   s  e Zd ZU dZdZdZdZdZdZdZ	dZ
dZdZdZdZdZdZdZ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#Z/dd$d%Z0dd&d'Z1d(d) Z2d*d+ Z3e"eed,d-d.Z4e"dd0d1Z5e"d2d3 Z6d4d5 Z7e"d6d7 Z8d8d9 Z9e"dd:d;Z:dd<d=Z;e"dd>d?Z<e"de=d@dAdBZ>e"e=d@dCdDZ?e"de@d@dEdFZAe"e=dGdHdIZBddJdKZCdLdM ZDe"eEdNdOeFd@dPdQZGe"e=d@dRdSZHe"ddTdUZIe"dd@eJeK eKdVdWdXZLe"dd@eJeK eKdVdYdZZMe"dd@eJeK eKdVd[d\ZNe"ddGd]d^ZOe"dd@eJeK ePeK dVd_d`Z@e"dd@eJeK ePeK dVdadbZQe"ddGdcddZRe"dd@dedfZSe"ddGdgdhZTe"didj ZUe"ddkdlZVe"dee=edmdndoZWe"dpdq ZXe"ddrdsZYdtdu ZZddwdxZ[dydz Z\d{d| Z]d}d~ Z^dd Z_dd Z`dd Zadd ZbddddZcdd Zddd ZedddZfdd ZgdvddddZhdd Zidd ZjekdddZldd Zmdd Zndd ZodddZpddddddZqddddZrdd Zsdd Ztdd Zudd Zvdd ZwdddZxe"ddddddZye"dd ZzdZ{e"dd Z|ddddZ}e"dddddZ~ddÄ Zekddń ZdddǄZe"dddɄZdd˄ ZdS )rv   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_branchrU   rd   rQ   r/   rm   rV   ro   rq   rs   valuesZvalues_dictrS   db_nameis_recursion_savedisable_simpleno_aclacl_default_user_policyrx   Z
acl_staticry   rz   r{   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   varsr}   r   r1   rW   )r:   r   rl   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/   rR   instance__dict__datetimenowtimezoneutcr   CmfDateauto_nowauto_now_adddate_value_oldCmfDateTimer   r   __func__r3   r]   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_objectrY   r^   virtualZCmfOrmImplicitLazyLoadrR   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_saver\   gen_idr^   gr/   r   r   
is_changedr   setattr)rF   r   r   r5   ir$   r%   r   r   r   ri   1  s2      zBaseModel.__init__c                 C   s   | j  }|d= |S )Nsave)r   r   )rF   r"   r   r   r   __getstate__Q  s    
zBaseModel.__getstate__c                 C   s   || _ |   d S rC   )r   r   )rF   stater   r   r   __setstate__V  s    zBaseModel.__setstate__c                 C   s
   t | jS rC   )hashr   r   r   r   r   __hash__Z  s    zBaseModel.__hash__c                 C   s
   t | jS rC   )r1   ro   r   r   r   r   ro   ]  s    zBaseModel.dpc                 C   s6   t |tks|j}n|}|dd }ttjj| S )N:r   )r1   strrh   splitr   r   includer   )r:   r   ZtuuidrR   r   r   r   get_model_by_ida  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>o  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   q  s     
  N)r/   r3   rF   r   r   r   r   r   keysj  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   y  s     z#BaseModel.items.<locals>.<listcomp>r   r   r   r   r   r   r   r   u  s    zBaseModel.itemsc                    s    fdd j ||dD S )ug   
            возвращает списком инициализированные поля
        c                    s   g | ]}t  |qS r   r   r   r   r   r   r     s     z$BaseModel.values.<locals>.<listcomp>r   r   r   r   r   r   r}   {  s    zBaseModel.valuesc              
   C   s:   zt | |W S  tk
r4 } z
t|W 5 d }~X Y nX d S 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   rh   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g}	d }
|r*tj||	d}
nN|rl|rlt|}|sP|ddd d S t|}tj|||	d}
n|ddd |
s|d	|d
|d|dd |r|
jdkr|d	|d
|d|dd |
jdkr|
jd|
ddsR|d	|d
|d|dd nNz|
j	ddddgd W n4 t
k
rP   |d	|d
|d|dd Y nX |
jrht|
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   	cmf_alertui_view_formr/   z+DEV: FATAL get_ui_full_path class_name=NoneTabortz3DEV: FATAL get_ui_full_path ui_name=None, code=Noneu$   Объект не найден id = z ui_name = z code = )
CmfProjectCmfDocument	CmfFolderZCmfSDeskRequestTypeCmfTaskr   zPPP-PR-BROWSEF)objZraise_errorr   r;   code	parent_id)check_fields z&rup=0/z/?parent_id=z&vf=z&code=z	&ui_name=#-)r   r   r   get_obj_by_idZget_class_name_by_ui_nameget_model_by_nameZget_obj_by_coderR   Zcheck_project_role_access_acl_check_readCmfPermissionErrorr   r   rK   is_not_nullr/   r   cls_ui_view_formr   r   rJ   Ztranslit_stripr;   rh   )r:   r   rJ   r   rK   r   Zruppublic_callr   r/   r   rR   rl   Ztmp_ui_moduleZtranslit_nameZtmp_parent_idZrup_txtr   Zurlr   r   r   get_ui_full_path  sL    


	 $

DzBaseModel.get_ui_full_pathc                 O   s   | j |ddi|S )Nr   T)r   r:   rg   r5   r   r   r   public_get_ui_full_path  s    z!BaseModel.public_get_ui_full_pathc                 O   s   d S rC   r   rF   rg   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                 C   s   dS NFr   r   r   r   r   _sdesk_check_access  s    zBaseModel._sdesk_check_accessc                    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   lenrW   r1   r   r   rv   
CmfRelBase)r   r   r   r   is_model_obj  s    0z&BaseModel.asdict.<locals>.is_model_objr   c                    s   g | ]}|j f  qS r   get_values_dictr   r   paramsr   r   r     s     z$BaseModel.asdict.<locals>.<listcomp>)r]   r   r3   r2   rW   r1   r   r   rv   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   r]   r   	Exception)nr   r   r   r   inc_obj_count  s    
z0BaseModel.get_values_dict.<locals>.inc_obj_countNTr   full_fields_loadc                    s   g | ]}|j f  qS r   r   )r   r   r   r   r   r   )  s     z-BaseModel.get_values_dict.<locals>.<listcomp>.rR   )r   )r   r  r   r]   r!   r   r   r/   
CmfM2MBaseCmfBackrefBaserh   CmfRelationBaser   r   rR   )rF   r/   r  rr  r?   Z	field_valZfield_valuer   r   r   r     s.    

 

zBaseModel.get_values_dictc                    s,   | j  } d k	r( fdd}t||}|S )Nc                    s    | j  krdS | jdkrdS dS )NTr   FvisiblerR   fr  r   r   filter_visible>  s
    

z-BaseModel.meta_fields.<locals>.filter_visible)r/   r}   filter)r:   r  r/   r  r   r  r   meta_fields8  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< |dkrd}t| D ]\}
}|
dr,d}|t	|
k r|
|d   dkrq|d7 }q|
d|  }||||f< t
|| |||< ||
= qq|
drJt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r6| 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sd|rJ|j|rJ|dkrJ||ji }t|||df  t|||df  qJnL| D ]B\}}|jdks|r|j|r|dkr||ji  qq|D ]}
|
|kr||
= q|	 D ] \}
}||
i }t|| q(| D ]\}
}| j|
}|rRt|trR| }|stg}i }|D ],}t|}|j|||
||d t|| q|  t|| qR 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parentTr   r   r   N+u   Синтаксис +field u)    устарел, используй fieldr   u=   У "-" не может быть вложенных полейalwayslogic_prefixlazy      )fields_is_lazyrelation_field_nameauto_fieldshack_parent_noalwaysc                    s2   d}|   D ] \}}|d7 }|r| |7 }q|S )Nr   r   )r   )Z_BaseModel__fieldscr$   r%   Z_BaseModel__field_countr   r   Z__field_count  s    z4BaseModel._fields_load_expand.<locals>.__field_count  u_   DEV: WARNING. В запросе используется слишком много полей: u;   . Возможно, где-то используется **)Z
debug_only)!r   intr]   rW   CmfModelrX   r3   r   endswithr   maxrc   ZCmfDeprecatedErrorra   r   r/   r}   	load_moderR   r\   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   r-  H  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   	partitionr\   r4   r}   _fields_split)r:   r/   Zfull_field_namer/  r?   r&   Zsub_field_namer   r   r   r4    s    zBaseModel._fields_splitc                 C   s|   ddl }|  }|rg }ntj}dd |p,|D }| | | j||d |  | }|dkrxt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!)timeconfigZORM_DEFAULT_FIELDSr4  r-  r   debug)r:   r/   r   r6  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/   r}   rR   extendZget_required_fieldsr  r    r   r!   rW   r   r,  rX   _enrich_load_plan)
r:   r  required_fieldsrH   Zrequired_fflr?   r/  Z	field_fflr1  r2  r   r   r   r;    s$    



zBaseModel._enrich_load_planc                 C   s   |  | |S rC   )_load_fields_build_load_plan)rF   r/   forcer   r   r   load_fields+  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	  rh   r  r  r   r   AssertionError)r   rA  Zloadedr?   rH   Zlist_loadedZrel_instance)	strip_fflr   r   rC  <  s(    


z)BaseModel._load_fields.<locals>.strip_fflT)include_deletedr  )dst_instancesrc_instancerA  c              	      sz  |j ddD ]f}|| }| | }|jdkr4|j|_|jdkrxt|jttfr\t|j|_n|j|_t|tr|	  qt|t
r|jr|r|||i  nB|r|j|jkr̈ |j|j||i d n|r|||i  qt|ttfrfdd |jD }|jD ]X}|jj|krF |||jj ||i d ||jj= n|jr
|||i  q
qt|trtqdS )un   Если поле изменилось, то доводим новое значение до кондиции.Tr  .)rA  c                 S   s   i | ]}|j j|qS r   )r   rh   )r   Zsrc_ir   r   r   r5    s      z@BaseModel._load_fields.<locals>.merge_fields.<locals>.<dictcomp>N)r   r   rh   r   r   r3   r]   r   r  apply_changesr	  r   r=  r!   r  r   r   rB  )rE  rF  rA  r?   Z	src_fieldZ	dst_fieldZsrc_instancesZdst_i)merge_fieldsr   r   rH  j  sJ    



 

 

z,BaseModel._load_fields.<locals>.merge_fields)r   r   r   printr   rv   r]   r   rR   _getr   )rF   r  r   Znew_instancer   )rH  rC  r   r=  /  s0     
   /
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   r]   rN  rL  r2   sortedrM  r   r   r   r>    s    

zBaseModel._build_load_plan)r:   r   c                O   s   |  |}| j|d|i|S x   
        fields - список мета-правил для указания какие поля грузить
        r  )r>  rJ  r:   r/   rg   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 rQ  Nr   Fvirtual_cache_timelifer/   simple)r  mapper)r>  r   r^   r!   rJ  r:   r/   rg   r5   r  r?   rH   r   r   r   sget  s    
zBaseModel.sgetc             	   O   s  | j }d}|dd}|d| j }d}d|krB|d }|d= | j|ddd	g|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}t|pg }|d |r(|dg }|D ]}||dg  q| |}| j||d|d|}|r|jrdd|j |_||_||_|jsttdrtj|}|S )rQ  r   Zis_public_formFr   TrD  
logic_typeactivityzparent.ui_form_schemer/   rD  r   ztarget.ui_form_jsonZlogic_typesINOR=Nui_form_schemer/   r  cmf_deletedui_group_fieldsr/   rU  )r  rV  rD  zDELETED CmfAutomationUiForm)ui_formr!   rJ   r)   rX  r  rR   r_  r   ZCmfUiFormSchemeRulerY  r   rZ  targetui_form_jsonr;   r   addr4   r>  rJ  ra  ui_form_namerY   rc  Zui_get_hook)r:   r/   rg   r5   rf  rh  Ztmp_is_public_formZtmp_ui_view_formZtmp_include_deletedZtmp_objZui_form_scheme_ruleZ
fields_setgroupsZ
group_datar  retr   r   r   ui_get  sP    


zBaseModel.ui_getc          
      O   sz  d| j kr |ds |dd |rf|D ]<}t| |d}t|ddr(tjsT|jt_q(ttj|jt_q(| jj|d|i|}|svd|krv|	d}t
|tr|j}|dk	rvd|krv| tjkrttd	rtjj|d
gd}|rvdd|jg|d< | jj|d|i|}nd| tjkr nV|sv|dd }	|	 rvt|	dkrvd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
        ra  rD  FNrT  r  r   r   CmfTaskCodeHistorytask_id)r   r/   r   r^  r  r  LIKEz%-)r/   r!   r\   r^   r   jscache_timeliferT  minro   popr   r   rh   r   r   rY   rl  rX  rm  r   isdigitr   )
r:   r  rg   r5   r?   rH   instr   Ztask_code_historyZcode_numberr   r   r   rJ    sD    


zBaseModel._getc                O   s   |  |}| j|d|i|S rP  )r>  _listrR  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 rS  )r>  r   r^   r3   ru  rW  r   r   r   slistL  s    
zBaseModel.slistc                O   s   t | dr |ds |dd |rf|D ]<}t| |d}t|ddr(tjsT|jt_q(ttj|jt_q(| jj	| f|d|i|}|S )   
        Т.к. по show definition люди придут за гайдом по использованию filter именно сюда, дублирую доку
        https://bcrm.carbonsoft.ru/project/Document/DOC-000282
        ra  rD  FNrT  r  )
rY   r!   r\   r^   r   rp  rT  rq  ro   r3   )r:   r  rg   r5   r?   rH   Z	inst_listr   r   r   ru  Z  s    
zBaseModel._listc                O   s   |  |}| j|d|i|S rP  )r>  _countrR  r   r   r   countm  s    
zBaseModel.countc                O   s@   t | dr |ds |dd | jj| f|d|i|}|S )rw  ra  rD  Fr  )rY   r!   r\   ro   ry  )r:   r  rg   r5   rj  r   r   r   rx  u  s    zBaseModel._countc                 O   s   | j j| jf| S rC   )ro   query_deprecatedrq   r   r   r   r   rz    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 }t|tj jr||pRt|dd}|rhdd |D }n| }|
sddg}
tj	d	| d
 d}|D ]}|pi |j
}|dkr|jpg }|	r||	g}|rt|dk r$ddd| dgddd| dgdd| dgddd| dgg}n&dddd| dgddd| dgg}|j
dkr|dkrd|dddd| dgddddgggg}|j
dkr|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r:q||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   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, показали первые 100r  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.rc   r  r   r   r   <lambda>      z.BaseModel.field_options_list.<locals>.<lambda>EXISTSr  r   )r/   r  sliceorder_byu)   Некорректный тип поля )r/   r!   rZ   rW   r   r   r^   r,  r   r   rR   default_options_filterr   anybuiltinsr  ry  r*  rq  r:  r3   )r:   r!  	object_idZobject_fieldsmodels_listr  r/   r~  r  r  r  r|  r5   rH   resultsr  r,  Zprocessed_countmZmodel_filterZsearch_filtermodel_countZmodel_startZmodel_lengthZmodel_slicer   r   r   r{    s    



zBaseModel.field_options_listc                 C   sd   |  |d }t||}|D ]B}ttjj|d dd   |d }|| |jdd qd S )Nr   r   r   r   depth)	r!   r^   r   r   r   r   r   ra   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   rc   r  r   r^   rq   )r:   queryr  r  Zorder_fieldsr   r   r   r   order_query  s    


 zBaseModel.order_queryc                 C   s   t | j dt  S )Nr   )r1   r   Zuuid1r   r   r   r   r     s    zBaseModel.gen_idr   c                 C   s`   |dks| j sdS d| _ | jddD ]6}|jsJt|jtrJt|jddrJq$|j|d d q$dS )ub   
            сброс состояния объекта после сохранения
        r   NFTr  r   r  )r   r}   r   r   rh   rv   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   %  s      z2BaseModel._load_changed_fields.<locals>.<listcomp>Tr   c                    s    g | ]}t t |ts|qS r   )r   r^   r  r   r   r   r   r   &  s      )r   r   r@  )rF   r/   r   r   r   _load_changed_fields   s    zBaseModel._load_changed_fieldsc                 K   s   d S rC   r   rF   _kwargsr   r   r   before_save_hook*  s    zBaseModel.before_save_hookc                 K   s   d S rC   r   r  r   r   r   before_save_data_hook-  s    zBaseModel.before_save_data_hookc                 C   s   g S rC   r   r   r   r   r   save_preload_fields1  s    zBaseModel.save_preload_fieldsc                 C   s   |   }|r| | d S rC   )r  r@  )rF   r  r   r   r   save_prepare7  s    zBaseModel.save_preparec                 C   s   d S rC   r   r   r   r   r   check_simple_perm<  s    zBaseModel.check_simple_permc                 C   s   d S rC   r   r   r   r   r   _check_project_perm?  s    zBaseModel._check_project_perm	only_datac                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||S )N.r   r   r   r   )r}   r   r   r   r   r   r   r   r   r   rh   r   r   r   r^   r   r/   cmf_modified_by_idis_nullr   r   cmf_author_idr   r  
_save_data)rF   r  rg   r5   rH   r   r   r   r   r   _save_importB  s.    



zBaseModel._save_importc                    s   ddd fdd
}|S )NF)r  save_importc                    s6  d _ tjrd} tjs| s|rdt_t j f|dtji|}| rrdt_|ddrrt trr jrr 	  |rdt_ 
   jrd _   nt j f|ddd|  
  tjdkr   t tr jr       jf | t j f|d| i| d _d _     S )NTFr  emit)r  Z
invalidate)r   r   Zsave_only_data_hackr1   r  r!   r   rX   r   r  r  r   import_originalr  disable_permissionsr  _calc_root_parentr  r  r   r  )r  r  rg   r5   r
  r   r   r   save_with_flush_  s:    
 
 
z5BaseModel.save_flush_wrapper.<locals>.save_with_flushr   )rF   r  r  r   r   r   save_flush_wrapper^  s    Bz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)ro   rl   r}   rR   r)  r   rh   )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r6 jnd}zb jsnd _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
r4 }	 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ox j d	  S )u)  
            Финальное низкоуровневое сохранение в базу
            Умышленно не разделяем save() на update() и create(), т.к.
            обычно в бизнес-логике очень много общего кода.
        Fc                    s0   d}||k r, j ddD ]}|j|| d qd S )Nr   Tr  r  )r}   r   )r  r  Z	max_depthrH   r   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, rO   , r   rP   )r6  _acl_check_writeverbose_namer   r1   ro   creater  r4   ZCmfOrmUniqueErrorr   r   r   logging	exceptionZCmfOrmIntegrityErrorr   r8  rI  rR   r   r/   )rF   r  r  rg   r5   r  r6  startr  r   r   r9  r   r   r   r    s6    

0zBaseModel._save_datac                 O   s<  |   D ]}|jdk	rtjrqttj}t|t	rD|j
rD| |_t|trZ|j
rZ||_| jr|jdk	rlqt|t	r|jr| |_t|tr|jr||_qttdd}|r$d| jkrtjrtjr| jjr|j| _| jrd| jkr| jjdkr|j| _| jr$d| jkr$| jjdkr$|j| _| jf | | j||S )uA   
        Супер общая бизнес логика
        .r   Nr   r   r   )r}   r   r   import_moder   r   r   r   r   r   r   r   rh   r   r   r   r^   r/   r  r  r   r   r  r   r  r  r  )rF   rg   r5   rH   r   r   r   r   r   r     s4    



"zBaseModel.savec                 C   s   |    | j  | S rC   )r   ro   Zcommitr   r   r   r   _test_save_commit	  s    
zBaseModel._test_save_commitc                 K   s   t t}tjjjtjjjtjjjf}t	 D ]}||kr:q,|j
ddddgd| |dD ]X}t|ddr|t|j t|j t|ddrT|t|j t|j qTq,|S )uw   
        Формируем кеш словарь связи объектов по parent_id и tree_parent_id
        r  r   r   tree_parent_idT)r/   TECHCOM_nocacherD  include_systemN)r   r   r   r   r   CmfAccessListZCmfAccessRule
CmfCommentr(  r   rv  r^   sysinternr   rg  r   r  )rD  r  r5   resultZskip_modelsrl   Zobj_datar   r   r   _build_relation_cache  s"     
"zBaseModel._build_relation_cachec                 K   s~   t  }tjj| jkr|  d}z<z|jf ddi| W n t	k
rZ   t
 } Y nX W 5 tjj| jkrx|j|  X d S )NNNNr?  T)r   disable_aclr   r   r   r  	__enter____exit__deleter  r  exc_inforF   r   r5   r  r  r   r   r   _delete_child_object&  s    zBaseModel._delete_child_objectc           
      K   s   | j f |}t }| jjh}|rjt }|D ]8}||kr*|| D ]"}||krLq>|| || q>q*|}qtjjjj	dgdd|gddD ]}| j
|f| q|D ]*}tjjj|dgd }	r| j
|	f| qd S )Nr   r   r\  Tr/   r  r  r   )r  r   r   rh   rg  r   r   r   r  r3   r  r   r   
rF   r5   Zrelation_cacheZchildren_id_setlevelZ
next_levelr   Zchild_idcommentchildr   r   r   _children_recursion_delete6  s,    


  
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^  Tr  )r   r   r   r3   r  rF   r5   Zessential_child_model_nameZessential_child_modelr  r   r   r   _essential_children_deleteR  s    

z$BaseModel._essential_children_deletec                 K   s   |ri S g S )u(   Получим всех потомковr   )rF   group_by_modelsr  r   r   r   list_childrenY  s    zBaseModel.list_children)	recursiver?  TEXKOM_db_deletec                O   s   | j dgd | jdkrf|s |r6| jf d|i| n0|s^| jdd }r^td|  d|n|   t| tr| jr|sd| _	|
d	d | j||S |   t| jj| f||S )
Nr   r   r  	CmfNotifyZCmfAttachmentr  T)	skip_subsu   Нельзя удалить u1   , на него ссылаются потомкиr  )r@  rR   r  r  ZCmfOrmHasReferenceErrorr  r   r(  logical_deletera  r\   r   r  r1   ro   r  )rF   r  r?  r  rg   r5   childrenr   r   r   r  ]  s    
zBaseModel.deleter  c                O   sF   d| _ |dd | j||}| jdkrB|r:| jf | n|   |S )uy   
        Восстановление из корзины логически удаленного объекта
        Fr  Tr  )ra  r\   r   rR   _children_recursion_restore_essential_children_restore)rF   r  rg   r5   r  r   r   r   restorew  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  rD  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|gdddD ]}| j
|f| q|D ],}tjjj|dgdd }	r| j
|	f| qdS )	ul   
        Рекурсивно восстанавливаем все дочерние объекты
        T)rD  r   r   r\  r  r[  N)r  r   r   rh   rg  r   r   r   r  r3   r  r   r   r  r   r   r   r    s.    


   
z%BaseModel._children_recursion_restorec                 C   sD  | j dkrd S | j dkrBtjtjkrBtjjd| j| dd tdt	| t
oR| jj}t	| tod| jj}| jrt	| to| jr| jjn| jj}nt	| to| jj}| j}zF| jddD ]4\}}|jrqtjjd	||||| jj|| | jd
	 qW 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_statusuX   Отказано в модификации системного объекта {self.id}Tr  write	access_levelinitial_acl_keyobject_modelZobject_owner_idobject_fieldr  object_parent_idobject_instancer   u:   Отказано в модификации объекта )rw   r   r   system_personr   CmfAuditaudit_eventrR   r   r   rX   r  oldr(  r   rx   r   r  newr   r   r  check_accessr   rh   rg   )rF   r  obj_parent_idZobj_owner_idrR   r?   rH   r   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}| j}zP| jddD ]>\}}|j	r^qNt
jjd|||| jj|| | jd}d|krNtqNW 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   u0   Отказано в чтении объекта r  r  )rw   r   rX   r  rh   r(  r   rR   r   r   r   r  r  r   r   r   rg   r   r  )	rF   r   r  r  rR   r?   rH   rulesr   r   r   r   r     s2        
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  rg   r5   r   r   r   r   r    s    
zBaseModel.createc                 C   s   | j S rC   )rU   rr   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   r5  0  s   
 z-BaseModel.all_models_meta.<locals>.<dictcomp>r/   )rR   rb  rd  r/   )	_all_models_metar   rV   rU   r   rd  ra   rR   rb  )r:   _argsr  r  ZmodelClsZcustom_fields_metar   r   r   all_models_meta(  s"    


zBaseModel.all_models_meta)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f |S )Nr   )r  r/   r   r^   r   r   Z
CmfBackrefCmfGenericBackrefCmfTUUIDZforeign_keyrR   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^  ==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   r  c  s     z-BaseModel.upsert.<locals>.check_simple_filterT)r   r  )Z
for_updater  r   u9   Ключ в фильтре upsert не уникален: r  r   r   r  )r3   r   r   r   r   r4   )r:   r  r  r  r5   Zobj_listr   r  r   upsertU  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   rO   : rP   )rY   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   rv   	from_jsonr   r   r   r   r     s     z'BaseModel.from_json.<locals>.<listcomp>r   c                 S   s   i | ]\}}|t |qS r   r  )r   r$   r%   r   r   r   r5    s      z'BaseModel.from_json.<locals>.<dictcomp>r   T)r   r3   r]   r  Zget_cls_by_tuuid_strr   )r   r  r:   r/   r   r   r   r    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/   rj  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  ro   Z_load_extra_fieldsr   r/   r   rW   r	  r  r!   CmfRelationZCmfM2Mrl   r   r   dump_data_dictCmfGenericRelationCmfGenericM2MrI  ra   )
r:   Z	upper_resr  r  rG   Z	item_dictr?   r@   Zfk_modelr  r   r   r   r    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 r   )r   rv   r   r	  r  )rF   otherr   r   r   __eq__  s    

zBaseModel.__eq__)NNF)FN)NN)NN)NN)NNNNNr   F)N)NN)N)NNTF)NN)NF)N)N)
NNNNNFNNNN)NN)r   )N)FN)T)N)N)N)r   r   r   rm   rV   Zfields_orderr  r  Zverbose_name_pluralr   rb  rd  r   Zno_cacher  r   rN   rw   r   __annotations__r   rx   boolry   r   rz   r{   rQ   r/   rS   r   r   iconrd   classmethodr   r   rI   r   r   ri   r   r   r   re   ro   r   r   r   r}   r   r   r   r   r   r   r   r   r   r   r  r]   r-  r4  r3   r  r;  r@  r=  r   r2   rL  rN  r>  Typeru   r!   rX  rk  rJ  r   rv  ru  ry  rx  rz  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  r4   r  r  r  r  r  r   r   r   r   r   rv      sV  


	
 




  A

"
0 "
42  

                    ^



E

2!
(
*


+

<)	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  nullablerS   readonlyr  u
   Авторr  r.   r  r,  r   u   Владелецu   РодительrX   r.   
base_modelr  u'   Последний изменивший)r.   r  r,  r   autor   u   Кто захватил r  )r.   r  r,  r   r+  r   u   Дата захвата)r.   r  r,  indexr   u   Дата создания)r.   r0  r   r  r,  r1  r+  u   Дата изменения)r.   r0  r   r  r,  r1  r+  r   u   Дата просмотра)r0  r.   r   r  r,  r1  r   u   Удален)r.   r  r,  r   r+  r1  u   Номер версииZ
CmfVersion)r.   r  r,  r1  r   widgetr   c                 C   s
   t | jS rC   )r1   r~   r   r   r   r   r~   b  s    zCmfModel.db_nameNc                 K   s|   ddg}|r4dD ]"}|D ]}| | d|  qq| j|d t }| jrX|| j t| dg D ]}|| qdt|S )Nr   cmf_owner_assistants)r   r4  r-   r   )ra   r@  r   r   rg  r^   r3   )rF   r/   r5   Zself_fieldsZperson_field_namer  r  ownerr   r   r   all_relation_personsf  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   ra  cmf_versionr  
cmf_importr  import_raw_jsonext_idr  )r.   r?   Zfield_qualnamerequiredr  r#  )ra   r/   r}   rR   r)  r.   r   r+  r  r  r#  )r:   Zfields_namer  r/   r?   rH   r   r   r   import_shop_fieldst  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   )r]   r   r)  rY   r   r   r   r   r   r!   r8   r  )r:   rg   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   r4  Z
user_localr  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  )r7  r   r'  r   r   r   r   strftimer   r   r   r   _increment_version  s    zCmfModel._increment_versionc                    s   |    t j||S rC   )r>  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_ownerr4  r   )
r@  r   r  r  r   r  r   ra   rY   r4  )rF   r  perm_parentr5  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   r4  r?  r@  c                 S   s   g | ]}|r|qS r   r   r   r5  r   r   r   r     s      z'CmfModel.get_owners.<locals>.<listcomp>)r@  r   r  r   r   ra   r  rY   r4  r  r:  rB  )rF   rg   r5   Zownersr5  r   r   r   
get_owners  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   rB  r8   r  r   rA   r   r   r    s    zCmfModel._acl_check_writec                 K   s   |ri ng }t  D ]}dd| g}|r4|j| jkr4q|rD|jdkrDqt|tr^d|dd| gg}|r~|j|d }r|||j< q||j|ddgd q|S )ur  
        Получим всех потомков
        Пока только parent and tree_parent
        Может логику через модель надо определять, т.к. связи разные могут быть...
        Поддержка soft_link? Связи, которые надо разрывать при удалении.
        r  r^  )r  r]  tree_parentr  r  r/   )	r(  r   rR   r   rW   rX   ry  r:  r3   )rF   r  r  r  r  rl   Zfilter_r  r   r   r   r    s    

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  loadr;   rh   r  r   r   r   get_project_name  s    zCmfModel.get_project_name)N)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CmfBoolra  Z	CmfBigIntr7  re   r   r~   r6  r$  r<  r  r{  r>  r   rB  rD  r  r  rJ  rt   r   r   rA   r   r(    s   
   	
     

      

r(  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 )
BaseM2MModelTr(  r)  Fr*  u%   Родительская запись)r.   r1  u   Корневая записьN)
r   r   r   r   rK  ZCmfM2MTUUIDr   r  r   Zroot_idr   r   r   r   rR  	  s   
rR  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.   r+  r   r   r   r   description	  s   rV  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   ri   rY   r;   Zleft_name_cacheZright_name_cacher   rA   r   r   ri   	  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)ro   rp   rX  r,  rq   r1   r   rz  joinright_idr   left_idr  r   rh   r  allr:  r  )r:   r   r  r  r  ro   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
CmfStr4096rV  ri   r$  rc  rt   r   r   rA   r   rS  	  s
   rS  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.descriptionrT  TNrU  r   r   r   r   rV  U	  s   rV  c                    sV   t  j|| d|kr0t|d dr0|d j| _d|krRt|d drR|d j| _d S rW  rY  r   rA   r   r   ri   Y	  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 )NrX  r  )ro   rp   r   r   r  rl   r   r1   rX  rq   rz  rZ  r[  r   r\  r  rh   r  r]  )r:   r   r  ro   r^  rZ  Zleft_clsZ	right_clsra  r`  rb  r  r   r   r   rc  `	  s.    





zCmfM2MModel.select_related)Trd  r   r   rA   r   re  R	  s
   re  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eed
ddddd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$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dd,Z&ej jej jdd-dd.Z'ej jej j(d/ddg d0Z)ej jej jd1d2ddg d3Z*ej jej jd4ddd5Z+ej jej jd6dddd7Z,ej jej jd8ddd5Z-ej jej j.d9d dd:Z/dZ0g Z1d;gZ2ej jej j3d<dddd=d>Z4 fd?d@Z5e6dedBdCdDZ7e6dEdF Z8e6dGdH Z9dIdJ Z:e6dKdL Z;e6ddMdNZ<e6ddOdPZ=e6ddQdRZ>e6ddSdTZ?e6ddUdVZ@dWdX ZAdYdZ ZBeCd[d\ ZDd]d^ ZEd_d` ZFdadb ZGdcdd ZHdedf ZIdgdh ZJdidj ZKdkdl ZLdmdn ZMddodpZNdddqdrdsZOddtduZPd=dveQdBdwdxZRddzd{ZSd|d} ZTd~d ZUdd fdd
ZVdd ZW fddZXd=ddd fdd
ZYdddZZdd Z[e6dd Z\e6dddddddZ]dd Z^dd Z_dd Z`dd Zaddd fdd
Zbdd fdd
Zcdd Zde6dd ZedddZfdddZge6dd Zhej jej jddddZiej jej jdddZjej jej jdddddZkej jej jdddd.Zlej jej j.ddd ddZmej jej jndddd#dZoej jej jnddd#ddZpej jej jnddddZqej jej jdddddZrdd Zsdd ZtddĄ ZuddƄ ZvdddȄZwddʄ Zxdd̄ Zydd΄ ZzdddЄZ{dd҄ Z|ddԄ Z}ddք Z~ fdd؄Z  ZS )rX   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  r1  u   Кодu3   Код в реальном мире из жизни)r.   r1  uniquer,  r  u   Системный объектu   Нельзя удалятьF)r.   r  r+  r   r  u
   Текстu   Текст сущностиu!   Добавить описание)r.   r  Zplaceholderu   Задачи сущностиr   r  )r.   r   backrefr  u#   Документы сущностиr   u'   Комментарии сущностиr  r  	CmfImportu   ИмпортированZimport_objects)r+  rl   r.   ri  r  u,   Исходная версия импортаr  )r.   r  r+  u&   Сырые данные импорта)r.   r+  r  u"   Ид внешней системы)r.   r,  r  u   Избранный дляZCmfPersonVarZ	favorites)r.   rX  rl   ri  r  r   u3   В избранное всем участникам)r   r.   r  u!   Родительская нодаr-  u   Ветви дереваrE  )r.   ri  r  r,  r   u(   Есть вложенные узлы old)r.   r  r,  u$   Есть вложенные узлы)r.   r   r  r,  u)   Не отображать в деревеu!   Корневой Родительr.  ordernou   Сортировкаr   )r.   r1  r  r+  r   c                    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csvr3  c                    s0   fdd}fddfdd}dd }sHd	d
 j  D t }|dkr2| d}t|ddd}	ddl}
|
j|	dd|
jd}g }t| D ]\}}g }D ]R}|dkrt	|||t
j jr||||j n
|| |||| q|dkr|| || qW 5 Q R X n|dkr| d}t|ddd|}|d |d t| D ]L\}}t }|jddD ] \}}|j|jd||< q||| qt|d W 5 Q R X ntd| t|d,}t|  W  5 Q R  W  5 Q R  S Q R X W 5 Q R X dS )zV
        https://bcrm.carbonsoft.ru/project/Document/DOC-007693#spec-007668-b
        c                  3   sD   d} d}j  | | | gd}|s&q@| |7 } |D ]
}|V  q2qd S )Nr   r  )r  r  r/   )r3   )r  stepdatarow)r   r:   r/   r   r   paginate_data
  s    z,CmfEntity.export2file.<locals>.paginate_datac                    s^   | sdS t | trt| jS t | tr0t| jS t | trRd fdd| D S t| S d S )Nr   ,c                    s   g | ]} |qS r   r   )r   rv  convert_valr   r   r   0
  s     z>CmfEntity.export2file.<locals>.convert_val.<locals>.<listcomp>)r   rX   r   r;   r(  r   r3   rZ  )valry  r   r   rz  (
  s    




z*CmfEntity.export2file.<locals>.convert_valc              	      sh   d}| D ]0}|d| d| | d  d| | d  d7 }qd j  d| d	 d  d
| d j  d	}|S )Nr   <z
 caption="r.   z	" value="rh   z"/>z id="r   z">z</>rR   )ru  r  r   rr   r   r   dict2xml4
  s
    .*z'CmfEntity.export2file.<locals>.dict2xmlc                 S   s   | dD ]}t| |} q
| S )u   
            Получить поле объекта. Как getattr, только работает с вложенными полями
            Например: get_included_attr(doc, 'person.second_name')
            r-   )r   r^   )r   Z	field_strrH   r   r   r   get_included_attr;
  s    z0CmfEntity.export2file.<locals>.get_included_attrc                 S   s   g | ]}|j r|jqS r   r  )r   rH   r   r   r   r   G
  s      z)CmfEntity.export2file.<locals>.<listcomp>rs  z/export.csvzw+r   )newliner   N;")Z	delimiterZ	quotecharZquotingZxmlz/export.xmlz&<?xml version="1.0" encoding="utf-8"?>z<tasks>Tr  )r.   rh   z</tasks>u7   Это формат не поддерживается: rb)r/   r}   tempfileZTemporaryDirectoryopenrs  writerZQUOTE_MINIMAL	enumerater   r   r   ra   r.   Zwriterowr  r]   r   rh   r  base64Z	b64encoder  decode)r:   r/   r   Zformat_filerw  r  r  Ztmpdir	file_pathZcsvfilers  r  Zcsv_headr   rv  Zcsv_rowrH   r  ru  r?   r  r   )r   r:   rz  r/   r   export2file
  sR    


 






zCmfEntity.export2filec                 C   s   | j od| j kS )N-ordernor  rr   r   r   r   _is_orderno_descending_sorto
  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   x
  s   z.CmfEntity._revers_ordering.<locals>.<listcomp>r  rr   r   r   r   _revers_orderings
  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   r4  r  c                 S   s   g | ]}t |jqS r   )r   r;   rC  r   r   r   r   
  s     z/CmfEntity.check_owner_perms.<locals>.<listcomp>u   Это действие над u4    разрешено только Владельцу(u1   ) или Руководителю проекта(u   ) или Помощникам(u   ) или Admin.)message)r   r  r   rD  r   r   r;   r  rY   r4  rZ  r   r   r  Zcheck_admin_mode)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                 O   sL   |t jjkr$|t jjkr$tddd tjj||dsHtjt j|d  d S )NzKDEV: FATAL self.id != g.current_person.id and self.id != g.system_person.idTr   )	person_idobj_id)personr   )	r   r   r   r  r   r   ZCmfPersonViewr!   r   )r:   r  r  rg   r5   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 )Nrk  r   r}  r|  r  r  r  r/   r  r&  Tr  r  orderno_partition_byr!   _orderno_filterra   rk  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 )Nrk  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   r`  rF  )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  rF  )r!   r  r   r  )r:   r  r  r  r   r   r   	move_down
  s    
zCmfEntity.move_downc                 C   sd   | j |d}|d }| jddg|||d gd}t|s<d S |d }|j|krRd S | j||j|dS )NrF  r  r  r   r   r/   r  r  r   )ry  r3   r   r   r  )r:   r  r  Z
count_objsZ	half_objsZbefore_listr  r   r   r   move_middle
  s    
zCmfEntity.move_middlec                 C   sR   ddd gg}| j rNg }|| | | j  | j D ]}||dt| |g q2|S )Nrk  !=r^  )r  ra   r@  r^   )rF   r  Zpartition_filterr?   r   r   r   r  
  s    

zCmfEntity._orderno_filterc              	   C   sb   | j r| jrd S |  }t  | j|dgdgd}W 5 Q R X |rX|jrX|jd | _nd| _d S )Nr  rk  )r  r  r/   r&  )r   rk  r  r   r  r!   )rF   r  Zmax_itemr   r   r   _calc_orderno
  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   href  s    zCmfEntity.hrefc                 O   s   dS )un   
        Условие отображения оповещения в ОС через браузер
        Fr   r   r   r   r   	notify_os  s    zCmfEntity.notify_osc                 C   s   d S rC   r   r   r   r   r   rq    s    zCmfEntity._calc_tree_parentc                 C   s   | j s|  | _ d S rC   )r   gen_coder   r   r   r   rr    s    zCmfEntity._calc_codec                 C   s   t   dd l}| }|  d |   }d}d}| jdd|gdd| jggdd	r|d
7 }|   d|   }||k s6td| d| j dq6| | }|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  rD  r   u8   Превышен лимит поиска кода limit=z model=uA   , возможно надо отключить def gen_code: passz$!!! --- gen_code::duration too long r  r  rO   r  rP   )r   r  r6  get_code_prefixnext_code_numberrX  r   rB  rR   rI  r/   r   )rF   r6  r  r   limitr   r9  r   r   r   r    s     
 ".zCmfEntity.gen_codec                 C   s   | j S rC   )rL   r   r   r   r   r  3  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  rD  r   rn  )rX  r'  r   r   )rF   Z
max_numberZlastr   r   r    _get_current_code_number_from_db6  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   )timeoutzlock release error z, lock_name z
, timeout Nr   Z06)ZAPPREDIS_DBrR   redislockacquirerelease
exceptionsr   r   r8  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_nameV  s    zCmfEntity.gen_namec                 O   s
   | | j S rC   )	log_level)rF   r?   rg   r5   r   r   r   _get_field_log_levelY  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  )
rP  Zcache_fieldsr   rO  r7  ZviewsZlikesZstatus_closed_atZstatus_modified_atZstatus_in_progress_endr  Zcache_.u&   DEV: INFO. Возможно, поле uI    не попало в аудит, т.к. его old не загруженtextr  r4   r  r  r      z<br>)r  r  r   r  parent_name
audit_dataZhtml_diff_data)r   r   r)  rc   r   r   r8  r`   rh   r  r  Z
audit_diff	html_diffra   r   r;   rR   r  r   r   r  r   r   rZ  )rF   auditr  r  r?   r  r  Z_audit_diffZ
_html_diffr  tmp_namer   r   r   _system_auditb  s`    



zCmfEntity._system_audit)notifyr  c          	      O   s   | j r
d S |sd S | j|d | js(d S | jrD| jddddd d S | jddD ]R\}}|js`qP|j|jkrnqP| 	|}|d	krqP|
 }|rP| j||||d
d qPd S )Nr  u   Созданоr  FZ
obj_create)r  r  notify_typeTr  rn  Zobj_edit)r?   r  )r   r  audit_fieldsr   _audit_add_comment_and_notifyr   r   rh   r  r  r  )	rF   r  r  rg   r5   r?   r  r  r  r   r   r   _audit_changes  s*    
zCmfEntity._audit_changesc                 C   s<   t j| ||djdd}|dkr8|r8| j|jj||d d S )N)r  r  r  Fr  r   )r  r?   r  )r   r  r   all_place_notifyr  rh   )rF   r  r  r  r?   r  r  r   r   r   r    s    z'CmfEntity._audit_add_comment_and_notify)	recursionc                O   sH   | j ddgd t }| jr(|| j t| dg D ]}|| q4|S )Nr   r4  r   )r@  r   r   rg  r^   )rF   r  rg   r5   r  r5  r   r   r   get_all_followers  s    zCmfEntity.get_all_followers   Уведомлениеc                 O   s(   |   D ]}| j|jj|||d qdS )uw   
        Отправляем всем причастным людям текстовое оповещение
        )r  r;   r  r  N)r  _place_notifyr   rh   )rF   r  Znotify_namer  rg   r5   r  r   r   r   r    s    zCmfEntity.all_place_notifyc                 K   s   t jjf d| i| d S )Nr   )r   r  Zplace_notify)rF   r5   r   r   r   r    s    zCmfEntity._place_notifyc                 C   sd   | j jr`| j  | jdgd}|D ]:}|j  |jD ]$}| j rP| j| q8| j| q8q$d S )N
person_varr   )is_favoriter   favorite_forrI  r6  r  ra   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   ri   r   r   r  )rF   r   rg   r5   rA   r   r   ri     s    
zCmfEntity.__init__c                 C   sV   | j r| j jjs| j dg | j r,| j jp0| j}| j|krR| j  t|| _d S )Nroot_parent_id)	r  r  r   r@  r   root_parentrI  r   r   )rF   r  r   r   r   r    s    

zCmfEntity._calc_root_parentc                    s   t   dddg S )Nrk  zparent.root_parent_idr  )r8   r  r   rA   r   r   r    s    zCmfEntity.save_preload_fields)r  r  r  c                   sL  | 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!f d|i| |S )	NuN   Запрещено редактировать системный объект Tr   ztree_parent.tree_node_is_branchr  F)r  r  r  )"r  r   r   r   r;   r   r   r   r   r  r  rE  r@  r   tree_node_is_branchr   r  tree_child_deleterq  r  rr  r  r  rl  rm  rn  ro  rp  r   r  r  r8   _acl_spread_inheritancer  )rF   r  r  r  rg   r5   r  rA   r   r   r     s@    

zCmfEntity.savec                 C   s:   t jd| jdd t| j}|r6t jtj|S |S )Nr   r   r   )ospathrZ  r   r   r   r7  Z
UPLOAD_DIR)rF   Zabsoluter  r   r   r   get_files_dir:  s    "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   rj  cmf_emit_eventzevent-z1this event DEPRECATED, use is\_changed-class_namer   )r=   event_persons	emit_listr   Zevent_current_personr   r  placerR   Zrelation_personsZchanged_fieldschanged_relationsactionTr  )rO  r   rP  Zcmf_viewed_byrN  rM  .zemit: FIXME is changed bug r-   uR   DEV: INFO Могла не прийти инвалидация для old-поля r4   insertZdeletedjsurlr   session_tab_id)'collectionsr   rR   r   r  r   r  r   r   r!   r  rh   rY   r   r   r  r  r6  ra   r   r   r^   r   r  r8  r   r   r/   r   r  Z_changesr3   r`   r:  r   ra  r   r  r  )rF   r   r  r  Zbodypr  r$   r%   rH   r  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     z{}%r  z%{}%r  )stripr   r   ra   formatrZ  )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!   ra   rc   rR   r   r3   )r:   r  r/   r  r  rg   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   rZ   r   	lock_pingr   r   r   r   r    s    zCmfEntity.lock_pingc                 C   s   | j stdt| j S )ut   
        Из редиса заберём структуру, где есть данные
        :return:
        r  )r   rZ   r   	lock_infor   r   r   r   r    s    zCmfEntity.lock_infoc                 C   s   | j stdt| j dS )u`   
        Захват объекта на редактирование
        :return:
        r  i  )r   rZ   r   r  r   r   r   r   r    s    zCmfEntity.lockc                 C   s   | j stdt| j S )u>   
        Снятие захвата
        :return:
        r  )r   rZ   r   unlockr   r   r   r   r    s    zCmfEntity.unlock)r?  skip_owner_checkc                   s  |    | ddg | jr<|s<tjjd| j dd d S |sH|   tj	j
dd| jgdD ]}|jdd	 q^d
t d }| jrtd| jjs| d| j d | jj | _| d| j d | jj | _t| dr*t| dr*| jddgd | jr*| jj| _| d| j | _| j| _| j rB| j|  | js| j}| jdkr|| j  | jr|| jdd }tjj d| jt!j"| t#|d t$ j|d|i|S )Nr  r   u<   Нельзя удалять системный объект Tr   r  r  rF  )r  ZDELz%Y%m%d%H%M%Sz[A-Z]+-\d{4,}\Zr  loginemailr   r&   r  r   r  r  )r  r  r   r  r  r?  )%r  r@  r  r   r   r   r   r  r   r  r3   r  r   r   r=  r   rematchrh   Z
max_lengthr;   rY   r  Zdeleted_loginr  rE  rI  r  r   rR   r  r   r  r   r   r   r8   )rF   r?  r  rg   r5   r  r0  r  rA   r   r   r    sF    


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 j|d|i|S )	Nr  r  Tra  r  )rD  r/   r   r  )r@  r  r   r   r   ra  r  rE  r  r;   r  r  rg  rh   r(   r   r8   r  )rF   r  rg   r5   rE  rA   r   r   r    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  rF  NFTr  )
tree_nodesr,  rX  r   r  r   )rF   r  rl   r   r   r   r   r  (  s     zCmfEntity.tree_child_deletec                 O   s@  ddl m} |jjdddd}| s6tjjddd d}zt }tjjdd| jgdgdD ]&}|jd D ]}	|jd |	 ||	< qjq\t| d}
|
  g }| D ]}|tj|| d q|
| |
jr|
  |
  d}ntjd W 5 z|r|  W n4 t	k
r8 } zt
d	|  W 5 d
}~X Y nX X d
S )uD  
        Синхронизируем настройки полей с фронта
        Получаем список полей с фронта, в нужном порядке для ui_group.
        Приводим в соответствие модель, БД, и запрашиваемый список.
        Поля которые удалили(нет в fields) убираем из ui_group, но оставляем в базе(!!! важно) и в модели
        (в модели поля может не быть, если её удаляли).
        r   )r  z(lock::cmf__base_model__custom_field_synci  )r  Zblocking_timeoutu   Невозможно изменить список полей, так как уже запущен процесс изменения.Tr   z'custom_field_sync:: release lock error Nr  r  rf  rG  	ui_fieldsr_  )rl   FuI   Изменений в модели данных не обнаружено)cmf.appr  r  r  r  r   r   r   r  r   r   r8  r]   r   Z	CmfUiFormr3   rR   rf  CmfCustomClassinitr}   ra   CmfCustomField	from_dictrH  r   save_changesrG  )r:   rg   r5   r  Z
redis_lockZneed_release_lockr   r  Zui_form_rowr   custom_classcustom_fieldsZcustom_field_datar   r   r   custom_field_sync2  s8    	


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   r  ztask-comment-)r  zaudit-task-comment-)r  r  r  r   r6  )rF   r  rg   r5   r  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  rG  )r   ra   rY   r   r  r3   r   r   )rF   r  r5   r  _fieldsr$   r  r  r   r   r   _update_opened_notifiess  s    z!CmfEntity._update_opened_notifiesc                 C   s   dS )uE    Базовый шаблон почтовых уведомлений zmail_notification.htmlr   rr   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<   Список для проверки прав доступа)rl   r,  r  r.   u!   Наследовать праваu#   Наследуем права от )r  r,  r/  r.   u*   Кеш Владельца Родителя)r,  r  r.   r+  u;   Наследуемый список прав доступа)r,  r.   r+  r  u;   Эффективный список прав доступа)r,  r  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_inheritrA  r  r  r   )r@  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   rE  r   r  r  rA  )rF   rA  r   r   r   rl    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  )rA  r   r  r@  r  r  r  r  r   r   r   r   rm    s    
z#CmfEntity._calc_perm_inherit_acl_idc                 C   s   d S rC   r   r   r   r   r   rn    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_idrh   r   r   r   r   r  Zclear_auto_acl_acl_scaffold)rF   r?  r   r   r   ro    s.    


zCmfEntity._calc_perm_aclc                 C   s   d S rC   r   r   r   r   r   r    s    zCmfEntity._acl_scaffoldc                 K   s   |    |   | jrr| jddddg d| j_| jjD ]*}|jdkrR|  q:d|_|jdd q:| jj	  | jdd d S )NZpolicyr  zrules.disabledzrules.sys_typeTr0  r  )
r  r  r  r@  r  r  sys_typer  r   rh   )rF   r  Zruler   r   r   r    s    

zCmfEntity.disable_aclc                 C   sb   | j js$| jjs$| jjs$| jjs$d S | dddddg d }| j rL| jj}n| jrX| j}|| _d S )Nr  Zperm_acl_idr  r  r  )r  r   r  r  r  r@  r   r  )rF   r  r   r   r   rp    s$    
z"CmfEntity._calc_perm_effective_aclc                 C   s  | j r
dS | jjs| jjsdS td | jjrtd|   |}|dkrTt }|D ]F}tj	j
j d|j | jj| jjd}tdtt|  qXtd | jjrg }g }| jjg}|rd}|d| }||d }|}|dkrt }|D ]}tj	j
j d	|j | jj|d
}d}	|D ]\}
|	d7 }	|
d |krftd|
d  d q2t|
d dkr~q2||
d  q2q || }tdt| dt|  qtdt|  td |rd}|d| }||d }|}|dkrt }|D ]R}tj	j
j d|j | jj|d
}tj	j
j d|j | jj|d
}qtdt| dt|  qtd td tj  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 всё пересчитать без оптимизаций.
        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   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_listr   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
                                        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
                                            ZDoneu/   Шаг 3. Перезагружаем кеш ACL)r   r  r   r  r   r8  rX   r   r   r  ro   Z_ddZSessionZexecuterQ   rh   r   r   r3   r   rH  ra   r  Ztrigger_reload)rF   Zspread_modelsZ_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 )NTr4  F)r   r   rY   r4  r   r   r   r   r    s
    z"CmfEntity._acl_subjects_is_changedc                 C   s:   g }| j r|| j  t| dr6| jD ]}|| q&|S )Nr4  )r   ra   rY   r4  )rF   r  r5  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_read  s    z'CmfEntity._acl_subjects_list_level_readc                    s   ddl m} | jr| jr| jjdd }t||d }|oF|j| j}t	| t
oX| jj}|rd|js|jjd| jj|| jj| j| jj|| | jd	 t  S )Nr   r   r   r  r  )r   r   rf  r  rh   r3  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)NNrs  )NN)NN)N)N)N)T)NN)r  N)F)N)N)F)N)r   r   r   r   rf  r   r!  Zmenu_tree_parent_idZmenu_tree_ordernor|   r  compilerg  r(  rd   rK  Z	CmfStr256r;   ZCmfStr64r   rQ  r  Z	CmfMarkupr  r  ZtasksZ	documentsZcommentsr  r8  r  r   r/   ZCmfJsonr9  ZCmfStrr:  r  r  r  r  rE  r  Zhas_tree_nodesr  Ztree_hiddenrL  r  r  r  r  ZCmfIntrk  r  r$  r  r  r  r  r  r  r  r  r  r  r  r  re   r  r  rq  rr  r  r  r  r  r  r  r  r  r  r   r  r  r  r  ri   r  r  r   r  r  r  r|  r  r  r  r  r  r  r  r	  r
  r  r  Zperm_publicr  r  r  rA  r  r  r  r  Zperm_encryptr  rl  rm  rn  ro  r  r  rp  r  r  r  r  r  rt   r   r   rA   r   rX   |	  s  


		  
                       V




		
<

	
	6
b



.

,


             	   
      

 "
rX   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 )r  NrR   
field_typeui_group_name	ui_groupsrU   r.   rN   db_typedb_column_namedb_table_namer2  rl   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 )Nr   c                 S   s   i | ]}t ||qS r   )r  caption_to_name)r   choicer   r   r   r5  	  s      z,CmfCustomField.from_dict.<locals>.<dictcomp>)r  r  r  rU   r  r  r  r<  rU   )r   r   r   r3   Z__dataclass_fields___calc_db_choice_table_name)	r:   r#  rl   rU   Zui_meta_nativer5   r$   r%   r  r   r   r   r    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   )rZ  rR   r   r   r   r   r   )rF   rl   r"  r   r   r   gen_db_choice_table_name  s
    "z'CmfCustomField.gen_db_choice_table_namec                 C   s\   t | dd }|sd S |dkrDd| _| || _| j| _| j| jd< n|| |krX|| _d S )Nrl   ZCUSTOM_CHOICE_MODELT)r^   r!  r*  r"  rl   rU   )rF   rl   Z	rel_modelr   r   r   r&    s    z)CmfCustomField._calc_db_choice_table_name)N)r   r   r   rR   r   r!  r  r  r  r   rU   r]   r.   rN   r"  r  r  r
   r  r2  rl   r   r   r!  r"  r$  r  r*  r&  r   r   r   r   r    s(   
r  c                   @   s   e Zd Zee dddZdd Zee 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 )r  r   c                 C   s:   || _ d | _g | _d | _d | _g | _d | _d | _d | _d S rC   )	r_  Zcurrent_fieldsr  
db_columnsr   add_to_db_fieldscustom_fields_indexmodel_file_pathmodel_bk_path)rF   r_  r   r   r   ri   2  s    zCmfCustomClass.__init__c           	      C   s.  d| _ dd | jjj| jjD | _| j }tt	}| jj
 D ]}|jrD||j}d}d}t|ttfrrn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 |r| j| qDd
| _ qDdd | jD | _dS )u6   Загрузим конфигурацию моделиFc                 S   s$   i | ]}|d   dr|d  |qS )r;   r
  r  )r   columnr   r   r   r5  B  s    z'CmfCustomClass.init.<locals>.<dictcomp>Nr  r   r1   rl   )rR   r  r  r  r.   rN   r2  rU   r  r  r  rl   Tc                 S   s   i | ]}|j |qS r   r~  )r   
field_datar   r   r   r5  o  s      )r   r_  ro   rp   Zinspect_table_columnsrQ   r+  r   r   r3   r/   r}   rN   r!   rR   rW   r  r  r	  rr  r  _field_type_namer.   r2  rU   r&  r  ra   r-  )	rF   r+  Zfields_ui_groupsr@   r  r  Z_db_table_nameZdb_field_infor1  r   r   r   r  =  sH    



zCmfCustomClass.initr   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  Tr   N)rN   r  ra   rR   r_  r/   r+  r,  r   rY   r   )rF   r/   r1  rH   r   r   r   rH  q  s    zCmfCustomClass.merge_fieldsc           	         sj  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 ]ttjj}t|tsqtds,qtjj
jjjdkr fdd jrj D ]} d| qpqjr҈j D ]:\}}|dd	 D krtjjj
jj|jd
 qD ]8}jr|j j krtj!j
jj|j  qq" _#j#$d_%j#$d}j#& rPj#'j% (| |'j# dS )uP   Создадим поля в базе и сохраним файл модели.r&   r  r   ZCmfCascadeChoicec                    sx    fddD }|sd }n|d }|sLt jjjjj d jd}|rt di  D ]}|jj	| q`d S )Nc                    s(   g | ] }|j kr|j d  kr|qS )rh   )choice_parent_idr;   r   r$  r%  r3  r   r   r     s    
 zCCmfCustomClass.save_changes.<locals>._rec_check.<locals>.<listcomp>r   rh   r"  r  )
r   CmfCustomFieldChoicecreate_choicer_  rR   r"  r!   r}   r   rh   )r3  r%  Z
cur_choiceZvv
_rec_checkZch_model_datar1  rF   r5  r   r:    s     z/CmfCustomClass.save_changes.<locals>._rec_checkNc                 S   s   g | ]
}|j qS r   )r;   r4  r   r   r   r     s     z/CmfCustomClass.save_changes.<locals>.<listcomp>r6  z.bk))r,  r^   r   r/   r  rW   r  NotImplementedr"  r!  r_  ro   rp   Zadd_custom_choice_modelrR   Zadd_custom_m2m_modelr  rQ   r'  r	  r  Zadd_custom_columnr  rY   r   r7  Zlist_choicer2  r   r}   r   r8  r;   Zdelete_choice_get_model_file_pathr.  Zwith_suffixr/  r  rename_write_custom_model_file)	rF   r  r  Z
table_nameZcolumn_namer%   r$   r%  Zmodel_tmp_pathr   r9  r   r    sf    







zCmfCustomClass.save_changesc                    s   dd l  dd }z
|  W nz tjk
r   td | jr`| j r`td | j| j	 n(| j	r| j	 rtd | j	
  n |   Y nX  fdd}tjr | d S )	Nr   c                  S   sJ   t tj } 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/usr/bin/envpython3z	manage.pyZautogenT)check)pathlibPathr7  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     zDCmfCustomClass.apply_changes.<locals>.restart_crm.<locals>.<genexpr>/bin/systemctlrestart)rI  rJ  )
sleeprA  rB  r7  SERVICESr  rZ  rI  rE  Popen)Zcommandgeventr   r   restart_crm  s    

z1CmfCustomClass.apply_changes.<locals>.restart_crm)rO  rE  ZSubprocessErrorr  r  r/  r  infor=  r.  rD  r7  rL  Zspawn)rF   rG  rP  r   rN  r   rG    s$    



zCmfCustomClass.apply_changes)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#   Такое имя уже есть: rO   rP   )r   r   r   r$  ranger)  r+  )r  r.   Z	name_basennr?   r   r   r   calc_field_name  s    



zCmfCustomClass.calc_field_name)r.   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)   r4  r   r   r   rH    s     z1CmfCustomClass.caption_to_name.<locals>.<genexpr>)r   rZ  )r.   r;   r   r   r   r$    s    zCmfCustomClass.caption_to_name)r@   c                 C   s8   | j D ],}t|dd }t|tr|dr|  S qd S )NrR   ZCmf)rD   r^   r   r   rc   )r@   r>   Zbase_class_namer   r   r   r2    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)loaderc                 S   s    t | trd| ddS | S )Nz'''{}'''z'''z""")r   r   r  replace)xr   r   r   r    r  z9CmfCustomClass._write_custom_model_file.<locals>.<lambda>Zquotezcmf_model.tmpltcustom.Nr  )rN   r/  )Zjinja2ZEnvironmentZFileSystemLoaderr  r  rZ  r7  rC  filtersZget_templater_  	__bases__r   rc   r  r  Zrender)rF   r  Z	jinja_envtemplater/  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/fieldsrZ  r   r-   Nr  z/custom/T)parentsexist_okz__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)rA  rB  r7  rC  r_  rK   r\  r   rc   rZ  r   mkdirr  r  rI  r  r  findallrR   )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)r   r   r   r%  rX   ri   r  r   r  rH  r  rG  r&  r   rT  r$  r7   r2  rA  rB  r>  r<  r   r   r   r   r  1  s   4M.r  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   r!  rK   r   rJ   r   rc  rd  r;   r   r   r   r   rb  E  s   
rb  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_factoryr  rk  T
allow_movechildren_countr  r  )r   r   r   r  r   r!  r  r"  dataclassesrH   r3   r  rk  r'  rg  rh  r  r  r   r   r   r   re  _  s   
re  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   UBQLParseErrorq  s   rj  c                 C   s   d|krNt ||s*| d|j d| t||}t|tjjsFd S | S t	 }|
dd }d}tjj D ]8}t ||rrd}t||}t|tjjrr||  qr|s| d| t|S )Nr-   u   У модели u    не найдено поле rn  FTu0   Не найдено поле у моделей: )rY   rj  rR   r^   rW   r   r/   r   r,  r   r   r   rX   r   r4   r3   )r:   rl   Z
field_pathrH   r  Zright_field_nameZfound_field_flagr   r   r   _get_field_model_listt  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  ZCmfPersonGroupZ
CmfOrgUnitZCmfRoleZCmfWorkflowZCmfTagZCmfRelationOptionZCmfLogicTyper   Z
CmfCompanyZCmfActivityr!   r   rh   )r:   r   
model_listrl   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 INro  zNOT LIKEr  z	NOT ILIKEr  zNOT SIMILAR TOr  z
NOT EXISTSr]  r  r  z([^"'])z\1"z"\2)flagsr   []r   rn  rx  )r  ')ro  rp  rx  )rq  r  )g.current_userg.now()g.date())TrueFalseNoner  )r  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:    Должно быть:   ОШИБКА!!!)rI  r   rz  )
test_casesr   Zubql_convertedr  r   r   r   test_quote_ubql  s    d
zUbqlConverter.test_quote_ubqlr   c              
      s   t |}|dd}|dd}|dd}t|}fddttd	 fd
d z|} |}W nB jk
r } z"tj	d|j
d  d d }W 5 d }~X Y nX |S )Nrr  z'__G_CURRENT_USER'rs  z	'__G_NOW'rt  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)   rk  ra   rm  )r   Zskip_orderbyZblqr?   rl  r{  Zexists_filterZ_valZ
tuuid_valsr   r   )_recursive_ubql_processr:   rl   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:  ra   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)   ra   )r   r  r   r   )_recursive_ubql_order_byr  r   r    s$    

**
z8UbqlConverter.ubql2bql.<locals>._recursive_ubql_order_byu&   Ошибка обработки UBQL: r   u   . UBQL отключен)r   rz  rX  astZliteral_evalr3   rj  r   r   r   rg   )r:   r   rl   Zfilter_ubqlZ
filter_bqlr   r   )r  r  r:   rl   r   r   z  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()]rO  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  rI  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  rj  r$  rk  rm  r&  r   rz  r  r3   r   r  r  r   r   r   r   r   p  s   

Z
wz
7r   )Dr  ri  rA  r  r  r   r  r   r   Zcollections.abcr   r   r   	functoolsr   typingr   r	   r
   typesr   r  r  Zredis.exceptionsr  rE  r   Z
sqlalchemyr   Zsqlalchemy.ormr   Ztransliterater   Z
cmf.fieldsr   r   Zcmf.util.immutablesr   r   Zcmf.utilr   Zcmf.base_errorr   r   r   r   rn   r  r  r'   r[   r    r+   r1   r,   ZTypeVarru   rv   r(  rR  rS  re  rX   r  r  rb  re  r   r   r   r   r   <module>   s   

u              D  ;*          |B  