File Coverage

blib/lib/Dancer2/Plugin/Deferred.pm
Criterion Covered Total %
statement 56 59 94.9
branch 8 12 66.6
condition 8 10 80.0
subroutine 15 15 100.0
pod 3 4 75.0
total 90 100 90.0


line stmt bran cond sub pod time code
1 2     2   863176 use 5.008001;
  2         6  
2 2     2   6 use strict;
  2         2  
  2         30  
3 2     2   6 use warnings;
  2         3  
  2         98  
4              
5             package Dancer2::Plugin::Deferred;
6             our $AUTHORITY = 'cpan:YANICK';
7             $Dancer2::Plugin::Deferred::VERSION = '0.007017';
8             # ABSTRACT: Defer messages or data across redirections
9             # VERSION
10              
11 2     2   7 use Dancer2::Core::Types qw/Str/;
  2         2  
  2         13  
12 2     2   1150 use URI;
  2         2  
  2         40  
13 2     2   773 use URI::QueryParam;
  2         928  
  2         67  
14              
15 2     2   864 use Dancer2::Plugin 0.200000;
  2         16751  
  2         17  
16              
17             has var_key => (
18             is => 'ro',
19             isa => Str,
20             from_config => sub { 'dpdid' },
21             );
22              
23             has var_keep_key => (
24             is => 'ro',
25             isa => Str,
26             from_config => sub { 'dpd_keep' },
27             );
28              
29             has params_key => (
30             is => 'ro',
31             isa => Str,
32             from_config => sub { 'dpdid' },
33             );
34              
35             has session_key_prefix => (
36             is => 'ro',
37             isa => Str,
38             from_config => sub { 'dpd_' },
39             );
40              
41             has template_key => (
42             is => 'ro',
43             isa => Str,
44             from_config => sub { 'deferred' },
45             );
46              
47             plugin_keywords 'deferred', 'all_deferred', 'deferred_param';
48              
49             sub deferred {
50 3     3 1 230 my ( $plugin, $key, $value ) = @_;
51 3         8 my $app = $plugin->app;
52              
53 3         9 my $id = $plugin->_get_id;
54              
55             # message data is flat "dpd_$id" to avoid race condition with
56             # another session
57 3   50     101 my $data = $app->session->read( $plugin->session_key_prefix . $id ) || {};
58            
59             # set value or destructively retrieve it
60 3 50       2132 if ( defined $value ) {
61 3         12 $data->{$key} = $value;
62             }
63             else {
64             $value =
65             $app->request->var( $plugin->var_keep_key )
66             ? $data->{$key}
67 0 0       0 : delete $data->{$key};
68             }
69              
70             # store remaining data or clear it if no deferred messages are left
71 3 50       10 if ( keys %$data ) {
72 3         43 $app->session->write( $plugin->session_key_prefix . $id => $data );
73 3         234 $app->request->var( $plugin->var_key => $id );
74             }
75             else {
76 0         0 $app->session->delete( $plugin->session_key_prefix . $id );
77 0         0 $app->request->var( $plugin->var_key => undef );
78             }
79 3         33 return $value;
80             };
81              
82             sub all_deferred {
83 9     9 1 14 my $plugin = shift;
84 9         19 my $app = $plugin->app;
85              
86 9         23 my $id = $plugin->_get_id;
87 9   100     274 my $data = $plugin->app->session->read( $plugin->session_key_prefix . $id ) || {};
88              
89 9 100       487 unless ( $app->request->var( $plugin->var_keep_key ) ) {
90 8         218 $app->session->delete( $plugin->session_key_prefix . $id );
91 8         1401 $app->request->var( $plugin->var_key, undef );
92             }
93 9         175 return $data;
94             }
95              
96             sub deferred_param {
97 3     3 1 10 my $plugin = shift;
98              
99 3         55 $plugin->app->request->var( $plugin->var_keep_key => 1 );
100              
101 3         65 return ( $plugin->params_key => $plugin->app->request->var( $plugin->var_key ) );
102             }
103              
104             # not crypto strong, but will be stored in session, which should be
105             sub _get_id {
106 12     12   15 my $plugin = shift;
107              
108 12   66     168 return $plugin->app->request->var( $plugin->var_key )
109             || sprintf( "%08d", int( rand(100_000_000) ) );
110             }
111              
112             sub BUILD {
113 2     2 0 5038 my $plugin = shift;
114              
115             $plugin->app->add_hook(
116             Dancer2::Core::Hook->new(
117             name => 'before_template',
118             code => sub {
119 9     9   12082 my $data = shift;
120 9         27 $data->{$plugin->template_key} = $plugin->all_deferred;
121             }
122             )
123 2         48 );
124              
125             $plugin->app->add_hook(
126             Dancer2::Core::Hook->new(
127             name => 'before',
128             code => sub {
129 11     11   101372 my $id = $plugin->app->request->params->{ $plugin->params_key };
130 11 100       352 $plugin->app->request->var( $plugin->var_key => $id )
131             if $id;
132             }
133             )
134 2         160318 );
135              
136             $plugin->app->add_hook(
137             Dancer2::Core::Hook->new(
138             name => 'after',
139             code => sub {
140 11     11   45341 my $response = shift;
141 11 100 100     190 if ( $plugin->app->request->var( $plugin->var_key )
142             && $response->status =~ /^3/ )
143             {
144 2         89 my $u = URI->new( $response->header("Location") );
145 2         147 $u->query_param( $plugin->deferred_param );
146 2         259 $response->header( "Location" => $u );
147             }
148             }
149             )
150 2         678 );
151             };
152              
153             1;
154              
155              
156             # vim: ts=4 sts=4 sw=4 et:
157              
158             __END__