SAL-SURVEY

From GTALUG

Sitemap > Culture > Psema4 > SAL > SAL-SURVEY

A basic poll script using the SAL modules.

Screenshots

salsurvey.png

salsurveyhelp.png


Source

#!/usr/bin/perl

# This script is licensed under the FDL (Free Documentation License)
# The complete license text can be found at http://www.gnu.org/copyleft/fdl.html

use strict;
use SAL::WebApplication;
my $app = new SAL::WebApplication;
my $q = $app->{cgi};
my $self_url = $app->{cgi}->script_name();
my $user_id = $app->{cgi}->remote_user();
my $user_name = lookup_name($user_id);

my $survey_question = '';
my $survey_server = 'localhost';
my $survey_user = '';
my $survey_pass = '';
my $survey_db = 'Survey';

my $canvas;

# Register our application's modes
if (! $app->register_default(\&start)) { $app->throw_error("Could not register default mode 'start'\n"); }
if (! $app->register_mode('cast', \&cast)) { $app->throw_error("Could not register mode 'cast'\n"); }
if (! $app->register_mode('help', \&help)) { $app->throw_error("Could not register mode 'help'\n"); }
if (! $app->register_toolbar(\&build_toolbar)) { $app->throw_error("Could not register toolbar\n"); }
if (! $app->register_html_header(\&build_html_header)) { $app->throw_error("Could not register html header\n"); }

# Setup any databases
my $dbo_data = $app->{dbo_factory}->spawn_mysql($survey_server, $survey_user, $survey_pass, $survey_db);
my $dbo_results = $app->{dbo_factory}->spawn_mysql($survey_server, $survey_user, $survey_pass, $survey_db);

# Run the application
$app->run();

#===========
# Callbacks
#===========

###############################################################
sub start {
	my $sid = $q->param('sid') || '0';
	my $is_ok_to_vote = 0;

	my ($w, $h, $rh, $rw);

	# Get the Question...
	($w, $h) = $dbo_data->execute(qq[SELECT Question FROM SurveyQuestions WHERE SID=?], $sid);
	$survey_question = $dbo_data->{data}->[0][0];

	# Find out if this user's already voted...
	($w, $h) = $dbo_data->execute(qq[SELECT * FROM SurveyData WHERE SID=? AND Name=?], $sid, $user_id);
	if ($h < 1) { $is_ok_to_vote = 1; }

	# Get the Survey Choices...
	($w, $h) = $dbo_data->execute(qq[SELECT * FROM SurveyChoices WHERE SID=? ORDER BY ChoiceNum], $sid);

	# Calculate results
	($rw, $rh) = $dbo_results->execute(qq[SELECT sum(if(SurveyData.Choice='0', 1, 0)) as a, sum(if(SurveyData.Choice='1', 1, 0)) as b, sum(if(SurveyData.Choice='2', 1, 0)) as c FROM SurveyData WHERE SID=?], $sid);

	my $total_votes = $dbo_results->{data}->[0][0] + $dbo_results->{data}->[0][1] + $dbo_results->{data}->[0][2];
	my @pctgs;
	if ($dbo_results->{data}->[0][0] > 0) {	$pctgs[0] = ($dbo_results->{data}->[0][0] / $total_votes) * 100; }
	if ($dbo_results->{data}->[0][1] > 0) {	$pctgs[1] = ($dbo_results->{data}->[0][1] / $total_votes) * 100; }
	if ($dbo_results->{data}->[0][2] > 0) {	$pctgs[2] = ($dbo_results->{data}->[0][2] / $total_votes) * 100; }
	$pctgs[0] = sprintf("%.2f", $pctgs[0]);
	$pctgs[1] = sprintf("%.2f", $pctgs[1]);
	$pctgs[2] = sprintf("%.2f", $pctgs[2]);

	my $canvas = qq[<h3 align=center>Survey Question:<br/>$survey_question</h3>];

	if ($is_ok_to_vote) {
		$canvas .= qq[<center><form action=$self_url method=POST><table border=0 width=300 cellpadding=2 cellspacing=0>];
		for (my $y = 0; $y < $h; $y++) {
			$canvas .= qq[<tr><td align=center><input type="radio" name="choice" value="$y"></td><td align=left>$dbo_data->{data}->[$y][1]</td></tr>];
		}
		$canvas .= qq[<tr><td><input type="hidden" name="mode" value="cast"><input type="hidden" name="sid" value="$sid"></td><td><input type="submit" value="Cast Vote"></td></tr></table></form></center>];
	} else {
######### User has already cast a vote, so display a message instead of displaying the form.
		$canvas .= qq[<p align=left> </p><p align=center>You have already voted in this survey.</p>];
	}

######### Display Results
	$canvas .= qq[
<p align=center> <br/>Survey Results ($total_votes Total Votes)</p>
<center>
<table width=600 border=0 cellpadding=0 cellspacing=0 style="border-right: 1px solid #000;">
];
	for (my $y = 0; $y < $h; $y++) {
		my $progress_width= $pctgs[$y] * 2;
		my $style;
		if ($y == 0) {
			$style = "border-top: 1px solid #000; border-bottom: 1px solid #000; border-left: 1px solid #000; background-color: #ddd;";
		} else {
			$style = "border-bottom: 1px solid #000; border-left: 1px solid #000; background-color: #ddd;";
		}

		$canvas .= qq[<tr><td align=left width=340>$dbo_data->{data}->[$y][1]</td><td align=right width=60>$pctgs[$y]% </td><td align=left width=200 style="$style"><img src="/images/progress.png" width=$progress_width height=24></td></tr>];
	}

	$canvas .= qq[
</table>
</center>
];

	$app->write($canvas);
	$app->paint("User Feedback Survey");
}
###############################################################
sub cast {
	my $sid = $q->param('sid') || '0';
	my $choice = $q->param('choice');

	$dbo_data->do(qq[INSERT INTO SurveyData (SID, Name, Choice)  VALUES('$sid', '$user_id', '$choice')]);

	my $canvas = qq[
<h3 align=left>Your vote has been cast!</h3>
<a href="$self_url?sid=$sid">Back to start</a>
];

	$app->write($canvas);
	$app->paint("User Feedback Survey");
}
###############################################################
sub help {
	my $pod_file = "/var/www$self_url";

        # define some html tags we want to substitute in
        my $hr_html = '';
        my $titlebg_html = '<h1 style="background-color: #ffd; font-family: times;">';
        my $section_title_html = '<h2 style="text-decoration: underline; font-family: times; page-break-before: always;">';
        my $index_section_html = '<h2 style="text-decoration: underline; font-family: times;">';
                                                                                                                             
        # get the html version of the pod
        my $pod_contents = `pod2html --infile=$pod_file --index`;
                                                                                                                             
        # make it nicer
        # remove extraneous simple tags
        my @bad_tags = qw(<html> </html> <head> </head> <body> </body>);
        foreach my $tag (@bad_tags) {
                $pod_contents =~ s/$tag//ig;
        }
                                                                                                                             
        # remove the title tags seperately, so we can take out the text between them
        $pod_contents =~ s/<title>.*<\/title>//ig;
                                                                                                                             
        # remove the link tag seperately so we can remove the text inside it
        $pod_contents =~ s/<link.*>//ig;
                                                                                                                             
        # substitute our settings in
        $pod_contents =~ s/<hr.*\/>/$hr_html/ig;
        $pod_contents =~ s/<h1>/$titlebg_html/ig;
        $pod_contents =~ s/<h2>/$section_title_html/ig;
                                                                                                                             
        # remove any multi-newlines
        $pod_contents =~ s/\n+/\n/g;

	$app->write($index_section_html . "Index</h2>" . $pod_contents);
	$app->paint("Help Files...");
}
###############################################################
sub build_toolbar {
	my $mode = $app->{cgi}->param('mode');

	my $toolbar;
	if ($mode ne 'help') {
		$toolbar =  qq[
<a href="$self_url?mode=help" style="background-color: #fff;"><img src="/icons/unknown.gif" alt="Help" border=0></a>  
];
	} else {
		$toolbar .= qq[
<a href="$self_url" style="background-color: #fff;"><img src="/images/extra_icons/list.gif" alt="Back to Survey" border=0></a>  
];
	}

	return $toolbar
}
###############################################################
sub build_html_header {
	my $html_header = qq[
<script language="javascript">
function isReady(form) {
	for (var e = 0; e < form.elements.length; e++) {
		var el = form.elements[e];
		if (el.name.toLowerCase().substring(0,3) == "opt") {
			return true;
		} else {
			if (el.type == 'text' || el.type == 'textarea' || el.type == 'password' || el.type == 'file' ) {
				if (el.value == '') {
					alert('Please fill out the text field ' + el.name.toUpperCase());
					el.focus();
					return false;
				}
			}
			if (el.type == 'checkbox') {
				if (! el.checked) {
					alert('Please fill in Required Checkbox ' + el.name.toUpperCase());
					el.focus();
					return false;
				}
			}
		}
	}
}
</script>
];

	return $html_header
}
###############################################################


#===============
# Support Funcs
#===============

sub lookup_name {
	my $id = shift;
	my @record = split(/:/, `getent passwd | grep ^$id`);
	return $record[4];
}

sub sql_build_value_list {
	my @items = @_;
	my @clean = sql_clean(@items);
	my $value_list;

	foreach my $item (@clean) {
		$value_list .= qq['$item', ];
	}

	$value_list =~ s/,\s$//;
	return $value_list;
}

sub sql_clean {
	my @items = @_;
	my @clean;

	foreach my $item (@items) {
		$item =~ s/'//g;
		$item =~ s/"//g;
		$item =~ s/;//g;
		push (@clean, $item);
	}
	return @clean;
}

sub get_datetime {
	my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime();
	$mon++;
	$year += 1900;

	my $datetime = qq[$year-$mon-$mday $hour:$min:$sec];

	return $datetime;
}

=pod

=head1 SAL Surveys

=head2 Requirements

=item Apache
 - Basic Auth authentication (mod_auth_mysql, mod_auth_external, etc)

=item SAL

=item MySQL Database "Surveys"

   Tables:
 - SurveyQuestions (SID int(11), Question varchar(255))
 - SurveyChoices (SID int(11), Choice varchar(255), ChoiceNum int(11))
 - SurveyData (SID int(11), Name varchar(16), Choice int(11))

=item Images

 - progress.png (a 1px wide image for the progress bar)
 - unknown.gif for toolbar-link to help (image can be found in apache icon directory)
 - list.gif for toolbar-link to back to the survey from help (or alternate from apache icon directory)

=cut
Customize