File Coverage

blib/lib/Plack/App/Register.pm
Criterion Covered Total %
statement 27 86 31.4
branch 0 24 0.0
condition 0 15 0.0
subroutine 9 16 56.2
pod n/a
total 36 141 25.5


line stmt bran cond sub pod time code
1             package Plack::App::Register;
2              
3 2     2   100217 use base qw(Plack::Component::Tags::HTML);
  2         3  
  2         1187  
4 2     2   207852 use strict;
  2         4  
  2         52  
5 2     2   10 use warnings;
  2         7  
  2         138  
6              
7 2         20 use Plack::Util::Accessor qw(generator logo_image_url message_cb
8 2     2   13 redirect_register redirect_error register_cb title);
  2         8  
9 2     2   1610 use Plack::Request;
  2         151967  
  2         82  
10 2     2   2392 use Plack::Response;
  2         2749  
  2         90  
11 2     2   1031 use Plack::Session;
  2         1155  
  2         67  
12 2     2   1174 use Tags::HTML::Container;
  2         35670  
  2         126  
13 2     2   1331 use Tags::HTML::Login::Register 0.09;
  2         647660  
  2         2168  
14              
15             our $VERSION = 0.05;
16              
17             sub _css {
18 0     0     my ($self, $env) = @_;
19              
20 0           $self->{'_container'}->process_css;
21 0           $self->{'_login_register'}->process_css({
22             'info' => 'blue',
23             'error' => 'red',
24             });
25              
26 0           return;
27             }
28              
29             sub _message {
30 0     0     my ($self, $env, $message_type, $message) = @_;
31              
32 0 0         if (defined $self->message_cb) {
33 0           $self->message_cb->($env, $message_type, $message);
34             }
35              
36 0           return;
37             }
38              
39             sub _prepare_app {
40 0     0     my $self = shift;
41              
42             # Defaults which rewrite defaults in module which I am inheriting.
43 0 0         if (! defined $self->generator) {
44 0           $self->generator(__PACKAGE__.'; Version: '.$VERSION);
45             }
46              
47 0 0         if (! defined $self->title) {
48 0           $self->title('Register page');
49             }
50              
51             # Inherite defaults.
52 0           $self->SUPER::_prepare_app;
53              
54             # Defaults from this module.
55 0           my %p = (
56             'css' => $self->css,
57             'tags' => $self->tags,
58             );
59 0           $self->{'_login_register'} = Tags::HTML::Login::Register->new(%p,
60             'logo_image_url' => $self->logo_image_url,
61             );
62 0           $self->{'_container'} = Tags::HTML::Container->new(%p);
63              
64 0           return;
65             }
66              
67             sub _process_actions {
68 0     0     my ($self, $env) = @_;
69              
70 0 0 0       if (defined $self->register_cb && $env->{'REQUEST_METHOD'} eq 'POST') {
71 0           my $req = Plack::Request->new($env);
72 0           my $body_params_hr = $req->body_parameters;
73 0           my ($status, $messages_ar) = $self->_register_check($env, $body_params_hr);
74 0           my $res = Plack::Response->new;
75 0 0         if ($status) {
76 0 0         if ($self->register_cb->($env, $body_params_hr->{'username'},
77             $body_params_hr->{'password1'})) {
78              
79 0           $self->_message($env, 'info',
80             "User '$body_params_hr->{'username'}' is registered.");
81 0           $res->redirect($self->redirect_register);
82             } else {
83 0           $res->redirect($self->redirect_error);
84             }
85             } else {
86 0           $res->redirect($self->redirect_error);
87             }
88 0           $self->psgi_app($res->finalize);
89 0           return;
90             }
91              
92 0           return;
93             }
94              
95             sub _register_check {
96 0     0     my ($self, $env, $body_parameters_hr) = @_;
97              
98 0 0 0       if (! exists $body_parameters_hr->{'register'}
99             || $body_parameters_hr->{'register'} ne 'register') {
100              
101 0           $self->_message($env, 'error', 'There is no register POST.');
102 0           return 0;
103             }
104 0 0 0       if (! defined $body_parameters_hr->{'username'} || ! $body_parameters_hr->{'username'}) {
105 0           $self->_message($env, 'error', "Parameter 'username' doesn't defined.");
106 0           return 0;
107             }
108 0 0 0       if (! defined $body_parameters_hr->{'password1'} || ! $body_parameters_hr->{'password1'}) {
109 0           $self->_message($env, 'error', "Parameter 'password1' doesn't defined.");
110 0           return 0;
111             }
112 0 0 0       if (! defined $body_parameters_hr->{'password2'} || ! $body_parameters_hr->{'password2'}) {
113 0           $self->_message($env, 'error', "Parameter 'password2' doesn't defined.");
114 0           return 0;
115             }
116 0 0         if ($body_parameters_hr->{'password1'} ne $body_parameters_hr->{'password2'}) {
117 0           $self->_message($env, 'error', 'Passwords are not same.');
118 0           return 0;
119             }
120              
121 0           return 1;
122             }
123              
124             sub _tags_middle {
125 0     0     my ($self, $env) = @_;
126              
127 0           my $messages_ar = [];
128 0 0         if (exists $env->{'psgix.session'}) {
129 0           my $session = Plack::Session->new($env);
130 0           $messages_ar = $session->get('messages');
131 0           $session->set('messages', []);
132             }
133             $self->{'_container'}->process(
134             sub {
135 0     0     $self->{'_login_register'}->process($messages_ar);
136             },
137 0           );
138              
139 0           return;
140             }
141              
142             1;
143              
144             __END__
145              
146             =pod
147              
148             =encoding utf8
149              
150             =head1 NAME
151              
152             Plack::App::Register - Plack register application.
153              
154             =head1 SYNOPSIS
155              
156             use Plack::App::Register;
157              
158             my $obj = Plack::App::Register->new(%parameters);
159             my $psgi_ar = $obj->call($env);
160             my $app = $obj->to_app;
161              
162             =head1 METHODS
163              
164             =head2 C<new>
165              
166             my $obj = Plack::App::Register->new(%parameters);
167              
168             Constructor.
169              
170             =over 8
171              
172             =item * C<author>
173              
174             Author string to HTML head.
175              
176             Default value is undef.
177              
178             =item * C<content_type>
179              
180             Content type for output.
181              
182             Default value is 'text/html; charset=__ENCODING__'.
183              
184             =item * C<css>
185              
186             Instance of CSS::Struct::Output object.
187              
188             Default value is CSS::Struct::Output::Raw instance.
189              
190             =item * C<css_init>
191              
192             Reference to array with CSS::Struct structure.
193              
194             Default value is CSS initialization from Tags::HTML::Page::Begin like
195              
196             * {
197             box-sizing: border-box;
198             margin: 0;
199             padding: 0;
200             }
201              
202             =item * C<encoding>
203              
204             Set encoding for output.
205              
206             Default value is 'utf-8'.
207              
208             =item * C<favicon>
209              
210             Link to favicon.
211              
212             Default value is undef.
213              
214             =item * C<flag_begin>
215              
216             Flag that means begin of html writing via L<Tags::HTML::Page::Begin>.
217              
218             Default value is 1.
219              
220             =item * C<flag_end>
221              
222             Flag that means end of html writing via L<Tags::HTML::Page::End>.
223              
224             Default value is 1.
225              
226             =item * C<generator>
227              
228             HTML generator string.
229              
230             Default value is 'Plack::App::Register; Version: __VERSION__'.
231              
232             =item * C<logo_image_url>
233              
234             Logo image URL.
235              
236             Default value is undef.
237              
238             =item * C<message_cb>
239              
240             Callback to process message from application.
241             Arguments for callback are: C<$env>, C<$message_type> and C<$message>.
242             Returns undef.
243              
244             Default value is undef.
245              
246             =item * C<psgi_app>
247              
248             PSGI application to run instead of normal process.
249             Intent of this is change application in C<_process_actions> method.
250              
251             Default value is undef.
252              
253             =item * C<redirect_register>
254              
255             Redirect URL after successful registering.
256              
257             Default value is undef.
258              
259             =item * C<redirect_error>
260              
261             Redirect URL after error in registering.
262              
263             Default value is undef.
264              
265             =item * C<register_cb>
266              
267             Callback for main registering.
268             Arguments for callback are: C<$env>, C<username> and C<$password>.
269             Returns 0/1 for (un)successful registration.
270              
271             Default value is undef.
272              
273             =item * C<script_js>
274              
275             Reference to array with Javascript code strings.
276              
277             Default value is [].
278              
279             =item * C<script_js_src>
280              
281             Reference to array with Javascript URLs.
282              
283             Default value is [].
284              
285             =item * C<status_code>
286              
287             HTTP status code.
288              
289             Default value is 200.
290              
291             =item * C<tags>
292              
293             Instance of Tags::Output object.
294              
295             Default value is
296              
297             Tags::Output::Raw->new(
298             'xml' => 1,
299             'no_simple' => ['script', 'textarea'],
300             'preserved' => ['pre', 'style'],
301             );
302              
303             =item * C<title>
304              
305             Page title.
306              
307             Default value is 'Register page'.
308              
309             =back
310              
311             Returns instance of object.
312              
313             =head2 C<call>
314              
315             my $psgi_ar = $obj->call($env);
316              
317             Implementation of login page.
318              
319             Returns reference to array (PSGI structure).
320              
321             =head2 C<to_app>
322              
323             my $app = $obj->to_app;
324              
325             Creates Plack application.
326              
327             Returns Plack::Component object.
328              
329             =head1 EXAMPLE
330              
331             =for comment filename=register_psgi.pl
332              
333             use strict;
334             use warnings;
335              
336             use CSS::Struct::Output::Indent;
337             use Plack::App::Register;
338             use Plack::Runner;
339             use Tags::Output::Indent;
340              
341             # Run application.
342             my $app = Plack::App::Register->new(
343             'css' => CSS::Struct::Output::Indent->new,
344             'generator' => 'Plack::App::Register',
345             'tags' => Tags::Output::Indent->new(
346             'preserved' => ['style'],
347             'xml' => 1,
348             ),
349             )->to_app;
350             Plack::Runner->new->run($app);
351              
352             # Output:
353             # HTTP::Server::PSGI: Accepting connections at http://0:5000/
354              
355             # > curl http://localhost:5000/
356             # <!DOCTYPE html>
357             # <html lang="en">
358             # <head>
359             # <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
360             # <meta name="generator" content="Plack::App::Register" />
361             # <meta name="viewport" content="width=device-width, initial-scale=1.0" />
362             # <title>
363             # Register page
364             # </title>
365             # <style type="text/css">
366             # * {
367             # box-sizing: border-box;
368             # margin: 0;
369             # padding: 0;
370             # }
371             # .container {
372             # display: flex;
373             # align-items: center;
374             # justify-content: center;
375             # height: 100vh;
376             # }
377             # .form-register {
378             # width: 300px;
379             # background-color: #f2f2f2;
380             # padding: 20px;
381             # border-radius: 5px;
382             # box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
383             # }
384             # .form-register fieldset {
385             # border: none;
386             # padding: 0;
387             # margin-bottom: 20px;
388             # }
389             # .form-register legend {
390             # font-weight: bold;
391             # margin-bottom: 10px;
392             # }
393             # .form-register p {
394             # margin: 0;
395             # padding: 10px 0;
396             # }
397             # .form-register label {
398             # display: block;
399             # font-weight: bold;
400             # margin-bottom: 5px;
401             # }
402             # .form-register input[type="text"], .form-register input[type="password"] {
403             # width: 100%;
404             # padding: 8px;
405             # border: 1px solid #ccc;
406             # border-radius: 3px;
407             # }
408             # .form-register button[type="submit"] {
409             # width: 100%;
410             # padding: 10px;
411             # background-color: #4CAF50;
412             # color: #fff;
413             # border: none;
414             # border-radius: 3px;
415             # cursor: pointer;
416             # }
417             # .form-register button[type="submit"]:hover {
418             # background-color: #45a049;
419             # }
420             # .form-register .messages {
421             # text-align: center;
422             # }
423             # .info {
424             # color: blue;
425             # }
426             # .error {
427             # color: red;
428             # }
429             # </style>
430             # </head>
431             # <body>
432             # <div class="container">
433             # <div class="inner">
434             # <form class="form-register" method="post">
435             # <fieldset>
436             # <legend>
437             # Register
438             # </legend>
439             # <p>
440             # <label for="username" />
441             # User name
442             # <input type="text" name="username" id="username" />
443             # </p>
444             # <p>
445             # <label for="password1">
446             # Password #1
447             # </label>
448             # <input type="password" name="password1" id="password1" />
449             # </p>
450             # <p>
451             # <label for="password2">
452             # Password #2
453             # </label>
454             # <input type="password" name="password2" id="password2" />
455             # </p>
456             # <p>
457             # <button type="submit" name="register" value="register">
458             # Register
459             # </button>
460             # </p>
461             # </fieldset>
462             # </form>
463             # </div>
464             # </div>
465             # </body>
466             # </html>
467              
468             =begin html
469              
470             <a href="https://raw.githubusercontent.com/michal-josef-spacek/Plack-App-Register/master/images/register_psgi_screenshot.png">
471             <img src="https://raw.githubusercontent.com/michal-josef-spacek/Plack-App-Register/master/images/register_psgi_screenshot.png" alt="Example screenshot" width="300px" height="300px" />
472             </a>
473              
474             =end html
475              
476             =head1 DEPENDENCIES
477              
478             L<Plack::Component::Tags::HTML>,
479             L<Plack::Request>,
480             L<Plack::Response>,
481             L<Plack::Session>,
482             L<Plack::Util::Accessor>,
483             L<Tags::HTML::Container>,
484             L<Tags::HTML::Login::Register>.
485              
486             =head1 SEE ALSO
487              
488             =over
489              
490             =item L<Plack::App::Login>
491              
492             Plack login application.
493              
494             =item L<Plack::App::Login::Password>
495              
496             Plack login/password application.
497              
498             =back
499              
500             =head1 REPOSITORY
501              
502             L<https://github.com/michal-josef-spacek/Plack-App-Register>
503              
504             =head1 AUTHOR
505              
506             Michal Josef Špaček L<mailto:skim@cpan.org>
507              
508             L<http://skim.cz>
509              
510             =head1 LICENSE AND COPYRIGHT
511              
512             © 2023-2025 Michal Josef Špaček
513              
514             BSD 2-Clause License
515              
516             =head1 VERSION
517              
518             0.05
519              
520             =cut