| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- package Trog::Routes::JSON;
- use v5.36;
- use re '/aa';
- use Clone qw{clone};
- use JSON::MaybeXS();
- use Scalar::Util();
- use Trog::Utils();
- use Trog::Config();
- use Trog::Auth();
- use Trog::Routes::HTML();
- use Trog::Log::Metrics();
- our %routes = (
- '/api/catalog' => {
- method => 'GET',
- callback => \&catalog,
- parameters => {},
- },
- '/api/webmanifest' => {
- method => 'GET',
- callback => \&webmanifest,
- parameters => {},
- },
- '/api/version' => {
- method => 'GET',
- callback => \&version,
- parameters => {},
- },
- '/api/auth_change_request/(.*)' => {
- method => 'GET',
- callback => \&process_auth_change_request,
- captures => ['token'],
- parameters => {
- token => sub { my $tok = shift; $tok =~ m/[a-f|0-9|-]+/; },
- },
- noindex => 1,
- robot_name => '/api/auth_change_request/*',
- },
- '/api/posts_of_form' => {
- method => 'GET',
- auth => 1,
- parameters => {
- # Same shape series.json demands of child_form.
- form => sub { $_[0] =~ m/^[A-Za-z0-9_-]+\.tx$/ },
- },
- callback => \&posts_of_form,
- noindex => 1,
- },
- '/api/requests_per' => {
- method => 'GET',
- auth => 1,
- parameters => {
- period => sub {
- grep {
- my $valid = $_;
- List::Util::any { $_ eq $valid } @_
- } qw{second minute hour day week month year};
- },
- num_periods => \&Scalar::Util::looks_like_number,
- before => \&Scalar::Util::looks_like_number,
- code => \&Scalar::Util::looks_like_number,
- },
- callback => \&requests_per,
- },
- );
- # Clone / redact for catalog
- my $cloned = clone( \%routes );
- foreach my $r ( keys(%$cloned) ) {
- delete $cloned->{$r}{callback};
- }
- my $enc = JSON::MaybeXS->new( utf8 => 1 );
- # Note to authors, don't forget to update this
- sub _version () {
- return '1.0';
- }
- # Special case of a non data-structure JSON return
- sub version ($query) {
- state $ret = [ 200, [ 'Content-type' => "application/json", ETag => 'version-' . _version() ], [ _version() ] ];
- return $ret;
- }
- sub catalog ($query) {
- return _render( 200, { ETag => 'catalog-' . _version() }, %$cloned );
- }
- sub webmanifest ($query) {
- state $headers = { ETag => 'manifest-' . _version() };
- my $theme_dir = Trog::Themes::get_dir();
- state %manifest = (
- "icons" => [
- { "src" => "$theme_dir/img/icon/favicon-32.png", "type" => "image/png", "sizes" => "32x32" },
- { "src" => "$theme_dir/img/icon/favicon-48.png", "type" => "image/png", "sizes" => "48x48" },
- { "src" => "$theme_dir/img/icon/favicon-167.png", "type" => "image/png", "sizes" => "167x167" },
- { "src" => "$theme_dir/img/icon/favicon-180.png", "type" => "image/png", "sizes" => "180x180" },
- { "src" => "$theme_dir/img/icon/favicon-192.png", "type" => "image/png", "sizes" => "192x192" },
- { "src" => "$theme_dir/img/icon/favicon-512.png", "type" => "image/png", "sizes" => "512x512" },
- ],
- );
- return _render( 200, $headers, %manifest );
- }
- sub process_auth_change_request ($query) {
- my $token = $query->{token};
- my $msg = Trog::Auth::process_change_request($token);
- return $query->{tpsgi}->forbidden($query) unless $msg;
- return _render(
- 200, undef,
- message => $msg,
- result => 'success',
- );
- }
- =head2 posts_of_form
- Implements GET /api/posts_of_form. Requires a login.
- The id and title of every post of the named type which the caller is allowed to
- see. This is what fills a relation field's dropdown in the post editor -- see
- www/scripts/post_relations.js and the x-tcms-relations tables in the post type
- sidecars.
- Only id and title: the caller is populating a picker, and a post's body is
- nobody's business here.
- =cut
- sub posts_of_form ($query) {
- my @posts = Trog::Routes::HTML::_post_helper( { form => $query->{form}, limit => 0 }, [], $query->{user_acls} );
- return _render(
- 200, undef,
- posts => [ map { { id => $_->{id}, title => $_->{title} } } @posts ],
- );
- }
- sub requests_per ($query) {
- my $code = Trog::Utils::coerce_array( $query->{code} );
- return _render(
- 200, undef,
- %{ Trog::Log::Metrics::requests_per( $query->{period}, $query->{num_periods}, $query->{before}, @$code ) }
- );
- }
- sub _render ( $code, $headers, %data ) {
- return Trog::Renderer->render(
- code => 200,
- data => \%data,
- template => 'bogus.tx',
- contenttype => 'application/json',
- headers => $headers,
- # TODO it may be appropriate to cache some of these methods.
- nocache => 1,
- );
- }
- 1;
|