File Coverage

blib/lib/Authorization/AccessControl/Dispatch.pm
Criterion Covered Total %
statement 44 44 100.0
branch 12 12 100.0
condition 4 5 80.0
subroutine 9 9 100.0
pod 5 5 100.0
total 74 75 98.6


line stmt bran cond sub pod time code
1             package Authorization::AccessControl::Dispatch 0.04;
2 7     7   239929 use v5.26;
  7         27  
3 7     7   39 use warnings;
  7         15  
  7         402  
4              
5             # ABSTRACT: Dispatch result/status appropriately following ACL request yield
6              
7 7     7   664 use Readonly;
  7         5697  
  7         485  
8              
9 7     7   629 use experimental qw(signatures);
  7         5176  
  7         79  
10              
11 57     57 1 256654 sub new($class, %params) {
  57         104  
  57         118  
  57         88  
12 57         93 my $granted = delete($params{granted});
13 57 100       138 $granted = !!$granted if (defined($granted)); #force into boolean/undef
14 57         102 my $entity = delete($params{entity});
15 57 100       126 undef($entity) unless ($granted); # ensure we don't hold the protected value if access is not granted
16              
17 57 100       124 die("Unsupported params: ", join(', ', keys(%params))) if (keys(%params));
18              
19 56         159 Readonly::Hash1 my %data => (
20             _granted => $granted,
21             _entity => $entity,
22             );
23              
24 56         1983 bless(\%data, $class);
25             }
26              
27 19     19 1 71 sub granted($self, $sub) {
  19         26  
  19         19  
  19         21  
28 19 100       51 $sub->($self->{_entity}) if ($self->{_granted});
29 18         249 return $self;
30             }
31              
32 18     18 1 30 sub denied($self, $sub) {
  18         22  
  18         22  
  18         17  
33 18 100 100     49 $sub->() if (defined($self->{_granted}) && !$self->{_granted});
34 17         280 return $self;
35             }
36              
37 16     16 1 26 sub null($self, $sub) {
  16         19  
  16         17  
  16         19  
38 16 100       44 $sub->() if (!defined($self->{_granted}));
39 15         186 return $self;
40             }
41              
42 9     9 1 29 sub is_granted($self) {
  9         11  
  9         10  
43 9   50     28 return ($self->{_granted} // 0) != 0;
44             }
45              
46             =head1 NAME
47              
48             Authorization::AccessControl::Dispatch - Dispatch result/status appropriately
49             following ACL request yield
50              
51             =head1 SYNOPSIS
52              
53             use Authorization::AccessControl::Dispatch;
54              
55             my $dispatch = Authorization::AccessControl::Dispatch->new(
56             granted => 1,
57             entity => 'some secure value');
58              
59             $dispatch->denied(...); # not called
60             $dispatch->null(...); # not called
61             $dispatch->granted(sub($val) { $c->render(text => $val) }); # renders value
62              
63             $request->yield(sub(){...})
64             ->granted(sub($val) { #handle success
65             })
66             ->denied(sub() { # handle denial
67             })
68             ->null(sub() { # handle not found
69             })
70              
71             Handlers can be repeated:
72              
73             $request->yield(sub(){...})
74             ->granted(sub($value){ $c->render(json => $value) })
75             ->granted(\&write_audit_log)
76              
77             =head1 DESCRIPTION
78              
79             This is a lightweight class that simply facilitates a "promise-style" callback
80             interface for dealing with the result of
81             L in
82             C
83              
84             Dispatch instances are immutable: none of their properties may be altered after
85             object creation.
86              
87             =head1 METHODS
88              
89             =head2 new
90              
91             Authorization::AccessControl::Dispatch->new(granted => [0|1|undef], entity => ...)
92              
93             Creates a new Dispatch instance. C is a trinary value reflecting the
94             request status: "truthy" indicates permitted, "falsy" indicates denied, and
95             undefined indicates that necessary attributes could not be evaluated because the
96             data value was not present. C is the data value, to be passed to
97             L handlers. If C is anything but "truthy", the C
98             value is immediately undefined before proceeding.
99              
100             =head2 granted
101              
102             $dispatch->granted(sub($result){...})
103              
104             Registers a handler to be executed when the request is permitted by the ACL.
105             Handler receives one argument: the
106             Led value
107              
108             Repeatable. Chainable.
109              
110             =head2 denied
111              
112             $dispatch->denied(sub(){...})
113              
114             Registers a handler to be executed when the request is denied by the ACL.
115             Handler receives no arguments.
116              
117             Repeatable. Chainable.
118              
119             =head2 null
120              
121             $dispatch->null(sub(){ ... })
122              
123             Registers a handler to be executed when the
124             Led value is undefined.
125             Handler receives no arguments.
126              
127             Repeatable. Chainable.
128              
129             =head2 is_granted
130              
131             $dispatch->is_granted()
132              
133             Returns a boolean value reflecting whether or not the request was permitted by
134             the ACL
135              
136             =head1 AUTHOR
137              
138             Mark Tyrrell C<< >>
139              
140             =head1 LICENSE
141              
142             Copyright (c) 2024 Mark Tyrrell
143              
144             Permission is hereby granted, free of charge, to any person obtaining a copy
145             of this software and associated documentation files (the "Software"), to deal
146             in the Software without restriction, including without limitation the rights
147             to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
148             copies of the Software, and to permit persons to whom the Software is
149             furnished to do so, subject to the following conditions:
150              
151             The above copyright notice and this permission notice shall be included in all
152             copies or substantial portions of the Software.
153              
154             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
155             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
156             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
157             AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
158             LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
159             OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
160             SOFTWARE.
161              
162             =cut
163              
164             1;
165              
166             __END__