--- loncom/publisher/testbankimport.pm 2004/04/23 22:42:05 1.4 +++ loncom/publisher/testbankimport.pm 2008/06/05 01:24:59 1.14 @@ -1,5 +1,5 @@ # Handler for parsing text upload problem descriptions into .problems -# $Id: testbankimport.pm,v 1.4 2004/04/23 22:42:05 raeburn Exp $ +# $Id: testbankimport.pm,v 1.14 2008/06/05 01:24:59 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -30,18 +30,18 @@ use strict; use Apache::Constants qw(:common :http :methods); use Apache::loncacc; use Apache::loncommon(); -use Apache::Log(); use Apache::lonnet; use HTML::Entities(); use Apache::lonlocal; use Apache::lonupload; use File::Basename(); +use LONCAPA(); # ---------------------------------------------------------------- Display Control sub display_control { # figure out what page we're on and where we're heading. - my $page = $ENV{'form.page'}; - my $command = $ENV{'form.go'}; + my $page = $env{'form.page'}; + my $command = $env{'form.go'}; my $current_page = &calculate_page($page,$command); return $current_page; } @@ -86,13 +86,13 @@ function setElements() { var iter = 0 var selParam = 0 END_SCRIPT - if (exists($ENV{'form.blocks'}) ) { + if (exists($env{'form.blocks'}) ) { $$jsref .= qq| - document.forms.display.blocks.value = $ENV{'form.blocks'}\n|; - } elsif (exists($ENV{'form.qnumformat'}) ) { + document.forms.display.blocks.value = $env{'form.blocks'}\n|; + } elsif (exists($env{'form.qnumformat'}) ) { $$jsref .= <<"TO_HERE"; for (iter=0; iter "0", + 'leftmargin' => "0", + 'marginwidth' => "0", + 'topmargin' => "0", + 'marginheight' => "0"); + + my $start_page = + &Apache::loncommon::start_page('Create Testbank directory',undef, + {'only_body' => 1, + 'add_entries' => \%body_layout, + 'js_ready' => 1,}); + my $end_page = + &Apache::loncommon::end_page({'js_ready' => 1,}); $$jsref = <<"END_OF_ONE"; function verify() { if ((document.forms.dataForm.newdir.value == '') || (!document.forms.dataForm.newdir.value)) { @@ -363,22 +386,22 @@ function createWin() { document.dataForm.newdir.value = ""; newWindow = window.open("","CreateDir","HEIGHT=400,WIDTH=750,scrollbars=yes") newWindow.document.open() - newWindow.document.write("Create Testbank directory\\n") - newWindow.document.write("\\n") + newWindow.document.write('$start_page') newWindow.document.write("[Author Header]\\n") newWindow.document.write("\\n") newWindow.document.write("\\n") newWindow.document.write("\\n") newWindow.document.write("\\n") newWindow.document.write("\\n") - newWindow.document.write("
  

Location: $fullpath

New Directory

  
\\n") - newWindow.document.write("Enter the name of the new directory where you will store the converted testbank questions

") + newWindow.document.write("Enter the name of the new directory where you will save the converted testbank questions

") newWindow.document.write("") newWindow.document.write("") newWindow.document.write("") newWindow.document.write("$fullpath") newWindow.document.write("") newWindow.document.write("
") + newWindow.document.write("") + newWindow.document.write('$end_page') newWindow.document.close() newWindow.focus() } @@ -389,10 +412,10 @@ function setElements() { var iter = 0 var selParam = 0 |; - foreach my $item (keys %ENV) { + foreach my $item (keys %env) { if ($item =~ m/^form\.(\w+)$/) { my $name = $1; - my $value = $ENV{"form.$name"}; + my $value = $env{"form.$name"}; unless ($value eq "") { if ($name eq "newdir") { $$jsref .= qq( document.forms.dataForm.$name.value = "$value"\n); @@ -433,8 +456,8 @@ The Testbank Upload utility can b
  • All questions (including question text and all foils) must occur before any of the answers. Each question should begin on a new line, and should start with the question number. Questions should be numbered sequentially using a number followed immediately by a space, a period, or enclosed in parentheses, i.e., 1 , 1., (1), 1), or (1 .
  • Multiple choice and multiple answer correct questions should consist of: (i) the question number followed by (ii) the question text beginning on the same line and (iii) two or more foils, with each foil beginning on a new line and prefixed by a unique letter, or Roman numeral, listed in alphabetic or numeric order, beginning at a (alphabetic) or i (Roman numeral), followed by a period, or enclosed in parentheses, i.e., a., (a), i., or (i).
  • One or more correct answers should be provided for all questions (although blank answers may be provided for essay questions). Answers should be numbered sequentially, using the same scheme as used for the questions, and must occur after all the questions. -
  • If fill-in-the-blank or multiple answer questions have more than one correct answer, each answer should appear in a comma-, tab-, space-, or new line-delimited list. For a ranking/ordering question, the "answer" should contain the foil identifiers correctly ordered in a similarly delimited list.
  • - +
  • If fill-in-the-blank or multiple answer questions have more than one correct answer, each answer should appear in a comma-, tab-, space-, or new line-delimited list. For a ranking/ordering question, the "answer" should contain the foil identifiers correctly ordered in a similarly delimited list. If two or more foils have the same ranking, they should occur together, with an equals sign separating equally ranked foils [e.g., (b),(e)=(a),(d),(c)].
  • + Five steps are involved in the import process.
    1. Upload your text file to the server.|); @@ -447,7 +470,7 @@ Five steps are involved in the import pr $r->print(qq|
    2. Provide information about the question format - i.e., question numbering style, and the number of blocks of questions of each question type.
    3. Provide information about the questions in each block, including question type, start and end question numbers for each block, and foil labelling style and answer format where required.
    4. -
    5. Create a new directory where you will store the converted testbank questions.
    6. +
    7. Create a new directory where you will save the converted testbank questions.
    8. Complete the import of questions to the selected pool.
    @@ -645,8 +668,8 @@ Please indicate the number of blocks of sub display_two { my ($r,$uname,$fn,$page,$textref,$qcount) = @_; - my $blocks = $ENV{'form.blocks'}; - my $qnumformat = $ENV{'form.qnumformat'}; + my $blocks = $env{'form.blocks'}; + my $qnumformat = $env{'form.qnumformat'}; my @types = ("MC","MA","TF","Ess","FIB","Ord"); my %typenames = ( MC => "Multiple Choice", @@ -858,10 +881,10 @@ END_OF_FUNC # ---------------------------------------------------------------- Display Three sub display_three { my ($r,$uname,$fn,$page,$textref,$qcount) = @_; - my $qnumformat = $ENV{'form.qnumformat'}; - my $filename = $ENV{'form.filename'}; - my $source = $ENV{'form.go'}; - my $blocks = $ENV{'form.blocks'}; + my $qnumformat = $env{'form.qnumformat'}; + my $filename = $env{'form.filename'}; + my $source = $env{'form.go'}; + my $blocks = $env{'form.blocks'}; my @items = (); my @bgcolors = ('#ffffff','#eeeeee'); my @types = ("MC","MA","TF","Ess","FIB","Ord"); @@ -876,18 +899,18 @@ sub display_three { my %multparts = (); my $numitems = 0; for (my $i=0; $i<$blocks; $i++) { - if (($ENV{"form.start_$i"} ne '') && ($ENV{"form.end_$i"} ne '')) { - $start[$i] = $ENV{"form.start_$i"}; - $end[$i] = $ENV{"form.end_$i"}; + if (($env{"form.start_$i"} ne '') && ($env{"form.end_$i"} ne '')) { + $start[$i] = $env{"form.start_$i"}; + $end[$i] = $env{"form.end_$i"}; $nums[$i] = $end[$i]-$start[$i] +1; - $qtype[$i] = $ENV{"form.qtype_$i"}; + $qtype[$i] = $env{"form.qtype_$i"}; if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) { - $foilformats[$i] = $ENV{"form.foilformat_$i"}; + $foilformats[$i] = $env{"form.foilformat_$i"}; } else { $foilformats[$i] = ''; } if (($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "TF") || ($qtype[$i] eq "Ord")) { - $ansrtypes[$i] = $ENV{"form.ansr_$i"}; + $ansrtypes[$i] = $env{"form.ansr_$i"}; } else { $ansrtypes[$i] = ''; } @@ -950,17 +973,31 @@ END_OF_ONE $foiltag = $alphabet[$k-1].'.'; } elsif ($foilformats[$i] eq "lcparen") { $foiltag = '('.$alphabet[$k-1].')'; + } elsif ($foilformats[$i] eq "lconeparen") { + $foiltag = $alphabet[$k-1].')'; + } elsif ($foilformats[$i] eq "lcdotparen") { + $foiltag = $alphabet[$k-1].'.)'; } elsif ($foilformats[$i] eq "ucperiod") { $foiltag = $alphabet[$k-1].'.'; $foiltag =~ tr/a-z/A-Z/; } elsif ($foilformats[$i] eq "ucparen") { $foiltag = '('.$alphabet[$k-1].')'; $foiltag =~ tr/a-z/A-Z/; + } elsif ($foilformats[$i] eq "uconeparen") { + $foiltag = $alphabet[$k-1].')'; + $foiltag =~ tr/a-z/A-Z/; + } elsif ($foilformats[$i] eq "ucdotparen") { + $foiltag = $alphabet[$k-1].'.)'; + $foiltag =~ tr/a-z/A-Z/; } elsif ($foilformats[$i] eq "romperiod") { $foiltag = $romans[$k-1].'.'; } elsif ($foilformats[$i] eq "romparen") { $foiltag = '('.$romans[$k-1].')'; - } + } elsif ($foilformats[$i] eq "romoneparen") { + $foiltag = $romans[$k-1].')'; + } elsif ($foilformats[$i] eq "romdotparen") { + $foiltag = $romans[$k-1].'.)'; + } $r->print(qq|$foiltag $multparts{$j}[$k]
    \n|); } } @@ -993,7 +1030,7 @@ END_OF_ONE    - Create a directory to store your testbank questions. + Create a directory to save your testbank questions. @@ -1003,7 +1040,7 @@ END_OF_ONE   -Please choose a destination LON-CAPA directory in which to store your uploaded questions.   +Please choose a destination LON-CAPA directory in which to save your uploaded questions.   @@ -1071,9 +1108,9 @@ Please choose a destination LON-CAPA dir # ---------------------------------------------------------------- Final Display sub final_display { my ($r,$uname,$fn,$page,$textref) = @_; - my $qnumformat = $ENV{'form.qnumformat'}; - my $blocks = $ENV{'form.blocks'}; - my $newdir = $ENV{'form.newdir'}; + my $qnumformat = $env{'form.qnumformat'}; + my $blocks = $env{'form.blocks'}; + my $newdir = $env{'form.newdir'}; my $linkdir = $newdir; if ($linkdir =~ m#^/home/$uname/public_html/(.+)$#) { $linkdir = '/priv/'.$uname.'/'.$1; @@ -1090,21 +1127,21 @@ sub final_display { my %multparts = (); my $numitems = 0; for (my $i=0; $i<$blocks; $i++) { - $start[$i] = $ENV{"form.start_$i"}; - $end[$i] = $ENV{"form.end_$i"}; + $start[$i] = $env{"form.start_$i"}; + $end[$i] = $env{"form.end_$i"}; if (($end[$i] - $start[$i]) >= 0) { $nums[$i] = $end[$i] - $start[$i]+1; } else { $nums[$i] = 0; } - $qtype[$i] = $ENV{"form.qtype_$i"}; + $qtype[$i] = $env{"form.qtype_$i"}; if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) { - $foilformats[$i] = $ENV{"form.foilformat_$i"}; + $foilformats[$i] = $env{"form.foilformat_$i"}; } else { $foilformats[$i] = ''; } if (($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "TF") || ($qtype[$i] eq "Ord")) { - $ansrtypes[$i] = $ENV{"form.ansr_$i"}; + $ansrtypes[$i] = $env{"form.ansr_$i"}; } $numitems += $nums[$i]; } @@ -1132,14 +1169,14 @@ sub final_display { if ($qtype[$i] eq "MC") { $items[$k] =~ tr/A-Z/a-z/; $items[$k] =~ s/\W//g; - if ($foilformats[$i] eq "lcperiod" || $foilformats[$i] eq "lcparen" || $foilformats[$i] eq "ucparen" || $foilformats[$i] eq "ucperiod") { + if ($foilformats[$i] eq "lcperiod" || $foilformats[$i] eq "lcparen" || $foilformats[$i] eq "lconeparen" || $foilformats[$i] eq "lcdotparen" || $foilformats[$i] eq "ucparen" || $foilformats[$i] eq "ucperiod" || $foilformats[$i] eq "uconeparen" || $foilformats[$i] eq "ucdotparen") { for (my $j=0; $j<@alphabet; $j++) { if ($alphabet[$j] eq $items[$k]) { push @{$answers{$k}}, $j; last; } } - } elsif (($foilformats[$i] eq "romparen") || ($foilformats[$i] eq "romperiod")) { + } elsif (($foilformats[$i] eq "romparen") || ($foilformats[$i] eq "romperiod") || ($foilformats[$i] eq "romoneparen") || ($foilformats[$i] eq "romdotparen")) { for (my $j=0; $j<@romans; $j++) { if ($romans[$j] eq $items[$k]) { push @{$answers{$k}}, $j; @@ -1151,19 +1188,58 @@ sub final_display { $items[$k] =~ tr/A-Z/a-z/; my @corrects = split/$patterns{$ansrtypes[$i]}/,$items[$k]; foreach my $correct (@corrects) { - $correct =~s/\W//g; + my @tied; + if ($qtype[$i] eq "Ord") { + if ($correct =~ /=/) { + @tied = split(/=/,$correct); + for (my $j=0; $j<@tied; $j++) { + $tied[$j] =~ s/\W//g; + } + } else { + $correct =~s/\W//g; + } + } else { + $correct =~s/\W//g; + } if ($foilformats[$i] eq "lcperiod" || $foilformats[$i] eq "lcparen" || $foilformats[$i] eq "ucparen" || $foilformats[$i] eq "ucperiod") { - for (my $j=0; $j<@alphabet; $j++) { - if ($alphabet[$j] eq $correct) { - push @{$answers{$k}}, $j; - last; + if (($qtype[$i] eq "Ord") && (@tied > 0)) { + my @ties; + foreach my $tie (@tied) { + for (my $j=0; $j<@alphabet; $j++) { + if ($alphabet[$j] eq $tie) { + push(@ties,$j); + last; + } + } + } + my $ans = join('=',@ties); + push(@{$answers{$k}},$ans); + } else { + for (my $j=0; $j<@alphabet; $j++) { + if ($alphabet[$j] eq $correct) { + push @{$answers{$k}}, $j; + last; + } } } - } elsif (($foilformats[$i] eq "romparen") || ($foilformats[$i] eq "romperiod")) { - for (my $j=0; $j<@romans; $j++) { - if ($romans[$j] eq $correct) { - push @{$answers{$k}}, $j; - last; + } elsif (($foilformats[$i] eq "romparen") || ($foilformats[$i] eq "romperiod") || ($foilformats[$i] eq "romoneparen") || ($foilformats[$i] eq "romdotparen")) { + if (($qtype[$i] eq "Ord") && (@tied > 0)) { + my @ties; + foreach my $tie (@tied) { + for (my $j=0; $j<@romans; $j++) { + if ($romans[$j] eq $tie) { + push(@ties,$j); + last; + } + } + } + push(@{$answers{$k}},join('=',@ties)); + } else { + for (my $j=0; $j<@romans; $j++) { + if ($romans[$j] eq $correct) { + push @{$answers{$k}}, $j; + last; + } } } } @@ -1318,8 +1394,6 @@ END_OF_BLOCK - - END_OF_FAIL return; } @@ -1410,32 +1484,42 @@ sub file_split { } elsif ($qnumformat eq "trailparen") { $qpattern = '\d{1'.$numpat.'\)'; } - my @questions = split/[\r\n\f]+\s?$qpattern\s?/,$text_in; + my @questions = split/[\r\n\f]+\s*$qpattern\s*/,$text_in; # my @questions = split/\n\s\d{1,3}\.\s/,$text_in; shift @questions; my %multparts = (); for (my $i=0; $i<$blocks; $i++) { if (${$numsref}[$i] > 0) { - if ((${$qtyperef}[$i] eq "MC") || (${$qtyperef}[$i] eq "MA")) { + if ((${$qtyperef}[$i] eq "MC") || (${$qtyperef}[$i] eq "MA") || (${$qtyperef}[$i] eq "Ord")) { my $splitstr = ''; if (${$foilsref}[$i] eq "lcperiod") { $splitstr = '[a-z]\.'; } elsif (${$foilsref}[$i] eq "lcparen") { $splitstr = '\([a-z]\)'; + } elsif (${$foilsref}[$i] eq "lconeparen") { + $splitstr = '[a-z]\)'; + } elsif (${$foilsref}[$i] eq "lcdotparen") { + $splitstr = '[a-z]\.\)'; } elsif (${$foilsref}[$i] eq "ucperiod") { $splitstr = '[A-Z]\.'; } elsif (${$foilsref}[$i] eq "ucparen") { $splitstr = '\([A-Z]\)'; + } elsif (${$foilsref}[$i] eq "uconeparen") { + $splitstr = '[A-Z]\)'; + } elsif (${$foilsref}[$i] eq "ucdotparen") { + $splitstr = '[A-Z]\.\)'; } elsif (${$foilsref}[$i] eq "romperiod") { $splitstr = '[ivx]+\.'; } elsif (${$foilsref}[$i] eq "romparen") { $splitstr = '\([ivx]+\)'; + } elsif (${$foilsref}[$i] eq "romoneparen") { + $splitstr = '[ivx]+\)'; + } elsif (${$foilsref}[$i] eq "romdotparen") { + $splitstr = '[ivx]+\.\)'; } for (my $j=${$startsref}[$i]-1; $j<${$endsref}[$i]; $j++) { - @{$multparts{$j}} = split/[\r\n\f]+\s?$splitstr\s?/,$questions[$j]; + @{$multparts{$j}} = split/[\r\n\f]+\s*$splitstr\s*/,$questions[$j]; chomp(@{$multparts{$j}}); - foreach my $foil (@{$multparts{$j}}) { - } } } elsif (${$qtyperef}[$i] eq "FIB") { for (my $j=${$startsref}[$i]-1; $j<${$endsref}[$i]; $j++) { @@ -1523,7 +1607,26 @@ sub create_mcq { |; for (my $k=0; $k<@{$qstnref}-1; $k++) { - $output .= " ".${$qstnref}[$k+1]."\n"; + my $ansval; + my $num = 0; + for (my $i=0; $i<@{$answerref}; $i++) { + if ($$answerref[$i] =~ /=/) { + my @tied = split(/=/,$$answerref[$i]); + foreach my $tie (@tied) { + if ($k == $tie) { + $ansval = $num + 1; + last; + } + } + $num += scalar(@tied); + } elsif ($k == $$answerref[$i]) { + $ansval = $num + 1; + last; + } else { + $num ++; + } + } + $output .= " ".${$qstnref}[$k+1]."\n"; } chomp($output); $output .= qq| @@ -1621,7 +1724,9 @@ sub create_ess { + $answertxt + |; } elsif ($qtype eq "TF") { @@ -1667,21 +1772,20 @@ sub handler { my $javascript = ''; my $page_name = ''; my $current_page = ''; - my $loadentries = ''; my $qcount = ''; # # phase two: re-attach user # - if ($ENV{'form.uploaduname'}) { - $ENV{'form.filename'}='/priv/'.$ENV{'form.uploaduname'}.'/'. - $ENV{'form.filename'}; + if ($env{'form.uploaduname'}) { + $env{'form.filename'}='/priv/'.$env{'form.uploaduname'}.'/'. + $env{'form.filename'}; } ($uname,$udom)= - &Apache::loncacc::constructaccess($ENV{'form.filename'}, + &Apache::loncacc::constructaccess($env{'form.filename'}, $r->dir_config('lonDefDomain')); unless (($uname) && ($udom)) { $r->log_reason($uname.' at '.$udom. - ' trying to publish file '.$ENV{'form.filename'}. + ' trying to publish file '.$env{'form.filename'}. ' - not authorized', $r->filename); return HTTP_NOT_ACCEPTABLE; @@ -1689,14 +1793,14 @@ sub handler { my $fn; my $badfile = 0; - if ($ENV{'form.filename'}) { - $fn=$ENV{'form.filename'}; + if ($env{'form.filename'}) { + $fn=$env{'form.filename'}; $fn=~s/^http\:\/\/[^\/]+\///; $fn=~s/^\///; - $fn=~s/(\~|priv\/)(\w+)//; + $fn=~s{(~|priv/)($LONCAPA::username_re)}{}; $fn=~s/\/+/\//g; } else { - $r->log_reason($ENV{'user.name'}.' at '.$ENV{'user.domain'}. + $r->log_reason($env{'user.name'}.' at '.$env{'user.domain'}. ' unspecified filename for upload', $r->filename); return HTTP_NOT_FOUND; } @@ -1709,8 +1813,7 @@ sub handler { my $dirpath = '/home/'.$uname.'/public_html'; my @text = (); - my $loadentries = ''; - if ($ENV{'form.phase'} eq 'three') { + if ($env{'form.phase'} eq 'three') { if (-e "$dirpath$fn") { open(TESTBANK,"<$dirpath$fn"); @text = ; @@ -1724,37 +1827,41 @@ sub handler { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; - if ($ENV{'form.phase'} eq 'three') { + my %loadentries; + if ($env{'form.phase'} eq 'three') { $current_page = &display_control(); my @PAGES = ('Welcome','Blocks','Format','Target','Confirmation'); $page_name = $PAGES[$current_page]; if ($page_name eq 'Blocks') { - $loadentries = 'onLoad= "setElements()"'; + $loadentries{'onload'} = "setElements()"; &jscript_one(\$javascript); } elsif ($page_name eq 'Format') { - $qcount = question_count($ENV{'form.qnumformat'},\@text); + $qcount = question_count($env{'form.qnumformat'},\@text); &jscript_two(\$javascript,$qcount); } elsif ($page_name eq 'Target') { - if ($ENV{'form.go'} eq "PreviousPage") { - $loadentries = 'onLoad = "setElements()"'; + if ($env{'form.go'} eq "PreviousPage") { + $loadentries{'onload'} = "setElements()"; } &jscript_three($fullpath,\$javascript); } elsif ($page_name eq 'Confirmation') { &jscript_four(\$javascript,$fullpath); } - } + } + + $javascript = "\n"; + + $r->print(&Apache::loncommon::start_page('Upload testbank questions to Construction Space', + $javascript, + {'add_entries' => \%loadentries})); - $r->print("LON-CAPA Construction Space\n"); - - $r->print(&Apache::loncommon::bodytag('Upload testbank questions to Construction Space',undef,$loadentries)); - - if (($uname ne $ENV{'user.name'}) || ($udom ne $ENV{'user.domain'})) { + if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) { $r->print('

    '.&mt('Co-Author').': '.$uname. &mt(' at ').$udom.'

    '); } - if ($ENV{'form.phase'} eq 'three') { + if ($env{'form.phase'} eq 'three') { if ($badfile) { &file_error($r,$uname,$fn,$current_page); } else { @@ -1764,7 +1871,7 @@ sub handler { &display_three ($r,$uname,$fn,$current_page,\@text,$qcount) if $page_name eq 'Target'; &final_display ($r,$uname,$fn,$current_page,\@text) if $page_name eq 'Confirmation'; } - } elsif ($ENV{'form.phase'} eq 'two') { + } elsif ($env{'form.phase'} eq 'two') { my $flag = &Apache::lonupload::phasetwo($r,$fn,$uname,$udom,'testbank'); if ($flag eq 'ok') { my $current_page = 0; @@ -1773,7 +1880,7 @@ sub handler { } else { &Apache::lonupload::phaseone($r,$fn,$uname,$udom,'testbank'); } - $r->print(''); + $r->print(&Apache::loncommon::end_page()); return OK; } 1;