Cl2ww

From WeBWorK_wiki
Jump to navigation Jump to search
#!/usr/bin/perl -w
use strict;
#
# cl2ww [-c|-s] [crs-sxn [crs-sxn.. ]]
#
#   process classlist files for class-sections indicated, creating 
#   corresponding webwork userlist files, classnum.lst
#    -s : assume the webwork roster has section & recitation # = section num
#         (e.g., 115-103 has sxn=103, rct=103)
#    -c : assume the webwork roster has the section # = course # and 
#         recitation # = section # (e.g., 115-103 has sxn=115, rct=103)
#    otherwise, assume that section # = section # rounded down, recitation #
#         = section number (e.g., 215-021 has sxn=020, rct=021)
#
# by Gavin LaRose
# version 1.34
# changes: 1.34: add -s flag
#          1.33: add -c flag
#          1.32: correct handling of csv files generated by python
#          1.31: bugfix; chomp newlines from file names, avoid double 
#                counting students in 215, 216 if -all is used, make 
#                instructors show up with section number and 000 for 
#                recitation
#          1.3 : update to get rid of passwords, add instructor 
#          1.2 : revised recitation number support
#          1.1 : added support for recitation number
# 5 jan 2010 
#
# (c)2013 Gavin LaRose/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/>.
#
#------------------------------------------------------------------------------
# variables
#
my $dataDir = '/home/glarose/IFS-Home/LSA-Files/Private/classlists/data';
my @instrFiles = ('instr_pw.csv', 'instr.csv');

select STDERR; $|=1;
select STDOUT; $|=1;

#------------------------------------------------------------------------------
# main
#
my $cflag = 0;
if ( @ARGV && $ARGV[0] eq '-c' ) {
    $cflag = 1;
    shift( @ARGV );
}
if ( @ARGV && $ARGV[0] eq '-s' ) {
    $cflag = 2;
    shift( @ARGV );
}
if ( ! @ARGV ) {
    my $fname = "none";
    print "course-section to process (e.g., 115-all, 216-102)? ";
    chomp( $fname = <STDIN> );

    push( @ARGV, $fname );
}

# we make $classes{crs-num} = [ list of webwork roster lines ]
my %classes = ();

# webwork lines are 
#   studentID, lName, fmName, status, comment, section, recitation, \
#         email, loginName

foreach my $course ( @ARGV ) {
    my @fileList = ();
    my ( $crs, $sxn ) = ( $course =~ /(\d+)-((\d+)|(all))/ );
    die("* error: course identifier $course is not in the form CRS-SXN\n")
	if ( ! defined($crs) || ! defined($sxn) || ! $crs || ! $sxn );

    if ( $sxn eq 'all' ) {
	if ( $crs =~ /^21[56]/ ) {
	    @fileList = `/bin/ls ${crs}_??[1-4].csv 2> /dev/null`;
	    @fileList = `/bin/ls $dataDir/${crs}_??[1-4].csv 2> /dev/null` 
		if ( ! @fileList );
	} else {
	    @fileList = `/bin/ls ${crs}_*.csv 2> /dev/null`;
	    @fileList = `/bin/ls $dataDir/${crs}_*.csv 2> /dev/null` 
		if ( ! @fileList );
	}
    } else {
	push(@fileList, "${crs}_${sxn}.csv");
    }
    for ( my $i=0; $i<@fileList; $i++ ) { 
	chomp($fileList[$i]);
	if ( ! -f $fileList[$i] && ! -f "$dataDir/$fileList[$i]" ) {
	    @fileList = ();
	    last;
	} elsif ( ! -f $fileList[$i] ) {
	    $fileList[$i] = "$dataDir/$fileList[$i]";
	}
    }
    die("* error: missing class roster file(s)\n") if ( ! @fileList );

    print "reading course file: ";
    foreach my $f ( @fileList ) {
	my ( $c, $s ) = ($f =~ /(\d{3})_(\d{3})/);
	print "$c-$s.. ";
	open( IF, $f ) or die("* error: cannot open $f for reading\n");
	while ( <IF> ) {

# first line is a header; skip it
	    if ( /^[0-9]/ ) {
		s/\s*$//;
		s/\"//g;
		my @entry = csvSplit( $_ );
		my $cnum = $entry[0] . "_" . $entry[1];

	# update section and recitation if needed
		my ( $snum, $rcn );
		if ( $cflag == 1 ) {
		    $snum = $entry[0];
		    $rcn = $entry[1];
		} elsif ( $cflag == 2 ) {
		    $rcn = $entry[1];
		    $snum = $rcn;
		} else {
		    $rcn = $entry[1];
		    $snum = substr($entry[1],0,2) . '0';
		}

		$classes{"$crs-$sxn"} = [ ] 
		    if ( ! defined( $classes{"$crs-$sxn"} ) );

# generate webwork user data line
		push( @{$classes{"$crs-$sxn"}}, 
		      "$entry[-1], $entry[3], $entry[4], C, , $snum, " .
		      "$rcn, $entry[2]\@umich.edu, $entry[2]" );
	    }
	}
    }
    print "done\n";
}

# where can we find instructor data?
my $instrFile = ;
foreach my $iFile ( @instrFiles ) {
    if ( -f "$dataDir/$iFile" ) {
	$instrFile = $iFile;
	last;
    }
}
my @instrList = ();
@instrList = `/bin/cat $dataDir/$instrFile 2> /dev/null` if ( $instrFile );

foreach ( keys %classes ) {
    my $fn = $_ . ".lst";
    while ( -f "$fn"  ) {
        print "file $fn exists: [cr] to overwrite or newname: ";
        chomp( $fn = <STDIN> );
    }
    $fn = ( $fn eq "" ) ? $_ . ".lst" : $fn;
    open ( FN, ">$fn") or die ("* error: cannot open file $fn for writing\n");

# get instructor data, if possible
    my @instrLines = ();
    if ( @instrList ) {
	my ( $crs, $sxn ) = ( $_ =~ /(\d+)-((\d+)|(all))/ );
	if ( $sxn eq 'all' ) {
	    @instrLines = grep {/^$crs,/} @instrList;
	} else {
	    @instrLines = grep {/^$crs,$sxn,/} @instrList;
	}
    }
    foreach my $iLine ( @instrLines ) {
	$iLine =~ s/\s*$//;
	my @vals = csvSplit(/,/, $iLine);
	my ( $sxn, $rcn );
	if ( $cflag ) {
	    $sxn = $vals[0];
	    $rcn = $vals[1];
	} else {
	    $rcn = $vals[1]; $rcn =~ s/\d$/0/;
	    $sxn = '000';
	}
	print FN "$vals[5], $vals[3], $vals[4], C, , $sxn, " .
	    "$rcn, $vals[2]\@umich.edu, $vals[2]\n";
    }

    foreach my $ent ( @{$classes{$_}} ) {
        print FN "$ent\n";
    }
    close FN;
    if ( @instrLines ) {
	print "wrote userdata to file $fn, including instructor(s)\n";
    } else {
	print "wrote userdata to file $fn; could not add instructor(s)\n";
    }
}

#
#------------------------------------------------------------------------------
# subroutines
#
# sub getpass {
#
# generate a random password of the form wordNword2, with word being 
#    four letters long, N being a random digit, and word2 being three
#    letters long.  this uses the arrays @threes and @fours loaded by
#    loadDict
#
#     my $rand1 = int(rand()*(@fours));
#     my $rand2 = int(rand()*(@threes));
#     my $randd = int(rand()*10);
#     return $fours[$rand1] . $randd . $threes[$rand2];
# }

# sub loadDict {
#     my ( $df3, $df4 ) = @_;
#
# returns arrays of 'nice' three and four letter words from the dictionary
#    files $df3 and $df4
#
#     @threes = ();
#     @fours = ();
#     open(DF, $df3) or die("** can't open dictionary file $df3 **\n");
#     while ( <DF> ) {
#         chomp;
#         push @threes, $_;
#     }
#     close(DF);
#     open(DF, $df4) or die("** can't open dictionary file $df4 **\n");
#     while ( <DF> ) {
#         chomp;
#         push @fours, $_;
#     }
#     close(DF);
# }

sub csvSplit {
    my $line = shift();

    my @fields = ();
    while ( $line ) {
        my $term = ;
        if ( $line =~ /^"/ ) { #"
            $line = substr( $line, 1 );     # bite off quote
            my $ind = index( $line, '"' );  # "
            $term = substr( $line, 0, $ind );
            $line = ( $term =~ /$line,?$/ ) ?  : substr( $line, $ind+1 );
     # get rid of any trailing comma
            $line =~ s/^,//;

        } else {
            my $ind = index( $line, ',' );
            $term = ($ind == -1) ? $line : substr( $line, 0, $ind );

            $line = ( $term =~ /$line,?$/ ) ?  : substr( $line, $ind );
     # get rid of any trailing comma
            $line =~ s/^,//;
        }
        push( @fields, $term );
    }
    return @fields;
}

#
# end script
#------------------------------------------------------------------------------