use Debbugs::CGI qw(:url :html);
-html_escape(bug_url($ref,mbox=>'yes',mboxstatus=>'yes'));
-
=head1 DESCRIPTION
This module is a replacement for parts of common.pl; subroutines in
use warnings;
use strict;
use vars qw($VERSION $DEBUG %EXPORT_TAGS @EXPORT_OK @EXPORT);
-use base qw(Exporter);
+use Exporter qw(import);
+
use Debbugs::URI;
use HTML::Entities;
use Debbugs::Common qw(getparsedaddrs make_list);
use Params::Validate qw(validate_with :types);
+
use Debbugs::Config qw(:config);
use Debbugs::Status qw(splitpackages isstrongseverity);
+use Debbugs::User qw();
+
use Mail::Address;
use POSIX qw(ceil);
use Storable qw(dclone);
-use List::Util qw(max);
-
+use List::AllUtils qw(max);
+use File::stat;
+use Digest::MD5 qw(md5_hex);
use Carp;
use Debbugs::Text qw(fill_in_template);
$DEBUG = 0 unless defined $DEBUG;
@EXPORT = ();
- %EXPORT_TAGS = (url => [qw(bug_url bug_links bug_linklist maybelink),
- qw(set_url_params pkg_url version_url),
+ %EXPORT_TAGS = (url => [qw(bug_links bug_linklist maybelink),
+ qw(set_url_params version_url),
qw(submitterurl mainturl munge_url),
qw(package_links bug_links),
],
util => [qw(cgi_parameters quitcgi),
],
forms => [qw(option_form form_options_and_normal_param)],
+ usertags => [qw(add_user)],
misc => [qw(maint_decode)],
package_search => [qw(@package_search_key_order %package_search_keys)],
+ cache => [qw(calculate_etag etag_does_not_match)],
#status => [qw(getbugstatus)],
);
@EXPORT_OK = ();
}
-=head2 bug_url
-
- bug_url($ref,mbox=>'yes',mboxstat=>'yes');
-
-Constructs urls which point to a specific
-
-XXX use Params::Validate
-
-=cut
-
-sub bug_url{
- my $ref = shift;
- my %params;
- if (@_ % 2) {
- shift;
- %params = (%URL_PARAMS,@_);
- }
- else {
- %params = @_;
- }
- carp "bug_url is deprecated, use bug_links instead";
-
- return munge_url('bugreport.cgi?',%params,bug=>$ref);
-}
-
-sub pkg_url{
- my %params;
- if (@_ % 2) {
- shift;
- %params = (%URL_PARAMS,@_);
- }
- else {
- %params = @_;
- }
- carp "pkg_url is deprecated, use package_links instead";
- return munge_url('pkgreport.cgi?',%params);
-}
-
=head2 munge_url
my $url = munge_url($url,%params_to_munge);
while (my ($key,$value) = splice @old_param,0,2) {
push @new_param,($key,$value) unless exists $params{$key};
}
- $new_url->query_form(@new_param,%params);
+ $new_url->query_form(@new_param,
+ map {($_,$params{$_})}
+ sort keys %params);
return $new_url->as_string;
}
sub version_url{
my %params = validate_with(params => \@_,
- spec => {package => {type => SCALAR,
+ spec => {package => {type => SCALAR|ARRAYREF,
},
found => {type => ARRAYREF,
default => [],
sub quitcgi {
- my $msg = shift;
+ my ($msg, $status) = @_;
+ $status //= '500 Internal Server Error';
+ print "Status: $status\n";
print "Content-Type: text/html\n\n";
print fill_in_template(template=>'cgi/quit',
variables => {msg => $msg}
}
-=head HTML
+=head1 HTML
=head2 htmlize_packagelinks
}
my @links = ();
for my $type (qw(src package)) {
- push @links, map {(munge_url('pkgreport.cgi?',
+ push @links, map {my $t_type = $type;
+ if ($_ =~ s/^src://) {
+ $t_type = 'src';
+ }
+ (munge_url('pkgreport.cgi?',
%options,
- $type => $_,
+ $t_type => $_,
),
- $_);
+ ($t_type eq 'src'?'src:':'').$_);
} make_list($param{$type}) if exists $param{$type};
}
for my $type (qw(maint owner submitter correspondent)) {
sub maybelink {
my ($links,$regex,$join) = @_;
+ if (not defined $regex and not defined $join) {
+ $links =~ s{(.*?)((?:(?:ftp|http|https)://[\S~-]+?/?)?)([\)\'\:\.\,]?(?:\s|\.<|$))}
+ {html_escape($1).(length $2?q(<a href=").html_escape($2).q(">).html_escape($2).q(</a>):'').html_escape($3)}geimo;
+ return $links;
+ }
$join = ' ' if not defined $join;
my @return;
my @segments;
return htmlize_addresslinks($prefixfunc, \&mainturl, $maints);
}
-
-our $_maintainer;
-our $_maintainer_rev;
-
=head2 bug_linklist
bug_linklist($separator,$class,@bugs)
XXX Use L<Params::Validate>; we want to be able to support query
arguments here too; we should be able to combine bug_links and this
-function into one. [Hell, bug_url should be one function with this one
-too.]
+function into one.
=cut
}
+sub add_user {
+ my ($user,$usertags,$bug_usertags,$seen_users,$cats,$hidden) = @_;
+ $seen_users = {} if not defined $seen_users;
+ $bug_usertags = {} if not defined $bug_usertags;
+ $usertags = {} if not defined $usertags;
+ $cats = {} if not defined $cats;
+ $hidden = {} if not defined $hidden;
+ return if exists $seen_users->{$user};
+ $seen_users->{$user} = 1;
+
+ my $u = Debbugs::User::get_user($user);
+
+ my %vis = map { $_, 1 } @{$u->{"visible_cats"}};
+ for my $c (keys %{$u->{"categories"}}) {
+ $cats->{$c} = $u->{"categories"}->{$c};
+ $hidden->{$c} = 1 unless defined $vis{$c};
+ }
+ for my $t (keys %{$u->{"tags"}}) {
+ $usertags->{$t} = [] unless defined $usertags->{$t};
+ push @{$usertags->{$t}}, @{$u->{"tags"}->{$t}};
+ }
+
+ %{$bug_usertags} = ();
+ for my $t (keys %{$usertags}) {
+ for my $b (@{$usertags->{$t}}) {
+ $bug_usertags->{$b} = [] unless defined $bug_usertags->{$b};
+ push @{$bug_usertags->{$b}}, $t;
+ }
+ }
+}
+
+
=head1 Forms
for my $key (keys %{$param{form_option}}) {
# strip out leader; shouldn't be anything here without one,
# but skip stupid things anyway
- my $o_key = $key;
next unless $key =~ s/^\Q$form_option_leader\E//;
if ($key =~ /^add_(.+)$/) {
# this causes a specific parameter to be added
if (defined $value and $o_value eq $value) {
$selected = ' selected';
}
- $output .= qq(<option value="$o_value"$selected>$name</option>\n);
+ $output .= q(<option value=").html_escape($o_value).qq("$selected>).
+ html_escape($name).qq(</option>\n);
}
return $output;
};
return Debbugs::Text::fill_in_template(template=>$param{template},
(exists $param{language}?(language=>$param{language}):()),
variables => $variables,
+ hole_var => {'&html_escape' => \&html_escape,
+ },
);
}
wantarray ? @output : $output[0];
}
+=head1 cache
+
+=head2 calculate_etags
+
+ calculate_etags(files => [qw(list of files)],additional_data => [qw(any additional data)]);
+
+=cut
+
+sub calculate_etags {
+ my %param =
+ validate_with(params => \@_,
+ spec => {files => {type => ARRAYREF,
+ default => [],
+ },
+ additional_data => {type => ARRAYREF,
+ default => [],
+ },
+ },
+ );
+ my @additional_data = @{$param{additional_data}};
+ for my $file (@{$param{files}}) {
+ my $st = stat($file) or warn "Unable to stat $file: $!";
+ push @additional_data,$st->mtime;
+ push @additional_data,$st->size;
+ }
+ return(md5_hex(join('',sort @additional_data)));
+}
+
+=head2 etag_does_not_match
+
+ etag_does_not_match(cgi=>$q,files=>[qw(list of files)],
+ additional_data=>[qw(any additional data)])
+
+
+Checks to see if the CGI request contains an etag which matches the calculated
+etag.
+
+If there wasn't an etag given, or the etag given doesn't match, return the etag.
+
+If the etag does match, return 0.
+
+=cut
+
+sub etag_does_not_match {
+ my %param =
+ validate_with(params => \@_,
+ spec => {files => {type => ARRAYREF,
+ default => [],
+ },
+ additional_data => {type => ARRAYREF,
+ default => [],
+ },
+ cgi => {type => OBJECT},
+ },
+ );
+ my $submitted_etag =
+ $param{cgi}->http('if-none-match');
+ my $etag =
+ calculate_etags(files=>$param{files},
+ additional_data=>$param{additional_data});
+ if (not defined $submitted_etag or
+ length($submitted_etag) != 32
+ or $etag ne $submitted_etag
+ ) {
+ return $etag;
+ }
+ if ($etag eq $submitted_etag) {
+ return 0;
+ }
+}
+
1;