File Coverage

blib/lib/Net/OATH/Server/Lite/Endpoint/User.pm
Criterion Covered Total %
statement 100 106 94.3
branch 58 72 80.5
condition 9 15 60.0
subroutine 18 19 94.7
pod 0 5 0.0
total 185 217 85.2


line stmt bran cond sub pod time code
1             package Net::OATH::Server::Lite::Endpoint::User;
2 2     2   6050 use strict;
  2         2  
  2         79  
3 2     2   8 use warnings;
  2         2  
  2         75  
4             use overload
5 20     20   75681 q(&{}) => sub { shift->psgi_app },
6 2     2   14 fallback => 1;
  2         2  
  2         14  
7              
8 2     2   118 use Try::Tiny qw/try catch/;
  2         2  
  2         96  
9 2     2   451 use Plack::Request;
  2         46774  
  2         37  
10 2     2   12 use Params::Validate;
  2         2  
  2         88  
11 2     2   8 use JSON::XS qw/decode_json encode_json/;
  2         2  
  2         82  
12 2     2   807 use Convert::Base32 qw/encode_base32/;
  2         2012  
  2         119  
13              
14 2     2   415 use Net::OATH::Server::Lite::Error;
  2         4  
  2         17  
15              
16             sub new {
17 2     2 0 4291 my $class = shift;
18 2         77 my %args = Params::Validate::validate(@_, {
19             data_handler => 1,
20             });
21 2         15 my $self = bless {
22             data_handler => $args{data_handler},
23             }, $class;
24 2         9 return $self;
25             }
26              
27             sub data_handler {
28 0     0 0 0 my ($self, $handler) = @_;
29 0 0       0 $self->{data_handler} = $handler if $handler;
30 0         0 $self->{data_handler};
31             }
32              
33             sub psgi_app {
34 20     20 0 29 my $self = shift;
35 20   66     109 return $self->{psgi_app}
36             ||= $self->compile_psgi_app;
37             }
38              
39             sub compile_psgi_app {
40 2     2 0 4 my $self = shift;
41              
42             my $app = sub {
43 20     20   25 my $env = shift;
44 20         108 my $req = Plack::Request->new($env);
45 20         146 my $res; try {
46 20         532 $res = $self->handle_request($req);
47             } catch {
48             # Internal Server Error
49 0         0 warn $_;
50 0         0 $res = $req->new_response(500);
51 20         121 };
52 20         5341 return $res->finalize;
53 2         13 };
54              
55 2         12 return $app;
56             }
57              
58             sub handle_request {
59 20     20 0 26 my ($self, $request) = @_;
60              
61             my $res = try {
62 20     20   454 my $code = 200;
63              
64 20         127 my $data_handler = $self->{data_handler}->new(request => $request);
65 20 100 66     183 Net::OATH::Server::Lite::Error->throw(
66             code => 500,
67             error => q{server_error},
68             ) unless ($data_handler && $data_handler->isa(q{Net::OATH::Server::Lite::DataHandler}));
69              
70             # HTTP method MUST be POST
71 19 50       56 Net::OATH::Server::Lite::Error->throw() unless ($request->method eq q{POST});
72              
73             # content MUST be JSON
74 19         130 my $content = {};
75 19         20 eval {
76 19 50       50 $content = decode_json($request->content) if $request->content;
77             };
78 19 100       14090 Net::OATH::Server::Lite::Error->throw() if $@;
79              
80 18 100 100     186 unless (defined $content->{method} &&
      33        
81             ($content->{method} eq q{create} ||
82             $content->{method} eq q{read} ||
83             $content->{method} eq q{update} ||
84             $content->{method} eq q{delete})) {
85 1         9 Net::OATH::Server::Lite::Error->throw(
86             description => q{method not found},
87             );
88             }
89              
90 17         22 my $user;
91 17 100       42 if ($content->{method} eq q{create}) {
92 4 100       11 if ($content->{id}) {
93 1         9 Net::OATH::Server::Lite::Error->throw();
94             } else {
95 3         12 $user = Net::OATH::Server::Lite::Model::User->new(
96             id => $data_handler->create_id(),
97             secret => $data_handler->create_secret(),
98             );
99              
100 3 100       13 $user->type($content->{type}) if $content->{type};
101 3 50       10 $user->algorithm($content->{algorithm}) if $content->{algorithm};
102 3 50       7 $user->digits($content->{digits}) if $content->{digits};
103 3 50       7 $user->counter($content->{counter}) if $content->{counter};
104 3 50       5 $user->period($content->{period}) if $content->{period};
105 3 100       9 Net::OATH::Server::Lite::Error->throw() unless $user->is_valid;
106              
107 2 100       5 unless ($data_handler->insert_user($user)) {
108 1         9 Net::OATH::Server::Lite::Error->throw(
109             code => 500,
110             error => q{server_error},
111             );
112             }
113              
114 1         182 $code = 201;
115             }
116             }
117              
118 14 100       39 if ($content->{method} eq q{read}) {
119 4 100       9 if ($content->{id}) {
120 3 100       13 $user = $data_handler->select_user($content->{id}) or
121             Net::OATH::Server::Lite::Error->throw(
122             code => 404,
123             description => q{invalid id},
124             );
125             } else {
126 1         6 Net::OATH::Server::Lite::Error->throw(
127             description => q{missing id},
128             );
129             }
130             }
131              
132 11 100       142 if ($content->{method} eq q{update}) {
133 5 100       11 if ($content->{id}) {
134 4 100       14 $user = $data_handler->select_user($content->{id}) or
135             Net::OATH::Server::Lite::Error->throw(
136             code => 404,
137             description => q{invalid id},
138             );
139              
140 3 50       321 $user->type($content->{type}) if $content->{type};
141 3 50       28 $user->algorithm($content->{algorithm}) if $content->{algorithm};
142 3 50       7 $user->digits($content->{digits}) if $content->{digits};
143 3 100       12 $user->counter($content->{counter}) if $content->{counter};
144 3 50       11 $user->period($content->{period}) if $content->{period};
145 3 100       32 Net::OATH::Server::Lite::Error->throw() unless $user->is_valid;
146              
147 2 100       8 unless ($data_handler->update_user($user)) {
148 1         10 Net::OATH::Server::Lite::Error->throw(
149             code => 500,
150             error => q{server_error},
151             );
152             }
153             } else {
154 1         11 Net::OATH::Server::Lite::Error->throw(
155             description => q{missing id},
156             );
157             }
158             }
159              
160 7 100       108 if ($content->{method} eq q{delete}) {
161 4 100       8 if ($content->{id}) {
162 3 100       9 $user = $data_handler->select_user($content->{id}) or
163             Net::OATH::Server::Lite::Error->throw(
164             code => 404,
165             description => q{invalid id},
166             );
167              
168 2 100       196 unless ($data_handler->delete_user($user->id)) {
169 1         16 Net::OATH::Server::Lite::Error->throw(
170             code => 500,
171             error => q{server_error},
172             );
173             }
174             } else {
175 1         6 Net::OATH::Server::Lite::Error->throw(
176             description => q{missing id},
177             );
178             }
179             }
180              
181 4 100       73 my $params = ($content->{method} eq q{delete}) ? {} :
182             _create_response_from_user($user);
183              
184 4         933 return $request->new_response($code,
185             [ "Content-Type" => "application/json;charset=UTF-8",
186             "Cache-Control" => "no-store",
187             "Pragma" => "no-cache" ],
188             [ encode_json($params) ]);
189             } catch {
190 16 50   16   193 if ($_->isa("Net::OATH::Server::Lite::Error")) {
191 16         49 my $error_params = {
192             error => $_->error,
193             };
194 16 100       110 $error_params->{error_description} = $_->description if $_->description;
195              
196 16         112 return $request->new_response($_->code,
197             [ "Content-Type" => "application/json;charset=UTF-8",
198             "Cache-Control" => "no-store",
199             "Pragma" => "no-cache" ],
200             [ encode_json($error_params) ]);
201             } else {
202 0         0 die $_;
203             }
204 20         150 };
205             }
206              
207             sub _create_response_from_user {
208 3     3   6 my ($user) = @_;
209 3 50 33     32 return unless ($user && $user->isa(q{Net::OATH::Server::Lite::Model::User}));
210              
211             return {
212 3         13 id => $user->id,
213             secret => encode_base32($user->secret),
214             type => $user->type,
215             algorithm => $user->algorithm,
216             digits => $user->digits,
217             counter => $user->counter,
218             period => $user->period,
219             };
220             }
221              
222             1;