@@ -4568,6 +4702,10 @@ UPLOAD
SCANTRONFORM
}
+
+ # Chunk of the form that prompts to view a scoring office file,
+ # corrected file, skipped records in a file.
+
$r->print(<
'."\n";
$result.=''."\n";
+# Attempt to restore parameters from last session, set defaults if not present
+ my %Saveable_Parameters=&clicker_grading_parameters();
+ &Apache::loncommon::restore_course_settings('grades_clicker',
+ \%Saveable_Parameters);
+ if (!$env{'form.pcorrect'}) { $env{'form.pcorrect'}=100; }
+ if (!$env{'form.pincorrect'}) { $env{'form.pincorrect'}=100; }
+ if (!$env{'form.gradingmechanism'}) { $env{'form.gradingmechanism'}='attendance'; }
+ if (!$env{'form.upfiletype'}) { $env{'form.upfiletype'}='iclicker'; }
+
+ my %checked;
+ foreach my $gradingmechanism ('attendance','personnel','specific') {
+ if ($env{'form.gradingmechanism'} eq $gradingmechanism) {
+ $checked{$gradingmechanism}="checked='checked'";
+ }
+ }
+
my $upload=&mt("Upload File");
my $type=&mt("Type");
my $attendance=&mt("Award points just for participation");
my $personnel=&mt("Correctness determined from response by course personnel");
- my $specific=&mt("Correctness determined from response with clicker ID");
+ my $specific=&mt("Correctness determined from response with clicker ID(s)");
my $pcorrect=&mt("Percentage points for correct solution");
my $pincorrect=&mt("Percentage points for incorrect solution");
- my $selectform=&Apache::loncommon::select_form('iclicker','upfiletype',
- ('iclicker' => 'i>clicker'));
-
+ my $selectform=&Apache::loncommon::select_form($env{'form.upfiletype'},'upfiletype',
+ ('iclicker' => 'i>clicker',
+ 'interwrite' => 'interwrite PRS'));
+ $symb = &Apache::lonenc::check_encrypt($symb);
$result.=<
function sanitycheck() {
@@ -6248,13 +7179,13 @@ function sanitycheck() {
$type: $selectform
-$attendance:
-$personnel:
-$specific:
-
-
-$pcorrect:
-$pincorrect:
+$attendance:
+$personnel:
+$specific:
+
+
+$pcorrect:
+$pincorrect:
ENDUPFORM
@@ -6268,43 +7199,52 @@ sub process_clicker_file {
my ($r)=@_;
my ($symb)=&get_symb($r);
if (!$symb) {return '';}
+
+ my %Saveable_Parameters=&clicker_grading_parameters();
+ &Apache::loncommon::store_course_settings('grades_clicker',
+ \%Saveable_Parameters);
+
my ($result) = &showResourceInfo($symb,$env{'form.probTitle'});
if (($env{'form.gradingmechanism'} eq 'specific') && ($env{'form.specificid'}!~/\w/)) {
- $result.=''.&mt('You need to specify a clicker ID for the correct answer').' ';
- return $result.&show_grading_menu_form($symb);
+ $result.=''.&mt('You need to specify a clicker ID for the correct answer').' ';
+ return $result.&show_grading_menu_form($symb);
}
my %clicker_ids=&gather_clicker_ids();
- my %correct_ids=();
+ my %correct_ids;
if ($env{'form.gradingmechanism'} eq 'personnel') {
- %correct_ids=&gather_adv_clicker_ids();
+ %correct_ids=&gather_adv_clicker_ids();
}
if ($env{'form.gradingmechanism'} eq 'specific') {
- my $correct_id=$env{'form.specificid'};
- $correct_id=~tr/a-z/A-Z/;
- $correct_id=~s/\s//gs;
- $correct_id=~s/^0+//;
- $correct_ids{$correct_id}='specified';
+ foreach my $correct_id (split(/[\s\,]/,$env{'form.specificid'})) {;
+ $correct_id=~tr/a-z/A-Z/;
+ $correct_id=~s/\s//gs;
+ $correct_id=~s/^[\#0]+//;
+ $correct_id=~s/[\-\:]//g;
+ if ($correct_id) {
+ $correct_ids{$correct_id}='specified';
+ }
+ }
}
if ($env{'form.gradingmechanism'} eq 'attendance') {
- $result.=&mt('Score based on attendance only');
+ $result.=&mt('Score based on attendance only');
} else {
- my $number=0;
- $result.=''.&mt('Correctness determined by the following IDs').' ';
- foreach my $id (sort(keys(%correct_ids))) {
- $result.=''.$id.' - ';
- if ($correct_ids{$id} eq 'specified') {
- $result.=&mt('specified');
- } else {
- my ($uname,$udom)=split(/\:/,$correct_ids{$id});
- $result.=&Apache::loncommon::plainname($uname,$udom);
- }
- $result.=' ';
- $number++;
- }
- if ($number==0) {
- $result.=''.&mt('No IDs found to determine correct answer').' ';
- return $result.&show_grading_menu_form($symb);
- }
+ my $number=0;
+ $result.=''.&mt('Correctness determined by the following IDs').' ';
+ foreach my $id (sort(keys(%correct_ids))) {
+ $result.=''.$id.' - ';
+ if ($correct_ids{$id} eq 'specified') {
+ $result.=&mt('specified');
+ } else {
+ my ($uname,$udom)=split(/\:/,$correct_ids{$id});
+ $result.=&Apache::loncommon::plainname($uname,$udom);
+ }
+ $number++;
+ }
+ $result.="
\n";
+ if ($number==0) {
+ $result.=''.&mt('No IDs found to determine correct answer').' ';
+ return $result.&show_grading_menu_form($symb);
+ }
}
if (length($env{'form.upfile'}) < 2) {
$result.=&mt('[_1] Error: [_2] The file you attempted to upload, [_3] contained no information. Please check that you entered the correct filename.',
@@ -6313,17 +7253,87 @@ sub process_clicker_file {
''.&HTML::Entities::encode($env{'form.upfile.filename'},'<>&"').' ');
return $result.&show_grading_menu_form($symb);
}
- my %responses=();
- my @questiontitles=();
+
+# Were able to get all the info needed, now analyze the file
+
+ $result.=&Apache::loncommon::studentbrowser_javascript();
+ $symb = &Apache::lonenc::check_encrypt($symb);
+ my $heading=&mt('Scanning clicker file');
+ $result.=(<
+
+$heading
+
+
+
+
+
+
+
+
+ENDHEADER
+ my %responses;
+ my @questiontitles;
my $errormsg='';
my $number=0;
if ($env{'form.upfiletype'} eq 'iclicker') {
- ($errormsg,$number)=&iclicker_eval(\@questiontitles,\%responses);
+ ($errormsg,$number)=&iclicker_eval(\@questiontitles,\%responses);
+ }
+ if ($env{'form.upfiletype'} eq 'interwrite') {
+ ($errormsg,$number)=&interwrite_eval(\@questiontitles,\%responses);
+ }
+ $result.=' '.&mt('Found [_1] question(s)',$number).' '.
+ ' '.
+ &mt('Awarding [_1] percent for correct and [_2] percent for incorrect responses',
+ $env{'form.pcorrect'},$env{'form.pincorrect'}).
+ ' ';
+# Remember Question Titles
+# FIXME: Possibly need delimiter other than ":"
+ for (my $i=0;$i<$number;$i++) {
+ $result.=' ').'" />';
+ }
+ my $correct_count=0;
+ my $student_count=0;
+ my $unknown_count=0;
+# Match answers with usernames
+# FIXME: Possibly need delimiter other than ":"
+ foreach my $id (keys(%responses)) {
+ if ($correct_ids{$id}) {
+ $result.="\n".' ';
+ $correct_count++;
+ } elsif ($clicker_ids{$id}) {
+ $result.="\n".' ';
+ $student_count++;
+ } else {
+ $result.="\n ".&mt('Unregistered Clicker')." ".$id." ";
+ $result.="\n".' '.
+ "\n".&mt("Username").": ".
+ "\n".&mt("Domain").": ".
+ &Apache::loncommon::select_dom_form($env{'course.'.$env{'request.course.id'}.'.domain'},'udom'.$id).' '.
+ &Apache::loncommon::selectstudent_link('clickeranalysis','uname'.$id,'udom'.$id);
+ $unknown_count++;
+ }
+ }
+ $result.=' '.
+ &mt('Found [_1] registered and [_2] unregistered clickers.',$student_count,$unknown_count);
+ if ($env{'form.gradingmechanism'} ne 'attendance') {
+ if ($correct_count==0) {
+ $errormsg.="Found no correct answers answers for grading!";
+ } elsif ($correct_count>1) {
+ $result.=''.&mt("Found [_1] entries for grading!",$correct_count).' ';
+ }
+ }
+ if ($number<1) {
+ $errormsg.="Found no questions.";
}
- $result.=' '.&mt('Found [_1] questions',$number).' ';
- foreach my $id (keys %responses) {
- $result.=' '.$id.' - '.$responses{$id};
+ if ($errormsg) {
+ $result.=''.&mt($errormsg).' ';
+ } else {
+ $result.=' ';
}
+ $result.='
'."\n".
+ '
'."\n";
return $result.&show_grading_menu_form($symb);
}
@@ -6332,32 +7342,159 @@ sub iclicker_eval {
my $number=0;
my $errormsg='';
foreach my $line (split(/[\n\r]/,$env{'form.upfile'})) {
- chomp($line);
- foreach my $quoted ($line=~/\,\s*\"([^\"]*)\"\s*\,/g) {
- my $replace=$quoted;
- $replace=~s/\,//g;
- &Apache::lonnet::logthis($quoted.' - '.$replace.' ');
- $line=~s/\,\s*\"\Q$quoted\E\"\s*\,/,$replace,/gs;
+ my %components=&Apache::loncommon::record_sep($line);
+ my @entries=map {$components{$_}} (sort(keys(%components)));
+ if ($entries[0] eq 'Question') {
+ for (my $i=3;$i<$#entries;$i+=6) {
+ $$questiontitles[$number]=$entries[$i];
+ $number++;
+ }
+ }
+ if ($entries[0]=~/^\#/) {
+ my $id=$entries[0];
+ my @idresponses;
+ $id=~s/^[\#0]+//;
+ for (my $i=0;$i<$number;$i++) {
+ my $idx=3+$i*6;
+ push(@idresponses,$entries[$idx]);
+ }
+ $$responses{$id}=join(',',@idresponses);
+ }
+ }
+ return ($errormsg,$number);
+}
+
+sub interwrite_eval {
+ my ($questiontitles,$responses)=@_;
+ my $number=0;
+ my $errormsg='';
+ my $skipline=1;
+ my $questionnumber=0;
+ my %idresponses=();
+ foreach my $line (split(/[\n\r]/,$env{'form.upfile'})) {
+ my %components=&Apache::loncommon::record_sep($line);
+ my @entries=map {$components{$_}} (sort(keys(%components)));
+ if ($entries[1] eq 'Time') { $skipline=0; next; }
+ if ($entries[1] eq 'Response') { $skipline=1; }
+ next if $skipline;
+ if ($entries[0]!=$questionnumber) {
+ $questionnumber=$entries[0];
+ $$questiontitles[$number]=&mt('Question [_1]',$questionnumber);
+ $number++;
+ }
+ my $id=$entries[4];
+ $id=~s/^[\#0]+//;
+ $id=~s/^v\d*\://i;
+ $id=~s/[\-\:]//g;
+ $idresponses{$id}[$number]=$entries[6];
+ }
+ foreach my $id (keys %idresponses) {
+ $$responses{$id}=join(',',@{$idresponses{$id}});
+ $$responses{$id}=~s/^\s*\,//;
+ }
+ return ($errormsg,$number);
+}
+
+sub assign_clicker_grades {
+ my ($r)=@_;
+ my ($symb)=&get_symb($r);
+ if (!$symb) {return '';}
+# See which part we are saving to
+ my ($partlist,$handgrade,$responseType) = &response_type($symb);
+# FIXME: This should probably look for the first handgradeable part
+ my $part=$$partlist[0];
+# Start screen output
+ my ($result) = &showResourceInfo($symb,$env{'form.probTitle'});
+
+ my $heading=&mt('Assigning grades based on clicker file');
+ $result.=(<
+
+$heading
+ENDHEADER
+# Get correct result
+# FIXME: Possibly need delimiter other than ":"
+ my @correct=();
+ my $gradingmechanism=$env{'form.gradingmechanism'};
+ my $number=$env{'form.number'};
+ if ($gradingmechanism ne 'attendance') {
+ foreach my $key (keys(%env)) {
+ if ($key=~/^form\.correct\:/) {
+ my @input=split(/\,/,$env{$key});
+ for (my $i=0;$i<=$#input;$i++) {
+ if (($correct[$i]) && ($input[$i]) &&
+ ($correct[$i] ne $input[$i])) {
+ $result.=''.
+ &mt('More than one correct result given for question "[_1]": [_2] versus [_3].',
+ $env{'form.question:'.$i},$correct[$i],$input[$i]).' ';
+ } elsif ($input[$i]) {
+ $correct[$i]=$input[$i];
+ }
+ }
+ }
}
- my @entries=split(/\,/,$line);
- if ($entries[0] eq 'Question') {
- for (my $i=3;$i<$#entries;$i+=6) {
- $$questiontitles[$number]=$entries[$i];
- $number++;
+ for (my $i=0;$i<$number;$i++) {
+ if (!$correct[$i]) {
+ $result.=''.
+ &mt('No correct result given for question "[_1]"!',
+ $env{'form.question:'.$i}).' ';
}
}
- if ($entries[0]=~/^\#/) {
- my $id=$entries[0];
- my @idresponses=();
- $id=~s/^[\#0]+//;
+ $result.=' '.&mt("Correct answer: [_1]",join(', ',map { ($_?$_:'-') } @correct));
+ }
+# Start grading
+ my $pcorrect=$env{'form.pcorrect'};
+ my $pincorrect=$env{'form.pincorrect'};
+ my $storecount=0;
+ foreach my $key (keys(%env)) {
+ my $user='';
+ if ($key=~/^form\.student\:(.*)$/) {
+ $user=$1;
+ }
+ if ($key=~/^form\.unknown\:(.*)$/) {
+ my $id=$1;
+ if (($env{'form.uname'.$id}) && ($env{'form.udom'.$id})) {
+ $user=$env{'form.uname'.$id}.':'.$env{'form.udom'.$id};
+ }
+ }
+ if ($user) {
+ my @answer=split(/\,/,$env{$key});
+ my $sum=0;
for (my $i=0;$i<$number;$i++) {
- my $idx=3+$i*6;
- push(@idresponses,$entries[$idx]);
+ if ($answer[$i]) {
+ if ($gradingmechanism eq 'attendance') {
+ $sum+=$pcorrect;
+ } else {
+ if ($answer[$i] eq $correct[$i]) {
+ $sum+=$pcorrect;
+ } else {
+ $sum+=$pincorrect;
+ }
+ }
+ }
+ }
+ my $ave=$sum/(100*$number);
+# Store
+ my ($username,$domain)=split(/\:/,$user);
+ my %grades=();
+ $grades{"resource.$part.solved"}='correct_by_override';
+ $grades{"resource.$part.awarded"}=$ave;
+ $grades{"resource.regrader"}="$env{'user.name'}:$env{'user.domain'}";
+ my $returncode=&Apache::lonnet::cstore(\%grades,$symb,
+ $env{'request.course.id'},
+ $domain,$username);
+ if ($returncode ne 'ok') {
+ $result.="Failed to save student $username:$domain. Message when trying to save was ($returncode) ";
+ } else {
+ $storecount++;
}
- $$responses{$id}=join(',',@idresponses);
}
}
- return ($errormsg,$number);
+# We are done
+ $result.=' '.&mt('Successfully stored grades for [_1] student(s).',$storecount).
+ '
'."\n".
+ '
'."\n";
+ return $result.&show_grading_menu_form($symb);
}
sub handler {
@@ -6431,6 +7568,8 @@ sub handler {
$request->print(&process_clicker($request));
} elsif ($command eq 'processclickerfile' && $perm{'mgr'}) {
$request->print(&process_clicker_file($request));
+ } elsif ($command eq 'assignclickergrades' && $perm{'mgr'}) {
+ $request->print(&assign_clicker_grades($request));
} elsif ($command eq 'csvform' && $perm{'mgr'}) {
$request->print(&upcsvScores_form($request));
} elsif ($command eq 'csvupload' && $perm{'mgr'}) {