From ae772194d3c49e2a019d3d0d1383cf1c31ecc735 Mon Sep 17 00:00:00 2001 From: Matthew Horsfall Date: Sun, 28 Apr 2024 08:39:08 -0400 Subject: [PATCH] Remove unused PAUSE 1999 version code --- app_1999.psgi | 82 - lib/PAUSE/HeavyCGI.pm | 896 --- lib/PAUSE/HeavyCGI/Date.pm | 79 - lib/PAUSE/HeavyCGI/Debug.pm | 39 - lib/PAUSE/HeavyCGI/Exception.pm | 31 - lib/PAUSE/HeavyCGI/ExePlan.pm | 169 - lib/PAUSE/HeavyCGI/IfModified.pm | 74 - lib/PAUSE/HeavyCGI/Layout.pm | 95 - lib/PAUSE/HeavyCGI/SquidRemoteAddr.pm | 41 - lib/PAUSE/HeavyCGI/UnmaskQuery.pm | 108 - lib/PAUSE/Middleware/Auth/Basic.pm | 24 - lib/pause_1999/Todo | 1 - lib/pause_1999/authen_user.pm | 249 - lib/pause_1999/config.pm | 512 -- lib/pause_1999/edit.pm | 7283 --------------------- lib/pause_1999/fixup.pm | 63 - lib/pause_1999/index.pm | 49 - lib/pause_1999/layout.pm | 150 - lib/pause_1999/main.pm | 999 --- lib/pause_1999/message.pm | 42 - lib/pause_1999/pausegif.pm | 18 - lib/pause_1999/saxfilter01.pm | 68 - lib/pause_1999/speedlinkgif.pm | 59 - lib/pause_1999/startform.pm | 50 - lib/pause_1999/usermenu.pm | 138 - lib/pause_1999/userstatus.pm | 63 - t/lib/pause_1999/Test/Config.pm | 37 - t/lib/pause_1999/Test/Environment.pm | 172 - t/lib/pause_1999/Test/Fixtures/Author.pm | 116 - t/lib/pause_1999/Test/MySQL.pm | 172 - t/lib/pause_1999/Test/SiteModel.pm | 93 - t/lib/pause_1999/Test/SiteModel/Parser.pm | 128 - 32 files changed, 12100 deletions(-) delete mode 100644 app_1999.psgi delete mode 100644 lib/PAUSE/HeavyCGI.pm delete mode 100644 lib/PAUSE/HeavyCGI/Date.pm delete mode 100644 lib/PAUSE/HeavyCGI/Debug.pm delete mode 100644 lib/PAUSE/HeavyCGI/Exception.pm delete mode 100644 lib/PAUSE/HeavyCGI/ExePlan.pm delete mode 100644 lib/PAUSE/HeavyCGI/IfModified.pm delete mode 100644 lib/PAUSE/HeavyCGI/Layout.pm delete mode 100644 lib/PAUSE/HeavyCGI/SquidRemoteAddr.pm delete mode 100644 lib/PAUSE/HeavyCGI/UnmaskQuery.pm delete mode 100644 lib/PAUSE/Middleware/Auth/Basic.pm delete mode 100644 lib/pause_1999/Todo delete mode 100644 lib/pause_1999/authen_user.pm delete mode 100644 lib/pause_1999/config.pm delete mode 100644 lib/pause_1999/edit.pm delete mode 100644 lib/pause_1999/fixup.pm delete mode 100644 lib/pause_1999/index.pm delete mode 100644 lib/pause_1999/layout.pm delete mode 100644 lib/pause_1999/main.pm delete mode 100644 lib/pause_1999/message.pm delete mode 100644 lib/pause_1999/pausegif.pm delete mode 100644 lib/pause_1999/saxfilter01.pm delete mode 100644 lib/pause_1999/speedlinkgif.pm delete mode 100644 lib/pause_1999/startform.pm delete mode 100644 lib/pause_1999/usermenu.pm delete mode 100644 lib/pause_1999/userstatus.pm delete mode 100644 t/lib/pause_1999/Test/Config.pm delete mode 100644 t/lib/pause_1999/Test/Environment.pm delete mode 100644 t/lib/pause_1999/Test/Fixtures/Author.pm delete mode 100644 t/lib/pause_1999/Test/MySQL.pm delete mode 100644 t/lib/pause_1999/Test/SiteModel.pm delete mode 100644 t/lib/pause_1999/Test/SiteModel/Parser.pm diff --git a/app_1999.psgi b/app_1999.psgi deleted file mode 100644 index 57cae5117..000000000 --- a/app_1999.psgi +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env perl - -use strict; -use warnings; -use FindBin; -use lib "$FindBin::Bin/lib"; -use Plack::Builder; -use Plack::Request; -use Plack::App::Directory::Apaxy; -use Log::Dispatch::Config; - -Log::Dispatch::Config->configure("$FindBin::Bin/etc/plack_log.conf.".($ENV{PLACK_ENV} // 'development')); - -# preload stuff -use pause_1999::config; -use pause_1999::index; -use pause_1999::fixup; -use perl_pause::disabled2; - -use BSD::Resource (); -#BSD::Resource::setrlimit(BSD::Resource::RLIMIT_CPU(), -# 60*10, 60*10); -#BSD::Resource::setrlimit(BSD::Resource::RLIMIT_DATA(), -# 40*1024*1024, 40*1024*1024); -BSD::Resource::setrlimit(BSD::Resource::RLIMIT_CORE(), - 40*1024*1024, 40*1024*1024); - -my $pause_app = sub { - my $req = Plack::Request->new(shift); - - if (-f "/etc/PAUSE.CLOSED") { - return perl_pause::disabled2::handler($req); - } - - my $res = - pause_1999::fixup::handler($req) // - pause_1999::config::handler($req); - return $res if ref $res; - [$res =~ /^\d+$/ ? $res : 500, [], [$res]]; -}; - -my $index_app = sub { - my $req = Plack::Request->new(shift); - my $res = pause_1999::index::handler($req); - return $res if ref $res; - [$res =~ /^\d+$/ ? $res : 500, [], [$res]]; -}; - -builder { - enable 'LogDispatch', logger => Log::Dispatch::Config->instance; -# enable 'AccessLog::Timed', format => 'combined'; - enable 'ReverseProxy'; -# enable_if {$_[0]->{REMOTE_ADDR} eq '127.0.0.1'} 'ReverseProxy'; -# enable 'ErrorDocument', -# 500 => '', -# 404 => '', -# 403 => '', -# ; - enable 'ServerStatus::Tiny', path => '/status'; - - # Static files are serverd by us; maybe some day we want to change that - enable 'Static', - path => qr{(?:(? "$FindBin::Bin/htdocs"; - - mount '/pub/PAUSE' => builder { - enable '+PAUSE::Middleware::Auth::Basic'; - Plack::App::Directory::Apaxy->new(root => $PAUSE::Config->{FTPPUB}); - }; - - mount '/incoming' => builder { - enable '+PAUSE::Middleware::Auth::Basic'; - Plack::App::Directory::Apaxy->new(root => $PAUSE::Config->{INCOMING_LOC}); - }; - - mount '/pause' => builder { - enable_if {$_[0]->{PATH_INFO} =~ /authenquery/ ? 1 : 0} '+PAUSE::Middleware::Auth::Basic'; - $pause_app; - }; - - mount '/' => builder { $index_app }; -}; diff --git a/lib/PAUSE/HeavyCGI.pm b/lib/PAUSE/HeavyCGI.pm deleted file mode 100644 index c47c9ac2a..000000000 --- a/lib/PAUSE/HeavyCGI.pm +++ /dev/null @@ -1,896 +0,0 @@ -package PAUSE::HeavyCGI; -use 5.005; # for fields support and package-named exceptions -use HTTP::Status qw(:constants); -use PAUSE::HeavyCGI::Date; -use PAUSE::HeavyCGI::Exception; -use strict; -use vars qw($VERSION $DEBUG); - -$VERSION = "0.013302"; - -sub can_gzip { - my PAUSE::HeavyCGI $self = shift; - return $self->{CAN_GZIP} if defined $self->{CAN_GZIP}; - my $acce = $self->{REQ}->header('Accept-Encoding') || ""; - return $self->{CAN_GZIP} = 0 unless $acce; - $self->{CAN_GZIP} = $acce =~ /\bgzip\b/; -} - -sub can_png { - my PAUSE::HeavyCGI $self = shift; - return $self->{CAN_PNG} if defined $self->{CAN_PNG}; - my $acce = $self->{REQ}->header("Accept") || ""; - return $self->{CAN_PNG} = 0 unless $acce; - $self->{CAN_PNG} = $acce =~ m|image/png|i; -} - -sub can_utf8 { - my PAUSE::HeavyCGI $self = shift; - return $self->{CAN_UTF8} if defined $self->{CAN_UTF8}; - - # From chapter 14.2. HTTP/1.1 - - ## If no Accept-Charset header is present, the default is that any - ## character set is acceptable. If an Accept-Charset header is present, - ## and if the server cannot send a response which is acceptable - ## according to the Accept-Charset header, then the server SHOULD send - ## an error response with the 406 (not acceptable) status code, though - ## the sending of an unacceptable response is also allowed. - - my $acce = $self->{REQ}->header("Accept-Charset") || ""; - if (defined $acce){ - if ($acce =~ m|\butf-8\b|i){ - $self->{CAN_UTF8} = 1; - } else { - $self->{CAN_UTF8} = 0; - } - return $self->{CAN_UTF8}; - } - my $protocol = $self->{REQ}->protocol || ""; - my($major,$minor) = $protocol =~ m|HTTP/(\d+)\.(\d+)|; - $self->{CAN_UTF8} = $major >= 1 && $minor >= 1; -} - -sub deliver { - my PAUSE::HeavyCGI $self = shift; - my $req = $self->{REQ}; - my $res = $self->{RES}; - # warn "Going to send_http_header"; - return $res->finalize if $req->method eq "HEAD"; - # warn "Going to print content"; - $res->body($self->{CONTENT}); - $res->finalize; # we've sent the headers and the body, apache shouldn't talk - # to the browser anymore -} - -sub handler { - warn "The handler of the request hasn't defined a handler subroutine."; - __PACKAGE__->new( REQ => shift )->dispatch; -} - -sub dispatch { - my PAUSE::HeavyCGI $self = shift; - $self->init; - eval { $self->prepare; }; - if ($@) { - if (UNIVERSAL::isa($@,"PAUSE::HeavyCGI::Exception")) { - if ($@->{ERROR}) { - warn "\$\@ ERROR[$@->{ERROR}]"; - $@->{ERROR} = [ $@->{ERROR} ] unless ref $@->{ERROR}; - warn "\$\@ ERROR[$@->{ERROR}]"; - push @{$self->{ERROR}}, @{$@->{ERROR}}; - warn "self ERROR[$self->{ERROR}]"; - } elsif ($@->{HTTP_STATUS}) { - return $@->{HTTP_STATUS}; - } - } else { - # this is not a known error type, we need to handle it anon - if ($self->{ERRORS_TO_BROWSER}) { - push @{$self->{ERROR}}, " ", $@; - } else { - $self->{REQ}->logger->({level => 'error', message => $@}); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - } - return $self->{DONE} if $self->{DONE}; # backwards comp now, will go away - $self->{CONTENT} = $self->layout->as_string($self); - $self->finish; - $self->deliver; -} - -sub expires { - my PAUSE::HeavyCGI $self = shift; - my($set) = @_; - $set = PAUSE::HeavyCGI::Date->new(unix => $set) - if defined($set) and not ref($set); # allow setting to a number - $self->{EXPIRES} = $set if defined $set; - return $self->{EXPIRES}; # even if not defined $self->{EXPIRES}; -} - -sub finish { - my PAUSE::HeavyCGI $self = shift; - - my $res = $self->{RES}; - my $content_type = "text/html"; - $content_type .= "; charset=$self->{CHARSET}" if defined $self->{CHARSET}; - $res->content_type($content_type); - - eval { require Compress::Zlib; }; - $self->{CAN_GZIP} = 0 if $@; # we cannot compress anyway :-) - - if ($self->can_gzip) { - $res->header('Content-Encoding', 'gzip'); - $self->{CONTENT} = Compress::Zlib::memGzip($self->{CONTENT}); - } - - $res->header('Vary', join ", ", 'accept-encoding'); - $res->header('Expires', $self->expires->http) if $self->expires; - $res->header('Last-Modified',$self->last_modified->http); - $res->header('Content-Length', length($self->{CONTENT})); -} - -sub init { - return; -} - -sub instance_of { - my($self,$class) = @_; - return $class->instance if $class->can("instance"); - my $requirefile = $class; - $requirefile =~ s/::/\//g; - $requirefile .= ".pm"; - # warn "requiring[$requirefile]"; - require $requirefile; - $class->instance; -} - -sub layout { - my PAUSE::HeavyCGI $self = shift; - require PAUSE::HeavyCGI::Layout; - my @l; - push @l, qq{PAUSE::HeavyCGI default page -
};
-  push @l, $self->instance_of("PAUSE::HeavyCGI::Debug");
-  push @l, qq{
}; - PAUSE::HeavyCGI::Layout->new(@l); -} - -sub last_modified { - my PAUSE::HeavyCGI $self = shift; - my($set) = @_; - $set = PAUSE::HeavyCGI::Date->new(unix => $set) - if defined($set) and not ref($set); # allow setting to a number - $self->{LAST_MODIFIED} = $set if defined $set; - return $self->{LAST_MODIFIED} if defined $self->{LAST_MODIFIED}; - $self->{LAST_MODIFIED} = - PAUSE::HeavyCGI::Date->new(unix => $self->time); -} - -sub myurl { - my PAUSE::HeavyCGI $self = shift; - return $self->{MYURL} if defined $self->{MYURL}; - require URI::URL; - my $req = $self->{REQ} or - return URI::URL->new("http://localhost"); - $self->{MYURL} = URI::URL->new($req->base); -} - -sub new { - my($class,%opt) = @_; - no strict "refs"; - my $self = bless {}, $class; - while (my($k,$v) = each %opt) { - $self->{$k} = $v; - } - $self; -} - -sub prepare { - my PAUSE::HeavyCGI $self = shift; - if (my $ep = $self->{EXECUTION_PLAN}) { - $ep->walk($self); - } else { - die "No execution plan!"; - } -} - -sub serverroot_url { - my PAUSE::HeavyCGI $self = shift; - return $self->{SERVERROOT_URL} if $self->{SERVERROOT_URL}; - require URI::URL; - my $req = $self->{REQ} or - return URI::URL->new("http://localhost"); - my $host = $req->env->{SERVER_NAME}; # XXX: $r->server->server_hostname; - my $port = $req->port || 80; - my $protocol = $port == 443 ? "https" : "http"; - my $explicit_port = ($port == 80 || $port == 443) ? "" : ":$port"; - $self->{SERVERROOT_URL} = URI::URL->new( - "$protocol\://" . - $host . - $explicit_port . - "/" - ); -} - -sub time { - my PAUSE::HeavyCGI $self = shift; - $self->{TIME} ||= time; -} - -sub today { - my PAUSE::HeavyCGI $self = shift; - return $self->{TODAY} if defined $self->{TODAY}; - my(@time) = localtime($self->time); - $time[4]++; - $time[5] += 1900; - $self->{TODAY} = sprintf "%04d-%02d-%02d", @time[5,4,3]; -} - -# CGI form handling - -sub checkbox { - my($self,%arg) = @_; - - my $name = $arg{name}; - my $value; - defined($value = $arg{value}) or ($value = "on"); - my $checked; - my @sel = $self->{REQ}->param($name); - if (@sel) { - for my $s (@sel) { - if ($s eq $value) { - $checked = 1; - last; - } - } - } else { - $checked = $arg{checked}; - } - sprintf(qq{}, - $self->escapeHTML($name), - $self->escapeHTML($value), - $checked ? qq{ checked="checked"} : "" - ); -} - -# pause_1999::main -sub checkbox_group { - my($self,%arg) = @_; - - my $name = $arg{name}; - my @sel = $self->{REQ}->param($name); - unless (@sel) { - if (exists $arg{default}) { - my $default = $arg{default}; - @sel = ref $default ? @$default : $default; - } - } - - my %sel; - @sel{@sel} = (); - my @m; - - $name = $self->escapeHTML($name); - - my $haslabels = exists $arg{labels}; - my $linebreak = $arg{linebreak} ? "
" : ""; - - for my $v (@{$arg{values} || []}) { - push(@m, - sprintf( - qq{%s%s}, - $name, - $self->escapeHTML($v), - exists $sel{$v} ? qq{ checked="checked"} : "", - $haslabels ? $arg{labels}{$v} : $self->escapeHTML($v), - $linebreak, - ) - ); - } - join "", @m; -} - -sub escapeHTML { - my($self, $what) = @_; - return unless defined $what; - my %escapes = qw(& & " " > > < <); - $what =~ s[ ([&"<>]) ][$escapes{$1}]xg; # ]] cperl-mode comment - $what; -} - -sub file_field { - my($self) = shift; - $self->text_pw_field(FIELDTYPE=>"file", @_); -} - -sub hidden_field { - my($self) = shift; - $self->text_pw_field(FIELDTYPE=>"hidden", @_); -} - -sub password_field { - my($self) = shift; - $self->text_pw_field(FIELDTYPE=>"password", @_); -} - -# pause_1999::main -sub radio_group { - my($self,%arg) = @_; - my $name = $arg{name}; - my $value; - my $checked; - my $sel = $self->{REQ}->param($name); - my $haslabels = exists $arg{labels}; - my $values = $arg{values} or Carp::croak "radio_group called without values"; - defined($checked = $arg{checked}) - or defined($checked = $sel) - or defined($checked = $arg{default}) - or $checked = ""; - # some people like to check the first item anyway: - # or ($checked = $values->[0]); - my $escname=$self->escapeHTML($name); - my $linebreak = $arg{linebreak} ? "
" : ""; - my @m; - for my $v (@$values) { - my $escv = $self->escapeHTML($v); - if ($DEBUG) { - warn "escname undef" unless defined $escname; - warn "escv undef" unless defined $escv; - warn "v undef" unless defined $v; - warn "\$arg{labels}{\$v} undef" unless defined $arg{labels}{$v}; - warn "checked undef" unless defined $checked; - warn "haslabels undef" unless defined $haslabels; - warn "linebreak undef" unless defined $linebreak; - } - push(@m, - sprintf( - qq{%s%s}, - $escname, - $escv, - $v eq $checked ? qq{ checked="checked"} : "", - $haslabels ? $arg{labels}{$v} : $escv, - $linebreak, - )); - } - join "", @m; -} - -# pause_1999::main -sub scrolling_list { - my($self, %arg) = @_; - # name values size labels - my $size = $arg{size} ? qq{ size="$arg{size}"} : ""; - my $multiple = $arg{multiple} ? q{ multiple="multiple"} : ""; - my $haslabels = exists $arg{labels}; - my $name = $arg{name}; - my @sel = $self->{REQ}->param($name); - if (!@sel && exists $arg{default} && defined $arg{default}) { - my $d = $arg{default}; - @sel = ref $d ? @$d : $d; - } - my %sel; - @sel{@sel} = (); - my @m; - push @m, sprintf qq{"; - join "", @m; -} - -# pause_1999::main -sub submit { - my($self,%arg) = @_; - my $name = $arg{name} || ""; - my $val = $arg{value} || $name; - sprintf qq{}, - $self->escapeHTML($name), - $self->escapeHTML($val); -} - -# pause_1999::main -sub textarea { - my($self,%arg) = @_; - my $req = $self->{REQ}; - my $name = $arg{name} || ""; - my $val = $req->param($name) || $arg{default} || $arg{value} || ""; - my($r) = exists $arg{rows} ? qq{ rows="$arg{rows}"} : ''; - my($c) = exists $arg{cols} ? qq{ cols="$arg{cols}"} : ''; - my($wrap)= exists $arg{wrap} ? qq{ wrap="$arg{wrap}"} : ''; - sprintf qq{}, - $self->escapeHTML($name), - $r, $c, $wrap, $self->escapeHTML($val); -} - -# pause_1999::main -sub textfield { - my($self) = shift; - $self->text_pw_field(FIELDTYPE=>"text", @_); -} - -sub text_pw_field { - my($self, %arg) = @_; - my $name = $arg{name} || ""; - my $fieldtype = $arg{FIELDTYPE}; - - my $req = $self->{REQ}; - my $val; - if ($fieldtype eq "FILE") { - if ($req->can("upload")) { - if ($req->upload($name)) { - $val = $req->upload($name); - } else { - $val = $req->param($name); - } - } else { - $val = $req->param($name); - } - } else { - $val = $req->param($name); - } - defined $val or - defined($val = $arg{value}) or - defined($val = $arg{default}) or - ($val = ""); - - sprintf qq{}, - $self->escapeHTML($name), - $self->escapeHTML($val), - exists $arg{size} ? " size=\"$arg{size}\"" : "", - exists $arg{maxlength} ? " maxlength=\"$arg{maxlength}\"" : ""; -} - -sub uri_escape { - my PAUSE::HeavyCGI $self = shift; - my $string = shift; - return "" unless defined $string; - require URI::Escape; - my $s = URI::Escape::uri_escape($string, '^\w '); - $s =~ s/ /+/g; - $s; -} - -sub uri_escape_light { - my PAUSE::HeavyCGI $self = shift; - require URI::Escape; - URI::Escape::uri_escape(shift,q{<>#%"; \/\?:&=+,\$}); #" -} - -1; - -=head1 NAME - -PAUSE::HeavyCGI - Framework to run complex CGI tasks on an Apache server - -=head1 SYNOPSIS - - use PAUSE::HeavyCGI; - -=head1 WARNING UNSUPPORTED ALPHA CODE RELEASED FOR DEMO ONLY - -The release of this software was only for evaluation purposes to -people who are actively writing code that deals with Web Application -Frameworks. This package is probably just another Web Application -Framework and may be worth using or may not be worth using. As of this -writing (July 1999) it is by no means clear if this software will be -developed further in the future. The author has written it over many -years and is deploying it in several places. B - -There is no official support for this software. If you find it useful -or even if you find it useless, please mail the author directly. - -But please make sure you remember: THE RELEASE IS FOR DEMONSTRATION -PURPOSES ONLY. - -=head1 DESCRIPTION - -The PAUSE::HeavyCGI framework is intended to provide a couple of -simple tricks that make it easier to write complex CGI solutions. It -has been developed on a site that runs all requests through a single -mod_perl handler that in turn uses CGI.pm or Apache::Request as the -query interface. So PAUSE::HeavyCGI is -- as the name implies -- not -merely for multi-page CGI scripts (for which there are other -solutions), but it is for the integration of many different pages into -a single solution. The many different pages can then conveniently -share common tasks. - -The approach taken by PAUSE::HeavyCGI is a components-driven one with -all components being pure perl. So if you're not looking for yet -another embedded perl solution, and aren't intimidated by perl, please -read on. - -=head2 Stacked handlers suck - -If you have had a look at stacked handlers, you might have noticed -that the model for stacking handlers often is too primitive. The model -supposes that the final form of a document can be found by running -several passes over a single entity, each pass refining the entity, -manipulating some headers, maybe even passing some notes to the next -handler, and in the most advanced form passing pnotes between -handlers. A lot of Web pages may fit into that model, even complex -ones, but it doesn't scale well for pages that result out of a -structure that's more complicated than adjacent items. The more -complexity you add to a page, the more overhead is generated by the -model, because for every handler you push onto the stack, the whole -document has to be parsed and recomposed again and headers have to be -re-examined and possibly changed. - -=head2 Why not subclass Apache - -Inheritance provokes namespace conflicts. Besides this, I see little -reason why one should favor inheritance over a B relationship. -The current implementation of PAUSE::HeavyCGI is very closely coupled -with the Apache class anyway, so we could do inheritance too. No big -deal I suppose. The downside of the current way of doing it is that we -have to write - - my $r = $obj->{R}; - -very often, but that's about it. The upside is, that we know which -manpage to read for the different methods provided by C<$obj->{R}>, -C<$obj->{CGI}>, and C<$obj> itself. - -=head2 Composing applications - -PAUSE::HeavyCGI takes an approach that is more ambitious for handling -complex tasks. The underlying model for the production of a document -is that of a puzzle. An HTML (or XML or SGML or whatever) page is -regarded as a sequence of static and dynamic parts, each of which has -some influence on the final output. Typically, in today's Webpages, -the dynamic parts are filled into table cells, i.e. contents between -some C<< >> tokens. But this is not necessarily so. The -static parts in between typically are some HTML markup, but this also -isn't forced by the model. The model simply expects a sequence of -static and dynamic parts. Static and dynamic parts can appear in -random order. In the extreme case of a picture you would only have one -part, either static or dynamic. HeavyCGI could handle this, but I -don't see a particular advantage of HeavyCGI over a simple single -handler. - -In addition to the task of generating the contents of the page, there -is the other task of producing correct headers. Header composition is -an often neglected task in the CGI world. Because pages are generated -dynamically, people believe that pages without a Last-Modified header -are fine, and that an If-Modified-Since header in the browser's -request can go by unnoticed. This laissez-faire principle gets in the -way when you try to establish a server that is entirely driven by -dynamic components and the number of hits is significant. - -=head2 Header Composition, Parameter Processing, and Content Creation - -The three big tasks a CGI script has to master are Headers, Parameters -and the Content. In general one can say, content creation SHOULD not -start before all parameters are processed. In complex scenarios you -MUST expect that the whole layout may depend on one parameter. -Additionally we can say that some header related data SHOULD be -processed very early because they might result in a shortcut that -saves us a lot of processing. - -Consequently, PAUSE::HeavyCGI divides the tasks to be done for a -request into four phases and distributes the four phases among an -arbitrary number of modules. Which modules are participating in the -creation of a page is the design decision of the programmer. - -The perl model that maps (at least IMHO) ideally to this task -description is an object oriented approach that identifies a couple of -phases by method names and a couple of components by class names. To -create an application with PAUSE::HeavyCGI, the programmer specifies -the names of all classes that are involved. All classes are singleton -classes, i.e. they have no identity of their own but can be used to do -something useful by working on an object that is passed to them. -Singletons have an @ISA relation to L which can be -found on CPAN. As such, the classes can only have a single instance -which can be found by calling the C<< CLASS->instance >> method. We'll -call these objects after the mod_perl convention I. - -Every request maps to exactly one PAUSE::HeavyCGI object. The -programmer uses the methods of this object by subclassing. The -HeavyCGI constructor creates objects of the AVHV type (pseudo-hashes). - -*** Note: after 0.0133 this was changed to an ordinary hash. *** - -If the inheriting class needs its own constructor, this needs to be an -AVHV compatible constructor. A description of AVHV can be found in -L. - -*** Note: after 0.0133 this was changed to be an ordinary hash. *** - -An PAUSE::HeavyCGI object usually is constructed with the -C method and after that the programmer calls the C -method on this object. HeavyCGI will then perform various -initializations and then ask all nominated handlers in turn to perform -the I
method and in a second round to perform the I -method. In most cases it will be the case that the availability of a -method can be determined at compile time of the handler. If this is -true, it is possible to create an execution plan at compile time that -determines the sequence of calls such that no runtime is lost to check -method availability. Such an execution plan can be created with the -L module. All of the called methods will -get the HeavyCGI request object passed as the second parameter. - -There are no fixed rules as to what has to happen within the C
-and C method. As a rule of thumb it is recommended to -determine and set the object attributes LAST_MODIFIED and EXPIRES (see -below) within the header() method. It is also recommended to inject -the L module as the last header handler, -so that the application can abort early with an Not Modified header. I -would recommend that in the header phase you do as little as possible -parameter processing except for those parameters that are related to -the last modification date of the generated page. - -=head2 Terminating the handler calls or triggering errors. - -Sometimes you want to stop calling the handlers, because you think -that processing the request is already done. In that case you can do a - - die PAUSE::HeavyCGI::Exception->new(HTTP_STATUS => status); - -at any point within prepare() and the specified status will be -returned to the Apache handler. This is useful for example for the -PAUSE::HeavyCGI::IfModified module which sends the response headers -and then dies with HTTP_STATUS set to Apache::Constants::DONE. -Redirectors presumably would set up their headers and set it to -Apache::Constants::HTTP_MOVED_TEMPORARILY. - -Another task for Perl exceptions are errors: In case of an error -within the prepare loop, all you need to do is - - die PAUSE::HeavyCGI::Exception->new(ERROR=>[array_of_error_messages]); - -The error is caught at the end of the prepare loop and the anonymous -array that is being passed to $@ will then be appended to -C<@{$self-E{ERROR}}>. You should check for $self->{ERROR} within -your layout method to return an appropriate response to the client. - -=head2 Layout and Text Composition - -After the header and the parameter phase, the application should have -set up the object that is able to characterize the complete -application and its status. No changes to the object should happen -from now on. - -In the next phase PAUSE::HeavyCGI will ask this object to perform the -C method that has the duty to generate an -PAUSE::HeavyCGI::Layout (or compatible) object. Please read more -about this object in L. For our HeavyCGI -object it is only relevant that this Layout object can compose itself -as a string in the as_string() method. As a layout object can be -composed as an abstraction of a layout and independent of -request-specific contents, it is recommended to cache the most -important layouts. This is part of the reponsibility of the -programmer. - -In the next step HeavyCGI stores a string representation of current -request by calling the as_string() method on the layout object and -passing itself to it as the first argument. By passing itself to the -Layout object all the request-specific data get married to the -layout-specific data and we reach the stage where stacked handlers -usually start, we get at a composed content that is ready for -shipping. - -The last phase deals with setting up the yet unfinished headers, -eventually compressing, recoding and measuring the content, and -delivering the request to the browser. The two methods finish() and -deliver() are responsible for that phase. The default deliver() method -is pretty generic, it calls finish(), then sends the headers, and -sends the content only if the request method wasn't a HEAD. It then -returns Apache's constant DONE to the caller, so that Apache won't do -anything except logging on this request. The method finish is more apt -to being overridden. The default finish() method sets the content type -to text/html, compresses the content if the browser understands -compressed data and Compress::Zlib is available, it also sets the -headers Vary, Expires, Last-Modified, and Content-Length. You most -probably will want to override the finish method. - -head2 Summing up - +-------------------+ - | sub handler {...} | - +--------------------+ | (sub init {...}) | - |Your::Class |---defines------>| | - |ISA PAUSE::HeavyCGI| | sub layout {...} | - +--------------------+ | sub finish {...} | - +-------------------+ - - +-------------------+ - | sub new {...} | - +--------------------+ | sub dispatch {...}| - |PAUSE::HeavyCGI |---defines------>| sub prepare {...} | - +--------------------+ | sub deliver {...} | - +-------------------+ - - +----------------------+ +--------------------+ - |Handler_1 .. Handler_N| | sub header {...} | - |ISA Class::Singleton |---define----->| sub parameter {...}| - +----------------------+ +--------------------+ - - +----+ - |Your| - |Duty| - +----------------------------+----------------------------------------+----+ - |Apache | calls Your::Class::handler() | | - +----------------------------+----------------------------------------+----+ - | | nominates the handlers, | | - |Your::Class::handler() | constructs $self, | ** | - | | and calls $self->dispatch | | - +----------------------------+----------------------------------------+----+ - | | $self->init (does nothing) | ?? | - | | $self->prepare (see below) | | - |PAUSE::HeavyCGI::dispatch()| calls $self->layout (sets up layout)| ** | - | | $self->finish (headers and | ** | - | | gross content) | | - | | $self->deliver (delivers) | ?? | - +----------------------------+----------------------------------------+----+ - |PAUSE::HeavyCGI::prepare() | calls HANDLER->instance->header($self) | ** | - | | and HANDLER->instance->parameter($self)| ** | - | | on all of your nominated handlers | | - +----------------------------+----------------------------------------+----+ - - -=head1 Object Attributes - -As already mentioned, the HeavyCGI object is a pseudo-hash, i.e. can -be treated like a HASH, but all attributes that are being used must be -predeclared at compile time with a C clause. - -The convention regarding attributes is as simple as it can be: -uppercase attributes are reserved for the PAUSE::HeavyCGI class, all -other attribute names are at your disposition if you write a subclass. - -The following attributes are currently defined. The module author's -production environment has a couple of attributes more that seem to -work well but most probably need more thought to be implemented in a -generic way. - -=over - -=item CAN_GZIP - -Set by the can_gzip method. True if client is able to handle gzipped -data. - -=item CAN_PNG - -Set by the can_png method. True if client is able to handle PNG. - -=item CAN_UTF8 - -Set by the can_utf8 method. True if client is able to handle UTF8 -endoded data. - -=item CGI - -An object that handles GET and POST parameters and offers the method -param() and upload() in a manner compatible with Apache::Request. -Needs to be constructed and set by the user typically in the -contructor. - -=item CHARSET - -Optional attribute to denote the charset in which the outgoing data -are being encoded. Only used within the finish method. If it is set, -the finish() method will set the content type to text/html with this -charset. - -=item CONTENT - -Scalar that contains the content that should be sent to the user -uncompressed. During te finish() method the content may become -compressed. - -=item DOCUMENT_ROOT - -Unused. - -=item ERROR - -Anonymous array that accumulates error messages. HeavyCGI doesn't -handle the error though. It is left to the user to set up a proper -response to the user. - -=item EXECUTION_PLAN - -Object of type L. It is recommended to -compute the object at startup time and always pass the same execution -plan into the constructor. - -=item EXPIRES - -Optional Attribute set by the expires() method. If set, HeavyCGI will -send an Expires header. The EXPIRES attribute needs to contain an -L object. - -=item HANDLER - -If there is an EXECUTION_PLAN, this attribute is ignored. Without an -EXECUTION_PLAN, it must be an array of package names. HeavyCGI treats -the packages as Class::Singleton classes. During the prepare() method -HeavyCGI calls HANDLER->instance->header($self) and -HANDLER->instance->parameter($self) on all of your nominated handlers. - -=item LAST_MODIFIED - -Optional Attribute set by the last_modified() method. If set, HeavyCGI -will send a Last-Modified header of the specified time, otherwise it -sends a Last-Modified header of the current time. The attribute needs -to contain an L object. - -=item MYURL - -The URL of the running request set by the myurl() method. Contains an -URI::URL object. - -=item R - -The Apache Request object for the running request. Needs to be set up -in the constructor by the user. - -=item REFERER - -Unused. - -=item SERVERROOT_URL - -The URL of the running request's server-root set by the -serverroot_url() method. Contains an URI::URL object. - -=item SERVER_ADMIN - -Unused. - -=item TIME - -The time when this request started set by the time() method. Please -note, that the time() system call is considerable faster than the -method call to PAUSE::HeavyCGI::time. The advantage of calling using -the TIME attribute is that it is self-consistent (remains the same -during a request). - -=item TODAY - -Today's date in the format 9999-99-99 set by the today() method, based -on the time() method. - -=back - - - -=head2 Performance - -Don't expect PAUSE::HeavyCGI to serve 10 million page impressions a -day. The server I have developed it for is a double processor machine -with 233 MHz, and each request is handled by about 30 different -handlers: a few trigonometric, database, formatting, and recoding -routines. With this overhead each request takes about a tenth of a -second which in many environments will be regarded as slow. On the -other hand, the server is well respected for its excellent response -times. YMMV. - -=head1 BUGS - -The fields pragma doesn't mix very well with Apache::StatINC. When -working with HeavyCGI you have to restart your server quite often when -you change your main class. I believe, this could be fixed in -fields.pm, but I haven't tried. A workaround is to avoid changing the -main class, e.g. by delegating the layout() method to a different -class. - -*** Note: this has no meaning anymore after 0.0133 *** - -=head1 AUTHOR - -Andreas Koenig . Thanks to Jochen Wiedmann -for heavy debates about the code and crucial performance enhancement -suggestions. The development of this code was sponsered by -www.speed-link.de. - -=cut - diff --git a/lib/PAUSE/HeavyCGI/Date.pm b/lib/PAUSE/HeavyCGI/Date.pm deleted file mode 100644 index 43df9003b..000000000 --- a/lib/PAUSE/HeavyCGI/Date.pm +++ /dev/null @@ -1,79 +0,0 @@ -package PAUSE::HeavyCGI::Date; -use 5.005; -use strict; - -use vars qw($VERSION); -$VERSION = sprintf "%d.%03d", q$Revision: 1.3 $ =~ /(\d+)\.(\d+)/; - -use HTTP::Date (); -use overload '""' => "http"; - -sub new { - my($class,%arg) = @_; - $arg{unix} = time unless %arg; - my $self = bless {}, $class; - while (my($k,$v) = each %arg) { - $self->{$k} = $v; - } - $self; -} - -sub unix { - my $self = shift; - my($set) = @_; - if (defined $set) { - $self->{unix} = $set; - $self->{http} = undef; - } - return $self->{unix} if defined $self->{unix}; # can be 0 - $self->{unix} = HTTP::Date::str2time($self->{http}); -} - -sub http { - my $self = shift; - my($set) = @_; - if (defined $set) { - $self->{http} = $set; - $self->{unix} = undef; - } - unless (defined $self->{unix}) { - require Carp; - Carp::confess("No time in my object"); - } - $self->{http} ||= HTTP::Date::time2str($self->{unix}); # can't be 0 or "" -} - -1; - -=head1 NAME - -PAUSE::HeavyCGI::Date - represent a date as both unix time and HTTP time - -=head1 SYNOPSIS - - my $date = PAUSE::HeavyCGI::Date->new; - - $date->unix(time); # set - print $date->unix; # get - print $date->http; # get as http - print $date; # same thing due to overloading - -=head1 DESCRIPTION - -This class implements a simple dual value date variable. There are -only two accessor methods that let you set and get dates. unix() sets -and gets the UNIX time, and http() gets and sets the HTTP time. -Whenever a time is set the other time gets undefined. Retrieving an -undefined time triggers a conversion from the other time. That way the -two times are always synced. - -=head1 PREREQUISITES - -The class uses HTTP::Date internally. - -=head1 AUTHOR - -andreas koenig - -=cut - diff --git a/lib/PAUSE/HeavyCGI/Debug.pm b/lib/PAUSE/HeavyCGI/Debug.pm deleted file mode 100644 index d7623c0b4..000000000 --- a/lib/PAUSE/HeavyCGI/Debug.pm +++ /dev/null @@ -1,39 +0,0 @@ -package PAUSE::HeavyCGI::Debug; -use base 'Class::Singleton'; -use Data::Dumper; -use strict; - -sub as_string { - my PAUSE::HeavyCGI::Debug $self = shift; - my PAUSE::HeavyCGI $mgr = shift; - - # An AVHV is ugly to look at, so we convert to an HASH - - my(%f,$k,$v); - - while (($k,$v) = each %$mgr){ - next unless defined $v; - $f{$k} = $v; - } - Data::Dumper::Dumper( \%f ) -} - -1; - -=head1 NAME - -PAUSE::HeavyCGI::Debug - inspect the Pseudohash as Hash with Data::Dumper - -=head1 SYNOPSIS - - push @layout, "
",
-               $self->instance_of("PAUSE::HeavyCGI::Debug"),
-               "

\n"; - -=head1 DESCRIPTION - -Can be used to inspect the application object within an output page. -The Class is just implemented as an illustration. - -=cut - diff --git a/lib/PAUSE/HeavyCGI/Exception.pm b/lib/PAUSE/HeavyCGI/Exception.pm deleted file mode 100644 index b00354a12..000000000 --- a/lib/PAUSE/HeavyCGI/Exception.pm +++ /dev/null @@ -1,31 +0,0 @@ -package PAUSE::HeavyCGI::Exception; -use strict; - -sub new { - my $class = shift; - bless { @_ }, $class; -} - -1; - -=head1 NAME - - PAUSE::HeavyCGI::Exception - exception class for PAUSE::HeavyCGI - -=head1 SYNOPSIS - - die PAUSE::HeavyCGI::Exception->new(HTTP_STATUS => status); - die PAUSE::HeavyCGI::Exception->new(ERROR => [error, ...]); - -=head1 DESCRIPTION - -The execution of the PAUSE::HeavyCGI::prepare method is protected by -an eval. Within that block the above mentioned exceptions can be -thrown. For a discussion of the semantics of these errors, see -L. - -You need not C the PAUSE::HeavyCGI::Error module, it is -already required by PAUSE::HeavyCGI. - -=cut - diff --git a/lib/PAUSE/HeavyCGI/ExePlan.pm b/lib/PAUSE/HeavyCGI/ExePlan.pm deleted file mode 100644 index 0ae0d10f3..000000000 --- a/lib/PAUSE/HeavyCGI/ExePlan.pm +++ /dev/null @@ -1,169 +0,0 @@ -package PAUSE::HeavyCGI::ExePlan; -use PAUSE::HeavyCGI; # want only the instance_of method -use strict; -# use fields qw(PLAN DEBUG FUNCTIONAL WATCHVARIABLE); - -use vars '$VERSION'; -$VERSION = sprintf "%d.%03d", q$Revision: 1.10 $ =~ /(\d+)\.(\d+)/; - -# no singleton, every Application can have its own execution plan even -# every object can have it's own, although, it probably doesn't pay - -sub new { - my($me,%arg) = @_; - my $methods = $arg{METHODS} || [qw(header parameter)]; - my $classes = $arg{CLASSES} || []; - my $functional = $arg{WALKTYPE} eq "f"; - my $watchvariable = $arg{WATCHVARIABLE}; - my $debug = $arg{DEBUG} || 0; #### undocumented - my @plan; - for my $method (@$methods) { - for my $class (@$classes) { - my($obj,$subr); - eval { $obj = $class->instance; }; - if ($@) { - $obj = PAUSE::HeavyCGI->instance_of($class); - } - next unless $subr = $obj->can($method); - if ($functional) { - push @plan, $subr, $obj; - } else { - push @plan, $obj, $method; - } - } - } - no strict "refs"; - my $self = bless {}, $me; - $self->{PLAN} = [ @plan ]; - $self->{DEBUG} = $debug; - $self->{FUNCTIONAL} = $functional; - $self->{WATCHVARIABLE} = $watchvariable; - $self; -} - -sub walk { - my PAUSE::HeavyCGI::ExePlan $self = shift; - my PAUSE::HeavyCGI $application = shift; - if ($self->{WATCHVARIABLE}) { - require Data::Dumper; - } - for (my $i=0;;$i+=2) { - warn sprintf( - "entering method[%s] walktype[%s]", - $self->{PLAN}[$i]."::".$self->{PLAN}[$i+1], - $self->{FUNCTIONAL} ? "f" : "m", - ) if $self->{DEBUG} && $self->{DEBUG} & 1; - my $before = $self->{WATCHVARIABLE} ? - Data::Dumper::Dumper($application->{$self->{WATCHVARIABLE}}) : - ""; - if ($self->{FUNCTIONAL}) { - my $subr = $self->{PLAN}[$i] or last; - my $obj = $self->{PLAN}[$i+1]; - $subr->($obj,$application); - } else { - my $obj = $self->{PLAN}[$i] or last; - my $method = $self->{PLAN}[$i+1]; - $obj->$method($application); - } - warn sprintf "exiting" if $self->{DEBUG} && $self->{DEBUG} & 2; - my $after = $self->{WATCHVARIABLE} ? - Data::Dumper::Dumper($application->{$self->{WATCHVARIABLE}}) : ""; - unless ($before eq $after) { - warn sprintf( - "variable %s changed value from[%s]to[%s] in method[%s]", - $self->{WATCHVARIABLE}, - $before, - $after, - $self->{PLAN}[$i]."::".$self->{PLAN}[$i+1], - ); - } - } -} - -1; - -__END__ - - -=head1 NAME - -PAUSE::HeavyCGI::ExePlan - Creates an execution plan for PAUSE::HeavyCGI - -=head1 SYNOPSIS - - use PAUSE::HeavyCGI::ExePlan; - my $plan = PAUSE::HeavyCGI::ExePlan->new( - METHODS => ["header", "parameter"], - CLASSES => ["my_application::foo", "my_application::bar", ... ], - DEBUG => 1, - WALKTYPE => "m", - WATCHVARIABLE => "SOME VARIABLE", - - $plan->walk; - -=head1 DESCRIPTION - -When an execution plan object is instantiated, it immediately visits -all specified classes, collects the singleton objects for these -classes, and checks if the classes define the specified methods. It -creates an array of objects and methods or an array of code -references. - -The walk method walks through the execution plan in the stored order -and sends each singleton object the appropriate method and passes the -application object as the first argument. - -Normally, every application has its own execution plan. If the -execution plan is calculated at load time of the application class, -all objects of this class can share a common execution plan, thus -speeding up the requests. Consequently it is recommended to have an -initialization in all applications that instantiates an execution plan -and passes it to all application objects in the constructor. - -=head1 ARGUMENTS TO THE CONSTRUCTOR - -=over - -=item METHODS - -An anonymous array consisting of method names that shall be called -when walk() is called. Defaults to - - [qw(header parameter)] - -=item CLASSES - -An anonymous array of class names (a.k.a. widgets) that shall be -visited when walk() is called. Has no default. - -=item DEBUG - -Currently only 0 and 1, 2 or 3 are allowed. If 1, each class/method -pair triggers a warning on entering their execution. If 2, the warning -is triggered at exit of the subroutine. If 3, both entry and exit -trigger a warning. - -=item WATCHVARIABLE - -Name of a member variable. Defaults to C. By setting -WATCHVARIABLE you can watch a member variable of the PAUSE::HeavyCGI -object on entering/exiting each call to each class/method pair. Only -changes of the variable trigger a warning. - -=item WALKTYPE - -A single letter, either C (default) or C. If set to C, all -method calls issued by the call to walk() are execute as method calls. -If set to C, all method calls are replaced by their equivalent -subroutine calls, bypassing perl's method dispatch algorithm. The -latter is recommended on the production server, the former is -recommended in the development environment. C allows you to use the -Apache::StatINC module with the effect it usually has. Using -Apache::StatINC with WALKTYPE=f has B, as all subroutines -are preserved when Apache::StatINC reloads a file, so the execution -plan will not note the change. - -=back - -=cut - diff --git a/lib/PAUSE/HeavyCGI/IfModified.pm b/lib/PAUSE/HeavyCGI/IfModified.pm deleted file mode 100644 index 85200744b..000000000 --- a/lib/PAUSE/HeavyCGI/IfModified.pm +++ /dev/null @@ -1,74 +0,0 @@ -package PAUSE::HeavyCGI::IfModified; -use strict; -use base 'Class::Singleton'; - -use vars qw($VERSION); -$VERSION = sprintf "%d.%03d", q$Revision: 1.1 $ =~ /(\d+)\.(\d+)/; - -use HTTP::Date (); - -sub header { - my PAUSE::HeavyCGI::IfModified $self = shift; - my PAUSE::HeavyCGI $mgr = shift; - - my $now = $mgr->time; - my $req = $mgr->{REQ}; - - my $last_modified = $mgr->last_modified; - $mgr->{RES}->header('Date', HTTP::Date::time2str($now)); - - if (my $ifmodisi = $req->header('If-Modified-Since')) { - # warn "Got ifmodisi[$ifmodisi]"; - $ifmodisi =~ s/\;.*//; - my $ret; - if ($last_modified->http eq $ifmodisi) { - $ret = 304; - } else { - my $ifmodisi_unix = HTTP::Date::str2time($ifmodisi); - if (defined $ifmodisi_unix - && - $ifmodisi_unix < $now - && - $ifmodisi_unix >= $last_modified->unix - ) { - $ret = 304; - } - } - return $mgr->{DONE} = $ret if $ret; - } -} - -1; - -=head1 NAME - -PAUSE::HeavyCGI::IfModified - Within PAUSE::HeavyCGI return 304 - -=head1 SYNOPSIS - - require PAUSE::HeavyCGI::IfModified; - push @{$mgr->{HANDLER}}, - "PAUSE::HeavyCGI::IfModified"; # $mgr is an PAUSE::HeavyCGI object - -=head1 DESCRIPTION - -If-modified-since is tricky. We have pages with very differing -last modification. Some are modified NOW, some are old, most are -MADE now but would have been just the same many hours ago. - -Because it's the recipe that is used for the composition of a page, it -may well be that a page that has never been generated before, -nonetheless has a Last-Modified date in the past. The Last-Modified -header acts as a weak validator for cache activities, and the older a -document appears to be, the longer the cache will store it for us by -default. When the cache revisits us after it has got a valid -Last-Modified header, it will use an If-Modified-Since header and if -we carefully determine our own Last-Modified time, we can spare a lot -of processing by returning a Not Modified response instead of working. - -IfModified should be one of the last handlers in any PAUSE::HeavyCGI -environment, at least it must be processed after all the handlers that -might set the LAST_MODIFIED date. - -=cut - diff --git a/lib/PAUSE/HeavyCGI/Layout.pm b/lib/PAUSE/HeavyCGI/Layout.pm deleted file mode 100644 index 82a2926ea..000000000 --- a/lib/PAUSE/HeavyCGI/Layout.pm +++ /dev/null @@ -1,95 +0,0 @@ -package PAUSE::HeavyCGI::Layout; -use 5.005; - -use strict; -use vars qw($VERSION); - -#use fields qw[ - -### CONTENT -### PREJOINED - -#]; - -$VERSION = sprintf "%d.%03d", q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/; - -sub new { - my($class,@arr) = @_; - no strict "refs"; - my $self = bless {}, $class; - $self->{CONTENT} = [@arr]; - $self; -} - -sub content { - my PAUSE::HeavyCGI::Layout $self = shift; - @{$self->{CONTENT}}; -} - -sub prejoin { #make the array shorter - my PAUSE::HeavyCGI::Layout $self = shift; - return if $self->{PREJOINED}; - my $a = $self->{CONTENT}; - my($i) = 0; - while ($i < @$a-2){ - if ( ref($a->[$i]) || ref($a->[$i+1])){ - ++$i; - } else { - splice @$a, $i, 2, join("",$a->[$i],$a->[$i+1]); - } - } - $self->{PREJOINED} = 1; -} - -sub as_string { - my PAUSE::HeavyCGI::Layout $self = shift; - my PAUSE::HeavyCGI $mgr = shift; - my @m; - for my $chunk ($self->content) { - if (ref $chunk and $chunk->can("as_string")) { - push @m, $chunk->as_string($mgr); - } else { - push @m, "$chunk"; - # Carp::cluck("Hey-4. chunk[$chunk]"); - } - } - join "", @m; -} - -1; - -=head1 NAME - -PAUSE::HeavyCGI::Layout - Represent a page layout in an array - -=head1 SYNOPSIS - - my $layout = PAUSE::HeavyCGI::Layout->new(@array); - - $layout->prejoin; # make the array more compact - - my @array = $layout->content; - my $string = $layout->as_string($object); - -=head1 DESCRIPTION - -The constructor new() takes as an argument an array of elements. -Elements may be strings and objects in any order. - -The content() method returns the array of elements. - -The prejoin() method joins adjacent string elements, leaving at most -one string element between objects in the array. - -The as_string() method takes an object, say $mgr, as an argument and -joins all elements of the array such that all chunks that represent an -object are called with - - $chunk->as_string($mgr) - -and all chunks that represent a string are fillers in between. Objects -that do not understand the as_string method are just filled in as -strings, leaving room for debugging or overloading or whatever. - -=cut - diff --git a/lib/PAUSE/HeavyCGI/SquidRemoteAddr.pm b/lib/PAUSE/HeavyCGI/SquidRemoteAddr.pm deleted file mode 100644 index e5a4a0c56..000000000 --- a/lib/PAUSE/HeavyCGI/SquidRemoteAddr.pm +++ /dev/null @@ -1,41 +0,0 @@ -package Apache::HeavyCGI::SquidRemoteAddr; -use Apache::Constants qw(:common); -use constant SRA_DEBUG => 0; -use strict; -use vars qw($VERSION $NoHeader_warned); -$VERSION = sprintf "%d.%03d", q$Revision: 1.5 $ =~ /(\d+)\.(\d+)/; - - -sub handler { - my $r = shift; - - my $xff = $r->header_in('X-Forwarded-For')||""; - if (my($ip) = $xff =~ /([^,\s]+)$/) { - $r->connection->remote_ip($ip); - } else { - warn sprintf "No IP in X-Forwarded-For[%s]", $xff - unless $NoHeader_warned++; - } - warn sprintf "HERE Headers[%s]", join " ", $r->headers_in if SRA_DEBUG; - - DECLINED; -} - -1; - -__END__ - -=head1 NAME - -Apache::HeavyCGI::SquidRemoteAddr - Pass X-Forwarded-For Header through as remote_ip - -=head1 SYNOPSIS - - PerlPostReadRequestHandler Apache::HeavyCGI::SquidRemoteAddr - -=head1 DESCRIPTION - -Author Vivek Khera, taken from his mod_perl_tuning document. - -=cut - diff --git a/lib/PAUSE/HeavyCGI/UnmaskQuery.pm b/lib/PAUSE/HeavyCGI/UnmaskQuery.pm deleted file mode 100644 index c726a367c..000000000 --- a/lib/PAUSE/HeavyCGI/UnmaskQuery.pm +++ /dev/null @@ -1,108 +0,0 @@ -package Apache::HeavyCGI::UnmaskQuery; -use Apache::Constants qw(:common); -use constant AHU_DEBUG => 0; -use strict; -use vars qw($VERSION); -$VERSION = sprintf "%d.%03d", q$Revision: 1.11 $ =~ /(\d+)\.(\d+)/; - - -sub handler { - my($r) = @_; - my $uri = $r->uri; - if ( my($u1,$u2) = $uri =~ / ^ ([^?]+?) ; ([^?]*) $ /x ) { - $r->uri($u1); - # $u2 =~ s/%..//g; # just testing - $u2 =~ s/;/&/g if $u2 =~ /&/; # don't mix: bug in Apache::Request ? - $r->args($u2); - warn "UnmaskQuery(v$VERSION): u1[$u1]u2[$u2]" if AHU_DEBUG; - } elsif ($uri =~ /\?/) { - my $args = $r->args; - if ($args =~ /&/ and $args =~ s/;/&/g) { # don't mix! - $r->args($args); - warn "UnmaskQuery(v$VERSION): args[$args]" if AHU_DEBUG; - } else { - warn "UnmaskQuery(v$VERSION): nothing" if AHU_DEBUG; - } - } elsif ( my($u1,$u2) = $uri =~ m/^(.*?)%3[Bb](.*)$/ ) { - # protect against old proxies that escape volens nolens - $r->uri($u1); - $u2 =~ s/%3B/;/gi; - $u2 =~ s/%26/;/gi; # & - $u2 =~ s/%3D/=/gi; - $r->args($u2); - warn "UnmaskQuery(v$VERSION): oldproxy-u1[$u1]u2[$u2]" - if 1||AHU_DEBUG; - } - - DECLINED; -} - -1; - -__END__ - -=head1 NAME - -Apache::HeavyCGI::UnmaskQuery - Allow queries without a questionmark - -=head1 SYNOPSIS - - - require Apache::HeavyCGI::UnmaskQuery; - $PerlPostReadRequestHandler = "Apache::HeavyCGI::UnmaskQuery"; - - - -or- - - PerlModule Apache::HeavyCGI::UnmaskQuery - PerlPostReadRequestHandler Apache::HeavyCGI::UnmaskQuery - -=head1 DESCRIPTION - -This Apache Handler can be used from apache 1.3 (when -post_read_request was introduced) upwards to turn a request that looks -like an ordinary static request to the unsuspecting observer into a -query that can be handled by the CGI or Apache::Request module or by -the $r->args method. - -The reason why you might want to do this lies in the fact that many -cache servers in use today (1999) are configured wrongly in that they -disallow caching of URIs with a questionmark in them. By composing -URIs with a semicolon instead of a questionmark, these cache servers -can be tricked into working correctly. - -Thus this handler replaces the first semicolon in any request for an -URI with a questionmark (unless that URI does already contain a -questionmark). As this is being done in the very early stage of -apache's handling phase, namely in a PerlPostReadRequestHandler, all -subsequent phases can be tricked into seeing the request as a query. - -Unfortunately the last paragraph is not completely true. Apache 1.3.4 -is not allowing C<%2F> (a slash in ASCII) and C<%00> (a binary 0) in -the I section of the HTTP URI, only in the I -section. Apparently the URL is parsed before the during read_request.... - - Breakpoint 1, 0x80b9d05 in ap_unescape_url () - (gdb) bt - #0 0x80b9d05 in ap_unescape_url () - #1 0x80b5a56 in ap_some_auth_required () - #2 0x80b5fb0 in ap_process_request () - #3 0x80adbcd in ap_child_terminate () - #4 0x80add58 in ap_child_terminate () - #5 0x80adeb3 in ap_child_terminate () - #6 0x80ae490 in ap_child_terminate () - #7 0x80aecc3 in main () - (gdb) c - - -So if any parameter needs to contain a slash or a binary 0, -we must resort to a different escape method. Now it's turning -ridiculous quickly. I believe, this is a bug in apache and must be -fixed there. But what if the apche group doesn't listen to us? - -Easy answer: don't escape slashes if you want to use this technique. -Don't dare to need binary nulls in your parameters. Until it is -figured out if apache group sees this as a bug or not. - -=cut - diff --git a/lib/PAUSE/Middleware/Auth/Basic.pm b/lib/PAUSE/Middleware/Auth/Basic.pm deleted file mode 100644 index 99e59c914..000000000 --- a/lib/PAUSE/Middleware/Auth/Basic.pm +++ /dev/null @@ -1,24 +0,0 @@ -package PAUSE::Middleware::Auth::Basic; -use strict; -use parent qw(Plack::Middleware::Auth::Basic); -use Plack::Request; -use HTTP::Status qw(:constants); -use pause_1999::authen_user; - -sub prepare_app { shift->realm('PAUSE') } - -sub call { - my($self, $env) = @_; - - my $auth = $env->{HTTP_AUTHORIZATION} - or return $self->unauthorized; - - my $req = Plack::Request->new($env); - my $res = pause_1999::authen_user::handler($req); - - return $res->finalize if ref $res; - return $self->unauthorized unless $res == HTTP_OK; - return $self->app->($env); -} - -1; diff --git a/lib/pause_1999/Todo b/lib/pause_1999/Todo deleted file mode 100644 index 7a145479f..000000000 --- a/lib/pause_1999/Todo +++ /dev/null @@ -1 +0,0 @@ -DONE. diff --git a/lib/pause_1999/authen_user.pm b/lib/pause_1999/authen_user.pm deleted file mode 100644 index b5935e122..000000000 --- a/lib/pause_1999/authen_user.pm +++ /dev/null @@ -1,249 +0,0 @@ -package pause_1999::authen_user; -use pause_1999::main; -use HTTP::Status qw(:constants); -use base 'Class::Singleton'; -use PAUSE (); -use PAUSE::Crypt; -use strict; -our $VERSION = "1052"; - -=comment - -Apache::AuthenDBI was not enough for my taste. I want the username -case insensitive but the password case sensitive. I want to store the -user record early and this seems an appropriate place. - - - -=cut - -sub header { - my pause_1999::authen_user $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - if (my $u = $req->user) { - #This is a database application with nearly all users having write access - #Write access means expiration any moment - my $headers = $mgr->{RES}->headers; - $headers->header('Pragma', 'no-cache'); $headers->header('Cache-control', 'no-cache'); - # XXX: $res->no_cache(1); - # This is annoying when we ask for the who-is-who list and it - # hasn't changed since the last time, but for most cases it's - # safer to expire - - # we are not authenticating here, we retrieve the user record from - # the open database. Thus - my $dbh = $mgr->connect; # and not authentication database - local($dbh->{RaiseError}) = 0; - my($sql,$sth); - $sql = qq{SELECT * - FROM users - WHERE userid=? AND ustatus != 'nologin'}; - $sth = $dbh->prepare($sql); - if ($sth->execute($u)) { - if (0 == $sth->rows) { - my($sql7,$sth7); - $sql7 = qq{SELECT * - FROM users - WHERE userid=?}; - $sth7 = $dbh->prepare($sql7); - $sth7->execute($u); - my $error; - if ($sth7->rows > 0) { - $error = "User '$u' set to nologin. Many users with an insecure password have got their password reset recently because of an incident on perlmonks.org. Please talk to modules\@perl.org to find out how to proceed"; - } else { - $error = "User '$u' not known"; - } - die PAUSE::HeavyCGI::Exception->new(ERROR => $error); - } else { - $mgr->{User} = $mgr->fetchrow($sth, "fetchrow_hashref"); - } - } else { - die PAUSE::HeavyCGI::Exception->new(ERROR => $dbh->errstr); - } - $sth->finish; - - my $dbh2 = $mgr->authen_connect; - $sth = $dbh2->prepare("SELECT secretemail - FROM $PAUSE::Config->{AUTHEN_USER_TABLE} - WHERE $PAUSE::Config->{AUTHEN_USER_FLD}=?"); - $sth->execute($u); - my($secretemail) = $sth->fetchrow_array; - $mgr->{User}{secretemail} = $secretemail; - $sth->finish; - - $sql = qq{SELECT * - FROM grouptable - WHERE user=?}; - $sth = $dbh2->prepare($sql); - if ($sth->execute($u)) { - $mgr->{UserGroups} = {}; - while (my $rec = $mgr->fetchrow($sth, "fetchrow_hashref")) { - $mgr->{UserGroups}{$rec->{ugroup}} = undef; - } - } else { - die PAUSE::HeavyCGI::Exception->new(ERROR => $dbh2->errstr); - } - $sth->finish; - - delete $mgr->{UserGroups}{mlrepr}; # virtual group, disallow in the table - $sql = qq{SELECT * - FROM list2user - WHERE userid=?}; - $sth = $dbh->prepare($sql); - $sth->execute($u) or die PAUSE::HeavyCGI::Exception->new(ERROR => $dbh->errstr); - if ($sth->rows > 0) { - $mgr->{UserGroups}{mlrepr} = undef; # is a virtual group - $mgr->{IsMailinglistRepresentative} = {}; - while (my $rec = $mgr->fetchrow($sth, "fetchrow_hashref")) { - $mgr->{IsMailinglistRepresentative}{$rec->{maillistid}} = undef; - } - } - - $mgr->{UserSecrets} = $req->env->{'psgix.pnotes'}{usersecrets}; - if ( $mgr->{UserSecrets}{forcechange} ) { - $mgr->{Action} = "change_passwd"; # ueberschreiben - $mgr->{REQ}->param(ACTION=>"change_passwd"); # faelschen - } - } -} - -sub handler { - my($req) = @_; - - local $SIG{__WARN__} = sub { - my $message = shift; - chomp $message; - Log::Dispatch::Config->instance->log( - level => 'warn', - message => $message, - ); - }; - - my $cookie; - my $uri = $req->path || ""; - my $args = $req->uri->query; - warn "WATCH: uri[$uri]args[$args]"; - if ($cookie = $req->header('Cookie')) { - if ( $cookie =~ /logout/ ) { - warn "WATCH: cookie[$cookie]"; - my $res = $req->new_response(HTTP_UNAUTHORIZED); - $res->cookies->{logout} = { - value => '', - path => $uri, - expires => "Sat, 01-Oct-1974 00:00:00 UTC", - }; - return $res; - } - } - if ($args) { - my $logout; - if ( my $logout = $req->query_parameters->get('logout') ) { - warn "WATCH: logout[$logout]"; - if ($logout =~ /^1/) { - my $res = $req->new_response(HTTP_MOVED_PERMANENTLY); - $res->cookies->{logout} = { - value => '', - path => $uri, - expires => "Sat, 01-Oct-2027 00:00:00 UTC", - }; - $res->header("Location",$uri); - return $res; - } elsif ($logout =~ /^2/) { # badname - my $redir = $req->base; - $redir->path($req->uri->path); - $redir->userinfo('baduser:badpass'); - warn "redir[$redir]"; - my $res = $req->new_response(HTTP_MOVED_PERMANENTLY); - $res->header("Location",$redir); - return $res; - } elsif ($logout =~ /^3/) { # cancelnote - return HTTP_UNAUTHORIZED; - } - } - } - # return HTTP_OK unless $r->is_initial_req; #only the first internal request - - my $auth = $req->env->{HTTP_AUTHORIZATION} or return HTTP_UNAUTHORIZED; - return HTTP_UNAUTHORIZED unless $auth =~ /^Basic (.*)$/i; #decline if not Basic - my($user_sent, $sent_pw) = split /:/, (MIME::Base64::decode($1) || ":"), 2; - - my $attr = { - data_source => $PAUSE::Config->{AUTHEN_DATA_SOURCE_NAME}, - username => $PAUSE::Config->{AUTHEN_DATA_SOURCE_USER}, - password => $PAUSE::Config->{AUTHEN_DATA_SOURCE_PW}, - pwd_table => $PAUSE::Config->{AUTHEN_USER_TABLE}, - uid_field => $PAUSE::Config->{AUTHEN_USER_FLD}, - pwd_field => $PAUSE::Config->{AUTHEN_PASSWORD_FLD}, - }; - - my $dbh; - warn "DEBUG: attr.data_source[$attr->{data_source}]"; - unless ($dbh = DBI->connect($attr->{data_source}, - $attr->{username}, - $attr->{password}, - {mysql_auto_reconnect => 1})) { - $req->logger->({level => 'error', message => " db connect error with $attr->{data_source} ".$req->path }); - my $redir = $req->path; - $redir =~ s/authen//; - delete $req->env->{REMOTE_USER}; - return $req->new_response(HTTP_INTERNAL_SERVER_ERROR, undef, $redir); - } - - # generate statement - my $user_record; - my @try_user = $user_sent; - push @try_user, uc $user_sent if $user_sent ne uc $user_sent; - - my $statement = qq{SELECT * FROM $attr->{pwd_table} - WHERE $attr->{uid_field}=?}; - # prepare statement - my $sth; - unless ($sth = $dbh->prepare($statement)) { - $req->logger->({level => 'error', message => "can not prepare statement: $DBI::errstr". $req->path }); - $dbh->disconnect; - return $req->new_response(HTTP_INTERNAL_SERVER_ERROR); - } - for my $user (@try_user){ - unless ($sth->execute($user)) { - $req->logger->({level => 'error', message => " can not execute statement: $DBI::errstr" . $req->path }); - $dbh->disconnect; - return $req->new_response(HTTP_INTERNAL_SERVER_ERROR); - } - - if ($sth->rows == 1){ - $user_record = pause_1999::main::->fetchrow($sth, "fetchrow_hashref"); - $req->env->{REMOTE_USER} = $user; - last; - } - } - $sth->finish; - - my $crypt_pw = $user_record->{$attr->{pwd_field}}; - if ($crypt_pw) { - if (PAUSE::Crypt::password_verify($sent_pw, $crypt_pw)) { - PAUSE::Crypt::maybe_upgrade_stored_hash({ - password => $sent_pw, - old_hash => $crypt_pw, - dbh => $dbh, - username => $user_record->{user}, - }); - $req->env->{'psgix.pnotes'}{usersecrets} = $user_record; - $dbh->do - ("UPDATE usertable SET lastvisit=NOW() where user=?", - +{}, - $user_record->{user}, - ); - $dbh->disconnect; - return HTTP_OK; - } else { - warn sprintf "crypt_pw[%s]user[%s]uri[%s]auth_required[%d]", - $crypt_pw, $user_record->{user}, $req->path, HTTP_UNAUTHORIZED; - } - } - - $dbh->disconnect; - return HTTP_UNAUTHORIZED; -} - -1; diff --git a/lib/pause_1999/config.pm b/lib/pause_1999/config.pm deleted file mode 100644 index 4743eb66b..000000000 --- a/lib/pause_1999/config.pm +++ /dev/null @@ -1,512 +0,0 @@ -#!/usr/bin/perl -- -*- Mode: cperl; -*- -package pause_1999::config; -use pause_1999::main; -use PAUSE::HeavyCGI::ExePlan; -use strict; -use PAUSE (); -use HTTP::Status qw(:constants); -use vars qw( $Exeplan ); -use vars qw($VERSION); -$VERSION = "949"; - -# Tell the system which packages want to see the headers or the -# parameters. -$Exeplan = PAUSE::HeavyCGI::ExePlan->new( - CLASSES => [qw( -pause_1999::authen_user -pause_1999::edit -pause_1999::usermenu -)]); - -our $DEFAULT_USER_ACTIONS = -{ - # PUBLIC - request_id => { - verb => "Request PAUSE account", - priv => "public", - cat => "00reg/01", - desc => "Apply for a PAUSE account.", - }, - - mailpw => { - verb => "Forgot Password?", - priv => "public", - cat => "00urg/01", - desc => <<'DESC', -A passwordmailer that sends you a password that enables you to set a new password. -DESC - }, - - pause_04about => { - verb => "About PAUSE", - priv => "public", - cat => "01self/04a", - desc => "Same as modules/04pause.html on any CPAN server", - }, - - pause_04imprint => { - verb => "Imprint/Impressum", - priv => "public", - cat => "01self/06b", - }, - - pause_05news => { - verb => "PAUSE News", - priv => "public", - cat => "01self/05", - desc => "What's going on on PAUSE", - }, - - pause_06history => { - verb => "PAUSE History", - priv => "public", - cat => "01self/06", - desc => "Old News", - }, - - pause_namingmodules => { - verb => "On The Naming of Modules", - priv => "public", - cat => "01self/04b", - desc => "A couple of suggestions that hopefully get you on track", - }, - - who_pumpkin => { - verb => "List of pumpkins", - priv => "public", - cat => "02serv/05", - desc => "A list, also available as YAML", - }, - - who_admin => { - verb => "List of admins", - priv => "public", - cat => "02serv/06", - desc => "A list, also available as YAML", - }, - - # USER - - # USER/FILES - - add_uri => { - verb => "Upload a file to CPAN", - priv => "user", - cat => "User/01Files/01up", - desc => <<'DESC', -This is the heart of the Upload Server, the page most heavily used on -PAUSE. -DESC - }, - - show_files => { - verb => "Show my files", - priv => "user", - cat => "User/01Files/02show", - desc => "find . -ls resemblance", - }, - - edit_uris => { - verb => "Repair a Pending Upload", - priv => "user", - cat => "User/01Files/03rep", - desc => <<'DESC', -When an upload you requested hangs for some reason, you can go here and edit the -file to be uploaded. -DESC - }, - - delete_files => { - verb => "Delete Files", - priv => "user", - cat => "User/01Files/04del", - desc => <<'DESC', -Schedule files for deletion. There is a delay until the deletion really happens. -Until then you can also undelete files here. -DESC - }, - - # User/Permissions - - peek_perms => { - verb => "View Permissions", - priv => "user", - cat => "User/04Permissions/01", - desc => "Whose uploads of what are being indexed on PAUSE", - }, - - share_perms => { - verb => "Change Permissions", - priv => "user", - cat => "User/04Permissions/02", - desc => <<'DESC', -Enable other users to upload a module for any of your namespaces, manage your -own permissions. -DESC - }, - - # User/Util - - tail_logfile => { - verb => "Tail Daemon Logfile", - priv => "user", - cat => "User/05Utils/06", - }, - - reindex => { - verb => "Force Reindexing", - priv => "user", - cat => "User/05Utils/02", - desc => <<'DESC', -Tell the indexer to index a file again (e.g. after a change in the perms table) -DESC - }, - - reset_version => { - verb => "Reset Version", - priv => "user", - cat => "User/05Utils/02", - desc => <<'DESC', -Overrule the record of the current version number of a module that the indexer -uses and set it to 'undef' -DESC - }, - - # User/Account - - change_passwd => { - verb => "Change Password", - priv => "user", - cat => "User/06Account/02", - desc => "Change your password any time you want.", - }, - - edit_cred => { - verb => "Edit Account Info", - priv => "user", - cat => "User/06Account/01", - desc => <<'DESC', -Edit your user name, your email addresses (both public and secret one), -change the URL of your homepage.", -DESC - }, - - pause_logout => { - verb => "About Logging Out", - priv => "user", - cat => "User/06Account/04", - }, - - # ADMIN+mlrep+modlistmaint - - add_user => { - verb => "Add a User or Mailinglist", - priv => "admin", - cat => "01usr/01add", - desc => "Admins can add users or mailinglists.", - - }, - - manage_id_requests => { - verb => "Manage a registration request (alpha)", - priv => "admin", - cat => "01usr/01rej", - desc => "show/reject open registration requests", - }, - - edit_ml => { - verb => "Edit a Mailinglist", - priv => "admin", - cat => "01usr/02", - desc => <<'DESC', -Admins and mailing list representatives can change the name, address and -description of a mailing list. -DESC - }, - - email_for_admin => { - verb => "Look up the forward email address", - priv => "admin", - cat => "01usr/01look", - desc => "Admins can look where email should go", - }, - - select_user => { - verb => "Select User/Action", - priv => "admin", - cat => "01usr/03", - desc => <<'DESC', -Admins can access PAUSE as-if they were somebody else. Here they select a -user/action pair. -DESC - }, - - post_message => { - verb => "Post a message", - priv => "admin", - cat => "01usr/04", - desc => "Post a message to a specific user.", - }, - - dele_message => { - verb => "Show/Delete Msgs", - priv => "admin", - cat => "01usr/05", - desc => "Delete your messages from the message board.", - }, - - show_ml_repr => { - verb => "Show Mailinglist Reps", - priv => "mlrepr", - cat => "09root/04", - desc => <<'DESC', -Admins and the representatives themselves can lookup who is elected to be -representative of a mailing list. -DESC - }, - - index_users => { - verb => "Index users with digrams (BROKEN)", - priv => "admin", - desc => "Batch-index all users.", - cat => "09root/05", - }, - - select_ml_action => { - - verb => "Select Mailinglist/Action", - priv => "mlrepr", - cat => "09root/02", - desc => <<'DESC', -Representatives of mailing lists have their special menu here. -DESC - }, - - "check_xhtml" => { - verb => "Show bad xhtml output", - priv => "admin", - cat => "09root/06", - desc => "Monitor bad xhtml output stored from previous sessions", - }, - - "coredump" => { - priv => "admin", - cat => "09root/07", - } - -}; - -sub handler { - my($req) = shift; - my $dti = PAUSE::downtimeinfo(); - my $downtime = $dti->{downtime}; - my $willlast = $dti->{willlast}; - my $user = $req->user; - if (time >= $downtime && time < $downtime + $willlast) { - use Time::Duration; - my $delta = $downtime + $willlast - time; - my $expr = Time::Duration::duration($delta); - my $willlast_dur = Time::Duration::duration($willlast); - - my $closed_text = qq{

PAUSE is closed for -maintainance for about $willlast_dur. Estimated time of opening is in -$expr.

Sorry for the inconvenience and Thanks for -your patience.

}; - - if ($user && $user eq "ANDK") { # would prefer a check of the admin role here - $req->env->{'psgix.notes'}{CLOSED} = $closed_text; - } else { - my $res = $req->new_response(HTTP_OK); - $res->content_type("text/html"); - - $res->body(qq{ PAUSE -CLOSED

Closed for Maintainance

-$closed_text

Andreas Koenig

}); - - return $res; - } - } - my $self = pause_1999::main-> - new( - - DownTime => $downtime, - WillLast => $willlast, - ActionTuning => $DEFAULT_USER_ACTIONS, - ActiveColor => "#bbffbb", - AllowAdminTakeover => [qw( - add_uri - change_passwd - delete_files - edit_cred - edit_ml - edit_uris - reindex - reset_version - share_perms - dele_message - )], - AllowMlreprTakeover => [qw( -edit_ml -reset_version -share_perms -)], - AuthenDsn => $PAUSE::Config->{AUTHEN_DATA_SOURCE_NAME}, - AuthenDsnPasswd => $PAUSE::Config->{AUTHEN_DATA_SOURCE_PW}, - AuthenDsnUser => $PAUSE::Config->{AUTHEN_DATA_SOURCE_USER}, - CHARSET => $pause_1999::main::DO_UTF8 ? "utf-8" : "iso-8859-1", - EXECUTION_PLAN => $Exeplan, - MailMailerConstructorArgs => $PAUSE::Config->{MAIL_MAILER}, - MailtoAdmins => join(",",@{$PAUSE::Config->{ADMINS}}), - ModDsn => $PAUSE::Config->{MOD_DATA_SOURCE_NAME}, - ModDsnPasswd => $PAUSE::Config->{MOD_DATA_SOURCE_PW}, - ModDsnUser => $PAUSE::Config->{MOD_DATA_SOURCE_USER}, - REQ => $req, - RES => $req->new_response(HTTP_OK), - RootURL => "/pause", - SessionDataDir => "$PAUSE::Config->{RUNDATA}/session/sdata", - SessionCounterDir => "$PAUSE::Config->{RUNDATA}/session/cnt", - # add more instance variables here. Make sure, they are - # declared in main.pm - - ); - - if ($req->user) { - $self->{QueryURL} = "authenquery"; - - ############# Main Switch for experimental CGI Patch ############# - # patched CGI stands for overloaded values in multipart/formdata - - if (0) { # I do not intend to think further about the patchedCGI - # approach. I believe these headers are not really needed - $self->{UseModuleSet} = $self->{QueryURL} eq "authenquery" ? - "patchedCGI" : "ApReq"; - } else { - $self->{UseModuleSet} = "ApReq"; - } - - # Increase the risk but improve the debugging - $self->need_multipart(1) if $self->{UseModuleSet} eq "patchedCGI"; - - } else { - - $self->{QueryURL} = "query"; - $self->{UseModuleSet} = "ApReq"; - - } - - $self->{OurEmailFrom} = "\"Perl Authors Upload Server\" <$PAUSE::Config->{UPLOAD}>"; - # warn "Debug: OurEmailFrom=UPLOAD[$self->{OurEmailFrom}]"; - my(@time) = gmtime; # sec,min,hour,day,month,year - my $quartal = int($time[4]/3) + 1; # 1..4 - $self->{SessionCounterFile} = "$self->{SessionCounterDir}/Q$quartal"; - - $self->{WaitDir} = "$PAUSE::Config->{RUNDATA}/wait"; - $self->{WaitUserDb} = "users"; - - $self->dispatch; -} - - -######## The following patch allows us to track down what the -######## multipart header said about each variable - -package CGI::MultipartVariables; -use overload "\"\"", "as_string", fallback => 1; - -sub new { bless {}, shift; } -sub set_value { my($self,$val) = @_; $self->{VALUE} = $val; } -sub set_header { my($self,$val) = @_; $self->{HEADER} = $val; } -sub as_string { shift->{VALUE}; } -# sub as_number { shift->{"VALUE"}+0; } -sub multipart_header { shift->{HEADER}; } - - -package CGI; - -##### -# subroutine: read_multipart -# -# Read multipart data and store it into our parameters. -# An interesting feature is that if any of the parts is a file, we -# create a temporary file and open up a filehandle on it so that the -# caller can read from it if necessary. -##### -sub CGI::read_multipart { - my($self,$boundary,$length,$filehandle) = @_; - my($buffer) = $self->new_MultipartBuffer($boundary,$length,$filehandle); - return unless $buffer; - my $filenumber = 0; - while (!$buffer->eof) { - my %header = $buffer->readHeader; - - unless (%header) { - $self->cgi_error("400 Bad request (malformed multipart POST)"); - return; - } - - my($param)= $header{'Content-Disposition'}=~/ name="?([^\";]*)"?/; - - # Bug: Netscape doesn't escape quotation marks in file names!!! - my($filename) = $header{'Content-Disposition'}=~/ filename="?([^\";]*)"?/; - - # add this parameter to our list - $self->add_parameter($param); - - # If no filename specified, then just read the data and assign it - # to our parameter list. - unless ($filename) { - my($value) = $buffer->readBody; - my $var = CGI::MultipartVariables->new; - $var->set_value($value); - $var->set_header(\%header); - push(@{$self->{$param}},$var); - next; - } - - my ($tmpfile,$tmp,$filehandle); - UPLOADS: { - # If we get here, then we are dealing with a potentially large - # uploaded form. Save the data to a temporary file, then open - # the file for reading. - - # skip the file if uploads disabled - if ($CGI::DISABLE_UPLOADS) { - my $data; - while (defined($data = $buffer->read)) { } - last UPLOADS; - } - - # choose a relatively unpredictable tmpfile sequence number - my $seqno = unpack("%16C*",join('',localtime,values %ENV)); - for (my $cnt=10;$cnt>0;$cnt--) { - next unless $tmpfile = new TempFile($seqno); - $tmp = $tmpfile->as_string; - last if $filehandle = Fh->new($filename,$tmp,$CGI::PRIVATE_TEMPFILES); - $seqno += int rand(100); - } - die "CGI open of tmpfile: $!\n" unless $filehandle; - $CGI::DefaultClass->binmode($filehandle) if $CGI::needs_binmode; - - my ($data); - local($\) = ''; - while (defined($data = $buffer->read)) { - print $filehandle $data; - } - - # back up to beginning of file - seek($filehandle,0,0); - $CGI::DefaultClass->binmode($filehandle) if $CGI::needs_binmode; - - # Save some information about the uploaded file where we can get - # at it later. - $self->{'.tmpfiles'}->{$filename}= { - name => $tmpfile, - info => {%header}, - }; - push(@{$self->{$param}},$filehandle); - } - } - warn "leaving CGI::read_multipart"; -} - -1; diff --git a/lib/pause_1999/edit.pm b/lib/pause_1999/edit.pm deleted file mode 100644 index 6d849e9de..000000000 --- a/lib/pause_1999/edit.pm +++ /dev/null @@ -1,7283 +0,0 @@ -#!/usr/bin/perl -- -*- Mode: cperl; -*- - -package pause_1999::edit; -use base 'Class::Singleton'; -use pause_1999::main; -use strict; -use Encode (); -use Fcntl qw(O_RDWR O_RDONLY); -use File::Find qw(find); -use PAUSE::Crypt; -use POSIX (); -use URI::Escape; -use Text::Format; -use HTTP::Status qw(:constants); -eval {require Time::Duration}; -our $HAVE_TIME_DURATION = !$@; - -our $Valid_Userid = qr/^[A-Z]{3,9}$/; -our $Yours = "Thanks,\n-- \nThe PAUSE Team\n"; - -use utf8; # must be after the qr// for perl-5.6.1 - -our $VERSION = "1071.02"; - -our $strict_chapterid = 1; - -sub parameter { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - my($param,@allow_submit,%allow_action); - - # What is allowed here is allowed to anybody - @allow_action{ - ( - "pause_04about", - "pause_04imprint", - "pause_05news", - "pause_06history", - "pause_namingmodules", - "request_id", - "who_pumpkin", - "who_admin", - )} = (); - - @allow_submit = ( - "request_id", - ); - - if ($mgr->{User} && $mgr->{User}{userid} && $mgr->{User}{userid} ne "-") { - - # warn "userid[$mgr->{User}{userid}]"; - - # All authenticated Users - for my $command ( - "add_uri", - "change_passwd", - "delete_files", - "edit_cred", - # "edit_mod", - "edit_uris", - # "apply_mod", - "pause_logout", - "peek_perms", - "reindex", - "reset_version", - "share_perms", - "show_files", - "tail_logfile", - ) { - $allow_action{$command} = undef; - push @allow_submit, $command; - } - - # Only Mailinglist Representatives - if (exists $mgr->{UserGroups}{mlrepr}) { - for my $command ( - "select_ml_action", - "edit_ml", - # "edit_mod", - "reset_version", - "show_ml_repr", - ) { - $allow_action{$command} = undef; - push @allow_submit, $command; - } - } - - # Only Modulelist Maintainers - if (0 && exists $mgr->{UserGroups}{modmaint}) { - for my $command ( - "add_mod", - "apply_mod", - ) { - $allow_action{$command} = undef; - push @allow_submit, $command; - } - } - - # Postmaster or admin - if ( - exists $mgr->{UserGroups}{admin} - or - exists $mgr->{UserGroups}{postmaster} - ) { - for my $command ( - "email_for_admin", - ) { - $allow_action{$command} = undef; - push @allow_submit, $command; - } - } - - # Only Admins - if (exists $mgr->{UserGroups}{admin}) { - # warn "We have an admin here"; - for my $command ( - "add_user", - "edit_ml", - "select_user", - "show_ml_repr", - # "add_mod", # all admins may maintain the module list for now - # "apply_mod", - "check_xhtml", - "coredump", - "dele_message", - "index_users", - "post_message", - "manage_id_requests", - # "test_session", - ) { - $allow_action{$command} = undef; - push @allow_submit, $command; - } - } - - } elsif ($param = $req->param("ABRA")) { - - # TUT: if they sent ABRA, the only thing we let them do is change - # their password. The parameter consists of username-dot-token. - my($user, $passwd) = $param =~ m|(.*?)\.(.*)|; # - - # We allow changing of the password with this password. We leave - # everything else untouched - - my $dbh; - $dbh = $mgr->authen_connect; - my $sql = sprintf qq{DELETE FROM abrakadabra - WHERE NOW() > expires }; - $dbh->do($sql); - $sql = qq{SELECT * - FROM abrakadabra - WHERE user=? AND chpasswd=?}; - my $sth = $dbh->prepare($sql); - if ( $sth->execute($user,$passwd) and $sth->rows ) { - # TUT: in the keys of %allow_action we store the methods that are - # allowed in this request. @allow_submit does something similar. - $allow_action{"change_passwd"} = undef; - push @allow_submit, "change_passwd"; - - # TUT: by setting $mgr->{User}{userid}, we can let change_passwd - # know who we are dealing with - $mgr->{User}{userid} = $user; - - # TUT: Let's pretend they requested change_passwd. I guess, if we - # would drop that line, it would still work, but I like redundant - # coding in such cases - $param = $req->parameters->set("ACTION","change_passwd"); # override - - } else { - die PAUSE::HeavyCGI::Exception->new(ERROR => "You tried to authenticate the -parameter ABRA=$param, but the database doesn't know about this token."); - } - $allow_action{"mailpw"} = undef; - push @allow_submit, "mailpw"; - - } else { - - # warn "unauthorized access (but OK)"; - $allow_action{"mailpw"} = undef; - push @allow_submit, "mailpw"; - - } - $mgr->{AllowAction} = [ sort { $a cmp $b } keys %allow_action ]; - # warn "allowaction[@{$mgr->{AllowAction}}]"; - # warn "allowsubmit[@allow_submit]"; - - $param = $req->param("ACTION"); - # warn "ACTION-param[$param]req[$req]"; - if ($param && exists $allow_action{$param}) { - $mgr->{Action} = $param; - } else { - # ...they might ask for it in a submit button - ACTION: for my $action (@allow_submit) { - - # warn "DEBUG: action[$action]"; - - # we inherited from a different project: One submitbutton on a page - if ( - $param = $req->param("pause99_$action\_sub") - ) { - # warn "action[$action]"; - $mgr->{Action} = $action; - last ACTION; - } - - # Also inherited: One submitbutton but also only one textfield, - # so that RETURN on the textfield submits the form - if ( - $param = $req->param("pause99_$action\_1") - ) { - $req->parameters->set("pause99_$action\_sub", $param); # why? - $mgr->{Action} = $action; - last ACTION; - } - - # I had intended that parameters matching /_sub.*/ are only used - # in cases where RETURN might be used instead of SUBMIT. Then I - # erroneously used "pause99_add_uri_subdirtext" - - my(@partial) = grep /^pause99_\Q$action\E_/, $req->param; - PART: for my $partial (@partial) { - $req->parameters->set("pause99_$action\_sub", $partial); # why not $mgr->{ActionComment}? - $mgr->{Action} = $action; - last PART; - } - } - } - my $action = $mgr->{Action}; - if (!$action || $req->param('lsw')) { # let submit win - - # the let submit win parameter was introduced when I realized that - # submit should always win but was afraid that it might break - # something when we suddenly let submit win in all cases. So new - # forms should always specify lsw=1 so we can migrate to making it - # the default some day. - - # New and more generic than the inherited ones above: several submit buttons - my @params = grep s/^(weak)?SUBMIT_pause99_//i, $req->param; - for my $p (@params) { - # warn "p[$p]"; - for my $a (@allow_submit) { - if ( substr($p,0,length($a)) eq $a ) { - $mgr->{Action} = $a; - last; - } - } - last if $mgr->{Action}; - } - } - $action = $mgr->{Action}; - # warn "action[$action]"; - # warn sprintf "param[%s]", join ":", $mgr->{REQ}->param; - if ($action) { # delegate to a subroutine - die PAUSE::HeavyCGI::Exception->new(ERROR => "Unanticipated Error on Server. -Please report to the administrator what you were trying to do") - unless $self->can($action); - my @action_result = $self->$action($mgr); - # sanity check: - for (0..$#action_result) { - next if defined $action_result[$_]; - warn "undefined element in \@action_result: _[$_]#[$#action_result]action[$action]"; - } - $mgr->{EditOutput} = join "", @action_result; - } else { - $mgr->{Action} = "menu"; # no undefined warnings please - } -} - -sub menu { - return; -} - -sub manage_id_requests { # was reject_id_request - # intimate knowledge of session handling required - my $self = shift; - my $mgr = shift; - return unless exists $mgr->{UserGroups}{admin}; - my $req = $mgr->{REQ}; - my @m; - my %ALL; - my $delete; - if ($req->param("subaction") && $req->param("subaction") eq "delete") { - $delete = $req->param("USERID"); - } - my $dbh = $mgr->connect; - my $sthu = $dbh->prepare("SELECT userid from users where userid=?"); - my $sthm = $dbh->prepare("SELECT modid from mods where modid=?"); - find - ( - {wanted => sub { - my $path = $_; - my @stat = stat $path or die "Could not stat '$path': $!"; - return unless -f _; - my $mtime = $stat[9]; - open my $fh, $path or die "Couldn't open '$path': $!"; - local $/; - my $content = <$fh>; - my $session = Storable::thaw $content; - # warn "DEBUG: mtime[$mtime]stat[@stat]session[$session]"; - my $userid = $session->{APPLY}{userid} or return; - if ($delete && $session->{_session_id} eq $delete) { - unlink $path or die "Could not unlink '$path': $!"; - return; - } - my $type; - if (exists $session->{APPLY}{fullname}) { - $sthu->execute($userid); - return if $sthu->rows > 0; - $type = "user"; - } elsif (exists $session->{APPLY}{modid}) { - $sthm->execute($session->{APPLY}{modid}); - return if $sthm->rows > 0; - $type = "mod"; - } - if ($session->{APPLY}{rationale} =~ /\b(?:BLONDE\s+NAKED|NAKED\s+SEXY|FREE\s+CUMSHOT|CUMSHOT\s+VIDEOS|FREE\s+SEX|FREE\s+TUBE|GROUP\s+SEX|FREE\s+PORN|SEX\s+VIDEO|SEX\s+MOVIES?|SEX\s+TUBE|SEX\s+MATURE|STREET\s+BLOWJOBS|SEX\s+PUBLIC|TUBE\s+PORN|PORN\s+TUBE|TUBE\s+VIDEOS|VIDEO\s+TUBE|XNXX\s+VIDEOS|XXX\s+FREE|ANIMAL\s+SEX|GIRLS\s+SEX|PORN\s+VIDEOS?|PORN\s+MOVIES|TITS\s+PORN|RAW\s+SEX|DEEPTHROAT\s+TUBE|celeb\s+porn|PREGNANT\s+TUBE|picture\s+sex|NAKED\s+WOMEN|WOMEN\s+MOVIES|MATURE\s+NAKED|SEX\s+ANIME|hot\s+nude|nude\s+celebs|ANIME\s+TUBES|SEX\s+DOG|MATURE\s+SEX|MATURE\s+PUSSY|Rape\s+Porn|brutal\s+fuck|rape\s+video|ANIMAL\s+TUBE|SHEMALE\s+CUMSHOT|ANIMAL\s+PORN|ANIMAP\s+CLIP|CLIP\s+SEX|PUBLIC\s+BLOWJOB|free\s+lesbian|lesbian\s+sex|SEX\s+ZOO|tv-adult|numismata.org|www.soulcommune.com|www.petsusa.org|www.csucssa.org|www.thisis50.com|www.comunidad-latina.net|www.singlefathernetwork.com|www.freetoadvertise.biz|gayforum.dk|www.purevolume.com|playgroup.themouthpiece.com|www.bananacorp.cl|party.thebamboozle.com|blog.tellurideskiresort.com|www.pethealthforums.com|www.burropride.com|lpokemon.19.forumer.com|Zootube365|Eskimotube|xtube-1|phentermine without a prescription)\b/i) { - unlink $path or die "Could not unlink '$path': $!"; - return; - } - $ALL{$path} = { - session => $session, - mtime => $mtime, - type => $type, - }; - }, - no_chdir => 1, - }, - $mgr->{SessionDataDir}, # a bit under $PAUSE::Config->{RUNDATA} - ); -push @m, qq{

View all pending applications for new user IDs and for modules registrations

-

- -}; - require YAML::Syck; - require JSON::XS; - my $jx = JSON::XS->new->indent->canonical; - for my $k (sort { $ALL{$b}{type} cmp $ALL{$a}{type} || $ALL{$b}{mtime} <=> $ALL{$a}{mtime} } keys %ALL) { - my $esc = $mgr->escapeHTML($jx->encode($ALL{$k}{session})); - $esc =~ s/ / /g; - $esc =~ s/\n//g; - $esc =~ s/\\n//g; - push @m, sprintf - ( - ' - - -', - $ALL{$k}{type}, - $ALL{$k}{session}{APPLY}{userid}, - POSIX::strftime("%FT%TZ", gmtime $ALL{$k}{mtime}), - exists $ALL{$k}{session}{APPLY}{fullname} ? "add_user" : "add_mod", - $ALL{$k}{session}{_session_id}, - exists $ALL{$k}{session}{APPLY}{fullname} ? "add_user_sub" : "add_mod_preview", - $ALL{$k}{session}{_session_id}, - $esc, - ); - } - push @m, "
TypeUserid/TimeRaw Session
-%s - -%s -
-%s -
-
-Go To Registration -
-Delete Registration -
%s
%s

"; - join "", @m; -} - -sub as_string { - my $self = shift; - my $mgr = shift; - my @m; - warn "mgr->Action undef" unless defined $mgr->{Action}; - my $action; - $action = $mgr->{ActionTuning}{$mgr->{Action}}{verb} - if exists $mgr->{ActionTuning}{$mgr->{Action}}; - # $action ||= $mgr->{Action}; - push @m, sprintf qq{\n

%s

\n}, $action if $action; - my $sentit; - my @err = @{$mgr->{ERROR}||[]}; - push @m, @err and $sentit++ if @err; - # warn "sentit[$sentit]"; - push @m, $mgr->{EditOutput} and $sentit++ if !$sentit && $mgr->{EditOutput}; - # warn "sentit[$sentit]"; - unless ($sentit) { - push @m, sprintf( - qq{\n

%slease choose an action from the menu.

\n}, - $mgr->{User}{fullname} ? - sprintf("Hi %s,
p",$mgr->escapeHTML($mgr->{User}{fullname})) : - "P" - ); - - # warn sprintf "DEBUG: host believes he is[%s]", $mgr->myurl->host; - - push @m, qq{

The usermenu to the left shows all menus available to - you, the table below shows descriptions for all menues available - to anybody on PAUSE.

\n}; - - my $alter = 0; - my $bgcolor = $alter ? "alternate1" : "alternate2"; - push @m, qq{
\n}; #}; - for my $p (qw(public user mlrepr modmaint admin)) { - for my $act (sort { - $mgr->{ActionTuning}{$a}{cat} cmp $mgr->{ActionTuning}{$b}{cat} - } - grep { $mgr->{ActionTuning}{$_}{priv} eq $p } - keys %{$mgr->{ActionTuning}}) { - $alter ^= 1; - $bgcolor = $alter ? "alternate1" : "alternate2"; - $mgr->{ActionTuning}{$act}{verb} ||= $act; - push @m, qq{ -}; - for my $k (qw(priv desc)) { - my $v = $mgr->{ActionTuning}{$act}{$k} || "N/A"; - push @m, qq{} - } - push @m, qq{\n}; - } - } - push @m, qq{
ActionGroupDescription
$mgr->{ActionTuning}{$act}{verb}$v
\n
\n}; - } - @m; -} - -=head2 active_user_record - -Admin users can act on behalf of users. They do this by supplying -HIDDENNAME parameter which is checked here. Representatives of -mailinglists also have the ability to use HIDDENNAME to act on behalf -of a mailing list. - -=cut - -sub active_user_record { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $hidden_user = shift; - my $opt = shift || {}; # hashref, e.g. checkonly => 1 - - my $hidden_user_ok = $opt->{hidden_user_ok}; # caller is absolutely - # sure that hidden_user - # is authenticated or - # harmless (mailpw) - - my $req = $mgr->{REQ}; - if ($hidden_user) { - require Carp; - Carp::cluck("hidden_user[$hidden_user] passed in as argument with hidden_user_ok[$hidden_user_ok]"); - } else { - my $hiddenname_para = $req->param('HIDDENNAME') || ""; - $hidden_user ||= $hiddenname_para; - warn "DEBUG: hidden_user[$hidden_user] after hiddenname parameter[$hiddenname_para]"; - } - { - my $uc_hidden_user = uc $hidden_user; - unless ($uc_hidden_user eq $hidden_user) { - $req->logger->({level => 'error', message => "Warning: Had to uc the hidden_user $hidden_user" }); - $hidden_user = $uc_hidden_user; - } - } - my $u = {}; - $req->logger->({level => 'error', message => sprintf("Watch: mgr/User/userid[%s]hidden_user[%s]mgr/UserGroups[%s]caller[%s]where[%s]", - $mgr->{User}{userid}, - $hidden_user, - join(":", keys %{$mgr->{UserGroups}}), - join(":", caller), - __FILE__.":".__LINE__, - ) - }); - if ( - $hidden_user - && - $hidden_user ne $mgr->{User}{userid} - ){ - - # Imagine, MSERGEANT wants to pass Win32::ASP to WNODOM - - my $dbh1 = $mgr->connect; - my $sth1 = $dbh1->prepare("SELECT * FROM users WHERE userid=?"); - $sth1->execute($hidden_user); - unless ($sth1->rows){ - require Carp; - Carp::cluck( - sprintf( - "ALERT: hidden_user[%s] rows_as_s[%s] rows_as_d[%d]", - $hidden_user, - $sth1->rows, - $sth1->rows, - )); - die PAUSE::HeavyCGI::Exception - ->new(ERROR => - "Unidentified error happened, please write to the PAUSE admin - at $PAUSE::Config->{ADMIN} and help him identifying what's going on. Thanks!"); - } - my $hiddenuser_h1 = $mgr->fetchrow($sth1, "fetchrow_hashref"); - require YAML::Syck; print STDERR "Line " . __LINE__ . ", File: " . __FILE__ . "\n" . YAML::Syck::Dump({hiddenuser_h1 => $hiddenuser_h1}); # XXX - - $sth1->finish; - - # $hiddenuser_h1 should now be WNODOM's record - - if ($opt->{checkonly}) { - # since we have checkonly this is the MSERGEANT case - return $hiddenuser_h1; - } elsif ( - $hiddenuser_h1->{isa_list} - ) { - - # This is NOT the MSERGEANT case - - if ( - exists $mgr->{IsMailinglistRepresentative}{$hiddenuser_h1->{userid}} - || - ( - $mgr->{UserGroups} - && - exists $mgr->{UserGroups}{admin} - ) - ){ - # OK, we believe you come with good intentions, but we check - # if this action makes sense because we fear for the integrity - # of the database, no matter if you are user or admin. - if ( - grep { $_ eq $mgr->{Action} } @{$mgr->{AllowMlreprTakeover}} - ) { - warn "Watch: privilege escalation"; - $u = $hiddenuser_h1; # no secrets for a mailinglist - } else { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => - sprintf( - qq[Action '%s' seems not to be supported - for a mailing list], - $mgr->{Action}, - ) - ); - } - } - } elsif ( - $hidden_user_ok - || - $mgr->{UserGroups} - && - exists $mgr->{UserGroups}{admin} - ) { - - # This isn't the MSERGEANT case either, must be admin - # The case of hidden_user_ok is when they forgot password - - my $dbh2 = $mgr->authen_connect; - my $sth2 = $dbh2->prepare("SELECT secretemail, lastvisit - FROM $PAUSE::Config->{AUTHEN_USER_TABLE} - WHERE $PAUSE::Config->{AUTHEN_USER_FLD}=?"); - $sth2->execute($hidden_user); - my $hiddenuser_h2 = $mgr->fetchrow($sth2, "fetchrow_hashref"); - $sth2->finish; - for my $h ($hiddenuser_h1, $hiddenuser_h2) { - for my $k (keys %$h) { - $u->{$k} = $h->{$k}; - } - } - } elsif (0) { - return $u; - } else { - # So here is the MSERGEANT case, most probably - # But the ordinary record must do. No secret email stuff here, no passwords - # 2009-06-15 akoenig : adamk reports a massive security hole - require YAML::Syck; - require Carp; - Carp::confess - ( - YAML::Syck::Dump({ hiddenuser => $hiddenuser_h1, - error => "looks like unwanted privilege escalation", - u => $u, - })); - # maybe we should just return the current user here? or we - # should check the action? Don't think so, filling HiddenUser - # member might be OK but returning the other user? Unlikely. - } - } else { - unless ($mgr->{User}{fullname}) { - # this guy most probably came via ABRA and we should fill some slots - - - my $dbh1 = $mgr->connect; - my $sth1 = $dbh1->prepare("SELECT * FROM users WHERE userid=?"); - $sth1->execute($mgr->{User}{userid}); - die PAUSE::HeavyCGI::Exception - ->new(ERROR => - "Unidentified error happened, please write to the PAUSE admin - at $PAUSE::Config->{ADMIN} and help them identify what's going on. Thanks!") - unless $sth1->rows; - - $mgr->{User} = $mgr->fetchrow($sth1, "fetchrow_hashref"); - $sth1->finish; - - } - %$u = (%{$mgr->{User}||{}}, %{$mgr->{UserSecrets}||{}}); - } - $mgr->{HiddenUser} = $u; - $u; -} - -sub edit_cred { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - my($u,$nu); # user, newuser - my @m = "\n"; - $u = $self->active_user_record($mgr); - push @m, qq{}; - push @m, qq{

Editing $u->{userid}}; - if (exists $mgr->{UserGroups}{admin}) { - push @m, sprintf " (lastvisit %s)", $u->{lastvisit}||"before 2005-12-02"; - } - push @m, qq{

}; - - # @allmeta *must* be the union of meta and secmeta - my @meta = qw( fullname asciiname email homepage cpan_mail_alias ustatus); - my @secmeta = qw(secretemail); - my @allmeta = qw( fullname asciiname email secretemail homepage cpan_mail_alias ustatus); - - my $cpan_alias = lc($u->{userid}) . '@cpan.org'; - my $fullnamecomment = "PAUSE supports names containing UTF-8 characters. "; - if ($mgr->can_utf8) { - - $fullnamecomment .= "As your browser seems to support UTF-8 too, - feel free to enter your name as it is written natively. "; - - } else { - - $fullnamecomment .= "As your browser does not seem to support - UTF-8, you can only use characters encoded in ISO-8859-1. "; - - } - - $fullnamecomment .= "See also the field ASCII transliteration - below."; - - my %meta = ( - ustatus => { - type => "checkbox", - args => { - name => "pause99_edit_cred_ustatus", - value => "delete", - label => "Account can be removed", - }, - short => "Remove account?", - - long => "You have not yet uploaded any files - to the CPAN, so your account can still be - cancelled. If you want to retire your - account, please click here. If you do - this, your account will not be removed - immediately but instead be removed - manually by the database maintainer at a - later date.", - - }, - email => { - type => "textfield", - args => { - name => "pause99_edit_cred_email", - size => 50, - maxlength => 255, - }, - short => "Publicly visible email address - (published in many listings)", - }, - secretemail => { - type => "textfield", - args => { - name => "pause99_edit_cred_secretemail", - size => 50, - maxlength => 255, - }, - - short => "Secret email address only used - by the PAUSE, never published.", - - long => "If you leave this field empty, - PAUSE will use the public email address - for communicating with you.", - - }, - homepage => { - type => "textfield", - args => { - name => "pause99_edit_cred_homepage", - size => 50, - maxlength => 255, - }, - short => "Homepage or any contact URL except mailto:", - }, - fullname => { - type => "textfield", - args => { - name => "pause99_edit_cred_fullname", - size => 50, - maxlength => 127, # caution! - }, - short => "Full Name", - long => $fullnamecomment, - }, - asciiname => { - type => "textfield", - args => { - name => "pause99_edit_cred_asciiname", - size => 50, - maxlength => 255, - }, - short => "ASCII transliteration of Full Name", - - long => "If your Full Name contains - characters above 0x7f, please supply an - ASCII transliteration that can be used in - mail written in ASCII. Leave empty if you - trust the Text::Unidecode module.", - - }, - cpan_mail_alias=>{ - type=>"radio_group", - args=>{ - name=> "pause99_edit_cred_cpan_mail_alias", - values=> [qw(publ secr none)], - labels=>{ - none => "neither nor", - publ => "my public email address", - secr => "my secret email address", - }, - default => "none", - }, - short=>"The email address - $cpan_alias should be configured to forward mail to ...", - - long=>"cpan.org has a mail - address for you and it's your choice if you want it to point to your - public email address or to your secret one. Please allow a few hours - for any change you make to this setting for propagation. BTW, let us - reassure you that cpan.org gets the data through a secure - channel.

Note: you can disable redirect by clicking - neither nor or by using an invalid email address in the - according field above, but this will prevent you from recieving - emails from services like rt.cpan.org." - - }, - ); - my $consistentsubmit = 0; - if ($req->param("pause99_edit_cred_sub")) { - my $wantemail = $req->param("pause99_edit_cred_email"); - my $wantsecretemail = $req->param("pause99_edit_cred_secretemail"); - my $wantalias = $req->param("pause99_edit_cred_cpan_mail_alias"); - use Email::Address; - my $addr_spec = $Email::Address::addr_spec; - if ($wantemail=~/^\s*$/ && $wantsecretemail=~/^\s*$/) { - push @m, qq{ERROR: Both of your email fields are left blank, this is not the way it is intended on PAUSE, PAUSE must be able to contact you. Please fill out at least one of the two email fields.
}; - } elsif ($wantalias eq "publ" && $wantemail=~/^\s*$/) { - push @m, qq{ERROR: You chose your email alias on CPAN to point to your public email address but your public email address is left blank. Please either pick a different choice for the alias or fill in a public email address.
}; - } elsif ($wantalias eq "publ" && $wantemail=~/\Q$cpan_alias\E/i) { - push @m, qq{ERROR: You chose your email alias on CPAN to point to your public email address but your public email address field contains $cpan_alias. This looks like a circular reference. Please either pick a different choice for the alias or fill in a more reasonable public email address.
}; - } elsif ($wantalias eq "secr" && $wantsecretemail=~/^\s*$/) { - push @m, qq{ERROR: You chose your email alias on CPAN to point to your secret email address but your secret email address is left blank. Please either pick a different choice for the alias or fill in a secret email address.
}; - } elsif ($wantalias eq "secr" && $wantsecretemail=~/\Q$cpan_alias\E/i) { - push @m, qq{ERROR: You chose your email alias on CPAN to point to your secret email address but your secret email address field contains $cpan_alias. This looks like a circular reference. Please either pick a different choice for the alias or fill in a more reasonable secret email address.
}; - } elsif ($wantsecretemail!~/^\s*$/ && $wantsecretemail!~/^\s*$addr_spec\s*$/) { - push @m, qq{ERROR: Your secret email address doesn't look like valid email address.
}; - } elsif ($wantemail!~/^\s*$/ && $wantemail!~/^\s*$addr_spec\s*$/) { - push @m, qq{ERROR: Your public email address doesn't look like valid email address.
}; - } else { - $consistentsubmit = 1; - } - if ($consistentsubmit) { - # more testing: make sure that we have in asciiname only ascii - if (my $wantasciiname = $req->param("pause99_edit_cred_asciiname")) { - if ($wantasciiname =~ /[^\040-\177]/) { - push @m, qq{ERROR: Your asciiname seems to contain non-ascii characters.}; - $consistentsubmit = 0; - } else { - # set asciiname to empty if it equals fullname - my $wantfullname = $req->param("pause99_edit_cred_fullname"); - if ($wantfullname eq $wantasciiname) { - $req->parameters->set("pause99_edit_cred_asciiname", ""); - } - } - } else { - # set asciiname on our own if they don't supply it - my $wantfullname = $req->param("pause99_edit_cred_fullname"); - if ($wantfullname =~ /[^\040-\177]/) { - require Text::Unidecode; - $wantfullname = $mgr->any2utf8($wantfullname); - $wantasciiname = Text::Unidecode::unidecode($wantfullname); - $req->parameters->set("pause99_edit_cred_asciiname", $wantasciiname); - } - } - } - - } - if ($consistentsubmit) { - my($mailsprintf1,$mailsprintf2,$saw_a_change); - $mailsprintf1 = "%11s: [%s]%s"; - $mailsprintf2 = " was [%s]\n"; - my $now = time; - my $myurl = $mgr->myurl; - my $myurlstr = $myurl->can("unparse") ? $myurl->unparse : $myurl->as_string; - $myurlstr =~ s/[?;].*//; - - # We once duplicated nearly exactly the same code of 100 lines. - # Once for secretemail, once for the other attributes. Lines - # marked with four hashmarks are the ones that differ. Why not - # make it a function? Well, that function would have to take at - # least 5 arguments and we want some variables in the lexical - # scope. So I made it a loop for two complicated arrays. - for my $quid ( - [ - "connect", - \@meta, - "users", - "userid", - 1 - ], - ["authen_connect", - \@secmeta, - $PAUSE::Config->{AUTHEN_USER_TABLE}, - $PAUSE::Config->{AUTHEN_USER_FLD}, - 0 - ] - ) { - my($connect,$atmeta,$table,$column,$mailto_admins) = @$quid; - my(@set,@mailblurb); - my $dbh = $mgr->$connect(); #### the () for older perls - for my $field (@$atmeta) { #### - # warn "field[$field]"; - # Ignore fields we do not intend to change - unless ($meta{$field}){ - warn "Someone tried strange field[$field], ignored"; - next; - } - # find out the form field name - my $form_field = "pause99_edit_cred_$field"; - if ( $field eq "ustatus" ) { - if ( $u->{"ustatus"} eq "active" ) { - next; - } elsif (!$req->param($form_field)) { - $req->parameters->set($form_field,"unused"); - } - } - # $s is the value they entered - my $s_raw = $req->param($form_field) || ""; - # we're in edit_cred - my $s; - $s = $mgr->any2utf8($s_raw); - $s =~ s/^\s+//; - $s =~ s/\s+\z//; - if ($s ne $s_raw) { - $req->parameters->set($form_field,$s); - } - $nu->{$field} = $s; - $u->{$field} = "" unless defined $u->{$field}; - my $mb; # mailblurb - if ($u->{$field} ne $s) { - $saw_a_change = 1; - - # No UTF8 running before we have the system walking - # my $utf = $mgr->formfield_as_utf8($s); - # unless ( $s eq $utf ) { - # $req->parameters->set($form_field, $utf); - # $s = $utf; - # } - # next if $mgr->{User}{$field} eq $s; - - # not ?-ising this as rely on quote() method - push @set, "$field = " . $dbh->quote($s); - $mb = sprintf($mailsprintf1, - $field, - $s, - sprintf($mailsprintf2,$u->{$field}) - ); - if ($field eq "ustatus") { - push @set, "ustatus_ch = NOW()"; - } - } else { - $mb = sprintf( - $mailsprintf1, - $field, - $s, - "\n" - ); - } - if ($field eq "secretemail") { - $mb = sprintf $mailsprintf1, $field, "CENSORED", "\n"; - } - push @mailblurb, $mb; - } - if (@set) { - - my @query_params = ($now, $mgr->{User}{userid}, $u->{userid}); - my $sql = "UPDATE $table SET " . #### - join(", ", @set, "changed = ?, changedby=?") . - " WHERE $column = ?"; #### - my $mailblurb = qq{Record update in the PAUSE users database: - -}; - $mailblurb .= sprintf($mailsprintf1, "userid", $u->{userid}, "\n"); - $mailblurb .= join "", @mailblurb; - $mailblurb .= qq{ - -Data were entered by $mgr->{User}{userid} ($mgr->{User}{fullname}). -Please check if they are correct. - -Thanks, -The PAUSE Team -}; - # warn "sql[$sql]mailblurb[$mailblurb]"; - # die; - if ($dbh->do($sql, undef, @query_params)) { - push @m, qq{The new data are registered in table $table.
}; - $nu = $self->active_user_record($mgr,$u->{userid}); - if ($nu->{userid} && $nu->{userid} eq $mgr->{User}{userid}) { - $mgr->{User} = $nu; - } - # Send separate emails to user and public places because - # CC leaks secretemail to others - my @to; - my %umailset; - for my $lu ($u, $nu) { - for my $att (qw(secretemail email)) { - if ($lu->{$att}){ - $umailset{qq{<$lu->{$att}>}} = 1; - last; - } - } - } - push @to, join ", ", keys %umailset; - push @to, $mgr->{MailtoAdmins} if $mailto_admins; #### - my $header = {Subject => "User update for $u->{userid}"}; - $mgr->send_mail_multi(\@to,$header, $mailblurb); - } else { - push @{$mgr->{ERROR}}, sprintf(qq{Could not enter the data - into the database: %s.},$dbh->errstr); - } - } - } # end of quid loop - if ($saw_a_change) { - # expire temporary token to free mailpw for immediate use - my $sql = sprintf qq{DELETE FROM abrakadabra - WHERE user = ?}; - my $dbh = $mgr->authen_connect(); - $dbh->do($sql,undef,$u->{userid}); - } else { - push @m, qq{No change seen, nothing done.
}; - } - } - push @m, qq{
}; - my $alter = 1; - for my $field (@allmeta) { - unless ($meta{$field}){ - warn "Someone tried strange field[$field], ignored"; - next; - } - if ( $field eq "ustatus" ) { - if ( $u->{"ustatus"} eq "active" ) { - next; - } - } - $alter ^= 1; - my $alterclass = $alter ? "alternate1" : "alternate2"; - push @m, qq{}; - } - push @m, qq{

$meta{$field}{short}

}; - push @m, qq{ -

$meta{$field}{long}

-} if $meta{$field}{long}; - my %args = %{$meta{$field}{args}}; - my $type = $meta{$field}{type}; - my $form = $mgr->$type(%args, default=>$u->{$field}); - # warn "field[$field]u->field[$u->{$field}]"; - # warn "form[$form]"; - push @m, qq{$form
\n}; - push @m, qq{}; - @m; -} - -sub select_user { - my pause_1999::edit $self = shift; - my $mgr = shift; - $mgr->prefer_post(0); - my $req = $mgr->{REQ}; - if (my $action = $req->param("ACTIONREQ")) { - if ( - $self->can($action) - ) { - $req->parameters->set("ACTION",$action); - $mgr->{Action} = $action; - return $self->$action($mgr); - } else { - die "cannot action[$action]"; - } - } - my @m; - my %user_meta = $self->user_meta($mgr); - push @m, $mgr->scrolling_list( - 'name' =>'HIDDENNAME', - default => [$mgr->{User}{userid}], - %{$user_meta{userid}{args}}, - ); - push @m, qq{\n
\n}; - my $action_map = $self->_action_map_to_verb($mgr,$mgr->{AllowAdminTakeover}); - push @m, $mgr->scrolling_list( - 'name' => 'ACTIONREQ', - values => $mgr->{AllowAdminTakeover}, - labels => $action_map, - default => ['edit_cred'], - size => 13, - ); - push @m, qq{\n
\n}; - push @m, qq{}; - @m; -} - -sub _action_map_to_verb { - my($self,$mgr,$actions) = @_; - my %action_map = map { $_, $_ } @$actions; - while (my($k,$v) = each %{$mgr->{ActionTuning}}) { - next unless exists $action_map{$k}; - for ($mgr->{ActionTuning}{$k}{verb}) { - $action_map{$k} = $_ if $_; - } - } - \%action_map; -} - -=head2 select_ml_action - -Like select_user, very much like select_user, more copy and paste than -should be. - -=cut - -sub select_ml_action { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - my $dbh = $mgr->connect; - if (my $action = $req->param("ACTIONREQ")) { - if ( - $self->can($action) - && - grep { $_ eq $action } @{$mgr->{AllowMlreprTakeover}} - ) { - $req->parameters->set("ACTION",$action); - $mgr->{Action} = $action; - return $self->$action($mgr); - } else { - die "cannot or want not action[$action]"; - } - } - my @m; - - push @m, qq{

Mailinglist support is intended to be available on a - delegates/representatives basis, that means, one or more users - are "elected" (no formal election though) to be allowed to act - on behalf of a mailing list. There is no password for a mailing - list, there are no user credentials for a mailing list. There - are no uploads for mailing lists, thus no deletes or repairs of - uploads.

There are only the infos about the mailing list - editable via the method edit_ml and ther are a number of - modules associated with a mailing list and these are accessible - in the edit_mod method.

The menu item Select - Mailinglist/Action lets you access the available methods and - the mailing lists you are associated with. Only people elected - as a representative of a mailing list should be able to ever see - the menu entry.

This feature is available since Oct 25th, - 1999 and hardly tested, so please take care and let us know how - it goes.

- -

Choose your mailing list and the action and click the submit - button.

}; - - my $sql = qq{SELECT users.userid - FROM users, list2user - WHERE isa_list > '' - AND users.userid = list2user.maillistid - AND list2user.userid = ? - ORDER BY users.userid -}; - - my $sth = $dbh->prepare($sql); - $sth->execute($mgr->{User}{userid}); - my %u; - while (my @row = $mgr->fetchrow($sth, "fetchrow_array")) { - $u{$row[0]} = $row[0]; - } - my $size1 = $sth->rows > 18 ? 15 : $sth->rows; - my $size2 = scalar @{$mgr->{AllowMlreprTakeover}} > 18 ? 15 : scalar @{$mgr->{AllowMlreprTakeover}}; - my($action_map) = $self->_action_map_to_verb($mgr,$mgr->{AllowMlreprTakeover}); - push @m, $mgr->scrolling_list( - 'name' =>'HIDDENNAME', - 'values' => [sort {lc($u{$a}) cmp lc($u{$b})} keys %u], - default => [$mgr->{User}{userid}], - size => $size1, - labels => \%u, - ); - push @m, $mgr->scrolling_list( - 'name' => 'ACTIONREQ', - values => $mgr->{AllowMlreprTakeover}, - labels => $action_map, - default => ['edit_ml'], - size => $size2, - ); - push @m, qq{}; - @m; -} - -sub pause_04about { - my pause_1999::edit $self = shift; - my $mgr = shift; - $self->show_document($mgr,"04pause.html",1); -} - -sub pause_logout { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $x = $self->show_document($mgr,"logout.html"); - my $rand = rand 1; - # the redirect solutions fail miserably the second time when tried - # with the exact same querystring again. - $x =~ s/__RANDOMSTRING__/$rand/g; - $x; -} - -sub pause_04imprint { - my pause_1999::edit $self = shift; - my $mgr = shift; - $self->show_document($mgr,"imprint.html"); -} - -sub pause_05news { - my pause_1999::edit $self = shift; - my $mgr = shift; - $self->show_document($mgr,"index.html"); -} - -sub pause_06history { - my pause_1999::edit $self = shift; - my $mgr = shift; - $self->show_document($mgr,"history.html"); -} - -sub pause_namingmodules { - my pause_1999::edit $self = shift; - my $mgr = shift; - $self->show_document($mgr,"namingmodules.html"); -} - -sub show_document { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $doc = shift || "04pause.html"; - my $rewrite = shift || 0; - my $dir = $FindBin::Bin; - my @m; - # push @m, sprintf "DEBUG: %s %s
", $dir, -e $dir ? "exists" : "doesn't exist. "; - for my $subdir ("htdocs", "pause", "pause/../htdocs", "pause/..", "") { - my $file = "$dir/$subdir/$doc"; - next unless -f $file; - push @m, qq{
}; - open my $fh, $file or die; - if ($] > 5.007) { - binmode $fh, ":utf8"; - } - local $/; - my $html_in = <$fh>; - close $fh; - - if ($rewrite) { - use XML::SAX::ParserFactory; - use XML::SAX::Writer; - use pause_1999::saxfilter01; - use XML::LibXML::SAX; - $XML::SAX::ParserPackage = "XML::LibXML::SAX"; - - my @html_out; - my $w = XML::SAX::Writer->new(Output => \@html_out); - my $f = pause_1999::saxfilter01->new(Handler => $w); - my $p = XML::SAX::ParserFactory->parser(Handler => $f); - $p->parse_string($html_in); - while ($html_out[0] =~ /^<[\?\!]/){ # remove XML Declaration, DOCTYPE - shift @html_out; - } - push @m, join "", @html_out; - } else { - my $html = $html_in; - $html =~ s/^.*?]*>//si; - $html =~ s|.*$||si; - push @m, $html; - } - - last; - } - unless (@m) { - push @m, "document '$doc' not found on the server"; - } - join "", @m; -} - -sub tail_logfile { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - my $tail = $req->param("pause99_tail_logfile_1") || 5000; - my($file) = $PAUSE::Config->{PAUSE_LOG}; - if ($PAUSE::Config->{TESTHOST}) { - $file = "/usr/local/apache/logs/error_log"; # for testing - } - open my $fh, $file or die "Could not open $file: $!"; - seek $fh, -$tail, 2; - local($/); - $/ = "\n"; - <$fh>; - $/ = undef; - my @m; - push @m, $mgr->scrolling_list( - name => "pause99_tail_logfile_1", - size => 1, - values => [qw( 2000 5000 10000 20000 40000) ], - ); - push @m, qq{}; - push @m, "
", $mgr->escapeHTML(<$fh>), "
"; - join "", @m; -} - -sub change_passwd { - my pause_1999::edit $self = shift; - my $mgr = shift; - $mgr->prefer_post(1); - my $req = $mgr->{REQ}; - my @m; - my $u = $self->active_user_record($mgr); - push @m, qq{}; - push @m, qq{

Changing Password of $u->{userid}

}; # }; - if (my $param = $req->param("ABRA")) { - push @m, qq{}; - } - - if ($req->param("pause99_change_passwd_sub")) { - if (my $pw1 = $req->param("pause99_change_passwd_pw1")) { - if (my $pw2 = $req->param("pause99_change_passwd_pw2")) { - if ($pw1 eq $pw2) { - # create a new crypted password, store it, report - my $pwenc = PAUSE::Crypt::hash_password($pw1); - my $dbh = $mgr->authen_connect; - my $sql = qq{UPDATE $PAUSE::Config->{AUTHEN_USER_TABLE} - SET $PAUSE::Config->{AUTHEN_PASSWORD_FLD} = ?, - forcechange = ?, - changed = ?, - changedby = ? - WHERE $PAUSE::Config->{AUTHEN_USER_FLD} = ?}; - # warn "sql[$sql]"; - my $rc = $dbh->do($sql,undef, - $pwenc,0,time,$mgr->{User}{userid},$u->{userid}); - warn "rc[$rc]"; - die PAUSE::HeavyCGI::Exception - ->new(ERROR => - sprintf qq[Could not set password: '%s'], $dbh->errstr - ) unless $rc; - if ($rc == 0) { - $sql = qq{INSERT INTO $PAUSE::Config->{AUTHEN_USER_TABLE} - ($PAUSE::Config->{AUTHEN_USER_FLD}, - $PAUSE::Config->{AUTHEN_PASSWORD_FLD}, - forcechange, - changed, - changedby ) VALUES - (?, ?, ?, ?, ?) -}; # }; - $rc = $dbh->do($sql,undef, - $u->{userid}, - $pwenc, - 0, - time, - $mgr->{User}{userid}, - $u->{userid} - ); - die PAUSE::HeavyCGI::Exception - ->new(ERROR => - sprintf qq[Could not insert user record: '%s'], $dbh->errstr - ) unless $rc; - } - for my $anon ($mgr->{User}, $u) { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => "Panic: unknown user") unless $anon->{userid}; - next if $anon->{fullname}; - $req->logger({level => 'error', message => "Unknown fullname for $anon->{userid}!" }); - } - - push @m, "New password stored and enabled. Be prepared that - you will be asked for a new authentication on the next request. If - this doesn't work out, it may be that you have to restart the - browser."; - - my $mailblurb = sprintf( - qq{Password update on PAUSE: - -%s (%s) visited the -password changer on PAUSE at %s UTC -and changed the password for %s (%s). - -No action is required, but it would be a good idea if somebody -would check the correctness of the new password. - -Thanks, -The PAUSE Team -}, - $mgr->{User}->{userid}, - $mgr->{User}{fullname}||"fullname N/A", - scalar gmtime, - $u->{userid}, - $u->{fullname}||"fullname N/A"); - my %umailset; - my $name = $u->{asciiname} || $u->{fullname} || ""; - my $Uname = $mgr->{User}{asciiname} || $mgr->{User}{fullname} || ""; - if ($u->{secretemail}) { - $umailset{qq{"$name" <$u->{secretemail}>}} = 1; - } elsif ($u->{email}) { - $umailset{qq{"$name" <$u->{email}>}} = 1; - } - if ($u->{userid} ne $mgr->{User}{userid}) { - if ($mgr->{User}{secretemail}) { - $umailset{qq{"$Uname" <$mgr->{User}{secretemail}>}} = 1; - }elsif ($mgr->{User}{email}) { - $umailset{qq{"$Uname" <$mgr->{User}{email}>}} = 1; - } - } - my @to = keys %umailset; - my $header = {Subject => "Password Update"}; - $mgr->send_mail_multi(\@to, $header, $mailblurb); - } else { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => "The two passwords didn't match."); - } - } else { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => "You need to fill in the same password in both fields."); - } - } else { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => "Please fill in the form with passwords."); - } - } else { - if ( $mgr->{UserSecrets}{forcechange} ) { - push @m, qq{

Your password in the database is tainted which - means you have to renew it. If you believe this is wrong, please - complain, it's always possible that you are seeing a bug.

}; - } - - push @m, qq{

Please fill in your new password in both textboxes. - Only if both fields contain the same password, we will be able to - proceed.

}; - - push @m, $mgr->password_field(name=>"pause99_change_passwd_pw1", - maxlength=>72, - size=>16); - push @m, qq{\n}; - push @m, $mgr->password_field(name=>"pause99_change_passwd_pw2", - maxlength=>72, - size=>16); - push @m, qq{\n}; - push @m, qq{}; - } - @m; -} - -sub add_uri { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - my $debug_table = $req->parameters; # XXX: $r->parms - warn sprintf "DEBUG: req[%s]", join(":",%$debug_table); - $PAUSE::Config->{INCOMING_LOC} =~ s|/$||; - my @m; - my $u = $self->active_user_record($mgr); - die PAUSE::HeavyCGI::Exception - ->new(ERROR => - "Unidentified error happened, please write to the PAUSE admins - at $PAUSE::Config->{ADMIN} and help them identifying what's going on. Thanks!") - unless $u->{userid}; - push @m, qq{}; - my $can_multipart = $mgr->can_multipart; - push @m, qq{}; - push @m, qq{

Add a file for $u->{userid}

}; - my($tryupload) = $mgr->can_multipart; - my($uri); - my $userhome = PAUSE::user2dir($u->{userid}); - - if ($req->param("SUBMIT_pause99_add_uri_HTTPUPLOAD") - || $req->param("SUBMIT_pause99_add_uri_httpupload")) { - my $upl = $req->upload('pause99_add_uri_httpupload'); - unless ($upl->size) { - warn "Warning: maybe they hit RETURN, no upload size, not doing HTTPUPLOAD"; - $req->parameters->set("SUBMIT_pause99_add_uri_HTTPUPLOAD",""); - $req->parameters->set("SUBMIT_pause99_add_uri_httpupload",""); - } - } - if (! $req->param("SUBMIT_pause99_add_uri_HTTPUPLOAD") - &&! $req->param("SUBMIT_pause99_add_uri_httpupload") - &&! $req->param("SUBMIT_pause99_add_uri_uri") - &&! $req->param("SUBMIT_pause99_add_uri_upload") - ) { - # no submit button - if ($req->param("pause99_add_uri_uri")) { - $req->parameters->set("SUBMIT_pause99_add_uri_uri", "2ndguess"); - } elsif ($req->param("pause99_add_uri_upload")) { - $req->parameters->set("SUBMIT_pause99_add_uri_upload", "2ndguess"); - } - } - - my $didit = 0; - my $mailblurb = ""; - my $success = ""; - my $now = time; - if ( - $req->param("SUBMIT_pause99_add_uri_httpupload") || # from 990806 - $req->param("SUBMIT_pause99_add_uri_HTTPUPLOAD") - ) { - if ($mgr->{UseModuleSet} eq "ApReq") { - my $upl; - if ( - $upl = $req->upload("pause99_add_uri_httpupload") or # from 990806 - $upl = $req->upload("HTTPUPLOAD") - ) { - if ($upl->size) { - my $filename = $upl->filename; - $filename =~ s(.*/)()gs; # no slash - $filename =~ s(.*\\)()gs; # no backslash - $filename =~ s(.*:)()gs; # no colon - $filename =~ s/[^A-Za-z0-9_\-\.\@\+]//g; # only ASCII-\w and - . @ + allowed - my $to = "$PAUSE::Config->{INCOMING_LOC}/$filename"; - # my $fhi = $upl->fh; - require File::Copy; - if (-f $to && -s _ == 0) { # zero sized files are a common problem - unlink $to; - } - if (File::Copy::copy($upl->path, $to)){ - $uri = $filename; - # Got an empty $to in the HTML page, so for debugging.. - my $h1 = qq{

File successfully copied to '$to'

}; - warn "h1[$h1]filename[$filename]"; - push @m, $h1; - } else { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => - "Couldn't copy file '$filename' to '$to': $!"); - } - unless ($upl->filename eq $filename) { - - require Dumpvalue; - my $dv = Dumpvalue->new; - push @m, sprintf(q( - -

Your filename has been altered as it contained characters besides -the class [A-Za-z0-9_\\-\\.\\@\\+]. DEBUG: your filename[%s] corrected -filename[%s].

- -), - $dv->stringify($upl->filename), - $dv->stringify($filename) - ); - $req->parameters->set("pause99_add_uri_httpupload",$filename); - } - } else { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => - "uploaded file was zero sized"); - } - } else { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => - "Could not create an upload object. DEBUG: upl[$upl]"); - } - } elsif ($mgr->{UseModuleSet} eq "patchedCGI") { - warn "patchedCGI not supported anymore"; - - my $handle; - if ( - $handle = $req->param('pause99_add_uri_httpupload') or - $handle = $req->param('HTTPUPLOAD') - ) { - no strict; - use File::Copy; - $filename = "$handle"; - $filename =~ s(.*/)()s; # no slash - $filename =~ s(.*\\)()s; # no backslash - $filename =~ s(.*:)()s; # no colon - $filename =~ s/[^A-Za-z0-9_\-\.\@\+]//g; # only ASCII-\w and - . @ + allowed - my $to = "$PAUSE::Config->{INCOMING_LOC}/$filename"; - if (File::Copy::copy(\*$handle, $to)){ - $uri = $filename; - push @m, qq{

File successfully copied to '$to'

}; - } else { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => - "Couldn't copy file '$filename' to '$to': $!"); - } - } - } else { - die "Illegal UseModuleSet: $mgr->{UseModuleSet}"; - } - } elsif ( $req->param("SUBMIT_pause99_add_uri_uri") ) { - $uri = $req->param("pause99_add_uri_uri"); - $req->parameters->set("pause99_add_uri_httpupload",""); # I saw spurious - # nonsense in the - # field that broke - # XHTML - } elsif ( $req->param("SUBMIT_pause99_add_uri_upload") ) { - $uri = $req->param("pause99_add_uri_upload"); - $req->parameters->set("pause99_add_uri_httpupload",""); # I saw spurious - # nonsense in the - # field that broke - # XHTML - } - # my $myurl = $mgr->myurl; - my $server = $PAUSE::Config->{SERVER_NAME}; # XXX: $r->server->server_hostname - my $dbh = $mgr->connect; - - - - if (! $uri ) { - push @m, "\n\n
\n\n"; - } else { - push @m, $self->add_uri_continue_with_uri($mgr,$uri,\$success,\$didit); - } - - push @m, qq{\n - -

This form enables you to enter one file at a time - into CPAN in one of these ways:

}; - - if ($tryupload) { - - push @m, qq{\n\n}; - - } else { - - push @m, qq{\n\n}; - - } - - push @m, qq{\n}; - - push @m, qq{
HTTP Upload: As an - HTTP upload: enter the filename in the lower text field. - Hint: If you encounter problems processing this form, - it may be due to the fact that your browser can\'t handle - multipart/form-data forms that support file - upload. In such a case, please retry to access this file-upload-disabled - form.
HTTP Upload: As - you do not seem to want HTTP upload enabled, we do - not offer it. If this is not what you want, try to - explicitly - enable HTTP upload.
GET URL: PAUSE fetches - any http or ftp URL that can be handled by LWP: use the text - field (please specify the complete URL). How to use this - for direct publishing from your github repository has been - described by Mike Schilli in the historical posting - http://blog.usarundbrief.com/?p=36 but it is not available on - the net anymore. If you find a copy, please let us - know.
\n
Please, make sure your filename - contains a version number. For security reasons you will never - be able to upload a file with the same name again (not even - after deleting it). Thank you.
- -

There is no need to upload README files separately. The - upload server will unwrap your files (.tar.gz or .zip files - only) within a few hours after uploading and will put the - topmost README file as, say, Foo-Bar-3.14.readme into your - directory. Hint: if you're looking for an even more - convenient way to upload files than this form, you can try the - cpan-upload script. -

- -}; #}; - - - - # SUBDIR - - # if ($mgr->{User}{userid} eq "ANDK") { - if (1) { - - push @m, qq{

Target Directory

If you want to load the - file into a directory below your CPAN directory, - please specify the directory name here. Any number of - subdirectory levels is allowed, they all will be - created on the fly if they don't exist yet. Only sane - directory names are allowed and the number of - characters for the whole path is limited.

- NOTE: To upload a Perl6 distribution a target - directory whose top level subdirectory is "Perl6" must - be specified. In addition, a Perl6 distribution must - contain a META6.json. Pause will only consider it a - Perl6 dist if these two conditions are satisfied. -

}; - - - push @m, qq{
}; - push @m, $self->scroll_subdirs($mgr,$u); - push @m, $mgr->textfield( - name => "pause99_add_uri_subdirtext", - size => 32, - maxlength => 128 - ); - push @m, qq{
}; - - } - - - # HTTP UPLOAD - - push @m, "

Upload Material

"; - - if ($tryupload) { - $mgr->need_multipart(1); - $mgr->{RES}->header("Accept","*"); - - push @m, qq{\n}; - } - - # via FTP GET - - warn "DEBUG: UPLOAD[$PAUSE::Config->{UPLOAD}]"; - push @m, qq{\n}; - - # END OF UPLOAD OPTIONS - - push @m, "\n
If your browser can handle - file upload, enter the filename here and I'll transfer it - to your homedirectory:
}; - - push @m, $mgr->file_field(name => 'pause99_add_uri_httpupload', - size => 50); - push @m, "\n
"; - push @m, qq{
If you want me to fetch a - file from an URL, enter the full URL here.
}; - - push @m, $mgr->textfield( - name => "pause99_add_uri_uri", - size => 64, - maxlength => 128 - ); - push @m, "\n
"; - push @m, qq{
\n"; - - my $want_to_send_email_on_upload_submission = 0; - if ($want_to_send_email_on_upload_submission && $didit) { - my $her = $mgr->{User}{userid} eq $u->{userid} ? "his/her" : - "$u->{userid}'s"; - - my $mailblurb = $self->wrap(qq{$mgr->{User}{userid} -($mgr->{User}{fullname}) visited the PAUSE and requested an upload -into $her directory. The request used the following parameters:}); - $mailblurb .= "\n"; - - my @mb; - my $longest = 0; - for my $param ($req->param) { - next if $param eq "HIDDENNAME"; - next if $param eq "CAN_MULTIPART"; - next if $param eq "pause99_add_uri_sub"; # we're not interested - my $v = $req->param($param); - next unless defined $v; - next unless length $v; - $longest = length($param) if length($param) > $longest; - push @mb, [$param,$v]; - } - for my $mb (@mb) { - my($param, $v) = @$mb; - $mailblurb .= sprintf qq{ %-*s [%s]\n}, $longest, $param, $v; - } - $mailblurb .= "\n"; - $mailblurb .= $self->wrappar($success); - $mailblurb .= "\n\nThanks for your contribution,\n-- \nThe PAUSE Team\n"; -# my $header = { -# To => qq{$PAUSE::Config->{ADMIN}, $u->{email}, $mgr->{User}{email}}, -# Subject => qq{Notification from PAUSE}, -# }; - my %umailset; - my $name = $u->{asciiname} || $u->{fullname} || ""; - if ($u->{secretemail}) { - $umailset{qq{"$name" <$u->{secretemail}>}} = 1; - } elsif ($u->{email}) { - $umailset{qq{"$name" <$u->{email}>}} = 1; - } - if ($u->{userid} ne $mgr->{User}{userid}) { - my $Uname = $mgr->{User}{asciiname} || $mgr->{User}{fullname} || ""; - if ($mgr->{User}{secretemail}) { - $umailset{qq{"$Uname" <$mgr->{User}{secretemail}>}} = 1; - }elsif ($mgr->{User}{email}) { - $umailset{qq{"$Uname" <$mgr->{User}{email}>}} = 1; - } - } - $umailset{$PAUSE::Config->{ADMIN}} = 1; - my @to = keys %umailset; - my $header = { - Subject => "Notification from PAUSE", - }; - $mgr->send_mail_multi(\@to, $header, $mailblurb); - } - - @m; -} - -sub add_uri_continue_with_uri { - my($self,$mgr,$uri,$success,$didit) = @_; - my $req = $mgr->{REQ}; - my $u = $self->active_user_record($mgr); - my $userhome = PAUSE::user2dir($u->{userid}); - my $dbh = $mgr->connect; - my $now = time; - my $server = $PAUSE::Config->{SERVER_NAME}; # XXX: $r->server->server_hostname - my @m; - push @m, "\n\n
\n", - "\n\n", - ; - - require URI::URL; - eval { URI::URL->new("$uri", $PAUSE::Config->{INCOMING}); }; - - - if ($@) { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => [qq{ -Sorry, $uri could not be recognized as an uri (}, - $@, - qq{\)

Please -try again or report errors to the administrator

}]); - } else { - my $filename; - ($filename = $uri) =~ s,.*/,, ; - $filename =~ s/[^A-Za-z0-9_\-\.\@\+]//g; # only ASCII-\w and - . @ + allowed - - if ($filename eq "CHECKSUMS") { - # userid DERHAAG demonstrated that it could be uploaded on 2002-04-26 - die PAUSE::HeavyCGI::Exception - ->new(ERROR => "Files with the name CHECKSUMS cannot be - uploaded to CPAN, they are reserved for - CPAN's internals."); - - } - - my $subdir = ""; - if ( $req->param("pause99_add_uri_subdirtext") ) { - $subdir = $req->param("pause99_add_uri_subdirtext"); - } elsif ( $req->param("pause99_add_uri_subdirscrl") ) { - $subdir = $req->param("pause99_add_uri_subdirscrl"); - } - - my $uriid = "$userhome/$filename"; - - if (defined $subdir && length $subdir) { - # disallowing . to make /./ and /../ handling easier - $subdir =~ s|[^A-Za-z0-9_\-\@\+/]||g; # as above minus "." plus "/" - $subdir =~ s|^/+||; - $subdir =~ s|/$||; - $subdir =~ s|/+|/|g; - } - my $is_perl6 = 0; - if (defined $subdir && length $subdir) { - $is_perl6 = 1 if $subdir =~ /^Perl6\b/; - $uriid = "$userhome/$subdir/$filename"; - } - - if ( length $uriid > 255 ) { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => "Path name too long: $uriid is longer than - 255 characters."); - } - - ALLOW_OVERWRITE: if ( - $filename =~ /(readme|\.html|\.txt|\.[xy]ml|\.json|\.[pr]df|\.pod)(\.gz|\.bz2)?$/i - || - $uriid =~ m!^C/CN/CNANDOR/(?:mp_(?:app|debug|doc|lib|source|tool)|VISEICat(?:\.idx)?|VISEData)! - ) { - # Overwriting allowed - $dbh->do("DELETE FROM uris WHERE uriid = ?", undef, $uriid); - } - my $query = q{INSERT INTO uris - (uriid, userid, - basename, - uri, - changedby, changed, is_perl6) - VALUES (?, ?, ?, ?, ?, ?, ?)}; - my @query_params = ( - $uriid, $u->{userid}, $filename, $uri, $mgr->{User}{userid}, $now, - $is_perl6 - ); - #display query - my $cp = $mgr->escapeHTML("$query/(@query_params)"); - push @m, qq{

Submitting query

}; - if ($mgr->{UseModuleSet} eq "patchedCGI") { - warn "patchedCGI not supported anymore"; - my @debug = "DEBUGGING patched CGI:\n"; - push @debug, scalar localtime; - my %headers = %{ $req->headers }; # XXX: or maybe use header_field_names - for my $h (keys %headers) { - next if $h =~ /Authorization/; # security! - push @debug, sprintf " %s: %s\n", $h, $headers{$h}; - } - for ($req->param) { - push @debug, " $_: "; - my($val) = $req->param($_); - push @debug, $val; - push @debug, "
\n"; - if (ref $val) { - push @debug, "
"; - my $valh; - if ($val->can("multipart_header")) { - $valh = $val->multipart_header; - } else { - push( - @debug, - " CAN'T multipart_header, val[$val]

\n"); - next; - } - push @debug, " valh[$valh]"; - for my $h (keys %$valh) { - push @debug, " $h: $valh->{$h}
\n"; - } - push @debug, "

\n"; - } - } - warn join "", @debug; - push @m, "Resulting SQL: ", $cp; - } - local($dbh->{RaiseError}) = 0; - if ($dbh->do($query, undef, @query_params)) { - $$success .= qq{ - -The request is now entered into the database where the PAUSE daemon -will pick it up as soon as possible (usually 1-2 minutes). - -}; - $$didit = 1; - push @m, (qq{ - -

Query succeeded. Thank you for your contribution

- -

As it is done by a separate process, it may take a few minutes to -complete the upload. The processing of your file is going on while you -read this. There\'s no need for you to retry. The form below is only -here in case you want to upload further files.

- -

Please tidy up your homedir: CPAN is getting larger every day which -is nice but usually there is no need to keep old an outdated version -of a module on several hundred mirrors. Please consider removing old versions of -your module from PAUSE and CPAN. If you are worried that someone might -need an old version, it can always be found on the backpan -

- -}); - - my $usrdir = "https://$server/pub/PAUSE/authors/id/$userhome"; - my $tailurl = "https://$server/pause/authenquery?ACTION=tail_logfile" . - "&pause99_tail_logfile_1=5000"; - my $etailurl = $mgr->escapeHTML($tailurl); - push @m, (qq{ - -

Debugging: your submission should show up soon at $usrdir. If something's wrong, please -check the logfile of the daemon: see the tail of it with $etailurl. If you already know what's going wrong, you -may wish to visit the repair -tool for pending uploads.

- -} - ); - - $$success .= qq{ - -During upload you can watch the logfile in $tailurl. - -You'll be notified as soon as the upload has succeeded, and if the -uploaded package contains modules, you'll get another notification -from the indexer a little later (usually within 1 hour). - -}; - - } else { - my $errmsg = $dbh->errstr; - $mgr->{RES}->status(406); - push @m, (qq{ - -

Could not enter the URL into the database. -Reason:

$errmsg

- -}); - if ($errmsg =~ /non\s+unique\s+key|Duplicate/i) { - $mgr->{RES}->status(409); - my $sth = $dbh->prepare("SELECT * FROM uris WHERE uriid=?"); - $sth->execute($uriid); - my $rec = $mgr->fetchrow($sth, "fetchrow_hashref"); - for my $k (qw(changed dgot dverified)) { - if ($rec->{$k}) { - $rec->{$k} .= sprintf " [%s UTC]", scalar gmtime $rec->{$k}; - } - } - my $as_table = $self->hash_as_table($rec); - push @m, qq{ - -

This indicates that you probably tried to upload a file that is -already in the database. You will most probably have to rename your -file and try again, because PAUSE doesn\'t let you upload a file -twice.

- -

This seems to be the record causing the conflict:
$as_table

- -}; - } - } - } - - push @m, "\n\n
\n"; - - push @m, (qq{
\n}); - return @m; -} - -sub manifind { - my($self) = @_; - my $cwd = Cwd::cwd(); - warn "cwd[$cwd]"; - my %files = %{ExtUtils::Manifest::manifind()}; - if (keys %files == 1 && exists $files{""} && $files{""} eq "") { - warn "ALERT: BUG in MANIFIND, falling back to zsh !!!"; - - # This bug was caused by libc upgrade: perl and apache were - # compiled with 2.1.3; upgrading to 2.2.5 and/or later - # recompilation of apache has caused readdir() to return a list of - # empty strings. - - open my $ls, "zsh -c 'ls **/*(.)' |" or die; - %files = map { chomp; $_ => "" } <$ls>; - close $ls; - } - - %files; -} - -sub scroll_subdirs { - my $self = shift; - my $mgr = shift; - my $u = shift; - my $userhome = PAUSE::user2dir($u->{userid}); - require ExtUtils::Manifest; - if (chdir "$PAUSE::Config->{MLROOT}/$userhome"){ - warn "DEBUG: MLROOT[$PAUSE::Config->{MLROOT}] userhome[$userhome] E:M:V[$ExtUtils::Manifest::VERSION]"; - } else { - return ""; - } - my %files = $self->manifind; - my %seen; - my @dirs = sort grep !$seen{$_}++, grep s|(.+)/[^/]+|$1|, keys %files; - return "" unless @dirs; - unshift @dirs, "."; - my $size = @dirs > 18 ? 15 : scalar(@dirs); - my @m; - push @m, $mgr->scrolling_list( - 'name' => "pause99_add_uri_subdirscrl", - 'values' => \@dirs, - 'size' => $size, - ); - push @m, qq{
}; - @m; -} - -sub wrap { - my $self = shift; - my $p = shift; - my($wrapped); - $wrapped = Text::Format->new("firstIndent"=>0)->format($p); - $wrapped; -} - -sub wrappar { - my $self = shift; - my @p = split /\n\n/, shift; - my($wrapped); - $wrapped = Text::Format->new("firstIndent"=>0)->paragraphs(@p); - $wrapped; -} - -sub delete_files { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - my @m; - my $u = $self->active_user_record($mgr); - $mgr->prefer_post(1); - push @m, qq{}; - require ExtUtils::Manifest; - require HTTP::Date; - my $dbh = $mgr->connect; - local($dbh->{RaiseError}) = 0; - my $userhome = PAUSE::user2dir($u->{userid}); - push @m, qq{

Files in directory authors/id/$userhome

}; #}; - require Cwd; - my $cwd = Cwd::cwd(); - - if (chdir "$PAUSE::Config->{MLROOT}/$userhome"){ - warn "DEBUG: MLROOT[$PAUSE::Config->{MLROOT}] userhome[$userhome] ExtUtils:Manifest:VERSION[$ExtUtils::Manifest::VERSION]"; - } else { - # QUICK DEPARTURE - push @m, qq{No files found in authors/id/$userhome}; - return @m; - } - - # NONO, this is nothing we should die from: - # die PAUSE::HeavyCGI::Exception - # ->new(ERROR => [qq{No files found in authors/id/$userhome}]); - - - my $time = time; - my $blurb = ""; - # my $myurl = $mgr->myurl; - my $server = $PAUSE::Config->{SERVER_NAME}; # XXX: $r->server->server_hostname - if ($req->param('SUBMIT_pause99_delete_files_delete')) { - - foreach my $f ($req->param('pause99_delete_files_FILE')) { - if ($f =~ m,^/, || $f =~ m,/\.\./,) { - $blurb .= "WARNING: illegal filename: $userhome/$f\n"; - next; - } - unless (-f $f){ - $blurb .= "WARNING: file not found: $userhome/$f\n"; - next; - } - if ($f =~ m{ (^|/) CHECKSUMS }x) { - $blurb .= "WARNING: CHECKSUMS not erasable: $userhome/$f\n"; - next; - } - $dbh->do( - "INSERT INTO deletes VALUES (?, ?, ?)", undef, - "$userhome/$f", $time, "$mgr->{User}{userid}" - ) or next; - - $blurb .= "\$CPAN/authors/id/$userhome/$f\n"; - - # README - next if $f =~ /\.readme$/; - my $readme = $f; - $readme =~ s/(\.tar.gz|\.zip)$/.readme/; - if ($readme ne $f && -f $readme) { - $dbh->do( - q{INSERT INTO deletes VALUES (?,?,?)}, undef, - "$userhome/$readme", $time, $mgr->{User}{userid}, - ) or next; - $blurb .= "\$CPAN/authors/id/$userhome/$readme\n"; - } - } - } elsif ($req->param('SUBMIT_pause99_delete_files_undelete')) { - foreach my $f ($req->param('pause99_delete_files_FILE')) { - my $sql = "DELETE FROM deletes WHERE deleteid = ?"; - $dbh->do( - $sql, undef, - "$userhome/$f" - ) or warn sprintf "FAILED Query: %s/: %s", $sql, "$userhome/$f", $DBI::errstr; - } - } - if ($blurb) { - my $tf = Text::Format->new("firstIndent"=>0,); - my @blurb = scalar $tf->format(sprintf( - qq{According to a request entered by %s the -following files and the symlinks pointing to them have been scheduled -for deletion. They will expire after 72 hours and then be deleted by a -cronjob. Until then you can undelete them via -https://%s/pause/authenquery?ACTION=delete_files or -http://%s/pause/authenquery?ACTION=delete_files -}, - $mgr->{User}{fullname}, - $server, - $server)); - push @blurb, $blurb; - push @blurb, scalar $tf->format(qq{Note: to encourage deletions, all of past CPAN -glory is collected on http://history.perl.org/backpan/}); - push @blurb, qq{The PAUSE Team}; - # $blurb = Text::Format->new("firstIndent"=>0,)->paragraphs(@blurb); - $blurb = join "\n", @blurb; - - my %umailset; - my $name = $u->{asciiname} || $u->{fullname} || ""; - my $Uname = $mgr->{User}{asciiname} || $mgr->{User}{fullname} || ""; - if ($u->{secretemail}) { - $umailset{qq{"$name" <$u->{secretemail}>}} = 1; - } elsif ($u->{email}) { - $umailset{qq{"$name" <$u->{email}>}} = 1; - } - if ($u->{userid} ne $mgr->{User}{userid}) { - if ($mgr->{User}{secretemail}) { - $umailset{qq{"$Uname" <$mgr->{User}{secretemail}>}} = 1; - }elsif ($mgr->{User}{email}) { - $umailset{qq{"$Uname" <$mgr->{User}{email}>}} = 1; - } - } - $umailset{$PAUSE::Config->{ADMIN}} = 1; - my @to = keys %umailset; - my $header = { - Subject => "Files of $u->{userid} scheduled for deletion" - }; - $mgr->send_mail_multi(\@to,$header,$blurb); - } - - my $submit_butts = qq{}; - push @m, $submit_butts; - push @m, "
";
-
-  my %files = $self->manifind;
-  my(%deletes,%whendele,$sth);
-  if (
-      $sth = $dbh->prepare(qq{SELECT deleteid, changed
-                              FROM deletes
-                              WHERE deleteid
-                              LIKE ?})           #}
-      and
-      $sth->execute("$userhome/%")
-      and
-      $sth->rows
-     ) {
-    my $dhash;
-    while ($dhash = $mgr->fetchrow($sth, "fetchrow_hashref")) {
-      $dhash->{deleteid} =~ s/\Q$userhome\E\///;
-      $deletes{$dhash->{deleteid}}++;
-      $whendele{$dhash->{deleteid}} = $dhash->{changed};
-    }
-  }
-  $sth->finish if ref $sth;
-
-  require HTTP::Date;
-  foreach my $f (keys %files) {
-    unless (stat $f) {
-      warn "ALERT: Could not stat f[$f]: $!";
-      next;
-    }
-    my $blurb = $deletes{$f} ?
-	$self->scheduled($whendele{$f}) :
-	    HTTP::Date::time2str((stat _)[9]);
-    $files{$f} = sprintf " %-50s %7d  %s", $f, -s _, $blurb;
-  }
-
-  chdir $cwd or die;
-
-  my $field = $mgr->checkbox_group(
-				    name      => 'pause99_delete_files_FILE',
-				    'values'  => [sort keys %files],
-				    linebreak => 'true',
-				    labels    => \%files
-				   );
-  $field =~ s!
\s*!\n!gs; - - push @m, $field; - push @m, "
"; - push @m, $submit_butts; - - @m; -} - -sub show_files { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - my @m; - my $u = $self->active_user_record($mgr); - $mgr->prefer_post(1); - require ExtUtils::Manifest; - require HTTP::Date; - my $dbh = $mgr->connect; - local($dbh->{RaiseError}) = 0; - my $userhome = PAUSE::user2dir($u->{userid}); - push @m, qq{

Files in directory authors/id/$userhome

}; - require Cwd; - my $cwd = Cwd::cwd(); - - if (chdir "$PAUSE::Config->{MLROOT}/$userhome"){ - warn "DEBUG: MLROOT[$PAUSE::Config->{MLROOT}] userhome[$userhome] E:M:V[$ExtUtils::Manifest::VERSION]"; - } else { - # QUICK DEPARTURE - push @m, qq{No files found in authors/id/$userhome}; - return @m; - } - - my $time = time; - - push @m, "
";
-
-  my %files = $self->manifind;
-
-  my(%deletes,%whendele,$sth);
-  if (
-      $sth = $dbh->prepare(qq{SELECT deleteid, changed
-                              FROM deletes
-                              WHERE deleteid
-                              LIKE ?})
-      and
-      $sth->execute("$userhome/%")
-      and
-      $sth->rows
-     ) {
-    my $dhash;
-    while ($dhash = $mgr->fetchrow($sth, "fetchrow_hashref")) {
-      $dhash->{deleteid} =~ s/\Q$userhome\E\///;
-      $deletes{$dhash->{deleteid}}++;
-      $whendele{$dhash->{deleteid}} = $dhash->{changed};
-    }
-  }
-  $sth->finish if ref $sth;
-
-  require HTTP::Date;
-  foreach my $f (sort keys %files) {
-    unless (stat $f) {
-      warn "ALERT: Could not stat f[$f]: $!";
-      next;
-    }
-    my $blurb = $deletes{$f} ?
-	$self->scheduled($whendele{$f}) :
-	    HTTP::Date::time2str((stat _)[9]);
-    push @m, sprintf " %-50s %7d  %s
", $f, -s _, $blurb; - } - - chdir $cwd or die; - - push @m, "
"; - - @m; -} - -sub scheduled { - my $self = shift; - my($when) = shift; - my $time = time; - my $expires = $when + ($PAUSE::Config->{DELETES_EXPIRE} - || 60*60*24*2); - my $return = "Scheduled for deletion \("; - $return .= $time < $expires ? "due at " : "already expired at "; - $return .= HTTP::Date::time2str($expires); - $return .= "\)"; - $return; -} - -sub add_user_doit { - my($self,$mgr,$userid,$fullname,$dont_clear) = @_; - my $req = $mgr->{REQ}; - my $T = time; - my $dbh = $mgr->connect; - local($dbh->{RaiseError}) = 0; - my @m; - my($query,$sth,@qbind); - my($email) = $req->param('pause99_add_user_email'); - my($homepage) = $req->param('pause99_add_user_homepage'); - if ( $req->param('pause99_add_user_subscribe') gt '' ) { - $query = qq{INSERT INTO users ( - userid, isa_list, introduced, - changed, changedby) - VALUES ( - ?, ?, ?, - ?, ?)}; - @qbind = ($userid,1,$T,$T,$mgr->{User}{userid}); - } else { - $query = qq{INSERT INTO users ( - userid, email, homepage, fullname, - isa_list, introduced, changed, changedby) - VALUES ( - ?, ?, ?, ?, - ?, ?, ?, ?)}; - @qbind = ($userid,"CENSORED",$homepage,$fullname,"",$T,$T,$mgr->{User}{userid}); - } - - # We have a query for INSERT INTO users - - push @m, qq{

Submitting query

}; - if ($dbh->do($query,undef,@qbind)) { - push @m, sprintf(qq{

Query succeeded.

Do you want to }. - qq{register a module for %s?

}, - $userid, - $userid, - ); - my(@blurb); - my($subject); - my $need_onetime = 0; - if ( $req->param('pause99_add_user_subscribe') gt '' ) { - - # Add a mailinglist: INSERT INTO maillists - - $need_onetime = 0; - $subject = "Mailing list added to PAUSE database"; - my($maillistid) = $userid; - my($maillistname) = $fullname; - my($subscribe) = $req->param('pause99_add_user_subscribe'); - my($changed) = $T; - push @blurb, qq{ -Mailing list entered by }; - push @blurb, $mgr->{User}{fullname}; - push @blurb, qq{: - -Userid: $userid -Name: $maillistname -Description: }; - push @blurb, $self->wrap($subscribe); - $query = qq{INSERT INTO maillists ( - maillistid, maillistname, - subscribe, changed, changedby, address) - VALUES ( - ?, ?, - ?, ?, ?, ?)}; - my @qbind2 = ($maillistid, $maillistname, - $subscribe, $changed, $mgr->{User}{userid}, $email); - unless ($dbh->do($query,undef,@qbind2)) { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => [qq{

Query[$query]with qbind2[@qbind2] failed. - Reason:

$DBI::errstr

}]); - } - - } else { - - # Not a mailinglist: Compose Welcome - - $subject = qq{Welcome new user $userid}; - $need_onetime = 1; - # not for mailing lists - if ($need_onetime) { - - my $onetime = sprintf "%08x", rand(0xffffffff); - - my $sql = qq{INSERT INTO $PAUSE::Config->{AUTHEN_USER_TABLE} ( - $PAUSE::Config->{AUTHEN_USER_FLD}, - $PAUSE::Config->{AUTHEN_PASSWORD_FLD}, - secretemail, - forcechange, - changed, - changedby - ) VALUES ( - ?,?,?,?,?,? - )}; - my $pwenc = PAUSE::Crypt::hash_password($onetime); - my $dbh = $mgr->authen_connect; - local($dbh->{RaiseError}) = 0; - my $rc = $dbh->do($sql,undef,$userid,$pwenc,$email,1,time,$mgr->{User}{userid}); - die PAUSE::HeavyCGI::Exception - ->new(ERROR => - [qq{

Query [$sql] failed. Reason:

$DBI::errstr

}. - qq{

This is very unfortunate as we have no option to rollback.}. - qq{The user is now registered in mod.users and could not be regi}. - qq{stered in authen_pause.$PAUSE::Config->{AUTHEN_USER_TABLE}

}] - ) unless $rc; - $dbh->disconnect; - my $otpwblurb = qq{ - -(This mail has been generated automatically by the Perl Authors Upload -Server on behalf of the admin $PAUSE::Config->{ADMIN}) - -As already described in a separate message, you\'re a registered Perl -Author with the userid $userid. For the sake of approval I have -assigned to you a change-password-only-password that enables -you to pick your own password. This password is \"$onetime\" -(without the enclosing quotes). Please visit - - https://pause.perl.org/pause/authenquery?ACTION=change_passwd - -and use this password to initialize your account in the authentication -database. Once you have entered your password there, your one-time -password is expired automatically. If you cannot connect to the above -URL, you can replace 'https' with 'http', but then you are not using -SSL encryption. Be careful to always use an SSL connection if -possible, otherwise your password can be intercepted by third parties. - -Thanks & Regards, --- -$PAUSE::Config->{ADMIN} -}; - - my $header = { - Subject => $subject, - }; - warn "header[$header]otpwblurb[$otpwblurb]"; - $mgr->send_mail_multi([$email,$PAUSE::Config->{ADMIN}], - $header, - $otpwblurb); - - } - - @blurb = qq{ -Welcome $fullname, - -PAUSE, the Perl Authors Upload Server, has a userid for you: - - $userid - -Once you\'ve gone through the procedure of password approval (see the -separate mail you should receive about right now), this userid will be -the one that you can use to upload your work or edit your credentials -in the PAUSE database. - -This is what we have stored in the database now: - - Name: $fullname - email: CENSORED - homepage: $homepage - enteredby: $mgr->{User}{fullname} - -Please note that your email address is exposed in various listings and -database dumps. You can register with both a public and a secret email -if you want to protect yourself from SPAM. If you want to do this, -please visit - https://pause.perl.org/pause/authenquery?ACTION=edit_cred -or - http://pause.perl.org/pause/authenquery?ACTION=edit_cred - -If you need any further information, please visit - \$CPAN/modules/04pause.html. -If this doesn't answer your questions, contact modules\@perl.org. - -Thank you for your prospective contributions, -The PAUSE Team -}; - - my($memo) = $req->param('pause99_add_user_memo'); - push @blurb, "\nNote from $mgr->{User}{fullname}:\n$memo\n\n" - if length $memo; - } - - # both users and mailing lists run this code - - warn "DEBUG: UPLOAD[$PAUSE::Config->{UPLOAD}]"; - my(@to) = @{$PAUSE::Config->{ADMINS}}; - push @m, qq{ Sending separate mails to: -}, join(" AND ", @to, $email), qq{ -
-From: $PAUSE::Config->{UPLOAD}
-Subject: $subject\n};
-
-    my($blurb) = join "", @blurb;
-    require HTML::Entities;
-    my($blurbcopy) = HTML::Entities::encode($blurb,"<>");
-    push @m, $blurbcopy, "
\n"; - - my $header = { - Subject => $subject - }; - $mgr->send_mail_multi(\@to,$header,$blurb); - $blurb =~ s/\bCENSORED\b/$email/; - $mgr->send_mail_multi([$email],$header,$blurb); - - unless ($dont_clear) { - warn "Info: clearing all fields"; - for my $field (qw(userid fullname email homepage subscribe memo)) { - my $param = "pause99_add_user_$field"; - $req->parameters->set($param,""); - } - } - - } else { - push @m, sprintf(qq{

Query [$query] failed. Reason:

%s

\n}, - $dbh->errstr); - } - push @m, "Content of user record in table users:
"; - my $usertable = $self->usertable($mgr,$userid); - push @m, $usertable; - @m; -} - -sub get_secretemail { - my($self, $mgr, $userid) = @_; - my $dbh2 = $mgr->authen_connect; - my $sth2 = $dbh2->prepare("SELECT secretemail - FROM $PAUSE::Config->{AUTHEN_USER_TABLE} - WHERE $PAUSE::Config->{AUTHEN_USER_FLD}=?"); - $sth2->execute($userid); - my($h2) = $mgr->fetchrow($sth2, "fetchrow_array"); - $sth2->finish; - $h2; -} - -sub add_user { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - my @m; - - my $dbh = $mgr->connect; - local($dbh->{RaiseError}) = 0; - - if ($req->param("USERID")) { - my $session = $mgr->session; - my $s = $session->{APPLY}; - for my $a (keys %$s) { - $req->parameters->set("pause99_add_user_$a" => $s->{$a}); - warn "retrieving from session a[$a]s(a)[$s->{$a}]"; - } - } - - my $userid; - if ( $userid = $req->param("pause99_add_user_userid") ) { - - $userid = uc($userid); - $userid ||= ""; - my @error; - if ( $userid !~ $Valid_Userid ) { - my $euserid = $mgr->escapeHTML($userid); - - push @error, qq{userid[$euserid] does not match - $Valid_Userid.}; - - } - - $req->parameters->set("pause99_add_user_userid", $userid) if $userid; - my $doit = 0; - my $dont_clear; - my $fullname_raw = $req->param('pause99_add_user_fullname'); - my($fullname); - $fullname = $mgr->any2utf8($fullname_raw); - warn "fullname[$fullname]fullname_raw[$fullname_raw]"; - if ($fullname ne $fullname_raw) { - $req->parameters->set("pause99_add_user_fullname",$fullname); - my $debug = $req->param("pause99_add_user_fullname"); - warn "debug[$debug]fullname[$fullname]"; - } - unless ($fullname) { - warn "no fullname"; - push @error, qq{No fullname, nothing done.}; - } - unless (@error) { - if ($req->param('SUBMIT_pause99_add_user_Definitely')) { - $doit = 1; - } elsif ( - $req->param('SUBMIT_pause99_add_user_Soundex') - || - $req->param('SUBMIT_pause99_add_user_Metaphone') - ) { - - # START OF SOUNDEX/METAPHONE check - - my ($surname); - my($s_package) = $req->param('SUBMIT_pause99_add_user_Soundex') ? - 'Text::Soundex' : 'Text::Metaphone'; - - ($surname = $fullname) =~ s/.*\s//; - my $query = qq{SELECT userid, fullname, email, homepage, - introduced, changedby, changed - FROM users - WHERE isa_list='' -}; - my $sth = $dbh->prepare($query); - $sth->execute; - my $s_func; - if ($s_package eq "Text::Soundex") { - require Text::Soundex; - $s_func = \&Text::Soundex::soundex; - } elsif ($s_package eq "Text::Metaphone") { - require Text::Metaphone; - $s_func = \&Text::Metaphone::Metaphone; - } - my $s_code = $s_func->($surname); - warn "s_code[$s_code]"; - my $requserid = $req->param("pause99_add_user_userid")||""; - my $reqfullname = $req->param("pause99_add_user_fullname")||""; - my $reqemail = $req->param("pause99_add_user_email")||""; - my $reqhomepage = $req->param("pause99_add_user_homepage")||""; - my($suserid,$sfullname, $spublic_email, $shomepage, - $sintroduced, $schangedby, $schanged); - # if a user has a preference to display secret emails in a - # certain color, they can enter it here: - my %se_color_map = ( - jv => "black", - andk => "#f33", - ); - my $se_color = $se_color_map{lc $mgr->{User}{userid}} || "red"; - my @urows; - while (($suserid, $sfullname, $spublic_email, $shomepage, - $sintroduced, $schangedby, $schanged) = - $mgr->fetchrow($sth, "fetchrow_array")) { - (my $dbsurname = $sfullname) =~ s/.*\s//; - next unless $s_func->($dbsurname) eq $s_code; - my @urow; - my $score = 0; - my $ssecretemail = $self->get_secretemail($mgr, $suserid); - push @urow, ""; - if (defined($suserid)&&length($suserid)) { - my $duserid = $mgr->escapeHTML($suserid); - if ($requserid eq $suserid) { - $duserid = "$duserid"; - $score++; - } - push @urow, "$duserid"; - } else { - push @urow, " "; - } - { - my($bold,$end_bold) = ("",""); - my $dfullname = $mgr->escapeHTML($sfullname); - if ($sfullname eq $reqfullname) { - $dfullname = "$dfullname"; - $score++; - } elsif ($sfullname =~ /\Q$surname\E/) { - $dfullname =~ s|(\Q$surname\E)|$1|; - $score++; - } - if (defined($sfullname)&&length($sfullname)) { - push @urow, "$bold$dfullname$end_bold"; - } else { - push @urow, " "; - } - } - my $broken_spublic_email = $spublic_email; - $broken_spublic_email =~ $mgr->escapeHTML($broken_spublic_email); - $broken_spublic_email =~ s|@|
@|; - { - my($bold,$end_bold) = ("",""); - if ($spublic_email eq $reqemail) { - ($bold,$end_bold) = ("",""); - $score++; - } - push @urow, "$bold$broken_spublic_email$end_bold"; - } - push @urow, ""; - if ($ssecretemail) { - my($bold,$end_bold) = ("",""); - if ($ssecretemail eq $reqemail) { - ($bold,$end_bold) = ("",""); - $score++; - } - push @urow, "secret email: $bold$ssecretemail$end_bold
"; - } - if ($shomepage) { - my($bold,$end_bold) = ("",""); - if ($shomepage eq $reqhomepage) { - ($bold,$end_bold) = ("",""); - $score++; - } - push @urow, "homepage: $bold$shomepage$end_bold
"; - } - if ($sintroduced) { - my $time = scalar(gmtime($sintroduced)); - $time =~ s/\s/\ /g; - push @urow, "introduced on: $time
"; - } - if ($schanged) { - my $time = scalar(gmtime($schanged)); - $time =~ s/\s/\ /g; - push @urow, "changed on: $time by $schangedby
"; - } else { - push @urow, "changed by: $schangedby
"; - } - push @urow, "\n"; - my $line = join "", @urow; - push @urows, { line => $line, score => $score }; - } - if (@urows) { - my @rows = map { $_->{line} } sort { $b->{score} <=> $a->{score} } @urows; - $doit = 0; - $dont_clear = 1; - unshift @rows, qq{ -

Not submitting $userid, maybe we have a duplicate here

-

$s_package converted the fullname [$fullname] to [$s_code]

- - - - - - -}; - push @rows, qq{
useridfullname(public) emailother
\n}; - push @m, @rows; - } else { - $doit = 1; - } - - # END OF SOUNDEX/METAPHONE check - - } - } - my $T = time; - if ($doit) { - push @m, $self->add_user_doit($mgr,$userid,$fullname,$dont_clear); - } elsif (@error) { - push @m, qq{

Error processing form

}; - for (@error) { - push @m, "
    ", "
  • $_
  • ", "
"; - } - push @m, qq{

Please retry.

}; - } else { - warn "T[$T]doit[$doit]userid[$userid]"; - } - } else { - warn "No userid, nothing done"; - } - - my $submit_butts = join("", - $mgr->submit(name=>"SUBMIT_pause99_add_user_Soundex", - value=>" Insert with soundex care "), - $mgr->submit(name=>"SUBMIT_pause99_add_user_Metaphone", - value=>" Insert with metaphone care "), - $mgr->submit(name=>"SUBMIT_pause99_add_user_Definitely", - value=>" Insert most definitely ")); - - my $delete_link = sprintf( - qq{

If this is a bad request: Delete the ID request

}, - $userid, - ); - - push(@m, - qq{

Add a user or mailinglist

}, - $submit_butts, - - "
userid (entering lowercase is OK, but it will be - uppercased by the server):
", - - $mgr->textfield(name=>"pause99_add_user_userid", size=>12, maxlength=>9), - - qq{
full name (mailinglist name):
}, - - $mgr->textfield(name=>"pause99_add_user_fullname", - size=>50, - maxlength=>50), - - qq{
email address (for mailing lists this is the real - address):
}, - - $mgr->textfield(name=>"pause99_add_user_email", - size=>50, - maxlength=>50), - - qq{
homepage url (ignored for mailing lists):
}, - - $mgr->textfield(name=>"pause99_add_user_homepage", - size=>50, - maxlength=>256), - - qq{
subscribe information if this user is a mailing list - (leave blank for ordinary users):
}, - - $mgr->textfield(name=>"pause99_add_user_subscribe", - size=>50, - maxlength=>256), - qq{
}, - - qq{
If you want to send a message to new author, please - enter it here:
}, - - $mgr->textarea(name=>"pause99_add_user_memo", - rows=>6, - cols=>60), - qq{
}, - $submit_butts, - qq{
}, - $delete_link, - ); - - @m; -} - - -sub usertable { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $userid = shift; - my $req = $mgr->{REQ}; - my $dbh = $mgr->connect; - my $sql = "SELECT * FROM users WHERE userid=?"; - my $sth = $dbh->prepare($sql); - $sth->execute($userid); - return unless $sth->rows == 1; - my $rec = $mgr->fetchrow($sth, "fetchrow_hashref"); - return $self->hash_as_table($rec); -} - -sub hash_as_table { - my($self,$rec) = @_; - my @m; - push @m, qq{}; - for my $k (sort keys %$rec) { - push @m, sprintf(qq{\n}, - $k, - $rec->{$k} || " " - ); - } - push @m, qq{
%s%s
\n}; - join "", @m; -} - -sub request_id { - my pause_1999::edit $self = shift; - my $mgr = shift; - - my(@m); - - push @m, q{ -

A PAUSE account is only required to distribute and manage Perl module - distributions on CPAN. You do not need a PAUSE account to submit - bug reports to RT or participate - in many Perl community sites — please register a - Bitcard account instead.

- }; - - my $req = $mgr->{REQ}; - $mgr->prefer_post(1); - - # first time: form - # second time with error: error message + form - # second time without error: OK message - # bot debunked? => "Thank you!" - - my $showform = 0; - my $regOK = 0; - - if ($req->param('url')) { # debunked - return "Thank you!"; - } - my $fullname = $req->param( 'pause99_request_id_fullname') || ""; - my $ufullname = $mgr->any2utf8($fullname); - if ($ufullname ne $fullname) { - $req->parameters->set("pause99_request_id_fullname", $ufullname); - $fullname = $ufullname; - } - my $email = $req->param( 'pause99_request_id_email') || ""; - my $homepage = $req->param( 'pause99_request_id_homepage') || ""; - my $userid = $req->param( 'pause99_request_id_userid') || ""; - my $rationale = $req->param("pause99_request_id_rationale") || ""; - my $urat = $mgr->any2utf8($rationale); - if ($urat ne $rationale) { - $req->parameters->set("pause99_request_id_rationale", $urat); - $rationale = $urat; - } - warn sprintf( - "userid[%s]Valid_Userid[%s]args[%s]", - $userid, - $Valid_Userid, - scalar($req->uri->query)||"", - ); - - if ( $req->param("SUBMIT_pause99_request_id_sub") ) { - # check for errors - - my @errors = (); - if ( $fullname ) { - unless ($fullname =~ /[ ]/) { - push @errors, "Name does not look like a full civil name. Please accept our apologies if you believe we're wrong. In this case please write to @{$PAUSE::Config->{ADMINS}}."; - } - } else { - push @errors, "You must supply a name\n"; - } - unless( $email ) { - push @errors, "You must supply an email address\n"; - } - if ( $rationale ) { - - $rationale =~ s/^\s+//; - $rationale =~ s/\s+$//; - $rationale =~ s/\s+/ /; - push @errors, "Thank you for giving us a short description of - what you're planning to contribute, but frankly, this looks a - bit too short" if length($rationale)<10; - push @errors, "Please do not use HTML links in your description of - what you're planning to contribute" if $rationale =~ /<\s*a\s+href\s*=/ims; - - my $url_count =()= $rationale =~ m{https?://}gi; - push @errors, "Please do not include more than one URL in your description of - what you're planning to contribute" if $url_count > 1; - - } else { - - push @errors, "You must supply a short description of what - you're planning to contribute\n"; - - } - if ( $userid ) { - $userid = uc $userid; - $req->parameters->set('pause99_request_id_userid', $userid); - my $db = $mgr->connect; - my $sth = $db->prepare("SELECT userid FROM users WHERE userid=?"); - $sth->execute($userid); - warn sprintf("userid[%s]Valid_Userid[%s]matches[%s]", - $userid, - $Valid_Userid, - $userid =~ $Valid_Userid || "", - ); - if ($sth->rows > 0) { - my $euserid = $mgr->escapeHTML($userid); - push @errors, "The userid $euserid is already taken."; - } elsif ($userid !~ $Valid_Userid) { - my $euserid = $mgr->escapeHTML($userid); - push @errors, "The userid $euserid does not match $Valid_Userid."; - } - $sth->finish; - } else { - push @errors, "You must supply a desired user-ID\n"; - } - - if( @errors ) { - push @m, qq{

Error processing form

}; - for (@errors) { - push @m, "
    ", "
  • $_
  • ", "
"; - } - push @m, qq{

Please retry.

}; - $showform = 1; - } else { - $regOK = 1; - } - } else { - $showform = 1; - } - if ($showform) { - my $alt = 0; - # push @m, "\n"; - foreach my $arr ( - { - topic => 'Your full name (civil name)', - fname => 'pause99_request_id_fullname', - - fcomment => "Unicode Characters OK.", - footnote => "Note: You can enter fairly free-form text here but it must consist of at least two space-separated words. This is a spam protection measure we discovered accidentally. Back when PAUSE was developed in the nineties, people would generally fill out a field asking for a full name with a first name and a second name, like Ben Cartwright or Tony Nelson. When this trivial expectation was coded into the server as a sanity check, it turned out to block many spam bots because they often did not try to enter a space in the middle of the field. It was only around 2003 that people started complaining that they had tried Peter and it did not work. Apologies for insisting, Peter – but feel free to make something up to satisfy the requirement.", - - }, - { - topic => 'Email', - fname => 'pause99_request_id_email', - fcomment => 'required, otherwise we cannot send you the password', - }, - { - topic => 'Web site', - fname => 'pause99_request_id_homepage', - fcomment => 'optional' - }, - { - topic => 'Desired ID', - fname => 'pause99_request_id_userid', - fcomment => "3-9 characters matching [A-Z], please", - - }, - ) { - $alt ^= 1; - my $altname = $alt ? "alternate1" : "alternate2"; - push @m, qq{

$arr->{topic}

}; - if (my $note = $arr->{fcomment}) { - push @m, qq{$note

}; - } - push @m, $mgr->textfield( name => $arr->{fname}, size => 32 ); - if (my $note = $arr->{footnote}) { - push @m, qq{

$note

}; - } - push @m, "

"; - } - - push @m, qq{

A short description of why you would like a - PAUSE ID:

required; include what you are planning to contribute; do not use HTML

}; - - push @m, $mgr->textarea(name=>"pause99_request_id_rationale", - rows=>8, - cols=>60); - push @m, q{ -

If you're a bot, then type something in here:
}; - push @m, qq{

}; - # push @m, "
\n"; - - push @m, qq{}; - - } - if ($regOK) { - - my @to = $mgr->{MailtoAdmins}; - push @to, $email; - my $time = time; - push @m, qq{ Sending mail to: @to}; - if ($rationale) { - # wrap it - $rationale =~ s/\r\n/\n/g; - $rationale =~ s/\r/\n/g; - my @rat = split /\n\n/, $rationale; - my $tf = Text::Format->new( bodyIndent => 4, firstIndent => 5); - $rationale = $tf->paragraphs(@rat); - $rationale =~ s/^\s{5}/\n /gm; - } - - my $session = $mgr->session; - $session->{APPLY} = { - fullname => $fullname, - email => $email, - homepage => $homepage, - userid => $userid, - rationale => $rationale, - }; - require Data::Dumper; print STDERR "Line " . __LINE__ . ", File: " . __FILE__ . "\n" . Data::Dumper->new([$session->{APPLY}],[qw(APPLY)])->Indent(1)->Useqq(1)->Dump; # XXX - if (lc($fullname) eq lc($userid)) { - die "fullname looks like spam"; - } - if (my @x = $rationale =~ /(\.info)/g) { - die "rationale looks like spam" if @x >= 5; - } - if (my @x = $rationale =~ m|(http://)|g) { - die "rationale looks like spam" if @x >= 5; - } - if ($rationale =~ /interesting/i && $homepage =~ m|http://[^/]+\.cn/.+\.htm$|) { - die "rationale looks like spam"; - } - my $sessionID = $mgr->userid; - my $host = "https://pause.perl.org"; - # $host = "http://k242.linux.bogus" if $PAUSE::Config->{TESTHOST}; - my $blurb = <<"MAIL"; -Request to register new user - -fullname: $fullname - userid: $userid - mail: CENSORED -homepage: $homepage - why: -$rationale - -The following links are only valid for PAUSE maintainers: - -Registration form with editing capabilities: - $host/pause/authenquery?ACTION=add_user&USERID=$sessionID&SUBMIT_pause99_add_user_sub=1 -Immediate (one click) registration: - $host/pause/authenquery?ACTION=add_user&USERID=$sessionID&SUBMIT_pause99_add_user_Definitely=1 -MAIL - my $subject = "PAUSE ID request ($userid; $fullname)"; - my $header = { - To => $email, - Subject => $subject, - }; - - require HTML::Entities; - my($blurbcopy) = HTML::Entities::encode($blurb,qq{<>&"}); - $blurbcopy =~ s{( - https?:// - [^"'<>\s]+ # arbitrary exclusions, we had \S there, - # but it broke too often - ) - }{$1}xg; - $blurbcopy =~ s|(>http.*?)U|$1\n U|gs; # break the long URL - push @m, qq{
-From: $PAUSE::Config->{UPLOAD}
-Subject: $subject
-
-$blurbcopy
-
-
-}; #}; - $header = { - Subject => $subject - }; - warn "To[@to]Subject[$header->{Subject}]"; - $mgr->send_mail_multi(\@to,$header,$blurb); - } - - return @m; -} - -sub mailpw { - my pause_1999::edit $self = shift; - my $mgr = shift; - my(@m,$param,$email); - my $req = $mgr->{REQ}; - - # TUT: We reach this point in the code only if the Querystring - # specified ACTION=mailpw or something equivalent. The parameter ABRA - # is used to denote the token that we might have sent them. - my $abra = $req->param("ABRA") || ""; - push @m, qq{}; - - # TUT: The parameter pause99_mailpw_1 denotes the userid of the user - # for whom a password change was requested. Note that anybody has - # access to that parameter, we do not authentify its origin. Of - # course not, because that guy says he has lost the password:-) If - # this parameter is there, we are asked to send a token. Otherwise - # they only want to see the password-requesting form. - $param = $req->param("pause99_mailpw_1"); - if ( $param ) { - $param = uc($param); - unless ($param =~ /^[A-Z\-]+$/) { - if ($param =~ /@/) { - die PAUSE::HeavyCGI::Exception->new(ERROR => - qq{Please supply a userid, not an email address.}); - } - die PAUSE::HeavyCGI::Exception->new(ERROR => - sprintf qq{A userid of %s - is not allowed, please retry with a valid userid. Nothing done.}, $mgr->escapeHTML($param)); - } - - # TUT: The object $mgr is our knows/is/can-everything object. Here - # it connects us to the authenticating database - my $authen_dbh = $mgr->authen_connect; - my $sql = qq{SELECT * - FROM usertable - WHERE user = ? }; - my $sth = $authen_dbh->prepare($sql); - $sth->execute($param); - my $rec = {}; - if ($sth->rows == 1) { - $rec = $mgr->fetchrow($sth, "fetchrow_hashref"); - } else { - my $u; - eval { - $u = $self->active_user_record($mgr,$param); - }; - if ($@) { - die PAUSE::HeavyCGI::Exception->new(ERROR => - qq{Cannot find a userid - of $param, please - retry with a valid - userid.}); - - } elsif ($u->{userid} && $u->{email}) { - # this is one of the 94 users (counted on 2005-01-05) that has - # a users record but no usertable record - $sql = qq{INSERT INTO usertable (user,secretemail,forcechange,changed) - VALUES (?, ?, 1, ?)}; - - $authen_dbh->do($sql,{},$u->{userid},$u->{email},time) - or die PAUSE::HeavyCGI::Exception->new(ERROR => - qq{The userid of $param - is too old for this interface. Please get in touch with administration.}); - - $rec->{secretemail} = $u->{email}; - } else { - die PAUSE::HeavyCGI::Exception->new(ERROR => - qq{A userid of $param - is not known, please retry with a valid userid.}); - } - } - - # TUT: all users may have a secret and a public email. We pick what - # we have. - unless ($email = $rec->{secretemail}) { - my $u = $self->active_user_record($mgr,$param,{hidden_user_ok => 1}); - require YAML::Syck; print STDERR "Line " . __LINE__ . ", File: " . __FILE__ . "\n" . YAML::Syck::Dump({u=>$u}); # XXX - - $email = $u->{email}; - } - if ($email) { - - # TUT: Before we insert a record from that table, we remove old - # entries so the primary key of an old record doesn't block us now. - $sql = sprintf qq{DELETE FROM abrakadabra - WHERE NOW() > expires}; - $authen_dbh->do($sql); - - my $passwd = sprintf "%08x" x 4, rand(0xffffffff), rand(0xffffffff), - rand(0xffffffff), rand(0xffffffff); - # warn "pw[$passwd]"; - my $then = time + $PAUSE::Config->{ABRA_EXPIRATION}; - $sql = sprintf qq{INSERT INTO abrakadabra - ( user, chpasswd, expires ) - VALUES - ( ?, ?, from_unixtime(?) ) }; - local($authen_dbh->{RaiseError}) = 0; - if ( $authen_dbh->do($sql,undef,$param,$passwd,$then) ) { - } elsif ($authen_dbh->errstr =~ /Duplicate entry/) { - my $duration; - if ($HAVE_TIME_DURATION) { - $duration = Time::Duration::duration($PAUSE::Config->{ABRA_EXPIRATION}); - } else { - $duration = sprintf "%d seconds", $PAUSE::Config->{ABRA_EXPIRATION}; - } - die PAUSE::HeavyCGI::Exception->new - ( - ERROR => sprintf( - qq{A token for $param that allows - changing of the password has been requested recently - (less than %s ago) and is still valid. Nothing - done.}, - $duration, - ), - ); - } else { - die PAUSE::HeavyCGI::Exception->new(ERROR => $authen_dbh->errstr); - } - - # TUT: a bit complicated only because we switched back and forth - # between Apache::URI and URI::URL - my $myurl = $mgr->myurl; - my $me; - if ($myurl->can("unparse")) { - $me = $myurl->unparse; - $me =~ s/\?.*//; - } else { - $me = $myurl->as_string; - } - $me =~ s/^http:/https:/; # do not blindly inherit the schema - my $mailblurb = qq{ - -(this an automatic mail sent by a program because somebody asked for -it. If you did not intend to get it, please let us know and we will -take more precautions to prevent abuse.) - -Somebody, probably you, has visited the URL - - $me?ACTION=mailpw - -and asked that you, "$param", should get a token that enables the -setting of a new password. Here it is (please watch out for line -wrapping errors of your mail reader and other cut and paste errors, -this URL must not contain any spaces): - - $me?ACTION=change_passwd;ABRA=$param.$passwd - -Please visit this URL, it should open you the door to a password -changer that lets you set a new password for yourself. This token -will expire within a few hours. If you don't need it, do nothing. By -the way, your old password is still valid. - -$Yours}; - my $header = { Subject => "Your visit at $me" }; - warn "mailto[$email]mailblurb[$mailblurb]"; - $mgr->send_mail_multi([$email], $header, $mailblurb); - - push @m, qq{ - -

A token to change the password for $param is on its way to its - owner. Should the mail not arrive, please tell us.

- -}; - return @m; # no need to repeat form - - } else { - push @m, sprintf qq{ - -

We have not found the email of $param. Please try with a different - name or mail to the administrator directly.

- -}; - - } - return @m; - } - - # TUT: First time here, send them the password requesting form - push @m, qq{ - -

This form lets you request a token that enables you to set a new -password. It only operates correctly if the database knows you and -your email adress. Please fill in your userid on the CPAN. The token -will be mailed to that userid.

- -}; - push @m, $mgr->textfield(name => "pause99_mailpw_1", - size => 32); - push @m, qq{ - -}; - @m; -} - -sub edit_ml { - my pause_1999::edit $self = shift; - - my $mgr = shift; - my(@m); - push @m, q{ -Excerpt from a mail:
-
-   From: andreas.koenig@anima.de (Andreas J. Koenig)
-   To: kstar@chapin.edu
-   Subject: Re: [elagache@ipn.caida.org: No email found for CAIDA? (Re: Missing CAIDA password?)]
-   Date: 02 Nov 2000 17:59:28 +0100
-
-   A mailing list occupies the same namespace as users because we do
-   not want that users and mailing lists get confused. But a mailing
-   list does not have a password and does not have a directory of its
-   own. Only people can upload and occupy a directory and have a
-   password. (It's clear that the user namespace is not related to the
-   modules namespace, right?)
-
-   The Module List may list a mailinglist as "the contact", so the
-   field userid in the table mods identifies either a mailing list or
-   a user. This has been useful in the past when several clueful
-   people represent several related modules and use a common mailing
-   list as the contact.
-
-   The table list2user maps mailing lists to their owners so that the
-   owners can edit the data associated with the mailing list like
-   address and comment. The table list2user does not have a web
-   interface because we are not really established as the primary
-   source for mailing list information and so it has not been used
-   much. But I'm open to offer one if you believe it's useful.
-   [...]
-
-}; - - my $req = $mgr->{REQ}; - my $selectedid = ""; - my $selectedrec = {}; - my $u = $self->active_user_record($mgr); - push @m, qq{}; - my $param; - if ($param = $req->param("pause99_edit_ml_3")) { # upper selectbox - $selectedid = $param; - } elsif ($param = $req->param("HIDDENNAME")) { - $selectedid = $param; - $req->parameters->set("pause99_edit_ml_3",$param); - } - warn sprintf( - "selectedid[%s]IsMR[%s]", - $selectedid, - join(":", - keys(%{$mgr->{IsMailinglistRepresentative}}) - ) - ); - my($sql,@bind); - if (exists $mgr->{IsMailinglistRepresentative}{$selectedid}) { - $sql = qq{SELECT users.userid - FROM users JOIN list2user - ON users.userid = list2user.maillistid - WHERE users.isa_list > '' - AND list2user.userid = ? - ORDER BY users.userid -}; - @bind = $mgr->{User}{userid}; - } else { - $sql = qq{SELECT userid FROM users WHERE isa_list > '' ORDER BY userid}; - @bind = (); - } - my $dbh = $mgr->connect; - my $sth = $dbh->prepare($sql); - $sth->execute(@bind); - my @all_mls; - my %mls_lab; - if ($sth->rows) { - my $sth2 = $dbh->prepare(qq{SELECT * FROM maillists WHERE maillistid=?}); - while (my($id) = $mgr->fetchrow($sth, "fetchrow_array")) { - # register this mailinglist for the selectbox - push @all_mls, $id; - # query for more info about it - $sth2->execute($id); - my($rec) = $mgr->fetchrow($sth2, "fetchrow_hashref"); - # we will display the name along the ID - $mls_lab{$id} = "$id ($rec->{maillistname})"; - if ($id eq $selectedid) { - # if this is the selected one, we just store it immediately - $selectedrec = $rec; - } - } - } - my $size = @all_mls > 18 ? 15 : scalar(@all_mls); - push @m, $mgr->scrolling_list( - 'name' => "pause99_edit_ml_3", - 'values' => \@all_mls, - 'labels' => \%mls_lab, - 'size' => $size, - ); - push @m, qq{

}; - if ($selectedid) { - push @m, qq{

Record for $selectedrec->{maillistid}

\n}; - my @m_mlrec; - my $force_sel = $req->param('pause99_edit_ml_2'); - my $update_sel = $req->param('pause99_edit_ml_4'); - my %meta = ( - maillistname => { - - headline => "The name of the mailing list", - - note => "The name appears in the CPAN - authors list, so it is good if - the name contains the term - mailing list or something - equivalent", - - type => "textfield", - args => { - size => 50, - maxsize => 64, - } - }, - address => { - - headline => "The address of the - mailing list", - - note => "This is the address where - people post to (where all members - of the group can be contacted)", - - type => "textfield", - args => { - size => 50, - } - }, - subscribe => { - headline => "How to subscribe", - - note => "This is a text that - describes how to join the mailing - list. E.g. the mailing list - subscribe address or a URL with - more details.", - - type => "textarea", - args => { - rows => 5, - cols => 60, - } - }, - ); - my $mailblurb = qq{Record update in the PAUSE mailinglists database: - -}; - my($mailsprintf1,$mailsprintf2,$saw_a_change); - $mailsprintf1 = "%12s: [%s]%s"; - $mailsprintf2 = " was [%s]\n"; - my $now = time; - - $mailblurb .= sprintf($mailsprintf1, "userid", $selectedrec->{maillistid}, "\n"); - - for my $field (qw(maillistname address subscribe)) { - my $headline = $meta{$field}{headline} || $field; - my $note = $meta{$field}{note}; - push @m_mlrec, sprintf qq{

%s

}, $headline; - push @m_mlrec, sprintf qq{

%s

}, $note if $note; - my $fieldtype = $meta{$field}{type}; - my $fieldname = "pause99_edit_ml_$field"; - if ($force_sel){ - $req->parameters->set($fieldname, $selectedrec->{$field}||""); - } elsif ($update_sel) { - my $param = $req->param($fieldname); - if ($param ne $selectedrec->{$field}) { - $mailblurb .= sprintf($mailsprintf1, - $field, - $param, - sprintf($mailsprintf2,$selectedrec->{$field}) - ); - my $sql = qq{UPDATE maillists - SET $field=?, - changed=?, - changedby=? - WHERE maillistid=?}; - my $usth = $dbh->prepare($sql); - my $ret = $usth->execute($param, $now, $u->{userid}, $selectedrec->{maillistid}); - $saw_a_change = 1 if $ret > 0; - $usth->finish; - } else { - $mailblurb .= sprintf($mailsprintf1, $field, $selectedrec->{$field}, "\n"); - } - } - push @m_mlrec, $mgr->$fieldtype( - 'name' => $fieldname, - 'value' => $selectedrec->{$field}, - %{$meta{$field}{args} || {}} - ); - push @m_mlrec, qq{
\n}; - } - push @m_mlrec, qq{
}; - - if ($saw_a_change) { - push @m, "

The record has been updated in the database

"; - $mailblurb .= qq{ -Data entered by $mgr->{User}{fullname}. -Please check if they are correct. - -$Yours}; - my @to = ($u->{secretemail}||$u->{email}, $mgr->{MailtoAdmins}); - warn "sending to[@to]"; - warn "mailblurb[$mailblurb]"; - my $header = { - Subject => "Mailinglist update for $selectedrec->{maillistid}" - }; - $mgr->send_mail_multi(\@to, $header, $mailblurb); - } elsif ($update_sel) { # it should have been updated but wasn't? - - push @m, "

It seems to me the record was NOT updated. Maybe -nothing changed? Please take a closer look and inform an admin if -things didn't proceed as expected.

"; - - } - push @m, @m_mlrec; - } - @m; -} - -sub edit_mod { - my $self = shift; - my $mgr = shift; - $mgr->prefer_post(0); - my(@m); - my $req = $mgr->{REQ}; - my $selectedid = ""; - my $selectedrec = {}; - my $u = $self->active_user_record($mgr); - my @to = $mgr->{MailtoAdmins}; - if ($u->{cpan_mail_alias} =~ /^(publ|secr)$/ - && - time - ($u->{introduced}||0) > 86400 - ) { - $to[0] .= sprintf ",%s\@cpan.org", lc $u->{userid}; - # warn qq{Prepared to send mail to: @to}; - } else { - # we have nothing else, so we must send separate mail - my $user_email = $u->{secretemail}; - $user_email ||= $u->{email}; - push @to, $user_email if $user_email; - warn qq{Prepared to send separate mails to: }, join(" AND ", - map { "[$_]" } @to); - } - - push @m, qq{}; - if (my $param = $req->param("pause99_edit_mod_3")) { # upper selectbox - $selectedid = $param; - } - - push @m, qq{ - -

The select box shows all the modules that have been - registered for user $u->{userid} officially via - modules\@perl.org, i.e. that are included (or about to be - included) in the module list.

If you are missing a - module of yours, maybe you have never registered it? - Consider registering and visit the Register Namespace page. If - you are missing certain other pieces, please let - modules\@perl.org know, see modules/04pause.html - on CPAN for details.

You can edit the infos - stored in the database on this page. The changes you make - will take effect when the next module list will be - released. Thank you for your help!

- -}; - - my $dbh = $mgr->connect; - if (0) { - warn sprintf( - "selectedid[%s]IsMailinglistRepr[%s]", - $selectedid, - join(":", - keys(%{$mgr->{IsMailinglistRepresentative}}) - ) - ); - } - my($sth); - if ($selectedid and exists $mgr->{IsMailinglistRepresentative}{$selectedid}) { - my $sql = qq{SELECT modid - FROM mods, list2user - ON mods.userid = list2user.maillistid - WHERE mods.userid=? - AND list2user.userid = ? - ORDER BY modid}; - my @bind = ($selectedid, $mgr->{User}{userid}); - $sth = $dbh->prepare($sql); - my $ret = $sth->execute(@bind); - } else { - my $sql = qq{SELECT modid - FROM mods - WHERE userid=? - ORDER BY modid}; - my @bind = $u->{userid}; - $sth = $dbh->prepare($sql); - my $ret = $sth->execute(@bind); - } - my @all_mods; - my $is_only_one; - if (my $rows = $sth->rows) { - while (my($id) = $mgr->fetchrow($sth, "fetchrow_array")) { - # register this mailinglist for the selectbox - push @all_mods, $id; - if ($rows == 1) { - # if this is the selected one, we just store it immediately - $selectedid = $id; - $is_only_one++; - } - if ($id eq $selectedid) { - my $sth2 = $dbh->prepare(qq{SELECT * - FROM mods - WHERE modid=? - AND userid=?}); - $sth2->execute($id,$u->{userid}); - my($rec) = $mgr->fetchrow($sth2, "fetchrow_hashref"); - $selectedrec = $rec; - } - } - } - my $all_mods = scalar @all_mods; - my $size = $all_mods > 18 ? 15 : $all_mods; - unless ($size) { - - push @m, qq{

Sorry, there are no modules registered belonging to - $u->{userid}. Please note, only modules that are - already registered in the module list can be edited - here. If you believe, this is a bug, please contact - @{$PAUSE::Config->{ADMINS}}.

}; - - return @m; - } - push @m, $mgr->scrolling_list( - 'name' => "pause99_edit_mod_3", - 'values' => \@all_mods, - 'size' => $size, - ); - - push @m, qq{
}; - if ($selectedid) { - push @m, $self->_edit_mod_selected($mgr,\@to,$selectedrec,$u,$is_only_one); - } - - @m; -} - -sub _edit_mod_selected { - my($self,$mgr,$to,$selectedrec,$u,$is_only_one) = @_; - my @m; - my $req = $mgr->{REQ}; - my @to = @$to; - my $dbh = $mgr->connect; - push @m, qq{

Record for $selectedrec->{modid}

More - about the meaning of the DSLIP status in the module - list. To delete, add or rename an entry, mail to - modules\@perl.org.

}; - - my @m_modrec; - my $force_sel = $req->param('pause99_edit_mod_2'); - # || $is_only_one; - my $update_sel = $req->param('pause99_edit_mod_4'); - - my(@stat_meta) = $self->stat_meta; - my(@chap_meta) = $self->chap_meta($mgr); - my(@desc_meta) = $self->desc_meta; - - my %meta = ( - @stat_meta, - @desc_meta, - userid => { - type => "textfield", - headline => "CPAN User-ID", - - note => "If you change the userid, you will - lose control over the module and - the other userid will become the - owner. That's a one way move, take - care!", - - args => { - size => 12, - maxlength => 9, - }, - }, - mlstatus => { - type => "scrolling_list", - headline => "Lifecycle", - - note => "Select one of list, - hide, or delete, - normal case is of course - list. Select delete - only if the module definitely has - gone for some time. If the module - has no public relevance and is - not needed in the module list or - if it is abandoned but might have - a revival some day, maybe by - being claimed by another author, - please keep it for a while as - hide.", - - args => { - size => 1, - values => [qw(list hide delete)], - labels => - { - list => "List in Module List", - hide => "Hide from modulelist, but keep in database", - delete=> "Can be deleted from database", - }, - } - }, - @chap_meta, - ); - my $mailblurb = qq{Record update in the PAUSE modules database: - -}; - my($mailsprintf1,$mailsprintf2,$saw_a_change); - $mailsprintf1 = "%12s: [%s]%s"; - $mailsprintf2 = " was [%s]\n"; - my $now = time; - $mailblurb .= sprintf($mailsprintf1, "modid", $selectedrec->{modid}, "\n"); - - my $alter = 0; - for my $field (qw( -statd -stats -statl -stati -statp -description -userid -chapterid -mlstatus -)) { - my $headline = $meta{$field}{headline} || $field; - my $note = $meta{$field}{note} || ""; - $alter ^= 1; - my $alterclass = $alter ? "alternate1" : "alternate2"; - push @m_modrec, qq{\n

$headline

}; - push @m_modrec, qq{$note
} if $note; - my $fieldtype = $meta{$field}{type}; - my $fieldname = "pause99_edit_mod_$field"; - if ($field =~ /^stat/) { # there are many blanks instead of - # question marks, I believe - if (0) { - warn sprintf( - "field[%s]value[%s]mfals[%s]", - $field, - $selectedrec->{$field}, - $meta{$field}{args}{labels}{$selectedrec->{$field}}, - ); - } - $selectedrec->{$field} = "?" unless exists - $meta{$field}{args}{labels}{$selectedrec->{$field}}; - } elsif ($field eq "chapterid") { - die "chapterid not integer" if $strict_chapterid && - $selectedrec->{$field} !~ /^\d*$/; - } - if ($force_sel) { - $req->parameters->set($fieldname, $selectedrec->{$field}||""); - } elsif ($update_sel) { - my $param = $req->param($fieldname); - my $uparam = $mgr->any2utf8($param); - if ($uparam ne $param) { - $req->parameters->set($fieldname,$uparam); - $param = $uparam; - } - if ($param ne $selectedrec->{$field}) { - if ($field eq "userid") { - # die if the user doesn't exist - my $ucparam = uc $param; - unless ($ucparam eq $param) { - $param = $ucparam; - $req->parameters->set($fieldname, $param); - } - my $nu = $self->active_user_record($mgr, $param, {checkonly => 1}); - - die PAUSE::HeavyCGI::Exception - ->new(ERROR => sprintf("Unknown user[%s]", - $param, - )) unless - $nu->{userid} eq $param; - - # add the new user to @to - if ($nu->{cpan_mail_alias} =~ /^(publ|secr)$/ - && - time - ($nu->{introduced}||0) > 86400 - ) { - $to[0] .= sprintf ",%s\@cpan.org", lc $nu->{userid}; - push @m, qq{ Sending mail to: @to}; - } else { - # we have nothing else, so we must send separate mail - my $nuser_email = $nu->{secretemail}; - $nuser_email ||= $nu->{email}; - push @to, $nuser_email if $nuser_email; - push @m, qq{ Sending separate mails to: }, join(" AND ", - map { "[$_]" } @to); - } - # Now also update primeur table. We can do that with an - # update. If the record does not exist, we don't need it - # updated anyway - my $query = "UPDATE primeur SET userid=? WHERE package=? AND userid=?"; - my $ret = $dbh->do($query,{},$nu->{userid},$selectedrec->{modid},$u->{userid}); - $ret ||= 0; - warn "INFO: Updated primeur with $nu->{userid},$selectedrec->{modid},$u->{userid} and ret[$ret]"; - } elsif ($field eq "description") { - # Truncate if necessary, the database won't do it anymore - substr($param,44) = "" if length($param)>44; - } elsif ($field eq "chapterid") { - die "param not integer" if $strict_chapterid && - ($selectedrec->{$field} !~ /^\d*$/ || $param !~ /^\d*$/); - } - $mailblurb .= sprintf($mailsprintf1, - $field, - $param, - sprintf($mailsprintf2,$selectedrec->{$field}) - ); - - my $sql = qq{UPDATE mods - SET $field=?, - changed=?, - changedby=? - WHERE modid=?}; - - my $usth = $dbh->prepare($sql); - my $ret = $usth->execute($param, - $now, - $mgr->{User}{userid}, - $selectedrec->{modid}); - - $saw_a_change = 1 if $ret > 0; - $usth->finish; - - } else { - - if ($field eq "chapterid") { - die "illegal chapterid. selectedrec/field[$selectedrec->{$field}]". - "param[$param]" - if $strict_chapterid && - ($selectedrec->{$field} !~ /^\d*$/ || $param !~ /^\d*$/); - } - $mailblurb .= sprintf($mailsprintf1, - $field, - $selectedrec->{$field}, - "\n" - ); - } - } elsif ($is_only_one) { - # as if they had selected it already - $req->parameters->set($fieldname, $selectedrec->{$field}||""); - } - push @m_modrec, $mgr->$fieldtype( - 'name' => $fieldname, - 'value' => $selectedrec->{$field}, - %{$meta{$field}{args} || {}} - ); - push @m_modrec, qq{
\n}; - } - push @m_modrec, qq{
}; - - if ($saw_a_change) { - push @m, "

The record has been updated in the database

"; - $mailblurb .= qq{ -Data entered by $mgr->{User}{fullname} ($mgr->{User}{userid}). -Please check if they are correct. - -$Yours}; - push @to, $mgr->{User}{secretemail}||$mgr->{User}{email} - unless $mgr->{User}{userid} eq $u->{userid}; - warn sprintf "sending to[%s]", join(" AND ",@to); - warn "mailblurb[$mailblurb]"; - my $header = { - Subject => "Module update for $selectedrec->{modid}" - }; - $mgr->send_mail_multi(\@to, $header, $mailblurb); - } elsif ($update_sel) { # it should have been updated but wasn't? - - push @m, "It seems to me the record was NOT updated. Maybe - nothing has changed? Please take a closer look and inform an admin if - things didn't proceed as expected.
"; - - } - push @m, @m_modrec; - return @m; -} -sub edit_uris { - my pause_1999::edit $self = shift; - my $mgr = shift; - my(@m); - my $req = $mgr->{REQ}; - my $selectedid = ""; - my $selectedrec = {}; - if (my $param = $req->param("pause99_edit_uris_3")) { # upper selectbox - $selectedid = $param; - } - my $u = $self->active_user_record($mgr); - push @m, qq{}; - - push @m, qq{

for user $u->{userid}

}; - my $dbh = $mgr->connect; - my $sql = qq{SELECT uriid - FROM uris - WHERE dgot='' - AND userid=? - ORDER BY uriid}; - my $sth = $dbh->prepare($sql); - $sth->execute($u->{userid}); - my @all_recs; - my %labels; - if (my $rows = $sth->rows) { - my $sth2 = $dbh->prepare(qq{SELECT * - FROM uris - WHERE dgot='' - AND dverified='' - AND uriid=? - AND userid=?}); - while (my($id) = $mgr->fetchrow($sth, "fetchrow_array")) { - # register this mailinglist for the selectbox - push @all_recs, $id; - # query for more info about it - $sth2->execute($id,$u->{userid}); # really needed only for the - # record we want to edit, but - # maybe also needed for a - # label in the selectbox - my($rec) = $mgr->fetchrow($sth2, "fetchrow_hashref"); - # we will display the name along the ID - # $labels{$id} = "$id ($rec->{userid})"; - $labels{$id} = $id; # redundant, but flexible - if ($rows == 1 || $id eq $selectedid) { - # if this is the selected one, we just store it immediately - $selectedid = $id; - $selectedrec = $rec; - } - } - } else { - return "

No pending uploads for $u->{userid} found

"; - } - push @m, $mgr->scrolling_list( - 'name' => "pause99_edit_uris_3", - 'values' => \@all_recs, - 'labels' => \%labels, - 'size' => 1, - ); - push @m, qq{
}; - if ($selectedid) { - push @m, qq{

Record for $selectedrec->{uriid}

-}; - my @m_rec; - my $force_sel = $req->param('pause99_edit_uris_2'); - my $update_sel = $req->param('pause99_edit_uris_4'); - - my %meta = - ( - uri => - { - type => "textfield", - headline => "URI to download", - args => { - size => 60, - maxlength => 255, - }, - - note => qq{If you change this field to a different URI, - PAUSE will try to fetch this URI instead. Note that the - filename on PAUSE will remain unaltered. So you can fix a - typo, but you cannot alter the name of the uploaded file, it - will be the original filename. So this is only an opportunity - to fix broken uploads that cannot be completed, not an - opportunity to turn the time back. - -

To re-iterate: If you change the content of this field to - http://www.slashdot.org/, PAUSE will fetch the current - Slashdot page and will put it into - $selectedrec->{uriid}. If you change it to - FooBar-3.14.tar.gz, PAUSE will try to get - $PAUSE::Config->{INCOMING}/FooBar-3.14.tar.gz and if it - finds it, it puts it into $selectedrec->{uriid}.

- -

An example: if you made a typo and requested to upload - http://badsite.org/foo instead of - http://goodsite.org/foo, just correct the thing in the - textfield below.

- -

Another example: If your upload was unsuccessful and you now have - a bad file in the incoming directory, then you have the - problem that PAUSE tries to fetch your file (say foo) - but doesn't succeed and then it retries and retries. Your - solution: transfer the file into the incoming directory with - a different name (say bar) using ftp. Fill in - the different name below. PAUSE will fetch bar and - upload it as foo. So you're done.

} - - }, - nosuccesstime => { - - headline => "UNIX time of last - unsuccessful attempt to retrieve - this item", - - }, - nosuccesscount => { - - headline=>"Number of unsuccessful - attempts so far", - - }, - changed => { - headline => "Record was last changed on", - }, - changedby => { - headline => "Record was last changed by", - }, - ); - my $mailblurb = qq{Record update in the PAUSE uploads database: - -}; - my($mailsprintf1,$mailsprintf2,$saw_a_change); - $mailsprintf1 = "%12s: [%s]%s"; - $mailsprintf2 = " was [%s]\n"; - my $now = time; - $mailblurb .= sprintf($mailsprintf1, "uriid", $selectedrec->{uriid}, "\n"); - - for my $field (qw( -uri -nosuccesstime -nosuccesscount -changed -changedby -)) { - my $headline = $meta{$field}{headline} || $field; - my $note = $meta{$field}{note} || ""; - push @m_rec, qq{

$headline

}; - push @m_rec, qq{$note
} if $note; - my $fieldtype = $meta{$field}{type}; - my $fieldname = "pause99_edit_uris_$field"; - if ($force_sel) { - $req->parameters->set($fieldname, $selectedrec->{$field}||""); - } elsif ($update_sel && $fieldtype) { - my $param = $req->param($fieldname); - if ($param ne $selectedrec->{$field}) { - $mailblurb .= sprintf($mailsprintf1, - $field, - $param, - sprintf($mailsprintf2,$selectedrec->{$field}) - ); - - # no, we do not double check for user here. What if they - # change the owner? And we do not prepare outside the loop - # because the is a $fields in there - my $sql = qq{UPDATE uris - SET $field=?, - changed=?, - changedby=? - WHERE uriid=?}; - - my $usth = $dbh->prepare($sql); - my $ret = $usth->execute($param, - $now, - $u->{userid}, - $selectedrec->{uriid}); - - $saw_a_change = 1 if $ret > 0; - $usth->finish; - - } else { - $mailblurb .= sprintf($mailsprintf1, $field, $selectedrec->{$field}, "\n"); - } - } - if ($fieldtype) { - warn "fieldtype[$fieldtype]fieldname[$fieldname]field[$field]rec->{field}[$selectedrec->{$field}]"; - push @m_rec, $mgr->$fieldtype( - 'name' => $fieldname, - 'value' => $selectedrec->{$field}, - %{$meta{$field}{args} || {}} - ); - } else { - # not editable fields - push @m_rec, sprintf "%s
\n", $selectedrec->{$field}||0; - } - push @m_rec, qq{
\n}; - } - push @m_rec, qq{
}; - - if ($saw_a_change) { - push @m, "

The record has been updated in the database

"; - $mailblurb .= qq{ -Data entered by $mgr->{User}{fullname} ($mgr->{User}{userid}). -Please check if they are correct. - -$Yours}; - my @to = ($u->{secretemail}||$u->{email}, $mgr->{MailtoAdmins}); - push @to, $mgr->{User}{secretemail}||$mgr->{User}{email}; - warn "sending to[@to]"; - warn "mailblurb[$mailblurb]"; - my $header = { - Subject => "Uri update for $selectedrec->{uriid}" - }; - $mgr->send_mail_multi(\@to,$header,$mailblurb); - } elsif ($update_sel) { # it should have been updated but wasn't? - push @m, "It seems to me the record was NOT updated. Maybe nothing has changed? - Please take a closer look and - inform an admin if things didn't proceed as expected.
"; - } - push @m, @m_rec; - } - @m; -} - -sub show_ml_repr { - my pause_1999::edit $self = shift; - my $mgr = shift; - my(@m); - my $dbh = $mgr->connect; - my $sth = $dbh->prepare("SELECT maillistid, userid - FROM list2user - ORDER BY maillistid, userid"); - $sth->execute; - - push @m, qq{

These are the contents of the table list2user. - There\'s currently no way to edit the table except - direct SQL. The table says who is representative of a - mailing list.

}; - - push @m, qq{ - -\n}; - while (my $rec = $mgr->fetchrow($sth, "fetchrow_hashref")) { - push @m, sprintf( - qq{\n}, - $rec->{maillistid}, - $rec->{userid}, - ); - } - $sth->finish; - push @m, qq{
Mailing listUser-ID
%s%s
\n}; - @m; -} - - - -sub add_mod { - my pause_1999::edit $self = shift; - my $mgr = shift; - my(@m); - my $req = $mgr->{REQ}; - - my $dbh = $mgr->connect; - local($dbh->{RaiseError}) = 0; - - my %meta = ($self->modid_meta, - $self->chap_meta($mgr), - $self->stat_meta, - $self->desc_meta, - $self->user_meta($mgr)); - - $meta{modid}{note} = qq{Modulename or a complete line in module list - format. The latter is only valid for the - guess button.}; - - $meta{comment} = { - type => "textarea", - note => "only for the mail, not for the database", - args => { - rows => 5, - cols => 60, - } - }; - - if ($req->param("USERID")) { - my $session = $mgr->session; - my $s = $session->{APPLY}; - for my $a (keys %$s) { - $req->parameters->set("pause99_add_mod_$a", $s->{$a}); - warn "retrieving from session a[$a]s(a)[$s->{$a}]"; - } - } - - my @errors = (); - my @hints = (); - my($guessing,$modid); - if ( $req->param("SUBMIT_pause99_add_mod_hint") ) { - $guessing++; - my $wanted = {}; - $self->_add_mod_hint($mgr, $wanted, $dbh, \@hints); - $modid = $wanted->{modid}; - } elsif ( $req->param("SUBMIT_pause99_add_mod_insertit") ) { - - $modid = $req->param('pause99_add_mod_modid')||""; - if ($modid =~ /([^A-Za-z0-9_\:])/) { - my $illegal = ord($1); - push @errors, sprintf(qq{The module name contains the illegal character 0x%x. - Please correct and retry.}, #}, - $illegal); # - } - unless (length($modid)) { - push @errors, qq{The module name is missing.}; - } - # $req->parameters->set("pause99_add_mod_modid", $modid) if $modid; - - my($chapterid) = $req->param('pause99_add_mod_chapterid'); - warn "chapterid[$chapterid]"; - die "chapterid not integer" if $strict_chapterid && $chapterid !~ /^\d*$/; - warn "chapterid[$chapterid]"; - unless ($meta{chapterid}{args}{labels}{$chapterid}) { - push @errors, qq{The chapterid [$chapterid] is not known.}; - } - die "chapterid not integer" if $strict_chapterid && $chapterid !~ /^\d*$/; - warn "chapterid[$chapterid]"; - - my($statd) = $req->param('pause99_add_mod_statd'); - $req->parameters->set('pause99_add_mod_statd',$statd='?') unless $statd; - unless ($meta{statd}{args}{labels}{$statd}) { - push @errors, qq{The D status of the DSLIP [$statd] is not known.}; - } - - my($stats) = $req->param('pause99_add_mod_stats'); - $req->parameters->set('pause99_add_mod_stats',$stats='?') unless $stats; - unless ($meta{stats}{args}{labels}{$stats}) { - push @errors, qq{The S status of the DSLIP [$stats] is not known.}; - } - - my($statl) = $req->param('pause99_add_mod_statl'); - $req->parameters->set('pause99_add_mod_statl',$statl='?') unless $statl; - unless ($meta{statl}{args}{labels}{$statl}) { - push @errors, qq{The L status of the DSLIP [$statl] is not known.}; - } - - my($stati) = $req->param('pause99_add_mod_stati'); - $req->parameters->set('pause99_add_mod_stati',$stati='?') unless $stati; - unless ($meta{stati}{args}{labels}{$stati}) { - push @errors, qq{The I status of the DSLIP [$stati] is not known.}; - } - - my($statp) = $req->param('pause99_add_mod_statp'); - $req->parameters->set('pause99_add_mod_statp',$statp='?') unless $statp; - unless ($meta{statp}{args}{labels}{$statp}) { - # XXX for the first few weeks we allow statp to be empty - # push @errors, qq{The P status of the DSLIP [$statp] is not known.}; - } - - # must be treated as utf8 - my($description) = $req->param('pause99_add_mod_description')||""; - my $ud = $mgr->any2utf8($description); - if ($ud ne $description) { - $req->parameters->set('pause99_add_mod_description',$ud); - $description = $ud; - } - $description =~ s/^\s+//; - $description =~ s/\s+\z//; - if (length($description)>44) { - substr($description,44) = ''; - push @errors, qq{The description was too long and had to be truncated.}; - } elsif (not length($description)) { - push @errors, qq{The description is missing.}; - } - $req->parameters->set("pause99_add_mod_description", $description) if $description; - - my($userid) = $req->param('pause99_add_mod_userid'); - unless ($meta{userid}{args}{labels}{$userid}) { - push @errors, qq{The userid [$userid] is not known.}; - } - - goto FORMULAR if @errors; - - my(@to,$subject,@blurb,$query,$sth,@qvars,@qbind); - my $time = time; - - @qvars = qw( modid statd stats statl stati statp - description userid - chapterid introduced changed changedby ); - - @qbind = ( $modid, $statd, $stats, $statl, $stati, $statp, - $description, $userid, - $chapterid, $time, $time, $mgr->{User}{userid} ); - - $query = qq{INSERT INTO mods \(} . - join(", ", @qvars) . - qq{\) VALUES \(} . join(",",map {qq{?}} @qbind) . qq{)}; - - push @m, qq{Submitting query: }; - if (0) { # too noisy for my taste - push @m, qq{$query
- - -}; - for my $i (0..$#qvars) { - push @m, qq{\n}; - } - push @m, qq{
parambindvalue
}, $mgr->escapeHTML($qvars[$i]), - qq{}, $mgr->escapeHTML($qbind[$i]), qq{
\n}; - } - - unless ($dbh->do($query,undef,@qbind)) { - my $err = $dbh->errstr; - if ($err =~ /duplicate/i) { - $sth = $dbh->prepare("SELECT userid - FROM mods - WHERE modid=?"); - $sth->execute($modid); - my $otheruser = $mgr->fetchrow($sth, "fetchrow_array"); - my $url = "authenquery?ACTION=edit_mod;pause99_edit_mod_modid=$modid;HIDDENNAME=$otheruser"; - push @errors, qq{$err -- - Do you want to edit $modid instead?}; - } else { - push @errors, $err; - } - goto FORMULAR; - } - push @m, qq{Query succeeded.}; - - @to = $mgr->{MailtoAdmins}; - my $userobj = $self->active_user_record($mgr,$userid); - # The logic for sending mail up to version 1.144 made - # replying difficult. That's why we change that after 1.144 - - # New logic: public address might be fake. We send to secret or - # public email separately if we need to, otherwise we send to - # userid@cpan.org. But there is a time gap between this database - # and cpan.org's database. - if ($userobj->{cpan_mail_alias} =~ /^(publ|secr)$/ - && - time - ($userobj->{introduced}||0) > 86400 - ) { - $to[0] .= sprintf ",%s\@cpan.org", lc $userid; - push @m, qq{ Sending mail to: @to}; - } else { - # we have nothing else, so we must send separate mail - my $user_email = $userobj->{secretemail}; - $user_email ||= $userobj->{email}; - push @to, $user_email if $user_email; - push @m, qq{ Sending separate mails to: }, join(" AND ", - map { "[$_]" } @to); - } - - my $user_fullname = $userobj->{fullname}; - - my $chap_shorttitle = "???"; - $sth = $dbh->prepare("SELECT shorttitle - FROM chapters - WHERE chapterid=?"); - warn "chapterid[$chapterid]"; - $sth->execute($chapterid); - warn "chapterid[$chapterid]"; - if ($sth->rows == 1) { - $chap_shorttitle = $mgr->fetchrow($sth, "fetchrow_array"); - $chap_shorttitle = substr($chap_shorttitle,3) if $chap_shorttitle =~ /^\d/; - } else { - warn "ALERT: could not find chaptertitle"; - } - - my $gmtime = gmtime($time) . " UTC"; - - # as string - # sprintf "%-$Modlist::GLOBAL->{WIDTH_COL1WRITE}s%s%s%s%s %-45s%-${filler}s %s", @{$self}[2..9]; # 15/16 - # as HTML - # sprintf "%-$Modlist::GLOBAL->{WIDTH_COL1WRITE}s%s%s%s%s %-45s", @{$self}[2..7]; - - my($mdirname,$mbasename) = $modid =~ /^(.+::)([^:]+)$/; - $mdirname ||= ""; - $mbasename ||= $modid; - my $modwidth = $mdirname ? 15 : 17; # for the two colons - $mdirname .= "\n::" if $mdirname; - my $ml_entry = sprintf(("%s%-".$modwidth."s %s%s%s%s%s %-44s %s\n"), - $mdirname, $mbasename, $statd, $stats, $statl, $stati, $statp, - $description, $userid); - my $server = $PAUSE::Config->{SERVER_NAME}; # XXX: $r->server->server_hostname - - my $comment = $req->param("pause99_add_mod_comment") || ""; - if ($comment) { - # Don't wrap it, this is written by us. - # Don't escape it, it's for mail - $comment = sprintf "\n%s comments:\n%s\n--\n", - $mgr->{User}{userid}, $comment; - } - - $subject = qq{New module $modid}; - @blurb = qq{ -The next version of the Module List will list the following module: - - modid: $modid - DSLIP: $statd$stats$statl$stati$statp - description: $description - userid: $userid ($user_fullname) - chapterid: $chapterid ($chap_shorttitle) - enteredby: $mgr->{User}{userid} ($mgr->{User}{fullname}) - enteredon: $gmtime - -The resulting entry will be: - -$ml_entry$comment -Please allow a few days until the entry will appear in the published -module list. - -Parts of the data listed above can be edited interactively on the -PAUSE. See https://$server/pause/authenquery?ACTION=edit_mod - -Thanks for registering, --- -The PAUSE Team -}; - - my($blurb) = join "", @blurb; - require HTML::Entities; - my($blurbcopy) = HTML::Entities::encode($blurb,"<>&"); - warn "DEBUG: UPLOAD[$PAUSE::Config->{UPLOAD}]"; - push @m, qq{
-From: $PAUSE::Config->{UPLOAD}
-Subject: $subject
-
-$blurbcopy
-
-}; - warn "blurb[$blurb]"; - - my $header = { - Subject => $subject - }; - warn "To[@to]Subject[$header->{Subject}]"; - $mgr->send_mail_multi(\@to, $header, $blurb); - } else { - $modid = $req->param('pause99_add_mod_modid')||""; - } - if ($modid) { - - # http://www.xray.mpe.mpg.de/cgi-bin/w3glimpse/modules?query=LibWeb%3A%3ACore&errors=0&case=on&maxfiles=100&maxlines=30 - # xray does not allow semicolons instead of ampersands, so we have - # to do some extra escaping - my $emodid = URI::Escape::uri_escape($modid,'\W'); - my $query = join( - "&", - "query=$emodid", - "error=0", - "case=on", - "maxfiles=100", - "maxlines=30" - ); - my $uri = "http://www.xray.mpe.mpg.de/cgi-bin/w3glimpse/modules?" . $query; - push @m, sprintf qq{Search for %s at xray
}, $uri, $modid; - warn "uri[$uri]modid[$modid]"; - } else { - warn "DEBUG: No modid"; - } - - FORMULAR: - my @formfields = qw( modid chapterid statd stats statl stati statp - description userid comment ); - if (@errors) { - push @m, qq{

ERROR: - The submission was rejected due to the following:

}; - push @m, join("\n", map { "

$_

" } @errors); - - push @m, qq{

Nothing done. Please correct the form below - and retry.


}; - - } elsif ($guessing) { - # Nothing to do here, I suppose - } elsif ($req->param("SUBMIT_pause99_add_mod_preview")) { - # Currently it is always eq "preview", but we do not check that. - # Nothing to do here, they said so. Used in CPAN::Admin. Undocumented! - } else { - # As we have had so much success, there is no point in leaving the - # form filled - # warn "clearing all fields"; - for my $field (@formfields) { - my $param = "pause99_add_mod_$field"; - # there must be a more elegant way to specify empty list for - # chapterid. If I knew, which, the setting of 99 would be - # triggered later on. I would believe. - if ($req->param($param)){ - if ($param =~ /_chapterid$/) { - $req->parameters->set($param,""); - } elsif ($param =~ /_stat.$/) { - $req->parameters->set($param,"?"); - } else { - $req->parameters->set($param,""); - } - } - } - } - - my $submit_butts = $mgr->submit( - name=>"SUBMIT_pause99_add_mod_insertit", - value=>" Submit to database ", - ); - my $hint_butt = $mgr->submit( - name=>"SUBMIT_pause99_add_mod_hint", - value=>" Guess the rest without submitting ", - ); - if ($req->param("pause99_add_mod_userid")) { - # Easier to spot, harder to browse on Netscape - # $meta{userid}{args}{size} = 1; - - # Yet better, much less bandwidth: - $meta{userid}{type} = "textfield"; - $meta{userid}{headline} = "userid"; - $meta{userid}{args}{size} = 12; - $meta{userid}{args}{maxlength} = 9; - } - push @m, qq{
}; - push @m, $submit_butts; - push @m, qq{
}; - for my $field (@formfields){ - my $headline = $meta{$field}{headline} || $field; - my $note = $meta{$field}{note} || ""; - push @m, qq{

$headline

}; - push @m, qq{

$note

} if $note; - my $fieldtype = $meta{$field}{type} or die "empty fieldtype"; - my $fieldname = "pause99_add_mod_$field"; - # warn sprintf "field[%s]value[%s]", $field, $req->param($fieldname); - if ($field eq "chapterid") { - my $val = $req->param($fieldname); - die "chapterid not integer" if $strict_chapterid && $val !~ /^\d*$/; - } - push @m, $mgr->$fieldtype( - 'name' => $fieldname, - %{$meta{$field}{args} || {}} - ); - if ($field eq "modid") { - push @m, qq{
}; - if (@hints) { - push @m, qq{}; - for (@hints) { - push @m, qq{\n}; - } - push @m, qq{
$_
\n
}; - } - push @m, $hint_butt; - push @m, qq{
\n}; - } - } - push @m, qq{
}; - push @m, $submit_butts; - return @m; -} - -sub _add_mod_hint { - my($self, $mgr, $wanted, $dbh, $hints) = @_; - my($dsli,@desc); - my $req = $mgr->{REQ}; - ($wanted->{modid},$dsli,@desc) = split /\s+/, $req->param("pause99_add_mod_modid"); - - my $userid = pop @desc; - my $sth_mods = $dbh->prepare(qq{SELECT * FROM mods WHERE modid=?}); - $sth_mods->execute($wanted->{modid}); - - if ($sth_mods->rows > 0) { - my $rec = $mgr->fetchrow($sth_mods, "fetchrow_hashref"); - my $userid = $rec->{userid}; - push @$hints, "$wanted->{modid} is registered in the module list by $userid. "; - } else { - push @$hints, "$wanted->{modid} is not registered in the module list. "; - } - - my $sth = $dbh->prepare(qq{SELECT * FROM packages - WHERE package=?}); - $sth->execute($wanted->{modid}); - - if ($userid) { - warn "userid[$userid]"; - # XXX check if user exists, and if not, suggest alternatives - } else { - # XXX check if somebody has already uploaded the module and if - # so, tell the user. Link to readme. - my $rows = $sth->rows; - warn "rows[$rows]"; - if ($rows > 0) { - my $rec = $mgr->fetchrow($sth, "fetchrow_hashref"); - my $dist = $rec->{dist}; - my $readme = $dist; - $readme =~ s/(\.tar[._-]gz|\.tar.Z|\.tgz|\.zip)$/.readme/; - $userid = $mgr->file_to_user($dist); - - push @$hints, qq{Dist $dist, current version - $rec->{version} has been uploaded by $userid. - Try the readme.} - - } - } - $sth->finish; - - # guess the chapter, code also found in mldistwatch - my($root) = $wanted->{modid} =~ /^([^:]+)/; - - $sth = $dbh->prepare("SELECT chapterid - FROM mods - WHERE modid = ?"); - $sth->execute($root); - my $chapterid; - if ($sth->rows == 1) { - $chapterid = $mgr->fetchrow($sth, "fetchrow_array"); - } else { - $sth = $dbh->prepare(qq{SELECT chapterid - FROM mods - WHERE modid LIKE ?}); - - $sth->execute("$root\::%"); - $chapterid = $mgr->fetchrow($sth, "fetchrow_array"); - } - - warn "chapterid[$chapterid]"; - $req->parameters->set("pause99_add_mod_modid",$wanted->{modid}); - my(@dsli) = $dsli =~ /(.?)(.?)(.?)(.?)(.?)/; - $req->parameters->set("pause99_add_mod_statd",$dsli[0]||"?"); - $req->parameters->set("pause99_add_mod_stats",$dsli[1]||"?"); - $req->parameters->set("pause99_add_mod_statl",$dsli[2]||"?"); - $req->parameters->set("pause99_add_mod_stati",$dsli[3]||"?"); - $req->parameters->set("pause99_add_mod_statp",$dsli[4]||"?"); - my $description = join " ", @desc; - $description ||= ""; - $req->parameters->set("pause99_add_mod_description",$description); - $chapterid ||= ""; - warn "chapterid[$chapterid]"; - $req->parameters->set("pause99_add_mod_chapterid",$chapterid); - $req->parameters->set("pause99_add_mod_userid",$userid); -} - -sub apply_mod { - my pause_1999::edit $self = shift; - my $mgr = shift; - $mgr->prefer_post(1); - my(@m); - my $req = $mgr->{REQ}; - $mgr->{CAN_GZIP} = 0; # for debugging - my $u = $self->active_user_record($mgr); - push @m, qq{}; - if ($mgr->{User}{userid} ne $u->{userid}) { - push @m, qq{

Applying in the name of $u->{userid}

\n}; - } - - my $dbh = $mgr->connect; - my $sth; - local($dbh->{RaiseError}) = 0; - - my %meta = ($self->modid_meta, - $self->chap_meta($mgr), - $self->stat_meta, - $self->desc_meta); - - $meta{modid}{note} = "Please try to suggest a nested namespace that - is based on an existing root namespace. New - entries to the root namespace are less likely - to be approved."; - - $meta{chapfirm} = { - headline => "Do you really want this chapterid?", - type => "checkbox", - }; - $meta{similar} = { - - headline => "Modules with similar functionality", - type => "textfield", - - note => "If any related modules already exist on - CPAN, please let us know and discuss the - relation between your module and these - already existing modules below. Enter - just the module names, separated by - whitespace.", - - args => { - size => 60, - } - - }; - $meta{communities} = { - headline => "Places where this module has been or will be discussed publicly", - note => "Mailinglists, newsgroups, chatrooms, CVS repository, etc.", - type => "textfield", - args => { - size => 60, - } - - }; - $meta{rationale} = { - headline => "Rationale", - type => "textarea", - - note => "Please discuss your reasoning about the - namespace choice, the uniqueness of your - approach and why you believe this module - should be listed in the module list. - Especially if you suggest a new rootlevel - namespace you are required to argue why this - new namespace is necessary.", - - args => { - rows => 15, - cols => 60, - } - }; - - my @errors = (); - my @hints = (); - my $applying_userid = $u->{userid}; - my($chap_confirm,$modid); - if ( $req->param("SUBMIT_pause99_apply_mod_send") ) { - my($modid,$root,@appropriate_chapterid); - if (length($modid = $req->param("pause99_apply_mod_modid"))) { - if ($modid =~ /([^A-Za-z0-9_\:])/) { - my $illegal = ord($1); - push @errors, sprintf(qq{The module name contains the illegal character 0x%x. - Please correct and retry.}, #}, - $illegal); - } elsif ($modid !~ /^[A-Za-z]/) { - push @errors, qq{The module name doesn't start with a letter. - Please correct and retry.}; - } elsif ($modid !~ /[A-Za-z0-9]\z/) { - push @errors, qq{The module name doesn't end with a letter or digit. - Please correct and retry.}; - } - - $sth = $dbh->prepare(qq{SELECT * FROM mods - WHERE modid=?}); - $sth->execute($modid); - if ($sth->rows) { - my $modrec = $mgr->fetchrow($sth, "fetchrow_hashref"); - push @errors, qq{Module $modid has already been registered by $modrec->{userid}.}; -# with the modulelist line
-#
$mlline
}; - } - - $sth = $dbh->prepare(qq{SELECT * FROM packages - WHERE package=?}); - $sth->execute($modid); - - # XXX check if somebody has already uploaded the module and if - # so, tell the user. Link to readme. - - # XXX nonono, we should rather check the perms, not the uploads. - # If somebody else has first come rights we must reject - # everything now. If this user has first come rights we can - # auto-register immediately (unless other errors occur, maybe - # even a root namespace should be rejected). Only if nobody has - # first come rights we shall proceed with the application. - my $rows = $sth->rows; - if ($rows > 0) { - my $rec = $mgr->fetchrow($sth, "fetchrow_hashref"); - my $dist = $rec->{dist}; - my $registered_userid = $mgr->file_to_user($dist); - - if ($applying_userid eq $registered_userid) { - if ($PAUSE::Config->{AUTO_REGISTER_FOR_FIRST_COME}) { - # examine the perms of this user now if he is first-come, - # set something so that we do not even send a mail and - # promote/upgrade him to state "module list" right away. - } - } else { - push @errors, qq{Dist $dist, current version - $rec->{version} has been uploaded by $registered_userid. - Please contact $registered_userid or choose a different namespace.}; - } - } - $sth->finish; - - # guess the chapter, code also found in mldistwatch - ($root) = $modid =~ /^([^:]+)/; - warn "root[$root]"; - $sth = $dbh->prepare("SELECT chapterid - FROM mods - WHERE modid = ? OR modid LIKE ?"); - $sth->execute($root, "$root\::%"); - my(%appr); - if ($sth->rows) { - while (my $chid = $mgr->fetchrow($sth, "fetchrow_array")) { - $appr{$chid} = undef; - } - @appropriate_chapterid = keys %appr; - } - - - } else { - push @errors, qq{No module name chosen. You need to supply a module name.}; - } - - my($chapterid) = $req->param('pause99_apply_mod_chapterid'); - die "chapterid not numeric" if $strict_chapterid && $chapterid !~ /^\d*$/; - warn "appropriate_chapterid[@appropriate_chapterid]"; - my($chap_confirmed) = $req->param('pause99_apply_mod_chapfirm'); - if (!$chapterid) { - push @errors, qq{No chapter given.}; - } elsif ( ! @appropriate_chapterid) { - # That's OK, a new rootnamespace - } elsif (! $self->is_subset($chapterid,\@appropriate_chapterid)){ - $chap_confirm++; - unless ( $chap_confirmed ) { - my $plural = @appropriate_chapterid>1 ? "s" : ""; - my $chlist = @appropriate_chapterid>1 ? - $self->verbose_list(@appropriate_chapterid) : $appropriate_chapterid[0]; - - push @errors, sprintf(qq{Module rootnamespace %s doesn\'t - match chapter. %s is already registered - in the chapter%s %s. If you really believe that - it belongs to chapter %s too, please turn on the - small checkbox next to the chapterselection.}, - - $root, - $root, - $plural, - $chlist, - $chapterid - ); - } - } - - my($statd) = $req->param('pause99_apply_mod_statd'); - $req->parameters->set('pause99_apply_mod_statd',$statd='?') unless $statd; - if ($statd eq '?') { - push @errors, qq{The D status of the DSLIP [$statd] is not known.}; - } - - my($stats) = $req->param('pause99_apply_mod_stats'); - $req->parameters->set('pause99_apply_mod_stats',$stats='?') unless $stats; - if ($stats eq '?') { - push @errors, qq{The S status of the DSLIP [$stats] is not known.}; - } - - my($statl) = $req->param('pause99_apply_mod_statl'); - $req->parameters->set('pause99_apply_mod_statl',$statl='?') unless $statl; - if ($statl eq "?") { - push @errors, qq{The L status of the DSLIP [$statl] is not known.}; - } - - my($stati) = $req->param('pause99_apply_mod_stati'); - $req->parameters->set('pause99_apply_mod_stati',$stati='?') unless $stati; - if ($stati eq "?") { - push @errors, qq{The I status of the DSLIP [$stati] is not known.}; - } - - my($statp) = $req->param('pause99_apply_mod_statp'); - $req->parameters->set('pause99_apply_mod_statp',$statp='?') unless $statp; - if ($statp eq "?") { - push @errors, qq{The P status of the DSLIP [$statp] is not known.}; - } - - # must be treated as utf8 - my($description) = $req->param('pause99_apply_mod_description')||""; - my $ud = $mgr->any2utf8($description); - if ($ud ne $description) { - $req->parameters->set('pause99_apply_mod_description',$ud); - $description = $ud; - } - $description =~ s/^\s+//; - $description =~ s/\s+\z//; - if (length($description)>44) { - substr($description,44) = ''; - push @errors, qq{The description was too long and had to be truncated.}; - } elsif (not length($description)) { - push @errors, qq{The description is missing.}; - } - $req->parameters->set("pause99_apply_mod_description", $description) if $description; - - goto FORMULAR2 if @errors; - - my(@to,$subject,@blurb,$query,$sth,@qvars,@qbind); - my $time = time; - - @to = $mgr->{MailtoAdmins}; - my $userobj = $self->active_user_record($mgr,$applying_userid); - - if ($userobj->{cpan_mail_alias} =~ /^(publ|secr)$/ - && - time - ($userobj->{introduced}||0) > 86400 - ) { - $to[0] .= sprintf ",%s\@cpan.org", lc $applying_userid; - push @m, qq{ Sending mail to: @to}; - } else { - my $user_email = $userobj->{secretemail}; - $user_email ||= $userobj->{email}; - push @to, $user_email if $user_email; - push @m, qq{ Sending separate mails to: }, join(" AND ", - map { "[$_]" } @to); - } - - my $user_fullname = $userobj->{fullname}; - - my $chap_shorttitle = "???"; - $sth = $dbh->prepare("SELECT shorttitle - FROM chapters - WHERE chapterid=?"); - $sth->execute($chapterid); - if ($sth->rows == 1) { - $chap_shorttitle = $mgr->fetchrow($sth, "fetchrow_array"); - $chap_shorttitle = substr($chap_shorttitle,3) if $chap_shorttitle =~ /^\d/; - } else { - warn "ALERT: could not find chaptertitle"; - } - - my $gmtime = gmtime($time) . " UTC"; - - my($mdirname,$mbasename) = $modid =~ /^(.+::)([^:]+)$/; - $mdirname ||= ""; - $mbasename ||= $modid; - my $modwidth = $mdirname ? 15 : 17; # for the two colons - $mdirname .= "\n::" if $mdirname; - my $ml_entry = sprintf(("%s%-".$modwidth."s %s%s%s%s%s %-44s %s\n"), - $mdirname, $mbasename, $statd, $stats, $statl, $stati, $statp, - $description, $applying_userid); - my $server = $PAUSE::Config->{SERVER_NAME}; # XXX: $r->server->server_hostname - - my $rationale = $req->param("pause99_apply_mod_rationale") || ""; - if ($rationale) { - # wrap it - $rationale =~ s/\r\n/\n/g; - $rationale =~ s/\r/\n/g; - my @rat = split /\n\n/, $rationale; - my $tf = Text::Format->new( bodyIndent => 4, firstIndent => 5); - $rationale = $tf->paragraphs(@rat); - $rationale =~ s/^\s{5}/\n /gm; - } - my $similar = $req->param("pause99_apply_mod_similar") || ""; - if ($similar) { - # wrap it - my $tf = Text::Format->new( bodyIndent => 4, firstIndent => 4); - $similar = $tf->format($similar); - } - my $communities = $req->param("pause99_apply_mod_communities") || ""; - if ($communities) { - # wrap it - my $tf = Text::Format->new( bodyIndent => 4, firstIndent => 4); - $communities = $tf->format($communities); - } - - my $session = $mgr->session; - $session->{APPLY} = { - modid => $modid, - statd => $statd, - stats => $stats, - statl => $statl, - stati => $stati, - statp => $statp, - description => $description, - userid => $applying_userid, - chapterid => $chapterid, - }; - my $sessionID = $mgr->userid; - $subject = qq{Module submission $modid}; - my $urlenc_module = URI::Escape::uri_escape($modid,'\W'); - @blurb = qq{ -The following module was proposed for inclusion in the Module List: - - modid: $modid - DSLIP: $statd$stats$statl$stati$statp - description: $description - userid: $applying_userid ($user_fullname) - chapterid: $chapterid ($chap_shorttitle) - communities: -$communities - similar: -$similar - rationale: -$rationale - enteredby: $mgr->{User}{userid} ($mgr->{User}{fullname}) - enteredon: $gmtime - -The resulting entry would be: - -$ml_entry - -Thanks for registering, --- -The PAUSE Team - -PS: The following links are only valid for module list maintainers: - -Registration form with editing capabilities: - https://pause.perl.org/pause/authenquery?ACTION=add_mod&USERID=$sessionID&SUBMIT_pause99_add_mod_preview=1 -Immediate (one click) registration: - https://pause.perl.org/pause/authenquery?ACTION=add_mod&USERID=$sessionID&SUBMIT_pause99_add_mod_insertit=1 -Peek at the current permissions: - https://pause.perl.org/pause/authenquery?pause99_peek_perms_by=me&pause99_peek_perms_query=$urlenc_module -}; - - my($blurb) = join "", @blurb; - require HTML::Entities; - my($blurbcopy) = HTML::Entities::encode($blurb,"<>&"); - $blurbcopy =~ s|(https?://[^\s\"]+)|$1|g; - $blurbcopy =~ s|(>http.*?)U|$1\n U|gs; # break the long URL - # warn "DEBUG: UPLOAD[$PAUSE::Config->{UPLOAD}]"; - push @m, qq{
-From: $PAUSE::Config->{UPLOAD}
-Subject: $subject
-
-$blurbcopy
-
-
-}; - warn "blurb[$blurb]"; - - my $header = { - Subject => $subject - }; - warn "To[@to]Subject[$header->{Subject}]"; - $mgr->send_mail_multi(\@to, $header, $blurb); - } else { - $modid = $req->param('pause99_apply_mod_modid')||""; - } - - push @m, qq{

Please use this form to apply for the registration of - a namespace for a module you have written or are going - to write. The request will be sent off to the - modules\@perl.org people who are maintaining the Modules - List. A registration is not a prerequisite for - uploading. It is just recommended for better - searchability of the CPAN and to avoid namespace - clashes. You will be notified when the registration is - approved but you can upload immediately, there's no need - to wait for an approval. On the contrary, you are - encouraged to upload immediately.

If you are - facing any problems with this form, please report to - modules\@perl.org.
Thank you for - registering.


}; - - - FORMULAR2: - my @formfields = qw( modid chapterid chapfirm statd stats statl stati statp - description communities similar rationale ); - if (@errors) { - my $plural = @errors > 1 ? "s" : ""; - push @m, qq{

ERROR: - The submission didn't succeed due to the following reason$plural:

}; - push @m, join("\n", map { "

$_

" } @errors); - - push @m, qq{

Nothing done. Please correct the form below - and retry.


}; - - } elsif ($req->param("SUBMIT_pause99_apply_mod_preview")) { - # Currently it is always eq "preview", but we do not check that. - # Nothing to do here, they said so. Used in CPAN::Admin. Undocumented! - } else { - # As we have had so much success, there is no point in leaving the - # form filled - # warn "clearing all fields"; - for my $field (@formfields) { - my $param = "pause99_apply_mod_$field"; - # there must be a more elegant way to specify empty list for - # chapterid. If I knew, which, the setting of 99 would be - # triggered later on. I would believe. - if ($req->param($param)){ - if ($param =~ /chapterid/) { - $req->parameters->set($param,""); - } else { - $req->parameters->set($param,""); - } - } - } - } - - my $submit_butts = $mgr->submit( - name=>"SUBMIT_pause99_apply_mod_send", - value=>" Submit to modules\@perl.org ", - ); - push @m, qq{
}; - for my $field (@formfields){ - next if $field eq "chapfirm" && ! $chap_confirm; - my $headline = $meta{$field}{headline} || $field; - my $note = $meta{$field}{note} || ""; - push @m, qq{

$headline

}; - push @m, qq{

$note

} if $note; - push @m, qq{

}; - my $fieldtype = $meta{$field}{type} or die "empty fieldtype"; - my $fieldname = "pause99_apply_mod_$field"; - push @m, $mgr->$fieldtype( - 'name' => $fieldname, - %{$meta{$field}{args} || {}} - ); - push @m, qq{

\n}; - } - push @m, qq{
}; - push @m, $submit_butts; - return @m; -} - -sub is_subset { - my($self, $item, $arr) = @_; - for my $i (@$arr) { - return 1 if $i eq $item; - } - return; -} - -sub verbose_list { - my($self,@arr) = @_; - my $result; - return unless @arr; - if (@arr > 2) { - $result = join ", ", @arr[0..$#arr-1]; - $result .= ", and $arr[-1]"; - } elsif (@arr > 1) { - $result = "$arr[0] and $arr[1]"; - } else { - $result = $arr[0]; - } - $result; -} - -sub stat_meta { - my($deftype) = "scrolling_list"; # or "radio_group"; - my(%statd,%stats,%statl,%stati,%statp,@statd,@stats,@statl,@stati,@statp); - @statd{@statd = qw(i c a b R M S ?)} = qw( idea pre-alpha - alpha beta released mature standard unknown); - @stats{@stats = qw(d m u n a ?)} = qw( - developer mailing-list comp.lang.perl.* none abandoned unknown); - @statl{@statl = qw(p c + o h ?)} = qw( perl C C++ other hybrid unknown); - @stati{@stati = qw(f r O p h n ?)} = qw( functions - references+ties object-oriented pragma hybrid none unknown ); - @statp{@statp = qw(p g l b a 2 o d r n ?)} = qw( Standard-Perl - GPL LGPL BSD Artistic Artistic_2 open-source distribution_allowed - restricted_distribution no_licence unknown ); - - for my $hash (\%statd,\%stats,\%statl,\%stati,\%statp) { - for my $k (keys %$hash) { - $hash->{$k} = $deftype =~ /radio/ ? - qq{$k ($hash->{$k}) } : - qq{$k -- $hash->{$k}}; - } - } - - return ( - statd => { - type => $deftype, - headline => "Development Stage (Note: No implied timescales)", - args => { - values => \@statd, - labels => \%statd, - default => '?', - } - }, - stats => { - type => $deftype, - headline => "Support Level", - - note => qq{The module list says about the flags - n and a:
-
-n - None known, try comp.lang.perl.modules
-a - abandoned; volunteers welcome to take over maintainance
-}, - - args => { - values => \@stats, - labels => \%stats, - default => '?', - } - }, - statl => { - type => $deftype, - headline => "Language Used", - args => { - values => \@statl, - labels => \%statl, - default => '?', - } - }, - stati => { - type => $deftype, - headline => "Interface Style", - args => { - values => \@stati, - labels => \%stati, - default => '?', - } - }, - statp => { - type => $deftype, - headline => "Public license", - - note => qq{This field is here to help acquiring - solid data about which licences the CPAN modules are subject to. - Filling in this form field is not a substitute for a proper - license statement in the actual package you are uploading. So - please verify that all your uploaded files contain a proper - license. This field will be used to help certifying the legal - status of your package.
Standard-Perl denotes that - the user may choose between GPL and Artistic,
GPL - stands for GNU General Public License,
LGPL for GNU - Lesser General Public License (previously known as "GNU Library - General Public License"),
BSD for the BSD License, -
Artistic for the Artistic license alone,
- Artistic_2 for the artistic license 2.0 or later
- open-source for any other Open Source license listed at http://www.opensource.org/licenses/, -
distribution_allowed is for any license that is not - approved by www.opensource.org but that allows distribution - without restrictions,
restricted_distribution is for - code that limits distribution somehow, and
no_licence - is for code that bears no licence at all.
The last two items - on the list might become a problem for CPAN in the future, so - please try to clear things up to avoid them.--Thanks! - -}, - - args => { - values => \@statp, - labels => \%statp, - default => '?', - } - }, - ); -} - -sub chap_meta { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $dbh = $mgr->connect; - my $sth3 = $dbh->prepare("SELECT chapterid, shorttitle - FROM chapters"); - my(%chap); - $sth3->execute; - while (my($chapterid, $shorttitle) = $mgr->fetchrow($sth3, "fetchrow_array")) { - $chap{$chapterid} = sprintf "%03d %s", $chapterid, $shorttitle; - } - my @sorted = sort { $a <=> $b } keys %chap; - unshift @sorted, ""; - $chap{""} = "Please select chapter"; - $sth3->finish; - return ( - chapterid => { - type => "scrolling_list", - headline => "Module List Chapter", - - note => "The module list has all modules - categorized in chapters. Please pick the one - you would prefer to have your module listed - in.", - - args => { - size => 1, - default => "", - values => \@sorted, - labels => \%chap, - }, - } - ); -} - -sub desc_meta { - return ( - description => { - type => "textfield", - headline => "Description in Module List (44 chars limit)", - args => { - size => 44, - maxlength => 44, - } - }, - ); -} - -sub modid_meta { - return ( - modid => { - type => "textfield", - headline => "Name of the module", - args => { - size => 44, - maxlength => 112, - } - }, - ); -} - -=pod - -In user_meta liegt noch der ganze Scheiss herum, mit dem ich die -unglaubliche Langsamkeit analysiert habe, die eintrat, als ich den -alten Algorithmus durch 5.8 habe durchlaufen lassen. - -Am Schluss (mit $sort_method="splitted") war 5.8 etwa gleich schnell -wie 5.6, aber die Trickserei ist etwas zu aufwendig fuer meinen -Geschmack. - -Also, der Fehler war, dass ich zuerst einen String zusammengebaut -habe, der UTF-8 enthalten konnte und uebermaessig lang war und dann -darueber im Sort-Algorithmus lc laufen liess. Jedes einzelne lc hat -etwas Zeit gekostet, da es im Sort-Algorithmus war, musste es 40000 -mal statt 2000 mal laufen. Soweit, so klar auf einen Blick: richtige -Loesung ist es, den String mit Hilfe des "translit" Feldes zo kurz zu -lassen, dass nur ASCII verbleibt, dann ein downgrade, dann lc, und -dann erst Sortieren. In einem zweiten Hash traegt man den -Display-String herum. - -Was bis heute ein Mysterium ist, ist die Frage, wieso das Einschalten -der Statistik, also ein hoher *zusaetzlicher* Aufwand, die Zeit auf -ein Sechstel biz Zehntel *gedrueckt* hat. Da muss etwas Schlimmes mit -$a und $b passieren. - -=cut - -sub user_meta { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $dbh = $mgr->connect; - my $sql = qq{SELECT userid, fullname, isa_list, asciiname - FROM users}; - my $sth = $dbh->prepare($sql); - $sth->execute; - my(%u,%labels); - # my $sort_method = "gogo"; - my $sort_method = "splitted"; - if (0) { # worked mechanically correct but slow with 5.7.3@16103. - # The slowness is not in the fetchrow but in the sort with - # lc below. At the time of the test $mgr->fetchrow turned - # on UTF-8 flag on everything, including pure ASCII. - - while (my @row = $mgr->fetchrow($sth, "fetchrow_array")) { - $u{$row[0]} = $row[2] ? "mailinglist $row[0]" : "$row[1] ($row[0])"; - } - - } elsif (0) { - - # here we are measuring where the time is spent and tuning up and - # down and experiencing strange effects. - - my $start = Time::HiRes::time(); - my %tlc; - while (my @row = $sth->fetchrow_array) { - if ($] > 5.007) { - # apparently it pays to only turn on UTF-8 flag if necessary - defined && /[^\000-\177]/ && Encode::_utf8_on($_) for @row; - } - $u{$row[0]} = $row[2] ? "mailinglist $row[0]" : - $row[3] ? "$row[3]=$row[1] ($row[0])" : "$row[1] ($row[0])"; - - if (0) { - # measuring lc() alone does not explain the slow sort. We see - # about 0.4 secs for lc() on all names when they all have the - # UTF-8 flag on, about 0.07 secs when only selected ones have - # the flag on. - next unless $row[1]; - my $tlcstart = Time::HiRes::time(); - $tlc{$row[1]} = lc $row[1]; - $tlc{$row[1]} = Time::HiRes::time() - $tlcstart; - } - } - # warn sprintf "TIME: fetchrow and lc on users: %7.4f", Time::HiRes::time()-$start; - my $top = 10; - for my $t (sort { $tlc{$b} <=> $tlc{$a} } keys %tlc) { - warn sprintf "%-43s: %9.7f\n", $t, $tlc{$t}; - last unless --$top; - } - } else { # splitted! - my $start = Time::HiRes::time(); - while (my @row = $sth->fetchrow_array) { - if ($] > 5.007) { - # apparently it pays to only turn on UTF-8 flag if necessary - defined && /[^\000-\177]/ && Encode::_utf8_on($_) for @row; - } - my $disp = $row[2] ? - "$row[0] (mailinglist)" : - $row[3] ? - "$row[0]:$row[3]=$row[1]" : - "$row[0]:$row[1]"; - substr($disp, 52) = "..." if length($disp) > 55; - my($sort) = $disp =~ /^([\000-\177]+)/; - utf8::downgrade($sort) if $] > 5.007; - $u{$row[0]} = lc $sort; - $labels{$row[0]} = $disp; - } - warn sprintf "TIME: fetchrow and split on users: %7.4f", Time::HiRes::time()-$start; - } - my $start = Time::HiRes::time(); - our @tlcmark = (); - our $Collator; - if ($sort_method eq "U:C") { - require Unicode::Collate; - $Collator = Unicode::Collate->new(); - } - # use sort qw(_mergesort); - # use sort qw(_quicksort); - my @sorted = sort { - if (0) { - # Mysterium: the worst case was to have all names with UTF-8 - # flag, Sort_method="lc" and running no statistics. Turning on - # the statistics here reduced runtime from 77-133 to 12 secs. - # With only selected names having UTF-8 flag on we reach 10 secs - # without the statistics and 12 with it. BTW, mergesort counts - # 20885 comparisons, quicksort counts 23201. - push( - @tlcmark, - sprintf("%s -- %s: %9.7f", - $u{$a}, - $u{$b}, - Time::HiRes::time()) - ); - } - if (0) { - } elsif ($sort_method eq "lc") { - # we reach minimum of 10 secs here, better than 77-133 but still - # unacceptable. We seem to have to fight against two bugs: slow - # lc() always is one bug, extremely slow lc() when combined with - # sort is the other one. We must solve it as we did in metalist: - # maintain a sortdummy in the database and let the database sort - # on ascii. - lc($u{$a}) cmp lc($u{$b}); - } elsif ($sort_method eq "U:C") { - $Collator->cmp($a,$b); - # v0.10 completely bogus and 67 secs - } elsif ($sort_method eq "splitted") { - $u{$a} cmp $u{$b}; - } else { - # we reach 0.27 secs here with mergesort, 0.28 secs after we - # switched to quicksort. - $u{$a} cmp $u{$b}; - } - } keys %u; - warn sprintf "TIME: sort on users: %7.4f", Time::HiRes::time()-$start; - if (@tlcmark) { - warn "COMPARISONS: $#tlcmark"; - my($Ltlcmark) = $tlcmark[0] =~ /:\s([\d\.]+)/; - # warn "$Ltlcmark;$tlcmark[0]"; - my $Mdura = 0; - for my $t (1..$#tlcmark) { - my($tlcmark) = $tlcmark[$t] =~ /:\s([\d\.]+)/; - my $dura = $tlcmark - $Ltlcmark; - if ($dura > $Mdura) { - my($lterm) = $tlcmark[$t-1] =~ /(.*):/; - warn sprintf "%s: %9.7f\n", $lterm, $dura; - $Mdura = $dura; - } - $Ltlcmark = $tlcmark; - } - } - - return ( - userid => { - type => "scrolling_list", - args => { - 'values' => \@sorted, - size => 10, - labels => $sort_method eq "splitted" ? \%labels : \%u, - }, - } - ); -} - -sub check_xhtml { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - my @m; - my $dir = "/var/run/httpd/deadmeat"; - if (my $file = $req->param("pause99_check_xhtml_look")) { - open my $fh, "$dir/$file" or die "Couldn't open $file: $!"; - if ($] > 5.007) { - binmode $fh, ":utf8"; - } - local $/; - my $html = <$fh>; - push @m, $mgr->escapehtml($html); - } else { - require DirHandle; - my $dh = DirHandle->new($dir) or die "Couldn't open dir[$dir]: $!"; - if (my @dirent = grep /\.xhtml$/, $dh->read()) { - my %label; - my %mtime; - for my $de (@dirent) { - my @stat = stat "$dir/$de"; - $label{$de} = sprintf " %s %d %s\n", $de, $stat[7], scalar gmtime($stat[9]); - $mtime{$de} = $stat[9]; - } - @dirent = sort { $mtime{$b} <=> $mtime{$a}} @dirent; - push @m, $mgr->radio_group("name" => "pause99_check_xhtml_look", - "values" => \@dirent, - "labels" => \%label, - "linebreak" => 1, - ); - push @m, $mgr->submit(name => "SUBMIT_pause99_check_xhtml_sub", - value => "Look"); - } else { - push @m, qq{No bad xhtml output detected.}; - } - } - @m; -} - -sub index_users { - my pause_1999::edit $self = shift; - my $mgr = shift; - my(@m); - push @m, "NOT YET"; - my $db = $mgr->connect; - my $id_sql = qq{SELECT userid, fullname - FROM users}; - my $id_sth = $db->prepare($id_sql); - - require WAIT; - require WAIT::Database; - - my @localtime = localtime; - $localtime[5] += 1900; - $localtime[4]++; - my $jobid = sprintf "%04s-%02s-%02s_%02s:%02s_%d", @localtime[5,4,3,2,1], $$; - my $name = "$mgr->{WaitUserDb}-$jobid"; - my $directory = $mgr->{WaitDir}; - warn "name[$name] directory[$directory]"; - my $wdb = WAIT::Database->create(name => $name, - directory => $directory, - ) - or die "Could not create database $mgr->{WaitUserDb}: $@\n"; - - - my $filter = [ - "pause99_edit_users_utflc_20010505", - "pause99_edit_users_digrams_20010505", - ]; - - # create-table statement - my $table = $wdb->create_table( - name => "uidx", - attr => [ - 'docid', - 'userid', # key - ], - keyset => [['docid']], - ## layout => $layout, - invindex => [ - userid_and_fullname => $filter, - ] - ); - - # XXX - - $table->close; - $wdb->close; - - @m; -} - -sub WAIT::Filter::pause99_edit_users_digrams_20010505 { - # must be written with "shift" and not with = @_. WAIT seems to need - # that. - my $string = shift; - my @result; - my $start; -# use utf8; - my $end = length($string) - 2; - for ($start=0; $start<$end; $start++) { - my $s = substr $string, $start, 3; - push @result, $s; - } - @result; -} - -sub WAIT::Filter::pause99_edit_users_utflc_20010505 { -# use utf8; - my $s = shift; - my $lc = lc $s; - $lc; -} - -sub who_pumpkin { - my $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - - my @m; - - push @m, qq{

Query the grouptable table for who is a - pumpkin bit holder

- -

Registered pumpkins: -}; - - my @hres; - { - my $db = $mgr->authen_connect; - my $sth = $db->prepare("SELECT user FROM grouptable WHERE ugroup='pumpking' order by user"); - $sth->execute; - while (my @row = $sth->fetchrow_array) { - push @hres, $row[0]; - } - $sth->finish; - }; - my $output_format = $req->param("OF"); - if ($output_format){ - if ($output_format eq "YAML") { - require YAML::Syck; - local $YAML::Syck::ImplicitUnicode = 1; - my $dump = YAML::Syck::Dump(\@hres); - my $edump = Encode::encode_utf8($dump); - my $res = $mgr->{RES}; - $res->content_type("text/plain; charset=utf8"); - $res->body($edump); - return $mgr->{DONE} = HTTP_OK; - } else { - die "not supported OF=$output_format" - } - } else { - push @m, join ", ", @hres; - push @m, "

"; - my $href = sprintf("query?ACTION=who_pumpkin;OF=YAML"); - push @m, qq{

-YAML -

}; - return join "", @m; - } -} - -sub who_admin { - my $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - - my @m; - - push @m, qq{

Query the grouptable table for who is an - admin bit holder

- -

Registered admins: -}; - - my @hres; - { - my $db = $mgr->authen_connect; - my $sth = $db->prepare("SELECT user FROM grouptable WHERE ugroup='admin' order by user"); - $sth->execute; - while (my @row = $sth->fetchrow_array) { - push @hres, $row[0]; - } - $sth->finish; - }; - my $output_format = $req->param("OF"); - if ($output_format){ - if ($output_format eq "YAML") { - require YAML::Syck; - local $YAML::Syck::ImplicitUnicode = 1; - my $dump = YAML::Syck::Dump(\@hres); - my $edump = Encode::encode_utf8($dump); - my $res = $mgr->{RES}; - $res->content_type("text/plain; charset=utf8"); - $res->body($edump); - return $mgr->{DONE} = HTTP_OK; - } else { - die "not supported OF=$output_format" - } - } else { - push @m, join ", ", @hres; - push @m, "

"; - my $href = sprintf("query?ACTION=who_admin;OF=YAML"); - push @m, qq{

-YAML -

}; - return join "", @m; - } -} - -sub email_for_admin { - my $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - - my @m; - my %ALL; - - push @m, qq{

Query a combination of usertable table and user for public or private emails according to the preferences

- - -}; - - { - my $dba = $mgr->authen_connect; - my $dbm = $mgr->connect; - my $sth1 = $dbm->prepare(qq{SELECT userid, email - FROM users - WHERE isa_list = '' - AND ( - cpan_mail_alias='publ' - OR - cpan_mail_alias='secr' - )}); - $sth1->execute; - while (my($id,$mail) = $sth1->fetchrow_array) { - $ALL{$id} = $mail; # we store public email even for those who want - # secret, because we never know if we will find a - # secret one - } - $sth1->finish; - my $sth2 = $dbm->prepare(qq{SELECT userid - FROM users - WHERE cpan_mail_alias='secr' - AND isa_list = ''}); - $sth2->execute; - my $sth3 = $dba->prepare(qq{SELECT secretemail - FROM usertable - WHERE user=?}); - while (my($id) = $sth2->fetchrow_array) { - $sth3->execute($id); - next unless $sth3->rows; - my($mail) = $sth3->fetchrow_array or next; - $ALL{$id} = $mail; - } - $sth2->finish; - $sth3->finish; - }; - my $output_format = $req->param("OF"); - if ($output_format){ - if ($output_format eq "YAML") { - require YAML::Syck; - local $YAML::Syck::ImplicitUnicode = 1; - my $dump = YAML::Syck::Dump(\%ALL); - my $edump = Encode::encode_utf8($dump); - my $res = $mgr->{RES}; - $res->content_type("text/plain; charset=utf8"); - $res->body($edump); - return $mgr->{DONE} = HTTP_OK; - } else { - die "not supported OF=$output_format" - } - } else { - for my $id (sort keys %ALL) { - my($mail) = $ALL{$id}; - my $esc_mail = $mgr->escapeHTML($mail); - push @m, "\n"; - } - push @m, "
idid\@cpan.org gets forwarded to
$id$esc_mail
"; - my $href = sprintf("authenquery?ACTION=email_for_admin;OF=YAML"); - push @m, qq{

-YAML -

}; - return join "", @m; - } -} - -sub peek_perms { - my $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - - my @m; - - push @m, qq{

Query the perms table by author or by - module. Select the option and fill in a module name or - user ID as appropriate. The answer is all modules that an - user ID is registered for or all user IDs registered for a - module, as appropriate.

- -

Registration comes in one of three types: type - modulelist is the registration in the old module - list (like first-come with metadata). Type - first-come is the automatic registration on a - first-come-first-serve basis that happens on the initial - upload. And type co-maint is the registration as - co-maintainer which means that the primary maintainer of - the namespace has granted permission to upload this module - to other userid(s). Per namespace there can only be one - primary maintainer (userid in the modulelist or the - first-come category) and any number of userids in - the co-maint category. Being registered in any of - the categories means that a user is able not only to - upload a module in that namespace but also be accepted by - the indexer. In other words, the indexer will not ignore - uploads for that namespace by that person.

- -

The - contents of the tables presented on this page are mostly - generated automatically, so please report any errors you - observe to @{$PAUSE::Config->{ADMINS}} so that the tables - can be corrected.--Thank you!

}; - - - unless ($req->param("pause99_peek_perms_query")) { - $req->parameters->set("pause99_peek_perms_query", $mgr->{User}{userid}); - } - unless ($req->param("pause99_peek_perms_by")) { - $req->parameters->set("pause99_peek_perms_by","a"); - } - - push @m, $mgr->scrolling_list('name' => 'pause99_peek_perms_by', - size => 1, - values => [qw(me ml a)], - labels => { - "me" => "for a module--exact match", - "ml" => qq{for a module--SQL "LIKE" match}, - "a" => "of an author", - } - ); - push @m, $mgr->textfield('name' => 'pause99_peek_perms_query', - size => 44, - maxlength => 112, - ); - push @m, qq{ -

}; - - if (my $qterm = $req->param("pause99_peek_perms_query")) { - my $by = $req->param("pause99_peek_perms_by"); - my @query = ( - qq{SELECT primeur.package, - primeur.userid, - "first-come", - primeur.userid - FROM primeur LEFT JOIN users ON primeur.userid=users.userid -}, - qq{SELECT perms.package, - perms.userid, - "co-maint", - primeur.userid - FROM perms LEFT JOIN users ON perms.userid=users.userid - LEFT JOIN primeur ON perms.package=primeur.package -}, - ); - - my $db = $mgr->connect; - my @res; - my %seen; - for my $query (@query) { - my %fields = ( - "first-come" => { - package => "primeur.package", - userid => "primeur.userid", - }, - "co-maint" => { - package => "perms.package", - userid => "perms.userid", - } - ); - my($qtype) = $query =~ /\"(.+)\"/; - my($fmap) = $fields{$qtype}; - my $where; - if ($by =~ /^m/) { - if ($by eq "me") { - $where = qq{WHERE $fmap->{package}=?}; - } else { - $where = qq{WHERE $fmap->{package} LIKE ? LIMIT 1000}; - # I saw 5.7.3 die with Out Of Memory on the query "%" when no - # Limit was applied - } - } elsif ($by eq "a") { - $where = qq{WHERE $fmap->{userid}=?}; - } else { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => "Illegal parameter for pause99_peek_perms_by"); - } - $query .= $where; - my $sth = $db->prepare($query); - $sth->execute($qterm); - if ($sth->rows > 0) { - # warn sprintf "query[%s]qterm[%s]rows[%d]", $query, $qterm, $sth->rows; - while (my @row = $mgr->fetchrow($sth, "fetchrow_array")) { - if ($seen{join "|", @row[0,1]}++){ - # warn "Ignoring row[$row[0]][$row[1]]"; - next; - } - push @res, \@row; - } - } - $sth->finish; - } - if (@res) { - for my $row (@res) { - # add the owner on column 3 - # will already be set except for co-maint modules where the - # owner is in the modlist but not first-come - $row->[3] ||= $self->owner_of_module($mgr,$row->[0]); - } - my @column_names = qw(module userid type owner); - my $output_format = $req->param("OF"); - if ($output_format){ - my @hres; - for my $row (@res) { - push @hres, { map {$column_names[$_] => $row->[$_] } 0..$#$row }; - } - if ($output_format eq "YAML") { - require YAML::Syck; - local $YAML::Syck::ImplicitUnicode = 1; - my $dump = YAML::Syck::Dump(\@hres); - my $edump = Encode::encode_utf8($dump); - my $res = $mgr->{RES}; - $res->content_type("text/plain; charset=utf8"); - $res->body($edump); - return $mgr->{DONE} = HTTP_OK; - } else { - die "not supported OF=$output_format" - } - } - push @m, qq{}; #}; - push @m, qq{}; - push @m, map { ""} @column_names; - push @m, qq{}; - for my $row (sort { - $a->[0] cmp $b->[0] - || - $a->[1] cmp $b->[1] - || - $a->[2] cmp $b->[2] - || - $a->[3] cmp $b->[3] - } @res) { - push @m, qq{}; - # pause99_peek_perms_by=m&pause99_peek_perms_query=PerlIO&pause99_peek_perms_sub=+Submit+ - - push @m, sprintf( - qq{ - - - -}, - $mgr->escapeHTML($row->[0]), - $mgr->escapeHTML($row->[0]), - $mgr->escapeHTML($row->[1]), - $mgr->escapeHTML($row->[1]), - $mgr->escapeHTML($row->[2]), - $mgr->escapeHTML($row->[3]), - ); - push @m, qq{}; - } - my $href = sprintf("authenquery?pause99_peek_perms_by=%s;". - "pause99_peek_perms_query=%s;pause99_peek_perms_sub=1;". - "OF=YAML", - $req->param("pause99_peek_perms_by"), - URI::Escape::uri_escape($req->param("pause99_peek_perms_query"),'\W'), - ); - push @m, qq{
" . $mgr->escapeHTML($_) . "
%s%s%s%s
-YAML -}; - } else { - push @m, qq{No records found.}; - } - - } - - @m; -} - -sub owner_of_module { - my($self,$mgr,$m) = @_; - my $dbh = $mgr->connect; - return PAUSE::owner_of_module($m, $dbh); -} - -sub reindex { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - my @m; - my $u = $self->active_user_record($mgr); - push @m, qq{}; - require ExtUtils::Manifest; - require HTTP::Date; - my $dbh = $mgr->connect; - local($dbh->{RaiseError}) = 0; - my $userhome = PAUSE::user2dir($u->{userid}); - - push @m, qq{Indexing normally happens only once, shortly after the - upload takes place. Sometimes it is necessary to reindex - a file. The reason is typically one of the - following:
    - -
  • A file that contained a current version of a module got deleted, -now an older file should be considered current.
  • - -
  • The perms table got altered, now a file should be -visited again to overrule the previous indexing decision.
  • - -
  • At the time of uploading PAUSE had a bug and made a wrong indexing -decision.
  • - -
With this form you can tell the indexer to index selected files - again. As it is done by a cron job, it may take up to an hour - until the indexer actually executes the command. If this doesn't - repair the index, please email me. }; - - require Cwd; - my $cwd = Cwd::cwd(); - - # QUICK DEPARTURE - unless (chdir "$PAUSE::Config->{MLROOT}/$userhome"){ - push @m, qq{No files found in authors/id/$userhome}; - return @m; - } - - my $blurb; - my $server = $PAUSE::Config->{SERVER_NAME}; # XXX: $r->server->server_hostname - if ($req->param('SUBMIT_pause99_reindex_delete')) { - - my $sql = "DELETE FROM distmtimes - WHERE dist = ?"; - my $sth = $dbh->prepare($sql); - foreach my $f ($req->param('pause99_reindex_FILE')) { - if ($f =~ m,^/, || $f =~ m,/\.\./,) { - $blurb .= "WARNING: illegal filename: $userhome/$f\n"; - next; - } - unless (-f $f){ - $blurb .= "WARNING: file not found: $userhome/$f\n"; - next; - } - if ($f =~ m{ (^|/) CHECKSUMS }x) { - $blurb .= "WARNING: indexing CHECKSUMS considered unnecessary: $userhome/$f\n"; - next; - } - # delete from distmtimes where distmtimes.dist like '%SREZIC%Tk-DateE%'; - my $ret = $sth->execute("$userhome/$f"); - $blurb .= "\$CPAN/authors/id/$userhome/$f\n"; - - } - } - if ($blurb) { - my $eta; - { - my $ctf = "$PAUSE::Config->{CRONPATH}/CRONTAB.ROOT"; # crontabfile - unless (-f $ctf) { - $ctf = "/tmp/crontab.root"; - } - if (-f $ctf) { - open my $fh, $ctf or die "XXX"; - local $/ = "\n"; - my $minute; - while (<$fh>) { - s/\#.*//; - next unless /mldistwatch/; - ($minute) = split " ", $_, 2; - last; - } - require Set::Crontab; - my $sc; - eval { $sc = Set::Crontab->new($minute,[0..59]); }; - if ($@) { - warn "Could not create a Crontab object: $@ (minute[$minute])"; - $eta = "N/A"; - } else { - my $now = time; - $now -= $now%60; - for (my $i = 1; $i<=60; $i++) { - my $fut = $now + $i * 60; - my $fum = int $fut % 3600 / 60; - next unless $sc->contains($fum); - $eta = gmtime( $fut + $PAUSE::Config->{RUNTIME_MLDISTWATCH} ) . " UTC"; - last; - } - } - } else { - warn "Not found: $ctf"; - $eta = "N/A"; - } - } - $blurb = sprintf(qq{According to a request entered by %s the -following files have been scheduled for reindexing. - -%s -Estimated time of job completion: %s - -%s}, - $mgr->{User}{fullname}, - $blurb, - $eta, - $Yours, - ); - my %umailset; - my $name = $u->{asciiname} || $u->{fullname} || ""; - my $Uname = $mgr->{User}{asciiname} || $mgr->{User}{fullname} || ""; - if (0) { # debugging - require Data::Dumper; - my $dd = Data::Dumper::Dumper({ u => $u, mgrUser => $mgr->{User} }); - warn "email debugging: dd[$dd]"; - - # By debugging this, I found out, that $u always had a - # secretemail but $mgr->{User} didn't (upto rev 230). - - } - if ($u->{secretemail}) { - $umailset{qq{"$name" <$u->{secretemail}>}} = 1; - } elsif ($u->{email}) { - $umailset{qq{"$name" <$u->{email}>}} = 1; - } - if ($mgr->{User}{userid} ne $u->{userid}) { - if ($mgr->{User}{secretemail}) { - $umailset{qq{"$Uname" <$mgr->{User}{secretemail}>}} = 1; - }elsif ($mgr->{User}{email}) { - $umailset{qq{"$Uname" <$mgr->{User}{email}>}} = 1; - } - } - $umailset{$PAUSE::Config->{ADMIN}} = 1; - my $header = { - Subject => "Scheduled for reindexing $u->{userid}" - }; - $mgr->send_mail_multi([keys %umailset], $header, $blurb); - - push @m, qq{
$blurb

}; - - } - - push @m, qq{

Files in directory authors/id/$userhome

}; - - my $submitbutton = qq{}; - push @m, $submitbutton; - push @m, "
";
-
-  my %files = $self->manifind;
-
-  foreach my $f (keys %files) {
-    if (
-        $f =~ /readme$/ ||
-        $f eq "CHECKSUMS"
-       ) {
-      delete $files{$f};
-      next;
-    }
-    $files{$f} = sprintf " %s", $f;
-  }
-
-  chdir $cwd or die;
-
-  my $field = $mgr->checkbox_group(
-				    name      => 'pause99_reindex_FILE',
-				    'values'  => [sort keys %files],
-				    linebreak => 'true',
-				    labels    => \%files
-				   );
-  $field =~ s!
\s*!\n!gs; - - push @m, $field; - push @m, "
"; - push @m, $submitbutton; - - @m; -} - -sub share_perms { - my pause_1999::edit $self = shift; - my $mgr = shift; - my(@m); - my $req = $mgr->{REQ}; - - $mgr->prefer_post(1); # because the querystring can get too long - - my $subaction = $req->param("SUBACTION"); - unless ($subaction) { - ####################### 2.1 2.2 3.1 3.2 4.1 - SUBACTION: for my $sa (qw(movepr remopr makeco remocos remome)) { - if ($req->param("pause99_share_perms_$sa") - or - $req->param("SUBMIT_pause99_share_perms_$sa") - or - $req->param("weaksubmit_pause99_share_perms_$sa") - ) { - $subaction = $sa; - last SUBACTION; - } - } - } - my $u = $self->active_user_record($mgr); - # warn sprintf "subaction[%s] u->userid[%s]", $subaction||"", $u->{userid}||""; - push @m, qq{}; - push @m, qq{}; # let submit win - - my $scrolling_list_mod = $self->share_perms_scrl_mod($mgr,$u->{userid}); - my $scrolling_list_remove_primary = $self->share_perms_scrl_remove_primary($mgr,$u); - my $scrolling_list_make_comaintainer = $self->share_perms_scrl_make_comaintainer($mgr,$u); - my $scrolling_list_remove_maintainer = $self->share_perms_scrl_remove_maintainer($mgr,$u); - - unless ($subaction) { - - # NOTE: the 6 submit buttons below are "weak" submit buttons. I - # want that people first reach the next page with more text and - # more options. - - - push @m, qq{

Permissions on PAUSE come in three flavors:

- - -
    -
  • - only one user per module can be either -
    -
      -
    • - registered in modulelist or -
    • -
    • - primary maintainer on a first-come-first-serve - basis; -
    • -
    -
  • -
  • - many users can get granted permissions as co-maintainers, - which means their uploads for the given module are honoured by - the indexer. -
  • -
- -

You can view your current set of permissions on the View Permissions page. To - change permissions, select one of the following submit - buttons, each of which leads you to a different page:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- 1. You are registered in modulelist -
$scrolling_list_mod - - Module Metadata has been removed from PAUSE and - is no longer editable. Please contact a PAUSE administrator to - choose a new owner. -
2. You are primary maintainer:
$scrolling_list_remove_primary - - - 2.1 Transfer primary maintainership status to somebody else - (you become co-maintainer) -
- - - 2.2 Give up primary maintainership status (abandoning it without - transfering it to someone else) -
- 3. Making and unmaking co-maintainers (for both modulelist - owners and primary maintainers): -
$scrolling_list_make_comaintainer - - - 3.1 Make somebody else co-maintainer -
- - 3.2 Remove a co-maintainer
4. You are co-maintainer
$scrolling_list_remove_maintainer - - 4.1 Give up co-maintainership status -
- -}; - - return @m; - } - - my $method = "share_perms_$subaction"; - # warn "method[$method]"; - push @m, $self->$method($mgr); - @m; -} - -sub share_perms_scrl_mod { - my($self,$mgr,$userid) = @_; - my $dbh = $mgr->connect; - my $sql = qq{SELECT modid - FROM mods - WHERE userid=? - AND mlstatus='list' - ORDER BY modid}; - my @bind = $userid; - my $sth = $dbh->prepare($sql); - my $ret = $sth->execute(@bind); - my @all_mods; - while (my($id) = $mgr->fetchrow($sth, "fetchrow_array")) { - # register this mailinglist for the selectbox - push @all_mods, $id; - } - return "--NONE--" unless @all_mods; - my $all_mods = scalar @all_mods; - my $size = $all_mods > 18 ? 15 : $all_mods; - $mgr->scrolling_list( - 'name' => "pause99_edit_mod_3", - 'values' => \@all_mods, - 'size' => $size, - ); -} - -sub share_perms_scrl_remove_primary { - my($self,$mgr,$u) = @_; - my $dbh = $mgr->connect; - - my $all_mods = $self->all_pmods_not_mmods($mgr,$u); - my @all_mods = sort keys %$all_mods; - my $n = scalar @all_mods; - return "--NONE--" unless $n; - my $size = $n > 18 ? 15 : $n; - $mgr->scrolling_list( - 'name' => "pause99_share_perms_pr_m", - 'multiple' => 1, - 'values' => \@all_mods, - 'size' => $size, - ); -} - -sub share_perms_scrl_make_comaintainer { - my($self,$mgr,$u) = @_; - my $dbh = $mgr->connect; - - my $all_mods = $self->all_pmods($mgr,$u); - my @all_mods = sort keys %$all_mods; - my $n = scalar @all_mods; - return "--NONE--" unless $n; - my $size = $n > 18 ? 15 : $n; - # it should be sufficiently helpful to prepare only makeco_m on - # these two submit buttons. For 3.2 people may be a little confused - # but it is so rarely needed that we do not worry. - $mgr->scrolling_list( - 'name' => "pause99_share_perms_makeco_m", - 'multiple' => 1, - 'values' => \@all_mods, - 'size' => $size, - ); -} - -sub share_perms_scrl_remove_maintainer { - my($self,$mgr,$u) = @_; - my $dbh = $mgr->connect; - - my $all_mods = $self->all_only_cmods($mgr,$u); - my @all_mods = sort keys %$all_mods; - my %labels; - for my $m (@all_mods) { - # get the owner for modlist modules that don't have first-come - my $owner = $all_mods->{$m} || $self->owner_of_module($mgr,$m) || '?'; - $labels{$m} = "$m => $owner"; - } - my $n = scalar @all_mods; - return "--NONE--" unless $n; - my $size = $n > 18 ? 15 : $n; - $mgr->scrolling_list( - name => "pause99_share_perms_remome_m", - multiple => 1, - values => \@all_mods, - labels => \%labels, - size => $size, - ); -} - -sub share_perms_remocos { - my pause_1999::edit $self = shift; - my $mgr = shift; - my(@m); - my $req = $mgr->{REQ}; - - my $u = $self->active_user_record($mgr); - - my $db = $mgr->connect; - my $all_mods = $self->all_pmods($mgr,$u); - my $all_comaints = $self->all_comaints($mgr,$all_mods,$u); - if ( - $req->param("SUBMIT_pause99_share_perms_remocos") - ) { - eval { - my @sel = $req->param("pause99_share_perms_remocos_tuples"); - my $sth1 = $db->prepare("DELETE FROM perms WHERE package=? AND userid=?"); - if (@sel) { - for my $sel (@sel) { - my($selmod,$otheruser) = $sel =~ /^(\S+)\s--\s(\S+)$/; - die PAUSE::HeavyCGI::Exception - ->new(ERROR => "You do not seem to be owner of $selmod") - unless exists $all_mods->{$selmod}; - unless (exists $all_comaints->{$sel}) { - push @m, "

Cannot handle tuple $sel. If you - believe, this is a bug, please complain.

"; - next; - } - my $ret = $sth1->execute($selmod,$otheruser); - my $err = ""; - $err = $db->errstr unless defined $ret; - $ret ||= ""; - warn "DEBUG: selmod[$selmod]ret[$ret]err[$err]"; - if ($ret) { - push @m, "

Removed $otheruser from co-maintainers of $selmod.

\n"; - } else { - push @m, "

Error trying to remove $otheruser from co-maintainers of - $selmod: $err

\n"; - } - } - } else { - push @m, qq{

You need to select one or more packages. Nothing done.

} - } - }; - if ($@) { - push @m, "

", $@->{ERROR}, "

"; - } - push @m, "
\n"; - } - $all_comaints = $self->all_comaints($mgr,$all_mods,$u); - my @all = sort keys %$all_comaints; - my $n = scalar @all; - my $size = $n > 18 ? 15 : $n; - unless ($size) { - - push @m, qq{

There are no co-maintainers registered to any of - $u->{userid}'s modules.

}; - - return @m; - } - - push @m, qq{

Remove co-maintainer status

The scrolling - list shows you, which packages are associated with other - maintainers besides yourself. Every line denotes a tuple - of a namespace and a userid. Select those that you want to - remove and press Remove

}; - if (@all == 1) { - # selectboxes with only ine option to select look confusing and - # better be preselected: - $req->parameters->set("pause99_share_perms_remocos_tuples",$all[0]); - } - push @m, $mgr->scrolling_list( - 'name' => "pause99_share_perms_remocos_tuples", - 'multiple' => 1, - 'values' => \@all, - 'size' => $size, - ); - push @m, qq{

}; - push @m, qq{

}; - push @m, qq{

}; - @m; -} - -sub all_comaints { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $all_mods = shift; - my $u = shift; - my $result = {}; - my $db = $mgr->connect; - my $or = join " OR\n", map { "package='$_'" } keys %$all_mods; - my $sth2 = $db->prepare(qq{SELECT package, userid - FROM perms - WHERE userid <> '$u->{userid}' AND ( $or )}); - $sth2->execute; - while (my($p,$i) = $mgr->fetchrow($sth2,"fetchrow_array")) { - $result->{"$p -- $i"} = undef; - warn "p[$p]i[$i]"; - } - return $result; -} - -sub all_only_cmods { - my($self,$mgr,$u) = @_; - my $all_pmods = $self->all_pmods($mgr,$u); - my $all_mods = $self->all_cmods($mgr,$u); - - for my $k (keys %$all_pmods) { - delete $all_mods->{$k}; - } - $all_mods; -} - -sub share_perms_remome { - my pause_1999::edit $self = shift; - my $mgr = shift; - my(@m); - my $req = $mgr->{REQ}; - - my $u = $self->active_user_record($mgr); - my $db = $mgr->connect; - - my $all_mods = $self->all_only_cmods($mgr,$u); - - if ( - $req->param("SUBMIT_pause99_share_perms_remome") - ) { - eval { - my(@selmods); - if (@selmods = $req->param("pause99_share_perms_remome_m") - ) { - local($db->{RaiseError}) = 0; - my $sth = $db->prepare("DELETE FROM perms WHERE package=? AND userid=?"); - for my $selmod (@selmods) { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => "You do not seem to be co-maintainer of $selmod") - unless exists $all_mods->{$selmod}; - my $ret = $sth->execute($selmod,$u->{userid}); - my $err = ""; - $err = $db->errstr unless defined $ret; - $ret ||= ""; - warn "DEBUG: selmod[$selmod]ret[$ret]err[$err]"; - if ($ret) { - push @m, "

Removed $u->{userid} from co-maintainers of $selmod.

\n"; - delete $all_mods->{$selmod}; - } else { - push @m, "

Error trying to remove $u->{userid} from co-maintainers of - $selmod: $err

\n"; - } - } - } else { - push @m, qq{

You need to select one or more packages. Nothing done.

}; - } - }; - if ($@) { - push @m, "

", $@->{ERROR}, "

"; - } - push @m, "
\n"; - } - - my @all_mods = sort keys %$all_mods; - my $n = scalar @all_mods; - my $size = $n > 18 ? 15 : $n; - unless ($size) { - - push @m, qq{

Sorry, $u->{userid} does not seem to be co-maintainer of any module.

}; - - return @m; - } - push @m, qq{

Give up co-maintainer status

Please select one or - more namespaces for which you want to be removed from - the co-maintainer table and press Give Up

}; - - push @m, qq{

Select one or more namespaces:

}; - if (@all_mods == 1) { - $req->parameters->set("pause99_share_perms_remome_m",$all_mods[0]); - } - push @m, $mgr->scrolling_list( - 'name' => "pause99_share_perms_remome_m", - 'multiple' => 1, - 'values' => \@all_mods, - 'size' => $size, - ); - push @m, qq{

}; - push @m, qq{

}; - push @m, qq{

}; - - @m; -} - -sub share_perms_makeco { - my pause_1999::edit $self = shift; - my $mgr = shift; - my(@m); - my $req = $mgr->{REQ}; - - my $u = $self->active_user_record($mgr); - # warn "u->userid[%s]", $u->{userid}; - - my $db = $mgr->connect; - - my $all_pmods = $self->all_pmods($mgr,$u); - # warn sprintf "all_pmods[%s]", join("|", keys %$all_pmods); - my $all_mods = {%$all_pmods}; - - if ( - $req->param("SUBMIT_pause99_share_perms_makeco") - ) { - eval { - my(@selmods,$other_user); - if (@selmods = $req->param("pause99_share_perms_makeco_m") - and - $other_user = $req->param("pause99_share_perms_makeco_a") - ) { - $other_user = uc $other_user; - my $sth1 = $db->prepare("SELECT userid - FROM users - WHERE userid=?"); - $sth1->execute($other_user); - die PAUSE::HeavyCGI::Exception - ->new(ERROR => sprintf( - "%s is not a valid userid.", - $mgr->escapeHTML($other_user), - ) - ) - unless $sth1->rows; - local($db->{RaiseError}) = 0; - my $sth = $db->prepare("INSERT INTO perms (package,lc_package,userid) - VALUES (?,?,?)"); - for my $selmod (@selmods) { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => "You do not seem to be maintainer of $selmod") - unless exists $all_mods->{$selmod}; - my $ret = $sth->execute($selmod,lc $selmod,$other_user); - my $err = ""; - $err = $db->errstr unless defined $ret; - $ret ||= ""; - warn "DEBUG: selmod[$selmod]other_user[$other_user]ret[$ret]err[$err]"; - if ($ret) { - push @m, "

Added $other_user to co-maintainers of $selmod.

\n"; - } elsif ($err =~ /Duplicate entry/) { - push @m, "

$other_user was already a co-maintainer of $selmod: skipping

"; - } else { - push @m, "

Error trying to add $other_user to co-maintainers of - $selmod: $err

\n"; - } - } - } else { - push @m, qq{

You need to select one or more packages and enter a userid. - Nothing done.

}; - } - }; - if ($@) { - push @m, "

", $@->{ERROR}, "

"; - } - push @m, "
\n"; - } - - my @all_mods = sort keys %$all_mods; - my $n = scalar @all_mods; - my $size = $n > 18 ? 15 : $n; - unless ($size) { - - push @m, qq{

Sorry, there are no modules registered belonging to - $u->{userid}.

}; - - return @m; - } - push @m, qq{

Select a co-maintainer

Please select one or - more namespaces for which you want to select a - co-maintainer, enter the CPAN userid of the co-maintainer - into the text field and press Make Co-Maintainer

}; - - push @m, qq{

Select one or more namespaces:

}; - if (@all_mods == 1) { - $req->parameters->set("pause99_share_perms_makeco_m",$all_mods[0]); - } - push @m, $mgr->scrolling_list( - 'name' => "pause99_share_perms_makeco_m", - 'multiple' => 1, - 'values' => \@all_mods, - 'size' => $size, - ); - push @m, qq{

}; - push @m, qq{

Select a userid:
}; - push @m, $mgr->textfield( - 'name' => "pause99_share_perms_makeco_a", - size => 15, - maxlength => 9, - ); - push @m, qq{

}; - push @m, qq{

}; - - @m; -} - -sub share_perms_remopr { - my pause_1999::edit $self = shift; - my $mgr = shift; - my(@m); - my $req = $mgr->{REQ}; - - my $u = $self->active_user_record($mgr); - - my $db = $mgr->connect; - - my $all_mods = $self->all_pmods_not_mmods($mgr,$u); - - if (0) { - # here I discovered that Apache::Request has case-insensitive keys - my %p = map { $_, [ $req->param($_)] } $req->param; - require Data::Dumper; print STDERR "Line " . __LINE__ . ", File: " . __FILE__ . "\n" . Data::Dumper->new([\%p],[qw()])->Indent(1)->Useqq(1)->Dump; # XXX - - } - - if ( - $req->param("SUBMIT_pause99_share_perms_remopr") - ) { - eval { - my(@selmods); - if (@selmods = $req->param("pause99_share_perms_pr_m") - ) { - local($db->{RaiseError}) = 0; - my $sth = $db->prepare("DELETE FROM primeur WHERE userid=? AND package=?"); - for my $selmod (@selmods) { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => "You do not seem to be maintainer of $selmod") - unless exists $all_mods->{$selmod}; - my $ret = $sth->execute($u->{userid},$selmod); - my $err = ""; - $err = $db->errstr unless defined $ret; - $ret ||= ""; - warn "DEBUG: selmod[$selmod]ret[$ret]err[$err]"; - if ($ret) { - push @m, "

Removed primary maintainership of $u->{userid} from $selmod.

\n"; - } else { - push @m, "

Error trying to remove primary maintainership of $u->{userid} - from $selmod: $err

\n"; - } - } - } else { - push @m, qq{

You need to select one or more packages. Nothing done.

}; - } - }; - if ($@) { - push @m, "

", $@->{ERROR}, "

"; - } - push @m, "
\n"; - } - - $all_mods = $self->all_pmods_not_mmods($mgr,$u); # yes, again! - my @all_mods = sort keys %$all_mods; - my $n = scalar @all_mods; - my $size = $n > 18 ? 15 : $n; - unless ($size) { - - push @m, qq{

Sorry, there are no modules registered belonging to - $u->{userid}.

}; - - return @m; } push @m, qq{

Give up maintainership - status

Please select one or more namespaces for which you - want to give up primary maintainership status and press - Give Up Maintainership Status. Note: you keep co-maintainer - status after this move. If you want to get rid of that too, - please visit Give up - co-maintainership status next.

}; - - push @m, qq{

Select one or more namespaces:

}; - if (@all_mods == 1) { - $req->parameters->set("pause99_share_perms_pr_m",$all_mods[0]); - } - push @m, $mgr->scrolling_list( - 'name' => "pause99_share_perms_pr_m", - 'multiple' => 1, - 'values' => \@all_mods, - 'size' => $size, - ); - push @m, qq{

}; - push @m, qq{

}; - - @m; -} - -sub share_perms_movepr { - my pause_1999::edit $self = shift; - my $mgr = shift; - my(@m); - my $req = $mgr->{REQ}; - - my $u = $self->active_user_record($mgr); - - my $db = $mgr->connect; - - my $all_mods = $self->all_pmods_not_mmods($mgr,$u); - - if ( - $req->param("SUBMIT_pause99_share_perms_movepr") - ) { - eval { - my(@selmods,$other_user); - if (@selmods = $req->param("pause99_share_perms_pr_m") - and - $other_user = $req->param("pause99_share_perms_movepr_a") - ) { - $other_user = uc $other_user; - my $sth1 = $db->prepare("SELECT userid - FROM users - WHERE userid=?"); - $sth1->execute($other_user); - die PAUSE::HeavyCGI::Exception - ->new(ERROR => sprintf( - "%s is not a valid userid.", - $mgr->escapeHTML($other_user), - ) - ) - unless $sth1->rows; - local($db->{RaiseError}) = 0; - my $sth = $db->prepare("UPDATE primeur SET userid=? WHERE package=?"); - for my $selmod (@selmods) { - die PAUSE::HeavyCGI::Exception - ->new(ERROR => "You do not seem to be maintainer of $selmod") - unless exists $all_mods->{$selmod}; - my $ret = $sth->execute($other_user,$selmod); - my $err = ""; - $err = $db->errstr unless defined $ret; - $ret ||= ""; - warn "DEBUG: selmod[$selmod]other_user[$other_user]ret[$ret]err[$err]"; - if ($ret) { - push @m, "

Made $other_user primary maintainer of $selmod.

\n"; - } else { - push @m, "

Error trying to make $other_user primary maintainer of - $selmod: $err

\n"; - } - } - } else { - push @m, qq{

You need to select one or more packages and enter a userid. - Nothing done.

}; - } - }; - if ($@) { - push @m, "

", $@->{ERROR}, "

"; - } - push @m, "
\n"; - } - - $all_mods = $self->all_pmods_not_mmods($mgr,$u); # yes, again! - my @all_mods = sort keys %$all_mods; - my $n = scalar @all_mods; - my $size = $n > 18 ? 15 : $n; - unless ($size) { - - push @m, qq{

Sorry, there are no modules registered belonging to - $u->{userid}.

}; - - return @m; - } - - push @m, qq{

Pass maintainership status

Please select one - or more namespaces for which you want to pass primary - maintainership status, enter the CPAN userid of the new - maintainer into the text field and press Pass Maintainership - Status. Note: you keep co-maintainer status after this move. - If you want to get rid of that too, please visit Give up - co-maintainership status next.

}; - - push @m, qq{

Select one or more namespaces:

}; - if (@all_mods == 1) { - $req->parameters->set("pause99_share_perms_pr_m",$all_mods[0]); - } - push @m, $mgr->scrolling_list( - 'name' => "pause99_share_perms_pr_m", - 'multiple' => 1, - 'values' => \@all_mods, - 'size' => $size, - ); - push @m, qq{

}; - push @m, qq{

Select a userid:
}; - push @m, $mgr->textfield( - 'name' => "pause99_share_perms_movepr_a", - size => 15, - maxlength => 9, - ); - push @m, qq{

}; - push @m, qq{

}; - - @m; -} - -sub all_pmods { - my $self = shift; - my $mgr = shift; - my $u = shift; - my $db = $mgr->connect; - my(%all_mods); - my $sth2 = $db->prepare(qq{SELECT package - FROM primeur - WHERE userid=?}); - $sth2->execute($u->{userid}); - while (my($id) = $mgr->fetchrow($sth2, "fetchrow_array")) { - $all_mods{$id} = undef; - } - $sth2->finish; - \%all_mods; -} - -sub all_pmods_not_mmods { - my $self = shift; - my $mgr = shift; - my $u = shift; - my $db = $mgr->connect; - my(%all_mods); - my $sth2 = $db->prepare(qq{SELECT package - FROM primeur - WHERE userid=?}); - $sth2->execute($u->{userid}); - while (my($id) = $mgr->fetchrow($sth2, "fetchrow_array")) { - $all_mods{$id} = undef; - } - $sth2->finish; - \%all_mods; -} - -sub all_cmods { - my $self = shift; - my $mgr = shift; - my $u = shift; - my $db = $mgr->connect; - my(%all_mods); - my $sth2 = $db->prepare(qq{SELECT perms.package, primeur.userid - FROM perms LEFT JOIN primeur - ON perms.package = primeur.package - WHERE perms.userid=?}); - $sth2->execute($u->{userid}); - while (my($id, $owner) = $mgr->fetchrow($sth2, "fetchrow_array")) { - $all_mods{$id} = $owner; - } - $sth2->finish; - \%all_mods; -} - - - - -=pod - -Thanks to Slaven Rezic for his help in finding the solution how to -produce core dumps of apache under Linux. Here are the guts: - -Running h2ph is required and beforehand it is recommended to test as -root something like this: - -mkdir tmp -chown nobody tmp -cd tmp -limit coredumpsize 30m -perl -e ' - require "syscall.ph"; - require "linux/sys.ph"; - require "linux/prctl.ph"; - $user = shift or die; - my $uid = (getpwnam($user))[2]; - $< = $> = $uid; - print syscall(&SYS_prctl,&PR_SET_DUMPABLE,1); - warn $<; - dump;' nobody -ls -l core - -If this shows a core file when run with the same perl as the -webserver, then it should succeed on the webserver too. - -You will additionally have to set coredumpsize for nobody via -/etc/security/limits.conf and add CoreDumpDirectory -/directory/owned/by/nobody to the httpd.conf or do something -equivalent. - -=cut - - -sub coredump { - my $self = shift; - my $mgr = shift; - - die "The coredump interface was just a testbed to find out how to - enable coredumps on Linux. Now disabled."; - - require "syscall.ph"; - require "linux/sys.ph"; - require "linux/prctl.ph"; - warn syscall(&SYS_prctl,&PR_SET_DUMPABLE,1); - chdir "/usr/local/apache/cores" or die "Couldn't chdir: $!"; - warn "**************>>>>>>>>>> strace -p $$\n"; - sleep 10; - require Cwd; - my $cwd = Cwd::cwd(); - require BSD::Resource; - my($nowsoft,$nowhard) = BSD::Resource::getrlimit(BSD::Resource::RLIMIT_CORE()); - $mgr->{REQ}->logger({level => 'error', message => "UID[$<]EUID[$>]cwd[$cwd]nowsoft[$nowsoft]nowhard[$nowhard]"}); - CORE::dump; -} - -sub dele_message { - my($self,$mgr) = @_; - - my @m = qq{

Admins can add and delete messages to a message board. - When a user visits PAUSE they see the pending messages for them and - are requested to answer to the admin who placed the message. Usage - scenario: email bounces, google doesn't get us closer to the user, - that kind of thing. When the cause is settled the admin should - delete the message to not any longer annoy the user with it. The - user cannot delete the message.

- -

To delete messages, click on the radio buttons and then press - Delete.

}; - - my $dbh = $mgr->connect; - my $req = $mgr->{REQ}; - my $sth = $dbh->prepare("SELECT * FROM messages where mfrom=? AND mstatus='active' - ORDER BY created desc"); - $sth->execute($mgr->{User}{userid}); - if ($sth->rows) { - if ($req->param('SUBMIT_pause99_dele_message_sub')) { - # get another handle - my $sth2 = $dbh->prepare("UPDATE messages set mstatus='deleted' - WHERE mfrom=? AND c=?"); - for my $m ($req->param('pause99_dele_message_m')) { - $sth2->execute($mgr->{User}{userid}, $m); - } - $sth->execute($mgr->{User}{userid}); - } - } - if ($sth->rows) { - push @m, qq{
};
-    my(@v,%l);
-    my $tf = Text::Format->new(firstIndent => 36, bodyIndent => 36, columns => 90);
-    while (my $rec = $sth->fetchrow_hashref) {
-      push @v, $rec->{c};
-      my $fmessage = $tf->format($rec->{message});
-      $fmessage =~ s/^\s+//;
-      $l{$rec->{c}} = sprintf(qq{%*s%*s %s | %s},
-                              $rec->{mto},
-                              length($rec->{mto}),
-                              $rec->{mto},
-                              10-length($rec->{mto}),
-                              "",
-                              $rec->{created},
-                              $mgr->escapeHTML($fmessage),
-                             );
-    }
-    my $field = $mgr->checkbox_group(
-                                      name      => 'pause99_dele_message_m',
-                                      'values'  => \@v,
-                                      linebreak => 'true',
-                                      labels    => \%l
-                                     );
-    $field =~ s!
\s*!\n!gs; - - push @m, $field; - push @m, qq{
}; - } else { - push @m, qq{

No messages found.

}; - } - @m; -} - -sub post_message { - my($self,$mgr) = @_; - - my @m = qq{

Admins can add and delete messages to a message board. - When a user visits PAUSE they see the pending messages for them and - are requested to answer to the admin who placed the message. Usage - scenario: email bounces, google doesn't get us closer to the user, - that kind of thing. When the cause is settled the admin should - delete the message to not any longer annoy the user with it. The - user cannot delete the message.

- -

To post a message, fill in the form and press - Submit.


}; - - my $dbh = $mgr->connect; - my $req = $mgr->{REQ}; - - my $mto = $req->param('pause99_post_message_mto'); - $mto = uc $mto; - my $mess = $req->param('pause99_post_message_mess'); - warn "mto[$mto]mess[$mess]"; - - my $showform = 0; - my $regOK = 0; - - if ($req->param('SUBMIT_pause99_post_message_sub')) { - my @errors = (); - unless ($mto) { - push @errors, "You must supply a message"; - } - if ($mto) { - my $sth = $dbh->prepare("SELECT userid FROM users where userid=?"); - $sth->execute($mto); - unless ($sth->rows) { - push @errors, sprintf "Userid %s is not known", $mgr->escapeHTML($mto); - } - $sth->finish; - } else { - push @errors, "You must supply a userid"; - } - if( @errors ) { - push @m, qq{

Error processing form

}; - for (@errors) { - push @m, "
    ", "
  • $_
  • ", "
"; - } - push @m, qq{

Please retry.

}; - } else { - # we don't sweat over the time zone, mysql does it in the zone - # of the server and turning it into UTC seems not worth the - # effort right now (2003-03-04) - my $sth = $dbh->prepare("INSERT INTO messages - (mfrom,mto,created,message) - VALUES (? ,? ,NOW() ,? )"); - $sth->execute($mgr->{User}{userid},$mto,$mess); - push @m, sprintf qq{Message to - %s posted.}, - ($mgr->escapeHTML($mto))x2; - for my $f (qw(mto mess)) { - $req->parameters->set("pause99_post_message_$f",""); - } - } - } - for my $arr ( - ['Userid','mto',10,10], - ['Message','mess',60,255], - ) { - push @m, qq{

$arr->[0]

}; - push @m, $mgr->textfield( - name => "pause99_post_message_$arr->[1]", - size => $arr->[2], - maxsize => $arr->[3] - ); - push @m, "

"; - } - push @m, qq{}; - - - @m; -} - -sub reset_version { - my pause_1999::edit $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - my @m; - my $u = $self->active_user_record($mgr); - push @m, qq{}; - my $dbh = $mgr->connect; - local($dbh->{RaiseError}) = 0; - - push @m, qq{

Note: resetting versions is a major inconvenience for - module users. This page will probably be withdrawn from PAUSE if - the perl community does not want to allow falling version numbers - on the CPAN. For now: use with care. Thanks.

- -

Below you see the packages and version numbers that - the indexer considers the current and highest version number that - it has seen so far. By selecting an item in the list and clicking - Forget, this value is set to undef. This opens the - way for a Force Reindexing run in which the version of the - package in the reindexed distribution can become the current.

- -

Did I say, this operation should not be done lightly? Because - users of the module out there may still have that higher version - installed and so will not notice the newer but lower-numbered - release. Let me repeat: please make responsible use of this - page.

- -

Q: So why is this page up at all?

- -

A: Combine a multi-module-distro with a small mistake in an - older release or a bug in the PAUSE indexer. In such a case you - will be happy to use this page and nobody else will ever notice - there was a problem.

- -}; - my $blurb = ""; - my($usersubstr) = sprintf("%s/%s/%s/", - substr($u->{userid},0,1), - substr($u->{userid},0,2), - $u->{userid}, - ); - my($usersubstrlen) = length $usersubstr; - my $sqls = "SELECT package, version, dist FROM packages - WHERE substring(dist,1,$usersubstrlen) = ?"; - my $sths = $dbh->prepare($sqls); - if ($req->param('SUBMIT_pause99_reset_version_forget')) { - my $sqls2 = "SELECT version FROM packages - WHERE package = ? AND substring(dist,1,$usersubstrlen) = ?"; - my $sths2 = $dbh->prepare($sqls2); - my $sqlu = "UPDATE packages - SET version='undef' - WHERE package = ? AND substring(dist,1,$usersubstrlen) = ?"; - my $sthu = $dbh->prepare($sqlu); - PKG: foreach my $f ($req->param('pause99_reset_version_PKG')) { - $sths2->execute($f,$usersubstr); - my($version) = $sths2->fetchrow_array; - next PKG if $version eq 'undef'; - my $ret = $sthu->execute($f,$usersubstr); - $blurb .= sprintf( - "%s: %s '%s' => 'undef'\n", - $ret==0 ? "Not reset" : "Reset", - $f, - $version, - ); - } - } - if ($blurb) { - - $blurb = sprintf(qq{According to a request by %s the following -packages have their recorded version set to 'undef'. - -%s - -%s}, - $mgr->{User}{fullname}, - $blurb, - $Yours, - ); - my %umailset; - my $name = $u->{asciiname} || $u->{fullname} || ""; - my $Uname = $mgr->{User}{asciiname} || $mgr->{User}{fullname} || ""; - - if ($u->{secretemail}) { - $umailset{qq{"$name" <$u->{secretemail}>}} = 1; - } elsif ($u->{email}) { - $umailset{qq{"$name" <$u->{email}>}} = 1; - } - if ($mgr->{User}{userid} ne $u->{userid}) { - if ($mgr->{User}{secretemail}) { - $umailset{qq{"$Uname" <$mgr->{User}{secretemail}>}} = 1; - }elsif ($mgr->{User}{email}) { - $umailset{qq{"$Uname" <$mgr->{User}{email}>}} = 1; - } - } - $umailset{$PAUSE::Config->{ADMIN}} = 1; - my $header = { - Subject => "Version reset for $u->{userid}" - }; - $mgr->send_mail_multi([keys %umailset], $header, $blurb); - - push @m, qq{
$blurb

}; - - } - $sths->execute($usersubstr); - if ($sths->rows == 0) { - push @m, qq{

No packages associated with $u->{userid}

}; - return @m; - } - - push @m, sprintf( - qq{

%d %s associated with %s

}, - $sths->rows, - $sths->rows == 1 ? "package" : "packages", - $u->{userid}, - ); - my(@maxl,%p); - while (my(@row) = $sths->fetchrow_array) { - for my $i (0..$#row) { - if (!$maxl[$i] or $maxl[$i]}; - push @m, $submitbutton; - push @m, "
";
-  my $field = $mgr->checkbox_group(
-                                   name      => 'pause99_reset_version_PKG',
-                                   'values'  => [sort keys %p],
-                                   linebreak => 'true',
-                                   labels    => \%p
-                                  );
-  $field =~ s!
\s*!\n!gs; - - push @m, $field; - push @m, "
"; - push @m, $submitbutton; - @m; -} - -1; -#Local Variables: -#mode: cperl -#cperl-indent-level: 2 -#End: diff --git a/lib/pause_1999/fixup.pm b/lib/pause_1999/fixup.pm deleted file mode 100644 index 7bce21e86..000000000 --- a/lib/pause_1999/fixup.pm +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/perl -- -*- Mode: cperl; -*- -package pause_1999::fixup; -use strict; -use HTTP::Status qw(:constants); -our $VERSION = "85"; - -=comment - -All Location below /pause share this FixupHandler. All we want to -achieve is that these mappings are in effect: - - /pause redir=> /pause/query CASE 1 - /pause/ trans=> /pause/query CASE 2 - /pause/query OK CASE 3 - /pause/authenquery OK CASE 3 - -I have the suspicion that this would be easier with a completely -different approach, but as it works, I do not investigate further now. - -=cut - -sub handler { - my $req = shift; - # return HTTP_OK unless $r->is_initial_req; - my $uri = $req->request_uri; - my $location = '/pause'; # $r->location; - - # CASE 3 - -# return DECLINED if $location =~ /query/; - - # warn "uri[$uri]location[$location] (Question was, does location ever match /query/?)"; - if ($uri eq $location) { - - # CASE 1 - - my $redir = $req->base; - my $is_ssl = $req->header("X-pause-is-SSL") || 0; - if ($is_ssl) { - $redir->scheme("https"); - } - $redir->path("$location/query"); - my $res = $req->new_response(HTTP_MOVED_PERMANENTLY); - $res->header("Location",$redir); - # warn "redir[$redir]"; - return $res->finalize; - } - return unless $uri eq "$location/"; - - # CASE 2 - - # warn sprintf "uri[%s]location[%s]path_info[%s]", $uri, $location, $r->path_info; - $req->path("$location/query"); - $req->path_info("") if $req->path_info; - return; -} - -1; - -#Local Variables: -#mode: cperl -#cperl-indent-level: 2 -#End: diff --git a/lib/pause_1999/index.pm b/lib/pause_1999/index.pm deleted file mode 100644 index ed60b2374..000000000 --- a/lib/pause_1999/index.pm +++ /dev/null @@ -1,49 +0,0 @@ -package pause_1999::index; -use strict; -use HTTP::Status qw(:constants); -our $VERSION = "304"; - -sub handler { - my $req = shift; - if (1) { # $r->is_initial_req - my $method = $req->method; - my $redir_to = $req->base; - my $is_ssl = $req->header("X-pause-is-SSL") || 0; - if ($is_ssl) { - $redir_to->scheme("https"); - } - if ($method eq 'GET' && $redir_to->path eq '/' && $req->env->{QUERY_STRING}) { - my $args = $req->env->{QUERY_STRING}; - # warn "Returning SERVER_ERROR: the_request[$the_request]uri[$uri]args[$args]"; - # return SERVER_ERROR; - $redir_to->path("/pause/query"); - $args =~ s|/$||; - $args =~ s|\s.*||; - $redir_to->query($args) if $args; - # warn "Statistics: Redirecting the_request[$the_request]redir_to[$redir_to]"; - my $res = $req->new_response(HTTP_MOVED_PERMANENTLY); - $res->header("Location",$redir_to); - return $res->finalize; - } - my $uri = $req->path; - #my $host = $r->server->server_hostname; - #my $args = $r->args; - #warn "index-uri[$uri]host[$host]args[$args]"; - return HTTP_NOT_FOUND unless $uri eq "/" || $uri eq "/index.html"; - #my(%redir) = ( - # "/" => "query", - # "/index.html" => "query?ACTION=pause_05news", - # ); - # $r->internal_redirect_handler("/query"); - $redir_to->path("/pause/query"); - $redir_to->query("ACTION=pause_05news") if $uri eq "/index.html"; - my $res = $req->new_response(HTTP_MOVED_PERMANENTLY); - $res->header("Location",$redir_to); - return $res->finalize; -# } else { -# return OK; - } -} - -1; - diff --git a/lib/pause_1999/layout.pm b/lib/pause_1999/layout.pm deleted file mode 100644 index ada67bde9..000000000 --- a/lib/pause_1999/layout.pm +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/perl -- -*- Mode: cperl; coding: utf-8; -*- -package pause_1999::layout; -use base 'Class::Singleton'; -use PAUSE::HeavyCGI::Layout; -use pause_1999::main; -use strict; -our $VERSION = "994"; - -sub layout { - my($self) = shift; - my $mgr = shift; - - # on a high-end application we would cache aggressively the three or - # twelve layouts that might be generated. On the PAUSE we don't mind - # to generate them again and again, speed is not an issue and layout - # is primitive - - my @l; - # http://validator.w3.org/check had (2000-10-17) the User-Agent - # "W3C_Validator/1.67 libwww-perl/5.48" - if (1 || $mgr->uagent =~ m|W3C_Validator/\d+\.\d+\s+libwww-perl/\d+\.\d+|) { - # When we had still doubt, we did only send the doctype to the - # validator. - if ($mgr->can_utf8) { - push @l, qq{}; - } else { - push @l, qq{}; - } - push @l, qq{}; - } - push @l, qq{}; - push @l, $PAUSE::Config->{TESTHOST} ? qq{pause\@home: } : qq{PAUSE: }; - push @l, $mgr->{Action} || "The CPAN back stage entrance"; - my $hspecial = $PAUSE::Config->{TESTHOST} ? "h2,h4,b,th,td { color: #486f8d; }" : ""; - - -=pod - -Netscape 479 was reading comments - -// body { font-family: Helvetica, Arial, sans-serif; } -// h2,h3,h4 { margin: 1% 8% 5% 3%; padding-left: 3em; background-color: silver; border: black; border-style: solid dotted none; } -// h1,h2,h3,h4 { margin: 0 0 5%; } - -=cut - - push @l, qq{ - - -}; #}; - push @l, qq{ -} if $hspecial; - push @l, qq{
}; #}; - push @l, $mgr->instance_of("pause_1999::pausegif"); - push @l, qq{

The [Perl programming] Authors Upload - Server

}; - push @l, $mgr->instance_of("pause_1999::userstatus"); - push @l, qq{

}; - - # - # MOTD - # - - my $downtime = $mgr->{DownTime}||0; - my $willlast = $mgr->{WillLast}||0; - my $deploy_two_apaches = 0; - if ($deploy_two_apaches && $] > 5.009005) { - require Config; - my($bin) = $Config::Config{bin} =~ m|^.*?/perl-(.+?)/|; - push @l, sprintf(qq{

This is perl %s;}, - $bin, - ); - push @l, sprintf(qq{ cf_time %s; }, - $Config::Config{cf_time}, - ); - - push @l, qq{when you run into problems try Port 8443 (https), - where perl 5.8.7 should be running (or Port 8000 - if you need http).

}; - - } - - if (time < $downtime) { - push @l, qq{
}; - use HTTP::Date; - my $httptime = HTTP::Date::time2str($downtime); - use Time::Duration; - my $delta = $downtime - time; - my $expr = Time::Duration::duration($delta); - my $willlast_dur = Time::Duration::duration($willlast); - - push @l, qq{

Scheduled downtime
On -$httptime (that is in $expr) PAUSE will be closed for maintainance -work. The estimated downtime is $willlast_dur.

}; #}; - - push @l, qq{
}; - - } elsif (time < $downtime+$willlast) { - my $user = $mgr->{User}{userid}; # if closed and somebody comes - # here, it currently is always - # ANDK - - my $closed_text = $mgr->{REQ}->env->{'psgix.notes'}{CLOSED}; - - push @l, qq{

Hi $user, you -see the site now but it is closed for maintainance. -Please be careful not to disturb the database operation. Expect -failures everywhere. Do not edit anything, it may get lost. Other -users get the following text:

$closed_text
}; - - } - - push @l, $mgr->instance_of("pause_1999::message"); - if ($mgr->{ERROR} && @{$mgr->{ERROR}}) { - push @l, qq{

Error

\n}, @{$mgr->{ERROR}}, - qq{

Please try again, probably by using the Back button of - your browser and repeating the last action you took.

}; - } else { - push @l, $mgr->instance_of("pause_1999::startform"); - push @l, qq{
}; #}; - - # - # MENU on the LEFT - # - push @l, $mgr->instance_of("pause_1999::usermenu"); - - push @l, qq{}; - push @l, qq{ }; - push @l, qq{}; - push @l, $mgr->instance_of("pause_1999::edit"); - push @l, qq{
\n}; - push @l, qq{}; - } - push @l, qq{
}; - push @l, $mgr->instance_of("pause_1999::speedlinkgif"); - push @l, qq{\n}; - PAUSE::HeavyCGI::Layout->new(@l); -} - -1; diff --git a/lib/pause_1999/main.pm b/lib/pause_1999/main.pm deleted file mode 100644 index b935d2490..000000000 --- a/lib/pause_1999/main.pm +++ /dev/null @@ -1,999 +0,0 @@ -=head1 NAME - -main - - -=head1 SYNOPSIS - - - -=head1 DESCRIPTION - -=head2 About how to add an action item to the usermenu - -Add a subroutine that implements it in edit.pm, - -add a security policy for the item in edit::parameter method, - -(optionally) add a verbose name to attribute ActionTuning in -config.pm, - -decide if the action should be allowed to the admin with "HIDDENNAME" -and if so, add it to AllowAdminTakeover attribute. - -if a mailing list is to be involved, decide if the action should be -allowed to the mailinglist-representative and if so, add it to -AllowMlreprTakeover - -That is it. - -In the menu, entries are being sorted by method name. If we have too -many menu entries, we need to think about grouping and different -sorting. - -=head2 about testing the whole thing - -query must offer "Forgot password", "About PAUSE", "PAUSE News", -"PAUSE History", and "Who is Who". - -Who is Who must display a list of > 1400 users and Szabo Balazs must -have an accent on the o and the last a. At the end of the list we find -KUJUN and KENSHAN in Japanese letters. Currently we have lowercase -people after uppercase people, but this ought to change. - -authenquery must display several menus. Edit account info should be -tested for Andreas Koenig with and without Umlaut. The mails that get -sent out should be reviewed if they have correct charset. - -A new perl installation will not only have impact on the Web -application but also on the cronjobs and other scripts on PAUSE and -possibly in the modulelist/ directory. So we should not replace the -perl at the same time as the application. We should rather leave the -default perl be the old perl and port one script after the other to -the new perl. - -=head2 Methods - -=over - -=cut - - - -package pause_1999::main; -use PAUSE::HeavyCGI; # This is much better than only second line - # alone. If PAUSE::HeavyCGI is not available, - # the errormessage of the next line would be 'No - # such pseudo-hash field "R" in variable $self' -use base PAUSE::HeavyCGI; -use Sys::Hostname; -# # use Apache::URI (); - - # use encoding "utf-8"; - - # apparently very buggy with 5.7.3@16103: test with select_user and - # the warn statement within scrolling_list that matches /AND/. - # Several nonsense things in the output. I do not want to dig into that. - - # Outcommenting of the use encoding statement is not enough: you must - # restart the server to get rid of it. BTW, HTML::Parser was 3.26 but - # with Unicode support off. - -use strict; -use vars qw($VERSION %entity2char $DO_UTF8); -$VERSION = "854"; - -$DO_UTF8 = 1; -use HTTP::Status qw(:constants); -require Unicode::String; -use HTML::Entities; -use String::Random (); -use Fcntl qw(O_RDWR); -use Time::HiRes (); - -{ - %entity2char = %HTML::Entities::entity2char; - while (my($k,$v) = each %entity2char) { - if ($v =~ /[^\000-\177]/) { - $entity2char{$k} = Unicode::String::latin1($v)->utf8; - # warn "CONV k[$k] v[$v]"; - } else { - delete $entity2char{$k}; - # warn "DEL v[$v]"; - } - } -} - -use fields qw( - -Action -ActionTuning -ActiveColor -AllowAction -AllowAdminTakeover -AllowMlreprTakeover -AuthenDsn -AuthenDsnPasswd -AuthenDsnUser -CanMultipart -DbHandle4Authen -DbHandle -DocumentRoot -DownTime -EditOutput -HiddenUser -IsMailinglistRepresentative -IsSSL -MailMailerConstructorArgs -MailtoAdmins -ModDsn -ModDsnPasswd -ModDsnUser -NeedMultipart -OurEmailFrom -PreferPost -QueryURL -RootURL -Session -SessionDataDir -SessionCounterDir -SessionCounterFile -UseModuleSet -User -UserAgent -UserGroups -UserId -UserSecrets -VERSION -WaitDir -WaitUserDb -WillLast - -); - -sub dispatch { - my $self = shift; - local $SIG{__WARN__} = sub { - my $message = shift; - chomp $message; - Log::Dispatch::Config->instance->log( - level => 'warn', - message => $message, - ); - }; - $self->init; - my $req = $self->{REQ}; - warn sprintf "DEBUG: uri[%s]location[%s]", $req->path, ''; # $r->location; - if ($req->path =~ m|^/pause/query/|) { # path info? - warn "Warning: killing this request, it has a path_info, only bots have them"; - return HTTP_NOT_FOUND; - } - eval { $self->prepare; }; - if ($@) { - if (UNIVERSAL::isa($@,"PAUSE::HeavyCGI::Exception")) { - if ($@->{ERROR}) { - require Carp; - $@->{ERROR} = [ $@->{ERROR} ] unless ref $@->{ERROR}; - push @{$self->{ERROR}}, @{$@->{ERROR}}; - require Data::Dumper; - print STDERR "Line " . __LINE__ . ", File: " . __FILE__ . "\n" . Data::Dumper->new([$self->{ERROR}],[qw(error)])->Indent(1)->Useqq(1)->Dump; # XXX - } elsif ($@->{HTTP_STATUS}) { - return $@->{HTTP_STATUS}; - } - } else { - # this is NOT a known error type, we need to handle it anon - if ($self->{ERRORS_TO_BROWSER}) { - push @{$self->{ERROR}}, " ", $@; - } else { - $req->logger->({level => 'error', message => $@ }); - return HTTP_INTERNAL_SERVER_ERROR; - } - } - } - return $self->{RES}->finalize if $self->{DONE}; # backwards comp now, will go away - $self->{CONTENT} = $self->layout->as_string($self); - $self->finish; - $self->deliver; -} - -sub layout { - my $self = shift; - $self->instance_of("pause_1999::layout")->layout($self); -} - -sub can_gzip { - my $self = shift; - my $req = $self->{REQ}; - # my $remote = $r->get_remote_host; <-- is not used now - # Just for debugging, because Netscape doesn't show source on gzipped pages - # if ($remote =~ /^62\.104\.4/ and $r->server->server_hostname =~ /^ak-/) { - # return $self->{CAN_GZIP} = 0; - # } - $self->SUPER::can_gzip; -} - -sub can_utf8 { - my $self = shift; - return $self->{CAN_UTF8} if defined $self->{CAN_UTF8}; - - # From chapter 14.2. HTTP/1.1 - - ## If no Accept-Charset header is present, the default is that any - ## character set is acceptable. If an Accept-Charset header is present, - ## and if the server cannot send a response which is acceptable - ## according to the Accept-Charset header, then the server SHOULD send - ## an error response with the 406 (not acceptable) status code, though - ## the sending of an unacceptable response is also allowed. - - my $acce = $self->{REQ}->header("Accept-Charset"); - if (defined $acce){ - if ($acce =~ m|\butf-8\b|i){ - $self->{CAN_UTF8} = 1; - } else { - $self->{CAN_UTF8} = 0; - } - warn "CAN_UTF8[$self->{CAN_UTF8}]acce[$acce]"; - return $self->{CAN_UTF8}; - } - # Mozilla/5.0 (X11; U; Linux 2.2.16-RAID i686; en-US; m18) - my $uagent = $self->uagent; - if ($uagent =~ /^Mozilla\/(\d+)\.\d+\s+\(X11;/ - && - $1 >= 5 - ) { - $self->{CAN_UTF8} = "mozilla 5X"; - warn "CAN_UTF8[$self->{CAN_UTF8}]uagent[$uagent]"; - return $self->{CAN_UTF8}; - } - if (0) { - # since we have a perlbal this protocol check is turns UTF-8 off - # more often than in previous times and reveals that our - # solutions for non-utf-8 browsers do not work anymore. - # Disabling completely for now. May need reconsidering, but - # maybe UTF-8 works everywhere now... - my $protocol = $self->{REQ}->protocol || ""; - my($major,$minor) = $protocol =~ m|HTTP/(\d+)\.(\d+)|; - $self->{CAN_UTF8} = $major >= 1 && $minor >= 1; - warn "CAN_UTF8[$self->{CAN_UTF8}]protocol[$protocol]uagent[$uagent]"; - } - $self->{CAN_UTF8} = 1; -} - -sub uagent { - my $self = shift; - return $self->{UserAgent} if defined $self->{UserAgent}; - $self->{UserAgent} = $self->{REQ}->header('User-Agent'); -} - -sub connect { - my $self = shift; - # local($SIG{PIPE}) = 'IGNORE'; - eval {$self->{DbHandle} ||= DBI->connect($self->{ModDsn}, - $self->{ModDsnUser}, - $self->{ModDsnPasswd}, - { RaiseError => 1, mysql_auto_reconnect => 1 })}; - return $self->{DbHandle} if $self->{DbHandle}; - $self->database_alert; -} - -sub database_alert { - my($self) = @_; - require Carp; - my $mess = Carp::longmess($@); - my $tsf = "$PAUSE::Config->{RUNDATA}/alert.db.not.available.ts"; - if (! -f $tsf or (time - (stat _)[9]) > 6*60*60) { - my $server = $self->myurl->can("host") ? $self->myurl->host : $self->myurl->hostname; - my $header = { - From => "database_alert", - To => $PAUSE::Config->{ADMIN}, - Subject => "PAUSE Database Alert $server", - }; - $self->send_mail($header,$mess); - open my $fh, ">", $tsf or warn "Could not open $tsf: $!"; - } - die PAUSE::HeavyCGI::Exception->new(ERROR => qq{ -Sorry, the PAUSE Database currently seems unavailable.
-Administration has been notified.
-Please try again later. -}); -} - -sub authen_connect { - my $self = shift; - # local($SIG{PIPE}) = 'IGNORE'; - eval {$self->{DbHandle4Authen} ||= DBI->connect($self->{AuthenDsn}, - $self->{AuthenDsnUser}, - $self->{AuthenDsnPasswd}, - { RaiseError => 1, mysql_auto_reconnect => 1 })}; - return $self->{DbHandle4Authen} if $self->{DbHandle4Authen}; - $self->database_alert; -} - -# 2000-04-02: Apache::URI does not satisfy me. It does not include -# scheme and server, but it does contain the whole querystring. I'll -# back out this myurl. The reason why I introduced it, was a problem -# on my machine at home, not on PAUSE, so there is hope that nothing -# breaks by setting it back to the previous state. - -# # sub myurl { -# # my PAUSE::HeavyCGI $self = shift; -# # return $self->{MYURL} if defined $self->{MYURL}; -# # my $r = $self->{R}; -# # my $myurl = $r->parsed_uri; -# # my $port = $r->server->port || 80; -# # my $scheme = $port == 443 ? "https" : "http"; -# # $myurl->scheme($scheme); # Apache::URI doesn't know that without -# # # hint, at least not with v1.00. Not well -# # # tested -# # $self->{MYURL} = $myurl; -# # } - -# 2002-06-08: Discovering that HeavyCGI gets https wrong. Retrying to -# reanimate Apache::URI now. -sub myurl { - my $self = shift; - return $self->{MYURL} if defined $self->{MYURL}; - use URI::URL; - my $req = $self->{REQ} or - return URI::URL->new("http://localhost"); - my $uri = $req->uri; - - # use Data::Dumper; - # warn "subprocess_env[".Data::Dumper::Dumper(scalar $r->subprocess_env)."]"; - # ONLY WORKS WITH PerlSetupEnv On: - # my $envscheme = $r->subprocess_env('HTTPS') ? "https" : "http"; - # my $scheme = $uri->scheme; - # warn "scheme[$scheme]envscheme[$envscheme]"; - # $uri->scheme($scheme); - - #### Summary scheme: don't use subprocess_env unless PerlSetupEnv is - #### On. You don't need it anyway, because $uri->scheme seems to - #### work OK. - - my $Hhostname = $req->header('Host'); - my $hostname = $uri->host(); - warn "hostname[$hostname]Hhostname[$Hhostname]"; - # $uri->hostname($Hhostname); # contains :8443!!!!! - - # my $rpath = $uri->rpath; - # $uri->path($rpath); - warn sprintf "DEBUG: uri[%s]location[%s]", $uri, ""; # $r->location; - - # XXX should have additional test if we are on pause - if (( $uri->port == 81 || $uri->port == 12081 ) - and $PAUSE::Config->{HAVE_PERLBAL} - ) { - if ($self->is_ssl($uri)) { - $uri->port(443); - $uri->scheme("https"); - } else { - $uri->port(80); - $uri->scheme("http"); - } - my($hh,$hport); - if ($Hhostname =~ /([^:]+):(\d+)/) { - ($hh,$hport) = ($1,$2); - $uri->port($hport); - } else { - $hh = $Hhostname; - } - $uri->host($hh); - } - - # my $port = $r->server->port || 80; - # my $explicit_port = ($port == 80 || $port == 443) ? "" : ":$port"; - # $self->{MYURL} = URI::URL->new( - # "$protocol://" . - # $r->server->server_hostname . - # $explicit_port . - # $script_name); - $uri->host($PAUSE::Config->{SERVER_NAME}) if $PAUSE::Config->{SERVER_NAME}; - $self->{MYURL} = $uri; -} - -# the argument $uri is important to prevent recursion between myurl -# and is_ssl -sub is_ssl { - my($self, $uri) = @_; - return $self->{IsSSL} if defined $self->{IsSSL}; - my $is_ssl = 0; - $uri ||= $self->myurl; - if ($uri->scheme eq "https") { - $is_ssl = 1; - } elsif ($PAUSE::Config->{TRUST_IS_SSL_HEADER}) { - my $header = $self->{REQ}->header("X-pause-is-SSL") || 0; - $is_ssl = !!$header; - } - return $self->{IsSSL} = $is_ssl; -} - -sub file_to_user { - my($self, $uriid) = @_; - $uriid =~ s|^/?authors/id||; - $uriid =~ s|^/||; - my $ret; - if ($uriid =~ m|^\w/| ) { - ($ret) = $uriid =~ m|\w/\w\w/([^/]+)/|; - } else { - die "Error: invalid uriid[$uriid]"; - } - $ret; -} - -sub send_mail_multi { - my($self,$to,$header,$blurb) = @_; - for my $to2 (@$to) { - $header->{To} = $to2; - $self->send_mail($header,$blurb); - } -} - -sub send_mail { - my($self, $header, $blurb) = @_; - require Mail::Mailer; - - my @args = @{$self->{MailMailerConstructorArgs}}; - - warn "constructing mailer with args[@args]"; - my $mailer = Mail::Mailer->new(@args); - - my @hdebug = %$header; $self->{REQ}->logger({level => 'error', message => sprintf("hdebug[%s]", join "|", @hdebug) }); - $header->{From} ||= $self->{OurEmailFrom}; - $header->{"Reply-To"} ||= join ", ", @{$PAUSE::Config->{ADMINS}}; - - if ($] > 5.007) { - require Encode; - for my $k (keys %$header) { - if ( grep { ord($_)>127 } $header->{$k} =~ /(.)/g ) { - $header->{$k} = Encode::encode("MIME-Q",$header->{$k}); - } - } - } - - my $u = Unicode::String::utf8($blurb); - my $binmode; - if (grep { $_>255 } $u->unpack) { - $header->{"MIME-Version"} = "1.0"; - $header->{"Content-Type"} = "Text/Plain; Charset=UTF-8"; - $header->{"Content-Transfer-Encoding"} = "8bit"; - $binmode = "utf8"; - } elsif (grep { $_>127 } $u->unpack) { - $header->{"MIME-Version"} = "1.0"; - $header->{"Content-Type"} = "Text/Plain; Charset=ISO-8859-1"; - $header->{"Content-Transfer-Encoding"} = "8bit"; - $blurb = $u->latin1; - } - - if ($PAUSE::Config->{TESTHOST}){ - warn "TESTHOST is NOT sending mail"; - require Data::Dumper; - warn "Line " . __LINE__ . ", File: " . __FILE__ . "\n" . - Data::Dumper->new([$header,$blurb],[qw(header blurb)]) - ->Indent(1)->Useqq(1)->Dump; - } else { - warn "opening mailer"; - $mailer->open($header); - warn "opened mailer"; - if ($binmode && $] > 5.007) { - my $ret = binmode $mailer, ":$binmode"; - warn "set binmode of mailer[$mailer] to :utf8? ret[$ret]"; - } - $mailer->print($blurb); - warn "printed blurb[$blurb]"; - $mailer->close; - warn "closed mailer"; - } - 1; -} - -sub finish { - my $self = shift; - - if ($self->can_utf8) { - } else { - warn sprintf "DEBUG: using Unicode::String uri[%s]gmtime[%s]", $self->{REQ}->uri, scalar gmtime(); - my $ustr = Unicode::String::utf8($self->{CONTENT}); - $self->{CONTENT} = $ustr->latin1; - $self->{CHARSET} = "ISO-8859-1"; - } - - use XML::Parser; - my $p1 = XML::Parser->new; - eval { $p1->parse($self->{CONTENT}); }; - if ($@) { - my $rand = String::Random::random_string("cn"); - warn "XML::Parser error. rand[$rand]\$\@[$@]"; - my $deadmeat = "/var/run/httpd/deadmeat/$rand.xhtml"; - require IO::Handle; - my $fh = IO::Handle->new; - if (open $fh, ">$deadmeat") { - if ($] > 5.007) { - binmode $fh, ":utf8"; - } - $fh->print($self->{CONTENT}); - $fh->close; - } else { - warn "Couldn't open >$deadmeat: $!"; - } - } - - if ($] > 5.007) { - require Encode; - # utf8::upgrade($self->{CONTENT}); # make sure it is UTF-8 encoded - $self->{CONTENT} = Encode::encode_utf8($self->{CONTENT}); - } - # $self->cleanup; # close db handles if necessary - $self->SUPER::finish; -} - -sub text_pw_field { - my($self, %arg) = @_; - my $name = $arg{name} || ""; - my $fieldtype = $arg{FIELDTYPE}; - - my $req = $self->{REQ}; - my $val; - if ($fieldtype eq "FILE") { - if ($req->can("upload")) { - if ($req->upload($name)) { - $val = $req->upload($name); - } else { - $val = $req->param($name); - if ($] > 5.007) { require Encode; $val = Encode::decode_utf8($val); } - } - } else { - $val = $req->param($name); - if ($] > 5.007) { require Encode; $val = Encode::decode_utf8($val); } - } - } else { - $val = $req->param($name); - # warn sprintf "name[%s]val[%s]", $name, $val||"UNDEF"; - if ($] > 5.007) { - require Encode; - # Warning: adding second parameter changes behavior (eats characters or so?) - $val = Encode::decode_utf8($val - # , Encode::FB_WARN() - ); - } - # warn sprintf "name[%s]val[%s]", $name, $val||"UNDEF"; - } - defined $val or - defined($val = $arg{value}) or - defined($val = $arg{default}) or - ($val = ""); - - sprintf(qq{\n}, - $self->escapeHTML($name), - $self->escapeHTML($val), - exists $arg{size} ? " size=\"$arg{size}\"" : "", - exists $arg{maxlength} ? " maxlength=\"$arg{maxlength}\"" : "" - ); -} - -sub textfield { - my($self) = shift; - $self->text_pw_field(FIELDTYPE=>"text", @_); -} - -sub password_field { - my($self) = shift; - $self->text_pw_field(FIELDTYPE=>"password", @_); -} - -sub file_field { - my($self) = shift; - $self->text_pw_field(FIELDTYPE=>"file", @_); -} - -sub checkbox { - my($self,%arg) = @_; - - my $name = $arg{name}; - my $value; - defined($value = $arg{value}) or ($value = "on"); - my $checked; - my @sel = $self->{REQ}->param($name); - if (@sel) { - for (@sel) { - if ($_ eq $value) { - $checked = 1; - last; - } - } - } else { - $checked = $arg{checked}; - } - $arg{label} = "" unless defined $arg{"label"}; - sprintf(qq{%s}, - $self->escapeHTML($name), - $self->escapeHTML($value), - $checked ? qq{ checked="checked"} : "", - $arg{label}, - ); -} - -sub radio_group { - my($self,%arg) = @_; - my $name = $arg{name}; - my $value; - my $checked; - my $sel = $self->{REQ}->param($name); - my $haslabels = exists $arg{labels}; - my $values = $arg{values} or Carp::croak "radio_group called without values"; - defined($checked = $arg{checked}) - or defined($checked = $sel) - or defined($checked = $arg{default}) - or $checked = ""; - # warn "checked[$checked]"; -# or ($checked = $values->[0]); - my $escname=$self->escapeHTML($name); - my $linebreak = $arg{linebreak} ? "
" : ""; - my @m; - for my $v (@$values) { - my $escv = $self->escapeHTML($v); - warn "escname undef" unless defined $escname; - warn "escv undef" unless defined $escv; - warn "v undef" unless defined $v; - warn "\$arg{labels}{\$v} undef" unless defined $arg{labels}{$v}; - warn "checked undef" unless defined $checked; - warn "haslabels undef" unless defined $haslabels; - warn "linebreak undef" unless defined $linebreak; - push(@m, - sprintf( - qq{%s%s}, - $escname, - $escv, - $v eq $checked ? qq{ checked="checked"} : "", - $haslabels ? $arg{labels}{$v} : $escv, - $linebreak, - )); - } - join "", @m; -} - -sub checkbox_group { - my($self,%arg) = @_; - - my $name = $arg{name}; - my @sel = $self->{REQ}->param($name); - unless (@sel) { - if (exists $arg{default}) { - my $default = $arg{default}; - @sel = ref $default ? @$default : $default; - } - } - - my %sel; - @sel{@sel} = (); - my @m; - - $name = $self->escapeHTML($name); - - my $haslabels = exists $arg{labels}; - my $linebreak = $arg{linebreak} ? "
" : ""; - - for my $v (@{$arg{values} || []}) { - push(@m, - sprintf( - qq{%s%s}, - - "line" . (1 + (scalar(@m) % 3)), - # toggle through "line1", "line2", "line3", "line1", ... - - $name, - $self->escapeHTML($v), - exists $sel{$v} ? qq{ checked="checked"} : "", - $haslabels ? $arg{labels}{$v} : $self->escapeHTML($v), - $linebreak, - ) - ); - } - join "", @m; -} - -# last edit 2000-03-30 -sub scrolling_list { - my($self, %arg) = @_; - # name values size labels - my $size = $arg{size} ? qq{ size="$arg{size}"} : ""; - my $multiple = $arg{multiple} ? qq{ multiple="multiple"} : ""; - my $haslabels = exists $arg{labels}; - my $name = $arg{name}; - # warn "name[$name]CGI[$self->{CGI}]"; - my @sel = $self->{REQ}->param($name); - if (!@sel && exists $arg{default} && defined $arg{default}) { - my $d = $arg{default}; - @sel = ref $d ? @$d : $d; - } else { - # require Data::Dumper; - # my $sel = Data::Dumper::Dumper(\@sel); - # warn "HERE2 sel[$sel]default[$arg{default}]"; - } - my %sel; - @sel{@sel} = (); - my @m; - push @m, sprintf qq{"; - join "", @m; -} - -# sub escapeHTML { # slow but doesn't lose the UTF8-Flag -sub escapeHTML { - my($self, $what) = @_; - return unless defined $what; - # require Devel::Peek; Devel::Peek::Dump($what) if $what =~ /Andreas/; - my %escapes = qw(& & " " > > < <); - $what =~ s[ ([&"<>]) ][$escapes{$1}]xg; # ]] cperl-mode comment - $what; -} - -sub can_multipart { - my $self = shift; - return $self->{CanMultipart} if defined $self->{CanMultipart}; - my $req = $self->{REQ}; - my $can = $req->param('CAN_MULTIPART'); # no guessing, no special casing - $can = 1 unless defined $can; # default - $self->{CanMultipart} = $can; -} - -sub need_multipart { - my $self = shift; - my $set = shift; - $self->{NeedMultipart} = $set if defined $set; - return $self->{NeedMultipart}; -} - -sub prefer_post { - return 1; # Because we should always prefer post now - - my $self = shift; - my $set = shift; - $self->{PreferPost} = $set if defined $set; - return $self->{PreferPost}; -} - -sub any2utf8 { - my $self = shift; - my $s = shift; - - if ($s =~ /[\200-\377]/) { - # warn "s[$s]"; - my $warn; - local $^W=1; - local($SIG{__WARN__}) = sub { $warn = $_[0]; warn "warn[$warn]" }; - my($us) = Unicode::String::utf8($s); - if ($warn and $warn =~ /utf8|can't/i) { - warn "DEBUG: was not UTF8, we suppose latin1 (apologies to shift-jis et al): s[$s]"; - $s = Unicode::String::latin1($s)->utf8; - warn "DEBUG: Now converted to: s[$s]"; - } else { - warn "seemed to be utf-8"; - } - } - $s = $self->decode_highbit_entities($s); # modifies in-place - if ($] > 5.007) { - require Encode; - Encode::_utf8_on($s); - } - $s; -} - -sub decode_highbit_entities { - my $self = shift; - my $s = shift; - # warn "s[$s]"; - my $c; - use utf8; - for ($s) { - s{ ( & \# (\d+) ;? ) - }{ ($2 > 127) ? chr($2) : $1 - }xeg; - - s{ ( & \# [xX] ([0-9a-fA-F]+) ;? ) - }{$c = hex($2); $c > 127 ? chr($c) : $1 - }xeg; - - s{ ( & (\w+) ;? ) - }{my $r = $entity2char{$2} || $1; warn "r[$r]2[$2]"; $r; - }xeg; - - } - # warn "s[$s]"; - $s; -} - -sub textarea { - my($self,%arg) = @_; - my $req = $self->{REQ}; - my $name = $arg{name} || ""; - my $val = $req->param($name) || $arg{default} || $arg{value} || ""; - my($r) = exists $arg{rows} ? qq{ rows="$arg{rows}"} : ''; - my($c) = exists $arg{cols} ? qq{ cols="$arg{cols}"} : ''; - my($wrap)= exists $arg{wrap} ? qq{ wrap="$arg{wrap}"} : ''; - sprintf qq{}, - $self->escapeHTML($name), - $r, $c, $wrap, $self->escapeHTML($val); -} - -sub submit { - my($self,%arg) = @_; - my $name = $arg{name} || ""; - my $val = $arg{value} || $name; - sprintf qq{}, - $self->escapeHTML($name), - $self->escapeHTML($val); -} - -sub DESTROY { - my $self = shift; - $self->{DbHandle4Authen}->disconnect if ref $self->{DbHandle4Authen}; - $self->{DbHandle}->disconnect if ref $self->{DbHandle}; -} - -sub session { - my $self = shift; - return $self->{Session} if defined $self->{Session}; - my $req = $self->{REQ}; - my $sid = $req->param('USERID'); # may fail - my %session; - require Apache::Session::Counted; - # XXX date string into CounterFile! - tie %session, 'Apache::Session::Counted', - $sid, { - Directory => $self->{SessionDataDir}, - DirLevels => 1, - CounterFile => $self->{SessionCounterFile}, - }; - $self->{Session} = \%session; -} - -sub userid { - my $self = shift; - # I'm working for the first time with Apache::Session::Counted - # Things have changed a bit. Until today we had no userid until we - # had dumped the current request. With Apache::Session we have a - # userid from the moment we open a session. Under many circumstances - # we do not need a session, so we do not need a userid. We typically - # need a userid either to retrieve an old value or to store a new - # value. We know that we have to retrieve an old value if there is a - # USERID=xxx parameter on the request. We know that we want to store - # something if we call ->userid. - - # Apache::Session will dump the current request even if we do not - # need it. That's stupid. Cookie based session concepts are - # careless. But let's delay this discussion and see if our code - # works first. - - return $self->{UserId} if defined $self->{UserId}; - # we must find out if there is an old request that needs to be - # restored because if there is, we must not create a new one. - # Because if we create a new one, the restorer cannot restore it - # without clobbering _session_id - - # Talking about session: lets delegate the problem to the session - - my $session = $self->session; - $self->{UserId} = $session->{_session_id}; - $session->{_session_id} = $self->{UserId}; # funny, isn't it? We - # trigger a STORE here - # which triggers a - # MODIFIED so that the - # DESTROY will actually - # save the hash -} - -sub wait_user_record_hook { - my $self = shift; - - my $method = shift; - my $id = shift; - - warn "method[$method]id[$id]\$\$[$$]"; - - require WAIT::Database; - require WAIT::Query::Base; - require WAIT::Query::Wais; - my $wdb = WAIT::Database->open(name => $self->{WaitUserDb}, - mode => O_RDWR, - directory => $self->{WaitDir}); - my $table = $wdb->table(name => "uidx"); - warn "HERE"; - my $sel_sth; - my $sel_sql = qq{SELECT userid, fullname - FROM users - WHERE userid=?}; - my $db = $self->connect; - $sel_sth = $db->prepare($sel_sql); - $sel_sth->execute($id); - unless ($sel_sth->rows) { - warn sprintf "WARNING: wait_hook called for method[%s] on id[%s] which - isn't in database. Skipping.", #' - $method, $id; - $sel_sth->finish; - $table->close; - $wdb->close; - return; - } - my $rec = $self->fetchrow($sel_sth, "fetchrow_hashref"); - my $uf = "$rec->{userid} $rec->{fullname}"; - warn "HERE"; - - if ($method eq "delete" && !$table->have(docid => $id)) { - warn "delete on not existing record id[$id], nothing done"; - } else { - my $ret = $table->$method( - 'docid' => $id, - userid_and_fullname => $uf, - ); - warn "HERE"; - # So it failed? Where's the error, what's the reason???' - warn sprintf("WARNING: FAILED to run method[%s]on id[%s]record[%s]",#' - $method, - $id, - join(":",%$rec), - ) unless $ret; - } - - warn "HERE"; - $table->close; - warn "HERE"; - $wdb->close; - warn "HERE"; - $sel_sth->finish; -} - -# A wrapper function for fetchrow_array and fetchrow_hashref -sub fetchrow { - my($self,$sth,$what) = @_; - if ($] < 5.007) { - return $sth->$what; - } else { - require Encode; - if (wantarray) { - my @arr = $sth->$what; - for (@arr) { - defined && /[^\000-\177]/ && Encode::_utf8_on($_); - } - return @arr; - } else { - my $ret = $sth->$what; - if (ref $ret) { - for my $k (keys %$ret) { - defined && /[^\000-\177]/ && Encode::_utf8_on($_) for $ret->{$k}; - } - return $ret; - } else { - defined && /[^\000-\177]/ && Encode::_utf8_on($_) for $ret; - return $ret; - } - } - } -} - -sub version { - my($self) = @_; - return $self->{VERSION} if defined $self->{VERSION}; - my $version = $VERSION; - for my $m (grep {! m!/Test/!} grep /pause_1999/, keys %INC) { - $m =~ s|/|::|g; - $m =~ s|\.pm$||; - my $v = $m->VERSION || 0; - warn "Warning: Strange versioning style in m[$m]v[$v]" if $v < 10; - $version = $v if $v > $version; - } - $version; -} - -1; - -=back - -=cut diff --git a/lib/pause_1999/message.pm b/lib/pause_1999/message.pm deleted file mode 100644 index 62ed95b5a..000000000 --- a/lib/pause_1999/message.pm +++ /dev/null @@ -1,42 +0,0 @@ -# -*- Mode: cperl; coding: utf-8 -*- -package pause_1999::message; -use base 'Class::Singleton'; -use pause_1999::main; -use strict; -use utf8; -our $VERSION = "946"; - -sub as_string { - my $self = shift; - my $mgr = shift; - my $user = $mgr->{HiddenUser}{userid} || $mgr->{User}{userid} or return; - my @m; - my $dbh = $mgr->connect; - my $sth = $dbh->prepare("select * from messages where mto=? AND mstatus='active'"); - $sth->execute($user); - if ($sth->rows > 0) { - push @m, qq{
}; - - push @m, qq{

This is the Message Board for user - $user. On the message board you see messages posted by - an admin to a user in case that email doesn't work:

}; - - push @m, qq{
}; - while (my $rec = $sth->fetchrow_hashref) { - push @m, qq{
$rec->{created} from $rec->{mfrom}\@cpan.org
}; - push @m, qq{
}; - push @m, $mgr->escapeHTML($rec->{message}); - push @m, qq{
}; - } - push @m, qq{
}; - - push @m, qq{

Note: Only the poster of a message can - delete it from the message board. Please contact them, so that - they clear the board for you.

}; - - push @m, qq{
\n}; - } - @m; -} - -1; diff --git a/lib/pause_1999/pausegif.pm b/lib/pause_1999/pausegif.pm deleted file mode 100644 index e89d4dae3..000000000 --- a/lib/pause_1999/pausegif.pm +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/perl -- -*- Mode: cperl; coding: utf-8; VAR: VALUE; ... -*- -package pause_1999::pausegif; -use base 'Class::Singleton'; -use pause_1999::main; -use strict; -use vars qw( $Exeplan ); -our $VERSION = "85"; - -sub as_string { - my pause_1999::pausegif $self = shift; - my pause_1999::main $mgr = shift; - my $gif = $mgr->can_png ? "png" : "jpg"; - qq{PAUSE Logo}; -} - -1; diff --git a/lib/pause_1999/saxfilter01.pm b/lib/pause_1999/saxfilter01.pm deleted file mode 100644 index e68c86169..000000000 --- a/lib/pause_1999/saxfilter01.pm +++ /dev/null @@ -1,68 +0,0 @@ -=pod - -Replace all relative links with links to www.cpan.org. - -These documents all live on CPAN and relative links are the correct -way to deal with them in the real documents. But when we offer them on -PAUSE, the links are not correct and we need to do some rewriting. - -=cut - -package pause_1999::saxfilter01; -use base XML::SAX::Base; -use strict; -our $VERSION = "512"; - -sub start_element { - my($self,$prop) = @_; - if ($prop->{Name} eq "body") { - $self->{InBody}++; - return; - } - return unless $self->{InBody}; - if ($prop->{Name} eq "a") { - my $href; - - $href = $prop->{Attributes}{"{}href"}{Value} if - $prop->{Attributes} && - $prop->{Attributes}{"{}href"} && - $prop->{Attributes}{"{}href"}{Value}; - - if (0) { - } elsif (!$href) { - # anchor - } elsif ($href =~ m{ ^ (?:ftp|http|https) : // }x ) { - # absolute - } elsif ($href =~ m{ ^ (?:mailto) : }x ) { - # absolute - } elsif ($href =~ m{^\#}) { - # anchor - } else { - $prop->{Attributes}{"{}href"}{Value} =~ s{^}{http://www.cpan.org/modules/}; - } - } - - $self->SUPER::start_element($prop); -} - -sub end_element { - my($self,$prop) = @_; - if ($prop->{Name} eq "body") { - $self->{InBody}--; - return; - } - return unless $self->{InBody}; - $self->SUPER::end_element($prop); -} - -sub characters { - my($self,$prop) = @_; - return unless $self->{InBody}; - $self->SUPER::characters($prop); -} - -sub doctype_decl { return; } - -sub processing_instruction { return; } - -1; diff --git a/lib/pause_1999/speedlinkgif.pm b/lib/pause_1999/speedlinkgif.pm deleted file mode 100644 index 175fd8c0b..000000000 --- a/lib/pause_1999/speedlinkgif.pm +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/perl -- -*- Mode: cperl; coding: utf-8 -*- - - - -=pod - -From 1997 or 1998 till 2002-12-31, Speed-Link was our sponsor, hence -the filename. - -From 2003-01-01, Loomes is taking over. - -From 2003-11-27, Fiz-Chemie is the Sponsor. - -=cut - -package pause_1999::speedlinkgif; -use base 'Class::Singleton'; -use pause_1999::main; -use strict; -use vars qw( $Exeplan ); -our $VERSION = "1069"; - -sub as_string { - my $self = shift; - my $mgr = shift; - my $pngjpg = $mgr->can_png ? "png" : "jpg"; - my $pnggif = $mgr->can_png ? "png" : "gif"; - my $validator_href = "http://validator.w3.org/check/referer"; - my $validator_comment = ""; - if ($mgr->{REQ}->path =~ /authen/ or $mgr->myurl->scheme eq "https") { - $validator_href = "http://validator.w3.org/file-upload.html"; - $validator_comment = q{
To validate, download page first.

}; - } - my $version = $mgr->version; - qq{ - - - - - - - - - - -
 
Rev: $version
$validator_comment
- Valid CSS! - - - Valid XHTML 1.0! - -
-}; -} - -1; diff --git a/lib/pause_1999/startform.pm b/lib/pause_1999/startform.pm deleted file mode 100644 index c65e073ed..000000000 --- a/lib/pause_1999/startform.pm +++ /dev/null @@ -1,50 +0,0 @@ -package pause_1999::startform; -use base 'Class::Singleton'; -use pause_1999::main; - -use strict; -our $VERSION = "854"; - -sub as_string { - my pause_1999::startform $self = shift; - my pause_1999::main $mgr = shift; - my @m; - my $myurl = $mgr->myurl; - my $can_unparse = $myurl->can("unparse"); -# my $me = $can_unparse ? $myurl->unparse : $myurl->as_string; -# $me =~ s/\?.*//; # unparse keeps the querystring which breaks XHTML - my $me = $myurl->path; - - # since we have a perlbal that does the https for us, we can easily - # have a wrong scheme in this $me and a wrong hostname, e.g. - # action="http://pause.perl.org:443/pause/authenquery" - warn "DEBUG: can_unparse[$can_unparse]me[$me]"; - - my $enctype; - my $method; - - # 2005 I decided to prefer post *always*, but then for example links - # to peek_perms stopped to work, so we should really decide - # case-by-case if we want get or post - if ($mgr->can_multipart && $mgr->need_multipart) { - $enctype = "multipart/form-data"; - $method = "post"; - } elsif (defined $mgr->prefer_post and $mgr->prefer_post) { - $enctype = "application/x-www-form-urlencoded"; - $method = "post"; - } else { - $enctype = "application/x-www-form-urlencoded"; - $method = "get"; - } - if ($PAUSE::Config->{TESTHOST}) { - warn "DEBUG: me[$me]enctype[$enctype]method[$method]"; - push @m, qq{

[ATTN: Form going to post to $me]

}; - } - push @m, qq{
}; - @m; -} - -1; diff --git a/lib/pause_1999/usermenu.pm b/lib/pause_1999/usermenu.pm deleted file mode 100644 index 6e0133023..000000000 --- a/lib/pause_1999/usermenu.pm +++ /dev/null @@ -1,138 +0,0 @@ -# -*- Mode: cperl; coding: utf-8 -*- -package pause_1999::usermenu; -use base 'Class::Singleton'; -use pause_1999::main; -use strict; -use utf8; -our $VERSION = "854"; - -sub as_string { - my $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - my $user = $req->user; - my $myurl = $mgr->myurl; - my $server = $myurl->can("host") ? $myurl->host : $myurl->hostname; - if (my $port = $myurl->port) { - if ($port != 80) { - warn "DEBUG: url[$myurl]port[$port]"; - $server .= ":$port"; - } - } - - if (0) { - $req->logger->({level => 'error', message => sprintf( - "Watch: server[%s]at[%s]line[%d]", - $server, - __FILE__, - __LINE__, - )}); - } - my @m; - push @m, qq{}; - my $activecolor = $mgr->{ActiveColor}; - unless ($user) { - push @m, qq{\n}; - - } - - - # warn "allowaction[@{$mgr->{AllowAction}||[]}]"; - my %grouplabel = ( - public => "Public", - user => "User", - mlrepr => "Mailinglists", - modmaint => "ModListMaint", - admin => "Admin", - ); - my @offer_groups = "public"; - if ($mgr->{User}{userid}) { - push @offer_groups, "user"; - for my $g (qw(mlrepr modmaint admin)) { - if (exists $mgr->{UserGroups}{$g} || exists $mgr->{UserGroups}{"admin"}) { - push @offer_groups, $g; - } - } - } - for my $priv (@offer_groups) { - last if $priv eq "user" and ! $mgr->{User}{userid}; - last if $priv eq "admin" and ! exists $mgr->{UserGroups}{admin}; - push @m, qq{}; - my $Lscat = ""; - for my $action ( - sort { - $mgr->{ActionTuning}{$a}{cat} - cmp - $mgr->{ActionTuning}{$b}{cat} - } - @{$mgr->{AllowAction}||[]} - ) { - - my $confpriv = $mgr->{ActionTuning}{$action}{priv}; - unless ($confpriv) { - warn "action[$action] has no confpriv!"; - $confpriv = "admin"; - } - next unless $confpriv eq $priv; - - my $verbose = $mgr->{ActionTuning}{$action}{verb} - if exists $mgr->{ActionTuning}{$action}; - $verbose ||= $action; - my $class; - warn "action undef" unless defined $action; - warn "mgr->Action undef" unless defined $mgr->{Action}; - my $cat = $mgr->{ActionTuning}{$action}{cat}; - if (substr($cat,0,1) =~ tr/A-Z//) { - my($scat) = $cat =~ m|.+?/\d\d(.+?)/|; - if ($scat ne $Lscat) { - push @m, qq{\n}; - $Lscat = $scat; - } - } - my $activemarkerleft = ""; - my $activemarkerright = ""; - my $activecol2 = ""; - if ($action eq $mgr->{Action}) { - $class = "activemenu"; - # $activemarkerleft = "\x{21d2} "; # Pfeil - - $activemarkerleft = "> "; # : "\x{25b6} "; # Dreieck - - #### IE6 alert. If I send this \x{25b6} with 5.6.1, then IE6 - #### cannot display a single page, as "Gregor Mosheh, B.S." - #### reported. - - # $activemarkerleft = "\x{266c} "; # 2 Sechzehntelnoten - # $activemarkerleft = "\x{300b} "; # hohes Zeichen wie ">>" - # $activemarkerright = "\x{21d0}"; - $activecol2 = ""; # "\x{25c0}"; - } else { - $class = "menuitem"; - } - push @m, qq{\n}; - } - } - push @m, qq{
}; - push @m, sprintf( - qq{%s%s%s%s}, - $mgr->{QueryURL}, - $action, - $activemarkerleft, - "", # $mgr->{ActionTuning}{$action}{cat}, - $verbose, - $activemarkerright, - ); - push @m, qq{
\n}; - @m; -} - -1; diff --git a/lib/pause_1999/userstatus.pm b/lib/pause_1999/userstatus.pm deleted file mode 100644 index a338502f3..000000000 --- a/lib/pause_1999/userstatus.pm +++ /dev/null @@ -1,63 +0,0 @@ -# -*- Mode: cperl; coding: utf-8 -*- -package pause_1999::userstatus; -use base 'Class::Singleton'; -use pause_1999::main; -use strict; -use utf8; -our $VERSION = "946"; - -sub as_string { - my $self = shift; - my $mgr = shift; - my $req = $mgr->{REQ}; - my $user = $req->user; - my $server = $mgr->myurl->can("host") ? $mgr->myurl->host : $mgr->myurl->hostname; - # $req->logger->({level => 'error', message => sprintf "Watch: server[%s]at[%s]line[%d]", $server, __FILE__, __LINE__}); - my $activecolor = $mgr->{ActiveColor}; - return unless $user && $user ne "-"; - my @m; - push @m, qq{}; - my($encr,$class); - if ($mgr->is_ssl) { - $encr = 1; - $class = "statusencr"; - } else { - $encr = 0; - $class = "statusunencr"; - } - - my $hu = ""; - if ($mgr->{HiddenUser}{userid} - && - $mgr->{HiddenUser}{userid} ne $mgr->{User}{userid} - ) { - $hu = sprintf qq{acting as %s <%s>
}, - $mgr->{HiddenUser}{userid}, - $mgr->escapeHTML( - $mgr->{HiddenUser}{secretemail} - || - $mgr->{HiddenUser}{email} - || - "No email???" - ); - } - push @m, sprintf( - qq{}, - $class, - $user, - $mgr->escapeHTML( - $mgr->{User}{secretemail} - || - $mgr->{User}{email} - || - "No email???" - ), - $hu, - $encr ? "encrypted session" : "unencrypted session", - ); - - push @m, qq{
%s <%s>
%s%s
\n}; - @m; -} - -1; diff --git a/t/lib/pause_1999/Test/Config.pm b/t/lib/pause_1999/Test/Config.pm deleted file mode 100644 index 028a1ed42..000000000 --- a/t/lib/pause_1999/Test/Config.pm +++ /dev/null @@ -1,37 +0,0 @@ -package pause_1999::Test::Config; - -use strict; -use warnings; -use Test::More; - -BEGIN { $INC{'PrivatePAUSE.pm'} = 1; } - -use PAUSE; - -sub set_mail_mailer { - my ( $class, $args ) = @_; - $PAUSE::Config->{MAIL_MAILER} = $args; - return $PAUSE::Config; -} - -sub set_authen_db { - my ( $class, $mysql ) = @_; - return $class->_set_db( $mysql, 'AUTHEN' ); -} - -sub set_mod_db { - my ( $class, $mysql ) = @_; - return $class->_set_db( $mysql, 'MOD' ); -} - -sub _set_db { - my ( $class, $mysql, $name ) = @_; - - $PAUSE::Config->{$name . '_DATA_SOURCE_NAME'} = $mysql->dsn; - $PAUSE::Config->{$name . '_DATA_SOURCE_USER'} = undef; - $PAUSE::Config->{$name . '_DATA_SOURCE_PW'} = undef; - - return $PAUSE::Config; -} - -1; diff --git a/t/lib/pause_1999/Test/Environment.pm b/t/lib/pause_1999/Test/Environment.pm deleted file mode 100644 index b515d05e4..000000000 --- a/t/lib/pause_1999/Test/Environment.pm +++ /dev/null @@ -1,172 +0,0 @@ -package pause_1999::Test::Environment; - -use Moose; -use Plack::Util; -use Plack::Test; -use Test::WWW::Mechanize::PSGI; - -use Class::MOP::Class; -use Plack::Test::MockHTTP; -use Capture::Tiny qw/capture_stderr/; -use Path::Tiny; -our $AppRoot = path(__FILE__)->parent->parent->parent->parent->parent->realpath; - -=head1 SYNOPSIS - -Set up a whole web environment ready to go. Currently supports: - -my ( $env, $author ) = pause_1999::Test::Environment->new_with_author( - username => 'ANDK', - asciiname => 'Andreas K', -); - -You now have databases: - - $env->authen_db->dbh - -A user in C<$author> and in the DB - -And a site model: - - $env->site_model( $author ) - ->change_passwd - ->change_passwd__submit( 'moo', 'moo' ); - -=cut - -use pause_1999::Test::MySQL; -use pause_1999::Test::Config; -use pause_1999::Test::SiteModel; -use pause_1999::Test::Fixtures::Author; - -has 'authen_db' => ( - is => 'ro', - isa => 'pause_1999::Test::MySQL', - lazy_build => 1, -); -sub authen_dbh { - my $self = shift; - $self->authen_db->dbh; -} - -sub _build_authen_db { - my $self = shift; - my $db = pause_1999::Test::MySQL->new( - schemas => ["$AppRoot/doc/authen_pause.schema.txt"] ); - pause_1999::Test::Config->set_authen_db($db); - return $db; -} - -has 'mod_db' => ( - is => 'ro', - isa => 'pause_1999::Test::MySQL', - lazy_build => 1, -); -sub mod_dbh { - my $self = shift; - $self->mod_db->dbh; -} - -sub _build_mod_db { - my $self = shift; - my $db - = pause_1999::Test::MySQL->new( schemas => ["$AppRoot/doc/mod.schema.txt"] ); - pause_1999::Test::Config->set_mod_db($db); - return $db; -} - -has 'plack_app' => ( - is => 'ro', - default => sub { Plack::Util::load_psgi "$AppRoot/app_1999.psgi" }, -); - -has 'plack_test' => ( - is => 'ro', - lazy_build => 1, -); - -sub _build_plack_test { - my $self = shift; - my $metaclass = Class::MOP::Class->create_anon_class( - superclasses => ['Plack::Test::MockHTTP'] ); - - my $plack_test = Plack::Test->create( $self->plack_app ); - $metaclass->rebless_instance($plack_test); - - my $method = $metaclass->add_method( - 'request', - sub { - my ( $obj, $req ) = @_; - my $result; - my ($stderr) = capture_stderr { - $result = Plack::Test::MockHTTP::request( $obj, $req ); - }; - $self->_filter_stderr($stderr); - return $result; - - } - ); - - return $plack_test; -} - -has 'mail_mailer' => ( - is => 'ro', - isa => 'ArrayRef[Str]', - default => sub {['testfile']}, -); - -sub BUILD { - my $self = shift; - pause_1999::Test::Config->set_mail_mailer( $self->mail_mailer ); -} - -sub new_with_author { - my ( $class, %options ) = @_; - my $self = $class->new(); - - my $author = pause_1999::Test::Fixtures::Author->new( - environment => $self, - %options, - ); - - return ( $self, $author ); -} - -sub site_model { - my ( $self, $author ) = @_; - my $metaclass = Class::MOP::Class->create_anon_class( - superclasses => [ - 'Test::WWW::Mechanize::PSGI', @Test::WWW::Mechanize::PSGI::ISA - ] - ); - - my $mech = Test::WWW::Mechanize::PSGI->new( app => $self->plack_app ); - $metaclass->rebless_instance($mech); - - my $method = $metaclass->add_method( - 'simple_request', - sub { - my ( $obj, $req ) = @_; - my $result; - my ($stderr) = capture_stderr { - $result = Test::WWW::Mechanize::PSGI::simple_request( $obj, - $req ); - }; - $self->_filter_stderr($stderr); - return $result; - - } - ); - - my $model = pause_1999::Test::SiteModel->new( mech => $mech ); - $model->set_user($author) if $author; - return $model; -} - -sub _filter_stderr { - my ( $self, $stderr ) = @_; - Test::More::note($stderr) unless $ENV{'HUSH_PAUSE_STDERR'}; -} - -1; diff --git a/t/lib/pause_1999/Test/Fixtures/Author.pm b/t/lib/pause_1999/Test/Fixtures/Author.pm deleted file mode 100644 index 13d2b2279..000000000 --- a/t/lib/pause_1999/Test/Fixtures/Author.pm +++ /dev/null @@ -1,116 +0,0 @@ -package pause_1999::Test::Fixtures::Author; - -use Moose; - -# Create a simple user - -=head1 SYNOPSIS - - my $author = pause_1999::Test::Fixtures::Author->new( - environment => $self, - username => 'ANDK', - asciiname => 'Andreas', - ); - -=cut - -has 'environment' => ( - is => 'ro', - isa => 'pause_1999::Test::Environment', - weak_ref => 1, -); - -has [qw/username asciiname/] => ( - is => 'ro', - isa => 'Str', - required => 1, -); - -has 'password_crypted' => ( - is => 'ro', - isa => 'Str', - lazy_build => 1, -); - -sub _build_password_crypted { - my $self = shift; - return crypt( $self->password, 'zz' ); -} - -has 'email' => ( - is => 'ro', - isa => 'Str', - lazy_build => 1, -); - -sub _build_email { - my $self = shift; - return $self->username . '@example.com'; -} - -has 'cpan_mail_alias' => ( - is => 'ro', - isa => 'Str', - default => 'publ', -); - -has 'fullname' => ( - is => 'ro', - isa => 'Str', - lazy_build => 1, -); - -sub _build_fullname { $_[0]->asciiname } - -has 'password' => ( - is => 'ro', - isa => 'Str', - default => sub { rand(999) }, -); - -has 'ustatus' => ( - is => 'ro', - isa => 'Str', - default => 'active', -); - -has 'ugroup' => ( - is => 'ro', - isa => 'ArrayRef[Str]', - default => sub { [] }, -); - -sub BUILD { - my $self = shift; - - my $usertable = $self->environment->authen_dbh->prepare( " - INSERT INTO usertable (user, password, secretemail) - VALUES (?, ?, ?) - " ); - $usertable->execute( $self->username, $self->password_crypted, $self->email ); - - my $grouptable = $self->environment->authen_dbh->prepare( " - INSERT INTO grouptable (user, ugroup) - VALUES (?, ?) - " ); - for my $ugroup ( @{ $self->ugroup } ) { - $grouptable->execute( $self->username, $ugroup ); - } - - my $mod_users = $self->environment->mod_dbh->prepare( " - INSERT INTO users (userid, email, ustatus, fullname, asciiname, cpan_mail_alias, ustatus_ch) - VALUES (?, ?, ?, ?, ?, ?, NOW()) - " ); - $mod_users->execute( - $self->username, $self->email, $self->ustatus, - $self->fullname, $self->asciiname, $self->cpan_mail_alias, - ); -} - -sub req { - my ( $self, $req ) = @_; - $req->headers->authorization_basic( $self->username, $self->password ); - return $req; -} - -1; diff --git a/t/lib/pause_1999/Test/MySQL.pm b/t/lib/pause_1999/Test/MySQL.pm deleted file mode 100644 index fa34d097f..000000000 --- a/t/lib/pause_1999/Test/MySQL.pm +++ /dev/null @@ -1,172 +0,0 @@ -package pause_1999::Test::MySQL; - -use Test::Requires qw(Test::mysqld); - -use Moose; -use Test::mysqld; -use Test::More; -use DBI; -use File::Temp qw/tempfile/; -use Capture::Tiny qw/capture_merged/; -use Path::Tiny; - -$SIG{INT} = sub { die "caught SIGINT, shutting down mysql\n" }; - -=head2 SYNOPSIS - - my $db - = pause_1999::Test::MySQL->new( schemas => ['doc/mod.schema.txt'] ); - - my $dbh = $db->dbh; - - # Drop straight in to the mysql console: - $dbh->debug_console - -=cut - -# These are the only caller-configurable parts - -# SQL to load at instantiation -has 'schemas' => ( - is => 'ro', - isa => 'ArrayRef[Str]', - default => sub {[]}, -); - -# Location of the mysql client binary -has 'mysql_client' => ( - is => 'ro', - isa => 'Str', - default => ($ENV{'PAUSE_MYSQL_CLIENT'} || 'mysql'), -); - -# These are the public methods - -# DBH -has 'dbh' => ( - is => 'ro', - isa => 'DBI::db', - lazy_build => 1, -); - -# Drops you in to `mysql` connected to the database -sub debug_console { - my $self = shift; - $self->run_mysql(); -} - -sub dsn { - my $self = shift; - return $self->mysqld->dsn( dbname => $self->_db_name ); -} - -# Private attributes - -# Object-specific database name -has '_db_name' => ( - is => 'ro', - isa => 'Str', - lazy_build => 1, -); - -sub _build__db_name { - my $self = shift; - return 'db_' . ( $self + 0 ) . int(rand 999_999); -} - -# Location of the config file for the mysql client -has '_auth_file' => ( - is => 'ro', - isa => 'Str', - lazy_build => 1, -); - -sub _build__auth_file { - my $self = shift; - my ($fh, $filename) = tempfile(); - my $args = $self->dsn; - $args =~ s/DBI:mysql://; - - my %options = map { split /=/ } split( /;/, $args ); - $options{'database'} = delete $options{'dbname'}; - $options{'socket'} = delete $options{'mysql_socket'}; - $options{'default-character-set'} = 'utf8'; - - my $auth_content = join "\n", "[client]", - map { "$_=" . $options{$_} } keys %options; - - print $fh $auth_content; - close $fh; - return $filename; -} - -sub BUILD { - my $self = shift; - my $dbh = $self->dbh; - - for my $schema ( @{$self->schemas} ) { - note("Loading schema: $schema"); - my $body = path($schema)->slurp; - for (grep $_, split /;\n/s, $body) { - $dbh->do($_); - } - } -} - - - -sub _build_dbh { - my $self = shift; - my $dbname = $self->_db_name; - - my $master_dbh = DBI->connect( - $self->mysqld->dsn( - dbname => 'test', - 'default-character-set' => 'utf8' - ) - ); - - note("Creating new MySQL database: $dbname"); - $master_dbh->do( 'CREATE DATABASE ' . $dbname ) - or die $master_dbh->errstr; - - # Connect to it - my $dbh = DBI->connect( $self->mysqld->dsn( dbname => $dbname ), - '', '', { RaiseError => 1 } ); - - return $dbh; -} - -sub run_mysql { - my $self = shift; - my $cmd = shift || ''; - $cmd = "< $cmd" if $cmd; - my $exe = $self->mysql_client; - system(sprintf("%s --defaults-extra-file=%s %s", $exe, $self->_auth_file, $cmd)); -} - -# mysqld singleton. We might have different tests that want to execute in -# seperate DBs, but I can't see why we'd want to be running more than one -# mysqld, so we do a singleton here -our $mysqld; - -sub mysqld { - my $self = shift; - return $mysqld if $mysqld; - - note("Starting a test mysqld"); - note( - capture_merged( - sub { $mysqld = Test::mysqld->new( - my_cnf => { 'skip-networking' => '' } - ); - } - ) - ); - die $Test::mysqld::errstr unless $mysqld; - note("mysqld started"); - - return $mysqld; -} - -1; diff --git a/t/lib/pause_1999/Test/SiteModel.pm b/t/lib/pause_1999/Test/SiteModel.pm deleted file mode 100644 index f37277887..000000000 --- a/t/lib/pause_1999/Test/SiteModel.pm +++ /dev/null @@ -1,93 +0,0 @@ -package pause_1999::Test::SiteModel; - -use Moose; -use Scalar::Util qw/blessed/; -extends 'WWW::Mechanize::Boilerplate'; -with 'pause_1999::Test::SiteModel::Parser'; - -# Define a model that represents the web front-end so that we don't end up -# writing a lot of fragile tests just before the HTML and form parameters change -# underneath us. -# -# Allows us to do something like this: -# $m->change_passwd->change_passwd__submit('foo', 'foo'); -# Which goes to the change_passwd page and then changes the password, while -# doing all the boring boilerplate tasks like checking requests succeeded. - -sub url { - my $self = shift; - my $atom = shift || $self; - return '/pause/authenquery?ACTION=' . $atom -} - -sub set_user { - my ( $self, $user ) = @_; - my ( $username, $password ) - = blessed $user - ? ( $user->username, $user->password ) - : ( $user->{username}, $user->{password} ); - - $self->mech->{'basic_authentication'} = {}; - $self->mech->credentials( $username, $password ); - return $self; -} - -sub clear_user { - my $self = shift; - $self->mech->{'basic_authentication'} = {}; - $self->mech->{'__username'} = ""; - $self->mech->{'__password'} = ""; - return $self; -} - -my %fetch_pages = ( - homepage => '/pause/authenquery', - pausecss => '/pause/pause.css', - unknownpath => '/.not-well-known/acme-challenge/jhoQM', - challengereadme => '/.well-known/acme-challenge/README', -); -while ( my ( $atom, $desc ) = each %fetch_pages ) { - __PACKAGE__->create_fetch_method( - method_name => $atom, - page_description => $atom, - page_url => $fetch_pages{$atom}, - ); -} - -# Create many simple fetch methods -%fetch_pages = ( - change_passwd => 'Change Password', - delete_files => 'Delete files', - email_for_admin => 'Look up the forward email address', - show_files => 'Show my files', -); -while ( my ( $atom, $desc ) = each %fetch_pages ) { - __PACKAGE__->create_fetch_method( - method_name => $atom, - page_description => $desc, - page_url => url($atom), - ); -} - -__PACKAGE__->create_form_method( - method_name => 'change_passwd__submit', - form_number => 1, - form_description => 'change password form', - assert_location => url('change_passwd'), - transform_fields => sub { - my ( $self, $pw1, $pw2 ) = @_; - return { - pause99_change_passwd_pw1 => $pw1, - pause99_change_passwd_pw2 => $pw2, - }; - }, -); - -__PACKAGE__->create_link_method( - method_name => 'email_for_admin__yaml', - link_description => 'YAML', - find_link => { text => 'YAML' }, - assert_location => url('email_for_admin'), -); - -1; diff --git a/t/lib/pause_1999/Test/SiteModel/Parser.pm b/t/lib/pause_1999/Test/SiteModel/Parser.pm deleted file mode 100644 index 3ae5c8d43..000000000 --- a/t/lib/pause_1999/Test/SiteModel/Parser.pm +++ /dev/null @@ -1,128 +0,0 @@ -package pause_1999::Test::SiteModel::Parser; - -use Moose::Role; -use HTML::TreeBuilder; -use YAML::XS qw/Load/; -requires 'mech'; - -# See the SiteModel for the basic justification -# -# Extend the SiteModel to be able to ->parse() certain pages -# -# Add the URL fragment to %pages, with a list of parsers to be used to extract -# data from the page. Parsers are by name in %parsers, and receive a -# HTML::TreeBuilder object. - -our %pages = ( - homepage => ['basic'], - title_only => ['title','header'], - delete_files => [qw/basic author_directory file_list/], - email_for_admin => [qw/basic email_for_admin/], - email_for_admin__yaml => [qw/yaml/], - show_files => [qw/basic author_directory file_list/], -); - -our %parsers = ( - author_directory => sub { - my $tree = shift; - my ($directory) = ( $tree->as_text =~ m!Files in directory (.+?) ! ); - return $directory; - }, - basic => sub { - my $tree = shift; - my $status_box = $tree->find_by_attribute( class => 'statusunencr' ) - || $tree->find_by_attribute( class => 'statusencr' ); - - my ( $username, $email ) = ( $status_box->as_text =~ m/(.+) <(.+)>/ ); - - return { - username => $username, - email => $email, - }; - }, - email_for_admin => sub { - my $tree = shift; - my @all_tables = $tree->look_down( _tag => 'table' ); - my @content_tables = $all_tables[2]->look_down( _tag => 'table' ); - my $author_table = $content_tables[2]; - my %authors - = map { length $_->as_text == 0 ? undef : $_->as_text } - $author_table->look_down( _tag => 'td' ); - return \%authors; - }, - file_list => sub { - my $tree = shift; - my $pre = $tree->look_down( _tag => 'pre' ); - return [] unless $pre; - my @files = map { - my $line = $_; - if ( $line =~ m/([^ ]+)\s+(\d+)\s+([^<]+)/ ) { - { filename => $1, size => $2, date => $3 }; - } - else { - (); - } - } split( m!
|\n!, $pre->as_HTML ); - return \@files; - }, - header => sub { - my $tree = shift; - my $status_box = $tree->find_by_attribute( _tag => 'h2', class => 'firstheader' ); - return $status_box->as_text; - }, - title => sub { - my $tree = shift; - my $status_box = $tree->find_by_attribute( _tag => 'title' ); - return $status_box->as_text; - }, - yaml => sub { - my ( $tree, $content ) = @_; - return scalar Load $content; - }, -); - -sub parse { - my $self = shift; - - my $url = $self->mech->uri; - $url =~ s!http://[^/]+!!; - - # Check we know how to parse this page - my $page_spec_force = shift; - my $page_spec; - - if ( $page_spec_force ) { - $page_spec = $pages{ $page_spec_force } || die "Unknown page spec [$page_spec_force]"; - } - else { - if ($url =~ m!/pause/authenquery\?ACTION=email_for_admin[;&]OF=YAML! ) - { - $page_spec = $pages{'email_for_admin__yaml'}; - } - elsif ( $url =~ m!/pause/authenquery\?ACTION=(.+)! ) { - $page_spec = $pages{$1} - || die "Don't know how to autoparse [$url] ($1)"; - } - elsif ( $url eq '/pause/authenquery' ) { - $page_spec = $pages{'homepage'}; - } - else { - die "Don't know how to autoparse [$url]"; - } - } - - # Get the TreeBuilder for ir - my $tree = HTML::TreeBuilder->new(); - $tree->parse( $self->mech->content ); - $tree->eof(); - $tree->elementify(); - - my %result = map { - my $parser = $parsers{$_} || die "Unknown parser [$_]"; - $_ => $parser->( $tree, $self->mech->content ); - } @$page_spec; - - return \%result; -} - -1;