[LON-CAPA-cvs] cvs: loncom /homework inputtags.pm matchresponse.pm optionresponse.pm radiobuttonresponse.pm rankresponse.pm /interface lonpdfupload.pm /xml lonxml.pm
raeburn
raeburn at source.lon-capa.org
Sat Feb 21 11:03:58 EST 2026
raeburn Sat Feb 21 16:03:58 2026 EDT
Modified files:
/loncom/homework inputtags.pm optionresponse.pm matchresponse.pm
rankresponse.pm radiobuttonresponse.pm
/loncom/interface lonpdfupload.pm
/loncom/xml lonxml.pm
Log:
- Bug 6121
- Support eforms.sty included in 2021-06-19 version of AcroTex bundle, in
which UTF-16BE text encoding (including initial BOM) is used for form
field names.
- Escape underscores and ampersands in form field names.
- Avoid potentially problematic characters including .) in form field
names by always using encrypted symb as first item in field name.
- Include &user_<hashed uname:udom> in each form field name and check
against hashed uname:dom from %env when processing uploaded PDF form.
- Field name stem defined outside foils loop (approriate $temp appended
in loop for each foil).
- Include ID_$input_id as last item in form field name for textline and
textarea to support multiple ordered submissions for a single response
item.
-------------- next part --------------
Index: loncom/homework/inputtags.pm
diff -u loncom/homework/inputtags.pm:1.373 loncom/homework/inputtags.pm:1.374
--- loncom/homework/inputtags.pm:1.373 Fri Feb 6 22:01:31 2026
+++ loncom/homework/inputtags.pm Sat Feb 21 16:03:57 2026
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# input definitions
#
-# $Id: inputtags.pm,v 1.373 2026/02/06 22:01:31 raeburn Exp $
+# $Id: inputtags.pm,v 1.374 2026/02/21 16:03:57 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -50,11 +50,12 @@
=cut
package Apache::inputtags;
-use HTML::Entities();
use strict;
+use HTML::Entities();
use Apache::loncommon;
use Apache::lonhtmlcommon;
use Apache::lonlocal;
+use Apache::lonxml;
use Apache::lonnet;
use LONCAPA;
@@ -201,7 +202,7 @@
sub start_textfield {
my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
my $result = "";
- my $id = &start_input($parstack,$safeeval);
+ my $input_id = &start_input($parstack,$safeeval);
my $resid=$Apache::inputtags::response[-1];
if ($target eq 'web') {
$Apache::lonxml::evaluate--;
@@ -307,19 +308,18 @@
$result.='\strut \\\\\strut \\\\\strut \\\\\strut \\\\}}}';
} else {
if ($env{'form.pdfFormFields'} eq 'yes') {
- my $prefix = &Apache::lonenc::check_encrypt($env{'request.symb'});
- $prefix =~ s{^/}{};
- unless ($prefix =~ /^(uploaded|enc)/) {
- $prefix = 'res/'.$prefix;
- }
+ my $fieldname = &Apache::lonenc::encrypted($env{'request.symb'},1);
unless ($env{'request.symb'} =~ /^uploaded/) {
- $prefix .= '&'.$env{'request.course.id'};
- }
- my $fieldname = $prefix.
- '&part_'. $Apache::inputtags::part.
- '&textresponse'.
- '&HWVAL_' . $Apache::inputtags::response['-1'];
- $result.='\TextField[name='.$fieldname.',multiline=true,height=6\baselineskip,width=270,borderwidth=0,backgroundcolor={.85 .85 .85}]\\';
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ $fieldname .= '&'.$cdom.'&'.$cnum;
+ }
+ $fieldname .= '&user_'. &Apache::lonxml::get_user_digest().
+ '&part_'. $Apache::inputtags::part.
+ '&textresponse'.
+ '&HWVAL_' . $resid.
+ '&ID_'. $input_id;
+ $result.='\TextField[name='.$fieldname.',multiline=true,height=6\baselineskip,width=270pt,borderwidth=0,backgroundcolor={.85 .85 .85}]\\';
} else {
my $TeXwidth=$width_of_box/80;
$result = '\vskip 1 mm \fbox{\fbox{\parbox{'.$TeXwidth.'\textwidth-5mm}{';
@@ -477,7 +477,7 @@
}
my $name = 'HWVAL_'.$id;
my $itemid = 'HWVAL_'.$partid.'_'.$id;
- # NOTE: the input id should match the one given by defaut_homework input_id().
+ # NOTE: the input id should match the one given by default_homework input_id().
my $input_tag_id = $itemid.'_'.$input_id;
if ($Apache::inputtags::status[-1] eq 'CANNOT_ANSWER') {
$name = "none";
@@ -536,18 +536,20 @@
if ($size != 0) {$size=$size*2; $size.=' mm';} else {$size='40 mm';}
if ($env{'form.pdfFormFields'} eq 'yes'
&& $Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
- my $prefix = &Apache::lonenc::check_encrypt($env{'request.symb'});
- $prefix =~ s{^/}{};
- unless ($prefix =~ /^(uploaded|enc)/) {
- $prefix = 'res/'.$prefix;
- }
+ my $fieldname = &Apache::lonenc::encrypted($env{'request.symb'},1);
unless ($env{'request.symb'} =~ /^uploaded/) {
- $prefix .= '&'.$env{'request.course.id'};
- }
- my $fieldname = $prefix.
- '&part_'. $Apache::inputtags::part.
- '&textresponse'.
- '&HWVAL_' . $Apache::inputtags::response['-1'];
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ $fieldname .= '\&'.$cdom.'\&'.$cnum;
+ }
+ $fieldname .= '\&user\_'.&Apache::lonxml::get_user_digest();
+ my $escpart = $Apache::inputtags::part;
+ $escpart =~ s{_}{\\_}g;
+ my $escres = $Apache::inputtags::response[-1];
+ $escres =~ s{_}{\\_}g;
+ my $escid = $input_id;
+ $escid =~ s{_}{\\_}g;
+ $fieldname .= '\&part\_'.$escpart.'\&textresponse\&HWVAL\_'.$escres.'\&ID\_'.$escid;
$result='\textField{'.$fieldname.'}{'.$size.'}{12 bp}';
} else {
$result='\framebox['.$size.'][s]{\tiny\strut}';
Index: loncom/homework/optionresponse.pm
diff -u loncom/homework/optionresponse.pm:1.205 loncom/homework/optionresponse.pm:1.206
--- loncom/homework/optionresponse.pm:1.205 Fri Feb 6 22:01:31 2026
+++ loncom/homework/optionresponse.pm Sat Feb 21 16:03:57 2026
@@ -1,7 +1,7 @@
# LearningOnline Network with CAPA
# option list style responses
#
-# $Id: optionresponse.pm,v 1.205 2026/02/06 22:01:31 raeburn Exp $
+# $Id: optionresponse.pm,v 1.206 2026/02/21 16:03:57 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -735,17 +735,21 @@
($checkboxchoices?&mt('Choices: ').'<b>'.$opt[0].','.$opt[1].'</b>. ':'').
&mt('Select all that are [_1].','<b>'.$checkboxopt.'</b>');
}
- my $prefix;
+ my $fieldname;
if ($target eq 'tex' and $env{'form.pdfFormFields'} eq 'yes'
&& $Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
- $prefix = &Apache::lonenc::check_encrypt($env{'request.symb'});
- $prefix =~ s{^/}{};
- unless ($prefix =~ /^(uploaded|enc)/) {
- $prefix = 'res/'.$prefix;
- }
+ $fieldname = &Apache::lonenc::encrypted($env{'request.symb'},1);
unless ($env{'request.symb'} =~ /^uploaded/) {
- $prefix .= '&'.$env{'request.course.id'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ $fieldname .= '\&'.$cdom.'\&'.$cnum;
}
+ $fieldname .= '\&user\_'.&Apache::lonxml::get_user_digest();
+ my $escpart = $Apache::inputtags::part;
+ $escpart =~ s{_}{\\_}g;
+ my $escres = $Apache::inputtags::response['-1'];
+ $escres =~ s{_}{\\_}g;
+ $fieldname .= '\&part\_'.$escpart.'\&optionresponse\&HWVAL\_'.$escres.':';
}
foreach $name (@whichopt) {
if ($target eq 'web') {
@@ -762,8 +766,7 @@
if($target eq 'tex' and $env{'form.pdfFormFields'} eq 'yes'
&& $Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
- my $fieldname = $prefix.'&part_'.$Apache::inputtags::part.'&optionresponse'.'&HWVAL_'.$Apache::inputtags::response['-1'].':'.$temp;
- $optionlist = &Apache::lonxml::print_pdf_start_combobox($fieldname);
+ $optionlist = &Apache::lonxml::print_pdf_start_combobox($fieldname.$temp);
}
foreach my $option (@opt) {
Index: loncom/homework/matchresponse.pm
diff -u loncom/homework/matchresponse.pm:1.98 loncom/homework/matchresponse.pm:1.99
--- loncom/homework/matchresponse.pm:1.98 Fri Feb 6 22:01:31 2026
+++ loncom/homework/matchresponse.pm Sat Feb 21 16:03:57 2026
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Full matching style response
#
-# $Id: matchresponse.pm,v 1.98 2026/02/06 22:01:31 raeburn Exp $
+# $Id: matchresponse.pm,v 1.99 2026/02/21 16:03:57 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -679,18 +679,22 @@
} else {
$numrows = 1;
}
- my $prefix;
+ my ($fieldname,$escpart);
if (($Apache::lonhomework::type ne 'exam') &&
($target eq 'tex' and $env{'form.pdfFormFields'} eq 'yes'
&& $Apache::inputtags::status[-1] eq 'CAN_ANSWER')) {
- $prefix = &Apache::lonenc::check_encrypt($env{'request.symb'});
- $prefix =~ s{^/}{};
- unless ($prefix =~ /^(uploaded|enc)/) {
- $prefix = 'res/'.$prefix;
- }
+ $fieldname = &Apache::lonenc::encrypted($env{'request.symb'},1);
unless ($env{'request.symb'} =~ /^uploaded/) {
- $prefix .= '&'.$env{'request.course.id'};
- }
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ $fieldname .= '\&'.$cdom.'\&'.$cnum;
+ }
+ $fieldname .= '\&user\_'.&Apache::lonxml::get_user_digest();
+ my $escres = $Apache::inputtags::response['-1'];
+ $escres =~ s{_}{\\_}g;
+ $escpart = $Apache::inputtags::part;
+ $escpart =~ s{_}{\\_}g;
+ $fieldname .= '\&part\_'.$escpart.'\&matchresponse\&HWVAL\_'.$escres.':';
}
foreach my $name (@whichfoils) {
my $lastopt=$lastresponse{$name};
@@ -702,8 +706,7 @@
if ($Apache::lonhomework::type ne 'exam') {
if($env{'form.pdfFormFields'} eq 'yes'
&& $Apache::inputtags::status['-1'] eq 'CAN_ANSWER') {
- my $fieldname = $prefix . '&part_'. $Apache::inputtags::part .'&matchresponse'. '&HWVAL_' . $Apache::inputtags::response['-1'] . ':' . $temp . '&submit_' . $Apache::inputtags::part . '&';
- $optionlist = &Apache::lonxml::print_pdf_start_combobox($fieldname);
+ $optionlist = &Apache::lonxml::print_pdf_start_combobox($fieldname.$temp.'\&submit\_'.$escpart.'\&');
} else {
$optionlist='\framebox[10 mm][s]{\tiny\strut}';
Index: loncom/homework/rankresponse.pm
diff -u loncom/homework/rankresponse.pm:1.77 loncom/homework/rankresponse.pm:1.78
--- loncom/homework/rankresponse.pm:1.77 Fri Feb 6 22:01:31 2026
+++ loncom/homework/rankresponse.pm Sat Feb 21 16:03:57 2026
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# rank style response
#
-# $Id: rankresponse.pm,v 1.77 2026/02/06 22:01:31 raeburn Exp $
+# $Id: rankresponse.pm,v 1.78 2026/02/21 16:03:57 raeburn Exp $
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
@@ -372,7 +372,7 @@
my $temp=1;
my $id=$Apache::inputtags::response[-1];
my $part=$Apache::inputtags::part;
- my ($lastresponse,$newvariation,$prefix);
+ my ($lastresponse,$newvariation);
if ((($Apache::lonhomework::history{"resource.$part.type"} eq 'randomizetry') ||
($Apache::lonhomework::type eq 'randomizetry')) &&
($Apache::inputtags::status[-1] eq 'CAN_ANSWER')) {
@@ -403,26 +403,30 @@
} else {
$numrows = 1;
}
+ my $fieldname;
if($target eq 'tex' && $env{'form.pdfFormFields'} eq 'yes') {
$result .= '\strut \\\\ \strut \\\\' ;
- $prefix = &Apache::lonenc::check_encrypt($env{'request.symb'});
- $prefix =~ s{^/}{};
- unless ($prefix =~ /^(uploaded|enc)/) {
- $prefix= 'res/'.$prefix;
- }
+ $fieldname = &Apache::lonenc::encrypted($env{'request.symb'},1);
unless ($env{'request.symb'} =~ /^uploaded/) {
- $prefix .= '&'.$env{'request.course.id'};
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ $fieldname .= '\&'.$cdom.'\&'.$cnum;
}
+ $fieldname .= '\&user\_'.&Apache::lonxml::get_user_digest();
+ my $escres = $id;
+ $escres =~ s{_}{\\_}g;
+ my $escpart = $part;
+ $escpart =~ s{_}{\\_}g;
+ $fieldname .= '\&part\_'.$escpart.'\&rankresponse\&HWVAL\_'.$escres.':';
}
foreach my $name (@whichfoils) {
my $lastopt=$lastresponse{$name};
my $optionlist='';
if ($target ne 'tex') {
$optionlist = "<option value=\"\"></option>\n";
- }
+ }
if ($target eq 'tex' && $env{'form.pdfFormFields'} eq 'yes') {
- my $fieldname = $prefix.'&part_'.$Apache::inputtags::part.'&rankresponse'.'&HWVAL_'.$Apache::inputtags::response['-1'].':'.$temp;
- $optionlist = &Apache::lonxml::print_pdf_start_combobox($fieldname);
+ $optionlist = &Apache::lonxml::print_pdf_start_combobox($fieldname.$temp);
}
my $option;
foreach $option (@whichopt) {
Index: loncom/homework/radiobuttonresponse.pm
diff -u loncom/homework/radiobuttonresponse.pm:1.164 loncom/homework/radiobuttonresponse.pm:1.165
--- loncom/homework/radiobuttonresponse.pm:1.164 Fri Feb 6 22:01:31 2026
+++ loncom/homework/radiobuttonresponse.pm Sat Feb 21 16:03:57 2026
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
-# mutliple choice style responses
+# multiple choice style responses
#
-# $Id: radiobuttonresponse.pm,v 1.164 2026/02/06 22:01:31 raeburn Exp $
+# $Id: radiobuttonresponse.pm,v 1.165 2026/02/21 16:03:57 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1129,24 +1129,20 @@
my $temp = 0;
my $result;
- my $prefix = &Apache::lonenc::check_encrypt($env{'request.symb'});
- $prefix =~ s{^/}{};
- unless ($prefix =~ /^(uploaded|enc)/) {
- $prefix = 'res/'.$prefix;
- }
+ my $fieldname = &Apache::lonenc::encrypted($env{'request.symb'},1);
unless ($env{'request.symb'} =~ /^uploaded/) {
- $prefix .= '&'.$env{'request.course.id'};
- }
- $result .= "\\begin{$venv}";
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ $fieldname .= '\&'.$cdom.'\&'.$cnum;
+ }
+ $fieldname .= '\&user\_'.&Apache::lonxml::get_user_digest();
+ my $escpart = $Apache::inputtags::part;
+ $escpart =~ s{_}{\\_}g;
+ my $escres = $Apache::inputtags::response['-1'];
+ $escres =~ s{_}{\\_}g;
+ $fieldname .= '\&part\_'.$escpart.'\&radiobuttonresponse\&HWVAL\_'.$escres;
+ $result = "\\begin{$venv}";
foreach my $name ( @{$whichfoils} ) {
-
- my $fieldname =
- $prefix
- . '&part_'
- . $Apache::inputtags::part
- . '&radiobuttonresponse'
- . '&HWVAL_'
- . $Apache::inputtags::response['-1'];
$result .= '\item[{'
. &Apache::lonxml::print_pdf_radiobutton( $fieldname,
$temp )
Index: loncom/interface/lonpdfupload.pm
diff -u loncom/interface/lonpdfupload.pm:1.30 loncom/interface/lonpdfupload.pm:1.31
--- loncom/interface/lonpdfupload.pm:1.30 Sat Feb 7 00:00:21 2026
+++ loncom/interface/lonpdfupload.pm Sat Feb 21 16:03:57 2026
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# PDF Form Upload Handler
#
-# $Id: lonpdfupload.pm,v 1.30 2026/02/07 00:00:21 raeburn Exp $
+# $Id: lonpdfupload.pm,v 1.31 2026/02/21 16:03:57 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -37,6 +37,8 @@
use Apache::lonlocal;
use File::MMagic;
use CAM::PDF;
+use Encode::Guess;
+use Digest::SHA();
use LONCAPA qw(:DEFAULT :match);
use strict;
@@ -158,7 +160,9 @@
'<h2 class="LC_heading_2">'.&mt('Submit answers via PDF Form upload').'</h2>'
.'<p>'.&mt('This course allows you to submit your answers to assignments by uploading a PDF containing completed form fields.').'</p>'
.'<ul><li>'.&mt('Your PDF must have been originally downloaded via the print utility (with PDF form fields option selected in the Layout options)').'</li>'
- .'<li>'.&mt('Submissions for past-due problems will be ignored, unless a grace period is in effect').'</li></ul>'
+ .'<li>'.&mt('Submissions for past-due problems will be ignored, unless a grace period is in effect').'</li>'
+ .'<li>'.&mt('Submissions for problems which are currently inaccessible will be ignored.').'</li>'
+ .'</ul>'
.'<br />'
.'<form method="post" enctype="multipart/form-data" onsubmit="return checkFilename(this);" action="">'
.&Apache::lonhtmlcommon::start_pick_box()
@@ -180,18 +184,19 @@
}
sub processPDF {
- my $result = (); # message for Browser
+ my $result; # message for Browser
my @pdfdata = (); # answers from PDF-Forms
@pdfdata = &get_pdf_data(); # get answers from PDF-Form
if (scalar @pdfdata) {
- &grade_pdf(@pdfdata);
+ $result = &grade_pdf(@pdfdata);
} else {
- $result .= '<p class="LC_error">'
- .&mt("Can't find any valid PDF form fields.")
- .'</p>';
+ $result = '<p class="LC_error">'
+ .&mt("Can't find any valid PDF form fields.")
+ .'</p>';
}
+ return $result;
}
sub get_pdf_data() {
@@ -208,6 +213,10 @@
# dot in fieldnames. So a fieldname like "i.am.aFormfield" will offer three fieldnames
# "i", "i.am" and "i.am.aFormfield". The fragmentary names keep no values and will be ignored.
if($dict->{'V'}) {
+ my $decoder = Encode::Guess->guess($field);
+ if (ref($decoder)) {
+ $field = $decoder->decode($field);
+ }
push(@data, $field."?". $dict->{'V'}{'value'}); #binding fieldname with value
}
}
@@ -217,7 +226,7 @@
sub grade_pdf {
my @pdfdata = @_;
- my ($result,$meta,%grades,%problems,%foreigncourse,$debug);
+ my ($result,$meta,%grades,%problems,%foreigncourse,%mismatchuser,%hwvals,$debug);
my $navmap = Apache::lonnavmaps::navmap->new();
if (!defined($navmap)) {
@@ -249,32 +258,36 @@
,$env{'user.domain'}.':'.$env{'user.name'})
.'</p>';
}
-
- } elsif (($entry =~ m{^(uploaded|res)/}) || ($entry =~ m{^enc/\d+/})) {
+ } elsif ($entry =~ m{^/enc/\d+/}) {
$debug .= 'found: a problem -> '.$entry;
- my ($cid, $part, $type, $HWVAL);
+ my ($cid, $cdom, $cnum, $digest_user, $part, $type, $HWVAL, $input_id);
my ($label, $value) = ($entry =~ /^([^?]*)\?(.*)/);
- my ($symb, $rest) = split('&', $label, 2);
- if ($symb =~ m{^enc/}) {
- $symb = &Apache::lonenc::check_decrypt("/$symb");
- } elsif ($symb =~ m{^res/}) {
- $symb =~ s{^res/}{};
+ my ($encsymb, $rest) = split('&', $label, 2);
+ my $symb = &Apache::lonenc::unencrypted($encsymb);
+ if (($env{'request.role.adv'}) ||
+ (&Apache::lonnet::EXT('resource.0.encrypturl',$symb) !~ /^yes$/i)) {
+ &Apache::lonenc::reset_enc();
}
if ($symb =~ /^uploaded/) {
- ($part, $type, $HWVAL) = split('&', $rest);
+ ($digest_user, $part, $type, $HWVAL, $input_id) = split('&', $rest);
} else {
- ($cid, $part, $type, $HWVAL) = split('&', $rest);
+ ($cdom, $cnum, $digest_user, $part, $type, $HWVAL, $input_id) = split('&', $rest);
+ $cid = $cdom.'_'.$cnum;
}
my ($map,$id,$resource)=&Apache::lonnet::decode_symb($symb);
if ($map =~ m{^uploaded/($match_domain)/($match_courseid)/default(_?\d*)\.(page|sequence)}) {
- my $mapcid = $1.'_'.$2;
- if ($mapcid ne $env{'request.course.id'}) {
- push(@{$foreigncourse{$mapcid}},$symb);
- }
- } elsif ($map =~ m{^($match_domain)/($match_username)/}) {
- if ($cid ne $env{'request.course.id'}) {
- push(@{$foreigncourse{$cid}},$symb);
- }
+ ($cdom,$cnum) = ($1,$2);
+ $cid = $cdom.'_'.$cnum;
+ }
+ if ($cid ne $env{'request.course.id'}) {
+ push(@{$foreigncourse{$cid}},$symb);
+ next;
+ }
+ $digest_user =~ s/^user_//;
+ if ($digest_user ne
+ &Digest::SHA::sha1_hex(&Encode::decode('UTF-8',$env{'user.name'}.':'.$env{'user.domain'}))) {
+ $mismatchuser{$symb} = 1;
+ next;
}
next unless (exists($restitles{$symb}));
$value =~ s/(.*)\n/$1/;
@@ -283,18 +296,36 @@
if ($type eq 'radiobuttonresponse' && $value eq 'Off' ) {
next;
}
-
+
my $submit = $part;
$submit =~ s/part_(.*)/submit_$1/;
if ($problems{$symb.$part}) {
- $problems{$symb.$part}{$HWVAL} = $value;
+ if ($type eq 'textresponse') {
+ if (ref($problems{$symb.$part}{$HWVAL}) eq 'HASH') {
+ $problems{$symb.$part}{$HWVAL}{$input_id} = $value;
+ } else {
+ my $prevval = $problems{$symb.$part}{$HWVAL};
+ my $previd = $problems{$symb.$part}{'inputid'};
+ delete($problems{$symb.$part}{'inputid'});
+ $problems{$symb.$part}{$HWVAL} = {
+ $previd => $prevval,
+ $input_id => $value,
+ };
+ }
+ } else {
+ $problems{$symb.$part}{$HWVAL} = $value;
+ }
} else {
- $problems{$symb.$part} = { 'resource' => $resource,
+ $problems{$symb.$part} = { 'resource' => $resource,
'symb' => $symb,
'submitted' => $part,
$submit => 'Answer',
$HWVAL => $value};
+ if ($type eq 'textresponse') {
+ $problems{$symb.$part}{'inputid'} = $input_id;
+ }
}
+ $hwvals{$symb.$part}{$HWVAL} = 1;
} else {
$debug .= 'found: -> '.$entry;
next;
@@ -314,6 +345,24 @@
foreach my $key (sort(keys(%problems))) {
my %problem = %{$problems{$key}};
+ if (ref($hwvals{$key}) eq 'HASH') {
+ foreach my $hwval (keys(%{$hwvals{$key}})) {
+ if (ref($problem{$hwval}) eq 'HASH') {
+ my %valhash = %{$problem{$hwval}};
+ my %ordered;
+ foreach my $innerkey (keys(%valhash)) {
+ my $tail = (split(/_/,$innerkey))[-1];
+ $ordered{$tail} = $problem{$hwval}{$innerkey};
+ }
+ if (keys(%ordered)) {
+ $problem{$hwval} = [];
+ foreach my $digit (sort( { $a <=> $b } keys(%ordered))) {
+ push(@{$problem{$hwval}},$ordered{$digit});
+ }
+ }
+ }
+ }
+ }
my ($problemname, $grade) = &grade_problem(%problem);
$result .= &Apache::loncommon::start_data_table_row();
@@ -370,11 +419,22 @@
}
}
+ if (keys(%mismatchuser)) {
+ $result .= '<div class="LC_warning">'
+ .&mt('Your uploaded PDF form contained the following resource(s) for a user who is not you:')
+ .'<ul>'."\n";
+ foreach my $symb (keys(%mismatchuser)) {
+ my ($map,$id,$resource)=&Apache::lonnet::decode_symb($symb);
+ $result .= '<li>'.$resource.'</li>';
+ }
+ $result .= '</ul>';
+ }
+
return $result;
}
sub grade_problem {
- my %problem = @_;
+ my (%problem) = @_;
my ($title, $part) = ();
&Apache::loncommon::ssi_with_retries('/res/'.$problem{'resource'}, 5, %problem);
@@ -390,7 +450,7 @@
my %problemhash = &Apache::lonnet::restore($problem{'symb'});
my $grade = $problemhash{"resource.$part.award"};
- return ($title, $grade);
+ return ($title, $grade);
}
sub parse_grade_answer {
Index: loncom/xml/lonxml.pm
diff -u loncom/xml/lonxml.pm:1.578 loncom/xml/lonxml.pm:1.579
--- loncom/xml/lonxml.pm:1.578 Mon Dec 22 20:50:26 2025
+++ loncom/xml/lonxml.pm Sat Feb 21 16:03:58 2026
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# XML Parser Module
#
-# $Id: lonxml.pm,v 1.578 2025/12/22 20:50:26 raeburn Exp $
+# $Id: lonxml.pm,v 1.579 2026/02/21 16:03:58 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -75,6 +75,8 @@
use POSIX qw(strftime);
use Time::HiRes qw( gettimeofday tv_interval );
use Symbol();
+use Encode();
+use Digest::SHA();
sub register {
my ($space, at taglist) = @_;
@@ -2602,6 +2604,19 @@
return $result;
}
+sub get_user_digest {
+ my ($uname,$udom,$digest_user);
+ if (($env{'form.grade_username'} ne '') && ($env{'form.grade_domain'} ne '')) {
+ $uname = $env{'form.grade_username'};
+ $udom = $env{'form.grade_domain'};
+ } else {
+ $uname = $env{'user.name'};
+ $udom = $env{'user.domain'};
+ }
+ my $digest = &Digest::SHA::sha1_hex(&Encode::decode('UTF-8',$uname.':'.$udom));
+ return $digest;
+}
+
1;
__END__
More information about the LON-CAPA-cvs
mailing list