package PgCommitFest::Handler; require PgCommitFest::CommitFest; require PgCommitFest::CommitFestTopic; require PgCommitFest::Patch; require PgCommitFest::PatchComment; require PgCommitFest::Request; use strict; use warnings; use FCGI; use POSIX; use Template; our %ACTION = ( 'login' => \&PgCommitFest::Handler::login, 'logout' => \&PgCommitFest::Handler::logout, 'commitfest_activity' => \&PgCommitFest::CommitFest::activity, 'commitfest_activity.rss' => \&PgCommitFest::CommitFest::activity_rss, 'commitfest_delete' => \&PgCommitFest::CommitFest::delete, 'commitfest_form' => \&PgCommitFest::CommitFest::form, 'commitfest_search' => \&PgCommitFest::CommitFest::search, 'commitfest_view' => \&PgCommitFest::CommitFest::view, 'commitfest_topic_delete' => \&PgCommitFest::CommitFestTopic::delete, 'commitfest_topic_form' => \&PgCommitFest::CommitFestTopic::form, 'commitfest_topic_search' => \&PgCommitFest::CommitFestTopic::search, 'patch_bump' => \&PgCommitFest::Patch::bump, 'patch_form' => \&PgCommitFest::Patch::form, 'patch_delete' => \&PgCommitFest::Patch::delete, 'patch_view' => \&PgCommitFest::Patch::view, 'patch_comment_form' => \&PgCommitFest::PatchComment::form, 'patch_comment_delete' => \&PgCommitFest::PatchComment::delete ); sub main_loop { $SIG{'PIPE'} = sub { die "SIGPIPE\n"; }; while (1) { # Invoke main request handler and save any resulting error message. my $r = PgCommitFest::Request->new(); last if !defined $r; eval { handler($r); if (! $r->response_sent) { $r->error_exit('No response was generated.'); } }; my $err = $@; # Roll back any uncommited database work. $r->db->tidy if $r->db_is_connected; # Print errors to system log. if ($err && $err ne "SIGPIPE\n" && $err ne "DONE\n") { print STDERR $err; if (defined $r && ! $r->response_sent) { $r->set_title('Internal Server Error'); $r->render_template('error', { 'error_list' => [ $err ] }); } } } } sub handler { my ($r) = @_; my ($action, $extrapath); my $url = $ENV{'REQUEST_URI'}; $url =~ s/\?.*//; # Remove questionmark and anything after it if ($url eq '/') { $action = 'commitfest_search'; } elsif ($url =~ /^\/action\/([^\/]*)(\/(.*))?$/) { $action = $1; $extrapath = $3; } if (defined $action && exists $ACTION{$action}) { $ACTION{$action}->($r, $extrapath); } else { $r->header('Status', '404 Not Found'); $r->set_title('Page Not Found'); $r->render_template('404'); } return; } sub login { my ($r) = @_; # Prompt for user ID and password. $r->set_title('Log in'); $r->add_control('userid', 'text', 'User ID', 'required' => 1); $r->add_control('password', 'password', 'Password', 'required' => 1); $r->add_control('uri', 'hidden', 'URI'); my %value = $r->initialize_controls(); # Handle cancellation. $r->redirect('/') if $r->cgi('cancel'); # Attempt to validate login. if ($r->cgi('go') && ! $r->is_error) { my $pg_login_db = PgCommitFest::DB->connect(defined $ENV{'PGCOMMITFEST_LOGIN_DB'} ? $ENV{'PGCOMMITFEST_LOGIN_DB'} : 'dbi:Pg:dbname=pgcommitfest user=pgcommitfest', defined $ENV{'PGCOMMITFEST_LOGIN_DB_USERNAME'} ? $ENV{'PGCOMMITFEST_LOGIN_DB_USERNAME'} : '', defined $ENV{'PGCOMMITFEST_LOGIN_DB_PASSWORD'} ? $ENV{'PGCOMMITFEST_LOGIN_DB_PASSWORD'} : '' ); my $u = $pg_login_db->select_one(<disconnect; if (defined $u) { my $random_bits; open(RANDOM_BITS, 'db->insert('session', { 'id' => $session_cookie, 'userid' => $u->{'userid'} }); $r->db->commit; my $expires = strftime("%a, %d-%b-%Y %H:%M:%S GMT", localtime(time + (86400 * 7))); $r->header('Set-Cookie', "session=$session_cookie; path=/; expires=$expires"); $r->redirect($value{'uri'} ne '' ? $value{'uri'} : '/'); } else { $r->error('Invalid user ID or password.'); } } # Display template. $r->render_template('login'); } sub logout { my ($r) = @_; $r->header('Set-Cookie', "session=; path=/"); my $session = $r->cookie('session'); if (defined $r->cookie('session')) { $r->db->delete('session', { 'id' => $r->cookie('session') }); $r->db->commit(); } $r->redirect('/'); } 1;