File Coverage

blib/lib/WebPrototypes/Registration.pm
Criterion Covered Total %
statement 71 75 94.6
branch 8 12 66.6
condition 5 14 35.7
subroutine 19 22 86.3
pod 8 8 100.0
total 111 131 84.7


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__