| 1 | #!/usr/bin/perl |
|---|
| 2 | use strict; |
|---|
| 3 | use warnings; |
|---|
| 4 | use LWP::UserAgent; |
|---|
| 5 | use autobox; |
|---|
| 6 | use autobox::Core; |
|---|
| 7 | |
|---|
| 8 | # ------------------------------------------------------------------------- |
|---|
| 9 | |
|---|
| 10 | package Net::Wassr::TODO; |
|---|
| 11 | |
|---|
| 12 | use JSON::Syck; |
|---|
| 13 | use Carp; |
|---|
| 14 | |
|---|
| 15 | our $VERSION = 0.01; |
|---|
| 16 | our $BASE_URL = 'http://api.wassr.jp/todo'; |
|---|
| 17 | our $APIHOST = 'api.wassr.jp:80'; |
|---|
| 18 | our $APIREALM = 'API Authentication'; |
|---|
| 19 | |
|---|
| 20 | sub new { |
|---|
| 21 | my $class = shift; |
|---|
| 22 | my $args = shift; |
|---|
| 23 | |
|---|
| 24 | croak "username missing" unless $args->{username}; |
|---|
| 25 | croak "password missing" unless $args->{password}; |
|---|
| 26 | |
|---|
| 27 | my $ua = LWP::UserAgent->new(agent => __PACKAGE__."/".$VERSION); |
|---|
| 28 | $ua->env_proxy; |
|---|
| 29 | $ua->credentials( |
|---|
| 30 | $APIHOST, $APIREALM, |
|---|
| 31 | $args->{username}, $args->{password} |
|---|
| 32 | ); |
|---|
| 33 | |
|---|
| 34 | bless {ua => $ua}, $class; |
|---|
| 35 | } |
|---|
| 36 | |
|---|
| 37 | sub list { |
|---|
| 38 | my ($self, ) = @_; |
|---|
| 39 | |
|---|
| 40 | my $ret = []; |
|---|
| 41 | my $page = 1; |
|---|
| 42 | while (1) { |
|---|
| 43 | my $res = $self->{ua}->get("$BASE_URL/list.json?page=$page"); |
|---|
| 44 | if ($res->is_success) { |
|---|
| 45 | my $dat = JSON::Syck::Load($res->content); |
|---|
| 46 | if ($dat->size()) { |
|---|
| 47 | $ret->push( @$dat ); |
|---|
| 48 | } else { |
|---|
| 49 | return $ret; |
|---|
| 50 | } |
|---|
| 51 | } else { |
|---|
| 52 | croak $res->status_line; |
|---|
| 53 | } |
|---|
| 54 | |
|---|
| 55 | $page++; |
|---|
| 56 | } |
|---|
| 57 | } |
|---|
| 58 | |
|---|
| 59 | sub done { |
|---|
| 60 | my ($self, $todo_rid) = @_; |
|---|
| 61 | |
|---|
| 62 | my $res = $self->{ua}->post("$BASE_URL/done.json", [todo_rid => $todo_rid]); |
|---|
| 63 | if ($res->is_success) { |
|---|
| 64 | return $res->content; |
|---|
| 65 | } else { |
|---|
| 66 | croak $res->status_line; |
|---|
| 67 | } |
|---|
| 68 | } |
|---|
| 69 | |
|---|
| 70 | sub add { |
|---|
| 71 | my ($self, $body) = @_; |
|---|
| 72 | |
|---|
| 73 | my $res = $self->{ua}->post("$BASE_URL/add.json", [body => $body]); |
|---|
| 74 | if ($res->is_success) { |
|---|
| 75 | return $res->content; |
|---|
| 76 | } else { |
|---|
| 77 | croak $res->status_line; |
|---|
| 78 | } |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | package main; |
|---|
| 82 | use strict; |
|---|
| 83 | use warnings; |
|---|
| 84 | use Switch; |
|---|
| 85 | use YAML::Syck; |
|---|
| 86 | use IO::File; |
|---|
| 87 | use IO::Prompt; |
|---|
| 88 | |
|---|
| 89 | our $CONFFILE = "$ENV{HOME}/.wassr-todo"; |
|---|
| 90 | |
|---|
| 91 | sub main { |
|---|
| 92 | my $command = shift @ARGV || 'list'; |
|---|
| 93 | |
|---|
| 94 | my $conf; |
|---|
| 95 | if ( -e $CONFFILE ) { |
|---|
| 96 | $conf = YAML::Syck::LoadFile($CONFFILE); |
|---|
| 97 | } else { |
|---|
| 98 | $conf->{username} = prompt 'username:'; |
|---|
| 99 | $conf->{password} = prompt 'password:', -echo => '*'; |
|---|
| 100 | YAML::Syck::DumpFile($CONFFILE => $conf); |
|---|
| 101 | } |
|---|
| 102 | |
|---|
| 103 | my $c = Net::Wassr::TODO->new($conf); |
|---|
| 104 | |
|---|
| 105 | switch ($command) { |
|---|
| 106 | case 'list' { |
|---|
| 107 | my $list = $c->list; |
|---|
| 108 | |
|---|
| 109 | print $list->map(sub { |
|---|
| 110 | $_[0]->{todo_rid} . ' ' . $_[0]->{body} |
|---|
| 111 | })->join("\n"); |
|---|
| 112 | print "\n"; |
|---|
| 113 | } |
|---|
| 114 | case 'done' { |
|---|
| 115 | my $todo_rid = shift @ARGV; |
|---|
| 116 | die "TODO rid missing for $command" unless $todo_rid; |
|---|
| 117 | print $c->done($todo_rid), "\n"; |
|---|
| 118 | } |
|---|
| 119 | case 'bd' { |
|---|
| 120 | # braindump |
|---|
| 121 | require File::Temp; |
|---|
| 122 | |
|---|
| 123 | my $editor = $ENV{EDITOR}; |
|---|
| 124 | die "\$ENV{EDITOR} missing" unless $editor; |
|---|
| 125 | |
|---|
| 126 | my $fh = File::Temp->new(UNLINK => 0); |
|---|
| 127 | my $fn = $fh->filename; |
|---|
| 128 | $fh->close; |
|---|
| 129 | |
|---|
| 130 | system $editor, $fn; |
|---|
| 131 | upload_textfile( $c, $fn ); |
|---|
| 132 | unlink $fn; |
|---|
| 133 | } |
|---|
| 134 | else { |
|---|
| 135 | die "unknown command $command"; |
|---|
| 136 | } |
|---|
| 137 | } |
|---|
| 138 | } |
|---|
| 139 | |
|---|
| 140 | sub upload_textfile { |
|---|
| 141 | my ($c, $fname) = @_; |
|---|
| 142 | |
|---|
| 143 | my $fh = IO::File->new($fname, 'r'); |
|---|
| 144 | while (<$fh>) { |
|---|
| 145 | s/[\r\n]//g; |
|---|
| 146 | my $line = $_; |
|---|
| 147 | |
|---|
| 148 | $c->add( $line ); |
|---|
| 149 | } |
|---|
| 150 | } |
|---|
| 151 | |
|---|
| 152 | &main(); |
|---|