o k`)@sddlZddlZddlZddlmZddlTddlmZddlm Z ddl m Z m Z ddl mZddlmZdd lmZmZdd lmZmZmZdd lmZdd lmZdd lmZmZmZm Z m!Z!ddl"m#Z#m$Z$ddl%m&Z&m'Z'm(Z(ddl)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3ddl4m5Z5m6Z6dZ7dZ8ddZ9e:dej;ejddZ?e:dej;Z@d ddZAGdddeBZCdS)!N) IntOption)*)get_column_names)IPermissionRequestor)ResourceResourceNotFound) TicketSystem)Report)as_intcontent_disposition)format_datetime format_timefrom_utimestamp)tag) Paginator)exception_to_unicodequote_query_stringsub_vars sub_vars_re to_unicode)_tag_)HTTPBadRequestIRequestHandler RequestDone) ChromeINavigationContributor add_ctxtnavadd_link add_noticeadd_script_dataadd_stylesheet add_warning auth_link web_context)IWikiSyntaxProvider WikiParserz @SORT_COLUMN@z@LIMIT_OFFSET@cCs|dkrdS|r t|SdS)zNormalize a cell value for display. >>> (cell_value(None), cell_value(0), cell_value(1), cell_value('v')) ('', '0', '1', 'v') r0)str)vr+4/usr/lib/python3/dist-packages/trac/ticket/report.py cell_value1sr-z --.*$ # single line "--" comment | /\*([^*/]|\*[^/]|/[^*])*\*/ # C style comment | '(\\.|[^'\\])*' # literal string | \([^()]+\) # parenthesis group cCsdt|dS)N r)lengroup)mr+r+r,_expand_with_spaceAsr2cCs(d}||kr|}tt|}||ks|S)aStrip an SQL query to leave only its toplevel structure. This is probably not 100% robust but should be enough for most needs. >>> re.sub(r'\s+', lambda m: '<%d>' % len(m.group(0)), sql_skeleton('''\n SELECT a FROM (SELECT x FROM z ORDER BY COALESCE(u, ')/*(')) ORDER \n /* SELECT a FROM (SELECT x /* FROM z \n ORDER BY */ COALESCE(u, ')X(')) ORDER */ \n BY c, (SELECT s FROM f WHERE v in ('ORDER BY', '(\')') \n ORDER BY (1), '') -- LIMIT \n ''')) '<9>SELECT<1>a<1>FROM<48>ORDER<164>BY<1>c,<144>' N)_sql_resubr2)sqloldr+r+r, sql_skeletonEs  r7z ORDER\s+BYcCs\|durt|}||}t|dkr*|dt|d|t|d dfS|dfS)zSplit an SQL query according to a toplevel clause regexp. We assume there's only one such clause present in the outer query. >>> split_sql('''SELECT a FROM x ORDER BY u, v''', _order_by_re) ('SELECT a FROM x ', ' u, v') Nrr()r7splitupperr/)r5 clause_reskelblocksr+r+r, split_sql]s   *r?c@seZdZeeeeeej Z e ddddZ e ddddZ dZ d d Zd d Zd dZddZddZddZddZddZddZddZddZdd Zhd!Zd"d#Zd:d$d%Zed&ejej BZ!d'd(Z"d)d*Z#d+d,Z$ . /d;d0d1Z%d2d3Z&d4d5Z'd6d7Z(dd||j|jvrddtjtd|jdfVdSdS)N REPORT_VIEWmainnavrFz View Ticketshref)permrealmREPORT_LIST_IDrarrNrArGr+r+r,get_navigation_itemss z!ReportModule.get_navigation_itemscCsgd}|d|fgS)N) REPORT_CREATE REPORT_DELETE REPORT_MODIFYREPORT_SQL_VIEWrK REPORT_ADMINr+)rHactionsr+r+r,get_permission_actionssz#ReportModule.get_permission_actionscCs:td|j|j}|r|dr|d|jd<dSdS)Nz/report(?:/(?:([0-9]+)|%s))?$r9idT)rematchrQ path_infor0args)rHrIr]r+r+r, match_requests zReportModule.match_requestc Cs|jd|j}||j|di}|jdd}d}|jdkrQ|dkr,||n|dkr7| ||n |dkrA| |||d krK| |nLt t d |d vrad }||||d k}n6|dkrnd}|||}n)||jkr||\}}}|r||d|ifSn|||\}}}|r||d|ifSddlm}d|tjvo|j|}||jks|dkrd||j|jvrt|t d|jdt|d|jt dn |rt|t d|rt|t d|jd|j|d<|jd|d<nd|d<t|d||fS)Nr[rKactionviewPOSTnewdeleteeditclearzInvalid request arguments.)copyrfrdzreport_edit.htmlrhzreport_delete.html content_typer) QueryModule TICKET_VIEWzAvailable ReportsrMupzNew Custom Query query_hrefsaved_query_hrefzcommon/css/report.css)r_getintrQrOrPrequiregetmethod _do_create _do_delete_do_save _do_clearrr_render_editor_render_confirm_delete _render_list _render_viewtrac.ticket.queryrjrenvis_component_enabledrrNrArquerysessionr!) rHrIr[dataratemplaterirjshow_query_linkr+r+r,process_requests\         zReportModule.process_requestcCs||jdd|jvr||jt|j}|j dd|_ |j dd|_ |j dd|_ | t|td||j|jdS)NrTcanceltitler(r~ descriptionzThe report has been created.)rOrPrpr_redirectrNrAr r|rqrr~rinsertrrr[)rHrIrAr+r+r,rss  zReportModule._do_createcCsf||j|dd|jvr||j|t|j| t |t d|d||jdS)NrUrz%The report {%(id)d} has been deleted.)r[) rOrPrpr_rrNrAr r|rerr)rHrIr[r+r+r,rts  zReportModule._do_deletecCs||j|dd|jvr8t|j|}|jdd|_|jdd|_|jdd|_ | t |t d| |j|dS) z#Save report changes to the databaserVrrr(r~rzYour changes have been saved.N)rOrPrpr_r r|rqrr~rupdaterrrrNrA)rHrIr[rAr+r+r,rus  zReportModule._do_savecCs0dD] }||jvr |j|=q||jdS)N)rm query_tickets)rrrNrA)rHrInamer+r+r,rvs  zReportModule._do_clearcCs>||j|dt|j|j}td||dd||ddS)NrUz!Delete Report {%(num)s} %(title)s)numrre)r[r)rrarA)rOrPrpr r|rr)rHrIr[rr+r+r,rxsz#ReportModule._render_confirm_deletec Cs||jkr!||j|dt|j|}|j|j|j}}}n||jdd}}}|j d|}|r=|d7}|sD||jkrJddd}n d|j d d}||||d |d <t |j} | || ||S) NrVrTr(r~z (copy)rdraerrorrfr)r[rr5rrA)rQrOrPrpr r|rrr~r_rqradd_wiki_toolbarsadd_auto_preview) rHrIr[rhrrrr~rchromer+r+r,rw s.       zReportModule._render_editorcs>jdd}jjdddddjd}fdd tj|tD}|d kr6d |i}d |d fS|dkrGjgd|dddn|dkrXjgd|ddddfdd}tdt |d dt dd d td|ddt ddtd|ddt ddfdd |D}||d }d!|d"fS)#z%Render the list of available reports.sortrAascr9rminmaxformatcs0g|]}dj|jvr|j|j|jfqS)rK)rOrPr[rr).0rArIrHr+r, 0s z-ReportModule._render_list..rssrowszreport_list.rssapplication/rss+xmlcsv)rArrtext/csvz reports.csvmimetypefilenametab text/tab-separated-valuesz reports.tsvcs jjdjdd|S)Nr)rrr+)rNrAr_rq)kwargs)rrIr+r, report_href@sz.ReportModule._render_list..report_href alternate)rRSS FeedComma-delimited Text text/plainTab-delimited Textc s<g|]\}}}|||dj|vdj|vfqS)rVrU)rOrP)rr[rrrr+r,rLs )reportsrrzreport_list.htmlN) r_rqror selectr|bool _send_csvrr#r)rHrIrrrrrrr+)rrIrHr,ry*sF         zReportModule._render_list> __class__ __color__ __style__ __bgcolor__ __fgcolor__ __grouplink__cA s t|j}|j|j|j}}}ddd|D}|rr|ddks*|drr|ddkr2|n|dd}d }d |vrW||vrVtd d }  j j d | dn|ddkra|d7}||7} j t |nF|drddl m} m} z| j|j|ddd}Wn | y} z j j d t| dWYd} ~ nd} ~ ww |j jd} | dkr||||d|f}t|j}|dt|}jdd|jddd| |jjdtdd}d|}jdd jjdddddi fd d!}d"|d#||||d$dd|d% }z || |}Wn t!yh} ztd&| d'|d(<d)|dfWYd} ~ Sd} ~ ww|"t#|t#|pudd*z |$|||}Wnt%y} ztd&| d'|d(<WYd} ~ n(d} ~ wwt&|d+kr|\} }t'd,t()t*| t(t(+t(j)|d-d.d/|d(<|d(rd)|dfS|\}}}}}|dko|}|du}d0d1|D}t&|}d}|r`t,|d||}||d2<|j-rt.d3|dd4td5|j/r#t.d6|dd4td7g}|0d8}|D]} |1|| d4dt2| td9| d gq,gd:fd;d1|D|_3dd}$|# krr|d< |d<t<|$d<|s|ri d?vr|jj=}%|%d@|%>dAdB fD] \}&}'|' |&<qWdn 1swY fdCdD}(t?||( dE}|"d})|#dFr|#@dFrdG|$dH<n3|#dd=kr|#dd=krg})|"1|)|"1gn|#dd=kr#dG|$dH<n |#dd=kr/|"1g|)1|$qntA|j}*g}+g},d}-t9|D]\}.}/d}0g}1dI|1i}2t7j}3d}4d}5g}6|"D]})g}7|)D]t}$tB|/|0}'|'|$|0dJ}8|$dK}#|0d7}0|#dLkr|'|-kr|'}-|+1|'o|*C|'gf|.|2dM<|#|jDvr|'|2|#<|#dNvr|'|2dO<|#:d=}#|#dPvr|61|8n|#dQkr|'}3n|#dRkr|'}4n|#dSkr|'}5|71|8qb|11|7q\|4rt|3|2dOt|4|5dT}9nt|3|2dO}9|9jEdU|9vrqE|,1|/|6r)|6D]}8|*F|G|9|8dA}:|:|/|8dV<|8dA<q|9|2dW<|+r7|+dd};ng};d|;fg}+|;1|2qE|"|"|+|dX| dYkrat|dGdZ|d[<d\|d]fS| d^kr{rmd_nd`}<|jH||,da|tL|dvdwhD]}?N|?O}@|@rWdy|@vrW|@dy|>|@dz<q>|>rjtP|>d{tA|jQ|rytRtd|d}|d~d)|dfS)z?Retrieve the report results and pre-process them for rendering.r(css|]}|VqdSN)strip)rliner+r+r, csz,ReportModule._render_view..r?zquery:?Nz report=%szreport=z6When specified, the report number should be "%(num)s".rrfrrE&zquery:)QueryQuerySyntaxError)rArr5z{%i} %srKpager9)rrrr)rrrrcsd}r |d<dkr|d<kr|d<|||dr'dnd|d<j|S)zsGenerate links to this report preserving user variables, and sorting and paging variables. rr9rrrN)rhrrqrNrA)rparams)r_r default_maxr[rrrIsort_colr+r,rs z.ReportModule._render_view..report_hrefrb)r[resourceF) rarAcontextrrrr_show_args_formmessage paginatorrzReport failed: %(error)s)rrzreport_view.html)r_rrr8z*Report execution failed: %(error)s %(sql)szwhite-space: pre)style)rr5cSsg|]}t|qSr+)list)rrowr+r+r,rz-ReportModule._render_view..rnext)rz Next Pageprevz Previous Pagez Page %(num)d)rNclassstringrcsg|] }tt|qSr+)dictziprp)fieldsr+r,rcurrentr)colrhiddenr)status resolutionpriorityseverityz(SELECT name, %s FROM enum WHERE type=%%svalueintcs,|}r |St|tr|}|Sr)rq isinstancer)lower)rval)idx sort_valuesr+r,sortkeys   z*ReportModule._render_view..sortkey)keyreverse__Tr cell_groups)rheaderindexr __group____idx__)rAticketr[_idr[)reporterccownerrP parent_realm parent_id)parent_VIEWrr) header_groups row_groupsnumrowsr)absurlsrz report.rssrrz report_%s.csvz report.csvrrrz report_%s.tsvz report.tsvrrr)rrrrrrrW)r[rz SQL Queryr.css.|]}|dD] }tt|dVqqdS)r9r[N)r)r)rrgrr+r+r,rs rrm)query_constraints query_timer_USERroptionsr) arg_valuesz-The following arguments are missing: %(args)s, )r_)Sr r|rrr~join splitlines startswithrrrNrArr{rr from_stringrget_hrefr_rq _send_sqlrrPrOrpr$rorDrBr get_var_argsget_default_var_args ValueErrorrrexecute_paginated_report TracErrorr/rrprerhrr has_next_pagerhas_previous_pageget_shown_pagesappendr) shown_pagesr current_page num_itemsrget_ticket_field_labels enumerater capitalizerdb_querycastsortedendswithrr- format_author _html_colsr; format_emailschildrr#rKeyErrorsetget_ticket_fieldsby_namerr add_jquery_uir")ArHrIr[rrrr5r~ report_iderrrrerreport_resourcerlimitoffsetrrrescolsresultsr missing_args limit_offsetneed_paginator need_reorderrrpagedatarr field_labelsrrrdbrrr header_grouprrauthorized_resultsprev_group_valuerow_idxresultcol_idxrrrPrr email_cells cell_groupcellremails row_grouprvarrargattrsr+) r_rrrr[rrrrIrrr,rzWsD                                                              zReportModule._render_viewcCs|||\}}}|sttd|d|jd|||jd|jd}d} g} d} |tdtd} |j j } | }||j ksH|dkrL| }nTd | }|jd ||z| ||Wn+ty}z|jd |||t|d d ||fWYd}~WdSd}~ww|d} d| }|jd||z| ||Wn+ty}z|jd|||t|d d ||fWYd}~WdSd}~wwt|}|jdd}|jjddddd}|jd|||rdndg}|r||vrttd|dd}d|vr|d|r#d| ||rdndf}t|vr2|t|p/d}n1|rcd|vr?| d| |t|}t|t|\}}|rX| |d|d d!| g}d} | |krwdd"t|d#t|g} t|vr|t| }n|pt|}d"|vrd|| g}|jd$||z| ||Wn<ty}z/|jd |||t|d d | s| rt|td%ttd&||fWYd}~WdSd}~ww|pg}t|}Wdn 1swY||| || fS)'aC :param req: `Request` object. :param id: Integer id of the report. :param sql: SQL query that generates the report. :param args: SQL query arguments. :param limit: Maximum number of results to return (optional). :param offset: Offset to start of results (optional). z"Report {%(num)s} has no SQL query.rzReport {%d} with SQL "%s"zRequest args: %rNr1r(z"SELECT COUNT(*) FROM ( %s ) AS tabzReport {%d} SQL (count): %sz;Exception caught while executing Report {%d}: %r, args %r%sT) tracebackz#SELECT * FROM ( %s ) AS tab LIMIT 1zReport {%d} SQL (col names): %sz7Exception caught while executing Report {%d}: args %r%srrr9rz %r %s (%s)^r*z/Query parameter "sort=%(sort_col)s" is invalid)rrz%s %sASCDESCz __group__ ASCr.zORDER BYrLIMITOFFSETz#Report {%d} SQL (order + limit): %szHint: if the report failed due to automatic modification of the ORDER BY clause or the addition of LIMIT/OFFSET, please look up %(sort_column)s and %(limit_offset)s in TracReports to see how to gain complete control over report rewriting.) sort_columnr3) sql_sub_varsrrlogdebugr_replace SORT_COLUMN LIMIT_OFFSETr|rcursorrQexecute Exceptionwarningrfetchonerrqrorquoter7r? _order_by_rerr)r;rfetchall)rHrIr[r5r_r-r.r2rrorder_byr3base_sqlr8rU count_sqlr+ colnames_sqlr0rr order_colsr=beforeafterr+r+r,rs                      Q dz%ReportModule.execute_paginated_reportz%^\s*--\s*(\w*)[ ]*=[ ]*([^\r\n]*)\r?$cCsDi}|jD]}|s qt|j|||<qd|vr |j|d<|S)Nr)r_isupperrrqauthname)rHrI report_argsrEr+r+r,r %s  zReportModule.get_var_argscsfdd}|j||S)Ncs|d|ddS)Nr9r8) setdefaultr0) fullmatchrfr+r,extract_default_var4sz>ReportModule.get_default_var_args..extract_default_var)arg_default_rer4)rHrfr5rjr+rir,r 3s z!ReportModule.get_default_var_argsc stggfddfdd}fdd}t}|jj(}td|D]}|dr;||||q+|t ||q+Wd n1sOwYtD]}|=qZ| fS) z;Extract $XYZ-style variables from the `sql` query. csz|z|}|dr|dd}|ds|}Wnty5d}t|<|Ynw|dS)N$r9r()addrr$r)r)anamerE)r_r2namesvaluesr+r, add_value?s     z,ReportModule.sql_sub_vars..add_valuecs|ddS)Nr9%s)r0)r]rqr+r,replNsz'ReportModule.sql_sub_vars..replcsrt|dd}t|dkr|S|ddd}dd|D}dgt||ddd<|D]}|q-|j|S)Nr9rEr8cSsg|]}d|qS)z'%s'r+rr+r+r,rXrzCReportModule.sql_sub_vars..repl_literal..rr)rr:r/concat)exprr8partsrparamrsr+r, repl_literalSs   z/ReportModule.sql_sub_vars..repl_literalz('(?:[^']|(?:''))*')'N) r%ioStringIOr|rr\r:rwriterr4getvalue) rHr5r_rtrysql_ior8rvrr+)rqr_r2rorpr,rO8s"    zReportModule.sql_sub_vars,rNc sdd}dd}||||||dfdd} | } tjjr'd} n d| } t| } |d |d |d | durG|d | |rR|d td||| | t )NcStt|dSNiso8601)r r)tr+r+r,iso_timepz(ReportModule._send_csv..iso_timecSrr)r r)dtr+r+r, iso_datetimesrz,ReportModule._send_csv..iso_datetime)timedatetime changetimedatecreatedmodifiedc3sttjtjddddtjdfdd}fdd Dd V|fd d DVD]}|fd d t|DVq6dS)Nutf-8 T)encodingnewline write_through) delimiterquotingcs*|}dd|S)Nr)writerowr~truncateseek)rprv)outwriterr+r,rs   z9ReportModule._send_csv..iterate..writerowcsg|] }|dtqS)r)rqrr-rc)col_conversionsr+r,rsz;ReportModule._send_csv..iterate..sc3s|] }|jvr|VqdSrr!rrHr+r,rsz:ReportModule._send_csv..iterate..c3s.|]\}}|jvr||VqdSrr)rirA)r0 convertersrHr+r,rs )r{BytesIOrr TextIOWrapper QUOTE_MINIMALr)rrrr0rrHsep)rrrr,iterates&   z'ReportModule._send_csv..iterate Content-Typez;charset=utf-8Content-LengthContent-Disposition attachment) rr|use_chunked_encodingrr/ send_response send_headerr end_headersr}r) rHrIr0rrrrrrrrlengthr+rr,rns4      zReportModule._send_csvc Cs||j|dt}|d||df|r-|d}|dd|||d| }| d| dd| d t ||rY| d t d d ||||t) NrWs-- ## %s: %s ## -- rs-- %s z -- rrztext/plain;charset=utf-8rrrz report_%s.sql)rOrPrpr{rr}encoderrr~rrr/r rr) rHrIr[rrr5rlinesrr+r+r,r s(   zReportModule._send_sqlccsd|jfVdS)NrA _format_linkrr+r+r,get_link_resolversszReportModule.get_link_resolversc#sdtjfddfVdS)Nz !?\{(?P%s\s*)[0-9]+\}cs|d|dd||S)NrAr9rEr)xyzrr+r,rz.ReportModule.get_wiki_syntax..)r&INTERTRAC_SCHEMErr+rr,get_wiki_syntaxs   zReportModule.get_wiki_syntaxc Cs|||||}|r |S||\}}} zt|j|Wnty/tj|dtddYSwd|j |j |vrHtj||j ||ddStj|dtddS) Nzmissing reportzreport does not exist)class_rrKrA)rNrzforbidden reportzno permission to view report) shorthand_intertrac_helper split_linkr r|rrrRrrIrOrPrNrA) rH formatternstargetlabelrh intertracr[r_fragmentr+r+r,rs(   zReportModule._format_link)rr)rrNr)*__name__ __module__ __qualname__ implementsrrrr%r rPrrBrDrQrJrSrZr`rrsrtrurvrxrwryr!rzrr\compile MULTILINEUNICODErkr r rOrr rrrr+r+r+r,r@osV;   * M 6 :r@r)Drr{r\ trac.configr trac.core trac.db.apir trac.permr trac.resourcerrtrac.ticket.apirtrac.ticket.modelr trac.utilr r trac.util.datefmtr r rtrac.util.htmlrtrac.util.presentationrtrac.util.textrrrrrtrac.util.translationrr trac.web.apirrrtrac.web.chromerrrrrr r!r"r#r$ trac.wikir%r&rSrTr-rrVERBOSEr3r2r7r[r? Componentr@r+r+r+r,s<       0