blob: ce8af5fa31e4b81237f3811501e12d93b0a5d37b [file] [log] [blame]
Akron80f731d2017-04-03 20:10:58 +02001#!/usr/bin/env perl
2use Mojolicious::Lite;
3use Mojo::ByteStream 'b';
4use Mojo::Date;
Akrone5ef4e02017-04-19 17:07:52 +02005use Mojo::JSON qw/true false encode_json/;
Akron741b2b12017-04-13 22:15:59 +02006use strict;
7use warnings;
8use Mojo::JWT;
Akron80f731d2017-04-03 20:10:58 +02009
10# This is an API fake server with fixtures
11
Akron3042f242017-04-15 16:57:55 +020012# TODO: Test the fake server
13
Akronbc213c02017-04-20 16:45:55 +020014my $secret = 's3cr3t';
15
16helper jwt_encode => sub {
Akron741b2b12017-04-13 22:15:59 +020017 shift;
Akrone5ef4e02017-04-19 17:07:52 +020018 return Mojo::JWT->new(
Akronbc213c02017-04-20 16:45:55 +020019 secret => $secret,
Akron741b2b12017-04-13 22:15:59 +020020 token_type => 'api_token',
Akronbc213c02017-04-20 16:45:55 +020021 expires => time + (3 * 34 * 60 * 60),
Akron741b2b12017-04-13 22:15:59 +020022 claims => { @_ }
23 );
24};
25
Akronbc213c02017-04-20 16:45:55 +020026helper jwt_decode => sub {
27 my ($c, $auth) = @_;
28 $auth =~ s/\s*api_token\s+//;
29 return Mojo::JWT->new(secret => $secret)->decode($auth);
30};
31
Akron741b2b12017-04-13 22:15:59 +020032
33# Base page
Akronbe9d5b32017-04-05 20:48:24 +020034get '/' => sub {
35 shift->render(text => 'Fake server available');
36};
37
Akron741b2b12017-04-13 22:15:59 +020038
Akron3042f242017-04-15 16:57:55 +020039# Search fixtures
40get '/search' => sub {
41 my $c = shift;
42 my $v = $c->validation;
43 $v->optional('q');
44 $v->optional('page');
45 $v->optional('ql');
46 $v->optional('count');
47 $v->optional('context');
48
Akron089ae2c2017-04-17 17:59:23 +020049 # Check for Baum
50 my $response = {
51 "\@context" => "http://korap.ids-mannheim.de/ns/KoralQuery/v0.3/context.jsonld",
52 "meta" => {
53 "count" => 25,
54 "startIndex" => 0,
Akronbc213c02017-04-20 16:45:55 +020055 "authorized" => undef,
Akron089ae2c2017-04-17 17:59:23 +020056 "timeout" => 120000,
57 "context" => {
58 "left" => ["token",40],
59 "right" => ["token",40]
Akron3042f242017-04-15 16:57:55 +020060 },
Akron089ae2c2017-04-17 17:59:23 +020061 "fields" => ["pubDate","subTitle","author","pubPlace","title","textSigle","UID","ID","layerInfos","corpusSigle","docSigle","corpusID","textClass"],
62 "version" => "0.55.7",
63 "benchmark" => "0.120577834 s",
64 "totalResults" => 51,
65 "serialQuery" => "tokens:s:Baum",
66 "itemsPerPage" => 25
67 },
68 "query" => {
69 "\@type" => "koral:token",
70 "wrap" => {
71 "\@type" => "koral:term",
72 "layer" => "orth",
73 "key" => "Baum",
74 "match" => "match:eq",
75 "foundry" => "opennlp",
76 "rewrites" => [
77 {
Akron3042f242017-04-15 16:57:55 +020078 "\@type" => "koral:rewrite",
79 "src" => "Kustvakt",
80 "operation" => "operation:injection",
81 "scope" => "foundry"
82 }
Akron089ae2c2017-04-17 17:59:23 +020083 ]
84 }
85 },
86 "matches" => [
87 {
88 "field" => "tokens",
89 "pubPlace" => "München",
90 "textSigle" => "GOE/AGI/00000",
91 "docSigle" => "GOE/AGI",
92 "corpusSigle" => "GOE",
93 "title" => "Italienische Reise",
94 "subTitle" => "Auch ich in Arkadien!",
95 "author" => "Goethe, Johann Wolfgang von",
96 "layerInfos" => "base/s=spans corenlp/c=spans corenlp/p=tokens corenlp/s=spans dereko/s=spans malt/d=rels mdp/d=rels opennlp/p=tokens opennlp/s=spans tt/l=tokens tt/p=tokens tt/s=spans",
97 "startMore" => true,
98 "endMore" => true,
99 "snippet" => "<span class=\"context-left\"><span class=\"more\"></span>sie etwas bedeuten zu wollen und machte mit der Oberlippe eine fatale Miene. ich sprach sehr viel mit ihr durch, sie war überall zu Hause und merkte gut auf die Gegenstände. so fragte sie mich einmal, was das für ein </span><span class=\"match\"><mark>Baum</mark></span><span class=\"context-right\"> sei. es war ein schöner großer Ahorn, der erste, der mir auf der ganzen Reise zu Gesichte kam. den hatte sie doch gleich bemerkt und freute sich, da mehrere nach und nach erschienen, daß sie auch diesen Baum unterscheiden könne<span class=\"more\"></span></span>",
100 "matchID" => "match-GOE/AGI/00000-p2030-2031",
101 "UID" => 0,
102 "pubDate" => "1982"
Akron3042f242017-04-15 16:57:55 +0200103 },
Akron089ae2c2017-04-17 17:59:23 +0200104 {
105 "field" => "tokens",
106 "pubPlace" => "München",
107 "textSigle" => "GOE/AGI/00000",
108 "docSigle" => "GOE/AGI",
109 "corpusSigle" => "GOE",
110 "title" => "Italienische Reise",
111 "subTitle" => "Auch ich in Arkadien!",
112 "author" => "Goethe, Johann Wolfgang von",
113 "layerInfos" => "base/s=spans corenlp/c=spans corenlp/p=tokens corenlp/s=spans dereko/s=spans malt/d=rels mdp/d=rels opennlp/p=tokens opennlp/s=spans tt/l=tokens tt/p=tokens tt/s=spans",
114 "startMore" => true,
115 "endMore" => true,
116 "snippet" => "<span class=\"context-left\"><span class=\"more\"></span>für ein Baum sei. es war ein schöner großer Ahorn, der erste, der mir auf der ganzen Reise zu Gesichte kam. den hatte sie doch gleich bemerkt und freute sich, da mehrere nach und nach erschienen, daß sie auch diesen </span><span class=\"match\"><mark>Baum</mark></span><span class=\"context-right\"> unterscheiden könne. sie gehe, sagte sie, nach Bozen auf die Messe, wo ich doch wahrscheinlich auch hinzöge. wenn sie mich dort anträfe, müsse ich ihr einen Jahrmarkt kaufen, welches ich ihr denn auch versprach. dort wollte sie auch ihre neue<span class=\"more\"></span></span>",
117 "matchID" => "match-GOE/AGI/00000-p2068-2069",
118 "UID" => 0,
119 "pubDate" => "1982"
120 }
121 ]
122 };
123
Akron14a79e62017-04-24 20:16:58 +0200124 # Error responses:
125 if ($v->param('ql') && $v->param('ql') eq 'cosmas3') {
126 return $c->render(json => {
127 errors => [[101,"No entity found for id","test_h"]]
128 });
129 };
Akron089ae2c2017-04-17 17:59:23 +0200130
Akronf44a0a22018-07-05 11:19:49 +0200131 if ($v->param('q')) {
132 if ($v->param('q') eq 'server_fail') {
133 return $c->render(
134 status => 500,
135 inline => 'Oooops'
136 );
137 }
138 elsif ($v->param('q') eq '[orth=das') {
139 return $c->render(
140 status => 400,
141 json => {
142 "meta" => {
143 "count" => 13
144 },
145 "collection" => {
146 '@type' => "koral:docGroup",
147 "operation" => "operation:and",
148 "operands" => [
149 {
150 '@type' => "koral:doc",
151 "match" => "match:eq",
152 "type" => "type:regex",
153 "value" => "CC-BY.*",
154 "key" => "availability"
155 },
156 {
157 "operands" => [
158 {
159 '@type' => "koral:doc",
160 "match" => "match:eq",
161 "value" => "WPD",
162 "key" => "corpusSigle"
163 },
164 {
165 '@type' => "koral:doc",
166 "match" => "match:eq",
167 "value" => "GOE",
168 "key" => "corpusSigle"
169 }
170 ],
171 '@type' => "koral:docGroup",
172 "operation" => "operation:or"
173 }
174 ],
175 "rewrites" => [
176 {
177 '@type' => "koral:rewrite",
178 "src" => "Kustvakt",
179 "operation" => "operation:insertion",
180 "scope" => "availability(FREE)"
181 }
182 ]
183 },
184 '@context' => "http://korap.ids-mannheim.de/ns/koral/0.3/context.jsonld",
185 "errors" => [
186 [302,"Parantheses/brackets unbalanced.",0],
187 [302,"Could not parse query >>> [orth=der <<<."]
188 ]
189 }
190 );
191 }
Akron3fe9fc32018-03-20 13:12:31 +0100192 };
193
Akronbc213c02017-04-20 16:45:55 +0200194 if (my $auth = $c->req->headers->header('Authorization')) {
195 if (my $jwt = $c->jwt_decode($auth)) {
196 $response->{meta}->{authorized} = $jwt->{username} if $jwt->{username};
197 };
198 };
199
Akron089ae2c2017-04-17 17:59:23 +0200200 if ($v->param('page')) {
201 $response->{meta}->{startIndex} = $v->param("startIndex");
202 };
203
204
205 # Simple search fixture
206 return $c->render(
207 json => $response
Akron3042f242017-04-15 16:57:55 +0200208 );
209};
210
211
Akrone5ef4e02017-04-19 17:07:52 +0200212
Akron3042f242017-04-15 16:57:55 +0200213############
214# Auth API #
215############
216
Akron80f731d2017-04-03 20:10:58 +0200217# Request API token
Akronbc213c02017-04-20 16:45:55 +0200218get '/auth/logout' => sub {
219 my $c = shift;
220
221 if (my $auth = $c->req->headers->header('Authorization')) {
222 if (my $jwt = $c->jwt_decode($auth)) {
223 my $user = $jwt->{username} if $jwt->{username};
224
225 $c->app->log->debug('Server-Logout: ' . $user);
226 return $c->render(json => { msg => [[0, 'Fine!']]});
227 };
228 };
229
230 return $c->render(status => 400, json => { error => [[0, 'No!']]});
231};
232
233
234# Request API token
Akron80f731d2017-04-03 20:10:58 +0200235get '/auth/apiToken' => sub {
236 my $c = shift;
237
238 # Get auth header
239 my $auth = $c->req->headers->authorization;
240
241 # Authorization missing or not basic
Akron741b2b12017-04-13 22:15:59 +0200242 if (!$auth || $auth !~ s/\s*Basic\s+//gi) {
Akron80f731d2017-04-03 20:10:58 +0200243 return $c->render(
244 json => {
Akron741b2b12017-04-13 22:15:59 +0200245 error => [[2, 'x']]
Akron80f731d2017-04-03 20:10:58 +0200246 }
247 );
248 };
249
250 # Decode header
251 my ($username, $pwd) = @{b($auth)->b64_decode->split(':')->to_array};
252
Akron741b2b12017-04-13 22:15:59 +0200253 # the password is 'pass'
254 if ($pwd) {
255
256 # the password is 'pass'
257 if ($pwd eq 'pass') {
258
259 # Render info with token
Akronbc213c02017-04-20 16:45:55 +0200260 my $jwt = $c->jwt_encode(username => $username);
Akrone5ef4e02017-04-19 17:07:52 +0200261
262 # Render in the Kustvakt fashion:
263 return $c->render(
264 format => 'html',
265 text => encode_json({
266 %{$jwt->claims},
267 expires => $jwt->expires,
268 token => $jwt->encode,
269 token_type => 'api_token'
270 })
271 );
Akron741b2b12017-04-13 22:15:59 +0200272 };
273
Akron80f731d2017-04-03 20:10:58 +0200274 return $c->render(
275 json => {
Akronbc213c02017-04-20 16:45:55 +0200276 error => [[2004, undef]]
Akron80f731d2017-04-03 20:10:58 +0200277 }
278 );
279 };
280
281 return $c->render(
282 json => {
Akronbc213c02017-04-20 16:45:55 +0200283 error => [[2004, undef]]
Akron80f731d2017-04-03 20:10:58 +0200284 }
285 );
286};
287
288app->start;
Akron46b9f212017-05-01 13:55:17 +0200289
290
291__END__
292
293
294 # Temporary:
295 my $collection_query = {
296 '@type' => "koral:docGroup",
297 "operation" => "operation:or",
298 "operands" => [
299 {
300 '@type' => "koral:docGroup",
301 "operation" => "operation:and",
302 "operands" => [
303 {
304 '@type' => "koral:doc",
305 "key" => "title",
306 "match" => "match:eq",
307 "value" => "Der Birnbaum",
308 "type" => "type:string"
309 },
310 {
311 '@type' => "koral:doc",
312 "key" => "pubPlace",
313 "match" => "match:eq",
314 "value" => "Mannheim",
315 "type" => "type:string"
316 },
317 {
318 '@type' => "koral:docGroup",
319 "operation" => "operation:or",
320 "operands" => [
321 {
322 '@type' => "koral:doc",
323 "key" => "subTitle",
324 "match" => "match:eq",
325 "value" => "Aufzucht oder Pflege",
326 "type" => "type:string"
327 },
328 {
329 '@type' => "koral:doc",
330 "key" => "subTitle",
331 "match" => "match:eq",
332 "value" => "Gedichte",
333 "type" => "type:string"
334 }
335 ]
336 }
337 ]
338 },
339 {
340 '@type' => "koral:doc",
341 "key" => "pubDate",
342 "match" => "match:geq",
343 "value" => "2015-03-05",
344 "type" => "type:date"
345 }
346 ]
347 };