B
    fb                 @   s^   d dl m Z mZmZ d dlmZ d dlmZ d dlT d dlm	Z	m
Z
mZ G dd de	jZdS )	    )datetime	timedeltatimezone)uuid1)	dataclass)*)
cmf_notifyCmfRelationCmfTypec                   s  e Zd ZdZdZdZi Zee	j
ejde	j
ejdgZeed< ejf eZejjddd	g ZeG d
d dZedd Zedd Zedd Zed<ddZedd ZeedddZeedddZed=dd Zed!d!d"edd#d$Z  fd%d&Z!ed>d'd(Z"ed?d)d*Z#ed+d, Z$e%e&d!d!d-d.d/ Z'e%e&d!d!d-d0d1 Z(ed2d3 Z)ed4d5 Z*ed6d7 Z+e%e&d!d!d8d9d:d; Z,  Z-S )@	CmfNotifyZNotifyZdeskZNTFzcommon/templateszcmf/templatesloaderclose_open_notifiesconfirm_unconfirmed_notifiesplace_notifyc               @   s*  e Zd ZU dZdZeed< dZeed< dZeed< dZ	e
ed< dZeed	< dZ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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Zeed< dZeed< dZ dS )zCmfNotify.NotifyCtxu1  
        notify_type - тип сообщения
        возможные варианты:
        - просто сообщение (default) -- message
        - редактирование объекта -- obj_edit
        - создание объекта -- obj_create
        - удаление объекта -- obj_delete
        - добавление комментария -- comment_create
        - редактирование комментария -- comment_edit
        - удаление комментария -- comment_delete
        N	person_idnametextr   priorityFstrikethrough
alarm_datemessagenotify_typeobj_hrefobj_codeobj_parent_nameobj_link html_changed_fields
owner_nameowner_initialsperson_phone_mobileperson_phoneperson_nameperson_emailperson_loginmsg_from_idmsg_from_namemsg_from_codemsg_from_login)!__name__
__module____qualname____doc__r   str__annotations__r   r   r   intr   boolr   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   comments r2   r2   ./cmf/models/cmf_notify.py	NotifyCtx   s2   
r4   c             C   sl   |j p
|j}d|j d|j d|j }|  }|r<| }| j|}|j|d}t	| j
|||gd d S )N[z] (z) )ctx)args)r#   r$   r   r   r   +get_default_mail_notification_template_name
_jinja_envget_templaterenderschedule_deferred_jobprocess_email)cls
notify_ctxobjrcpt_tosubjectmail_templatetemplate
email_bodyr2   r2   r3   send_email_notify_old@   s    zCmfNotify.send_email_notify_oldc             C   s   t dd}|jp|j}t|dkr4|d d  d}| d|j d| |j }|jpZ|j}|svtd|j d d S t	| j
||gd d S )	NT)full_url   z...
u4   SMS уведомление пользователю u_    не отправлено, не указан номер мобильного телефона.)r7   )app_base_hrefr   msglenr   r    r!   	cmf_alertr"   r<   process_sms)r>   r?   urlsubjr   phoner2   r2   r3   send_sms_notify_oldO   s    
zCmfNotify.send_sms_notify_oldc       	      K   s  d|ks|d dkr&t jtjd|d< d|kr:|d}ntj}|jj|d< |j	j|d< |j
j|d< |jj|d< d	|d
< |rd|ks|d dkr|j	|d< d|ks|d dkrt jtjd|d< t|d tr|d j|d< |d |d< |ptj}|j	j|d< |ddg |jr |jjd nd|jr6|jjd nd |d< |rtdd}|j|d< |j
|d< | |d  |d< t|dr|jr|jj	j|d< nd |d< tj|}||d< |d |d< |d |d< |d
 |d < |d! |d"< |d# |d$< | jf |}|S )%Nr   .)tzmsg_fromr%   r&   r'   r(   u   Уведомлениеr   r   rK   r   r   
first_name	last_namer   r   r   T)rG   r   r   r   parentr   r   rQ   r!   phone_mobiler    r"   emailr#   loginr$   )r   nowr   utcpopgcurrent_personidvaluer   coderZ   
isinstancer
   current_userload_fieldsrU   rV   rJ   hrefhasattrrW   models	CmfPersonget_notify_opt_cachedr4   )	r>   r@   r   kwargsrT   Znotify_ownerrO   notify_optsr6   r2   r2   r3   prepare_notify_ctx_old]   sL    

4


z CmfNotify.prepare_notify_ctx_oldNr   Fr   c
          	   K   s  t jrt d dS t|d}tj|}|dkr8dS d}|t jj	krb|dkrb|d r^d}ndS |r|j
jrv|jjs|ddg d}|rd	}|sd
}| jdd|j	gdd|gdd|gdddgdddggdddgd}|st }|sd}|jr|jdkr| d|j }|jr$|jr$|r*||_d	|_| jd7  _||_||_d|_|	r^|	|_n
|j  |r|j|_|j	|_|j|_|j|_t|dr|j
r|j
jj|_ |j!|_"t|dr|j# rt$|jt%r|jj|_&nt'|j|_&nd|_|j(s
g |_(|j(rFt)|j(jdkrF|j(jdd d d |krF|S t j*j+r^t j*j+jd ndt j*j,rxt j*j,jd nd }|r|jjnd}t j*j	jt j*jjt j*jjt j*j-j|dt.j/t0j1d2 t./ 3d||dt4  |dd }|j(5| d|_6|jp||_|d! |_7|d" |_8|d# p.|d$ |_9|d% pB|d& |_:|sRd
|_|;  |d' sp|j<d(krt=d)|||j"jd*|gd+ |j<d,kr|j>st=d-| |gd+ |S ).u  
        obj: CmfEntity

        :param obj:
        :param msg_from:
        :param person: Идентификатор пользователя которому отправляется сообщение
        :param name: Наименование объекта уведомления
        :param msg: Текст сообщения
        force - форсированная отправка
        :param priority:
        :param strikethrough:
        :param alarm_date: Будильник для уведомлений
        :param force_notify_current_person: отправить сообщение себе
        :param notify_type: Тип сообщения. Описание см в структуре NotifyCtx
        uB   Уведомления отключены g.disable_notify = FalseNri   TFemail_if_self_changesrW   rb   openclosedobj_idz==r   status	cron_done	confirmed
unread_cntr1   
cron_force)filterfieldsu   Уведомлениеr   u
    + еще    r   r   )r`   r   rb   rZ   Zinitials)rS   z%H:%MzCmfComment:)Z	cmf_ownerZcmf_created_atZcmf_created_at_formattedmsg_type_textr   r`   parent_name	log_level
notify_smsZnotify_emailrX   rQ   rY   rZ   Z	notify_os1z	notify-os)r   commentr   )event_persons2znotify-important-)?r^   disable_notifydebugcmfutilZget_obj_id_by_anyrh   ri   rj   r_   r`   rW   
is_definedrb   re   getr   ru   r   rv   rr   Zpriotityr   r   r   Zset_nowr   rq   r   ui_nameZobj_ui_namerg   ra   r   rf   r   loadrc   r	   Zobj_status_namer-   r1   rL   rd   rU   rV   rZ   r   r[   r   r\   Z	isoformatZstrftimer   appendrs   person_notify_smsperson_notify_emailr!   r#   saver   cmf_emit_eventrt   )r>   rK   personr   r{   r@   force_notify_current_personforcer   r   rk   r   rl   Zdesk_notifynotifyZfilter_statusr   r|   r   r2   r2   r3   r      s    








zCmfNotify.place_notifyc       	      K   s0  t jrt d dS d|kr(|d dk	s0tdd|krD|d dk	sLtd|d t jjkrj|dsjdS d	|kr|d	}|d
dddg nd}|d}t	j
j|dddgd}|st d|  dS |dg }t	j||}| j||f|}|dkrdS | ||}|r,| || | | |S )u  
        obj: CmfEntity

        :param obj:
        :param msg_from:
        :param person_id: Идентификатор пользователя которому отправляется сообщение
        :param recipient_opt: Опции получателя для проверки разрешения получать уведомления пользователем
        :param name: Наименование объекта уведомления
        :param text: Тема сообщения
        :param msg: Текст сообщения
        :param priority:
        :param strikethrough:
        :param alarm_date: Будильник для уведомлений
        :param force_notify_current_person: отправить сообщение себе
        :param notify_type: Тип сообщения. Описание см в структуре NotifyCtx
        uB   Уведомления отключены g.disable_notify = FalseNrK   .u   Укажите msgr   u   Укажите person_idr   r@   rW   rb   r   rf   r~   zphone_mobile.numberzphone.number)r`   rx   u   В метод place_notify пришел отсутствующий или удаленный пользователь person_id=recipient_opt)r^   r   r   AssertionErrorr_   r`   r   r]   re   rh   ri   ZCmfPersonNotifyOptZcheck_permission_notify_eventZprepare_notify_ctxZcreate_desk_notifysend_email_notifysend_sms_notify)	r>   rk   r@   r   r   r   Znotify_allowedr?   r   r2   r2   r3   stol_place_notify<  s6    




zCmfNotify.stol_place_notify)event_type_codec             C   s  t  }t|drP|jdkrP|jr,|jdsPx| D ]}dh||jj< q6W |S |j}|jdkrh|jj}t|dsvd}tj	
||j d| }|stj	
|d| }|sdS g }xF|d D ]8}|j|d	d
}	|	dkr||t  || d qx|	D ]}
tj|
jj}|dkr"q |
js4||
 ||
jjt  d}|dkrd|d rdd	}nx|dkr~|d r~d	}n^|dkr|d rd	}nD|dkr|d rd	}n*|dkr|d rd	}||
jj d |r ||
jj d q W qW |rztjjdd}tjj|j|dgd}xP|D ]H}t|tjjrH|j}|jj|kr.|r.||d kr.||jj= q.W |d r>|jdkr>||d  x|d D ]}|| sqtt|| tjjrxd|| D ]*}||jjt  ||jj d qW n,||| jjt  ||| jj d qW xv|D ]n}|drftd| dd t j!rDtjj|d gd!}|rD|j"rD|j"jdrDtd"| dd qDW |S )#uY   
        Рассчитываем набор юзеров и их галочек
        logic_prefixZ
CmfProjectzCmfProject:rY   N.z
AllModels.Znotify_membersT)Zall_nested_personsFz
var:authorZemail_if_authorz	var:ownerZemail_if_owner)zvar:responsiblezvar:executorsZemail_if_responsiblezvar:spectatorsZemail_if_spectatorzvar:current_userrn   rd   zsdesk-client:default)rb   members)	parent_idZproject_role_idrx   Znotify_custom_fieldCmfTaskzvar:zDEV: Var user in notify! )abortrb   )r`   rx   z DEV: Var user person in notify! )#dictrg   
class_namer   
startswithZall_relation_personsr`   ra   rh   ZCmfProjectNotifySchemeZget_notify_rule_data_cachedZextract_var_obj
setdefaultsetaddri   rj   
user_localr   ZCmfProjectRoler   ZCmfProjectRoleAssignrW   rc   cmfrx   ZCmfRelationBasere   
issubclasstypeZ
CmfM2MBaserM   configDEBUGrb   )r>   r@   r   Z
recipientsuZtmp_parent_idZ	rule_dataZnon_local_personsZuser_idZ	var_usersZvar_userrl   rY   Z	proj_roleZproj_role_assignuser
field_nameir2   r2   r3   get_notify_membersu  s    







"

zCmfNotify.get_notify_membersc             C   s6  |dkrd}d}d||dgS |dkr<d}d}d||dgS |d	krZd
}d}d||dgS |dkrd}|d|j   7 }d}d||dgS |dkr|jdkr|jdkrd}d}nDd}|jj|jj }|d| 7 }|jj|jj }|d| 7 }d}d||dgS |dkrPd}|d|j j d|j jr4|j jnd 7 }d}d||dgS |dkr|jrd}|d|j   7 }d}d||dgS |d krd!}|d|j j d|j jr|j jnd 7 }d"}d||dgS |d#kr|jrd$}|d%|j	 7 }d&}d||dgS |d'kr>d(}|d%|j	 7 }d)}d||dgS |d*kr^d+}d,}d||dgS |d-kr|jrd.}d/}d||dgS |d0krd1}d2}d||dgS |d3krd4}|j
jr|d5|j
jj	 7 }|j
r|d6|j
j	 7 }d7}d||dgS |d8krg }|jjrd9}|jr*|jj	}d9}	|jr>|jj	}	d:| }||	kr`|d;|	 7 }|d<7 }|jj r|d%|jj  7 }d=}|d>||d |jjrt|jt|jj }
|
rd?d@dA |
D }d:| d<}|jj r|d%|jj  7 }dB}|d>||d |S |dCkr2dD}d>dE|dgS |dFkrhdG}|jj rVt|jj }dH}d>||dgS |dIkrdJ}|jj rt|jj }dK}d>||dgS |dLkrdM}|jj rt|jj }dN}d>||dgS |dOkr
dP}|jj rt|jj }dQ}d>||dgS |dRkr|jjr>|jr>|jjj|jjkr>g S |jdSkr\dH}d>dT|dgS d9}	|jrp|jj	}	dU|jj	 dV|	 d<}|jj r|d%|jj  7 }|jjr|jrdW|jjj	 dX|jj	 dY}ndZ}d>||dgS |d[kr
d\| }d]}d>||dgS |d^kr*d_}d`}d>||dgS |dakrRdb| dc}dd}d>||dgS |dekrrdf}dg}d>||dgS |dhkrdi}dj}x0|jjD ]$}||jjkr|dk|j	 7 }qW x0|jjD ]$}||jjkr|dl|j	 7 }qW d>||dgS dmdndodpdqg}|drkrg g g ds}xz|jdtduD ]j\}}|js<q(|j|jkrNq(||kr\q(||}|dvk rtq(| }|r(|| | q(W g }dw}|dv r|dvd|dv |d |d> r|d>d|d> |d |d r|dd|d |d |S | }d>dx| dy|j	 |dgS )zu  
        Логика:
        - по спец. событиям типа assigned, придет и assigned и updated, поэтому поля спец.событий
            дополнительно нужно отфильтровывать в updated
        Zrestoredu   Восстановленоu   восстановил   )r}   r   message_titleZdeletedu   Удаленоu   удалилZcreatedu   Созданоu   создалZ	publishedu9   Выпущены изменения в документеz<br>u!   выпустил документZshareddefaultu[   Отменен публичный доступ к документу в интернете.u9   отменил публикацию в интернетеui   Документ опубликован для публичного доступа в интернете.u   <br>Анонимные: u"   <br>Авторизованные: u,   опубликовал в интернетеZcomment_createdu$   Комментарий создан.z: r   u%   написал комментарийZcomment_updatedu&   Комментарий изменен.u%   изменил комментарийZcomment_deletedu#   Комментарий удаленu#   удалил комментарийZattachment_createdu#   Добавлено вложение u   добавил вложениеZattachment_deletedu   Удалено вложениеu   удалил вложениеZworklog_createdu+   Сделана запись о работеu)   сделал запись о работеZworklog_updatedu&   Журнал работ измененu&   изменил журнал работZworklog_deletedu$   Журнал работ удаленu$   удалил журнал работZmovedu   Перемещеноu    из проекта u    в проект u1   переместил в другой проектassignedu   Не установленu%   Задача назначена на u   , ожидает r   u'   назначил исполнителяry   z, c             S   s   g | ]}t |jqS r2   )r-   r   ).0er2   r2   r3   
<listcomp>]  s    z5CmfNotify._prepare_notify_message.<locals>.<listcomp>u-   назначил соисполнителейZresolvedu   добавил решениеu1   В задаче добавлено решениеrp   u   Задача завершенаu   завершил задачуZwork_startedu   Работа начатаu   начал работуZwork_stoppedu#   Работа остановленаu%   приостановил работуZreopenedu#   Задача переоткрытаu!   переоткрыл задачуchanged_statusZCLOSEDu   Задача закрытаu!   Статус изменен на u   , ожидаем u   изменил статус c "u   " на ""u   изменил статусZapprove_startedu.   Ожидается подтверждение u+   запустил подтверждениеZapprove_rejectedu6   Пользователь отклонил запросu   отклонил запросZapprove_success_fullu   Утверждение u    завершеноu)   утверждение завершеноZapprove_success_oneu:   Пользователь подтвердил запросu!   подтвердил запросZspectators_changedu'   изменены наблюдателиu4   Изменен состав наблюдателейu   <br>добавлен: u   <br>удален: responsiblerr   ZviewsZresult_textrW   updated)r   ry   r   T)
is_changedr   u   изменилu   Пришло событие u    по объекту )r   	html_diffZperm_policy_anonymousZperm_policy_guestchoicesra   Zcaptionnewr   r   rW   oldr   waiting_forrr   r   	executorsr   joinr-   rb   Zcache_status_typeZ
spectatorsitemsr   Z_get_field_log_level)r>   r@   r   rK   r   Z	anonymousZguestZresr   r   Znew_executorsr   Z	spectatorZskip_field_namesZtmp_listr   Z	field_objr}   r   r2   r2   r3   _prepare_notify_message  s   

*
*





















&













z!CmfNotify._prepare_notify_messagec          
   C   s   |j j}|jj}|jj}|jj}|j}tjj|d}	y$tj	j
|||||dd|	dsVdS W nH tk
rl   dS  tk
r }
 z|
jd |krdS  W dd}
~
X Y nX |jdkr|jrtjj|j|	dsdS |r|jdkr|jrtjj|j|	dsdS d	S )
u   
        Проверяет, что у получателя notify есть доступ к объекту
        Доп. проверяются права у private-комментариев
        )r`   readF)initial_acl_keyZobject_modelZobject_owner_idZ	object_idZobject_parent_idZaccess_levelZraise_errorchecking_personry   N
CmfComment)Zcheck_for_userT)Zperm_effective_acl_idra   r   cmf_owner_idr`   r   rh   ri   r   ZCmfAccessListZcheck_accessZCmfACLNotInitializedErrorZCmfACLNotFoundErrorr7   Zprivater   Zcheck_visibility)r>   r@   	member_idobj_commentr   Zobj_parent_idr   Zself_idr   r   r   r2   r2   r3   _check_perm_for_notify  s6    z CmfNotify._check_perm_for_notifyT)r   auditc            O   s   |j r
d S |sd S |sd S |js$d S tjr.d S d}|dkr>d}d }d }	|jdkr|}|jj}t|drt|j	 rtd S |j
dkrd S |jdkr|}|jj}|jdkr|}|jj}|jd	kr|jsd S |jd
kr|}	|jj}|r| ||}
n|	r| |	|}
n| ||}
|jdkrJ|sJx.|
D ]&}tj||d |d djdd q W |sTd S x|
D ]}|d dkrpqZ| ||}tjj d|d  d|j }|rZxt| D ]h\}}| j|||dsȐqtjj 6 tjj||||d |d d|krdnd|d W d Q R X qW qZW d S )NF)r   r   Tr   is_dummyr   ZCmfAttachmentZCmfTimeTrackerHistoryri   ZCmfGanttTask)r   ZCmfDocumentr   r}   )rW   r   r}   )r   )ry   r   r   r   )r   rd   )r@   r   r   rK   r{   r   r   )Zdisable_auditZsmart_notifyr^   r   r   rW   ra   rg   r   r   r}   r   Ztaskr   rh   r   r   r   r_   r   verbose_namer   r   r   utilr   Zdisable_aclr   r   )r>   r@   r   r   r   r7   rk   r   r   Zdependent_objZmsg_listZmsg_datar   r   r   Z	email_setr2   r2   r3   smart_all_place_notify  s    







z CmfNotify.smart_all_place_notifyc                s<   t  j|| td| j  d| jji| j gd d S )Nznotify-person-Z	notify_id)r   )superemitr   r   r   r`   ra   )selfr7   rk   )	__class__r2   r3   r   n  s
    
zCmfNotify.emitc             C   sh   |st jjj}dd|gdddgg}|r8|dd|jg | j|dgd}x|D ]}d|_|  qNW d S )Nr   z==rr   z!=rp   rq   )rw   rx   )r^   r_   r`   ra   r   listrr   r   )r>   r   r@   Z_filternotifiesr   r2   r2   r3   r   v  s    

zCmfNotify.close_open_notifiesc             C   sH   |st jj}| jdd|gdddggd}x|D ]}d|_|  q.W d S )Nr   z==rt   False)rw   T)r^   r_   r`   r   rt   r   )r>   r   r   r   r2   r2   r3   r     s    
z&CmfNotify.confirm_unconfirmed_notifiesc             C   s   |j dkr|j  }n&|j dkr,|g}ntd|j   d S xP|D ]H}tj|jj	}|d ksF|d slqFtj
j|||jd|j  d qFW d S )NZCmfPersonGroupri   z,DEV: handle_mention_event unknown obj type: Zemail_if_mentionsu   Вас упомянули в )r@   r   r   rK   )r   Z
rg_membersr   Z
all_nestedrM   rh   ri   rj   r`   ra   r   r   r   r   lower)r>   r@   Zevent_personZpersonsr   rl   r2   r2   r3   handle_mention_event  s    


zCmfNotify.handle_mention_event)	only_once
system_jobc             O   s   t j }|j| ||d d S )N)rB   )rh   CmfPluginMailBoxget_local_mailboxsend_message)Zrctp_torB   rE   r7   rk   mail_boxr2   r2   r3   r=     s    
zCmfNotify.process_emailc             O   s   t j }|| | d S )N)rh   CmfPluginSMSGateget_local_smsgater   )rQ   r   r7   rk   sms_gater2   r2   r3   rN     s    
zCmfNotify.process_smsc             C   s\   t jj|jdgd}|rV|jrV|jdrV|j|jddsVd|j	 d|j
 d|j S |jS )	Nr   )r`   rx   ztask.sdzsdesk-client:default)ZprojectZ	role_code/z/?obj=:)rh   ri   r   r   r   r   r   Zin_project_rolerW   	ui_moduler   rb   r   )r>   r   r@   r   r2   r2   r3   _calc_notify_obj_link  s
    zCmfNotify._calc_notify_obj_linkc       
      C   s   |j s
d S |j j}d|j d|j d|j }|  }|rB| }| j||d}tdd | |_| j	
|}|j|d}tj }	|	j|||d d S )	Nr5   z] (z) )r   r@   T)rG   )r   )rB   )r#   ra   r   r   r   r8   r   rJ   r   r9   r:   r;   rh   r   r   r   )
r>   r   r@   rA   rB   rC   rf   rD   rE   r   r2   r2   r3   r     s    
zCmfNotify.send_email_notifyc             C   sf   |j std|j d d S tdd |j }|j}| d| }|j j}tj	 }|
|| d S )Nu4   SMS уведомление пользователю u_    не отправлено, не указан номер мобильного телефона.T)rG   rI   )r!   rM   r   rJ   r   r   ra   rh   r   r   r   )r>   r   r@   rO   rP   r   rQ   r   r2   r2   r3   r     s    
zCmfNotify.send_sms_notifyz	@minutely)r   r   Zschedulec           
   O   s  t jjddgdddgdddggd}d	d
 |D }xZt jjdddgdddt tdd gdddgdd|gggdgdgd}|sP td|j d|  d }|j	rt
j|j	ddgd}|jry td t j|| d|_W n4 tk
r } ztd|  W d d }~X Y nX |jrty td t j|| d|_W n4 tk
rr } ztd|  W d d }~X Y nX d|_|  |j  q6W d S )Nz--rq   rs   z==Frv   T)rx   rw   c             S   s   h | ]
}|j qS r2   )rq   )r   r@   r2   r2   r3   	<setcomp>  s    z1CmfNotify.celery_minutely_hook.<locals>.<setcomp>ORZcmf_modified_at<   )ZminutesINr   )rw   rx   Zorder_byuB   Обработка отправки уведомлений для z: r   )Zinclude_deletedrx   u   Отправляем СМСz"models.CmfNotify.send_sms_notify: u   Отправляем emailz$models.CmfNotify.send_email_notify: )rh   r   Zslistr   r   r[   r   printr`   rq   r   Zget_obj_by_idr   r   Zsms_done	ExceptionZloggingZ	exceptionr   r   Z
email_doners   r   ZdpZcommit)r7   rk   Zforce_objectsZforce_object_idsr   r@   r   r2   r2   r3   celery_minutely_hook  sD    
"
"zCmfNotify.celery_minutely_hook)Nr   NFFr   N)N)NN)N).r)   r*   r+   r   r   Zcode_prefixZ_optionsZjinja2ZFileSystemLoaderospathr   r   ZPROJECT_DIRZ_loaderZEnvironmentr9   r   r   Zapi_methodsr   r4   classmethodrF   rR   rm   r   r   r-   r   r   r   r   r   r   r   r   staticmethodZcmf_deferred_jobr=   rN   r   r   r   r   __classcell__r2   r2   )r   r3   r   	   s^   "'6   '9k  )ar   N)r   r   r   Zuuidr   Zdataclassesr   Zcmf.includeZ
cmf.fieldsr   r	   r
   r   r2   r2   r2   r3   <module>   s
   