Looking Ahead

Understanding and Deploying LDAP Directory Services > 20. Developing New Applications > Example 2: An Employee Time-Off Request Web Application

<  BACK CONTINUE  >
153021169001182127177100019128036004029190136140232051053054012002228051028019253207149

Example 2: An Employee Time-Off Request Web Application

A common administrative task that managers must handle is a request by an employee for paid time off, usually in the form of sick days and vacation days. In a typical organization, the time off request process consists of these steps:

  1. An employee fills out a paper form specifying the days she will be on vacation or the days she was out sick.

  2. The employee gives the paper form to her manager.

  3. The manager approves or turns down the request and informs the employee of the decision.

  4. If the manager approves the request, he sends the paper form to the payroll department, where the time off is tracked and reported on the employee's paycheck.

In this section, we present a sample workflow application that uses an HTML form, an LDAP directory service, and email to automate most of these steps.

Directory Use

Our time-off request processing application uses the directory service for the following tasks :

  • Finding the employee's entry given her user ID. This is done using an LDAP subtree search.

  • Finding the DN of the employee's manager. This is done by checking her directory entry for a manager attribute value.

  • Verifying the employee's identity by checking a password she provides against the one stored in the directory entry. This is done using an LDAP bind operation.

  • Retrieving the email address of the employee's manager. This is done by reading the manager's entry using an LDAP search operation with a base object scope.

Because all the directory interaction takes place in a single Perl script, our time-off request application is able to use the directory efficiently . Because of a limitation of the PerLDAP module we use, however, two connections to the LDAP server are made instead of one. This minor problem is discussed in greater detail later.

The Source Code

The source code for our time-off request workflow application consists of two files: an HTML form called timeoff.html and a Perl common gateway interface (CGI) script called processto.pl. The HTML form provides the interface for an employee who is making the time off request. The Perl CGI script processes the form, uses email to send the request to the employee's manager, and provides feedback to the employee so she knows her request has been received and sent to her manager.

Listing 20.12 shows the contents of the timeoff.html file. The majority of the HTML code consists of a form that will be posted to the processto.pl script (as specified by line 5 of Listing 20.12).

Listing 20.12 The source code for the timeoff.html form

1. <HTML> 2. <TITLE>Employee Time Off Request Form</TITLE> 3. <BODY> 4. <CENTER><H2>Employee Time Off Request Form</H2></CENTER> 5. <FORM METHOD=post ACTION=/cgibin/processto.pl> 6. <TABLE> 7. <TR><TD>User ID:</TD><TD> 8. <INPUT NAME =" userid " TYPE="text"</TD> 9. <TD>Password:</TD><TD> 10. <INPUT NAME="password" TYPE="password"></TD> 11. </TABLE> 12. <HR> 13. <H3>Sick Time Requested:</H3> 14. Start Date: 15. <INPUT NAME="sickstart" TYPE="text" SIZE=12> 16.    End Date: 17. <INPUT NAME="sickend" TYPE="text" SIZE=12> 18.    Total Hours: 19. <INPUT NAME="sickhours" TYPE="text" SIZE=10> 20. <HR> 21. <H3>Vacation Time Requested:</H3> 22. Start Date: 23. <INPUT NAME="vacstart" TYPE="text" SIZE=12> 24.    End Date: 25. <INPUT NAME="vacend" TYPE="text" SIZE=12> 26.    Total Hours: 27. <INPUT NAME="vachours" TYPE="text" SIZE =10> 28. <HR> 29. <H3>Explanation:</H3> 30. <TEXTAREA NAME="explanation" ROWS=3 COLS=60> 31. </TEXTAREA> 32. <HR> 33. <INPUT TYPE="submit" VALUE="Send This Request To Your Manager"> 34.         35. <INPUT TYPE="reset" VALUE="Clear This Form"> 36. </FORM> 37. </BODY> 38. </HTML>

This HTML file defines 11 form input fields. Two of the form fields are for employee identification ( userid and password ), seven are for data about the time-off request itself ( sickstart , sickend , sickhours , vacstart , vacend , vachours , and explanation ), and two buttons are provided to submit and clear the form.

The processto.pl Perl script is responsible for all of the directory interaction and for sending a time-off request message to an employee's manager using SMTP. It uses the PerLDAP module (which can be downloaded from the Netscape developer Web site at http://developer.netscape.com/ tech/directory ) and the CGI and Net::SMTP modules (which can be downloaded from the comprehensive Perl archive network (CPAN) Web site at http://www.cpan.org/) . Because the processto.pl script is fairly long, we discuss it in several chunks . The first part of the script is shown in Listing 20.13.

Listing 20.13 The processto.pl prelude

1. #!/usr/local/bin/perl 2. # processto.pl -- Perl 5 script to process time off requests 3. # submitted by timeoff.html and e-mail them to an employee's 4. # manager. 5. # 6. # Requires the PerLDAP, CGI, and Net::SMTP modules. 7. use Mozilla::LDAP::Conn; 8. use CGI; 9. use Net::SMTP; 10. # LDAP server information 11. $ldapbase = "dc=airius,dc=com"; 12. $ldaphost = "directory.airius.com"; 13. $ldapport = "389"; 14. # SMTP server (for outgoing messages) 15. $smtphost = "mailhost.airius.com"; 16. $smtpFrom = "timeoff-service\@airius.com"; 17. # Global variables 18. $employeeName = ""; 19. $managerName = "";

The directory search base (used when locating the employee's entry), the LDAP server information, and the information needed to send email messages using SMTP is defined using global variables on lines 10 “16. The employeeName and managerName globals defined on lines 17 “19 are used by the findManagerEmail subroutine (discussed later) to convey additional information back to the script's main module.

The first part of the processto.pl main module is shown in Listing 20.14. This code makes extensive use of the object-oriented CGI processing interface provided by the CGI Perl module to transfer values from the posted form variables into local Perl variables.

Listing 20.14 The processto.pl main module (part 1 of 2)

1. # Start of main: 2. # Reject excessively huge posts and all file uploads 3. $CGI::POST_MAX=1024 * 10; # accept a maximum of 10K of data 4. $CGI::DISABLE_UPLOADS = 1; # disallow all file uploads 5. $post = new CGI; 6. print $post->header(); 7. # Get the values of all of the posted form variables 8. $userid = $post->param( "userid" ); 9. $password = $post->param( "password" ); 10. $sickstart = $post->param( "sickstart" ); 11. $sickend = $post->param( "sickend" ); 12. $sickhours = $post->param( "sickhours" ); 13. $vacstart = $post->param( "vacstart" ); 14. $vacend = $post->param( "vacend" ); 15. $vachours = $post->param( "vachours" ); 16. $explanation = $post->param( "explanation" ); 17. # Validate the posted variables 18. if ( $password eq "" ) { 19. incompleteForm( $post, 20. "Please go back and enter your Password" ); 21. } 22. if ( $userid eq "" ) { 23. incompleteForm( $post, 24. "Please go back and enter your User ID" ); 25. } 26. if ( $sickhours eq "" && $vachours eq "" ) { 27. incompleteForm( $post, "Please go back and enter " 28. . "some sick or vacation hours" ); 29. } 30. $employeeName = $userid; # best we have (for now)

Lines 17 “30 perform simple validation of the form contents to ensure that the minimum required set of information was provided by the employee who submitted the form.

The remainder of the main module is shown in Listing 20.15. This code first tries to find the email address of the employee's manager. If an address is found, it constructs a time-off request email message using the information posted in the time-off request form, and it sends the message to the manager for approval.

Listing 20.15 The processto.pl main module (part 2 of 2)

1. # find manager's e-mail address 2. $managerEmail = findManagerEmail( $post, $userid, $password ); 3. # construct and send an e-mail message to the manager 4. if ( $managerEmail ne "" ) { 5. $subject = "Time off request for $userid ($employeeName)."; 6. $text = "$subject\n\n"; 7. if ( $sickhours ne "" ) { 8. $text .= "Sick time hours: " 9. . "$sickhours ($sickstart-$sickend)\n"; 10. } 11. if ( $vachours ne "" ) { 12. $text .= "Vacation time hours: " 13. . "$vachours ($vacstart-$vacend)\n"; 14. } 15. if ( $explanation ne "" ) { 16. $text .= "\nExplanation: $explanation\n"; 17. } 18. $text .= "\nTo approve this request, reply and include " 19. . "the word APPROVE in the message text.\n"; 20. $text .= "\nTo deny this request, reply and include " 21. . "the word DENY in the message text.\n"; 22. $rc = sendMailMessage( $managerEmail, $smtpFrom, 23. $subject, $text ); 24. if ( $rc == 0 ) { 25. print $post->h3( "Your request has been sent to " 26. . "your manager ($managerName). You should " 27. . "soon receive an e-mail message telling " 28. . "you if your request was approved." ); 29. } else { 30. print $post->b( "Unable to send e-mail message. " 31. . "Please try again later." ); 32. displayBackButton(); 33. } 34. } 35. $post->end_html(); 36. # End of main.

All the directory interaction takes place inside the findManagerEmail subroutine (described next ), which is called on line 2. The remainder of the code in the main module constructs an email message and calls on the sendMailMessage subroutine (described later) to send the message to the manager.

The first part of the findManagerEmail subroutine is shown in Listing 20.16. The job of this subroutine is to authenticate the employee, locate her manager using the manager attribute, and read an email address value from the manager's mail attribute. Because the manager attribute is a DN-valued attribute, there is no need to do a subtree search to find the manager entry ”we can get to it directly using the value found in the employee's manager attribute.

Listing 20.16 The processto.pl findManagerEmail subroutine (part 1 of 2)

1. # Start of findManagerEmail: 2. # Connect to the LDAP server and authenticate as the user. 3. # Locate their manager's entry via the "manager" attribute. 4. # Read the manager's e-mail address from his/her "mail" 5. # attribute and return it. 6. # If any errors occur, a message is output in HTML and "" 7. # is returned. 8. # This function also emits some HTML to show the employee 9. # and manager's names , etc. 10. sub 11. findManagerEmail( $cgiout, $userid, $password ) 12. { 13. local( $cgiout, $userid, $password ) = @_; 14. local( @attrlist, $ldap, $employeeDN, $managerDN, 15. $managerMail ); 16. @attrlist = ( "cn", "mail", "manager" ); 17. $managerMail = ""; 18. # Open an anonymous connection to the LDAP server 19. $ldap = new Mozilla::LDAP::Conn( $ldaphost, $ldapport ); 20. if ( ! $ldap ) { 21. print $cgiout->b( "Unable to connect to directory" 22. . " service. Please try again later." ); 23. displayBackButton( $cgiout ); 24. return ""; 25. } 26. # Find the employee's entry 27. $entry = $ldap->search( $ldapbase, "subtree", 28. "(uid=$userid)", 0, @attrlist ); 29. if ( ! $entry ) { 30. print $cgiout->b( "No match for User ID $userid" ); 31. displayBackButton(); 32. $ldap->close; 33. return ""; 34. } 35. # Extract interesting information from the employee entry 36. $employeeDN = $entry->{"dn"}; 37. if ( $entry->{"cn"}) { 38. $employeeName = $entry->{"cn"}[0]; 39. print $cgiout->h3( "Hello $employeeName." ); 40. } 41. if ( $entry->{"manager"}) { 42. $managerDN = $entry->{"manager"}[0]; 43. } else { 44. $managerDN = ""; 45. }

We use the small attrlist array defined on line 16 in all the LDAP search requests we make. The code on lines 18 “25 opens an anonymous, unauthenticated connection to the LDAP server using the PerLDAP modules' object-oriented interface. The code on lines 26 “34 uses PerlLDAP method calls to find the employee's entry by performing a subtree search with a filter based on the user ID. Lines 35 “45 extract the employee's name (from the cn attribute) and the DN of the employee's manager (from the manager attribute), if they are present.

The remainder of the findManagerEmail subroutine is shown in Listing 20.17. This code checks the employee's password by binding to the LDAP server and reads the manager entry in order to return the manager's email address.

Listing 20.17 The processto.pl findManagerEmail subroutine (part 2 of 2)

1. # Close existing connection and open an authenticated 2. # connection to the LDAP server 3. $ldap->close; 4. $ldap = new Mozilla::LDAP::Conn( $ldaphost, $ldapport, 5. $employeeDN, $password ); 6. if ( ! $ldap ) { 7. print $cgiout->b( "Unable to authenticate to " 8. . "the directory service. Please check " 9. . "your password and try again." ); 10. displayBackButton( $cgiout ); 11. return ""; 12. } 13. # Read manager entry to get name and e-mail address 14. if ( $managerDN eq "" ) { 15. print $cgiout->h3( "Your manager is not listed in your " 16. . "directory entry. Please contact the " 17. . "IS HelpDesk for assistance." ); 18. } else { 19. $entry = $ldap->search( $managerDN, "base", 20. "(objectClass=*)", 0, @attrlist ) ; 21. if ( ! $entry ) { 22. print $cgiout->h3( "Your manager is not listed in " 23. . "the directory. Please contact the " 24. . "IS HelpDesk for assistance." ); 25. } else { 26. if ( $entry->{"mail"}) { 27. $managerMail = $entry->{"mail"}[0]; 28. } 29. if ( $entry->{"cn"}) { 30. $managerName = $entry->{"cn"}[0]; 31. } else { 32. $managerName = $managerMail; # best we have 33. } 34. } 35. } 36. # Clean up and return 37. $ldap->close; 38. $managerMail; 39. } 40. # End of findManagerEmail.

At the time of this writing, the PerLDAP module does not support binding a second time on the same connection, so the code on lines 1 “12 closes the connection that was previously used to find the employee's entry and creates a new connection, binding using the employee DN and password. Short of requiring that the employee enter her DN in the time-off request form (not recommended!), there is no way to avoid using two connections like this; we need to first search by user ID to find the DN that we use in the authenticated bind.

The code on lines 13 “25 reads the manager's entry by performing a base object search on the manager DN. Because just one entry needs to be examined, this kind of search is very efficient in most LDAP server implementations . Lines 26 “35 extract the manager's name (from the cn attribute) and email address (from the mail attribute), if they are present. The code on lines 36 “40 closes the second LDAP connection and returns the managerMail value.

The remainder of the code in the processto.pl CGI script consists of utility subroutines that do not interact with the directory service. The first two of these subroutines are the incompleteForm and displayBackButton subroutines shown in Listing 20.18.

Listing 20.18 The processto.pl incompleteForm and displayBackButton subroutines

1. # Start of incompleteForm: 2. sub 3. incompleteForm { 4. local( $cgiout, $msg ) = @_; 5. print $cgiout->b( "Incomplete form. $msg." ), "\n"; 6. displayBackButton( $cgiout ); 7. print $cgiout->end_html; 8. exit; 9. } 10. # End of incompleteForm. 11. # Start of displayBackButton: 12. sub 13. displayBackButton { 14. local( $cgiout ) = @_; 15. print $cgiout->start_form, 16. $cgiout->button(-name=>'goback', -value=>'Go Back', 17. -onClick=>'window.back()'), $cgiout->end_form; 18. } 19. # End of displayBackButton.

The incompleteForm subroutine is called by the main module to report to the employee in a consistent manner that he or she neglected to fill in one of the required form fields. The displayBackButton subroutine is called in several places to generate HTML code for a Go Back button, which provides a convenient way for the employee to return to the original form so she can make needed corrections or fill in missing information.

The last piece of the processto.pl script is the sendMailMessage subroutine shown in Listing 20.19. This subroutine is called by the main module and uses the Net::SMTP Perl module to send an email message.

Listing 20.19 The processto.pl sendMailMessage subroutine

1. # Start of sendMailMessage: 2. # Returns 0 if all goes well and non-zero if not. 3. sub 4. sendMailMessage() 5. { 6. local( $to, $from, $subject, $text ) = @_; 7. local( $smtp ); 8. $smtp = Net::SMTP->new( $smtphost ); 9. if ( ! $smtp ) { 10. return 1; 11. } 12. $smtp->mail( $from ); 13. $smtp->to( $to ); 14. $smtp->data(); 15. $smtp->datasend( "To: $to\n" ); 16. $smtp->datasend( "From: $from\n" ); 17. if ( $subject ne "" ) { 18. $smtp->datasend( "Subject: $subject\n" ); 19. } 20. $smtp->datasend( "\n$text" ); 21. $smtp->dataend(); 22. $smtp->quit; 23. 0; # success 24. } 25. # End of sendMailMessage.

The Employee's Experience

Now, let's take a look at the time-off workflow application in action. Employees connect to a well-advertised location (such as http://hr/timeoff.html) using their Web browser. An empty form is displayed based on the timeoff.html HTML file discussed earlier. Figure 20.13 shows a sample vacation request form completed by an employee named Babs Jensen.

Figure 20.13 A sample time-off request form.

After the employee clicks on the Send This Request To Your Manager button, the processto.pl CGI script is invoked behind the scenes to process the form and notify the manager about the request. The script also produces confirmation output for the employee. A sample response is shown in Figure 20.14.

Figure 20.14 A sample response to a time-off request submission.

The Manager's Experience

Managers do not interact with the HTML form (unless they request some time off for themselves ). Instead, they receive an email message that instructs them to reply and mark the request with APPROVE or DENY . The message generated by Babs' request is shown in Figure 20.15.

Figure 20.15 A sample manager email message generated by the processto.pl script.

Replies are sent to a special address called timeoff-service@airius.com , which is monitored by a human or automated service within the payroll department. That person or service is responsible for recording the information as needed and notifying the employee about her request via email.

Ideas for Improvement

Our time-off request directory-enabled workflow application could be improved in many ways. Here are a few ideas:

  • Improve the timeoff.html form by having it check for empty required fields using JavaScript (instead of requiring that the employee submit the form, wait for the CGI script to validate the fields and inform her of her mistake, and then click on Go Back to fill in the required fields).

  • Improve the timeoff.html form by having it calculate a value for the two Total Hours: fields using JavaScript.

  • Improve the timeoff.html form by adding JavaScript code to validate the date fields.

  • Write a script that can be used to process replies sent by managers to the timeoff-service email address. The script should send a message back to the employee to let her know if her request was approved or denied , and it should also submit data about time-off requests approved by managers to a payroll system.

  • To further streamline the request approval process, change the processto.pl script to generate an HTML email message that contains two buttons labeled Approve and Deny that perform those respective functions.

  • If you keep track of whether an employee is on vacation or not in your directory service (this is typically done to support automated vacation email responders), enhance the processto.pl script to check whether an employee's manager is currently on vacation and, if so, send the time-off request to the manager's manager instead. Be sure to inform the employee who submitted the request that this was done.



Understanding and Deploying LDAP Directory Services,  2002 New Riders Publishing
<  BACK CONTINUE  >

Index terms contained in this section

applications
         developing
                    timeoff.html example 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th
developing
         applications
                    timeoff.html example 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th
directories
         applications
                    developing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th
listings
          timeoff.html source code 2nd 3rd 4th 5th
                    processto.pl displayBackButton subroutine 2nd 3rd 4th
                    processto.pl findManagerEmail subroutine 2nd 3rd 4th 5th 6th 7th 8th 9th
                    processto.pl incompleteForm subroutine 2nd
                    processto.pl main module 2nd 3rd 4th 5th 6th 7th 8th
                    processto.pl prelude 2nd 3rd 4th
                    processto.pl sendMailMessage subroutine 2nd 3rd
processto.pl displayBackButton subroutine
          timeoff.html source code 2nd 3rd 4th
processto.pl findManagerEmail subroutine
          timeoff.html source code 2nd 3rd 4th 5th 6th 7th 8th 9th
processto.pl incompleteForm subroutine
          timeoff.html source code 2nd
processto.pl main module
          timeoff.html source code 2nd 3rd 4th 5th 6th 7th 8th
processto.pl prelude
          timeoff.html source code 2nd 3rd 4th
processto.pl sendMailMessage subroutine
          timeoff.html source code 2nd 3rd
timeoff.html utility example 2nd 3rd 4th
          employee point of view 2nd
          improvement ideas 2nd 3rd
          manager point of view 2nd
          source code 2nd 3rd 4th 5th
                    processto.pl displayBackButton subroutine 2nd 3rd 4th
                    processto.pl findManagerEmail subroutine 2nd 3rd 4th 5th 6th 7th 8th 9th
                    processto.pl incompleteForm subroutine 2nd
                    processto.pl main module 2nd 3rd 4th 5th 6th 7th 8th
                    processto.pl prelude 2nd 3rd 4th
                    processto.pl sendMailMessage subroutine 2nd 3rd

2002, O'Reilly & Associates, Inc.



Understanding and Deploying LDAP Directory Services
Understanding and Deploying LDAP Directory Services (2nd Edition)
ISBN: 0672323168
EAN: 2147483647
Year: 1997
Pages: 245

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net