File Coverage

lib/Web/ComposableRequest/Session.pm
Criterion Covered Total %
statement 59 59 100.0
branch 11 14 78.5
condition 13 15 86.6
subroutine 12 12 100.0
pod 6 6 100.0
total 101 106 95.2


line stmt bran cond sub pod time code
1             package Web::ComposableRequest::Session;
2              
3 1     1   1124 use namespace::autoclean;
  1         2  
  1         13  
4              
5 1     1   125 use Web::ComposableRequest::Constants qw( EXCEPTION_CLASS FALSE NUL TRUE );
  1         2  
  1         12  
6 1     1   483 use Web::ComposableRequest::Util qw( bson64id is_arrayref throw );
  1         2  
  1         8  
7 1         8 use Unexpected::Types qw( ArrayRef Bool HashRef
8             NonEmptySimpleStr NonZeroPositiveInt
9 1     1   471 Object SimpleStr Undef );
  1         4  
10 1     1   1134 use Moo;
  1         2  
  1         10  
11              
12             # Public attributes
13             has 'authenticated' => is => 'rw', isa => Bool, default => FALSE;
14              
15             has 'messages' => is => 'ro', isa => HashRef[ArrayRef],
16 3     3   212 builder => sub { {} };
17              
18             has 'updated' => is => 'ro', isa => NonZeroPositiveInt, required => TRUE;
19              
20             has 'username' => is => 'rw', isa => SimpleStr, default => NUL;
21              
22             # Private attributes
23             has '_config' => is => 'ro', isa => Object, init_arg => 'config',
24             required => TRUE;
25              
26             has '_mid' => is => 'rwp', isa => NonEmptySimpleStr | Undef;
27              
28             has '_request' => is => 'ro', isa => Object, init_arg => 'request',
29             required => TRUE, weak_ref => TRUE;
30              
31             has '_session' => is => 'ro', isa => HashRef, init_arg => 'session',
32             required => TRUE;
33              
34             # Private functions
35             my $_session_attr = sub {
36             my $conf = shift; my @public = qw( authenticated messages updated username );
37              
38             return keys %{ $conf->session_attr }, @public;
39             };
40              
41             # Construction
42             around 'BUILDARGS' => sub {
43             my ($orig, $self, @args) = @_; my $attr = $orig->( $self, @args );
44              
45             for my $k ($_session_attr->( $attr->{config} )) {
46             my $v = $attr->{session}->{ $k }; defined $v and $attr->{ $k } = $v;
47             }
48              
49             $attr->{updated} //= time;
50              
51             return $attr;
52             };
53              
54             sub BUILD {
55 6     6 1 1064 my $self = shift; my $conf = $self->_config;
  6         33  
56              
57 6         20 my $max_time = $conf->max_sess_time;
58              
59 6 100 66     108 if ($self->authenticated and $max_time
      100        
60             and time > $self->updated + $max_time) {
61 1         18 my $req = $self->_request;
62 1         22 my $msg = $conf->expire_session->( $self, $req );
63              
64 1         19 $self->authenticated( FALSE );
65 1         22 $self->_set__mid( $self->add_status_message( $msg ) );
66             $req->_log->( { level => 'debug',
67 1         30 message => $req->loc_default( @{ $msg } ) } );
  1         11  
68             }
69              
70 6         161 return;
71             }
72              
73             # Public methods
74             sub add_status_message {
75 6     6 1 104 my ($self, $msg) = @_;
76              
77 6 50       15 is_arrayref $msg or throw 'Parameter [_1] not an array reference', [ $msg ];
78              
79 6         23 $self->messages->{ my $mid = bson64id } = $msg;
80              
81 6         33 return $mid;
82             }
83              
84             sub collect_message_id {
85 3     3 1 1008 my ($self, $req) = @_;
86              
87 3 100 100     49 return $self->_mid && exists $self->messages->{ $self->_mid }
88             ? $self->_mid : $req->query_params->( 'mid', { optional => TRUE } );
89             }
90              
91             sub collect_status_message {
92 3     3 1 298 my ($self, $req) = @_; my ($mid, $msg);
  3         3  
93              
94             $mid = $self->_mid
95             and $msg = delete $self->messages->{ $mid }
96 3 100 100     23 and return $req->loc( @{ $msg } );
  1         6  
97              
98             $mid = $req->query_params->( 'mid', { optional => TRUE } )
99             and $msg = delete $self->messages->{ $mid }
100 2 100 66     12 and return $req->loc( @{ $msg } );
  1         5  
101              
102 1         12 return;
103             }
104              
105             sub collect_status_messages {
106 1     1 1 24 my ($self, $req) = @_; my @messages = ();
  1         2  
107              
108 1 50       7 my $mid = $req->query_params->( 'mid', { optional => TRUE } )
109             or return \@messages;
110              
111 1         7 my @keys = reverse sort keys %{ $self->messages };
  1         9  
112              
113 1         5 while (my $key = $keys[ 0 ]) {
114 3 50       9 $key gt $mid and next; my $msg = delete $self->messages->{ $key };
  3         10  
115              
116 3         4 push @messages, $req->loc( @{ $msg } ); shift @keys;
  3         11  
  3         153  
117             }
118              
119 1         5 return \@messages;
120             }
121              
122             sub trim_message_queue {
123 4     4 1 5 my $self = shift; my @queue = sort keys %{ $self->messages };
  4         6  
  4         26  
124              
125 4         39 while (@queue > $self->_config->max_messages) {
126 1         3 my $mid = shift @queue; delete $self->messages->{ $mid };
  1         7  
127             }
128              
129 4         4 return;
130             }
131              
132             sub update {
133             my $self = shift;
134              
135             for my $k ($_session_attr->( $self->_config )) {
136             $self->_session->{ $k } = $self->$k();
137             }
138              
139             $self->_session->{updated} = time;
140             return;
141             }
142              
143             before 'update' => sub {
144             my $self = shift; $self->trim_message_queue; return;
145             };
146              
147             1;
148              
149             __END__