#!/usr/bin/perl # reading-list.cgi - create a list of journal titles for regular reading # Eric Lease Morgan # August 20, 2007 - added about page # July 13, 2007 - added better messages, ability to add & delete, dynamic menu # can't seem to set the expiration value for sessions # July 12, 2007 - first investigations playing with MyLibrary::Patron # require/use use CGI; use CGI::Carp qw(fatalsToBrowser); use MyLibrary::Core; use MyLibrary::Patron; use MyLibrary::Auth::Basic; use strict; # define constants use constant TEMPLATE => 'etc/template.txt'; use constant HOME => 'etc/home.txt'; use constant CREATE => 'etc/create.txt'; use constant SIGNIN => 'etc/signin.txt'; use constant COOKIENAME => 'patrons'; use constant CMDTERM => 'term'; use constant TERM => 'etc/term.txt'; use constant ERROR => 'etc/error.txt'; use constant LOCATION => 'URL'; use constant CHOICES_A => 'etc/choices-authenticated.txt'; use constant CHOICES_N => 'etc/choices-not.txt'; use constant EXPIRE => '60m'; use constant ABOUT => 'etc/about.txt'; # configure MyLibrary::Config->instance( 'patrons' ); # initialize my $cgi = CGI->new; my $html; # authenticate, if there is a cookie my ( $auth, $session_id, $status, $username ); if ( $cgi->cookie( COOKIENAME )) { $session_id = $cgi->cookie( COOKIENAME ); $auth = MyLibrary::Auth::Basic->new( sessid => $session_id, session_expire => EXPIRE ); $status = $auth->status; $username = $auth->username; } # get the command my $cmd = $cgi->param( 'cmd' ); # branch accordingly if (! $cmd ) { # display the home page $html = &slurp(TEMPLATE); $html =~ s/##CONTENT##/&slurp( HOME )/e; $html =~ s/##NUMBER_OF_RESOURCES##/&commify( &number_of_items )/e; $html =~ s/##FACETS##/&facet_term_combinations( MyLibrary::Facet->new( name => 'Subjects' ))/e; } elsif ( $cmd eq 'about' ) { # display the home page $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ABOUT )/e; } elsif ( $cmd eq 'del' ) { # get the input my $id = $cgi->param( 'id' ); my $confirm = $cgi->param( 'confirm' ); # check for id if ( ! $id ) { # display an error my $title = $cgi->h1( 'Software error' ); my $message = $cgi->p( 'This function requires a resource ID as input. Call Eric.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # make sure they are authenticatead elsif ( $status ne 'authenticated' ) { # display an error my $title = $cgi->h1( 'Something went wrong' ); my $message = $cgi->p( 'You need to be authenticated in order to delete something from a reading list. Please ' . $cgi->a({ href => './?cmd=signin' }, 'sign in' ) . '.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # make sure the passed id is valid elsif ( ! MyLibrary::Resource->new( id => $id )) { # display an error my $title = $cgi->h1( 'Software error' ); my $message = $cgi->p( "The supplied resource ID ($id) does not point to a valid resource. Call Eric." ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # confirm the deletion elsif ( ! $confirm ) { # return a confirmation my $resource = MyLibrary::Resource->new( id => $id ); my $name = $resource->name; my $title = $cgi->h1( 'Are you sure?' ); my $message = $cgi->p( "Are you sure you want to remove $name from your reading list? " . $cgi->a({ href => './?cmd=del&id=' . $resource->id . '&confirm=yes' }, 'Yes') . ', remove it. ' . $cgi->a({ href => './?cmd=my' }, 'No' ) . ', never mind.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # do the work elsif ( $confirm eq 'yes' ) { # get this patron and update their resource list my $patron = MyLibrary::Patron->new( username => $username ); $patron->patron_resources( del => [ $id ]); $patron->commit; # display the results my $title = $cgi->h1( 'Done' ); my $message = $cgi->p( "The title has been removed from your reading list. You might now want to view " . $cgi->a({ href => './?cmd=my' }, 'your list' ) . '.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } } elsif ( $cmd eq 'add' ) { # get the input my $id = $cgi->param( 'id' ); # make sure they are authenticated if ( $status ne 'authenticated' ) { # display an error my $title = $cgi->h1( 'Something went wrong' ); my $message = $cgi->p( 'You need to be authenticated in order to add something to a reading list. Please ' . $cgi->a({ href => './?cmd=signin' }, 'sign in' ) . '.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # make sure there is input elsif ( ! $id ) { # display an error my $title = $cgi->h1( 'Software error' ); my $message = $cgi->p( 'No id was supplied. Call Eric.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # sanity check elsif ( ! MyLibrary::Resource->new( id => $id )) { # display an error my $title = $cgi->h1( 'Software error' ); my $message = $cgi->p( "The supplied resource ID ($id) does not exist. Call Eric." ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # do the work else { # get this patron and add this item to their pile my $patron = MyLibrary::Patron->new( username => $username ); my $resource = MyLibrary::Resource->new( id => $id ); my $name = $resource->name; $patron->patron_resources( new => [ $id ]); $patron->commit; # display the result my $username = $auth->username; my $title = $cgi->h1( 'Success!' ); my $message = $cgi->p( "The title, $name, has been added to your reading list. You might now want to view " . $cgi->a({ href => './?cmd=my' }, 'your list' ) . '.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } } elsif ( $cmd eq 'my' ) { # make sure they are authenticated if ( $status ne 'authenticated' ) { # display an error my $title = $cgi->h1( 'Bummer' ); my $message = $cgi->p( 'You need to be signed in to use this function. ' . $cgi->a({ href => './?cmd=signin' }, 'Sign in' ) . '.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # do the work else { # create the patron my $patron = MyLibrary::Patron->new( username => $username ); my $reading_list; foreach ( $patron->patron_resources( sort => 'name' )) { my $resource = MyLibrary::Resource->new( id => $_ ); my $url = &get_location( $resource, LOCATION ); $reading_list .= $cgi->li( $cgi->a({ href => $url }, $resource->name ) . ' (' . $cgi->a({ href => './?cmd=del&id=' . $resource->id }, 'remove' ) . ')' ); } # sanity check if ( $reading_list ) { $reading_list = $cgi->ol( $reading_list )} else { $reading_list = $cgi->p( '(Your reading list is empty.)' )} # display the list, or lack thereof my $title = $cgi->h1( "Reading list for $username" ); my $message = $cgi->p( 'Here is your current reading list:' ); $message .= $reading_list; $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } } elsif ($cmd eq 'term') { # get the input and find the term my $term_id = $cgi->param('id'); my $term = MyLibrary::Term->new( id => $term_id ); # build an html list of resources for the input my @resource_ids = $term->related_resources( sort => 'name' ); my $list; foreach my $id ( @resource_ids ) { # get this resouce my $resource = MyLibrary::Resource->new( id => $id ); # get the url my $url = &get_location( $resource, LOCATION ); # build a list $list .= $cgi->li($cgi->a({-href => $url }, $resource->name) . ' (' . $cgi->a({ href => './?cmd=add&id=' . $resource->id }, 'add' ) . ')' ); } $list = $cgi->ol($list); # display the page $html = &slurp(TEMPLATE); $html =~ s/##CONTENT##/&slurp( TERM )/e; $html =~ s/##TERM##/$term->term_name/e; $html =~ s/##TERM_NOTE##/$term->term_note/e; $html =~ s/##RESOURCE_LIST##/$list/e; } elsif ( $cmd eq 'create' ) { # get the input my $username = $cgi->param( 'username' ); my $password = $cgi->param( 'password' ); my $echo = $cgi->param( 'echo' ); # sanity check if ( ! $username or ! $password ) { # display an error $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( CREATE )/e; } # more sanity checking elsif ( ! $username or ! $password or ! $echo ) { # display an error my $title = $cgi->h1( 'Something went wrong' ); my $message = $cgi->p( 'Alas, you need to complete all three fields. Please go back and try again.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # even more checking elsif ( $password ne $echo ) { # display an error my $title = $cgi->h1( 'Something went wrong' ); my $message = $cgi->p( 'Bummer, your password and echoed password do not match. Please go back and try again.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # make sure the name isn't already taken elsif ( MyLibrary::Patron->new( username => $username )) { # display an error my $title = $cgi->h1( 'Something went wrong' ); my $message = $cgi->p( 'Hmmm, that username has already been take. Please try another.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # whew! else { # do the work my $patron = MyLibrary::Patron->new; $patron->patron_username( $username ); $patron->patron_password( $password ); $patron->patron_stylesheet_id( 1 ); $patron->commit; # display the result my $title = $cgi->h1( 'Congrats!' ); my $message = $cgi->p( "The account named $username has been created. Now, please " . $cgi->a({ href => './?cmd=signin' }, 'sign in' ) . '.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } } elsif ( $cmd eq 'signin' ) { # get the input my $username = $cgi->param( 'username' ); my $password = $cgi->param( 'password' ); # make sure they aren't already logged in if ( $status eq 'authenticated' ) { # display an error my $username = $auth->username; my $title = $cgi->h1( 'Oops!' ); my $message = $cgi->p( "It seems as if you are already signed in as $username. If this is not you, then please " . $cgi->a({ href => './?cmd=signout' }, 'sign out' ) . ' and sign in again.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # display the form elsif ( ! $username or ! $password ) { # display form $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( SIGNIN )/e; } # do the work else { # authenticate; my $auth = MyLibrary::Auth::Basic->new( session_expire => EXPIRE ); my $return_code = $auth->authenticate( username => $username, password => $password ); # cool if ( $return_code eq 'success' ) { # set the cookie $session_id = $auth->sessid; $status = $auth->status; $username = $auth->username; my $cookie = $cgi->cookie( -name => COOKIENAME, -value => $session_id ); my $header = $cgi->header( -cookie => $cookie, -type => 'text/html', -charset => 'utf-8' ); # set up the result my $title = $cgi->h1( "Hello, $username" ); my $message = $cgi->p( 'You have sucessfully signed in. Welcome.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; $html =~ s/##STATUS##/$status/ge; $html =~ s/##USERNAME##/$username/ge; $html =~ s/##SESSIONID##/$session_id/ge; $html =~ s/##CHOICES##/&choices/ge; # send the cookie, the html, and quit print $header; print $html; exit; } # bad input elsif ( $return_code eq 'password failure' or $return_code eq 'username failure' ) { # display an error my $title = $cgi->h1( 'Username/password problem' ); my $message = $cgi->p( 'That username/password combination is invalid. Please try again.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # unknown error else { # display an error my $title = $cgi->h1( 'Software error' ); my $message = $cgi->p( "Unknown value for return_code ($return_code). Call Eric." ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } } } elsif ( $cmd eq 'signout' ) { # do the work, immediately my $cookie = $cgi->cookie( -name => COOKIENAME, -value => '', -expires => '-1h' ); my $header = $cgi->header( -cookie => $cookie, -type => 'text/html', -charset => 'utf-8' ); $auth->close_session; # re-define $session_id = ''; $status = ''; $username = ''; # set up the result my $title = $cgi->h1( 'Sign out' ); my $message = $cgi->p( 'You have successfully signed out. Thank you for being with us. ' . $cgi->a({ href => './?cmd=signin' } , 'Sign in' ) . ' again.' ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; $html =~ s/##STATUS##/$status/ge; $html =~ s/##USERNAME##/$username/ge; $html =~ s/##SESSIONID##/$session_id/ge; $html =~ s/##CHOICES##/&choices/ge; # reset the cookie, send the html, and quit, immediately print $header; print $html; exit; } elsif ( $cmd eq 'listall' ) { # create a list of everybody my $username_list; foreach my $patron ( MyLibrary::Patron->get_patrons ) { $username_list .= $cgi->li( $patron->patron_username ) } $username_list = $cgi->ul( $username_list ); # display the result my $title = $cgi->h1( 'Usernames' ); my $message = $cgi->p( 'This is a list of the usernames in the system. There is no delete function implemented, yet.' ); $message .= $username_list; $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } else { # display an error my $title = $cgi->h1( 'Software error' ); my $message = $cgi->p( "Unknown value for cmd ($cmd). Call Eric." ); $html = &slurp( TEMPLATE ); $html =~ s/##CONTENT##/&slurp( ERROR )/e; $html =~ s/##TITLE##/$title/e; $html =~ s/##MESSAGE##/$message/e; } # done $html =~ s/##STATUS##/$status/ge; $html =~ s/##USERNAME##/$username/ge; $html =~ s/##SESSIONID##/$session_id/ge; $html =~ s/##CHOICES##/&choices/ge; print $cgi->header( -type => 'text/html', -charset => 'utf-8' ); print $html; exit; ############# # subroutines sub choices { # return a set of menu options if ( $status eq 'authenticated' ) { return &slurp( CHOICES_A )} else { return &slurp( CHOICES_N )} } sub slurp { # open a file named by the input and return its contents my $f = @_[0]; my $r; open (F, "< $f"); while () { $r .= $_ } close F; return $r; } sub number_of_items { return scalar(MyLibrary::Resource->get_resources(output => 'id')) } sub facet_term_combinations { # get the input my @facets = @_; # initialize my $terms; foreach ( @facets ) { # create a list of terms associated with each facet foreach my $id ($_->related_terms(sort => 'name')) { my $term = MyLibrary::Term->new( id => $id ); $terms .= '
  • ' . $term->term_name . ' (' . &commify( scalar( $term->related_resources )) . ' items)
  • '; } } # done return $cgi->ol( $terms ); } sub commify { # cool hack; http://www.unix.org.ua/orelly/perl/cookbook/ch02_18.htm my $text = reverse $_[0]; $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g; return scalar reverse $text; } sub get_location { # get the input my $resource = shift; my $location_type = shift; # initialize my $location; # process each location foreach ( $resource->resource_locations ) { my $type = MyLibrary::Resource::Location::Type->new( id => $_->resource_location_type ); if ( $type->name eq $location_type ) { $location = $_->location; last; } } # done return $location }