package App::bif::wlog; use strict; use warnings; use utf8; use Bif::Mo; use DBIx::ThinSQL qw/case coalesce sq qv/; use Text::FormatTable; our $VERSION = '0.1.5_4'; extends 'App::bif'; sub run { my $self = shift; my $id; if ( my $str = $self->opts->{identity} ) { unless ( $str eq '-' ) { my $iinfo = $self->get_topic( $str, 'identity' ); $id = $iinfo->{id}; } } else { $id = $self->db->xval( select => 'b.identity_id', from => 'bifkv b', where => { key => 'self' }, ); } return $self->work_log_long($id) if $self->opts->{long}; return $self->work_log_short($id); } sub work_log_long { my $self = shift; my $identity_id = shift; my $db = $self->db; my $sth = $db->xprepare( with => 'src', as => sq( select => [ 'wb.id AS id', 'wb.stop - wb.start AS delta', ], from => 'work_buffers wb', ), select => [ 'wb.topic_id', q{strftime('%Y-%m-%d %H:%M:%S', } . q{ wb.gtime_start, 'unixepoch') AS start}, q{wb.start_comment AS start_comment}, q{strftime('%Y-%m-%d %H:%M:%S', } . q{ wb.gtime_stop, 'unixepoch') AS stop}, q{wb.stop_comment AS stop_comment}, q{ printf('%+0.2d:%0.2d:%0.2d', } . q{ src.delta / 3600, } . q{ (src.delta - 3600 * (src.delta / 3600)) / 60, } . q{ src.delta % 60 ) AS delta}, q{COALESCE(printf('%s %s [%s]', t.kind, t.id, t.path),'') AS path}, ], from => 'src', inner_join => 'work_buffers wb', on => 'wb.id = src.id', left_join => 'topics t', on => 't.id = wb.topic_id', order_by => 'wb.id DESC', ); $sth->execute; my ( $yellow, $bold, $reset ) = $self->colours( 'yellow', 'bold', 'reset' ); $self->start_pager; while ( my $ref = $sth->hashref ) { my $table = Text::FormatTable->new(' l l'); $table->row( $yellow . 'Work:', $ref->{path} . $reset ); $table->row( 'Start:', $ref->{start} ); $table->row( 'Stop:', $ref->{stop} ); $table->row( 'Delta:', $ref->{delta} ); $table->row( 'StartComment:', $ref->{start_comment} ) if $ref->{start_comment}; $table->row( 'StopComment:', $ref->{stop_comment} ) if $ref->{stop_comment}; print $table->render, "\n"; } return $self->ok('WorkLogLong'); } sub work_log_short { my $self = shift; my $identity_id = shift; my $db = $self->db; my $sth = $db->xprepare( with => 'worked', as => sq( # Grab stuff from the work_buffers table select => [ 'wb.gtime_start AS start', q{strftime('%Y-%m-%d', } . q{ wb.gtime_start, 'unixepoch') AS start_ymd}, 'wb.gtime_stop AS stop', 'wb.stop - wb.start AS delta', 't.id AS id', 'i.shortname AS shortname', 'COALESCE(t.path,"-") AS path', q{COALESCE(wb.start_comment || ', ' || wb.stop_comment,} . q{wb.start_comment, wb.stop_comment, '-') AS comment}, 'wb.billable AS billable', case ( when => 'wb.billable != 1', then => qv('-'), else => qv(''), )->as('change_id'), ], from => 'work_buffers wb', left_join => 'topics t', on => 't.id = wb.topic_id', $identity_id ? ( inner_join => 'identities i', on => { 'i.id' => $identity_id }, ) : ( inner_join => 'bifkv b', on => { 'b.key' => 'self', }, inner_join => 'identities i', on => 'i.id = b.identity_id', ), # Grab stuff from the work_deltas table union_all_select => [ 'wd.gtime_start AS start', q{strftime('%Y-%m-%d', } . q{ wd.gtime_start, 'unixepoch') AS start_ymd}, 'wd.gtime_stop AS stop', 'wd.stop - wd.start AS delta', 't.id AS id', 'i.shortname AS shortname', 't.path AS path', q{COALESCE(wd.start_comment || ', ' || wd.stop_comment,} . q{wd.start_comment, wd.stop_comment, '-') AS comment}, '1 AS billable', 'wd.change_id AS change_id', ], from => 'work_deltas wd', inner_join => 'topics t', on => 't.id = wd.topic_id', inner_join => 'changes c', on => { 'c.id' => \'wd.change_id', $identity_id ? ( 'c.identity_id' => $identity_id, ) : (), }, inner_join => 'identities i', on => 'i.id = c.identity_id', ), # Sum the above grouped by day ',' => 'worked_summary', as => sq( select => [ 'w.start_ymd AS start_ymd', 'SUM(w.delta) AS delta', "julianday(date('now','localtime'))" . " - julianday(w.start_ymd) AS day" ], from => 'worked w', group_by => [ 'start_ymd', 'day' ], ), # Now format all of that nicely select => [ 'w.start_ymd AS start_ymd', 'w.start AS start', "strftime('%H:%M', w.start, 'unixepoch') AS start_hm", 'w.stop AS stop', "COALESCE(strftime('%H:%M', w.stop, 'unixepoch')," . "'') AS stop_hm", q{ printf('%+0.2d:%0.2d', } . q{ round(w.delta / 3600), } . q{ (w.delta - 3600 * round(w.delta / 3600)) / 60) AS delta_hm }, 'w.shortname AS shortname', 'w.id AS id', 'w.path AS path', 'w.comment AS comment', 'w.billable AS billable', 'w.change_id AS change_id', ], from => 'worked w', # total/summary row union_all_select => [ 'ws.start_ymd AS start_ymd', '-1 AS start', '-1 AS start_hm', '-1 AS stop', '-1 AS stop_hm', q{ printf('%+0.2d:%0.2d', } . q{ round(ws.delta / 3600), } . q{ (ws.delta -} . q{ 3600 * round(ws.delta / 3600)) / 60) AS delta_hm}, '-1 AS shortname', 'NULL AS id', 'NULL AS path', 'ws.day AS comment', 'NULL AS billable', 'NULL AS change_id', ], from => 'worked_summary ws', order_by => [ 'start_ymd DESC', 'start ASC', 'stop ASC' ] ); $sth->execute; $self->start_pager; my ( $yellow, $bold, $reset ) = $self->colours( 'yellow', 'bold', 'reset' ); my $i = 0; my $table = Text::FormatTable->new(' l l l r r '); my $first = 1; while ( my $ref = $sth->hashref ) { if ( $ref->{start_hm} eq '-1' ) { # Every 200 rows or so spit out the table and start again. if ( $i > 200 ) { print $table->render( $self->term_width ), "\n"; $table = Text::FormatTable->new(' l l l r r '); $i = 1; } elsif ($i) { $table->row( '-', '', '', '', '' ); } if ( 0 == $ref->{comment} ) { $table->head( $yellow . $ref->{start_ymd}, 'Who', "Activity [today]", 'CID', $ref->{delta_hm} . $reset ); } elsif ( 1 == $ref->{comment} ) { $table->head( $yellow . $ref->{start_ymd}, 'Who', "Activity [yesterday]", 'CID', $ref->{delta_hm} . $reset ); } else { $table->head( $yellow . $ref->{start_ymd}, 'Who', "Activity [$ref->{comment} days ago]", 'CID', $ref->{delta_hm} . $reset ); } } else { $table->row( ( $ref->{stop_hm} ? '' : $bold ) . "$ref->{start_hm} - $ref->{stop_hm}", $ref->{shortname}, "$ref->{comment} [$ref->{path}]", $ref->{change_id}, $ref->{delta_hm} . $reset, ); } $i++; } print $table->render( $self->term_width ), "\n"; return $self->ok('WorkLogShort'); } 1; __END__ =head1 NAME =for bif-doc #log bif-wlog - review work buffer entries =head1 VERSION 0.1.5_4 (2015-08-04) =head1 SYNOPSIS bif wlog [OPTIONS...] =head1 DESCRIPTION The B<bif-wlog> command prints the entries in the work buffer that have been created with the L<bif-work> command. =head1 OPTIONS =over =item --identity, -i IDENTITY_ID Limit work buffer/delta items displayed to those created by IDENTITY_ID. Use "-" to see all identity work deltas. =item --long, -l Display a multiple-line email-style version of each work buffer entry. =back =head1 SEE ALSO L<bif-work> =head1 AUTHOR Mark Lawrence E<lt>nomad@null.netE<gt> =head1 COPYRIGHT AND LICENSE Copyright 2015 Mark Lawrence <nomad@null.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.