WwclearAnonymous

From WeBWorK_wiki
Jump to navigation Jump to search
#!/usr/bin/perl -w
#
# wwclearAnonymous: 
#    clear all versioned sets from practice users in @courses for which
#    the practice users are not currently logged in
#
# by Gavin LaRose, <glarose@umich.edu>
my $version = '1.21';
my $lastmod = '9 Aug 2010';
#
# changelog: 1.21: update copyright
#            1.2: correct for new database API
#            1.1: add logging capability
#
#  (c)2010 Regents of the University of Michigan
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
# 
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
# 
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#------------------------------------------------------------------------------ 
# configuration
#
use strict;
$ENV{PATH} = '/bin:/usr/bin';

# to get data from databases
my $wwHome = '/var/www/webwork/webwork2';
use lib '/var/www/webwork/webwork2/lib';
use WeBWorK::CourseEnvironment;
use WeBWorK::DB;
use WeBWorK::Utils;

# my @courses = ( qw( ma105-demo ) );
my @courses = ( qw( mathprep ) );

# should we log data about the number of tests taken?
my $keepLog = 1;

# the format of the log file is 
#    year mo da : course (#tests; #users), ..
# where #tests is the total number of tests deleted and #users the (maximum) 
# number of guest logins that had tests to delete when the script was run.  
# thus an entry will be like
#    2006 10 18 : ma105-demo (3; 1), ma115-demo (5; 2), ma116-demo (0; 0)
# if the script is run more than one time on a given day it will update the
# totals in the file.  this means that the number of tests is incremented 
# and if the maximum number of users is greater than that in the file the 
# maximum is also updated; if there are no tests in any of the courses, no 
# log entry is written
# my $logFile = '/var/www/data/gateways/demo_tests.txt';
my $logFile = '/var/www/data/webwork/demo_tests.txt';

#------------------------------------------------------------------------------ 
# main

main();
# suppress residual errors (why is this necessary?)
open( DN, ">/dev/null" );
*STDERR = *DN;

sub main {
# data logging: logData{course} = { user => numtests }
    my %logData = () if ( $keepLog );

    foreach my $crs ( @courses ) {
	 $logData{$crs} = { } if ( $keepLog );

# bring up a course environment and database object
	 my $ce = WeBWorK::CourseEnvironment->new({webwork_dir => $wwHome,
						   courseName  => $crs});
	 my $db = WeBWorK::DB->new($ce->{dbLayout});

# get a list of all practice users
	 my @prUsers = grep {/^practice/} ( $db->listUsers() );

    # check to see which users are logged in
	 my @prKeys = $db->getKeys( @prUsers );
	 my @loggedIn = ();
	 foreach my $key ( @prKeys ) {
	     if ( defined($key) && 
		  time() <= $key->timestamp() + $ce->{sessionKeyTimeout} ) {
		 push( @loggedIn, $key->user_id() );
	     }
	 }

	 my @delUsers = ();
    # don't delete sets for those users
	 foreach my $user ( @prUsers ) {
	     my $skip = 0;
	     foreach my $in ( @loggedIn ) {
		 if ( $user eq $in ) {
		     $skip = 1;
		     last;
		 }
	     }
	     push( @delUsers, $user ) if ( ! $skip );
	 }

    # get and delete versioned sets for remaining practice users
	 # we have to get a list of all sets assigned, and then figure
	 #    out which of those are versioned
	 my @versionedSets = ();
	 if ( @delUsers ) {
	     my $user = $delUsers[0];
	     my @usIDs = map {[$user, $_]} ($db->listUserSets( $user ));
	     my @userSets = $db->getMergedSets( @usIDs );
	     @versionedSets = grep {$_->assignment_type =~ /gateway/} @userSets;
	     # and condense this down to just the assignment names
	     @versionedSets = map { $_->set_id } @versionedSets;
	 }

	 foreach my $user ( @delUsers ) {

	     my @setVersions = ();
	     foreach my $setID ( @versionedSets ) {
		 push(@setVersions, (map {[$setID,$_]} 
				     ($db->listSetVersions($user,$setID))));
	     }

	     $logData{$crs}->{$user} = scalar( @setVersions ) if ( $keepLog );

	     foreach my $setvID ( @setVersions ) {
		 $db->deleteSetVersion( $user, $setvID->[0], $setvID->[1] );
	     }
	 }
    }
    writeLogData( \%logData ) if ( $keepLog );
}

#
#------------------------------------------------------------------------------ 
# subroutines

sub writeLogData {
    my $dataRef = shift();
    my %logData = %$dataRef;

# build a new logData array logNums{crs} = [ numTests, numUsers ]
    my %logNums = ();
    my $totNumTests = 0;
    foreach my $crs ( keys ( %logData ) ) {
	 my $numTests = 0;
	 my $numUsers = 0;
	 foreach my $user ( keys ( %{$logData{$crs}} ) ) {
	     $numTests += $logData{$crs}->{$user};
	     $numUsers++ if ( $logData{$crs}->{$user} );
	 }
	 $totNumTests += $numTests;
	 $logNums{$crs} = [ $numTests, $numUsers ];
    }

    if ( $totNumTests ) {
	 my @timeVars = localtime();
	 my $year = $timeVars[5] + 1900;
	 my $month = sprintf("%02d", $timeVars[4] + 1);
	 my $day = sprintf("%02d", $timeVars[3]);

	 my $lineFmt = '\d{4} \d{2} \d{2} : ';
	 foreach my $crs ( @courses ) { $lineFmt .= $crs . ' \(\d+; \d+\), '; }
	 $lineFmt =~ s/, $//;

	 my @logLines = ();
	 @logLines = `/bin/cat $logFile` if ( -f $logFile );

	 open( LF, ">$logFile" ) or die("wwclearAnonymous: Cannot open log " .
					"file $logFile for writing.\n");

	 my $addedLogData = 0;
	 foreach my $line ( @logLines ) {
	     if ( $line =~ /^($lineFmt)/ ) {

		 if ( $line =~ /^$year $month $day/ )  {
		     my $newLine = "$year $month $day : ";
		     foreach my $crs ( @courses ) {
			 my ( $numTests, $numUsers ) = 
			     ( $line =~ /$crs \((\d+); (\d+)\)/ );

			 if ( defined( $numTests ) && defined( $numUsers ) &&
			      defined( $logData{$crs} ) ) {
			     $numTests += $logNums{$crs}->[0];
			     $numUsers = 
				 $logNums{$crs}->[1] if ( $numUsers < 
							  $logNums{$crs}->[1] );
			 }
			 $newLine .= "$crs ($numTests; $numUsers), ";
		     }
		     $newLine =~ s/, $//;
		     print LF $newLine, "\n";
		     $addedLogData = 1;

		 } else {
		     print LF $line;
		 }
	     } else {
	 # bad line format; skip line
		 next;
	     }
	 }
	 if ( ! $addedLogData ) {
	     my $newLine = "$year $month $day : ";
	     foreach my $crs ( @courses ) {
		 if ( defined( $logNums{$crs} ) ) {
		     $newLine .= "$crs (" . $logNums{$crs}->[0] . "; " . 
			 $logNums{$crs}->[1] . "), ";
		 } else { 
		     $newLine .= "$crs (0; 0), ";
		 }
	     }
	     $newLine =~ s/, $//;
	     print LF $newLine, "\n";
	 }
	 close(LF);
	 return 1;
    } else {
	 return 1;  # don't log anything if there are no tests taken
    }
}
#
#------------------------------------------------------------------------------