#!/usr/local/bin/webwork-perl ## This file is profExportClasslistDatabase.pl ## #################################################################### # Copyright @ 1995-2000 University of Rochester # All Rights Reserved #################################################################### use lib '.'; use webworkInit; # WeBWorKInitLine use CGI qw(:standard); use Global; use Auth; use strict; use GDBM_File; my $cgi = new CGI; my %inputs = $cgi->Vars(); # get information from CGI inputs (see also below for additional information) my $Course = $inputs{'course'}; my $User = $inputs{'user'}; my $Session_key = $inputs{'key'}; # verify that information has been received unless($Course && $User && $Session_key) { &wwerror("$0","The script did not receive the proper input data.","",""); } # establish environment for this script &Global::getCourseEnvironment($Course); my $scriptsDirectory = getWebworkScriptDirectory; my $databaseDirectory = getCourseDatabaseDirectory; my $templateDirectory = getCourseTemplateDirectory; my $cgiURL = getWebworkCgiURL; my $CL_Database = $Global::CL_Database; my $path_to_CL_DB = "${databaseDirectory}$CL_Database"; # File names require "${scriptsDirectory}$Global::HTMLglue_pl"; require "${scriptsDirectory}$Global::DBglue_pl"; require "${scriptsDirectory}$Global::classlist_DBglue_pl"; require "${scriptsDirectory}$Global::FILE_pl";; my $DELIM = $Global::delim; # log access &Global::log_info('', query_string); my $passwordFile = &Global::getCoursePasswordFile($Course); my $permissionsFile = &Global::getCoursePermissionsFile($Course); my $permissions = &get_permissions($inputs{'user'}, $permissionsFile); my $keyFile = &Global::getCourseKeyFile($Course); #verify session key &verify_key($inputs{'user'}, $inputs{'key'}, $keyFile, $Course); # verify permissions are correct if ($permissions != $Global::instructor_permissions ) { print "permissions = $permissions instructor_permissions = $Global::instructor_permissions\n"; print &html_NO_PERMISSION; exit(0); } # get the rest of the information from the submitted form my $classlistFilename = $inputs{'classList'}; my $update_firstName = $inputs{'update_firstName'}; my $update_lastName = $inputs{'update_lastName'}; my $update_status = $inputs{'update_status'}; my $update_comment = $inputs{'update_comment'}; my $update_section = $inputs{'update_section'}; my $update_recitation = $inputs{'update_recitation'}; my $update_email_address = $inputs{'update_email_address'}; my $update_drop = $inputs{'update_drop'}; ## either 'drop', 'leave', or 'remove' $update_firstName = 0 unless defined $update_firstName; $update_lastName = 0 unless defined $update_lastName; $update_status = 0 unless defined $update_status; $update_comment = 0 unless defined $update_comment; $update_section = 0 unless defined $update_section; $update_recitation = 0 unless defined $update_recitation; $update_email_address = 0 unless defined $update_email_address; my $CL_status = get_CL_database_status(); wwerror('Classlist Database is unlocked', 'You must go back and lock the classlist database before you can export it to an ascii file.') unless $CL_status eq 'locked'; wwerror('No classlist file selected', 'You must go back and select a classlist file.') unless $classlistFilename =~ /\w/; my $msg1 = updateClasslistDB($classlistFilename); my $msg2 = initial_passwords(); my $msg3 = "$msg1" . "$msg2"; uploadSuccess("$msg3"); exit; ## end of main script sub updateClasslistDB { ## builds the classlist DB and returns a message my ($classlistFilename) = @_; #get data from class list. my $fileName="${templateDirectory}$classlistFilename"; ## e.g. fileName=m161.lst my $message = "\nGetting classlist file from: $fileName
\n"; checkClasslistFile($Global::noOfFieldsInClasslist,$fileName); open(FILE, "$fileName") || wwerror($0, "Can't open $fileName"); my @classList=; close(FILE); ################################### # Before updating the database we back it up ################################### if ( -e "$path_to_CL_DB" ) { $message .= "Backing up current classlist database to: ${path_to_CL_DB}_bak1
\n"; &backup($path_to_CL_DB); } my %loginName_StudentID_Hash = %{getLoginName_StudentID_Hash()}; my %studentID_LoginName_Hash =%{getStudentID_LoginName_Hash()}; # my $WW_DB_exists = 0; # $WW_DB_exists = 1 if ( -e "${databaseDirectory}$Global::database" ); # my %loginName_StudentID_Hash_from_WW_DB =(); # my %studentID_LoginName_Hash_from_WW_DB =(); # if ($WW_DB_exists) { # %loginName_StudentID_Hash_from_WW_DB =%{getLoginName_StudentID_Hash_from_WW_DB()}; # %studentID_LoginName_Hash_from_WW_DB = reverse %loginName_StudentID_Hash_from_WW_DB; # } my $errors =''; my %new_good_classlist_students =(); ## students in new classlist without conflicts my %new_bad_classlist_students =(); ## students in new classlist with conflicts foreach (@classList) { ## read through classlist and create ## class list database unless ($_ =~ /\S/) {next;} ## skip blank lines chomp; my @classListRecord=&getRecord($_); my ($studentID, $lastName, $firstName, $status, $comment, $section, $recitation, $email_address, $login_name) = @classListRecord; ## First we get a list of any conflicts with current students if ((defined $loginName_StudentID_Hash{$login_name}) and ($loginName_StudentID_Hash{$login_name} ne $studentID)) { $errors .= "$firstName $lastName, $login_name, $studentID
\n "; $new_bad_classlist_students{$login_name} =1; next; } if ((defined $studentID_LoginName_Hash{$studentID}) and ($studentID_LoginName_Hash{$studentID} ne $login_name)) { $errors .= "$firstName $lastName, $login_name, $studentID
\n "; $new_bad_classlist_students{$login_name} =1; next; } ## OK, the student record has no conflicts $new_good_classlist_students{$login_name} =1; ## Handle students already in classlist DB if (defined $loginName_StudentID_Hash{$login_name}) { &attachCLRecord($login_name); &CL_putStudentLastName ($lastName, $login_name) if $update_firstName; &CL_putStudentFirstName ($firstName, $login_name) if $update_lastName; &CL_putStudentStatus ($status, $login_name) if $update_status; &CL_putComment ($comment, $login_name) if $update_comment; &CL_putClassSection ($section,$login_name) if $update_section; &CL_putClassRecitation ($recitation,$login_name) if $update_recitation; &CL_putStudentEmailAddress ($email_address, $login_name) if $update_email_address; $Global::over_ride_CLBD_lock = 1; &saveCLRecord($login_name); $Global::over_ride_CLBD_lock = 0; } else { ## Handle new students &CL_putStudentID ($studentID, $login_name); &CL_putStudentLastName ($lastName, $login_name); &CL_putStudentFirstName ($firstName, $login_name); &CL_putStudentStatus ($status, $login_name); &CL_putComment ($comment, $login_name); &CL_putClassSection ($section,$login_name); &CL_putClassRecitation ($recitation,$login_name); &CL_putStudentEmailAddress ($email_address, $login_name); $Global::over_ride_CLBD_lock = 1; &saveCLRecord($login_name); $Global::over_ride_CLBD_lock = 0; } } ## Now we take care of students who are in the current classlist database but are not in ## the classlist file. my %drop_list =(); my $login_name; %loginName_StudentID_Hash = %{getLoginName_StudentID_Hash()}; foreach $login_name (keys %loginName_StudentID_Hash) { $drop_list{$login_name} = 1 unless ( (defined ($new_good_classlist_students{$login_name})) or (defined ($new_bad_classlist_students{$login_name})) ); } if ($update_drop eq 'drop') { my $status = 'D'; $status = $Global::statusDrop[0] if defined $Global::statusDrop[0]; foreach $login_name (keys %drop_list) { &attachCLRecord($login_name); &CL_putStudentStatus($status, $login_name); $Global::over_ride_CLBD_lock = 1; &saveCLRecord($login_name); $Global::over_ride_CLBD_lock = 0; } } elsif ($update_drop eq 'remove') { foreach $login_name (keys %drop_list) { $Global::over_ride_CLBD_lock = 1; deleteClassListRecord($login_name); $Global::over_ride_CLBD_lock = 0; } } else { ## if this case $update_drop eq 'leave' and we do nothing } unlock_CL_database(); if ($errors) { $message .= '
The following students HAVE NOT BEEN ENTERED IN THE CLASSLIST DATABASE because of a conflict with entries in the WeBWorK problem set database or the classlist database. These students have a studentID or a loginName that conflicts with a current student. Enter this information again from the Add Student(s) Page to get a more detailed error message and instructions on how to correct the problem.

'; $message .= "\n $errors
"; } $message; } sub initial_passwords { my %studentsinclass=(); my @classListRecord=(); my $msg =''; # Check that the files exist: # The permissions file must exist and have both read and write privilages. # The password file must exist and have both read and write privilages. unless ( -r $passwordFile and -w $passwordFile) { wwerror ($0, "Permissions set incorrectly on $passwordFile or its directory. Cannot access file to both read and write."); } unless ( -r $permissionsFile and -w $permissionsFile) { wwerror ($0, "Permissions set incorrectly on $permissionsFile or its directory. Cannot access file to both read and write."); } my $login_name; my @classList = @{getAllLoginNames()}; $msg .= "\n

Modifying the password file :\n $passwordFile
\n "; foreach $login_name (@classList) { ## read through classlist database and create ## passwords for all active students ## except if passwords already exist for student attachCLRecord($login_name); my $status = CL_getStudentStatus($login_name); my $studentID = CL_getStudentID($login_name); $studentsinclass{$login_name}++ unless(&dropStatus($status)); if(&dropStatus($status)) { $msg .= '       '."$login_name not added because status is $status
\n "; } elsif (&get_password($login_name, $passwordFile)) { $msg .= '   '."$login_name not added because password already exists
\n "; } else { &new_password($login_name, $studentID, $passwordFile); &put_permissions(0,$login_name,$permissionsFile); $msg .= "added: $login_name, $studentID
\n "; } } my @pwStudents = &get_keys_from_db($passwordFile); my ($ans,$student); $msg .= "\n
The following login's (if any) in the password and permissions databases are either\n "; $msg .= "(1) not listed in the new class list database file \n"; $msg .= "or (2) have DROP status in the new class list database file.\n"; $msg .= "They will all be removed from the password and permissions databases.

\n "; foreach $student (@pwStudents) { next if defined($studentsinclass{$student}); &delete_password($student,$passwordFile); &delete_permissions($student,$permissionsFile); $msg .= "$student
\n "; } # ## if the owner of the password file is running this script (e.g. when the password file is first created) # ## set the permissions correctly # # open (PASSWORDFILE, "$passwordFile") or wwerror($0, "Can't open $passwordFile"); # my @stat = stat PASSWORDFILE; # close PASSWORDFILE; # # if ($< == $stat[4]) { # # chmod($Global::password_permission, $passwordFile) or # wwerror($0, "Can't do chmod($Global::password_permission, $passwordFile)"); # chown(-1,$Global::numericalGroupID,$passwordFile) or # wwerror($0, "Can't do chown(-1,$Global::numericalGroupID,$passwordFile)"); # } # # open (PERMISSIONSFILE, "$permissionsFile") or wwerror($0, "Can't open $permissionsFile"); # @stat = stat PERMISSIONSFILE; # close PERMISSIONSFILE; # # if ($< == $stat[4]) { # # chmod($Global::permissions_permission, $permissionsFile) or # wwerror($0, "Can't do chmod($Global::permissions_permission, $permissionsFile)"); # chown(-1,$Global::numericalGroupID,$permissionsFile) or # wwerror($0, "Can't do chown(-1,$Global::numericalGroupID,$permissionsFile)"); # } $msg; } sub uploadSuccess { my ($msg) = @_; print"content-type: text/html\n\n

Success, the classlist database has been updated.

\n"; print $msg; print &htmlBOTTOM("profImportClasslistDatabase.pl", \%inputs); } sub backup { ## takes as a parameter the full path name ## makes upto two backups of the file with _bak1, or _bak2 ## appended to filename where _bak1 is the most recent backup use File::Copy; my $fileName =$_[0]; if (-e "${fileName}_bak1") { rename("${fileName}_bak1","${fileName}_bak2") or &wwerror("$0","can't rename ${fileName}_bak1"); } if (-e "${fileName}") { copy("${fileName}","${fileName}_bak1") or &wwerror("$0","can't copy ${fileName}"); } }