From 7ccbc3af1237e00a90b57746d8a419b9dea892db Mon Sep 17 00:00:00 2001 From: Lucas Date: Sat, 4 Mar 2023 21:58:18 +0000 Subject: [PATCH] api: initial migration --- lib/PoorBooru.pm | 20 ++++++ lib/PoorBooru/API/V0.pm | 29 +++++++++ lib/PoorBooru/API/V0/Controller/Meta.pm | 25 ++++++++ lib/PoorBooru/API/V0/Controller/Tags.pm | 82 +++++++++++++++++++++++++ poorbooru-api-v0.conf | 8 +++ poorbooru.conf | 6 ++ script/poorbooru | 10 +++ script/poorbooru-api-v0 | 10 +++ 8 files changed, 190 insertions(+) create mode 100644 lib/PoorBooru.pm create mode 100644 lib/PoorBooru/API/V0.pm create mode 100644 lib/PoorBooru/API/V0/Controller/Meta.pm create mode 100644 lib/PoorBooru/API/V0/Controller/Tags.pm create mode 100644 poorbooru-api-v0.conf create mode 100644 poorbooru.conf create mode 100755 script/poorbooru create mode 100755 script/poorbooru-api-v0 diff --git a/lib/PoorBooru.pm b/lib/PoorBooru.pm new file mode 100644 index 0000000..d20d767 --- /dev/null +++ b/lib/PoorBooru.pm @@ -0,0 +1,20 @@ +package PoorBooru; +use v5.36; +use strict; +use warnings; + +use Mojo::Base "Mojolicious"; + +sub startup ($self) +{ + $self->moniker("poorbooru"); + + my $config = $self->plugin("Config"); + $self->secrets($config->{secrets}); + + $self->plugin(Mount => { + "/api/v0" => $self->home->child("script", "poorbooru-api-v0"), + }); +} + +1; diff --git a/lib/PoorBooru/API/V0.pm b/lib/PoorBooru/API/V0.pm new file mode 100644 index 0000000..a9f8e09 --- /dev/null +++ b/lib/PoorBooru/API/V0.pm @@ -0,0 +1,29 @@ +package PoorBooru::API::V0; +use v5.36; +use strict; +use warnings; + +use Mojo::Base "Mojolicious"; + +use PoorBooru::Schema; + +sub startup ($self) +{ + $self->moniker("poorbooru-api-v0"); + + my $config = $self->plugin("Config"); + $self->secrets($config->{secrets}); + + $self->helper(schema => sub { + state $schema = PoorBooru::Schema->connect($config->{dsn}) + }); + + my $r = $self->routes; + + $r->get("/meta")->to("meta#index"); + + $r->get("/tags")->to("tags#list"); + $r->get("/tag/:tag_id_or_name")->to("tags#show"); +} + +1; diff --git a/lib/PoorBooru/API/V0/Controller/Meta.pm b/lib/PoorBooru/API/V0/Controller/Meta.pm new file mode 100644 index 0000000..d172fd8 --- /dev/null +++ b/lib/PoorBooru/API/V0/Controller/Meta.pm @@ -0,0 +1,25 @@ +package PoorBooru::API::V0::Controller::Meta; +use v5.36; +use strict; +use warnings; + +use Mojo::Base "Mojolicious::Controller"; + +sub index ($self) +{ + return $self->render(json => [ + { path => "/meta", verb => "GET" }, + + { path => "/tags", verb => "GET" }, + { path => "/tags", verb => "POST" }, + { path => "/tag/:tag_id_or_name", verb => "GET" }, + + { path => "/media/:media_id", verb => "GET" }, + { path => "/media/download/:media_id", verb => "GET" }, + + { path => "/random/media", verb => "GET" }, + { path => "/random/tag", verb => "GET" }, + ]); +}; + +1; diff --git a/lib/PoorBooru/API/V0/Controller/Tags.pm b/lib/PoorBooru/API/V0/Controller/Tags.pm new file mode 100644 index 0000000..4698c28 --- /dev/null +++ b/lib/PoorBooru/API/V0/Controller/Tags.pm @@ -0,0 +1,82 @@ +package PoorBooru::API::V0::Controller::Tags; +use v5.36; +use strict; +use warnings; + +use Mojo::Base "Mojolicious::Controller"; + +my $MEDIA_SEARCH_OPTS = { + order_by => { -desc => "media_id" }, + rows => 5, +}; +my $TAGS_COUNT_VIEW_SEARCH_OPTS = { + order_by => { -desc => "count" }, + rows => 5, +}; + +sub _pager_links ($c, $pager) +{ + +{ map +( $_ => ($pager->$_ and + $c->url_with->query({page => $pager->$_})) ), + qw(first_page previous_page current_page next_page last_page) } +} + +sub list ($self) +{ + my $v = $self->validation; + my $page = $v->optional("page")->num(1, undef)->param // 1; + + return $self->render( + json => {error => "Invalid page number"}, + status => 400, + ) if $v->has_error; + + my $paged_tags = $self->schema->resultset("TagCountView") + ->search({}, $TAGS_COUNT_VIEW_SEARCH_OPTS)->page($page); + my @tags = map +{ + id => $_->tag_id, + name => $_->name, + count => $_->count, + }, $paged_tags->all; + + return $self->render(json => { + pager => _pager_links($self, $paged_tags->pager), + tags => \@tags, + }); +}; + +sub show ($self) +{ + my $v = $self->validation; + my $page = $v->optional("page")->num(1, undef)->param // 1; + + return $self->render( + json => {error => "Invalid page number"}, + status => 400, + ) if $v->has_error; + + my $tag_id_or_name = $self->stash("tag_id_or_name"); + my $tag = $self->schema->resultset("Tag")->single([ + { tag_id => $tag_id_or_name }, + { name => $tag_id_or_name }, + ]); + + return $self->render( + json => {error => "Tag not found"}, + status => 404, + ) if !defined($tag); + + my $paged_media = $self->schema->resultset("MediaTag") + ->search({ tag_id => $tag->tag_id }, $MEDIA_SEARCH_OPTS) + ->page($page); + my @media = map { $_->media_id } $paged_media->all; + + return $self->render(json => { + id => $tag->tag_id, + name => $tag->name, + pager => _pager_links($self, $paged_media->pager), + media => \@media, + }); +}; + +1; diff --git a/poorbooru-api-v0.conf b/poorbooru-api-v0.conf new file mode 100644 index 0000000..96753a9 --- /dev/null +++ b/poorbooru-api-v0.conf @@ -0,0 +1,8 @@ +{ + dsn => "dbi:SQLite:dbname=db/PoorBooru.db", + + secrets => [ + # Generate with "openssl rand -hex 32". + pack("H*", "a0b1..."), + ], +} diff --git a/poorbooru.conf b/poorbooru.conf new file mode 100644 index 0000000..c53fe99 --- /dev/null +++ b/poorbooru.conf @@ -0,0 +1,6 @@ +{ + secrets => [ + # Generate with "openssl rand -hex 32". + pack("H*", "a0b1..."), + ], +} diff --git a/script/poorbooru b/script/poorbooru new file mode 100755 index 0000000..a51508b --- /dev/null +++ b/script/poorbooru @@ -0,0 +1,10 @@ +#!/usr/bin/env perl +use v5.36; +use strict; +use warnings; + +use Mojo::File qw(curfile); +use lib curfile->dirname->sibling("lib")->to_string; +use Mojolicious::Commands; + +Mojolicious::Commands->start_app("PoorBooru"); diff --git a/script/poorbooru-api-v0 b/script/poorbooru-api-v0 new file mode 100755 index 0000000..628d388 --- /dev/null +++ b/script/poorbooru-api-v0 @@ -0,0 +1,10 @@ +#!/usr/bin/env perl +use v5.36; +use strict; +use warnings; + +use Mojo::File qw(curfile); +use lib curfile->dirname->sibling("lib")->to_string; +use Mojolicious::Commands; + +Mojolicious::Commands->start_app("PoorBooru::API::V0");