File Coverage

blib/lib/App/Dochazka/CLI/Commands/History.pm
Criterion Covered Total %
statement 44 148 29.7
branch 10 66 15.1
condition 0 18 0.0
subroutine 15 20 75.0
pod 5 5 100.0
total 74 257 28.7


line stmt bran cond sub pod time code
1             # *************************************************************************
2             # Copyright (c) 2014-2016, SUSE LLC
3             #
4             # All rights reserved.
5             #
6             # Redistribution and use in source and binary forms, with or without
7             # modification, are permitted provided that the following conditions are met:
8             #
9             # 1. Redistributions of source code must retain the above copyright notice,
10             # this list of conditions and the following disclaimer.
11             #
12             # 2. Redistributions in binary form must reproduce the above copyright
13             # notice, this list of conditions and the following disclaimer in the
14             # documentation and/or other materials provided with the distribution.
15             #
16             # 3. Neither the name of SUSE LLC nor the names of its contributors may be
17             # used to endorse or promote products derived from this software without
18             # specific prior written permission.
19             #
20             # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21             # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22             # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23             # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24             # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25             # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26             # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27             # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28             # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29             # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30             # POSSIBILITY OF SUCH DAMAGE.
31             # *************************************************************************
32             #
33             # History commands
34             package App::Dochazka::CLI::Commands::History;
35              
36 20     20   271 use 5.012;
  20         45  
37 20     20   61 use strict;
  20         19  
  20         286  
38 20     20   52 use warnings;
  20         19  
  20         394  
39              
40 20     20   53 use App::CELL qw( $CELL );
  20         19  
  20         1406  
41 20     20   78 use App::Dochazka::CLI qw( $current_emp $debug_mode );
  20         21  
  20         1388  
42 20     20   72 use App::Dochazka::CLI::Util qw( lookup_employee parse_test rest_error truncate_to );
  20         20  
  20         872  
43 20     20   93 use Data::Dumper;
  20         31  
  20         719  
44 20     20   89 use Exporter 'import';
  20         25  
  20         447  
45 20     20   9490 use Text::Table;
  20         203334  
  20         493  
46 20     20   99 use Web::MREST::CLI qw( send_req );
  20         23  
  20         21185  
47              
48              
49              
50              
51             =head1 NAME
52              
53             App::Dochazka::CLI::Commands::History - History commands
54              
55              
56              
57              
58             =head1 PACKAGE VARIABLES
59              
60             =cut
61              
62             our @EXPORT_OK = qw(
63             add_priv_history
64             add_schedule_history
65             dump_priv_history
66             dump_schedule_history
67             set_history_remark
68             );
69              
70              
71              
72              
73             =head1 FUNCTIONS
74              
75             The functions in this module are called from the parser when it recognizes a command.
76              
77              
78             =head2 Command handlers
79              
80             Command handler functions are called from the parser.
81              
82              
83             =head3 dump_priv_history
84              
85             PRIV HISTORY
86             EMPLOYEE_SPEC PRIV HISTORY
87              
88             =cut
89              
90             sub dump_priv_history {
91 2 50   2 1 7 print "Entering " . __PACKAGE__ . "::dump_priv_history\n" if $debug_mode;
92 2         3 my ( $ts, $th ) = @_;
93              
94             # parse test
95 2 50       9 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
96              
97             my $emp_spec = ( $th->{'EMPLOYEE_SPEC'} )
98 0 0       0 ? $th->{'EMPLOYEE_SPEC'}
99             : $current_emp;
100              
101 0         0 return _dump_history(
102             emp_spec => $emp_spec,
103             type => 'priv',
104             );
105             }
106              
107              
108             =head3 dump_schedule_history
109              
110             SCHEDULE HISTORY
111             EMPLOYEE_SPEC SCHEDULE HISTORY
112              
113             =cut
114              
115             sub dump_schedule_history {
116 2 50   2 1 6 print "Entering " . __PACKAGE__ . "::dump_schedule_history\n" if $debug_mode;
117 2         3 my ( $ts, $th ) = @_;
118              
119             # parse test
120 2 50       9 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
121              
122             my $emp_spec = ( $th->{'EMPLOYEE_SPEC'} )
123 0 0       0 ? $th->{'EMPLOYEE_SPEC'}
124             : $current_emp;
125              
126 0         0 return _dump_history(
127             emp_spec => $emp_spec,
128             type => 'schedule',
129             );
130             }
131              
132              
133             =head3 add_priv_history
134              
135             Add privilege history record.
136              
137             EMPLOYEE_SPEC PRIV_SPEC _DATE
138             EMPLOYEE_SPEC PRIV_SPEC EFFECTIVE _DATE
139             EMPLOYEE_SPEC SET PRIV_SPEC _DATE
140             EMPLOYEE_SPEC SET PRIV_SPEC EFFECTIVE _DATE
141              
142             =cut
143              
144             sub add_priv_history {
145 4 50   4 1 11 print "Entering " . __PACKAGE__ . "::add_priv_history\n" if $debug_mode;
146 4         5 my ( $ts, $th ) = @_;
147              
148             # parse test
149 4 50       15 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
150              
151             my $emp_spec = ( $th->{'EMPLOYEE_SPEC'} )
152 0 0       0 ? $th->{'EMPLOYEE_SPEC'}
153             : $current_emp;
154              
155             return _add_history(
156             emp_spec => $emp_spec,
157             type => 'priv',
158             effective => $th->{'_DATE'},
159 0         0 priv => $th->{'PRIV_SPEC'},
160             );
161             }
162              
163              
164             =head3 add_schedule_history
165              
166             Add schedule history record.
167              
168             EMPLOYEE_SPEC SCHEDULE_SPEC _DATE
169             EMPLOYEE_SPEC SCHEDULE_SPEC EFFECTIVE _DATE
170             EMPLOYEE_SPEC SET SCHEDULE_SPEC _DATE
171             EMPLOYEE_SPEC SET SCHEDULE_SPEC EFFECTIVE _DATE
172              
173             =cut
174              
175             sub add_schedule_history {
176 4 50   4 1 10 print "Entering " . __PACKAGE__ . "::add_schedule_history\n" if $debug_mode;
177 4         5 my ( $ts, $th ) = @_;
178              
179             # parse test
180 4 50       16 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
181              
182             my $emp_spec = ( $th->{'EMPLOYEE_SPEC'} )
183 0 0       0 ? $th->{'EMPLOYEE_SPEC'}
184             : $current_emp;
185              
186 0         0 my ( $key_spec, $key ) = $th->{'SCHEDULE_SPEC'} =~ m/^(.*)\=(.*)$/;
187 0         0 $key_spec = lc $key_spec;
188              
189             return _add_history(
190             emp_spec => $emp_spec,
191             type => 'schedule',
192 0         0 effective => $th->{'_DATE'},
193             $key_spec => $key,
194             );
195             }
196              
197              
198             =head3 set_history_remark
199              
200             PHISTORY_SPEC REMARK
201             PHISTORY_SPEC SET REMARK
202             SHISTORY_SPEC REMARK
203             SHISTORY_SPEC SET REMARK
204              
205             =cut
206              
207             sub set_history_remark {
208 4 50   4 1 11 print "Entering " . __PACKAGE__ . "::dump_schedule_history\n" if $debug_mode;
209 4         5 my ( $ts, $th ) = @_;
210              
211             # parse test
212 4 50       15 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
213              
214 0           my ( $type, $id_spec, $id );
215 0 0         if ( $th->{'PHISTORY_SPEC'} ) {
    0          
216 0           $type = 'priv';
217 0           $id_spec = 'phid';
218 0           $id = $th->{'PHISTORY_SPEC'};
219             } elsif ( $th->{'SHISTORY_SPEC'} ) {
220 0           $type = 'schedule';
221 0           $id_spec = 'shid';
222 0           $id = $th->{'SHISTORY_SPEC'};
223             } else {
224 0           die "Agh~! neither PHISTORY_SPEC nor SHISTORY_SPEC given";
225             }
226              
227 0   0       my $remark = $th->{'_REST'} || '';
228 0           $remark =~ s/[\"\']//g;
229              
230 0           my $status = send_req( 'POST', "$type/history/$id_spec/$id", <<"EOS" );
231             { "remark" : "$remark" }
232             EOS
233              
234 0           return $status;
235             }
236              
237              
238             =head2 Helper functions
239              
240             Functions called from multiple command handlers.
241              
242              
243             =head3 _add_history
244              
245             Add a history record
246              
247             =cut
248              
249             sub _add_history {
250 0     0     my %ARGS = @_;
251              
252             # get type
253 0           my $type = $ARGS{'type'};
254              
255             # get EID
256 0           my ( $emp_obj, $status );
257 0           $status = _process_employee_spec( $ARGS{'emp_spec'} );
258 0 0         return $status unless $status->ok;
259 0           my $eid = $status->payload->{'eid'};
260              
261             # get key_spec and key
262 0           my ( $key_spec, $key );
263 0 0         if ( exists( $ARGS{'priv'} ) ) {
    0          
    0          
264 0           $key_spec = 'priv';
265 0           $key = $ARGS{'priv'};
266             } elsif ( exists( $ARGS{'scode'} ) ) {
267             # special case - since the underlying App::Dochazka::REST resource
268             # only takes a 'sid', we have to look up the scode to determine the sid
269 0           my $status = send_req( 'GET', "schedule/scode/$ARGS{'scode'}" );
270 0           my $sid;
271 0 0 0       if ( $status->ok and $status->code eq 'DISPATCH_SCHEDULE_FOUND' ) {
272 0           $sid = $status->payload->{'sid'};
273             } else {
274 0           return $status;
275             }
276 0           $key_spec = 'sid';
277 0           $key = $sid;
278             } elsif ( exists( $ARGS{'sid'} ) ) {
279 0           $key_spec = 'sid';
280 0           $key = $ARGS{'sid'};
281             } else {
282 0   0       die "AHAAHHA!! bad key_spec " . ( $key_spec || "undefined" );
283             }
284              
285             # get effective
286 0   0       my $effective = $ARGS{'effective'} || "undefined";
287              
288             # send REST request
289 0           $status = send_req( 'POST', "$type/history/eid/$eid", <<"EOS" );
290             { "$key_spec" : "$key", "effective" : "$effective" }
291             EOS
292              
293 0 0 0       if ( $status->ok and $status->code eq 'DOCHAZKA_CUD_OK' ) {
294 0 0         if ( $type eq 'priv' ) {
    0          
295             $status = $CELL->status_ok( "DOCHAZKA_CLI_PRIV_HISTORY_ADD",
296 0           args => [ $status->payload->{'phid'} ] );
297             } elsif ( $type eq 'schedule' ) {
298             $status = $CELL->status_ok( "DOCHAZKA_CLI_SCHEDULE_HISTORY_ADD",
299 0           args => [ $status->payload->{'shid'} ] );
300             } else {
301 0   0       die "AH!@! bad type " . ( $type || "undefined" );
302             }
303             }
304              
305 0           return $status;
306             }
307              
308              
309             =head3 _dump_history
310              
311             =cut
312              
313             sub _dump_history {
314 0     0     my %ARGS = @_;
315              
316             # get type
317 0           my $type = $ARGS{'type'};
318              
319             # get EID
320 0           my ( $emp_obj, $status );
321 0           $status = _process_employee_spec( $ARGS{'emp_spec'} );
322 0 0         return $status unless $status->ok;
323 0           my $eid = $status->payload->{'eid'};
324 0 0         die "AAHQ! Could not extract EID from payload: " . Dumper( $status ) unless $eid;
325              
326             # get $type history for that EID
327 0           $status = send_req( 'GET', "$type/history/eid/$eid" );
328 0 0         if ( $status->ok ) {
329 0           my $pl;
330 0 0         if ( $type eq 'priv' ) {
    0          
331 0           $pl .= _print_priv_history( $status->payload );
332             } elsif ( $type eq 'schedule' ) {
333 0           $pl .= _print_schedule_history( $status->payload );
334             } else {
335 0   0       die "AH! bad type " . $type || "undefined";
336             }
337 0           return $CELL->status_ok( 'DOCHAZKA_CLI_NORMAL_COMPLETION', payload => $pl );
338             }
339              
340 0           return $status;
341             }
342              
343              
344             =head3 _print_priv_history
345              
346             Take a privhistory and print it
347              
348             =cut
349              
350             sub _print_priv_history {
351 0     0     my $props = shift;
352 0           my $eid = $props->{'eid'};
353 0           my $nick = $props->{'nick'};
354              
355 0           my $pl = '';
356 0           $pl .= "Privilege history of $nick (EID $eid):\n\n";
357              
358 0           my $t = Text::Table->new( 'PHID', 'Effective date', 'Privlevel', 'Remark' );
359 0           foreach my $entry ( @{ $props->{'history'} } ) {
  0            
360 0           my ( $effective ) = $entry->{'effective'} =~ m/(\S+)\s/;
361             $t->add(
362             $entry->{'phid'},
363             $effective,
364             $entry->{'priv'},
365 0           truncate_to( $entry->{'remark'} ),
366             );
367             }
368              
369 0           $pl .= $t;
370              
371 0           return $pl;
372             }
373              
374              
375             =head3 _print_schedule_history
376              
377             Take a schedhistory and print it
378              
379             =cut
380              
381             sub _print_schedule_history {
382 0     0     my $props = shift;
383 0           my $eid = $props->{'eid'};
384 0           my $nick = $props->{'nick'};
385              
386 0           my $pl = '';
387 0           $pl .= "Schedule history of $nick (EID $eid):\n\n";
388              
389 0           my $t = Text::Table->new( 'SHID', 'Effective date', 'SID', 'scode', 'Remark' );
390 0           foreach my $entry ( @{ $props->{'history'} } ) {
  0            
391 0           my ( $effective ) = $entry->{'effective'} =~ m/(\S+)\s/;
392 0           my $status = send_req( 'GET', 'schedule/sid/' . $entry->{'sid'} );
393 0           my ( $scode, $remark );
394 0 0         if ( $status->ok ) {
395 0   0       $scode = $status->payload->{'scode'} || '';
396             } else {
397 0           $scode = '';
398             }
399             $t->add(
400             $entry->{'shid'},
401             $effective,
402             $entry->{'sid'},
403             $scode,
404 0           truncate_to( $entry->{'remark'} ),
405             );
406             }
407              
408 0           $pl .= $t;
409              
410 0           return $pl;
411             }
412              
413              
414             =head3 _process_employee_spec
415              
416             Given EMPLOYEE_SPEC, return a status object that can either be OK with
417             employee object in payload or NOT_OK with mrest_declare_status already
418             called.
419              
420             =cut
421              
422             sub _process_employee_spec {
423 0     0     my $emp_spec = shift;
424              
425 0           my ( $eid, $status );
426 0 0         if ( $emp_spec->can('eid') ) {
    0          
427 0           $status = $CELL->status_ok( 'DUMMY', payload => $emp_spec->TO_JSON );
428             } elsif ( ref( $emp_spec ) eq '' ) {
429 0           $status = lookup_employee( key => $emp_spec );
430 0 0         return rest_error( $status, "Employee lookup" ) unless $status->ok;
431             } else {
432 0           die "AGHHAH! bad employee specifier";
433             }
434              
435 0           return $status;
436             }
437            
438              
439             1;