The Monash Unit Description Avatar

A.J.Hurst

Version

Table of Contents

1 Global Constants
2 Overview
2.1 The Manifest
2.2 User Issues
2.3 Pedagogic Issues
2.4 Legacy Issues
2.5 Directories and files
3 The MonAtar Main cgi script and Authentication
3.1 avatar initialization
3.2 avatar main control branches
3.2.1 re-entering the avatar
3.2.2 Logging in to the Avatar
3.2.3 Perform avatar authentication
3.2.4 Handle Illegal Parameters
3.3 avatar subroutines
3.4 getLatestApproved: subroutine to find most recent approved version
4 The Unit Selection Page
5 View a Unit Description
5.1 doView: view a unit description
5.2 getDocument: retrieve a unit description file
6 Edit a Unit Description
6.1 doEdit: Generate an Edit Markup of the Unit Description
6.2 doChange: Generate an Editable Text of the specified Field
6.3 doUpdate: Incorporate changes into the Unit Description
6.4 doSave: Incorporate changes into the Unit Description
6.5 doSubmit: Incorporate changes into the Unit Description
7 Compare Unit Decriptions
8 Show Unit Descriptions
9 doApprove: Approve a Unit Description
9.1 doApprove: What Approvals are Possible for this User?
9.2 doApprove: Select Unit(s) to Approve
9.3 doApprove: Give Approval to Unit
9.4 The Approval XML Translation Rules
10 Review a Unit Description
10.1 doReview: start a review template
10.2 doReviewSubmit: submit a unit review
11 XSL Stylesheets and Transformers
11.1 MakeReviewForm.xsl An XSL script to Generate a Review Form
11.2 mergexml.xsl Merge Updates with Description
11.3 MonAtar-appr.xsl Merge Approval Information with Description
11.4 V1toV2.xsl Converter Script
11.5 xml2html.xsl Convert XML Description to HTML
11.6 xml2txt.xsl Convert XML Description to Plain Text
12 TODO
13 DONE
14 Indices
14.1 Files
14.2 Chunks
14.3 Identifiers


<version 1> = 2.8.5
Chunk referenced in 15 18 20 22 30

1. Global Constants

<context variables 2> =
my $TESTING = 0;
Chunk referenced in 13
Chunk defined in 2,3,4,5,6,7,8,9,10,11

Define whether we are running in test mode

<context variables 3> =
my $WEBPAGE = "/u/homes1/ajh"; my $SERVER = "http://www.csse.monash.edu.au";
Chunk referenced in 13
Chunk defined in 2,3,4,5,6,7,8,9,10,11

Define the location of the home web page, and the base server address

<context variables 4> =
#my $TestingVersion = "<B> Test Version! </B>"; my $TestingVersion = ""; my $SUBMISSIONS = "$WEBPAGE/units";
Chunk referenced in 13
Chunk defined in 2,3,4,5,6,7,8,9,10,11

Set this to the name of the unit descriptions directory. There is one of these directories for each faculty using the avatar

<context variables 5> =
my $CGIPAGE = "$SERVER/cgi-bin/cgiwrap/ajh";
Chunk referenced in 13
Chunk defined in 2,3,4,5,6,7,8,9,10,11

Define the base page for any cgi scripts.

<context variables 6> =
my $XMLPAGE = "$WEBPAGE/cgi-bin";
Chunk referenced in 13
Chunk defined in 2,3,4,5,6,7,8,9,10,11

Define where all XML and XSL support scripts and files are stored.

<context variables 7> =
my $APPROVALS = "$XMLPAGE/MonAtar-IT.appr";
Chunk referenced in 13
Chunk defined in 2,3,4,5,6,7,8,9,10,11
<context variables 8> =
my $TMP = "$WEBPAGE/tmp";
Chunk referenced in 13
Chunk defined in 2,3,4,5,6,7,8,9,10,11
<context variables 9> =
my $GRAPHICS = "$SERVER/~ajh/graphics";
Chunk referenced in 13
Chunk defined in 2,3,4,5,6,7,8,9,10,11
<context variables 10> =
# Set this to the name of the CGI on your web server $SCRIPT = "$CGIPAGE/MonAtar";
Chunk referenced in 13
Chunk defined in 2,3,4,5,6,7,8,9,10,11
<context variables 11> =
# Define the xslt processor and options $XSLTOPTS = "XML_CATALOG_FILES=$XMLPAGE/catalog"; $XSLTPROC = "$XSLTOPTS /usr/local/bin/xsltproc"; $XP = "--param";
Chunk referenced in 13
Chunk defined in 2,3,4,5,6,7,8,9,10,11

2. Overview

This document describes Version 2 of the Infotech Subject Avatar, now know as MonAtar (MONash AvaTAR).

The purpose of the system is to maintain on-line documentation associated with course and unit offerings, originally within the Faculty of Information Technology at Monash, but recently extended to other faculties (Business and Economics, Medicine). The system is built using XML technology, while the actual Common Gateway Interface (CGI) components are written in Perl. This document details the main Perl component MonAtar, with links to the other components.

The XML components of the system include document type definitions (dtds), XML templates, and eXtensible Stylesheet Language Transformations (XSLT). The latter perform significant amounts of processing within the system, and are invoked from within the main Perl cgi script, the MonAtar program itself. These documents are defined separately, as defining XSLT documents within an XML document can get a bit bizarre!

2.1 The Manifest

Files used in this system are described below. In general, XSL files are maintained separately, because of the editing issues mentioned above.

a2x.w
The literate program (old style) to convert text to XML markup. This is actually uploaded to the cgi web site as the derived file a2x.pl.
basic2html.xsl
XSLT transformer for basic markup items
maketest.pl
A hastily cobbled together perl script to generate a test version for running on the local host.
monatar.xlp
The source form of this document. This is a literate program, translated to the output file MonAtar by a suite of XSLT scripts. MonAtar is a perl cgi script.
UnitDescriptionV2.dtd
The document type definition for the unit description itself.
UnitTemplateV2.xml
This defines the initial form of a freshly created unit decription.
V1toV2.xsl
XSLT script to convert unit description documents from Version 1 to Version 2 format
V2Guidelines.xml
An XML file that is converted to V2Guidelines.html and uploaded to the web site. This file contains helpful instructions on how to edit the various parts of the unit description file.
xml2html.xsl
XSLT script to convert unit description documents from Version 2 to HTML, presented as a viewable document or editable document, depending upon the value of the parameter ViewOrEdit (View or Edit respectively).
xml2txt.xsl
XSLT script to translate XML markup to formatted plain text, for editing by novice editors.
xmlextract.xsl
xslt.dtd
A link to the document type definition for all the XSLT scripts that form part of this package.
MakeReviewForm.xsl
mergexml.xsl
MonAtar-appr.xsl
Merge approval information with an XML unit description.
MonAtar-version.xsl
Review2html.xsl
ReviewV1.dtd
sanitiseV2.xsl
stylesheet.dtd

2.2 User Issues

  1. Have separate edit buttons for each section.
  2. Incorporate a2x.pl into monatar litprog
  3. Design Version Control interface
  4. Create a lock file on the no version comment page. Delete this lock file when edits are saved or submitted. Good question is what happens if the user doesn't save or submit. Should the lock be removed say after 24 hours? (The edits are saved, but not in the archive.)
  5. add StartPoint mechanism to always display description at edit point.
  6. Generate the prohibitions matrix; change wording of submit statement; include subject description in email; define interest groups

2.3 Pedagogic Issues

Ainslie Ellis writes:

I have looked at the new format. It looks fine.

Is it possible to provide a sample outline that has a brief comment under each heading (or a link to an html page if a longer comment is needed) that indicates what should be thought of at each stage. I already have a lot of this information. and am happy to write up a checklist for each item if you think this would be useful.

Also in the objectives part, I would prefer this to commence with At the completion of a unit a student should be able to:

followed by perhaps a comment like

with a link to an html document (see attachment for this email) for more detail.

2.4 Legacy Issues

  1. Write a conversion xsl script from old format to new. Complete, called V1toV2.xsl
  2. Create copy of units directory and archive wherein all descriptions can be converted. Keep this up-to-date until change-over. Done.
  3. The new cgi script will be cookie based, to avoid reauthentication. Done.
  4. The new cgi script will be monolithic, to eliminate a majority security hole in the previous version. Done.

2.5 Directories and files

There are various locations where the files are to be stored, defined symbolically within this script as:

XMLPAGE
The directory containing all xml and xsl files required for MonAtar use. On shelob this is $WEBPAGE/cgi-bin, while on ararat it is $WEBPAGE/xml
basic2html.xsl
XSL script included by xml2html.xsl
canonical.pl
perl script to convert an XML file into canonical form. I'm not sure this is required any longer, since sanitise.xsl has been written?

3. The MonAtar Main cgi script and Authentication

"MonAtar" 12 =
#!/usr/bin/perl <initialization 13,14> <subroutines 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106> <get parameters 15,16,17> if ($auth->param('UnitCode') && @params==1) { &doView($auth->param('UnitCode')); } elsif ($auth->param('compare')) { &doCompare; } elsif ($auth->param('authaction') =~ /Authenticate/) { <perform avatar authentication 20> } elsif ($auth->param('authenticate') || (!$cookie)) { <login to avatar 19> } elsif (!$auth->param && $cookie) { <re-enter avatar 18> } elsif ($auth->param('reenter')) { <re-enter avatar 18> } elsif ($auth->param('view')) { &doView($auth->param('UnitCode')); } elsif ($auth->param('create')) { &doEdit(1); } elsif ($auth->param('edit')) { &doEdit(0); } elsif ($auth->param('change')) { &doChange(); } elsif ($auth->param('update')) { &doUpdate(); } elsif ($auth->param('Save')) { &doSave(); } elsif ($auth->param('Submit')) { &doSubmit(); } elsif ($auth->param('compare')) { &doCompare; } elsif ($auth->param('show')) { &doShow; } elsif ($auth->param('approve')) { &doApprove; } elsif ($auth->param('review')) { &doReview; } elsif ($auth->param('reviewSubmit')) { &doReviewSubmit; } else { <illegal parameters 21> } &printBottom; close DEBUG; close LOG; exit;

The order of tests in here is very important, and controls the security of the system. Do not reorder these tests without obeying the following rules! The key issue is that the avatar can be used without authentication for viewing or comparing unit descriptions, but for all other purposes, the user must be authenticated. A cookie is issued once the user has authenticated, and this avoids having to re-authenticate on repeat visits to the home avatar page.

Two pages generated by the avatar have special significance. They are the login page and authenticating page. The login page requires the user to enter details of their AuthCate userid and password, while the authenticating page performs the authentication of these details by looking up the Monash Directory Pages, and returning information about what is found. This page also sets a cookie, to avoid the user having to re-authenticate.

The first test therefore checks to see if the desired display is to view a unit description. This is prompted by a single parameter UnitCode=unitcode. Any additional parameters and this non-authenticated display will fall through to require authentication.

The next page that can be viewed without authentication is the authenticating page itself. This is the second test, and is driven by the parameter authaction=Authenticate, generated by the login page. It must appear before the login page itself, since no cookie has yet been issued, and we want all attempts to visit pages without cookies to trap to the login page. If authentication is successful, we move to the Unit Selection Page.

If the avatar is invoked with an explicit request to authenticate, or no cookie has yet been issued, we generate the login page.

If the avatar is invoked with no explicit parameters, but a cookie has been issued, then this is a revisit to the avatar, and we generate the Welcome (Back) Page.

Subsequent tests branch into other sections of the avatar for handling.

The final step, if no tests succeed, is to issue a warning about illegal parameters to the avatar.

3.1 avatar initialization

<initialization 13> =
my @additions=("/local/lib/perl5/site_perl/5.6.0"); push(@INC,@additions); #print join(',',@INC),"\n"; require Net::LDAP; use Carp; use CGI qw(:standard :html3); $auth = new CGI; <context variables 2,3,4,5,6,7,8,9,10,11> my $ldap_server = 'directory.monash.edu'; my $ldap_port = 389; my $ldap_basedn = 'o=Monash University, c=AU'; my $dn; # set to 1 for various debugging information my $debug = 1; # cleared once HTML headers have been printed my $needHeaders = 1; # This is the displayed title... $TITLE = "InfoTech Unit Avatar: Authentication";
Chunk referenced in 12
Chunk defined in 13,14
<initialization 14> =
$TimeStamp = `/bin/date "+%Y%m%d:%H%M%S"`; chop $TimeStamp; $timestamp = $TimeStamp; $timestamp=~s/://;
Chunk referenced in 12
Chunk defined in 13,14

This is my timestamp. I use a contraction of the ISO standard, where the date and time are in most significant order, with a colon separating the day of the month from the hour of the day. The year is 4 digits, all others are 2 digits with a leading zero if required.

<get parameters 15> =
@params = $auth->param; unless(open LOG,">>$SUBMISSIONS/log") { printError('NoLog',"Cannot open log file $SUBMISSIONS/log"); exit; } $School = "(No School)"; $Faculty = "(No Faculty)"; $Staff = "(No Staff Info)"; $rawCookie=$ENV{'HTTP_COOKIE'}; @rawCookies = split(/;/,$rawCookie); foreach(@rawCookies){ m/([^=]*)=(.*)$/; my ($key,$val) = ($1,$2); print LOG $TimeStamp,' <version 1> (key,val)=',"($key,$val)\n"; $cookies{$key} = $val; } if ($cookies{'AVATAR'}) { $cid = $cookies{'AVATAR'}; $cid=~s/\+/ /g; $cookie="AVATAR=".$cid; $cid =~ s/--/=/g; grabPersonData($cid); } my $logindata = 0; foreach $name (@params) { if ($name eq 'myuid') {$logindata++;} if ($name eq 'mypass') {$logindata++;} my $value = $auth->param($name); $value =~ s/</&lt;/g; #if ($name ne 'mypass') { # print LOG $name,"=",$value," "; #} } $UnitCode = $auth->param('UnitCode'); $UnitCode =~ tr/a-z/A-Z/;
Chunk referenced in 12
Chunk defined in 15,16,17
<get parameters 16> =
$EditExpert = $auth->param('EditExpert');
Chunk referenced in 12
Chunk defined in 15,16,17

Does this editor want to edit the XML markup directly, or does she prefer to use plain text? Set to 1 (in doEdit) if the former.

<get parameters 17> =
# This is the debugging file $debugfile = "dummy.dbg"; if ($UnitCode) {$debugfile = "$UnitCode.dbg"}; open DEBUG,">$TMP/$debugfile"; print DEBUG "rawCookie=$rawCookie\n"; print DEBUG "Cookie=$cookie\n"; print DEBUG "cid=$cid\n"; print DEBUG "School=$School\n"; print DEBUG "Faculty=$Faculty\n";
Chunk referenced in 12
Chunk defined in 15,16,17

3.2 avatar main control branches

3.2.1 re-entering the avatar

<re-enter avatar 18> =
$TITLE="Infotech Unit Avatar: Home Page (Version <version 1>)"; &printHtmlHeaders; $cid=~s/--/=/g; &grabPersonData($cid); print "<P></P><h1 align=\"center\" style=\"color:#339933;". "background-color:#99ffcc\">Welcome back, $given!</h1>"; &doUnitSelection;
Chunk referenced in 12

We have cookie data, so the user has already authenticated and re-entered the avatar. Convert the flattened equals signs back to equals, and extract the given name as the first word in the common name or cn field. Print the Welcome Back heading, and then generate the Unit Selection Page.

3.2.2 Logging in to the Avatar

<login to avatar 19> =
&printHtmlHeaders; print start_form(-action=>"$SCRIPT"), h2("Please supply your AuthCate username and password"), "Username: ",textfield('myuid'),p, "Password: ",password_field('mypass'),p, submit('authaction','Authenticate me!'), hidden('UnitCode',$auth->param('UnitCode')), end_form; print "<em>It may take a minute or so to process</em>"; print " - <b>PLEASE MAKE SURE YOU HAVE COOKIES ENABLED</b>"; print "<p>(If you have already authenticated, click your browser "; print "RELOAD/REFRESH button to go to the Unit Selection Page)</p>";
Chunk referenced in 12

No parameters supplied to avatar, or authentication forced, so print the login page.

3.2.3 Perform avatar authentication

<perform avatar authentication 20> =
&doAuthenticate; if ($dn) { unless(open LOG,">>$SUBMISSIONS/log") { printError('NoLog',"Cannot open log file $SUBMISSIONS/log"); exit; } print LOG $TimeStamp,' <version 1> ',$dn,"\n"; &grabPersonData($dn); my $cookie = $dn; $cookie=~s/=/--/g; $cookie=~s/ /\+/g; print "Set-Cookie: AVATAR=$cookie\n"; print LOG $TimeStamp,' <version 1> ',"Set-Cookie: AVATAR=$cookie\n"; close LOG; $TITLE="Welcome to the Infotech Unit Avatar Home Page (V<version 1>)"; &printHtmlHeaders; # could put first time information in here? if ($UnitCode) { &doEdit(0); } else { &doUnitSelection; } }
Chunk referenced in 12

Handle the authentication process. I am very grateful to Nate Bailey for the original code upon which this subroutine is based, but as it has been significantly altered, all responsibility rests with me!

If authentication succeeds, we get back a domain name dn, which is analyzed to extract the user's given name, and then encoded to avoid problems with internal equal signs, before being returned to the client as a cookie for subsequent authentication purposes.

Finally, we generate the Unit Selection Page.

3.2.4 Handle Illegal Parameters

<illegal parameters 21> =
$TITLE="Infotech Unit Avatar: Error Page"; &printHtmlHeaders; $_=$auth->p."These are the parameters and values:"; $_=$_."<P STYLE=\"margin-left:20pt\">"; foreach $name (@params) { $_=$_.$name.'='.$auth->param($name).'<BR>'; } $_=$_.'</P>'; &printError("Illegal Parameters",$_);
Chunk referenced in 12

Note that we should not normally enter this code. If we do, it is because the avatar has been called with unknown parameters, so we print that fact, together with a synopsis of the parameters in error.

3.3 avatar subroutines

<subroutines 22> =
sub doLogOperation { my($location)=(shift); print LOG $TimeStamp,' <version 1> ',"$Editor calls $location\n"; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106
<subroutines 23> =
sub doAuthenticate { my($uid,$passwd) = (param('myuid'),param('mypass')); if (!($uid.$passwd)) { &printHtmlHeaders(); &printError('Insufficient information', "You left one or more of the fields blank -- ". "you must fill out all the fields."); } elsif ($uid eq 'sjoy' && $passwd eq '*****') { $dn = "cn=Sally Joy2, ou=Department of Racketeering, ". "ou=Faculty of Business and Economics, ou=Staff, ". "o=Monash University, c=au"; } elsif ($uid eq 'ajh' && $passwd eq '*****') { $dn = "cn=John Hurst2, ou=School of Microsoftware Imagineering, ". "ou=Faculty of Information Technology, ou=Staff, ". "o=Monash University, c=au"; } elsif ($uid eq 'luff' && $passwd eq '*****') { $dn = "cn=Tony Luff2, ou=Department of Immaculate Conception, ". "ou=Faculty of Medicine, ou=Staff, o=Monash University, c=au"; } elsif ($uid eq 'dnh' && $passwd eq '*****') { $dn = "cn=David Hurst, ou=Department of Students, ". "ou=Faculty of Information Technology, ou=Student, o=Monash University, c=au"; } else { $dn = doLDAP(undef,$uid,$passwd); } }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106

doAuthenticate collects username and password parameters from the call, checks that they are non-empty, and calls the LDAP authentication routine.

<subroutines 24> =
sub doLDAP { my ($dn,$uid,$pass) = @_; my $mesg; if ($pass eq "") { $pass = $uid; $uid = $dn; $dn = undef; } my $ld = Net::LDAP->new($ldap_server, port => $ldap_port); unless ($ld) { carp "ldap_open to $ldap_server failed!"; return undef; } if ($pass eq '') { carp "ldap bind for $uid failed: no password!"; return undef; } unless ($dn) { unless (($mesg=$ld->bind) && $mesg->code==LDAP_SUCCESS) { carp "ldap anon bind to $ldap_server failed"; return undef; } my $filter = "(uid=$uid)"; unless ($mesg = $ld->search(base=>$ldap_basedn, filter=>$filter)) { carp "ldap search for $uid failed"; return undef; } my @entries = $mesg->all_entries; unless (scalar(@entries) == 1) { &printError("not exactly one ldap entry for $uid"); return undef; } $dn = $entries[0]->dn(); } ###################################################### ### WARNING!!! If we don't have '$pass', this will ### ### successfully make an _anonymous_ bind. ### ###################################################### unless (($mesg=$ld->bind($dn, password=>$pass)) && $mesg->code==LDAP_SUCCESS) { $ld->unbind; printError("LDAP bind failed", "I could not connect to the LDAP server. ". "It returned an error code of ".$mesg->code. ", which means: ".$mesg->error.""); return undef; } unless ($mesg = $ld->search(base=>$dn, filter=>'(objectclass=*)')) { $ld->unbind; carp "Search with $uid 's basedn ($dn) failed"; return undef; } return $dn; } sub doProcessDescription { print start_html(), h1('Calling propose('.$auth->param('propose').', '.$auth->param('UnitCode').')'), end_form; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106
<subroutines 25> =
sub printBottom { return; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106
<subroutines 26> =
sub printHtmlHeaders { #if (!$needheaders) {return;} print header('text/html'); my $ADT = "$SERVER/~ajh/adt"; print <<"END"; <html> <head> <meta content="text/html; charset=ASCII" http-equiv="Content-Type"> <title> $TITLE </title> <link rel="stylesheet" href="$SERVER/~ajh/styles/monash.css" type="text/css"> </head> <body> <div class="spacer"></div> <div id="global-header"> <div id="global-images"> <table width="100%" bgcolor="white"> <tr width="100%"> <td align="left"> <table> <tr> <td align="left"> <a href="http://www.monash.edu.au"> <span style="font-family:sans-serif; font-size:+160%;font-weight:bold; background-color:#ffffff;color:black"> MONASH UNIVERSITY </span> </a> </td> </tr> <tr> <td align="left"> <a href="http://www.infotech.monash.edu.au" COLOR="black"> <span style="font-family:sans-serif; font-size:+140%;font-weight:bold; background-color:#ffffff; color:black"> INFORMATION TECHNOLOGY</span> </a> </td> </tr> <tr> <td align="left"> <a href="http://www.csse.monash.edu.au" COLOR="black"> <span style="font-family:sans-serif; font-size:+120%;font-weight:bold; background-color:#ffffff;color:black"> Computer Science and Software Engineering</span> </a> </td> </tr> </table> </td> <td align="right"> <img id="banner-image" SRC="$SERVER/~ajh/images/banner/4472=R761-11.jpg" height="79" alt="steam loco"> </td> </tr> </table> </div> <div class="spacer"></div> <table id="global-nav" summary="Layout for site-wide navigation"><tr> <td align="left"><span style="font-size:+140%"> M O N A T A R $TestingVersion </span> </td><td> $TITLE </td> </tr></table> <table id="global-utils" summary="Layout for utility navigation"> <tr><td align="left"> <a HREF="$ADT/../index.html" accesskey="4">John Hurst</a> | <a HREF="$ADT/index.html" accesskey="4">InfoTech AD(T)</a> | <a HREF="$ADT/quality/index.html">Quality</a> | <a HREF="$ADT/quality/V2Guidelines.html">Completing an Avatar Entry</a> | </td> </tr> </table> </div> <div class="spacer"></div> <div style="background-color:#99ffcc"> END # If the person has authenticated, let them know we know who they are. if (defined $dn) { @splitdn = split(/,/,$dn); $name = $splitdn[0]; $name =~ s/.*=//; } $needHeaders = 0; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106
<subroutines 27> =
sub printLDAPError { if ($needHeaders) {&printHtmlHeaders();} $lderr = ldap_get_lderrno($ld,$blah1,$blah2); $errmsg = ldap_err2string($lderr); print p,"\nError: $errmsg\n",p,hr; &printBottom; return; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106
<subroutines 28> =
sub printError { my ($type, $info) = @_; $TITLE="InfoTech Unit Avatar: Sorry!"; if ($needHeaders) {&printHtmlHeaders();} print h2("$type"); print "<FONT SIZE=\"+1\">$info<BR>"; print "<P>Click this link to return to the Welcome page: "; print "<A HREF=\"$SCRIPT\">Infotech Unit Avatar</A></P></FONT>"; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106
<subroutines 29> =
sub printBadAuth { if ($needHeaders) {&printHtmlHeaders();} print p,"The login/password you have supplied is incorrect.",p; print "Return to <a href=\"$SCRIPT\">authentication screen</a>."; &printBottom; exit; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106
<subroutines 30> =
sub grabPersonData { my $dn = shift; #print LOG $TimeStamp,' <version 1> ',"grabPersonData($dn)\n"; $dn =~ /cn *= *([^,]*),/; $Editor = $1; $Editor =~ /([\w]*) ([\w]*)/; $EscEditor = $Editor; $EscEditor =~ s/'/&quote;/g; ($given,$surname) = ($1,$2); if ($dn =~ /ou *= *([\w\s]*School[\w\s]*)/) {$School = $1}; if ($dn =~ /ou *= *([\w\s]*Department[\w\s]*)/) {$School = $1}; if ($dn =~ /ou *= *([\w\s]*Faculty[\w\s]*)/) {$Faculty = $1}; if ($dn =~ /ou *= *((Staff|Student)[\w\s]*)/) {$Staff = $1}; #if ($Staff=~/^Student$/) {$School=""; $Faculty="";} if ($Faculty=~/Information/) { <grabPersonData: set submission details for InfoTech 31> } elsif ($Faculty=~/Business/) { $SUBMISSIONS="$WEBPAGE/units-buseco"; $APPROVALS = "$XMLPAGE/MonAtar-Bus.appr"; $FECEADR="John.Hurst\@infotech.monash.edu.au"; $FECEOFF="John.Hurst\@infotech.monash.edu.au"; } elsif ($Faculty=~/Medicine/) { $SUBMISSIONS="$WEBPAGE/units-med"; $APPROVALS = "$XMLPAGE/MonAtar-Med.appr"; $FECEADR="John.Hurst\@infotech.monash.edu.au"; $FECEOFF="John.Hurst\@infotech.monash.edu.au"; } else { <grabPersonData: set submission details for no Faculty 32> } print LOG $TimeStamp,' <version 1> ', "editor=$Editor,expert=$EditExpert,unitcode=$UnitCode,". "given=$given,surname=$surname,school=$School,faculty=$Faculty,". "staff=$Staff,unitsfile=$SUBMISSIONS\n"; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106

(Bug 20031009:115255) When extraction the school, department or faculty information, we must allow for leading words before the school/department/faculty key word, so that places like Peninsula School of Network Computing are not discriminated against.

<grabPersonData: set submission details for InfoTech 31> =
$SUBMISSIONS="$WEBPAGE/units"; $APPROVALS = "$XMLPAGE/MonAtar-IT.appr"; $FECEADR="fecvote\@infotech.monash.edu.au"; $FECEOFF="Ralph.Gillon\@infotech.monash.edu.au". ",Geraldine.DCosta\@infotech.monash.edu.au";
Chunk referenced in 30
<grabPersonData: set submission details for no Faculty 32> =
print LOG "No units database for $Faculty\n"; $SUBMISSIONS="$WEBPAGE/units"; $APPROVALS = "$XMLPAGE/MonAtar-IT.appr"; $FECEADR="fecvote\@infotech.monash.edu.au"; $FECEOFF="Ralph.Gillon\@infotech.monash.edu.au";
Chunk referenced in 30

If the faculty is not one of those directly handled, print log message and use InfoTech as default.

3.4 getLatestApproved: subroutine to find most recent approved version

<subroutines 33> =
sub getLatestApproved { my $unitcode = shift; my $dir="$SUBMISSIONS/archive"; my @units; opendir(ARCHIVE,$dir); my @archfiles=grep(!/^\.\.?$/,readdir(ARCHIVE)); foreach $f (@archfiles) { if ($f =~ /^$UnitCode-[0-9]+-A/) { unshift(@units,$f); } } closedir ARCHIVE; @units=sort(@units); if ($TESTING) {print join(', ',@units);} $ApprovedVersion=""; if (@units) {$ApprovedVersion=$units[$#ApprovedVersion];} if ($TESTING) {print "[",$ApprovedVersion,"]";} }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106

4. The Unit Selection Page

<subroutines 34> =
sub doUnitSelection { print $auth->start_html(), $auth->start_form(-method=>"post", -action=>"$SCRIPT", -target=>"_blank"); if (($Staff !~ /^Staff|Student$/)) { print "Sorry, but you are not authorised to use this form, $given"; } else { <selection page text 35> } print $auth->endform,$auth->hr; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106

Collect the domain name from the parameter, and analyse it for school and faculty data. If the person identified is not staff, then they cannot use the avatar.

<selection page text 35> =
my %hints = ( 'review'=>"May be completed by staff or students. ". "(See the <A HREF=\"$SERVER/~ajh/". "adt/quality/index.html#Using%20the%20Review". "%20System\">ADT Quality Page</A> for help)", 'compare'=>'Compare two unit descriptions (under development)', 'show'=>"Show summary of unit descriptions matching the above ". "prefix. <B>This can also be used to compare changes since ". "the last approval of a unit.</B>", 'showall'=>"Show a list of <B>all</B> unit descriptions ". "matching the above prefix", 'showapproval'=>"Show the approval work flow of unit ". "descriptions matching the above prefix", 'view'=>"Generate a read-only view of the unit description" ); if ($Staff=~/^Staff$/) { print $auth->p, textfield(-name=>'UnitCode',-default=>$UnitCode,-size=>10), " Enter unit code here, please $given", $auth->hidden('Editor',$Editor); print $auth->p, $auth->table({-cellpadding=>0,-cellspacing=>0}, Tr(td({-'colspan'=>"2"},"<B>USER functions</B>"),td()), Tr(td({-'bgcolor'=>"#99ffcc",-align=>"center"}, $auth->submit(-name=>'review', -value=>'REVIEW Unit')), td($hints{'review'}."\n")), Tr(td({-'bgcolor'=>"#99ffcc",-align=>"center"}, $auth->submit(-name=>'view', -value=>'VIEW Description')), td($hints{'view'}."\n")), Tr(td({-'bgcolor'=>"#99ffcc",-align=>"center"}), td(textfield(-name=>'DisplayDate',-size=>10), "Enter date YYYYMMDDHHMMSS (or prefix) to restrict view\n")), Tr(td({-'bgcolor'=>"#99ffcc",-align=>"center"}, $auth->submit(-name=>'edit', -value=>'EDIT Existing Description')), td("Generate an editable view of the current unit description")), Tr(td({-'bgcolor'=>"#99ffcc"}, $auth->submit(-name=>'create', -value=>'CREATE New Description')), td("Create a new unit description")), Tr(td(),td()), Tr(td({-'colspan'=>"2"},"<B>MANAGEMENT functions</B>"),td()), Tr(td({-'bgcolor'=>"#99ffcc",-align=>"center"}, $auth->submit(-name=>'compare', -value=>'COMPARE Descriptions')), td($hints{'compare'}."\n")), Tr(td({-'bgcolor'=>"#99ffcc",-align=>"center"}, $auth->submit(-name=>'show', -value=>'SHOW Descriptions')), td($hints{'show'}."\n")), Tr(td({-'bgcolor'=>"#99ffcc",-align=>"center"}, $auth->submit(-name=>'show', -value=>'SHOW ALL Descriptions')), td($hints{'showall'}."\n")), Tr(td({-'bgcolor'=>"#99ffcc",-align=>"center"}, $auth->submit(-name=>'show', -value=>'SHOW APPROVAL Profile')), td($hints{'showapproval'}."\n")), Tr(td({-'bgcolor'=>"#99ffcc",-align=>"center"}, $auth->submit(-name=>'approve', -value=>'APPROVE Description')), td("(Only available for authorised users)"."\n")), ); } elsif ($Staff=~/^Student$/) { print "<P>What unit do you wish to view or review, $given? ", textfield('UnitCode',$UnitCode), "</P>", $auth->hidden('Editor',$Editor); print $auth->p, $auth->table( Tr(td("<B>USER functions</B>"),td()), Tr(td($auth->submit('review','REVIEW Unit')),td($hints{'review'})), Tr(td($auth->submit('view','VIEW Description')), td("View the unit description")), ); } print $auth->p, "Note: If you enter a partial unit code (such as BUS), ", "the SHOW (ALL) DESCRIPTIONS button will limit its search to just ", "those units starting with that prefix. The prefix can be ", "as long or as short as you desire. An empty unit code ", "will show all units.</P>"; print $auth->p, "<B>NB: If when using the back button you do not see the page ", "you expect, click reload/refresh to refresh the actual contents</B>"; print $auth->p, "<B>Version 2.7.0 has a new work-flow for approvals.</B>", "<BR/>\n", "<B>Version 2.6.15 adds date-restricted sub-view.</B>", "<BR/>\n", "<B>Version 2.6.12 adds change dates to fields.</B>", "<BR/>\n", "<B>Version 2.6.5 restructures the submit and approve processes.</B>";
Chunk referenced in 34

Generate the main content of the Unit Selection Page. The purpose of this page is to allow the user to choose between a range of options for the unit description document. These options are specified by buttons on the page, and cause reinvocation of the avatar with appropriate parameters.

5. View a Unit Description

5.1 doView: view a unit description

doView is responsible for collecting the nominated unit description document, and formatting it using xsltproc under the stylesheet xml2html.xsl, the standard html view of a unit description for version 2 descriptions. (If a version 1 description is encountered, use FECSA-html.xsl instead.) Since this page is intended for printing, it uses a standard text/html header, and does not call printHtmlHeaders!

Parms: /---------\ see list ---------->| MonAtar | below \---------/ | V getDocument: result in $TMP/$UnitCode.xml +--------------------+ | $TMP/$UnitCode.xml | +--------------------+ | V +--------------+ /----------\ | xml2html.xsl |---->| xsltproc | (If V1, use FECSA-html.xsl instead) +--------------+ \----------/ | V / \ /OK?\ no \ /------> Error, Translation \ / | yes V display this file delete TMP files

The following parameters are passed to MonAtar.

UnitCode
The unit code
Editor
If present, an authenticated user
EditExpert
If present, a boolean indicating the expert status of the user
<subroutines 36> =
sub doView { doLogOperation("doView"); $UnitCode=~tr/a-z/A-Z/; &getDocument(1,0); $DisplayDate = $auth->param('DisplayDate'); if ($DisplayDate) { $DisplayDate .= "00000000000000"; $DisplayDate = substr($DisplayDate,0,14); } print header('text/html'); # plain header! <doView: set xsltproc parameters 37> $cmd="$XSLTPROC $parms -o $dest $xsl $src 2>$erf"; `$cmd`; $err = ""; open ERR,"<$erf"; while (<ERR>) {$err.=$_}; close ERR; if ($err) { <doView: handle errors 39> } else { # use the resultant HTML file as returned page open NEW,"<$dest"; while (<NEW>) {print;} close NEW; } unlink $src,$dest,$erf; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106

Force the unit code to be upper case. Get the document. Set xslt processing parameters, and process the description to html. Gather the error output, and if that is non-empty, display in an error page, otherwise the output of the translation is used. Discard all temporary files.

<doView: set xsltproc parameters 37> =
$src="$TMP/$UnitCode.xml"; <doView: set stylesheet according to version 38> $dest="$TMP/$UnitCode$destmod.html"; $erf="$TMP/$UnitCode-edit.stderr"; $datetime=$TimeStamp; #`/bin/date "+%d %b %Y %H:%M"`; chop($datetime); $datetime="$XP DateAndTime \"'$datetime'\""; if (defined($Editor)) {$editor="$XP Editor \"'$EscEditor'\""} else {$editor=""}; $unit="$XP UnitCode \"'$UnitCode'\""; $expert="$XP EditExpert \"\'$EditExpert\'\""; $parms="$datetime $editor $unit $expert"; if ($DisplayDate) { $parms .= " $XP DisplayDate \"\'$DisplayDate\'\""; }
Chunk referenced in 36

xsltproc requires 2 parameters, the stylesheet $xsl defining the translations, and the source xml document $src. In addition, we specify the destination html document $dest, an error file for stderr $erf, a date and time parameter $datetime, an editor parameter $Editor, and a unit code parameter $UnitCode. The latter three are used within the xsl stylesheet.

<doView: set stylesheet according to version 38> =
open XML,"<$src" or print "Cannot open $src!<BR>"; $xsl = ""; while (<XML>) { if (/<UnitDescription>/) { $xsl = "$XMLPAGE/FECSA-html.xsl"; last; } elsif (/UnitDescriptionV2/) { $xsl = "xml2html.xsl"; last; } } close XML; if (!$xsl) { printError("Document Type","unable to determine document type for $UnitCode"); return; }
Chunk referenced in 37

This avatar may be called upon to handle version 1 documents. Read the first few lines of the document to see what version it is, and set the xsl stylesheet appropriately.

<doView: handle errors 39> =
$err=~s/&/&amp;/g; $err=~s/</&lt;/g; print "<P>doView: There was an error in translating the source file \n"; print "<TT>$TMP/$UnitCode.xml</TT>.\n"; print "Here is the output that was generated.\n"; print "If you cannot interpret this, please contact John Hurst.<P>\n"; print "<P><B>Command:</B></P>\n"; print "<PRE>\n"; print "$EditOrView\n"; print "$cmd\n"; print "<PRE>\n"; print "<P><B>Output:</B></P>\n"; print "</PRE>\n"; print "$err\n"; print "</PRE>\n"; print "\n";
Chunk referenced in 36 106

There were errors. Before we display the error file, we munge out all ampersands into ampersand entities, and all less than signs into less than entities.

5.2 getDocument: retrieve a unit description file

<subroutines 40> =
sub getDocument { my $readonly = shift; my $createOK = shift; $getDoc="<P>Getting Document $UnitCode\n"; my $erf="$TMP/$UnitCode-new.stderr"; if (-f "$SUBMISSIONS/$UnitCode.xml") { # previous submission available, copy it into $TMP $source="$SUBMISSIONS/$UnitCode.xml"; $getDoc .= "<P>previous submission available, copy it into $TMP\n"; } elsif ($readonly && -f "$SUBMISSIONS/archive/$UnitCode") { $source="$SUBMISSIONS/archive/$UnitCode"; $getDoc .= "<P>using $UnitCode, copy it into $TMP\n"; $UnitCode =~ s/-[0-9]+-.$//; } elsif ($createOK) { my $cmd; my $src="$XMLPAGE/UnitTemplateV2.xml"; my $xsl="$XMLPAGE/mergexml.xsl"; my $tmp="$TMP/$UnitCode-new1.xml"; my $p1 = "$XP FieldA \"'UnitCode'\""; my $p2 = "$XP NewText \"'$UnitCode'\""; my $parms="$p1 $p2"; $getDoc .= "New $UnitCode document, grabbing $src\n"; $cmd="$XSLTPROC $parms -o $tmp $xsl $src 2>$erf"; $getDoc.="New $UnitCode, merging Unit Code ($cmd)\n"; `$cmd`; $source="$TMP/$UnitCode-new.xml"; $p1 = "$XP FieldA \"'FacultyInformation'\""; $p2 = "$XP FieldB \"'FIProposer'\""; my $p3 = "$XP NewText \"'$EscEditor'\""; $parms="$p1 $p2 $p3"; $cmd="$XSLTPROC $parms -o $source $xsl $tmp 2>>$erf"; $getDoc .= "New $UnitCode, setting Proposer ($cmd)\n"; `$cmd`; # must do this to make persistent copy `cp $source "$SUBMISSIONS/$UnitCode.xml"`; unlink $tmp; } else { printError('Missing Document', "I couldn't find the Unit Description for $UnitCode. ". "Do you need to CREATE a new one?"); exit; } <getDocument: and sanitise it 41> unlink $erf; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106

The getDocument subroutine retrieves the XML unit description document for the unit $UnitCode. There are two parameters to the routine:

readonly
A boolean which hen true indicates that the document is to be accessed read only.
createOK
A boolean which when true indicates that the document can be created if it does not already exist.

If the document is to be created, the template UnitTemplateV2.xml is retrieved, and the new unit code merged into it using the XSLT transformation mergexml.xsl.

<getDocument: and sanitise it 41> =
$tmp="$TMP/$UnitCode.xml"; $cmd="$XSLTPROC -o $tmp $XMLPAGE/sanitiseV2.xsl $source 2>$erf"; $getDoc .= "Sanitise $UnitCode ($cmd)"; `$cmd`; if (! -z $erf) { open ERRS,$erf; while (<ERRS>) {$getDoc .= $_;} close ERRS; } $getDoc .= "<P>closed $tmp\n"; print DEBUG $getDoc,"\n";
Chunk referenced in 40

We used to just copy the document here, with the only alteration being to force the DOCTYPE line. However, a transformer sanitiseV2.xsl is now used to render the current document into a canonical form.

6. Edit a Unit Description

There are three stages to editing the unit description, each of which is handled by a separate invocation of the avatar.

Before anything else, ensure that we have a Version Comment.

Next, doEdit generates a rendered version of the unit description, marked up with buttons to change the various editable fields of the document. Each of these buttons forces a call on the next stage of the avatar, with parameters indicating the unit, the field, and the user.

The next stage doChange renders the selected field in an editable text window. The XML of the selected field is extracted from the master document, and converted to ascii text according to the markup. This is done so that naive users are not required to edit XML text directly.

The final stage doUpdate converts the ascii text back into XML, and replaces the original field of the master document with this new text.

6.1 doEdit: Generate an Edit Markup of the Unit Description

<subroutines 42> =
sub doEdit { doLogOperation("doEdit"); my $createOK = shift; my $StartPoint = $auth->param('StartPoint'); my $VersionComment = $auth->param('VersionComment'); $UnitCode=~tr/a-z/A-Z/; if ($UnitCode=~/^$/) { printError('No Unit Code', "You need to enter a unit code in the form ABC1234. ". "Please return to the Welcome page and try again"); exit; } if ($createOK & !$VersionComment) { $VersionComment="Initial Draft"; } getDocument(0,$createOK); <doEdit: parameter debugging 43> $TITLE="InfoTech Unit Avatar: Edit $UnitCode"; &printHtmlHeaders; if ($auth->param('edit')=~/Expert/) {$EditExpert=1;} if ($auth->param('edit')=~/Novice/) {$EditExpert=0;} my $myself=$auth->self_url; if ($StartPoint) { print $auth->p, "Go To <A HREF=\"$myself#$StartPoint\">$StartPoint</A>\n"; } if (! -f "$TMP/$UnitCode.xml") { print "<P>No $TMP/$UnitCode.xml!\n"; print $getDoc; return; } if (!$Editor) { if ($cookie =~ /cn--([^,]+),/) { $Editor = $1; print "<P>Editor = $Editor</P>\n"; $auth->param('Editor',$Editor); } else { print "<P><B>DO NOT HAVE AN EDITOR</B>"; print "<P>Cookie = $cookie\n"; return; } } <doEdit: have a Version Comment 45> }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106

doEdit is responsible for collecting the nominated unit description document, and formatting it using xsltproc under the stylesheet xml2html.xsl, the standard html view of a unit description. Gather the error output, and if that is non-empty, we display that in an error page, otherwise the output of the translation is used.

Now (v2.6.13) that there are auto version comments, the final macro call has been reduced from a choice (which depended on a non-null $VersionComment) between the two <doEdit: do NOT have a Version Comment 44> and <doEdit: have a Version Comment 45> macros.

<doEdit: parameter debugging 43> =
if ($debug) { $_=$TimeStamp." doEdit:These are the parameters and values:\n"; foreach $name (@params) { $_=$_." ".$name.'='.$auth->param($name)."\n"; } $_=$_." ".$field.'='.$newtext."\n"; $_=$_."\n"; print DEBUG; }
Chunk referenced in 42
<doEdit: do NOT have a Version Comment 44> =
print $auth->p, "Please enter a comment to describe the changes being made.", "This comment will be recorded in the document version history.", "Click 'edit' when done"; print $auth->start_form(-action=>"$SCRIPT"), $auth->hidden('UnitCode',$UnitCode), $auth->hidden('Editor',$Editor,), $auth->hidden('StartPoint',$StartPoint), $auth->hidden('EditExpert',$EditExpert), $auth->textarea(-name=>'VersionComment', -default=>$VersionComment, -override=>1, -rows=>10, -columns=>80), $auth->p, $auth->submit('edit'), $auth->end_form;

The routine was invoked with no Version Comment parameter. This is essential for version control, so we first invoke a simple textarea screen for the user to enter a version comment. This will be passed around on all subsequent updates following this doEdit call, but discarded once out of the edit-change-update cycle. This allows users to edit multiple fields on the one version comment.

(20031020:152839) omitted. Now that there is an automatic version history comment added, this is no longer essential. The user can still edit the field in the final edit pane.

<doEdit: have a Version Comment 45> =
print "<P>Note: Clicking on Headings and SubHeadings below will take ", "you to the corresponding place in the <A HREF=\"", "$SERVER/~ajh/adt/quality/V2Guidelines.html", "\">Guidelines Document</A></P>\n"; $VersionComment=~s/'/&apos;/g; $VersionComment=~s/"/&quot;/g; <doEdit: change Editor level 46> print $auth->p,"<B>Reason for Document Update:</B> $VersionComment"; <doEdit: set xsltproc parameters 48> $cmd="$XSLTPROC $parms -o $dest $xsl $src 2>$erf"; `$cmd`; $err = ""; open ERR,"<$erf"; while (<ERR>) {$err.=$_}; close ERR; if ($err) { <doEdit: handle errors 49> } else { print $auth->hr; print "<div style=\"background-color:#fff\">"; # use the resultant HTML file as returned page open NEW,"<$dest"; while (<NEW>) {print;} close NEW; print $auth->hr, $auth->p, "Is the version comment below still accurate after all your changes?", " If not, correct it below and click 'edit'", $auth->p, $auth->start_form(-action=>"$SCRIPT"), $auth->hidden('UnitCode',$UnitCode), $auth->hidden('Editor',$Editor), $auth->hidden('StartPoint',$StartPoint), $auth->hidden('EditExpert',$EditExpert), $auth->textarea(-name=>'VersionComment', -default=>$VersionComment, -override=>1, -rows=>10, -columns=>80), $auth->p, $auth->submit('edit'), $auth->end_form, $auth->hr, $auth->p, $auth->start_form(-action=>"$SCRIPT"), $auth->hidden('UnitCode',$UnitCode), $auth->hidden('Editor',$Editor), $auth->hidden('StartPoint',$StartPoint), $auth->hidden('EditExpert',$EditExpert), $auth->hidden('VersionComment',$VersionComment), $auth->submit('Save'), "Click this button to save your edits and return ", "to the Avatar Home Page. ", $auth->end_form, $auth->p, $auth->start_form(-action=>"$SCRIPT"), $auth->hidden('UnitCode',$UnitCode), $auth->hidden('Editor',$Editor), $auth->hidden('StartPoint',$StartPoint), $auth->hidden('EditExpert',$EditExpert), $auth->hidden('VersionComment',$VersionComment), $auth->submit('Submit'), "Click this button to submit your unit description for ", "<B STYLE=\"color:red\">SCHOOL</B> ", "approval and return to the Avatar Home Page. ", $auth->p, "<B STYLE=\"color:red\">NOTE THAT DIRECT SUBMISSION TO FEC IS NO LONGER POSSIBLE</B> ", $auth->end_form; print "</div>\n"; }
Chunk referenced in 42
<doEdit: change Editor level 46> =
if ($EditExpert) { print "<P>You are currently an <B>Expert</B> editor, $Editor!</P>\n"; } else { print "<P>You are currently a <B>Novice</B> editor, $Editor!</P>\n"; } print $auth->p,<doEdit: helpful text 47> print $auth->start_form(-action=>"$SCRIPT"), $auth->hidden('UnitCode',$UnitCode), $auth->hidden('Editor',$Editor,), $auth->hidden('VersionComment',$VersionComment), $auth->hidden('StartPoint',$StartPoint), $auth->p, $auth->submit('edit','Novice'), $auth->submit('edit','Expert'), $auth->hidden('EditExpert',$EditExpert), $auth->end_form; print $auth->hr;
Chunk referenced in 45

The first part of this part asks the user to nominate whether they wish to edit plain text ('Novice' user) or XML ('Expert' user). The value of $EditExpert is set on entry to the doEdit subroutine (see above).

<doEdit: helpful text 47> =
"<P>When editing your Unit Description, you can choose to ", "edit plain text (with some markup), or XML.</P><P>Plain ", "text is more user friendly, but less powerful; while editing ", "the XML requires strict discipline in tag closing and nesting. ", "Also please bear in mind that editing plain text may lose some ", "document formatting. (If you do not understand this message, ", "you can safely ignore it and proceed straight to the 'edit' box.)</P>", "<P>Click the Expert button if you want to edit the XML directly</P>";
Chunk referenced in 46

We have to sanitise the version comment for passing as a parameter into xsltproc. The call on xsltproc renders the XML unit description document into HTML, with clickable buttons to change the various editable fields.

Question: what should be done with the version comment at this stage?. One option is to insert it into the XML document as soon as possible, another is to defer it until the document is saved and/or archived, yet another is to add it as an editable field (but not yet part of the XML).

<doEdit: set xsltproc parameters 48> =
$xsl = "xml2html.xsl"; $src="$TMP/$UnitCode.xml"; $dest="$TMP/$UnitCode$destmod.html"; $erf="$TMP/$UnitCode-edit.stderr"; $datetime=$TimeStamp; #`/bin/date "+%d %b %Y %H:%M"`; chop($datetime); $datetime="$XP DateAndTime \"'$datetime'\""; if (defined($Editor)) {$editor="$XP Editor \"'$EscEditor'\""} else {$editor=""}; $unit="$XP UnitCode \"'$UnitCode'\""; $expert="$XP EditExpert \"\'$EditExpert\'\""; $change="$XP ViewOrEdit \"'Edit'\""; $version="$XP VersionComment \"'$VersionComment'\""; $server="$XP Server \"'$SCRIPT'\""; $parms="$datetime $editor $unit $expert $change $version $server";
Chunk referenced in 45

xsltproc requires 2 parameters, the stylesheet $xsl defining the translations, and the source xml document $src. In addition, we specify the destination html document $dest, an error file for stderr $erf, a date and time parameter $datetime, an editor parameter $Editor, and a unit code parameter $UnitCode. The latter three are used within the xsl stylesheet.

<doEdit: handle errors 49> =
$err=~s/&/&amp;/g; $err=~s/</&lt;/g; print "<P>doEdit: There was an error in translating the source file \n"; print "<TT>$TMP/$UnitCode.xml</TT>.\n"; print "Here is the output that was generated.\n"; print "If you cannot interpret this, please contact John Hurst.<P>\n"; print "<P><B>Command:</B></P>\n"; print "<PRE>\n"; print "$EditOrView\n"; print "$cmd\n"; print "<PRE>\n"; print "<P><B>Output:</B></P>\n"; print "</PRE>\n"; print "$err\n"; print "</PRE>\n"; print "\n";
Chunk referenced in 45

There were errors. Before we display the error file, we munge out all ampersands into ampersand entities, and all less than signs into less than entities.

6.2 doChange: Generate an Editable Text of the specified Field

Parms: /---------\ see list ---------->| MonAtar | below \---------/ | V getDocument: result in $TMP/$UnitCode.xml +--------------------+ | $TMP/$UnitCode.xml | +--------------------+ | V +-------------+ /----------\ | xml2txt.xsl |---->| xsltproc |<---- Param FieldA "fieldA value" +-------------+ \----------/ Param FieldB "fieldB value" | Param EditExpert "Novice|Expert" V / \ /OK?\ no \ /------> Error, Cannot happen! \ / | yes V +---------------------------+ text if EditExpert = Novice | $TMP/$UnitCode$suffix.txt | +---------------------------+ xml if EditExpert = Expert use this file to build default value in form delete TMP files

The following parameters are passed to MonAtar.

change
a value passed in from the doEdit generated form, with the structure Change FieldA/FieldB, where FieldA and FieldB are hierarchical field tags from the Unit Description document. These are used to extract the original value from the document for setting the default editing value.
UnitCode
The unit code
Editor
an authenticated user
EditExpert
a boolean indicating the expert status of the user
<subroutines 50> =
sub doChange { doLogOperation("doChange"); $change = $auth->param('change'); $VersionComment = $auth->param('VersionComment'); $UnitCode=~tr/a-z/A-Z/; $change=~s#^Change ([^/]*)(/(.*))?$#\1\2#; $FieldA=$1; $FieldB=$3; $suffix=$FieldA.$FieldB; getDocument(0,0); $TITLE="Infotech Avatar: Updating $UnitCode"; &printHtmlHeaders; if ($EditExpert) { print "<P>You are currently an <B>Expert</B> editor!</P>\n"; } else { print "<P>You are currently a <B>Novice</B> editor!</P>\n"; } if ($debug) { $_=$auth->p."doChange($UnitCode,$Editor,$FieldA,$FieldB)=>$change\n"; $_=$_.$auth->p."These are the parameters and values:\n"; $_=$_."<P STYLE=\"margin-left:20pt\">"; foreach $name (@params) { $_=$_.$name.'='.$auth->param($name).'<BR>'; } $_=$_.'</P>'; print DEBUG $_; } print $auth->h2("Editing $UnitCode $change field ..."), $auth->p, "Edit the following text, then click this 'Update' ", "button."; <doChange: print helpful hints 51> my $xsl = "$XMLPAGE/xml2txt.xsl"; if ($EditExpert) {$xsl = "$XMLPAGE/xmlextract.xsl"}; my $src = "$TMP/$UnitCode.xml"; my $dst = "$TMP/$UnitCode$suffix.txt"; my $prm = "$XP FieldA \"\'$FieldA\'\" $XP FieldB \"\'$FieldB\'\""; $prm .= " $XP EditExpert \"\'$EditExpert\'\""; my $ers = "$TMP/$UnitCode-change.ers"; my $cmd = "$XSLTPROC $prm $xsl $src >$dst 2>$ers"; my $res = `$cmd`; if ($debug) { print DEBUG "doChange: $cmd\n"; } my $val = ""; open XML,$dst; while (<XML>) {$val=$val.$_;} close XML; unlink $dst; print $auth->start_form(-action=>"$SCRIPT"), $auth->submit('update',"Update the $change"); <doChange: warn about editing ObjText 52> print $auth->p, $auth->textarea(-name=>$change, -default=>$val, -override=>1, -rows=>50, -columns=>80), $auth->p, $auth->hidden(-name=>'UnitCode',-default=>$UnitCode), $auth->hidden(-name=>'Editor',-default=>$Editor), $auth->hidden('EditExpert',$EditExpert), $auth->hidden(-name=>'VersionComment',-default=>$VersionComment), $auth->hidden(-name=>'FieldA',-default=>$FieldA), $auth->hidden(-name=>'FieldB',-default=>$FieldB), $auth->hidden(-name=>'value',-default=>$val), $auth->end_form; unlink $ers; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106
<doChange: print helpful hints 51> =
if (!$EditExpert) { print "Some helpful hints:"; print $auth->p, "<P>Text in this window should be formatted to reflect its logical ", "structure, and is used to build the document structure of the ", "XML fragment.</P>", "<UL><LI>Blank lines represent paragraph breaks. ", "<B>DON'T put blank lines between items in an (un)numbered list, ", "otherwise each item will be a separate list!</B></LI>", "<LI>(Carriage) returns or enters are ignored if the next line ", "has the same indentation as the previous line.</LI>", "<LI>Itemized text should be consistently indented, and flagged ", "with a leading '+', '-' or 'o' character, followed by at least ", "one blank.</LI>", "<LI>Numbered text should be consistently indented, and flagged ", "with one or more leading digits, followed by a full stop and at ", "least one blank.</LI>", "<LI>Nested itemized or numbered paragraphs can be shown by ", "increasing the indentation.</LI>", "<LI>{\\b bold}, {\\i italic}, and {\\ul underline} can be used to ", "markup highlighted text</LI></UL>\n"; }
Chunk referenced in 50
<doChange: warn about editing ObjText 52> =
if ($change=~m^UnitObjectives/ObjText^) { print $auth->p,'<span style="color:red"><b><blink>'. 'IF YOU CONTINUE TO EDIT THIS FIELD, IT WILL BE DELETED.'. '</blink> USE YOUR BACK BUTTON NOW TO CANCEL!</b></span>'; }
Chunk referenced in 50

6.3 doUpdate: Incorporate changes into the Unit Description

<subroutines 53> =
sub doUpdate { doLogOperation("doUpdate"); my $FieldA = $auth->param('FieldA'); my $FieldB = $auth->param('FieldB'); my $VersionComment = $auth->param('VersionComment'); my $field = $FieldA; if ($FieldB) {$field="$FieldA/$FieldB";} my $suffix = $FieldA.$FieldB; my $newtext = $auth->param($field); $UnitCode=~tr/a-z/A-Z/; getDocument(0,0); <doUpdate: parameter debugging 54> $newtext =~ s/\r/ /g; if ($auth->param('update')=~/Change Classification/) { $FieldA = "Classification"; $field=$FieldA; $Attribute = "BOK"; $newtext = $auth->param("BOK"); $newtext =~ s/.*\((.*)\)/\1/; } elsif ($auth->param('update')=~m^Update the UnitObjectives/ObjText^) { $newtext=""; } else { if (!$EditExpert) { <doUpdate: convert plain text to XML 55> } <doUpdate: sanitise newtext 56> } <doUpdate: call the xslt processor 57> if (-s $ers && $debug) {print DEBUG "doUpdate: failed on merge\n";} if (-z $ers) { <doUpdate: check revised document 59> if (-s $ers && $debug) {print DEBUG "doUpdate: failed on check\n";} } if (-s $ers) { <doUpdate: error reporting 58> } else { rename "$TMP/$UnitCode-new.xml","$SUBMISSIONS/$UnitCode.xml"; if ($VersionComment) {$VersionComment.="; ";} $VersionComment.="modified $field"; $auth->param(-name=>'StartPoint',-values=>[$field]); $auth->param(-name=>'VersionComment',-values=>[$VersionComment]); &doEdit(0); } unlink $ers; return; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106

doUpdate is called when the user has edited a field of the description, and clicks the "Update the ...." button. The avatar is invoked with the following set of parameters:

UnitCode
The unit code
Editor
The editor of the document
field
The element name of the field being edited.
tag
(This parameter varies with the tag of the field being edited.) The new value of the field.
value
The original value of the field (not used)

We grab the new text to replace the field. This is the raw ascii text, as edited by the user. Write this text into a file, for conversion by the ascii to xml translator, a2x. Call the translator, and read the translated text (now in XML markup) back into $newtext.

<doUpdate: parameter debugging 54> =
if ($debug) { $_=$TimeStamp." doUpdate:These are the parameters and values:\n"; foreach $name (@params) { $_=$_." ".$name.'='.$auth->param($name)."\n"; } $_=$_." ".$field.'='.$newtext."\n"; $_=$_."\n"; print DEBUG; print DEBUG "doUpdate($UnitCode,$Editor,$field,$newtext)=>$suffix\n"; print DEBUG "Opening $TMP/$UnitCode$suffix.txt\n"; }
Chunk referenced in 53 60 61
<doUpdate: convert plain text to XML 55> =
my $txt = "$TMP/$UnitCode$suffix.txt"; open FIELD,">$txt"; print FIELD $newtext; close FIELD; $newtext=""; $cmd="$XMLPAGE/a2x.pl $txt"; if ($debug) { print DEBUG "doUpdate: $cmd\n"; } `$cmd`; unlink $txt; my $xml = "$TMP/$UnitCode$suffix.xml"; open FIELD,$xml; while (<FIELD>) {s#<p></p>##; $newtext=$newtext.$_;} close FIELD; unlink $xml; #print "<P>Finished translation to XML\n";
Chunk referenced in 53
<doUpdate: sanitise newtext 56> =
$newtext=~s/\n/ /g; $newtext=~s/ +/ /g; $newtext=~s/"/&quot;/g; $newtext=~s/'/&apos;/g; $newtext=~tr/[\x80-\xff]/?/; if ($debug) { print DEBUG $newtext; print DEBUG "<P>End of translated text\n"; }
Chunk referenced in 53

sanitise the new text to be inserted by

  1. removing all new lines and replacing them with spaces
  2. replacing multiple spaces with a single space
  3. changing double quotes (which foul up the parameter passing at the command line level) to XML entities
  4. ditto for single quotes
  5. ensuring that all characters are 7-bit ASCII
For debugging purposes, print the new sanitised text.

<doUpdate: call the xslt processor 57> =
$proc="$XSLTPROC"; $xsl="$XMLPAGE/mergexml.xsl"; $src="$TMP/$UnitCode.xml"; $dst="$TMP/$UnitCode-new.xml"; $ers="$TMP/$UnitCode-new.ers"; $prms="$XP FieldA \"\'$FieldA\'\" $XP FieldB \"\'$FieldB\'\""; $prms.=" $XP NewText \"\'$newtext\'\" $XP Attribute \"\'$Attribute\'\""; $prms.=" $XP DateTime \"\'$timestamp\'\""; $cmd="$proc $prms -o $dst $xsl $src 2>$ers"; if ($debug) {print DEBUG "$cmd\n"}; `$cmd`;
Chunk referenced in 53

We add the edited field into the unit description with the aid of the mergexml.xsl XSLT transform. This script takes an existing XML unit description and merges the NexText parameter into the field FieldA/FieldB. This is a two level addressing operation, since many fields of the unit description are subfields of top-level fields. See the mergexml.xsl documentation for further details of this transformation.

<doUpdate: error reporting 58> =
$TITLE="Infotech Avatar: Error in Updating $UnitCode"; &printHtmlHeaders; print "<P>doUpdate: There was an error in adding your edits to \n"; print "<TT>$TMP/$UnitCode.xml</TT>.\n"; print "Here is the output that was generated.\n"; print "If you cannot interpret this, please contact John Hurst.<P>\n"; print "<P><B>Command:</B></P>\n"; print "<PRE>\n"; print "$cmd\n"; print "<PRE>\n"; print "<P><B>Output:</B></P>\n"; print "</PRE>\n"; $err=""; open ERR,"<$ers";while(<ERR>){$err.=$_;} close ERR; $err=~s/&/&amp;/g; $err=~s/</&lt;/g; print "$err\n"; print "</PRE>\n"; print "\n";
Chunk referenced in 53 60 61
<doUpdate: check revised document 59> =
$proc="$XSLTPROC"; $xsl="xml2html.xsl"; $src="$TMP/$UnitCode-new.xml"; $dst="$TMP/$UnitCode-new.html"; $ers="$TMP/$UnitCode-new.ers"; $prms="$XP UnitCode \"\'$UnitCode\'\" "; $cmd="$proc $prms -o $dst $xsl $src 2>$ers"; print DEBUG "doUpdate: check revised document ($cmd)\n"; `$cmd`;
Chunk referenced in 53
We have a new document, UnitCode-new.xml, which we should check for well-formedness before proceding further. Do this by running it through the view stylesheet.

6.4 doSave: Incorporate changes into the Unit Description

<subroutines 60> =
sub doSave { doLogOperation("doSave"); my $VersionComment = $auth->param('VersionComment'); my @Classification = $auth->param('BOK'); $UnitCode=~tr/a-z/A-Z/; getDocument(0,0); $TITLE="Infotech Unit Avatar: Save Document"; &printHtmlHeaders; $src="$TMP/$UnitCode.xml"; print $auth->p,"<P>Timestamp=$timestamp</P>\n"; $k="V"; $FullUnitCode="$UnitCode-$timestamp-$k"; $dest="$SUBMISSIONS/archive/$FullUnitCode"; <doUpdate: parameter debugging 54> $proc="$XSLTPROC"; $xsl="$XMLPAGE/MonAtar-version.xsl"; $src="$TMP/$UnitCode.xml"; $dst="$TMP/$UnitCode-new.xml"; $ers="$TMP/$UnitCode-new.ers"; $prms="$XP Date \"\'$timestamp\'\" ". "$XP Editor \"\'$EscEditor\'\" ". "$XP VersionComment \"\'$VersionComment\'\""; $cmd="$proc $prms -o $dst $xsl $src 2>$ers"; #print "<P>$cmd\n"; `$cmd`; $err=""; open ERR,"<$ers";while(<ERR>){$err.=$_;} close ERR; if ($err) { <doUpdate: error reporting 58> } else { `cp "$TMP/$UnitCode-new.xml" "$dest"`; rename "$TMP/$UnitCode-new.xml","$SUBMISSIONS/$UnitCode.xml"; print $auth->p,"Save successful! Click to reenter avatar, ". "or view edited description"; print $auth->start_form(-action=>"$SCRIPT"), $auth->submit('reenter',"Reenter Avatar"), $auth->submit('view',"View Updated Unit"), $auth->hidden('UnitCode',$UnitCode), $auth->end_form; } unlink $ers; return; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106

doSave is called when the user clicks the final "Save" button on the doEdit page. The avatar is invoked with the following set of parameters:

UnitCode
The unit code
Editor
The editor of the document
VersionComment
The comment to insert in the version history, along with Editor, Date and Time information.

6.5 doSubmit: Incorporate changes into the Unit Description

<subroutines 61> =
sub doSubmit { doLogOperation("doSubmit"); my $VersionComment = $auth->param('VersionComment'); $UnitCode=~tr/a-z/A-Z/; getDocument(0,0); $TITLE="Infotech Unit Avatar: Submit Document"; &printHtmlHeaders; $src="$TMP/$UnitCode.xml"; print $auth->p,"<P>Timestamp=$timestamp</P>\n"; $k="M"; $FullUnitCode="$UnitCode-$timestamp-$k"; $dest="$SUBMISSIONS/archive/$FullUnitCode"; <doUpdate: parameter debugging 54> $proc="$XSLTPROC"; $xsl="$XMLPAGE/MonAtar-version.xsl"; $src="$TMP/$UnitCode.xml"; $dst="$TMP/$UnitCode-new.xml"; $ers="$TMP/$UnitCode-new.ers"; $prms="$XP Date \"\'$timestamp\'\" ". "$XP Editor \"\'$EscEditor\'\" ". "$XP VersionComment \"\'$VersionComment\'\""; $cmd="$proc $prms -o $dst $xsl $src 2>$ers"; #print "<P STYLE=\"margin-left:20pt\">$cmd</P>\n"; `$cmd`; <doSubmit: get document values 62> $err=""; open ERR,"<$ers";while(<ERR>){$err.=$_;} close ERR; if ($err) { <doUpdate: error reporting 58> } else { `cp "$TMP/$UnitCode-new.xml" "$dest"`; rename "$TMP/$UnitCode-new.xml","$SUBMISSIONS/$UnitCode.xml"; <doSubmit: send mail to SEC members 63> print $auth->p,"<B>Submit successful!</B>"; print $auth->p, "Click to reenter avatar, ", "or simply delete this window and reuse original window."; print $auth->start_form(-action=>"$SCRIPT"), $auth->submit('reenter',"Avatar"), $auth->hidden('UnitCode',$UnitCode), $auth->end_form; } return; }
Chunk referenced in 12
Chunk defined in 22,23,24,25,26,27,28,29,30,33,34,36,40,42,50,53,60,61,65,66,69,74,76,98,103,104,105,106

doSubmit is called when the user clicks the final "Submit" button on the doEdit page. The avatar is invoked with the following set of parameters:

UnitCode
The unit code
Editor
The editor of the document
VersionComment
The comment to insert in the version history, along with Editor, Date and Time information.
The document is also archived with the extension "M" (for unit subMission to the school level).

<doSubmit: get document values 62> =
open DOCVALS,"<$TMP/$UnitCode.msgs"; while (<DOCVALS>) {$docvals.=$_}; close DOCVALS; $docvals=~s/UnitName = (.*)\$\n//s; $UnitName = $1; $docvals=~s/UnitSummary = (.*)\$\n//s; $UnitSummary = $1;
Chunk referenced in 61
<doSubmit: send mail to SEC members 63> =
my $mode = "submitted"; getLatestApproved($UnitCode); $mailmsg="A unit description (for a new or existing unit)\n"; $mailmsg.=" $UnitCode $UnitName\n"; $mailmsg.="has been $mode at URL:\n\n"; $mailmsg.=" $SCRIPT?UnitCode=$FullUnitCode\n\n"; if ($ApprovedVersion) { $mailmsg.="You can compare this with the latest (Faculty) approved"; $mailmsg.=" version by clicking\n\n"; $mailmsg.=" $SCRIPT?". "compare=compare&BaseCode=$ApprovedVersion". "&UnitCode=$FullUnitCode\n\n"; } if ($mode=~/saved/) { $mailmsg.="WARNING: This revision has not been notified to SEC\n"; $mailmsg.="******** You must explicitly SUBMIT the description "; $mailmsg.="for that to happen!\n\n"; } $mailmsg.="Author of Revisions: $Editor\n"; $mailmsg.="Unit Synopsis: $UnitSummary\n"; if ($UnitCode) { $esub="[MonAtar] $UnitCode $UnitName ($mode) "; <doSubmit: get submission data 64> # send each of the school SEC members an email foreach $eadr (@adrs) { $recipients.=$eadr."\n"; &sendmail($eadr,$esub,$mailmsg); } # Send the ADT a copy $eadr="John.Hurst\@infotech.monash.edu.au"; $recipients.=$eadr."\n"; &sendmail($eadr,$esub,$mailmsg); # sanitise the ProposerEmail field(s) $ProposerEMail=~tr/\r\n /,,,/; $ProposerEMail =~s/,,+/,/g; @emails = split(',',$ProposerEMail); # chop at commas foreach $email (@emails) { $email =~ s/[\s;]//g; if ($email =~ /^[\w\.-@<>"]+$/) { $recipients.=$email."\n"; &sendmail($email,$esub,$mailmsg); } else { print "<P>$email not emailed as it contains illegal characters</P>\n"; } } # sanitise the ContactEmail field(s) $ContactEMail=~tr/\r\n /,,,/; $ContactEMail =~s/,,+/,/g; @emails = split(',',$ContactEMail); # chop at commas foreach $email (@emails) { $email =~ s/[\s;]//g; if ($email =~ /^[\w\.-@<>"]+$/) { $recipients.=$email."\n"; &sendmail($email,$esub,$mailmsg); } else { print "<P>$email not emailed as it contains illegal characters</P>\n"; } } print "<P>The following email addresses have been notified of your submission</P>\n"; print "<PRE STYLE=\"margin-left:20pt\">$recipients</PRE>\n"; print "with the following message:\n"; print "<PRE STYLE=\"margin-left:20pt\">$mailmsg</PRE>\n"; if ($debug) { print DEBUG "Submit: emailed the following recipients:\n$recipients\n"; } }
Chunk referenced in 61
<doSubmit: get submission data 64> =
my ($fac,$sch); print DEBUG "doSubmit: Faculty=$Faculty, School=$School\n"; if ($Faculty=~/Information Technology/) { $fac="IT"; if ($School=~/Gippsland/) {$sch="gscit"} elsif ($School=~/Business Systems/) {$sch="sbs"} elsif ($School=~/Computer Science/) {$sch="csse"} elsif ($School=~/Network/) {$sch="snc"} elsif ($School=~/Information Management/) {$sch="sims"} elsif ($School=~/Multimedia/) {$sch="sms"} elsif ($School=~/Business and Information Technology/) {$sch="mum"} elsif ($School=~/South Africa/) {$sch="sa"} else { printError("No School","No school code $School to receive submission"); } } elsif ($Faculty=~/Medicine/) { printError("No Faculty","$Faculty not currently receiving submissions"); } elsif ($Faculty=~/Business/) { printError("No Faculty","$Faculty not currently receiving submissions"); } else { printError("No Faculty","$Faculty not currently receiving submissions"); } my $submitdataname = "MonAtar-$fac-$sch.adr"; open ADRS,$submitdataname or printError("No Addresses","I couldn't find the addresses $submitdataname to email"); my @adrs; while (<ADRS>) { chop; push(@adrs,$_); } close ADRS; # Here a kludge to check if editor's school is the same # as the proposing school for the unit. If not, send to both. my