RSS Git Download  Clone
Raw Blame History
package CommsLog;

# switch on query output to console using "SQL_TRACE=1 dance"

use Dancer2;

use DateTime;
use Local::DB;
use Local::Utils;
use Data::Printer;
use SQL::Abstract::More;

# warn setting('environment'); # dispatch.cgi requires manual set in BEGIN block

# turn off datetime objects:
# $Local::DBIx::Simple::Result::NO_AUTO_DATE_INFLATION = 1;

my $dbix = Local::DB->dbix({ dbname => 'hilis4' });

# maximum number of records to retrieve ----------------------------------------
my $max_msg_num = setting('max_results');
#-------------------------------------------------------------------------------

our $VERSION = '0.01';

hook before => sub {
    $ENV{SQL_TRACE} ||= setting('enable_sql_trace'); # don't override if already set

    return if request->path_info =~ m!^/index!; # don't need a session for this

    my $vars = request->parameters->as_hashref; _debug($vars);
    my $session_id = $vars->{_sid} or halt 'Not logged into HILIS.';
    check_session($session_id)
        or halt 'Session expired. Please return to HILIS and try again.';
};

hook before_template_render => sub {
    my $tokens = shift;
    my %uri = map { $_ => uri_for('/' . $_) } qw(search new_record);
    $tokens->{uri_for} = \%uri;

    $tokens->{session_id} =
        body_parameters->get('_sid') || query_parameters->get('_sid');
};

# original route/tt:
get '/index' => sub { template index => {}, { layout => 'default' } };

get '/' => sub { template 'main' };

post '/search' => sub {
    my $vars = request->parameters->as_hashref; _debug($vars);

    my $results = do_search($vars); # p $results;
    template 'main', { results => $results };
};

post '/new_record' => sub {
    # get user.id corresponding to session id:
    my $user_id = get_user_id( body_parameters->get('_sid') ); # p $user_id;
    my $details = body_parameters->get('details');

    my %h = (
        user_id  => $user_id,
        details  => $details,
    );
    my $res = $dbix->insert('general_comms_log', \%h);

    if ( $res->rows ) {
        var msg => 'input success';
    }
    else {
        var msg => 'input failed'; # may not get this far, probably 500 error
    }
    forward '/search', { details => $details };
};

#===============================================================================
sub do_search {
    my $vars = shift; # username, details, start_date, end_date

    my @cols = ( 'l.details', 'u.first_name', 'u.last_name', 'l.time' );
    my @rels = ( 'general_comms_log|l' => 'l.user_id=u.id' => 'users|u' );

    my %params = (
        -columns => \@cols,
        -where   => get_search_params($vars),
        -from    => [ -join => @rels ],
    ); # p \%params;
    my ($sql, @bind) = SQL::Abstract::More->new->select(%params); # p [$sql, \@bind];

    { # check count, return if excessive (> $max_msg_num):
        local $params{'-columns'} = 'COUNT(*)';
        my ($sql, @bind) = SQL::Abstract::More->new->select(%params); # p [$sql, \@bind];
        my $n = $dbix->query($sql, @bind)->value;
        if ( $n > $max_msg_num ) {
            var msg => "too many records found ($n), please limit search"
                . " and retry ...";
            var total => $n;
            return undef;
        }
    }

    my $res = $dbix->query($sql, @bind)->hashes;
    return $res;
}

sub get_search_params {
    my $vars = shift;

    my %h;
    if ( my $username = $vars->{username} ) { # search username & last_name
        push @{ $h{'-or'} }, [
            'u.username'  => { -like => $username . '%' },
            'u.last_name' => { -like => $username . '%' },
        ];
    }
    if ( my $details = $vars->{details} ) {
        $h{'l.details'} = { -rlike => $details };
    }
    { # dates:
        my ($start_date, $end_date) = map reformat_date($vars->{$_}),
            qw/start_date end_date/; # p [$start_date, $end_date];
        my $date_key = 'DATE(l.time)';

        if ( $start_date && $end_date ) {
            $h{$date_key} = { -between => [$start_date, $end_date] };
        }
        else {
            if ( $start_date ) {
                $h{$date_key} = { '>=' => $start_date };
            }
            elsif ( $end_date ) {
                $h{$date_key} = { '<=' => $end_date };
            }
        } # p \%h;
    }
    return \%h;
}

sub get_user_id {
    my $session_id = shift; # p $session_id;

    my @rels = ( 'sessions|s' => 's.userid=u.username' => 'users|u' );
    my %params = (
        -columns => 'u.id',
        -where   => { 's.id' => $session_id },
        -from    => [ -join => @rels ],
    );
    my ($sql, @bind) = SQL::Abstract::More->new->select(%params); # p [$sql, \@bind];
    my $id = $dbix->query($sql, @bind)->value;
    return $id;
}

sub check_session {
    my $session_id = shift || return 0; # p $session_id;

    my $now = Local::Utils::time_now; # p $now;

    my %h = (
        id   => $session_id,
        time => { '>' => $now->subtract( minutes => 30 ) },
    );
    return $dbix->count(sessions => \%h);
}

sub reformat_date { # returns date in yyyy-mm-dd format
    my $str = shift || return; # p $str;
    # $date =~ s/(^\d{1,2})\/(\d{1,2})\/(\d{4}$)/$3-$2-$1/;
    my $dt = Local::Utils::date_string_to_datetime($str)
        or die "cannot parse date string: $str"; # p $dt->ymd;
    return $dt->ymd;
}

sub _debug { p @_ if setting('environment') =~ /^dev/ }

true;