#! /usr/bin/perl
# Copyright 2001-2019 Leslie Richardson
# This file is part of Open Admin for Schools.
# Synchronize School Courses
# Display courses by start and endterm, select those to synchronize.
# Get course enrollment data from SaskEd.
# Find the differences between the two for each course in turn.
# Do the course enrollments to get synchronized.
# Rerun Query to check synchronization.
# Passed Values: none.
# Notes: the dates in doEnrollments are not passed from previous page,
# but rather are the values from config files. Might be better to use
# SaskEd date values from query... later.
my $self = 'synccourses.pl';
my $additionalcomments = 'Additional Comments';
my $version = '2019-12-06';
use DBI;
use CGI;
use XML::Writer;
use XML::Writer::String;
use Data::UUID;
use HTTP::Request::Common qw(POST);
use HTTP::Headers;
use LWP::UserAgent;
use XML::LibXML;
use Number::Format qw(round);
my %lex = ( 'Main' => 'Main',
'Error' => 'Error',
);
eval require "../../etc/admin.conf";
if ( $@ ) {
print $lex{Error}. " $@ \n";
die $lex{Error}. " $@\n";
}
eval require "slxmllibNew.pl";
if ( $@ ) {
print $lex{Error}. " $@ \n";
die $lex{Error}. " $@\n";
}
my $dsn = "DBI:$dbtype:dbname=$dbase";
$dbh = DBI->connect($dsn,$user,$password);
$dbh->{mysql_enable_utf8} = 1;
my $q = new CGI;
my %arr = $q->Vars;
print $q->header( -charset, $charset);
# Date Stuff setup; required for the SDS transfers header also
# $sec, $min, $hour, $mday, $mon,
# $year, $wday, $yday, $isdst ) = localtime(time);
my @tim = localtime(time);
$year = $tim[5] + 1900;
$tim[4]++;
for (0..4){ if (length($tim[$_]) == 1){ $tim[$_] = '0'.$tim[$_];}}
$currdate = "$year-$tim[4]-$tim[3]";
$currtime = "$tim[2]:$tim[1]:$tim[0]";
# Print Page Header
print qq{$doctype\n
\n};
}
# Create the https post request
my $req = POST $url, [ XML=>$output->value ];
$req->content_type('application/xml;charset="utf-8"');
$req->authorization_basic($sds_userid, $sds_password);
# Issue the request and receive a response
my $res = $ua->request($req);
# Check the status of the response
if ($res->is_success) {
# For Debugging Data Errors
if ($debug){
print qq{
\n};
}
# Parse the response.
my $parser = XML::LibXML->new();
eval {$doc = $parser->parse_string($res->content)};
if ($@){
print qq{Error: $@ \n};
print qq{
Sask Ed Error:\n},$res->content,qq{
\n};
print qq{\n};
die;
}
$doc->setEncoding('UTF-8');
$root = $doc->getDocumentElement;
$root->setNamespace($xmlns,'sl',1);
$status = $root->findvalue('//sl:SL_Status/sl:SL_StatusCode');
# We are now setup to parse the root element.
} else { # Transfer Error!
my $err = $res->status_line;
print qq{
Transfer Error: $err
};
die qq{Transfer Error\n};
}
my $course_ref = parseSCEbyClass();
return $course_ref;
}
#--------------------------------
sub parseStudentCourseEnrollments { # passed document root object.
#--------------------------------
# This does a printout of the structure.... next sub creates object.
my @studinfo = $root->findnodes('//sl:StudentCourseEnrollments');
my $count = 1;
my $sth = $dbh->prepare("select lastname, firstname from student
where provnum = ? ");
foreach my $student (@studinfo){
my $provnum = $student->findvalue('sl:StudentIdentification/sl:DeptAssignedPersonId');
my $birthdate = $student->findvalue('sl:StudentIdentification/sl:BirthDate');
$sth->execute($provnum);
if ($DBI::errstr){ print $DBI::errstr; die $DBI::errstr;}
my ($lastname, $firstname) = $sth->fetchrow;
print "
$firstname $lastname ( $provnum - $birthdate )
\n";
print "
\n";
print "
Schoolyear
Termstart
Termend
";
print "
ClassId
Mode
Mark Src
\n";
my @classes = $student->findnodes('sl:StudentSchoolClasses/sl:StudentTermClasses');
foreach my $class (@classes) {
my $schoolyear = $class->findvalue('sl:TermInfo/@SchoolYear');
my $termstart = $class->findvalue('sl:TermInfo/sl:StartDate');
my $termend = $class->findvalue('sl:TermInfo/sl:EndDate');
my @sections = $class->findnodes('sl:StudentClass');
foreach my $section (@sections) {
my $classid = $section->findvalue('sl:ClassId');
my $mode = $section->find('sl:ModeOfInstruction/@Code');
my $marksource = $section->findvalue('sl:MarkSource/@Code');
print "
$schoolyear
$termstart
$termend
\n";
print "
$classid
$mode
$marksource
\n";
}
}
print "
\n";
}
} # End of Sub
#----------------------
sub parseSCEbyClass {
#----------------------
# passed document root object.
# Parse SchoolCourseEnrollments, and return a reference to a courses
# hash containing refs to a list (array) of provincial numbers.
my @studinfo = $root->findnodes('//sl:StudentCourseEnrollments');
my $count = 1;
my %courses;
foreach my $student (@studinfo){
my $provnum = $student->findvalue('sl:StudentIdentification/sl:DeptAssignedPersonId');
# my $birthdate = $student->findvalue('sl:StudentIdentification/sl:BirthDate');
my @classes = $student->findnodes('sl:StudentSchoolClasses/sl:StudentTermClasses');
foreach my $class (@classes) {
#my $schoolyear = $class->findvalue('sl:TermInfo/@SchoolYear');
my $termstart = $class->findvalue('sl:TermInfo/sl:StartDate');
my $termend = $class->findvalue('sl:TermInfo/sl:EndDate');
my @sections = $class->findnodes('sl:StudentClass');
foreach my $section (@sections) {
my $classid = $section->findvalue('sl:ClassId');
my $mode = $section->find('sl:ModeOfInstruction/@Code');
my $marksource = $section->findvalue('sl:MarkSource/@Code');
$coursedata{"$classid:$termstart:$termend"} = "$mode:$marksource";
if (not defined $courses{"$classid:$termstart:$termend"}) {
$courses{"$classid:$termstart:$termend"} = [ $provnum ];
} else {
push @{$courses{"$classid:$termstart:$termend"}},$provnum;
}
}
} # End of StudentSchoolClasses
} # End of student loop
return \%courses;
} # End of parseSCEbyCourse
#------------
sub showTerms {
#------------
print qq{
\n};
print qq{Select a start term / end term combination