--- loncom/interface/lonquickgrades.pm 2011/06/01 21:32:50 1.97
+++ loncom/interface/lonquickgrades.pm 2017/12/18 23:51:14 1.112
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Quick Student Grades Display
#
-# $Id: lonquickgrades.pm,v 1.97 2011/06/01 21:32:50 www Exp $
+# $Id: lonquickgrades.pm,v 1.112 2017/12/18 23:51:14 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -29,12 +29,31 @@
package Apache::lonquickgrades;
use strict;
-use Apache::Constants qw(:common :http);
+use Apache::Constants qw(:common :http REDIRECT);
use POSIX;
use Apache::loncommon;
use Apache::lonlocal;
use Apache::lonnet;
use Apache::grades;
+use Apache::loncoursedata;
+use Apache::lonstudentassessment;
+use Apache::lonuserstate;
+
+use Time::HiRes;
+use Spreadsheet::WriteExcel;
+use Spreadsheet::WriteExcel::Utility();
+#
+# Excel data
+#
+my $excel_sheet;
+my $excel_workbook;
+my $filename;
+my $format;
+my $request_aborted;
+my $header_row;
+my $cols_output;
+my %prog_state;
+
sub handler {
my $r = shift;
@@ -57,31 +76,84 @@ sub real_handler {
return OK;
}
- # Send header, don't cache this page
- &Apache::loncommon::no_cache($r);
- $r->send_http_header;
-
+ my $cangrade=&Apache::lonnet::allowed('mgr');
my $showPoints =
(($env{'course.'.$env{'request.course.id'}.'.grading'} eq 'standard')
|| ($env{'course.'.$env{'request.course.id'}.'.grading'} eq 'categories'));
- my $notshowSPRSlink =
- (($env{'course.'.$env{'request.course.id'}.'.grading'} eq 'external')
- || ($env{'course.'.$env{'request.course.id'}.'.grading'} eq 'externalnototals'));
- my $notshowTotals=
- $env{'course.'.$env{'request.course.id'}.'.grading'} eq 'externalnototals';
- my $showCategories=
- $env{'course.'.$env{'request.course.id'}.'.grading'} eq 'categories';
+ my $reinitresult;
- my $title = "Grading and Statistics";#$showPoints ? "Points Display" : "Completed Problems Display";
- my $brcrum = [{href=>"/adm/quickgrades",text => "Points Display"}];
- $r->print(&Apache::loncommon::start_page($title,undef,
- {'bread_crumbs' => $brcrum})
- );
+ unless ($cangrade) {
+ # Check for critical messages and redirect if present.
+ my ($redirect,$url) = &Apache::loncommon::critical_redirect(300,'grades');
+ if ($redirect) {
+ &Apache::loncommon::content_type($r,'text/html');
+ $r->header_out(Location => $url);
+ return REDIRECT;
+ }
+
+ # Check if course needs to be re-initialized
+ my $loncaparev = $r->dir_config('lonVersion');
+ ($reinitresult,my @reinit) = &Apache::loncommon::needs_coursereinit($loncaparev);
+
+ if ($reinitresult eq 'switch') {
+ &Apache::loncommon::content_type($r,'text/html');
+ $r->send_http_header;
+ $r->print(&Apache::loncommon::check_release_result(@reinit));
+ return OK;
+ } elsif ($reinitresult eq 'update') {
+ my $cid = $env{'request.course.id'};
+ my $cnum = $env{'course.'.$cid.'.num'};
+ my $cdom = $env{'course.'.$cid.'.domain'};
+ &Apache::loncommon::content_type($r,'text/html');
+ $r->send_http_header;
+ &startpage($r,$showPoints);
+ my $preamble = '
'.
+ '
'.
+ &mt('Your course session is being updated because of recent changes by course personnel.').
+ ' '.&mt('Please be patient.').'
'.
+ '';
+ %prog_state = &Apache::lonhtmlcommon::Create_PrgWin($r,undef,$preamble);
+ &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,&mt('Updating course'));
+ $r->rflush();
+ my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum");
+ &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,&mt('Finished'));
+ &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
+ my $closure = <
+//
+
+ENDCLOSE
+ if ($ferr) {
+ $r->print($closure.&Apache::loncommon::end_page());
+ my $requrl = $r->uri;
+ $env{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
+ $env{'user.reinit'} = 1;
+ return HTTP_NOT_ACCEPTABLE;
+ } else {
+ $r->print($closure);
+ }
+ } elsif ((&Apache::loncommon::course_type() eq 'Placement') &&
+ (!$env{'request.role.adv'})) {
+ my $furl = &Apache::lonpageflip::first_accessible_resource();
+ &Apache::loncommon::content_type($r,'text/html');
+ $r->header_out(Location => $furl);
+ return REDIRECT;
+ }
+ }
+
+ unless ($reinitresult eq 'update') {
+ # Send header, don't cache this page
+ &Apache::loncommon::no_cache($r);
+ $r->send_http_header;
+ &startpage($r,$showPoints);
+ }
+ $r->rflush();
&startGradeScreen($r,'quick');
- my $cangrade=&Apache::lonnet::allowed('mgr');
#
# Pick student
#
@@ -89,11 +161,44 @@ sub real_handler {
my $udom;
my $stdid;
if ($cangrade) {
+ $r->print("".&mt("Download Multiple")."
".
+ ''."\n"
+ );
+ $r->print("
".&mt("Display Individual")."
");
if ($env{'form.uname'}) { $uname=$env{'form.uname'}; }
if ($env{'form.udom'}) { $udom=$env{'form.udom'}; }
if ($env{'form.id'}) { $stdid=$env{'form.id'}; }
if (($stdid) && ($udom)) {
- $uname=(&Apache::lonnet::idget($udom,$stdid))[1];
+ $uname=(&Apache::lonnet::idget($udom,[$stdid],'ids'))[1];
}
if (($stdid) && (!$uname)) {
$r->print(''.&mt("Unknown Student/Employee ID: [_1]",$stdid).'
');
@@ -106,14 +211,22 @@ sub real_handler {
$r->print(&mt('For User [_1] or Student/Employee ID [_2] at Domain [_3]'
,''
,' '
- ,$chooseopt).'
'.
- '');
+ ,$chooseopt).
+ ' ');
if (($uname) && ($udom)) {
$r->print(''.&mt('Full Name: [_1]',&Apache::loncommon::plainname($uname,$udom)).'
');
}
}
$r->rflush();
+ my $notshowSPRSlink =
+ (($env{'course.'.$env{'request.course.id'}.'.grading'} eq 'external')
+ || ($env{'course.'.$env{'request.course.id'}.'.grading'} eq 'externalnototals'));
+ my $notshowTotals=
+ $env{'course.'.$env{'request.course.id'}.'.grading'} eq 'externalnototals';
+ my $showCategories=
+ $env{'course.'.$env{'request.course.id'}.'.grading'} eq 'categories';
+
my ($navmap,$totalParts,$totalPossible,$totalRight,$totalAttempted,$topLevelParts,$topLevelRight,$topLevelAttempted)=
&getData($showPoints,$uname,$udom);
@@ -130,6 +243,43 @@ sub real_handler {
}
+sub getStudentCatGrade {
+ my ($uname,$udom,%categories)=@_;
+ my ($navmap,$totalParts,$totalPossible,$totalRight,$totalAttempted,$topLevelParts,$topLevelRight,$topLevelAttempted)=
+ &getData(1,$uname,$udom);
+ return &output_category_table(undef,0,$navmap,0,%categories);
+}
+
+sub getAllStudentData {
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+
+ my %categories=&Apache::lonnet::dump('grading_categories',$cdom,$cnum);
+
+ my $classlist = &Apache::loncoursedata::get_classlist();
+
+ my $statusidx = &Apache::loncoursedata::CL_STATUS();
+ my $usernameidx = &Apache::loncoursedata::CL_SNAME();
+ my $domainidx = &Apache::loncoursedata::CL_SDOM();
+ my $fullnameidx = &Apache::loncoursedata::CL_FULLNAME();
+
+ foreach my $key (keys(%{$classlist})) {
+ my $student = $classlist->{$key};
+ my $perc=&getStudentCatGrade($classlist->{$student}->[$usernameidx],
+ $classlist->{$student}->[$domainidx],
+ %categories);
+ }
+}
+
+sub startpage {
+ my ($r,$showPoints) = @_;
+ my $title = "Grading and Statistics";#$showPoints ? "Points Display" : "Completed Problems Display";
+ my $brcrum = [{href=>"/adm/quickgrades",text => "Points Display"}];
+ $r->print(&Apache::loncommon::start_page($title,undef,
+ {'bread_crumbs' => $brcrum})
+ );
+}
+
sub startGradeScreen {
my ($r,$mode)=@_;
@@ -181,7 +331,7 @@ sub startGradeScreen {
if ($env{'form.symb'}) {
$r->print("\n".' '.
+ '&command=gradingmenu"> '.
&mt('Problem Grading').' ');
}
@@ -195,6 +345,68 @@ sub endGradeScreen {
$r->print(''.&Apache::loncommon::end_page());
}
+# -----------
+
+
+sub excel_cleanup {
+ undef ($excel_sheet);
+ undef ($excel_workbook);
+ undef ($filename);
+ undef ($format);
+}
+
+
+sub excel_initialize {
+ my ($r) = @_;
+
+ &excel_cleanup();
+
+ # Create sheet
+ ($excel_workbook,$filename,$format)=
+ &Apache::loncommon::create_workbook($r);
+ return if (! defined($excel_workbook));
+ #
+ # Add a worksheet
+ my $sheetname = $env{'course.'.$env{'request.course.id'}.'.description'};
+ $sheetname = &Apache::loncommon::clean_excel_name($sheetname);
+ $excel_sheet = $excel_workbook->addworksheet($sheetname);
+ #
+ # Put the course description in the header
+ $excel_sheet->write($header_row,$cols_output++,
+ $env{'course.'.$env{'request.course.id'}.'.description'},
+ $format->{'h1'});
+}
+
+sub excel_finish {
+ my ($r) = @_;
+ if ($request_aborted || ! defined($excel_sheet)) {
+ &excel_cleanup();
+ return;
+ }
+ #
+ # Write the excel file
+ $excel_workbook->close();
+ #
+ # Close the progress window
+ &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
+ #
+ # Tell the user where to get their excel file
+ $r->print('
'.
+ ''.&mt('Your Excel spreadsheet').''."\n");
+ $r->rflush();
+ &excel_cleanup();
+ return;
+}
+
+
+#
+# CSV data
+#
+# -----------
+
+#
+# Go through the complete course and collect data
+#
sub getData {
@@ -232,7 +444,7 @@ sub getData {
if ($curRes == $iterator->BEGIN_MAP()) {$depth++;}
if ($curRes == $iterator->END_MAP()) { $depth--; }
- if (ref($curRes) && $curRes->is_problem() && !$curRes->randomout)
+ if (ref($curRes) && $curRes->is_gradable() && !$curRes->randomout)
{
# Get number of correct, incorrect parts
my $parts = $curRes->parts();
@@ -242,12 +454,11 @@ sub getData {
my $stack = $iterator->getStack();
for my $part (@{$parts}) {
- my $completionStatus = $curRes->getCompletionStatus($part);
my $dateStatus = $curRes->getDateStatus($part);
my $weight = $curRes->weight($part);
my $problemstatus = $curRes->problemstatus($part);
- if ($completionStatus == $curRes->EXCUSED()) {
+ if ($curRes->solved($part) eq 'excused') {
next;
}
if ($showPoints) {
@@ -462,7 +673,7 @@ sub outputCategories {
&Apache::lonnet::put('grading_categories',\%categories,$cdom,$cnum);
}
# new categories loaded now
- &output_category_table($r,$cangrade,$navmap,%categories);
+ &output_category_table($r,$cangrade,$navmap,1,%categories);
#
if ($cangrade) {
$r->print(&Apache::loncommon::resourcebrowser_javascript().
@@ -472,40 +683,6 @@ sub outputCategories {
''.
'');
}
-#
-# Debug
-#
-# my %data=&dumpdata($navmap);
-# foreach (keys(%data)) {
-# $r->print("\n
".$_.'='.$data{$_});
-# }
-# my @debugarray=('5:1','4:3','1:1','5:5','6:7');
-# $r->print("Array: ".join(',',@debugarray).'
');
-# $r->print("0,0,0: ".join(',',&drop(0,0,0,@debugarray)).'
');
-# $r->print("1,0,0: ".join(',',&drop(1,0,0,@debugarray)).'
');
-# $r->print("0,1,0: ".join(',',&drop(0,1,0,@debugarray)).'
');
-# $r->print("1,1,0: ".join(',',&drop(1,1,0,@debugarray)).'
');
-#
-# $r->print("0,0,2: ".join(',',&drop(0,0,2,@debugarray)).'
');
-# $r->print("1,0,2: ".join(',',&drop(1,0,2,@debugarray)).'
');
-# $r->print("0,1,2: ".join(',',&drop(0,1,2,@debugarray)).'
');
-# $r->print("1,1,2: ".join(',',&drop(1,1,2,@debugarray)).'
');
-#
-# $r->print("0,0,4: ".join(',',&drop(0,0,4,@debugarray)).'
');
-# $r->print("1,0,4: ".join(',',&drop(1,0,4,@debugarray)).'
');
-# $r->print("0,1,4: ".join(',',&drop(0,1,4,@debugarray)).'
');
-# $r->print("1,1,4: ".join(',',&drop(1,1,4,@debugarray)).'
');
-#
-# $r->print("0,0,5: ".join(',',&drop(0,0,5,@debugarray)).'
');
-# $r->print("1,0,5: ".join(',',&drop(1,0,5,@debugarray)).'
');
-# $r->print("0,1,5: ".join(',',&drop(0,1,5,@debugarray)).'
');
-# $r->print("1,1,5: ".join(',',&drop(1,1,5,@debugarray)).'
');
-#
-# $r->print("0,0,7: ".join(',',&drop(0,0,7,@debugarray)).'
');
-# $r->print("1,0,7: ".join(',',&drop(1,0,7,@debugarray)).'
');
-# $r->print("0,1,7: ".join(',',&drop(0,1,7,@debugarray)).'
');
-# $r->print("1,1,7: ".join(',',&drop(1,1,7,@debugarray)).'
');
-
}
#
@@ -588,21 +765,23 @@ sub process_category_edits {
#
sub output_category_table {
- my ($r,$cangrade,$navmaps,%categories)=@_;
+ my ($r,$cangrade,$navmaps,$output,%categories)=@_;
my $totalweight=0;
my $totalpoints=0;
- $r->print(&Apache::loncommon::start_data_table());
+ if ($output) {
+ $r->print(&Apache::loncommon::start_data_table());
#
- &output_category_table_header($r,$cangrade);
+ &output_category_table_header($r,$cangrade);
+ }
#
my @order=split(/\,/,$categories{'order'});
#
my %performance=&dumpdata($navmaps);
my $maxpos=$#order;
for (my $i=0;$i<=$maxpos;$i++) {
- my ($correct,$possible,$type,$weight)=&output_and_calc_category($r,$cangrade,$navmaps,$order[$i],$i,$maxpos,\%performance,1,%categories);
+ my ($correct,$possible,$type,$weight)=&output_and_calc_category($r,$cangrade,$navmaps,$order[$i],$i,$maxpos,\%performance,$output,%categories);
unless ($possible) { next; }
$totalpoints+=$weight*$correct/$possible;
$totalweight+=$weight;
@@ -611,9 +790,10 @@ sub output_category_table {
my $perc=0;
if ($totalweight) { $perc=100.*$totalpoints/$totalweight; }
- &bottom_line_category($r,$cangrade,$perc);
-#
- $r->print(&Apache::loncommon::end_data_table());
+ if ($output) {
+ &bottom_line_category($r,$cangrade,$perc);
+ $r->print(&Apache::loncommon::end_data_table());
+ }
return $perc;
}
@@ -639,14 +819,15 @@ sub output_category_table_header {
sub output_and_calc_category {
my ($r,$cangrade,$navmaps,$id,$currentpos,$maxpos,$performance,$output,%categories)=@_;
+
+ if ($output) { $r->print("\n".&Apache::loncommon::start_data_table_row()); }
- my $iconpath = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL') . "/");
- my %lt=&Apache::lonlocal::texthash(
+ if ($output && $cangrade) {
+ my $iconpath = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL') . "/");
+ my %lt=&Apache::lonlocal::texthash(
'up' => 'Move Up',
'dw' => 'Move Down');
- if ($output) { $r->print("\n".&Apache::loncommon::start_data_table_row()); }
- if ($output && $cangrade) {
$r->print(<