Bug 22835: Serve plugin static files through API
authorAgustin Moyano <agustinmoyano@theke.io>
Thu, 25 Apr 2019 05:13:37 +0000 (02:13 -0300)
committerMartin Renvoize <martin.renvoize@ptfs-europe.com>
Tue, 18 Jun 2019 16:34:44 +0000 (17:34 +0100)
This patch serves static files declared within plugins.

To declare static files the plugin must implement the method 'static_routes' which retrieves the spec of static file routes to add to the API.

Once those routes are added to the API, the become available through the /api/v1/contrib/<api_namespace>/static/<path>/<to>/<file>/<filename> endpoint.

To test:
1) Install bug-22835-plugin.kpz
2) Point your browser to /api/v1/contrib/kitchensink/static/static_files/mm.gif
CHECK => No file is served
3) Apply this patch
4) restart_all
5) Repeat step 2.
SUCCESS => File is served!
6) Sign off

Sponsored-by: Theke Solutions
Signed-off-by: Arthur Suzuki <arthur.suzuki@biblibre.com>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>

Koha/REST/Plugin/PluginRoutes.pm
Koha/REST/V1/Static.pm [new file with mode: 0644]

index f51c7bd..43ac913 100644 (file)
@@ -50,11 +50,11 @@ sub register {
     {
         @plugins = Koha::Plugins->new()->GetPlugins(
             {
-                method => 'api_routes',
+                method => 'api_namespace',
             }
         );
         # plugin needs to define a namespace
-        @plugins = grep { $_->api_namespace } @plugins;
+        #@plugins = grep { $_->api_namespace } @plugins;
     }
 
     foreach my $plugin ( @plugins ) {
@@ -98,21 +98,38 @@ sub inject_routes {
 sub merge_spec {
     my ( $spec, $plugin ) = @_;
 
-    my $plugin_spec = $plugin->api_routes;
+    if($plugin->can('api_routes')) {
+        my $plugin_spec = $plugin->api_routes;
 
-    foreach my $route ( keys %{ $plugin_spec } ) {
+        foreach my $route ( keys %{ $plugin_spec } ) {
+            my $THE_route = '/contrib/' . $plugin->api_namespace . $route;
+            if ( exists $spec->{ $THE_route } ) {
+                # Route exists, overwriting is forbidden
+                Koha::Exceptions::Plugin::ForbiddenAction->throw(
+                    "Attempted to overwrite $THE_route"
+                );
+            }
 
-        my $THE_route = '/contrib/' . $plugin->api_namespace . $route;
-        if ( exists $spec->{ $THE_route } ) {
-            # Route exists, overwriting is forbidden
-            Koha::Exceptions::Plugin::ForbiddenAction->throw(
-                "Attempted to overwrite $THE_route"
-            );
+            $spec->{'paths'}->{ $THE_route } = $plugin_spec->{ $route };
         }
-
-        $spec->{'paths'}->{ $THE_route } = $plugin_spec->{ $route };
     }
 
+    if($plugin->can('static_routes')) {
+        my $plugin_spec = $plugin->static_routes;
+
+        foreach my $route ( keys %{ $plugin_spec } ) {
+
+            my $THE_route = '/contrib/' . $plugin->api_namespace . '/static'.$route;
+            if ( exists $spec->{ $THE_route } ) {
+                # Route exists, overwriting is forbidden
+                Koha::Exceptions::Plugin::ForbiddenAction->throw(
+                    "Attempted to overwrite $THE_route"
+                );
+            }
+
+            $spec->{'paths'}->{ $THE_route } = $plugin_spec->{ $route };
+        }
+    }
     return $spec;
 }
 
diff --git a/Koha/REST/V1/Static.pm b/Koha/REST/V1/Static.pm
new file mode 100644 (file)
index 0000000..d0f31c9
--- /dev/null
@@ -0,0 +1,90 @@
+package Koha::REST::V1::Static;
+
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 3 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use Modern::Perl;
+
+use Mojo::Base 'Mojolicious::Controller';
+
+use Try::Tiny;
+
+=head1 API
+
+=head2 Class methods
+
+=head3 get
+
+Mehtod that gets file contents
+
+=cut
+
+sub get {
+    my $self = shift;
+    my $c = $self->openapi->valid_input or return;
+
+    if (   C4::Context->preference('UseKohaPlugins')
+        && C4::Context->config("enable_plugins") )
+    {
+        my $path = $c->req->url->path->leading_slash(1);
+
+        return $c->render(status => 400, openapi => { error => 'Endpoint inteded for plugin static files' }) unless "$path" =~ /^\/api\/v1\/contrib/;
+
+        my $namespace = $path->[3];
+
+        my $checkpath = '/api/v1/contrib/'.$namespace.'/static';
+
+        return $c->render(status => 400, openapi => { error => 'Endpoint inteded for plugin static files' }) unless "$path" =~ /\Q$checkpath/;
+
+        my @plugins = Koha::Plugins->new()->GetPlugins(
+            {
+                method => 'api_namespace',
+            }
+        );
+
+        @plugins = grep { $_->api_namespace eq $namespace} @plugins;
+        warn scalar(@plugins);
+        return $c->render({ status => 404, openapi => { error => 'File not found' } }) unless scalar(@plugins) > 0;
+        return $c->render({ status => 500, openapi => { error => 'Namespace not unique' } }) unless scalar(@plugins) == 1;
+
+        my $plugin = $plugins[0];
+
+        my $basepath = $plugin->bundle_path;
+
+        warn $basepath;
+
+        my $relpath = join ('/', splice (@$path, 5));
+
+        warn $relpath;
+
+        warn join('/', $basepath, $relpath);
+        return try {
+            my $asset = Mojo::Asset::File->new(path => join('/', $basepath, $relpath));
+            return $c->render({ status => 404, openapi => { error => 'File not found' } }) unless $asset->is_file;
+            # $c->res->headers->content_type("image/jpeg");
+            return $c->reply->asset($asset);
+        }
+        catch {
+            return $c->render({ status => 404, openapi => { error => 'File not found' } });
+        }
+
+    } else {
+        $c->render({ status => 500, openapi => { error => 'Plugins are not enabled' } })
+    }
+
+
+}
+
+1;
\ No newline at end of file