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   1621963 use 5.008001;
  2         23  
2 2     2   14 use strict;
  2         4  
  2         70  
3 2     2   12 use warnings;
  2         4  
  2         145  
4              
5             package Dancer2::Plugin::Deferred;
6             our $AUTHORITY = 'cpan:YANICK';
7             $Dancer2::Plugin::Deferred::VERSION = '0.007018';
8             # ABSTRACT: Defer messages or data across redirections
9             # VERSION
10              
11 2     2   15 use Dancer2::Core::Types qw/Str/;
  2         11  
  2         19  
12 2     2   2042 use URI;
  2         5  
  2         74  
13 2     2   938 use URI::QueryParam;
  2         1654  
  2         71  
14              
15 2     2   1161 use Dancer2::Plugin 0.200000;
  2         27932  
  2         24  
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 367 my ( $plugin, $key, $value ) = @_;
51 3         44 my $app = $plugin->app;
52              
53 3         17 my $id = $plugin->_get_id;
54              
55             # message data is flat "dpd_$id" to avoid race condition with
56             # another session
57 3   50     118 my $data = $app->session->read( $plugin->session_key_prefix . $id ) || {};
58            
59             # set value or destructively retrieve it
60 3 50       3123 if ( defined $value ) {
61 3         13 $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       13 if ( keys %$data ) {
72 3         54 $app->session->write( $plugin->session_key_prefix . $id => $data );
73 3         355 $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         94 return $value;
80             };
81              
82             sub all_deferred {
83 9     9 1 18 my $plugin = shift;
84 9         25 my $app = $plugin->app;
85              
86 9         26 my $id = $plugin->_get_id;
87 9   100     396 my $data = $plugin->app->session->read( $plugin->session_key_prefix . $id ) || {};
88              
89 9 100       638 unless ( $app->request->var( $plugin->var_keep_key ) ) {
90 8         283 $app->session->delete( $plugin->session_key_prefix . $id );
91 8         953 $app->request->var( $plugin->var_key, undef );
92             }
93 9         281 return $data;
94             }
95              
96             sub deferred_param {
97 3     3 1 18 my $plugin = shift;
98              
99 3         85 $plugin->app->request->var( $plugin->var_keep_key => 1 );
100              
101 3         91 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   24 my $plugin = shift;
107              
108 12   66     236 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 8822 my $plugin = shift;
114              
115             $plugin->app->add_hook(
116             Dancer2::Core::Hook->new(
117             name => 'before_template',
118             code => sub {
119 9     9   13361 my $data = shift;
120 9         35 $data->{$plugin->template_key} = $plugin->all_deferred;
121             }
122             )
123 2         67 );
124              
125             $plugin->app->add_hook(
126             Dancer2::Core::Hook->new(
127             name => 'before',
128             code => sub {
129 11     11   129139 my $id = $plugin->app->request->params->{ $plugin->params_key };
130 11 100       427 $plugin->app->request->var( $plugin->var_key => $id )
131             if $id;
132             }
133             )
134 2         310026 );
135              
136             $plugin->app->add_hook(
137             Dancer2::Core::Hook->new(
138             name => 'after',
139             code => sub {
140 11     11   42466 my $response = shift;
141 11 100 100     221 if ( $plugin->app->request->var( $plugin->var_key )
142             && $response->status =~ /^3/ )
143             {
144 2         137 my $u = URI->new( $response->header("Location") );
145 2         241 $u->query_param( $plugin->deferred_param );
146 2         376 $response->header( "Location" => $u );
147             }
148             }
149             )
150 2         1056 );
151             };
152              
153             1;
154              
155              
156             # vim: ts=4 sts=4 sw=4 et:
157              
158             __END__