view release on metacpan or search on metacpan
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
#$Id: $
package Apache::SdnFw::lib::Core;
use strict;
use Carp;
use Apache::SdnFw::lib::DB;
#use Apache::SdnFw::lib::Memcached;
use Apache::SdnFw::object::home;
use Template;
use LWP::UserAgent;
use Crypt::CBC;
use Crypt::Blowfish;
use XML::Dumper;
use XML::Simple;
use Net::SMTP::SSL;
use Net::FTP;
use Digest::MD5 qw(md5_hex);
use MIME::Base64 qw(encode_base64);
use MIME::QuotedPrint qw(encode_qp);
use Date::Format;
use Data::Dumper;
use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(mime_type);
BEGIN {
# preload all top level objects
# where the hell are we when we startup?
opendir(ROOT,$ENV{HTTPD_ROOT});
while (my $scode = readdir(ROOT)) {
if (-d "$ENV{HTTPD_ROOT}/$scode/object") {
print STDERR "Loading $scode...";
my $smem = `ps -o rss --no-heading -p $$` if ($ENV{MEM_CALC});
my $s = {};
my %db_object;
my $base = $scode;
my $objectpath = "$ENV{HTTPD_ROOT}/$base/object";
#print STDERR "Objectpath = $objectpath\n";
my %conf;
my $cfile = "$ENV{HTTPD_ROOT}/conf/$scode.conf";
if (-e $cfile) {
open F, $cfile;
while (my $l = <F>) {
chomp $l;
next if ($l =~ m/^#/);
if ($l =~ m/^([^=]+)=(.+)$/) {
$conf{$1} = $2;
}
}
close F;
#print STDERR "DB_STRING,USER=$conf{DB_STRING},$conf{DB_USER}\n";
$s->{dbh} = db_connect($conf{DB_STRING},$conf{DB_USER});
%db_object = db_q($s,"
SELECT code, name
FROM objects
",'keyval');
}
if (-d $objectpath) {
opendir(DIR,$objectpath);
while (my $d = readdir(DIR)) {
next if ($d =~ m/^\./);
next if (!-f "$objectpath/$d" || !($d =~ m/\.pm$/i));
$d =~ s/\.pm$//i;
#print STDERR "Trying to load $d\n";
eval "use $base\:\:object\:\:$d";
if ($@) {
print STDERR "$@\nSKIPPING PRELOAD OF $objectpath/$d.pm\n";
undef $@;
next;
}
# make sure to load the database tables with the objects we load
if (defined($s->{dbh})) {
unless($d =~ m/^(me|config|template)$/) {
if (defined($db_object{$d})) {
delete $db_object{$d};
} else {
my $config = "$base\:\:object\:\:$d\:\:config";
no strict 'refs';
if (defined(&{$config})) {
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
$s->{obase} = $s->{env}{OBJECT_BASE};
$s->{ubase} = $s->{env}{BASE_URL};
$s->{cbase} = "$s->{env}{HTTPD_ROOT}/$s->{obase}";
$s->{self_url} = ($s->{env}{FORCE_HTTPS} ? 'https' : 'http').'://'.
$s->{server_name}.$s->{ubase};
return $s;
}
#########################
# PROCESS
#########################
=head2 process
$s->process();
We should be sending back the following
$s->{r} => (
file_path => if we want to send back a file handle
filename => to force the name of the file going back
content => raw string data to dump back upstream
error => error string to display or log
return_code => to just send back a raw return code
set_cookie => [
array of cookies to send back
],
redirect => redirect to this url
)
=cut
sub process {
my $s = shift;
if ($s->{env}{FORCE_HTTPS} && !$s->{env}{HTTPS}) {
$s->{r}{redirect} = "https://$s->{server_name}$s->{uri}";
$s->{r}{redirect} .= "?$s->{args}" if ($s->{args});
return;
}
# populate a unique variable that can be used on all form variables
# to kill autocomplete
$s->{acfb} = md5_hex("$s->{object}$s->{function}$s->{employee_id}".time);
# the way this works is we look at the url, then decide if we need
# to processes further by connecting to the database
# or if we should just punt and return back a file handle
if ($s->{uri} =~ m/^$s->{ubase}(.*)$/) {
$s->{raw_path} = $1 || '/';
$s->run();
if ($s->{return_code}) {
$s->{r}{return_code} = $s->{return_code};
return;
}
if ($s->{in}{debug} && $s->{env}{DEV}) {
#delete $s->{content};
$s->{content} = Data::Dumper->Dump([$s]);
$s->{content_type} = 'text/plain';
}
# always make the content type xml for api
$s->{content_type} = 'text/xml' if ($s->{api} || $s->{o}{perl_dump});
# move the content type back to the return hash
$s->{r}{content_type} = $s->{content_type};
# set some things for logging purposes
$s->{r}{log_user} = $s->{log_user} || '-';
$s->{r}{log_location} = $s->{log_location} || '-';
if ($s->{redirect}) {
# if we have any messages to display, dump them to session and then
# pick them back up on the redirect
if ($s->{message}) {
$s->session_add('message',$s->{message});
}
$s->{r}{redirect} = $s->{redirect};
return;
}
# add the top menu to everything unless for some reason we are not text/html
if ($s->{content_type} eq 'text/html' && !$s->{in}{print}) {
$s->{r}{content} = $s->_content_add_menu();
# if the object has a template, then put the returned content
# into that menu
if (defined($s->{o}{template})) {
my $out;
$s->tt($s->{o}{template}, { s => $s },\$out);
$s->{r}{content} .= $out;
} else {
$s->{r}{content} .= $s->{message} if ($s->{message});
if ($s->{o}{footer}) {
$s->tt($s->{o}{footer}, { s => $s });
}
$s->{r}{content} .= $s->{content};
}
} elsif ($s->{api}) {
$s->{r}{content} = qq(<?xml version="1.0" ?>\n<response>\n);
$s->{r}{content} .= "<object>$s->{object}</object>\n" if ($s->{object});
$s->{r}{content} .= "<function>$s->{function}</function>\n" if ($s->{function});
$s->{r}{content} .= $s->{message} if ($s->{message});
$s->{r}{content} .= $s->{content};
$s->{r}{content} .= '</response>';
} elsif ($s->{o}{perl_dump}) {
$s->{r}{content} = qq(<?xml version="1.0" ?>\n);
my $dump = new XML::Dumper;
$s->{r}{content} .= $dump->pl2xml(\%{$s->{perl_dump}});
} else {
$s->{r}{content} = $s->{content};
}
# add some stuff to head like stylesheet or other things
# which modules might have added, but only if our content type is still text/html
if ($s->{content_type} eq 'text/html') {
unless($s->{nohead}) {
$s->{r}{head} = $s->_head_add_title();
$s->{r}{head} .= $s->_head_add_css();
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
values of information that is passed to template toolkit. $string can be a
reference to a string variable, or to an array ref, in which case the results
are pushed into that array. If $string is not defined, then the results are
appended to $s->{content}.
$s->tt('object/template.tt', { s => $s, hash => \%hash });
$s->tt('object/template.tt', { s => $s, list => \@list },\$output);
$s->tt(\$template, { s => $s },\@output);
=cut
my $s = shift;
my $fname = shift;
my $args = shift;
my $string = shift;
#my $agentfname;
#if ($s->{agent}) {
# ($fname = $agentfname) =~ s/([^\/]+\.tt)$/$s->{agent}\/$1/;
#}
$fname .= '.xml' if ($s->{api});
if (defined $string) {
if (ref $string eq 'ARRAY') {
my $tmp;
$s->{tt}->process($fname,$args,\$tmp) || croak $s->{tt}->error();
push @{$string}, $tmp;
} else {
$s->{tt}->process($fname,$args,$string) || croak $s->{tt}->error();
}
} else {
$s->{tt}->process($fname,$args) || croak $s->{tt}->error();
}
}
=head2 update_and_log
$s->update_and_log(
table => tablename,
idfield => idfield,
object => object,
id => id,
existing => \%hash,
update => \%hash);
=cut
sub update_and_log {
my $s = shift;
my %args = @_;
croak "Missing table" unless($args{table});
croak "Missing idfield" unless($args{idfield});
croak "Missing object" unless($args{object});
croak "Missing id" unless($args{id});
croak "Missing existing" unless(defined($args{existing}));
croak "Missing update" unless(defined($args{update}));
#croak "<pre>".Data::Dumper->Dump([\%{$args{update}}])."</pre>";
my %update;
foreach my $k (keys %{$args{update}}) {
if (exists($args{existing}{$k})) {
my $object;
if ($args{update}{$k} =~ m/^(.+):(\d*)$/) {
$object = $1;
$args{update}{$k} = $2;
}
if ($args{update}{$k} ne $args{existing}{$k}) {
$update{$k} = $args{update}{$k};
my $old = $args{existing}{$k};
my $new = $update{$k};
my $field = $k;
if ($object) {
$field = $object;
$old = $s->db_q("SELECT name
FROM ${object}s_v_keyval
WHERE id=?
",'scalar',
v => [ $args{existing}{$k} ])
if ($args{existing}{$k});
$new = $s->db_q("SELECT name
FROM ${object}s_v_keyval
WHERE id=?
",'scalar',
v => [ $update{$k} ])
if ($update{$k});
}
$s->log($args{object},$args{id},
"$args{object} $field changed from [$old] to [$new]");
}
} else {
croak "Existing data for $args{object} field $k not defined";
}
}
#croak "<pre>".Data::Dumper->Dump([\%update])."</pre>";
if (keys %update) {
$s->db_update_key($args{table},$args{idfield},$args{id},\%update);
}
}
sub in_to_hash {
=head2 in_to_hash
my %hash = $s->in_to_hash($identifier,[$noblanks]);
=cut
my $s = shift;
my $identifier = shift;
my $noblanks = shift;
my %tmp;
foreach my $key (keys %{$s->{in}}) {
if ($key =~ m/^$identifier:(.+):(.+)$/) {
if ($noblanks) {
$tmp{$1}{$2} = $s->{in}{$key}
unless($s->{in}{$key} eq '');
} else {
$tmp{$1}{$2} = $s->{in}{$key};
}
}
}
return %tmp;
}
sub log {
=head2 log
$s->log($ref,$ref_id,$msg);
=cut
my $s = shift;
my $ref = shift;
my $ref_id = shift;
my $msg = shift;
$s->db_insert('logs',{
employee_id => $s->{employee_id},
ref => $ref,
ref_id => $ref_id,
log_msg => (substr $msg, 0, 255),
});
}
sub xsave_pdf {
=head2 xsave_pdf
$s->xsave_pdf($pdf_name,$fname,$args);
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
# in a different way
if ($croak =~ m/^ERROR:\s+invalid input syntax for type date:\s+"(.+)"/) {
$message = "'$1' is not a valid date";
$croak = 0;
} elsif ($croak =~ m/^ERROR:\s+null value in column "(.+)" violates not-null constraint/) {
$message = "The database field '$1' can not be null/empty. Is there a for field that you left blank that needed to be filled in?";
$croak = 0;
} elsif ($croak =~ m/^ERROR:\s+invalid input syntax for integer: "(.+)"/) {
$message = "'$1' is not a valid integer";
$croak = 0;
}
}
if ($s->{raw_message}) {
$s->{raw_message} .= "\n";
}
$s->{raw_message} .= $message;
my $class = ($croak) ? 'alert' : 'warning';
if ($s->{o}{perl_dump}) {
$s->{perl_dump}{error} = $message;
} elsif (!defined($s->{tt})) {
print "alert: $message\n";
$s->{message} .= $message;
} else {
if ($s->{quiet_errors} && $croak) {
$message = "Sorry an error has occured";
}
$s->tt('alert.tt', { s => $s, message => $message, class => $class }, \$alert);
$s->{message} .= $alert;
}
# add some debugging information so we know where the error is getting called from
#$s->{message} .= "<pre>".Carp::longmess('Stack-Trace')."</pre>";
if ($croak && $s->{object} ne 'e') {
$s->send_error($croak);
}
}
sub send_error {
=head2 send_error
$s->send_error($msg);
=cut
my $s = shift;
my $msg = shift;
# make sure we do not report errors to ourself, otherwise we go into a circular loop!
# if this was a croak, it means that we should record this error into the main error
# recording system
my $error = $s->escape($msg);
my $employee = '<employee>'.$s->escape("$s->{employee_id} $s->{employee}{name}").
'</employee>' if ($s->{employee_id});
my $in = $s->escape(Data::Dumper->Dump([\%{$s->{in}}]));
my $env = $s->escape(Data::Dumper->Dump([\%{$s->{env}}]));
my $session = $s->escape(Data::Dumper->Dump([\%{$s->{session_data}}]));
my $uri = $s->escape($s->{uri});
my $xml = <<END;
<?xml version="1.0" encoding="UTF-8"?>
<error>
<message>$error</message>
$employee
<var_in>$in</var_in>
<uri>$uri</uri>
<var_env>$env</var_env>
<remote_addr>$s->{remote_addr}</remote_addr>
<server_name>$s->{server_name}</server_name>
<session_data>$session</session_data>
</error>
END
my $ua = new LWP::UserAgent;
$ua->timeout(5);
my $req = new HTTP::Request('POST' => "http://erp.smalldognet.com/sdnerp/e");
$req->content_type('application/x-www-form-urlencoded');
$req->content($xml);
$ua->request($req);
}
sub lwp_xml {
my $s = shift;
my $url = shift;
my $ua = new LWP::UserAgent;
my $req = new HTTP::Request('GET' => $url);
my $resp = $ua->request($req);
if ($resp->is_success) {
my $content = $resp->content;
my $xml = eval { XMLin($content); };
if ($@) {
croak "Failed to eval returned xml: $@";
} else {
return $xml;
}
} else {
croak "Request to $url failed";
}
}
sub confirm {
=head2 confirm
$s->confirm($msg);
=cut
my $s = shift;
my $message = shift;
$s->tt('confirm.tt', { s => $s, message => $message });
}
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
=cut
my $s = shift;
my $message = shift;
if ($s->{employee_id}) {
my $notify;
$s->tt('notify.tt', { s => $s, message => $message}, \$notify);
$s->{message} .= $notify;
}
}
sub run {
my $s = shift;
# first we need a database connection but not for our database debug option
$s->{dbh} = db_connect($s->{env}{DB_STRING},$s->{env}{DB_USER})
unless($s->{object} eq 'dbdb');
#get_memd($s);
# figure out where our base code directory is so we can use templates
# and other things
foreach my $i (@INC) {
if (-d "$i/Apache/SdnFw") {
$s->{plib} = "$i/Apache/SdnFw";
last;
}
}
my @path;
if ($s->{agent}) {
push @path, "$ENV{HTTPD_ROOT}/$s->{obase}/tt/$s->{agent}";
push @path, "$ENV{HTTPD_ROOT}/$s->{obase}/object";
push @path, "$ENV{HTTPD_ROOT}/$s->{obase}/tt";
push @path, "$s->{plib}/tt/$s->{agent}";
push @path, "$s->{plib}/tt";
push @path, "$s->{plib}/object";
} else {
push @path, "$ENV{HTTPD_ROOT}/$s->{obase}/object";
push @path, "$ENV{HTTPD_ROOT}/$s->{obase}/tt";
push @path, "$s->{plib}/tt";
push @path, "$s->{plib}/object";
}
push @path, "/data/$s->{obase}";
$s->{tt} = Template->new(
INCLUDE_PATH => \@path,
INTERPOLATE => 1,
RELATIVE => 1,
EVAL_PERL => 1,
COMPILE_DIR => '/tmp/tt_cache',
COMPILE_EXT => '.cache',
# remove leading and trailing whitespace and newlines
#PRE_CHOMP => 2,
#POST_CHOMP => 2,
#STAT_TTL => 1,
OUTPUT => \$s->{content},
);
#$s->{content} .= "<pre>".Data::Dumper->Dump([$s])."</pre>"; return;
#$s->{content} .= "<pre>".Data::Dumper->Dump([\@INC])."</pre>"; return;
# if ($s->{raw_path} eq '/logout') {
# return unless($s->_authenticate());
# }
# if we barf below anywhere we do not want to show anything but the raw error so set this
$s->{nomenu} = 1;
# at this point, we need to look for $object
# and from there $function
# and make it into a path that we can then run
# $object will be things like /objectname
# or /objectname/function
# and will only go two levels deep
@{$s->{path}} = split '/', $s->{raw_path};
shift @{$s->{path}}; # get rid of the blank due to starting with /
if (scalar @{$s->{path}} < 1) {
# set home if we did not explicitly call a object
push @{$s->{path}}, 'home';
}
# make sure we are not trying to call strange stuff
foreach my $v (@{$s->{path}}) {
croak "invalid path value '$v'" unless($v =~ m/^[a-z0-9_\.]+$/);
}
croak "invalid path (more than 2 keys)" if (scalar @{$s->{path}} > 2);
$s->{object} = $s->{path}[0];
$s->{function} = $s->{path}[1] || 'list';
# this is a stupid hack because I could not create an object called return
$s->{object} = 'oreturn' if ($s->{object} eq 'return');
if ($s->{object} eq 'logout') {
$s->_authenticate();
$s->{function} = 'home' if ($s->{function} eq 'list');
$s->redirect(object => $s->{function},
function => 'list');
return;
}
if ($s->{env}{DEV} && $s->{object} eq 'debug') {
$s->{content} = Data::Dumper->Dump([$s]);
$s->{content_type} = 'text/plain';
return;
}
no strict 'refs';
if ($s->{object} ne 'help') {
$s->{obj_base} = $s->{obase}.'::object::'.$s->{object};
my $config = $s->{obj_base}.'::config';
# make sure we can find the object
unless(defined(&{$config})) {
# see if there is a generic object defined
$s->{obj_base} = 'Apache::SdnFw::object::'.$s->{object};
eval "use $s->{obj_base}";
$config = $s->{obj_base}.'::config';
unless(defined(&{$config})) {
$s->alert("Sorry, I have no idea what a $s->{object} is, or how to $s->{function} it ($config)");
return;
} else {
$s->{generic_object} = 1;
}
}
$s->{o} = &{$config}($s);
}
# clear the no menu now
delete $s->{nomenu};
unless ($s->{o}{public}) {
# then we need to authenticate the person
return unless($s->_authenticate());
} else {
# a public interface, but we still need to authorize them
# but they are not an employee
if ($s->{o}{auth}) {
return unless($s->_interface_auth());
} elsif ($s->{o}{local_auth}) {
my $auth = $s->{obj_base}.'::auth';
return unless(&{$auth}($s));
}
# so we don't show anything but the raw html that the public thing spits out
$s->{nomenu} = 1;
}
if ($s->{object} eq 'home' && $s->{function} eq 'list' && $s->{api}) {
_api_calls($s);
return;
}
$s->{log_user} = $s->{employee_id} if ($s->{employee_id});
$s->session_load();
#croak "<pre>".Data::Dumper->Dump([$s])."</pre>";
# make sure we actually have functions defined
if ($s->{object} ne 'help') {
unless(defined($s->{o}{functions})) {
$s->alert("Sorry, there were no functions defined for $s->{object}");
return;
}
}
if ($s->{object} eq 'help') {
return unless($s->help());
} elsif ($s->{function} eq 'permission') {
return unless($s->permission());
} else {
# confirm access to this function by this person
if ($s->{o}{public}) {
1;
} elsif ($s->{object} eq 'me') {
# just confirm we have an employee_id
unless($s->{employee_id}) {
$s->alert("Missing or invalid employee_id");
return;
}
} else {
return unless($s->access($s->{function}));
}
# run our pre logic
my $pre = $s->{obase}.'::object::config::pre';
if (defined(&{$pre})) {
return unless(&{$pre}($s));
}
my $addhelp;
if ($s->{employee}{admin}) {
$addhelp = 1; # add a help link for admin
} else {
if (-e "/data/$s->{obase}/template/help/$s->{object}.tt") {
$addhelp = 1;
}
}
$s->add_action(object => 'help',
title => 'help',
function => $s->{object}) if ($addhelp && !$s->{agent});
return unless($s->call($s->{function}));
}
if ($s->{object} ne 'help') {
# do any post processing
my $post = $s->{obase}.'::object::config::post';
if (defined(&{$post})) {
&{$post}($s);
}
}
#$s->{content} .= "<pre>".Data::Dumper->Dump([$s])."</pre>";
}
sub call {
my $s = shift;
my $f = shift;
# make sure it's a valid function
unless(defined($s->{o}{functions}{$f})) {
$s->alert("Sorry, $f is not defined for $s->{object}");
return 0;
}
my $function = $s->{obj_base}.'::'.$f;
no strict 'refs';
# do a final check to see if the function is valid
# and maybe call the generic function
unless (defined(&{$function})) {
$function = 'generic_'.$f;
unless(defined(&{$function})) {
$s->alert("Sorry, you can not $f a $s->{object}");
return 0;
}
}
# setup some convience variables so we have to type less
$s->{uof} = "$s->{ubase}/$s->{object}/$s->{function}";
$s->{uo} = "$s->{ubase}/$s->{object}";
if ($s->{o}{log_stderr}) {
my $dd = Data::Dumper->new([\%{$s->{in}}],[qw(data)]);
$dd->Indent(0);
$s->db_insert('object_debug',{
o => $s->{object},
f => $s->{function},
i => $dd->Dump(),
});
}
# actually call the function
eval {
&{$function}($s);
};
if ($@) {
# force text/html just in case so we always return html....
$s->{content_type} = 'text/html';
if ($s->{dbh}->{AutoCommit} == 0) {
$s->{dbh}->rollback;
}
# check for database errors and report them differently.....
if ($@ =~ m/^ERROR:\s+alert:(.+)/) {
$s->alert($1);
} elsif ($@ =~ m/^alert:(.+)/) {
my $msg = $1;
$msg =~ s/ at \/usr.+$//g;
$s->alert($msg);
} elsif ($s->{api}) {
$s->alert($@,$@);
} else {
$s->alert("<pre>$@</pre>",$@);
}
}
}
sub build_x12 {
=head2 build_x12
my %hash = $s->build_x12($doctype,\%vendor,\%data);
This function looks for a perl parser file for the specific vendor
for the specific $doctype (850, 855, 856, 810, etc) and returns
a hash which can then be fed into format_x12.
=cut
my $s = shift;
my $doctype = shift;
my $vendor = shift;
my $data = shift;
# my $function = $s->{obj_base}.'::'.$f;
croak "Unknown vendor code" unless($vendor->{code});
croak "Missing doctype" unless($doctype);
#croak "vendor=".Data::Dumper->Dump([$vendor]);
#croak "data=".Data::Dumper->Dump([$data]);
my $base = $s->{obase} || $s->{env}{OBJECT_BASE};
my $package = $base.'::edimap::'.$vendor->{code}.'::'.$doctype;
no strict 'refs';
eval "use $package";
my $function = $package.'::build';
my %return = &{$function}($s,$vendor,$data);
return %return;
}
sub format_x12 {
=head2 format_x12
my $x12 = $s->format_x12($vendor_edi_document_id,\%data);
=cut
my $s = shift;
my $vendor_edi_document_id = shift;
my $data = shift;
my @list = $s->db_q("
SELECT segment_code, segment_order, element_code,
element_order, name, element_type, min_length,
max_length, segment_option
FROM vendor_edi_segment_elements_v
WHERE vendor_edi_document_id=?
ORDER BY segment_order, element_order
",'arrayhash',
v => [ $vendor_edi_document_id ]);
unless(defined($data->{vendor})) {
croak "Missing vendor information in data";
}
my %work;
foreach my $ref (@list) {
my $segment_code = $ref->{segment_code};
unless(defined($work{segment}{$segment_code})) {
push @{$work{segments}}, $segment_code;
$work{segment}{$segment_code}{loop} = $ref->{segment_option};
}
push @{$work{segment}{$segment_code}{elements}}, {
element_code => $ref->{element_code},
element_order => $ref->{element_order},
name => $ref->{name},
element_type => $ref->{element_type},
min_length => $ref->{min_length},
max_length => $ref->{max_length},
};
}
# croak "test".Data::Dumper->Dump([\%work]);
my %loops_completed;
my $output;
foreach my $seg (@{$work{segments}}) {
if ($work{segment}{$seg}{loop}) {
my $loop = $work{segment}{$seg}{loop};
next if (defined($loops_completed{$loop}));
# our segment is within a loop, so lets look in that loop instead
# but only if we have not visited the loop before
next unless(defined($data->{$loop}));
foreach my $loop_ref (@{$data->{$loop}}) {
my $loop_seg = $loop_ref->{key};
croak "Missing key in loop segment" unless($loop_seg);
my $elements = $work{segment}{$loop_seg}{elements};
$output .= _output_x12_segment($s,$elements,$loop_seg,$loop_ref);
$output .= $data->{vendor}{segment_term}."\n";
}
$loops_completed{$loop} = 1;
} elsif (defined($data->{$seg})) {
my $elements = $work{segment}{$seg}{elements};
$output .= _output_x12_segment($s,$elements,$seg,\%{$data->{$seg}});
$output .= $data->{vendor}{segment_term}."\n";
}
}
return $output;
}
sub _output_x12_segment {
my $s = shift;
my $elements = shift;
my $seg_code = shift;
my $hashref = shift;
my $max_order = _max_order($hashref);
my @list;
push @list, $seg_code;
foreach my $eref (@{$elements}) {
next if ($eref->{element_order} > $max_order); # do not do elements higher
my $n = $eref->{element_order};
my $value = (defined($hashref->{$n}))
? $hashref->{$n}
: '';
$value =~ s/\*//g;
if ($eref->{element_type} eq 'DT') {
if ($eref->{min_length} == 6) {
$value =~ s/^20//;
}
$value =~ s/-//g;
}
if ($eref->{element_type} eq 'TM') {
$value =~ s/\D//;
}
if (defined($hashref->{$n})) {
if ($eref->{min_length} > 1) {
if (length $value < $eref->{min_length}) {
if ($eref->{element_type} eq 'AN') {
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
sub _max_order {
my $hashref = shift;
my $order = 0;
foreach my $k (keys %{$hashref}) {
$order = $k if ($k > $order);
}
return $order;
}
sub verify_x12 {
my $s = shift;
my $vendor = shift;
my $dataref = shift;
# all we do here right now is make sure our header envelope matches who we think
# is sending to use, and who they thing they are sending to....
my %check = (
partner_edi_identifier => 'ISA08',
partner_edi_qualifier => 'ISA07',
vendor_code => 'ISA06',
vendor_code_qual => 'ISA05',
);
foreach my $k (keys %check) {
my $value = $dataref->{$check{$k}};
$value =~ s/\s//g;
croak "No $k to compare" unless($vendor->{$k});
croak "Database $k value $vendor->{$k} != X12 $check{$k} value $value"
if ($vendor->{$k} ne $value);
}
}
sub parse_x12 {
my $s = shift;
my $vendor = shift;
my $input = shift;
#print "Input=$input\n";
$vendor->{element_sep} = '\*' if ($vendor->{element_sep} eq '*');
# kill cr
$input =~ s/\r//g;
if ($vendor->{segment_term}) {
# if we have an actual character terminator, then kill all newlines
$input =~ s/\n//g unless($vendor->{segment_term} eq "\n");
} else {
# use newline as our terminator
$vendor->{segment_term} = "\n";
}
#print "Input2=$input\n";
my @data;
foreach my $seg (split $vendor->{segment_term}, $input) {
my @e = split $vendor->{element_sep}, $seg;
push @data, [ @e ];
}
#print " ".Data::Dumper->Dump([\@data]);
my %x;
my %work;
unless($vendor->{partner_edi_identifier} && $vendor->{partner_edi_qualifier}) {
croak "Partner $vendor->{partner_id}} has unknown identifier or qualifier";
}
my $dt;
my $i_ref = undef;
my $g_ref = undef;
my $s_ref = undef;
foreach my $seg (@data) {
#print "Processing $seg->[0]\n" if ($args{v});
unless(defined($i_ref)) {
if ($seg->[0] eq 'ISA') {
%x = _x12_map($s,$vendor->{edi_version_id},'ISA',$seg);
if ($x{error}) {
croak $x{error};
}
$x{groups} = [];
$i_ref = $x{groups};
$x{group_count} = 0;
#print $seg->[0].": ".Data::Dumper->Dump([\%x]) if ($args{v});
next;
} else {
croak "ISA not found";
}
}
if ($seg->[0] eq 'IEA') {
$dt = 'HEAD';
# print $seg->[0].": ".Data::Dumper->Dump([\%tmp]) if ($args{v});
my %tmp = _x12_map($s,$vendor->{edi_version_id},'IEA',$seg);
if ($tmp{error}) {
croak $tmp{error};
} elsif ($tmp{IEA01} != $x{group_count}) {
$x{error} = "Group count in IEA ($tmp{IEA01}) ne groups ($x{group_count})";
} elsif ($tmp{inter_control_num} ne $x{inter_control_num}) {
$x{error} = "IEA control num ne ISA control number";
}
last;
}
if ($seg->[0] eq 'GE') {
$dt = 'HEAD';
# we need to count ourself
#$g_ref->{set_count}++;
my %tmp = _x12_map($s,$vendor->{edi_version_id},'GE',$seg);
#print $seg->[0].": ".Data::Dumper->Dump([\%tmp]) if ($args{v});
if ($tmp{error}) {
$g_ref->{error} = $tmp{error};
} elsif ($tmp{GE01} != $g_ref->{set_count}) {
$g_ref->{error} = "Set count in GE ($tmp{GE01}) ne sets ($g_ref->{set_count})";
} elsif ($tmp{group_control_num} ne $g_ref->{group_control_num}) {
$g_ref->{error} = "GE control num ne GS control number";
}
$g_ref = undef;
next;
}
if ($seg->[0] eq 'SE') {
$dt = 'HEAD';
# we need to count ourself
$s_ref->{segment_count}++;
my %tmp = _x12_map($s,$vendor->{edi_version_id},'SE',$seg);
#print $seg->[0].": ".Data::Dumper->Dump([\%tmp]) if ($args{v});
#print Data::Dumper->Dump([$s_ref]);
if ($tmp{error}) {
$s_ref->{error} = $tmp{error};
} elsif ($tmp{SE01} != $s_ref->{segment_count}) {
$s_ref->{error} = "Segment count in SE ($tmp{SE01}) ne segments ($s_ref->{segment_count})";
} if ($tmp{SE02} ne $s_ref->{ST02}) {
$s_ref->{error} = "SE control num $tmp{SE02} ne ST control number $s_ref->{ST02}";
}
$s_ref = undef;
next;
}
unless(defined($g_ref)) {
if ($seg->[0] eq 'GS') {
my %tmp = _x12_map($s,$vendor->{edi_version_id},'GS',$seg);
if ($tmp{error}) {
croak $tmp{error};
}
#print $seg->[0].": ".Data::Dumper->Dump([\%tmp]) if ($args{v});
$tmp{sets} = [];
$tmp{set_count} = 0;
# make sure they are sending to the right person
# unless($tmp{GS03} eq $work{partner}{edi_identifier}) {
# # kill this group because we did not match
# # our Data Interchange Control Number is GS06
# $tmp{error} = "Document Identifier $tmp{GS03} does not match partner identifier $work{partner}{edi_identifier}";
# }
push @{$i_ref}, { %tmp };
$g_ref = $i_ref->[$x{group_count}];
$x{group_count}++;
# croak "test: ".Data::Dumper->Dump([\%tmp]);
# now that we have the group, we need to load the
# rest of the data matching this version and for this
# vendor/partner
#_loadmap($tmp{GS08},$tmp{GS02});
next;
} else {
croak "GS not found";
}
}
unless(defined($s_ref)) {
if ($seg->[0] eq 'ST') {
$dt = 'HEAD';
my %tmp = _x12_map($s,$vendor->{edi_version_id},'ST',$seg);
if ($tmp{error}) {
croak $tmp{error};
}
# do we have this document for this vendor, and is it the right version?
# unless(defined($work{vendor_documents}{$tmp{ST01}}) &&
# $g_ref->{GS08} eq $work{vendor_documents}{$tmp{ST01}}{version_code}) {
# $tmp{error} = "Document $tmp{ST01}/$g_ref->{GS08} not defined for vendor";
# }
#croak "test: ".Data::Dumper->Dump([\%tmp]);
$tmp{segments} = [];
$tmp{segment_count} = 1;
push @{$g_ref->{sets}}, { %tmp };
$s_ref = $g_ref->{sets}[$g_ref->{set_count}];
$g_ref->{set_count}++;
$dt = $tmp{ST01};
next;
} else {
croak "ST not found";
}
}
my %hash = _x12_map($s,$vendor->{edi_version_id},$seg->[0],$seg);
# print $seg->[0].": ".Data::Dumper->Dump([\%hash]) if ($args{v});
push @{$s_ref->{segments}}, { %hash } if (keys %hash);
$s_ref->{segment_count}++;
}
return %x;
}
sub _x12_map {
my $s = shift;
my $version = shift;
my $type = shift;
my $arrayref = shift;
# load up our segment information first
# if it is not defined yet
unless(defined($s->{x12map}{$type})) {
%{$s->{x12map}{$type}} = $s->db_q("
SELECT s.segment_code, se.element_order, e.*,
s.segment_code || to_char(se.element_order,'FM00') as key
FROM edi_segments s
JOIN edi_segment_elements se ON s.edi_segment_id=se.edi_segment_id
JOIN edi_elements e ON se.element_code=e.element_code
WHERE s.segment_code=?
AND s.edi_version_id=?
",'hashhash',
k => 'element_order',
v => [ $type, $version ]);
# unless(keys %{$s->{x12map}{$type}}) {
# croak "No keys found for segment $type version $version";
# }
}
my $mapref = $s->{x12map}{$type};
my %hash;
my %error;
for my $i ( 1 .. $#{$arrayref}) {
next unless(defined($mapref->{$i}));
my $value = $arrayref->[$i];
my $length = length $value;
my $key = $mapref->{$i}{key};
# does a required field have values?
if ($mapref->{$i}{option} eq 'M' && $length == 0) {
$error{error} = "required field $key ($i) missing data";
return %error;
}
if ($length && $mapref->{$i}{min}) {
my $min = $mapref->{$i}{min};
my $max = $mapref->{$i}{max};
# is the value the correct length
if ($length < $min || $length > $max) {
$error{error} = "field $key ($i) length invalid ($min < $length < $max)";
return %error;
}
}
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
my %doc = $s->db_q("
SELECT *
FROM vendor_edi_documents_v
WHERE edi_vendor_id=?
AND document_code='997'
",'hash',
v => [ $vendor->{edi_vendor_id} ]);
unless($doc{vendor_edi_document_id}) {
croak "Can not find 997 document for vendor $vendor->{edi_vendor_id}";
}
my %out;
$s->x12_add_isa($vendor,\%out,$edi_trans_id);
$s->x12_add_gs('FA',$vendor,\%out,$edi_trans_id);
croak "No Groups" unless (ref $dataref->{groups} eq 'ARRAY');
croak "More than 1 Group" if (scalar @{$dataref->{groups}} > 1);
$s->x12_add_st('997',$dataref->{ISA13},\%out);
# process everything now
foreach my $gref (@{$dataref->{groups}}) {
croak "No Sets in group" unless (ref $gref->{sets} eq 'ARRAY');
$out{AK1}{1} = $gref->{GS01}; # these are things like IM, PO, etc
$out{AK1}{2} = $gref->{GS06};
$out{AK9}{2} = 0; # number of sets
$out{AK9}{3} = 0; # received
$out{AK9}{4} = 0; # accepted
if (scalar @{$gref->{sets}} ne $gref->{set_count}) {
croak "Sets array does not equal set count";
}
foreach my $sref (@{$gref->{sets}}) {
$out{AK9}{2}++;
$out{AK9}{3}++;
$out{AK9}{4}++;
croak "No Segments in set" unless (ref $sref->{segments} eq 'ARRAY');
push @{$out{loop}}, {
key => 'AK2',
1 => $sref->{ST01},
2 => $sref->{ST02},
};
$out{SE}{1}++;
push @{$out{loop}}, {
key => 'AK5',
1 => 'A',
};
$out{SE}{1}++;
}
# accept if we had no errors
$out{AK9}{1} = 'A' if ($out{AK9}{2} == $out{AK9}{4}); # accepted
$out{AK9}{1} = 'P' if ($out{AK9}{2} > $out{AK9}{4} && $out{AK9}{4}); # partial accept
$out{AK9}{1} = 'R' unless ($out{AK9}{4}); # reject all
$out{SE}{1}++; # for the AK1
$out{SE}{1}++; # for the AK9
}
#print Data::Dumper->Dump([\%out]);
my $x12 = $s->format_x12($doc{vendor_edi_document_id},\%out);
#print $x12;
$s->send_x12('997',$x12,$vendor->{edi_vendor_id},$edi_trans_id);
}
sub x12_add_isa {
my $s = shift;
my $vendor = shift;
my $out = shift;
my $edi_trans_id = $s->db_insert('edi_transactions',{
filename => 'n/a',
},'edi_trans_id');
$out->{vendor} = $vendor;
$out->{edi_trans_id} = $edi_trans_id;
if ($s->{env}{DEV}) {
foreach my $k (qw(vendor_code vendor_code_qual)) {
$vendor->{$k} = $vendor->{"test_$k"}
if ($vendor->{"test_$k"});
}
}
$out->{ISA}{1} = '00';
$out->{ISA}{2} = '';
$out->{ISA}{3} = '00';
$out->{ISA}{4} = '';
$out->{ISA}{5} = $vendor->{partner_edi_qualifier};
$out->{ISA}{6} = $vendor->{partner_edi_identifier};
$out->{ISA}{7} = $vendor->{vendor_code_qual};
$out->{ISA}{8} = $vendor->{vendor_code};
$out->{ISA}{9} = $s->{datetime}{ymd};
$out->{ISA}{10} = (substr $s->{datetime}{ymdhms},8,2).
(substr $s->{datetime}{ymdhms},10,2);
$out->{ISA}{11} = 'U';
$out->{ISA}{12} = '00401';
$out->{ISA}{13} = $edi_trans_id; #control number
$out->{ISA}{14} = '0'; # acknowledge (0,1)?
$out->{ISA}{15} = ($s->{env}{DEV}) ? 'T' : 'P'; # usage (T = test, P = production)
$out->{ISA}{16} = $vendor->{subelement_sep};
$out->{IEA}{1} = 0; # populate our footer, so other things can count up as needed
$out->{IEA}{2} = $out->{ISA}{13};
}
sub x12_add_gs {
my $s = shift;
my $groupid = shift;
my $vendor = shift;
my $out = shift;
my $gs_id = $s->db_insert('edi_gs',{
group_identifier => $groupid,
edi_trans_id => $out->{edi_trans_id},
edi_vendor_id => $vendor->{edi_vendor_id},
},'edi_gs_id');
$out->{edi_gs_id} = $gs_id;
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
} else {
$s->alert("Connection error to $server$url: ".$resp->status_line);
return undef;
}
}
sub edi_get {
=head2 edi_get
my $data = $s->edi_post($ref,$url);
=cut
my $s = shift;
my $ref = shift;
my $url = shift;
my $server = ($s->{env}{DEV})
? $ref->{sdn_dev_url}
: $ref->{sdn_url};
croak "Unknown sdn_url" unless($server);
my $ua = new LWP::UserAgent;
$ua->timeout(5);
my $req = new HTTP::Request('GET' => "$server$url");
my $resp = $ua->request($req);
my $rxml;
if ($resp->is_success) {
my $dump = new XML::Dumper;
my $rxml = $dump->xml2pl($resp->content);
if (defined($rxml->{data})) {
return $rxml->{data};
} elsif (defined($rxml->{error})) {
$s->alert("Error from $server: $rxml->{error}");
return undef;
}
} else {
$s->alert("Connection error to $server$url: ".$resp->status_line);
return undef;
}
}
sub access {
my $s = shift;
my $function = shift;
# check and see if we have an entry for this object/function
my %hash = $s->db_q("
SELECT a.action_id, a.name, a.a_object, a.a_function,
concat(ga.group_id) as groups
FROM actions_v a
LEFT JOIN group_actions ga ON a.action_id=ga.action_id
WHERE a.a_object=?
AND a.a_function=?
GROUP BY 1,2,3,4
",'hash',
v => [ $s->{object}, $function ]);
#croak "<pre>".Data::Dumper->Dump([\%hash])."</pre>";
# if we do not, then add the object/function to the admin group
unless($hash{action_id}) {
$hash{groups} = $s->_set_default_access($s->{object},$function);
}
# we have a problem here....how do we deal with people who
# we do not want to to have access to "everything"?
# if someone has "strict_perms", then skip this everyone check
# if there are no groups listed, then it's open to everyone
if (!$hash{groups} && !$s->{employee}{strict_perms}) {
# set a flag so we know we can skip location checking as well
$s->{no_location_check} = 1;
return 1;
}
# otherwise check and see which group this person belongs to
foreach my $g (split ',', $hash{groups}) {
foreach my $eg (split ',', $s->{employee}{groups}) {
return 1 if ($g eq $eg);
}
}
my $alert;
$s->tt('noaccess.tt', { s => $s,
message => "Sorry, you do not have access to $function a $s->{object}" }, \$alert);
$s->{message} .= $alert;
return 0;
}
sub _set_default_access {
my $s = shift;
my $object = shift;
my $function = shift;
my $action_id = $s->db_insert('actions', {
a_object => $object,
a_function => $function,
name => (ucfirst $function).' '.(ucfirst $object).'s',
},'action_id');
# and add this action to the admin group
my $groups = $s->db_q("
SELECT group_id
FROM groups
WHERE admin IS TRUE
",'scalar');
$s->db_q("INSERT INTO group_actions (group_id, action_id)
SELECT g.group_id, $action_id
FROM groups g
WHERE g.group_id IN (?)
",undef,
v => [ $groups ]);
return $groups;
}
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
last unless($eol);
}
if ($onerow) {
return @{$rows[0]};
}
return @rows;
}
sub mime_type {
my $s = shift;
return unless($s->{r}{file_path});
return 'text/html' if ($s->{r}{file_path} =~ m/\.html?$/i);
return 'image/jpeg' if ($s->{r}{file_path} =~ m/\.jpg$/i);
return 'image/png' if ($s->{r}{file_path} =~ m/\.png$/i);
return 'image/gif' if ($s->{r}{file_path} =~ m/\.gif$/i);
return 'text/xml' if ($s->{r}{file_path} =~ m/\.x(m|s)l$/i);
return 'text/css' if ($s->{r}{file_path} =~ m/\.css$/i);
return 'application/pdf' if ($s->{r}{file_path} =~ m/\.pdf$/i);
return 'text/plain' if ($s->{r}{file_path} =~ m/\.txt$/i);
}
sub session_delete {
my $s = shift;
my $key = shift;
if ($key) {
# just delete one key
if (defined($s->{session_data}{$key})) {
delete $s->{session_data}{$key};
_session_update($s);
}
} else {
# delete entire session
$s->{session_data} = undef;
$s->db_q("
DELETE FROM employee_sessions
WHERE employee_id=?
",undef,
v => [ $s->{employee_id} ]);
}
}
sub session_add {
my $s = shift;
my $key = shift;
my $value = shift;
my $insert = 1 unless(defined($s->{session_data}));
$s->{session_data}{$key} = $value;
_session_update($s,$insert);
}
sub _session_update {
my $s = shift;
my $insert = shift;
Data::Dumper->Purity(1);
Data::Dumper->Deepcopy(1);
my $dd = Data::Dumper->new([\%{$s->{session_data}}],['$s->{session_data}']);
if ($insert) {
$s->db_insert('employee_sessions',{
employee_id => $s->{employee_id},
data => $dd->Dump(),
});
} else {
$s->db_q("
UPDATE employee_sessions SET data=?, last_update_ts=now()
WHERE employee_id=?
",undef,
v => [ $dd->Dump(), $s->{employee_id} ]);
}
}
sub session_load {
my $s = shift;
my $data = $s->db_q("
SELECT data
FROM employee_sessions
WHERE employee_id=?
",'scalar',
v => [ $s->{employee_id} ]);
if ($data) {
eval $data;
if ($@) {
croak "Error in eval of session data: $@";
}
# pre-populate any messages which are in the session, then remove them
if ($s->{session_data}{message}) {
$s->{message} .= $s->{session_data}{message};
$s->session_delete('message');
}
} else {
$s->{session_data} = undef;
}
}
sub check_location_id {
my $s = shift;
my $location_id = shift;
croak "location_id is not set in session_data or is invalid"
unless($s->{session_data}{location_id} =~ m/^\d+$/);
# this is a function to make sure the current location matches
# whatever value we are passing into this function
if (ref $location_id eq 'ARRAY') {
foreach my $id (@{$location_id}) {
croak "Invalid location_id passed into check_location_id ($id)"
unless($id =~ m/^\d+$/);
return 1 if ($id eq $s->{session_data}{location_id});
}
} else {
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
}
print F '"'.(join '","', @row).'"'."\n";
}
close F;
$s->{content_type} = 'application/csv' if ($type eq 'csv');
$s->{content_type} = 'text/plain' if ($type ne 'csv');
$s->{r}{file_path} = "/tmp/$filename";
$s->{r}{filename} = $filename;
}
sub encrypt {
my $s = shift;
my $data = shift;
my $k = $s->{env}{CRYPT_KEY} || 'ilikegreeneggsandhamsamiam';
my $cipher = new Crypt::CBC($k,'Blowfish');
my $out = $cipher->encrypt($data) if ($data);
my @tmp;
foreach my $c (split '', $out) {
push @tmp, unpack('c',$c);
}
return join '|', @tmp;
}
sub decrypt {
my $s = shift;
my $data = shift;
my $tmp;
foreach my $c (split /\|/, $data) {
$tmp .= pack('c',$c);
}
my $k = $s->{env}{CRYPT_KEY} || 'ilikegreeneggsandhamsamiam';
my $cipher = new Crypt::CBC($k,'Blowfish');
my $out = $cipher->decrypt($tmp) if ($tmp);
return $out;
}
sub help {
my $s = shift;
# we use our function to look for help
$s->{function} = 'home' if ($s->{function} eq 'list');
my $path = "$s->{function}.tt";
if ($s->{function} eq 'system') {
unless($s->{employee}{admin}) {
$s->alert("Sorry, you are not an admin, you can't look at that");
return;
}
# show our system help file, disaster recovery type information
$s->{nomenu} = 1;
my $debug = "<pre>".Data::Dumper->Dump([$s])."</pre>";
$s->tt('system.tt', { s => $s });
#$s->{content} .= $debug;
return;
}
if ($s->{in}{f} eq 'save' && $s->{employee}{admin}) {
open F, ">/data/$s->{obase}/template/help/$s->{function}.tt";
$s->{in}{help_text} =~ s/\r//g;
print F $s->{in}{help_text};
close F;
}
if (-e "/data/$s->{obase}/template/help/$path") {
if ($s->{employee}{admin}) {
$s->add_action(function => $s->{function},
title => 'edit',
params => "f=edit");
if ($s->{in}{f} eq 'edit') {
open F, "/data/$s->{obase}/template/help/$s->{function}.tt";
while (my $line = <F>) {
$s->{help_text} .= $s->escape($line);
}
close F;
$s->tt('help_edit.tt', { s => $s, });
return;
}
} else {
$s->add_action(
title => 'edit',
class => 'greyout',
nourl => 1);
}
my $help;
$s->tt("template/help/$s->{function}.tt", { s => $s }, \$help);
$help =~ s/\n\n/<br><br>/g;
$s->{help_text} = $help;
$s->tt('help.tt', { s => $s });
} else {
if ($s->{employee}{admin}) {
$s->add_action(function => $s->{function},
title => 'add',
params => "f=add");
if ($s->{in}{f} eq 'add') {
$s->tt('help_add.tt', { s => $s, });
return;
}
} else {
$s->add_action(
title => 'add',
class => 'greyout',
nourl => 1);
}
$s->{content} = "Sorry no help file found for $s->{function}";
}
if ($s->{employee}{admin}) {
$s->add_action(function => 'system',
title => 'emergency information');
}
#$s->{content} = "<pre>".Data::Dumper->Dump([$s])."</pre>";
}
sub permission {
my $s = shift;
# manage permissions on an object. This should only be accessable
# with thos who are part of an admin group
unless($s->{employee}{admin}) {
$s->alert("You are not an admin. You can not do this!");
return 0;
}
$s->add_action(function => 'list') if (defined($s->{o}{functions}{list}));
# before we get down to looking at the current permissions, lets make sure
# we have defined them all in the database first
my %check = $s->db_q("
SELECT a_function, action_id
FROM actions_v
WHERE a_object=?
",'keyval',
v => [ $s->{object} ]);
foreach my $f (keys %{$s->{o}{functions}}) {
unless(defined($check{$f})) {
$s->_set_default_access($s->{object},$f);
}
}
my %existing = $s->db_q("
SELECT a.a_function, a.action_id, concat(ga.group_id) as gids
FROM actions_v a
LEFT JOIN group_actions_v ga ON a.action_id=ga.action_id
WHERE a.a_object=?
GROUP BY 1,2
",'hashhash',
k => 'a_function',
v => [ $s->{object} ]);
foreach my $f (keys %existing) {
foreach my $id (split ',', $existing{$f}{gids}) {
$existing{$f}{groupids}{$id} = $id;
}
}
my @groups = $s->db_q("
SELECT *
FROM groups
ORDER BY name
",'arrayhash');
if ($s->{in}{update}) {
foreach my $f (keys %{$s->{o}{functions}}) {
if ($s->{in}{"f:all:$f"}) {
# by clearing all actions, we give everyone permission
$s->db_q("
DELETE FROM group_actions
WHERE action_id=?
",undef,
v => [ $check{$f} ]);
} else {
foreach my $g (@groups) {
if ($s->{in}{"f:$g->{group_id}:$f"}
&& !defined($existing{$f}{groupids}{$g->{group_id}})) {
# we need to create a new entry
$s->db_insert('group_actions',{
action_id => $check{$f},
group_id => $g->{group_id},
});
} elsif (!defined($s->{in}{"f:$g->{group_id}:$f"})
&& defined($existing{$f}{groupids}{$g->{group_id}})) {
# we need to delete an entry
$s->db_q("
DELETE FROM group_actions
WHERE action_id=?
AND group_id=?
",undef,
v => [ $check{$f}, $g->{group_id} ]);
}
}
}
}
$s->notify("Permissions updated");
if ($s->{in}{return}) {
$s->redirect(function => $s->{in}{return},
params => $s->{in}{return_args});
}
return;
}
#croak "<pre>".Data::Dumper->Dump([\%existing])."</pre>";
$s->tt('permission.tt', { s => $s, groups => \@groups, existing => \%existing });
}
sub sendmail {
my $s = shift;
my %info = @_;
my %from;
my $nodev;
if ($info{from}) {
$nodev = 1;
$from{email} = $info{from};
} else {
%from = $s->db_q("
SELECT *
FROM employees_v
WHERE employee_id=?
",'hash',
v => [ $s->{employee_id} ]);
croak "Unknown email address for you...." unless($from{email});
$info{from} = qq("$from{name}" <$from{email}>) unless($info{from});
#$info{bcc} = qq("$from{name}" <$from{email}>);
}
# Check to make sure we are getting passed all the information we need;
foreach my $key (qw(to from subject)) {
croak "Missing '$key' parameter on sendmail call" unless($info{$key});
}
foreach my $key (qw(to cc bcc)) {
# make sure and put spaces around any email addresses
if ($info{$key}) {
$info{$key} =~ s/,/, /g;
}
}
my @attachments;
# if we have an attachment, check all the files first
if (defined($info{attachment})) {
foreach my $a (@{$info{attachment}}) {
croak "Could not find /tmp/$a" unless (-e "/tmp/$a");
push(@attachments,$a);
}
}
if ($s->{env}{DEV} && !$nodev) {
$info{subject} .= " (normally for $info{to})";
$info{to} = $info{from};
delete $info{bcc};
}
my $data;
$data .= "From: $info{from}\n";
$data .= "To: $info{to}\n";
$data .= "Cc: $info{cc}\n" if ($info{cc});
$data .= "Bcc: $info{bcc}\n" if ($info{bcc});
$data .= "Subject: $info{subject}\n";
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
return unless($s->check_in_id());
my %hash = $s->db_q("SELECT * FROM $s->{o}{view} WHERE $s->{o}{id}=?",'hash',
v => [ $s->{in}{$s->{o}{id}} ]);
$s->add_action(function => 'list') if (defined($s->{o}{functions}{list}));
unless($hash{$s->{o}{id}}) {
$s->alert("$s->{object} $s->{in}{$s->{o}{id}} not found");
return;
}
if (defined($s->{o}{relations})) {
foreach my $ref (@{$s->{o}{relations}}) {
my $ob = $ref->{s} || '1';
@{$hash{relation}{$ref->{t}}} = $s->db_q("
SELECT * FROM $ref->{t}_v
WHERE $s->{o}{id}=?
ORDER BY $ob",
'arrayhash',
v => [ $s->{in}{$s->{o}{id}} ]);
}
}
$s->add_action(function => 'create') if (defined($s->{o}{functions}{create}));
$s->add_action(function => 'edit',
params => "$s->{o}{id}=$hash{$s->{o}{id}}") if (defined($s->{o}{functions}{edit}));
$s->add_action(function => 'delete',
params => "$s->{o}{id}=$hash{$s->{o}{id}}") if (defined($s->{o}{functions}{delete}));
if (defined($s->{o}{subs})) {
foreach my $sub (@{$s->{o}{subs}}) {
my $nf = $sub->{nf} || $sub->{n};
@{$hash{sub}{$sub->{t}}} = $s->db_q("
SELECT $sub->{k}, $nf
FROM $sub->{t}
WHERE $s->{o}{id}=?
ORDER BY $sub->{n}",
'arrayhash',
v => [ $s->{in}{$s->{o}{id}} ]);
$s->add_action(function => 'create',
object => $sub->{o},
title => "Add ".ucfirst $sub->{o},
params => "$s->{o}{id}=$hash{$s->{o}{id}}")
unless($sub->{no_add});
}
}
if (defined($s->{o}{display_functions})) {
foreach my $function (@{$s->{o}{display_functions}}) {
my $title = $function;
$title =~ s/_/ /g;
$s->add_action(function => $function,
title => $title,
params => "$s->{o}{id}=$hash{$s->{o}{id}}");
}
}
#croak "<pre>".Data::Dumper->Dump([\%hash])."<pre>";
$s->tt('display.tt',{ s => $s, hash => \%hash });
}
sub generic_addnote {
my $s = shift;
return unless($s->check_in_id());
if ($s->{in}{note_text}) {
$s->db_insert('notes',{
employee_id => $s->{employee_id},
ref => $s->{object},
ref_id => $s->{in}{$s->{o}{id}},
note_text => $s->{in}{note_text},
});
$s->{redirect} = "$s->{ubase}/$s->{object}/display?$s->{o}{id}=$s->{in}{$s->{o}{id}}";
} else {
$s->add_action(function => 'display',
params => "$s->{o}{id}=$s->{in}{$s->{o}{id}}");
$s->tt('addnote.tt',{ s => $s, });
}
}
sub generic_search {
my $s = shift;
$s->add_action(function => 'list') if (defined($s->{o}{functions}{list}));
my @search;
my $id;
foreach my $f (@{$s->{o}{fields}}) {
if ($f->{search} && $s->{in}{$f->{k}}) {
push @search, { k => $f->{k}, v => $s->{in}{$f->{k}} };
}
}
if ($s->{in}{$s->{o}{id}} =~ m/^\d+$/) {
# if they gave us an id, then skip everything else
undef @search;
push @search, { k => $s->{o}{id}, v => $s->{in}{$s->{o}{id}} };
}
if (scalar @search) {
$s->{content} = "<pre>".Data::Dumper->Dump([\@search])."</pre>";
} else {
$s->tt('search.tt',{ s => $s, });
}
}
sub generic_note {
my $s = shift;
return unless($s->check_in_id());
my @list = $s->db_q("
SELECT *
FROM notes_v
WHERE ref=?
AND ref_id=?
",'arrayhash',
v => [ $s->{object}, $s->{in}{$s->{o}{id}} ]);
foreach my $ref (@list) {
$ref->{note_text} =~ s/\n/<br>/g;
}
$s->add_action(function => 'display',
params => "$s->{o}{id}=$s->{in}{$s->{o}{id}}");
$s->tt('note.tt',{ s => $s, list => \@list });
}
sub generic_log {
my $s = shift;
return unless($s->check_in_id());
my $ref = $s->{o}{log_ref} || $s->{object};
my @list = $s->db_q("
SELECT *
FROM logs_v
WHERE ref=?
AND ref_id=?
",'arrayhash',
v => [ $ref, $s->{in}{$s->{o}{id}} ]);
$s->add_action(function => 'display',
params => "$s->{o}{id}=$s->{in}{$s->{o}{id}}") if (defined($s->{o}{functions}{display}));
$s->tt('log.tt',{ s => $s, list => \@list });
}
sub generic_delete {
my $s = shift;
return unless($s->check_in_id());
my %hash = $s->db_q("SELECT * FROM $s->{o}{view} WHERE $s->{o}{id}=?",'hash',
v => [ $s->{in}{$s->{o}{id}} ]);
$s->db_q("DELETE FROM $s->{o}{table}
WHERE $s->{o}{id}=?
",undef,
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
AND $k1=?
AND $k2=?
",undef,
v => [ $id, $s->{in}{$k1}, $s->{in}{$k2} ]);
} else {
$s->db_q("
DELETE FROM $args{table}
WHERE $args{k}=?
AND $args{id}=?
",undef,
v => [ $id, $s->{in}{$args{id}} ]);
}
}
}
# insert new rows
foreach my $k (keys %{$s->{in}}) {
if ($k =~ m/^$args{in_regex}:(\S+)$/) {
my $id = $1;
unless(defined($existing{$id})) {
if ($k1) {
$s->db_insert($args{table}, {
$args{k} => $id,
$k1 => $s->{in}{$k1},
$k2 => $s->{in}{$k2},
});
} else {
$s->db_insert($args{table}, {
$args{k} => $id,
$args{id} => $s->{in}{$args{id}},
});
}
}
}
}
}
sub generic_create {
my $s = shift;
foreach my $ref (@{$s->{o}{fields}}) {
if ($ref->{kv}) {
@{$s->{o}{menu}{$ref->{k}}} = $s->db_q("
SELECT id, name
FROM $ref->{kv}
ORDER BY name
",'arrayhash');
} elsif ($ref->{r}) {
my $table = $ref->{r};
if ($table ne $s->{object}) {
eval {
@{$s->{o}{menu}{$ref->{k}}} = $s->db_q("
SELECT id, name
FROM ${table}s_v_keyval
ORDER BY name
",'arrayhash');
};
}
}
}
#croak "<pre>".Data::Dumper->Dump([\%{$s->{o}}])."<pre>";
$s->add_action(function => 'list') if (defined($s->{o}{functions}{list}));
$s->tt('create.tt',{ s => $s, });
}
sub generic_edit {
my $s = shift;
return unless($s->check_in_id());
my %hash = $s->db_q("SELECT * FROM $s->{o}{view} WHERE $s->{o}{id}=?",'hash',
v => [ $s->{in}{$s->{o}{id}} ]);
foreach my $ref (@{$s->{o}{fields}}) {
if ($ref->{w}) {
@{$hash{menu}{$ref->{r}}} = $s->db_q("
SELECT $ref->{i} as id, name
FROM $ref->{r}s
WHERE $ref->{w}=?
ORDER BY name
",'arrayhash',
v => [ $hash{$ref->{w}} ]);
} elsif ($ref->{kv}) {
@{$hash{menu}{$ref->{r}}} = $s->db_q("
SELECT id, name
FROM $ref->{kv}
ORDER BY name
",'arrayhash');
} elsif ($ref->{r}) {
my $table = $ref->{r};
@{$hash{menu}{$ref->{r}}} = $s->db_q("
SELECT id, name
FROM ${table}s_v_keyval
ORDER BY name
",'arrayhash');
}
}
if (defined($s->{o}{relations})) {
foreach my $ref (@{$s->{o}{relations}}) {
@{$hash{relation}{$ref->{t}}} = $s->db_q("
SELECT * FROM $ref->{t}_v_$s->{object}
WHERE $s->{o}{id}=?
ORDER BY 1",
'arrayhash',
v => [ $s->{in}{$s->{o}{id}} ]);
}
}
#croak "<pre>".Data::Dumper->Dump([\%hash])."</pre>";
$s->add_action(function => 'list') if (defined($s->{o}{functions}{list}));
$s->add_action(function => 'display',
params => "$s->{o}{id}=$hash{$s->{o}{id}}") if (defined($s->{o}{functions}{display}));
$s->add_action(function => 'delete',
params => "$s->{o}{id}=$hash{$s->{o}{id}}") if (defined($s->{o}{functions}{delete}));
$s->tt('edit.tt',{ s => $s, hash => \%hash });
}
sub generic_import {
my $s = shift;
my $localfile = "/tmp/import_$s->{object}_$s->{employee_id}.csv";
if ($s->{o}{subof}) {
# means we need a parent type ID to carry through everywhere,
# so we need to load the details of that object
no strict 'refs';
my $config = $s->{obase}.'::object::'.$s->{o}{subof}.'::config';
$s->{o}{sub_object} = &{$config}($s);
return unless($s->check_in_id($s->{o}{sub_object}{id}));
$s->{subof_key} = $s->{o}{sub_object}{id};
$s->{subof_id} = $s->{in}{$s->{subof_key}};
}
if (defined($s->{in}{file}{Contents})) {
#unless ($s->{in}{file}{'Content-Type'} =~ m/^(text|application)\/(csv|vnd\.ms-excel)$/) {
# $s->alert("Sorry, file must be a CSV file. This one is a $s->{in}{file}{'Content-Type'}");
# return;
#}
# save the contents to disk, then give them options on the import to map
# the fields to the right spot
$s->{in}{file}{Contents} =~ s/\r/\n/g;
$s->{in}{file}{Contents} =~ s/\n\n/\n/g;
my @header = $s->csv_to_array((split "\n", $s->{in}{file}{Contents})[0],1);
open F, ">$localfile";
print F $s->{in}{file}{Contents};
close F;
foreach my $ref (@{$s->{o}{fields}}) {
if ($ref->{r}) {
my $table = $ref->{r};
@{$s->{menu}{$ref->{r}}} = $s->db_q("
SELECT id, name
FROM ${table}s_v_keyval
ORDER BY name
",'arrayhash');
}
}
# try and process the file
#croak "<pre>".Data::Dumper->Dump([\%{$s->{in}}])."</pre>";
#croak "dump\n".Data::Dumper->Dump([\@header]);
$s->tt('map_import.tt', { s => $s, header => \@header });
return;
}
if ($s->{in}{process}) {
#croak "<pre>".Data::Dumper->Dump([\%{$s->{in}}])."</pre>";
# load the file
unless(-e $localfile) {
$s->alert("Sorry, can't find import file $localfile");
return;
}
my $file;
open F, $localfile;
while (<F>) {
$file .= $_;
}
close F;
my %fmap;
foreach my $f (keys %{$s->{in}}) {
if ($f =~ m/^f:(\d+)$/) {
$fmap{$1} = $s->{in}{$f} if ($s->{in}{$f});
}
}
unless(keys %fmap) {
$s->alert("No fields where defined to map import file into");
return;
}
$s->{dbh}->begin_work;
my $data_import_id = $s->db_insert('data_imports',{
table_name => $s->{o}{table},
employee_id => $s->{employee_id},
count => 0,
},'data_import_id');
if ($s->{in}{clear}) {
my $where;
if ($s->{subof_key}) {
$where = " WHERE $s->{subof_key}=$s->{subof_id}";
}
if (defined($s->{o}{create_session_extra})) {
my $key = $s->{o}{create_session_extra};
$where = " WHERE $key = $s->{session_data}{$key}";
}
eval { $s->db_q("DELETE FROM $s->{o}{table}$where"); };
if ($@) {
$s->alert("Sorry, could not delete all the existing $s->{object}s");
return;
}
}
my @r = $s->csv_to_array($file);
my $count;
my %default;
foreach my $k (keys %{$s->{in}}) {
if ($k =~ m/^default:([^:]+)$/) {
my $fn = $1;
if ($s->{in}{"default:$fn:null"}) {
# override only null values
$default{null}{$fn} = $s->{in}{$k} if ($s->{in}{$k});
} else {
# only override everyting
$default{all}{$fn} = $s->{in}{$k} if ($s->{in}{$k});
}
}
}
if (defined($s->{o}{create_session_extra})) {
my $key = $s->{o}{create_session_extra};
$default{all}{$key} = $s->{session_data}{$key};
}
#$s->alert("<pre>".Data::Dumper->Dump([\%default])."</pre>");
#return;
#my @debug;
for my $i ( 1 .. $#r ) {
my %import;
foreach my $n (keys %fmap) {
$import{$fmap{$n}} = $r[$i][$n-1];
}
# clean up....
foreach my $k (keys %import) {
$import{$k} =~ s/(\s+|,)$//; # strip trailing spaces and other crap like commas
$import{$k} =~ s/^\s+//; # strip leading
}
# verify....
foreach my $f (@{$s->{o}{fields}}) {
if ($import{$f->{k}} && $f->{verify}) {
if ($f->{verify} eq 'phone') {
unless($s->verify_phone(\$import{$f->{k}})) {
$import{$f->{k}} = '';
}
} elsif ($f->{verify} eq 'email') {
unless($s->verify_email(\$import{$f->{k}})) {
$import{$f->{k}} = '';
}
} elsif ($f->{verify} eq 'zipcode') {
unless($s->verify_zipcode(\$import{$f->{k}},\$import{state},\$import{city})) {
$import{$f->{k}} = '';
$import{state} = '';
$import{city} = '';
}
}
}
}
# override values from the file it they were defined
# in the default values area
foreach my $k (keys %{$default{all}}) {
$import{$k} = $default{all}{$k};
}
foreach my $k (keys %{$default{null}}) {
$import{$k} = $default{null}{$k} unless($import{$k});
}
#push @debug, { %import };
$import{data_import_id} = $data_import_id;
# add any required subof key
$import{$s->{subof_key}} = $s->{subof_id} if ($s->{subof_key});
eval { $s->db_insert($s->{o}{table},\%import); };
if ($@) {
$s->alert("Error while processing line $i of file: $@\n".
"<pre>".Data::Dumper->Dump([\%import])."</pre>");
$s->{dbh}->rollback;
return;
} else {
$count++;
}
}
#croak "process dump\n".Data::Dumper->Dump([\@r]);
$s->db_update_key('data_imports','data_import_id',$data_import_id,{
count => $count
});
$s->{dbh}->commit;
unlink $localfile;
if ($s->{subof_key}) {
$s->notify("File imported successfully. $count rows processed. ".
$s->object_link(function => 'display',
object => $s->{o}{subof},
params => "$s->{subof_key}=$s->{subof_id}",
title => 'Continue'));
} else {
$s->notify("File imported successfully. $count rows processed. ".
$s->object_link(function => 'list',
title => 'Continue'));
}
#$s->{content} .= "<pre>".Data::Dumper->Dump([\@debug])."</pre>";
return;
}
# before we can do anything, make sure we have a data_import_id field on this
# table, otherwise we can not roll this back or delete what we just imported
eval {
$s->db_q("SELECT data_import_id
FROM $s->{o}{table}
LIMIT 1
");
};
if ($@) {
$s->alert("Sorry, you can not import into this object because it does not have a ".
"data_import_id field in the database table");
return;
}
$s->tt('import.tt', { s => $s, });
}
sub generic_list {
my $s = shift;
my $ob = $s->{o}{list_orderby} || 1;
my @list = $s->db_q("SELECT * FROM $s->{o}{view} ORDER BY $ob",'arrayhash');
$s->add_action(function => 'create') if (defined($s->{o}{functions}{create}));
$s->add_action(function => 'sync') if (defined($s->{o}{functions}{sync}));
$s->add_action(function => 'import') if (defined($s->{o}{functions}{import}));
$s->add_action(function => 'search') if (defined($s->{o}{functions}{search}));
$s->tt('list.tt',{ s => $s, list => \@list });
}
sub calendar {
my $s = shift;
my $start_day = shift || $s->{datetime}{ymd};
my $months = shift || 1;
croak "invalid calendar months value: $months" unless($months =~ m/^\d+$/);
$months = 12 if ($months > 12);
my @list = $s->db_q("
SELECT d.stat_date, extract('dow' from d.stat_date) as dow,
to_char(d.stat_date, 'Month YYYY') as month_name,
to_char(d.stat_date, 'DD') as day,
to_char(d.stat_date, 'YYYY-MM') as month,
CASE WHEN d.stat_date < date(now()) THEN TRUE ELSE FALSE END as past
FROM date_values(date(date_trunc('month',date(?))),
date(date_trunc('month',date(?)) + interval '$months month' - interval '1 day')) d
ORDER BY d.stat_date
",'arrayhash',
v => [ $start_day, $start_day ]);
my @weeks;
my %week;
foreach my $ref (@list) {
if (keys %week) {
if ($ref->{dow} == 0) {
push @weeks, { %week };
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
return $str;
}
sub add_calendar {
my $s = shift;
my $id = shift;
$s->add_js('calendar');
return qq|id="$id" onclick="javascript: new CalendarDateSelect( \$('$id'), {close_on_click: true, embedded:true, year_range:1} );"|;
}
sub _head_add_title {
my $s = shift;
if (ref $s->{title} eq 'ARRAY') {
my $t = join ' :: ', @{$s->{title}};
$s->{title} = $t;
}
if ($s->{env}{TITLE}) {
if ($s->{title}) {
$s->{title} = "$s->{env}{TITLE} :: $s->{title}";
} else {
$s->{title} = $s->{env}{TITLE};
}
}
$s->{title} = $s->{uri} unless($s->{title});
return "<title>$s->{title}</title>\n";
}
sub _interface_auth {
my $s = shift;
# make sure we have some things
croak "id not defined in object $s->{object}" unless($s->{o}{id});
croak "table not defined in object $s->{object}" unless($s->{o}{table});
croak "view not defined in object $s->{object}" unless($s->{o}{view});
croak "interface not defined in object $s->{object}" unless($s->{o}{interface});
if ($s->{object} eq 'logout' && $s->{cookies}{IL}) {
$s->db_q("
UPDATE $s->{o}{table} SET interface_cookie=NULL
WHERE interface_cookie=?
",undef,
v => [ $s->{cookies}{IL} ],
);
#$s->{raw_path} = '/';
#$s->{uri} =~ s/logout//;
}
SWITCH: {
last if ($s->_interface_check_cookie());
last if ($s->_interface_check_login());
}
#$s->{content} .= "<pre>".Data::Dumper->Dump([$s])."</pre>";
return 1 if ($s->{$s->{o}{id}});
$s->{nomenu} = 1;
$s->{title} = 'Login';
$s->tt('interface_login.tt',{ s => $s });
return 0;
}
sub _interface_check_login {
my $s = shift;
if ($s->{in}{interface_email} && $s->{in}{interface_password}) {
$s->{in}{interface_email} = lc $s->{in}{interface_email};
my %hash = $s->db_q("
SELECT *
FROM $s->{o}{view}
WHERE interface_email=?
",'hash',
v => [ $s->{in}{interface_email} ],
);
my $md5pass;
if ($s->{env}{DEV}) {
# skip password checking on dev
$md5pass = $hash{interface_password};
} else {
$md5pass = md5_hex($hash{interface_email}.$s->{in}{interface_password});
}
if ($md5pass eq $hash{interface_password}) {
my $cookie = $s->_interface_cookie_key(
id => $hash{$s->{o}{id}},
password => $hash{interface_password},
);
$s->{$s->{o}{id}} = $hash{$s->{o}{id}};
$s->{$s->{o}{interface}} = { %hash };
push @{$s->{r}{set_cookie}}, "IL=$cookie; path=/;";
$s->db_update_key($s->{o}{table},$s->{o}{id},$hash{$s->{o}{id}},{
interface_cookie => $cookie,
});
return 1;
} else {
$s->{error}{login} = "Invalid password";
}
}
return 0;
}
sub _interface_check_cookie {
my $s = shift;
if ($s->{cookies}{IL}) {
my %hash = $s->db_q("
SELECT *
FROM $s->{o}{view}
WHERE interface_cookie=?
lib/Apache/SdnFw/lib/Core.pm view on Meta::CPAN
}
}
sub _authenticate {
my $s = shift;
if ($s->{in}{forgot_email}) {
if ($s->verify_email(\$s->{in}{forgot_email})) {
my %employee = $s->db_q("
SELECT *
FROM employees
WHERE email=?
",'hash',
v => [ $s->{in}{forgot_email} ]);
if ($employee{employee_id}) {
my $new = int(rand(1)*100000);
$s->db_q("
UPDATE employees SET passwd=?
WHERE employee_id=?
",undef,
v => [ $new, $employee{employee_id} ]);
$s->sendmail(to => $employee{email},
from => 'root@'.$s->{server_name},
subject => 'Password Reset',
body => "Your password at $s->{server_name} has has been reset\n\n".
"username: $employee{login}\n".
"password: $new\n\n".
"Please login, and then go change your password.");
$s->{error}{login} = "Your password has been reset and sent to $employee{email}";
} else {
$s->{error}{login} = "Unknown email";
$s->{in}{forgot} = 1;
}
} else {
$s->{error}{login} = "That is not a valid email";
$s->{in}{forgot} = 1;
}
}
if ($s->{object} eq 'logout' && $s->{cookies}{L}) {
$s->db_q("
UPDATE employees SET cookie=NULL
WHERE cookie=?
",undef,
v => [ $s->{cookies}{L} ],
);
#$s->{raw_path} = '/';
#$s->{uri} =~ s/logout//;
}
SWITCH: {
last if ($s->_check_api());
last if ($s->_check_cookie());
last if ($s->_check_login());
}
#$s->{content} .= "<pre>".Data::Dumper->Dump([$s])."</pre>";
return 1 if ($s->{employee_id});
$s->{nomenu} = 1;
$s->{title} = 'Login';
unless($s->{in}{ori_args}) {
$s->{in}{ori_args} = $s->{args};
}
if ($s->{in}{forgot}) {
$s->tt('forgot.tt',{ s => $s });
} else {
$s->tt('login.tt',{ s => $s });
}
return 0;
}
sub _check_login {
my $s = shift;
if ($s->{in}{login} && $s->{in}{passwd}) {
my %hash = $s->db_q("
SELECT *
FROM employees_v_login
WHERE lower(login)=lower(?)
",'hash',
v => [ $s->{in}{login} ],
);
my $md5pass = md5_hex($hash{login}.$s->{in}{passwd});
if ($md5pass eq $hash{passwd} && !$hash{account_expired}) {
my $cookie = $s->_cookie_key(
employee_id => $hash{employee_id},
passwd => $hash{passwd},
);
$s->{employee_id} = $hash{employee_id};
$s->{employee} = { %hash };
_employee_permissions($s);
push @{$s->{r}{set_cookie}}, "L=$cookie; path=/;";
$s->db_update_key('employees','employee_id',$hash{employee_id},{
cookie => $cookie,
});
# now, populate args
if ($s->{in}{ori_args}) {
foreach my $kv (split '&', $s->{in}{ori_args}) {
my ($k,$v) = split '=', $kv;
$v =~ tr/+/ /;
$v =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge;
$s->{in}{$k} = $v;
}
}
return 1;
} else {
$s->{error}{login} = "Invalid password or login";
}
} elsif ($s->{env}{IP_LOGIN}) {
my %hash = $s->db_q("