File Coverage

blib/lib/Convos/Controller/User.pm
Criterion Covered Total %
statement 30 118 25.4
branch 7 38 18.4
condition 2 13 15.3
subroutine 7 27 25.9
pod 7 7 100.0
total 53 203 26.1


line stmt bran cond sub pod time code
1             package Convos::Controller::User;
2              
3             =head1 NAME
4              
5             Convos::Controller::User - Mojolicious controller for user data
6              
7             =cut
8              
9 2     2   8676 use Mojo::Base 'Mojolicious::Controller';
  2         4  
  2         13  
10 2     2   359 use Convos::Core::Util qw/ as_id id_as /;
  2         4  
  2         139  
11 2     2   9 use Mojo::Asset::File;
  2         3  
  2         17  
12 2     2   41 use Mojo::Date;
  2         2  
  2         12  
13 2 50   2   59 use constant DEBUG => $ENV{CONVOS_DEBUG} ? 1 : 0;
  2         4  
  2         3450  
14              
15             =head1 METHODS
16              
17             =head2 auth
18              
19             Check authentication and login
20              
21             =cut
22              
23             sub auth {
24 0     0 1 0 my $self = shift;
25              
26 0 0       0 if ($self->session('login')) {
    0          
27 0         0 return 1;
28             }
29             elsif ($self->req->url->path =~ /\.json$/) {
30 0         0 $self->render(json => {}, status => 403);
31             }
32             else {
33 0         0 $self->redirect_to('index');
34             }
35              
36 0         0 return 0;
37             }
38              
39             =head2 delete
40              
41             Render a delete user confirmation page on GET and deletes the logged in
42             user on POST.
43              
44             =cut
45              
46             sub delete {
47 0     0 1 0 my $self = shift;
48              
49 0 0       0 if ($self->req->method ne 'POST') {
50 0         0 return $self->render(layout => 'tactile');
51             }
52              
53             $self->delay(
54             sub {
55 0     0   0 my ($delay) = @_;
56 0         0 $self->app->core->delete_user({login => $self->session('login')}, $delay->begin);
57             },
58             sub {
59 0     0   0 my ($delay, $err) = @_;
60 0         0 $self->logout;
61             },
62 0         0 );
63             }
64              
65             =head2 login
66              
67             Show the login form. Also responds to JSON requests with login status.
68              
69             =cut
70              
71             sub login {
72 3     3 1 4415 my $self = shift;
73              
74 3 50       72 unless ($self->app->config->{redis_version}) {
75             return $self->delay(
76             sub {
77 0     0   0 my ($delay) = @_;
78 0         0 $self->redis->info(server => $delay->begin);
79             },
80             sub {
81 0     0   0 my ($delay, $server_info) = @_;
82 0         0 my $app = $self->app;
83 0 0       0 $app->config->{redis_version} = $server_info =~ /redis_version:(\d+\.\d+)/ ? $1 : '0e0';
84 0         0 $app->log->info("Redis server version: @{[$app->config->{redis_version}]}");
  0         0  
85 0         0 $self->login;
86             },
87 0         0 );
88             }
89              
90 3         57 $self->stash(form => 'login');
91              
92 3 50       51 if ($self->session('login')) {
93 0         0 $self->logf(debug => '[reg] Already logged in') if DEBUG;
94 0         0 return $self->redirect_to('view');
95             }
96 3 50       55 if ($self->req->method ne 'POST') {
97 3   50     195 return $self->respond_to(html => {template => 'index'}, json => {json => {login => $self->session('login') || ''}});
98             }
99              
100             $self->delay(
101             sub {
102 0     0   0 my ($delay) = @_;
103 0         0 $self->app->core->login($self->validation, $delay->begin);
104             },
105             sub {
106 0     0   0 my ($delay, $error) = @_;
107 0 0       0 return $self->render('index', status => 401) if $error;
108 0         0 my $login = $self->validation->param('login');
109 0         0 $self->session(login => $login);
110 0         0 $self->respond_to(html => sub { $self->redirect_last($login) }, json => {json => {login => $login}});
  0         0  
111             },
112 0         0 );
113             }
114              
115             =head2 register
116              
117             See L.
118              
119             =cut
120              
121             sub register {
122 1     1 1 3232 my $self = shift;
123 1         15 my $validation = $self->validation;
124 1         227 my $invite_code = $ENV{CONVOS_INVITE_CODE};
125 1         2 my ($output);
126              
127 1 50       3 if ($self->session('login')) {
128 0         0 $self->logf(debug => '[reg] Already logged in') if DEBUG;
129 0         0 return $self->redirect_to('view');
130             }
131              
132 1         16 $self->stash(form => 'register');
133              
134 1 50 0     15 if ($invite_code and $invite_code ne ($self->param('invite') || '')) {
      33        
135 0         0 return $self->render('index', form => 'invite_only', status => 400);
136             }
137 1 50       8 if ($self->req->method ne 'POST') {
138 1         62 return $self->render('index');
139             }
140              
141 0           $validation->required('login')->like(qr/^\w+$/)->size(3, 15);
142 0           $validation->required('email')->like(qr/.\@./);
143 0           $validation->required('password_again')->equal_to('password');
144 0           $validation->required('password')->size(5, 255);
145 0           $output = $validation->output;
146 0   0       $output->{login} = lc($output->{login} || '');
147              
148             $self->delay(
149             sub {
150 0     0     my $delay = shift;
151 0           $self->redis->sismember('users', $output->{login}, $delay->begin);
152 0           $self->redis->scard('users', $delay->begin);
153             },
154             sub { # Check invitation unless first user
155 0     0     my ($delay, $exists) = @_;
156              
157 0 0         $validation->error(login => ['taken']) if $exists;
158 0 0         return $self->render('index', status => 400) if $validation->has_error;
159              
160 0           $self->logf(debug => '[reg] New user login=%s', $output->{login}) if DEBUG;
161 0           $self->session(login => $output->{login});
162 0           $self->redis->hmset(
163             "user:$output->{login}" =>
164             {digest => $self->_digest($output->{password}), email => $output->{email}, avatar => $output->{email}},
165             $delay->begin
166             );
167 0           $self->redis->sadd(users => $output->{login}, $delay->begin);
168             },
169             sub {
170 0     0     my ($delay, @saved) = @_;
171 0           $self->redirect_to('wizard');
172             }
173 0           );
174             }
175              
176             =head2 logout
177              
178             Will delete data from session.
179              
180             =cut
181              
182             sub logout {
183 0     0 1   my $self = shift;
184 0           $self->session(login => undef);
185 0           $self->redirect_to('index');
186             }
187              
188             =head2 edit
189              
190             Change user profile.
191              
192             =cut
193              
194             sub edit {
195 0     0 1   my $self = shift;
196 0           my $login = $self->session('login');
197 0 0         my $method = $self->req->method eq 'POST' ? '_edit' : 'render';
198              
199             $self->delay(
200             sub {
201 0     0     my ($delay) = @_;
202 0 0         $self->redis->hgetall("user:$login", $delay->begin) if $method eq 'render';
203 0           $self->conversation_list($delay->begin);
204 0 0         $self->notification_list($delay->begin) if $self->stash('full_page');
205             },
206             sub {
207 0     0     my ($delay, $user) = @_;
208 0 0         $user = {} if ref $user ne 'HASH';
209 0           $self->param($_ => $user->{$_}) for keys %$user;
210 0           $self->$method;
211             },
212 0           );
213             }
214              
215             =head2 tz_offset
216              
217             Used to save timezone offset in hours. This value will be saved in session
218             under "tz_offset".
219              
220             =cut
221              
222             sub tz_offset {
223 0     0 1   my $self = shift;
224 0   0       my $offset = ($self->param('hour') || 0) - (localtime)[2];
225              
226 0           $self->session(tz_offset => $offset);
227 0           $self->render(json => {offset => $offset});
228             }
229              
230             sub _edit {
231 0     0     my $self = shift;
232 0           my $login = $self->session('login');
233 0           my $validation = $self->validation;
234              
235 0           $validation->required('email')->like(qr{.\@.});
236 0           $validation->optional('avatar')->size(3, 64);
237 0 0         $validation->has_error and return $self->render(status => 400);
238 0   0       $validation->output->{avatar} ||= '';
239              
240             $self->delay(
241             sub {
242 0     0     my $delay = shift;
243 0           $self->redis->hmset("user:$login", $validation->output, $delay->begin);
244             },
245             sub {
246 0     0     my ($delay, $saved) = @_;
247 0           $self->render;
248             },
249 0           );
250             }
251              
252             sub _digest {
253 0     0     crypt $_[1], join '', ('.', '/', 0 .. 9, 'A' .. 'Z', 'a' .. 'z')[rand 64, rand 64];
254             }
255              
256             =head1 COPYRIGHT
257              
258             See L.
259              
260             =head1 AUTHOR
261              
262             Jan Henning Thorsen
263              
264             Marcus Ramberg
265              
266             =cut
267              
268             1;