# The LearningOnline Network with CAPA # Quick Student Grades Display # # $Id: lonquickgrades.pm,v 1.127 2024/01/05 19:10:30 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA 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 2 of the License, or # (at your option) any later version. # # LON-CAPA 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 LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt # # http://www.lon-capa.org/ # package Apache::lonquickgrades; use strict; 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; return real_handler($r); } sub real_handler { my $r = shift; &Apache::loncommon::get_unprocessed_cgi($ENV{QUERY_STRING}); # Handle header-only request if ($env{'browser.mathml'}) { &Apache::loncommon::content_type($r,'text/xml'); } else { &Apache::loncommon::content_type($r,'text/html'); } if ($r->header_only) { $r->send_http_header; return OK; } 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 $reinitresult; if ($env{'request.course.id'}) { my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; my $clientip = &Apache::lonnet::get_requestor_ip($r); my ($blocked,$blocktext) = &Apache::loncommon::blocking_status('grades',$clientip,$cnum,$cdom); if ($blocked) { my $checkrole = "cm./$cdom/$cnum"; if ($env{'request.course.sec'} ne '') { $checkrole .= "/$env{'request.course.sec'}"; } unless ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) && ($env{'request.role'} !~ m{^st\./$cdom/$cnum})) { &grades_blocked($r,$blocktext,$showPoints); return OK; } } } 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; } my ($cid,$cnum,$cdom); if ($reinitresult) { $cid = $env{'request.course.id'}; $cnum = $env{'course.'.$cid.'.num'}; $cdom = $env{'course.'.$cid.'.domain'}; } if (($reinitresult eq 'main') || ($reinitresult eq 'both')) { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; &startpage($r,$showPoints); my $preamble = '
'.&mt('Sections').''. &Apache::loncommon::help_open_topic("Chart_Sections"). ' | '. ''.&mt('Groups').''. ' | '. ''.&mt('Student Data').''. &Apache::loncommon::help_open_topic("Chart_Student_Data"). ' | '. ''.&mt('Access Status').''. &Apache::loncommon::help_open_topic("Chart_Enrollment_Status"). ' | '. ''.&mt('Output Format').''. &Apache::loncommon::help_open_topic("Chart_Output_Formats"). ' | |
'."\n". &Apache::lonstatistics::SectionSelect('Section','multiple',5). ' | '. &Apache::lonstatistics::GroupSelect('Group','multiple',5). ' | '. &Apache::lonstatistics::StudentDataSelect('StudentData','multiple',5,undef). ' | '."\n". &Apache::lonhtmlcommon::StatusOptions(undef,undef,5). ' | '."\n". &Apache::lonstudentassessment::CreateAndParseOutputSelector(). ' | '. ''. ' |
'.&mt("Unknown Student/Employee ID: [_1]",$stdid).'
'); $stdid=''; } if (($uname eq '') && ($udom eq '')) { $uname = $env{'user.name'}; $udom = $env{'user.domain'}; } $r->print('\n"); } my $requrl = $r->uri; $env{'user.error.msg'} = "$requrl:bre:0:0:Navmap initialization failed."; return HTTP_NOT_ACCEPTABLE; } if ($cangrade) { $r->print("\n\n"); } &endGradeScreen($r); return OK; } sub grades_blocked { my ($r,$blocktext,$caller) = @_; my $title = 'Points Display'; if ($caller eq 'spreadsheet') { $title = 'Spreadsheet'; } elsif ($env{'course.'.$env{'request.course.id'}.'.grading'} ne 'standard') { $title = 'Completed Problems Display'; } my $brcrum = [{href=>"/adm/quickgrades",text => $title}]; &Apache::lonhtmlcommon::clear_breadcrumbs(); &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/quickgrades', text=> $title}); my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs($title); &Apache::loncommon::content_type($r,'text/html'); &Apache::loncommon::no_cache($r); $r->send_http_header; $r->print(&Apache::loncommon::start_page($title). $breadcrumbs. $blocktext. &Apache::loncommon::end_page()); return; } 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)=@_; my $showPoints = $env{'course.'.$env{'request.course.id'}.'.grading'} eq 'standard'; my $hidetotals = $env{'course.'.$env{'request.course.id'}.'.hidetotals'}; my $notshowSPRSlink = (($env{'course.'.$env{'request.course.id'}.'.grading'} eq 'external') || ($env{'course.'.$env{'request.course.id'}.'.grading'} eq 'externalnototals') || ($env{'course.'.$env{'request.course.id'}.'.grading'} eq 'categories')); my $notshowTotals = $env{'course.'.$env{'request.course.id'}.'.grading'} eq 'externalnototals'; my $showSPRSlink = $env{'course.'.$env{'request.course.id'}.'.grading'} eq 'spreadsheet'; my $showCategories = $env{'course.'.$env{'request.course.id'}.'.grading'} eq 'categories'; my $allowed_to_view = &Apache::lonnet::allowed('vgr',$env{'request.course.id'}); if ((!$allowed_to_view) && ($env{'request.course.sec'} ne '')) { $allowed_to_view = &Apache::lonnet::allowed('vgr', "$env{'request.course.id'}/$env{'request.course.sec'}"); } my $allowed_to_edit = &Apache::lonnet::allowed('mgr',$env{'request.course.id'}); if ((!$allowed_to_edit) && ($env{'request.course.sec'} ne '')) { $allowed_to_edit = &Apache::lonnet::allowed('mgr', "$env{'request.course.id'}/$env{'request.course.sec'}"); } if ($allowed_to_view) { my @notes; push(@notes,&mt('Students do not see total points.')) if ($notshowTotals); push(@notes,&mt('Students do not see link to spreadsheet.')) if ($notshowSPRSlink); push(@notes,&mt('Students will see points based on problem weights.')) if ($showPoints); if (($showPoints) && ($hidetotals ne '')) { if ($hidetotals eq 'all') { push(@notes,&mt('Students do not see course totals.')); } else { my @secs = split(/,/,$hidetotals); if (@secs == 1) { push(@notes,&mt('Students in section [_1] do not see course totals.', $hidetotals)); } elsif (@secs > 1) { push(@notes,&mt('Students in sections [_1] do not see course totals.', join(', ',@secs))); } } } push(@notes,&mt('Students will see points based on categories.')) if ($showCategories); push(@notes,&mt('Students will see link to spreadsheet.')) if ($showSPRSlink); push(@notes, &Apache::lonhtmlcommon::coursepreflink(&mt('Grade display settings'),'grading')); $r->print(&Apache::loncommon::head_subbox(join(' ',@notes))); } $r->print("\n".''.&mt('Total raw points: [_1]/[_2]',&numberout($totalcorrect),&numberout($totalpossible)).'
'); $r->print(''.&mt('Adjusted raw points: [_1]/[_2]',&numberout($totalcorrect),&numberout($totalpossible)).'
'); } # Calculation if ($output) { $r->print(''.&mt('Calculated points: [_1]/[_2]',&numberout($totalcorrect),&numberout($totalpossible)).'
'); $r->print(''); if ($type eq 'percent') { my $perc='---'; if ($totalpossible) { $perc=100.*$totalcorrect/$totalpossible; } $r->print(&mt('[_1] percent',&numberout($perc))); } else { $r->print(&mt('[_1]/[_2] points',&numberout($totalcorrect),&numberout($totalpossible))); } $r->print('
'); } if ($output) { $r->print('