Bug 24545: Fix license statements
[srvgit] / Koha / REST / Plugin / Query.pm
index f1402d9..4bdbb90 100644 (file)
@@ -2,22 +2,23 @@ package Koha::REST::Plugin::Query;
 
 # 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 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.
+# 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.
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
 
 use Modern::Perl;
 
 use Mojo::Base 'Mojolicious::Plugin';
+use List::MoreUtils qw(any);
 use Scalar::Util qw(reftype);
 
 use Koha::Exceptions;
@@ -53,19 +54,24 @@ Generates the DBIC query from the query parameters.
 
             my $reserved_params;
             my $filtered_params;
+            my $path_params;
 
             my $reserved_words = _reserved_words();
+            my @query_param_names = keys %{$c->req->params->to_hash};
 
             foreach my $param ( keys %{$params} ) {
                 if ( grep { $param eq $_ } @{$reserved_words} ) {
                     $reserved_params->{$param} = $params->{$param};
                 }
-                else {
+                elsif ( grep { $param eq $_ } @query_param_names ) {
                     $filtered_params->{$param} = $params->{$param};
                 }
+                else {
+                    $path_params->{$param} = $params->{$param};
+                }
             }
 
-            return ( $filtered_params, $reserved_params );
+            return ( $filtered_params, $reserved_params, $path_params );
         }
     );
 
@@ -99,6 +105,35 @@ Generates the DBIC order_by attributes based on I<$params>, and merges into I<$a
         }
     );
 
+=head3 dbic_merge_prefetch
+
+    $attributes = $c->dbic_merge_prefetch({ attributes => $attributes, result_set => $result_set });
+
+Generates the DBIC prefetch attribute based on embedded relations, and merges into I<$attributes>.
+
+=cut
+
+    $app->helper(
+        'dbic_merge_prefetch' => sub {
+            my ( $c, $args ) = @_;
+            my $attributes = $args->{attributes};
+            my $result_set = $args->{result_set};
+            my $embed = $c->stash('koha.embed');
+
+            return unless defined $embed;
+
+            my @prefetches;
+            foreach my $key (keys %{$embed}) {
+                my $parsed = _parse_prefetch($key, $embed, $result_set);
+                push @prefetches, $parsed if defined $parsed;
+            }
+
+            if(scalar(@prefetches)) {
+                $attributes->{prefetch} = \@prefetches;
+            }
+        }
+    );
+
 =head3 _build_query_params_from_api
 
     my $params = _build_query_params_from_api( $filtered_params, $reserved_params );
@@ -143,6 +178,45 @@ is raised.
             return $params;
         }
     );
+
+=head3 stash_embed
+
+    $c->stash_embed( $c->match->endpoint->pattern->defaults->{'openapi.op_spec'} );
+
+=cut
+
+    $app->helper(
+        'stash_embed' => sub {
+
+            my ( $c, $args ) = @_;
+
+            my $spec = $args->{spec} // {};
+
+            my $embed_spec   = $spec->{'x-koha-embed'};
+            my $embed_header = $c->req->headers->header('x-koha-embed');
+
+            Koha::Exceptions::BadParameter->throw("Embedding objects is not allowed on this endpoint.")
+                if $embed_header and !defined $embed_spec;
+
+            if ( $embed_header ) {
+                my $THE_embed = {};
+                foreach my $embed_req ( split /\s*,\s*/, $embed_header ) {
+                    my $matches = grep {lc $_ eq lc $embed_req} @{ $embed_spec };
+
+                    Koha::Exceptions::BadParameter->throw(
+                        error => 'Embeding '.$embed_req. ' is not authorised. Check your x-koha-embed headers or remove it.'
+                    ) unless $matches;
+
+                    _merge_embed( _parse_embed($embed_req), $THE_embed);
+                }
+
+                $c->stash( 'koha.embed' => $THE_embed )
+                    if $THE_embed;
+            }
+
+            return $c;
+        }
+    );
 }
 
 =head2 Internal methods
@@ -180,7 +254,8 @@ sub _build_order_atom {
     my $param = $string;
     $param =~ s/^(\+|\-|\s)//;
     if ( $result_set ) {
-        $param = (keys %{$result_set->attributes_from_api({ $param => 1 })})[0];
+        my $model_param = $result_set->from_api_mapping->{$param};
+        $param = $model_param if defined $model_param;
     }
 
     if ( $string =~ m/^\+/ or
@@ -198,4 +273,77 @@ sub _build_order_atom {
     }
 }
 
+=head3 _parse_embed
+
+    my $embed = _parse_embed( $string );
+
+Parses I<$string> and outputs data valid for passing to the Kohaa::Object(s)->to_api
+method.
+
+=cut
+
+sub _parse_embed {
+    my $string = shift;
+
+    my $result;
+    my ( $curr, $next ) = split /\s*\.\s*/, $string, 2;
+
+    if ( $next ) {
+        $result->{$curr} = { children => _parse_embed( $next ) };
+    }
+    else {
+        if ( $curr =~ m/^(?<relation>.*)\+count/ ) {
+            my $key = $+{relation} . "_count";
+            $result->{$key} = { is_count => 1 };
+        }
+        else {
+            $result->{$curr} = {};
+        }
+    }
+
+    return $result;
+}
+
+=head3 _merge_embed
+
+    _merge_embed( $parsed_embed, $global_embed );
+
+Merges the hash referenced by I<$parsed_embed> into I<$global_embed>.
+
+=cut
+
+sub _merge_embed {
+    my ( $structure, $embed ) = @_;
+
+    my ($root) = keys %{ $structure };
+
+    if ( any { $root eq $_ } keys %{ $embed } ) {
+        # Recurse
+        _merge_embed( $structure->{$root}, $embed->{$root} );
+    }
+    else {
+        # Embed
+        $embed->{$root} = $structure->{$root};
+    }
+}
+
+sub _parse_prefetch {
+    my ( $key, $embed, $result_set) = @_;
+
+    return unless exists $result_set->prefetch_whitelist->{$key};
+
+    my $ko_class = $result_set->prefetch_whitelist->{$key};
+    return $key unless defined $embed->{$key}->{children} && defined $ko_class;
+
+    my $prefetch = {};
+    foreach my $child (keys %{$embed->{$key}->{children}}) {
+        my $parsed = _parse_prefetch($child, $embed->{$key}->{children}, $ko_class->new);
+        $prefetch->{$key} = $parsed if defined $parsed;
+    }
+
+    return unless scalar(keys %{$prefetch});
+
+    return $prefetch;
+}
+
 1;