159 lines
3.8 KiB
Perl
159 lines
3.8 KiB
Perl
package PoorBooru::API::V0;
|
|
use Dancer2;
|
|
use Dancer2::Plugin::DBIC;
|
|
|
|
our $VERSION = v0;
|
|
|
|
set serializer => "JSON";
|
|
|
|
use constant {
|
|
DEFAULT_CONTENT_TYPE => "application/json",
|
|
};
|
|
|
|
my $TAG_NAME_RE = qr/^[0-9]*[A-Z_a-z][0-9A-Z_a-z]*$/;
|
|
my $NUMERIC_ID_RE = qr/^[1-9][0-9]*$/;
|
|
|
|
my $MEDIA_SEARCH_OPTS = {
|
|
order_by => { -desc => "media_id" },
|
|
rows => 20,
|
|
};
|
|
my $TAGS_COUNT_VIEW_SEARCH_OPTS = {
|
|
order_by => { -desc => "count" },
|
|
rows => 100,
|
|
};
|
|
|
|
|
|
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,
|
|
};
|
|
}
|
|
|
|
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 $page !~ $NUMERIC_ID_RE;
|
|
|
|
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 { $_ !~ $TAG_NAME_RE } @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 ($tag, $tag_rset, @media);
|
|
my $tag_id_or_name = route_parameters->get("tag_id_or_name");
|
|
|
|
$tag_rset = schema("default")->resultset("Tag");
|
|
$tag = $tag_rset->single({ tag_id => $tag_id_or_name }) //
|
|
$tag_rset->single({ name => $tag_id_or_name });
|
|
|
|
send_error("Tag not found", 404) if !defined($tag);
|
|
|
|
@media = map { $_->media_id } schema("default")->resultset("MediaTag")
|
|
->search({ tag_id => $tag->tag_id })->all;
|
|
|
|
return {
|
|
id => $tag->tag_id,
|
|
name => $tag->name,
|
|
media => \@media,
|
|
};
|
|
};
|
|
|
|
get "/media" => sub {
|
|
my $page = query_parameters->get("page") // 1;
|
|
send_error("Invalid page number", 400) if $page !~ $NUMERIC_ID_RE;
|
|
|
|
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;
|