diff options
-rw-r--r-- | Bugzilla/Constants.pm | 1 | ||||
-rw-r--r-- | Bugzilla/Template.pm | 25 | ||||
-rwxr-xr-x | buglist.cgi | 33 | ||||
-rw-r--r-- | t/008filter.t | 2 | ||||
-rw-r--r-- | template/en/default/list/list.html.tmpl | 2 | ||||
-rw-r--r-- | template/en/default/list/list.ics.tmpl | 103 |
6 files changed, 162 insertions, 4 deletions
diff --git a/Bugzilla/Constants.pm b/Bugzilla/Constants.pm index a1bf74ba0..a61cb4620 100644 --- a/Bugzilla/Constants.pm +++ b/Bugzilla/Constants.pm @@ -103,6 +103,7 @@ use constant contenttypes => "js" => "application/x-javascript" , "csv" => "text/plain" , "png" => "image/png" , + "ics" => "text/calendar" , }; 1; diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm index c123154bb..310a18161 100644 --- a/Bugzilla/Template.pm +++ b/Bugzilla/Template.pm @@ -293,6 +293,31 @@ sub create { return $var; }, + # iCalendar contentline filter + ics => [ sub { + my ($context, @args) = @_; + return sub { + my ($var) = shift; + my ($par) = shift @args; + my ($output) = ""; + + $var =~ s/[\r\n]/ /g; + $var =~ s/([;\\\"])/\\$1/g; + + if ($par) { + $output = sprintf("%s:%s", $par, $var); + } else { + $output = $var; + } + + $output =~ s/(.{75,75})/$1\n /g; + + return $output; + }; + }, + 1 + ], + # We force filtering of every variable in key security-critical # places; we have a none filter for people to use when they # really, really don't want a variable to be changed. diff --git a/buglist.cgi b/buglist.cgi index 0871a8c54..8a02ca490 100755 --- a/buglist.cgi +++ b/buglist.cgi @@ -172,6 +172,14 @@ sub DiffDate { return $date; } +sub iCalendarDateTime { + my ($datestr) = @_; + my $date = str2time($datestr); + my ($s,$m,$h,$d,$mo,$y,$wd)= gmtime $date; + $date = sprintf "%04d%02d%02dT%02d%02d%02dZ", 1900+$y,$mo+1,$d,$h,$m,$s; + return $date; +} + sub LookupNamedQuery { my ($name) = @_; confirm_login(); @@ -525,6 +533,9 @@ if ($dotweak) { push(@selectcolumns, "bug_status") if !grep($_ eq 'bug_status', @selectcolumns); } +if ($format->{'extension'} eq 'ics') { + push(@selectcolumns, "opendate") if !grep($_ eq 'opendate', @selectcolumns); +} ################################################################################ # Query Generation @@ -712,10 +723,23 @@ while (my @row = FetchSQLData()) { # Process certain values further (i.e. date format conversion). if ($bug->{'changeddate'}) { $bug->{'changeddate'} =~ - s/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/$1-$2-$3 $4:$5:$6/; - $bug->{'changeddate'} = DiffDate($bug->{'changeddate'}); + s/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/$1-$2-$3 $4:$5:$6/; + if ($format->{'extension'} eq 'ics') { + $bug->{'changeddate'} = iCalendarDateTime($bug->{'changeddate'}); + } + else { + $bug->{'changeddate'} = DiffDate($bug->{'changeddate'}); + } + } + + if ($bug->{'opendate'}) { + if ($format->{'extension'} eq 'ics') { + $bug->{'opendate'} = iCalendarDateTime($bug->{'opendate'}); + } + else { + $bug->{'opendate'} = DiffDate($bug->{'opendate'}); + } } - ($bug->{'opendate'} = DiffDate($bug->{'opendate'})) if $bug->{'opendate'}; # Record the owner, product, and status in the big hashes of those things. $bugowners->{$bug->{'assigned_to'}} = 1 if $bug->{'assigned_to'}; @@ -800,6 +824,9 @@ $vars->{'splitheader'} = $::COOKIE{'SPLITHEADER'} ? 1 : 0; $vars->{'quip'} = GetQuip(); $vars->{'currenttime'} = time(); +if ($format->{'extension'} eq 'ics') { + $vars->{'currenttime'} = iCalendarDateTime(scalar gmtime $vars->{'currenttime'}); +} # The following variables are used when the user is making changes to multiple bugs. if ($dotweak) { diff --git a/t/008filter.t b/t/008filter.t index 722802bb8..e0aa5b05f 100644 --- a/t/008filter.t +++ b/t/008filter.t @@ -202,7 +202,7 @@ sub directive_ok { # Note: If a single directive prints two things, and only one is # filtered, we may not catch that case. return 1 if $directive =~ /FILTER\ (html|csv|js|url_quote|css_class_quote| - quoteUrls|time|uri|xml|lower| + ics|quoteUrls|time|uri|xml|lower| unitconvert|none)/x; return 0; diff --git a/template/en/default/list/list.html.tmpl b/template/en/default/list/list.html.tmpl index 82cf5dbfd..c0291024c 100644 --- a/template/en/default/list/list.html.tmpl +++ b/template/en/default/list/list.html.tmpl @@ -139,6 +139,8 @@ <td valign="middle"> <a href="buglist.cgi? [% urlquerypart FILTER html %]&ctype=csv">CSV</a> | + <a href="buglist.cgi? + [% urlquerypart FILTER html %]&ctype=ics">iCalendar</a> | <a href="colchange.cgi? [% urlquerypart FILTER html %]">Change Columns</a> | diff --git a/template/en/default/list/list.ics.tmpl b/template/en/default/list/list.ics.tmpl new file mode 100644 index 000000000..27dc1b401 --- /dev/null +++ b/template/en/default/list/list.ics.tmpl @@ -0,0 +1,103 @@ +[%# 1.0@bugzilla.org %] +[%# The contents of this file are subject to the Mozilla Public + # License Version 1.1 (the "License"); you may not use this file + # except in compliance with the License. You may obtain a copy of + # the License at http://www.mozilla.org/MPL/ + # + # Software distributed under the License is distributed on an "AS + # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + # implied. See the License for the specific language governing + # rights and limitations under the License. + # + # The Original Code is the Bugzilla Bug Tracking System. + # + # The Initial Developer of the Original Code is Netscape Communications + # Corporation. Portions created by Netscape are + # Copyright (C) 1998 Netscape Communications Corporation. All + # Rights Reserved. + # + # Contributor(s): William Jon McCann <mccann@jhu.edu> + #%] +[% PROCESS global/variables.none.tmpl %] +BEGIN:VCALENDAR +CALSCALE:GREGORIAN +[%+ PROCESS ics_prodid +%] +VERSION:2.0 +[% FOREACH bug = bugs %] +BEGIN:VTODO +[%+ PROCESS ics_dtstart +%] +[%+ PROCESS ics_summary +%] +[%+ PROCESS ics_uid base_url=Param('urlbase') bug_id=bug.bug_id +%] +[%+ PROCESS ics_url base_url=Param('urlbase') bug_id=bug.bug_id +%] +[%+ PROCESS ics_status bug_status = bug.bug_status +%] +[%+ PROCESS ics_dtstamp +%] +[% IF bug.changeddate %] +[%+ bug.changeddate FILTER ics('LAST-MODIFIED') +%] +[% END %] +[% IF bug.percentage_complete %] +[%+ bug.percentage_complete FILTER format('%d') FILTER ics('PERCENT-COMPLETE') +%] +[% END %] +[% IF bug.product %] +[%+ bug.product FILTER ics('X-BUGZILLA-PRODUCT') +%] +[% END %] +[% IF bug.component %] +[%+ bug.component FILTER ics('X-BUGZILLA-COMPONENT') +%] +[% END %] +[% IF bug.version %] +[%+ bug.version FILTER ics('X-BUGZILLA-VERSION') +%] +[% END %] +[% IF bug.keywords %] +[%+ bug.keywords FILTER ics('X-BUGZILLA-KEYWORDS') +%] +[% END %] +END:VTODO +[% END %] +END:VCALENDAR + +[% BLOCK ics_prodid %] + [% "-//Mozilla/Bugzilla $VERSION//EN" FILTER ics('PRODID') %] +[% END %] + +[% BLOCK ics_uid %] + [% "${bug_id}@${base_url}" FILTER uri FILTER ics('UID') %] +[% END %] + +[% BLOCK ics_url %] + [% "${base_url}show_bug.cgi?id=${bug_id}" FILTER uri FILTER ics('URL;VALUE=URI') %] +[% END %] + +[% BLOCK ics_dtstart %] + [% bug.opendate FILTER ics('DTSTART') %] +[% END %] + +[% BLOCK ics_dtstamp %] + [% currenttime FILTER ics('DTSTAMP') %] +[% END %] + +[% BLOCK ics_status %] + [% status = "" %] + [% FOREACH state = closedstates %] + [% IF bug_status == state %] + [% status = 'COMPLETED' %] + [% LAST %] + [% END %] + [% END %] + [% IF NOT status %] + [% IF bug_status == 'ASSIGNED' %] + [% status = 'IN-PROGRESS' %] + [% ELSE %] + [% status = 'NEEDS-ACTION' %] + [% END %] + [% END %] + [% status FILTER ics('STATUS') %] +[% END %] + +[% BLOCK ics_summary %] + [% IF bug.short_desc %] + [% summary = bug.short_desc %] + [% ELSIF bug.short_short_desc %] + [% summary = bug.short_short_desc %] + [% ELSE %] + [% summary = "$terms.Bug $bug.bug_id" %] + [% END %] + [% summary FILTER ics('SUMMARY') %] +[% END %] |