version 1.795, 2024/07/01 22:29:01
|
version 1.796, 2024/12/03 23:34:10
|
Line 47 use Apache::lonstathelpers;
|
Line 47 use Apache::lonstathelpers;
|
use Apache::lonquickgrades; |
use Apache::lonquickgrades; |
use Apache::bridgetask(); |
use Apache::bridgetask(); |
use Apache::lontexconvert(); |
use Apache::lontexconvert(); |
|
use Apache::loncourserespicker; |
use String::Similarity; |
use String::Similarity; |
use HTML::Parser(); |
use HTML::Parser(); |
use File::MMagic; |
use File::MMagic; |
use LONCAPA; |
use LONCAPA; |
|
use LONCAPA::ltiutils(); |
|
|
use POSIX qw(floor); |
use POSIX qw(floor); |
|
|
Line 636 COMMONJSFUNCTIONS
|
Line 638 COMMONJSFUNCTIONS
|
#--- Dumps the class list with usernames,list of sections, |
#--- Dumps the class list with usernames,list of sections, |
#--- section, ids and fullnames for each user. |
#--- section, ids and fullnames for each user. |
sub getclasslist { |
sub getclasslist { |
my ($getsec,$filterbyaccstatus,$getgroup,$symb,$submitonly,$filterbysubmstatus) = @_; |
my ($getsec,$filterbyaccstatus,$getgroup,$symb,$submitonly,$filterbysubmstatus,$filterbypbid,$possibles) = @_; |
my @getsec; |
my @getsec; |
my @getgroup; |
my @getgroup; |
my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status')); |
my $stu_status = join(':',&Apache::loncommon::get_env_multiple('form.Status')); |
Line 664 sub getclasslist {
|
Line 666 sub getclasslist {
|
# |
# |
my %sections; |
my %sections; |
my %fullnames; |
my %fullnames; |
|
my %passback; |
my ($cdom,$cnum,$partlist); |
my ($cdom,$cnum,$partlist); |
if (($filterbysubmstatus) && ($submitonly ne 'all') && ($symb ne '')) { |
if (($filterbysubmstatus) && ($submitonly ne 'all') && ($symb ne '')) { |
$cdom = $env{"course.$env{'request.course.id'}.domain"}; |
$cdom = $env{"course.$env{'request.course.id'}.domain"}; |
$cnum = $env{"course.$env{'request.course.id'}.num"}; |
$cnum = $env{"course.$env{'request.course.id'}.num"}; |
my $res_error; |
my $res_error; |
($partlist) = &response_type($symb,\$res_error); |
($partlist) = &response_type($symb,\$res_error); |
|
} elsif ($filterbypbid) { |
|
$cdom = $env{"course.$env{'request.course.id'}.domain"}; |
|
$cnum = $env{"course.$env{'request.course.id'}.num"}; |
} |
} |
foreach my $student (keys(%$classlist)) { |
foreach my $student (keys(%$classlist)) { |
my $end = |
my $end = |
Line 756 sub getclasslist {
|
Line 762 sub getclasslist {
|
} |
} |
} |
} |
} |
} |
|
if ($filterbypbid) { |
|
if (ref($possibles) eq 'HASH') { |
|
unless (exists($possibles->{$student})) { |
|
delete($classlist->{$student}); |
|
next; |
|
} |
|
} |
|
my $udom = |
|
$classlist->{$student}->[&Apache::loncoursedata::CL_SDOM()]; |
|
my $uname = |
|
$classlist->{$student}->[&Apache::loncoursedata::CL_SNAME()]; |
|
if (($udom ne '') && ($uname ne '')) { |
|
my %pbinfo = &Apache::lonnet::get('nohist_'.$cdom.'_'.$cnum.'_linkprot_pb',[$filterbypbid],$udom,$uname); |
|
if (ref($pbinfo{$filterbypbid}) eq 'ARRAY') { |
|
$passback{$student} = $pbinfo{$filterbypbid} |
|
} else { |
|
delete($classlist->{$student}); |
|
next; |
|
} |
|
} |
|
} |
$section = ($section ne '' ? $section : 'none'); |
$section = ($section ne '' ? $section : 'none'); |
if (&canview($section)) { |
if (&canview($section)) { |
if (!@getsec || grep(/^\Q$section\E$/,@getsec)) { |
if (!@getsec || grep(/^\Q$section\E$/,@getsec)) { |
Line 771 sub getclasslist {
|
Line 798 sub getclasslist {
|
} |
} |
} |
} |
my @sections = sort(keys(%sections)); |
my @sections = sort(keys(%sections)); |
return ($classlist,\@sections,\%fullnames); |
return ($classlist,\@sections,\%fullnames,\%passback); |
} |
} |
|
|
sub canmodify { |
sub canmodify { |
Line 1034 sub verifyreceipt {
|
Line 1061 sub verifyreceipt {
|
return $string; |
return $string; |
} |
} |
|
|
|
sub initialpassback { |
|
my ($request,$symb) = @_; |
|
my $cdom = $env{"course.$env{'request.course.id'}.domain"}; |
|
my $cnum = $env{"course.$env{'request.course.id'}.num"}; |
|
my $crstype = &Apache::loncommon::course_type(); |
|
my %passback = &Apache::lonnet::dump('nohist_linkprot_passback',$cdom,$cnum); |
|
my $readonly; |
|
unless ($perm{'mgr'}) { |
|
$readonly = 1; |
|
} |
|
my $formname = 'initialpassback'; |
|
my $navmap = Apache::lonnavmaps::navmap->new(); |
|
my $output; |
|
if (!defined($navmap)) { |
|
if ($crstype eq 'Community') { |
|
$output = &mt('Unable to retrieve information about community contents'); |
|
} else { |
|
$output = &mt('Unable to retrieve information about course contents'); |
|
} |
|
return '<p>'.$output.'</p>'; |
|
} |
|
return &Apache::loncourserespicker::create_picker($navmap,'passback',$formname,$crstype,undef, |
|
undef,undef,undef,undef,undef,undef, |
|
\%passback,$readonly); |
|
} |
|
|
|
sub passback_filters { |
|
my ($request,$symb) = @_; |
|
my $cdom = $env{"course.$env{'request.course.id'}.domain"}; |
|
my $cnum = $env{"course.$env{'request.course.id'}.num"}; |
|
my $crstype = &Apache::loncommon::course_type(); |
|
my ($launcher,$appname,$setter,$linkuri,$linkprotector,$scope,$chosen); |
|
if ($env{'form.passback'} ne '') { |
|
$chosen = &unescape($env{'form.passback'}); |
|
($linkuri,$linkprotector,$scope) = split("\0",$chosen); |
|
($launcher,$appname,$setter) = &get_passback_launcher($cdom,$cnum,$chosen); |
|
} |
|
my $result; |
|
if ($launcher ne '') { |
|
$result = &launcher_info_box($launcher,$appname,$setter,$linkuri,$scope). |
|
'<p><br />'.&mt('Set criteria to use to list students for possible passback of scores, then push Next [_1]', |
|
'→'). |
|
'</p>'; |
|
} |
|
$result .= '<form action="/adm/grades" method="post" name="gradingMenu">'."\n". |
|
'<input type="hidden" name="passback" value="'.&escape($chosen).'" />'."\n". |
|
'<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n"; |
|
my ($submittext,$newcommand); |
|
if ($launcher ne '') { |
|
$submittext = &mt('Next').' →'; |
|
$newcommand = 'passbacknames'; |
|
$result .= &selectfield(0)."\n"; |
|
} else { |
|
$submittext = '← '.&mt('Previous'); |
|
$newcommand = 'initialpassback'; |
|
if ($env{'form.passback'}) { |
|
$result .= '<span class="LC_warning">'.&mt('Invalid launcher').'</span>'."\n"; |
|
} else { |
|
$result .= '<span class="LC_warning">'.&mt('No launcher selected').'</span>'."\n"; |
|
} |
|
} |
|
$result .= '<input type="hidden" name="command" value="'.$newcommand.'" />'."\n". |
|
'<div>'."\n". |
|
'<input type="submit" value="'.$submittext.'" />'."\n". |
|
'</div>'."\n". |
|
'</form>'."\n"; |
|
return $result; |
|
} |
|
|
|
sub names_for_passback { |
|
my ($request,$symb) = @_; |
|
my $cdom = $env{"course.$env{'request.course.id'}.domain"}; |
|
my $cnum = $env{"course.$env{'request.course.id'}.num"}; |
|
my $crstype = &Apache::loncommon::course_type(); |
|
my ($launcher,$appname,$setter,$linkuri,$linkprotector,$scope,$chosen); |
|
if ($env{'form.passback'} ne '') { |
|
$chosen = &unescape($env{'form.passback'}); |
|
($linkuri,$linkprotector,$scope) = split("\0",$chosen); |
|
($launcher,$appname,$setter) = &get_passback_launcher($cdom,$cnum,$chosen); |
|
} |
|
my ($result,$ctr,$newcommand,$submittext); |
|
if ($launcher ne '') { |
|
$result = &launcher_info_box($launcher,$appname,$setter,$linkuri,$scope); |
|
} |
|
$ctr = 0; |
|
my @statuses = &Apache::loncommon::get_env_multiple('form.Status'); |
|
my $stu_status = join(':',@statuses); |
|
$result .= '<form action="/adm/grades" method="post" name="passbackusers">'."\n". |
|
'<input type="hidden" name="symb" value="'.&Apache::lonenc::check_encrypt($symb).'" />'."\n"; |
|
if ($launcher ne '') { |
|
$result .= '<input type="hidden" name="passback" value="'.&escape($chosen).'" />'."\n". |
|
'<input type="hidden" name="Status" value="'.$stu_status.'" />'."\n"; |
|
my ($sections,$groups,$group_display,$disabled) = §ions_and_groups(); |
|
my $section_display = join(' ',@{$sections}); |
|
my $status_display; |
|
if ((grep(/^Any$/,@statuses)) || |
|
(@statuses == 3)) { |
|
$status_display = &mt('Any'); |
|
} else { |
|
$status_display = join(' '.&mt('or').' ',map { &mt($_); } @statuses); |
|
} |
|
$result .= '<p>'.&mt('Student(s) with stored passback credentials for [_1], and also satisfy:', |
|
'<span class="LC_cusr_emph">'.$linkuri.'</span>'). |
|
'<ul>'. |
|
'<li>'.&mt('Section(s)').": $section_display</li>\n". |
|
'<li>'.&mt('Group(s)').": $group_display</li>\n". |
|
'<li>'.&mt('Status').": $status_display</li>\n". |
|
'</ul>'; |
|
my ($classlist,undef,$fullname) = &getclasslist($sections,'1',$groups,'','','',$chosen); |
|
if (keys(%$fullname)) { |
|
$newcommand = 'passbackscores'; |
|
$result .= &build_section_inputs(). |
|
&checkselect_js('passbackusers'). |
|
'<p><br />'. |
|
&mt("To send scores, check box(es) next to the student's name(s), then push 'Send Scores'."). |
|
'</p>'. |
|
&check_script('passbackusers', 'stuinfo')."\n". |
|
'<input type="button" '."\n". |
|
'onclick="javascript:checkSelect(this.form.stuinfo);" '."\n". |
|
'value="'.&mt('Send Scores').'" /> <br />'."\n". |
|
&check_buttons()."\n". |
|
&Apache::loncommon::start_data_table(). |
|
&Apache::loncommon::start_data_table_header_row(); |
|
my $loop = 0; |
|
while ($loop < 2) { |
|
$result .= '<th>'.&mt('No.').'</th><th>'.&mt('Select').'</th>'. |
|
'<th>'.&nameUserString('header').' '.&mt('Section/Group').'</th>'; |
|
$loop++; |
|
} |
|
$result .= &Apache::loncommon::end_data_table_header_row()."\n"; |
|
foreach my $student (sort |
|
{ |
|
if (lc($$fullname{$a}) ne lc($$fullname{$b})) { |
|
return (lc($$fullname{$a}) cmp lc($$fullname{$b})); |
|
} |
|
return $a cmp $b; |
|
} |
|
(keys(%$fullname))) { |
|
$ctr++; |
|
my $section = $classlist->{$student}->[&Apache::loncoursedata::CL_SECTION()]; |
|
my $group = $classlist->{$student}->[&Apache::loncoursedata::CL_GROUP()]; |
|
my $udom = $classlist->{$student}->[&Apache::loncoursedata::CL_SDOM()]; |
|
my $uname = $classlist->{$student}->[&Apache::loncoursedata::CL_SNAME()]; |
|
if ( $perm{'vgr'} eq 'F' ) { |
|
if ($ctr%2 ==1) { |
|
$result.= &Apache::loncommon::start_data_table_row(); |
|
} |
|
$result .= '<td align="right">'.$ctr.' </td>'. |
|
'<td align="center"><label><input type="checkbox" name="stuinfo" value="'. |
|
$student.':'.$$fullname{$student}.':::SECTION'.$section. |
|
') " /> </label></td>'."\n".'<td>'. |
|
&nameUserString(undef,$$fullname{$student},$uname,$udom). |
|
' '.$section.($group ne '' ?'/'.$group:'').'</td>'."\n"; |
|
|
|
if ($ctr%2 ==0) { |
|
$result .= &Apache::loncommon::end_data_table_row()."\n"; |
|
} |
|
} |
|
} |
|
if ($ctr%2 ==1) { |
|
$result .= &Apache::loncommon::end_data_table_row(); |
|
} |
|
$result .= &Apache::loncommon::end_data_table()."\n"; |
|
if ($ctr) { |
|
$result .= '<input type="button" '. |
|
'onclick="javascript:checkSelect(this.form.stuinfo);" '. |
|
'value="'.&mt('Send Scores').'" />'."\n"; |
|
} |
|
} else { |
|
$submittext = '← '.&mt('Previous'); |
|
$newcommand = 'passback'; |
|
$result .= '<span class="LC_warning">'.&mt('No students match the selection criteria').'</p>'; |
|
} |
|
} else { |
|
$newcommand = 'initialpassback'; |
|
$submittext = &mt('Start over'); |
|
if ($env{'form.passback'}) { |
|
$result .= '<span class="LC_warning">'.&mt('Invalid launcher').'</span>'."\n"; |
|
} else { |
|
$result .= '<span class="LC_warning">'.&mt('No launcher selected').'</span>'."\n"; |
|
} |
|
} |
|
$result .= '<input type="hidden" name="command" value="'.$newcommand.'" />'."\n"; |
|
if (!$ctr) { |
|
$result .= '<div>'."\n". |
|
'<input type="submit" value="'.$submittext.'" />'."\n". |
|
'</div>'."\n"; |
|
} |
|
$result .= '</form>'."\n"; |
|
return $result; |
|
} |
|
|
|
sub do_passback { |
|
my ($request,$symb) = @_; |
|
my $cdom = $env{"course.$env{'request.course.id'}.domain"}; |
|
my $cnum = $env{"course.$env{'request.course.id'}.num"}; |
|
my $crstype = &Apache::loncommon::course_type(); |
|
my ($launcher,$appname,$setter,$linkuri,$linkprotector,$scope,$chosen); |
|
if ($env{'form.passback'} ne '') { |
|
$chosen = &unescape($env{'form.passback'}); |
|
($linkuri,$linkprotector,$scope) = split("\0",$chosen); |
|
($launcher,$appname,$setter) = &get_passback_launcher($cdom,$cnum,$chosen); |
|
} |
|
if ($launcher ne '') { |
|
$request->print(&launcher_info_box($launcher,$appname,$setter,$linkuri,$scope)); |
|
} |
|
my $error; |
|
if ($perm{'mgr'}) { |
|
if ($launcher ne '') { |
|
my @poss_students = &Apache::loncommon::get_env_multiple('form.stuinfo'); |
|
if (@poss_students) { |
|
my %possibles; |
|
foreach my $item (@poss_students) { |
|
my ($stuname,$studom) = split(/:/,$item,3); |
|
$possibles{$stuname.':'.$studom} = 1; |
|
} |
|
my ($sections,$groups,$group_display,$disabled) = §ions_and_groups(); |
|
my ($classlist,undef,$fullname,$pbinfo) = |
|
&getclasslist($sections,'1',$groups,'','','',$chosen,\%possibles); |
|
if ((ref($classlist) eq 'HASH') && (ref($pbinfo) eq 'HASH')) { |
|
my %passback = %{$pbinfo}; |
|
my (%tosend,%remotenotok,%scorenotok,%zeroposs,%nopbinfo); |
|
foreach my $possible (keys(%possibles)) { |
|
if ((exists($classlist->{$possible})) && |
|
(exists($passback{$possible})) && (ref($passback{$possible}) eq 'ARRAY')) { |
|
$tosend{$possible} = 1; |
|
} |
|
} |
|
if (keys(%tosend)) { |
|
my ($lti_in_use,$crsdef); |
|
my ($ltinum,$ltitype) = ($linkprotector =~ /^(\d+)(c|d)$/); |
|
if ($ltitype eq 'c') { |
|
my %crslti = &Apache::lonnet::get_course_lti($cnum,$cdom,'provider'); |
|
$lti_in_use = $crslti{$ltinum}; |
|
$crsdef = 1; |
|
} else { |
|
my %domlti = &Apache::lonnet::get_domain_lti($cdom,'linkprot'); |
|
$lti_in_use = $domlti{$ltinum}; |
|
} |
|
if (ref($lti_in_use) eq 'HASH') { |
|
my $msgformat = $lti_in_use->{'passbackformat'}; |
|
my $keynum = $lti_in_use->{'cipher'}; |
|
my $scoretype = 'decimal'; |
|
if ($lti_in_use->{'scoreformat'} =~ /^(decimal|ratio|percentage)$/) { |
|
$scoretype = $1; |
|
} |
|
my $pbsymb = &Apache::loncommon::symb_from_tinyurl($linkuri,$cnum,$cdom); |
|
my $pbmap; |
|
if ($pbsymb =~ /\.(page|sequence)$/) { |
|
$pbmap = &Apache::lonnet::deversion((&Apache::lonnet::decode_symb($pbsymb))[2]); |
|
} else { |
|
$pbmap = &Apache::lonnet::deversion((&Apache::lonnet::decode_symb($pbsymb))[0]); |
|
} |
|
$pbmap = &Apache::lonnet::clutter($pbmap); |
|
my $pbscope; |
|
if ($scope eq 'res') { |
|
$pbscope = 'resource'; |
|
} elsif ($scope eq 'map') { |
|
$pbscope = 'nonrec'; |
|
} elsif ($scope eq 'rec') { |
|
$pbscope = 'map'; |
|
} |
|
my $sigmethod = 'HMAC-SHA1'; |
|
my $type = 'linkprot'; |
|
my $clientip = &Apache::lonnet::get_requestor_ip(); |
|
my $lonhost = $Apache::lonnet::perlvar{'lonHostID'}; |
|
my $ip = &Apache::lonnet::get_host_ip($lonhost); |
|
my $numstudents = scalar(keys(%tosend)); |
|
my %prog_state = &Apache::lonhtmlcommon::Create_PrgWin($request,$numstudents); |
|
my $outcome = &Apache::loncommon::start_data_table(). |
|
&Apache::loncommon::start_data_table_header_row(); |
|
my $loop = 0; |
|
while ($loop < 2) { |
|
$outcome .= '<th>'.&mt('No.').'</th>'. |
|
'<th>'.&nameUserString('header').' '.&mt('Section/Group').'</th>'. |
|
'<th>'.&mt('Score').'</th>'; |
|
$loop++; |
|
} |
|
$outcome .= &Apache::loncommon::end_data_table_header_row()."\n"; |
|
my $ctr=0; |
|
foreach my $student (sort |
|
{ |
|
if (lc($$fullname{$a}) ne lc($$fullname{$b})) { |
|
return (lc($$fullname{$a}) cmp lc($$fullname{$b})); |
|
} |
|
return $a cmp $b; |
|
} (keys(%$fullname))) { |
|
next unless ($tosend{$student}); |
|
my ($uname,$udom) = split(/:/,$student); |
|
&Apache::lonhtmlcommon::Increment_PrgWin($request,\%prog_state,'last student'); |
|
my ($uname,$udom) = split(/:/,$student); |
|
my $uhome = &Apache::lonnet::homeserver($uname,$udom), |
|
my $id = $passback{$student}[0], |
|
my $url = $passback{$student}[1], |
|
my ($total,$possible,$usec); |
|
if (ref($classlist->{$student}) eq 'ARRAY') { |
|
$usec = $classlist->{$student}->[&Apache::loncoursedata::CL_SECTION]; |
|
} |
|
if ($pbscope eq 'resource') { |
|
$total = 0; |
|
$possible = 0; |
|
my $navmap = Apache::lonnavmaps::navmap->new($uname,$udom); |
|
if (ref($navmap)) { |
|
my $res = $navmap->getBySymb($pbsymb); |
|
if (ref($res)) { |
|
my $partlist = $res->parts(); |
|
if (ref($partlist) eq 'ARRAY') { |
|
my %record = &Apache::lonnet::restore($pbsymb,$env{'request.course.id'},$udom,$uname); |
|
foreach my $part (@{$partlist}) { |
|
next if ($record{"resource.$part.solved"} =~/^excused/); |
|
my $weight = &Apache::lonnet::EXT("resource.$part.weight",$pbsymb,$udom,$uname,$usec); |
|
$possible += $weight; |
|
if (($record{'version'}) && (exists($record{"resource.$part.awarded"}))) { |
|
my $awarded = $record{"resource.$part.awarded"}; |
|
if ($awarded) { |
|
$total += $weight * $awarded; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} elsif (($pbscope eq 'map') || ($pbscope eq 'nonrec')) { |
|
($total,$possible) = |
|
&Apache::lonhomework::get_lti_score($uname,$udom,$pbmap,$pbscope); |
|
} |
|
if (($id ne '') && ($url ne '') && ($possible)) { |
|
my ($sent,$score,$code,$result) = |
|
&LONCAPA::ltiutils::send_grade($cdom,$cnum,$crsdef,$type,$ltinum,$keynum,$id, |
|
$url,$scoretype,$sigmethod,$msgformat,$total,$possible); |
|
my $no_passback; |
|
if ($sent) { |
|
if ($code == 200) { |
|
delete($tosend{$student}); |
|
my $namespace = $cdom.'_'.$cnum.'_lp_passback'; |
|
my $store = { |
|
'score' => $score, |
|
'ip' => $ip, |
|
'host' => $lonhost, |
|
'protector' => $linkprotector, |
|
'deeplink' => $linkuri, |
|
'scope' => $scope, |
|
'url' => $url, |
|
'id' => $id, |
|
'clientip' => $clientip, |
|
'whodoneit' => $env{'user.name'}.':'.$env{'user.domain'}, |
|
}; |
|
my $value=''; |
|
foreach my $key (keys(%{$store})) { |
|
$value.=&escape($key).'='.&Apache::lonnet::freeze_escape($store->{$key}).'&'; |
|
} |
|
$value=~s/\&$//; |
|
&Apache::lonnet::courselog(&escape($linkuri).':'.$uname.':'.$udom.':EXPORT:'.$value); |
|
&Apache::lonnet::cstore({'score' => $score},$chosen,$namespace,$udom,$uname,'',$ip,1); |
|
$ctr++; |
|
if ($ctr%2 ==1) { |
|
$outcome .= &Apache::loncommon::start_data_table_row(); |
|
} |
|
my $section = $classlist->{$student}->[&Apache::loncoursedata::CL_SECTION()]; |
|
my $group = $classlist->{$student}->[&Apache::loncoursedata::CL_GROUP()]; |
|
$outcome .= '<td align="right">'.$ctr.' </td>'. |
|
'<td>'.&nameUserString(undef,$$fullname{$student},$uname,$udom). |
|
' '.$section.($group ne '' ?'/'.$group:'').'</td>'. |
|
'<td>'.$score.'</td>'."\n"; |
|
if ($ctr%2 ==0) { |
|
$outcome .= &Apache::loncommon::end_data_table_row()."\n"; |
|
} |
|
} else { |
|
$remotenotok{$student} = 1; |
|
$no_passback = "Passback response for ".$linkprotector." was $code ($result)"; |
|
&Apache::lonnet::logthis($no_passback." for $uname:$udom in ${cdom}_${cnum}"); |
|
} |
|
} else { |
|
$scorenotok{$student} = 1; |
|
$no_passback = "Passback of grades not sent for ".$linkprotector; |
|
&Apache::lonnet::logthis($no_passback." for $uname:$udom in ${cdom}_${cnum}"); |
|
} |
|
if ($no_passback) { |
|
&Apache::lonnet::log($udom,$uname,$uhome,$no_passback." score: $score; total: $total; possible: $possible"); |
|
my $ltigrade = { |
|
'ltinum' => $ltinum, |
|
'lti' => $lti_in_use, |
|
'crsdef' => $crsdef, |
|
'cid' => $cdom.'_'.$cnum, |
|
'uname' => $uname, |
|
'udom' => $udom, |
|
'uhome' => $uhome, |
|
'pbid' => $id, |
|
'pburl' => $url, |
|
'pbtype' => $type, |
|
'pbscope' => $pbscope, |
|
'pbmap' => $pbmap, |
|
'pbsymb' => $pbsymb, |
|
'format' => $scoretype, |
|
'scope' => $scope, |
|
'clientip' => $clientip, |
|
'linkprot' => $linkprotector, |
|
'total' => $total, |
|
'possible' => $possible, |
|
'score' => $score, |
|
}; |
|
&Apache::lonnet::put('linkprot_passback_pending',$ltigrade,$cdom,$cnum); |
|
} |
|
} else { |
|
if (($id ne '') && ($url ne '')) { |
|
$zeroposs{$student} = 1; |
|
} else { |
|
$nopbinfo{$student} = 1; |
|
} |
|
} |
|
} |
|
&Apache::lonhtmlcommon::Close_PrgWin($request,\%prog_state); |
|
if ($ctr%2 ==1) { |
|
$outcome .= &Apache::loncommon::end_data_table_row(); |
|
} |
|
$outcome .= &Apache::loncommon::end_data_table(); |
|
if ($ctr) { |
|
$request->print('<p><br />'.&mt('Scores sent to launcher CMS').'</p>'. |
|
'<p>'.$outcome.'</p>'); |
|
} else { |
|
$request->print('<p>'.&mt('No scores sent to launcher CMS').'</p>'); |
|
} |
|
if (keys(%tosend)) { |
|
$request->print('<p>'.&mt('No scores sent for following')); |
|
my ($zeros,$nopbcreds,$noconfirm,$noscore); |
|
foreach my $student (sort |
|
{ |
|
if (lc($$fullname{$a}) ne lc($$fullname{$b})) { |
|
return (lc($$fullname{$a}) cmp lc($$fullname{$b})); |
|
} |
|
return $a cmp $b; |
|
} (keys(%$fullname))) { |
|
next unless ($tosend{$student}); |
|
my ($uname,$udom) = split(/:/,$student); |
|
my $line = '<li>'.&nameUserString(undef,$$fullname{$student},$uname,$udom).'</li>'."\n"; |
|
if ($zeroposs{$student}) { |
|
$zeros .= $line; |
|
} elsif ($nopbinfo{$student}) { |
|
$nopbcreds .= $line; |
|
} elsif ($remotenotok{$student}) { |
|
$noconfirm .= $line; |
|
} elsif ($scorenotok{$student}) { |
|
$noscore .= $line; |
|
} |
|
} |
|
if ($zeros) { |
|
$request->print('<br />'.&mt('Total points possible was 0').':'. |
|
'<ul>'.$zeros.'</ul><br />'); |
|
} |
|
if ($nopbcreds) { |
|
$request->print('<br />'.&mt('Missing unique identifier and/or passback location').':'. |
|
'<ul>'.$nopbcreds.'</ul><br />'); |
|
} |
|
if ($noconfirm) { |
|
$request->print('<br />'.&mt('Score receipt not confirmed by receiving CMS').':'. |
|
'<ul>'.$noconfirm.'</ul><br />'); |
|
} |
|
if ($noscore) { |
|
$request->print('<br />'.&mt('Score computation or transmission failed').':'. |
|
'<ul>'.$noscore.'</ul><br />'); |
|
} |
|
$request->print('</p>'); |
|
} |
|
} else { |
|
$error = &mt('Settings for deep-link launch target unavailable, so no scores were sent'); |
|
} |
|
} else { |
|
$error = &mt('No available students for whom scores can be sent.'); |
|
} |
|
} else { |
|
$error = &mt('Classlist could not be retrieved so no scores were sent.'); |
|
} |
|
} else { |
|
$error = &mt('No students selected to receive scores so none were sent.'); |
|
} |
|
} else { |
|
if ($env{'form.passback'}) { |
|
$error = &mt('Deep-link launch target was invalid so no scores were sent.'); |
|
} else { |
|
$error = &mt('Deep-link launch target was missing so no scores were sent.'); |
|
} |
|
} |
|
} else { |
|
$error = &mt('You do not have permission to manage grades, so no scores were sent'); |
|
} |
|
if ($error) { |
|
$request->print('<p class="LC_info">'.$error.'</p>'); |
|
} |
|
return; |
|
} |
|
|
|
sub get_passback_launcher { |
|
my ($cdom,$cnum,$chosen) = @_; |
|
my ($linkuri,$linkprotector,$scope) = split("\0",$chosen); |
|
my ($ltinum,$ltitype) = ($linkprotector =~ /^(\d+)(c|d)$/); |
|
my ($appname,$setter); |
|
if ($ltitype eq 'c') { |
|
my %lti = &Apache::lonnet::get_course_lti($cnum,$cdom,'provider'); |
|
if (ref($lti{$ltinum}) eq 'HASH') { |
|
$appname = $lti{$ltinum}{'name'}; |
|
if ($appname) { |
|
$setter = ' (defined in course)'; |
|
} |
|
} |
|
} elsif ($ltitype eq 'd') { |
|
my %lti = &Apache::lonnet::get_domain_lti($cdom,'linkprot'); |
|
if (ref($lti{$ltinum}) eq 'HASH') { |
|
$appname = $lti{$ltinum}{'name'}; |
|
if ($appname) { |
|
$setter = ' (defined in domain)'; |
|
} |
|
} |
|
} |
|
if ($linkuri =~ m{^\Q/tiny/$cdom/\E(\w+)$}) { |
|
my $key = $1; |
|
my $tinyurl; |
|
my ($result,$cached)=&Apache::lonnet::is_cached_new('tiny',$cdom."\0".$key); |
|
if (defined($cached)) { |
|
$tinyurl = $result; |
|
} else { |
|
my $configuname = &Apache::lonnet::get_domainconfiguser($cdom); |
|
my %currtiny = &Apache::lonnet::get('tiny',[$key],$cdom,$configuname); |
|
if ($currtiny{$key} ne '') { |
|
$tinyurl = $currtiny{$key}; |
|
&Apache::lonnet::do_cache_new('tiny',$cdom."\0".$key,$currtiny{$key},600); |
|
} |
|
} |
|
if ($tinyurl) { |
|
my ($crsnum,$launchsymb) = split(/\&/,$tinyurl); |
|
if ($crsnum eq $cnum) { |
|
my %passback = &Apache::lonnet::get('nohist_linkprot_passback',[$launchsymb],$cdom,$cnum); |
|
if (ref($passback{$launchsymb}) eq 'HASH') { |
|
if (exists($passback{$launchsymb}{$chosen})) { |
|
return ($launchsymb,$appname,$setter) |
|
} |
|
} |
|
} |
|
} |
|
} |
|
return (); |
|
} |
|
|
|
sub sections_and_groups { |
|
my (@sections,@groups,$group_display); |
|
@groups = &Apache::loncommon::get_env_multiple('form.group'); |
|
if (grep(/^all$/,@groups)) { |
|
@groups = ('all'); |
|
$group_display = 'all'; |
|
} elsif (grep(/^none$/,@groups)) { |
|
@groups = ('none'); |
|
$group_display = 'none'; |
|
} elsif (@groups > 0) { |
|
$group_display = join(', ',@groups); |
|
} |
|
if ($env{'request.course.sec'} ne '') { |
|
@sections = ($env{'request.course.sec'}); |
|
} else { |
|
@sections = &Apache::loncommon::get_env_multiple('form.section'); |
|
} |
|
my $disabled = ' disabled="disabled"'; |
|
if ($perm{'mgr'}) { |
|
if (grep(/^all$/,@sections)) { |
|
undef($disabled); |
|
} else { |
|
foreach my $sec (@sections) { |
|
if (&canmodify($sec)) { |
|
undef($disabled); |
|
last; |
|
} |
|
} |
|
} |
|
} |
|
if (grep(/^all$/,@sections)) { |
|
@sections = ('all'); |
|
} |
|
return(\@sections,\@groups,$group_display,$disabled); |
|
} |
|
|
|
sub launcher_info_box { |
|
my ($launcher,$appname,$setter,$linkuri,$scope) = @_; |
|
my $shownscope; |
|
if ($scope eq 'res') { |
|
$shownscope = &mt('Resource'); |
|
} elsif ($scope eq 'map') { |
|
$shownscope = &mt('Folder'); |
|
} elsif ($scope eq 'rec') { |
|
$shownscope = &mt('Folder + sub-folders'); |
|
} |
|
return '<p>'. |
|
&Apache::lonhtmlcommon::start_pick_box(). |
|
&Apache::lonhtmlcommon::row_title(&mt('Launch Item Title')). |
|
&Apache::lonnet::gettitle($launcher); |
|
&Apache::lonhtmlcommon::row_closure(). |
|
&Apache::lonhtmlcommon::row_title(&mt('Deep-link')). |
|
$linkuri. |
|
&Apache::lonhtmlcommon::row_closure(). |
|
&Apache::lonhtmlcommon::row_title(&mt('Launcher')). |
|
$appname.' '.$setter. |
|
&Apache::lonhtmlcommon::row_closure(). |
|
&Apache::lonhtmlcommon::row_title(&mt('Score Type')). |
|
$shownscope. |
|
&Apache::lonhtmlcommon::row_closure(1). |
|
&Apache::lonhtmlcommon::end_pick_box().'</p>'."\n"; |
|
} |
|
|
#--- This is called by a number of programs. |
#--- This is called by a number of programs. |
#--- Called from the Grading Menu - View/Grade an individual student |
#--- Called from the Grading Menu - View/Grade an individual student |
#--- Also called directly when one clicks on the subm button |
#--- Also called directly when one clicks on the subm button |
Line 1065 sub listStudents {
|
Line 1697 sub listStudents {
|
} |
} |
} |
} |
|
|
my %js_lt = &Apache::lonlocal::texthash ( |
$request->print(&checkselect_js()); |
'multiple' => 'Please select a student or group of students before clicking on the Next button.', |
|
'single' => 'Please select the student before clicking on the Next button.', |
|
); |
|
&js_escape(\%js_lt); |
|
$request->print(&Apache::lonhtmlcommon::scripttag(<<LISTJAVASCRIPT)); |
$request->print(&Apache::lonhtmlcommon::scripttag(<<LISTJAVASCRIPT)); |
function checkSelect(checkBox) { |
|
var ctr=0; |
|
var sense=""; |
|
if (checkBox.length > 1) { |
|
for (var i=0; i<checkBox.length; i++) { |
|
if (checkBox[i].checked) { |
|
ctr++; |
|
} |
|
} |
|
sense = '$js_lt{'multiple'}'; |
|
} else { |
|
if (checkBox.checked) { |
|
ctr = 1; |
|
} |
|
sense = '$js_lt{'single'}'; |
|
} |
|
if (ctr == 0) { |
|
alert(sense); |
|
return false; |
|
} |
|
document.gradesub.submit(); |
|
} |
|
|
|
function reLoadList(formname) { |
function reLoadList(formname) { |
if (formname.saveStatusOld.value == pullDownSelection(formname.Status)) {return;} |
if (formname.saveStatusOld.value == pullDownSelection(formname.Status)) {return;} |
Line 1380 LISTJAVASCRIPT
|
Line 1986 LISTJAVASCRIPT
|
return ''; |
return ''; |
} |
} |
|
|
#---- Called from the listStudents routine |
#---- Called from the listStudents and the names_for_passback routines. |
|
|
|
sub checkselect_js { |
|
my ($formname) = @_; |
|
if ($formname eq '') { |
|
$formname = 'gradesub'; |
|
} |
|
my %js_lt; |
|
if ($formname eq 'passbackusers') { |
|
%js_lt = &Apache::lonlocal::texthash ( |
|
'multiple' => 'Please select a student or group of students before pushing the Save Scores button.', |
|
'single' => 'Please select the student before pushing the Save Scores button.', |
|
); |
|
} else { |
|
%js_lt = &Apache::lonlocal::texthash ( |
|
'multiple' => 'Please select a student or group of students before clicking on the Next button.', |
|
'single' => 'Please select the student before clicking on the Next button.', |
|
); |
|
} |
|
&js_escape(\%js_lt); |
|
return &Apache::lonhtmlcommon::scripttag(<<LISTJAVASCRIPT); |
|
|
|
function checkSelect(checkBox) { |
|
var ctr=0; |
|
var sense=""; |
|
var len = checkBox.length; |
|
if (len == undefined) len = 1; |
|
if (len > 1) { |
|
for (var i=0; i<len; i++) { |
|
if (checkBox[i].checked) { |
|
ctr++; |
|
} |
|
} |
|
sense = '$js_lt{'multiple'}'; |
|
} else { |
|
if (checkBox.checked) { |
|
ctr = 1; |
|
} |
|
sense = '$js_lt{'single'}'; |
|
} |
|
if (ctr == 0) { |
|
alert(sense); |
|
return false; |
|
} |
|
document.$formname.submit(); |
|
} |
|
LISTJAVASCRIPT |
|
|
|
} |
|
|
sub check_script { |
sub check_script { |
my ($form,$type) = @_; |
my ($form,$type) = @_; |
Line 10560 sub verify_scantron_grading {
|
Line 11214 sub verify_scantron_grading {
|
|
|
sub href_symb_cmd { |
sub href_symb_cmd { |
my ($symb,$cmd)=@_; |
my ($symb,$cmd)=@_; |
return '/adm/grades?symb='.&HTML::Entities::encode(&Apache::lonenc::check_encrypt($symb),'<>&"').'&command='.$cmd; |
return '/adm/grades?symb='.&HTML::Entities::encode(&Apache::lonenc::check_encrypt($symb),'<>&"').'&command='. |
|
&HTML::Entities::encode($cmd,'<>&"'); |
} |
} |
|
|
sub grading_menu { |
sub grading_menu { |
Line 10669 sub grading_menu {
|
Line 11324 sub grading_menu {
|
|
|
] |
] |
}); |
}); |
|
my $cdom = $env{"course.$env{'request.course.id'}.domain"}; |
|
my $cnum = $env{"course.$env{'request.course.id'}.num"}; |
|
my %passback = &Apache::lonnet::dump('nohist_linkprot_passback',$cdom,$cnum); |
|
if (keys(%passback)) { |
|
$fields{'command'} = 'initialpassback'; |
|
my $url6 = &Apache::lonhtmlcommon::build_url('grades/',\%fields); |
|
push (@{$menu[1]{items}}, |
|
{ linktext => 'Passback of Scores', |
|
url => $url6, |
|
permission => $permissions{'either'}, |
|
icon => 'passback.png', |
|
linktitle => 'Passback scores to launcher CMS for resources accessed via LTI-mediated deep-linking', |
|
}); |
|
} |
# Create the menu |
# Create the menu |
my $Str; |
my $Str; |
$Str .= '<form method="post" action="" name="gradingMenu">'; |
$Str .= '<form method="post" action="" name="gradingMenu">'; |
Line 11889 sub handler {
|
Line 12557 sub handler {
|
undef,undef,undef,undef,undef,undef,undef,1); |
undef,undef,undef,undef,undef,undef,undef,1); |
$request->print('<div style="padding:0;clear:both;margin:0;border:0"></div>'); |
$request->print('<div style="padding:0;clear:both;margin:0;border:0"></div>'); |
&submit_download_link($request,$symb); |
&submit_download_link($request,$symb); |
|
} elsif ($command eq 'initialpassback') { |
|
&startpage($request,$symb,[{href=>'', text=>'Choose Launcher'}],undef,1); |
|
$request->print(&initialpassback($request,$symb)); |
|
} elsif ($command eq 'passback') { |
|
&startpage($request,$symb, |
|
[{href=>&href_symb_cmd($symb,'initialpassback'), text=>'Choose Launcher'}, |
|
{href=>'', text=>'Types of User'}],undef,1); |
|
$request->print(&passback_filters($request,$symb)); |
|
} elsif ($command eq 'passbacknames') { |
|
my $chosen; |
|
if ($env{'form.passback'} ne '') { |
|
if ($env{'form.passback'} eq &unescape($env{'form.passback'})) { |
|
$env{'form.passback'} = &escape($env{'form.passback'} ); |
|
} |
|
$chosen = &HTML::Entities::encode($env{'form.passback'},'<>"&'); |
|
} |
|
&startpage($request,$symb, |
|
[{href=>&href_symb_cmd($symb,'initialpassback'), text=>'Choose Launcher'}, |
|
{href=>&href_symb_cmd($symb,'passback').'&passback='.$chosen, text=>'Types of User'}, |
|
{href=>'', text=>'Select Users'}],undef,1); |
|
$request->print(&names_for_passback($request,$symb)); |
|
} elsif ($command eq 'passbackscores') { |
|
my ($chosen,$stu_status); |
|
if ($env{'form.passback'} ne '') { |
|
if ($env{'form.passback'} eq &unescape($env{'form.passback'})) { |
|
$env{'form.passback'} = &escape($env{'form.passback'} ); |
|
} |
|
$chosen = &HTML::Entities::encode($env{'form.passback'},'<>"&'); |
|
} |
|
if ($env{'form.Status'}) { |
|
$stu_status = &HTML::Entities::encode($env{'form.Status'}); |
|
} |
|
&startpage($request,$symb, |
|
[{href=>&href_symb_cmd($symb,'initialpassback'), text=>'Choose Launcher'}, |
|
{href=>&href_symb_cmd($symb,'passback').'&passback='.$chosen, text=>'Types of User'}, |
|
{href=>&href_symb_cmd($symb,'passbacknames').'&Status='.$stu_status.'&passback='.$chosen, text=>'Select Users'}, |
|
{href=>'', text=>'Execute Passback'}],undef,1); |
|
$request->print(&do_passback($request,$symb)); |
} elsif ($command) { |
} elsif ($command) { |
&startpage($request,$symb,[{href=>'', text=>'Access denied'}]); |
&startpage($request,$symb,[{href=>'', text=>'Access denied'}]); |
$request->print('<p class="LC_error">'.&mt('Access Denied ([_1])',$command).'</p>'); |
$request->print('<p class="LC_error">'.&mt('Access Denied ([_1])',$command).'</p>'); |