]> git.ktnx.net Git - lsl.git/blob - lib/App/LazyShoppingList/API/v1.pm
fix retrieval of shopping list items
[lsl.git] / lib / App / LazyShoppingList / API / v1.pm
1 use v5.26;
2 use warnings;
3 use utf8;
4
5 package App::LazyShoppingList::API::v1;
6 use App::LazyShoppingList::API;
7 use Dancer2;
8
9 our $VERSION = '0.1';
10
11 use JSON();
12
13 use experimental 'signatures';
14
15 set charset      => 'UTF-8';
16 set serializer => 'JSON';
17
18 # get the URI for the list of shopping lists
19 get '/' => sub {
20     return { lists => uri_for('/list') };
21 };
22
23 # get the list of shopping lists
24 get '/list' => sub {
25     my $dbh = get_database;
26     $dbh->txn_begin;
27
28     my %r = ( lists_version => get_lists_version($dbh), lists => [] );
29     for my $list (
30         $dbh->resultset('ShoppingList')
31         ->search( undef,
32             { order_by => { -asc => 'name' } } )->all
33         )
34     {
35         push @{ $r{lists} },
36             { uri => uri_for( "/list/" . $list->id ), name => $list->name };
37     }
38
39     $dbh->txn_commit;
40     return \%r;
41 };
42
43 # create shopping list
44 post '/list' => sub {
45     my $req = request_data;
46
47     my $name = $req->{name};
48     unless ($name) {
49         return exception 400, "Missing list name";
50     }
51
52     my $dbh = get_database;
53     $dbh->txn_begin;
54     my $list = $dbh->resultset('ShoppingList')->create({
55             name => $name});
56     $list->discard_changes;
57
58     my  $lists_ver = increment_lists_version($dbh);
59
60     $dbh->txn_commit;
61
62     return {
63         uri           => uri_for( '/list/' . $list->id ),
64         version       => $list->version,
65         lists_version => $lists_ver
66     };
67 };
68
69 # get shopping list items
70 get '/list/:list_id' => sub {
71     my $list_id = route_parameters->get('list_id');
72     length($list_id) and $list_id =~ /^\d{1,18}$/ or return invalid_input;
73
74     my $dbh = get_database;
75
76     warn $dbh;
77     my %r = ( items => [] );
78     $dbh->txn_begin;
79
80     $r{lists_version} = get_lists_version($dbh);
81
82     my $list = $dbh->resultset('ShoppingList')->find($list_id);
83
84     unless ($list) {
85         $dbh->txn_commit;
86         return exception 404, "No list with that ID found";
87     }
88
89     $r{version} = $list->version;
90
91     my @items = $dbh->resultset('ShoppingListItem')->search(
92         { shopping_list => $list->id },
93         { order_by      => { -asc => 'id' } }
94     )->all;
95     for my $item (@items) {
96         push @{ $r{items} },
97             {   uri =>
98                 uri_for( sprintf( "/list/%s/%s", $list->id, $item->id ) ),
99                 description => $item->description,
100                 done        => JSON->boolean( $item->done ),
101                 version     => $item->version,
102             };
103     }
104
105     $dbh->txn_commit;
106
107     return \%r;
108 };
109
110 # create shopping list item
111 post '/list/:id' => sub {
112     my $list_id = route_parameters->get('id');
113     length($list_id) and $list_id =~ /^\d{1,18}$/
114         or return invalid_input('bad list ID');
115
116     my $req = request_data;
117
118     my $descr = $req->{description};
119     my $done  = JSON->boolean( $req->{done} // 0 );
120
121     my $dbh = get_database;
122     $dbh->txn_begin;
123
124     my %r = (
125         lists_version => get_lists_version($dbh),
126     );
127
128     my $list = $dbh->resultset('ShoppingList')->find($list_id);
129
130     unless ($list) {
131         $dbh->txn_commit;
132         exception 404, "No such list";
133     }
134
135     my $item = $dbh->resultset('ShoppingListItem')->create(
136         {   shopping_list => $list->id,
137             description   => $descr,
138             done          => $done,
139         }
140     );
141     $item->discard_changes;
142
143     $list->update( { version => $list->version + 1 } );
144
145     $r{uri} = uri_for( sprintf( "list/%s/%s", $list->id, $item->id ) );
146     $r{version} = $item->version;
147     $r{list_version} = $list->version;
148
149     $dbh->txn_commit;
150
151     return \%r;
152 };
153
154 # modify shopping list item
155 put '/list/:list_id/:item_id' => sub {
156     my $list_id = route_parameters->get('list_id');
157     length($list_id) and $list_id =~ /^\d{1,18}$/
158         or return invalid_input('bad list ID');
159
160     my $item_id = route_parameters->get('item_id');
161     length($item_id) and $item_id =~ /^\d{1,18}$/
162         or return invalid_input('bad item ID');
163
164     my $req = request_data;
165
166     my $descr = $req->{description};
167     my $done  = JSON->boolean( $req->{done} // 0 );
168     my $version = $req->{version};
169
170     length($version) and $version =~ /^\d{1,18}$/
171         or return invalid_input('bad version');
172
173     my $dbh = get_database;
174     $dbh->txn_begin;
175
176     my %r = (
177         lists_version => get_lists_version($dbh),
178     );
179
180     my $list = $dbh->resultset('ShoppingList')->find($list_id);
181     unless ($list) {
182         $dbh->txn_commit;
183         return exception 404, "No such list";
184     }
185
186     my $item = $dbh->resultset('ShoppingListItem')->find({shopping_list => $list->id, id => $item_id});
187     unless ($item) {
188         $dbh->txn_commit;
189         return exception 404, "No such item";
190     }
191
192     # in case no real changes are needed will return the current state
193     if (   defined($descr) and $descr ne ( $item->description // '' )
194         or defined($done) and $done != $item->done )
195     {
196         unless ($version == $item->version) {
197             $dbh->txn_commit;
198             return exception 409, exception =>
199                 sprintf( 'Outdated version (current is %d)', $item->version );
200         }
201
202         $item->update({
203             defined($descr) ? (description  => $descr) : (),
204             defined($done) ? (done =>  $done) : (),
205             version => $version + 1,
206         });
207
208         $list->update( { version => $list->version + 1 } );
209     }
210
211     $r{uri} = uri_for( sprintf( "list/%s/%s", $list->id, $item->id ) );
212     $r{version} = $item->version;
213     $r{list_version} = $list->version;
214
215     $dbh->txn_commit;
216
217     return \%r;
218 };
219
220 true;