From 0df739776d31ef72e1022afccb8ea8f7c6824818 Mon Sep 17 00:00:00 2001 From: ajt <> Date: Thu, 6 Oct 2005 02:40:32 -0800 Subject: [PATCH] [project @ 2005-10-06 03:40:32 by ajt] add usertags support darcs changelog: * make "+" optional in usertag command * look at usertags as well as normal tags when doing a tag=xxx query * first pass at usertag setting for service * refactor the logic for changing usertags * store bugs in sorted order * store Bugs: field in Tag: stanza as many lines * fix up "user" handling in control@ * fix variable name in Debbugs::User * initial support for user setting in service * make Debbugs::User a proper module, first pass * switch from require to use for Debbugs::User * make usertags a pkgreport parameter * first pass at usertags support --- Debbugs/User.pm | 135 ++++++++++++++++++++++++++++++++++++++++++ cgi/common.pl | 8 +++ cgi/pkgreport.cgi | 23 +++++++ scripts/errorlib.in | 2 +- scripts/process.in | 2 +- scripts/processall.in | 2 +- scripts/service.in | 54 ++++++++++++++++- 7 files changed, 221 insertions(+), 5 deletions(-) create mode 100644 Debbugs/User.pm diff --git a/Debbugs/User.pm b/Debbugs/User.pm new file mode 100644 index 00000000..7b8c38ee --- /dev/null +++ b/Debbugs/User.pm @@ -0,0 +1,135 @@ + +package Debbugs::User; + +=head1 NAME + +Debbugs::User -- User settings + +=head1 SYNOPSIS + +use Debbugs::User qw(is_valid_user read_usertags write_usertags); + +read_usertags(\%ut, $userid); +write_usertags(\%ut, $userid); + +=head1 EXPORT TAGS + +=over + +=item :all -- all functions that can be exported + +=back + +=head1 FUNCTIONS + +=cut + +use warnings; +use strict; +use vars qw($VERSION $DEBUG %EXPORT_TAGS @EXPORT_OK @EXPORT); +use base qw(Exporter); + +BEGIN { + ($VERSION) = q$Revision: 1.1 $ =~ /^Revision:\s+([^\s+])/; + $DEBUG = 0 unless defined $DEBUG; + + @EXPORT = (); + @EXPORT_OK = qw(is_valid_user read_usertags write_usertags); + $EXPORT_TAGS{all} = [@EXPORT_OK]; +} + + +my $gSpoolPath = "/org/bugs.debian.org/spool"; + +sub esc { + my $s = shift; + if ($s =~ m/^[0-9a-zA-Z_+.-]$/) { return $s; } + else { return sprintf("%%%02X", ord($s)); } +} + +sub filefromemail { + my $e = shift; + my $l = length($e) % 7; + return "$gSpoolPath/user/$l/" . join("", map { esc($_); } split //, $e); +} + +sub read_stanza { + my $f = shift; + my $field = 0; + my @res; + while (<$f>) { + chomp; + last if (m/^$/); + + if ($field && m/^ (.*)$/) { + $res[-1] .= "\n" . $1; + } elsif (m/^([^:]+):\s+(.*)$/) { + $field = $1; + push @res, ($1, $2); + } + } + return @res; +} + +sub read_usertags { + my $ut = shift; + my $u = shift; + my $p = filefromemail($u); + my $uf; + + open($uf, "< $p") or return; + while(1) { + my @stanza = read_stanza($uf); + last if ($#stanza == -1); + if ($stanza[0] eq "Tag") { + my %tag = @stanza; + my $t = $tag{"Tag"}; + $ut->{$t} = [] unless defined $ut->{$t}; + push @{$ut->{$t}}, split /\s*,\s*/, $tag{Bugs}; + } + } + close($uf); +} + +sub fmt { + my $s = shift; + my $n = shift; + my $sofar = 0; + my $res = ""; + while ($s =~ m/^([^,]*,\s*)(.*)$/ || $s =~ m/^([^,]+)()$/) { + my $k = $1; + $s = $2; + unless ($sofar == 0 or $sofar + length($k) <= $n) { + $res .= "\n "; + $sofar = 1; + } + $res .= $k; + $sofar += length($k); + } + return $res . $s; +} + +sub write_usertags { + my $ut = shift; + my $u = shift; + my $p = filefromemail($u); + + open(U, "> $p") or die "couldn't write to $p"; + for my $t (keys %{$ut}) { + next if @{$ut->{$t}} == 0; + print U "Tag: $t\n"; + print U fmt("Bugs: " . join(", ", @{$ut->{$t}}), 77) . "\n"; + print U "\n"; + } + close(U); +} + +sub is_valid_user { + my $u = shift; + return ($u =~ /^[a-zA-Z0-9._+-]+[@][a-z0-9-.]{4,}$/); +} + + +1; + +__END__ diff --git a/cgi/common.pl b/cgi/common.pl index a6feece1..7bd76d26 100644 --- a/cgi/common.pl +++ b/cgi/common.pl @@ -18,6 +18,7 @@ use Debbugs::MIME qw(decode_rfc1522); $MLDBM::RemoveTaint = 1; +my %common_bugusertags; my $common_mindays = 0; my $common_maxdays = -1; my $common_archive = 0; @@ -180,6 +181,7 @@ sub set_option { if ($opt eq "arch") { $common_arch = $val; } if ($opt eq "maxdays") { $common_maxdays = $val; } if ($opt eq "mindays") { $common_mindays = $val; } + if ($opt eq "bugusertags") { %common_bugusertags = %{$val}; } } sub readparse { @@ -820,6 +822,12 @@ sub getbugstatus { %status = %{ readbug( $bugnum, $location ) }; $status{ id } = $bugnum; + + if (defined $common_bugusertags{$bugnum}) { + $status{keywords} = "" unless defined $status{keywords}; + $status{keywords} .= " " unless $status{keywords} eq ""; + $status{keywords} .= join(" ", @{$common_bugusertags{$bugnum}}); + } $status{tags} = $status{keywords}; my %tags = map { $_ => 1 } split ' ', $status{tags}; diff --git a/cgi/pkgreport.cgi b/cgi/pkgreport.cgi index 86ebba63..e92e9d75 100755 --- a/cgi/pkgreport.cgi +++ b/cgi/pkgreport.cgi @@ -11,6 +11,8 @@ require './common.pl'; require '/etc/debbugs/config'; require '/etc/debbugs/text'; +use Debbugs::User; + use vars qw($gPackagePages $gWebDomain); if (defined $ENV{REQUEST_METHOD} and $ENV{REQUEST_METHOD} eq 'HEAD') { @@ -43,6 +45,19 @@ my $arch = $param{'arch'} || undef; my $show_list_header = ($param{'show_list_header'} || $userAgent->{'show_list_header'} || "yes" ) eq "yes"; my $show_list_footer = ($param{'show_list_footer'} || $userAgent->{'show_list_footer'} || "yes" ) eq "yes"; +my $users = $param{'users'} || ""; +my %bugusertags; +my %ut; +for my $user (split /\s*,\s*/, $users) { + Debbugs::User::read_usertags(\%ut, $user); +} +for my $t (keys %ut) { + for my $b (@{$ut{$t}}) { + $bugusertags{$b} = [] unless defined $bugusertags{$b}; + push @{$bugusertags{$b}}, $t; + } +} + { if (defined $param{'vt'}) { my $vt = $param{'vt'}; @@ -148,6 +163,7 @@ set_option("arch", $arch); set_option("use-bug-idx", defined($param{'use-bug-idx'}) ? $param{'use-bug-idx'} : 0); set_option("show_list_header", $show_list_header); set_option("show_list_footer", $show_list_footer); +set_option("bugusertags", \%bugusertags); my $title; my @bugs; @@ -260,7 +276,14 @@ if (defined $pkg) { $title = "bugs tagged $tag"; $title .= " in $dist" if defined $dist; my @tags = split /,/, $tag; + my %bugs = (); + for my $t (@tags) { + for my $b (@{$ut{$t}}) { + $bugs{$b} = 1; + } + } @bugs = @{getbugs(sub {my %d = @_; + return 1 if $bugs{$d{"bug"}}; my %tags = map { $_ => 1 } split ' ', $d{"tags"}; return grep(exists $tags{$_}, @tags); })}; diff --git a/scripts/errorlib.in b/scripts/errorlib.in index 92dd76f1..820f0f5f 100755 --- a/scripts/errorlib.in +++ b/scripts/errorlib.in @@ -1,5 +1,5 @@ # -*- perl -*- -# $Id: errorlib.in,v 1.50 2005/10/06 03:32:13 ajt Exp $ +# $Id: errorlib.in,v 1.51 2005/10/06 03:40:32 ajt Exp $ use Mail::Address; use Debbugs::MIME qw(decode_rfc1522 encode_rfc1522); diff --git a/scripts/process.in b/scripts/process.in index d46cda9e..2b0d0aad 100755 --- a/scripts/process.in +++ b/scripts/process.in @@ -1,5 +1,5 @@ #!/usr/bin/perl -# $Id: process.in,v 1.104 2005/10/06 03:32:13 ajt Exp $ +# $Id: process.in,v 1.105 2005/10/06 03:40:32 ajt Exp $ # # Usage: process nn # Temps: incoming/Pnn diff --git a/scripts/processall.in b/scripts/processall.in index 6ce4fe9e..b2834494 100755 --- a/scripts/processall.in +++ b/scripts/processall.in @@ -1,5 +1,5 @@ #!/usr/bin/perl -# $Id: processall.in,v 1.11 2005/10/06 03:32:13 ajt Exp $ +# $Id: processall.in,v 1.12 2005/10/06 03:40:32 ajt Exp $ # # Usage: processall # diff --git a/scripts/service.in b/scripts/service.in index dd895dff..94104c0b 100755 --- a/scripts/service.in +++ b/scripts/service.in @@ -1,5 +1,5 @@ #!/usr/bin/perl -# $Id: service.in,v 1.113 2005/10/06 03:32:13 ajt Exp $ +# $Id: service.in,v 1.114 2005/10/06 03:40:32 ajt Exp $ # # Usage: service .nn # Temps: incoming/P.nn @@ -8,6 +8,7 @@ use File::Copy; use MIME::Parser; use Debbugs::MIME qw(decode_rfc1522 encode_rfc1522); use Debbugs::Mail qw(send_mail_message); +use Debbugs::User; $config_path = '/etc/debbugs'; $lib_path = '/usr/lib/debbugs'; @@ -131,6 +132,13 @@ $mergelowstate= 'idle'; $midix=0; $extras=""; +my $user = $replyto; +$user =~ s/,.*//; +$user =~ s/^.*<(.*)>.*$/$1/; +$user =~ s/[(].*[)]//; +$user =~ s/^\s*(\S+)\s+.*$/$1/; +$user = "" unless (Debbugs::User::is_valid_user($user)); + my $quickabort = 0; my $fuckheads = "(" . join("|", @gFuckheads) . ")"; @@ -236,6 +244,48 @@ END soon: UNSUBSCRIBE_TEXT soon: MAILINGLISTS_TEXT END + } elsif (m/^user\s+(\S+)\s*$/i) { + my $newuser = $1; + if (Debbugs::User::is_valid_user($newuser)) { + my $olduser = ($user ne "" ? " (was $user)" : ""); + &transcript("Setting user to $newuser$olduser.\n"); + $user = $newuser; + } else { + &transcript("Selected user id ($newuser) invalid, sorry\n"); + $user = ""; + } + } elsif (m/^usertags?\s+\#?(-?\d+)\s+(([=+-])\s*)?(\S.*)?$/i) { + $ok++; + $ref = $1; $addsubcode = $3 || "+"; $tags = $4; + if ($user eq "") { + &transcript("No valid user selected\n"); + } else { + my %ut; + Debbugs::User::read_usertags(\%ut, $user); + my @oldtags = (); my @newtags = (); + my %chtags = map { ($_, 1) } split /[,\s]+/, $tags; + for my $t (keys %chtags) { + $ut{$t} = [] unless defined $ut{$t}; + } + for my $t (keys %ut) { + my %res = map { ($_, 1) } @{$ut{$t}}; + push @oldtags, $t if defined $res{$ref}; + my $addop = ($addsubcode eq "+" or $addsubcode eq "="); + my $del = (defined $chtags{$t} ? $addsubcode eq "-" + : $addsubcode eq "="); + $res{$ref} = 1 if ($addop && defined $chtags{$t}); + delete $res{$ref} if ($del); + push @newtags, $t if defined $res{$ref}; + $ut{$t} = [ sort { $a <=> $b } (keys %res) ]; + } + if (@oldtags == 0) { + &transcript("There were no usertags set.\n"); + } else { + &transcript("Usertags were: " . join(" ", @oldtags) . ".\n"); + } + &transcript("Usertags are now: " . join(" ", @newtags) . ".\n"); + Debbugs::User::write_usertags(\%ut, $user); + } } elsif (!$control) { &transcript(<