PoorBooru/lib/PoorBooru/API/V0.pm

168 lines
4.1 KiB
Perl

package PoorBooru::API::V0;
use v5.32;
use Dancer2;
use Dancer2::Plugin::DBIC;
use constant {
DEFAULT_CONTENT_TYPE => "application/json",
};
our $VERSION = v0.0.1;
my $MEDIA_SEARCH_OPTS = {
order_by => { -desc => "media_id" },
rows => 20,
};
my $TAGS_COUNT_VIEW_SEARCH_OPTS = {
order_by => { -desc => "count" },
rows => 100,
};
sub validate_page_number ($) { $_[0] =~ /^[1-9][0-9]*$/ }
sub validate_tag_name ($) { $_[0] !~ /^[1-9][0-9]*$/ && $_[0] =~ /^\w+$/ }
sub mkpager ($)
{
my $pager = $_[0]->pager;
return {
first => $pager->first_page,
prev => $pager->previous_page,
cur => $pager->current_page,
next => $pager->next_page,
last => $pager->last_page,
};
}
set serializer => "JSON";
get "/meta" => sub {
return [
{ 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 => "/download/:media_id", verb => "GET" },
{ path => "/random", verb => "GET" },
],
};
get "/tags" => sub {
my $page = query_parameters->get("page") // 1;
send_error("Invalid page number", 400) if !validate_page_number($page);
my $paged_tags = schema("default")->resultset("TagsCountView")
->search({}, $TAGS_COUNT_VIEW_SEARCH_OPTS)->page($page);
my @tags = map +{
id => $_->tag_id,
name => $_->name,
count => $_->count,
}, $paged_tags->all;
return {
pager => mkpager($paged_tags),
tags => \@tags,
}
};
post "/tags" => sub {
my @tag_names = body_parameters->get_all("name");
send_error("No tags provided", 400) if @tag_names == 0;
send_error("Too many tags provided", 400) if @tag_names > 100;
send_error("Invalid tag names", 400) if
grep { validate_tag_name($_) } @tag_names;
my @tags;
eval {
@tags = map +{
id => $_->tag_id,
name => $_->name,
}, schema("default")->resultset("Tag")
->populate([map +{ name => $_ }, @tag_names]);
} or send_error("Tag exists", 409);
return \@tags;
};
get "/tag/:tag_id_or_name" => sub {
my $page = query_parameters->get("page") // 1;
send_error("Invalid page number", 400) if !validate_page_number($page);
my $tag_id_or_name = route_parameters->get("tag_id_or_name");
my $query = [
{ tag_id => $tag_id_or_name },
{ name => $tag_id_or_name },
];
my $tag = schema("default")->resultset("Tag")->single($query);
send_error("Tag not found", 404) if !defined($tag);
my $paged_media = schema("default")->resultset("MediaTag")
->search({ tag_id => $tag->tag_id }, $MEDIA_SEARCH_OPTS)
->page($page);
my @media = map { $_->media_id } $paged_media->all;
return {
id => $tag->tag_id,
name => $tag->name,
pager => mkpager($paged_media),
media => \@media,
};
};
get "/media" => sub {
my $page = query_parameters->get("page") // 1;
send_error("Invalid page number", 400) if !validate_page_number($page);
my $paged_media = schema("default")->resultset("Media")
->search({}, $MEDIA_SEARCH_OPTS)->page($page);
my @media = map { $_->media_id } $paged_media->all;
return {
pager => mkpager($paged_media),
media => \@media,
};
};
get "/media/:media_id" => sub {
my $media = schema("default")->resultset("Media")
->single({ media_id => route_parameters->get("media_id") });
send_error("Media not found", 404) if !defined($media);
return {
id => $media->media_id,
filename => $media->filename,
size => length($media->content),
download_path => "/download/" . $media->media_id,
};
};
get "/download/:media_id" => sub {
my $media = schema("default")->resultset("Media")
->single({ media_id => route_parameters->get("media_id") });
send_error("Media not found", 404) if !defined($media);
send_file(
\$media->content,
content_type => $media->content_type // DEFAULT_CONTENT_TYPE,
filename => $media->filename,
);
};
get "/random" => sub {
my $media = schema("default")->resultset("Media")
->search({}, { order_by => \"random()", limit => 1 })->single;
send_error("Media not found", 404) if !defined($media);
forward "/media/" . $media->media_id;
};
true;