The Monash Unit Description Avatar
A.J.Hurst
Version
Table of Contents
<version 1> = 2.8.5
1. Global Constants
<context variables 2> =my $TESTING = 0;
Define whether we are running in test mode
<context variables 3> =my $WEBPAGE = "/u/homes1/ajh";
my $SERVER = "http://www.csse.monash.edu.au";
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";
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";
Define the base page for any cgi scripts.
<context variables 6> =my $XMLPAGE = "$WEBPAGE/cgi-bin";
Define where all XML and XSL support scripts and files are
stored.
<context variables 7> =my $APPROVALS = "$XMLPAGE/MonAtar-IT.appr";
<context variables 8> =my $TMP = "$WEBPAGE/tmp";
<context variables 9> =my $GRAPHICS = "$SERVER/~ajh/graphics";
<context variables 10> =# Set this to the name of the CGI on your web server
$SCRIPT = "$CGIPAGE/MonAtar";
<context variables 11> =# Define the xslt processor and options
$XSLTOPTS = "XML_CATALOG_FILES=$XMLPAGE/catalog";
$XSLTPROC = "$XSLTOPTS /usr/local/bin/xsltproc";
$XP = "--param";
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
- Have separate edit buttons for each section.
- Incorporate a2x.pl into monatar litprog
- Design Version Control interface
- 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.)
- add StartPoint mechanism to always display description
at edit point.
- 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
- Write your cognitive domain objectives here
- Write your affective domain objectives here
- Write your psychomotor domain objectives here
- Write your social domain objectives here
with a link to an html document (see attachment for this
email) for more detail.
2.4 Legacy Issues
- Write a conversion xsl script from old format to
new. Complete, called V1toV2.xsl
- Create copy of units directory and archive wherein all
descriptions can be converted. Keep this up-to-date until
change-over. Done.
- The new cgi script will be cookie based, to avoid
reauthentication. Done.
- 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 12Chunk defined in 13,
14
<initialization 14> =$TimeStamp = `/bin/date "+%Y%m%d:%H%M%S"`; chop $TimeStamp;
$timestamp = $TimeStamp; $timestamp=~s/://;
Chunk referenced in 12Chunk 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/</</g;
#if ($name ne 'mypass') {
# print LOG $name,"=",$value," ";
#}
}
$UnitCode = $auth->param('UnitCode');
$UnitCode =~ tr/a-z/A-Z/;
Chunk referenced in 12Chunk defined in 15,
16,
17
<get parameters 16> =$EditExpert = $auth->param('EditExpert');
Chunk referenced in 12Chunk 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 12Chunk 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;
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>";
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;
}
}
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",$_);
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 12Chunk 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 12Chunk 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 12Chunk 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 12Chunk 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 12Chunk 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 12Chunk 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 12Chunk 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 12Chunk 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/'/"e;/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 12Chunk 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";
<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";
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 12Chunk 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 12Chunk 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>";
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 12Chunk 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\'\"";
}
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;
}
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/&/&/g; $err=~s/</</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 12Chunk 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";
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 12Chunk 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;
}
<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/'/'/g;
$VersionComment=~s/"/"/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";
}
<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;
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>";
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";
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/&/&/g; $err=~s/</</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";
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 12Chunk 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";
}
<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>';
}
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 12Chunk 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";
}
<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";
<doUpdate: sanitise newtext 56> =$newtext=~s/\n/ /g;
$newtext=~s/ +/ /g;
$newtext=~s/"/"/g;
$newtext=~s/'/'/g;
$newtext=~tr/[\x80-\xff]/?/;
if ($debug) {
print DEBUG $newtext;
print DEBUG "<P>End of translated text\n";
}
sanitise the new text to be inserted by
- removing all new lines and replacing them with spaces
- replacing multiple spaces with a single space
- changing double quotes (which foul up the parameter
passing at the command line level) to XML entities
- ditto for single quotes
- 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`;
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/&/&/g; $err=~s/</</g;
print "$err\n";
print "</PRE>\n";
print "\n";
<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`;
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 12Chunk 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 12Chunk 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;
<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";
}
}
<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