#!/usr/bin/perl
use strict;
use warnings;
use lib '/home/raj/perl5/lib/perl5';
use CGI;
use Template;
use Data::Dumper;
use Data::Printer alias => 'DEBUG'; # need to alias p() if using CGI
use DBIx::Simple;
use Mail::Sendmail;
use HTML::FillInForm;
use Data::FormValidator;
use Data::FormValidator::Constraints qw(:closures);
# use CGI::Carp qw(fatalsToBrowser); # use for devel
use CGI::HTMLError (trace => 1); # use in production
use FindBin qw($RealBin); # warn $RealBin;
use lib $RealBin . '/../../lib';
use LIMS::Model::Email;
use LIMS::Local::Utils; # text_wrap
use LIMS::Local::Config;
my $q = CGI->new(); # DEBUG($q);
# get form submission params:
my $vars = $q->Vars(); # DEBUG($vars);
# set $ENV{CENTRE} if required, BEFORE getting config:
if ( $vars->{service} ) {
$ENV{CENTRE} = $vars->{service}; # other centres
}
my $config = LIMS::Local::Config->instance;
my $dbix = DBIx::Simple->connect(@{ $config->{dbh_params} });
my $SERVICE = $config->{settings}->{service_email};
my $ADMIN = $config->{settings}->{admin_contact};
# template src:
use constant TMPL_DIR => $RealBin . '/../../templates';
use constant TMPL => 'user/application_form.tt';
use vars qw($content);
# if submitted form:
if ($vars->{register}) {
my $dfv = _dfv();
my $dfv_profile = _dfv_profile(); # DEBUG($dfv_profile);
my $results = $dfv->check($q, $dfv_profile); # DEBUG($results);
if ( $results->has_invalid or $results->has_missing ) { # DEBUG($results);
$content = { errs => $results->msgs, vars => $vars };
}
# check email not used:
elsif ( _email_in_use() ) { # returns 1 if email addr registered
$content = { addr_in_use => 1, vars => $vars };
}
else { # no validation errors:
my $rtn = send_application();
if ($rtn) { # sendmail error:
$content = { vars => $vars, msg => $rtn, admin => $SERVICE };
}
else { # messages sent OK:
$content = { vars => $vars, send_success => 1, admin => $SERVICE };
}
}
}
sub _email_in_use {
my $db = $config->{settings}->{production_db};
my $tbl = join '.', $db, 'users';
return $dbix->select( $tbl, 1, { email => $vars->{email} } )->list;
}
my $view = render_view($content);
print $q->header(), $view;
sub render_view {
my $content = shift;
$content->{settings} = $config->{settings};
{ # user locations:
my $sql = q!select location_name from user_locations where active = 'yes'!;
my $user_locations = $dbix->query($sql)->flat;
$content->{user_locations} = $user_locations;
}
{ # user roles:
my $roles = $dbix->query('select distinct(designation) from users')->flat;
$content->{roles} = $roles;
}
# get TT object:
my $t = Template->new({ INCLUDE_PATH => TMPL_DIR });
my $template_output;
$t->process(TMPL, $content, \$template_output)
|| die "Template process failed: ", $t->error(), "\n";
my $output = HTML::FillInForm->fill( \$template_output, $vars );
return $output;
}
sub send_application {
my $message_body = _message_body();
$vars->{_email_msg} = $message_body;
my $subject = sprintf 'HILIS [%s] Registration (%s, %s)',
uc $vars->{service}, uc $vars->{last_name}, ucfirst lc $vars->{first_name};
my %mail = (
config => $config->{settings},
message => $message_body,
subject => $subject,
); # DEBUG(\%mail);
my @recipients = ($ADMIN, $SERVICE, $vars->{email});
my %seen;
for my $addr (@recipients) {
next if $seen{$addr}++; # in case service_email & admin_contact are the same
$mail{recipient} = $addr; # DEBUG(\%mail);
my $rtn = LIMS::Model::Email->send_message(\%mail); # returns Return::Value object
return $rtn->string if $rtn->type ne 'success';
}
return 0; # messages sent OK
}
sub _dfv_profile {
return {
required => [ qw(last_name first_name contact email email2 tel dept) ],
optional => [ qw(location other_source role other_role)],
dependencies => {
location => { OTHER => 'other_source' }, # require 'other_source' if location == OTHER
designation => { OTHER => 'other_role' }, # require 'other_role' if designation == OTHER
},
require_some => { # require one from this group
location => [ 1, qw(location other_source) ],
role => [ 1, qw(designation other_role) ],
},
field_filters => {
first_name => _remove_spaces(),
last_name => _remove_spaces(),
},
constraint_methods => {
email => email(),
email2 => _check_emails_match(),
},
msgs => {
constraints => {
email_mismatch => 'e-mail addresses do not match',
},
},
}
}
sub _message_body {
my $str = $vars->{contact}; # ie departmental address
$str =~ s/\r\n/ /g; # convert new-lines to spaces
my @args = ("", "\t", $str); # free text - maybe loooong
my $addr = LIMS::Local::Utils::text_wrap(65, \@args);
my $divider = '-' x 75;
$vars->{other_source} ||= $vars->{location};
$vars->{other_role} ||= $vars->{designation};
my $message = "Your HILIS application has been submitted.\n\n";
$message .= "You should normally receive a response within 2 working days.\n\n";
$message .= "Please contact $SERVICE should you require any further details.\n\n";
$message .= $divider . "\n";
$message .= sprintf "%12s: %s\n", 'First Name', $vars->{first_name};
$message .= sprintf "%12s: %s\n", 'Last Name', $vars->{last_name};
$message .= sprintf "%12s: %s\n", 'Source', $vars->{other_source};
$message .= sprintf "%12s: %s\n", 'Dept', $vars->{dept};
$message .= sprintf "%12s: %s\n", 'Position', $vars->{other_role};
$message .= sprintf "%12s: %s\n", 'Address', $addr;
$message .= sprintf "%12s: %s\n", 'Telephone', $vars->{tel};
$message .= sprintf "%12s: %s\n", 'E-mail', $vars->{email};
$message .= sprintf "%12s: %s\n", 'Service', $vars->{service};
return $message;
}
sub _dfv {
my $defaults = $config->{dfv_defaults}; # DEBUG($defaults);
my $dfv = Data::FormValidator->new({}, $defaults);
return $dfv;
}
sub _check_emails_match {
return sub {
my $dfv = shift; # DEBUG($dfv);
$dfv->name_this('email_mismatch');
my $data = $dfv->get_filtered_data; # DEBUG($data);
return (
$data->{email} && $data->{email2} &&
$data->{email} eq $data->{email2}
); # returns truth
};
}
sub _remove_spaces {
return sub { my $str = shift; $str =~ s/\s+/\-/g; $str; }
}