o k`{@sddlZddlmZddlmZddlTddlTddlmZm Z m Z m Z m Z ddl mZmZmZmZmZddlmZddlmZdd lmZdd lmZmZdd lmZdd lmZm Z dd l!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'ddl(m)Z)ddl*m+Z+Gddde,Z-Gddde Z.Gddde Z/Gddde,Z0Gddde,Z1Gddde,Z2Gddde,Z3Gddde,Z4Gd d!d!e,Z5Gd"d#d#e,Z6Gd$d%d%e,Z7d&d'Z8d(d)Z9d*d+Z:dS),N)IEnvironmentSetupParticipant)IAttachmentChangeListener)*)IEmailDecoratorINotificationFormatterINotificationSubscriberNotificationEventNotificationSystem)RecipientMatchercreate_message_idget_from_authorget_message_addresses set_header) Subscription)PermissionSystem)translation_deactivated)Ticketsort_tickets_by_priority)lazy)format_date_or_datetime get_timezone)CRLFexception_to_unicodejinja2template shorten_line text_widthwrap_)Chromec@s,eZdZeeddZddZddZdS)TicketNotificationSystemcCsPd}||jvr&|j|dd|j|dd|j|dd|jdSdS)Nznotification-subscriberalways_notify_ccCarbonCopySubscriberalways_notify_updaterTicketUpdaterSubscriberalways_notify_previous_updater TicketPreviousUpdatersSubscriber)configsetsave)selfsectionr,:/usr/lib/python3/dist-packages/trac/ticket/notification.pyenvironment_created/s    z,TicketNotificationSystem.environment_createdcCdSNFr,r*r,r,r-environment_needs_upgrade:z2TicketNotificationSystem.environment_needs_upgradecCdSNr,r1r,r,r-upgrade_environment=r3z,TicketNotificationSystem.upgrade_environmentN)__name__ __module__ __qualname__ implementsrr.r2r6r,r,r,r-r +s  r cs&eZdZdZ  dfdd ZZS)TicketChangeEventz.Represent a ticket change `NotificationEvent`.NcsJtd||||||_|dur|dur|j|d}|pi|_||_dS)Nticket)cdate)super__init__comment get_changechanges attachment)r*categorytargettimeauthorr@rBrC __class__r,r-r?Ds    zTicketChangeEvent.__init__)NNN)r7r8r9__doc__r? __classcell__r,r,rHr-r;As r;cs(eZdZdZfddZddZZS)BatchTicketChangeEventz4Represent a ticket batch modify `NotificationEvent`.cs*tdd|||||_||_||_dS)Nr< batchmodify)r>r?r@ new_valuesaction)r*targetsrFrGr@rNrOrHr,r-r?Rs  zBatchTicketChangeEvent.__init__ccs4|jD]}t||}td||j|j|jVqdS)Nchanged)rErr;rFrGr@)r*envidmodelr,r,r-get_ticket_change_eventsYs  z/BatchTicketChangeEvent.get_ticket_change_events)r7r8r9rJr?rUrKr,r,rHr-rLOs rLc@seZdZdZeeedZe dZ e ddddZ e ddd d Z e dd d d ZeddZddZddZddZddZddZddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd3d/d0Z d1d2Z!d.S)4TicketFormatterz)Format `TicketChangeEvent` notifications.Kz[;\s,]+ notificationambiguous_char_widthsinglea.Width of ambiguous characters that should be used in the table of the notification mail. If `single`, the same width as characters in US-ASCII. This is expected by most users. If `double`, twice the width of US-ASCII characters. This is expected by CJK users. batch_subject_templatez(${prefix} Batch modify: ${tickets_descr}zSLike `ticket_subject_template` but for batch modifications. (''since 1.0'')ticket_subject_templatez#${prefix} #${ticket.id}: ${summary}zA Jinja2 text template snippet used to get the notification subject. The template variables are documented on the [TracNotification#Customizingthee-mailsubject TracNotification] page. cCs|jdkrdSdS)Ndouble)rYr1r,r,r- ambiwidthszTicketFormatter.ambiwidthccs dVdS)N)z text/plainr<r,)r* transportr,r,r-get_supported_styless z$TicketFormatter.get_supported_stylescCs@|jdkrdS|jdkr||S|jdvr||S||S)Nr<rM)attachment addedattachment deleted)realmrD_format_plaintext_batchmodify_format_plaintext_attachment_format_plaintext)r*rastyleeventr,r,r-formats      zTicketFormatter.formatc Cs|j}|jdk}t||jj|j}d}d}i}|s~|jr~ddlm }||jj ||jdD]H} | ds z z > zOld description: zNew description: ccz * cc: %s (removed), z * cc: %s (added)ownerreporterrk)rqrqz* %s: %s%s%s=>%s%sz %s%s)oldvaluenewvaluerSinitial_indentsubsequent_indentlinesepr`linkNr ticket_propsticket_body_hdrr< changes_body changes_descrchangeticket_notify_email.txt)#rErDrrRabs_hrefr<rSrFtrac.ticket.web_uirngrouped_changelog_entriesupdate_format_authorrCOLSr`strgetitemsreplace_diff_ccjoin time_fieldsrtby_name_format_time_fieldlenvaluescopyr populate_datar _format_props _format_hdr _format_body)r*rjr< newticketrrr change_datarnrrGfieldrrurvnewv new_descr old_descrcdescraddccdelccchgccrklength spacer_old spacer_newchg ticket_valuesdatar,r,r-rhs                =    &z!TicketFormatter._format_plaintextc Cs<|j}|jdk}d}|jj|j}|jj}t|zt d|jj |r$dndf|j ddd|j d}|jj rG|dt |jj |j ddd|j 7}|j}|j|d<t |d d |j ddd|j d |d <||d <||d <t|jdt||||||d d||id} || dWdS1swYdS)z;Format ticket attachment notification e-mail (untranslated)rcFz * Attachment "%s" %s.addedremovedrqrrrSrwrmrrvrNrGrr)rErDrRrr<rSrCrGrrfilenamerr`rwrrrrrrrrrr) r*rjr<rrrrGrrrr,r,r-rgsR            $z,TicketFormatter._format_plaintext_attachmentc CstPt|j|j}ddd|jD}ddd|D}|jjjddd|Dd}t |j d t |||j |j |j|d }||d Wd S1sVwYd S) z=Format batch ticket change notification e-mail (untranslated)rrcss |] \}}d||fVqdS)z%s to %sNr,).0propvalr,r,r- $sz@TicketFormatter._format_plaintext_batchmodify..rycs|]}d|VqdSz#%sNr,rtr,r,r-r',css|]}t|VqdSr5)rrr,r,r-r(r)rSN)r tickets_descrrr@rOrGticket_query_linkzbatch_ticket_notify_email.txt)rrrRrErrNrrqueryrrrr@rOrGr)r*rjticketsrrrrr,r,r-rf s$    $z-TicketFormatter._format_plaintext_batchmodifycCst|jd|Sr5)rrR format_author)r*rGr,r,r-r4zTicketFormatter._format_authorcCs\t|j}|j|dd}t|j||dd}|dWdS1s'wYdS)NT)textzutf-8)rrR load_templaterrender_template_stringencode)r*r template_namechrometemplatebodyr,r,r-r7s $zTicketFormatter._format_bodyc Cs|jdk}|j}|d}|jr'd|jdvr'|jdd}d|d|df}|jdd}|d kr8d |jj}||||j|jd }t|j}|j d i| } |sWd | } | S)Nrlsummaryrtz %s (was: %s)rvrurXsmtp_subject_prefix __default__[%s])prefixrr<rBrRzRe: r,) rDrErBr'rrR project_name_template_from_stringr\renderstrip) r*rj is_newticketr<rrrrrsubjr,r,r- _format_subj>s(   zTicketFormatter._format_subjcCsjddd|D}t|j}|jdd}|dkr d|jj}|||jd}|jd i|}t |S) Nrycsrrr,rr,r,r-rZrz;TicketFormatter._format_subj_batchmodify..rXrrr)rrrRr,) rrr[r'rrRrrrr)r*rrrrrrr,r,r-_format_subj_batchmodifyYs  z(TicketFormatter._format_subj_batchmodifycCs"d|jt|d|jd|jdfS)Nz#%s: %srrr)rr`)rSrrr`)r*r<r,r,r-rjs zTicketFormatter._format_hdrc Csdd|jD}gd}d}|D]f}|ddkrq|d}||jvr#q||p(d}||jvr=|j|d }|||}|d d krEq|d vrN||}d |d } t| |d|| || <t| ||| d|| d<|d7}q|d|dd} |d |dd} |j dd } | | d|j kr| | kr| | ks|d| d ks|d | d kr| } | } n+| | krt |j dd d| } |j | d} nt |j dd d| } |j | d} | dd| d} | d }ggf}g}d}| | g}dd|DD]}|d}||jvrq||pd}||jvr.|j|d }|||}|d vr8||}|ddksFd t |vrV| |dd |fqd|dt |f}|d } d|d | | |dd | }t||| d d | |dd |j}||  ||d7}qt|dt|dkr|d gg}g}tt|dD]]}|d|}|d|}t|t|}t|t|}|dkr|dkr||7}|dgt|dn|dkr |dkr||7}|dgt| d||||qttt|t|D];}|t|kr2| | dn |t|kr>| d| | ||t||}|d|||||d f7}q!|rz|| 7}|D]\}}|d d|d|ddg7}qf|| 7}|S)NcSsg|] }|ddvr|qS)name)rrxrF changetimer,rfr,r,r- ps z1TicketFormatter._format_props..)rrrrrtypetextarearrmrkrrrzr^labelr_r~-+cSsg|] }|ddkr|qS)rrwr,rr,r,r-rsz%s: %srqz z %-*s|%s%s:)rtrrrrrfindrmax_get_text_widthrminrappendr splitlinesrr`rrangeextend)r*r<rtwidthirfnamefvalrkidxwidth_lwidth_r half_colsseptxtvals_lrbigwidth_lrstr_tmprwrappedcell_lcell_rvals_lvals_r vals_diffdiff fmt_widthrvaluer,r,r-ros                                zTicketFormatter._format_propscCs(t|jdd}|rt|||dSdS)Ntracdefault_timezone)tzinform)rr'rr)r*rrkr r,r,r-rs z"TicketFormatter._format_time_fieldcsHj|j|fddD}fddD}||fS)Nc"g|] }|r|vr|qSr,rrx)oldccr*r,r-r z,TicketFormatter._diff_cc..cr r,r r )newccr*r,r-rr) addrsep_resplit)r*rurvrrr,)rrr*r-rs    zTicketFormatter._diff_cccCst||jdS)N)r`)rr`)r*rr,r,r-rszTicketFormatter._get_text_widthcCsFt|j|}|rt|tr|d}|s!|jddp |jdd}|S)Nr_rX smtp_from smtp_replyto)r rR isinstancetupler'r)r*rj from_emailr,r,r-_get_from_emails  zTicketFormatter._get_from_emailNcCst|j||||Sr5)r rR)r*targetidrmodtimemorer,r,r-_get_message_idrzTicketFormatter._get_message_idcs|jdkrdS||}|jdkr.t|j|j}||}dtt |}| |||j }n| |}|j} d| j }| dp@d} | ||d| }|jj| j } |jdkr{t|d|t|d || |||j | }| |j } | dur{| d | 7} t|d | j t|d | t|jjrtt|j} | d | d|jfD]}| |}|sq|d}|r|qrt|d}tdd|DMrfdd|D}|rt|d|dnd|vr|d=t|ddt|d|t|d|dS)Nr<rMrz%08dr|rmrlz In-Reply-To Referencesz #comment:%dzX-Trac-Ticket-IDzX-Trac-Ticket-URLr{r^Cccss|]\}}|VqdSr5r,rraddrr,r,r-rrz3TicketFormatter.decorate_message..cs g|] \}}|vr||fqSr,r,rto_addrsr,r-rs z4TicketFormatter.decorate_message..) addressesToSubjectz Message-ID)rerrDrrRrErrmaprrrFrrSrr<rget_comment_numberr use_public_ccr(r rGmatch_recipientaddr )r*rjmessagecharsetrrsubjectrmsgidr<rurlrsmatcherrcptr cc_addrsr,r!r-decorate_messages`                    z TicketFormatter.decorate_messager5)"r7r8r9rJr:rrrrecompilerOptionrYr[r\rr`rbrkrhrgrfrrrrrrrrrrrr3r,r,r,r-rV`sH     i&i  rVc@8eZdZdZeeddZddZddZdd Z d S) TicketOwnerSubscriberz3Allows ticket owners to subscribe to their tickets.cCsRd}t|r$|jdg}d|jvr$d|jdvr$||jdddt||S)Nr{rtru)_is_ticket_change_eventrErBr_ticket_change_subscribers)r*rjownersr,r,r-matches/s   zTicketOwnerSubscriber.matchescCtdS)Nz(Ticket that I own is created or modifiedrr1r,r,r-rw8z!TicketOwnerSubscriber.descriptioncC|jj}t|j|Sr5rIr7r rRdefault_subscriptionsr*klassr,r,r-rA;z+TicketOwnerSubscriber.default_subscriptionscCr/NTr,r1r,r,r-requires_authentication?r3z-TicketOwnerSubscriber.requires_authenticationN r7r8r9rJr:rr<rwrArFr,r,r,r-r8*s  r8c@r7) r$z2Allows updaters to subscribe to their own updates.cCsd}t|r |j}t||Sr5)r9rGr:)r*rjupdaterr,r,r-r<Hs zTicketUpdaterSubscriber.matchescCr=)NzI update a ticketrr1r,r,r-rwNr>z#TicketUpdaterSubscriber.descriptioncCr?r5r@rBr,r,r-rAQrDz-TicketUpdaterSubscriber.default_subscriptionscCr/rEr,r1r,r,r-rFUr3z/TicketUpdaterSubscriber.requires_authenticationNrGr,r,r,r-r$C r$c@r7) r&zAAllows subscribing to future changes simply by updating a ticket.cs8d}trfdd|jdjjfD}t||S)Ncsg|] \}|jkr|qSr,)rG)rrGrjr,r-ras z.zk SELECT DISTINCT author FROM ticket_change WHERE ticket=%s )r9rRdb_queryrErSr:)r*rjupdatersr,rJr-r<^s  z(TicketPreviousUpdatersSubscriber.matchescCr=)Nz,Ticket that I previously updated is modifiedrr1r,r,r-rwhr>z,TicketPreviousUpdatersSubscriber.descriptioncCr?r5r@rBr,r,r-rAkrDz6TicketPreviousUpdatersSubscriber.default_subscriptionscCr/rEr,r1r,r,r-rFor3z8TicketPreviousUpdatersSubscriber.requires_authenticationNrGr,r,r,r-r&Ys  r&c@r7) TicketReporterSubscriberz:Allows the users to subscribe to tickets that they report.cCs d}t|r |jd}t||S)Nr|)r9rEr:)r*rjr|r,r,r-r<xs  z TicketReporterSubscriber.matchescCr=)Nz"Ticket that I reported is modifiedrr1r,r,r-rw~r>z$TicketReporterSubscriber.descriptioncCr?r5r@rBr,r,r-rArDz.TicketReporterSubscriber.default_subscriptionscCr/rEr,r1r,r,r-rFr3z0TicketReporterSubscriber.requires_authenticationNrGr,r,r,r-rMsrIrMc@r7) NewTicketSubscriberz-Allows the users to subscribe to new tickets.ccsD|jdks |jdkr dS|jj}t|j|D]}|VqdS)Nr<rl)rerDrIr7r find_by_classrRsubscription_tuple)r*rjrCsr,r,r-r<s zNewTicketSubscriber.matchescCr=)NzAny ticket is createdrr1r,r,r-rwr>zNewTicketSubscriber.descriptioncCsgSr5r,r1r,r,r-rAr3z)NewTicketSubscriber.default_subscriptionscCr/r0r,r1r,r,r-rFr3z+NewTicketSubscriber.requires_authenticationNrGr,r,r,r-rNs rNc@r7) r"z+Carbon copy subscriber for cc ticket field.csrd}t|r4t|jfdd}||jdpd}d|jvr4d|jdvr4|||jdddt||S)Ncst|Sr5)r(cc_list)rxrr,r-sz.CarbonCopySubscriber.matches..rxrmrtru)r9rrRrErBrr:)r*rjcc_usersto_setr,rSr-r<s   zCarbonCopySubscriber.matchescCr=)Nz2Ticket that I'm listed in the CC field is modifiedrr1r,r,r-rwr>z CarbonCopySubscriber.descriptioncCr?r5r@rBr,r,r-rArDz*CarbonCopySubscriber.default_subscriptionscCr/rEr,r1r,r,r-rFr3z,CarbonCopySubscriber.requires_authenticationNrGr,r,r,r-r"s  r"c@r7) TicketAttachmentNotifierz(Sends notification on attachment change.cCs||d|jdS)Nrc)_notify_attachmentdater*rCr,r,r-attachment_addedsz)TicketAttachmentNotifier.attachment_addedcCs||dddS)Nrd)rXrZr,r,r-attachment_deletedrz+TicketAttachmentNotifier.attachment_deletedcCr4r5r,)r*rCold_parent_realm old_parent_idr,r,r-attachment_reparentedsz.TicketAttachmentNotifier.attachment_reparentedc Cs|jj}|jdkr dSt|j|j}t||||d|d}z t|j|WdSt yI}z|j d||j |jt |WYd}~dSd}~ww)Nr<r|)rCzJFailure sending notification when %s for attachment '%s' to ticket #%s: %s)resourceparentrerrRrSr;r notify Exceptionlogerrorrr)r*rCrDrFr`r<rjer,r,r-rXs   z+TicketAttachmentNotifier._notify_attachmentN) r7r8r9rJr:rr[r\r_rXr,r,r,r-rWs rWcCs|jdko |jdvS)Nr<)rlrQrcrd)rerDrJr,r,r-r9s r9c cs|sdSt|tttfs|g}t|j}t|D]}||vr-|||||qt |j}|j j }t}|D]4}| |}|sFq<|\} } } | D]} | d| d| | | | d| d| dfVqO| rp|| | fqsB         M$