#!/usr/local/bin/perl -w
use strict;
use warnings 'all';
use Cwd 'cwd';
use DBI;
my $args = { };
$args->{domain} = prompt("What is the web application domain?", "www.example.com");
$args->{application_name} = prompt("Application name?", "MyApp");
$args->{mail_errors_to} = prompt("Email errors to?", 'you@domain.com');
$args->{mail_errors_from} = prompt("Email errors from?", 'root@localhost.com');
$args->{smtp_server} = prompt("SMTP Server?", 'localhost');
$args->{session_dsn} = prompt("Session DSN?", "DBI:mysql:dbname:localhost");
$args->{session_user} = prompt("Session db username?");
$args->{session_pass} = prompt("Session db password?");
$args->{session_cookie_domain} = prompt("Session cookie domain?", $args->{domain});
$args->{session_timeout} = prompt("Session timeout? (in minutes)", 30);
$args->{session_cookie_name} = prompt("Session cookie name?", 'session-id');
$args->{app_dsn} = prompt("Application DSN?", $args->{session_dsn});
$args->{app_user} = prompt("Application db username?", $args->{session_user});
$args->{app_pass} = prompt("Application db password?", $args->{session_pass});
$args->{main_dsn} = prompt("Main DSN?", $args->{session_dsn});
$args->{main_user} = prompt("Main db username?", $args->{session_user});
$args->{main_pass} = prompt("Main db password?", $args->{session_pass});
warn "="x79, "\n";
warn "Creating database tables...\n";
eval {
my $dbh = DBI->connect( $args->{session_dsn}, $args->{session_user}, $args->{session_pass} );
$dbh->do(q~
CREATE TABLE `asp_sessions` (
`session_id` char(32) NOT NULL,
`session_data` blob,
`created_on` datetime default NULL,
`modified_on` datetime default NULL,
PRIMARY KEY (`session_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
~);
$dbh->disconnect();
1;
} or die $@;
eval {
my $dbh = DBI->connect( $args->{app_dsn}, $args->{app_user}, $args->{app_pass} );
$dbh->do(q~
CREATE TABLE `asp_applications` (
`application_id` varchar(100) NOT NULL,
`application_data` blob,
PRIMARY KEY (`application_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
~);
$dbh->disconnect();
1;
} or die $@;
warn "="x79, "\n";
warn "Creating directory structure...\n";
mkdir($args->{domain}) or die "Cannot mkdir('$args->{domain}'): $!";
foreach my $dir (qw( lib etc conf htdocs handlers PAGE_CACHE MEDIA ))
{
mkdir("$args->{domain}/$dir") or die "Cannot mkdir('$args->{domain}'): $!";
}# end foreach()
open my $ofh, '>', "$args->{domain}/conf/apache2-asp-config.xml";
print $ofh <<"CONFIG_XML";
\@ServerRoot\@/lib
DBI
environment-var1
value-1
environment-var2
value-2
mysetting
some-value
anothersetting
anothervalue
Apache2::ASP::ErrorHandler
@{[ $args->{mail_errors_to} ]}
@{[ $args->{mail_errors_from} ]}
@{[ $args->{smtp_server} ]}
@{[ $args->{application_name} ]}
\@ServerRoot\@
\@ServerRoot\@/handlers
\@ServerRoot\@/MEDIA
\@ServerRoot\@/htdocs
\@ServerRoot\@/PAGE_CACHE
Apache2::ASP::SessionStateManager::MySQL
@{[ $args->{session_cookie_domain} ]}
@{[ $args->{session_cookie_name} ]}
@{[ $args->{session_dsn} ]}
@{[ $args->{session_user} ]}
@{[ $args->{session_pass} ]}
@{[ $args->{session_timeout} ]}
Apache2::ASP::ApplicationStateManager::MySQL
@{[ $args->{app_dsn} ]}
@{[ $args->{app_user} ]}
@{[ $args->{app_pass} ]}
@{[ $args->{main_dsn} ]}
@{[ $args->{main_user} ]}
@{[ $args->{main_pass} ]}
CONFIG_XML
close($ofh);
open my $conf_ofh, '>', "$args->{domain}/conf/httpd.conf";
print $conf_ofh <<"CONF";
# Needed for CGI::Apache2::Wrapper to work properly:
LoadModule apreq_module modules/mod_apreq2.so
# Load up some important modules:
PerlModule DBI
PerlModule Apache2::ASP::ModPerl
# Admin website:
ServerName @{[ $args->{domain} ]}
DocumentRoot @{[ cwd() . '/' . $args->{domain} . '/htdocs' ]}
# Set the directory index:
DirectoryIndex index.asp
# All *.asp files are handled by Apache2::ASP::ModPerl
SetHandler perl-script
PerlResponseHandler Apache2::ASP::ModPerl
# !IMPORTANT! Prevent anyone from viewing your GlobalASA.pm
Order allow,deny
Deny from all
# All requests to /handlers/* will be handled by their respective handler:
SetHandler perl-script
PerlResponseHandler Apache2::ASP::ModPerl
CONF
close($conf_ofh);
open my $asa_ofh, '>', "$args->{domain}/htdocs/GlobalASA.pm";
print $asa_ofh <<"ASA";
package @{[ $args->{application_name} ]}::GlobalASA;
use strict;
use warnings 'all';
use base 'Apache2::ASP::GlobalASA';
use vars __PACKAGE__->VARS;
# sub Server_OnStart;
# sub Application_OnStart;
# sub Session_OnStart;
# sub Script_OnStart;
# sub Script_OnEnd;
# sub Script_OnError;
1;# return true:
ASA
close($asa_ofh);
warn "\nSetup is almost complete.
Make sure to add the following lines to your main httpd.conf:
# Unless you've already done this:
NameVirtualHost *:80
# And this (unless you already have):
AddModule perl_module modules/mod_perl.so
# And *Don't* forget about this line:
Include @{[ cwd() ]}/@{[ $args->{domain} ]}/conf/httpd.conf
";
open my $asp_ofh, '>', "$args->{domain}/htdocs/index.asp";
print $asp_ofh <<'ASP';
Apache2::ASP Test Page
Congratulations
You have successfully installed Apache2::ASP.
Visit your example contact form to see
several concepts in action.
ASP
close($asp_ofh);
open my $props_ofh, '>', "$args->{domain}/etc/properties.yaml";
print $props_ofh <<"YAML";
---
contact_form:
first_name:
is_missing: Required
last_name:
is_missing: Required
email:
is_missing: Required
is_invalid: Invalid
message:
is_missing: Required
YAML
close($props_ofh);
open my $data_ofh, '>', "$args->{domain}/etc/test_fixtures.yaml";
print $data_ofh <<"YAML";
---
contact_form:
first_name: John
last_name: Doe
email: john.doe\@test.com
message: This is a test message...just a test.
YAML
close($data_ofh);
mkdir "$args->{domain}/htdocs/examples" or die "CANNOT MKDIR examples: $!";
open my $contact_asp, '>', "$args->{domain}/htdocs/examples/contact.asp";
print $contact_asp <<"ASP";
<%
# Make a "sticky form":
if( my \$args = \$Session->{__lastArgs} )
{
\$Form->{\$_} = \$args->{\$_} foreach keys(\%\$args);
}# end if()
my \$errors = \$Session->{validation_errors} || { };
my \$err = sub {
my \$name = shift;
return unless \$errors->{\$name};
%><%= \$Server->HTMLEncode( \$errors->{\$name} ) %><%
};
%>
Apache2::ASP Example Contact Form
<%
map { delete( \$Session->{\$_} ) } qw/
validation_errors
__lastArgs
msg
/;
%>
ASP
close($contact_asp);
mkdir( "$args->{domain}/handlers/examples" );
open my $handler_ofh, '>', "$args->{domain}/handlers/examples/contact.pm";
print $handler_ofh <<'HANDLER';
package examples::contact;
use strict;
use warnings 'all';
use base 'Apache2::ASP::FormHandler';
use vars __PACKAGE__->VARS;
use Data::Properties::YAML;
#==============================================================================
sub run
{
my ($s, $context) = @_;
if( my $errors = $s->validate( $context ) )
{
$Session->{__lastArgs} = $Form;
$Session->{validation_errors} = $errors;
return $Response->Redirect( $ENV{HTTP_REFERER} );
}# end if()
# Uncomment to actually email someone:
if( 0 )
{
$Server->Mail(
From => 'root@localhost',
'reply-to' => $Form->{email},
To => 'you@yours.com',
Subject => "$ENV{HTTP_HOST} Contact Form Results",
Message => <<"EMAIL",
Dear admin,
$Form->{first_name} $Form->{last_name} <$Form->{email}> has sent you the
following message:
$Form->{message}
EMAIL
);
}# end if()
$Response->Write("Thanks for contacting us.
If this were a real form, you would have been redirected someplace.");
}# end run()
#==============================================================================
sub validate
{
my ($s, $context) = @_;
# Remove leading/trailing whitespace:
map {
$Form->{$_} =~ s/^\s+//;
$Form->{$_} =~ s/\s+$//;
} keys(%$Form);
no warnings 'uninitialized';
# We pull our warnings from a YAML properties file so they can be changed easily:
my $props = Data::Properties::YAML->new(
properties_file => $Config->web->application_root . '/etc/properties.yaml',
)->contact_form;
my $errors = { };
# Validate first_name:
unless( length($Form->{first_name}) )
{
$errors->{first_name} = $props->first_name->is_missing;
}# end unless()
# Validate last_name:
unless( length($Form->{last_name}) )
{
$errors->{last_name} = $props->last_name->is_missing;
}# end unless()
# Validate email:
if( length($Form->{email}) )
{
# Just a simple regex - knock yourself out if you want:
unless( $Form->{email} =~ m/^.*?@.*?\..+$/ )
{
$errors->{email} = $props->email->is_invalid;
}# end unless()
}
else
{
$errors->{email} = $props->email->is_missing;
}# end if()
# Validate message:
unless( length($Form->{message}) )
{
$errors->{message} = $props->message->is_missing;
}# end unless()
return keys(%$errors) ? $errors : undef;
}# end validate()
1;# return true:
HANDLER
close($handler_ofh);
mkdir "$args->{domain}/t";
open my $t_ofh, '>', "$args->{domain}/t/01.01-contact_form.t";
print $t_ofh <<'TEST';
#!/usr/bin/perl -w
use strict;
use warnings 'all';
use Test::More 'no_plan';
use base 'Apache2::ASP::Test::Base';
use HTML::Form;
use Data::Properties::YAML;
ok( my $s = __PACKAGE__->SUPER::new() );
# Get our contact_form testing data:
my %data = $s->data->contact_form->as_hash;
my $props = Data::Properties::YAML->new(
properties_file => $s->ua->context->config->web->application_root . '/etc/properties.yaml',
)->contact_form;
# Will it load?:
{
my $res = $s->ua->get("/examples/contact.asp");
is( $res->is_success => 1, "/examples/contact.asp loads");
}
### Validation Testing:
# first_name:
{
local $data{first_name} = '';
my $res = $s->ua->post("/handlers/examples.contact", [
%data
]);
# Redirected?:
is( $res->header('location') => '/examples/contact.asp' );
# Correct validation message?:
is(
$s->ua->context->session->{validation_errors}->{first_name} => $props->first_name->is_missing
);
}
# last_name:
{
local $data{last_name} = '';
my $res = $s->ua->post("/handlers/examples.contact", [
%data,
]);
# Redirected?:
is( $res->header('location') => '/handlers/examples.contact' );
# Correct validation message?:
is(
$s->ua->context->session->{validation_errors}->{last_name} => $props->last_name->is_missing
);
}
# email - missing:
{
local $data{email} = '';
my $res = $s->ua->post("/handlers/examples.contact", [
%data,
]);
# Redirected?:
is( $res->header('location') => '/handlers/examples.contact' );
# Correct validation message?:
is(
$s->ua->context->session->{validation_errors}->{email} => $props->email->is_missing
);
}
# email - invalid:
{
local $data{email} = 'invalid-email';
my $res = $s->ua->post("/handlers/examples.contact", [
%data,
]);
# Redirected?:
is( $res->header('location') => '/handlers/examples.contact' );
# Correct validation message?:
is(
$s->ua->context->session->{validation_errors}->{email} => $props->email->is_invalid
);
}
# message:
{
local $data{message} = '';
my $res = $s->ua->post("/handlers/examples.contact", [
%data,
]);
# Redirected?:
is( $res->header('location') => '/handlers/examples.contact' );
# Correct validation message?:
is(
$s->ua->context->session->{validation_errors}->{message} => $props->message->is_missing
);
}
# And make sure everything works when we submit the form nicely:
{
$s->ua->get("/examples/contact.asp");
my $res = $s->ua->post("/handlers/examples.contact", [
%data,
]);
# No error messages:
is(
$s->ua->context->session->{validation_errors} => undef
);
}
TEST
close($t_ofh);
#==============================================================================
sub prompt
{
my ($q, $default) = @_;
local $| = 1;
my $answer;
if( defined($default) )
{
print "\n$q: [$default] ";
}
else
{
print "\n$q: ";
}# end if()
chomp($answer = );
return $default if defined($default) && ! length($answer);
until( length($answer) )
{
print "$q: ";
chomp($answer = );
}# end until()
return $answer;
}# end prompt()