From 1edeb32ca9f3c27b4be9153fe18754b35be7c761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Rama=C5=A1euski?= <andrej@x2.cz> Date: Tue, 2 Aug 2022 00:19:52 +0200 Subject: [PATCH] Pridana podpora openapi --- Dockerfile | 3 +- lib/PZ.pm | 40 +++++++++++++++- lib/PZ/Controller/Shortcut.pm | 14 ++++++ lib/PZ/Helpers/Core.pm | 86 +++++++++++++++++++++++++++++++++++ lib/PZ/Schema/Result/User.pm | 5 ++ openapi.yaml | 62 +++++++++++++++++++++++++ 6 files changed, 207 insertions(+), 3 deletions(-) create mode 100644 lib/PZ/Helpers/Core.pm create mode 100644 openapi.yaml diff --git a/Dockerfile b/Dockerfile index 4096522..d6f1084 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,8 @@ RUN cpanm \ Mojo::Pg \ Mojo::Redis \ Mojo::JWT \ - Mojolicious::Plugin::Authentication + Mojolicious::Plugin::Authentication \ + Mojolicious::Plugin::OpenAPI ADD . /opt/PZ WORKDIR /opt/PZ diff --git a/lib/PZ.pm b/lib/PZ.pm index c9eae00..bc0549a 100644 --- a/lib/PZ.pm +++ b/lib/PZ.pm @@ -20,6 +20,7 @@ sub startup { # Delka session $self->sessions->default_expiration($cfg->{session}{lifetime}); + $self->plugin('PZ::Helpers::Core'); $self->plugin('PZ::Helpers::OIDC'); my $redis = Mojo::Redis->new( 'redis://' . $cfg->{redis}{server} ); @@ -43,7 +44,10 @@ sub startup { autoload_user => 1, load_user => sub { my $c = shift; - return $c->session->{user}; + my $user = $c->schema->resultset('User')->find({ + id => $c->session->{user}{id}, + }); + return $user; }, validate_user => sub { my $c = shift; @@ -52,8 +56,40 @@ sub startup { }, }); + $self->plugin("OpenAPI" => { + url => $self->home->rel_file("openapi.yaml"), + schema => 'v3', + plugins => [qw(+SpecRenderer +Cors +Security)], + render_specification => 1, + render_specification_for_paths => 1, + default_response_codes => [400, 401, 403, 404, 500, 501], + + security => { + Token => sub { + my ($c, $definition, $scopes, $cb ) = @_; + + my $token = $c->req->headers->header('X-Auth-Token'); + + return $c->$cb('Authorization header not present') if ! $token; + + my $user = $c->schema->resultset('User')->find( + { token => $token } + ); + + if (! $user ) { + return $c->$cb('Invalid user'); + } + + $c->stash->{user} = $user; + return $c->$cb(); + } + } + }); + # defautni globalni promenne ve stash - $self->defaults(); + $self->defaults( + openapi_cors_allowed_origins => ['*'], + ); # vypnuti cache templatu pri vyvoji $self->renderer->cache->max_keys(0) if $cfg->{dev_mode}; diff --git a/lib/PZ/Controller/Shortcut.pm b/lib/PZ/Controller/Shortcut.pm index 792af36..2a4a1c8 100644 --- a/lib/PZ/Controller/Shortcut.pm +++ b/lib/PZ/Controller/Shortcut.pm @@ -74,4 +74,18 @@ sub qr ($c) { $c->render( data => $png ); } + +sub list ($c) { + my @shortcuts = (); + + SHORTCUT: + foreach my $shortcut ( $c->stash->{user}->shortcuts ) { + push @shortcuts, $c->spec_filter( + { $shortcut->get_columns }, 'Shortcut' + ); + } + + $c->render(json => \@shortcuts ); +} + 1; diff --git a/lib/PZ/Helpers/Core.pm b/lib/PZ/Helpers/Core.pm new file mode 100644 index 0000000..f566d9a --- /dev/null +++ b/lib/PZ/Helpers/Core.pm @@ -0,0 +1,86 @@ +package PZ::Helpers::Core; + +use base 'Mojolicious::Plugin'; + +use YAML; + +sub register { + my ($class, $self ) = @_; + + $self->helper(error => sub { + my $c = shift; + my $status = shift; + my $errors = []; + + $c->cirpack_ws->rollback(); + + if ( scalar @_ == 2 ) { + $errors = [{ code => shift, message => shift }]; + } + elsif ( ref $_[0] eq 'ARRAY' ) { + $errors = shift; + } + elsif ( ref $_[0] eq 'HASH' ) { + $errors = [ shift ]; + } + else { + $errors = [{ message => shift, code => undef }]; + } + + $c->stash( + status => $status, + openapi => { errors => $errors } + ); + + return undef; + }); + + $self->helper( trace => sub { + my $c = shift; + my $data = shift // ''; + + $data = Dump $data if ref $data; + $c->app->log->debug($data); + + }); + + $self->helper( spec_filter => sub { + my $c = shift; + my $data = shift; + my $class = shift; + + if (my $def =$c->openapi->spec("/components/schemas/$class")) { + my $filtered = {}; + + KEY: + foreach my $key ( keys %{ $def->{properties} } ) { + my $value = $data->{$key}; + my $nullable = 0; + + my $types = $def->{properties}{$key}{type}; + + if ( ref $types eq 'ARRAY' ) { + TYPE: + foreach my $type ( @{ $types } ) { + $nullable = 1, last if $type eq 'null'; + } + } + + if ( $key =~ /^cirpack_/ && $value eq 'XXX' ) { + $value = $nullable ? undef : ''; + } + + $filtered->{$key} = $value; + } + + $data = $filtered; + + } + + return $data; + }); + +} + +1; + diff --git a/lib/PZ/Schema/Result/User.pm b/lib/PZ/Schema/Result/User.pm index 58034cc..14b1102 100644 --- a/lib/PZ/Schema/Result/User.pm +++ b/lib/PZ/Schema/Result/User.pm @@ -39,6 +39,11 @@ __PACKAGE__->add_unique_constraint( 'token' => [qw(token)] ); +__PACKAGE__->has_many( + shortcuts => 'PZ::Schema::Result::Shortcut', + { 'foreign.user_id' => 'self.id', }, +); + sub set_token { my $self = shift; my $new = shift; diff --git a/openapi.yaml b/openapi.yaml new file mode 100644 index 0000000..bb13336 --- /dev/null +++ b/openapi.yaml @@ -0,0 +1,62 @@ +openapi: 3.0.3 + +info: + title: Piratský zkracovač + description: Piratský zkracovač API + version: 1.15.1 + license: + name: Artistic License 2.0 + url: https://www.perlfoundation.org/artistic-license-20.html + contact: + name: Andrej Ramašeuski + email: andrej@x2.cz + url: https://pardubicky.pirati.cz/lide/andrej-ramaseuski/ + +servers: + - url: https://z.pirati.cz/api + description: Production server + - url: http://127.0.0.1:3000/api + description: Test server + +components: + schemas: + Shortcut: + type: object + properties: + id: + type: integer + shortcut: + type: string + description: Zkratka + url: + type: string + description: URL pro přesměrování + code: + type: integer + description: Kód přesměrování + securitySchemes: + Token: + type: apiKey + in: header + name: X-Auth-Token + +paths: + /shortcuts: + get: + tags: + - shortcuts + security: + - Token: [] + summary: "Seznam zkratek" + operationId: Shortcuts + x-mojo-to: shortcut#list + responses: + 200: + description: Seznam zkratek + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Shortcut' + -- GitLab