View | Details | Raw Unified | Return to bug 30194
Collapse All | Expand All

(-)a/Koha/REST/Plugin/PluginRoutes.pm (-20 / +13 lines)
Lines 24-29 use Koha::Plugins; Link Here
24
use Koha::Logger;
24
use Koha::Logger;
25
25
26
use Clone qw( clone );
26
use Clone qw( clone );
27
use JSON::Validator::Schema::OpenAPIv2;
27
use Try::Tiny qw( catch try );
28
use Try::Tiny qw( catch try );
28
29
29
=head1 NAME
30
=head1 NAME
Lines 41-48 Koha::REST::Plugin::PluginRoutes Link Here
41
sub register {
42
sub register {
42
    my ( $self, $app, $config ) = @_;
43
    my ( $self, $app, $config ) = @_;
43
44
44
    my $spec      = $config->{spec};
45
    my $spec     = $config->{spec};
45
    my $validator = $config->{validator};
46
    my $validate = $config->{validate};
46
47
47
    my @plugins;
48
    my @plugins;
48
49
Lines 58-64 sub register { Link Here
58
        );
59
        );
59
60
60
        foreach my $plugin ( @plugins ) {
61
        foreach my $plugin ( @plugins ) {
61
            $spec = $self->inject_routes( $spec, $plugin, $validator );
62
            $spec = $self->inject_routes( $spec, $plugin, $validate );
62
        }
63
        }
63
64
64
    }
65
    }
Lines 71-84 sub register { Link Here
71
=cut
72
=cut
72
73
73
sub inject_routes {
74
sub inject_routes {
74
    my ( $self, $spec, $plugin, $validator ) = @_;
75
    my ( $self, $spec, $plugin, $validate ) = @_;
75
76
76
    return merge_spec( $spec, $plugin ) unless $validator;
77
    return merge_spec( $spec, $plugin ) unless $validate;
77
78
78
    return try {
79
    return try {
79
80
80
        my $backup_spec = merge_spec( clone($spec), $plugin );
81
        my $backup_spec = merge_spec( clone($spec), $plugin );
81
        if ( $self->spec_ok( $backup_spec, $validator ) ) {
82
        if ( $self->spec_ok( $backup_spec, $validate ) ) {
82
            $spec = merge_spec( $spec, $plugin );
83
            $spec = merge_spec( $spec, $plugin );
83
        }
84
        }
84
        else {
85
        else {
Lines 145-167 sub merge_spec { Link Here
145
=cut
146
=cut
146
147
147
sub spec_ok {
148
sub spec_ok {
148
    my ( $self, $spec, $validator ) = @_;
149
    my ( $self, $spec ) = @_;
149
150
150
    my $schema = $self->{'swagger-v2-schema'};
151
    my $schema = JSON::Validator::Schema::OpenAPIv2->new( $spec );
151
152
152
    return try {
153
    if ($schema->is_invalid) {
153
        $validator->load_and_validate_schema(
154
        warn $schema->errors->[0];
154
            $spec,
155
            {
156
                allow_invalid_ref => 1,
157
                schema => ( $schema ) ? $schema : undef,
158
            }
159
        );
160
        return 1;
161
    }
162
    catch {
163
        return 0;
164
    }
155
    }
156
157
    return !$schema->is_invalid;
165
}
158
}
166
159
167
1;
160
1;
(-)a/Koha/REST/V1.pm (-31 / +18 lines)
Lines 22-28 use Mojo::Base 'Mojolicious'; Link Here
22
use C4::Context;
22
use C4::Context;
23
use Koha::Logger;
23
use Koha::Logger;
24
24
25
use JSON::Validator::OpenAPI::Mojolicious;
25
use JSON::Validator::Schema::OpenAPIv2;
26
26
use Try::Tiny qw( catch try );
27
use Try::Tiny qw( catch try );
27
28
28
=head1 NAME
29
=head1 NAME
Lines 68-92 sub startup { Link Here
68
        $self->secrets([$secret_passphrase]);
69
        $self->secrets([$secret_passphrase]);
69
    }
70
    }
70
71
71
    my $validator = JSON::Validator::OpenAPI::Mojolicious->new;
72
    my $spec_file = $self->home->rel_file("api/v1/swagger/swagger.json");
72
73
73
    push @{$self->routes->namespaces}, 'Koha::Plugin';
74
    push @{$self->routes->namespaces}, 'Koha::Plugin';
74
75
75
    # Try to load and merge all schemas first and validate the result just once.
76
    # Try to load and merge all schemas first and validate the result just once.
76
    my $spec;
77
    my $swagger_schema = $self->home->rel_file("api/swagger-v2-schema.json");
78
    try {
77
    try {
79
        $spec = $validator->bundle(
78
80
            {
79
        my $schema = JSON::Validator::Schema::OpenAPIv2->new;
81
                replace => 1,
80
82
                schema => $self->home->rel_file("api/v1/swagger/swagger.yaml")
81
        $schema->resolve( $spec_file );
83
            }
82
84
        );
83
        my $spec = $schema->bundle->data;
85
84
86
        $self->plugin(
85
        $self->plugin(
87
            'Koha::REST::Plugin::PluginRoutes' => {
86
            'Koha::REST::Plugin::PluginRoutes' => {
88
                spec               => $spec,
87
                spec     => $spec,
89
                validator          => undef
88
                validate => 0,
90
            }
89
            }
91
        ) unless C4::Context->needs_install; # load only if Koha is installed
90
        ) unless C4::Context->needs_install; # load only if Koha is installed
92
91
Lines 94-104 sub startup { Link Here
94
            OpenAPI => {
93
            OpenAPI => {
95
                spec  => $spec,
94
                spec  => $spec,
96
                route => $self->routes->under('/api/v1')->to('Auth#under'),
95
                route => $self->routes->under('/api/v1')->to('Auth#under'),
97
                schema => ( $swagger_schema ) ? $swagger_schema : undef,
98
                allow_invalid_ref =>
99
                1,    # required by our spec because $ref directly under
100
                        # Paths-, Parameters-, Definitions- & Info-object
101
                        # is not allowed by the OpenAPI specification.
102
            }
96
            }
103
        );
97
        );
104
    }
98
    }
Lines 111-129 sub startup { Link Here
111
        $logger->error("Warning: Could not load REST API spec bundle: " . $_);
105
        $logger->error("Warning: Could not load REST API spec bundle: " . $_);
112
106
113
        try {
107
        try {
114
            $validator->load_and_validate_schema(
115
                $self->home->rel_file("api/v1/swagger/swagger.yaml"),
116
                {
117
                    allow_invalid_ref  => 1,
118
                    schema => ( $swagger_schema ) ? $swagger_schema : undef,
119
                }
120
            );
121
108
122
            $spec = $validator->schema->data;
109
            my $schema = JSON::Validator::Schema::OpenAPIv2->new;
110
            $schema->resolve( $spec_file );
111
112
            my $spec = $schema->bundle->data;
113
123
            $self->plugin(
114
            $self->plugin(
124
                'Koha::REST::Plugin::PluginRoutes' => {
115
                'Koha::REST::Plugin::PluginRoutes' => {
125
                    spec      => $spec,
116
                    spec     => $spec,
126
                    validator => $validator
117
                    validate => 1
127
                }
118
                }
128
            )  unless C4::Context->needs_install; # load only if Koha is installed
119
            )  unless C4::Context->needs_install; # load only if Koha is installed
129
120
Lines 131-140 sub startup { Link Here
131
                OpenAPI => {
122
                OpenAPI => {
132
                    spec  => $spec,
123
                    spec  => $spec,
133
                    route => $self->routes->under('/api/v1')->to('Auth#under'),
124
                    route => $self->routes->under('/api/v1')->to('Auth#under'),
134
                    allow_invalid_ref =>
135
                    1,    # required by our spec because $ref directly under
136
                            # Paths-, Parameters-, Definitions- & Info-object
137
                            # is not allowed by the OpenAPI specification.
138
                }
125
                }
139
            );
126
            );
140
        }
127
        }
(-)a/t/db_dependent/Koha/REST/Plugin/PluginRoutes.t (-9 / +8 lines)
Lines 25-32 use Test::MockModule; Link Here
25
use File::Basename;
25
use File::Basename;
26
use t::lib::Mocks;
26
use t::lib::Mocks;
27
27
28
use JSON::Validator::OpenAPI::Mojolicious;
29
30
# Dummy app for testing the plugin
28
# Dummy app for testing the plugin
31
use Mojolicious::Lite;
29
use Mojolicious::Lite;
32
30
Lines 72-79 subtest 'Bad plugins tests' => sub { Link Here
72
    my $t;
70
    my $t;
73
    warning_like
71
    warning_like
74
        { $t = Test::Mojo->new('Koha::REST::V1'); }
72
        { $t = Test::Mojo->new('Koha::REST::V1'); }
75
        [qr{Could not load REST API spec bundle: Invalid JSON specification},
73
        [qr{Could not load REST API spec bundle: /paths/~0001contrib~0001badass},
76
        qr{The resulting spec is invalid. Skipping Bad API Route Plugin},],
74
        qr{bother_wrong/put/parameters/0: /oneOf/1 Properties not allowed:},
75
        qr{Plugin Koha::Plugin::BadAPIRoute route injection failed: The resulting spec is invalid. Skipping Bad API Route Plugin},],
77
        'Bad plugins raise warning';
76
        'Bad plugins raise warning';
78
77
79
    my $routes = get_defined_routes($t);
78
    my $routes = get_defined_routes($t);
Lines 153-160 subtest 'Permissions and access to plugin routes tests' => sub { Link Here
153
    my $t;
152
    my $t;
154
    warning_like
153
    warning_like
155
        { $t = Test::Mojo->new('Koha::REST::V1'); }
154
        { $t = Test::Mojo->new('Koha::REST::V1'); }
156
        [qr{Could not load REST API spec bundle: Invalid JSON specification},
155
        [qr{Could not load REST API spec bundle: /paths/~0001contrib~0001badass},
157
        qr{The resulting spec is invalid. Skipping Bad API Route Plugin},],
156
        qr{bother_wrong/put/parameters/0: /oneOf/1 Properties not allowed:},
157
        qr{Plugin Koha::Plugin::BadAPIRoute route injection failed: The resulting spec is invalid. Skipping Bad API Route Plugin},],
158
        'Bad plugins raise warning';
158
        'Bad plugins raise warning';
159
159
160
    my $routes = get_defined_routes($t);
160
    my $routes = get_defined_routes($t);
Lines 262-269 sub traverse_routes { Link Here
262
    my $path = $route->pattern->unparsed || '/';
262
    my $path = $route->pattern->unparsed || '/';
263
263
264
    # Methods
264
    # Methods
265
    my $via = $route->via;
265
    my $methods = $route->methods // [];
266
    my $verb = !$via ? '*' : uc join ',', @$via;
266
    my $verb = !$methods ? '*' : uc join ',', @$methods;
267
    $routes->{$path}->{$verb} = 1;
267
    $routes->{$path}->{$verb} = 1;
268
268
269
    $depth++;
269
    $depth++;
270
- 

Return to bug 30194