![]() ![]() | ![]() |
- Customization for GCI_3 - Wording change.
1: # 2: # $Id: lonwhatsnew.pm,v 1.98.2.4 2010/09/19 15:05:59 raeburn 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::lonuserutils; 40: use Apache::Constants qw(:common :http); 41: use Time::Local; 42: use GDBM_File; 43: use lib '/home/httpd/lib/perl/'; 44: use LONCAPA; 45: use HTML::Entities; 46: 47: #---------------------------- 48: # handler 49: # 50: #---------------------------- 51: 52: sub handler { 53: my $r = shift; 54: if ($r->header_only) { 55: &Apache::loncommon::content_type($r,'text/html'); 56: $r->send_http_header; 57: return OK; 58: } 59: &Apache::loncommon::get_unprocessed_cgi( 60: $ENV{'QUERY_STRING'},['command','refpage']); 61: 62: my $command = $env{'form.command'}; 63: my $refpage = $env{'form.refpage'}; 64: 65: my %checkallowed = ( coursenormalmail => 1, 66: coursecritmail => 1, ); 67: foreach my $perm_check (['whn','whatsnew',1], 68: ['pch','coursediscussion',1], 69: ['mgr','handgrading',1], 70: ['vgr','abovethreshold',1], 71: ['opa','haserrors',1], 72: ['mdc','versionchanges',0], 73: ['vcl','newroles',1], 74: ['vcl','oldroles',1], 75: ['whn','crslogin',1], 76: ) { 77: my ($perm,$key,$check_section) = @{ $perm_check }; 78: my $scope = $env{'request.course.id'}; 79: if (!($checkallowed{$key} = &Apache::lonnet::allowed($perm,$scope))) { 80: $scope .= '/'.$env{'request.course.sec'}; 81: if ( $check_section ) { 82: $checkallowed{$key} = &Apache::lonnet::allowed($perm,$scope); 83: } 84: if ($checkallowed{$key}) { 85: $checkallowed{$key.'_section'} = $env{'request.course.sec'}; 86: } 87: } 88: } 89: 90: if ( ! $env{'request.course.fn'} || ! $checkallowed{'whatsnew'}) { 91: # Not in a course, or no whn priv in course 92: $env{'user.error.msg'}="/adm/whatsnew::whn:0:0:Cannot display what's new page"; 93: return HTTP_NOT_ACCEPTABLE; 94: } 95: 96: &Apache::loncommon::content_type($r,'text/html'); 97: $r->send_http_header; 98: 99: $r->print(&display_header($command,\%checkallowed)); 100: 101: &Apache::lonhtmlcommon::clear_breadcrumbs(); 102: &Apache::lonhtmlcommon::add_breadcrumb 103: ({href=>'/adm/whatsnew', 104: text=>"What's New?"}); 105: if (($command eq 'chgthreshold') && $checkallowed{'abovethreshold'}) { 106: &Apache::lonhtmlcommon::add_breadcrumb 107: ({href=>'/adm/whatsnew?command=chgthreshold&refpage='.$refpage, 108: text=>"Change thresholds"}); 109: $r->print(&Apache::lonhtmlcommon::breadcrumbs 110: ("What's New?",#'Course_Action_Items_Thresholds' 111: )); 112: } elsif (($command eq 'chginterval') && $checkallowed{'versionchanges'} ) { 113: &Apache::lonhtmlcommon::add_breadcrumb 114: ({href=>'/adm/whatsnew?command=chginterval&refpage='.$refpage, 115: text=>"Change interval"}); 116: $r->print(&Apache::lonhtmlcommon::breadcrumbs 117: ("What's New?",#'Course_Action_Items_Intervals' 118: )); 119: } elsif (($command eq 'chgdisc') && $checkallowed{'coursediscussion'}) { 120: &Apache::lonhtmlcommon::add_breadcrumb 121: ({href=>'/adm/whatsnew?command=chgdisc&refpage='.$refpage, 122: text=>"Change discussion display"}); 123: $r->print(&Apache::lonhtmlcommon::breadcrumbs 124: ("What's New?",#'Course_Action_Items_Intervals' 125: )); 126: } elsif ($command eq 'courseinit') { 127: &Apache::lonhtmlcommon::add_breadcrumb 128: ({href=>'/adm/whatsnew?command=courseinit&refpage='.$refpage, 129: text=>"Course initialization preference"}); 130: $r->print(&Apache::lonhtmlcommon::breadcrumbs 131: ("What's New?",#'Course_Action_Items_Initialization' 132: )); 133: } elsif ($command eq 'chgoldroleinterval' && $checkallowed{'oldroles'}) { 134: &Apache::lonhtmlcommon::add_breadcrumb 135: ({href=>'/adm/whatsnew?command=chgoldroleinterval&refpage='.$refpage, 136: text=>"Change interval"}); 137: $r->print(&Apache::lonhtmlcommon::breadcrumbs 138: ("What's New?",#'Course_Action_Items_Intervals' 139: )); 140: } elsif ($command eq 'chgnewroleinterval' && $checkallowed{'newroles'}) { 141: &Apache::lonhtmlcommon::add_breadcrumb 142: ({href=>'/adm/whatsnew?command=chgnewroleinterval&refpage='.$refpage, 143: text=>"Change interval"}); 144: $r->print(&Apache::lonhtmlcommon::breadcrumbs 145: ("What's New?",#'Course_Action_Items_Intervals' 146: )); 147: } elsif ($command eq 'chgcrslogininterval' && $checkallowed{'crslogin'}) { 148: &Apache::lonhtmlcommon::add_breadcrumb 149: ({href=>'/adm/whatsnew?command=chgcrslogininterval&refpage='.$refpage, 150: text=>"Change interval"}); 151: $r->print(&Apache::lonhtmlcommon::breadcrumbs 152: ("What's New?",#'Course_Action_Items_Intervals' 153: )); 154: } else { 155: $r->print(&Apache::lonhtmlcommon::breadcrumbs 156: ("What's New?",#'Course_Action_Items_Display' 157: )); 158: } 159: &display_main_box($r,$command,$refpage,\%checkallowed); 160: return OK; 161: } 162: 163: #------------------------------ 164: # display_main_box 165: # 166: # Display all the elements within the main box 167: #------------------------------ 168: 169: sub display_main_box { 170: my ($r,$command,$refpage,$checkallowed) = @_; 171: my $domain=&Apache::loncommon::determinedomain(); 172: my $function = &Apache::loncommon::get_users_function(); 173: my $lctype = lc(&Apache::loncommon::course_type()); 174: $r->print('<table width="100%" border="0" cellpadding="5" cellspacing="0"><tr><td width="100%">'); 175: 176: my %threshold_titles = &Apache::lonlocal::texthash ( 177: av_attempts => 'Average number of attempts', 178: degdiff => 'Degree of difficulty', 179: numstudents => 'Total number of students with submissions', 180: ); 181: my %versions = ( 182: -1 => "version changes since start of $lctype", 183: 2592000 => 'version changes since last month', 184: 604800 => 'version changes since last week', 185: 86400 => 'version changes since yesterday', 186: ); 187: my %newroles = ( 188: -1 => "roles which have become active since start of $lctype", 189: 2592000 => 'roles which have become active since last month', 190: 604800 => 'roles which have become active since last week', 191: 86400 => 'roles which have become active since yesterday', 192: ); 193: my %oldroles = ( 194: -1 => "roles which expired since start of $lctype", 195: 2592000 => 'roles which expired since last month', 196: 604800 => 'roles which expired since last week', 197: 86400 => 'roles which expired since yesterday', 198: ); 199: my %crslogins = ( 200: -1 => 'last logins for anyone who has ever logged in', 201: 2592000 => 'last logins for users in last 30 days', 202: 604800 => 'last logins for users in last 7 days', 203: 86400 => 'last logins for users in last 24 hours', 204: ); 205: my %interval_titles = ( 206: versions => \%versions, 207: newroles => \%newroles, 208: oldroles => \%oldroles, 209: crslogin => \%crslogins, 210: ); 211: my %initpage = &Apache::lonlocal::texthash ( 212: firstres => "first resource in the $lctype", 213: whatsnew => "What's New Page", 214: userpref => 'your general user preferences', 215: coursespecific => "specific setting for this $lctype", 216: ); 217: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; 218: my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; 219: 220: if (($command eq 'chgthreshold') 221: && $checkallowed->{'abovethreshold'}) { 222: &display_threshold_config($r,$refpage,\%threshold_titles, 223: $cdom,$crs); 224: } elsif (($command eq 'chginterval') 225: && $checkallowed->{'versionchanges'}) { 226: &display_interval_config($r,$refpage,\%interval_titles,'versions'); 227: } elsif (($command eq 'chgdisc') 228: && $checkallowed->{'coursediscussion'}) { 229: &display_discussion_config($r,$refpage); 230: } elsif ($command eq 'courseinit') { 231: &courseinit_config($r,$refpage,\%initpage); 232: } elsif (($command eq 'chgnewroleinterval') 233: && $checkallowed->{'newroles'}) { 234: &display_interval_config($r,$refpage,\%interval_titles,'newroles'); 235: } elsif (($command eq 'chgoldroleinterval') 236: && $checkallowed->{'oldroles'}) { 237: &display_interval_config($r,$refpage,\%interval_titles,'oldroles'); 238: } elsif (($command eq 'chgcrslogininterval') 239: && $checkallowed->{'crslogin'}) { 240: &display_interval_config($r,$refpage,\%interval_titles,'crslogin'); 241: } else { 242: &display_actions_box($r,$command,$refpage,\%threshold_titles, 243: \%interval_titles,\%initpage,$cdom,$crs,$checkallowed); 244: } 245: my $end_page = &Apache::loncommon::end_page(); 246: $r->print(<<END_OF_BLOCK); 247: </td> 248: </tr> 249: </table><br /> 250: $end_page 251: END_OF_BLOCK 252: } 253: 254: #------------------------------- 255: # display_header 256: # 257: # Display the header information and set 258: # up the HTML 259: #------------------------------- 260: 261: sub display_header { 262: my ($command,$checkallowed) = @_; 263: 264: my $scripttag; 265: unless ($command eq 'chgthreshold' || $command eq 'chginterval' || 266: $command eq 'chgoldroleinterval' || 267: $command eq 'chgnewroleinterval' || $command eq 'chgcrslogininterval') { 268: $scripttag = <<"END"; 269: <script type="text/javascript"> 270: // <![CDATA[ 271: function change_display(caller,change) { 272: caller.value = change; 273: document.visible.submit(); 274: } 275: 276: function changeAll(change) { 277: END 278: foreach my $item (keys(%{$checkallowed})) { 279: if ($item =~ /_section$/) { next; } 280: if ($$checkallowed{$item}) { 281: $scripttag.='document.visible.display_'.$item.'.value=change'. 282: "\n"; 283: } 284: } 285: $scripttag.='document.visible.submit(); 286: } 287: 288: function togglelogins() { 289: var total = document.visible.logincount.value; 290: var sumrow = document.visible.loginrow.value; 291: if (total == 0) { 292: return; 293: } 294: var showlogindetails = 0; 295: for (var i=0; i<document.visible.logindetails.length; i++) { 296: if (document.visible.logindetails[i].checked) { 297: showlogindetails = document.visible.logindetails[i].value; 298: } 299: } 300: var detval = "none"; 301: var sumval = ""; 302: if (showlogindetails == 1) { 303: detval = ""; 304: sumval = "none"; 305: } 306: for (var j=0; j<total; j++) { 307: var counter = j+1; 308: var itemid = "logindet_"+counter; 309: personele = document.getElementById(itemid); 310: if (personele != null) { 311: personele.style.display = detval; 312: } 313: } 314: var detheaderele = document.getElementById("logintitledet"); 315: if (detheaderele != null) { 316: detheaderele.style.display = detval; 317: } 318: for (var k=0; k<sumrow; k++) { 319: var counter = k+1; 320: var itemid = "loginsum_"+counter; 321: logincatele = document.getElementById(itemid); 322: if (logincatele != null) { 323: logincatele.style.display = sumval; 324: } 325: } 326: var sumheaderele = document.getElementById("logintitlesum"); 327: if (sumheaderele != null) { 328: sumheaderele.style.display = sumval; 329: } 330: return; 331: } 332: // ]]> 333: </script> 334: '; 335: } 336: my $course_type=&Apache::loncommon::course_type(); 337: return &Apache::loncommon::start_page("What's New?", 338: $scripttag); 339: } 340: 341: #------------------------------- 342: # display_actions_box 343: # 344: # Display the action items 345: # 346: #------------------------------- 347: 348: sub display_actions_box { 349: my ($r,$command,$refpage,$threshold_titles,$interval_titles,$initpage, 350: $cdom,$crs,$checkallowed) = @_; 351: my $custommenu = &Apache::loncommon::needs_gci_custom(); 352: my $udom = $env{'user.domain'}; 353: my $uname = $env{'user.name'}; 354: my $cid = $env{'request.course.id'}; 355: my $crstype = &Apache::loncommon::course_type(); 356: my $lctype = lc($crstype); 357: my %stulabel = ( 358: 'Course' => 'students', 359: 'Community' => 'members', 360: ); 361: my %lt = &Apache::lonlocal::texthash( 362: 'yacc' => 'You are accessing an invalid course', 363: 'gtfr' => 'Go to first resource', 364: 'hial' => 'Hide all', 365: 'shal' => 'Show all', 366: ); 367: 368: my %unread = (); 369: my %ungraded = (); 370: my %bombed = (); 371: my %triggered = (); 372: my %changed = (); 373: my @newmsgs = (); 374: my @critmsgs = (); 375: my @newdiscussions = (); 376: my @tograde = (); 377: my @bombs = (); 378: my @warnings = (); 379: my $msgcount = 0; 380: my $critmsgcount = 0; 381: my $expirecount; 382: my %expired; 383: my $activecount; 384: my %activated; 385: my %loggedin; 386: my $logincount; 387: my %res_title = (); 388: my %show = (); 389: my $needitems = 0; 390: my $boxcount = 0; 391: 392: my $result; 393: if ($command eq 'newcourseinit') { 394: $result = &store_courseinit_setting($uname,$udom,$cid,$initpage); 395: } 396: 397: my %threshold = (); 398: my %pagedesc = &Apache::lonlocal::texthash ( 399: firstres => 'First resource', 400: whatsnew => "What's New Page", 401: userpref => 'user preference', 402: coursespecific => $lctype.' only', 403: default => 'default', 404: ); 405: 406: my ($initcontrol,$initdisp) = &curr_courseinit(); 407: my $currinit = $pagedesc{$initdisp}.' ('.$pagedesc{$initcontrol}.')'; 408: 409: unless ($cid) { 410: $r->print('<p><span style="text-align: center; font-weight: bold;">'.$lt{'yacc'}.'</span></p>'); 411: return; 412: } 413: 414: my $header = ''; 415: if (($refpage eq 'start') && (!$custommenu)) { 416: if (tie(my %bighash,'GDBM_File',$env{'request.course.fn'}.'.db', 417: &GDBM_READER(),0640)) { 418: my $furl=&HTML::Entities::encode($bighash{'first_url'},'"<>&'); 419: untie(%bighash); 420: $header .= '<b><a href="'.$furl.'">'.$lt{'gtfr'}. 421: '</a></b><br />'; 422: } 423: } 424: unless ($custommenu) { 425: $header .= &mt('Page set to be displayed after you have selected a role in this '.$lctype).'.' 426: .' <span class="LC_nobreak">' 427: .&mt('Currently: [_1].','<i>'.$currinit.'</i>') 428: .' ' 429: .&mt('[_1]Change[_2] for just [_3]this '.$lctype.'[_4] or for [_5]all your courses/communities[_6].' 430: ,'<b>' 431: ,'</b>' 432: ,'<a href="/adm/whatsnew?command=courseinit&refpage='.$refpage.'">' 433: ,'</a>' 434: ,'<a href="/adm/preferences?action=changecourseinit&refpage='.$refpage.'">' 435: ,'</a>') 436: .' </span>'; 437: 438: $r->print(&Apache::loncommon::head_subbox($header)); 439: } 440: 441: if ($command eq 'reset') { 442: $result = &process_reset($cdom,$crs); 443: } elsif ($command eq 'update') { 444: $result = &process_update($uname,$udom,$threshold_titles); 445: } elsif ($command eq 'newinterval') { 446: $result = &store_interval_setting($uname,$udom,$cid,$interval_titles); 447: } elsif ($command eq 'newdiscconf') { 448: $result = &store_discussion_setting($uname,$udom,$cid); 449: } 450: 451: my $store_result=&store_display_settings($uname,$udom,$cid,$checkallowed); 452: 453: unless ($store_result eq 'ok') { 454: &Apache::lonnet::logthis('Error saving whatsnew settings: '. 455: $store_result.' for '.'user '.$uname.':'.$udom.' in '.$lctype.' '.$cid); 456: $result .= '<span class="LC_error">' 457: .&mt('Unable to save visibility settings due to [_1]', 458: $store_result) 459: .'</span>'; 460: } 461: 462: if ($result) { 463: $r->print($result.'<hr />'); 464: } 465: $r->rflush(); 466: 467: my (%timediff,%interval); 468: my %display_settings = &get_display_settings($uname,$udom,$cid); 469: $timediff{'versions'} = $display_settings{$cid.':interval'}; 470: unless (defined($timediff{'versions'})) { $timediff{'versions'} = 604800; } 471: $interval{'versions'} = $interval_titles->{'versions'}->{$timediff{'versions'}}; 472: 473: my %headings = &Apache::lonlocal::texthash( 474: coursediscussion => 'Unread '.$lctype.' discussion posts', 475: handgrading => 'Problems requiring handgrading', 476: haserrors => 'Problems with errors', 477: coursenormalmail => 'New '.$lctype.' messages', 478: coursecritmail => 'New critical messages in '.$lctype, 479: ); 480: 481: if ($timediff{'versions'} == -1) { 482: $headings{'versionchanges'} = &mt('Resources in '.$lctype.' with version changes since start of '.$lctype); 483: } elsif ($timediff{'versions'} == 2592000) { 484: $headings{'versionchanges'} = &mt('Resources in '.$lctype.' with version changes since last month'); 485: } elsif ($timediff{'versions'} == 604800) { 486: $headings{'versionchanges'} = &mt('Resources in '.$lctype.' with version changes since last week'); 487: } elsif ($timediff{'versions'} == 86400) { 488: $headings{'versionchanges'} = &mt('Resources in '.$lctype.' with version changes since yesterday'); 489: } 490: 491: $timediff{'oldroles'} = $display_settings{$cid.':oldroleinterval'}; 492: unless (defined($timediff{'oldroles'})) { $timediff{'oldroles'} = 604800; } 493: $interval{'oldroles'} = $interval_titles->{'oldroles'}->{$timediff{'oldroles'}}; 494: 495: if ($timediff{'oldroles'} == -1) { 496: $headings{'oldroles'} = &mt('Roles for which access to '.$lctype.' has expired since start of '.$lctype); 497: } elsif ($timediff{'oldroles'} == 2592000) { 498: $headings{'oldroles'} = &mt('Roles for which access to '.$lctype.' has expired since last month'); 499: } elsif ($timediff{'oldroles'} == 604800) { 500: $headings{'oldroles'} = &mt('Roles for which access to '.$lctype.' has expired since last week'); 501: } elsif ($timediff{'oldroles'} == 86400) { 502: $headings{'oldroles'} = &mt('Roles for which access to '.$lctype.' has expired since yesterday'); 503: } 504: 505: $timediff{'newroles'} = $display_settings{$cid.':newroleinterval'}; 506: unless (defined($timediff{'newroles'})) { $timediff{'newroles'} = 604800; } 507: $interval{'newroles'} = $interval_titles->{'newroles'}->{$timediff{'newroles'}}; 508: 509: if ($timediff{'newroles'} == -1) { 510: $headings{'newroles'} = &mt('Roles for which access to '.$lctype.' has become available since start of '.$lctype); 511: } elsif ($timediff{'newroles'} == 2592000) { 512: $headings{'newroles'} = &mt('Roles for which access to '.$lctype.' has become available since last month'); 513: } elsif ($timediff{'newroles'} == 604800) { 514: $headings{'newroles'} = &mt('Roles for which access to '.$lctype.' has become available since last week'); 515: } elsif ($timediff{'newroles'} == 86400) { 516: $headings{'newroles'} = &mt('Roles for which access to '.$lctype.' has become available since yesterday'); 517: } 518: 519: $timediff{'crslogin'} = $display_settings{$cid.':crslogininterval'}; 520: unless (defined($timediff{'crslogin'})) { $timediff{'crslogin'} = 604800; } 521: $interval{'crslogin'} = $interval_titles->{'crslogin'}->{$timediff{'crslogin'}}; 522: 523: if ($timediff{'crslogin'} == -1) { 524: $headings{'crslogin'} = &mt('Last login for anyone who has ever logged in'); 525: } elsif ($timediff{'crslogin'} == 2592000) { 526: $headings{'crslogin'} = &mt('Last login for users in last 30 days'); 527: } elsif ($timediff{'crslogin'} == 604800) { 528: $headings{'crslogin'} = &mt('Last login for users in last 7 days'); 529: } elsif ($timediff{'crslogin'} == 86400) { 530: $headings{'crslogin'} = &mt('Last login for users in last 24 hours'); 531: } 532: 533: my $now = time; 534: if ($timediff{'versions'} == -1) { 535: $timediff{'versions'} = time; 536: } 537: my $starttime = $now - $timediff{'versions'}; 538: 539: if ($timediff{'newroles'} == -1) { 540: $timediff{'newroles'} = time; 541: } 542: my $activatedstart = $now - $timediff{'newroles'}; 543: 544: if ($timediff{'oldroles'} == -1) { 545: $timediff{'oldroles'} = time; 546: } 547: 548: my $expiredstart = $now - $timediff{'oldroles'}; 549: 550: if ($timediff{'crslogin'} == -1) { 551: $timediff{'crslogin'} = time; 552: } 553: 554: my $crsloginstart = $now - $timediff{'crslogin'}; 555: 556: my $countunread = $display_settings{$cid.':countunread'}; 557: unless (defined($countunread)) { 558: $countunread = 'on'; 559: } 560: if ($$checkallowed{'abovethreshold'}) { 561: &get_curr_thresholds(\%threshold,$uname,$udom,$cid,$cdom,$crs,$custommenu); 562: } 563: 564: if ($custommenu) { 565: $headings{'abovethreshold'} = &mt('Questions with submissions'); 566: } else { 567: $headings{'abovethreshold'} = 568: &mt('(Problems with av. attempts ≥ [_1] or deg. difficulty ≥ [_2]) [_3] and total number of '.$stulabel{$crstype}.' with submissions ≥ [_4]', 569: $threshold{'av_attempts'},$threshold{'degdiff'}, 570: '<br />',$threshold{'numstudents'}); 571: } 572: 573: my @actionorder; 574: if ($custommenu) { 575: @actionorder = ('coursenormalmail','coursecritmail','abovethreshold','newroles','oldroles','crslogin'); 576: } else { 577: @actionorder = ('handgrading','haserrors','abovethreshold','versionchanges','coursediscussion','coursenormalmail','coursecritmail','newroles','oldroles'); 578: } 579: 580: foreach my $key (keys(%{$checkallowed})) { 581: if ($key =~ /_section$/) { next; } 582: $show{$key} = 0; 583: if ($$checkallowed{$key}) { 584: unless ($display_settings{$cid.':'.$key} eq 'hide') { 585: $show{$key} = 1; 586: } 587: } 588: } 589: 590: foreach my $item (@actionorder) { 591: unless ($item eq 'coursenormalmail' || $item eq 'coursecritmail' || 592: $item eq 'newroles' || $item eq 'oldroles') { 593: if ($show{$item}) { 594: $needitems = 1; 595: last; 596: } 597: } 598: } 599: 600: my $itemserror; 601: if ($needitems) { 602: $itemserror = &getitems(\%unread,\%ungraded,\%bombed,\%triggered,\%changed,\@newdiscussions,\@tograde,\@bombs,\@warnings,\%threshold,$cdom,$crs,\%res_title,\%show,$starttime,$countunread,$custommenu); 603: } 604: if ($show{'coursenormalmail'}) { 605: $msgcount = &getnormalmail(\@newmsgs); 606: } 607: if ($show{'coursecritmail'}) { 608: $critmsgcount = &getcritmail(\@critmsgs); 609: } 610: if ($show{'oldroles'}) { 611: $expirecount = &getexpired(\%expired,$expiredstart,'previous'); 612: } 613: if ($show{'newroles'}) { 614: $activecount = &getactivated(\%activated,$activatedstart,'active'); 615: } 616: if ($show{'crslogin'}) { 617: $logincount = &getloggedin($cdom,$crs,\%loggedin,$crsloginstart); 618: } 619: 620: $r->print(qq|<a href="javascript:changeAll('hide');">$lt{'hial'}</a> 621: <a href="javascript:changeAll('show');">$lt{'shal'}</a> 622: <form method="post" name="visible" action="/adm/whatsnew">\n|); 623: foreach my $item (keys(%{$checkallowed})) { 624: if ($item =~ /_section$/) { next; } 625: if ($$checkallowed{$item}) { 626: $r->print('<input type="hidden" name="display_'.$item.'" />'."\n"); 627: } 628: } 629: 630: $r->print('<input type="hidden" name="refpage" value="'.$refpage.'" />'); 631: unless($custommenu) { 632: $r->print('</form>'); 633: } 634: $r->print('<table class="LC_double_column"><tr><td class="LC_left_col">'); 635: 636: my $displayed = 0; 637: my $totalboxes = 0; 638: foreach my $key (keys(%{$checkallowed})) { 639: if ($key =~ /_section$/) { next; } 640: if ($key eq 'whatsnew' ) { next; } # whatsnew check creates no box 641: if ($$checkallowed{$key}) { 642: $totalboxes ++; 643: } 644: } 645: my $halfway = 4; 646: # my $halfway = int($totalboxes/2) + $totalboxes%2; 647: if ($custommenu) { 648: $halfway = 3; 649: } 650: foreach my $actionitem (@actionorder) { 651: if ($$checkallowed{$actionitem}) { 652: if ($displayed == $halfway) { 653: $r->print('</td><td> </td><td class="LC_right_col" >'); 654: } 655: &display_launcher($r,$actionitem,$refpage,$checkallowed,\%show,\%headings,\%res_title,\@tograde,\%ungraded,\@bombs,\%bombed,\%changed,\@warnings,\%triggered,\@newdiscussions,\%unread,$msgcount,\@newmsgs,$critmsgcount,\@critmsgs,\%interval,$countunread,\%expired,$expirecount,\%activated,$activecount,$crstype,$itemserror,\%loggedin,$logincount,$custommenu); 656: $displayed ++; 657: } 658: } 659: $r->print(' 660: </td> 661: </tr> 662: </table> 663: '); 664: if ($custommenu) { 665: $r->print("</form>\n"); 666: } 667: } 668: 669: #------------------------------- 670: # display_threshold_config 671: # 672: # Display the threshold setting screen 673: # 674: #------------------------------- 675: 676: sub display_threshold_config { 677: my ($r,$refpage,$threshold_titles,$cdom,$crs) = @_; 678: my $uname = $env{'user.name'}; 679: my $udom = $env{'user.dom'}; 680: my $cid = $env{'request.course.id'}; 681: my %threshold = (); 682: my $rowColor1 = "#ffffff"; 683: my $rowColor2 = "#eeeeee"; 684: my $rowColor; 685: 686: my @thresholditems = ("av_attempts","degdiff","numstudents"); 687: my %threshold_titles = &Apache::lonlocal::texthash( 688: av_attempts => 'Average number of attempts', 689: degdiff => 'Degree of difficulty', 690: numstudents => 'Total number of students with submissions', 691: ); 692: &get_curr_thresholds(\%threshold,$uname,$udom,$cid,$cdom,$crs); 693: 694: $r->print('<br /><form name="thresholdform" method="post" action="/adm/whatsnew">'. 695: &Apache::loncommon::start_data_table(). 696: &Apache::loncommon::start_data_table_header_row(). 697: '<th>'.&mt('Threshold Name').'</th>'."\n". 698: '<th>'.&mt('Current value').'</th>'."\n". 699: '<th>'.&mt('Change?').'</th>'."\n". 700: &Apache::loncommon::end_data_table_header_row()); 701: foreach my $type (@thresholditems) { 702: my $parameter = $env{'request.course.id'}.':threshold_'.$type; 703: # onchange is javascript to automatically check the 'Set' button. 704: my $onchange = 'onFocus="javascript:window.document.forms'. 705: "['thresholdform'].elements['".$parameter."_setparmval']". 706: '.checked=true;"'; 707: $r->print(&Apache::loncommon::start_data_table_row()."\n". 708: '<td>'.$threshold_titles{$type}.'</td>'."\n". 709: '<td>'.&Apache::lonhtmlcommon::textbox($parameter.'_value', 710: $threshold{$type}, 711: 10,$onchange).'</td>'."\n". 712: '<td>'. 713: &Apache::lonhtmlcommon::checkbox($parameter.'_setparmval'). 714: '</td>'."\n". 715: &Apache::loncommon::end_data_table_row()); 716: } 717: $r->print(&Apache::loncommon::end_data_table()."\n". 718: '<br /><input type="submit" name="threshold" value="'.&mt('Save').'" /> 719: <input type="hidden" name="command" value="update" /> 720: <input type="hidden" name="refpage" value="'.$refpage.'" /> 721: </form>'); 722: } 723: 724: #------------------------------- 725: # display_interval_config 726: # 727: # Display the interval setting screen 728: # 729: #------------------------------- 730: 731: sub display_interval_config { 732: my ($r,$refpage,$interval_titles,$context) = @_; 733: my $setting = 'interval'; 734: if ($context eq 'oldroles') { 735: $setting = 'oldroleinterval'; 736: } elsif ($context eq 'newroles') { 737: $setting = 'newroleinterval'; 738: } 739: my $lctype = lc(&Apache::loncommon::course_type()); 740: my $current = &get_current($env{'user.name'},$env{'user.domain'}, 741: $env{'request.course.id'},$setting); 742: if ($context eq 'oldroles') { 743: $r->print('<br />'.&mt('Choose the time window to use to display roles for which access to the '.$lctype.' expired.').'<br />'); 744: } elsif ($context eq 'newroles') { 745: $r->print('<br />'.&mt('Choose the time window to use to display roles for which access to the '.$lctype.' became available.').'<br />'); 746: } elsif ($context eq 'crslogin') { 747: $r->print('<br />'.&mt('Choose the time window to use to display the last login by a user in the '.$lctype).'<br />'); 748: } else { 749: $r->print('<br />'.&mt('Choose the time window to use to display resources in the '.$lctype.' with version changes.').'<br />'); 750: } 751: unless ($current eq '') { 752: if (ref($interval_titles->{$context}) eq 'HASH') { 753: $r->print(' '.&mt('Current value is "[_1]".','<b>'. 754: $interval_titles->{$context}->{$current}.'</b>').'<br />'); 755: } 756: } 757: $r->print('<br /> 758: <form method="post" name="intervalswitch" action="/adm/whatsnew"> 759: <input type="hidden" name="command" value="newinterval" /> 760: <input type="hidden" name="intervaltype" value="'.$context.'" /> 761: <input type="hidden" name="refpage" value="'.$refpage.'" />'. 762: &mt('Display:').' 763: <select name="interval"> 764: <option value="" selected="selected">'.&mt('Select').'</option> 765: '); 766: if (ref($interval_titles) eq 'HASH') { 767: if (ref($interval_titles->{$context}) eq 'HASH') { 768: foreach my $key (reverse sort ({$a cmp $b} (keys(%{$interval_titles->{$context}})))) { 769: $r->print('<option value="'.$key.'">'.&mt($interval_titles->{$context}->{$key}). 770: '</option>'."\n"); 771: } 772: } 773: } 774: $r->print('</select> 775: <input type="submit" name="display" value="'. 776: &mt('Save').'" /></form>'); 777: return; 778: } 779: 780: #---------------------------------------------- 781: # display_discussion_config 782: # 783: # Display the discussion display setting screen 784: # 785: #---------------------------------------------- 786: 787: sub display_discussion_config { 788: my ($r,$refpage) = @_; 789: my $current = &get_current($env{'user.name'},$env{'user.domain'}, 790: $env{'request.course.id'},'countunread'); 791: if ($current eq '') { 792: $current = 'on'; 793: } 794: my %opposite = ( 795: 'on' => 'off', 796: 'off' => 'on', 797: ); 798: $r->print('<script type="text/javascript"> 799: // <![CDATA[ 800: function toggle_countunread(choice) { 801: if (choice == "unchanged") { 802: document.discussionswitch.command.value = ""; 803: } 804: document.discussionswitch.submit(); 805: } 806: // ]]> 807: </script>'); 808: $r->print('<br />' 809: .&mt('Choose whether or not to display a count of the number of new posts for each resource or discussion board which has unread posts.') 810: .'<br />' 811: .&mt("This can increase the time taken to gather data for the [_1]What's New Page[_2] by a few seconds.",'<i>','</i>') 812: .' ' 813: .&mt('Currently set to [_1].','<b>'.$current.'</b>.') 814: ); 815: $r->print('<br /><br /> 816: <form method="post" name="discussionswitch" action="/adm/whatsnew"> 817: <input type="hidden" name="command" value="newdiscconf" /> 818: <input type="hidden" name="refpage" value="'.$refpage.'" /> 819: <input type="hidden" name="countunread" value="'.$opposite{$current}.'" /> 820: '); 821: $r->print('<br/> 822: <input type="button" name="display" value="'. 823: &mt('Change to [_1]',&mt($opposite{$current})).'" 824: onclick="javascript:toggle_countunread('."'change'".')" />'. 825: (' ' x7). 826: '<input type="button" name="nochange" value="'. 827: &mt("No change").'" 828: onclick="javascript:toggle_countunread('."'unchanged'".')" /> 829: </form>'); 830: return; 831: } 832: 833: #--------------------------------------------------- 834: # courseinit_config 835: # 836: # Set page displayed when course loads after 837: # selecting a role in the course from the roles page. 838: # 839: #--------------------------------------------------- 840: 841: sub courseinit_config { 842: my ($r,$refpage,$initpage) = @_; 843: my ($control,$current) = &curr_courseinit(); 844: my @chgstate = ('userpref','coursespecific'); 845: my @chgentry = ('firstres','whatsnew'); 846: my $lctype = lc(&Apache::loncommon::course_type()); 847: my %lt = &Apache::lonlocal::texthash( 848: 'chwp' => "Choose which page will be displayed when you enter this $lctype after selecting a role.", 849: 'cuva' => 'Current value is determined by', 850: 'anis' => 'and is set to display', 851: 'padc' => 'Page display controlled by', 852: 'chce' => 'Choose '.$lctype.' entry', 853: 'moce' => 'Save', 854: ); 855: $r->print(<<"END"); 856: <br />$lt{'chwp'} 857: <br />$lt{'cuva'}: <b> 858: $$initpage{$control}</b> $lt{'anis'} <b> 859: $$initpage{$current}</b>.<br /><br /> 860: <form method="post" name="courseinitswitch" action="/adm/whatsnew"> 861: <input type="hidden" name="command" value="newcourseinit" /> 862: <input type="hidden" name="refpage" value="$refpage" /> 863: $lt{'padc'}: 864: END 865: foreach my $choice (@chgstate) { 866: my $chkstring; 867: if ($choice eq $control) { 868: $chkstring = ' checked="checked" '; 869: } 870: $r->print('<span class="LC_nobreak"><label><input type="radio" name="courseinit_control" value="'. 871: $choice.'"'.$chkstring.'/>'.$$initpage{$choice}. 872: ' </label></span>'); 873: } 874: $r->print('<br /><br />'.&mt('If').' '.$$initpage{'coursespecific'}. 875: ' - <br />'.$lt{'chce'}.": \n"); 876: foreach my $choice (@chgentry) { 877: my $chkstring; 878: if (($choice eq $current) && ($control eq 'coursespecific')) { 879: $chkstring = ' checked="checked" '; 880: } 881: $r->print('<span class="LC_nobreak"><label><input type="radio" name="courseinit_page" value="'. 882: $choice.'"'.$chkstring.'/>'.$$initpage{$choice}. 883: ' </label></span>'); 884: } 885: $r->print('<br /><br /><input type="submit" name="display" value="'. 886: $lt{'moce'}.'" /></form>'); 887: return; 888: } 889: 890: sub curr_courseinit { 891: my $current = &get_current($env{'user.name'},$env{'user.domain'}, 892: $env{'request.course.id'},'courseinit'); 893: my $control; 894: if ($current) { 895: $control = 'coursespecific'; 896: } else { 897: $control = 'userpref'; 898: my %userenv = &Apache::lonnet::get('environment', 899: ['course_init_display']); 900: if (exists($userenv{'course_init_display'})) { 901: $current = $userenv{'course_init_display'}; 902: } 903: unless ($current) { 904: $current = 'whatsnew'; 905: } 906: } 907: return ($control,$current); 908: } 909: 910: sub display_launcher { 911: my ($r,$action,$refpage,$checkallowed,$show,$headings,$res_title, 912: $tograde,$ungraded,$bombs,$bombed,$changed,$warnings,$triggered, 913: $newdiscussions,$unread,$msgcount,$newmsgs,$critmsgcount,$critmsgs, 914: $interval,$countunread,$expired,$expirecount,$activated,$activecount, 915: $crstype,$itemserror,$loggedin,$logincount,$custommenu) = @_; 916: 917: if ($$checkallowed{$action}) { 918: &start_box($r,$show,$headings,$action,$refpage,$action,$custommenu); 919: if ($$show{$action}) { 920: if ($action eq 'handgrading') { # UNGRADED ITEMS 921: &display_handgrade($r,$tograde,$ungraded,$itemserror); 922: } elsif ($action eq 'haserrors') { # BOMBS 923: &display_haserrors($r,$bombs,$bombed,$res_title,$itemserror); 924: } elsif ($action eq 'versionchanges') { # VERSION CHANGES 925: &display_versionchanges($r,$changed,$res_title,$interval->{'versions'},$itemserror); 926: } elsif ($action eq 'abovethreshold') { # DEGDIFF/AV. TRIES TRIGGERS 927: &display_abovethreshold($r,$refpage,$warnings,$triggered, 928: $res_title,$itemserror,$custommenu); 929: } elsif ($action eq 'coursediscussion') { # UNREAD COURSE DISCUSSION 930: &display_coursediscussion($r,$newdiscussions,$unread, 931: $countunread,$res_title,$itemserror); 932: } elsif ($action eq 'coursenormalmail') { # NORMAL MESSAGES 933: &display_coursenormalmail($r,$msgcount,$newmsgs); 934: } elsif ($action eq 'coursecritmail') { # CRITICAL MESSAGES 935: &display_coursecritmail($r,$critmsgcount,$critmsgs); 936: } elsif ($action eq 'newroles') { # ACTIVATED ROLES 937: &display_rolechanges($r,$activecount,$activated,$interval->{'newroles'}, 938: $crstype); 939: } elsif ($action eq 'oldroles') { # EXPIRED ROLES 940: &display_rolechanges($r,$expirecount,$expired,$interval->{'oldroles'}, 941: $crstype); 942: } elsif ($action eq 'crslogin') { #LAST LOGIN 943: &display_crslogins($r,$logincount,$loggedin,$interval->{'crslogin'}, 944: $crstype); 945: 946: } 947: } 948: &end_box($r); 949: } 950: return; 951: } 952: 953: sub getitems { 954: my ($unread,$ungraded,$bombed,$triggered,$changed,$newdiscussions, 955: $tograde,$bombs,$warnings,$threshold,$cdom,$crs,$res_title,$show, 956: $starttime,$countunread,$custommenu) = @_; 957: my $navmap = Apache::lonnavmaps::navmap->new(); 958: if (!defined($navmap)) { 959: my $itemserror = '<span class="LC_warning">'.&mt('An error occurred retrieving information about the course.').'<br />'.&mt('It is recommended that you [_1]re-select the course[_2].','<a href="/adm/roles">','</a>').'</span>'; 960: return $itemserror; 961: } 962: # force retrieve Resource to seed the part id cache we'll need it later 963: my @allres=$navmap->retrieveResources(undef, 964: sub {if ($_[0]->is_problem) { $_[0]->parts();} return 1;}); 965: my %resourcetracker; 966: my $discussiontime; 967: 968: # Resource version changes 969: if ($$show{'versionchanges'}) { 970: &checkversions($cdom,$crs,$navmap,$changed,$starttime); 971: } 972: 973: if ($$show{'abovethreshold'}) { 974: %resourcetracker = &Apache::lonnet::dump('nohist_resourcetracker', 975: $cdom,$crs); 976: } 977: 978: foreach my $resource (@allres) { 979: my $result = ''; 980: my $applies = 0; 981: my $symb = $resource->symb(); 982: %{$$bombed{$symb}} = (); 983: %{$$ungraded{$symb}} = (); 984: %{$$triggered{$symb}} = (); 985: $$triggered{$symb}{numparts} = 0; 986: if ($resource->encrypted()) { 987: $$triggered{$symb}{'enclink'} = $resource->link(); 988: $$triggered{$symb}{'encsymb'} = $resource->shown_symb(); 989: } 990: my $title = $resource->compTitle(); 991: $$res_title{$symb} = $title; 992: my $ressymb = $resource->wrap_symb(); 993: 994: # Check if there are unread discussion postings 995: if ($$show{'coursediscussion'}) { 996: &check_discussions($resource,$symb,$ressymb,$title, 997: $newdiscussions,$unread,$countunread); 998: } 999: 1000: # Check for ungraded problems 1001: if ($resource->is_problem()) { 1002: if ($$show{'handgrading'}) { 1003: &check_handgraded($resource,$symb,$title,$cdom,$crs,$ungraded, 1004: $tograde); 1005: } 1006: } 1007: 1008: # Check for bombs 1009: if ($$show{'haserrors'}) { 1010: &check_bombed($resource,$symb,$title,$bombs,$bombed); 1011: } 1012: 1013: # Maxtries and degree of difficulty for problem parts, unless handgradeable 1014: if ($$show{'abovethreshold'}) { 1015: &check_thresholds($resource,$symb,\%resourcetracker, 1016: $triggered,$threshold,$warnings,$custommenu); 1017: } 1018: 1019: } 1020: return; 1021: } 1022: 1023: sub check_discussions { 1024: my ($resource,$symb,$ressymb,$title,$newdiscussions,$unread, 1025: $countunread) = @_; 1026: 1027: if (!$resource->hasDiscussion()) { return; } 1028: 1029: %{$$unread{$ressymb}} = (); 1030: $$unread{$ressymb}{'title'} = $title; 1031: $$unread{$ressymb}{'symb'} = $symb; 1032: if ($resource->encrypted()) { 1033: $$unread{$ressymb}{'enclink'} = $resource->link(); 1034: $$unread{$ressymb}{'encsymb'} = $resource->shown_symb(); 1035: } 1036: push(@{$newdiscussions}, $ressymb); 1037: 1038: $$unread{$ressymb}{'lastpost'} = $resource->last_post_time(); 1039: 1040: if ($countunread eq 'on') { 1041: $$unread{$ressymb}{'unreadcount'} = 1042: $resource->discussion_info('unread'); 1043: } 1044: } 1045: 1046: sub check_handgraded { 1047: my ($resource,$symb,$title,$cdom,$cnum,$ungraded,$tograde) = @_; 1048: if ($resource->is_problem()) { 1049: my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); 1050: my $partlist=$resource->parts(); 1051: my $handgradeable; 1052: foreach my $part (@$partlist) { 1053: if ($resource->handgrade($part) eq 'yes') { 1054: $handgradeable=1; last; 1055: } 1056: } 1057: if ($handgradeable) { 1058: my @ungraded = &Apache::bridgetask::get_queue_symb_status( 1059: 'gradingqueue',$symb,$cdom,$cnum); 1060: if (@ungraded > 0) { 1061: $$ungraded{$symb}{count} = scalar(@ungraded); 1062: $$ungraded{$symb}{title} = $title; 1063: if ($resource->encrypted()) { 1064: $$ungraded{$symb}{'enclink'} = $resource->link(); 1065: $$ungraded{$symb}{'encsymb'} = $resource->shown_symb(); 1066: } 1067: push(@{$tograde},$symb); 1068: } 1069: } 1070: } 1071: } 1072: 1073: sub check_bombed { 1074: my ($resource,$symb,$title,$bombs,$bombed) = @_; 1075: if ($resource->getErrors()) { 1076: my $errors = $resource->getErrors(); 1077: $errors =~ s/^,//; 1078: my @bombs = split(/,/, $errors); 1079: my $errorcount = scalar(@bombs); 1080: my $errorlink = '<a href="/adm/email?display='. 1081: &escape($bombs[0]).'">'. 1082: $title.'</a>'; 1083: $$bombed{$symb}{errorcount} = $errorcount; 1084: $$bombed{$symb}{errorlink} = $errorlink; 1085: push(@{$bombs}, $symb); 1086: } 1087: } 1088: 1089: sub check_thresholds { 1090: my ($resource,$symb,$resourcetracker,$triggered,$threshold,$warnings,$custommenu) = @_; 1091: # Compile maxtries and degree of difficulty for problem parts, unless handgradeable 1092: my @parts = @{$resource->parts()}; 1093: my %stats; 1094: my %lastreset = (); 1095: my $warning = 0; 1096: foreach my $part (@parts) { 1097: if ($resource->handgrade($part) eq 'yes') { 1098: next; 1099: } 1100: if ($resource->is_survey($part)) { 1101: next; 1102: } 1103: %{$stats{$part}} = (); 1104: my ($attempts,$users,$corrects,$degdiff,$av_attempts); 1105: if (exists($$resourcetracker{$symb."\0".$part."\0attempts"})) { 1106: $attempts = $$resourcetracker{$symb."\0".$part."\0attempts"}; 1107: } 1108: if (exists($$resourcetracker{$symb."\0".$part."\0users"})) { 1109: $users = $$resourcetracker{$symb."\0".$part."\0users"}; 1110: } 1111: if (exists($$resourcetracker{$symb."\0".$part."\0correct"})) { 1112: $corrects = $$resourcetracker{$symb."\0".$part."\0correct"}; 1113: } 1114: if ($attempts > 0) { 1115: $degdiff = 1 - ($corrects/$attempts); 1116: $degdiff = sprintf("%.2f",$degdiff); 1117: } 1118: if ($users > 0) { 1119: $av_attempts = $attempts/$users; 1120: $av_attempts = sprintf("%.2f",$av_attempts); 1121: } 1122: if ((($degdiff ne '' && $degdiff >= $$threshold{'degdiff'}) || ($av_attempts ne '' && $av_attempts >= $$threshold{'av_attempts'})) && ($users >= $$threshold{'numstudents'})) { 1123: $stats{$part}{degdiff} = $degdiff; 1124: $stats{$part}{attempts} = $av_attempts; 1125: $stats{$part}{users} = $users; 1126: $lastreset{$part} = $$resourcetracker{$symb."\0".$part."\0resettime"}; 1127: if ($lastreset{$part}) { 1128: $lastreset{$part} = &Apache::lonnavmaps::timeToHumanString($lastreset{$part}); 1129: } 1130: $warning = 1; 1131: } 1132: } 1133: if ($warning) { 1134: $$triggered{$symb}{title} = $resource->title; 1135: my $partcount = 0; 1136: @{$$triggered{$symb}{text}} = (); 1137: foreach my $part (@parts) { 1138: if (exists($stats{$part}{users})) { 1139: my $resetname = 'reset_'.&escape($symb."\0".$part); 1140: my $resettitle = 'title_'.&escape($symb."\0".$part); 1141: if (@parts > 1) { 1142: $$triggered{$symb}{text}[$partcount] = ' 1143: <td>'.&mt('part - ').$part.'</td>'; 1144: } else { 1145: $$triggered{$symb}{text}[$partcount] = ' 1146: <td>'.&mt('single part').'</td>'; 1147: } 1148: if ($custommenu) { 1149: $$triggered{$symb}{text}[$partcount] .= ' 1150: <td class="LC_right_item">'.$stats{$part}{users}.'</td>'; 1151: } else { 1152: $$triggered{$symb}{text}[$partcount] .= ' 1153: <td>'.$stats{$part}{users}.'</td> 1154: <td>'.$stats{$part}{attempts}.'</td> 1155: <td>'.$stats{$part}{degdiff}.'</td> 1156: <td>'.$lastreset{$part}.'</td> 1157: <td><input type="checkbox" name="'.$resetname.'" /><input type="hidden" name="'.$resettitle.'" value="'.&escape($$triggered{$symb}{title}).'" /></td>'; 1158: } 1159: $partcount ++; 1160: } 1161: $$triggered{$symb}{numparts} = $partcount; 1162: } 1163: push(@{$warnings},$symb); 1164: } 1165: } 1166: 1167: 1168: sub get_curr_thresholds { 1169: my ($threshold,$uname,$udom,$cid,$cdom,$crs,$custommenu) = @_; 1170: if ($custommenu) { 1171: %$threshold = (av_attempts => 0, 1172: degdiff => 0.00000000000000, 1173: numstudents => 1 1174: ); 1175: return; 1176: } 1177: # set default values 1178: %$threshold = (av_attempts => 2, 1179: degdiff => 0.5, 1180: numstudents => 2 1181: ); 1182: my %thresholdsettings = &Apache::lonnet::dump('nohist_whatsnew',$udom, 1183: $uname,$cid.':threshold'); 1184: my $thresholdcount = 0; 1185: my ($tmp) = %thresholdsettings; 1186: unless ($tmp =~ /^(con_lost|error|no_such_host)/i) { 1187: foreach my $item (keys %{$threshold}) { 1188: if (exists($thresholdsettings{$cid.':threshold_'.$item})) { 1189: $$threshold{$item} = 1190: $thresholdsettings{$cid.':threshold_'.$item}; 1191: $thresholdcount ++; 1192: } 1193: } 1194: } 1195: if ($thresholdcount == 3) { 1196: return; 1197: } 1198: my %coursesettings = &Apache::lonnet::dump('environment', 1199: $cdom,$crs,'internal.threshold'); 1200: my ($temp) = %coursesettings; 1201: unless ($temp =~ /^(con_lost|error|no_such_host)/i) { 1202: foreach my $item (keys %{$threshold}) { 1203: unless (exists($thresholdsettings{$cid.':threshold_'.$item})) { 1204: if (exists($coursesettings{'internal.threshold_'.$item})) { 1205: $$threshold{$item} = 1206: $coursesettings{'internal.threshold_'.$item}; 1207: } 1208: } 1209: } 1210: } 1211: return; 1212: } 1213: 1214: sub get_current { 1215: my ($uname,$udom,$cid,$caller) = @_; 1216: my $currvalue; 1217: my %settings = &Apache::lonnet::dump('nohist_whatsnew',$udom,$uname,$cid. 1218: ':'.$caller); 1219: my ($tmp) = %settings; 1220: unless ($tmp =~ /^(con_lost|error|no_such_host)/i) { 1221: $currvalue = $settings{$cid.':'.$caller}; 1222: } 1223: return $currvalue; 1224: } 1225: 1226: sub process_reset { 1227: my ($dom,$crs) = @_; 1228: my $result = '<b>'.&mt('Counters reset for following problems (and parts):'). 1229: '</b><br />'; 1230: my @agg_types = ('attempts','users','correct'); 1231: my %agg_titles = &Apache::lonlocal::texthash ( 1232: attempts => 'Number of submissions', 1233: users => 'Students with submissions', 1234: correct => 'Number of correct submissions', 1235: ); 1236: my @resets = (); 1237: my %titles = (); 1238: foreach my $key (keys(%env)) { 1239: next if ($key !~ /^form\.reset_(.+)$/); 1240: my $title = &unescape($env{'form.title_'.$1}); 1241: my $reset_item = &unescape($1); 1242: my %curr_aggregates = &Apache::lonnet::dump('nohist_resourcetracker',$dom,$crs,$reset_item); 1243: my %aggregates = (); 1244: my ($symb,$part) = split(/\0/,$reset_item); 1245: foreach my $type (@agg_types) { 1246: $aggregates{$reset_item."\0".$type} = 0; 1247: } 1248: $aggregates{$reset_item."\0".'resettime'} = time; 1249: my $putresult = &Apache::lonnet::put('nohist_resourcetracker',\%aggregates, 1250: $dom,$crs); 1251: if ($putresult eq 'ok') { 1252: $result .= $title.' -part '.$part.': '; 1253: my %new_aggregates = &Apache::lonnet::dump('nohist_resourcetracker',$dom,$crs,$reset_item); 1254: foreach my $type (@agg_types) { 1255: $result .= $agg_titles{$type}.' = '.$new_aggregates{$reset_item."\0".$type}.'; '; 1256: } 1257: $result =~ s/; $//; 1258: $result .= '<br />'; 1259: } else { 1260: $result = $title.' -part '.$part.': '.&mt('Unable to reset counters to zero due to [_1]',$putresult).'.<br />'."\n"; 1261: } 1262: } 1263: return $result; 1264: } 1265: 1266: sub process_update { 1267: my ($uname,$udom,$threshold_titles) = @_; 1268: my $setoutput = '<b>'.&mt('Changes to threshold(s) for problem tracking:').'</b><br />'; 1269: foreach (keys %env) { 1270: next if ($_!~/^form\.(.+)\_setparmval$/); 1271: my $name = $1; 1272: my $value = $env{'form.'.$name.'_value'}; 1273: if ($name && defined($value) && ($value ne '')) { 1274: my $put_result = &Apache::lonnet::put('nohist_whatsnew', 1275: {$name=>$value},$udom,$uname); 1276: 1277: my ($shortname) = ($name =~ /^\Q$env{'request.course.id'}\E:threshold_(.+)$/); 1278: if ($put_result eq 'ok') { 1279: $setoutput.=&mt('Set threshold for [_1] to [_2]', 1280: '<b>'.$$threshold_titles{$shortname}.'</b>', 1281: '<b>'.$value.'</b>').'<br />'; 1282: } else { 1283: $setoutput.=&mt('Unable to set threshold for [_1] to [_2] due to [_3].', 1284: '<b>'.$name.'</b>','<b>'.$value.'</b>', 1285: '<tt>'.$put_result.'</tt>').'<br />'; 1286: } 1287: } 1288: } 1289: return $setoutput; 1290: } 1291: 1292: sub getnormalmail { 1293: my ($newmsgs) = @_; 1294: # Check for unread mail in course 1295: my $msgcount = 0; 1296: 1297: my @messages = sort(&Apache::lonnet::getkeys('nohist_email')); 1298: foreach my $message (@messages) { 1299: my $msgid=&escape($message); 1300: my ($sendtime,$shortsubj,$fromname,$fromdom,$status,$fromcid)= 1301: &Apache::lonmsg::unpackmsgid($msgid); 1302: if (($fromcid) && ($fromcid eq $env{'request.course.id'})) { 1303: if (defined($sendtime) && $sendtime!~/error/) { 1304: my $numsendtime = $sendtime; 1305: if ($status eq 'new') { 1306: $sendtime = &Apache::lonlocal::locallocaltime($sendtime); 1307: $msgcount ++; 1308: if ($shortsubj eq '') { 1309: $shortsubj = &mt('No subject'); 1310: } 1311: push(@{$newmsgs}, { 1312: msgid => $msgid, 1313: sendtime => $sendtime, 1314: shortsub => $shortsubj, 1315: from => $fromname, 1316: fromdom => $fromdom 1317: }); 1318: } 1319: } 1320: } 1321: } 1322: return $msgcount; 1323: } 1324: 1325: sub getcritmail { 1326: my ($critmsgs) = @_; 1327: # Check for critical messages in course 1328: my %what=&Apache::lonnet::dump('critical'); 1329: my $result = ''; 1330: my $critmsgcount = 0; 1331: foreach my $msgid (sort(keys(%what))) { 1332: my ($sendtime,$shortsubj,$fromname,$fromdom,$status,$fromcid)= 1333: &Apache::lonmsg::unpackmsgid($msgid); 1334: if (($fromcid) && ($fromcid eq $env{'request.course.id'})) { 1335: if (defined($sendtime) && $sendtime!~/error/) { 1336: my $numsendtime = $sendtime; 1337: $sendtime = &Apache::lonlocal::locallocaltime($sendtime); 1338: $critmsgcount ++; 1339: if ($shortsubj eq '') { 1340: $shortsubj = &mt('No subject'); 1341: } 1342: push(@{$critmsgs}, { 1343: msgid => $msgid, 1344: sendtime => $sendtime, 1345: shortsub => $shortsubj, 1346: from => $fromname, 1347: fromdom => $fromdom 1348: }); 1349: } 1350: } 1351: } 1352: return $critmsgcount; 1353: } 1354: 1355: sub getexpired { 1356: my ($rolechgs,$rolechgtime,$status) = @_; 1357: my $expirecount = &getrolechanges($rolechgs,$rolechgtime,$status); 1358: return $expirecount; 1359: } 1360: 1361: sub getactivated { 1362: my ($rolechgs,$rolechgtime,$status) = @_; 1363: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; 1364: my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; 1365: my $now = time(); 1366: my $context = 'course'; 1367: my ($permission,$allowed) = 1368: &Apache::lonuserutils::get_permission($context); 1369: my $viewablesec = &Apache::lonuserutils::viewable_section($permission); 1370: my %changes=&Apache::lonnet::dump('nohist_rolelog',$cdom,$cnum); 1371: my (%stucounted,%advcounted); 1372: my $activatedcount = 0; 1373: if (keys(%changes) > 0) { 1374: foreach my $chg (sort { $b <=> $a } (keys(%changes))) { 1375: if (ref($changes{$chg}) eq 'HASH') { 1376: my $timestamp = $changes{$chg}{'exe_time'}; 1377: if ($timestamp) { 1378: if ($rolechgtime > 0) { 1379: if ($timestamp < $rolechgtime) { 1380: last; 1381: } 1382: } 1383: if (ref($changes{$chg}{'logentry'}) eq 'HASH') { 1384: next if ($changes{$chg}{'delflag'}); 1385: my $start = $changes{$chg}{'logentry'}{'start'}; 1386: my $end = $changes{$chg}{'logentry'}{'end'}; 1387: my $section = $changes{$chg}{'logentry'}{'section'}; 1388: my $role = $changes{$chg}{'logentry'}{'role'}; 1389: my $uname = $changes{$chg}{'uname'}; 1390: my $udom = $changes{$chg}{'udom'}; 1391: next if ($end && $end <= $now); 1392: if (($viewablesec ne '') && ($section ne '')) { 1393: next if ($viewablesec ne $section); 1394: } 1395: next if ($start >= $timestamp); 1396: if ($role eq 'st') { 1397: $stucounted{$uname.':'.$udom.':'.$section} = $start.':'.$end; 1398: } else { 1399: $advcounted{$uname.':'.$udom.':'.$role.':'.$section} = $start.':'.$end; 1400: } 1401: my %chginfo = ( 1402: 'section' => $section, 1403: 'uname' => $uname, 1404: 'udom' => $udom, 1405: 'role' => $role, 1406: 'status' => $status, 1407: ); 1408: $activatedcount ++; 1409: push (@{$rolechgs->{$timestamp}},\%chginfo); 1410: } 1411: } 1412: } 1413: } 1414: } 1415: $activatedcount += &getrolechanges($rolechgs,$rolechgtime,$status,\%stucounted,\%advcounted); 1416: return $activatedcount; 1417: } 1418: 1419: sub getrolechanges { 1420: my ($rolechgs,$rolechgtime,$status,$stucountref,$advcountref) = @_; 1421: my (%stucounted,%advcounted); 1422: if (ref($stucountref) eq 'HASH') { 1423: %stucounted = %{$stucountref}; 1424: } 1425: if (ref($advcountref) eq 'HASH') { 1426: %advcounted = %{$advcountref}; 1427: } 1428: my $withsec = 1; 1429: my $hidepriv = 1; 1430: my $context = 'course'; 1431: my @statuses = ($status); 1432: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; 1433: my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; 1434: my $now = time(); 1435: my ($permission,$allowed) = 1436: &Apache::lonuserutils::get_permission($context); 1437: my $viewablesec = &Apache::lonuserutils::viewable_section($permission); 1438: my $classlist = &Apache::loncoursedata::get_classlist(); 1439: my $secidx = &Apache::loncoursedata::CL_SECTION(); 1440: my $startidx = &Apache::loncoursedata::CL_START(); 1441: my $endidx = &Apache::loncoursedata::CL_END(); 1442: my $rolechgcount = 0; 1443: foreach my $key (keys(%{$classlist})) { 1444: my ($userstatus,$eventtime); 1445: my $student = $classlist->{$key}; 1446: if (ref($student) eq 'ARRAY') { 1447: my $start = $student->[$startidx]; 1448: my $end = $student->[$endidx]; 1449: my $sec = $student->[$secidx]; 1450: my ($stuname,$studom) = split(/:/,$key); 1451: if ($status eq 'active') { 1452: if (exists($stucounted{$key.':'.$sec})) { 1453: next; 1454: } 1455: } 1456: if (($end == 0) || ($end > $start)) { 1457: if ($start <= $now) { 1458: if ($end && $end < $now) { 1459: if ($rolechgtime > 0) { 1460: if ($end > $rolechgtime) { 1461: $userstatus = 'previous'; 1462: } 1463: } else { 1464: $userstatus = 'previous'; 1465: } 1466: } else { 1467: if ($rolechgtime > 0) { 1468: if ($start >= $rolechgtime) { 1469: $userstatus = 'active'; 1470: } 1471: } else { 1472: $userstatus = 'active'; 1473: } 1474: } 1475: } 1476: } 1477: next if ($userstatus ne $status); 1478: if ($status eq 'active') { 1479: $eventtime = $start; 1480: } else { 1481: $eventtime = $end; 1482: } 1483: if (($viewablesec ne '') && ($sec ne '')) { 1484: next if ($viewablesec ne $sec); 1485: } 1486: my %chginfo = ( 1487: 'section' => $sec, 1488: 'uname' => $stuname, 1489: 'udom' => $studom, 1490: 'role' => 'st', 1491: 'status' => $userstatus, 1492: ); 1493: $rolechgcount ++; 1494: push (@{$rolechgs->{$eventtime}},\%chginfo); 1495: } 1496: } 1497: my %advrolehash = &Apache::lonnet::get_my_roles($cnum,$cdom,undef, 1498: \@statuses,undef,undef,$withsec,$hidepriv); 1499: foreach my $item (keys(%advrolehash)) { 1500: my ($userstatus,$eventtime); 1501: my ($uname,$udom,$role,$section) = split(/:/,$item,-1); 1502: my ($start,$end) = split(/:/,$advrolehash{$item}); 1503: if ($start eq '-1' && $end eq '-1') { 1504: next; 1505: } else { 1506: if ($status eq 'active') { 1507: if (exists($advcounted{$item})) { 1508: next; 1509: } 1510: } 1511: if (($end == 0) || ($end > $start)) { 1512: if ($start <= $now) { 1513: if ($end && $end < $now) { 1514: if ($rolechgtime > 0) { 1515: if ($end > $rolechgtime) { 1516: $userstatus = 'previous'; 1517: } 1518: } else { 1519: $userstatus = 'previous'; 1520: } 1521: } else { 1522: if ($rolechgtime > 0) { 1523: if ($start >= $rolechgtime) { 1524: $userstatus = 'active'; 1525: } 1526: } else { 1527: $userstatus = 'active'; 1528: } 1529: } 1530: } 1531: } 1532: next if ($userstatus ne $status); 1533: if ($status eq 'active') { 1534: $eventtime = $start; 1535: } else { 1536: $eventtime = $end; 1537: } 1538: } 1539: if (($viewablesec ne '') && ($section ne '')) { 1540: next if ($viewablesec ne $section); 1541: } 1542: my %chginfo = ( 1543: 'section' => $section, 1544: 'uname' => $uname, 1545: 'udom' => $udom, 1546: 'role' => $role, 1547: 'status' => $userstatus, 1548: ); 1549: $rolechgcount ++; 1550: push (@{$rolechgs->{$eventtime}},\%chginfo); 1551: } 1552: return $rolechgcount; 1553: } 1554: 1555: sub getloggedin { 1556: my ($cdom,$crs,$lastlogins,$starttime) = @_; 1557: my $context = 'course'; 1558: my ($permission,$allowed) = 1559: &Apache::lonuserutils::get_permission($context); 1560: my $viewablesec = &Apache::lonuserutils::viewable_section($permission); 1561: my %crslogins=&Apache::lonnet::dump('nohist_crslastlogin',$cdom,$crs); 1562: my $logincount = 0; 1563: my ($tmp) = keys(%crslogins); 1564: unless ($tmp =~ /^(con_lost|error|no_such_host)/i) { 1565: if (keys(%crslogins) > 0) { 1566: foreach my $key (keys(%crslogins)) { 1567: my ($uname,$udom,$section,$role) = split(/:/,$key); 1568: my $eventtime = $crslogins{$key}; 1569: if ($eventtime > $starttime) { 1570: if (($viewablesec ne '') && ($section ne '')) { 1571: next if ($viewablesec ne $section); 1572: } 1573: my %chginfo = ( 1574: 'section' => $section, 1575: 'uname' => $uname, 1576: 'udom' => $udom, 1577: 'role' => $role, 1578: ); 1579: $logincount ++; 1580: push (@{$lastlogins->{$eventtime}},\%chginfo); 1581: } 1582: } 1583: } 1584: } 1585: return $logincount; 1586: } 1587: 1588: sub checkversions { 1589: my ($cdom,$crs,$navmap,$changed,$starttime) = @_; 1590: my %changes=&Apache::lonnet::dump('versionupdate',$cdom,$crs); 1591: my ($tmp) = keys(%changes); 1592: unless ($tmp =~ /^(con_lost|error|no_such_host)/i) { 1593: if (keys(%changes) > 0) { 1594: foreach my $key (sort(keys(%changes))) { 1595: if ($changes{$key} > $starttime) { 1596: my $version; 1597: my ($root,$extension)=($key=~/^(.*)\.(\w+)$/); 1598: my $currentversion=&Apache::lonnet::getversion($key); 1599: my $revdate = 1600: &Apache::lonnet::metadata($root.'.'.$extension, 1601: 'lastrevisiondate'); 1602: $revdate = &Apache::lonlocal::locallocaltime($revdate); 1603: my $linkurl=&Apache::lonnet::clutter($key); 1604: my $usedversion=$navmap->usedVersion('version_'.$linkurl); 1605: my @resources = $navmap->getResourceByUrl($linkurl,1); 1606: if (($usedversion) && ($usedversion ne 'mostrecent')) { 1607: $version = $usedversion; 1608: } else { 1609: $version = $currentversion; 1610: } 1611: foreach my $res (@resources) { 1612: if (ref($res) eq 'Apache::lonnavmaps::resource') { 1613: my $symb = $res->symb(); 1614: %{$$changed{$symb}} = ( 1615: current => $currentversion, 1616: version => $version, 1617: revdate => $revdate, 1618: ); 1619: } 1620: } 1621: } 1622: } 1623: } 1624: } 1625: return; 1626: } 1627: 1628: sub display_handgrade { 1629: my ($r,$tograde,$ungraded,$itemserror) = @_; 1630: my %lt = &Apache::lonlocal::texthash( 1631: 'prna' => 'Problem Name', 1632: 'nmun' => 'Number ungraded', 1633: 'nopr' => 'No problems require handgrading', 1634: ); 1635: if (@{$tograde} > 0) { 1636: $r->print('<tr class="LC_info_row"><td class="LC_left_item">'. 1637: $lt{'prna'}.'</td><td class="LC_right_item">'. 1638: $lt{'nmun'}.'</td></tr>'); 1639: my $rowNum = 0; 1640: foreach my $res (@{$tograde}) { 1641: $rowNum ++; 1642: my $css_class = $rowNum%2?' class="LC_odd_row"':''; 1643: my ($map,$id,$url)=&Apache::lonnet::decode_symb($res); 1644: my $linkurl=&Apache::lonnet::clutter($url); 1645: $linkurl .= '?symb='.&escape($res); 1646: if ($$ungraded{$res}{'enclink'}) { 1647: $linkurl = 1648: $$ungraded{$res}{'enclink'}.'?symb='.$$ungraded{$res}{'encsymb'}; 1649: } 1650: $r->print('<tr'.$css_class.'><td><a href="'.$linkurl.'">'.$$ungraded{$res}{title}.'</a></td><td class="LC_right_item">'.$$ungraded{$res}{count}.'</td></tr>'); 1651: } 1652: } elsif ($itemserror) { 1653: $r->print('<tr class="LC_empty_row"><td>'.$itemserror.'</td></tr>'); 1654: } else { 1655: $r->print('<tr class="LC_empty_row"><td>'.$lt{'nopr'}.'</td></tr>'); 1656: } 1657: } 1658: 1659: sub display_haserrors { 1660: my ($r,$bombs,$bombed,$res_title,$itemserror) = @_; 1661: my $bombnum = 0; 1662: my %lt = &Apache::lonlocal::texthash( 1663: reso => 'Resource', 1664: nmer => 'Number of errors', 1665: noer => 'No problems with errors', 1666: ); 1667: if (@{$bombs} > 0) { 1668: $r->print('<tr class="LC_info_row"><td class="LC_left_item">'. 1669: $lt{'reso'}.'</td><td class="LC_right_item">'. 1670: $lt{'nmer'}.'</td></tr>'); 1671: @{$bombs} = sort { &cmp_title($a,$b,$res_title) } @{$bombs}; 1672: foreach my $bomb (@{$bombs}) { 1673: $bombnum ++; 1674: my $css_class = $bombnum%2?' class="LC_odd_row"':''; 1675: $r->print('<tr'.$css_class.'><td>'.$$bombed{$bomb}{errorlink}. 1676: '</td><td class="LC_right_item">'. 1677: $$bombed{$bomb}{errorcount}.'</td></tr>'); 1678: } 1679: } elsif ($itemserror) { 1680: $r->print('<tr class="LC_empty_row"><td>'.$itemserror.'</td></tr>'); 1681: } else { 1682: $r->print('<tr class="LC_empty_row"><td>'.$lt{'noer'}.'</td></tr>'); 1683: } 1684: return; 1685: } 1686: 1687: sub display_abovethreshold { 1688: my ($r,$refpage,$warnings,$triggered,$res_title,$itemserror,$custommenu) = @_; 1689: my %lt = &Apache::lonlocal::texthash( 1690: reso => 'Resource', 1691: part => 'Part', 1692: nust => 'Num. students', 1693: avat => 'Av. Attempts', 1694: dedi => 'Deg. Diff', 1695: lare => 'Last Reset', 1696: reco => 'Reset Count?', 1697: rese => 'Reset counters to 0', 1698: nopr => 'No problems satisfy threshold criteria', 1699: ); 1700: if (@{$warnings} > 0) { 1701: @{$warnings} = sort { &cmp_title($a,$b,$res_title) } @{$warnings}; 1702: if ($custommenu) { 1703: my (%bynum,@overthresh); 1704: foreach my $item (@{$warnings}) { 1705: my ($probnum) = ($res_title->{$item} =~ /^Problem\s+(\d+)$/); 1706: if ($probnum ne '') { 1707: $bynum{$probnum} = $item; 1708: } 1709: } 1710: foreach my $num (sort { $a <=> $b } keys(%bynum)) { 1711: push(@overthresh,$bynum{$num}); 1712: } 1713: @{$warnings} = @overthresh; 1714: } 1715: if ($custommenu) { 1716: $r->print('<tr class="LC_info_row">'. 1717: '<td class="LC_left_item">'.$lt{'reso'}.'</td>'. 1718: '<td>'.$lt{'part'}.'</td><td class="LC_right_item">'.$lt{'nust'}.'</td></tr>'); 1719: } else { 1720: $r->print('<form name="reset_tracking" method="post" action="/adm/whatsnew">'. 1721: ' <input type="hidden" name="command" value="reset" />'."\n". 1722: ' <input type="hidden" name="refpage" value="'.$refpage.'" />'. 1723: "\n"); 1724: $r->print('<tr class="LC_info_row">'. 1725: '<td class="LC_left_item">'.$lt{'reso'}.'</td>'. 1726: '<td>'.$lt{'part'}.'</td><td>'.$lt{'nust'}.'</td>'. 1727: '<td>'.$lt{'avat'}.'</td><td>'.$lt{'dedi'}.'</td>'. 1728: '<td>'.$lt{'lare'}.'</td><td class="LC_right_item">'. 1729: $lt{'reco'}.'</td></tr>'); 1730: } 1731: my $row; 1732: foreach my $res (@{$warnings}) { 1733: $row++; 1734: my ($map,$id,$url)=&Apache::lonnet::decode_symb($res); 1735: my $linkurl=&Apache::lonnet::clutter($url); 1736: my $rowspan; 1737: if ($$triggered{$res}{numparts} > 1) { 1738: $rowspan = 'rowspan="'.$$triggered{$res}{numparts}.'"'; 1739: } 1740: $linkurl .= '?symb='.&escape($res); 1741: if ($$triggered{$res}{'enclink'}) { 1742: $linkurl = 1743: $$triggered{$res}{'enclink'}.'?symb='.$$triggered{$res}{'encsymb'}; 1744: } 1745: my $css_class = $row%2?' class="LC_odd_row"':''; 1746: $r->print('<tr'.$css_class.'>'. 1747: '<td class="LC_first_item" '.$rowspan.'><a href="'.$linkurl.'">'. 1748: $$triggered{$res}{title}.'</a></td>'); 1749: if (ref($$triggered{$res}{text}) eq 'ARRAY') { 1750: $r->print($$triggered{$res}{text}[0]); 1751: } 1752: $r->print('</tr>'); 1753: if (ref($$triggered{$res}{text}) eq 'ARRAY') { 1754: if (@{$$triggered{$res}{text}} > 1) { 1755: for (my $i=1; $i<@{$$triggered{$res}{text}}; $i++) { 1756: $r->print('<tr class="'.$css_class.'">'. 1757: $$triggered{$res}{text}[$i].'</tr>'); 1758: } 1759: } 1760: } 1761: } 1762: unless ($custommenu) { 1763: $r->print('<tr class="LC_info_row"><td colspan="7" class="LC_right_item"><br /><input type="submit" name="counters" value="'.$lt{'rese'}.'" /></td></tr></form>'); 1764: } 1765: } elsif ($itemserror) { 1766: $r->print('<tr class="LC_empty_row"><td>'.$itemserror.'</td></tr>'); 1767: } else { 1768: $r->print('<tr class="LC_empty_row"><td>'.$lt{'nopr'}.'</td></tr>'); 1769: } 1770: } 1771: 1772: sub display_versionchanges { 1773: my ($r,$changed,$res_title,$interval,$itemserror) = @_; 1774: my %lt = &Apache::lonlocal::texthash( 1775: 'reso' => 'Resource', 1776: 'revd' => 'Last revised', 1777: 'newv' => 'New version', 1778: 'veru' => 'Version used', 1779: ); 1780: if (keys(%{$changed}) > 0) { 1781: $r->print('<tr class="LC_info_row"><td class="LC_left_item">'. 1782: $lt{'reso'}.'</td><td>'.$lt{'revd'}.'</td><td>'. 1783: $lt{'newv'}.'</td><td class="LC_right_item">'. 1784: $lt{'veru'}.'</td></tr>'); 1785: my @changes = sort { &cmp_title($a,$b,$res_title) } keys(%{$changed}); 1786: my $changenum = 0; 1787: foreach my $item (@changes) { 1788: $changenum ++; 1789: my $css_class = $changenum%2?' class="LC_odd_row"':''; 1790: my ($map,$id,$url)=&Apache::lonnet::decode_symb($item); 1791: my $linkurl=&Apache::lonnet::clutter($url); 1792: $linkurl .= '?symb='.&escape($item); 1793: 1794: $r->print('<tr'.$css_class.'><td><a href="'.$linkurl.'">'. 1795: $$res_title{$item}.'</a></td><td>'. 1796: $$changed{$item}{'revdate'}.'</td><td>'. 1797: $$changed{$item}{'current'}.'</td><td>'. 1798: $$changed{$item}{'version'}.'</td></tr>'); 1799: } 1800: } elsif ($itemserror) { 1801: $r->print('<tr class="LC_empty_row"><td>'.$itemserror.'</td></tr>'); 1802: } else { 1803: $r->print('<tr class="LC_empty_row"><td>' 1804: .&mt('No '.$interval).'</td></tr>'); 1805: } 1806: return; 1807: } 1808: 1809: sub display_rolechanges { 1810: my ($r,$chgcount,$changed,$interval,$crstype) = @_; 1811: my $now = time(); 1812: my %lt = &Apache::lonlocal::texthash( 1813: 'user' => 'User', 1814: 'tich' => 'Time of change', 1815: 'role' => 'Role', 1816: 'sec' => 'Section', 1817: 'status' => 'Status', 1818: ); 1819: if ($chgcount) { 1820: $r->print('<tr class="LC_info_row">'. 1821: '<td class="LC_left_item">'.$lt{'tich'}.'</td>'. 1822: '<td class="LC_left_item">'.$lt{'user'}.'</td>'. 1823: '<td class="LC_left_item">'.$lt{'role'}.'</td>'. 1824: '<td class="LC_left_item">'.$lt{'sec'}.'</td>'. 1825: '<td class="LC_left_item">'.$lt{'status'}.'</td></tr>'); 1826: if (ref($changed) eq 'HASH') { 1827: my @changes = sort { $b <=> $a } (keys(%{$changed})); 1828: my $changenum = 0; 1829: foreach my $item (@changes) { 1830: if (ref($changed->{$item}) eq 'ARRAY') { 1831: foreach my $chg (@{$changed->{$item}}) { 1832: if (ref($chg) eq 'HASH') { 1833: my $section; 1834: my $role = 1835: &Apache::lonnet::plaintext($chg->{'role'},$crstype); 1836: my $status = &mt($chg->{'status'}); 1837: if ($chg->{'section'} eq '') { 1838: $section = &mt('none'); 1839: } else { 1840: $section = $chg->{'section'}; 1841: } 1842: my $uname = $chg->{'uname'}; 1843: my $udom = $chg->{'udom'}; 1844: $changenum ++; 1845: my $css_class = $changenum%2?' class="LC_odd_row"':''; 1846: my $link = 1847: &Apache::loncommon::aboutmewrapper(&Apache::loncommon::plainname($uname,$udom),$uname,$udom); 1848: $r->print('<tr'.$css_class.'>'. 1849: '<td>'.&Apache::lonlocal::locallocaltime($item).'</td>'. 1850: '<td>'.$link.'</td>'. 1851: '<td>'.$role.'</td>'. 1852: '<td>'.$section.'</td>'. 1853: '<td>'.$status.'</td></tr>'); 1854: } 1855: } 1856: } 1857: } 1858: } 1859: } else { 1860: $r->print('<tr class="LC_empty_row"><td>' 1861: .&mt('There are no '.$interval).'</td></tr>'); 1862: } 1863: return; 1864: } 1865: 1866: sub display_crslogins { 1867: my ($r,$logincount,$loggedin,$interval,$crstype) = @_; 1868: my %lt = &Apache::lonlocal::texthash( 1869: 'user' => 'User', 1870: 'role' => 'Role', 1871: 'sec' => 'Section', 1872: 'number' => 'Total number of logins', 1873: ); 1874: if ($logincount) { 1875: 1876: my $hdr = '<tr class="LC_info_row" style="display:none" id="logintitledet">'. 1877: '<td class="LC_left_item">'.$lt{'user'}.'</td>'. 1878: '<td class="LC_left_item">'.$lt{'role'}.'</td>'. 1879: '<td class="LC_left_item">'.$lt{'sec'}.'</td></tr>'. 1880: '<tr class="LC_info_row" id="logintitlesum">'. 1881: '<td class="LC_left_item">'.$lt{'number'}.'</td>'. 1882: '<td class="LC_left_item">'.$lt{'role'}.'</td>'. 1883: '<td class="LC_left_item">'.$lt{'sec'}; 1884: my (%bylastname,%counts); 1885: if (ref($loggedin) eq 'HASH') { 1886: my @logins = sort { $b <=> $a } (keys(%{$loggedin})); 1887: my $numlogin = 0; 1888: foreach my $item (@logins) { 1889: if (ref($loggedin->{$item}) eq 'ARRAY') { 1890: foreach my $user (@{$loggedin->{$item}}) { 1891: if (ref($user) eq 'HASH') { 1892: my $section; 1893: my $role = 1894: &Apache::lonnet::plaintext($user->{'role'},$crstype); 1895: my $status = &mt($user->{'status'}); 1896: if ($user->{'section'} eq '') { 1897: $section = &mt('none'); 1898: } else { 1899: $section = $user->{'section'}; 1900: } 1901: $counts{$user->{'role'}}{$section} ++; 1902: my $uname = $user->{'uname'}; 1903: my $udom = $user->{'udom'}; 1904: my $fullname = &Apache::loncommon::plainname($uname,$udom,'lastname'); 1905: my $link = 1906: &Apache::loncommon::aboutmewrapper($fullname,$uname,$udom); 1907: push(@{$bylastname{$fullname}}, 1908: '<td>'.$link.'</td>'. 1909: '<td>'.$role.'</td>'. 1910: '<td>'.$section.'</td>'); 1911: } 1912: } 1913: } 1914: } 1915: my $table; 1916: foreach my $person (sort(keys(%bylastname))) { 1917: if (ref($bylastname{$person}) eq 'ARRAY') { 1918: foreach my $item (@{$bylastname{$person}}) { 1919: $numlogin ++; 1920: my $css_class = $numlogin%2?' class="LC_odd_row"':''; 1921: $table .= '<tr'.$css_class.' style="display:none;" id="logindet_'.$numlogin.'">'.$item.'</tr>'; 1922: } 1923: } 1924: } 1925: my $numrow = 0; 1926: foreach my $role (sort(keys(%counts))) { 1927: my $showrole = &Apache::lonnet::plaintext($role,$crstype); 1928: if (ref($counts{$role}) eq 'HASH') { 1929: foreach my $sec (sort { $b <=> $a } (keys(%{$counts{$role}}))) { 1930: $numrow ++; 1931: my $css_class = $numrow%2?' class="LC_odd_row"':''; 1932: $table .= '<tr '.$css_class.' id="loginsum_'.$numrow.'">'. 1933: '<td>'.$counts{$role}{$sec}.'</td>'. 1934: '<td>'.$showrole.'</td>'. 1935: '<td>'.$sec.'</td></tr>'; 1936: } 1937: } 1938: } 1939: $r->print($hdr.'<input type="hidden" name="logincount" value="'.$numlogin. 1940: '" /><input type="hidden" name="loginrow" value="'.$numrow. 1941: '" /></td></tr>'.$table); 1942: } 1943: } else { 1944: $r->print('<tr class="LC_empty_row"><td>'. 1945: &mt('There are no '.$interval). 1946: '<input type="hidden" name="logincount" value="'.$logincount. 1947: '." /></td></tr>'); 1948: } 1949: return; 1950: } 1951: 1952: sub display_coursediscussion { 1953: my ($r,$newdiscussions,$unread,$countunread,$res_title,$itemserror) = @_; 1954: my $lctype = lc(&Apache::loncommon::course_type()); 1955: my %lt = &Apache::lonlocal::texthash( 1956: 'loca' => 'Location', 1957: 'type' => 'Type', 1958: 'numn' => 'Number of new posts', 1959: 'noun' => 'No unread posts in '.$lctype.' discussions', 1960: 'tmlp' => 'Time of last post', 1961: ); 1962: if (@{$newdiscussions} > 0) { 1963: $r->print('<tr class="LC_info_row"><td class="LC_left_item">'. 1964: $lt{'loca'}.'</td><td>'. 1965: $lt{'type'}.'</td>'); 1966: if ($countunread eq 'on') { 1967: $r->print('<td>'.$lt{'tmlp'}.'</td>'. 1968: '<td class="LC_right_item">'.$lt{'numn'}.'</td>'); 1969: } else { 1970: $r->print('<td class="LC_right_item">'.$lt{'tmlp'}.'</td>'); 1971: } 1972: $r->print("</tr>\n"); 1973: @{$newdiscussions} = sort { &cmp_title($a,$b,$res_title) } 1974: @{$newdiscussions}; 1975: my $rowNum = 0; 1976: foreach my $ressymb (@{$newdiscussions}) { 1977: $rowNum ++; 1978: my $forum_title = $$unread{$ressymb}{'title'}; 1979: my $type = 'Resource'; 1980: my $feedurl=&Apache::lonfeedback::get_feedurl($ressymb); 1981: my $disclink = $feedurl.'?symb='.$$unread{$ressymb}{symb}; 1982: if ($feedurl =~ /bulletinboard/) { 1983: $type = 'Discussion Board'; 1984: } 1985: if ($$unread{$ressymb}{'enclink'}) { 1986: $disclink = $$unread{$ressymb}{'enclink'}.'?symb='.$$unread{$ressymb}{'encsymb'}; 1987: } 1988: my $css_class = $rowNum%2?' class="LC_odd_row"':''; 1989: my $lastpost = &Apache::lonnavmaps::timeToHumanString( 1990: $$unread{$ressymb}{'lastpost'}); 1991: $r->print('<tr'.$css_class.'><td><a href="'.$disclink.'">'.$forum_title.'</a> </td><td>'.&mt($type).' </td>'); 1992: if ($countunread eq 'on') { 1993: my $unreadnum = $$unread{$ressymb}{'unreadcount'}; 1994: $r->print('<td>'.$lastpost.'</td><td class="LC_right_item">'. 1995: $unreadnum.' </td>'); 1996: } else { 1997: $r->print('<td class="LC_right_item">'.$lastpost.'</td>'); 1998: } 1999: $r->print("</tr>\n"); 2000: } 2001: } elsif ($itemserror) { 2002: $r->print('<tr class="LC_empty_row"><td>'.$itemserror.'</td></tr>'); 2003: } else { 2004: $r->print('<tr class="LC_empty_row"><td>'.$lt{'noun'}.'</td></tr>'); 2005: } 2006: } 2007: 2008: sub display_coursenormalmail { 2009: my ($r,$msgcount,$newmsgs) = @_; 2010: my $lctype = lc(&Apache::loncommon::course_type()); 2011: if ($msgcount > 0) { 2012: $r->print('<tr class="LC_info_row"><td class="LC_left_item">'. 2013: &mt('Number').'</td><td>'.&mt('Subject').'</td><td>'. 2014: &mt('Sender').'</td><td class="LC_right_item">'. 2015: &mt('Date/Time').'</td></tr>'); 2016: my $mailcount = 0; 2017: foreach my $msg (@{$newmsgs}) { 2018: $mailcount ++; 2019: my $css_class = $mailcount%2?' class="LC_odd_row"':''; 2020: $r->print('<tr'.$css_class.'><td>'.$mailcount 2021: .'. </td><td><a href="/adm/email?display=' 2022: .$msg->{'msgid'}.'">' 2023: .$msg->{'shortsub'}.'</a> </td><td> ' 2024: .$msg->{'from'}.':'.$msg->{'fromdom'}.' </td><td>' 2025: .$msg->{'sendtime'}.'</td></tr>'); 2026: } 2027: } else { 2028: $r->print('<tr class="LC_empty_row"><td>'. 2029: &mt('No new '.$lctype.' messages').'</td></tr>'); 2030: } 2031: } 2032: 2033: sub display_coursecritmail { 2034: my ($r,$critmsgcount,$critmsgs) = @_; 2035: my $lctype = lc(&Apache::loncommon::course_type()); 2036: if ($critmsgcount > 0) { 2037: $r->print('<tr class="LC_info_row"><td class="LC_left_item">'. 2038: &mt('Number').'</td><td>'.&mt('Subject').'</td><td>'. 2039: &mt('Sender').'</td><td class="LC_right_item">'. 2040: &mt('Date/Time').'</td></tr>'); 2041: my $mailcount = 0; 2042: foreach my $msg (@{$critmsgs}) { 2043: $mailcount ++; 2044: my $css_class = $mailcount%2?' class="LC_odd_row"':''; 2045: $r->print('<tr'.$css_class.'><td>'.$mailcount. 2046: '. </td><td><a href="/adm/email?folder=critical">'. 2047: $msg->{'shortsub'}.'</a> </td><td> '. 2048: $msg->{'from'}.':'.$msg->{'fromdom'}.' </td><td>'. 2049: $msg->{'sendtime'}.'</td></tr>'); 2050: } 2051: } else { 2052: $r->print('<tr class="LC_empty_row"><td>'. 2053: &mt('No unread critical messages in '.$lctype). 2054: '</td></tr>'); 2055: } 2056: } 2057: 2058: sub cmp_title { 2059: my ($a,$b,$res_title) = @_; 2060: my ($atitle,$btitle) = (lc($$res_title{$a}),lc($$res_title{$b})); 2061: $atitle=~s/^\s*//; 2062: $btitle=~s/^\s*//; 2063: return $atitle cmp $btitle; 2064: } 2065: 2066: sub get_display_settings { 2067: my ($uname,$udom,$cid) = @_; 2068: my %settings = &Apache::lonnet::dump('nohist_whatsnew',$udom,$uname,$cid); 2069: my ($tmp) = keys(%settings); 2070: if ($tmp=~ /^(con_lost|error|no_such_host)/i) { 2071: %settings = (); 2072: unless ($tmp =~ /^error: 2 /) { 2073: my $lctype = lc(&Apache::loncommon::course_type()); 2074: &Apache::lonnet::logthis('Error retrieving whatsnew settings: '. 2075: $tmp.' for '.$uname.':'.$udom.' for '.$lctype.': '.$cid); 2076: } 2077: } 2078: return %settings; 2079: } 2080: 2081: sub store_display_settings { 2082: my ($uname,$udom,$cid,$checkallowed) = @_; 2083: my %whatsnew_settings; 2084: my $result; 2085: foreach my $key (keys(%{$checkallowed})) { 2086: if ($key =~ /_section$/) { next; } 2087: if (exists($env{'form.display_'.$key})) { 2088: unless ($env{'form.display_'.$key} eq '') { 2089: $whatsnew_settings{$cid.':'.$key} = $env{'form.display_'.$key}; 2090: } 2091: } 2092: } 2093: if (keys(%whatsnew_settings)) { 2094: $result = &Apache::lonnet::put('nohist_whatsnew',\%whatsnew_settings, 2095: $udom,$uname); 2096: } else { 2097: $result = 'ok'; 2098: } 2099: return $result; 2100: } 2101: 2102: sub store_interval_setting { 2103: my ($uname,$udom,$cid,$interval_titles) = @_; 2104: my %interval_settings = (); 2105: my $result; 2106: my $context = $env{'form.intervaltype'}; 2107: if ($env{'form.interval'} ne '') { 2108: if ($context eq 'oldroles') { 2109: $interval_settings{$cid.':oldroleinterval'} = $env{'form.interval'}; 2110: } elsif ($context eq 'newroles') { 2111: $interval_settings{$cid.':newroleinterval'} = $env{'form.interval'}; 2112: } elsif ($context eq 'crslogin') { 2113: $interval_settings{$cid.':crslogininterval'} = $env{'form.interval'}; 2114: } else { 2115: $interval_settings{$cid.':interval'} = $env{'form.interval'}; 2116: } 2117: my $outcome = &Apache::lonnet::put('nohist_whatsnew', 2118: \%interval_settings,$udom,$uname); 2119: if ($outcome eq 'ok') { 2120: if (ref($interval_titles->{$context}) eq 'HASH') { 2121: $result = &mt('New filter setting: [_1].','<b>'. 2122: $interval_titles->{$context}->{$env{'form.interval'}}.'</b>').'<br />'; 2123: } 2124: } else { 2125: my $lctype = lc(&Apache::loncommon::course_type()); 2126: &Apache::lonnet::logthis('Error saving whatsnew '.$context.' interval setting'. 2127: ' '.$outcome.' for '.$uname.':'.$udom.' in '.$lctype.' '.$cid); 2128: $result = &mt('Unable to set interval to [_1] due to [_2].', 2129: '<b>'.$interval_titles->{$context}->{$env{'form.interval'}}.'</b>', 2130: '<tt>'.$outcome.'</tt>.<br />'); 2131: } 2132: } 2133: return $result; 2134: } 2135: 2136: sub store_discussion_setting { 2137: my ($uname,$udom,$cid) = @_; 2138: my %discussion_settings; 2139: my $result; 2140: if (defined($env{'form.countunread'})) { 2141: $discussion_settings{$cid.':countunread'} = $env{'form.countunread'}; 2142: my $outcome = &Apache::lonnet::put('nohist_whatsnew', 2143: \%discussion_settings,$udom,$uname); 2144: if ($outcome eq 'ok') { 2145: $result = &mt('Count unread posts in discussions display set to [_1]', 2146: '<b>'.&mt($env{'form.countunread'}).'</b>').'<br />'; 2147: 2148: } else { 2149: my $lctype = lc(&Apache::loncommon::course_type()); 2150: &Apache::lonnet::logthis('Error saving whatsnew countunread setting'. 2151: ' '.$outcome.' for '.$uname.':'.$udom.' in '.$lctype.' '.$cid); 2152: $result = &mt('Unable to set "number unread posts display" to [_1]'. 2153: ' due to [_2].', 2154: '<b>'.&mt($env{'form.countunread'}).'</b>', 2155: '<tt>'.$outcome.'</tt>.<br />'); 2156: } 2157: } 2158: return $result; 2159: } 2160: 2161: sub store_courseinit_setting { 2162: my ($uname,$udom,$cid,$initpage) = @_; 2163: my %courseinit_settings; 2164: my $page_control; 2165: my $result; 2166: if (defined($env{'form.courseinit_control'})) { 2167: if ($env{'form.courseinit_control'} eq 'userpref') { 2168: $courseinit_settings{$cid.':courseinit'} = ''; 2169: $page_control = 'global preferences'; 2170: } else { 2171: if (defined($env{'form.courseinit_page'})) { 2172: $courseinit_settings{$cid.':courseinit'} = 2173: $env{'form.courseinit_page'}; 2174: $page_control = 'course specific setting'; 2175: } 2176: } 2177: if ($page_control) { 2178: my $lctype = lc(&Apache::loncommon::course_type()); 2179: my $outcome = &Apache::lonnet::put('nohist_whatsnew', 2180: \%courseinit_settings,$udom,$uname); 2181: if ($outcome eq 'ok') { 2182: if ($page_control eq 'global preferences') { 2183: $result = &mt("Page displayed after role selection in $lctype now set by [_1]user's global preferences[_2].",'<b>','</b>'); 2184: } else { 2185: $result = &mt('Page displayed after role selection in this '.$lctype.' set to [_1].' 2186: ,'<b>'.$$initpage{$env{'form.courseinit_page'}}.'</b>'); 2187: } 2188: } else { 2189: &Apache::lonnet::logthis('Error saving whatsnew courseinit '. 2190: 'setting: '.$outcome.' for '.$uname. 2191: ':'.$udom.' in '.$lctype.' '.$cid); 2192: if ($page_control eq 'global preferences') { 2193: $result = &mt('Unable to set control of page display to [_1]'. 2194: ' due to [_2].', 2195: '<b>'.$page_control.'</b>', 2196: '<tt>'.$outcome.'</tt>.<br />'); 2197: } else { 2198: $result = &mt('Unable to set page display, after role selection, for this '.$lctype.' to [_1] due to [_2].' 2199: ,'<b>'.$$initpage{$env{'form.courseinit_page'}}.'</b>' 2200: ,'<tt>'.$outcome.'</tt>') 2201: .'<br />'; 2202: } 2203: } 2204: } 2205: } 2206: return $result; 2207: } 2208: 2209: sub start_box { 2210: my ($r,$show,$heading,$caller,$refpage,$action,$custommenu) = @_; 2211: my %lt = &Apache::lonlocal::texthash( 2212: chth => 'Change thresholds?', 2213: chin => 'Change interval?', 2214: chop => 'Change options?', 2215: ); 2216: my $showhide; 2217: if ($$show{$caller}) { 2218: $showhide = '<b><a href="javascript:change_display(document.visible.'. 2219: 'display_'.$caller.",'hide'".');">'. 2220: &mt('Hide').'</a></b>'; 2221: 2222: } else { 2223: $showhide = '<b><a href="javascript:change_display(document.visible.'. 2224: 'display_'.$caller.",'show'".');">'. 2225: &mt('Show').'</a></b>'; 2226: } 2227: 2228: $r->print(' 2229: <table class="LC_nested_outer"> 2230: <tr> 2231: <th class="LC_left_item">'.$$heading{$caller}.'</th> 2232: <th class="LC_right_item">'.$showhide.'</th> 2233: </tr>'); 2234: if (($caller eq 'abovethreshold') && ($$show{$caller})) { 2235: if ($$show{$caller} && !$custommenu) { 2236: $r->print(' 2237: <tr> 2238: <td class="LC_subheader" colspan="2"><a href="/adm/whatsnew?command=chgthreshold&refpage='.$refpage.'">'.$lt{'chth'}.'</a></td> 2239: </tr>'); 2240: } 2241: } elsif (($caller eq 'versionchanges') && ($$show{$caller})) { 2242: if ($$show{$caller}) { 2243: $r->print(' 2244: <tr> 2245: <td class="LC_subheader" colspan="2"><a href="/adm/whatsnew?command=chginterval&refpage='.$refpage.'">'.$lt{'chin'}.'</a></td> 2246: </tr>'); 2247: } 2248: } elsif ($caller eq 'coursediscussion') { 2249: if ($$show{$caller}) { 2250: $r->print(' 2251: <tr> 2252: <td class="LC_subheader" colspan="2"><a href="/adm/whatsnew?command=chgdisc&refpage='.$refpage.'">'.$lt{'chop'}.'</a></td> 2253: </tr>'); 2254: } 2255: } elsif (($caller eq 'newroles') && ($$show{$caller})) { 2256: if ($$show{$caller}) { 2257: $r->print(' 2258: <tr> 2259: <td class="LC_subheader" colspan="2"><a href="/adm/whatsnew?command=chgnewroleinterval&refpage='.$refpage.'">'.$lt{'chin'}.'</a></td> 2260: </tr>'); 2261: } 2262: } elsif (($caller eq 'oldroles') && ($$show{$caller})) { 2263: if ($$show{$caller}) { 2264: $r->print(' 2265: <tr> 2266: <td class="LC_subheader" colspan="2"><a href="/adm/whatsnew?command=chgoldroleinterval&refpage='.$refpage.'">'.$lt{'chin'}.'</a></td> 2267: </tr>'); 2268: } 2269: } elsif (($caller eq 'crslogin') && ($$show{$caller})) { 2270: if ($$show{$caller}) { 2271: $r->print(' 2272: <tr> 2273: <td class="LC_subheader" align="left"><span class="LC_nobreak"><label><input type="radio" name="logindetails" value="0" checked="checked" onclick="javascript:togglelogins();" /> '.&mt('Summary').'</label><label><input type="radio" name="logindetails" value="1" onclick="javascript:togglelogins();" /> '.&mt('Details').'</label></span></td><td class="LC_subheader"><a href="/adm/whatsnew?command=chgcrslogininterval&refpage='.$refpage.'">'.$lt{'chin'}.'</a></td> 2274: </tr>'); 2275: } 2276: } 2277: 2278: $r->print(' 2279: <tr> 2280: <td colspan="2"> 2281: <table class="LC_nested"> 2282: '); 2283: return; 2284: } 2285: 2286: sub end_box { 2287: my ($r) = shift; 2288: $r->print(' 2289: </table> 2290: </td> 2291: </tr> 2292: </table><br />'); 2293: return; 2294: } 2295: 2296: 1;