[LON-CAPA-cvs] cvs: loncom /interface lonwhatsnew.pm

raeburn lon-capa-cvs@mail.lon-capa.org
Mon, 23 May 2005 23:06:28 -0000


This is a MIME encoded message

--raeburn1116889588
Content-Type: text/plain

raeburn		Mon May 23 19:06:28 2005 EDT

  Modified files:              
    /loncom/interface	lonwhatsnew.pm 
  Log:
  Fixes to display of problems with errors.  Ability to set a threshold for av attempts, deg diff, number of submissions.  Ability to reset aggregate counters for tries, degdiff, users on a part-by-part basis.
  
  
--raeburn1116889588
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20050523190628.txt"

Index: loncom/interface/lonwhatsnew.pm
diff -u loncom/interface/lonwhatsnew.pm:1.12 loncom/interface/lonwhatsnew.pm:1.13
--- loncom/interface/lonwhatsnew.pm:1.12	Fri Apr 29 10:54:18 2005
+++ loncom/interface/lonwhatsnew.pm	Mon May 23 19:06:23 2005
@@ -1,5 +1,5 @@
 #
-# $Id: lonwhatsnew.pm,v 1.12 2005/04/29 14:54:18 raeburn Exp $
+# $Id: lonwhatsnew.pm,v 1.13 2005/05/23 23:06:23 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -52,10 +52,13 @@
     }
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['command']);
 
-    my $command = $env{'form.command'};
-
-    if ($command eq '') {
-        $command = "info";
+    my $command;
+    if ($env{'form.action'} eq 'reset') {
+        $command = 'reset';
+    } elsif ($env{'form.action'} eq 'update') {
+        $command = 'update';
+    } else {
+        $command = $env{'form.command'};
     }
 
     &Apache::loncommon::content_type($r,'text/html');
@@ -68,15 +71,15 @@
     }
 
     &Apache::lonhtmlcommon::clear_breadcrumbs();
-    if ($command eq 'config') {
+    if ($command eq 'chgthreshold') {
         &Apache::lonhtmlcommon::add_breadcrumb
-            ({href=>'/adm/whatsnew?command=config',
-              text=>"Configure display"});
+            ({href=>'/adm/whatsnew?command=threshold',
+              text=>"Change thresholds"});
         $r->print(&Apache::lonhtmlcommon::breadcrumbs
-            (undef,'Course Action Items','Course_Action_Items_Config'));
+            (undef,'Course Action Items','Course_Action_Items_Thresholds'));
     } else {
         &Apache::lonhtmlcommon::add_breadcrumb
-            ({href=>'/adm/whatsnew?command=info',
+            ({href=>'/adm/whatsnew',
               text=>"Display Action Items"});
         $r->print(&Apache::lonhtmlcommon::breadcrumbs
             (undef,'Course Action Items','Course_Action_Items_Display'));
@@ -94,30 +97,17 @@
     my ($r,$command) = @_;
     my $domain=&Apache::loncommon::determinedomain();
     my $tabbg=&Apache::loncommon::designparm('coordinator.tabbg',$domain);
-    my $selconfig;
-    my $selinfo;
-    if ($command eq 'config') {
-        $selinfo = 'selected="selected"';
-    } else {
-        $selconfig = 'selected="selected"';
-    }
-    my $picker = ('
-<form>
- <nobr>
-  <input type="submit" value="'.&mt('Change page to:').'" />
-   <select name="command">
-    <option value="info" '.$selinfo.'">'.&mt('Display Action Items').'</option>
-    <option value="config" '.$selconfig.'">'.&mt('Configure Settings').'</option>
-   </select>
- </nobr>
-</form>');
-                                                                               
     $r->print('<table width="100%" border="0" cellpadding="5" cellspacing="0"><tr><td width="100%">');
-                                                                               
-    if ($command eq 'config') {
-        &display_config_box($r,$picker);
+
+    my %threshold_titles = (
+                         av_attempts => 'Average number of attempts',
+                         degdiff => 'Degree of difficulty',
+                         numstudents => 'Total number of students with submissions',
+    );
+    if ($command eq 'chgthreshold') {
+        &display_config_box($r,$command,$tabbg,\%threshold_titles);
     } else {
-        &display_actions_box($r,$picker);
+        &display_actions_box($r,$command,\%threshold_titles);
     }
     $r->print(<<END_OF_BLOCK);
   </td>
@@ -155,7 +145,7 @@
 #-------------------------------
                                                                                 
 sub display_actions_box() {
-    my ($r,$picker) = @_;
+    my ($r,$command,$threshold_titles) = @_;
 
     my $rowColor1 = "#ffffff";
     my $rowColor2 = "#eeeeee";
@@ -181,18 +171,38 @@
         $function='admin';
     }
 
+    my %threshold = (
+                      av_attempts => 0,
+                      degdiff => 0.01,
+                      numstudents => 0,
+                     );
+
     my $pgbg=&Apache::loncommon::designparm($function.'.pgbg',$domain);
     my $tabbg=&Apache::loncommon::designparm($function.'.tabbg',$domain);
 
-    &getitems(\%unread,\%ungraded,\%bombed,\%triggered,\@newdiscussions,\@tograde,\@bombs,\@warnings,$rowColor1,$rowColor2);
-    my ($msgcount,$critmsgcount) = &getmail(\@newmsgs,\@critmsgs);
-
     unless ($env{'request.course.id'}) {
         $r->print('<br /><b><center>You are accessing an invalid course</center></b><br /><br />');
         return;
     }
 
-    $r->print('<b>'.$picker.'</b><br /><hr width="100%" /><table border="0" width="100%" cellpadding="2" cellspacing="4"><tr><td align="left" valign="top" width="45%">');
+    my $result;
+    my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+    my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
+
+    if ($command eq 'reset') {
+        $result = &process_reset($cdom,$crs);
+    } elsif ($command eq 'update') {
+        $result = &process_update($cdom,$crs,$threshold_titles);
+    }
+    if ($result) {
+        $r->print($result.'<hr width="100%" />');
+    }
+
+    &get_curr_thresholds(\%threshold,$cdom,$crs);
+    &getitems(\%unread,\%ungraded,\%bombed,\%triggered,\@newdiscussions,\@tograde,\@bombs,\@warnings,$rowColor1,$rowColor2,\%threshold,$cdom,$crs);
+    my ($msgcount,$critmsgcount) = &getmail(\@newmsgs,\@critmsgs);
+
+    $r->print('<br /><table border="0" width="100%" cellpadding="2" cellspacing="4"><tr><td align="left" valign="top" width="45%">');
 
 ## UNGRADED ITEMS ##
     $r->print(<<END);
@@ -242,6 +252,7 @@
 END
      my $bombnum = 0;
      if (@bombs > 0) {
+        $r->print('<tr bgcolor="#cccccc"><td><b><small>Resource</small></b></td><td align="right"><b><small>Number of errors</small></b></td></tr>');
 #        @bombs = sort { &cmp_title($a,$b) } @bombs;
         foreach my $bomb (@bombs) {
             if ($bombnum %2 == 1) {
@@ -249,7 +260,7 @@
             } else {
                 $rowColor = $rowColor2;
             }
-            $r->print('<tr bgcolor="'.$rowColor.'"><td>'.$bombed{$bomb}{errorlink}.'</td></tr>');
+            $r->print('<tr bgcolor="'.$rowColor.'"><td><small>'.$bombed{$bomb}{errorlink}.'</small></td><td align="right"><small>'.$bombed{$bomb}{errorcount}.'</small></td></tr>');
             $bombnum ++;
         }
     } else {
@@ -258,25 +269,30 @@
     $r->print('</table></td></tr></table></td></tr></table><br />');
 
 # DEGDIFF AND AV. TRIES TRIGGERS
-     $r->print(<<"END");
+    $r->print(<<"END");
            <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%">
             <tr>
              <td>
                <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000" width="100%">
                <tr>
-                <td bgcolor="$tabbg"><b>Problems with average attempts > 0 or degree of difficulty > 0</b></td>
+                <td bgcolor="$tabbg"><b>Problems with av. attempts &ge; $threshold{'av_attempts'} or deg. difficulty &ge; $threshold{'degdiff'}<br /> and total number of students with submissions &ge; $threshold{'numstudents'}</b></td>
+               </tr>
+               <tr>
+                <td bgcolor="$tabbg" align="right"><a href="/adm/whatsnew?command=chgthreshold"><b><small>Change thresholds?</small></b></a></td>
                </tr>
                 <tr>
                 <td bgcolor="#ffffff">
                  <table width="100%" cellspacing="0" cellpadding="0" border="0">
 END
-     my $warningnum = 0;
-     if (@warnings > 0) {
+    my $warningnum = 0;
+    if (@warnings > 0) {
 #        @warnings = sort { &cmp_title($a,$b) } @warnings;
-        $r->print('<tr bgcolor="#cccccc"><td><b><small>Resource</small></b></td><td align="right"><b><small>Part</small></b><td align="right"><b><small>Num. students</small></b></td><td align="right"><b><small>Av. Attempts</small></b></td><td align="right"><b><small>Deg. Diff</small></b></td></tr>');
+        $r->print('<form name="reset_tracking" method="post">'.
+                 '  <input type="hidden" name="action" value="reset"'."\n");
+        $r->print('<tr bgcolor="#cccccc"><td><b><small>Resource</small></b></td><td align="right"><b><small>Part</small></b></td><td align="right"><b><small>Num. students</small></b></td><td align="right"><b><small>Av. Attempts</small></b></td><td align="right"><b><small>Deg. Diff</small></b></td><td align="right"><b><small>Last Reset</small></b></td><td align="right"><b><small>Reset Count?</small></b></td></tr>');
         foreach my $res (@warnings) {
             if ($warningnum %2 == 1) {
-                 $rowColor = $rowColor1;
+                $rowColor = $rowColor1;
             } else {
                 $rowColor = $rowColor2;
             }
@@ -290,8 +306,9 @@
             $r->print('<tr bgcolor="'.$rowColor.'"><td '.$rowspan.'><a href="'.$linkurl.'"><small>'.$triggered{$res}{title}.'</small></a></td>'.$triggered{$res}{text});
             $warningnum ++;
         }
+        $r->print('<tr bgcolor="#cccccc"><td colspan="7" align="right"><br /><b><small><input type="submit" name="counters" value="Reset counters to 0" /></form>'); 
     } else {
-        $r->print('<tr><td bgcolor="#ffffff"><br /><center><b><i><small>No problems with av. attempts or degree of difficulty above thresholds</small></i></b></center><br /></td></tr>');
+        $r->print('<tr><td bgcolor="#ffffff"><br /><center><b><i><small>No problems satisfy threshold criteria.</small></i></b></center><br /></td></tr>');
     }
     $r->print('</table></td></tr></table></td></tr></table><br />');
 
@@ -414,33 +431,82 @@
 #-------------------------------
 # display_config_box
 #
-# Display the action items
+# Display the threshold setting screen 
 #
 #-------------------------------
                                                                                 
 sub display_config_box() {
-    my ($r,$picker) = @_;
-    $r->print('<b>'.$picker.'</b><br /><hr width="100%" /><table border="0" width="100%" cellpadding="2" cellspacing="4"><tr><td align="left" valign="top" width="45%">');
+    my ($r,$command,$tabbg,$threshold_titles) = @_;
+    my %threshold = ();
+    my $rowColor1 = "#ffffff";
+    my $rowColor2 = "#eeeeee";
+    my $rowColor;
+
+    my @thresholditems = ("av_attempts","degdiff","numstudents");
+    my %threshold_titles = (
+                         av_attempts => 'Average number of attempts',
+                         degdiff => 'Degree of difficulty',
+                         numstudents => 'Total number of students with submissions',
+                         );
+    &get_curr_thresholds(\%threshold);
+
+    $r->print('<br /><form name="thresholdform" method="post"><table border="0" cellpadding="2" cellspacing="4"><tr><td align="left" valign="top" width="45%">
+           <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000">
+            <tr>
+             <td>
+               <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000">
+                <tr>
+                <td bgcolor="#ffffff">
+                 <table cellspacing="0" cellpadding="4" border="0">
+     <tr bgcolor="'.$tabbg.'">
+      <th>Threshold Name</th>
+      <th>Current value</th>
+      <th>Change?</th>
+     </tr>');
+    my $rowNum =0;
+    foreach my $type (@thresholditems) {
+        my $parameter = 'internal.threshold_'.$type;
+# onchange is javascript to automatically check the 'Set' button.
+        my $onchange = 'onFocus="javascript:window.document.forms'.
+              "['thresholdform'].elements['".$parameter."_setparmval']".
+              '.checked=true;"';
+        if ($rowNum %2 == 1) {
+            $rowColor = $rowColor1;
+        } else {
+            $rowColor = $rowColor2;
+        }
+        $r->print('
+     <tr bgcolor="'.$rowColor.'">
+      <td>'.$threshold_titles{$type}.'</td>
+      <td>'.&Apache::lonhtmlcommon::textbox($parameter.'_value',
+                                            $threshold{$type},
+                                            10,$onchange).'</td>
+      <td>'
+           .&Apache::lonhtmlcommon::checkbox($parameter.'_setparmval').
+      '</td>
+     </tr>');
+        $rowNum ++;
+    }
+    $r->print('</table></td></tr></table></td></tr></table>
+           <br /><input type="submit" name="threshold" value="Make changes" />
+                 <input type="hidden" name="action" value="update" />
+               </form>');
 }
 
 sub getitems {
-    my ($unread,$ungraded,$bombed,$triggered,$newdiscussions,$tograde,$bombs,$warnings,$rowColor1,$rowColor2) = @_;
+    my ($unread,$ungraded,$bombed,$triggered,$newdiscussions,$tograde,$bombs,$warnings,$rowColor1,$rowColor2,$threshold,$cdom,$crs) = @_;
     my $navmap = Apache::lonnavmaps::navmap->new();
     my @allres=$navmap->retrieveResources();
-    my %discussiontime = &Apache::lonnet::dump('discussiontimes',
-               $env{'course.'.$env{'request.course.id'}.'.domain'},
-               $env{'course.'.$env{'request.course.id'}.'.num'});
-    my %lastread = &Apache::lonnet::dump('nohist_'.$env{'request.course.id'}.'_discuss',$env{'user.domain'},$env{'user.name'},'lastread');
+    my %discussiontime = &Apache::lonnet::dump('discussiontimes',$cdom,$crs);
+    my %lastread = &Apache::lonnet::dump('nohist_'.$env{'request.course.id'}.
+                '_discuss',$env{'user.domain'},$env{'user.name'},'lastread');
     my %lastreadtime = ();
     my @discussions = ();
     my ($classlist,$keylist) = &Apache::loncoursedata::get_classlist();
 
     my %resourcetracker =  &Apache::lonnet::dump('nohist_resourcetracker',
-               $env{'course.'.$env{'request.course.id'}.'.domain'},
-               $env{'course.'.$env{'request.course.id'}.'.num'});
-
-    my $diffcheck = 0;
-    my $triescheck = 0;
+               $cdom,$crs);
+    my %res_title;
     my $warningnum = 0;
     foreach my $key (keys(%lastread)) {
         my $newkey = $key;
@@ -451,11 +517,12 @@
         my $result = '';
         my $applies = 0;
         my $symb = $resource->symb();
-        %{$$bombed{$symb}} = ();
+#        %{$$bombed{$symb}} = ();
         %{$$ungraded{$symb}} = ();
         %{$$triggered{$symb}} = ();
         $$triggered{$symb}{numparts} = 0;
         my $title = $resource->compTitle();
+        $res_title{$symb} = $title;
         my $ressymb = $resource->wrap_symb();
 # Check for unread discussion postings
         if (defined($discussiontime{$ressymb})) {
@@ -468,9 +535,8 @@
             if (defined($lastreadtime{$ressymb})) {
                 $prevread = $lastreadtime{$ressymb};
             }
-            my %contrib = &Apache::lonnet::restore($ressymb,$env{'request.course.id'},
-            $env{'course.'.$env{'request.course.id'}.'.domain'},
-            $env{'course.'.$env{'request.course.id'}.'.num'});
+            my %contrib = &Apache::lonnet::restore($ressymb,
+                             $env{'request.course.id'},$cdom,$crs);
             if ($contrib{'version'}) {
                 for (my $id=1;$id<=$contrib{'version'};$id++) {
                     unless (($contrib{'hidden'}=~/\.$id\./) || ($contrib{'deleted'}=~/\.$id\./)) {
@@ -515,10 +581,12 @@
 # Check for bombs
         if ($resource->getErrors()) {
             my $errors = $resource->getErrors();
+            $errors =~ s/^,//;
             my @bombs = split(/,/, $errors);
             my $errorcount = scalar(@bombs);
             my $errorlink = '<a href="/adm/email?display='.
-                            &Apache::lonnet::escape($$bombs[0]).'">';
+                            &Apache::lonnet::escape($bombs[0]).'">'.
+                            $title.'</a>';
             $$bombed{$symb}{errorcount} = $errorcount;
             $$bombed{$symb}{errorlink} = $errorlink;
             push(@{$bombs}, $symb);
@@ -526,6 +594,7 @@
 # Compile maxtries and degree of difficulty for problem parts
         my @parts = @{$resource->parts()};
         my %stats;
+        my %lastreset = ();
         my $warning = 0;
         my $rowColor;
         foreach my $part (@parts) {
@@ -547,10 +616,12 @@
             if ($users > 0) {
                 $av_attempts = $attempts/$users;
             }
-            if (($degdiff ne '' && $degdiff >= $diffcheck) || ($av_attempts ne '' && $av_attempts >= $triescheck)) {
+            if ((($degdiff ne '' && $degdiff >= $$threshold{'degdiff'}) || ($av_attempts ne '' && $av_attempts >= $$threshold{'av_attempts'})) && ($users >= $$threshold{'numstudents'})) {
                 $stats{$part}{degdiff} = $degdiff;
                 $stats{$part}{attempts} = $av_attempts;
                 $stats{$part}{users} = $users;
+                my %resethash = &Apache::lonnet::restore($symb,'nohist_resourcetracker',$cdom,$crs);
+                $lastreset{$part} = &get_counter_resets(\%resethash,$part);
                 $warning = 1;
             }
         }
@@ -563,6 +634,8 @@
             $$triggered{$symb}{title} = $resource->title;
             foreach my $part (@parts) {
                 if (exists($stats{$part}{users})) {
+                    my $resetname = 'reset_'.&Apache::lonnet::escape($symb."\0".$part);
+                    my $resettitle = 'title_'.&Apache::lonnet::escape($symb."\0".$part);
                     if ($$triggered{$symb}{numparts}) {
                         $$triggered{$symb}{text} .= '<tr bgcolor="'.$rowColor.'">'."\n";
                     }
@@ -577,6 +650,8 @@
                          <td align="right"><small>'.$stats{$part}{users}.'</small></td>
                          <td align="right"><small>'.$stats{$part}{attempts}.'</small></td>
                          <td align="right"><small>'.$stats{$part}{degdiff}.'</small></td>
+                         <td align="right"><small>'.$lastreset{$part}.'</small></td>
+                         <td align="right"><small><input type="checkbox" name="'.$resetname.'" /><input type="hidden" name="'.$resettitle.'" value="'.&Apache::lonnet::escape($$triggered{$symb}{title}).'" /></td> 
                         </tr>';
                     $$triggered{$symb}{numparts} ++;
                 }
@@ -587,6 +662,101 @@
     }
 }
 
+sub get_counter_resets {
+    my ($resethash,$part) = @_;
+    my $lastreset = 'None';
+    if ($$resethash{'version'}) {
+        for (my $version=1;$version<=$$resethash{'version'};$version++) {
+            if (exists($$resethash{$version.':'.$part.'prev_attempts'})) {
+                 $lastreset = $$resethash{$version.':timestamp'};
+            }
+        }
+    }
+    unless ($lastreset eq 'None') {
+        $lastreset = localtime($lastreset);
+    }
+    return $lastreset;
+}
+
+sub get_curr_thresholds {
+    my ($threshold,$cdom,$crs) = @_;
+    my %coursesettings = &Apache::lonnet::dump('environment',
+                                     $cdom,$crs,'internal.threshold');
+    if (exists($coursesettings{'internal.threshold_av_attempts'})) {
+        $$threshold{'av_attempts'} = $coursesettings{'internal.threshold_av_attempts'};
+    }
+    if (exists($coursesettings{'internal.threshold_degdiff'})) {
+        $$threshold{'degdiff'} = $coursesettings{'internal.threshold_degdiff'};
+    }
+    if (exists($coursesettings{'internal.threshold_numstudents'})) {
+        $$threshold{'numstudents'} = $coursesettings{'internal.threshold_numstudents'};
+    }
+}
+
+sub process_reset {
+    my ($dom,$crs) = @_;
+    my $result = '<b>Counters reset for following problems (and parts):</b><br />';
+    my @agg_types = ('attempts','users','correct');
+    my %agg_titles = (
+                     attempts => 'Number of submissions',
+                     users => 'Students with submissions',
+                     correct => 'Number of correct submissions',
+                     );
+    my @resets = ();
+    my %titles = ();
+    foreach my $key (keys %env) {
+        next if ($key !~ /^form\.reset_(.+)$/);
+        my $title = &Apache::lonnet::unescape($env{'form.title_'.$1});
+        my $reset_item = &Apache::lonnet::unescape($1);
+        my %curr_aggregates = &Apache::lonnet::dump('nohist_resourcetracker',$dom,$crs,$reset_item);
+        my %resethash = ();
+        my %aggregates = ();
+        my ($symb,$part) = split/\0/,$reset_item;
+        foreach my $type (@agg_types) {
+            $aggregates{$reset_item."\0".$type} = 0;
+            $resethash{$part."\0".'prev_'.$type} = $curr_aggregates{$reset_item."\0".$type};
+        }  
+        my $putresult = &Apache::lonnet::put('nohist_resourcetracker',\%aggregates,
+                          $dom,$crs);
+        if ($putresult eq 'ok') {
+            my $storeresult = &Apache::lonnet::cstore(\%resethash,$symb,'nohist_resourcetracker',$dom,$crs);
+            $result .= $title.' -part '.$part.': ';
+            my %new_aggregates = &Apache::lonnet::dump('nohist_resourcetracker',$dom,$crs,$reset_item);
+            foreach my $type (@agg_types) {
+                $result .= $agg_titles{$type}.' = '.$new_aggregates{$reset_item."\0".$type}.'; ';
+            }
+            $result =~ s/; $//;
+            $result .= '<br />';
+        } else {
+            $result = $title.' -part '.$part.': '.&mt('Unable to reset counters to zero due to ').$putresult.'.<br />'."\n";
+        }
+    }
+    return $result;
+}
+
+sub process_update {
+    my ($dom,$crs,$threshold_titles) = @_;
+    my $setoutput = '<b>Changes to threshold(s):</b><br />';
+    foreach (keys %env) {
+        next if ($_!~/^form\.(.+)\_setparmval$/);
+        my $name  = $1;
+        my $value = $env{'form.'.$name.'_value'};
+        if ($name && defined($value)) {
+            my $put_result = &Apache::lonnet::put('environment',
+                                                  {$name=>$value},$dom,$crs);
+           
+            my ($shortname) = ($name =~ /^internal\.threshold_(.+)$/); 
+            if ($put_result eq 'ok') {
+                $setoutput.=&mt('Set threshold for').' <b>'.$$threshold_titles{$shortname}.'</b> '.&mt('to').' <b>'.$value.'</b>.<br />';
+            } else {
+                $setoutput.=&mt('Unable to set threshold for').' <b>'.$name.'</b> '.&mt('to').
+                    ' <b>'.$value.'</b> '.&mt('due to').' '.$put_result.'.<br />';
+            }
+        }
+    }
+    return $setoutput;
+}
+
 sub getmail {
     my ($newmsgs,$critmsgs) = @_;
 # Check for unread mail in course

--raeburn1116889588--