blob: c3808f6b722d23c0bc89a3b8ef967eae48931a99 [file] [log] [blame]
Akron0e1ed242018-10-11 13:22:00 +02001#!/usr/bin/env perl
2use Mojolicious::Lite;
3use Mojo::ByteStream 'b';
4use Mojo::Date;
5use Mojo::JSON qw/true false encode_json decode_json/;
6use strict;
7use warnings;
8use Mojo::JWT;
Akron6d49c1f2018-10-11 14:22:21 +02009use Mojo::File qw/path/;
10use Mojo::Util qw/slugify/;
Akron0e1ed242018-10-11 13:22:00 +020011
12# This is an API fake server with fixtures
13
14my $secret = 's3cr3t';
Akron73f36082018-10-25 15:34:59 +020015my $fixture_path = path(Mojo::File->new(__FILE__)->dirname)->child('..', 'fixtures');
Akron0e1ed242018-10-11 13:22:00 +020016
Akroncdfd9d52019-07-23 11:35:00 +020017our %tokens = (
Akron59992122019-10-29 11:28:45 +010018 'access_token' => "4dcf8784ccfd26fac9bdb82778fe60e2",
19 'refresh_token' => "hlWci75xb8atDiq3924NUSvOdtAh7Nlf9z",
20 'access_token_2' => "abcde",
Akron83209f72021-01-29 17:54:15 +010021 'access_token_3' => 'jvgjbvjgzucgdwuiKHJK',
Akron59992122019-10-29 11:28:45 +010022 'refresh_token_2' => "fghijk",
23 'new_client_id' => 'fCBbQkA2NDA3MzM1Yw==',
24 'new_client_secret' => 'KUMaFxs6R1WGud4HM22w3HbmYKHMnNHIiLJ2ihaWtB4N5JxGzZgyqs5GTLutrORj',
Akron83209f72021-01-29 17:54:15 +010025 'auth_token_1' => 'mscajfdghnjdfshtkjcuynxahgz5il'
Akroncdfd9d52019-07-23 11:35:00 +020026);
27
28helper get_token => sub {
29 my ($c, $token) = @_;
30 return $tokens{$token}
31};
32
Akron33f5c672019-06-24 19:40:47 +020033# Legacy:
Akron0e1ed242018-10-11 13:22:00 +020034helper jwt_encode => sub {
35 shift;
36 return Mojo::JWT->new(
37 secret => $secret,
38 token_type => 'api_token',
39 expires => time + (3 * 34 * 60 * 60),
40 claims => { @_ }
41 );
42};
43
Akron33f5c672019-06-24 19:40:47 +020044# Legacy;
Akron0e1ed242018-10-11 13:22:00 +020045helper jwt_decode => sub {
46 my ($c, $auth) = @_;
47 $auth =~ s/\s*api_token\s+//;
48 return Mojo::JWT->new(secret => $secret)->decode($auth);
49};
50
Akroncdfd9d52019-07-23 11:35:00 +020051# Expiration helper
52helper expired => sub {
53 my ($c, $auth, $set) = @_;
54
55
56 $auth =~ s/^[^ ]+? //;
57 if ($set) {
58 $c->app->log->debug("Set $auth for expiration");
59 $c->app->defaults('auth_' . $auth => 1);
60 return 1;
61 };
62
63 $c->app->log->debug("Check $auth for expiration: " . (
64 $c->app->defaults('auth_' . $auth) // '0'
65 ));
66
67 return $c->app->defaults('auth_' . $auth);
68};
Akron0e1ed242018-10-11 13:22:00 +020069
Akron6d49c1f2018-10-11 14:22:21 +020070# Load fixture responses
71helper 'load_response' => sub {
72 my $c = shift;
73 my $q_name = shift;
74 my $file = $fixture_path->child("response_$q_name.json");
Akron8ea84292018-10-24 13:41:52 +020075 $c->app->log->debug("Load response from $file");
76
Akron6d49c1f2018-10-11 14:22:21 +020077 unless (-f $file) {
78 return {
79 status => 500,
80 json => {
81 errors => [[0, 'Unable to load query response from ' . $file]]
82 }
83 }
84 };
Akron8ea84292018-10-24 13:41:52 +020085
Akron6d49c1f2018-10-11 14:22:21 +020086 my $response = $file->slurp;
Akrona3c353c2019-02-14 23:50:00 +010087 my $decode = decode_json($response);
88 unless ($decode) {
89 return {
90 status => 500,
91 json => {
92 errors => [[0, 'Unable to parse JSON']]
93 }
94 }
95 };
96
97 return $decode;
Akron6d49c1f2018-10-11 14:22:21 +020098};
99
Akron1a9d5be2020-03-19 17:28:33 +0100100app->defaults('oauth.client_list' => []);
101
Akron6d49c1f2018-10-11 14:22:21 +0200102
Akron0e1ed242018-10-11 13:22:00 +0200103# Base page
Akron63d963b2019-07-05 15:35:51 +0200104get '/v1.0/' => sub {
Akron6d49c1f2018-10-11 14:22:21 +0200105 shift->render(text => 'Fake server available');
Akron0e1ed242018-10-11 13:22:00 +0200106};
107
Akron32396632018-10-11 17:08:37 +0200108
Akrond00b4272020-02-05 17:00:33 +0100109get '/v1.0/redirect-target-a' => sub {
110 shift->render(text => 'Redirect Target!');
111} => 'redirect-target';
112
113
114# Base page
115get '/v1.0/redirect' => sub {
116 my $c = shift;
117 $c->res->code(308);
118 $c->res->headers->location($c->url_for('redirect-target')->to_abs);
119 return $c->render(text => '');
120};
121
122
Akron0e1ed242018-10-11 13:22:00 +0200123# Search fixtures
Akron63d963b2019-07-05 15:35:51 +0200124get '/v1.0/search' => sub {
Akron0e1ed242018-10-11 13:22:00 +0200125 my $c = shift;
126 my $v = $c->validation;
127 $v->optional('q');
128 $v->optional('page');
129 $v->optional('ql');
Akroncd42a142019-07-12 18:55:37 +0200130 $v->optional('cq');
Akron0e1ed242018-10-11 13:22:00 +0200131 $v->optional('count');
132 $v->optional('context');
Akron8ea84292018-10-24 13:41:52 +0200133 $v->optional('offset');
Akronc58bfc42020-10-05 12:09:45 +0200134 $v->optional('pipes');
Akron8ea84292018-10-24 13:41:52 +0200135 $v->optional('cutoff')->in(qw/true false/);
Akron0e1ed242018-10-11 13:22:00 +0200136
Akron32396632018-10-11 17:08:37 +0200137 $c->app->log->debug('Receive request');
138
Akron0e1ed242018-10-11 13:22:00 +0200139 # Response q=x&ql=cosmas3
140 if ($v->param('ql') && $v->param('ql') eq 'cosmas3') {
141 return $c->render(
142 status => 400,
143 json => {
144 "\@context" => "http://korap.ids-mannheim.de/ns/koral/0.3/context.jsonld",
145 "errors" => [[307,"cosmas3 is not a supported query language!"]]
146 });
147 };
148
Akron6d49c1f2018-10-11 14:22:21 +0200149 if (!$v->param('q')) {
Akron8ea84292018-10-24 13:41:52 +0200150 return $c->render(%{$c->load_response('query_no_query')});
Akron0e1ed242018-10-11 13:22:00 +0200151 };
152
Akron8ea84292018-10-24 13:41:52 +0200153 my @slug_base = ($v->param('q'));
154 push @slug_base, 'o' . $v->param('offset') if defined $v->param('offset');
155 push @slug_base, 'c' . $v->param('count') if defined $v->param('count');
156 push @slug_base, 'co' . $v->param('cutoff') if defined $v->param('cutoff');
Akroncd42a142019-07-12 18:55:37 +0200157 push @slug_base, 'cq' if defined $v->param('cq');
Akronc58bfc42020-10-05 12:09:45 +0200158 push @slug_base, 'p' . $v->param('pipes') if defined $v->param('pipes');
Akron8ea84292018-10-24 13:41:52 +0200159
Akron6d49c1f2018-10-11 14:22:21 +0200160 # Get response based on query parameter
Akron8ea84292018-10-24 13:41:52 +0200161 my $response = $c->load_response('query_' . slugify(join('_', @slug_base)));
Akron0e1ed242018-10-11 13:22:00 +0200162
163 # Check authentification
164 if (my $auth = $c->req->headers->header('Authorization')) {
Akron33f5c672019-06-24 19:40:47 +0200165
Akroncdfd9d52019-07-23 11:35:00 +0200166 $c->app->log->debug("There is an authorization header $auth");
Akron33f5c672019-06-24 19:40:47 +0200167 my $jwt;
168 if ($auth =~ /^Bearer/) {
169 # Username unknown in OAuth2
170 $response->{json}->{meta}->{authorized} = 'yes';
171 }
Akroncdfd9d52019-07-23 11:35:00 +0200172 elsif ($auth =~ /^api_token/ && ($jwt = $c->jwt_decode($auth))) {
Akron6d49c1f2018-10-11 14:22:21 +0200173 $response->{json}->{meta}->{authorized} = $jwt->{username} if $jwt->{username};
Akron0e1ed242018-10-11 13:22:00 +0200174 };
Akroncdfd9d52019-07-23 11:35:00 +0200175
176 # Code is expired
177 if ($c->expired($auth)) {
178
179 $c->app->log->debug("The access token has expired");
180
181 return $c->render(
182 status => 401,
183 json => {
184 errors => [[2003, 'Access token is expired']]
185 }
186 );
187 }
188
189 # Auth token is invalid
190 if ($auth =~ /^Bearer inv4lid/) {
191 $c->app->log->debug("The access token is invalid");
192
193 return $c->render(
194 status => 401,
195 json => {
196 errors => [[2011, 'Access token is invalid']]
197 }
198 );
199 }
Akron0e1ed242018-10-11 13:22:00 +0200200 };
201
Akronc58bfc42020-10-05 12:09:45 +0200202 if ($v->param('pipes')) {
203 $response->{json}->{meta}->{pipes} = $v->param('pipes');
Akron7b9a1962020-07-02 09:52:53 +0200204 };
205
Akron6d49c1f2018-10-11 14:22:21 +0200206 # Set page parameter
Akron0e1ed242018-10-11 13:22:00 +0200207 if ($v->param('page')) {
Akron6d49c1f2018-10-11 14:22:21 +0200208 $response->{json}->{meta}->{startIndex} = $v->param("startIndex");
Akron0e1ed242018-10-11 13:22:00 +0200209 };
210
Akron0e1ed242018-10-11 13:22:00 +0200211 # Simple search fixture
Akron32396632018-10-11 17:08:37 +0200212 $c->render(%$response);
213
214 $c->app->log->debug('Rendered result');
215
216 return 1;
Akron0e1ed242018-10-11 13:22:00 +0200217};
218
Akron80a84b22018-10-24 17:44:24 +0200219# Textinfo fixtures
Akron63d963b2019-07-05 15:35:51 +0200220get '/v1.0/corpus/:corpusId/:docId/:textId' => sub {
Akron80a84b22018-10-24 17:44:24 +0200221 my $c = shift;
222
223 my $file = join('_', (
224 'textinfo',
225 $c->stash('corpusId'),
226 $c->stash('docId'),
227 $c->stash('textId')
228 ));
229
230 my $slug = slugify($file);
231
232 # Get response based on query parameter
233 my $response = $c->load_response($slug);
234 return $c->render(%$response);
235};
236
Akron0e1ed242018-10-11 13:22:00 +0200237
Akronb80341d2018-10-15 19:46:23 +0200238# Matchinfo fixtures
Akron63d963b2019-07-05 15:35:51 +0200239get '/v1.0/corpus/:corpusId/:docId/:textId/:matchId/matchInfo' => sub {
Akronb80341d2018-10-15 19:46:23 +0200240 my $c = shift;
241
242 my $file = join('_', (
243 'matchinfo',
244 $c->stash('corpusId'),
245 $c->stash('docId'),
246 $c->stash('textId'),
247 $c->stash('matchId')
248 ));
249
Akronb8d0b402018-10-18 23:51:52 +0200250 my $slug = slugify($file);
251
Akronb80341d2018-10-15 19:46:23 +0200252 # Get response based on query parameter
Akronb8d0b402018-10-18 23:51:52 +0200253 my $response = $c->load_response($slug);
Akronb80341d2018-10-15 19:46:23 +0200254 return $c->render(%$response);
255};
256
Akron0e1ed242018-10-11 13:22:00 +0200257
Akronbe61f4c2018-10-20 00:52:58 +0200258# Statistics endpoint
Akron63d963b2019-07-05 15:35:51 +0200259get '/v1.0/statistics' => sub {
Akronbe61f4c2018-10-20 00:52:58 +0200260 my $c = shift;
261 my $v = $c->validation;
Akron5fa61e92019-07-15 11:56:11 +0200262 $v->optional('cq');
Akronbe61f4c2018-10-20 00:52:58 +0200263
264 my @list = 'corpusinfo';
Akron5fa61e92019-07-15 11:56:11 +0200265 if ($v->param('cq')) {
266 push @list, $v->param('cq');
Akronbe61f4c2018-10-20 00:52:58 +0200267 };
268 my $slug = slugify(join('_', @list));
269
270 # Get response based on query parameter
271 my $response = $c->load_response($slug);
272 return $c->render(%$response);
273};
274
Akron0e1ed242018-10-11 13:22:00 +0200275############
276# Auth API #
277############
278
279# Request API token
Akron63d963b2019-07-05 15:35:51 +0200280get '/v1.0/auth/logout' => sub {
Akron0e1ed242018-10-11 13:22:00 +0200281 my $c = shift;
282
283 if (my $auth = $c->req->headers->header('Authorization')) {
Akroncdfd9d52019-07-23 11:35:00 +0200284
285 if ($auth =~ /^Bearer/) {
286 $c->app->log->debug('Server-Logout: ' . $auth);
287 return $c->render(json => { msg => [[0, 'Fine!']]});
288 }
289
290 elsif (my $jwt = $c->jwt_decode($auth)) {
Akron0e1ed242018-10-11 13:22:00 +0200291 my $user = $jwt->{username} if $jwt->{username};
292
293 $c->app->log->debug('Server-Logout: ' . $user);
294 return $c->render(json => { msg => [[0, 'Fine!']]});
295 };
296 };
297
298 return $c->render(status => 400, json => { error => [[0, 'No!']]});
299};
300
301
302# Request API token
Akron63d963b2019-07-05 15:35:51 +0200303get '/v1.0/auth/apiToken' => sub {
Akron0e1ed242018-10-11 13:22:00 +0200304 my $c = shift;
305
306 # Get auth header
307 my $auth = $c->req->headers->authorization;
308
309 # Authorization missing or not basic
310 if (!$auth || $auth !~ s/\s*Basic\s+//gi) {
311 return $c->render(
312 json => {
313 error => [[2, 'x']]
314 }
315 );
316 };
317
318 # Decode header
319 my ($username, $pwd) = @{b($auth)->b64_decode->split(':')->to_array};
320
321 # the password is 'pass'
322 if ($pwd) {
323
324 # the password is 'pass'
325 if ($pwd eq 'pass') {
326
327 # Render info with token
328 my $jwt = $c->jwt_encode(username => $username);
329
330 # Render in the Kustvakt fashion:
331 return $c->render(
332 format => 'html',
333 text => encode_json({
334 %{$jwt->claims},
335 expires => $jwt->expires,
336 token => $jwt->encode,
337 token_type => 'api_token'
338 })
339 );
Akron3d673062019-01-29 15:54:16 +0100340 }
341
342 elsif ($pwd eq 'ldaperr') {
343 return $c->render(
344 format => 'html',
345 status => 401,
346 json => {
347 "errors" => [[2022,"LDAP Authentication failed due to unknown user or password!"]]
348 }
349 );
Akron0e1ed242018-10-11 13:22:00 +0200350 };
351
352 return $c->render(
353 json => {
354 error => [[2004, undef]]
355 }
356 );
357 };
358
359 return $c->render(
360 json => {
361 error => [[2004, undef]]
362 }
363 );
364};
365
Akron33f5c672019-06-24 19:40:47 +0200366
367# Request API token
Akron63d963b2019-07-05 15:35:51 +0200368post '/v1.0/oauth2/token' => sub {
Akron33f5c672019-06-24 19:40:47 +0200369 my $c = shift;
370
Akron63d963b2019-07-05 15:35:51 +0200371 my $grant_type = $c->param('grant_type') // 'undefined';
372
373 if ($grant_type eq 'password') {
Akron33f5c672019-06-24 19:40:47 +0200374
Akron8bbbecf2019-07-01 18:57:30 +0200375 # Check for wrong client id
376 if ($c->param('client_id') ne '2') {
377 return $c->render(
378 json => {
379 "error_description" => "Unknown client with " . $_->{client_id},
380 "error" => "invalid_client"
381 },
382 status => 401
383 );
384 }
Akron33f5c672019-06-24 19:40:47 +0200385
Akron8bbbecf2019-07-01 18:57:30 +0200386 # Check for wrong client secret
387 elsif ($c->param('client_secret') ne 'k414m4r-s3cr3t') {
388 return $c->render(
389 json => {
390 "error_description" => "Invalid client credentials",
391 "error" => "invalid_client"
392 },
393 status => 401
394 );
395 }
Akron33f5c672019-06-24 19:40:47 +0200396
Akron8bbbecf2019-07-01 18:57:30 +0200397 # Check for wrong user name
398 elsif ($c->param('username') ne 'test') {
399 return $c->render(json => {
400 error => [[2004, undef]]
401 });
402 }
403
404 # Check for ldap error
405 elsif ($c->param('password') eq 'ldaperr') {
406 return $c->render(
407 format => 'html',
408 status => 401,
409 json => {
410 "errors" => [
411 [
412 2022,
413 "LDAP Authentication failed due to unknown user or password!"
414 ]
415 ]
416 }
417 );
418 }
419
420 # Check for wrong password
421 elsif ($c->param('password') ne 'pass') {
422 return $c->render(json => {
423 format => 'html',
424 status => 401,
Akron33f5c672019-06-24 19:40:47 +0200425 "errors" => [[2022,"LDAP Authentication failed due to unknown user or password!"]]
Akron8bbbecf2019-07-01 18:57:30 +0200426 });
427 }
428
429 # Return fine access
430 return $c->render(
431 json => {
Akroncdfd9d52019-07-23 11:35:00 +0200432 "access_token" => $c->get_token('access_token'),
433 "refresh_token" => $c->get_token('refresh_token'),
Akron8bbbecf2019-07-01 18:57:30 +0200434 "scope" => "all",
435 "token_type" => "Bearer",
436 "expires_in" => 86400
437 });
438 }
439
440 # Refresh token
Akron63d963b2019-07-05 15:35:51 +0200441 elsif ($grant_type eq 'refresh_token') {
Akroncdfd9d52019-07-23 11:35:00 +0200442
443 if ($c->param('refresh_token') eq 'inv4lid') {
444 return $c->render(
445 status => 400,
446 json => {
447 "error_description" => "Refresh token is expired",
448 "error" => "invalid_grant"
449 }
450 );
451 };
452
453 $c->app->log->debug("Refresh the token in the mock server!");
454
Akron8bbbecf2019-07-01 18:57:30 +0200455 return $c->render(
456 status => 200,
457 json => {
Akroncdfd9d52019-07-23 11:35:00 +0200458 "access_token" => $c->get_token("access_token_2"),
459 "refresh_token" => $c->get_token("refresh_token_2"),
Akron8bbbecf2019-07-01 18:57:30 +0200460 "token_type" => "Bearer",
461 "expires_in" => 86400
Akron33f5c672019-06-24 19:40:47 +0200462 }
463 );
464 }
465
Akron83209f72021-01-29 17:54:15 +0100466 # Get auth_token_1
467 elsif ($grant_type eq 'authorization_code') {
468 if ($c->param('code') eq $tokens{auth_token_1}) {
469 return $c->render(
470 status => 200,
471 json => {
472 "access_token" => $tokens{access_token_3},
473 "expires_in" => 31536000,
474 "scope" => 'match_info search openid',
475 "token_type" => "Bearer"
476 }
477 );
478 };
479 }
480
Akron8bbbecf2019-07-01 18:57:30 +0200481 # Unknown token grant
482 else {
483 return $c->render(
Akron63d963b2019-07-05 15:35:51 +0200484 status => 400,
Akron8bbbecf2019-07-01 18:57:30 +0200485 json => {
486 "errors" => [
487 [
Akron63d963b2019-07-05 15:35:51 +0200488 0, "Grant Type unknown", $grant_type
Akron8bbbecf2019-07-01 18:57:30 +0200489 ]
490 ]
491 }
492 )
Akron33f5c672019-06-24 19:40:47 +0200493 }
Akron33f5c672019-06-24 19:40:47 +0200494};
495
Akron4cefe1f2019-09-04 10:11:28 +0200496# Revoke API token
497post '/v1.0/oauth2/revoke' => sub {
498 my $c = shift;
499
500 my $refresh_token = $c->param('token');
501
502 if ($c->param('client_secret') ne 'k414m4r-s3cr3t') {
503 return $c->render(
504 json => {
505 "error_description" => "Invalid client credentials",
506 "error" => "invalid_client"
507 },
508 status => 401
509 );
510 };
511
512 return $c->render(
513 text => ''
514 )
515};
Akron33f5c672019-06-24 19:40:47 +0200516
Akron59992122019-10-29 11:28:45 +0100517# Register a client
518post '/v1.0/oauth2/client/register' => sub {
519 my $c = shift;
520 my $json = $c->req->json;
521
Akrondc50c892021-05-05 18:12:02 +0200522 if ($json->{redirectURI}) {
523 return $c->render(
524 status => 400,
525 json => {
526 errors => [
527 [
528 201,
529 "Unrecognized field \"redirectURI\" (class de.ids_mannheim.korap.web.input.OAuth2ClientJson), not marked as ignorable (5 known properties: \"redirect_uri\", \"type\", \"name\", \"description\", \"url\"])\n at [Source: (org.eclipse.jetty.server.HttpInputOverHTTP); line: 1, column: 94] (through reference chain: de.ids_mannheim.korap.web.input.OAuth2ClientJson[\"redirectURI\"])"
530 ]
531 ]
532 }
533 );
534 };
535
Akron59992122019-10-29 11:28:45 +0100536 my $name = $json->{name};
Akron1a9d5be2020-03-19 17:28:33 +0100537 my $desc = $json->{description};
Akron59992122019-10-29 11:28:45 +0100538 my $type = $json->{type};
539 my $url = $json->{url};
Akrondc50c892021-05-05 18:12:02 +0200540 my $redirect_url = $json->{redirect_uri};
Akron59992122019-10-29 11:28:45 +0100541
Akron1a9d5be2020-03-19 17:28:33 +0100542 my $list = $c->app->defaults('oauth.client_list');
543
544 push @$list, {
Akrondc50c892021-05-05 18:12:02 +0200545 "client_id" => $tokens{new_client_id},
546 "client_name" => $name,
Akronbc94a9c2021-04-15 00:07:35 +0200547 "client_description" => $desc,
548 "client_url" => $url
Akron1a9d5be2020-03-19 17:28:33 +0100549 };
550
Akron59992122019-10-29 11:28:45 +0100551 # Confidential server application
552 if ($type eq 'CONFIDENTIAL') {
553 return $c->render(json => {
554 client_id => $tokens{new_client_id},
555 client_secret => $tokens{new_client_secret}
556 });
557 };
558
559 # Desktop application
560 return $c->render(json => {
561 client_id => $tokens{new_client_id}
562 });
563};
564
Akron33f5c672019-06-24 19:40:47 +0200565
Akron0f1b93b2020-03-17 11:37:19 +0100566# Register a client
567post '/v1.0/oauth2/client/list' => sub {
568 my $c = shift;
569
570 # $c->param('client_secret');
Akron1a9d5be2020-03-19 17:28:33 +0100571
572 # Is empty [] when nothing registered
573
Akron0f1b93b2020-03-17 11:37:19 +0100574 return $c->render(
Akron1a9d5be2020-03-19 17:28:33 +0100575 json => $c->stash('oauth.client_list'),
576 status => 200
577 );
578};
579
Akronbc94a9c2021-04-15 00:07:35 +0200580
581# Get token list
582post '/v1.0/oauth2/token/list' => sub {
583 my $c = shift;
584 return $c->render(json => [
585 {
586 "client_description" => "Nur ein Beispiel",
587 "client_id" => $tokens{new_client_id},
588 "client_name" => "Beispiel",
589 "client_url" => "",
590 "created_date" => "2021-04-14T19:40:26.742+02:00[Europe\/Berlin]",
591 "expires_in" => "31533851",
592 "scope" => [
593 "match_info",
594 "search",
595 "openid"
596 ],
597 "token" => "jhkhkjhk_hjgjsfz67i",
598 "user_authentication_time" => "2021-04-14T19:39:41.81+02:00[Europe\/Berlin]"
599 }
600 ]);
601};
602
Akron1a9d5be2020-03-19 17:28:33 +0100603del '/v1.0/oauth2/client/deregister/:client_id' => sub {
604 my $c = shift;
605 my $client_id = $c->stash('client_id');
606
607 my $list = $c->app->defaults('oauth.client_list');
608
609 my $break = -1;
610 for (my $i = 0; $i < @$list; $i++) {
Akrondc50c892021-05-05 18:12:02 +0200611 if ($list->[$i]->{client_id} eq $client_id) {
Akron1a9d5be2020-03-19 17:28:33 +0100612 $break = $i;
613 last;
614 };
615 };
616
617 if ($break != -1) {
618 splice @$list, $break, 1;
619 }
620
621 else {
622 return $c->render(
623 json => {
624 error_description => "Unknown client with $client_id.",
625 error => "invalid_client"
Akron0f1b93b2020-03-17 11:37:19 +0100626 },
Akron1a9d5be2020-03-19 17:28:33 +0100627 status => 401
628 );
629 };
630
631 return $c->render(
632 json => $c->stash('oauth.client_list'),
Akron0f1b93b2020-03-17 11:37:19 +0100633 status => 200
634 );
635};
636
Akron83209f72021-01-29 17:54:15 +0100637post '/v1.0/oauth2/authorize' => sub {
638 my $c = shift;
639 my $type = $c->param('response_type');
640 my $client_id = $c->param('client_id');
641 my $redirect_uri = $c->param('redirect_uri');
642
643 if ($type eq 'code') {
644
645 return $c->redirect_to(
646 Mojo::URL->new($redirect_uri)->query({
647 code => $tokens{auth_token_1},
648 scope => 'match_info search openid'
649 })
650 );
651 }
652};
653
Akron0f1b93b2020-03-17 11:37:19 +0100654
Akronabdf9a92021-01-12 19:06:57 +0100655#######################
656# Query Reference API #
657#######################
658
659use CHI;
660my $chi = CHI->new(
661 driver => 'Memory',
662 global => 1
663);
664
665# Store query
666put '/v1.0/query/~:user/:query_name' => sub {
667 my $c = shift;
668 my $user = $c->stash('user');
669 my $qname = $c->stash('query_name');
670
671 if ($chi->is_valid($qname)) {
672 return $c->render(
673 json => {
674 errors => [
675 {
676 message => 'Unable to store query reference'
677 }
678 ]
679 }, status => 400
680 );
681 };
682
683 my $json = $c->req->json;
684
685 my $store = {
686 name => $qname,
687 koralQuery => { '@type' => 'Okay' },
688 query => $json->{query},
689 queryType => $json->{queryType},
690 type => $json->{type},
691 queryLanguage => $json->{queryLanguage},
692 };
693
694 if (exists $json->{description}) {
695 $store->{description} = $json->{description}
696 };
697
698 # Set query reference
699 $chi->set($qname => $store);
700
701 my $queries = $chi->get('~queries') // [];
702 push @$queries, $qname;
703 $chi->set('~queries' => $queries);
704
705 return $c->render(
706 status => 201,
707 text => ''
708 );
709};
710
711# Get query
712get '/v1.0/query/~:user/:query_name' => sub {
713 my $c = shift;
714
715 my $user = $c->stash('user');
716 my $qname = $c->stash('query_name');
717
718 my $json = $chi->get($qname);
719
720 if ($json) {
721 return $c->render(
722 json => $json
723 );
724 };
725
726 return $c->render(
727 json => {
728 errors => [
729 {
730 message => 'Query reference not found'
731 }
732 ]
733 }, status => 404
734 );
735};
736
737
738# Get all queries
739get '/v1.0/query/~:user' => sub {
740 my $c = shift;
741 my $user = $c->stash('user');
742 my $qs = $chi->get('~queries') // [];
743 my @queries = ();
744 foreach (@$qs) {
745 push @queries, $chi->get($_);
746 };
747 return $c->render(json => { refs => \@queries });
748};
749
750
751# Store query
752del '/v1.0/query/~:user/:query_name' => sub {
753 my $c = shift;
754 my $user = $c->stash('user');
755 my $qname = $c->stash('query_name');
756
757 $chi->remove($qname);
758
759 my $queries = $chi->get('~queries') // [];
760
761 my @clean = ();
762 foreach (@$queries) {
763 push @clean, $_ unless $_ eq $qname
764 };
765
766 $chi->set('~queries' => \@clean);
767
768 return $c->render(
769 status => 200,
770 text => ''
771 );
772};
773
Akron0f1b93b2020-03-17 11:37:19 +0100774
Akron0e1ed242018-10-11 13:22:00 +0200775app->start;
776
777
778__END__
779
780
781 # Temporary:
782 my $collection_query = {
783 '@type' => "koral:docGroup",
784 "operation" => "operation:or",
785 "operands" => [
786 {
787 '@type' => "koral:docGroup",
788 "operation" => "operation:and",
789 "operands" => [
790 {
791 '@type' => "koral:doc",
792 "key" => "title",
793 "match" => "match:eq",
794 "value" => "Der Birnbaum",
795 "type" => "type:string"
796 },
797 {
798 '@type' => "koral:doc",
799 "key" => "pubPlace",
800 "match" => "match:eq",
801 "value" => "Mannheim",
802 "type" => "type:string"
803 },
804 {
805 '@type' => "koral:docGroup",
806 "operation" => "operation:or",
807 "operands" => [
808 {
809 '@type' => "koral:doc",
810 "key" => "subTitle",
811 "match" => "match:eq",
812 "value" => "Aufzucht oder Pflege",
813 "type" => "type:string"
814 },
815 {
816 '@type' => "koral:doc",
817 "key" => "subTitle",
818 "match" => "match:eq",
819 "value" => "Gedichte",
820 "type" => "type:string"
821 }
822 ]
823 }
824 ]
825 },
826 {
827 '@type' => "koral:doc",
828 "key" => "pubDate",
829 "match" => "match:geq",
830 "value" => "2015-03-05",
831 "type" => "type:date"
832 }
833 ]
834 };