#!/usr/bin/perl # week.pl (c) 2009 - 2010 Michael Greb # # 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; version 2 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. use 5.010; use strict; use warnings; use YAML; use Pod::Usage; use File::Slurp; use Term::Prompt; use WWW::Mechanize; use POSIX 'strftime'; use PostScript::Simple; my $CONFFILE = $ENV{HOME} . '/.hiveminder'; my (%conf, $hm); given (shift) { when ('get') { say getweek() } when ('clear') { clear() } when ('update') { update(shift) } when ('done') { done(@ARGV) } when ('edit') { editweek() } when ('add') { add() } when ('go') { go() } when ('report') { makereport() } default { pod2usage(1) } } sub _load_conf { return if %conf; %conf = %{ YAML::LoadFile($CONFFILE) || {} }; } sub _load_hiveminder { return if $hm; _load_conf(); require Net::Hiveminder; $hm = Net::Hiveminder->new( email => $conf{email}, password => $conf{password} ); } sub _format_tasks { my ($prefix, @tasks) = @_; my $str = ''; for my $task (@tasks) { (my $tags = $task->{tags}) =~ s/"//g; my $done = $task->{complete} ? '[DONE] ' : ''; $str .= $prefix . $done . '#' . $task->{record_locator} . " $task->{summary} [$tags]\n"; } return $str; } sub add { my $file = "/tmp/week-$$"; system $ENV{EDITOR}, $file; my $tasks = read_file($file); unlink $file; die "Aborted\n" unless $tasks; _load_hiveminder(); my @created = $hm->braindump( $tasks, returns => 'tasks', tokens => [ 'tag', 'week' ], ); say 'Created:'; say _format_tasks("\t", @created); } sub getweek { my $prefix = shift // ''; return _format_tasks( $prefix, getweektasks() ); } sub clear { unweek($_) for (getweektasks()); say "Done."; return; } sub unweek { my $task = shift; my $verbose = shift // 1; (my $new_tags = $task->{tags}) =~ s/\s?"week"//; say $task->{summary} if $verbose; $hm->update_task( $task->{record_locator}, tags => $new_tags ); return; } sub editweek { say "Carry over the following tasks?"; for my $task (getweektasks()) { if ($task->{complete}) { unweek($task); next; } my $carry_over = prompt('y', $task->{summary}, '', 'y'); unweek($task, 0) unless $carry_over; } return; } sub done { my $search = join(' ', @_); _load_hiveminder(); my @tasks = $hm->get_tasks( not => 'complete', query => $search, tag => 'week' ); unless (@tasks == 1) { # TODO prompt for each task say 'Sorry, multiple matches :<'; exit 1; } $hm->complete_tasks(@tasks); say getweek(); return; } sub update { _load_conf(); my $url = shift || $conf{taskurl}; die "Must specify URL.\n" unless $url; saveURL($url); my $tasks = getweek(' * '); die "Error retrieving tasks :<\n" unless $tasks; my $mech = WWW::Mechanize->new(); $mech->credentials( $conf{tuser}, $conf{tpass} ); $mech->get($url . '?action=edit'); $mech->form_id('edit'); my $page_text = $mech->value('text'); die "Couldn't find mikegrb :<\n" unless ( $page_text =~ s/== mikegrb ==[^=]+==/== mikegrb ==\n\n$tasks\n==/s ); $page_text =~ s/^\n+//g; $mech->field( 'text', $page_text ); $mech->field( 'comment', 'you are jealous of mikegrb\'s awesome' ); $mech->submit_form( form_id => 'edit', button => 'save' ); say 'Sup dawg, I heard you like tasks so I did ur shit for you'; return; } sub getweektasks { _load_hiveminder(); return $hm->get_tasks(tag=>'week'); } sub saveURL { my $url = shift; $conf{taskurl} = $url; YAML::DumpFile($CONFFILE, \%conf); return $url; } sub makereport { _load_hiveminder(); my $p = PostScript::Simple->new( papersize => 'letter', colour => 1, eps => 0, units => "in", coordorigin => 'LeftTop', direction => 'RightDown' ); $p->newpage; my $write_heading = sub { my ($y, $text) = @_; $p->setcolour("green"); $p->setfont("Helvetica", 20); $p->text(1,$y, $text); $p->line(1,$y, 7,$y); $p->setcolour("black"); }; my $write_task = sub { my ($y, $task) = @_; (my $tags = $task->{tags}) =~ s/"//g; $p->setfont("Helvetica", 8); $p->text(1.55, $y, "$task->{summary} [$tags]"); $p->setfont("Helvetica", 6); $p->text(1.25, $y, $task->{record_locator}); $p->line(1.25, $y - 0.03, 1.46, $y - 0.03) if $task->{complete}; }; $write_heading->(1, "Weekly Tasks"); my $y = 1.15; for my $task (getweektasks()) { $write_task->($y, $task); $y += 0.15; } $y += 0.25; $write_heading->($y, "Visible Tasks"); $y += 0.15; for my$task ($hm->todo_tasks) { $write_task->($y, $task); $y += 0.15; } $p->setfont("Courier", 10); $p->text(5.7,0.5, strftime("%Y-%m-%d %H:%M", localtime)); $p->output("/tmp/week.ps"); system 'lpr', '-r', '/tmp/week.ps'; # system 'open', '/tmp/week.ps'; return; } sub go { _load_conf(); system 'open', $conf{taskurl}; return; } =head1 NAME week.pl - Work with week related hiveminder tasks =head1 SYNOPSIS $ week.pl =head1 OPTIONS Command is one of: =over 8 =item B update the trac wiki tasks page, optionally takes a URL to replace current one =item B mark task matching $query that is incomplete and tagged with week as done =item B go the the current wiki tasks page in the browser =item B list the tasks currently tagged with week =item B opens $EDITOR to add new tasks, HM braindump format, week tag autoadded =item B remove the week tag from all tasks that have it =item B similiar to clear but ask for each task =item B Print the weekly report =back