File Coverage

blib/lib/App/Dochazka/CLI/Commands/Employee.pm
Criterion Covered Total %
statement 43 194 22.1
branch 6 98 6.1
condition 0 17 0.0
subroutine 16 28 57.1
pod 14 14 100.0
total 79 351 22.5


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             # employee command targets
34             package App::Dochazka::CLI::Commands::Employee;
35              
36 20     20   274 use 5.012;
  20         40  
37 20     20   59 use strict;
  20         20  
  20         294  
38 20     20   56 use warnings;
  20         18  
  20         419  
39              
40 20     20   53 use App::CELL qw( $CELL $log );
  20         31  
  20         1630  
41 20     20   86 use App::Dochazka::CLI qw( $current_emp $current_priv $debug_mode );
  20         32  
  20         1495  
42 20         940 use App::Dochazka::CLI::Util qw(
43             determine_employee
44             lookup_employee
45             parse_test
46             refresh_current_emp
47             rest_error
48 20     20   76 );
  20         25  
49 20     20   72 use App::Dochazka::Common::Model::Employee;
  20         20  
  20         374  
50 20     20   57 use Data::Dumper;
  20         19  
  20         627  
51 20     20   59 use Exporter 'import';
  20         21  
  20         381  
52 20     20   9130 use Term::ReadKey;
  20         27225  
  20         1212  
53 20     20   90 use Web::MREST::CLI qw( send_req );
  20         20  
  20         33666  
54              
55              
56              
57              
58             =head1 NAME
59              
60             App::Dochazka::CLI::Commands::Employee - Employee commands
61              
62              
63              
64              
65             =head1 PACKAGE VARIABLES AND EXPORTS
66              
67             =cut
68              
69             our @EXPORT_OK = qw(
70             employee_ldap
71             employee_ldap_import
72             employee_list
73             employee_profile
74             employee_team
75             set_employee_self_sec_id
76             set_employee_other_sec_id
77             set_employee_self_fullname
78             set_employee_other_fullname
79             set_employee_self_password
80             set_employee_other_password
81             set_employee_supervisor
82             );
83              
84              
85             =head1 FUNCTIONS
86              
87             =head2 Command handlers
88              
89             =head3 employee_profile
90              
91             EMPLOYEE
92             EMPLOYEE_SPEC
93             EMPLOYEE PROFILE
94             EMPLOYEE_SPEC PROFILE
95             EMPLOYEE SHOW
96             EMPLOYEE_SPEC SHOW
97              
98             =cut
99              
100             sub employee_profile {
101 6 50   6 1 14 print "Entering " . __PACKAGE__ . "::employee_profile\n" if $debug_mode;
102 6         8 my ( $ts, $th ) = @_;
103              
104             # parse test
105 6 50       23 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
106              
107             # determine employee
108 0         0 my $status = determine_employee( $th->{'EMPLOYEE_SPEC'} );
109 0 0       0 return $status unless $status->ok;
110 0         0 my $emp = $status->payload;
111              
112 0         0 return _display_employee_ok( $emp );
113             }
114              
115              
116             =head3 employee_ldap
117              
118             EMPLOYEE LDAP
119             EMPLOYEE_SPEC LDAP
120              
121             =cut
122              
123             sub employee_ldap {
124 0 0   0 1 0 print "Entering " . __PACKAGE__ . "::employee_ldap\n" if $debug_mode;
125 0         0 my ( $ts, $th ) = @_;
126              
127             # parse test
128 0 0       0 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
129              
130             # determine nick
131 0         0 my $nick;
132 0 0       0 if ( my $spec = $th->{'EMPLOYEE_SPEC'} ) {
133             # other; just take whatever is after the '='
134 0         0 ( $nick ) = $spec =~ m/=(.+)$/;
135             } else {
136             # self; get $nick from $current_emp
137 0         0 $nick = $current_emp->nick;
138             }
139              
140             # send the request
141 0         0 my $status = send_req( 'GET', "employee/nick/$nick/ldap" );
142 0 0       0 return $status unless $status->ok;
143              
144             # success: spawn and populate object
145             my $emp = App::Dochazka::Common::Model::Employee->spawn(
146 0         0 %{ $status->payload }
  0         0  
147             );
148              
149 0         0 my $message = "\n";
150 0         0 $message .= "Nick: " . $emp->nick . "\n";
151 0 0       0 $message .= "LDAP full name: " . ( $emp->fullname ? $emp->fullname : "(not set)" ) . "\n";
152 0   0     0 $message .= "LDAP email: " . ( $emp->email || "(not set)" ) . "\n";
153 0 0       0 $message .= "LDAP secondary ID: " . ( $emp->sec_id ? $emp->sec_id : "(not set)" ) . "\n";
154            
155 0 0       0 if ( $current_priv eq 'admin' ) {
156             # determine if employee already exists in Dochazka database
157 0         0 my $status = send_req( 'GET', "employee/nick/" . $emp->nick . "/minimal" );
158 0 0 0     0 if ( $status->level eq 'OK' and $status->code eq 'DOCHAZKA_EMPLOYEE_MINIMAL' ) {
159 0         0 my $nick = $status->payload->{'nick'};
160 0         0 my $eid = $status->payload->{'eid'};
161 0         0 $message .= "\nEmployee $nick already exists in Dochazka with EID $eid\n";
162             } else {
163 0         0 my $nick = $emp->nick;
164 0         0 $message .= "\nEmployee $nick is missing in Dochazka; to import, do \"EMPL=$nick LDAP IMPORT\"\n";
165             }
166             }
167              
168 0         0 return $CELL->status_ok( 'DOCHAZKA_CLI_NORMAL_COMPLETION', payload => $message );
169             }
170              
171              
172             =head3 employee_ldap_import
173              
174             EMPLOYEE_SPEC LDAP IMPORT
175              
176             =cut
177              
178             sub employee_ldap_import {
179 0 0   0 1 0 print "Entering " . __PACKAGE__ . "::employee_ldap_import\n" if $debug_mode;
180 0         0 my ( $ts, $th ) = @_;
181              
182             # parse test
183 0 0       0 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
184              
185             # determine nick
186 0         0 my ( $nick ) = $th->{'EMPLOYEE_SPEC'} =~ m/=(.+)$/;
187              
188             # send the request
189 0         0 my $status = send_req( 'PUT', "employee/nick/$nick/ldap" );
190 0 0 0     0 if ( $status->level eq 'OK' and $status->code eq 'DOCHAZKA_CUD_OK' ) {
191 0         0 return employee_profile( $ts, $th );
192             } else {
193 0         0 return $status;
194             }
195             }
196              
197            
198             =head3 employee_list
199              
200             EMPLOYEE LIST
201             EMPLOYEE LIST _TERM
202              
203             =cut
204              
205             sub employee_list {
206 0     0 1 0 my ( $ts, $th ) = @_;
207              
208             # parse test
209 0 0       0 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
210              
211 0         0 my $priv;
212 0 0       0 my $status = ( $priv = $th->{'_TERM'} )
213             ? send_req( 'GET', "employee/list/$priv" )
214             : send_req( 'GET', "employee/list" );
215              
216 0   0     0 $priv = $priv || 'all';
217              
218 0 0       0 return $status unless $status->ok;
219             return $CELL->status_ok( 'DOCHAZKA_CLI_NORMAL_COMPLETION',
220             payload => "\nList of employees with priv level ->$priv<-\n " .
221 0         0 join( "\n ", @{ $status->payload } ) . "\n" );
  0         0  
222             }
223              
224              
225             =head3 employee_team
226              
227             EMPLOYEE TEAM
228              
229             =cut
230              
231             sub employee_team {
232 0     0 1 0 my ( $ts, $th ) = @_;
233 0         0 $log->debug( "Entering " . __PACKAGE__ . "::employee_team" );
234              
235             # parse test
236 0 0       0 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
237              
238             # determine employee
239 0         0 my $status = determine_employee( $th->{'EMPLOYEE_SPEC'} );
240 0 0       0 return $status unless $status->ok;
241 0         0 my $emp = $status->payload;
242 0         0 my $eid = $emp->eid;
243 0         0 my $nick = $emp->nick;
244              
245 0 0       0 $status = ( $eid == $current_emp->eid )
246             ? send_req( 'GET', "employee/team" )
247             : send_req( 'GET', "employee/eid/$eid/team" );
248 0 0       0 return $status unless $status->ok;
249              
250 0         0 my $message = "\nList of employees in the team of ->$nick<-\n ";
251             $message .= ( $status->payload )
252 0 0       0 ? ( join( "\n ", @{ $status->payload } ) . "\n" )
  0         0  
253             : "(none)\n";
254              
255 0         0 return $CELL->status_ok( 'DOCHAZKA_CLI_NORMAL_COMPLETION',
256             payload => $message);
257             }
258              
259              
260             =head3 set_employee_self_sec_id
261              
262             SET EMPLOYEE SEC_ID _TERM
263              
264             =cut
265              
266             sub set_employee_self_sec_id {
267 2     2 1 3 my ( $ts, $th ) = @_;
268              
269             # parse test
270 2 50       14 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
271              
272             return _set_employee(
273             emp_obj => $current_emp,
274             prop => 'sec_id',
275 0         0 val => $th->{'_TERM'},
276             );
277             }
278              
279              
280             =head3 set_employee_self_fullname
281              
282             SET EMPLOYEE FULLNAME
283              
284             =cut
285              
286             sub set_employee_self_fullname {
287 2     2 1 5 my ( $ts, $th ) = @_;
288              
289             # parse test
290 2 50       10 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
291              
292             return _set_employee(
293             emp_obj => $current_emp,
294             prop => 'fullname',
295 0         0 val => $th->{'_REST'},
296             );
297             }
298              
299              
300             =head3 set_employee_other_sec_id
301              
302             EMPLOYEE_SPEC SET SEC_ID _TERM
303              
304             =cut
305              
306             sub set_employee_other_sec_id {
307 2     2 1 4 my ( $ts, $th ) = @_;
308              
309             # parse test
310 2 50       10 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
311              
312             return _set_employee(
313             emp_spec => $th->{'EMPLOYEE_SPEC'},
314             prop => 'sec_id',
315 0         0 val => $th->{'_TERM'},
316             );
317             }
318              
319              
320             =head3 set_employee_other_fullname
321              
322             EMPLOYEE_SPEC SET FULLNAME
323              
324             =cut
325              
326             sub set_employee_other_fullname {
327 2     2 1 4 my ( $ts, $th ) = @_;
328              
329             # parse test
330 2 50       10 return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
331              
332             return _set_employee(
333             emp_spec => $th->{'EMPLOYEE_SPEC'},
334             prop => 'fullname',
335 0           val => $th->{'_REST'},
336             );
337             }
338              
339              
340             =head3 set_employee_self_password
341              
342             Reset one's own password
343              
344             EMPLOYEE PASSWORD
345             EMPLOYEE SET PASSWORD
346              
347             =cut
348              
349             sub set_employee_self_password {
350 0     0 1   my ( $ts, $th ) = @_;
351              
352             # parse test
353 0 0         return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
354              
355             return _set_password(
356             eid => $current_emp->eid,
357 0           password => $th->{'_REST'},
358             );
359             }
360              
361              
362             =head3 set_employee_other_password
363              
364             Reset password of an arbitrary employee
365              
366             EMPLOYEE_SPEC PASSWORD
367             EMPLOYEE_SPEC SET PASSWORD
368              
369             =cut
370              
371             sub set_employee_other_password {
372 0 0   0 1   print "Entering " . __PACKAGE__ . "::set_employee_other_password\n" if $debug_mode;
373 0           my ( $ts, $th ) = @_;
374              
375             # parse test
376 0 0         return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
377              
378 0           my $status = determine_employee( $th->{EMPLOYEE_SPEC} );
379 0 0         return $status unless $status->ok;
380 0           my $emp = $status->payload;
381              
382             return _set_password(
383             eid => $emp->eid,
384 0           password => $th->{'_REST'},
385             );
386             }
387              
388              
389             =head3 set_employee_supervisor
390              
391             Set supervisor of an arbitrary employee
392              
393             EMPLOYEE_SPEC SUPERVISOR _TERM
394             EMPLOYEE_SPEC SET SUPERVISOR _TERM
395              
396             =cut
397              
398             sub set_employee_supervisor {
399 0 0   0 1   print "Entering " . __PACKAGE__ . "::set_employee_supervisor\n" if $debug_mode;
400 0           my ( $ts, $th ) = @_;
401              
402             # parse test
403 0 0         return parse_test( $ts, $th ) if $ts eq 'PARSE_TEST';
404              
405             # get employee object
406 0           my $status = determine_employee( $th->{EMPLOYEE_SPEC} );
407 0 0         return $status unless $status->ok;
408 0           my $emp = $status->payload;
409 0           my $emp_eid = $emp->eid;
410              
411             # get supervisor employee object
412 0           $status = determine_employee( 'EMPL=' . $th->{_TERM} );
413 0 0         return $status unless $status->ok;
414 0           my $supervisor = $status->payload;
415 0           my $supervisor_eid = $supervisor->eid;
416              
417             # send the HTTP request
418 0           $status = send_req( 'POST', "employee/eid", <<"EOS" );
419             { "eid" : $emp_eid, "supervisor" : $supervisor_eid }
420             EOS
421 0 0         return $status unless $status->ok;
422              
423             # display the employee profile -> it will include the new supervisor
424 0           $emp->reset( $status->payload );
425 0           return _display_employee_ok( $emp );
426             }
427              
428              
429              
430             =head2 Helper functions
431              
432             Functions used by multiple handlers
433              
434              
435             =head3 determine_priv
436              
437             Given an employee object, return the current priv level of that employee.
438             If the employee doesn't exist, the return value will be undef.
439              
440             =cut
441              
442             sub determine_priv {
443 0     0 1   my ( $emp ) = @_;
444              
445 0 0         return undef unless ref( $emp ) eq 'App::Dochazka::REST::Model::Employee';
446 0 0 0       return undef unless $emp->eid and $emp->nick;
447              
448             # GET priv/eid/:eid
449 0           my $status = send_req( 'GET', 'priv/eid/' . $emp->eid );
450 0 0         if ( $status->not_ok ) {
451 0           $log->error( "Could not determine priv level of employee -> " . $emp->nick .
452             "<- because: " . $status->text );
453 0           return undef;
454             }
455 0           return $status->payload->{'priv'};
456             }
457              
458              
459             =head3 determine_supervisor
460              
461             Given an employee object, return supervisor employee object.
462             If no supervisor can be determined, the 'eid' and 'nick' attributes of the
463             resulting supervisor object will be undefined.
464              
465             =cut
466              
467             sub determine_supervisor {
468 0     0 1   my ( $emp ) = @_;
469 0           my $supervisor = App::Dochazka::Common::Model::Employee->spawn();
470 0 0         if ( my $supervisor_eid = $emp->supervisor ) {
471 0           my $status = determine_employee( "EMPL=$supervisor_eid" );
472 0 0         if ( $status->ok ) {
473 0           $supervisor = $status->payload;
474             } else {
475 0           $log->warn( "Failed to look up supervisor by EID $supervisor_eid; error was " . $status->text );
476             }
477             }
478 0           return $supervisor;
479             }
480              
481              
482             =head3 _set_employee
483              
484             Function that the handlers are wrappers of
485              
486             =cut
487              
488             sub _set_employee {
489 0     0     my %PROPLIST = @_;
490 0           my $status;
491             my $emp_obj;
492 0 0         if ( my $e_spec = $PROPLIST{'emp_spec'} ) {
    0          
493 0           $status = determine_employee( $e_spec );
494 0 0         return $status unless $status->ok;
495 0           $emp_obj = $status->payload;
496             } elsif ( $emp_obj = $PROPLIST{'emp_obj'} ) {
497             } else {
498 0           die "AAAAAAAAAAAAAHHHHH!";
499             }
500 0           my $eid = $emp_obj->eid;
501 0           my $prop = $PROPLIST{'prop'};
502 0           my $val = $PROPLIST{'val'};
503 0           $val =~ s/['"]//g;
504 0           $status = send_req( 'POST', "employee/eid", <<"EOS" );
505             { "eid" : $eid, "$prop" : "$val" }
506             EOS
507 0 0         return rest_error( $status, "Modify employee profile" ) unless $status->ok;
508              
509 0           my $message = "Profile of employee " . $emp_obj->nick .
510             " has been modified ($prop -> $val)\n";
511              
512 0           return $CELL->status_ok( 'DOCHAZKA_CLI_NORMAL_COMPLETION', payload => $message );
513             }
514              
515              
516             =head3 _set_password
517              
518             Takes PARAMHASH with following properties:
519              
520             eid => EID of employee
521             password => the new password (*optional*)
522              
523             =cut
524              
525             sub _set_password {
526 0     0     my %PH = @_;
527 0           my $eid = $PH{'eid'};
528 0           my $newpass = $PH{'password'};
529              
530 0           print "It is important that the new password really be what you intended.\n";
531 0           print "Therefore, we are going to ask you to enter the desired password\n";
532 0           print "twice, so you have a chance to double-check. ";
533 0           print "\n\n";
534              
535             # prompt for new password and ask nicely for confirmation
536 0 0         if ( ! $newpass ) {
537 0           ReadMode ('noecho');
538 0           print "New password : ";
539 0           chomp( $newpass = <> );
540 0           ReadMode ('restore');
541 0           print "\n";
542             }
543 0           ReadMode ('noecho');
544 0           print "New password again: ";
545 0           chomp( my $confirm = <> );
546 0           ReadMode ('restore');
547 0           print "\n";
548 0 0         return $CELL->status_err( 'DOCHAZKA_CLI_NO_MATCH' ) unless $newpass eq $confirm;
549              
550             # send REST request
551 0           my $status = send_req( 'PUT', "employee/eid/$eid", <<"EOS" );
552             { "password" : "$newpass" }
553             EOS
554              
555 0 0         return $status unless $status->ok;
556 0           return $CELL->status_ok( 'DOCHAZKA_CLI_NORMAL_COMPLETION',
557             payload => "Password changed" );
558             }
559              
560              
561             =head3 _display_employee_ok
562              
563             Given an employee object, prepare OK return status intended for EMPLOYEE PROFILE
564             but usable also for other commands.
565              
566             =cut
567              
568             sub _display_employee_ok {
569 0     0     my ( $emp ) = @_;
570              
571             # determine supervisor
572 0           my $supervisor = determine_supervisor( $emp );
573              
574 0           my $message = "\n";
575 0 0         $message .= "Full name: " . ( $emp->fullname ? $emp->fullname : "(not set)" ) . "\n";
576 0           $message .= "Nick: " . $emp->nick . "\n";
577 0   0       $message .= "Email: " . ( $emp->email || "(not set)" ) . "\n";
578 0 0         $message .= "Secondary ID: " . ( $emp->sec_id ? $emp->sec_id : "(not set)" ) . "\n";
579 0           $message .= "Dochazka EID: " . $emp->eid . "\n";
580 0   0       $message .= "Reports to: " . ( $supervisor->nick || "(not set)" ) . "\n";
581              
582 0           return $CELL->status_ok( 'DOCHAZKA_CLI_NORMAL_COMPLETION', payload => $message );
583             }
584              
585              
586             1;