--- loncom/interface/lonparmset.pm 2014/12/12 02:12:18 1.548 +++ loncom/interface/lonparmset.pm 2015/04/28 13:12:46 1.549 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set parameters for assessments # -# $Id: lonparmset.pm,v 1.548 2014/12/12 02:12:18 raeburn Exp $ +# $Id: lonparmset.pm,v 1.549 2015/04/28 13:12:46 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -932,6 +932,162 @@ function showHide_courseContent() { COURSECONTENTSCRIPT } +sub toggleparmtextbox_js { + return <<"ENDSCRIPT"; + +if (!document.getElementsByClassName) { + function getElementsByClassName(node, classname) { + var a = []; + var re = new RegExp('(^| )'+classname+'( |$)'); + var els = node.getElementsByTagName("*"); + for(var i=0,j=els.length; i$remove'); + }); + + \$(wrapper).delegate(".LC_remove_ipacc","click", function(e){ + e.preventDefault(); \$(this).closest("div").remove(); + }) +}); + + +END +} + sub startpage { my ($r,$psymb,$crstype) = @_; @@ -2165,7 +2321,6 @@ sub assessparms { my ($got_chostname,$chostname,$cmajor,$cminor); my $totalstored = 0; my $now = time; - for (my $i=0;$i<=$#markers;$i++) { my ($needsrelease,$needsnewer,$name); if ($markers[$i] =~ /^[\d.]+\&0_availablestudent\&(1|2|3)$/) { @@ -2198,9 +2353,10 @@ sub assessparms { } } } - } elsif ($markers[$i] =~ /_(type|lenient|retrypartial|discussvote|examcode|printstartdate|printenddate)\&\d+$/) { + } elsif ($markers[$i] =~ /_(type|lenient|retrypartial|discussvote|examcode|printstartdate|printenddate|acc)\&\d+$/) { $name = $1; my $val = $values[$i]; + my $valmatch = ''; if ($name eq 'examcode') { if (&Apache::lonnet::validCODE($values[$i])) { $val = 'valid'; @@ -2217,15 +2373,32 @@ sub assessparms { $val = 'past'; } } + } elsif (($name eq 'lenient') || ($name eq 'acc')) { + my $stringtype = &get_stringtype($name); + my $stringmatch = &standard_string_matches($stringtype); + if (ref($stringmatch) eq 'ARRAY') { + foreach my $item (@{$stringmatch}) { + if (ref($item) eq 'ARRAY') { + my ($regexpname,$pattern) = @{$item}; + if ($pattern ne '') { + if ($val =~ /$pattern/) { + $valmatch = $regexpname; + $val = ''; + last; + } + } + } + } + } } $needsrelease = - $Apache::lonnet::needsrelease{"parameter:$name:$val"}; + $Apache::lonnet::needsrelease{"parameter:$name:$val:$valmatch"}; if ($needsrelease) { unless ($got_chostname) { ($chostname,$cmajor,$cminor) = ¶meter_release_vars(); $got_chostname = 1; } - $needsnewer = ¶meter_releasecheck($name,$val, + $needsnewer = ¶meter_releasecheck($name,$val,$valmatch, $needsrelease, $cmajor,$cminor); } @@ -2847,15 +3020,17 @@ sub storedata { if ($key =~ /^form\.([a-z]+)\_(.+)$/) { my $cmd=$1; my $thiskey=$2; + next if ($cmd eq 'settext' || $cmd eq 'setipallow' || $cmd eq 'setipdeny'); my ($tuname,$tudom)=&extractuser($thiskey); my $tkey=$thiskey; if ($tuname) { $tkey=~s/\.\[useropt\:$tuname\:$tudom\]\./\./; } if ($cmd eq 'set' || $cmd eq 'datepointer' || $cmd eq 'dateinterval') { - my ($data, $typeof, $text, $name, $valchk); + my ($data, $typeof, $text, $name, $valchk, $valmatch); if ($cmd eq 'set') { $data=$env{$key}; + $valmatch = ''; $valchk = $data; $typeof=$env{'form.typeof_'.$thiskey}; $text = &mt('Saved modified parameter for'); @@ -2863,6 +3038,21 @@ sub storedata { $name = 'type'; } elsif ($typeof eq 'string_lenient') { $name = 'lenient'; + my $stringmatch = &standard_string_matches($typeof); + if (ref($stringmatch) eq 'ARRAY') { + foreach my $item (@{$stringmatch}) { + if (ref($item) eq 'ARRAY') { + my ($regexpname,$pattern) = @{$item}; + if ($pattern ne '') { + if ($data =~ /$pattern/) { + $valmatch = $regexpname; + $valchk = ''; + last; + } + } + } + } + } } elsif ($typeof eq 'string_discussvote') { $name = 'discussvote'; } elsif ($typeof eq 'string_examcode') { @@ -2901,13 +3091,13 @@ sub storedata { } if ($name ne '') { my ($needsrelease,$needsnewer); - $needsrelease = $Apache::lonnet::needsrelease{"parameter:$name:$valchk"}; + $needsrelease = $Apache::lonnet::needsrelease{"parameter:$name:$valchk:$valmatch"}; if ($needsrelease) { unless ($got_chostname) { ($chostname,$cmajor,$cminor)=¶meter_release_vars(); $got_chostname = 1; } - $needsnewer = ¶meter_releasecheck($name,$valchk, + $needsnewer = ¶meter_releasecheck($name,$valchk,$valmatch, $needsrelease, $cmajor,$cminor); if ($needsnewer) { @@ -3194,6 +3384,62 @@ sub default_selector { return ''; } +sub string_ip_selector { + my ($thiskey, $showval) = @_; + my %access = ( + allow => [], + deny => [], + ); + if ($showval ne '') { + my @current; + if ($showval =~ /,/) { + @current = split(/,/,$showval); + } else { + @current = ($showval); + } + foreach my $item (@current) { + if ($item =~ /^\!([\[\]a-zA-Z\.\d\*\-]+)$/) { + push(@{$access{'deny'}},$1); + } elsif ($item =~ /^([\[\]a-zA-Z\.\d\*\-]+)$/) { + push(@{$access{'allow'}},$item); + } + } + } + if (!@{$access{'allow'}}) { + @{$access{'allow'}} = (''); + } + if (!@{$access{'deny'}}) { + @{$access{'deny'}} = (''); + } + my $output = ' +'; + foreach my $acctype ('allow','deny') { + $output .= ' +'; + } + $output .= ' + +
'.&mt('Allow from').''.&mt('Deny from').'
+
+
'."\n"; + my $num = 0; + foreach my $curr (@{$access{$acctype}}) { + $output .= '
'; + if ($num > 0) { + $output .= ''.&mt('Remove').''; + } + $output .= '
'."\n"; + $num ++; + } + $output .= ' +
+ +
+
'."\n"; + return $output; +} + +{ my %strings = ( 'string_yesno' @@ -3216,13 +3462,34 @@ my %strings = 'string_lenient' => [['yes', 'Yes' ], [ 'no', 'No' ], - [ 'default', 'Default - only bubblesheet grading is lenient' ]], + [ 'default', 'Default - only bubblesheet grading is lenient' ], + [ 'weighted', 'Yes, weighted (optionresponse in checkbox mode)' ]], 'string_discussvote' => [['yes','Yes'], ['notended','Yes, unless discussion ended'], ['no','No']], + 'string_ip' + => [['_allowfrom_','Hostname(s), or IP(s) from which access is allowed'], + ['_denyfrom_',], 'Hostname(s) or IP(s) from which access is disallowed'], ); +my %stringmatches = ( + 'string_lenient' + => [['weighted','^\-?[.\d]+,\-?[.\d]+,\-?[.\d]+,\-?[.\d]+$'],], + 'string_ip' + => [['_allowfrom_','[^\!]+'], + ['_denyfrom_','\!']], + ); + +my %stringtypes = ( + type => 'string_questiontype', + lenient => 'string_lenient', + retrypartial => 'string_yesno', + discussvote => 'string_discussvote', + examcode => 'string_examcode', + acc => 'string_ip', + ); + sub standard_string_options { my ($string_type) = @_; if (ref($strings{$string_type}) eq 'ARRAY') { @@ -3231,37 +3498,73 @@ sub standard_string_options { return; } +sub standard_string_matches { + my ($string_type) = @_; + if (ref($stringmatches{$string_type}) eq 'ARRAY') { + return $stringmatches{$string_type}; + } + return; +} + +sub get_stringtype { + my ($name) = @_; + if (exists($stringtypes{$name})) { + return $stringtypes{$name}; + } + return; +} + sub string_selector { my ($thistype, $thiskey, $showval, $name) = @_; if (!exists($strings{$thistype})) { - return &default_selector($thiskey,$showval); + return &default_selector($thiskey,$showval); } my %skiptype; if (($thistype eq 'string_questiontype') || ($thistype eq 'string_lenient') || ($thistype eq 'string_discussvote') || + ($thistype eq 'string_ip') || ($name eq 'retrypartial')) { my ($got_chostname,$chostname,$cmajor,$cminor); foreach my $possibilities (@{ $strings{$thistype} }) { next unless (ref($possibilities) eq 'ARRAY'); my ($parmval, $description) = @{ $possibilities }; - my $needsrelease=$Apache::lonnet::needsrelease{"parameter:$name:$parmval"}; + my $parmmatch; + if (ref($stringmatches{$thistype}) eq 'ARRAY') { + foreach my $item (@{$stringmatches{$thistype}}) { + if (ref($item) eq 'ARRAY') { + if ($parmval eq $item->[0]) { + $parmmatch = $parmval; + $parmval = ''; + last; + } + } + } + } + my $needsrelease=$Apache::lonnet::needsrelease{"parameter:$name:$parmval:$parmmatch"}; if ($needsrelease) { unless ($got_chostname) { ($chostname,$cmajor,$cminor)=¶meter_release_vars(); $got_chostname = 1; } - my $needsnewer=¶meter_releasecheck($name,$parmval,$needsrelease, - $cmajor,$cminor); + my $needsnewer=¶meter_releasecheck($name,$parmval,$parmmatch, + $needsrelease,$cmajor,$cminor); if ($needsnewer) { - $skiptype{$parmval} = 1; + if ($parmmatch ne '') { + $skiptype{$parmmatch} = 1; + } elsif ($parmval ne '') { + $skiptype{$parmval} = 1; + } } } } } - + + if ($thistype eq 'string_ip') { + return &string_ip_selector($thiskey,$showval); + } my $result; my $numinrow = 3; @@ -3278,7 +3581,7 @@ sub string_selector { foreach my $possibilities (@{ $strings{$thistype} }) { next unless (ref($possibilities) eq 'ARRAY'); my ($name, $description) = @{ $possibilities }; - next if ($skiptype{$name}); + next if ($skiptype{$name}); $rem = $i%($numinrow); if ($rem == 0) { if ($i > 0) { @@ -3286,24 +3589,66 @@ sub string_selector { } $result .= ''; } - $result .= ''. + my $colspan; + if ($i == @{ $strings{$thistype} }-1) { + $rem = @{ $strings{$thistype} }%($numinrow); + if ($rem) { + my $colsleft = $numinrow - $rem; + if ($colsleft) { + $colspan = $colsleft+1; + $colspan = ' colspan="'.$colspan.'"'; + } + } + } + my ($add,$onchange,$css_class); + if ($thistype eq 'string_lenient') { + if ($name eq 'weighted') { + my $display; + my %relatives = &Apache::lonlocal::texthash( + corrchkd => 'Correct (checked)', + corrunchkd => 'Correct (unchecked)', + incorrchkd => 'Incorrect (checked)', + incorrunchkd => 'Incorrect (unchecked)', + ); + my %textval = ( + corrchkd => '1.0', + corrunchkd => '1.0', + incorrchkd => '0.0', + incorrunchkd => '0.0', + ); + if ($showval =~ /^([\-\d\.]+)\,([\-\d\.]+)\,([\-\d\.]+)\,([\-\d\.]+)$/) { + $textval{'corrchkd'} = $1; + $textval{'corrunchkd'} = $2; + $textval{'incorrchkd'} = $3; + $textval{'incorrunchkd'} = $4; + $display = 'inline'; + $showval = $name; + } else { + $display = 'none'; + } + $add = '
'. + ''; + foreach my $reltype ('corrchkd','corrunchkd','incorrchkd','incorrunchkd') { + $add .= ''."\n". + ''; + } + $add .= '
'.&mt("Foil's submission status").''.&mt('Points').'
 '.$relatives{$reltype}.''. + '
'."\n"; + } + $onchange = ' onclick="javascript:toggleParmTextbox(this.form,'."'$thiskey'".');"'; + $css_class = ' class="LC_lenient_radio"'; + } + $result .= ''. ''; + $result .= ' />'.&mt($description).''.$add.''; $i++; } - $rem = @{ $strings{$thistype} }%($numinrow); - my $colsleft = $numinrow - $rem; - if ($colsleft > 1 ) { - $result .= ''. - ' '; - } elsif ($colsleft == 1) { - $result .= ' '; - } $result .= ''; } if ($result) { @@ -3312,6 +3657,64 @@ sub string_selector { return $result; } +sub oldversion_warning { + my ($name,$value,$chostname,$cmajor,$cminor,$needsrelease) = @_; + my $desc; + my $stringtype = &get_stringtype($name); + if ($stringtype ne '') { + if ($name eq 'examcode') { + $desc = $value; + } elsif (ref($strings{$stringtypes{$name}}) eq 'ARRAY') { + foreach my $possibilities (@{ $strings{$stringtypes{$name}} }) { + next unless (ref($possibilities) eq 'ARRAY'); + my ($parmval, $description) = @{ $possibilities }; + my $parmmatch; + if (ref($stringmatches{$stringtypes{$name}}) eq 'ARRAY') { + foreach my $item (@{$stringmatches{$stringtypes{$name}}}) { + if (ref($item) eq 'ARRAY') { + my ($regexpname,$pattern) = @{$item}; + if ($parmval eq $regexpname) { + if ($value =~ /$pattern/) { + $desc = $description; + $parmmatch = 1; + last; + } + } + } + } + last if ($parmmatch); + } elsif ($parmval eq $value) { + $desc = $description; + last; + } + } + } + } elsif (($name eq 'printstartdate') || ($name eq 'printenddate')) { + my $now = time; + if ($value =~ /^\d+$/) { + if ($name eq 'printstartdate') { + if ($value > $now) { + $desc = &Apache::lonlocal::locallocaltime($value); + } + } elsif ($name eq 'printenddate') { + if ($value < $now) { + $desc = &Apache::lonlocal::locallocaltime($value); + } + } + } + } + my $standard_name = &standard_parameter_names($name); + return '

'. + &mt('[_1] was [_2]not[_3] set to [_4].', + $standard_name,'','','"'.$desc.'"').'
'. + &mt('LON-CAPA version ([_1]) installed on home server ([_2]) does not meet version requirements ([_3] or newer).', + $cmajor.'.'.$cminor,$chostname, + $needsrelease). + '

'; +} + +} + # # Shift all start and end dates by $shift # @@ -3357,7 +3760,7 @@ sub newoverview { text=>"Overview Mode"}); my %loaditems = ( - 'onload' => "showHide_courseContent(); resize_scrollbox('mapmenuscroll','1','1');", + 'onload' => "showHide_courseContent(); resize_scrollbox('mapmenuscroll','1','1'); showHideLenient();", ); my $js = ' '; + +#FIXME need onload my $start_page = &Apache::loncommon::start_page('Set Parameters',$js, {'add_entries' => \%loaditems,}); my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Overview'); $r->print($start_page.$breadcrumbs); &startSettingsScreen($r,'parmset',$crstype); $r->print(< +
ENDOVER my @ids=(); my %typep=(); @@ -3495,6 +3903,7 @@ ENDOVER &listdata($r,$resourcedata,$listdata,$sortorder); } +#FIXME $r->print(&tableend(). ((($env{'form.store'}) || ($env{'form.dis'}))?'

':''). '
'); @@ -3542,14 +3951,24 @@ sub overview { my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'}; - + my $js = ''."\n"; &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/parmset?action=setoverview', text=>"Overview Mode"}); - my $start_page=&Apache::loncommon::start_page('Modify Parameters'); + my %loaditems = ( + 'onload' => "showHideLenient();", + ); + + my $start_page=&Apache::loncommon::start_page('Modify Parameters',$js,{'add_entries' => \%loaditems,}); my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Overview'); $r->print($start_page.$breadcrumbs); &startSettingsScreen($r,'parmset',$crstype); - $r->print('
'); + $r->print(''); # Store modified @@ -3567,7 +3986,7 @@ sub overview { # List data my $foundkeys=&listdata($r,$resourcedata,$resourcedata,$sortorder); - +#FIXME $r->print(&tableend().'

'. ($foundkeys?'':''.&mt('There are no parameters.').'').'

'. &Apache::loncommon::end_page()); @@ -4722,65 +5141,20 @@ sub parameter_release_vars { } sub parameter_releasecheck { - my ($name,$value,$needsrelease,$cmajor,$cminor) = @_; + my ($name,$value,$valmatch,$needsrelease,$cmajor,$cminor) = @_; my $needsnewer; my ($needsmajor,$needsminor) = split(/\./,$needsrelease); if (($cmajor < $needsmajor) || ($cmajor == $needsmajor && $cminor < $needsminor)) { $needsnewer = 1; - } else { - &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter:'.$name.':'.$value}); + } elsif ($valmatch) { + &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter:'.$name.'::'.$valmatch}); + } elsif ($value) { + &Apache::lonnet::update_released_required($Apache::lonnet::needsrelease{'parameter:'.$name.':'.$value.':'}); } return $needsnewer; } -sub oldversion_warning { - my ($name,$value,$chostname,$cmajor,$cminor,$needsrelease) = @_; - my $desc; - my %stringtypes = ( - type => 'string_questiontype', - lenient => 'string_lenient', - retrypartial => 'string_yesno', - discussvote => 'string_discussvote', - examcode => 'string_examcode', - ); - if (exists($stringtypes{$name})) { - if ($name eq 'examcode') { - $desc = $value; - } elsif (ref($strings{$stringtypes{$name}}) eq 'ARRAY') { - foreach my $possibilities (@{ $strings{$stringtypes{$name}} }) { - next unless (ref($possibilities) eq 'ARRAY'); - my ($parmval, $description) = @{ $possibilities }; - if ($parmval eq $value) { - $desc = $description; - last; - } - } - } - } elsif (($name eq 'printstartdate') || ($name eq 'printenddate')) { - my $now = time; - if ($value =~ /^\d+$/) { - if ($name eq 'printstartdate') { - if ($value > $now) { - $desc = &Apache::lonlocal::locallocaltime($value); - } - } elsif ($name eq 'printenddate') { - if ($value < $now) { - $desc = &Apache::lonlocal::locallocaltime($value); - } - } - } - } - my $standard_name = &standard_parameter_names($name); - return '

'. - &mt('[_1] was [_2]not[_3] set to [_4].', - $standard_name,'','','"'.$desc.'"').'
'. - &mt('LON-CAPA version ([_1]) installed on home server ([_2]) does not meet version requirements ([_3] or newer).', - $cmajor.'.'.$cminor,$chostname, - $needsrelease). - '

'; -} - sub handler { my $r=shift;