--- loncom/interface/lonwhatsnew.pm 2005/09/12 03:32:31 1.29 +++ loncom/interface/lonwhatsnew.pm 2006/05/01 19:37:34 1.54 @@ -1,5 +1,5 @@ # -# $Id: lonwhatsnew.pm,v 1.29 2005/09/12 03:32:31 raeburn Exp $ +# $Id: lonwhatsnew.pm,v 1.54 2006/05/01 19:37:34 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -52,41 +52,83 @@ sub handler { $r->send_http_header; return OK; } - &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['command']); + &Apache::loncommon::get_unprocessed_cgi( + $ENV{'QUERY_STRING'},['command','refpage']); - my $command; - if ($env{'form.action'} eq 'reset') { - $command = 'reset'; - } elsif ($env{'form.action'} eq 'update') { - $command = 'update'; - } else { - $command = $env{'form.command'}; + my $command = $env{'form.command'}; + my $refpage = $env{'form.refpage'}; + + my %checkallowed = ( coursenormalmail => 1, + coursecritmail => 1, ); + foreach my $perm_check (['whn','whatsnew',1], + ['pch','coursediscussion',1], + ['mgr','handgrading',1], + ['vgr','abovethreshold',1], + ['opa','haserrors',1], + ['mdc','versionchanges',0], + ) { + my ($perm,$key,$check_section) = @{ $perm_check }; + my $scope = $env{'request.course.id'}; + if (!($checkallowed{$key} = &Apache::lonnet::allowed($perm,$scope))) { + $scope .= '/'.$env{'request.course.sec'}; + if ( $check_section ) { + $checkallowed{$key} = &Apache::lonnet::allowed($perm,$scope); + } + if ($checkallowed{$key}) { + $checkallowed{$key.'_section'} = $env{'request.course.sec'}; + } + } } - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; - $r->print(&display_header()); - if (! (($env{'request.course.fn'}) && (&Apache::lonnet::allowed('vsa',$env{'request.course.id'})))) { - # Not in a course, or not allowed to modify parms - $env{'user.error.msg'}="/adm/whatsnew:vsa:0:0:Cannot display student activity"; + if ( ! $env{'request.course.fn'} || ! $checkallowed{'whatsnew'}) { + # Not in a course, or no whn priv in course + $env{'user.error.msg'}="/adm/whatsnew::whn:0:0:Cannot display what's new page"; return HTTP_NOT_ACCEPTABLE; } + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + + $r->print(&display_header($command,\%checkallowed)); + &Apache::lonhtmlcommon::clear_breadcrumbs(); - if ($command eq 'chgthreshold') { + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>'/adm/whatsnew', + text=>"Display Action Items"}); + if (($command eq 'chgthreshold') && $checkallowed{'abovethreshold'}) { &Apache::lonhtmlcommon::add_breadcrumb - ({href=>'/adm/whatsnew?command=threshold', + ({href=>'/adm/whatsnew?command=chgthreshold&refpage='.$refpage, text=>"Change thresholds"}); $r->print(&Apache::lonhtmlcommon::breadcrumbs - (undef,'Course Action Items','Course_Action_Items_Thresholds')); - } else { + ("What's New?",#'Course_Action_Items_Thresholds' + )); + } elsif (($command eq 'chginterval') && $checkallowed{'versionchanges'} ) { &Apache::lonhtmlcommon::add_breadcrumb - ({href=>'/adm/whatsnew', - text=>"Display Action Items"}); + ({href=>'/adm/whatsnew?command=chginterval&refpage='.$refpage, + text=>"Change interval"}); + $r->print(&Apache::lonhtmlcommon::breadcrumbs + ("What's New?",#'Course_Action_Items_Intervals' + )); + } elsif (($command eq 'chgdisc') && $checkallowed{'coursediscussion'}) { + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>'/adm/whatsnew?command=chgdisc&refpage='.$refpage, + text=>"Change discussion display"}); + $r->print(&Apache::lonhtmlcommon::breadcrumbs + ("What's New?",#'Course_Action_Items_Intervals' + )); + } elsif ($command eq 'courseinit') { + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>'/adm/whatsnew?command=courseinit&refpage='.$refpage, + text=>"Course initialization preference"}); + $r->print(&Apache::lonhtmlcommon::breadcrumbs + ("What's New?",#'Course_Action_Items_Initialization' + )); + } else { $r->print(&Apache::lonhtmlcommon::breadcrumbs - (undef,'Course Action Items','Course_Action_Items_Display')); + ("What's New?",#'Course_Action_Items_Display' + )); } - &display_main_box($r,$command); + &display_main_box($r,$command,$refpage,\%checkallowed); return OK; } @@ -97,30 +139,56 @@ sub handler { #------------------------------ sub display_main_box { - my ($r,$command) = @_; + my ($r,$command,$refpage,$checkallowed) = @_; my $domain=&Apache::loncommon::determinedomain(); - my $tabbg=&Apache::loncommon::designparm('coordinator.tabbg',$domain); + my $function = &Apache::loncommon::get_users_function(); + my $tabbg=&Apache::loncommon::designparm($function.'.tabbg',$domain); $r->print('
'); - my %threshold_titles = ( + my %threshold_titles = &Apache::lonlocal::texthash ( av_attempts => 'Average number of attempts', degdiff => 'Degree of difficulty', numstudents => 'Total number of students with submissions', ); + + my %interval_titles = &Apache::lonlocal::texthash ( + -1 => 'since start of course', + 2592000 => 'since last month', + 604800 => 'since last week', + 86400 => 'since yesterday', + ); + + my %initpage = &Apache::lonlocal::texthash ( + firstres => 'first resource in the course', + whatsnew => "what's new? page", + userpref => 'your general user preferences', + coursespecific => 'specific setting for this course', + ); my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; - if ($command eq 'chgthreshold') { - &display_config_box($r,$command,$tabbg,\%threshold_titles,$cdom,$crs); + if (($command eq 'chgthreshold') + && $checkallowed->{'abovethreshold'}) { + &display_threshold_config($r,$refpage,$tabbg,\%threshold_titles, + $cdom,$crs); + } elsif (($command eq 'chginterval') + && $checkallowed->{'versionchanges'}) { + &display_interval_config($r,$refpage,\%interval_titles); + } elsif (($command eq 'chgdisc') + && $checkallowed->{'coursediscussion'}) { + &display_discussion_config($r,$refpage); + } elsif ($command eq 'courseinit') { + &courseinit_config($r,$refpage,\%initpage); } else { - &display_actions_box($r,$command,\%threshold_titles,$cdom,$crs); + &display_actions_box($r,$tabbg,$command,$refpage,\%threshold_titles, + \%interval_titles,\%initpage,$cdom,$crs,$checkallowed); } + my $end_page = &Apache::loncommon::end_page(); $r->print(<

- - +$end_page END_OF_BLOCK } @@ -131,16 +199,33 @@ END_OF_BLOCK # up the HTML #------------------------------- -sub display_header{ - my $html=&Apache::lonxml::xmlbegin(); - my $bodytag=&Apache::loncommon::bodytag('Course Action Items'); - return(< -Course Action Items - -$bodytag -ENDHEAD +sub display_header { + my ($command,$checkallowed) = @_; + + my $scripttag; + unless ($command eq 'chgthreshold' || $command eq 'chginterval') { + $scripttag = <<"END"; + +'; + } + return &Apache::loncommon::start_page('Course Action Items',$scripttag); } #------------------------------- @@ -150,32 +235,46 @@ ENDHEAD # #------------------------------- -sub display_actions_box() { - my ($r,$command,$threshold_titles,$cdom,$crs) = @_; - +sub display_actions_box { + my ($r,$tabbg,$command,$refpage,$threshold_titles,$interval_titles, + $initpage,$cdom,$crs,$checkallowed) = @_; my $rowColor1 = "#ffffff"; my $rowColor2 = "#eeeeee"; - my $rowColor; + + my $udom = $env{'user.domain'}; + my $uname = $env{'user.name'}; + my $cid = $env{'request.course.id'}; + + my %lt = &Apache::lonlocal::texthash( + 'yacc' => 'You are accessing an invalid course.', + 'gtfr' => 'Go to first resource', + 'pgse' => 'Page set to be displayed after you have selected a role in this course?', + 'hial' => 'Hide all', + 'shal' => 'Show all', + ); my %unread = (); my %ungraded = (); my %bombed = (); my %triggered = (); + my %changed = (); my @newmsgs = (); my @critmsgs = (); my @newdiscussions = (); my @tograde = (); my @bombs = (); my @warnings = (); + my $msgcount = 0; + my $critmsgcount = 0; + my %res_title = (); + my %show = (); + my $needitems = 0; + my $boxcount = 0; - my $domain=&Apache::loncommon::determinedomain(); - my $function; - if ($env{'request.role'}=~/^(cc|in|ta|ep)/) { - $function='coordinator'; - } - if ($env{'request.role'}=~/^(su|dc|ad|li)/) { - $function='admin'; + my $result; + if ($command eq 'newcourseinit') { + $result = &store_courseinit_setting($uname,$udom,$cid,$initpage); } my %threshold = ( @@ -183,286 +282,196 @@ sub display_actions_box() { degdiff => 0.5, numstudents => 2, ); + my %pagedesc = &Apache::lonlocal::texthash ( + firstres => 'First resource', + whatsnew => "What's New? page", + userpref => 'user preference', + coursespecific => 'course only', + default => 'default', + ); - my $pgbg=&Apache::loncommon::designparm($function.'.pgbg',$domain); - my $tabbg=&Apache::loncommon::designparm($function.'.tabbg',$domain); + my ($initcontrol,$initdisp) = &curr_courseinit(); + my $currinit = $pagedesc{$initdisp}.' ('.$pagedesc{$initcontrol}.')'; - unless ($env{'request.course.id'}) { - $r->print('
You are accessing an invalid course.


'); + unless ($cid) { + $r->print('
'.$lt{'yacc'}.'


'); return; } - if (tie(my %bighash,'GDBM_File',$env{'request.course.fn'}.'.db', - &GDBM_READER(),0640)) { - my $furl=$bighash{'first_url'}; - $r->print('Go to first resource
Change your preferences
to suppress display of this screen when accessing courses as Course Coordinator in the future.

'); - untie(%bighash); - } - - my $result; + if ($refpage eq 'start') { + if (tie(my %bighash,'GDBM_File',$env{'request.course.fn'}.'.db', + &GDBM_READER(),0640)) { + my $furl=$bighash{'first_url'}; + untie(%bighash); + $r->print(''.$lt{'gtfr'}. + '
'); + } + } + $r->print($lt{'pgse'}.' '.&mt('Currently: [_1]',''.$currinit.''). + '   '.&mt('[_1] for just [_2]','Change', + 'this course').' '.&mt('or for all [_1].', + 'your courses').'

'); + if ($command eq 'reset') { $result = &process_reset($cdom,$crs); } elsif ($command eq 'update') { - $result = &process_update($cdom,$crs,$threshold_titles); + $result = &process_update($uname,$udom,$threshold_titles); + } elsif ($command eq 'newinterval') { + $result = &store_interval_setting($uname,$udom,$cid,$interval_titles); + } elsif ($command eq 'newdiscconf') { + $result = &store_discussion_setting($uname,$udom,$cid); } + + my $store_result=&store_display_settings($uname,$udom,$cid,$checkallowed); + + unless ($store_result eq 'ok') { + &Apache::lonnet::logthis('Error storing whatsnew settings: '. + $store_result.' for '.'user '.$uname.':'.$udom.' in course '.$cid); + $result .= &mt('Unable to store visibility settings due to [_1]', + $store_result); + } + if ($result) { $r->print($result.'
'); } $r->rflush(); - &get_curr_thresholds(\%threshold,$cdom,$crs); - &getitems(\%unread,\%ungraded,\%bombed,\%triggered,\@newdiscussions,\@tograde,\@bombs,\@warnings,$rowColor1,$rowColor2,\%threshold,$cdom,$crs,%res_title); - my ($msgcount,$critmsgcount) = &getmail(\@newmsgs,\@critmsgs); - - $r->print('
'); - -## UNGRADED ITEMS ## - $r->print(< -
- - - - -
Problems requiring handgrading
- -END - if (@tograde > 0) { - $r->print(''); - my $rowNum = 0; - foreach my $res (@tograde) { - if ($rowNum %2 == 1) { - $rowColor = $rowColor1; - } else { - $rowColor = $rowColor2; - } - my ($map,$id,$url)=&Apache::lonnet::decode_symb($res); - my $linkurl=&Apache::lonnet::clutter($url); - $linkurl .= '?symb='.&Apache::lonnet::escape($res); + my %display_settings = &get_display_settings($uname,$udom,$cid); + my $timediff = $display_settings{$cid.':interval'}; + unless (defined($timediff)) { $timediff = 604800; } + my $now = time; + my $interval = $$interval_titles{$timediff}; + if ($timediff == -1) { + $timediff = time; + } + my $starttime = $now - $timediff; + my $countunread = $display_settings{$cid.':countunread'}; + unless (defined($countunread)) { + $countunread = 'on'; + } + + my %headings = &Apache::lonlocal::texthash( + coursediscussion => 'Unread course discussion posts', + handgrading => 'Problems requiring handgrading', + haserrors => 'Problems with errors', + versionchanges => 'Resources in course with version changes '.$interval, + coursenormalmail => 'New course messages', + coursecritmail => 'New critical messages in course', + ); - $r->print(''); - $rowNum ++; - } - } else { - $r->print(''); + if ($$checkallowed{'abovethreshold'}) { + &get_curr_thresholds(\%threshold,$uname,$udom,$cid,$cdom,$crs); } - $r->print('
Problem NameNumber ungraded
'.$ungraded{$res}{title}.''.$ungraded{$res}{count}.'

  No problems require handgrading  


'); -## BOMBS ## - $r->print(<<"END"); - - -
- - - - - -
Problems with errors
- -END - my $bombnum = 0; - if (@bombs > 0) { - $r->print(''); - @bombs = sort { &cmp_title($a,$b,\%res_title) } @bombs; - foreach my $bomb (@bombs) { - if ($bombnum %2 == 1) { - $rowColor = $rowColor1; - } else { - $rowColor = $rowColor2; + $headings{'abovethreshold'} = &mt('Problems with av. attempts').' ≥ '.$threshold{'av_attempts'}.' '.&mt('or deg. difficulty').' ≥ '.$threshold{'degdiff'}.'
'.&mt('and total number of students with submissions').' ≥ '.$threshold{'numstudents'}; + + my @actionorder = ('handgrading','haserrors','abovethreshold','versionchanges','coursediscussion','coursenormalmail','coursecritmail'); + + foreach my $key (keys(%{$checkallowed})) { + if ($key =~ /_section$/) { next; } + $show{$key} = 0; + if ($$checkallowed{$key}) { + unless ($display_settings{$cid.':'.$key} eq 'hide') { + $show{$key} = 1; } - $r->print(''); - $bombnum ++; } - } else { - $r->print(''); } - $r->print('
ResourceNumber of errors
'.$bombed{$bomb}{errorlink}.''.$bombed{$bomb}{errorcount}.'

No problems with errors


'); -# DEGDIFF AND AV. TRIES TRIGGERS - $r->print(<<"END"); - - -
- - - - - - - - -
Problems with av. attempts ≥ $threshold{'av_attempts'} or deg. difficulty ≥ $threshold{'degdiff'}
and total number of students with submissions ≥ $threshold{'numstudents'}
Change thresholds?
- -END - my $warningnum = 0; - if (@warnings > 0) { - @warnings = sort { &cmp_title($a,$b,\%res_title) } @warnings; - $r->print(''. - ' '."\n"); - $r->print(''); - foreach my $res (@warnings) { - if ($warningnum %2 == 1) { - $rowColor = $rowColor1; - } else { - $rowColor = $rowColor2; - } - my ($map,$id,$url)=&Apache::lonnet::decode_symb($res); - my $linkurl=&Apache::lonnet::clutter($url); - my $rowspan; - if ($triggered{$res}{numparts} > 1) { - $rowspan = 'rowspan="'.$triggered{$res}{numparts}.'"'; + foreach my $item (@actionorder) { + unless ($item eq 'coursenormalmail' || $item eq 'coursecritmail') { + if ($show{$item}) { + $needitems = 1; + last; } - $linkurl .= '?symb='.&Apache::lonnet::escape($res); - $r->print(''.$triggered{$res}{text}); - $warningnum ++; } - $r->print(''); } - $r->print('
ResourcePartNum. studentsAv. AttemptsDeg. DiffLast ResetReset Count?
'.$triggered{$res}{title}.'

'); - } else { - $r->print('

No problems satisfy threshold criteria.


'); - - $r->print(' '); -## UNREAD COURSE DISCUSSION POSTS ## - $r->print(<<"END"); - -
- - - - - -
Unread course discussion posts
- -END - - if (@newdiscussions > 0) { - $r->print(''); - @newdiscussions = sort { &cmp_title($a,$b,\%res_title) } @newdiscussions; - my $rowNum = 0; - foreach my $ressymb (@newdiscussions) { - my $forum_title = $unread{$ressymb}{'title'}; - my $type = 'Resource'; - my $feedurl=&Apache::lonfeedback::get_feedurl($ressymb); - if ($feedurl =~ /bulletinboard/) { - $type = 'Bulletin Board'; - } - my $unreadnum = keys(%{$unread{$ressymb}}); - $unreadnum = $unreadnum - 2; - if ($unreadnum > 0) { - if ($rowNum %2 == 1) { - $rowColor = $rowColor1; - } else { - $rowColor = $rowColor2; - } - $r->print(''); - $rowNum ++; - } - } - } else { - $r->print(''); + if ($needitems) { + &getitems(\%unread,\%ungraded,\%bombed,\%triggered,\%changed,\@newdiscussions,\@tograde,\@bombs,\@warnings,$rowColor1,$rowColor2,\%threshold,$cdom,$crs,\%res_title,\%show,$starttime,$countunread); + } + if ($show{'coursenormalmail'}) { + $msgcount = &getnormalmail(\@newmsgs); + } + if ($show{'coursecritmail'}) { + $critmsgcount = &getcritmail(\@critmsgs); } - $r->print('
LocationTypeNumber of new posts
'.$forum_title.' '.$type.''.$unreadnum.' 

 No unread posts in course discussions


'); -## MESSAGES ## - $r->print(< - - - - - - - -
New course messages
- -END - if ($msgcount > 0) { - $r->print(''); - my $rowNum = 0; - my $mailcount = 1; - foreach my $msg (@newmsgs) { - if ($rowNum %2 == 1) { - $rowColor = $rowColor1; - } else { - $rowColor = $rowColor2; - } - $r->print(''); - $rowNum ++; - $mailcount ++; + $r->print(qq|$lt{'hial'} +   $lt{'shal'} + \n|); + foreach my $item (keys(%{$checkallowed})) { + if ($item =~ /_section$/) { next; } + if ($$checkallowed{$item}) { + $r->print(''."\n"); } - } else { - $r->print(''); } - $r->print('
'.&mt('Number').''.&mt('Subject').''.&mt('Sender').''.&mt('Date/Time').'
'.$mailcount.'.  '.$msg->{'shortsub'}.'    '.$msg->{'from'}.'@'.$msg->{'fromdom'}.' '.$msg->{'sendtime'}.'

No new course messages


'); - - $r->print(< - - - - - - -
New critical messages in course
- -END + $r->print('
'); - my $rowNum = 0; - my $mailcount = 1; - foreach my $msg (@critmsgs) { - if ($rowNum %2 == 1) { - $rowColor = $rowColor1; - } else { - $rowColor = $rowColor2; + my $displayed = 0; + my $totalboxes = 0; + foreach my $key (keys(%{$checkallowed})) { + if ($key =~ /_section$/) { next; } + if ($key eq 'whatsnew' ) { next; } # whatsnew check creates no box + if ($$checkallowed{$key}) { + $totalboxes ++; + } + } + my $halfway = int($totalboxes/2) + $totalboxes%2; + foreach my $actionitem (@actionorder) { + if ($$checkallowed{$actionitem}) { + if ($displayed == $halfway) { + $r->print(''); - $rowNum ++; - $mailcount ++; + &display_launcher($r,$actionitem,$refpage,$checkallowed,$tabbg,$rowColor1,$rowColor2,\%show,\%headings,\%res_title,\@tograde,\%ungraded,\@bombs,\%bombed,\%changed,\@warnings,\%triggered,\@newdiscussions,\%unread,$msgcount,\@newmsgs,$critmsgcount,\@critmsgs,$interval,$countunread); + $displayed ++; } - } else { - $r->print(''); } - - $r->print('
'); - if ($critmsgcount > 0) { - $r->print('
NumberSubjectSenderDate/Time
 '); } - $r->print('
'.$mailcount.'.  '.$msg->{'shortsub'}.'    '.$msg->{'from'}.'@'.$msg->{'fromdom'}.' '.$msg->{'sendtime'}.'

No unread critical messages in course


'); - $r->print(' - '); - $r->print(''); + + + + '); } #------------------------------- -# display_config_box +# display_threshold_config # # Display the threshold setting screen # #------------------------------- -sub display_config_box() { - my ($r,$command,$tabbg,$threshold_titles,$cdom,$crs) = @_; +sub display_threshold_config { + my ($r,$refpage,$tabbg,$threshold_titles,$cdom,$crs) = @_; + my $uname = $env{'user.name'}; + my $udom = $env{'user.dom'}; + my $cid = $env{'request.course.id'}; my %threshold = (); my $rowColor1 = "#ffffff"; my $rowColor2 = "#eeeeee"; my $rowColor; my @thresholditems = ("av_attempts","degdiff","numstudents"); - my %threshold_titles = ( + foreach my $item (@thresholditems) { + $threshold{$item} = ''; + } + my %threshold_titles = &Apache::lonlocal::texthash( av_attempts => 'Average number of attempts', degdiff => 'Degree of difficulty', numstudents => 'Total number of students with submissions', ); - &get_curr_thresholds(\%threshold,$cdom,$crs); + &get_curr_thresholds(\%threshold,$uname,$udom,$cid,$cdom,$crs); - $r->print('
+ $r->print('
+ + +
'); my $rowNum =0; foreach my $type (@thresholditems) { - my $parameter = 'internal.threshold_'.$type; + my $parameter = $env{'request.course.id'}.':threshold_'.$type; # onchange is javascript to automatically check the 'Set' button. my $onchange = 'onFocus="javascript:window.document.forms'. "['thresholdform'].elements['".$parameter."_setparmval']". @@ -501,207 +510,446 @@ sub display_config_box() { } $r->print('
@@ -477,7 +486,7 @@ sub display_config_box() {

- + + +
'); +} + +#------------------------------- +# display_interval_config +# +# Display the interval setting screen +# +#------------------------------- + +sub display_interval_config { + my ($r,$refpage,$interval_titles) = @_; + my $current = &get_current($env{'user.name'},$env{'user.domain'}, + $env{'request.course.id'},'interval'); + $r->print('
'.&mt('Choose the time window to use for display of version changes for resources in the course.')); + unless ($current eq '') { + $r->print(' '.&mt('Current value is [_1]',''. + $$interval_titles{$current}.'.')); + } + $r->print('

+
+ + +   +
'); + return; +} + +#---------------------------------------------- +# display_discussion_config +# +# Display the discussion display setting screen +# +#---------------------------------------------- + +sub display_discussion_config { + my ($r,$refpage) = @_; + my $current = &get_current($env{'user.name'},$env{'user.domain'}, + $env{'request.course.id'},'countunread'); + if ($current eq '') { + $current = 'on'; + } + my %opposite = ( + 'on' => 'off', + 'off' => 'on', + ); + $r->print(''); + $r->print('
'.&mt('Choose whether or not to display a count of the number of new posts for each resource or bulletin board which has unread posts.').'
'.&mt('This can increase the time taken to gather data for the [_1] page by a few seconds.',"What's New?").'  '.&mt('Currently set to [_1].',''.$current.'')); + $r->print('

+
+ + + +'); + $r->print('
+ +         +
'); + return; +} + +#--------------------------------------------------- +# courseinit_config +# +# Set page displayed when course loads after +# selecting a role in the course from the roles page. +# +#--------------------------------------------------- + +sub courseinit_config { + my ($r,$refpage,$initpage) = @_; + my ($control,$current) = &curr_courseinit(); + my @chgstate = ('userpref','coursespecific'); + my @chgentry = ('firstres','whatsnew'); + my %lt = &Apache::lonlocal::texthash( + 'chwp' => 'Choose which page will be displayed when you enter this course after selecting a role.', + 'cuva' => 'Current value is determined by', + 'anis' => 'and is set to display', + 'padc' => 'Page display controlled by', + 'chce' => 'Choose course entry', + 'moce' => 'Modify course entry', + ); + $r->print(<<"END"); +
$lt{'chwp'} +
$lt{'cuva'}: +$$initpage{$control} $lt{'anis'} +$$initpage{$current}.

+
+ + +$lt{'padc'}   +END + foreach my $choice (@chgstate) { + $r->print(''); + } + $r->print('

'.&mt('If').' '.$$initpage{'coursespecific'}. + '
'.$lt{'chce'}." \n"); + foreach my $choice (@chgentry) { + $r->print(''); + } + $r->print('

'); + return; +} + +sub curr_courseinit { + my $current = &get_current($env{'user.name'},$env{'user.domain'}, + $env{'request.course.id'},'courseinit'); + my $control; + if ($current) { + $control = 'coursespecific'; + } else { + $control = 'userpref'; + my %userenv = &Apache::lonnet::get('environment', + ['course_init_display']); + if (exists($userenv{'course_init_display'})) { + $current = $userenv{'course_init_display'}; + } + unless ($current) { + $current = 'whatsnew'; + } + } + return ($control,$current); +} + +sub display_launcher { + my ($r,$action,$refpage,$checkallowed,$tabbg,$rowColor1,$rowColor2,$show, + $headings,$res_title,$tograde,$ungraded,$bombs,$bombed,$changed, + $warnings,$triggered,$newdiscussions,$unread,$msgcount,$newmsgs, + $critmsgcount,$critmsgs,$interval,$countunread) = @_; + + if ($$checkallowed{$action}) { + &start_box($r,$tabbg,$show,$headings,$action,$refpage); + if ($$show{$action}) { + if ($action eq 'handgrading') { # UNGRADED ITEMS + &display_handgrade($r,$tograde,$rowColor1,$rowColor2, + $ungraded); + } elsif ($action eq 'haserrors') { # BOMBS + &display_haserrors($r,$bombs,$rowColor1,$rowColor2,$bombed, + $res_title); + } elsif ($action eq 'versionchanges') { # VERSION CHANGES + &display_versionchanges($r,$changed,$res_title,$rowColor1, + $rowColor2,$interval); + + } elsif ($action eq 'abovethreshold') { # DEGDIFF/AV. TRIES TRIGGERS + &display_abovethreshold($r,$refpage,$warnings,$triggered, + $res_title,$rowColor1,$rowColor2); + } elsif ($action eq 'coursediscussion') { # UNREAD COURSE DISCUSSION + &display_coursediscussion($r,$newdiscussions,$unread, + $countunread,$res_title,$rowColor1,$rowColor2); + } elsif ($action eq 'coursenormalmail') { # NORMAL MESSAGES + &display_coursenormalmail($r,$msgcount,$newmsgs,$rowColor1, + $rowColor2); + } elsif ($action eq 'coursecritmail') { # CRITICAL MESSAGES + &display_coursecritmail($r,$critmsgcount,$critmsgs,$rowColor1, + $rowColor2); + } + } + &end_box($r); + } + return; } sub getitems { - my ($unread,$ungraded,$bombed,$triggered,$newdiscussions,$tograde,$bombs,$warnings,$rowColor1,$rowColor2,$threshold,$cdom,$crs,$res_title) = @_; + my ($unread,$ungraded,$bombed,$triggered,$changed,$newdiscussions, + $tograde,$bombs,$warnings,$rowColor1,$rowColor2,$threshold,$cdom,$crs, + $res_title,$show,$starttime,$countunread) = @_; my $navmap = Apache::lonnavmaps::navmap->new(); # force retrieve Resource to seed the part id cache we'll need it later - my @allres=$navmap->retrieveResources(undef,sub {if ($_[0]->is_problem) { $_[0]->parts();} return 1;}); - my %discussiontime = &Apache::lonnet::dump('discussiontimes',$cdom,$crs); - my %lastread = &Apache::lonnet::dump('nohist_'.$env{'request.course.id'}. - '_discuss',$env{'user.domain'},$env{'user.name'},'lastread'); - my %lastreadtime = (); - my @discussions = (); - my ($classlist,$keylist) = &Apache::loncoursedata::get_classlist(); + my @allres=$navmap->retrieveResources(undef, + sub {if ($_[0]->is_problem) { $_[0]->parts();} return 1;}); + my %resourcetracker; + my $discussiontime; + +# Resource version changes + if ($$show{'versionchanges'}) { + &checkversions($cdom,$crs,$navmap,$changed,$starttime); + } - my %resourcetracker = &Apache::lonnet::dump('nohist_resourcetracker', - $cdom,$crs); - my $warningnum = 0; - foreach my $key (keys(%lastread)) { - my $newkey = $key; - $newkey =~ s/_lastread$//; - $lastreadtime{$newkey} = $lastread{$key}; + if ($$show{'abovethreshold'}) { + %resourcetracker = &Apache::lonnet::dump('nohist_resourcetracker', + $cdom,$crs); } + + my $warningnum = 0; foreach my $resource (@allres) { my $result = ''; my $applies = 0; my $symb = $resource->symb(); -# %{$$bombed{$symb}} = (); + %{$$bombed{$symb}} = (); %{$$ungraded{$symb}} = (); %{$$triggered{$symb}} = (); $$triggered{$symb}{numparts} = 0; my $title = $resource->compTitle(); $$res_title{$symb} = $title; my $ressymb = $resource->wrap_symb(); -# Check for unread discussion postings - if ($resource->hasDiscussion()) { - push(@discussions,$ressymb); - my $prevread = 0; - my $unreadcount = 0; - %{$$unread{$ressymb}} = (); - $$unread{$ressymb}{'title'} = $title; - $$unread{$ressymb}{'symb'} = $symb; - if (defined($lastreadtime{$ressymb})) { - $prevread = $lastreadtime{$ressymb}; - } - my %contrib = &Apache::lonnet::restore($ressymb, - $env{'request.course.id'},$cdom,$crs); - if ($contrib{'version'}) { - for (my $id=1;$id<=$contrib{'version'};$id++) { - unless (($contrib{'hidden'}=~/\.$id\./) || ($contrib{'deleted'}=~/\.$id\./)) { - if ($prevread <$contrib{$id.':timestamp'}) { - $$unread{$ressymb}{$unreadcount} = $id.': '.$contrib{$id.':subject'}; - $unreadcount ++; - } - } - } - } - if ($unreadcount) { push(@{$newdiscussions}, $ressymb); } - } + +# Check if there are unread discussion postings + if ($$show{'coursediscussion'}) { + &check_discussions($resource,$symb,$ressymb,$title, + $newdiscussions,$unread,$countunread); + } # Check for ungraded problems if ($resource->is_problem()) { - my $ctr = 0; - my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - my $partlist=$resource->parts(); - my $handgradeable; - foreach my $part (@$partlist) { - if ($resource->handgrade($part) eq 'yes') { - $handgradeable=1; last; - } - } - if ($handgradeable) { - foreach my $student (keys(%$classlist)) { - my ($uname,$udom) = split(/:/,$student); - my %status=&Apache::grades::student_gradeStatus($url,$symb,$udom,$uname,$partlist); - my $submitted = 0; - my $ungraded = 0; - foreach (keys(%status)) { - $submitted = 1 if ($status{$_} ne 'nothing'); - $ungraded = 1 if ($status{$_} =~ /^ungraded/); - my ($foo,$partid,$foo1) = split(/\./,$_); - if ($status{'resource.'.$partid.'.submitted_by'} ne '') { - $submitted = 0; - } - } - next if (!$submitted || !$ungraded); - $ctr ++; - } - if ($ctr) { - $$ungraded{$symb}{count} = $ctr; - $$ungraded{$symb}{title} = $title; - push(@{$tograde}, $symb); - } - } + if ($$show{'handgrading'}) { + &check_handgraded($resource,$symb,$title,$cdom,$crs,$ungraded, + $tograde); + } } # Check for bombs - if ($resource->getErrors()) { - my $errors = $resource->getErrors(); - $errors =~ s/^,//; - my @bombs = split(/,/, $errors); - my $errorcount = scalar(@bombs); - my $errorlink = ''. - $title.''; - $$bombed{$symb}{errorcount} = $errorcount; - $$bombed{$symb}{errorlink} = $errorlink; - push(@{$bombs}, $symb); - } -# Compile maxtries and degree of difficulty for problem parts - my @parts = @{$resource->parts()}; - my %stats; - my %lastreset = (); - my $warning = 0; - my $rowColor; - foreach my $part (@parts) { - %{$stats{$part}} = (); - my ($attempts,$users,$corrects,$degdiff,$av_attempts); - if (exists($resourcetracker{$symb."\0".$part."\0attempts"})) { - $attempts = $resourcetracker{$symb."\0".$part."\0attempts"}; - } - if (exists($resourcetracker{$symb."\0".$part."\0users"})) { - $users = $resourcetracker{$symb."\0".$part."\0users"}; - } - if (exists($resourcetracker{$symb."\0".$part."\0correct"})) { - $corrects = $resourcetracker{$symb."\0".$part."\0correct"}; - } - if ($attempts > 0) { - $degdiff = 1 - ($corrects/$attempts); - $degdiff = sprintf("%.2f",$degdiff); - } - if ($users > 0) { - $av_attempts = $attempts/$users; - $av_attempts = sprintf("%.2f",$av_attempts); - } - if ((($degdiff ne '' && $degdiff >= $$threshold{'degdiff'}) || ($av_attempts ne '' && $av_attempts >= $$threshold{'av_attempts'})) && ($users >= $$threshold{'numstudents'})) { - $stats{$part}{degdiff} = $degdiff; - $stats{$part}{attempts} = $av_attempts; - $stats{$part}{users} = $users; - $lastreset{$part} = $resourcetracker{$symb."\0".$part."\0resettime"}; - $warning = 1; + if ($$show{'haserrors'}) { + &check_bombed($resource,$symb,$title,$bombs,$bombed); + } + +# Maxtries and degree of difficulty for problem parts, unless handgradeable + if ($$show{'abovethreshold'}) { + &check_thresholds($resource,$symb,\%resourcetracker,$triggered, + $threshold,$warnings,$warningnum,$rowColor1,$rowColor2); + } + + } +} + +sub check_discussions { + my ($resource,$symb,$ressymb,$title,$newdiscussions,$unread, + $countunread) = @_; + + if (!$resource->hasDiscussion()) { return; } + + %{$$unread{$ressymb}} = (); + $$unread{$ressymb}{'title'} = $title; + $$unread{$ressymb}{'symb'} = $symb; + push(@{$newdiscussions}, $ressymb); + + $$unread{$ressymb}{'lastpost'} = $resource->last_post_time(); + + if ($countunread eq 'on') { + $$unread{$ressymb}{'unreadcount'} = $resource->unread_discussion(); + } +} + +sub check_handgraded { + my ($resource,$symb,$title,$cdom,$cnum,$ungraded,$tograde) = @_; + if ($resource->is_problem()) { + my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); + my $partlist=$resource->parts(); + my $handgradeable; + foreach my $part (@$partlist) { + if ($resource->handgrade($part) eq 'yes') { + $handgradeable=1; last; } } - if ($warning) { - if ($warningnum %2 == 1) { - $rowColor = $rowColor1; - } else { - $rowColor = $rowColor2; + if ($handgradeable) { + my @ungraded = &Apache::bridgetask::get_queue_symb_status( + 'gradingqueue',$symb,$cdom,$cnum); + if (@ungraded > 0) { + $$ungraded{$symb}{count} = scalar(@ungraded); + $$ungraded{$symb}{title} = $title; + push(@{$tograde}, $symb); } - $$triggered{$symb}{title} = $resource->title; - foreach my $part (@parts) { - if (exists($stats{$part}{users})) { - my $resetname = 'reset_'.&Apache::lonnet::escape($symb."\0".$part); - my $resettitle = 'title_'.&Apache::lonnet::escape($symb."\0".$part); - if ($$triggered{$symb}{numparts}) { - $$triggered{$symb}{text} .= ''."\n"; - } - if (@parts > 1) { - $$triggered{$symb}{text} .= ' - part - '.$part.''; - } else { - $$triggered{$symb}{text} .= ' - single part'; - } + } + } +} + +sub check_bombed { + my ($resource,$symb,$title,$bombs,$bombed) = @_; + if ($resource->getErrors()) { + my $errors = $resource->getErrors(); + $errors =~ s/^,//; + my @bombs = split(/,/, $errors); + my $errorcount = scalar(@bombs); + my $errorlink = ''. + $title.''; + $$bombed{$symb}{errorcount} = $errorcount; + $$bombed{$symb}{errorlink} = $errorlink; + push(@{$bombs}, $symb); + } +} + +sub check_thresholds { + my ($resource,$symb,$resourcetracker,$triggered,$threshold,$warnings, + $warningnum,$rowColor1,$rowColor2) = @_; +# Compile maxtries and degree of difficulty for problem parts, unless handgradeable + my @parts = @{$resource->parts()}; + my %stats; + my %lastreset = (); + my $warning = 0; + my $rowColor; + foreach my $part (@parts) { + if ($resource->handgrade($part) eq 'yes') { + next; + } + if ($resource->is_survey($part)) { + next; + } + %{$stats{$part}} = (); + my ($attempts,$users,$corrects,$degdiff,$av_attempts); + if (exists($$resourcetracker{$symb."\0".$part."\0attempts"})) { + $attempts = $$resourcetracker{$symb."\0".$part."\0attempts"}; + } + if (exists($$resourcetracker{$symb."\0".$part."\0users"})) { + $users = $$resourcetracker{$symb."\0".$part."\0users"}; + } + if (exists($$resourcetracker{$symb."\0".$part."\0correct"})) { + $corrects = $$resourcetracker{$symb."\0".$part."\0correct"}; + } + if ($attempts > 0) { + $degdiff = 1 - ($corrects/$attempts); + $degdiff = sprintf("%.2f",$degdiff); + } + if ($users > 0) { + $av_attempts = $attempts/$users; + $av_attempts = sprintf("%.2f",$av_attempts); + } + if ((($degdiff ne '' && $degdiff >= $$threshold{'degdiff'}) || ($av_attempts ne '' && $av_attempts >= $$threshold{'av_attempts'})) && ($users >= $$threshold{'numstudents'})) { + $stats{$part}{degdiff} = $degdiff; + $stats{$part}{attempts} = $av_attempts; + $stats{$part}{users} = $users; + $lastreset{$part} = $$resourcetracker{$symb."\0".$part."\0resettime"}; + if ($lastreset{$part}) { + $lastreset{$part} = &Apache::lonnavmaps::timeToHumanString($lastreset{$part}); + } + $warning = 1; + } + } + if ($warning) { + if ($warningnum %2 == 1) { + $rowColor = $rowColor1; + } else { + $rowColor = $rowColor2; + } + $$triggered{$symb}{title} = $resource->title; + foreach my $part (@parts) { + if (exists($stats{$part}{users})) { + my $resetname = 'reset_'.&Apache::lonnet::escape($symb."\0".$part); + my $resettitle = 'title_'.&Apache::lonnet::escape($symb."\0".$part); + if ($$triggered{$symb}{numparts}) { + $$triggered{$symb}{text} .= ''."\n"; + } + if (@parts > 1) { + $$triggered{$symb}{text} .= ' + part - '.$part.''; + } else { $$triggered{$symb}{text} .= ' - '.$stats{$part}{users}.' - '.$stats{$part}{attempts}.' - '.$stats{$part}{degdiff}.' - '.$lastreset{$part}.' - - '; - $$triggered{$symb}{numparts} ++; + single part'; } + $$triggered{$symb}{text} .= ' + '.$stats{$part}{users}.' + '.$stats{$part}{attempts}.' + '.$stats{$part}{degdiff}.' + '.$lastreset{$part}.' + + '; + $$triggered{$symb}{numparts} ++; } - push(@{$warnings},$symb); - $warningnum ++; } + push(@{$warnings},$symb); + $warningnum ++; } } + sub get_curr_thresholds { - my ($threshold,$cdom,$crs) = @_; - my %coursesettings = &Apache::lonnet::dump('environment', - $cdom,$crs,'internal.threshold'); - if (exists($coursesettings{'internal.threshold_av_attempts'})) { - $$threshold{'av_attempts'} = $coursesettings{'internal.threshold_av_attempts'}; + my ($threshold,$uname,$udom,$cid,$cdom,$crs) = @_; + my %thresholdsettings = &Apache::lonnet::dump('nohist_whatsnew',$udom, + $uname,$cid.':threshold'); + my $thresholdcount = 0; + my ($tmp) = %thresholdsettings; + unless ($tmp =~ /^(con_lost|error|no_such_host)/i) { + foreach my $item (keys %{$threshold}) { + if (exists($thresholdsettings{$cid.':threshold_'.$item})) { + $$threshold{$item} = + $thresholdsettings{$cid.':threshold_'.$item}; + $thresholdcount ++; + } + } + } + if ($thresholdcount == 3) { + return; } - if (exists($coursesettings{'internal.threshold_degdiff'})) { - $$threshold{'degdiff'} = $coursesettings{'internal.threshold_degdiff'}; + my %coursesettings = &Apache::lonnet::dump('environment', + $cdom,$crs,'internal.threshold'); + my ($temp) = %coursesettings; + unless ($temp =~ /^(con_lost|error|no_such_host)/i) { + foreach my $item (keys %{$threshold}) { + unless (exists($thresholdsettings{$cid.':threshold_'.$item})) { + if (exists($coursesettings{'internal.threshold_'.$item})) { + $$threshold{$item} = + $coursesettings{'internal.threshold_'.$item}; + } + } + } } - if (exists($coursesettings{'internal.threshold_numstudents'})) { - $$threshold{'numstudents'} = $coursesettings{'internal.threshold_numstudents'}; + return; +} + +sub get_current { + my ($uname,$udom,$cid,$caller) = @_; + my $currvalue; + my %settings = &Apache::lonnet::dump('nohist_whatsnew',$udom,$uname,$cid. + ':'.$caller); + my ($tmp) = %settings; + unless ($tmp =~ /^(con_lost|error|no_such_host)/i) { + $currvalue = $settings{$cid.':'.$caller}; } + return $currvalue; } sub process_reset { my ($dom,$crs) = @_; - my $result = 'Counters reset for following problems (and parts):
'; + my $result = ''.&mt('Counters reset for following problems (and parts):'). + '
'; my @agg_types = ('attempts','users','correct'); - my %agg_titles = ( + my %agg_titles = &Apache::lonlocal::texthash ( attempts => 'Number of submissions', users => 'Students with submissions', correct => 'Number of correct submissions', @@ -737,17 +985,17 @@ sub process_reset { } sub process_update { - my ($dom,$crs,$threshold_titles) = @_; + my ($uname,$udom,$threshold_titles) = @_; my $setoutput = 'Changes to threshold(s) for problem tracking:
'; foreach (keys %env) { next if ($_!~/^form\.(.+)\_setparmval$/); my $name = $1; my $value = $env{'form.'.$name.'_value'}; if ($name && defined($value)) { - my $put_result = &Apache::lonnet::put('environment', - {$name=>$value},$dom,$crs); + my $put_result = &Apache::lonnet::put('nohist_whatsnew', + {$name=>$value},$udom,$uname); - my ($shortname) = ($name =~ /^internal\.threshold_(.+)$/); + my ($shortname) = ($name =~ /^\Q$env{'request.course.id'}\E:threshold_(.+)$/); if ($put_result eq 'ok') { $setoutput.=&mt('Set threshold for [_1] to [_2]', ''.$$threshold_titles{$shortname}.'', @@ -762,8 +1010,8 @@ sub process_update { return $setoutput; } -sub getmail { - my ($newmsgs,$critmsgs) = @_; +sub getnormalmail { + my ($newmsgs) = @_; # Check for unread mail in course my $msgcount = 0; @@ -781,7 +1029,6 @@ sub getmail { if ($shortsubj eq '') { $shortsubj = &mt('No subject'); } - $shortsubj = &Apache::lonnet::unescape($shortsubj); push(@{$newmsgs}, { msgid => $msgid, sendtime => $sendtime, @@ -793,7 +1040,11 @@ sub getmail { } } } + return $msgcount; +} +sub getcritmail { + my ($critmsgs) = @_; # Check for critical messages in course my %what=&Apache::lonnet::dump('critical'); my $result = ''; @@ -809,7 +1060,6 @@ sub getmail { if ($shortsubj eq '') { $shortsubj = &mt('No subject'); } - $shortsubj = &Apache::lonnet::unescape($shortsubj); push(@{$critmsgs}, { msgid => $msgid, sendtime => $sendtime, @@ -820,7 +1070,285 @@ sub getmail { } } } - return ($msgcount,$critmsgcount); + return $critmsgcount; +} + + +sub checkversions { + my ($cdom,$crs,$navmap,$changed,$starttime) = @_; + my %changes=&Apache::lonnet::dump('versionupdate',$cdom,$crs); + my ($tmp) = keys(%changes); + unless ($tmp =~ /^(con_lost|error|no_such_host)/i) { + if (keys(%changes) > 0) { + foreach my $key (sort(keys(%changes))) { + if ($changes{$key} > $starttime) { + my $version; + my ($root,$extension)=($key=~/^(.*)\.(\w+)$/); + my $currentversion=&Apache::lonnet::getversion($key); + my $revdate = + &Apache::lonnet::metadata($root.'.'.$extension, + 'lastrevisiondate'); + $revdate = &Apache::lonlocal::locallocaltime($revdate); + my $linkurl=&Apache::lonnet::clutter($key); + my $usedversion=$navmap->usedVersion('version_'.$linkurl); + my @resources = $navmap->getResourceByUrl($linkurl,1); + if (($usedversion) && ($usedversion ne 'mostrecent')) { + $version = $usedversion; + } else { + $version = $currentversion; + } + foreach my $res (@resources) { + if (ref($res) eq 'Apache::lonnavmaps::resource') { + my $symb = $res->symb(); + %{$$changed{$symb}} = ( + current => $currentversion, + version => $version, + revdate => $revdate, + ); + } + } + } + } + } + } + return; +} + +sub display_handgrade { + my ($r,$tograde,$rowColor1,$rowColor2,$ungraded) = @_; + my $rowColor; + my %lt = &Apache::lonlocal::texthash( + 'prna' => 'Problem Name', + 'nmun' => 'Number ungraded', + 'nopr' => 'No problems require handgrading', + ); + if (@{$tograde} > 0) { + $r->print(''.$lt{'prna'}.''.$lt{'nmun'}.''); + my $rowNum = 0; + foreach my $res (@{$tograde}) { + if ($rowNum %2 == 1) { + $rowColor = $rowColor1; + } else { + $rowColor = $rowColor2; + } + my ($map,$id,$url)=&Apache::lonnet::decode_symb($res); + my $linkurl=&Apache::lonnet::clutter($url); + $linkurl .= '?symb='.&Apache::lonnet::escape($res); + + $r->print(''.$$ungraded{$res}{title}.''.$$ungraded{$res}{count}.''); + $rowNum ++; + } + } else { + $r->print('
  '.$lt{'nopr'}.'  

'); + } +} + +sub display_haserrors { + my ($r,$bombs,$rowColor1,$rowColor2,$bombed,$res_title) = @_; + my $bombnum = 0; + my $rowColor; + my %lt = &Apache::lonlocal::texthash( + reso => 'Resource', + nmer => 'Number of errors', + noer => 'No problems with errors', + ); + if (@{$bombs} > 0) { + $r->print(''.$lt{'reso'}.''.$lt{'nmer'}.''); + @{$bombs} = sort { &cmp_title($a,$b,$res_title) } @{$bombs}; + foreach my $bomb (@{$bombs}) { + if ($bombnum %2 == 1) { + $rowColor = $rowColor1; + } else { + $rowColor = $rowColor2; + } + $r->print(''.$$bombed{$bomb}{errorlink}.''.$$bombed{$bomb}{errorcount}.''); + $bombnum ++; + } + } else { + $r->print('
'.$lt{'noer'}.'

'); + } + return; +} + +sub display_abovethreshold { + my ($r,$refpage,$warnings,$triggered,$res_title,$rowColor1,$rowColor2) = @_; + my %lt = &Apache::lonlocal::texthash( + reso => 'Resource', + part => 'Part', + nust => 'Num. students', + avat => 'Av. Attempts', + dedi => 'Deg. Diff', + lare => 'Last Reset', + reco => 'Reset Count?', + rese => 'Reset counters to 0', + nopr => 'No problems satisfy threshold criteria', + ); + my $rowColor; + my $warningnum = 0; + if (@{$warnings} > 0) { + @{$warnings} = sort { &cmp_title($a,$b,$res_title) } @{$warnings}; + $r->print('
'. + ' '."\n". + ' '. + "\n"); + $r->print(''.$lt{'reso'}.''.$lt{'part'}.''.$lt{'nust'}.''.$lt{'avat'}.''.$lt{'dedi'}.''.$lt{'lare'}.''.$lt{'reco'}.''); + foreach my $res (@{$warnings}) { + if ($warningnum %2 == 1) { + $rowColor = $rowColor1; + } else { + $rowColor = $rowColor2; + } + my ($map,$id,$url)=&Apache::lonnet::decode_symb($res); + my $linkurl=&Apache::lonnet::clutter($url); + my $rowspan; + if ($$triggered{$res}{numparts} > 1) { + $rowspan = 'rowspan="'.$$triggered{$res}{numparts}.'"'; + } + $linkurl .= '?symb='.&Apache::lonnet::escape($res); + $r->print(''.$$triggered{$res}{title}.''.$$triggered{$res}{text}); + $warningnum ++; + } + $r->print('
'); + } else { + $r->print('
'.$lt{'nopr'}.'

'); + } +} + +sub display_versionchanges { + my ($r,$changed,$res_title,$rowColor1,$rowColor2,$interval) = @_; + my %lt = &Apache::lonlocal::texthash( + 'reso' => 'Resource', + 'revd' => 'Last revised', + 'newv' => 'New version', + 'veru' => 'Version used', + 'noup' => 'No updated versions', + ); + my $rowColor; + if (keys(%{$changed}) > 0) { + $r->print(''.$lt{'reso'}.''.$lt{'revd'}.''.$lt{'newv'}.''.$lt{'veru'}.''); + + + my @changes = sort { &cmp_title($a,$b,$res_title) } keys(%{$changed}); + my $changenum = 0; + foreach my $item (@changes) { + if ($changenum %2 == 1) { + $rowColor = $rowColor1; + } else { + $rowColor = $rowColor2; + } + my ($map,$id,$url)=&Apache::lonnet::decode_symb($item); + my $linkurl=&Apache::lonnet::clutter($url); + $linkurl .= '?symb='.&Apache::lonnet::escape($item); + + $r->print(''.$$res_title{$item}.''.$$changed{$item}{'revdate'}.''.$$changed{$item}{'current'}.''.$$changed{$item}{'version'}.''); + $changenum ++; + } + } else { + $r->print('
'.$lt{'noup'}.' '.$interval.'

'); + } + return; +} + +sub display_coursediscussion { + my ($r,$newdiscussions,$unread,$countunread,$res_title,$rowColor1, + $rowColor2) = @_; + my %lt = &Apache::lonlocal::texthash( + 'loca' => 'Location', + 'type' => 'Type', + 'numn' => 'Number of new posts', + 'noun' => 'No unread posts in course discussions', + 'tmlp' => 'Time of last post', + ); + my $rowColor; + if (@{$newdiscussions} > 0) { + $r->print(''.$lt{'loca'}. + ''.$lt{'type'}. + ''); + if ($countunread eq 'on') { + $r->print(''.$lt{'tmlp'}.''. + ''.$lt{'numn'}. + ''); + } else { + $r->print(''.$lt{'tmlp'}. + ''); + } + $r->print("\n"); + @{$newdiscussions} = sort { &cmp_title($a,$b,$res_title) } + @{$newdiscussions}; + my $rowNum = 0; + foreach my $ressymb (@{$newdiscussions}) { + my $forum_title = $$unread{$ressymb}{'title'}; + my $type = 'Resource'; + my $feedurl=&Apache::lonfeedback::get_feedurl($ressymb); + if ($feedurl =~ /bulletinboard/) { + $type = 'Bulletin Board'; + } + if ($rowNum %2 == 1) { + $rowColor = $rowColor1; + } else { + $rowColor = $rowColor2; + } + my $lastpost = &Apache::lonnavmaps::timeToHumanString( + $$unread{$ressymb}{'lastpost'}); + $r->print(''.$forum_title.' '.$type.' '); + if ($countunread eq 'on') { + my $unreadnum = $$unread{$ressymb}{'unreadcount'}; + $r->print(''.$lastpost.''. + '',$unreadnum.' '); + } else { + $r->print(''.$lastpost.''); + } + $r->print("\n"); + $rowNum ++; + } + } else { + $r->print('
 '. + $lt{'noun'}.'

'); + } +} + +sub display_coursenormalmail { + my ($r,$msgcount,$newmsgs,$rowColor1,$rowColor2) = @_; + my $rowColor; + if ($msgcount > 0) { + $r->print(''.&mt('Number').''.&mt('Subject').''.&mt('Sender').''.&mt('Date/Time').''); + my $rowNum = 0; + my $mailcount = 1; + foreach my $msg (@{$newmsgs}) { + if ($rowNum %2 == 1) { + $rowColor = $rowColor1; + } else { + $rowColor = $rowColor2; + } + $r->print(''.$mailcount.'.  '.$msg->{'shortsub'}.'    '.$msg->{'from'}.'@'.$msg->{'fromdom'}.' '.$msg->{'sendtime'}.''); + $rowNum ++; + $mailcount ++; + } + } else { + $r->print('

'.&mt('No new course messages').'

'); + } +} + +sub display_coursecritmail { + my ($r,$critmsgcount,$critmsgs,$rowColor1,$rowColor2) = @_; + my $rowColor; + if ($critmsgcount > 0) { + $r->print(''.&mt('Number').''.&mt('Subject').''.&mt('Sender').''.&mt('Date/Time').''); + my $rowNum = 0; + my $mailcount = 1; + foreach my $msg (@{$critmsgs}) { + if ($rowNum %2 == 1) { + $rowColor = $rowColor1; + } else { + $rowColor = $rowColor2; + } + $r->print(''.$mailcount.'.  '.$msg->{'shortsub'}.'    '.$msg->{'from'}.'@'.$msg->{'fromdom'}.' '.$msg->{'sendtime'}.''); + $rowNum ++; + $mailcount ++; + } + } else { + $r->print('

'.&mt('No unread critical messages in course').'

'); + } } sub cmp_title { @@ -831,4 +1359,206 @@ sub cmp_title { return $atitle cmp $btitle; } +sub get_display_settings { + my ($uname,$udom,$cid) = @_; + my %settings = &Apache::lonnet::dump('nohist_whatsnew',$udom,$uname,$cid); + my ($tmp) = keys(%settings); + if ($tmp=~ /^(con_lost|error|no_such_host)/i) { + %settings = (); + unless ($tmp =~ /^error: 2 /) { + &Apache::lonnet::logthis('Error retrieving whatsnew settings: '. + $tmp.' for '.$uname.':'.$udom.' for course: '.$cid); + } + } + return %settings; +} + +sub store_display_settings { + my ($uname,$udom,$cid,$checkallowed) = @_; + my %whatsnew_settings; + my $result; + foreach my $key (keys(%{$checkallowed})) { + if ($key =~ /_section$/) { next; } + if (exists($env{'form.display_'.$key})) { + unless ($env{'form.display_'.$key} eq '') { + $whatsnew_settings{$cid.':'.$key} = $env{'form.display_'.$key}; + } + } + } + if (keys(%whatsnew_settings)) { + $result = &Apache::lonnet::put('nohist_whatsnew',\%whatsnew_settings, + $udom,$uname); + } else { + $result = 'ok'; + } + return $result; +} + +sub store_interval_setting { + my ($uname,$udom,$cid,$interval_titles) = @_; + my %interval_settings = (); + my $result; + if (defined($env{'form.interval'})) { + $interval_settings{$cid.':interval'} = $env{'form.interval'}; + my $outcome = &Apache::lonnet::put('nohist_whatsnew', + \%interval_settings,$udom,$uname); + if ($outcome eq 'ok') { + $result = &mt('Interval set to version changes [_1]', + ''.$$interval_titles{$env{'form.interval'}}.'
'); + + } else { + &Apache::lonnet::logthis('Error storing whatsnew interval setting'. + ' '.$outcome.' for '.$uname.':'.$udom.' in course '.$cid); + $result = &mt('Unable to set interval to [_1] due to [_2].', + ''.$$interval_titles{$env{'form.interval'}}.'', + ''.$outcome.'.
'); + } + } + return $result; +} + +sub store_discussion_setting { + my ($uname,$udom,$cid) = @_; + my %discussion_settings; + my $result; + if (defined($env{'form.countunread'})) { + $discussion_settings{$cid.':countunread'} = $env{'form.countunread'}; + my $outcome = &Apache::lonnet::put('nohist_whatsnew', + \%discussion_settings,$udom,$uname); + if ($outcome eq 'ok') { + $result = &mt('Count unread posts in discussions display set to [_1]', + ''.$env{'form.countunread'}.'
'); + + } else { + &Apache::lonnet::logthis('Error storing whatsnew countunread setting'. + ' '.$outcome.' for '.$uname.':'.$udom.' in course '.$cid); + $result = &mt('Unable to set "number unread posts display" to [_1]'. + ' due to [_2].', + ''.$env{'form.countunread'}.'', + ''.$outcome.'.
'); + } + } + return $result; +} + +sub store_courseinit_setting { + my ($uname,$udom,$cid,$initpage) = @_; + my %courseinit_settings; + my $page_control; + my $result; + if (defined($env{'form.courseinit_control'})) { + if ($env{'form.courseinit_control'} eq 'userpref') { + $courseinit_settings{$cid.':courseinit'} = ''; + $page_control = 'global preferences'; + } else { + if (defined($env{'form.courseinit_page'})) { + $courseinit_settings{$cid.':courseinit'} = + $env{'form.courseinit_page'}; + $page_control = 'course specific setting'; + } + } + if ($page_control) { + my $outcome = &Apache::lonnet::put('nohist_whatsnew', + \%courseinit_settings,$udom,$uname); + if ($outcome eq 'ok') { + if ($page_control eq 'global preferences') { + $result = &mt('Page displayed after role selection in course now set by [_1]',"user's global preferences."); + } else { + $result = &mt('Page displayed after role selection in this course set to [_1]',''.$$initpage{$env{'form.courseinit_page'}}.'.'); + } + } else { + &Apache::lonnet::logthis('Error storing whatsnew courseinit '. + 'setting: '.$outcome.' for '.$uname. + ':'.$udom.' in course '.$cid); + if ($page_control eq 'global preferences') { + $result = &mt('Unable to set control of page display to [_1]'. + ' due to [_2].', + ''.$page_control.'', + ''.$outcome.'.
'); + } else { + $result = &mt('Unable to set page display, after role selection, for this course to [_1] due to [_2].', + ''.$$initpage{$env{'form.courseinit_page'}}.'', + ''.$outcome.'.
'); + } + } + } + } + return $result; +} + +sub start_box { + my ($r,$tabbg,$show,$heading,$caller,$refpage) = @_; + my %lt = &Apache::lonlocal::texthash( + chth => 'Change thresholds?', + chin => 'Change interval?', + chop => 'Change options?', + ); + my $showhide; + if ($$show{$caller}) { + $showhide = 'Hide'; + + } else { + $showhide = 'Show'; + } + + $r->print(' + + + + +
+ + + + '); + if (($caller eq 'abovethreshold') && ($$show{$caller})) { + if ($$show{$caller}) { + $r->print(' + + + '); + } + } elsif (($caller eq 'versionchanges') && ($$show{$caller})) { + if ($$show{$caller}) { + $r->print(' + + + '); + } + } elsif ($caller eq 'coursediscussion') { + if ($$show{$caller}) { + $r->print(' + + + '); + } + } + $r->print(' + + + +
+ + + + + +
'.$$heading{$caller}.''.$showhide.'
+
'.$lt{'chth'}.'
'.$lt{'chin'}.'
'.$lt{'chop'}.'
+ +'); + return; +} + +sub end_box { + my ($r) = shift; + $r->print(' +
+
+

'); + return; +} + 1; 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.