Initial import

This commit is contained in:
Lucas 2023-02-18 09:49:05 +00:00
commit 1ff831f80d
19 changed files with 956 additions and 0 deletions

37
lib/PoorBooru.pm Normal file
View file

@ -0,0 +1,37 @@
package PoorBooru;
use Dancer2;
use HTTP::Tiny;
our $VERSION = v0.1;
my $POORBOORU_API = setting("poorbooru_api");
hook before_template_render => sub {
my $tokens = shift;
$tokens->{uris}->{root} = uri_for("/");
$tokens->{uris}->{login} = uri_for("/login");
$tokens->{uris}->{logout} = uri_for("/logout");
$tokens->{uris}->{random} = uri_for("/random");
$tokens->{uris}->{tags} = uri_for("/tags");
};
get "/" => sub {
template "index" => {
"title" => "main",
};
};
get "/tags" => sub {
};
get "/tag/:tag_id" => sub {
};
get "/random" => sub {
};
get "/image/:image_id" => sub {
};
true;

113
lib/PoorBooru/API/V0.pm Normal file
View file

@ -0,0 +1,113 @@
package PoorBooru::API::V0;
use Dancer2;
use Dancer2::Plugin::DBIC;
our $VERSION = v0;
set serializer => "JSON";
set database => "db/booru.db";
my $DEFAULT_CONTENT_TYPE = "application/json";
my @ROUTES = (
{ path => "/meta", verb => "GET" },
{ path => "/tags", verb => "GET" },
{ path => "/tags/new", verb => "POST" },
{ path => "/tag/:tag_id_or_name", verb => "GET" },
{ path => "/random", verb => "GET" },
{ path => "/media/:media_id", verb => "GET" },
{ path => "/download/:media_id", verb => "GET" },
);
get "/meta" => sub {
return \@ROUTES;
};
get "/tags" => sub {
my @tags = schema("default")->resultset("TagsCountView")->all;
return [
map +( {
id => $_->tag_id,
name => $_->name,
count => $_->count,
} ), @tags,
];
};
post "/tags/new" => sub {
my $tag;
eval {
$tag = schema("default")->resultset("Tag")
->create({ name => body_parameters->get("name") });
} or send_error("Tag exists", 409);
return {
id => $tag->tag_id,
name => $tag->name,
};
};
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 => [
map +( {
id => $_,
uri => uri_for("/media/$_"),
donwload_uri => uri_for("/download/$_"),
} ), @media,
],
};
};
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;
};
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_uri => uri_for("/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,
);
};
true;

20
lib/PoorBooru/Schema.pm Normal file
View file

@ -0,0 +1,20 @@
use utf8;
package PoorBooru::Schema;
# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE
use strict;
use warnings;
use base 'DBIx::Class::Schema';
__PACKAGE__->load_namespaces;
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2023-02-18 09:09:31
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:0PabNwBpp04P3y4a8O5MtA
# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

View file

@ -0,0 +1,108 @@
use utf8;
package PoorBooru::Schema::Result::Media;
# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE
=head1 NAME
PoorBooru::Schema::Result::Media
=cut
use strict;
use warnings;
use base 'DBIx::Class::Core';
=head1 TABLE: C<media>
=cut
__PACKAGE__->table("media");
=head1 ACCESSORS
=head2 media_id
data_type: 'integer'
is_auto_increment: 1
is_nullable: 0
=head2 content
data_type: 'blob'
is_nullable: 0
size: 10485760
=head2 filename
data_type: 'text'
is_nullable: 0
size: 255
=head2 content_type
data_type: 'text'
is_nullable: 1
size: 255
=cut
__PACKAGE__->add_columns(
"media_id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"content",
{ data_type => "blob", is_nullable => 0, size => 10485760 },
"filename",
{ data_type => "text", is_nullable => 0, size => 255 },
"content_type",
{ data_type => "text", is_nullable => 1, size => 255 },
);
=head1 PRIMARY KEY
=over 4
=item * L</media_id>
=back
=cut
__PACKAGE__->set_primary_key("media_id");
=head1 RELATIONS
=head2 media_tags
Type: has_many
Related object: L<PoorBooru::Schema::Result::MediaTag>
=cut
__PACKAGE__->has_many(
"media_tags",
"PoorBooru::Schema::Result::MediaTag",
{ "foreign.media_id" => "self.media_id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
=head2 tags
Type: many_to_many
Composing rels: L</media_tags> -> tag
=cut
__PACKAGE__->many_to_many("tags", "media_tags", "tag");
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2023-02-18 09:09:31
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:X0A6CSw6yWOYvxhMNRoS0g
# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

View file

@ -0,0 +1,99 @@
use utf8;
package PoorBooru::Schema::Result::MediaTag;
# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE
=head1 NAME
PoorBooru::Schema::Result::MediaTag
=cut
use strict;
use warnings;
use base 'DBIx::Class::Core';
=head1 TABLE: C<media_tags>
=cut
__PACKAGE__->table("media_tags");
=head1 ACCESSORS
=head2 media_id
data_type: 'integer'
is_foreign_key: 1
is_nullable: 0
=head2 tag_id
data_type: 'integer'
is_foreign_key: 1
is_nullable: 0
=cut
__PACKAGE__->add_columns(
"media_id",
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
"tag_id",
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
);
=head1 PRIMARY KEY
=over 4
=item * L</media_id>
=item * L</tag_id>
=back
=cut
__PACKAGE__->set_primary_key("media_id", "tag_id");
=head1 RELATIONS
=head2 media
Type: belongs_to
Related object: L<PoorBooru::Schema::Result::Media>
=cut
__PACKAGE__->belongs_to(
"media",
"PoorBooru::Schema::Result::Media",
{ media_id => "media_id" },
{ is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
);
=head2 tag
Type: belongs_to
Related object: L<PoorBooru::Schema::Result::Tag>
=cut
__PACKAGE__->belongs_to(
"tag",
"PoorBooru::Schema::Result::Tag",
{ tag_id => "tag_id" },
{ is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
);
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2023-02-18 09:09:31
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:CaXiI8+eaCoDbot368Hjyw
# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

View file

@ -0,0 +1,106 @@
use utf8;
package PoorBooru::Schema::Result::Tag;
# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE
=head1 NAME
PoorBooru::Schema::Result::Tag
=cut
use strict;
use warnings;
use base 'DBIx::Class::Core';
=head1 TABLE: C<tags>
=cut
__PACKAGE__->table("tags");
=head1 ACCESSORS
=head2 tag_id
data_type: 'integer'
is_auto_increment: 1
is_nullable: 0
=head2 name
data_type: 'text'
is_nullable: 0
size: 255
=cut
__PACKAGE__->add_columns(
"tag_id",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
"name",
{ data_type => "text", is_nullable => 0, size => 255 },
);
=head1 PRIMARY KEY
=over 4
=item * L</tag_id>
=back
=cut
__PACKAGE__->set_primary_key("tag_id");
=head1 UNIQUE CONSTRAINTS
=head2 C<name_unique>
=over 4
=item * L</name>
=back
=cut
__PACKAGE__->add_unique_constraint("name_unique", ["name"]);
=head1 RELATIONS
=head2 media_tags
Type: has_many
Related object: L<PoorBooru::Schema::Result::MediaTag>
=cut
__PACKAGE__->has_many(
"media_tags",
"PoorBooru::Schema::Result::MediaTag",
{ "foreign.tag_id" => "self.tag_id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
=head2 medias
Type: many_to_many
Composing rels: L</media_tags> -> media
=cut
__PACKAGE__->many_to_many("medias", "media_tags", "media");
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2023-02-18 09:09:31
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:tlbIFVg6S6LAWWiR0ioHFw
# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;

View file

@ -0,0 +1,60 @@
use utf8;
package PoorBooru::Schema::Result::TagsCountView;
# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE
=head1 NAME
PoorBooru::Schema::Result::TagsCountView
=cut
use strict;
use warnings;
use base 'DBIx::Class::Core';
__PACKAGE__->table_class("DBIx::Class::ResultSource::View");
=head1 TABLE: C<tags_count_view>
=cut
__PACKAGE__->table("tags_count_view");
=head1 ACCESSORS
=head2 tag_id
data_type: 'integer'
is_nullable: 1
=head2 name
data_type: 'text'
is_nullable: 1
size: 255
=head2 count
data_type: (empty string)
is_nullable: 1
=cut
__PACKAGE__->add_columns(
"tag_id",
{ data_type => "integer", is_nullable => 1 },
"name",
{ data_type => "text", is_nullable => 1, size => 255 },
"count",
{ data_type => "", is_nullable => 1 },
);
# Created by DBIx::Class::Schema::Loader v0.07049 @ 2023-02-18 09:09:31
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:9NUzqweyXVu/G84fxb3eew
# You can replace this text with custom code or comments, and it will be preserved on regeneration
1;