#!/usr/local/bin/perl $VERSION = '0.003'; package FAQ; use strict; use warnings; use base 'Class::DBI'; sub set_table { my $table = shift; FAQ->set_db('Main', 'dbi:mysql:faq', 'faq', 'faq' ); FAQ->table( $table ); FAQ->columns( Primary => qw( qid ) ); FAQ->columns( Other => qw( submitted last_modified answered question answer ) ); } __PACKAGE__->add_constructor( unanswered_questions => 'answer IS NULL' ); package main; use strict; use warnings; use Template; use DBI; use CGI::Lite; use POSIX qw( strftime ); use File::Spec; use Mail::Mailer; use Getopt::Long; use Pod::Usage; use FindBin qw( $Bin ); sub set_table { my $table = shift; FAQ->set_db('Main', 'dbi:mysql:faq', 'faq', 'faq' ); FAQ->table( $table ); FAQ->columns( Primary => qw( qid ) ); FAQ->columns( Other => qw( submitted last_modified answered question answer ) ); } $| = 1; unless ( exists $ENV{SCRIPT_NAME} ) { my ( %opts ); GetOptions( \%opts, qw( help man email=s faq=s ) ) or pod2usage( verbose => 0 ) ; $opts{help} && pod2usage( verbose => 1 ); $opts{man} && pod2usage( verbose => 2 ); my ( $faq ) = $opts{faq} || pod2usage( verbose => 0 ); FAQ::set_table( $faq ); my @unanswered_questions = FAQ->unanswered_questions; exit unless @unanswered_questions; my $subject = "UNANSWERED QUESTIONS IN $faq FAQ"; my ( $email ) = $opts{email}; if ( $email ) { my $mailer = Mail::Mailer->new() or die "Can't create Mail::Mailer object\n"; $mailer->open( { 'To' => $email, 'Subject' => $subject, } ) or die "Can't open Mail::Mailer object\n"; select( $mailer ); } print "$subject\n", "-" x length( $subject ), "\n"; for ( @unanswered_questions ) { print "'", $_->question, "': submitted ", $_->submitted, "\n"; } exit; } print "Content-Type: text/html\n\n"; my $tmpdir = File::Spec->tmpdir(); open( STDERR, ">>$tmpdir/faq.log" ); my %params = CGI::Lite->new()->parse_form_data(); warn "PARAMS:\n\n", map "\t$_ = $params{$_}\n", keys %params; my $script = $ENV{SCRIPT_NAME}; warn "SCRIPT_NAME: $script\n"; my $path_info = $ENV{PATH_INFO}; my $dbh = DBI->connect( 'dbi:mysql:faq', 'faq', 'faq' ); my $user = $script =~ /admin/ ? 'admin' : ''; my $action = $params{action}; warn "ACTION: $action\n" if $action; my $table = $params{table}; my $qid = $params{qid}; if ( $action and $action eq 'New FAQ' and $table ) { $dbh->do( <do( "DROP TABLE IF EXISTS $table" ); } my @tables = $dbh->tables(); warn "tables: @tables\n"; my ( $curr_table ); ( undef, $curr_table ) = split( '/', $path_info ) if $path_info; warn "current table: $curr_table\n" if $curr_table; my @questions; if ( $curr_table ) { FAQ::set_table( $curr_table ); if ( my $new_question = $params{new_question} ) { FAQ->create( { question => $new_question, submitted => strftime( '%Y-%m-%d %H:%M:%S', localtime ), } ); } eval { die "no action" unless $action; die "no qid" unless $qid; my $question = FAQ->retrieve( qid => $qid ); die "no question" unless $question; $question->delete if $action eq 'Delete Question'; my $now = strftime( '%Y-%m-%d %H:%M:%S', localtime ); if ( $action eq "Update Answer" ) { unless ( $question->answer ) { $question->answered( $now ); } $question->answer( $params{answer} ); } $question->question( $params{question} ) if $action eq "Update Question"; $question->last_modified( $now ); $question->update; }; @questions = FAQ->retrieve_all(); } my $template = Template->new(); my $template_file = "faq.tmpl"; $template->process( $template_file, { questions => \@questions, tables => \@tables, table => $curr_table, script => $script, user => $user } ) || die $template->error(); =head1 NAME faq - a web based FAQ builder =head1 SYNOPSIS # create a database called 'faq' in mysql > mysqladmin create faq # if you like ... create the faq FAQ > mysql faq < faq.sql # in apache httpd.conf ScriptAlias /faq /path/to/faq/faq.pl ScriptAlias /faqadmin /path/to/faq/faq.pl AuthType Basic AuthUserFile /path/to/faq/faq.auth AuthName "FAQ Administration" require admin # if you want to have a seperate authorisation for the foo FAQ ... AuthType Basic AuthUserFile /path/to/faq/faq.auth AuthName "Foo FAQ Administration" require foo # if you want to be notified of any unanswered questions ... # in crontab 0 9 * * 1-5 faq.pl --email you@company.com --faq foo faq.pl --help --man --email [ email address ] --faq [ FAQ name ] =head1 OPTIONS =head2 email Specify e-mail address or (comma / semicolon seperated) email addresses to notify of unanswered questions. =head2 faq Specify name of FAQ to check for unanswered questions. =head1 README This is a simple CGI script for managing a web based FAQ. It uses mysql to store the questions and answers in the FAQ. It is pretty staightforward - basically, anyone can submit a new question through the "Add Question" form. There is also an admin user, that you should set up using HTTP authentication (see L<"SYNOPSIS">). You login as admin user by clicking on the "Login" button, and entering the authentication details that you have set up. The admin interface allows FAQ administrators to add or delete FAQs, answer questions, edit answers, or delete questions. If you want to set up different administrators on a per FAQ basis, you can do this because of the URL structure of the interface (see example in L<"SYNOPSIS">). If you want to be notified of any unanswered questions, for example using cron, you can invoke the script from the command line (see example in L<"SYNOPSIS">). =head1 SCRIPT CATEGORIES CGI =head1 PREREQUISITES C