--- loncom/interface/lonwhatsnew.pm 2016/10/23 21:50:55 1.120 +++ loncom/interface/lonwhatsnew.pm 2025/03/22 20:34:49 1.131 @@ -1,5 +1,7 @@ +# The LearningOnline Network +# What's New in a course # -# $Id: lonwhatsnew.pm,v 1.120 2016/10/23 21:50:55 raeburn Exp $ +# $Id: lonwhatsnew.pm,v 1.131 2025/03/22 20:34:49 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -62,17 +64,36 @@ sub handler { my $command = $env{'form.command'}; my $refpage = $env{'form.refpage'}; - my %checkallowed = ( coursenormalmail => 1, - coursecritmail => 1, ); + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; + + my ($isadhoc,%checkallowed); + + if ($env{'request.role'} =~ m{^(cc|co)/}) { + my $rolecode = $1; + if ($env{"environment.internal.$cdom.$crs.$env{'request.role'}.adhoc"}) { + $isadhoc = 1; + } + } elsif ($env{'request.role'} =~ m{^cr/$cdom/$cdom\-domainconfig/(\w+)\./}) { + my $rolename = $1; + if ($env{"environment.internal.$cdom.$crs.cr/$cdom/$cdom-domainconfig/$rolename.adhoc"}) { + $isadhoc = 1; + } + } + unless ($isadhoc) { + %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], + ['vgr','haserrors',1], + ['whn','versionchanges',1], ['vcl','newroles',1], ['vcl','oldroles',1], ['whn','crslogin',1], + ['vcl','sessions',1], ['mgr','resetcounters',1], ) { my ($perm,$key,$check_section) = @{ $perm_check }; @@ -97,7 +118,23 @@ sub handler { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; - $r->print(&display_header($command,\%checkallowed)); + my $udom = $env{'user.domain'}; + my $uname = $env{'user.name'}; + my $cid = $env{'request.course.id'}; + my $store_result = &store_display_settings($uname,$udom,$cid,\%checkallowed); + my $store_error; + + unless ($store_result eq 'ok') { + my $lctype = lc(&Apache::loncommon::course_type()); + &Apache::lonnet::logthis('Error saving whatsnew settings: '. + $store_result.' for '.'user '.$uname.':'.$udom.' in '.$lctype.' '.$cid); + $store_error = '' + .&mt('Unable to save visibility settings due to [_1]', + $store_result) + .''; + } + + $r->print(&display_header($command,$uname,$udom,$cid,\%checkallowed)); &Apache::lonhtmlcommon::clear_breadcrumbs(); &Apache::lonhtmlcommon::add_breadcrumb @@ -152,12 +189,19 @@ sub handler { $r->print(&Apache::lonhtmlcommon::breadcrumbs ("What's New?",#'Course_Action_Items_Intervals' )); + } elsif ($command eq 'chgsessionlimit' && $checkallowed{'sessions'}) { + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>'/adm/whatsnew?command=chgsessionlimit&refpage='.$refpage, + text=>"Change session range"}); + $r->print(&Apache::lonhtmlcommon::breadcrumbs + ("What's New?",#'Course_Action_Items_Sessions' + )); } else { $r->print(&Apache::lonhtmlcommon::breadcrumbs ("What's New?",#'Course_Action_Items_Display' )); } - &display_main_box($r,$command,$refpage,\%checkallowed); + &display_main_box($r,$command,$refpage,\%checkallowed,$cdom,$crs,$store_error); return OK; } @@ -168,7 +212,7 @@ sub handler { #------------------------------ sub display_main_box { - my ($r,$command,$refpage,$checkallowed) = @_; + my ($r,$command,$refpage,$checkallowed,$cdom,$crs,$store_error) = @_; my $domain=&Apache::loncommon::determinedomain(); my $function = &Apache::loncommon::get_users_function(); my $lctype = lc(&Apache::loncommon::course_type()); @@ -203,25 +247,30 @@ sub display_main_box { 604800 => 'last logins for users in last 7 days', 86400 => 'last logins for users in last 24 hours', ); + my %sessions = ( + 300 => 'course sessions active in the last 5 minutes', + 600 => 'course sessions active in the last 10 minutes', + 1800 => 'course sessions active in the last 30 minutes', + 7200 => 'course sessions active in the last 2 hours', + -7200 => 'course sessions with last activity more than 2 hours ago', + ); my %interval_titles = ( versions => \%versions, newroles => \%newroles, oldroles => \%oldroles, crslogin => \%crslogins, + sessions => \%sessions, ); - my %initpage = &Apache::lonlocal::texthash ( + my %initpage = ( firstres => "first resource in the $lctype", whatsnew => "What's New Page", userpref => 'your general user preferences', coursespecific => "specific setting for this $lctype", ); - my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; - my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; if (($command eq 'chgthreshold') && $checkallowed->{'abovethreshold'}) { - &display_threshold_config($r,$refpage,\%threshold_titles, - $cdom,$crs); + &display_threshold_config($r,$refpage,\%threshold_titles,$cdom,$crs); } elsif (($command eq 'chginterval') && $checkallowed->{'versionchanges'}) { &display_interval_config($r,$refpage,\%interval_titles,'versions'); @@ -239,9 +288,13 @@ sub display_main_box { } elsif (($command eq 'chgcrslogininterval') && $checkallowed->{'crslogin'}) { &display_interval_config($r,$refpage,\%interval_titles,'crslogin'); + } elsif (($command eq 'chgsessionlimit') + && $checkallowed->{'sessions'}) { + &display_interval_config($r,$refpage,\%interval_titles,'sessions'); } else { &display_actions_box($r,$command,$refpage,\%threshold_titles, - \%interval_titles,\%initpage,$cdom,$crs,$checkallowed); + \%interval_titles,\%initpage,$cdom,$crs, + $checkallowed,$store_error); } my $end_page = &Apache::loncommon::end_page(); $r->print(< +// + +END + $loadentries{'onload'} = 'toggleCourseInit(document.courseinitswitch);'; + } else { + unless (($command eq 'chgthreshold' && $checkallowed->{'abovethreshold'}) || + ($command eq 'chginterval' && $checkallowed->{'versionchanges'}) || + ($command eq 'chgdisc' && $checkallowed->{'coursediscussion'}) || + ($command eq 'chgoldroleinterval' && $checkallowed->{'oldroles'}) || + ($command eq 'chgnewroleinterval' && $checkallowed->{'newroles'}) || + ($command eq 'chgcrslogininterval' && $checkallowed->{'crslogin'}) || + ($command eq 'chgsessionlimit' && $checkallowed->{'sessions'})) { + my %display_settings = &get_display_settings($uname,$udom,$cid); + $scripttag = <<"END"; -'; +ENDTOGG + if (($checkallowed->{'crslogin'}) && ($display_settings{$cid.':crslogin'} ne 'hide')) { + $loadentries{'onload'} = "toggledetails('login');"; + } + if (($checkallowed->{'sessions'}) && ($display_settings{$cid.':sessions'} ne 'hide')) { + $loadentries{'onload'} .= "toggledetails('session');"; + } + } } my $course_type=&Apache::loncommon::course_type(); + if (keys(%loadentries)) { + $args->{'add_entries'} = \%loadentries; + } return &Apache::loncommon::start_page("What's New?", - $scripttag); + $scripttag,$args); } #------------------------------- @@ -353,7 +452,7 @@ function togglelogins() { sub display_actions_box { my ($r,$command,$refpage,$threshold_titles,$interval_titles,$initpage, - $cdom,$crs,$checkallowed) = @_; + $cdom,$crs,$checkallowed,$store_error) = @_; my $udom = $env{'user.domain'}; my $uname = $env{'user.name'}; my $cid = $env{'request.course.id'}; @@ -389,6 +488,8 @@ sub display_actions_box { my %activated; my %loggedin; my $logincount; + my %sessions; + my $sessioncount; my %res_title = (); my %show = (); my $needitems = 0; @@ -428,7 +529,7 @@ sub display_actions_box { } $header .= &mt('Page set to be displayed after you have selected a role in this '.$lctype).'.' .' ' - .&mt('Currently: [_1].',''.$currinit.'') + .&mt('Currently: [_1].',''.$currinit.'') .' ' .&mt('[_1]Change[_2] for just [_3]this '.$lctype.'[_4] or for [_5]all your courses/communities[_6].' ,'' @@ -451,15 +552,8 @@ sub display_actions_box { $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 saving whatsnew settings: '. - $store_result.' for '.'user '.$uname.':'.$udom.' in '.$lctype.' '.$cid); - $result .= '' - .&mt('Unable to save visibility settings due to [_1]', - $store_result) - .''; + if ($store_error) { + $result = $store_error; } if ($result) { @@ -533,6 +627,22 @@ sub display_actions_box { $headings{'crslogin'} = &mt('Last login for users in last 24 hours'); } + $timediff{'sessions'} = $display_settings{$cid.':sessionactivity'}; + unless (defined($timediff{'sessions'})) { $timediff{'sessions'} = 7200; } + $interval{'sessions'} = $interval_titles->{'sessions'}->{$timediff{'sessions'}}; + + if ($timediff{'sessions'} == -7200) { + $headings{'sessions'} = &mt('Session with activity more than 2 hours ago'); + } elsif ($timediff{'sessions'} == 7200) { + $headings{'sessions'} = &mt('Session with activity in last 2 hours'); + } elsif ($timediff{'sessions'} == 1800) { + $headings{'sessions'} = &mt('Session with activity in last 30 minutes'); + } elsif ($timediff{'sessions'} == 600) { + $headings{'sessions'} = &mt('Session with activity in last 10 minutes'); + } elsif ($timediff{'sessions'} == 300) { + $headings{'sessions'} = &mt('Session with activity in last 5 minutes'); + } + my ($now,$starttime,$activatedstart,$expiredstart,$crsloginstart); $now = time; @@ -573,7 +683,20 @@ sub display_actions_box { $threshold{'av_attempts'},$threshold{'degdiff'}, '',$threshold{'numstudents'}); - my @actionorder = ('handgrading','haserrors','abovethreshold','versionchanges','coursediscussion','coursenormalmail','coursecritmail','newroles','oldroles','crslogin'); + my @actionorder = ('handgrading','haserrors','abovethreshold','versionchanges','coursediscussion','coursenormalmail','coursecritmail','newroles','oldroles','crslogin','sessions'); + my %actioncolumn = ( + handgrading => 'left', + haserrors => 'left', + abovethreshold => 'left', + versionchanges => 'left', + coursediscussion => 'right', + coursenormalmail => 'right', + coursecritmail => 'right', + newroles => 'right', + oldroles => 'right', + crslogin => 'right', + sessions => 'right', + ); foreach my $key (keys(%{$checkallowed})) { if ($key =~ /_section$/) { next; } @@ -587,7 +710,8 @@ sub display_actions_box { foreach my $item (@actionorder) { unless ($item eq 'coursenormalmail' || $item eq 'coursecritmail' || - $item eq 'newroles' || $item eq 'oldroles') { + $item eq 'newroles' || $item eq 'oldroles' || + $item eq 'crslogin' || $item eq 'sessions') { if ($show{$item}) { $needitems = 1; last; @@ -600,7 +724,7 @@ sub display_actions_box { $itemserror = &getitems(\%unread,\%ungraded,\%bombed,\%triggered,\%changed,\@newdiscussions,\@tograde,\@bombs,\@warnings,\%threshold,$cdom,$crs,\%res_title,\%show,$starttime,$countunread,$checkallowed); } my $classlist; - if ($show{'oldroles'} || $show{'newroles'} || $show{'crslogin'}) { + if ($show{'oldroles'} || $show{'newroles'} || $show{'crslogin'} || $show{'sessions'}) { $classlist = &Apache::loncoursedata::get_classlist(); } if ($show{'coursenormalmail'}) { @@ -618,9 +742,16 @@ sub display_actions_box { if ($show{'crslogin'}) { $logincount = &getloggedin($cdom,$crs,\%loggedin,$crsloginstart); } - $r->print(qq|$lt{'hial'} - $lt{'shal'} - \n|); + if ($show{'sessions'}) { + $sessioncount = &getsessions($cdom,$crs,\%sessions,$timediff{'sessions'},$classlist); + } + my $showhideall = <<"END"; +$lt{'hial'} + $lt{'shal'} +END + $r->print(&Apache::loncommon::head_subbox($showhideall)); + $r->print(qq|\n|); + foreach my $item (keys(%{$checkallowed})) { if ($item =~ /_section$/) { next; } if ($$checkallowed{$item}) { @@ -639,14 +770,15 @@ sub display_actions_box { $totalboxes ++; } } - my $halfway = 4; + my $currcolumn = 'left'; # my $halfway = int($totalboxes/2) + $totalboxes%2; foreach my $actionitem (@actionorder) { - if ($$checkallowed{$actionitem}) { - if ($displayed == $halfway) { + if ($checkallowed->{$actionitem}) { + if (($actioncolumn{$actionitem} eq 'right') && ($currcolumn eq 'left')) { $r->print(' '); + $currcolumn = 'right'; } - &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,$classlist); + &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,\%sessions,$sessioncount,$classlist); $displayed ++; } } @@ -696,13 +828,18 @@ sub display_threshold_config { my $onchange = 'onfocus="javascript:window.document.forms'. "['thresholdform'].elements['".$parameter."_setparmval']". '.checked=true;"'; + my $aria_textbox = ' aria-label="'.&mt('Threshold value for [_1]', + $threshold_titles{$type}).'"'; + my $aria_checkbox = ' aria-label="'.&mt('Change threshold value for [_1]', + $threshold_titles{$type}).'"'; $r->print(&Apache::loncommon::start_data_table_row()."\n". ''.$threshold_titles{$type}.''."\n". ''.&Apache::lonhtmlcommon::textbox($parameter.'_value', $threshold{$type}, - 10,$onchange).''."\n". + 10,$onchange.$aria_textbox).''."\n". ''. - &Apache::lonhtmlcommon::checkbox($parameter.'_setparmval'). + &Apache::lonhtmlcommon::checkbox($parameter.'_setparmval', + '','',$aria_checkbox). ''."\n". &Apache::loncommon::end_data_table_row()); } @@ -727,6 +864,8 @@ sub display_interval_config { $setting = 'oldroleinterval'; } elsif ($context eq 'newroles') { $setting = 'newroleinterval'; + } elsif ($context eq 'sessions') { + $setting = 'sessionactivity'; } my $lctype = lc(&Apache::loncommon::course_type()); my $current = &get_current($env{'user.name'},$env{'user.domain'}, @@ -737,6 +876,8 @@ sub display_interval_config { $r->print(''.&mt('Choose the time window to use to display roles for which access to the '.$lctype.' became available.').''); } elsif ($context eq 'crslogin') { $r->print(''.&mt('Choose the time window to use to display the last login by a user in the '.$lctype).''); + } elsif ($context eq 'sessions') { + $r->print(''.&mt('Choose the time limit to use to display active user sessions in the '.$lctype.'.').''); } else { $r->print(''.&mt('Choose the time window to use to display resources in the '.$lctype.' with version changes.').''); } @@ -752,12 +893,19 @@ sub display_interval_config { '. &mt('Display:').' - + '.&mt('Select').' '); if (ref($interval_titles) eq 'HASH') { if (ref($interval_titles->{$context}) eq 'HASH') { - foreach my $key (reverse sort ({$a cmp $b} (keys(%{$interval_titles->{$context}})))) { + my @sorted; + if ($context eq 'sessions') { + @sorted = sort { $a <=> $b } (keys(%{$interval_titles->{$context}})); + push(@sorted,shift(@sorted)); + } else { + @sorted = reverse sort ({$a cmp $b} (keys(%{$interval_titles->{$context}}))); + } + foreach my $key (@sorted) { $r->print(''.&mt($interval_titles->{$context}->{$key}). ''."\n"); } @@ -833,46 +981,49 @@ sub courseinit_config { my ($control,$current) = &curr_courseinit(); my @chgstate = ('userpref','coursespecific'); my @chgentry = ('firstres','whatsnew'); + my $courseinitsty = 'display:none;'; + if ($control eq 'coursespecific') { + $courseinitsty = 'display:inline;'; + } my $lctype = lc(&Apache::loncommon::course_type()); my %lt = &Apache::lonlocal::texthash( 'chwp' => "Choose which page will be displayed when you enter this $lctype after selecting a role.", - 'cuva' => 'Current value is determined by', - 'anis' => 'and is set to display', 'padc' => 'Page display controlled by', - 'chce' => 'Choose '.$lctype.' entry', + 'chce' => "Choose $lctype entry", 'moce' => 'Save', ); - $r->print(<<"END"); + $lt{'cuva'} = &mt('Current value is determined by[_1]'.$initpage->{$control}.'[_2] and is set to display[_1]'.$initpage->{$current}.'[_2].', + ': ',''); + $r->print(<<"END"); $lt{'chwp'} -$lt{'cuva'}: -$$initpage{$control} $lt{'anis'} -$$initpage{$current}. +$lt{'cuva'} + -$lt{'padc'}: +$lt{'padc'} END foreach my $choice (@chgstate) { my $chkstring; if ($choice eq $control) { $chkstring = ' checked="checked" '; - } + } $r->print(''.$$initpage{$choice}. + $choice.'"'.$chkstring.' onclick="toggleCourseInit(this.form);" />'.&mt($initpage->{$choice}). ' '); } - $r->print(''.&mt('If').' '.$$initpage{'coursespecific'}. - ' - '.$lt{'chce'}.": \n"); + $r->print(''. + ''.$lt{'chce'}.''."\n"); foreach my $choice (@chgentry) { my $chkstring; if (($choice eq $current) && ($control eq 'coursespecific')) { $chkstring = ' checked="checked" '; } $r->print(''.$$initpage{$choice}. - ' '); + $choice.'"'.$chkstring.'/>'.&mt($initpage->{$choice}). + ' '); } - $r->print(''); return; } @@ -902,7 +1053,8 @@ sub display_launcher { $tograde,$ungraded,$bombs,$bombed,$changed,$warnings,$triggered, $newdiscussions,$unread,$msgcount,$newmsgs,$critmsgcount,$critmsgs, $interval,$countunread,$expired,$expirecount,$activated,$activecount, - $crstype,$itemserror,$loggedin,$logincount,$classlist) = @_; + $crstype,$itemserror,$loggedin,$logincount,$sessions,$sessioncount, + $classlist) = @_; if ($$checkallowed{$action}) { &start_box($r,$show,$headings,$action,$refpage); @@ -930,8 +1082,11 @@ sub display_launcher { &display_rolechanges($r,$expirecount,$expired,$interval->{'oldroles'}, $crstype,$classlist); } elsif ($action eq 'crslogin') { #LAST LOGIN - &display_crslogins($r,$logincount,$loggedin,$interval->{'crslogin'}, + &display_activity($r,'logins',$logincount,$loggedin,$interval->{'crslogin'}, $crstype,$classlist); + } elsif ($action eq 'sessions') { #ACTIVE SESSIONS + &display_activity($r,'sessions',$sessioncount,$sessions,$interval->{'sessions'}, + $crstype,$classlist); } } &end_box($r); @@ -1005,7 +1160,6 @@ sub getitems { $triggered,$threshold,$warnings, $checkallowed); } - } return; } @@ -1036,12 +1190,28 @@ sub check_discussions { 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 ($handgradeable,$is_task); my $partlist=$resource->parts(); - my $handgradeable; - foreach my $part (@$partlist) { - if ($resource->handgrade($part) eq 'yes') { - $handgradeable=1; last; + if ($resource->is_task()) { + $is_task = 1; + foreach my $part (@$partlist) { + if ($resource->handgrade($part) eq 'yes') { + $handgradeable=1; + last; + } + } + } else { + foreach my $part (@$partlist) { + my @types = $resource->responseType($part); + if (grep(/^essay$/,@types)) { + $handgradeable=1; + last; + } elsif (grep(/^custom$/,@types)) { + if ($resource->handgrade($part) eq 'yes') { + $handgradeable=1; + last; + } + } } } if ($handgradeable) { @@ -1050,6 +1220,7 @@ sub check_handgraded { if (@ungraded > 0) { $$ungraded{$symb}{count} = scalar(@ungraded); $$ungraded{$symb}{title} = $title; + $$ungraded{$symb}{is_task} = $is_task; if ($resource->encrypted()) { $$ungraded{$symb}{'enclink'} = $resource->link(); $$ungraded{$symb}{'encsymb'} = $resource->shown_symb(); @@ -1146,8 +1317,10 @@ sub check_thresholds { '.$stats{$part}{degdiff}.' '.$lastreset{$part}.''; if ($checkallowed->{'resetcounters'}) { + my $aria = ' aria-label="'.&mt('Reset counter for [_1] (part [_2])', + $$triggered{$symb}{title},$part).'"'; $$triggered{$symb}{text}[$partcount] .= - ''. + ''. ''; } $partcount ++; @@ -1213,7 +1386,7 @@ sub get_current { sub process_reset { my ($dom,$crs,$checkallowed) = @_; if (!$checkallowed->{'resetcounters'}) { - return ''.&mt('You do not the required privileges to reset counters'). + return ''.&mt('You do not have the required privileges to reset counters'). ''; } my $result = ''.&mt('Counters reset for following problems (and parts):'). @@ -1297,8 +1470,9 @@ sub getnormalmail { if ($emailstatus{$msgid} eq 'new') { $skipstatus = 1; } + my $esc_msgid = &escape($msgid); my ($sendtime,$shortsubj,$fromname,$fromdom,$status,$fromcid)= - &Apache::lonmsg::unpackmsgid($msgid,undef,$skipstatus,undef, + &Apache::lonmsg::unpackmsgid($esc_msgid,undef,$skipstatus,undef, $env{'request.course.id'}); if (($fromcid) && ($fromcid eq $env{'request.course.id'})) { if (defined($sendtime) && $sendtime!~/error/) { @@ -1309,7 +1483,7 @@ sub getnormalmail { $shortsubj = &mt('No subject'); } push(@{$newmsgs}, { - msgid => $msgid, + msgid => $esc_msgid, sendtime => $sendtime, shortsub => $shortsubj, from => $fromname, @@ -1330,8 +1504,9 @@ sub getcritmail { my $result = ''; my $critmsgcount = 0; foreach my $msgid (sort(keys(%what))) { + my $esc_msgid = &escape($msgid); my ($sendtime,$shortsubj,$fromname,$fromdom,$status,$fromcid)= - &Apache::lonmsg::unpackmsgid($msgid,undef,1,undef, + &Apache::lonmsg::unpackmsgid($esc_msgid,undef,1,undef, $env{'request.course.id'}); if (($fromcid) && ($fromcid eq $env{'request.course.id'})) { if (defined($sendtime) && $sendtime!~/error/) { @@ -1341,7 +1516,7 @@ sub getcritmail { $shortsubj = &mt('No subject'); } push(@{$critmsgs}, { - msgid => $msgid, + msgid => $esc_msgid, sendtime => $sendtime, shortsub => $shortsubj, from => $fromname, @@ -1586,6 +1761,78 @@ sub getloggedin { return $logincount; } +sub getsessions { + my ($cdom,$cnum,$sessions,$lastactive,$classlist) = @_; + my $context = 'course'; + my ($permission,$allowed) = + &Apache::lonuserutils::get_permission($context); + my %crs_sessions = &Apache::lonnet::get_course_sessions($cnum,$cdom,$lastactive); + my $sessioncount = 0; + if (keys(%crs_sessions) > 0) { + if (ref($classlist) eq 'HASH') { + my $viewablesec = &Apache::lonuserutils::viewable_section($permission); + my $secidx = &Apache::loncoursedata::CL_SECTION(); + my %coursepersonnel=&Apache::lonnet::get_course_adv_roles($cdom.'_'.$cnum,1); + my %personnel; + foreach my $role (sort(keys(%coursepersonnel))) { + my ($rolecode,$section); + if ($role =~ /:/) { + ($rolecode,$section) = split(/:/,$role); + } else { + $rolecode = $role; + } + if ($viewablesec ne '') { + next if ($viewablesec ne $section); + } + foreach my $user (split(/\,/,$coursepersonnel{$role})) { + push(@{$personnel{$user}{$rolecode}},$section); + } + } + foreach my $key (keys(%crs_sessions)) { + if (exists($classlist->{$key})) { + my $student = $classlist->{$key}; + my $section = $student->[$secidx]; + my $lastaccess = $crs_sessions{$key}; + if ($viewablesec ne '') { + next if ($viewablesec ne $section); + } + my ($stuname,$studom) = split(/:/,$key); + my %info = ( + 'section' => $section, + 'role' => 'st', + 'uname' => $stuname, + 'udom' => $studom, + ); + $sessioncount ++; + push(@{$sessions->{$lastaccess}},\%info); + } elsif (exists($personnel{$key})) { + my $lastaccess = $crs_sessions{$key}; + my ($uname,$udom) = split(/:/,$key); + if (ref($personnel{$key}) eq 'HASH') { + my ($showrole,$showsec); + foreach my $possrole ('cc','co','in','ta','ep','ad','st') { + if (exists($personnel{$key}{$possrole})) { + $showrole = $possrole; + $showsec = join(', ',@{$personnel{$key}{$possrole}}); + last; + } + } + my %info = ( + 'section' => $showsec, + 'role' => $showrole, + 'uname' => $uname, + 'udom' => $udom, + ); + $sessioncount ++; + push(@{$sessions->{$lastaccess}},\%info); + } + } + } + } + } + return $sessioncount; +} + sub checkversions { my ($cdom,$crs,$navmap,$changed,$starttime) = @_; my %changes=&Apache::lonnet::dump('versionupdate',$cdom,$crs); @@ -1641,13 +1888,24 @@ sub display_handgrade { foreach my $res (@{$tograde}) { $rowNum ++; my $css_class = $rowNum%2?' class="LC_odd_row"':''; - my $linkurl='/adm/grades'; - if ($$ungraded{$res}{'enclink'}) { - $linkurl.='?symb='.$$ungraded{$res}{'encsymb'}; + my $linkurl; + if ($$ungraded{$res}{'is_task'}) { + my ($map,$id,$url)=&Apache::lonnet::decode_symb($res); + $linkurl=&Apache::lonnet::clutter($url); + $linkurl .= '?symb='.&escape($res); + if ($$ungraded{$res}{'enclink'}) { + $linkurl = + $$ungraded{$res}{'enclink'}.'?symb='.$$ungraded{$res}{'encsymb'}; + } } else { - $linkurl.='?symb='.&escape($res); + $linkurl='/adm/grades'; + if ($$ungraded{$res}{'enclink'}) { + $linkurl.='?symb='.$$ungraded{$res}{'encsymb'}; + } else { + $linkurl.='?symb='.&escape($res); + } + $linkurl.='&command=ungraded'; } - $linkurl.='&command=ungraded'; $r->print(''.$$ungraded{$res}{title}.''.$$ungraded{$res}{count}.''); } } elsif ($itemserror) { @@ -1728,10 +1986,10 @@ sub display_abovethreshold { $r->print(''. ''. $$triggered{$res}{title}.''); - if (ref($$triggered{$res}{text}) eq 'ARRAY') { - $r->print($$triggered{$res}{text}[0]); - } - $r->print(''); + if (ref($$triggered{$res}{text}) eq 'ARRAY') { + $r->print($$triggered{$res}{text}[0]); + } + $r->print(''); if (ref($$triggered{$res}{text}) eq 'ARRAY') { if (@{$$triggered{$res}{text}} > 1) { for (my $i=1; $i<@{$$triggered{$res}{text}}; $i++) { @@ -1852,8 +2110,8 @@ sub display_rolechanges { return; } -sub display_crslogins { - my ($r,$logincount,$loggedin,$interval,$crstype,$classlist) = @_; +sub display_activity { + my ($r,$context,$count,$details,$interval,$crstype,$classlist) = @_; return unless (ref($classlist) eq 'HASH'); my %lt = &Apache::lonlocal::texthash( 'user' => 'User', @@ -1861,29 +2119,38 @@ sub display_crslogins { 'sec' => 'Section', 'number' => 'Total number of logins', ); - if ($logincount) { + my $prefix = 'login'; + if ($context eq 'sessions') { + $lt{'number'} = &mt('Total number of active user sessions'); + $lt{'active'} = &mt('Last active'); + $prefix = 'session'; + } + if ($count) { - my $hdr = ''. + my $hdr = ''. ''.$lt{'user'}.''. ''.$lt{'role'}.''. - ''.$lt{'sec'}.''. - ''. - ''.$lt{'number'}.''. - ''.$lt{'role'}.''. - ''.$lt{'sec'}; + ''.$lt{'sec'}.''; + if ($context eq 'sessions') { + $hdr .= ''.$lt{'active'}.''; + } + $hdr .= ''."\n". + ''. + ''.$lt{'number'}.''. + ''.$lt{'role'}.''. + ''.$lt{'sec'}; my (%bylastname,%counts); - if (ref($loggedin) eq 'HASH') { - my @logins = sort { $b <=> $a } (keys(%{$loggedin})); - my $numlogin = 0; + if (ref($details) eq 'HASH') { + my @items = sort { $b <=> $a } (keys(%{$details})); + my $num = 0; my $fullnameidx = &Apache::loncoursedata::CL_FULLNAME(); - foreach my $item (@logins) { - if (ref($loggedin->{$item}) eq 'ARRAY') { - foreach my $user (@{$loggedin->{$item}}) { + foreach my $item (@items) { + if (ref($details->{$item}) eq 'ARRAY') { + foreach my $user (@{$details->{$item}}) { if (ref($user) eq 'HASH') { my $section; my $role = &Apache::lonnet::plaintext($user->{'role'},$crstype); - my $status = &mt($user->{'status'}); if ($user->{'section'} eq '') { $section = &mt('none'); } else { @@ -1900,10 +2167,13 @@ sub display_crslogins { } my $link = &Apache::loncommon::aboutmewrapper($fullname,$uname,$udom); - push(@{$bylastname{$fullname}}, - ''.$link.''. - ''.$role.''. - ''.$section.''); + my $entry = ''.$link.''. + ''.$role.''. + ''.$section.''; + if ($context eq 'sessions') { + $entry .= ''.&Apache::lonlocal::locallocaltime($item).''; + } + push(@{$bylastname{$fullname}},$entry); } } } @@ -1912,9 +2182,9 @@ sub display_crslogins { foreach my $person (sort(keys(%bylastname))) { if (ref($bylastname{$person}) eq 'ARRAY') { foreach my $item (@{$bylastname{$person}}) { - $numlogin ++; - my $css_class = $numlogin%2?' class="LC_odd_row"':''; - $table .= ''.$item.''; + $num ++; + my $css_class = $num%2?' class="LC_odd_row"':''; + $table .= ''.$item.''; } } } @@ -1925,26 +2195,26 @@ sub display_crslogins { foreach my $sec (sort { $b <=> $a } (keys(%{$counts{$role}}))) { $numrow ++; my $css_class = $numrow%2?' class="LC_odd_row"':''; - $table .= ''. + $table .= ''. ''.$counts{$role}{$sec}.''. ''.$showrole.''. ''.$sec.''; } } } - $r->print($hdr.''.$table); } } else { $r->print(''. &mt('There are no '.$interval). - ''); } return; } - + sub display_coursediscussion { my ($r,$newdiscussions,$unread,$countunread,$res_title,$itemserror) = @_; my $lctype = lc(&Apache::loncommon::course_type()); @@ -2107,6 +2377,8 @@ sub store_interval_setting { $interval_settings{$cid.':newroleinterval'} = $env{'form.interval'}; } elsif ($context eq 'crslogin') { $interval_settings{$cid.':crslogininterval'} = $env{'form.interval'}; + } elsif ($context eq 'sessions') { + $interval_settings{$cid.':sessionactivity'} = $env{'form.interval'}; } else { $interval_settings{$cid.':interval'} = $env{'form.interval'}; } @@ -2179,7 +2451,7 @@ sub store_courseinit_setting { $result = &Apache::lonhtmlcommon::confirm_success(&mt("Page displayed after role selection in $lctype now set by [_1]user's global preferences[_2].",'','')); } else { $result = &Apache::lonhtmlcommon::confirm_success(&mt('Page displayed after role selection in this '.$lctype.' set to [_1].' - ,''.$$initpage{$env{'form.courseinit_page'}}.'')); + ,''.&mt($initpage->{$env{'form.courseinit_page'}}).'')); } } else { &Apache::lonnet::logthis('Error saving whatsnew courseinit '. @@ -2192,7 +2464,7 @@ sub store_courseinit_setting { ''.$outcome.''),1); } else { $result = &Apache::lonhtmlcommon::confirm_success(&mt('Unable to set page display, after role selection, for this '.$lctype.' to [_1] due to [_2].' - ,''.$$initpage{$env{'form.courseinit_page'}}.'' + ,''.&mt($initpage->{$env{'form.courseinit_page'}}).'' ,''.$outcome.''),1); } } @@ -2265,11 +2537,17 @@ sub start_box { if ($$show{$caller}) { $r->print(' - '.&mt('Summary').' '.&mt('Details').''.$lt{'chin'}.' + '.&mt('Summary').' '.&mt('Details').''.$lt{'chin'}.' + '); + } + } elsif (($caller eq 'sessions') && ($$show{$caller})) { + if ($$show{$caller}) { + $r->print(' + + '.&mt('Summary').' '.&mt('Details').''.$lt{'chin'}.' '); } } - $r->print('