File Coverage

blib/lib/Mojolicious/Plugin/Notifications.pm
Criterion Covered Total %
statement 69 73 94.5
branch 26 34 76.4
condition 13 20 65.0
subroutine 9 9 100.0
pod 1 1 100.0
total 118 137 86.1


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::Notifications;
2 10     10   109158 use Mojo::Base 'Mojolicious::Plugin';
  10         24  
  10         70  
3 10     10   2144 use Mojo::Collection qw/c/;
  10         27  
  10         681  
4 10     10   5130 use Mojolicious::Plugin::Notifications::Assets;
  10         30  
  10         377  
5 10     10   63 use Mojo::Util qw/camelize/;
  10         23  
  10         483  
6 10     10   57 use Scalar::Util qw/blessed/;
  10         21  
  10         11521  
7              
8             our $TYPE_RE = qr/^[-a-zA-Z_]+$/;
9              
10             our $VERSION = '1.06';
11              
12             # TODO:
13             # Maybe revert to tx-handler and use session instead of flash!
14             # TODO:
15             # Support Multiple Times Loading
16             # TODO:
17             # Subroutines for Engines should be given directly
18             # TODO:
19             # Engines may use hooks in addition
20              
21             # Register plugin
22             sub register {
23 10     10 1 504 my ($plugin, $app, $param) = @_;
24              
25 10   50     49 $param ||= {};
26              
27 10 50       103 my $debug = $app->mode eq 'development' ? 1 : 0;
28              
29             # Load parameter from Config file
30 10 50       221 if (my $config_param = $app->config('Notifications')) {
31 0         0 $param = { %$param, %$config_param };
32             };
33              
34 10 100       205 $param->{HTML} = 1 unless keys %$param;
35              
36             # Add engines from configuration
37 10         26 my %engine;
38 10         33 foreach my $name (keys %$param) {
39 18         85 my $engine = camelize $name;
40 18 100       180 if (index($engine,'::') < 0) {
41 16         49 $engine = __PACKAGE__ . '::' . $engine;
42             };
43              
44             # Load engine
45 18         71 my $e = $app->plugins->load_plugin($engine);
46 18 100       4122 $e->register($app, ref $param->{$name} ? $param->{$name} : undef);
47 18         499 $engine{lc $name} = $e;
48             };
49              
50             # Create asset object
51 10         76 my $asset = Mojolicious::Plugin::Notifications::Assets->new;
52              
53             # Set assets
54 10         38 foreach (values %engine) {
55 18 50       164 $asset->styles($_->styles) if $_->can('styles');
56 18 50       109 $asset->scripts($_->scripts) if $_->can('scripts');
57             };
58              
59              
60             # Add notifications
61             $app->helper(
62             notify => sub {
63 77     77   600767 my $c = shift;
64 77         168 my $type = shift;
65 77         205 my @msg = @_;
66              
67             # Ignore debug messages in production
68 77 50 33     933 return if $type !~ $TYPE_RE || (!$debug && $type eq 'debug');
      33        
69              
70 77         151 my $notes;
71              
72             # Notifications already set
73 77 100       255 if ($notes = $c->stash('notify.array')) {
74 26         309 push @$notes, [$type => @msg];
75             }
76              
77             # New notifications as a Mojo::Collection
78             else {
79 51         871 $c->stash('notify.array' => c([$type => @msg]));
80             };
81             }
82 10         127 );
83              
84              
85             # Embed notification display
86             $app->helper(
87             notifications => sub {
88 71     71   232202 my $c = shift;
89              
90 71 100       320 return $asset unless @_;
91              
92 55         170 my $e_type = lc shift;
93 55         147 my @param = @_;
94              
95             # Get stash notifications
96 55   66     176 my $notes = ($c->stash->{'notify.array'} //= c());
97              
98             # Get flash notifications
99 55         1090 my $flash = $c->flash('n!.a');
100              
101 55 100 66     16502 if ($flash && ref $flash eq 'ARRAY') {
102              
103             # Ensure that no harmful types are injected
104 11         34 unshift @$notes, grep { $_->[0] =~ $TYPE_RE } @$flash;
  21         205  
105             };
106              
107             # Emit hook for further flexibility
108 55         206 $app->plugins->emit_hook(
109             before_notifications => $c, $notes
110             );
111              
112             # Delete from stash
113 55         880 delete $c->stash->{'notify.array'};
114              
115             # Nothing to do
116 55 100 100     568 return '' unless $notes->size || @_;
117              
118             # Forward messages to notification center
119 46 50       421 if (exists $engine{$e_type}) {
120              
121 46         88 my %rule;
122 46   100     274 while ($param[-1] && index($param[-1], '-') == 0) {
123 1         7 $rule{lc(substr(pop @param, 1))} = 1;
124             };
125              
126 46         296 return $engine{$e_type}->notifications($c, $notes, \%rule, @param);
127             }
128             else {
129 0         0 $c->app->log->error(qq{Unknown notification engine "$e_type"});
130 0         0 return;
131             };
132             }
133 10         1476 );
134              
135              
136             # Add hook for redirects
137             $app->hook(
138             after_dispatch => sub {
139 61     61   32442 my $c = shift;
140              
141 61 100       194 if ($c->res->is_redirect) {
142             # Get notify array from stash
143 21         472 my $notes = delete $c->stash->{'notify.array'};
144              
145             # Check flash notes
146 21 100       197 if ($c->flash('n!.a')) {
147              
148             # Merge notes with flash
149 10 50       4260 if ($notes) {
150 10         30 unshift @$notes, @{$c->flash('n!.a')};
  10         42  
151             }
152              
153             # Get notes from flash
154             else {
155 0         0 $notes = $c->flash('n!.a');
156             };
157             };
158              
159 21 50       3086 if ($notes) {
160 21         111 $c->flash('n!.a' => $notes);
161             };
162             };
163 10         865 });
164             };
165              
166              
167             1;
168              
169              
170             __END__