]> git.ktnx.net Git - lsl.git/blobdiff - lib/App/LazyShoppingList/API/v1.pm
first take at a Dancer2 app, some functions work
[lsl.git] / lib / App / LazyShoppingList / API / v1.pm
diff --git a/lib/App/LazyShoppingList/API/v1.pm b/lib/App/LazyShoppingList/API/v1.pm
new file mode 100644 (file)
index 0000000..6e1cd31
--- /dev/null
@@ -0,0 +1,231 @@
+use v5.26;
+use warnings;
+use utf8;
+
+package App::LazyShoppingList::API::v1;
+use App::LazyShoppingList::API;
+use Dancer2;
+
+our $VERSION = '0.1';
+
+use JSON();
+
+use experimental 'signatures';
+
+set charset      => 'UTF-8';
+set serializer   => 'JSON';
+set content_type => 'application/json';
+
+
+# get the URI for the list of shopping lists
+get '/' => sub {
+    return { lists => uri_for('/list') };
+};
+
+# get the list of shopping lists
+get '/list' => sub {
+    my $dbh = get_database;
+    $dbh->txn_begin;
+
+    my %r = ( lists_version => get_lists_version($dbh), lists => [] );
+    for my $list (
+        $dbh->resultset('ShoppingList')
+        ->search( undef,
+            { order_by => { -asc => 'name' } } )->all
+        )
+    {
+        push @{ $r{lists} }, uri_for( "/list/" . $list->id );
+    }
+
+    $dbh->txn_commit;
+    return \%r;
+};
+
+# create shopping list
+post '/list' => sub {
+    my $req = decode_json(request_data);
+
+    my $name = $req->{name};
+    unless ($name) {
+        status 400;
+        content_type 'text/plain';
+        return "Missing list name";
+    }
+
+    my $dbh = get_database;
+    $dbh->txn_begin;
+    my $list = $dbh->resultset('ShoppingList')->create({
+            name => $name});
+    $list->discard_changes;
+
+    my  $lists_ver = increment_lists_version($dbh);
+
+    $dbh->txn_commit;
+
+    return {
+        uri           => uri_for( '/list/' . $list->id ),
+        version       => $list->version,
+        lists_version => $lists_ver
+    };
+};
+
+# get shopping list items
+get '/list/:list_id' => sub {
+    my $list_id = route_parameters->get('list_id');
+    length($list_id) and $list_id =~ /^\d{1,18}$/ or return invalid_input;
+
+    my $dbh = get_database;
+
+    warn $dbh;
+    my %r = ( items => [] );
+    $dbh->txn_begin;
+
+    $r{lists_version} = get_lists_version($dbh);
+
+    my $list = $dbh->resultset('ShoppingList')->find($list_id);
+
+    unless ($list) {
+        $dbh->txn_commit;
+        status 404;
+        content_type 'text/plain';
+        return "No list with that ID found";
+    }
+
+    $r{version} = $list->version;
+
+    my @items = $dbh->resultset('ShoppingListItem')
+        ->search( undef, { order_by => { -asc => 'id' } } )->all;
+    for my $item (@items) {
+        push @{ $r{items} },
+            {   uri =>
+                uri_for( sprintf( "/list/%s/%s", $list->id, $item->id ) ),
+                description => $item->description,
+                done        => JSON->boolean( $item->done ),
+                version     => $item->version,
+            };
+    }
+
+    $dbh->txn_commit;
+
+    return \%r;
+};
+
+# create shopping list item
+post '/list/:id' => sub {
+    my $list_id = route_parameters->get('id');
+    length($list_id) and $list_id =~ /^\d{1,18}$/
+        or return invalid_input('bad list ID');
+
+    my $req = decode_json(request_data);
+
+    my $descr = $req->{description};
+    my $done  = JSON->boolean( $req->{done} // 0 );
+
+    my $dbh = get_database;
+    $dbh->txn_begin;
+
+    my %r = (
+        lists_version => get_lists_version($dbh),
+    );
+
+    my $list = $dbh->resultset('ShoppingList')->find($list_id);
+
+    unless ($list) {
+        $dbh->txn_commit;
+        status 404;
+        content_type 'text/plain';
+        return "No such list";
+    }
+
+    my $item = $dbh->resultset('ShoppingListItem')->create(
+        {   shopping_list => $list->id,
+            description   => $descr,
+            done          => $done,
+        }
+    );
+    $item->discard_changes;
+
+    $list->update( { version => $list->version + 1 } );
+
+    $r{uri} = uri_for( sprintf( "list/%s/%s", $list->id, $item->id ) );
+    $r{version} = $item->version;
+    $r{list_version} = $list->version;
+
+    $dbh->txn_commit;
+
+    return \%r;
+};
+
+# modify shopping list item
+put '/list/:list_id/:item_id' => sub {
+    my $list_id = route_parameters->get('list_id');
+    length($list_id) and $list_id =~ /^\d{1,18}$/
+        or return invalid_input('bad list ID');
+
+    my $item_id = route_parameters->get('item_id');
+    length($item_id) and $item_id =~ /^\d{1,18}$/
+        or return invalid_input('bad item ID');
+
+    my $req = decode_json(request_data);
+
+    my $descr = $req->{description};
+    my $done  = JSON->boolean( $req->{done} // 0 );
+    my $version = $req->{version};
+
+    length($version) and $version =~ /^\d{1,18}$/
+        or return invalid_input('bad version');
+
+    my $dbh = get_database;
+    $dbh->txn_begin;
+
+    my %r = (
+        lists_version => get_lists_version($dbh),
+    );
+
+    my $list = $dbh->resultset('ShoppingList')->find($list_id);
+    unless ($list) {
+        $dbh->txn_commit;
+        status 404;
+        content_type 'text/plain';
+        return "No such list";
+    }
+
+    my $item = $dbh->resultset('ShoppingListItem')->find({shopping_list => $list->id, id => $item_id});
+    unless ($item) {
+        $dbh->txn_commit;
+        status 404;
+        content_type 'text/plain';
+        return "No such item";
+    }
+
+    # in case no real changes are needed will return the current state
+    if (   defined($descr) and $descr ne ( $item->description // '' )
+        or defined($done) and $done != $item->done )
+    {
+        unless ($version == $item->version) {
+            $dbh->txn_commit;
+            status 409;
+            content_type 'text/plain';
+            return
+                sprintf( 'Outdated version (current is %d)', $item->version );
+        }
+
+        $item->update({
+            defined($descr) ? (description  => $descr) : (),
+            defined($done) ? (done =>  $done) : (),
+            version => $version + 1,
+        });
+
+        $list->update( { version => $list->version + 1 } );
+    }
+
+    $r{uri} = uri_for( sprintf( "list/%s/%s", $list->id, $item->id ) );
+    $r{version} = $item->version;
+    $r{list_version} = $list->version;
+
+    $dbh->txn_commit;
+
+    return \%r;
+};
+
+true;