o k`V@s4ddlZddlmZddlZddlZddlZddlZddlmZddlm Z m Z ddl Tddl m Z mZddlmZddlmZmZdd lmZmZmZmZmZdd lmZmZmZdd lmZdd l m!Z!m"Z"m#Z#dd l$m%Z%ddl&m'Z'ddl(m)Z)ddl*m+Z+m,Z,m-Z-m.Z.m/Z/ddl0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:ddl;mZ>ddl?m@Z@mAZAmBZBmCZCddlDmEZEddlFmGZGmHZHmIZImJZJmKZKddlLmMZMmNZNddlOmPZPmQZQmRZRddlSmTZTmUZUmVZVmWZWmXZXmYZYmZZZm[Z[m\Z\m]Z]m^Z^m_Z_m`Z`maZambZbddlcmdZdmeZeGdddefZgGdddefZhdS)Ndatetime)AttachmentModule) BoolOptionOption)*)MimeviewIContentConverter)NotificationSystem)IPermissionPolicyPermissionSystem)ResourceResourceNotFoundget_resource_urlrender_resource_linkget_resource_shortname) ISearchSource search_to_sqlshorten_result)model) TicketSystemITicketManipulatorTicketFieldList)TicketChangeEvent)group_milestones)ITimelineEventProvider)as_boolas_intget_reporter_idlazyto_list) datetime_nowformat_datetimeformat_date_or_datetimefrom_utimestampget_date_format_hintget_datetime_format_hint parse_date to_utimestamp user_timeutc)Markuptag to_fragment)exception_to_unicodeempty is_obfuscated shorten_line) separated)_tag_tagn_N_ngettext)get_diff_options diff_blocks)IRequestHandlerarg_list_to_argsparse_arg_list)ChromeINavigationContributorITemplateProvider accesskey add_ctxtnavadd_link add_notice add_scriptadd_script_dataadd_stylesheet add_warning auth_linkchrome_info_script prevnext_nav web_context) format_toformat_to_htmlc@seZdZeeeeeee e e Z e jZeddddZeddddZeddd d Zed d d dZedddddZedZddZeddZddZddZddZdd Zd!d"Z d#d$Z!d%d&Z"d'd(Z#d)d*Z$d+d,Z%d-d.Z&d/d0Z'd1d2Z(d3d4Z)d5d6Z*d7d8Z+d9d:Z,d;d<Z-d=d>Z.dwd@dAZ/dBdCZ0dDdEZ1dwdFdGZ2dHdIZ3dJdKZ4dLdMZ5dxdOdPZ6dQdRZ7dSdTZ8dUdVZ9dydYdZZ:d[d\Z;dwd]d^ZdcddZ?dedfZ@dzdgdhZAdxdidjZBdxdkdlZCdmdnZDdxdodpZEdxdqdrZF NdxdsdtZGdxdudvZHdNS){ TicketModuletimelineticket_show_detailstruezcEnable the display of all ticket changes in the timeline, not only open / close operations.ticket_show_componentfalsezUEnable the display of component of tickets in the timeline. (''since 1.1.1'')newticket_formatteronelinerzWhich formatter flavor (e.g. 'html' or 'oneliner') should be used when presenting the description for new tickets. If 'oneliner', the [timeline] abbreviated_messages option applies. ticketpreserve_newlinesdefaultzWhether Wiki formatter should respect the new lines present in the Wiki text. If set to 'default', this is equivalent to 'yes' for new environments but keeps the old behavior for upgraded environments (i.e. 'no'). queryticketlink_queryz?status=!closedzThe base query to be used when linkifying values of ticket fields. The query is a URL query string starting with `?` as used in `query:` [TracQuery#UsingTracLinks Trac links]. )rXdocz/ticket/([0-9]+)$cCs t|_dSN)set_warn_for_moved_attrselfra4/usr/lib/python3/dist-packages/trac/ticket/web_ui.py__init__is zTicketModule.__init__cCs"|j}|dkr |jjdk}t|S)NrX)rWenvdatabase_initial_versionr)r`rWrararbmust_preserve_newlinesls z#TicketModule.must_preserve_newlinesccsHdtdddddfVdtdddd dfVd td d dd dfVdS)NrsszRSS Feedxmltrac.ticket.Ticketapplication/rss+xmlcsvzComma-delimited Texttext/csvtabzTab-delimited Texttsvtext/tab-separated-values)r3r_rararbget_supported_conversionsus    z&TicketModule.get_supported_conversionscCsJ|dkr |j||ddS|dkr|j||dddS|dkr#|||SdS) Nrmrn)mimetypero rq)seprsrh) export_csv _export_rss)r`reqrsrVkeyrararbconvert_content}s  zTicketModule.convert_contentcCs|j|jr dSdS)Ntickets newticket)ticket_path_rematch path_infor`rxrararbget_active_navigation_itemsz'TicketModule.get_active_navigation_itemccs<d|jvrddtjtd|jt|ddfVdSdS)N TICKET_CREATEmainnavr|z New Ticket)hrefr@)permr,ar3rr|r@rrararbget_navigation_itemss  z!TicketModule.get_navigation_itemscCs8|j|j}|r|d|jd<dS|jdkrdSdS)NidT /newticket)r}r~rgroupargs)r`rxr~rararb match_requests zTicketModule.match_requestcCs4d|jvr|jdkrttd||S||S)Nrrz)id can't be set for a new ticket request.)rr TracErrorr3_process_ticket_request_process_newticket_requestrrararbprocess_requests     zTicketModule.process_requestcCsgSr\rar_rararbget_htdocs_dirsszTicketModule.get_htdocs_dirscCstddgS)Nz trac.ticket templates) pkg_resourcesresource_filenamer_rararbget_templates_dirsszTicketModule.get_templates_dirsccs"d|jvrdtdfVdSdS)N TICKET_VIEWrVTickets)rr3rrararbget_search_filterss zTicketModule.get_search_filtersc csJd|vrdSt|j}|jj{}t|ddddd|ddg|\}}t|d g|\}} t|d g|\} } t|j} |d ||| f|| | D];\} }}}}}}}||d }d ||vr|j |t dt j t |j||d| | |||dt||t||fVqHWdn1swYt|j|||D]}|VqdS)NrVsummarykeywords descriptionreporterccrtextnewvaluevaluea2SELECT summary, description, reporter, type, id, time, status, resolution FROM ticket WHERE id IN ( SELECT id FROM ticket WHERE %s UNION SELECT ticket FROM ticket_change WHERE field='comment' AND %s UNION SELECT ticket FROM ticket_custom WHERE %s ) rr%(title)s: %(message)sclass_titlemessage)r realmredb_queryrcastrrrrVr4r,spanrformat_summaryr$rrget_search_results)r`rxtermsfilters ticket_realmdbsqlrsql2args2sql3args3 ticketsystemrdescauthortypetidtsstatus resolutiontresultrararbrsV          "zTicketModule.get_search_resultsccs<d|jvrdtdfV|jrdtddfVdSdSdS)NrrVzTickets opened and closedticket_detailszTicket updatesT)rr3timeline_detailsrrararbget_timeline_filterss z!TicketModule.get_timeline_filtersc#st|t|dddddt|jt|jfddfdd }|jj}d vs;d vrd}d}d} ||D]\\} } | rj|| kr`| d d } | d d | jqE| V| }| }d} qE|r|| kr|d d } | d d } | j| jg}|f| d dd}d| d| d|f} qE|r|V| }| }qE| r| Vn|r|Vd vr|dfD]}|didd} | r| Vqd vrt |j ||D] }|VqWddSWddS1swYdS)N)r|created)reopenedticketreopened) closedticketclosed) editedticketupdated)newrreditcs|\}}}}} } } |d} d| vrdS|d} d}|dkrEdvrC|rBfdd|D}td d t|t|d d t}ndSd vr^|d kr]| r]| r[|r[td| dd}n| }ndS|\}}|t||| ||| || || | ||f fS)Nrrrrrc s"g|] }t||qSra)r,iget capitalize.0k) field_labelsrarb szKTicketModule.get_timeline_events..produce_event..%(labels)s changed, labelsrVrrr) rrr5lenr2r,brr3r$)valuesrfieldscommentcidrrrrrr componentrVrinforkindverb)rrrx status_maprrarb produce_eventsF      z7TicketModule.get_timeline_events..produce_eventc 3s@d}|d|ddfD]v\ }}}}}}}} } | s | s q|r,||f|ddkrR|r?|| | | |}|r?||dfVdiddf\} } } }|||||d|f}|dkrq| } | o`| d d }|dd|f|d d}q|d kr|| d vr|| } q|ddkr| | |<q|r|| | | |}|r||dfVdSdSdS)Na SELECT t.id, tc.time, tc.author, t.type, t.summary, t.component, tc.field, tc.oldvalue, tc.newvalue FROM ticket_change tc INNER JOIN ticket t ON t.id = tc.ticket AND tc.time>=%%s AND tc.time<=%%s LEFT OUTER JOIN enum p ON p.type='priority' AND p.name=t.priority ORDER BY tc.time, COALESCE(p.value,'')='', %s, tc.ticket zp.valueintrrrr.r)rrrr3)rsplit)rdatarrrrrrfieldoldvaluerrrrrev)rts_startts_stoprarbproduce_ticket_change_eventssH      zFTicketModule.get_timeline_events..produce_ticket_change_eventsrVrrrr batchmodifyrzSELECT id, time, reporter, type, summary, description, component FROM ticket WHERE time>=%s AND time<=%s r) r(r rrreget_ticket_field_labelsrappendrrget_timeline_events)r`rxstartstoprrrprev_tprev_evbatch_evrrrV prev_ticketr{ batch_dataroweventra)rrrrxrrrrrbrsr  *      +"z TicketModule.get_timeline_eventsc Csj|d}|dkr||||S|d\ }}}}} } } } } }}|dkr3|j|j}|r1|d|7}|S|dkrrt|j|| | | }tdtdtd td d |}d }|jr^| r^| d }|t |}t |t j d|j|d|dS|dkrd }}| dkr| }n|}|}|j |d}|j|jd| dkr|ddkr|j}|j||dkd|t|jd||SdS)Nrrrurlz #comment:rz*Ticket %(ticketref)s (%(summary)s) createdz+Ticket %(ticketref)s (%(summary)s) reopenedz)Ticket %(ticketref)s (%(summary)s) closedz*Ticket %(ticketref)s (%(summary)s) updated)rrrrrz - #r) ticketrefrrrresourcerW wiki_flavorrU)r  shorten_lines)_render_batched_timeline_eventrrVrrrerr6timeline_componentr1r4r,emchild set_hintsrgget_hinttimeline_newticket_formatterrL)r`contextrrrrVrrrrrrrrrrrrrcomponent_prefixsummary_completedescr t_contextflavorrararbrender_timeline_eventis\    z"TicketModule.render_timeline_eventc Cs|d\ }}}}}} } } } } }|dkr"|jjddd|DdS|dkrBdd d|D}td |d }td tjd ||ddS|dkrZ|}|j|jd|t |j d|| SdS)Nrr,cs|]}t|VqdSr\strrrrararb z>TicketModule._render_batched_timeline_event..rru,​csrr\rrrararbrrzTickets %(ticketids)s) ticketidsz$Tickets %(ticketlist)s batch updatedrr) ticketlistrr) rrYjoinr3r4r,r rrgrLre)r`rrrr{rrrrrrrrrrr rrrararbr s  z+TicketModule._render_batched_timeline_eventcCsg}t|j||}|D]:}g}g}g}||||D]} | |||\} } } || || || q|rG|||dt||fq |jd} | sX|rX|dd} |sat |t d|| fS)Nractionz?There are no workflow actions defined for this ticket's status.) rreget_available_actions_get_action_controllersrender_ticket_action_controlrr,rrrGr4)r`rxrVaction_controlssorted_actionsr#rhintswidgets controllerlabelwidgethintselected_actionrararb_get_action_controlss4      z!TicketModule._get_action_controlsccs@t|jjD]}dd|||pgD}||vr|VqdS)z>Generator yielding the controllers handling the given `action`cSsg|]\}}|qSrara)rwrrararbrz8TicketModule._get_action_controllers..N)rreaction_controllersget_ticket_actions)r`rxrVr#r+actionsrararbr%sz$TicketModule._get_action_controllersc Cs$||jdt|j}d}d}|jdkrd}d}|||||j |p-t |d}||d<d|jv}|s>|jdkrt |j ||}t |d krQ|d nd}|j d |} d} | rm| |vrmd} t|td | d |||| \} } | rd} | D]} t|| q|t|td tdtdtdd||| | |||M} |s|jdkr| r|||| d|jd<|||\}}| }|||}||gdd|||d|||}||d<|jrd|d<t|d<d|fSt|dt |j}|!||s |"||#|d|fS)NrTrPOSTFfield_reporterrpreviewrr#'The action "%(name)s" is not available.nameYPlease review your configuration, probably starting with %(section)s in your %(tracini)s.[ticket]workflow = ...trac.inisectiontracini) author_idr5versiondescription_changer'r#disable_submitr preview_moderIzticket_box.htmlcommon/css/ticket.css ticket.html)$rrrequirerTicketremethod _populaterrrrr$rrGr3get_ticket_changesr4r,prercode_apply_ticket_changes_validate_ticket _do_creater0 _prepare_dataupdate_prepare_fieldsis_xhrrIrFr=add_wiki_toolbarsadd_auto_preview add_jquery_ui)r`rxrV plain_fieldsr7 reporter_idr8r5default_actionr#valid field_changesproblemsproblemr'r/rFrrchromerararbrs                 z'TicketModule._process_newticket_requestc' sjd}jdd}jr:djvr:t|j||}|j}t|j|jdd|dt } | d |j|| dtj|j||d jd d jvrYd pZd }|}|d vrjd} | rr| g} nddjD} |d kr||| S|dkr||| Snj|dkrj djd} ||| S|dkrĈj djd} ||| Sdjvri} |djddd|ndjvrjjn djvrTjdd} jd} | }|sttd| dt d| j!d} | d|rD"|dj| jjd | ni} |djdddnj#d!krd"}t$|j%}||vrud#}t&td$|d%|'|(|\} }|rd#}|D]}t&|qt&t)d&t*+d't*,d(t*-d)d*|.| ||| M}d+jvr|r|/|d"jd,<t0t1jd-d.}|||jd/pjjd0d1ni} |djddd|jdjdjdjd2jd3d4|2|t3d5| jr?t4|d6d7|d8<t |d9<d:|fSt5|j}jd;}|rc|d||d?fd@dA}d"}dBj7vrˆj7dB8}t9j|vr|:t9j}|d.kr|dC|d.|dD||dE|t;|dEkr|dF||dE|dG|dHt<dIj7dJd#}|r'|jj=U}|dKD]H\}}t1|}t1|}|jkr|dC||dLjfD] \}|dDt1|qj|kr|dG||dMjfD] \} |dFt1| q Wdn 1s"wYi}!jD]&} | dN}"j>|"|"}#|"j?vrMt@|#tArMtB|#dOtC}#|#|!|"<q,j|!d<tD|E|!|dPdQtFdRtG|j}$|$H|dSs|$I|$J|Kd>D]&}%|%jL}tM|jj!j|dT}&|d.rjcomment-historycnum comment-diff changetime)r#reassign_ownerresolve_resolution start_timecancel_comment edit_comment cnum_editzComment %(num)s not foundnumr)parentTICKET_EDIT_COMMENTdate #comment:%dr6TFr9r:r<r=r>r?r@submitr8rrrreassign_choiceresolve_choice)r#rrrprq cnum_histcversion)rrurdrrrchange_previewrrGrIzticket_preview.htmlformatrhzt%drj)filenamecs8j|dd}|rt|j|td|ddSdS)N)rrDTicket #%(id)sr)rrBrrVr3) css_classrrrxrVrarbadd_ticket_links  z=TicketModule._process_ticket_request..add_ticket_link query_ticketsfirstprevrnextlastrup query_hrefz#SELECT min(id), max(id) FROM ticketz(SELECT max(id) FROM ticket WHERE id < %sz(SELECT min(id) FROM ticket WHERE %s < idr;iso8601changes)comments_prefs old_valuesrrHrF)r alternatezPrevious Ticketz Next Ticketz Back to QueryrI)RrgetintrWrKrrgrMrerrIsendencoderrJrrKrTr_render_history _render_diff_render_comment_history_render_comment_diffrUauthnamerRredirectrrVr get_changerr3r rmodify_commentrLrr$rGrMrNr4r,rOrrPrQ_do_saver$r_insert_ticket_datarboolrsend_convertedsessionrrindexrrBr_old time_fields isinstancerr"r*rE _get_prefsrFr=rXrYrZrrryrrHr; out_mimetyperJ)'r`rxrrDrrerenderedr#rr text_fieldsrmr_rchangecomment_resourcer^r5r`rarrmimerrrglobal_sequencer{idxrmin_idmax_idprev_idnext_idrr;rrb conversionconversion_hrefrarrbr&s                                                        z$TicketModule._process_ticket_requestcCs*|jdd|jdd|jdddS)Nticket_comments_orderoldestticket_show_prop_changesrQticket_show_comments)comments_ordershow_prop_changes show_comments)rrrrararbr szTicketModule._get_prefsFcCs|tt||j|d|jtdS)Nabsurls)rVr(rrWemtpy)r(rKrrgr/)r`rxrVrrararbrTs zTicketModule._prepare_datacCst|j|Sr\)r=recc_list)r`rrararb_cc_listszTicketModule._cc_listcCsd}|jr |j}n0|jdd}|r|}n"t|d}|r9|dkr9|d}|dr9|dr9|d }d}| |}|rJ||vrHd nd }|||fS) zReturn an (action, recipient) tuple corresponding to a change of CC status for this user relative to the current `cc_list`.Nemailrr anonymousr<>z<>removeadd) is_authenticatedrrrstriprr startswithendswithr)r`rxrentryrrr#rrararb _toggle_ccs      zTicketModule._toggle_ccc s|s,fddjD}t|D]}|dr*|dd}d|jvr*||||<qn fddjD}tjjD]}||d|d|dq:|D]9\}}||jvrz|rat t |nd||<WqOt y} z||j vrx|||<nt | | WYd} ~ qOd} ~ wwqO| |djvrdjvr||d \} } } | d kr| | n | d kr| | d | |d <dSdSdS) NcsBi|]}|drd|ddjvr|ddj|qS)field_revert_N)rrrrrxrarb 6s z*TicketModule._populate.. checkbox_ rcsi|] }|j|qSra)rrrrrarbr@s cc_update revert_ccrrrr)rlistrrrKprotected_fieldspopitemsrr)r'r custom_fieldspopulaterrrr") r`rxrVr[rreachrre cc_actioncc_entryrrarrbrM4sJ               zTicketModule._populatecCs8g}|||D]}|dr|d|d<||q|S)N permanentrmrD)rendered_changelog_entriesr)r`rxrVrhrrararb _get_history\s  zTicketModule._get_historycs||jd|||}|fdd|D}|dd|d|dd|td |j|d t|td |j d |j |j d |fS)z-Extract the history for a ticket description.rcs*g|]}tfdd|dDr|qS)c3|]}|vVqdSr\rarfrrarbrjsz:TicketModule._render_history...r)any)rcrrarbrjsz0TicketModule._render_history..rz''Initial version''timer)rDrrzrTicket History)rrrhBack to Ticket #%(num)srvhistory_view.html) rrrJrreverserrUr3rArrrV)r`rxrVrrrhrarrbrds    zTicketModule._render_historyc)s<jdd}jd|}||kr||}}}ig}d} } |D]6} | d} | | <tfdd| dDr]|rH| |krHt|} | dkrV|rV| |krVt|} || | fq'||krj| dkrj| d} | dkru|| \}} nd \}} | | }| dkr|| \}}nttd j|d }j|d } | d  | d |}d }| t|dkr|| dd}fdd}i}|r||d d|t |}||||d|t j gd0fdd }g}|D]?\}}|vr4||||}}||kr4||}||||}ttdt||d}||||dq|g||||dt\} }!}"d}#|!D]}$|$dr`t|$dd }#nqN|#dkrid }#D]@}%||%}&|&ry|&ng}&||%}'|'r|'ng}'t|&|'|#d|!vd|!vd|!vd}(|(g|%|||%|||%dqk|rtdtj jjd|d td!|d"td#tj jjd$d%td&|rtd'tj jjd|d td!|d"ttd(td)td&t d*t!d+|"td,j|||"||||d-d-d. d/|fS)1zShow differences between two versions of a ticket description. `text_fields` is optionally a list of fields of interest, that are considered for jumping to the next change. rDr old_versionrc3rr\rarrrarbrrz,TicketModule._render_diff..rr)rNzNo differences to showrgrNcsbt||dD]'}|vr.|dD]\}}|d||<|dur-||vr-|d||<qqdS)Nrrrold)ranger)rr from_version to_versionrDrv)rrarbreplay_changess  z1TicketModule._render_diff..replay_changescsztdjd}|rt|td||}|jr'td|jd}d|j}n tdtd}}|||tj|j d S) Nrrz – Version %(num)srvv%dInitial Versioninitial)pathrevshortrevr) r3rr,r+rrrDrrer)rrrrr)rrxr`rVrarb version_infos  z/TicketModule._render_diff..version_infozProperty %(label)s %(rendered)s)r,r)r;rrj)propsdiffsrrr-Ur-B-i-brignore_blank_lines ignore_caseignore_space_changes)rrrrrrrj)r#rDrrvrrhr#rrPrevious Change Next Changecommon/css/diff.csscommon/js/diff.jsz Ticket Diffr) rrr new_versionrrj num_changesr old_ticket new_ticketlongcolshortcoldiff_view.htmlr\)#rrrrrrrr3rrrJdictrrerrrr_render_property_diffr,lir4strongr8rr splitlinesr9rBrrrJrFrDrU))r`rxrVrrrrrh descriptionsold_idxnew_idxrrD old_changer new_changetnewtold prev_version next_versionrrrrrrrrrr,rrj diff_style diff_options diff_data diff_contextoptionrold_textnew_textrra)rrrxr`rrVrbrxs                      zTicketModule._render_diffNcCs(|jj|j|dur |nd|dd|S)N)rrr{)rrVr)r`rxrVrmrDrararb_make_comment_urls zTicketModule._make_comment_urlc CsHg}||pgD]\}}}}||||d||||||dq |S)N)rDrzrrrr)get_comment_historyrr*) r`rxrVrmrhrDrzrrrararb_get_comment_historys  z!TicketModule._get_comment_historyc Cs||jd||||}|||||}|td|jtd|j|d|dd|fg|dt |td|jd |d |fS) z)Extract the history for a ticket comment.rTicket Comment History!Ticket #%(num)s, comment %(cnum)drwrmrnrm)rrr;r diff_action diff_argsrhrrvr) rrrJr,rr*rUr3rrA)r`rxrVrrmrhrrararbr*s   z$TicketModule._render_comment_historyc s|jd|jdd}|jd|}||kr!||}}n||kr)|d}i||D]}||d<q2fdd}t|\} } } d} | D]} | dr^t| d d } nqM| d kred } fd d }||}||}t ||| d| vd| vd| vd}|g||||dg}|}d }|t dkr|d}|r|j j j d|d}t|d|td|dt|d|j j j ddtd|r|j j j d|d}t|d|td|dt|tdtdtdt|dt|d |id!td"d#jd$td%j d&d'||d(|||d)|||d*|j j j d|dd+dd,d-fgd|d.|d/|d0| d1||d2|d3d-d4d4d5d6|fS)7z:Show differences between two versions of a ticket comment.rrDrrcsHtdjd}|rtd|d}d|}n tdtd}}|||dS) Nr.r/rrvrrr)rrr)r3r)rDrrr)rmrVrarbrJs   z7TicketModule._render_comment_diff..version_inforrrNrc sFz|d}Wntyttd|jdw|r!|SgS)NrzANo version %(version)d for comment %(cnum)d on ticket #%(ticket)s)rDrmrV)KeyErrorrr3rr)rDrrmrhrVrarbget_text]s z3TicketModule._render_comment_diff..get_textrrrr)rrrrrn)rmr#rDrrrvrrl)rmr#r-rr r r r rzTicket Comment Diffrr;r.r/rold_urlnew_urldiff_urlr0r1rmrrrjrrrVr)rrr)rrrJrrr,r8rrr9rrrVrrBr3rJrFrDrUr*)r`rxrVrrmrrrrr#r$r%r&r'r4r(r)rrr!r"rrar3rbr<s             z!TicketModule._render_comment_diffr text/plaincCsdd|jD}t}|dtjtj|dddd|tjd}|d gd d|Dt ||j }t |j g} |D]9} | d } || pGd } | d vrWt |j|| d} n| |jvrp|j| d} | rnt|t| | nd } | | q<|| |d|fS)NcSsg|] }|ddvr|qS)r;)rrorarrararbrs z+TicketModule.export_csv..srf T)encodingnewline write_through) delimiterquotingrcSsg|]}|dqSr:rarrararbrr2r;r)rownerr rz%s;charset=utf-8)rioBytesIOwritermwriter TextIOWrapper QUOTE_MINIMALwriterowrKrrrr=re format_emailsrby_namerr)r#rgetvalue)r`rxrVrursrcontentrDrcolsrr;rrrararbrvs6         zTicketModule.export_csvcCsng}|||D]}||i}d|vrdg|d<|dD]*\}}|dkr2|dg|q d}|ds;d}n|dsAd }||g|q |d} | r_td d t| d | d } |d} | rstd d t| d | d } |d } | rtddt| d | d } tddd| | | fD|d<q|j ||dd} || d<t |j  |d| ddd} | dfS)Nraddedrrchangedrr]rdeletedrrrz%(labels)s setz%(labels)s deleted; css|]}|r|VqdSr\ra)rgrararbrrz+TicketModule._export_rss..rTrrz ticket.rssrk) content_typeiterable) rrr setdefaultrr7rr"r3rTr=rerender_template)r`rxrVrrchange_summaryrrchgrsdroutputrararbrwsN     $zTicketModule._export_rssc Cs0d}|j}|jr`|jr`t|jddh}d|vr(d||vr(t|tdd}|dd|vrAd ||vrAt|td d}|d|rXd ||vrXt|td d}|s`||j|j d }|rxd||vrxt|tdd}|jr|js|s|rt t |d}d|j vr|j d|krt|tdn|j d|krt|tdd}|j dpd} | dkrt | ddurttd|p|j d}|jD]A} |jrt| dr| ||D] } d}t|td| dq| ||D]\} } d}| rt|tdt| | dqt|| qq|S)NTrrrTICKET_EDIT_DESCRIPTIONz-No permission to edit the ticket description.Fr TICKET_ADMINz,No permission to change the ticket reporter.TICKET_CHGPROPz&No permission to change ticket fields.r TICKET_APPENDz No permissions to add a comment.ror8rrz8This ticket has been modified since you started editing. view_timezaYour changes have not been saved because this ticket has been modified since you started editing.replytorz$Invalid comment threading identifierrdvalidate_commentz*The ticket comment is invalid: %(message)srz2The ticket field %(field)s is invalid: %(message)s)rr)rexistsrr]rrGr3discardrrrrr(rTracValueErrorticket_manipulatorshasattrrar4validate_ticketr,r) r`rxrVforce_collision_checkr^rrNrror` manipulatorrrrararbrRsh           zTicketModule._validate_ticketc Cs\t||||}||D]}|jd|jj||||qtd||d|j }z t |j  |Wn(t y^}z|jd|jt|t|tdt|dWYd}~nd}~wwtjd|j|j|jd}d |jvrt|td |d ||jj|j|jd d d||jvrt|td|d ||j||j|jdS)NSide effect for %srrz:Failure sending notification on creation of ticket #%s: %sz[The ticket has been created, but an error occurred while sending notifications: %(message)srbrr attachmentzPThe ticket %(ticketref)s has been created. You can now attach the desired files.)rrr rzTThe ticket %(ticketref)s has been created, but you don't have permission to view it.) rr%insertlogdebug __class____name__apply_action_side_effectsrrr renotify Exceptionerrorrr.rGr4r-r,rrrVrrCrrmrrrr|) r`rxrVr# controllersr+rrrrararbrS0sF   zTicketModule._do_createc Cs6t||||}d}tt}t|d}|jd}|j||||jdd} | rxd| }td||||} z t |j  | Wn8t yw} z,|j d|jt| td } |r_tj| |d } t|td | t| d d}WYd} ~ nd} ~ ww|D]} |j d | jj| |||qz||j|j|dS)Nrrrr`)whenr`r{rNz8Failure sending notification on change to ticket #%s: %srrlz]The %(change)s has been saved, but an error occurred while sending notifications: %(message)s)rrrk)rr%r!r*rrr save_changesrr rertrurorvrr.r3r,rrGr4r-rprqrrrsrrrV)r`rxrVr#rwfragmentnowrrrmrrrr+rararbrZs@     zTicketModule._do_savec st|jifdd}|jD]\}}|||pd||dqg}||||D]D}|jj} ||||} | D]4} || } | | } | vrj| d}| d}|| krj|rj| t d| | | ||d|| | | | q=q.t D]\} }|d |dkr| =qy|fS) zReturns a dictionary of field changes. The field changes are represented as: `{field: {'old': oldvalue, 'new': newvalue, 'by': what}, ...}` cs|||||d|<dS)N)rrbyr,)r)rrrrr_rrarb store_changes z5TicketModule.get_ticket_changes..store_changeruserrr|z^%(controller1)s changed "%(key)s" to "%(val1)s", but %(controller2)s changed it to "%(val2)s".) controller1ryval1 controller2val2r) rrerrrr%rqrrrNrr3r)r`rxrVr/r~rrr`r+cnameaction_changesryrrlast_newlast_byitemrar}rbrNsB   zTicketModule.get_ticket_changescCs|D] }||d||<qdS)zKApply the changes obtained from `get_ticket_changes` to the ticket rNra)r`rVr_ryrararbrQsz"TicketModule._apply_ticket_changesc Cszddlm}|j|s|p|S|dur|j}tt|}|||<|dkr)d|d<|s-|r;tj|p2||j ||dSdS)z;Return a link to /query with the appropriate name and valuer QueryModuleNrrr)rr) trac.ticket.queryrreis_component_enabledrZr;r<r,rrrY) r`rxr;rrrrYrrrararb _query_links   zTicketModule._query_linkc Csddlm}t|tr|j|s|S|dur|j}tt|}g}t t d|D]E\}} |dr<| | dq*| ro|dkrKt|j|| n| } t| sj|} d| | |<| tj| |j| d q*| | q*t|S) z@Splits a list of words and makes a query link to each separatelyrrNz ([;,\s]+)rr@r~rl)rrrrrerrZr;r< enumeratererrrr= format_authorr0copyr,rrrY) r`rr;rrYrrrrwordr word_argsrararb_query_link_wordss4        zTicketModule._query_link_wordsc sjt|j}t}|jD]%}|d}|d}|dd|dg|dd|dd|d } |d vrEj|||| d |d <|d vrOd|d<n|dkr|dsfddfdd|dDD} | gk|d<t| |jo|d |jv} g|d<dd| D|d<t d||} t j || d|d <n|dkr|dsz t j ||} Wn tyYnw| jrtt| j}td|d}|d |dn|dkrV|duod|v}d |jvr+|jd|d}|\}}}djvodjv}td td!td"d#||d$<||d%<||d&<||d<|r+||dd<|rV|dd'}|dd(d)d*}||krM|d=n d+||dd(<|d,vr|jr|dr||}|d}g}|dgD] }||dqt|r||vr||vr||n|d-kr||}|d.vr|d/krtd0ntd1}j|||| d |d <ns|d2kr|d3d4krՈj|||| d |d <nX|d3d5krj||||| d |d <nB|d6kr-||}||d7<|d3d8}t|trtt|||d9<n|pd:|d9<t d;d}|dNr;roptionalFoptionsskipeditableTrZ)rrkr)rYr)rrrr?rrrro milestonecustomcs g|] }d|jvr|qS)TICKET_CHG_MILESTONE)rrrmrrarbrs  z0TicketModule._prepare_fields..c3s|] }tj|VqdSr\)r Milestonere)roptr_rarbrsz/TicketModule._prepare_fields..r\cSs$g|]\}}|dd|DdqS)cSsg|]}|jqSrar:rrararbrsz;TicketModule._prepare_fields...)r,rra)rr, milestonesrararbrs optgroupscompactrDzReleased %(datetime)srrrTICKET_EDIT_CCrrzAdd Ccz Remove CcCc)rrN edit_labelrrrrr@rr)radioselectcheckbox)10ryesnorr referencerr timevaluerrrlc_timerz format_hint)#rKrrrrTrrrrcrr rrerVersionrrr)r"r3rrrrreplacer"extendrrrrr#getattrr%r&)r`rxrVr_rrrr;type_rZrgroupsrrDdtr cc_changedrrrrr old_cc_list new_cc_listrrrxrrlocalera)rxr`rbrVs                                   zTicketModule._prepare_fieldscs$jd}|d<|jjd<dd<|d<t|j|||}fdd}|dkr=||d |dd |ji} i} g} d } d } d |d}t}| |D]}|dr|d} |jjdur| |jjkr|d D]\}}|| vr|d| |<qtd} n@d|vr| |dg | |t | kr||d|dd||jjr|d D] \}}|d| |<qd|dvr|d<|d|kr||d| s| |qX|jjdur|| d}| D]}|dd}|r|ddkr|dnd}q||\}}||djddid}jd}|r)||d<jdkr<|||||||jjdurH|| t|j}dD]$}||}|}t|ss|j||||dd|<qP|||| | t|j|||||t|d kd dS)!z+Insert ticket data into the template `data`r`rDNrErCcsRdjvr'j|dd}dd||fgdd|Ddgd<dSdS) NrF) show_emailr9zReplying to [%s %s]:cSsg|]}d|qS)z> %sra)rlinerararbrlr2zLTicketModule._insert_ticket_data..quote_original..r)rrr"r)roriginallinkformatted_authorrbrrxrarbquote_originalfs   z8TicketModule._insert_ticket_data..quote_originalrrz ticket:%drFrrrorrmrrTrrz comment:%srrzrr)rrr8rcomment_historyr6rr?rz%s_link) r conflictsrrreplies attachmentsr'r#r closetimerF)rrrrDr=rerVrr]rrrTrrrUrr0rLrQ_render_property_changesrKrr0r author_classrattachment_datar)r`rxrVrrCr_r`rrrrrrmrrrrrrrrrrXr'r/rrrolerformatted_userrarrbrWs                       z TicketModule._insert_ticket_datac cs|jd}|j||dD]C}|j|dd}d||vrQ||||d|d|dvrN|ddd}||d}d ||vrN|dd=|dsNq|Vqd S) `Iterate on changelog entries, consolidating related changes in a `dict` object. rmrxrmrgrrrrATTACHMENT_VIEWN)rrgrouped_changelog_entriesrrr) r`rxrVrxattachment_realmrrrrmrararbrs     z'TicketModule.rendered_changelog_entriesc Cs@|D]\}}|d|d}}||||||||d<qdS)Nrrr)rr) r`rxrVr resource_newrrrrrararbrsz%TicketModule._render_property_changescsdd}dd}t|jfdd} j|i} | d} |dkr0|| |j||} | S|d vr]| |} | |}|rH|sHtd | d } | S|rT|sTtd |d } | Std | |d} | S| dkrq|dkrktd} | Std} | S| dkrs}td} | St|jj dd}t j td|d}td|d} | S| dkr| ddkrt j tdd}|d|||} | S| dkr| d}t|trtt||n|pd }t|trtt||n|pd }|||} | S|||} | S)!Ncssdd||||fddD}fddD}|r1tddt|t|dd}|r@td d t|t|dd}|sD|rPt||oM|oMtd |St|d |S) NcSs|Sr\ra)rrararbszITicketModule._render_property_diff..render_list..cg|] }|vr|qSrararr) elt_rendererold_listrarbrzKTicketModule._render_property_diff..render_list..crrarar)rnew_listrarbrrz%(value)s addedr@r%(value)s removedrP → )r5rr2r,r3)r split_listrrrMremvdra)rrrrb render_lists" z7TicketModule._render_property_diff..render_listcSs^|r|rttj|dddtj|dd}|S|s&|r&tdtj|dd}|Stj|dd}|S)Nztrac-field-oldrrztrac-field-newu→ ztrac-field-deleted)r,r)rrrrararbrender_defaults z:TicketModule._render_property_diff..render_defaultcspj}j||dS)Nr)r authorinfo)rrrbrxrrVrarbrs z6TicketModule._render_property_diff..authorinforrrrrzset to %(value)szchanged from %(old)s to %(new)s)rrrrr]unsetrkmodifiedrjr rlzmodified (%(diff)s))rjrrrz[,;\s]+)rurr)r=rerrIrrr4r3rrr,r functoolspartialr rrr)r#)r`rxrVrrrrrrr field_inforr old_author new_authorrrjtlformat_rarrbrsn  %         z"TicketModule._render_property_diffccst|j}|j|d}d}d}}|D]\}} } } } } | r#|fn|| f}||krX|r<|t|}|d|d<|V|}dd|ii}|i| d|d}| rX|sX|d7}||d <| d sk|d | |dd | | dkr| |d<| |d <|dd <| rd | vr| d d\}}||d <n| }t||d <}q| drt| dd}||i d| i||di | t t| dq| s| r| | kr| | | | | d|d| <q|r|t|}|d|d<|VdSdS)rrrNrrzr)rzrrrrrrmr3rrr`_commentrl)rrz)rrr,r) rrer get_changelogmaxrrTrrrUr$r)r`rVrxr changelogautonumlast_uidcurrentrzrrrrruidr last_comment parent_numthis_numrrararbr0sd            z&TicketModule.grouped_changelog_entries)Fr\)rr8)NNN)Irr __module__ __qualname__ implementsr r>r:rr?rExtensionPointrrfrrrrr rrrWrZrcompiler}rcrrgrrrzrrrrrrrrrrrr r0r%rrrrTrrrMrrrr*r,rrrvrwrRrSrrNrQrrrVrrrrrrarararbrN?s    ,, Xh  ( "  c -I*(+   | q  OrNc@s0eZdZdZeeejZddZdddZ dS) DefaultTicketPolicyaSDefault permission policy for the ticket system. * Users with `MILESTONE_VIEW` can edit the ticket milestone field. * Authenticated users with `TICKET_APPEND` or `TICKET_CHGPROP` can edit the description of a ticket they reported. * Authenticated users with `TICKET_APPEND` can edit their own ticket comments. cCs|dkr|t|jjvr||drd|vrdS|dkr?|dkr?|||jr?d|vs/d|vr?t|j|j}||d kr?dS|d kru|dkrw||d ry||j|jr{d||jvr}t|j|jj}| |j}|r||d krdSdSdSdSdSdSdSdS) NrrMILESTONE_VIEWTr[rr]r^rryrr) r rer5_is_valid_resourcerrrKrrxr)r`r#usernamerrrVrrararbcheck_permissionss:      z$DefaultTicketPolicy.check_permissionTcCs&|o|j|ko|r|jduS|jduSr\)rr)r`rexpected_realmrcrararbrs  z&DefaultTicketPolicy._is_valid_resourceN)T) rrrr__doc__rr rrrrrarararbres  r)irmrrrArrtrac.attachmentr trac.configrr trac.coretrac.mimeview.apirr trac.notification.apir trac.permr r trac.resourcer rrrr trac.searchrrr trac.ticketrtrac.ticket.apirrrtrac.ticket.notificationrtrac.ticket.roadmaprtrac.timeline.apir trac.utilrrrrr trac.util.datefmtr!r"r#r$r%r&r'r(r)r*trac.util.htmlr+r,r-trac.util.textr.r/r0r1trac.util.presentationr2trac.util.translationr3r4r5r6r7trac.versioncontrol.diffr8r9 trac.web.apir:r;r<trac.web.chromer=r>r?r@rArBrCrDrErFrGrHrIrJrKtrac.wiki.formatterrLrM ComponentrNrrarararbsZ       0 D4