# Name: Natalie Hawkins # Email: nhawkins_seattle@yahoo.com # This program is solely my own work, which has been influenced by the various # templates provided, the assignment requirements, and code written in class. use strict; # The "News::" classes required for this app are located here use lib qw(c:\\Program\ Files\\Apache\ Group\\Apache\\cgi-bin); use CGI; use CGI::Carp qw(fatalsToBrowser warningsToBrowser); use News::Auth; use News::ChannelList; my $q = CGI->new; my $auth = News::Auth->new( query => $q ); my $action = $q->param('action') || 'startpage'; # Dispatch tables to handle the 'actions'. my %unsecureDispatch = ( addaccount => \&displayAddAccountPage, createaccount => \&createAccount, logout => \&displayLogoutPage, login => \&checkCredentials, startpage => \&displayLoginPage ); my %secureDispatch = ( choose => \&displayChannelList, pickchannels => \&displaySelectedChannels ); # Choose a dispatch table to execute an 'action' # If the user is not authenticated, we perform an 'unsecure' action if (exists $unsecureDispatch{$action}) { $unsecureDispatch{$action}->(); } # The user must be authenticated for these 'actions' # For authenticated users, we can execute a 'secure' action elsif ($auth->isCookieAuthenticated && exists $secureDispatch{$action}) { $secureDispatch{$action}->(); } # if the 'action' doesn't exist in the 'unsecure' dispatch table # or if the user is not authenticated or is authenticated but the action # is not in the 'secure' dispatch table either # we default to displaying the login page. else { displayLoginPage(); } printHTMLbottom(); exit; # --------------------------- subroutines ---------------------------------------- # printUserMenu() # On various HTML pages, the user has these links as choices sub printUserMenu { print $q->a({ href => "?action=pickchannels" }, "Click here to show your selections"), $q->br(); print $q->a({ href => "?action=choose" }, "Click here to choose news feeds"), $q->br(); print $q->a({ href => "?action=logout" }, "Click here to logout"), $q->br(); }; # printHTMLtop( @cookies ) # On various HTML pages, the HTML page code starts like this... # If cookie objects are passed in (not required), they're included in the header info. sub printHTMLtop { my @cookies = @_; if (scalar @cookies) { print $q->header( -cookie => [ @cookies ] ); } else { print $q->header(); } print $q->start_html("News Feeds"); }; # printHTMLbottom() # On various HTML pages, the HTML code ends like this... sub printHTMLbottom { print $q->end_html(); }; # displayLoginPage() # Users can login or create a new account w/the news feeds program. # The user's news feed selections are stored in a database. # diplayLoginPage passes control to the checkCredentials page in the # case of a login, or to the addAccount page in the case that the # user chooses to create a new account. sub displayLoginPage { printHTMLtop(); print $q->start_form(); print $q->hidden( -name => 'action', -value => 'login', -override => 1 ); print "Login: ", $q->textfield( -name => 'login'), $q->br(); print "Password: ", $q->password_field( -name => 'password', -value => "", -override => 1); print $q->submit('button', "Login"); print $q->end_form(); print $q->br(); print $q->a({ href => "?action=addaccount" }, "Add a new account"); } # displayLogoutPage() # clears the login-authentication cookies # displays a link to the login page to startover sub displayLogoutPage { printHTMLtop( $auth->getClearAuthCookies() ); print $q->h1("Thanks for using News Feeds!"); # include a link with action = startover to go back to the login page. print $q->a({ href => "?action=startpage" }, "Start over"); } # displayAddAccountPage() # display a form with the fields login, password1, password2, and action = createaccount # Passes control to createAccount. sub displayAddAccountPage { printHTMLtop(); print $q->h1("Create a new account"); print $q->start_form(); print $q->hidden( -name => "action", -value => "createaccount", -override => 1); print "Enter an account login:", $q->textfield( -name => "newlogin"), $q->br(); print "Enter password: ", $q->password_field(-name => "password1", -value => "", -override => 1), $q->br(); print "Enter password (again): ", $q->password_field(-name => "password2", -value => "", -override => 1), $q->br(); print $q->submit('button', "Create account"); print $q->end_form(); } # createAccount() # If the two passwords entered match, then add the account, # else, report an error and return control to the addAccount page # so that the user can try again. sub createAccount { my ($newlogin, $pwd1, $pwd2) = ( $q->param("newlogin"), $q->param("password1"), $q->param("password2") ); # check that the login, password1, and password2 fields are all given # and that password1 is the same as password2 if ($newlogin && $pwd1 && $pwd2 && ($pwd1 eq $pwd2)) { # if yes, use $auth->addAccount to add the new account # display a welcome page and links to see previously selected news feeds, # choose new news feeds, or logout. $auth->addAccount($newlogin, $pwd1); printHTMLtop( $auth->getAuthCookies($newlogin) ); print $q->h1("Your new account has been created."); printUserMenu(); } # if no, display an error message and a link to return to the addAccount page else { printHTMLtop(); print $q->h1("You must supply a login and two password fields that match!"); print $q->a({ href => "?action=addaccount" }, "Click here to try again."), $q->br(); } } # checkCredentials() # The login and password entered in the displayLoginPage are checked against # the user database. If they match, create login-authentication cookies and # show the user the next choices for action, else return the user to the # displayLoginPage to try again. sub checkCredentials { if ($auth->isLoginAuthenticated) { printHTMLtop( $auth->getAuthCookies( $q->param('login') ) ); print $q->h1("Welcome to News Feeds"); printUserMenu(); } else { printHTMLtop(); print $q->h1("Your password or login was incorrect"); print $q->a({ href => "?action=startpage" }, "Click here to try again."), $q->br(); } } # displaySelectedChannels() # displays the channels that the user just selected. # for each channel, the channel's stories are displayed. # finally, displays links for the user to choose the next actions. sub displaySelectedChannels { printHTMLtop(); my $list = News::ChannelList->new; my $user = $auth->getUser; if ($q->param('button')) { my %params = %{ $q->Vars() }; # remove all of the user's previous choices $list->unsubscribeAll($user); # subscribe the user to the current choices foreach my $key (keys %params) { if (my ($id) = $key =~ /channel(\d+)/) { $list->subscribe($user, $id); } } } # show the user the channel titles and stories print $q->h2("Selected News Feeds for " . $user ); print "\n"; # the user's choices for the next action printUserMenu(); } # displayChannelList() # displays a list of all the available channels w/checkboxes next to them. # the channels the user previously selected, if any, are checked. sub displayChannelList { printHTMLtop(); my $list = News::ChannelList->new; print $q->h2("Select News Feeds:"); print $q->start_form; print $q->hidden( -name => 'action', -value => 'pickchannels', -override => 1 ); print $q->submit(-name => 'button', -value => "Select these news feeds"); print $q->p(); my %subscriptions = map { $_->getID => 1 } $list->getChannelsForUser($auth->getUser); foreach my $channel ($list->getAllChannels) { print $q->checkbox(-name => "channel" . $channel->getID, -value => 1, -label => $channel->getTitle, -checked => ($subscriptions{$channel->getID} ? 'checked' : ''), -override => 1); print $q->br(); } print $q->submit(-name => 'button', -value => "Select these news feeds"); print $q->end_form(); }