blob: 89ad3c3d833f6e91bace9abc6445b799af14660d [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';
Akron6d49c1f2018-10-11 14:22:21 +020015my $fixture_path = path(Mojo::File->new(__FILE__)->dirname);
Akron0e1ed242018-10-11 13:22:00 +020016
17helper jwt_encode => sub {
18 shift;
19 return Mojo::JWT->new(
20 secret => $secret,
21 token_type => 'api_token',
22 expires => time + (3 * 34 * 60 * 60),
23 claims => { @_ }
24 );
25};
26
27helper jwt_decode => sub {
28 my ($c, $auth) = @_;
29 $auth =~ s/\s*api_token\s+//;
30 return Mojo::JWT->new(secret => $secret)->decode($auth);
31};
32
33
Akron6d49c1f2018-10-11 14:22:21 +020034# Load fixture responses
35helper 'load_response' => sub {
36 my $c = shift;
37 my $q_name = shift;
38 my $file = $fixture_path->child("response_$q_name.json");
39 unless (-f $file) {
40 return {
41 status => 500,
42 json => {
43 errors => [[0, 'Unable to load query response from ' . $file]]
44 }
45 }
46 };
47 my $response = $file->slurp;
48 return decode_json($response);
49};
50
51
Akron0e1ed242018-10-11 13:22:00 +020052# Base page
53get '/' => sub {
Akron6d49c1f2018-10-11 14:22:21 +020054 shift->render(text => 'Fake server available');
Akron0e1ed242018-10-11 13:22:00 +020055};
56
Akron32396632018-10-11 17:08:37 +020057
Akron0e1ed242018-10-11 13:22:00 +020058# Search fixtures
59get '/search' => sub {
60 my $c = shift;
61 my $v = $c->validation;
62 $v->optional('q');
63 $v->optional('page');
64 $v->optional('ql');
65 $v->optional('count');
66 $v->optional('context');
67
Akron32396632018-10-11 17:08:37 +020068 $c->app->log->debug('Receive request');
69
Akron0e1ed242018-10-11 13:22:00 +020070 # Response q=x&ql=cosmas3
71 if ($v->param('ql') && $v->param('ql') eq 'cosmas3') {
72 return $c->render(
73 status => 400,
74 json => {
75 "\@context" => "http://korap.ids-mannheim.de/ns/koral/0.3/context.jsonld",
76 "errors" => [[307,"cosmas3 is not a supported query language!"]]
77 });
78 };
79
Akron6d49c1f2018-10-11 14:22:21 +020080 if (!$v->param('q')) {
81 return $c->render(%{$c->load_response('no_query')});
Akron0e1ed242018-10-11 13:22:00 +020082 };
83
Akron6d49c1f2018-10-11 14:22:21 +020084 # Get response based on query parameter
85 my $response = $c->load_response(slugify($v->param('q')));
Akron0e1ed242018-10-11 13:22:00 +020086
87 # Check authentification
88 if (my $auth = $c->req->headers->header('Authorization')) {
89 if (my $jwt = $c->jwt_decode($auth)) {
Akron6d49c1f2018-10-11 14:22:21 +020090 $response->{json}->{meta}->{authorized} = $jwt->{username} if $jwt->{username};
Akron0e1ed242018-10-11 13:22:00 +020091 };
92 };
93
Akron6d49c1f2018-10-11 14:22:21 +020094 # Set page parameter
Akron0e1ed242018-10-11 13:22:00 +020095 if ($v->param('page')) {
Akron6d49c1f2018-10-11 14:22:21 +020096 $response->{json}->{meta}->{startIndex} = $v->param("startIndex");
Akron0e1ed242018-10-11 13:22:00 +020097 };
98
Akron0e1ed242018-10-11 13:22:00 +020099 # Simple search fixture
Akron32396632018-10-11 17:08:37 +0200100 $c->render(%$response);
101
102 $c->app->log->debug('Rendered result');
103
104 return 1;
Akron0e1ed242018-10-11 13:22:00 +0200105};
106
107
Akronb80341d2018-10-15 19:46:23 +0200108# Matchinfo fixtures
109get '/corpus/:corpusId/:docId/:textId/:matchId/matchInfo' => sub {
110 my $c = shift;
111
112 my $file = join('_', (
113 'matchinfo',
114 $c->stash('corpusId'),
115 $c->stash('docId'),
116 $c->stash('textId'),
117 $c->stash('matchId')
118 ));
119
Akronb8d0b402018-10-18 23:51:52 +0200120 my $slug = slugify($file);
121
Akronb80341d2018-10-15 19:46:23 +0200122 # Get response based on query parameter
Akronb8d0b402018-10-18 23:51:52 +0200123 my $response = $c->load_response($slug);
Akronb80341d2018-10-15 19:46:23 +0200124 return $c->render(%$response);
125};
126
Akron0e1ed242018-10-11 13:22:00 +0200127
Akronbe61f4c2018-10-20 00:52:58 +0200128# Statistics endpoint
129get '/statistics' => sub {
130 my $c = shift;
131 my $v = $c->validation;
132 $v->optional('corpusQuery');
133
134 my @list = 'corpusinfo';
135 if ($v->param('corpusQuery')) {
136 push @list, $v->param('corpusQuery');
137 };
138 my $slug = slugify(join('_', @list));
139
140 # Get response based on query parameter
141 my $response = $c->load_response($slug);
142 return $c->render(%$response);
143};
144
Akron0e1ed242018-10-11 13:22:00 +0200145############
146# Auth API #
147############
148
149# Request API token
150get '/auth/logout' => sub {
151 my $c = shift;
152
153 if (my $auth = $c->req->headers->header('Authorization')) {
154 if (my $jwt = $c->jwt_decode($auth)) {
155 my $user = $jwt->{username} if $jwt->{username};
156
157 $c->app->log->debug('Server-Logout: ' . $user);
158 return $c->render(json => { msg => [[0, 'Fine!']]});
159 };
160 };
161
162 return $c->render(status => 400, json => { error => [[0, 'No!']]});
163};
164
165
166# Request API token
167get '/auth/apiToken' => sub {
168 my $c = shift;
169
170 # Get auth header
171 my $auth = $c->req->headers->authorization;
172
173 # Authorization missing or not basic
174 if (!$auth || $auth !~ s/\s*Basic\s+//gi) {
175 return $c->render(
176 json => {
177 error => [[2, 'x']]
178 }
179 );
180 };
181
182 # Decode header
183 my ($username, $pwd) = @{b($auth)->b64_decode->split(':')->to_array};
184
185 # the password is 'pass'
186 if ($pwd) {
187
188 # the password is 'pass'
189 if ($pwd eq 'pass') {
190
191 # Render info with token
192 my $jwt = $c->jwt_encode(username => $username);
193
194 # Render in the Kustvakt fashion:
195 return $c->render(
196 format => 'html',
197 text => encode_json({
198 %{$jwt->claims},
199 expires => $jwt->expires,
200 token => $jwt->encode,
201 token_type => 'api_token'
202 })
203 );
204 };
205
206 return $c->render(
207 json => {
208 error => [[2004, undef]]
209 }
210 );
211 };
212
213 return $c->render(
214 json => {
215 error => [[2004, undef]]
216 }
217 );
218};
219
220app->start;
221
222
223__END__
224
225
226 # Temporary:
227 my $collection_query = {
228 '@type' => "koral:docGroup",
229 "operation" => "operation:or",
230 "operands" => [
231 {
232 '@type' => "koral:docGroup",
233 "operation" => "operation:and",
234 "operands" => [
235 {
236 '@type' => "koral:doc",
237 "key" => "title",
238 "match" => "match:eq",
239 "value" => "Der Birnbaum",
240 "type" => "type:string"
241 },
242 {
243 '@type' => "koral:doc",
244 "key" => "pubPlace",
245 "match" => "match:eq",
246 "value" => "Mannheim",
247 "type" => "type:string"
248 },
249 {
250 '@type' => "koral:docGroup",
251 "operation" => "operation:or",
252 "operands" => [
253 {
254 '@type' => "koral:doc",
255 "key" => "subTitle",
256 "match" => "match:eq",
257 "value" => "Aufzucht oder Pflege",
258 "type" => "type:string"
259 },
260 {
261 '@type' => "koral:doc",
262 "key" => "subTitle",
263 "match" => "match:eq",
264 "value" => "Gedichte",
265 "type" => "type:string"
266 }
267 ]
268 }
269 ]
270 },
271 {
272 '@type' => "koral:doc",
273 "key" => "pubDate",
274 "match" => "match:geq",
275 "value" => "2015-03-05",
276 "type" => "type:date"
277 }
278 ]
279 };