File:  [LON-CAPA] / loncom / interface / lonwhatsnew.pm
Revision 1.21: download - view: text, annotated - select for diffs
Thu Jun 9 18:41:08 2005 UTC (19 years ago) by albertel
Branches: MAIN
CVS tags: version_1_99_1, version_1_99_0, HEAD
- only look at resources that have discussion that I care about

    1: #
    2: # $Id: lonwhatsnew.pm,v 1.21 2005/06/09 18:41:08 albertel Exp $
    3: #
    4: # Copyright Michigan State University Board of Trustees
    5: #
    6: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    7: #
    8: # LON-CAPA is free software; you can redistribute it and/or modify
    9: # it under the terms of the GNU General Public License as published by
   10: # the Free Software Foundation; either version 2 of the License, or
   11: # (at your option) any later version.
   12: #
   13: # LON-CAPA is distributed in the hope that it will be useful,
   14: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   15: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16: # GNU General Public License for more details.
   17: #
   18: # You should have received a copy of the GNU General Public License
   19: # along with LON-CAPA; if not, write to the Free Software
   20: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   21: #
   22: # /home/httpd/html/adm/gpl.txt
   23: #
   24: # http://www.lon-capa.org/
   25: #
   26: 
   27: 
   28: package Apache::lonwhatsnew;
   29: 
   30: use strict;
   31: use lib qw(/home/httpd/lib/perl);
   32: use Apache::lonnet;
   33: use Apache::loncommon();
   34: use Apache::lonhtmlcommon();
   35: use Apache::lonlocal;
   36: use Apache::loncoursedata();
   37: use Apache::lonnavmaps();
   38: use Apache::lonuserstate;
   39: use Apache::Constants qw(:common :http);
   40: use Time::Local;
   41: 
   42: #----------------------------
   43: # handler
   44: #
   45: #----------------------------
   46: 
   47: sub handler {
   48:     my $r = shift;
   49:     if ($r->header_only) {
   50:         &Apache::loncommon::content_type($r,'text/html');
   51:         $r->send_http_header;
   52:         return OK;
   53:     }
   54:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['command']);
   55: 
   56:     my $command;
   57:     if ($env{'form.action'} eq 'reset') {
   58:         $command = 'reset';
   59:     } elsif ($env{'form.action'} eq 'update') {
   60:         $command = 'update';
   61:     } else {
   62:         $command = $env{'form.command'};
   63:     }
   64: 
   65:     &Apache::loncommon::content_type($r,'text/html');
   66:     $r->send_http_header;
   67:     $r->print(&display_header());
   68:     if (! (($env{'request.course.fn'}) && (&Apache::lonnet::allowed('vsa',$env{'request.course.id'})))) {
   69:         # Not in a course, or not allowed to modify parms
   70:         $env{'user.error.msg'}="/adm/whatsnew:vsa:0:0:Cannot display student activity";
   71:         return HTTP_NOT_ACCEPTABLE;
   72:     }
   73: 
   74:     &Apache::lonhtmlcommon::clear_breadcrumbs();
   75:     if ($command eq 'chgthreshold') {
   76:         &Apache::lonhtmlcommon::add_breadcrumb
   77:             ({href=>'/adm/whatsnew?command=threshold',
   78:               text=>"Change thresholds"});
   79:         $r->print(&Apache::lonhtmlcommon::breadcrumbs
   80:             (undef,'Course Action Items','Course_Action_Items_Thresholds'));
   81:     } else {
   82:         &Apache::lonhtmlcommon::add_breadcrumb
   83:             ({href=>'/adm/whatsnew',
   84:               text=>"Display Action Items"});
   85:         $r->print(&Apache::lonhtmlcommon::breadcrumbs
   86:             (undef,'Course Action Items','Course_Action_Items_Display'));
   87:     }
   88:     &display_main_box($r,$command);
   89:     return OK;
   90: }
   91: 
   92: #------------------------------
   93: # display_main_box
   94: #
   95: # Display all the elements within the main box
   96: #------------------------------
   97:                                                                                 
   98: sub display_main_box {
   99:     my ($r,$command) = @_;
  100:     my $domain=&Apache::loncommon::determinedomain();
  101:     my $tabbg=&Apache::loncommon::designparm('coordinator.tabbg',$domain);
  102:     $r->print('<table width="100%" border="0" cellpadding="5" cellspacing="0"><tr><td width="100%">');
  103: 
  104:     my %threshold_titles = (
  105:                          av_attempts => 'Average number of attempts',
  106:                          degdiff => 'Degree of difficulty',
  107:                          numstudents => 'Total number of students with submissions',
  108:     );
  109:     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
  110:     my $crs = $env{'course.'.$env{'request.course.id'}.'.num'};
  111: 
  112:     if ($command eq 'chgthreshold') {
  113:         &display_config_box($r,$command,$tabbg,\%threshold_titles,$cdom,$crs);
  114:     } else {
  115:         &display_actions_box($r,$command,\%threshold_titles,$cdom,$crs);
  116:     }
  117:     $r->print(<<END_OF_BLOCK);
  118:   </td>
  119:  </tr>
  120: </table><br />
  121: </body>
  122: </html>
  123: END_OF_BLOCK
  124: }
  125: 
  126: #-------------------------------
  127: # display_header
  128: #
  129: # Display the header information and set
  130: # up the HTML
  131: #-------------------------------
  132: 
  133: sub display_header{
  134:     my $html=&Apache::lonxml::xmlbegin();
  135:     my $bodytag=&Apache::loncommon::bodytag('Course Action Items');
  136:     return(<<ENDHEAD);
  137: $html
  138: <head>
  139: <title>Course Action Items</title>
  140: </head>
  141: $bodytag
  142: ENDHEAD
  143: }
  144: 
  145: #-------------------------------
  146: # display_actions_box
  147: #
  148: # Display the action items
  149: #
  150: #-------------------------------
  151:                                                                                 
  152: sub display_actions_box() {
  153:     my ($r,$command,$threshold_titles,$cdom,$crs) = @_;
  154: 
  155:     my $rowColor1 = "#ffffff";
  156:     my $rowColor2 = "#eeeeee";
  157:     my $rowColor;
  158: 
  159:     my %unread = ();
  160:     my %ungraded = ();
  161:     my %bombed = ();
  162:     my %triggered = ();
  163:     my @newmsgs = ();
  164:     my @critmsgs = ();
  165:     my @newdiscussions = ();
  166:     my @tograde = ();
  167:     my @bombs = ();
  168:     my @warnings = ();
  169:     my %res_title = ();
  170: 
  171:     my $domain=&Apache::loncommon::determinedomain();
  172:     my $function;
  173:     if ($env{'request.role'}=~/^(cc|in|ta|ep)/) {
  174:         $function='coordinator';
  175:     }
  176:     if ($env{'request.role'}=~/^(su|dc|ad|li)/) {
  177:         $function='admin';
  178:     }
  179: 
  180:     my %threshold = (
  181:                       av_attempts => 0,
  182:                       degdiff => 0.01,
  183:                       numstudents => 0,
  184:                      );
  185: 
  186:     my $pgbg=&Apache::loncommon::designparm($function.'.pgbg',$domain);
  187:     my $tabbg=&Apache::loncommon::designparm($function.'.tabbg',$domain);
  188: 
  189:     unless ($env{'request.course.id'}) {
  190:         $r->print('<br /><b><center>You are accessing an invalid course.</center></b><br /><br />');
  191:         return;
  192:     }
  193: 
  194:     my ($furl,$ferr)=
  195:            &Apache::lonuserstate::readmap($cdom.'/'.$crs);
  196:     $r->print('<font size="+1"><a href="'.$furl.'">Go to first resource</a></font><a href="/adm/preferences?action=changecourseinit"></font><br />Change your preferences</a> to suppress display of this screen when accessing courses as Course Coordinator in the future.<br /><hr />');
  197: 
  198:     my $result;
  199: 
  200:     if ($command eq 'reset') {
  201:         $result = &process_reset($cdom,$crs);
  202:     } elsif ($command eq 'update') {
  203:         $result = &process_update($cdom,$crs,$threshold_titles);
  204:     }
  205:     if ($result) {
  206:         $r->print($result.'<hr width="100%" />');
  207:     }
  208: 
  209:     &get_curr_thresholds(\%threshold,$cdom,$crs);
  210:     &getitems(\%unread,\%ungraded,\%bombed,\%triggered,\@newdiscussions,\@tograde,\@bombs,\@warnings,$rowColor1,$rowColor2,\%threshold,$cdom,$crs,%res_title);
  211:     my ($msgcount,$critmsgcount) = &getmail(\@newmsgs,\@critmsgs);
  212: 
  213:     $r->print('<br /><table border="0" width="100%" cellpadding="2" cellspacing="4"><tr><td align="left" valign="top" width="45%">');
  214: 
  215: ## UNGRADED ITEMS ##
  216:     $r->print(<<END);
  217:            <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%">
  218:             <tr><td>
  219:              <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000" width="100%">
  220:               <tr>
  221:                <td bgcolor="$tabbg"><b>Problems requiring handgrading</b></td></tr>
  222:                   <tr>
  223:                    <td bgcolor="#ffffff">
  224:                      <table cellpadding="2" cellspacing="0" border="0" width="100%">
  225: END
  226: 
  227:     if (@tograde > 0) {
  228:         $r->print('<tr bgcolor="#cccccc"><td><b><small>Problem Name</small></b></td><td align="right"><b><small>Number ungraded</small></b></td></tr>');
  229:         my $rowNum = 0;
  230:         foreach my $res (@tograde) {
  231:             if ($rowNum %2 == 1) {
  232:                 $rowColor = $rowColor1;
  233:             } else {
  234:                 $rowColor = $rowColor2;
  235:             }
  236:             my ($map,$id,$url)=&Apache::lonnet::decode_symb($res);
  237:             my $linkurl=&Apache::lonnet::clutter($url);
  238:             $linkurl .= '?symb='.&Apache::lonnet::escape($res);
  239: 
  240:             $r->print('<tr bgcolor="'.$rowColor.'"><td><a href="'.$linkurl.'"><small>'.$ungraded{$res}{title}.'</small></a></td><td align="right"><small>'.$ungraded{$res}{count}.'</small></td></tr>');
  241:             $rowNum ++;
  242:         }
  243:     } else {
  244:         $r->print('<tr><td bgcolor="#ffffff"><br><center><i><b><small>&nbsp;&nbsp;No problems require handgrading&nbsp;&nbsp;</small><br><br></b></i></td></tr>');
  245:     }
  246:     $r->print('</table></td></tr></table></td></tr></table><br />');
  247: 
  248: ## BOMBS ##
  249:      $r->print(<<"END");
  250:            <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%">
  251:             <tr>
  252:              <td>
  253:                <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000" width="100%">
  254:                <tr>
  255:                 <td bgcolor="$tabbg"><b>Problems with errors</b></td>
  256:                </tr>
  257:                 <tr>
  258:                 <td bgcolor="#ffffff">
  259:                  <table width="100%" cellspacing="0" cellpadding="0" border="0">
  260: END
  261:      my $bombnum = 0;
  262:      if (@bombs > 0) {
  263:         $r->print('<tr bgcolor="#cccccc"><td><b><small>Resource</small></b></td><td align="right"><b><small>Number of errors</small></b></td></tr>');
  264:         @bombs = sort { &cmp_title($a,$b,\%res_title) } @bombs;
  265:         foreach my $bomb (@bombs) {
  266:             if ($bombnum %2 == 1) {
  267:                  $rowColor = $rowColor1;
  268:             } else {
  269:                 $rowColor = $rowColor2;
  270:             }
  271:             $r->print('<tr bgcolor="'.$rowColor.'"><td><small>'.$bombed{$bomb}{errorlink}.'</small></td><td align="right"><small>'.$bombed{$bomb}{errorcount}.'</small></td></tr>');
  272:             $bombnum ++;
  273:         }
  274:     } else {
  275:         $r->print('<tr><td bgcolor="#ffffff"><br /><center><b><i><small>No problems with errors</small></i></b></center><br /></td></tr>');
  276:     }
  277:     $r->print('</table></td></tr></table></td></tr></table><br />');
  278: 
  279: # DEGDIFF AND AV. TRIES TRIGGERS
  280:     $r->print(<<"END");
  281:            <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%">
  282:             <tr>
  283:              <td>
  284:                <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000" width="100%">
  285:                <tr>
  286:                 <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>
  287:                </tr>
  288:                <tr>
  289:                 <td bgcolor="$tabbg" align="right"><a href="/adm/whatsnew?command=chgthreshold"><b><small>Change thresholds?</small></b></a></td>
  290:                </tr>
  291:                 <tr>
  292:                 <td bgcolor="#ffffff">
  293:                  <table width="100%" cellspacing="2" cellpadding="2" border="0">
  294: END
  295:     my $warningnum = 0;
  296:     if (@warnings > 0) {
  297:         @warnings = sort { &cmp_title($a,$b,\%res_title) } @warnings;
  298:         $r->print('<form name="reset_tracking" method="post">'.
  299:                  '  <input type="hidden" name="action" value="reset" />'."\n");
  300:         $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>');
  301:         foreach my $res (@warnings) {
  302:             if ($warningnum %2 == 1) {
  303:                 $rowColor = $rowColor1;
  304:             } else {
  305:                 $rowColor = $rowColor2;
  306:             }
  307:             my ($map,$id,$url)=&Apache::lonnet::decode_symb($res);
  308:             my $linkurl=&Apache::lonnet::clutter($url);
  309:             my $rowspan;
  310:             if ($triggered{$res}{numparts} > 1) {
  311:                 $rowspan = 'rowspan="'.$triggered{$res}{numparts}.'"';
  312:             }
  313:             $linkurl .= '?symb='.&Apache::lonnet::escape($res);
  314:             $r->print('<tr bgcolor="'.$rowColor.'"><td '.$rowspan.'><a href="'.$linkurl.'"><small>'.$triggered{$res}{title}.'</small></a></td>'.$triggered{$res}{text});
  315:             $warningnum ++;
  316:         }
  317:         $r->print('<tr bgcolor="#cccccc"><td colspan="7" align="right"><br /><b><small><input type="submit" name="counters" value="Reset counters to 0" /></form>'); 
  318:     } else {
  319:         $r->print('<tr><td bgcolor="#ffffff"><br /><center><b><i><small>No problems satisfy threshold criteria.</small></i></b></center><br /></td></tr>');
  320:     }
  321:     $r->print('</table></td></tr></table></td></tr></table><br />');
  322: 
  323:     $r->print('</td><td width="5%">&nbsp;</td><td align="left" valign="top" width-"50%">');
  324: 
  325: ## UNREAD COURSE DISCUSSION POSTS ##
  326:     $r->print(<<"END");
  327:               <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%">
  328:                <tr><td>
  329:                 <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000" width="100%">
  330:                  <tr>
  331:                   <td bgcolor="$tabbg"><b>Unread course discussion posts</b></td>
  332:                  </tr>
  333:                  <tr>
  334:                    <td bgcolor="#ffffff">
  335:                    <table cellpadding="2" cellspacing="0" border="0" width="100%">
  336: END
  337:                                                                                   
  338:     if (@newdiscussions > 0) {
  339:         $r->print('<tr bgcolor="#cccccc"><td><b><small>Location</small></b></td><td><b><small>Type</small></b><td align="right"><b><small>Number of new posts</small></b></td></tr>');
  340:         @newdiscussions = sort { &cmp_title($a,$b,\%res_title) } @newdiscussions;
  341:         my $rowNum = 0;
  342:         foreach my $ressymb (@newdiscussions) {
  343:             my $forum_title = $unread{$ressymb}{'title'};
  344:             my $type = 'Resource';
  345:             my $feedurl=&Apache::lonfeedback::get_feedurl($ressymb);
  346:             if ($feedurl =~ /bulletinboard/) {
  347:                 $type = 'Bulletin Board';
  348:             }
  349:             my $unreadnum = keys(%{$unread{$ressymb}});
  350:             $unreadnum = $unreadnum - 2;
  351:             if ($unreadnum > 0) {
  352:                 if ($rowNum %2 == 1) {
  353:                     $rowColor = $rowColor1;
  354:                 } else {
  355:                     $rowColor = $rowColor2;
  356:                 }
  357:                 $r->print('<tr bgcolor="'.$rowColor.'"><td><small><a href="'.$feedurl.'?symb='.$unread{$ressymb}{symb}.'">'.$forum_title.'</a>&nbsp;</td><td><small>'.$type.'</small></td><td align="right">'.$unreadnum.'&nbsp;</td></tr>');
  358:                 $rowNum ++;
  359:             }
  360:         }
  361:     } else {
  362:         $r->print('<tr><td bgcolor="#ffffff"><br><center>&nbsp;<i><b><small>No unread posts in course discussions</small></b></i><br><br></td></tr>');
  363:     }
  364:     $r->print('</table></td></tr></table></td></tr></table><br />');
  365: 
  366: ## MESSAGES ##
  367:     $r->print(<<END);
  368:            <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%">
  369:             <tr>
  370:              <td>
  371:               <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000" width="100%">
  372:                <tr>
  373:                 <td bgcolor="$tabbg"><b>New course messages</b></td>
  374:                </tr>
  375:                <tr>
  376:                 <td bgcolor="#ffffff">
  377:                  <table width="100%" cellspacing="0" cellpadding="0" border="0">
  378: END
  379:     if ($msgcount > 0) {
  380:         $r->print('<tr bgcolor="#cccccc"><td><b><small>'.&mt('Number').'</small></b></td><td><b><small>'.&mt('Subject').'</small></b></td><td><b><small>'.&mt('Sender').'</small></b></td><td><b><small>'.&mt('Date/Time').'</small></b></td></tr>');
  381:         my $rowNum = 0;
  382:         my $mailcount = 1; 
  383:         foreach my $msg (@newmsgs) {
  384:             if ($rowNum %2 == 1) {
  385:                 $rowColor = $rowColor1;
  386:             } else {
  387:                 $rowColor = $rowColor2;
  388:             }
  389:             $r->print('<tr bgcolor="'.$rowColor.'"><td valign="top"><small>'.$mailcount.'. &nbsp;<small></td><td valign="top"><small><a href="/adm/communicate">'.$msg->{'shortsub'}.'</a>&nbsp; &nbsp;</small></td><td valign="top"><small>&nbsp;'.$msg->{'from'}.'@'.$msg->{'fromdom'}.'&nbsp;</small></td><td valign="top"><small>'.$msg->{'sendtime'}.'</small></td></tr>');
  390:             $rowNum ++;
  391:             $mailcount ++;
  392:         }
  393:     } else {
  394:         $r->print('<tr><td bgcolor="#ffffff" width="100%"><center><br /><b><i><small>No new course messages</small></i></b><br /><br /></center></td></tr>');
  395:     }
  396: 
  397:     $r->print('</table></td></tr></table></td></tr></table><br />');
  398: 
  399:     $r->print(<<END);
  400:            <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%">
  401:             <tr>
  402:              <td>
  403:               <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000" width="100%">
  404:                <tr>
  405:                 <td bgcolor="$tabbg"><b>New critical messages in course</b></td>
  406:                </tr>
  407:                <tr>                 <td bgcolor="#ffffff">
  408:                  <table width="100%" cellspacing="0" cellpadding="0" border="0">
  409: END
  410: 
  411:     if ($critmsgcount > 0) {
  412:         $r->print('<tr bgcolor="#cccccc"><td><b><small>Number</small></b></td><td><b><small>Subject</small></b></td><td><b><small>Sender</small></b></td><td><b><small>Date/Time</small></b></td></tr>');
  413:         my $rowNum = 0;
  414:         my $mailcount = 1;
  415:         foreach my $msg (@critmsgs) {
  416:             if ($rowNum %2 == 1) {
  417:                 $rowColor = $rowColor1;
  418:             } else {
  419:                 $rowColor = $rowColor2;
  420:             }
  421:             $r->print('<tr bgcolor="'.$rowColor.'"><td valign="top"><small>'.$mailcount.'. &nbsp;<small></td><td valign="top"><small><a href="/adm/mail?">'.$msg->{'shortsub'}.'</a>&nbsp; &nbsp;</small></td><td valign="top"><small>&nbsp;'.$msg->{'from'}.'@'.$msg->{'fromdom'}.'&nbsp;</small></td><td valign="top"><small>'.$msg->{'sendtime'}.'</small></td></tr>');
  422:             $rowNum ++;
  423:             $mailcount ++;
  424:         }
  425:     } else {
  426:         $r->print('<tr><td bgcolor="#ffffff" width="100%"><center><br /><b><i><small>No unread critical messages in course</small></i></b><br /><br /></center></td></tr>');
  427:     }
  428:                                                                                
  429:     $r->print('</table></td></tr></table></td></tr></table><br />');
  430: 
  431:     $r->print('
  432:            </table>
  433:           </td>
  434:          </tr>
  435:         </table>');
  436:     $r->print('</td></tr></table>');
  437: }
  438: 
  439: #-------------------------------
  440: # display_config_box
  441: #
  442: # Display the threshold setting screen 
  443: #
  444: #-------------------------------
  445:                                                                                 
  446: sub display_config_box() {
  447:     my ($r,$command,$tabbg,$threshold_titles,$cdom,$crs) = @_;
  448:     my %threshold = ();
  449:     my $rowColor1 = "#ffffff";
  450:     my $rowColor2 = "#eeeeee";
  451:     my $rowColor;
  452: 
  453:     my @thresholditems = ("av_attempts","degdiff","numstudents");
  454:     my %threshold_titles = (
  455:                          av_attempts => 'Average number of attempts',
  456:                          degdiff => 'Degree of difficulty',
  457:                          numstudents => 'Total number of students with submissions',
  458:                          );
  459:     &get_curr_thresholds(\%threshold,$cdom,$crs);
  460: 
  461:     $r->print('<br /><form name="thresholdform" method="post"><table border="0" cellpadding="2" cellspacing="4"><tr><td align="left" valign="top" width="45%">
  462:            <table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000">
  463:             <tr>
  464:              <td>
  465:                <table border="0" cellpadding="1" cellspacing="1" bgcolor="#000000">
  466:                 <tr>
  467:                 <td bgcolor="#ffffff">
  468:                  <table cellspacing="0" cellpadding="4" border="0">
  469:      <tr bgcolor="'.$tabbg.'">
  470:       <th>Threshold Name</th>
  471:       <th>Current value</th>
  472:       <th>Change?</th>
  473:      </tr>');
  474:     my $rowNum =0;
  475:     foreach my $type (@thresholditems) {
  476:         my $parameter = 'internal.threshold_'.$type;
  477: # onchange is javascript to automatically check the 'Set' button.
  478:         my $onchange = 'onFocus="javascript:window.document.forms'.
  479:               "['thresholdform'].elements['".$parameter."_setparmval']".
  480:               '.checked=true;"';
  481:         if ($rowNum %2 == 1) {
  482:             $rowColor = $rowColor1;
  483:         } else {
  484:             $rowColor = $rowColor2;
  485:         }
  486:         $r->print('
  487:      <tr bgcolor="'.$rowColor.'">
  488:       <td>'.$threshold_titles{$type}.'</td>
  489:       <td>'.&Apache::lonhtmlcommon::textbox($parameter.'_value',
  490:                                             $threshold{$type},
  491:                                             10,$onchange).'</td>
  492:       <td>'
  493:            .&Apache::lonhtmlcommon::checkbox($parameter.'_setparmval').
  494:       '</td>
  495:      </tr>');
  496:         $rowNum ++;
  497:     }
  498:     $r->print('</table></td></tr></table></td></tr></table>
  499:            <br /><input type="submit" name="threshold" value="Make changes" />
  500:                  <input type="hidden" name="action" value="update" />
  501:                </form>');
  502: }
  503: 
  504: sub getitems {
  505:     my ($unread,$ungraded,$bombed,$triggered,$newdiscussions,$tograde,$bombs,$warnings,$rowColor1,$rowColor2,$threshold,$cdom,$crs,$res_title) = @_;
  506:     my $navmap = Apache::lonnavmaps::navmap->new();
  507:     my @allres=$navmap->retrieveResources();
  508:     my %discussiontime = &Apache::lonnet::dump('discussiontimes',$cdom,$crs);
  509:     my %lastread = &Apache::lonnet::dump('nohist_'.$env{'request.course.id'}.
  510:                 '_discuss',$env{'user.domain'},$env{'user.name'},'lastread');
  511:     my %lastreadtime = ();
  512:     my @discussions = ();
  513:     my ($classlist,$keylist) = &Apache::loncoursedata::get_classlist();
  514: 
  515:     my %resourcetracker =  &Apache::lonnet::dump('nohist_resourcetracker',
  516:                $cdom,$crs);
  517:     my $warningnum = 0;
  518:     foreach my $key (keys(%lastread)) {
  519:         my $newkey = $key;
  520:         $newkey =~ s/_lastread$//;
  521:         $lastreadtime{$newkey} = $lastread{$key};
  522:     }
  523:     foreach my $resource (@allres) {
  524:         my $result = '';
  525:         my $applies = 0;
  526:         my $symb = $resource->symb();
  527: #        %{$$bombed{$symb}} = ();
  528:         %{$$ungraded{$symb}} = ();
  529:         %{$$triggered{$symb}} = ();
  530:         $$triggered{$symb}{numparts} = 0;
  531:         my $title = $resource->compTitle();
  532:         $$res_title{$symb} = $title;
  533:         my $ressymb = $resource->wrap_symb();
  534: # Check for unread discussion postings
  535: 	if ($resource->hasDiscussion()) {
  536:             push(@discussions,$ressymb);
  537:             my $prevread = 0;
  538:             my $unreadcount = 0;
  539:             %{$$unread{$ressymb}} = ();
  540:             $$unread{$ressymb}{'title'} = $title;
  541:             $$unread{$ressymb}{'symb'} = $symb;
  542:             if (defined($lastreadtime{$ressymb})) {
  543:                 $prevread = $lastreadtime{$ressymb};
  544:             }
  545:             my %contrib = &Apache::lonnet::restore($ressymb,
  546:                              $env{'request.course.id'},$cdom,$crs);
  547:             if ($contrib{'version'}) {
  548:                 for (my $id=1;$id<=$contrib{'version'};$id++) {
  549:                     unless (($contrib{'hidden'}=~/\.$id\./) || ($contrib{'deleted'}=~/\.$id\./)) {
  550:                         if ($prevread <$contrib{$id.':timestamp'}) {
  551:                             $$unread{$ressymb}{$unreadcount} = $id.': '.$contrib{$id.':subject'};
  552:                             $unreadcount ++;
  553:                         }
  554:                     }
  555:                 }
  556:             }
  557:             if ($unreadcount) { push(@{$newdiscussions}, $ressymb); }
  558: 	}
  559: 
  560: # Check for ungraded problems
  561:         if ($resource->is_problem()) {
  562:             my $ctr = 0;
  563:             my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
  564:             my ($partlist,$handgrade,$responseType) = 
  565: 		&Apache::grades::response_type($url,$symb);
  566: 	    my $handgradeable;
  567: 	    foreach my $value (values(%{$handgrade})) {
  568: 		if ($value eq 'yes') { $handgradeable=1; last; }
  569: 	    }
  570: 	    next if (!$handgradeable);
  571:  
  572:             foreach my $student (keys(%$classlist)) {
  573:                 my ($uname,$udom) = split(/:/,$student);
  574:                 my %status=&Apache::grades::student_gradeStatus($url,$symb,$udom,$uname,$partlist);
  575:                 my $submitted = 0;
  576:                 my $ungraded = 0;
  577:                 foreach (keys(%status)) {
  578:                     $submitted = 1 if ($status{$_} ne 'nothing');
  579:                     $ungraded = 1 if ($status{$_} =~ /^ungraded/);
  580:                     my ($foo,$partid,$foo1) = split(/\./,$_);
  581:                     if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
  582:                         $submitted = 0;
  583:                     }
  584:                 }
  585:                 next if (!$submitted || !$ungraded);
  586:                 $ctr ++;
  587:             }
  588:             if ($ctr) {
  589:                 $$ungraded{$symb}{count} = $ctr;
  590:                 $$ungraded{$symb}{title} = $title;
  591:                 push(@{$tograde}, $symb);
  592:             }
  593:         }
  594: 
  595: # Check for bombs
  596:         if ($resource->getErrors()) {
  597:             my $errors = $resource->getErrors();
  598:             $errors =~ s/^,//;
  599:             my @bombs = split(/,/, $errors);
  600:             my $errorcount = scalar(@bombs);
  601:             my $errorlink = '<a href="/adm/email?display='.
  602:                             &Apache::lonnet::escape($bombs[0]).'">'.
  603:                             $title.'</a>';
  604:             $$bombed{$symb}{errorcount} = $errorcount;
  605:             $$bombed{$symb}{errorlink} = $errorlink;
  606:             push(@{$bombs}, $symb);
  607:         }
  608: # Compile maxtries and degree of difficulty for problem parts
  609:         my @parts = @{$resource->parts()};
  610:         my %stats;
  611:         my %lastreset = ();
  612:         my $warning = 0;
  613:         my $rowColor;
  614:         foreach my $part (@parts) {
  615:             %{$stats{$part}} = ();
  616:             my ($attempts,$users,$corrects,$degdiff,$av_attempts);
  617:             if (exists($resourcetracker{$symb."\0".$part."\0attempts"})) {
  618:                 $attempts = $resourcetracker{$symb."\0".$part."\0attempts"};
  619:             }
  620:             if (exists($resourcetracker{$symb."\0".$part."\0users"})) {
  621:                 $users = $resourcetracker{$symb."\0".$part."\0users"};
  622:             }
  623:             if (exists($resourcetracker{$symb."\0".$part."\0correct"})) {
  624:                 $corrects = $resourcetracker{$symb."\0".$part."\0correct"};
  625:             }
  626:             if ($attempts > 0) {
  627:                 $degdiff =  1 - ($corrects/$attempts);
  628:                 $degdiff = sprintf("%.2f",$degdiff);
  629:             }
  630:             if ($users > 0) {
  631:                 $av_attempts = $attempts/$users;
  632:                 $av_attempts = sprintf("%.2f",$av_attempts);
  633:             }
  634:             if ((($degdiff ne '' && $degdiff >= $$threshold{'degdiff'}) || ($av_attempts ne '' && $av_attempts >= $$threshold{'av_attempts'})) && ($users >= $$threshold{'numstudents'})) {
  635:                 $stats{$part}{degdiff} = $degdiff;
  636:                 $stats{$part}{attempts} = $av_attempts;
  637:                 $stats{$part}{users} = $users;
  638: 		$lastreset{$part} = $resourcetracker{$symb."\0".$part."\0resettime"};
  639:                 $warning = 1;
  640:             }
  641:         }
  642:         if ($warning) {
  643:             if ($warningnum %2 == 1) {
  644:                 $rowColor = $rowColor1;
  645:             } else {
  646:                 $rowColor = $rowColor2;
  647:             }
  648:             $$triggered{$symb}{title} = $resource->title;
  649:             foreach my $part (@parts) {
  650:                 if (exists($stats{$part}{users})) {
  651:                     my $resetname = 'reset_'.&Apache::lonnet::escape($symb."\0".$part);
  652:                     my $resettitle = 'title_'.&Apache::lonnet::escape($symb."\0".$part);
  653:                     if ($$triggered{$symb}{numparts}) {
  654:                         $$triggered{$symb}{text} .= '<tr bgcolor="'.$rowColor.'">'."\n";
  655:                     }
  656:                     if (@parts > 1) {
  657:                         $$triggered{$symb}{text} .= '
  658:                          <td align="right"><small>part - '.$part.'<small></td>';
  659:                     } else {
  660:                         $$triggered{$symb}{text} .= '
  661:                          <td align="right"><small>single part</small></td>';
  662:                     }
  663:                     $$triggered{$symb}{text} .= '
  664:                          <td align="right"><small>'.$stats{$part}{users}.'</small></td>
  665:                          <td align="right"><small>'.$stats{$part}{attempts}.'</small></td>
  666:                          <td align="right"><small>'.$stats{$part}{degdiff}.'</small></td>
  667:                          <td align="right"><small>'.$lastreset{$part}.'</small></td>
  668:                          <td align="right"><small><input type="checkbox" name="'.$resetname.'" /><input type="hidden" name="'.$resettitle.'" value="'.&Apache::lonnet::escape($$triggered{$symb}{title}).'" /></td> 
  669:                         </tr>';
  670:                     $$triggered{$symb}{numparts} ++;
  671:                 }
  672:             }
  673:             push(@{$warnings},$symb);
  674:             $warningnum ++;
  675:         }
  676:     }
  677: }
  678: 
  679: sub get_curr_thresholds {
  680:     my ($threshold,$cdom,$crs) = @_;
  681:     my %coursesettings = &Apache::lonnet::dump('environment',
  682:                                      $cdom,$crs,'internal.threshold');
  683:     if (exists($coursesettings{'internal.threshold_av_attempts'})) {
  684:         $$threshold{'av_attempts'} = $coursesettings{'internal.threshold_av_attempts'};
  685:     }
  686:     if (exists($coursesettings{'internal.threshold_degdiff'})) {
  687:         $$threshold{'degdiff'} = $coursesettings{'internal.threshold_degdiff'};
  688:     }
  689:     if (exists($coursesettings{'internal.threshold_numstudents'})) {
  690:         $$threshold{'numstudents'} = $coursesettings{'internal.threshold_numstudents'};
  691:     }
  692: }
  693: 
  694: sub process_reset {
  695:     my ($dom,$crs) = @_;
  696:     my $result = '<b>Counters reset for following problems (and parts):</b><br />';
  697:     my @agg_types = ('attempts','users','correct');
  698:     my %agg_titles = (
  699:                      attempts => 'Number of submissions',
  700:                      users => 'Students with submissions',
  701:                      correct => 'Number of correct submissions',
  702:                      );
  703:     my @resets = ();
  704:     my %titles = ();
  705:     foreach my $key (keys(%env)) {
  706:         next if ($key !~ /^form\.reset_(.+)$/);
  707:         my $title = &Apache::lonnet::unescape($env{'form.title_'.$1});
  708:         my $reset_item = &Apache::lonnet::unescape($1);
  709:         my %curr_aggregates = &Apache::lonnet::dump('nohist_resourcetracker',$dom,$crs,$reset_item);
  710:         my %aggregates = ();
  711:         my ($symb,$part) = split(/\0/,$reset_item);
  712:         foreach my $type (@agg_types) {
  713:             $aggregates{$reset_item."\0".$type} = 0;
  714:         }  
  715: 	$aggregates{$reset_item."\0".'resettime'} = time;
  716:         my $putresult = &Apache::lonnet::put('nohist_resourcetracker',\%aggregates,
  717:                           $dom,$crs);
  718:         if ($putresult eq 'ok') {
  719:             $result .= $title.' -part '.$part.': ';
  720:             my %new_aggregates = &Apache::lonnet::dump('nohist_resourcetracker',$dom,$crs,$reset_item);
  721:             foreach my $type (@agg_types) {
  722:                 $result .= $agg_titles{$type}.' = '.$new_aggregates{$reset_item."\0".$type}.'; ';
  723:             }
  724:             $result =~ s/; $//;
  725:             $result .= '<br />';
  726:         } else {
  727:             $result = $title.' -part '.$part.': '.&mt('Unable to reset counters to zero due to [_1]',$putresult).'.<br />'."\n";
  728:         }
  729:     }
  730:     return $result;
  731: }
  732: 
  733: sub process_update {
  734:     my ($dom,$crs,$threshold_titles) = @_;
  735:     my $setoutput = '<b>Changes to threshold(s) for problem tracking:</b><br />';
  736:     foreach (keys %env) {
  737:         next if ($_!~/^form\.(.+)\_setparmval$/);
  738:         my $name  = $1;
  739:         my $value = $env{'form.'.$name.'_value'};
  740:         if ($name && defined($value)) {
  741:             my $put_result = &Apache::lonnet::put('environment',
  742:                                                   {$name=>$value},$dom,$crs);
  743:            
  744:             my ($shortname) = ($name =~ /^internal\.threshold_(.+)$/); 
  745:             if ($put_result eq 'ok') {
  746:                 $setoutput.=&mt('Set threshold for [_1] to [_2]',
  747: 				'<b>'.$$threshold_titles{$shortname}.'</b>',
  748: 				'<b>'.$value.'</b>').'<br />';
  749: 	    } else {
  750:                 $setoutput.=&mt('Unable to set threshold for [_1] to [_2] due to [_3].',
  751: 				'<b>'.$name.'</b>','<b>'.$value.'</b>',
  752: 				'<tt>'.$put_result.'</tt>').'<br />';
  753:             }
  754:         }
  755:     }
  756:     return $setoutput;
  757: }
  758: 
  759: sub getmail {
  760:     my ($newmsgs,$critmsgs) = @_;
  761: # Check for unread mail in course
  762:     my $msgcount = 0;
  763: 
  764:     my @messages = sort(&Apache::lonnet::getkeys('nohist_email'));
  765:     foreach my $message (@messages) {
  766: 	my $msgid=&Apache::lonnet::escape($message);
  767:         my ($sendtime,$shortsubj,$fromname,$fromdom,$status,$fromcid)=
  768:             &Apache::lonmsg::unpackmsgid($msgid);
  769:         if (($fromcid) && ($fromcid eq $env{'request.course.id'})) {
  770:             if (defined($sendtime) && $sendtime!~/error/) {
  771:                 my $numsendtime = $sendtime;
  772:                 $sendtime = &Apache::lonlocal::locallocaltime($sendtime);
  773:                 if ($status eq 'new') {
  774:                     $msgcount ++;
  775:                     if ($shortsubj eq '') {
  776:                         $shortsubj = &mt('No subject');
  777:                     }
  778:                     $shortsubj = &Apache::lonnet::unescape($shortsubj);
  779:                     push(@{$newmsgs}, {
  780:                         msgid    => $msgid,
  781:                         sendtime => $sendtime,
  782:                         shortsub => $shortsubj,
  783:                         from     => $fromname,
  784:                         fromdom  => $fromdom
  785:                         });
  786:                 }
  787:             }
  788:         }
  789:     }
  790: 
  791: # Check for critical messages in course
  792:     my %what=&Apache::lonnet::dump('critical');
  793:     my $result = '';
  794:     my $critmsgcount = 0;
  795:     foreach my $msgid (sort(keys(%what))) {
  796:         my ($sendtime,$shortsubj,$fromname,$fromdom,$status,$fromcid)=
  797:             &Apache::lonmsg::unpackmsgid($msgid);
  798:         if (($fromcid) && ($fromcid eq  $env{'request.course.id'})) {
  799:             if (defined($sendtime) && $sendtime!~/error/) {
  800:                 my $numsendtime = $sendtime;
  801:                 $sendtime = &Apache::lonlocal::locallocaltime($sendtime);
  802:                 $critmsgcount ++;
  803:                 if ($shortsubj eq '') {
  804:                     $shortsubj = &mt('No subject');
  805:                 }
  806:                 $shortsubj = &Apache::lonnet::unescape($shortsubj);
  807:                 push(@{$critmsgs}, {
  808:                         msgid    => $msgid,
  809:                         sendtime => $sendtime,
  810:                         shortsub => $shortsubj,
  811:                         from     => $fromname,
  812:                         fromdom  => $fromdom
  813:                         });
  814:             }
  815:         }
  816:     }
  817:     return ($msgcount,$critmsgcount);
  818: }
  819: 
  820: sub cmp_title {
  821:     my ($a,$b,$res_title) = @_;
  822:     my ($atitle,$btitle) = (lc($$res_title{$a}),lc($$res_title{$b}));
  823:     $atitle=~s/^\s*//;
  824:     $btitle=~s/^\s*//;
  825:     return $atitle cmp $btitle;
  826: }
  827: 
  828: 1;

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>