line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
1
|
|
|
1
|
|
301448
|
use strict; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
38
|
|
2
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
30
|
|
3
|
|
|
|
|
|
|
|
4
|
1
|
|
|
1
|
|
25
|
use 5.0100; |
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
82
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package WebPrototypes::Registration; |
7
|
|
|
|
|
|
|
BEGIN { |
8
|
1
|
|
|
1
|
|
27
|
$WebPrototypes::Registration::VERSION = '0.002'; |
9
|
|
|
|
|
|
|
} |
10
|
1
|
|
|
1
|
|
6
|
use parent qw(Plack::Component); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
6
|
|
11
|
1
|
|
|
1
|
|
1090
|
use Plack::Request; |
|
1
|
|
|
|
|
41738
|
|
|
1
|
|
|
|
|
38
|
|
12
|
1
|
|
|
1
|
|
885
|
use URL::Encode 'url_encode_utf8'; |
|
1
|
|
|
|
|
11111
|
|
|
1
|
|
|
|
|
70
|
|
13
|
1
|
|
|
1
|
|
968
|
use String::Random 'random_regex'; |
|
1
|
|
|
|
|
3511
|
|
|
1
|
|
|
|
|
73
|
|
14
|
1
|
|
|
1
|
|
904
|
use Email::Sender::Simple qw(sendmail); |
|
1
|
|
|
|
|
297792
|
|
|
1
|
|
|
|
|
9
|
|
15
|
1
|
|
|
1
|
|
325
|
use Email::Simple; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
23
|
|
16
|
1
|
|
|
1
|
|
6
|
use Email::Simple::Creator; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
23
|
|
17
|
1
|
|
|
1
|
|
1139
|
use Email::Valid; |
|
1
|
|
|
|
|
237662
|
|
|
1
|
|
|
|
|
47
|
|
18
|
|
|
|
|
|
|
|
19
|
1
|
|
|
1
|
|
10
|
use Plack::Util::Accessor qw( email_validator ); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
13
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub prepare_app { |
22
|
1
|
|
|
1
|
1
|
119
|
my $self = shift; |
23
|
1
|
50
|
|
|
|
10
|
$self->email_validator( Email::Valid->new() ) if !defined $self->email_validator; |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
|
26
|
0
|
|
|
0
|
1
|
0
|
sub find_user { die 'find_user needs to be implemented in subclass' } |
27
|
|
|
|
|
|
|
|
28
|
0
|
|
|
0
|
1
|
0
|
sub create_user { die 'find_user needs to be implemented in subclass' } |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub wrap_text{ |
31
|
3
|
|
|
3
|
1
|
6
|
my( $self, $text ) = @_; |
32
|
3
|
|
|
|
|
64
|
return "$text"; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub build_reply{ |
36
|
3
|
|
|
3
|
1
|
6
|
my( $self, $text ) = @_; |
37
|
3
|
|
|
|
|
22
|
return [ 200, [ 'Content-Type' => 'text/html' ], [ $self->wrap_text( $text ) ] ]; |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub call { |
41
|
3
|
|
|
3
|
1
|
67410
|
my($self, $env) = @_; |
42
|
3
|
|
|
|
|
35
|
my $req = Plack::Request->new( $env ); |
43
|
3
|
|
|
|
|
35
|
my $uerror = ''; |
44
|
3
|
|
|
|
|
6
|
my $eerror = ''; |
45
|
3
|
|
|
|
|
5
|
my $username = ''; |
46
|
3
|
|
|
|
|
6
|
my $email = ''; |
47
|
3
|
100
|
|
|
|
17
|
if( $req->method eq 'POST' ){ |
48
|
2
|
|
|
|
|
33
|
$username = $req->param( 'username' ); |
49
|
2
|
|
|
|
|
1313
|
$email = $req->param( 'email' ); |
50
|
2
|
100
|
|
|
|
33
|
if( $self->find_user( $username ) ){ |
51
|
1
|
|
|
|
|
8
|
$uerror = 'This username is already registered'; |
52
|
|
|
|
|
|
|
} |
53
|
2
|
100
|
|
|
|
20
|
if( !$self->email_validator->address( $email ) ){ |
54
|
1
|
|
|
|
|
1829
|
$eerror = 'Wrong format of email'; |
55
|
|
|
|
|
|
|
} |
56
|
2
|
50
|
66
|
|
|
421
|
if( !$uerror && !$eerror ){ |
57
|
1
|
|
|
|
|
7
|
my $pass_token = random_regex( '\w{40}' ); |
58
|
1
|
|
|
|
|
204
|
my $user = $self->create_user( username => $username, email => $email, pass_token => $pass_token ); |
59
|
1
|
|
|
|
|
16
|
$self->_send_pass_token( $env, $user, $username, $email, $pass_token ); |
60
|
1
|
|
|
|
|
1831
|
return $self->build_reply( "Email sent" ); |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
} |
63
|
2
|
|
|
|
|
27
|
my $encoded_username = url_encode_utf8( $username ); |
64
|
2
|
|
|
|
|
53
|
my $encoded_email = url_encode_utf8( $email ); |
65
|
2
|
|
|
|
|
63
|
return $self->build_reply( <
|
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Username: $uerror |
68
|
|
|
|
|
|
|
Email: $eerror |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
END |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub build_email { |
76
|
1
|
|
|
1
|
1
|
3
|
my( $self, $to, $reset_url ) = @_; |
77
|
1
|
|
|
|
|
46
|
return Email::Simple->create( |
78
|
|
|
|
|
|
|
header => [ |
79
|
|
|
|
|
|
|
To => $to, |
80
|
|
|
|
|
|
|
From => 'root@localhost', |
81
|
|
|
|
|
|
|
Subject => "Password reset", |
82
|
|
|
|
|
|
|
], |
83
|
|
|
|
|
|
|
body => $reset_url, |
84
|
|
|
|
|
|
|
); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub send_mail { |
88
|
0
|
|
|
0
|
1
|
0
|
my( $self, $mail ) = @_; |
89
|
0
|
|
|
|
|
0
|
sendmail( $mail ); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub _send_pass_token { |
93
|
1
|
|
|
1
|
|
3
|
my( $self, $env, $user, $username, $email, $pass_token ) = @_; |
94
|
1
|
0
|
50
|
|
|
16
|
my $my_server = $env->{HTTP_ORIGIN} // |
|
|
|
0
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
95
|
|
|
|
|
|
|
( $env->{'psgi.url_scheme'} // 'http' ) . '://' . |
96
|
|
|
|
|
|
|
( $env->{HTTP_HOST} // |
97
|
|
|
|
|
|
|
$env->{SERVER_NAME} . |
98
|
|
|
|
|
|
|
( $env->{SERVER_PORT} && $env->{SERVER_PORT} != 80 ? ':' . $env->{SERVER_PORT} : '' ) |
99
|
|
|
|
|
|
|
); |
100
|
1
|
|
|
|
|
9
|
my $reset_url = URI->new( $my_server ); |
101
|
1
|
|
|
|
|
72
|
$reset_url->path( "/ResetPass/reset/$username/$pass_token" ); |
102
|
1
|
|
|
|
|
58
|
$self->send_mail( $self->build_email( $email, $reset_url ) ); |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
1; |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=pod |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
=head1 NAME |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
WebPrototypes::Registration - (Experimental) Plack application for registering a new user |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=head1 VERSION |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
version 0.002 |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=head1 SYNOPSIS |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# connecting with DBIx::Class |
123
|
|
|
|
|
|
|
{ |
124
|
|
|
|
|
|
|
package My::Register; |
125
|
|
|
|
|
|
|
use parent 'WebPrototypes::Registration'; |
126
|
|
|
|
|
|
|
use Plack::Util::Accessor qw( schema ); |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub find_user { |
129
|
|
|
|
|
|
|
my( $self, $name ) = @_; |
130
|
|
|
|
|
|
|
return $self->schema->resultset( 'User' )->search({ username => $name })->next; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
sub create_user { |
134
|
|
|
|
|
|
|
my( $self, %fields ) = @_; |
135
|
|
|
|
|
|
|
return $self->schema->resultset( 'User' )->create({ %fields }); |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
use Plack::Builder; |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
my $app = My::Register->new( schema => $schema ); |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
builder { |
144
|
|
|
|
|
|
|
mount "/register" => builder { |
145
|
|
|
|
|
|
|
$app->to_app; |
146
|
|
|
|
|
|
|
}; |
147
|
|
|
|
|
|
|
}; |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=head1 DESCRIPTION |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
This application implements a user registration mechanism. After the registration |
152
|
|
|
|
|
|
|
and email address verification letter is sent. |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
The examples here are with DBIx::Class |
155
|
|
|
|
|
|
|
but they can be easily ported to other storage layers. |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
This application uses the Template Method design pattern. |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=head2 PURE VIRTUAL METHODS |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
These methods need to be overriden in subclass. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=over 4 |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=item find_user ( name ) |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
Should return a true value if the name is already registered |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=item create_user ( attributes ) |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
Should create the user object. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=back |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=head2 VIRTUAL METHODS |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
These methods have defaults - but should probably be overriden anyway. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=over 4 |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=item wrap_text ( text ) |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
Should return the html page containing the passed text fragment. By default it just adds |
184
|
|
|
|
|
|
|
the html and body tags. |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=item build_reply ( page_body ) |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
Should return the PSGI response data structure. |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=item build_email ( to_address, link_to_the_reset_page ) |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
Should create the email containing the link. |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=item send_mail ( mail ) |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
Should send the mail (created by build_mail). |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=back |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head2 OTHER METHODS |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=over 4 |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=item call ( env ) |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=back |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=head1 SEE ALSO |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
L |
211
|
|
|
|
|
|
|
L |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head1 AUTHOR |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
Zbigniew Lukasiak |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
This software is Copyright (c) 2011 by Zbigniew Lukasiak . |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
This is free software, licensed under: |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
The Artistic License 2.0 (GPL Compatible) |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=cut |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
__END__ |