--- loncom/homework/grades.pm 2002/07/08 21:18:54 1.37
+++ loncom/homework/grades.pm 2003/10/14 00:05:16 1.130.2.1.2.9
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# The LON-CAPA Grading handler
#
-# $Id: grades.pm,v 1.37 2002/07/08 21:18:54 ng Exp $
+# $Id: grades.pm,v 1.130.2.1.2.9 2003/10/14 00:05:16 albertel Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -30,7 +30,10 @@
# 7/26 H.K. Ng
# 8/20 Gerd Kortemeyer
# Year 2002
-# June, July 2002 H.K. Ng
+# June-August H.K. Ng
+# Year 2003
+# February, March H.K. Ng
+# July, H. K. Ng
#
package Apache::grades;
@@ -39,372 +42,823 @@ use Apache::style;
use Apache::lonxml;
use Apache::lonnet;
use Apache::loncommon;
+use Apache::lonhtmlcommon;
+use Apache::lonnavmaps;
use Apache::lonhomework;
+use Apache::loncoursedata;
+use Apache::lonmsg qw(:user_normal_msg);
use Apache::Constants qw(:common);
+use String::Similarity;
-sub moreinfo {
- my ($request,$reason) = @_;
- $request->print("Unable to process request: $reason");
- if ( $Apache::grades::viewgrades eq 'F' ) {
- $request->print('
');
- }
- return '';
-}
+my %oldessays=();
+my %perm=();
-sub verifyreceipt {
- my $request=shift;
- my $courseid=$ENV{'request.course.id'};
-# my $cdom=$ENV{"course.$courseid.domain"};
-# my $cnum=$ENV{"course.$courseid.num"};
- my $receipt=unpack("%32C*",$Apache::lonnet::perlvar{'lonHostID'}).'-'.
- $ENV{'form.receipt'};
- $receipt=~s/[^\-\d]//g;
- my $symb=$ENV{'form.symb'};
- unless ($symb) {
- $symb=&Apache::lonnet::symbread($ENV{'form.url'});
- }
- if ((&Apache::lonnet::allowed('mgr',$courseid)) && ($symb)) {
- $request->print('
Verifying Submission Receipt '.$receipt.'
');
- my $matches=0;
- my ($classlist) = &getclasslist('all','0');
- foreach my $student ( sort(@{ $$classlist{'all'} }) ) {
- my ($uname,$udom)=split(/\:/,$student);
- if ($receipt eq
- &Apache::lonnet::ireceipt($uname,$udom,$courseid,$symb)) {
- $request->print('Matching '.$student.' ');
- $matches++;
- }
- }
- $request->printf('
'.$matches." match%s
",$matches <= 1 ? '' : 'es');
-# needs to print who is matched
+# ----- These first few routines are general use routines.----
+#
+# --- Retrieve the parts that matches stores_\d+ from the metadata file.---
+sub getpartlist {
+ my ($url) = @_;
+ my @parts =();
+ my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));
+ foreach my $key (@metakeys) {
+ if ( $key =~ m/stores_(\w+)_.*/) {
+ push(@parts,$key);
+ }
}
- return '';
+ return @parts;
}
-sub student_gradeStatus {
- my ($url,$udom,$uname) = @_;
- my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
- my %record= &Apache::lonnet::restore($symb,$ENV{'request.course.id'},$udom,$uname);
- foreach my $part (&getpartlist($url)) {
- my ($temp,$part,$type)=split(/_/,$part);
- if ($type eq 'solved') {
- my ($status,$foo)=split(/_/,$record{"resource.$part.$type"},2);
- $status = 'partial' if ($foo =~ /^partially/);
- $status = 'nothing' if ($status eq '');
- return $type,$status;
- }
- }
- return '';
+# --- Get the symbolic name of a problem and the url
+sub get_symb_and_url {
+ my ($request) = @_;
+ (my $url=$ENV{'form.url'}) =~ s-^http://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--;
+ my $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url)));
+ if ($symb eq '') { $request->print("Unable to handle ambiguous references:$url:."); return ''; }
+ return ($symb,$url);
}
+# --- Retrieve the fullname for a user. Return lastname, first middle ---
+# --- Generation is attached next to the lastname if it exists. ---
sub get_fullname {
- my ($sname,$sdom) = @_;
+ my ($uname,$udom) = @_;
my %name=&Apache::lonnet::get('environment', ['lastname','generation',
'firstname','middlename'],
- $sdom,$sname);
+ $udom,$uname);
my $fullname;
my ($tmp) = keys(%name);
if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
- $fullname=$name{'lastname'}.$name{'generation'};
- if ($fullname =~ /[^\s]+/) { $fullname.=', '; }
- $fullname.=$name{'firstname'}.' '.$name{'middlename'};
+ $fullname = &Apache::loncoursedata::ProcessFullName
+ (@name{qw/lastname generation firstname middlename/});
+ } else {
+ &Apache::lonnet::logthis('grades.pm: no name data for '.$uname.
+ '@'.$udom.':'.$tmp);
}
return $fullname;
}
-sub listStudents {
- my ($request) = shift;
- my $cdom =$ENV{"course.$ENV{'request.course.id'}.domain"};
- my $cnum =$ENV{"course.$ENV{'request.course.id'}.num"};
- my $getsec =$ENV{'form.section'};
- my $submitonly=$ENV{'form.submitonly'};
-
- $request->print(< View Submissions for a Student or a Group of Students
- Resource: $ENV{'form.url'}
-
- View Problem: no
- yes
- Submissions:
- last sub only
- last sub & parts info
- all details
-
-
-
-
-
-
-
Select
Username
-
Fullname
Domain
-
Grade Status
-ENDTABLEST
- if ($ENV{'form.url'}) {
- $request->print(''."\n");
- }
- if ($ENV{'form.symb'}) {
- $request->print(''."\n");
- }
- $request->print(''."\n");
-
- my ($classlist) = &getclasslist($getsec,'0');
- foreach my $student ( sort(@{ $$classlist{$getsec} }) ) {
- my ($sname,$sdom) = split(/:/,$student);
- my ($type,$status) = &student_gradeStatus($ENV{'form.url'},$cdom,$sname);
- next if ($status eq 'nothing' && $submitonly eq 'yes');
-
- my $fullname = &get_fullname($sname,$sdom);
- if ( $Apache::grades::viewgrades eq 'F' ) {
- $request->print("\n".'
'.
- '
'."\n".
- '
'.$sname.'
'."\n".
- '
'.$fullname.'
'."\n".
- '
'.$sdom.'
'."\n");
- $request->print('
'.$status.'
'."\n");
+#--- Format fullname, username:domain if different for display
+#--- Use anywhere where the student names are listed
+sub nameUserString {
+ my ($type,$fullname,$uname,$udom) = @_;
+ if ($type eq 'header') {
+ return ' Fullname (Username) ';
+ } else {
+ return ' '.$fullname.' ('.$uname.
+ ($ENV{'user.domain'} eq $udom ? '' : ' ('.$udom.')').')';
+ }
+}
- $request->print('
');
- }
- }
- $request->print('
');
- $request->print('');
+#--- Get the partlist and the response type for a given problem. ---
+#--- Indicate if a response type is coded handgraded or not. ---
+sub response_type {
+ my ($url,$symb) = shift;
+ $symb=($ENV{'form.symb'} ne '' ? $ENV{'form.symb'} : (&Apache::lonnet::symbread($url))) if ($symb eq '');
+ my $allkeys = &Apache::lonnet::metadata($url,'keys');
+ my %seen = ();
+ my (@partlist,%handgrade);
+ foreach (split(/,/,&Apache::lonnet::metadata($url,'packages'))) {
+ if (/^\w+response_\w+.*/) {
+ my ($responsetype,$part) = split(/_/,$_,2);
+ my ($partid,$respid) = split(/_/,$part);
+ $responsetype =~ s/response$//; # make it compatible w/ navmaps - should move to that!!
+ my ($value) = &Apache::lonnet::EXT('resource.'.$part.'.handgrade',$symb);
+ $handgrade{$part} = $responsetype.':'.($value eq 'yes' ? 'yes' : 'no');
+ next if ($seen{$partid} > 0);
+ $seen{$partid}++;
+ push @partlist,$partid;
+ }
+ }
+ return \@partlist,\%handgrade;
}
-sub processGroup {
- my ($request) = shift;
- my $ctr = 0;
- my @stuchecked = (ref($ENV{'form.stuinfo'}) ? @{$ENV{'form.stuinfo'}}
- : ($ENV{'form.stuinfo'}));
- my $total = scalar(@stuchecked)-1;
- if ($stuchecked[0] eq '') {
- &userError($request,'No student was selected for viewing/grading.');
- return;
- }
- foreach (@stuchecked) {
- my ($sname,$sdom,$fullname) = split(/:/);
- $ENV{'form.student'} = $sname;
- $ENV{'form.fullname'} = $fullname;
- &submission($request,$ctr,$total);
- $ctr++;
- }
- return 'The End';
+#--- Show resource title
+#--- and parts and response type
+sub showResourceInfo {
+ my ($url,$probTitle) = @_;
+ my $result ='
'.
+ '
Current Resource: '.$probTitle.'
'."\n";
+ my ($partlist,$handgrade) = &response_type($url);
+ my %resptype = ();
+ my $hdgrade='no';
+ for (sort keys(%$handgrade)) {
+ my ($responsetype,$handgrade)=split(/:/,$$handgrade{$_});
+ my $partID = (split(/_/))[0];
+ $resptype{$partID} = $responsetype;
+ $hdgrade = $handgrade if ($handgrade eq 'yes');
+ $result.='
'."\n");
- $request->print('Step: '.($step ne '' ? $step : 'Use your browser back button to correct')
- .'
'."\n");
- return '';
+#--- Clean response type for display
+#--- Currently filters option response type only.
+sub cleanRecord {
+ my ($answer,$response,$symb) = @_;
+ if ($response eq 'option') {
+ my (@IDs,@ans);
+ foreach (split(/\&/,&Apache::lonnet::unescape($answer))) {
+ my ($optionID,$ans) = split(/=/);
+ push @IDs,$optionID.'';
+ push @ans,$ans;
+ }
+ my $grayFont = '';
+ return '
'.
+ '
Answer
'.
+ (join '
',@ans).'
'.
+ '
'.$grayFont.'Option ID
'.$grayFont.
+ (join '
'.$grayFont,@IDs).'
'.
+ '
';
+ }
+ if ($response eq 'essay') {
+ if (! exists ($ENV{'form.'.$symb})) {
+ my (%keyhash) = &Apache::lonnet::dump('nohist_handgrade',
+ $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
+ $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+
+ my $loginuser = $ENV{'user.name'}.':'.$ENV{'user.domain'};
+ $ENV{'form.keywords'} = $keyhash{$symb.'_keywords'} ne '' ? $keyhash{$symb.'_keywords'} : '';
+ $ENV{'form.kwclr'} = $keyhash{$loginuser.'_kwclr'} ne '' ? $keyhash{$loginuser.'_kwclr'} : 'red';
+ $ENV{'form.kwsize'} = $keyhash{$loginuser.'_kwsize'} ne '' ? $keyhash{$loginuser.'_kwsize'} : '0';
+ $ENV{'form.kwstyle'} = $keyhash{$loginuser.'_kwstyle'} ne '' ? $keyhash{$loginuser.'_kwstyle'} : '';
+ $ENV{'form.'.$symb} = 1; # so that we don't have to read it from disk for multiple sub of the same prob.
+ }
+ return '
'.&keywords_highlight($answer).'
';
+ }
+ return $answer;
}
-#FIXME - needs to handle multiple matches
-sub finduser {
- my ($name) = @_;
- my $domain = '';
- if ( $Apache::grades::viewgrades eq 'F' ) {
- my ($classlist) = &getclasslist('all','0');
- foreach ( sort(@{ $$classlist{'all'} }) ) {
- my ($posname,$posdomain) = split(/:/);
- if ($posname =~ $name) { $name=$posname; $domain=$posdomain; last; }
- }
- return ($name,$domain);
- } else {
- return ($ENV{'user.name'},$ENV{'user.domain'});
- }
+#-- A couple of common js functions
+sub commonJSfunctions {
+ my $request = shift;
+ $request->print(<
+ function radioSelection(radioButton) {
+ var selection=null;
+ if (radioButton.length > 1) {
+ for (var i=0; i 1) {
+ for (var i=0; i
+COMMONJSFUNCTIONS
}
+#--- Dumps the class list with usernames,list of sections,
+#--- section, ids and fullnames for each user.
sub getclasslist {
- my ($getsec,$hideexpired) = @_;
- my ($coursedomain,$coursenum) = split(/_/,$ENV{'request.course.id'});
- my %classlist=&Apache::lonnet::dump('classlist',$coursedomain,$coursenum);
- my $now = time;
- my (@holdsec,@sections);
- foreach my $student (keys(%classlist)) {
- my ($end,$start)=split(/:/,$classlist{$student});
- # still a student?
- if (($hideexpired) && ($end) && ($end < $now)) {
- next;
- }
- my ($unam,$udom) = split(/:/,$student,2);
- my $section = &Apache::lonnet::usection($udom,$unam,$ENV{'request.course.id'});
- $section = ($section ne '-1' ? $section : 'no');
- push @holdsec,$section;
- push (@{ $classlist{$getsec} }, $student) if ($getsec eq 'all' || $getsec eq $section);
- }
- my %seen = ();
- foreach my $item (@holdsec) {
- push (@sections, $item) unless $seen{$item}++;
- }
- return (\%classlist,\@sections);
+ my ($getsec,$filterlist) = @_;
+ $getsec = $getsec eq '' ? 'all' : $getsec;
+ my $classlist=&Apache::loncoursedata::get_classlist();
+ # Bail out if we were unable to get the classlist
+ return if (! defined($classlist));
+ #
+ my %sections;
+ my %fullnames;
+ foreach (keys(%$classlist)) {
+ # the following undefs are for 'domain', and 'username' respectively.
+ my (undef,undef,$end,$start,$id,$section,$fullname,$status)=
+ @{$classlist->{$_}};
+ # filter students according to status selected
+ if ($filterlist && $ENV{'form.Status'} ne 'Any') {
+ if ($ENV{'form.Status'} ne $status) {
+ delete ($classlist->{$_});
+ next;
+ }
+ }
+ $section = ($section ne '' ? $section : 'no');
+ if (&canview($section)) {
+ if ($getsec eq 'all' || $getsec eq $section) {
+ $sections{$section}++;
+ $fullnames{$_}=$fullname;
+ } else {
+ delete($classlist->{$_});
+ }
+ } else {
+ delete($classlist->{$_});
+ }
+ }
+ my %seen = ();
+ my @sections = sort(keys(%sections));
+ return ($classlist,\@sections,\%fullnames);
}
-sub getpartlist {
- my ($url) = @_;
- my @parts =();
- my (@metakeys) = split(/,/,&Apache::lonnet::metadata($url,'keys'));
- foreach my $key (@metakeys) {
- if ( $key =~ m/stores_([0-9]+)_.*/) {
- push(@parts,$key);
+sub canmodify {
+ my ($sec)=@_;
+ if ($perm{'mgr'}) {
+ if (!defined($perm{'mgr_section'})) {
+ # can modify whole class
+ return 1;
+ } else {
+ if ($sec eq $perm{'mgr_section'}) {
+ #can modify the requested section
+ return 1;
+ } else {
+ # can't modify the request section
+ return 0;
+ }
+ }
}
- }
- return @parts;
+ #can't modify
+ return 0;
}
-sub viewstudentgrade {
- my ($url,$symb,$courseid,$student,@parts) = @_;
- my $result ='';
- my $cellclr = '"#ffffdd"';
- my ($username,$domain) = split(/:/,$student);
-
- my $fullname = &get_fullname($username,$domain);
- my %record=&Apache::lonnet::restore($symb,$courseid,$domain,$username);
-
- $result.="