File Coverage

blib/lib/XAS/Service/Resource.pm
Criterion Covered Total %
statement 24 193 12.4
branch 0 34 0.0
condition 0 7 0.0
subroutine 8 40 20.0
pod 29 31 93.5
total 61 305 20.0


line stmt bran cond sub pod time code
1             package XAS::Service::Resource;
2              
3 1     1   1658 use strict;
  1         2  
  1         25  
4 1     1   3 use warnings;
  1         1  
  1         18  
5              
6 1     1   4 use XAS::Factory;
  1         1  
  1         9  
7 1     1   48 use Data::Dumper;
  1         0  
  1         34  
8 1     1   425 use Hash::MultiValue;
  1         1577  
  1         24  
9 1     1   6 use parent 'Web::Machine::Resource';
  1         1  
  1         6  
10 1     1   1539 use Web::Machine::Util 'create_header';
  1         5644  
  1         19  
11              
12             # -------------------------------------------------------------------------
13             # Web::Machine::Resource overrides
14             # ------------------------------------------------------------------------
15              
16             sub init {
17 0     0 1   my $self = shift;
18 0           my $args = shift;
19              
20             $self->{'tt'} = exists $args->{'template'}
21 0 0         ? $args->{'template'}
22             : undef;
23              
24             $self->{'json'} = exists $args->{'json'}
25 0 0         ? $args->{'json'}
26             : undef;
27              
28             $self->{'app_name'} = exists $args->{'app_name'}
29 0 0         ? $args->{'app_name'}
30             : 'Test App';
31              
32             $self->{'app_description'} = exists $args->{'app_description'}
33 0 0         ? $args->{'app_description'}
34             : 'Testing Testing 1 2 3';
35              
36             $self->{'alias'} = exists $args->{'alias'}
37 0 0         ? $args->{'alias'}
38             : 'resource';
39              
40 0           $self->errcode(0);
41 0           $self->errstr('');
42              
43 0           $self->{'env'} = XAS::Factory->module('environment');
44 0           $self->{'log'} = XAS::Factory->module('logger');
45              
46             }
47              
48             sub is_authorized {
49 0     0 1   my $self = shift;
50 0           my $auth = shift;
51              
52 0           my $stat = 0;
53              
54 0 0         if ($auth) {
55              
56 0           warn "is_authorized - override this please\n";
57 0           warn sprintf("username: %s, password: %s\n", $auth->username, $auth->password);
58              
59 0           $stat = 1;
60              
61 0           return $stat;
62              
63             }
64              
65 0           return create_header('WWWAuthenticate' => [ 'Basic' => ( realm => 'XAS Rest' ) ] );
66              
67             }
68              
69             sub options {
70 0     0 1   my $self = shift;
71              
72 0           my $options;
73             my @accepted;
74 0           my @provided;
75 0           my $allowed = $self->allowed_methods;
76              
77 0           foreach my $hash (@{$self->content_types_accepted}) {
  0            
78              
79 0           my ($key) = keys %$hash;
80 0           push(@accepted, $key);
81              
82             }
83              
84 0           foreach my $hash (@{$self->content_types_provided}) {
  0            
85              
86 0           my ($key) = keys %$hash;
87 0           push(@provided, $key);
88              
89             }
90              
91 0           $options->{'allow'} = join(',', @$allowed);
92 0           $options->{'accepted'} = join(',', @accepted);
93 0           $options->{'provides'} = join(',', @provided);
94              
95 0           return $options;
96              
97             }
98              
99 0     0 1   sub allowed_methods { [qw[ OPTIONS GET HEAD ]] }
100              
101             sub post_is_create {
102              
103             # uses "content_types_accepted" methods for procssing
104              
105 0     0 1   return 1;
106              
107             }
108              
109             sub content_types_accepted {
110              
111             return [
112 0     0 1   { 'application/json' => 'from_json' },
113             { 'application/x-www-form-urlencoded' => 'from_html' },
114             ];
115              
116             }
117              
118             sub content_types_provided {
119              
120             return [
121 0     0 1   { 'text/html' => 'to_html' },
122             { 'application/hal+json' => 'to_json' },
123             ];
124              
125             }
126              
127 0     0 1   sub charset_provided { return ['UTF-8']; }
128              
129             sub finish_request {
130 0     0 1   my $self = shift;
131 0           my $metadata = shift;
132              
133 0           my $alias = $self->alias;
134 0   0       my $user = $self->request->user || 'unknown';
135 0           my $uri = $self->request->uri;
136 0           my $method = $self->request->method;
137 0           my $code = $self->response->code;
138 0           my $path = $uri->path;
139              
140             my $fixup = sub {
141 0     0     my $status = shift;
142 0           my $format = shift;
143 0           my $data = shift;
144              
145 0           my $output;
146              
147 0 0         if ($format eq 'json') {
148              
149 0           $output = $self->format_json($data);
150 0           $self->response->content_type('application/hal+json');
151              
152             } else {
153              
154 0           $output = $self->format_html($data);
155 0           $self->response->content_type('text/html');
156              
157             }
158              
159 0           $self->response->body($output);
160 0           $self->response->header('Location' => $uri->path);
161 0           $self->response->status($status);
162              
163             {
164 1     1   594 use bytes;
  1         1  
  1         5  
  0            
165 0           $self->response->header('Content-Length' => length($output));
166             }
167              
168 0           };
169              
170 0           $self->log->info(
171             sprintf('%s: %s requested a %s for %s with a status of %s',
172             $alias, $user, $method, $path, $code)
173             );
174              
175 0 0         if (defined($metadata->{'exception'})) {
    0          
176              
177 0           my $data;
178 0           my $ex = $metadata->{'exception'};
179 0           my $ref = ref($metadata->{'exception'});
180 0   0       my $status = $self->errcode || 403;
181 0           my $type = $self->request->header('accept');
182 0 0         my $format = ($type =~ /json/) ? 'json' : 'html';
183              
184 0           $data->{'_links'} = $self->get_links();
185 0           $data->{'navigation'} = $self->get_navigation();
186              
187 0 0 0       if (($ref eq 'XAS::Exception') or ($ref eq 'Badger::Exception')) {
188              
189 0           $data->{'_embedded'}->{'errors'} = [{
190             title => $self->errstr,
191             status => $status,
192             code => $ex->type,
193             detail => $ex->info
194             }];
195              
196             } else {
197              
198 0           $data->{'_embedded'}->{'errors'} = [{
199             title => $self->errstr,
200             status => $status,
201             code => 'unknown error',
202             detail => sprintf('%s', $ex)
203             }];
204              
205             }
206              
207 0           $fixup->($status, $format, $data);
208              
209             } elsif ($self->response->status >= 400) {
210              
211 0           my $data;
212 0           my $body = join('
', @{$self->response->body});
  0            
213 0 0         my $code = ($self->response->status >= 500) ? 'http internal server error' : 'http client error';
214 0           my $status = $self->response->status;
215 0           my $type = $self->request->header('accept');
216 0 0         my $format = ($type =~ /json/) ? 'json' : 'html';
217              
218 0           $data->{'_links'} = $self->get_links();
219 0           $data->{'navigation'} = $self->get_navigation();
220              
221 0           $data->{'_embedded'}->{'errors'} = [{
222             title => sprintf('HTTP Error: %s', $self->response->status),
223             status => $self->response->status,
224             code => $code,
225             detail => $body,
226             }];
227              
228 0           $fixup->($status, $format, $data);
229              
230             }
231              
232             }
233              
234             # -------------------------------------------------------------------------
235             # methods
236             # -------------------------------------------------------------------------
237              
238             sub process_exception {
239 0     0 0   my $self = shift;
240 0           my $title = shift;
241 0           my $status = shift;
242              
243 0           $self->{'errcode'} = $$status;
244 0           $self->{'errstr'} = $title;
245              
246             }
247              
248             sub process_params {
249 0     0 1   my $self = shift;
250 0           my $params = shift;
251              
252 0           return 1;
253              
254             }
255              
256             sub get_navigation {
257 0     0 1   my $self = shift;
258              
259             return [{
260 0           link => '/',
261             text => 'Root',
262             }];
263              
264             }
265              
266             sub get_links {
267 0     0 1   my $self = shift;
268              
269             return {
270 0           self => {
271             title => 'Root',
272             href => '/',
273             },
274             };
275              
276             }
277              
278             sub get_response {
279 0     0 1   my $self = shift;
280              
281 0           my $data;
282              
283 0           $data->{'_links'} = $self->get_links();
284 0           $data->{'navigation'} = $self->get_navigation();
285              
286 0           return $data;
287              
288             }
289              
290             sub json_to_multivalue {
291 0     0 1   my $self = shift;
292 0           my $json = shift;
293              
294 0           my $decoded = $self->json->decode($json);
295 0           my $params = Hash::MultiValue->new();
296              
297 0           while (my ($key, $value) = each(%$decoded)) {
298              
299 0           $params->add($key, $value);
300              
301             }
302              
303 0           return $params;
304              
305             }
306              
307             sub from_json {
308 0     0 1   my $self = shift;
309              
310             # get the post parameters
311              
312 0           my $content = $self->request->content;
313 0           my $params = $self->json_to_multivalue($content);
314              
315 0           return $self->process_params($params);
316              
317             }
318              
319             sub from_html {
320 0     0 1   my $self = shift;
321              
322             # get the post parameters
323              
324 0           my $params = $self->request->parameters;
325              
326 0           return $self->process_params($params);
327              
328             }
329              
330             sub to_json {
331 0     0 1   my $self = shift;
332              
333 0           my $data = $self->get_response();
334 0           my $json = $self->format_json($data);
335              
336 0           return $json;
337              
338             }
339              
340             sub to_html {
341 0     0 1   my $self = shift;
342              
343 0           my $data = $self->get_response();
344 0           my $html = $self->format_html($data);
345              
346 0           return $html;
347              
348             }
349              
350             sub format_json {
351 0     0 1   my $self = shift;
352 0           my $data = shift;
353              
354 0           delete $data->{'navigation'};
355              
356 0           return $self->json->encode($data);
357              
358             }
359              
360             sub format_html {
361 0     0 1   my $self = shift;
362 0           my $data = shift;
363              
364 0           my $html;
365 0           my $view = {
366             view => {
367             title => $self->app_name,
368             description => $self->app_description,
369             template => 'dispatcher.tt',
370             data => $data,
371             }
372             };
373              
374 0           $self->tt->process('wrapper.tt', $view, \$html);
375              
376 0           return $html;
377              
378             }
379              
380             sub format_body {
381 0     0 0   my $self = shift;
382 0           my $data = shift;
383              
384 0           my $body;
385 0           my $type = $self->request->header('accept');
386 0 0         my $format = ($type =~ /json/) ? 'json' : 'html';;
387              
388 0 0         if ($format eq 'json') {
389              
390 0           $body = $self->format_json($data);
391              
392             } else {
393              
394 0           $body = $self->format_html($data);
395              
396             }
397              
398 0           return $body;
399              
400             }
401              
402             # -------------------------------------------------------------------------
403             # accessors
404             # -------------------------------------------------------------------------
405              
406             sub app_name {
407 0     0 1   my $self = shift;
408              
409 0           return $self->{'app_name'};
410              
411             }
412              
413             sub app_description {
414 0     0 1   my $self = shift;
415              
416 0           return $self->{'app_description'};
417              
418             }
419              
420             sub json {
421 0     0 1   my $self = shift;
422              
423 0           return $self->{'json'};
424              
425             }
426              
427             sub tt {
428 0     0 1   my $self = shift;
429              
430 0           return $self->{'tt'};
431              
432             }
433              
434             sub env {
435 0     0 1   my $self = shift;
436              
437 0           return $self->{'env'};
438              
439             }
440              
441             sub log {
442 0     0 1   my $self = shift;
443              
444 0           return $self->{'log'};
445              
446             }
447              
448             sub alias {
449 0     0 1   my $self = shift;
450              
451 0           return $self->{'alias'};
452              
453             }
454              
455             # -------------------------------------------------------------------------
456             # mutators
457             # -------------------------------------------------------------------------
458              
459             sub errcode {
460 0     0 1   my $self = shift;
461 0           my $code = shift;
462              
463 0 0         $self->{'errcode'} = $code if (defined($code));
464              
465 0           return $self->{'errcode'};
466              
467             }
468              
469             sub errstr {
470 0     0 1   my $self = shift;
471 0           my $string = shift;
472              
473 0 0         $self->{'errstr'} = $string if (defined($string));
474              
475 0           return $self->{'errstr'};
476              
477             }
478              
479             1;
480              
481             __END__