--- loncom/auth/lonroles.pm 2006/05/15 17:45:46 1.148 +++ loncom/auth/lonroles.pm 2009/04/14 23:52:07 1.219 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # User Roles Screen # -# $Id: lonroles.pm,v 1.148 2006/05/15 17:45:46 albertel Exp $ +# $Id: lonroles.pm,v 1.219 2009/04/14 23:52:07 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -27,6 +27,103 @@ # ### +=pod + +=head1 NAME + +Apache::lonroles - User Roles Screen + +=head1 SYNOPSIS + +Invoked by /etc/httpd/conf/srm.conf: + + + PerlAccessHandler Apache::lonacc + SetHandler perl-script + PerlHandler Apache::lonroles + ErrorDocument 403 /adm/login + ErrorDocument 500 /adm/errorhandler + + +=head1 OVERVIEW + +=head2 Choosing Roles + +C is a handler that allows a user to switch roles in +mid-session. LON-CAPA attempts to work with "No Role Specified", the +default role that a user has before selecting a role, as widely as +possible, but certain handlers for example need specification which +course they should act on, etc. Both in this scenario, and when the +handler determines via C's C<&allowed> function that a certain +action is not allowed, C is used as error handler. This +allows the user to select another role which may have permission to do +what they were trying to do. C can also be accessed via the +B button in the Remote Control. + +=begin latex + +\begin{figure} +\begin{center} +\includegraphics[width=0.45\paperwidth,keepaspectratio]{Sample_Roles_Screen} + \caption{\label{Sample_Roles_Screen}Sample Roles Screen} +\end{center} +\end{figure} + +=end latex + +=head2 Role Initialization + +The privileges for a user are established at login time and stored in the session environment. As a consequence, a new role does not become active till the next login. Handlers are able to query for privileges using C's C<&allowed> function. When a user first logs in, their role is the "common" role, which means that they have the sum of all of their privileges. During a session it might become necessary to choose a particular role, which as a consequence also limits the user to only the privileges in that particular role. + +=head1 INTRODUCTION + +This module enables a user to select what role he wishes to +operate under (instructor, student, teaching assistant, course +coordinator, etc). These roles are pre-established by the actions +of upper-level users. + +This is part of the LearningOnline Network with CAPA project +described at http://www.lon-capa.org. + +=head1 HANDLER SUBROUTINE + +This routine is called by Apache and mod_perl. + +=over 4 + +=item * + +Roles Initialization (yes/no) + +=item * + +Get Error Message from Environment + +=item * + +Who is this? + +=item * + +Generate Page Output + +=item * + +Choice or no choice + +=item * + +Table + +=item * + +Privileges + +=back + +=cut + + package Apache::lonroles; use strict; @@ -39,7 +136,12 @@ use Apache::loncommon; use Apache::lonhtmlcommon; use Apache::lonannounce; use Apache::lonlocal; +use Apache::lonpageflip(); +use Apache::lonnavdisplay(); use GDBM_File; +use LONCAPA qw(:DEFAULT :match); +use HTML::Entities; + sub redirect_user { my ($r,$title,$url,$msg,$launch_nav) = @_; @@ -50,8 +152,8 @@ sub redirect_user { my $swinfo=&Apache::lonmenu::rawconfig(); my $navwindow; if ($launch_nav eq 'on') { - $navwindow.=&Apache::lonnavmaps::launch_win('now',undef,undef, - ($url =~ m-^/adm/whatsnew-)); + $navwindow.=&Apache::lonnavdisplay::launch_win('now',undef,undef, + ($url =~ m-^/adm/whatsnew-)); } else { $navwindow.=&Apache::lonnavmaps::close(); } @@ -74,6 +176,21 @@ ENDREDIR return; } +sub error_page { + my ($r,$error,$dest)=@_; + &Apache::loncommon::content_type($r,'text/html'); + &Apache::loncommon::no_cache($r); + $r->send_http_header; + return OK if $r->header_only; + $r->print(&Apache::loncommon::start_page('Problems during Course Initialization'). + ''. + '

'.&mt('The following problems occurred:'). + $error. + '


'.&mt('Continue').''. + &Apache::loncommon::end_page()); +} + sub handler { my $r = shift; @@ -87,29 +204,92 @@ sub handler { # ================================================================== Roles Init if ($env{'form.selectrole'}) { + + my $locknum=&Apache::lonnet::get_locks(); + if ($locknum) { return 409; } + if ($env{'form.newrole'}) { $env{'form.'.$env{'form.newrole'}}=1; } if ($env{'request.course.id'}) { + # Check if user is CC trying to select a course role + if ($env{'form.switchrole'}) { + if (!defined($env{'user.role.'.$env{'form.switchrole'}})) { + &adhoc_course_role($then); + } + } my %temp=('logout_'.$env{'request.course.id'} => time); &Apache::lonnet::put('email_status',\%temp); &Apache::lonnet::delenv('user.state.'.$env{'request.course.id'}); } - &Apache::lonnet::appenv("request.course.id" => '', - "request.course.fn" => '', - "request.course.uri" => '', - "request.course.sec" => '', - "request.role" => 'cm', - "request.role.adv" => $env{'user.adv'}, - "request.role.domain" => $env{'user.domain'}); - -# Check if user is a DC trying to enter a course and needs privs to be created + &Apache::lonnet::appenv({"request.course.id" => '', + "request.course.fn" => '', + "request.course.uri" => '', + "request.course.sec" => '', + "request.role" => 'cm', + "request.role.adv" => $env{'user.adv'}, + "request.role.domain" => $env{'user.domain'}}); +# Check if user is a DC trying to enter a course or author space and needs privs to be created if ($numdc > 0) { foreach my $envkey (keys %env) { +# Is this an ad-hoc CC-role? if (my ($domain,$coursenum) = - ($envkey =~ m-^form\.cc\./(\w+)/(\w+)$-)) { + ($envkey =~ m-^form\.cc\./($match_domain)/($match_courseid)$-)) { + if ($dcroles{$domain}) { + &Apache::lonnet::check_adhoc_privs($domain,$coursenum, + $then,$now,'cc'); + } + last; + } +# Is this an ad-hoc CA-role? + if (my ($domain,$user) = + ($envkey =~ m-^form\.ca\./($match_domain)/($match_username)$-)) { + if (($domain eq $env{'user.domain'}) && ($user eq $env{'user.name'})) { + delete($env{$envkey}); + $env{'form.au./'.$domain.'/'} = 1; + my ($server_status,$home) = &check_author_homeserver($user,$domain); + if ($server_status eq 'switchserver') { + my $trolecode = 'au./'.$domain.'/'; + my $switchserver = '/adm/switchserver?otherserver='.$home.'&role='.$trolecode; + $r->internal_redirect($switchserver); + } + last; + } + if (my ($castart,$caend) = ($env{'user.role.ca./'.$domain.'/'.$user} =~ /^(\d*)\.(\d*)$/)) { + if (((($castart) && ($castart < $now)) || !$castart) && + ((!$caend) || (($caend) && ($caend > $now)))) { + my ($server_status,$home) = &check_author_homeserver($user,$domain); + if ($server_status eq 'switchserver') { + my $trolecode = 'ca./'.$domain.'/'.$user; + my $switchserver = '/adm/switchserver?otherserver='.$home.'&role='.$trolecode; + $r->internal_redirect($switchserver); + } + last; + } + } + # Check if author blocked ca-access + my %blocked=&Apache::lonnet::get('environment',['domcoord.author'],$domain,$user); + if ($blocked{'domcoord.author'} eq 'blocked') { + delete($env{$envkey}); + $env{'user.error.msg'}=':::1:User '.$user.' in domain '.$domain.' blocked domain coordinator access'; + last; + } if ($dcroles{$domain}) { - &check_privs($domain,$coursenum,$then,$now); + my ($server_status,$home) = &check_author_homeserver($user,$domain); + if (($server_status eq 'ok') || ($server_status eq 'switchserver')) { + &Apache::lonnet::check_adhoc_privs($domain,$user,$then, + $now,'ca'); + if ($server_status eq 'switchserver') { + my $trolecode = 'ca./'.$domain.'/'.$user; + my $switchserver = '/adm/switchserver?' + .'otherserver='.$home.'&role='.$trolecode; + $r->internal_redirect($switchserver); + } + } else { + delete($env{$envkey}); + } + } else { + delete($env{$envkey}); } last; } @@ -119,7 +299,8 @@ sub handler { foreach $envkey (keys %env) { next if ($envkey!~/^user\.role\./); my ($where,$trolecode,$role,$tstatus,$tend,$tstart); - &role_status($envkey,$then,$now,\$role,\$where,\$trolecode,\$tstatus,\$tstart,\$tend); + &Apache::lonnet::role_status($envkey,$then,$now,\$role,\$where, + \$trolecode,\$tstatus,\$tstart,\$tend); if ($env{'form.'.$trolecode}) { if ($tstatus eq 'is') { $where=~s/^\///; @@ -131,8 +312,10 @@ sub handler { # store role if recent_role list being kept if ($env{'environment.recentroles'}) { + my %frozen_roles = + &Apache::lonhtmlcommon::get_recent_frozen('roles',$env{'environment.recentrolesn'}); &Apache::lonhtmlcommon::store_recent('roles', - $trolecode,' '); + $trolecode,' ',$frozen_roles{$trolecode}); } @@ -144,7 +327,7 @@ sub handler { my $authnum=$cnum; if ($env{'course.'.$cdom.'_'.$cnum.'.keyauth'}) { ($authnum,$authdom)= - split(/\W/,$env{'course.'.$cdom.'_'.$cnum.'.keyauth'}); + split(/:/,$env{'course.'.$cdom.'_'.$cnum.'.keyauth'}); } # check with key authority unless (&Apache::lonnet::validate_access_key( @@ -169,8 +352,11 @@ sub handler { $cdom,$cnum, $env{'user.domain'}, $env{'user.name'}, - 'Assigned from '.$ENV{'REMOTE_ADDR'}.' at '.localtime().' for '. - $trolecode); + &mt('Assigned from [_1] at [_2] for [_3]' + ,$ENV{'REMOTE_ADDR'} + ,&Apache::lonlocal::locallocaltime() + ,$trolecode) + ); unless ($assignresult eq 'ok') { $assignresult=~s/^error\:\s*//; $message=&mt($assignresult). @@ -180,13 +366,13 @@ sub handler { } $r->print(< +
-$message
+$message
$end_page @@ -203,7 +389,7 @@ ENDENTEREDKEY my $end_page=&Apache::loncommon::end_page(); $r->print(< +
@@ -224,67 +410,105 @@ ENDENTERKEY "Role ".$trolecode); &Apache::lonnet::appenv( - 'request.role' => $trolecode, - 'request.role.domain' => $cdom, - 'request.course.sec' => $csec, - 'request.course.groups' => $cgrps); + {'request.role' => $trolecode, + 'request.role.domain' => $cdom, + 'request.course.sec' => $csec, + 'request.course.groups' => $cgrps}); my $tadv=0; - my $msg=&mt('Entering course ...'); if (($cnum) && ($role ne 'ca') && ($role ne 'aa')) { + my $msg; my ($furl,$ferr)= &Apache::lonuserstate::readmap($cdom.'/'.$cnum); if (($env{'form.orgurl'}) && ($env{'form.orgurl'}!~/^\/adm\/flip/)) { my $dest=$env{'form.orgurl'}; + if ($env{'form.symb'}) { + if ($dest =~ /\?/) { + $dest .= '&'; + } else { + $dest .= '?' + } + $dest .= 'symb='.$env{'form.symb'}; + } if (&Apache::lonnet::allowed('adv') eq 'F') { $tadv=1; } - &Apache::lonnet::appenv('request.role.adv'=>$tadv); - $r->internal_redirect($dest); + &Apache::lonnet::appenv({'request.role.adv'=>$tadv}); + if (($ferr) && ($tadv)) { + &error_page($r,$ferr,$dest); + } else { + $r->internal_redirect($dest); + } return OK; } else { - unless ($env{'request.course.id'}) { + if (!$env{'request.course.id'}) { &Apache::lonnet::appenv( - "request.course.id" => $cdom.'_'.$cnum); + {"request.course.id" => $cdom.'_'.$cnum}); $furl='/adm/roles?tryagain=1'; $msg= - '

'. - &mt('Could not initialize course at this time.'). - '

'.&mt('Please try again.').'

'.$ferr; + '

'. + &mt('Could not initialize [_1] at this time.', + $env{'course.'.$cdom.'_'.$cnum.'.description'}). + '

'.&mt('Please try again.').'

'.$ferr; } if (&Apache::lonnet::allowed('adv') eq 'F') { $tadv=1; } - &Apache::lonnet::appenv('request.role.adv'=>$tadv); + &Apache::lonnet::appenv({'request.role.adv'=>$tadv}); - # Check to see if the user is a CC entering a course - # for the first time - my (undef, undef, $role, $courseid) = split(/\./, $envkey); - if (substr($courseid, 0, 1) eq '/') { - $courseid = substr($courseid, 1); - } - $courseid =~ s/\//_/; - if ($role eq 'cc' && $env{'course.' . $courseid . - '.course.helper.not.run'}) { - $furl = "/adm/helper/course.initialization.helper"; - # Send the user to the course they selected - } elsif ($env{'request.course.id'}) { - if (&Apache::lonnet::allowed('whn', - $env{'request.course.id'}) - || &Apache::lonnet::allowed('whn', - $env{'request.course.id'}.'/' - .$env{'request.course.sec'}) - ) { - my $startpage = &courseloadpage($courseid); - unless ($startpage eq 'firstres') { - $msg = &mt('Entering course ....'); - &redirect_user($r,&mt('New in course'), - '/adm/whatsnew?refpage=start',$msg, - $env{'environment.remotenavmap'}); - return OK; + if (($ferr) && ($tadv)) { + &error_page($r,$ferr,$furl); + } else { + # Check to see if the user is a CC entering a course + # for the first time + my (undef, undef, $role, $courseid) = split(/\./, $envkey); + if (substr($courseid, 0, 1) eq '/') { + $courseid = substr($courseid, 1); + } + $courseid =~ s/\//_/; + if ($role eq 'cc' && $env{'course.' . $courseid . + '.course.helper.not.run'}) { + $furl = "/adm/helper/course.initialization.helper"; + # Send the user to the course they selected + } elsif ($env{'request.course.id'}) { + if ($env{'form.destinationurl'}) { + my $dest = $env{'form.destinationurl'}; + if ($env{'form.destsymb'} ne '') { + my $esc_symb = &HTML::Entities::encode($env{'form.destsymb'},'"<>&'); + $dest .= '?symb='.$esc_symb; + } + &redirect_user($r,&mt('Entering [_1]', + $env{'course.'.$courseid.'.description'}), + $dest,$msg, + $env{'environment.remotenavmap'}); + return OK; } - } + if (&Apache::lonnet::allowed('whn', + $env{'request.course.id'}) + || &Apache::lonnet::allowed('whn', + $env{'request.course.id'}.'/' + .$env{'request.course.sec'}) + ) { + my $startpage = &courseloadpage($courseid); + unless ($startpage eq 'firstres') { + $msg = &mt('Entering [_1] ...', + $env{'course.'.$courseid.'.description'}); + &redirect_user($r,&mt('New in course'), + '/adm/whatsnew?refpage=start',$msg, + $env{'environment.remotenavmap'}); + return OK; + } + } + } +# Are we allowed to look at the first resource? + if ($furl !~ m|^/adm/|) { +# Guess not ... + $furl=&Apache::lonpageflip::first_accessible_resource(); + } + $msg = &mt('Entering [_1] ...', + $env{'course.'.$courseid.'.description'}); + &redirect_user($r,&mt('Entering [_1]', + $env{'course.'.$courseid.'.description'}), + $furl,$msg, + $env{'environment.remotenavmap'}); } - &redirect_user($r,&mt('Entering Course'), - $furl,$msg, - $env{'environment.remotenavmap'}); return OK; } } @@ -322,15 +546,20 @@ ENDENTERKEY $r->send_http_header; return OK if $r->header_only; + my $brcrum =[{href=>"/admm/roles",text=>"User Roles"}]; my $swinfo=&Apache::lonmenu::rawconfig(); - my $start_page=&Apache::loncommon::start_page('User Roles'); + my $start_page=&Apache::loncommon::start_page('My Roles',undef,{bread_crumbs=>$brcrum}); my $standby=&mt('Role selected. Please stand by.'); $standby=~s/\n/\\n/g; - my $helptag='
'.&Apache::loncommon::help_open_menu('','General Intro','General_Intro','User Roles',1,undef,undef,undef,undef,,&mt("Click here for help")).'
'; + my $noscript=''.&mt('Use of LON-CAPA requires Javascript to be enabled in your web browser.').'
'.&mt('As this is not the case, most functionality in the system will be unavailable.').'

'; + $r->print(< -'); - $r->print(&Apache::loncommon::end_page()); + &findcourse_advice($r); + $r->print(''); + if ($countfuture) { + $r->print(&mt('The following [quant,_1,role,roles] will become active in the future:',$countfuture)); + my $doheaders = &roletable_headers($r,\%roleclass,\%sortrole, + $nochoose); + &print_rolerows($r,$doheaders,\%roleclass,\%sortrole,\%dcroles, + \%roletext); + my $tremark=''; + my $tbg; + if ($env{'request.role'} eq 'cm') { + $tbg="LC_roles_selected"; + $tremark=&mt('Currently selected.').' '; + } else { + $tbg="LC_roles_is"; + } + $r->print(&Apache::loncommon::start_data_table_row() + .' ' + .'' + .&mt('No role specified') + .'' + .''.$tremark.' ' + .&Apache::loncommon::end_data_table_row() + ); + + $r->print(&Apache::loncommon::end_data_table()); + } + $r->print(&Apache::loncommon::end_page()); return OK; } -# More than one possible role # ----------------------------------------------------------------------- Table - unless (($advanced) || ($nochoose)) { + unless ((!&Apache::lonmenu::show_course()) || ($nochoose) || ($countactive==1)) { $r->print("

".&mt('Select a Course to Enter')."

\n"); } - $r->print('
'); - unless ($nochoose) { $r->print(''); } - $r->print(''."\n"); - my $doheaders=-1; - foreach my $type ('Domain','Construction Space','Course','System') { - my $haverole=0; - foreach my $which (sort {uc($a) cmp uc($b)} (keys(%sortrole))) { - if ($roleclass{$sortrole{$which}} =~ /^\Q$type\E/) { - $haverole=1; - } - } - if ($haverole) { $doheaders++; } - } - + my $doheaders = &roletable_headers($r,\%roleclass,\%sortrole,$nochoose); if ($env{'environment.recentroles'}) { my %recent_roles = &Apache::lonhtmlcommon::get_recent('roles',$env{'environment.recentrolesn'}); @@ -631,8 +876,9 @@ ENDHEADER foreach (sort(keys(%recent_roles))) { if (defined($roletext{'user.role.'.$_})) { $output.=$roletext{'user.role.'.$_}; - if ($_ =~ m-dc\./(\w+)/- && $dcroles{$1}) { - $output .= &allcourses_row($1,'recent'); + if ($_ =~ m-dc\./($match_domain)/- + && $dcroles{$1}) { + $output .= &adhoc_roles_row($1,'recent'); } } elsif ($numdc > 0) { unless ($_ =~/^error\:/) { @@ -641,155 +887,315 @@ ENDHEADER } } if ($output) { - $r->print(""); + $r->print(&Apache::loncommon::start_data_table_empty_row() + .'' + .&Apache::loncommon::end_data_table_empty_row() + ); $r->print($output); - $r->print(""); $doheaders ++; } } if ($numdc > 0) { $r->print(&coursepick_jscript()); - $r->print(&Apache::loncommon::coursebrowser_javascript()); + $r->print(&Apache::loncommon::coursebrowser_javascript(). + &Apache::loncommon::authorbrowser_javascript()); } - foreach my $type ('Construction Space','Domain','Course','System') { - my $output; - foreach my $which (sort {uc($a) cmp uc($b)} (keys(%sortrole))) { - if ($roleclass{$sortrole{$which}} =~ /^\Q$type\E/) { - $output.=$roletext{$sortrole{$which}}; - if ($sortrole{$which} =~ m-dc\./(\w+)/-) { - if ($dcroles{$1}) { - $output .= &allcourses_row($1,''); - } - } - } - } - if ($output) { - if ($doheaders > 0) { - $r->print("". - ""); + &print_rolerows($r,$doheaders,\%roleclass,\%sortrole,\%dcroles,\%roletext); + if ($countactive > 1) { + my $tremark=''; + my $tbg; + if ($env{'request.role'} eq 'cm') { + $tbg="LC_roles_selected"; + $tremark=&mt('Currently selected.').' '; + } else { + $tbg="LC_roles_is"; + } + $r->print(&Apache::loncommon::start_data_table_row()); + unless ($nochoose) { + if ($env{'request.role'} ne 'cm') { + $r->print(''); + } else { + $r->print(''); } - $r->print($output); - } - } - my $tremark=''; - my $tfont='#003300'; - if ($env{'request.role'} eq 'cm') { - $r->print(''); - $tremark=&mt('Currently selected. '); - $tfont='#002200'; - } else { - $r->print(''); - } - unless ($nochoose) { - if ($env{'request.role'} ne 'cm') { - $r->print(''); - } else { - $r->print(''); - } - } - $r->print(''."\n"); - - $r->print('
 '.&mt('User Role').''.&mt('Extent'). - ''.&mt('Start').''.&mt('End').'
". - &mt('Recent Roles')."' + .&mt('Recent Roles') + .'
".&mt($type)."
 
 '.&mt('No role specified'). - ''.$tremark. - ' 
'); + } + $r->print('' + .&mt('No role specified') + .'' + .''.$tremark.' ' + .&Apache::loncommon::end_data_table_row() + ); + } + $r->print(&Apache::loncommon::end_data_table()); unless ($nochoose) { $r->print("\n"); } # ------------------------------------------------------------ Privileges Info if (($advanced) && (($env{'user.error.msg'}) || ($error))) { - $r->print('

Current Privileges

'); - - foreach $envkey (sort keys %env) { - if ($envkey=~/^user\.priv\.$env{'request.role'}\./) { - my $where=$envkey; - $where=~s/^user\.priv\.$env{'request.role'}\.//; - my $ttype; - my $twhere; - my ($tdom,$trest,$tsec)= - split(/\//,Apache::lonnet::declutter($where)); - if ($trest) { - if ($env{'course.'.$tdom.'_'.$trest.'.description'} eq 'ca') { - $ttype='Construction Space'; - $twhere='User: '.$trest.', Domain: '.$tdom; - } else { - $ttype='Course'; - $twhere=$env{'course.'.$tdom.'_'.$trest.'.description'}; - if ($tsec) { - $twhere.=' (Section/Group: '.$tsec.')'; - } - } - } elsif ($tdom) { - $ttype='Domain'; - $twhere=$tdom; - } else { - $ttype='System'; - $twhere='/'; - } - $r->print("\n

".$ttype.': '.$twhere.'

    '); - foreach (sort split(/:/,$env{$envkey})) { - if ($_) { - my ($prv,$restr)=split(/\&/,$_); - my $trestr=''; - if ($restr ne 'F') { - my $i; - $trestr.=' ('; - for ($i=0;$iprint('
  • '. - Apache::lonnet::plaintext($prv).$trestr. - '
  • '); - } - } - $r->print('
'); - } - } + $r->print('

'.&mt('Current Privileges').'

'); + $r->print(&privileges_info()); } $r->print(&Apache::lonnet::getannounce()); if ($advanced) { - $r->print('

This is LON-CAPA '. - $r->dir_config('lonVersion').'
'. - ''.&mt('Logout').'

'); + my $esc_dom = &HTML::Entities::encode($env{'user.domain'},'"<>&'); + $r->print('

' + .&mt('This is LON-CAPA [_1]',$r->dir_config('lonVersion')) + .'
' + .''.&mt('Logout').'  ' + .'' + .&mt('Course Catalog') + .'

'); } $r->print(&Apache::loncommon::end_page()); return OK; } -sub role_status { - my ($rolekey,$then,$now,$role,$where,$trolecode,$tstatus,$tstart,$tend) = @_; - my @pwhere = (); - if (exists($env{$rolekey}) && $env{$rolekey} ne '') { - (undef,undef,$$role,@pwhere)=split(/\./,$rolekey); - unless (!defined($$role) || $$role eq '') { - $$where=join('.',@pwhere); - $$trolecode=$$role.'.'.$$where; - ($$tstart,$$tend)=split(/\./,$env{$rolekey}); - $$tstatus='is'; - if ($$tstart && $$tstart>$then) { - $$tstatus='future'; - if ($$tstart<$now) { $$tstatus='will'; } +sub role_timezone { + my ($where,$timezones) = @_; + my $timezone; + if (ref($timezones) eq 'HASH') { + if ($where =~ m{^/($match_domain)/($match_courseid)}) { + my $cdom = $1; + my $cnum = $2; + if ($cdom && $cnum) { + if (!exists($timezones->{$cdom.'_'.$cnum})) { + my %timehash = + &Apache::lonnet::get('environment',['timezone'],$cdom,$cnum); + if ($timehash{'timezone'} eq '') { + if (!exists($timezones->{$cdom})) { + my %domdefaults = + &Apache::lonnet::get_domain_defaults($cdom); + if ($domdefaults{'timezone_def'} eq '') { + $timezones->{$cdom} = 'local'; + } else { + $timezones->{$cdom} = $domdefaults{'timezone_def'}; + } + } + $timezones->{$cdom.'_'.$cnum} = $timezones->{$cdom}; + } else { + $timezones->{$cdom.'_'.$cnum} = + &Apache::lonlocal::gettimezone($timehash{'timezone'}); + } + } + $timezone = $timezones->{$cdom.'_'.$cnum}; + } + } else { + my ($tdom) = ($where =~ m{^/($match_domain)}); + if ($tdom) { + if (!exists($timezones->{$tdom})) { + my %domdefaults = &Apache::lonnet::get_domain_defaults($tdom); + if ($domdefaults{'timezone_def'} eq '') { + $timezones->{$tdom} = 'local'; + } else { + $timezones->{$tdom} = $domdefaults{'timezone_def'}; + } + } + $timezone = $timezones->{$tdom}; + } + } + if ($timezone eq 'local') { + $timezone = undef; + } + } + return $timezone; +} + +sub roletable_headers { + my ($r,$roleclass,$sortrole,$nochoose) = @_; + my $doheaders; + if ((ref($sortrole) eq 'HASH') && (ref($roleclass) eq 'HASH')) { + $r->print('
' + .&Apache::loncommon::start_data_table() + .&Apache::loncommon::start_data_table_header_row() + ); + if (!$nochoose) { $r->print(' '); } + $r->print(''.&mt('User Role').'' + .''.&mt('Extent').'' + .''.&mt('Start').'' + .''.&mt('End').'' + .&Apache::loncommon::end_data_table_header_row() + ); + $doheaders=-1; + my @roletypes = &roletypes(); + foreach my $type (@roletypes) { + my $haverole=0; + foreach my $which (sort {uc($a) cmp uc($b)} (keys(%{$sortrole}))) { + if ($roleclass->{$sortrole->{$which}} =~ /^\Q$type\E/) { + $haverole=1; + } + } + if ($haverole) { $doheaders++; } + } + } + return $doheaders; +} + +sub roletypes { + my @types = ('Domain','Construction Space','Course','Unavailable','System'); + return @types; +} + +sub print_rolerows { + my ($r,$doheaders,$roleclass,$sortrole,$dcroles,$roletext) = @_; + if ((ref($roleclass) eq 'HASH') && (ref($sortrole) eq 'HASH')) { + my @types = &roletypes(); + foreach my $type (@types) { + my $output; + foreach my $which (sort {uc($a) cmp uc($b)} (keys(%{$sortrole}))) { + if ($roleclass->{$sortrole->{$which}} =~ /^\Q$type\E/) { + if (ref($roletext) eq 'HASH') { + $output.=$roletext->{$sortrole->{$which}}; + if ($sortrole->{$which} =~ m-dc\./($match_domain)/-) { + if (ref($dcroles) eq 'HASH') { + if ($dcroles->{$1}) { + $output .= &adhoc_roles_row($1,''); + } + } + } + } + } } - if ($$tend) { - if ($$tend<$then) { - $$tstatus='expired'; - } elsif ($$tend<$now) { - $$tstatus='will_not'; + if ($output) { + if ($doheaders > 0) { + $r->print(&Apache::loncommon::start_data_table_empty_row() + .'' + .&mt($type) + .'' + .&Apache::loncommon::end_data_table_empty_row() + ); + } + $r->print($output); + } + } + } +} + +sub findcourse_advice { + my ($r) = @_; + my $domdesc = &Apache::lonnet::domain($env{'user.domain'},'description'); + my $esc_dom = &HTML::Entities::encode($env{'user.domain'},'"<>&'); + if (&Apache::lonnet::auto_run(undef,$env{'user.domain'})) { + $r->print(&mt('If you were expecting to see an active role listed for a particular course in the [_1] domain, it may be missing for one of the following reasons:',$domdesc).' +
    +
  • '.&mt('The course has yet to be created.').'
  • +
  • '.&mt('Automatic enrollment of registered students has not been enabled for the course.').'
  • +
  • '.&mt('You are in a section of course for which automatic enrollment in the corresponding LON-CAPA course is not active.').'
  • +
  • '.&mt('The start date for automated enrollment has yet to be reached.').'
  • +
  • '.&mt('You registered for the course recently and there is a time lag between the time you register, and the time this information becomes available for the update of LON-CAPA course rosters.').'
  • +
'); + } else { + $r->print(&mt('If you were expecting to see an active role listed for a particular course, that course may not have been created yet.').'
'); + } + $r->print('

'.&mt('The [_1]Course Catalog[_2] provides information about all [_3] classes for which LON-CAPA courses have been created.','','',$domdesc).'
'); + $r->print(&mt('You can search the course catalog for courses which permit self-enrollment, if you would like to enroll in a course.').'

'); + &queued_selfenrollment($r); + return; +} + +sub queued_selfenrollment { + my ($r) = @_; + my %selfenrollrequests = &Apache::lonnet::dump('selfenrollrequests'); + my %reqs_by_date; + foreach my $item (keys(%selfenrollrequests)) { + if (ref($selfenrollrequests{$item}) eq 'HASH') { + if ($selfenrollrequests{$item}{'status'} eq 'request') { + if ($selfenrollrequests{$item}{'timestamp'}) { + push(@{$reqs_by_date{$selfenrollrequests{$item}{'timestamp'}}},$item); + } + } + } + } + if (keys(%reqs_by_date)) { + my $rolename = &Apache::lonnet::plaintext('st'); + $r->print(''.&mt('Enrollment requests pending Course Coordinator approval').'
'. + &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_header_row(). + ''.&mt('Date requested').''.&mt('Course title').''. + ''.&mt('User role').''.&mt('Section').''. + &Apache::loncommon::end_data_table_header_row()); + my @sorted = sort { $a <=> $b } (keys(%reqs_by_date)); + foreach my $item (@sorted) { + if (ref($reqs_by_date{$item}) eq 'ARRAY') { + foreach my $crs (@{$reqs_by_date{$item}}) { + my %courseinfo = &Apache::lonnet::coursedescription($crs); + my $usec = $selfenrollrequests{$crs}{'section'}; + if ($usec eq '') { + $usec = &mt('No section'); + } + $r->print(&Apache::loncommon::start_data_table_row(). + ''.&Apache::lonlocal::locallocaltime($item).''. + ''.$courseinfo{'description'}.''. + ''.$rolename.''.$usec.''. + &Apache::loncommon::end_data_table_row()); } } } + $r->print(&Apache::loncommon::end_data_table()); } + return; +} + +sub privileges_info { + my ($which) = @_; + my $output; + + $which ||= $env{'request.role'}; + + foreach my $envkey (sort(keys(%env))) { + next if ($envkey!~/^user\.priv\.\Q$which\E\.(.*)/); + + my $where=$1; + my $ttype; + my $twhere; + my (undef,$tdom,$trest,$tsec)=split(m{/},$where); + if ($trest) { + if ($env{'course.'.$tdom.'_'.$trest.'.description'} eq 'ca') { + $ttype='Construction Space'; + $twhere='User: '.$trest.', Domain: '.$tdom; + } else { + $ttype= &Apache::loncommon::course_type($tdom.'_'.$trest); + $twhere=$env{'course.'.$tdom.'_'.$trest.'.description'}; + if ($tsec) { + my $sec_type = 'Section'; + if (exists($env{"user.role.gr.$where"})) { + $sec_type = 'Group'; + } + $twhere.=' ('.$sec_type.': '.$tsec.')'; + } + } + } elsif ($tdom) { + $ttype='Domain'; + $twhere=$tdom; + } else { + $ttype='System'; + $twhere='/'; + } + $output .= "\n

".&mt($ttype).': '.$twhere.'

'."\n
    "; + foreach my $priv (sort(split(/:/,$env{$envkey}))) { + next if (!$priv); + + my ($prv,$restr)=split(/\&/,$priv); + my $trestr=''; + if ($restr ne 'F') { + $trestr.=' ('. + join(', ', + map { &Apache::lonnet::plaintext($_) } + (split('',$restr))).') '; + } + $output .= "\n\t". + '
  • '.&Apache::lonnet::plaintext($prv).$trestr.'
  • '; + } + $output .= "\n".'
'; + } + return $output; } sub build_roletext { - my ($trolecode,$tdom,$trest,$tstatus,$tryagain,$advanced,$tremark,$tbg,$tfont,$trole,$ttype,$twhere,$tpstart,$tpend,$nochoose,$button,$switchserver) = @_; - my $roletext=''; + my ($trolecode,$tdom,$trest,$tstatus,$tryagain,$advanced,$tremark,$tbg,$trole,$twhere,$tpstart,$tpend,$nochoose,$button,$switchserver,$reinit) = @_; + my $roletext=&Apache::loncommon::start_data_table_row(); my $is_dc=($trolecode =~ m/^dc\./); my $rowspan=($is_dc) ? '' : ' rowspan="2" '; @@ -799,55 +1205,95 @@ sub build_roletext { $buttonname=~s/\W//g; if (!$button) { if ($switchserver) { - $roletext.=''.&mt('Switch Server').''; + $roletext.='' + .'' + .&mt('Switch Server') + .''; } else { - $roletext.=(' '); + $roletext.=(' '); } } elsif ($tstatus eq 'is') { - $roletext.=''. + ''; + $trolecode."','".$buttonname.'\');" />'; } elsif ($tryagain) { $roletext.= - ''. + ''; + $trolecode."','".$buttonname.'\');" />'; } elsif ($advanced) { $roletext.= - ''. + ''; + $trolecode."','".$buttonname.'\');" />'; + } elsif ($reinit) { + $roletext.= + ''. + ''; } else { - $roletext.=' '; + $roletext.= + ''. + ''; } } - $tremark.=&Apache::lonannounce::showday(time,1, - &Apache::lonannounce::readcalendar($tdom.'_'.$trest)); - - $roletext.=''.$trole. - ''.$twhere. - ''.$tpstart. - ''.$tpend. - ''; + if ($trolecode !~ m/^(dc|ca|au|aa)\./) { + $tremark.=&Apache::lonannounce::showday(time,1, + &Apache::lonannounce::readcalendar($tdom.'_'.$trest)); + } + $roletext.=''.$trole.'' + .''.$twhere.'' + .''.$tpstart.'' + .''.$tpend.'' + .&Apache::loncommon::end_data_table_row(); if (!$is_dc) { - $roletext.=''.$tremark. - ' '."\n"; + $roletext.=&Apache::loncommon::continue_data_table_row() + .'' + .$tremark.' ' + .'' + .&Apache::loncommon::end_data_table_row(); } return $roletext; } -sub check_privs { - my ($cdom,$cnum,$then,$now) = @_; - my $cckey = 'user.role.cc./'.$cdom.'/'.$cnum; - if ($env{$cckey}) { - my ($role,$where,$trolecode,$tstart,$tend,$tremark,$tstatus,$tpstart,$tpend,$tfont); - &role_status($cckey,$then,$now,\$role,\$where,\$trolecode,\$tstatus,\$tstart,\$tend); - unless (($tstatus eq 'is') || ($tstatus eq 'will_not')) { - &set_privileges($cdom,$cnum); - } +sub check_needs_switchserver { + my ($possiblerole) = @_; + my $needs_switchserver; + my ($role,$where) = split(/\./,$possiblerole,2); + my (undef,$tdom,$twho) = split(/\//,$where); + my ($server_status,$home); + if (($role eq 'ca') || ($role eq 'aa')) { + ($server_status,$home) = &check_author_homeserver($twho,$tdom); + } else { + ($server_status,$home) = &check_author_homeserver($env{'user.name'}, + $env{'user.domain'}); + } + if ($server_status eq 'switchserver') { + $needs_switchserver = 1; + } + return $needs_switchserver; +} + +sub check_author_homeserver { + my ($uname,$udom)=@_; + if (($uname eq '') || ($udom eq '')) { + return ('fail',''); + } + my $home = &Apache::lonnet::homeserver($uname,$udom); + if (&Apache::lonnet::host_domain($home) ne $udom) { + return ('fail',$home); + } + my @ids=&Apache::lonnet::current_machine_ids(); + if (grep(/^\Q$home\E$/,@ids)) { + return ('ok',$home); } else { - &set_privileges($cdom,$cnum); + return ('switchserver',$home); } } @@ -856,7 +1302,7 @@ sub check_fordc { my $numdc = 0; if ($env{'user.adv'}) { foreach my $envkey (sort keys %env) { - if ($envkey=~/^user\.role\.dc\.\/(\w+)\/$/) { + if ($envkey=~/^user\.role\.dc\.\/($match_domain)\/$/) { my $dcdom = $1; my $livedc = 1; my ($tstart,$tend)=split(/\./,$env{$envkey}); @@ -872,10 +1318,83 @@ sub check_fordc { return $numdc; } +sub adhoc_course_role { + my ($then) = @_; + my ($cdom,$cnum); + $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + if (&check_forcc($cdom,$cnum,$then)) { + my $setprivs; + if (!defined($env{'user.role.'.$env{'form.switchrole'}})) { + $setprivs = 1; + } else { + my ($start,$end) = split(/\./,$env{'user.role.'.$env{'form.switchrole'}}); + if (($start && ($start>$then || $start == -1)) || + ($end && $end<$then)) { + $setprivs = 1; + } + } + if ($setprivs) { + if ($env{'form.switchrole'} =~ m-^(in|ta|ep|ad|st|cr)([\w/]*)\./\Q$cdom\E/\Q$cnum\E/?(\w*)$-) { + my $role = $1; + my $custom_role = $2; + my $usec = $3; + if ($role eq 'cr') { + if ($custom_role =~ m-^/$match_domain/$match_username/\w+$-) { + $role .= $custom_role; + } else { + return; + } + } + my (%userroles,%newrole,%newgroups,%group_privs); + my %cgroups = + &Apache::lonnet::get_active_groups($env{'user.domain'}, + $env{'user.name'},$cdom,$cnum); + foreach my $group (keys(%cgroups)) { + $group_privs{$group} = + $env{'user.priv.cc./'.$cdom.'/'.$cnum.'./'.$cdom.'/'.$cnum.'/'.$group}; + } + $newgroups{'/'.$cdom.'/'.$cnum} = \%group_privs; + my $area = '/'.$cdom.'/'.$cnum; + my $spec = $role.'.'.$area; + if ($usec ne '') { + $spec .= '/'.$usec; + $area .= '/'.$usec; + } + &Apache::lonnet::standard_roleprivs(\%newrole,$role,$cdom,$spec,$cnum,$area); + &Apache::lonnet::set_userprivs(\%userroles,\%newrole,\%newgroups); + my $adhocstart = $then-1; + $userroles{'user.role.'.$spec} = $adhocstart.'.'; + &Apache::lonnet::appenv(\%userroles,[$role,'cm']); + } + } + } + return; +} + +sub check_forcc { + my ($cdom,$cnum,$then) = @_; + my $is_cc; + if ($cdom ne '' && $cnum ne '') { + if (&Apache::lonnet::is_course($cdom,$cnum)) { + my $envkey = 'user.role.cc./'.$cdom.'/'.$cnum; + if (defined($env{$envkey})) { + $is_cc = 1; + my ($tstart,$tend)=split(/\./,$env{$envkey}); + if ($tstart && $tstart>$then) { $is_cc = 0; } + if ($tend && $tend <$then) { $is_cc = 0; } + } + } + } + return $is_cc; +} + sub courselink { my ($dcdom,$rowtype) = @_; my $courseform=&Apache::loncommon::selectcourse_link - ('rolechoice','dccourse'.$rowtype.'_'.$dcdom,'dcdomain'.$rowtype.'_'.$dcdom,'coursedesc'.$rowtype.'_'.$dcdom,$dcdom); + ('rolechoice','dccourse'.$rowtype.'_'.$dcdom, + 'dcdomain'.$rowtype.'_'.$dcdom,'coursedesc'.$rowtype.'_'. + $dcdom,$dcdom,undef); my $hiddenitems = ''. ''. ''. @@ -884,8 +1403,12 @@ sub courselink { } sub coursepick_jscript { + my %lt = &Apache::lonlocal::texthash( + plsu => "Please use the 'Select Course' link to open a separate pick course window where you may select the course you wish to enter.", + youc => 'You can only use this screen to select courses in the current domain.', + ); my $verify_script = <<"END"; - -END - return $process_pick; +sub coauthorlink { + my ($dcdom,$rowtype) = @_; + my $coauthorform=&Apache::loncommon::selectauthor_link('rolechoice',$dcdom); + my $hiddenitems = ''; + return $coauthorform.$hiddenitems; } sub display_cc_role { @@ -951,75 +1455,57 @@ sub display_cc_role { my $advanced = $env{'user.adv'}; my $tryagain = $env{'form.tryagain'}; unless ($rolekey =~/^error\:/) { - if ($rolekey =~ m-^user\.role.cc\./(\w+)/(\w+)$-) { + if ($rolekey =~ m-^user\.role.cc\./($match_domain)/($match_courseid)$-) { my $tcourseid = $1.'_'.$2; my $trolecode = 'cc./'.$1.'/'.$2; - my $trole = Apache::lonnet::plaintext('cc'); my $twhere; - my $tbg='#77FF77'; - my $tfont='#003300'; + my $ttype; + my $tbg='LC_roles_is'; my %newhash=&Apache::lonnet::coursedescription($tcourseid); if (%newhash) { $twhere=$newhash{'description'}. - ' '. - &Apache::loncommon::syllabuswrapper(&mt('Syllabus'),$2,$1,$tfont). - ''; + ' '. + &Apache::loncommon::syllabuswrapper(&mt('Syllabus'),$2,$1). + ''; + $ttype = $newhash{'type'}; } else { $twhere=&mt('Currently not available'); $env{'course.'.$tcourseid.'.description'}=$twhere; } + my $trole = &Apache::lonnet::plaintext('cc',$ttype); $twhere.="
".&mt('Domain').":".$1; - $roletext = &build_roletext($trolecode,$1,$2,'is',$tryagain,$advanced,'',$tbg,$tfont,$trole,&mt('Course'),$twhere,'','','',1,''); + $roletext = &build_roletext($trolecode,$1,$2,'is',$tryagain,$advanced,'',$tbg,$trole,$twhere,'','','',1,''); } } - return $roletext; + return ($roletext); } -sub allcourses_row { +sub adhoc_roles_row { my ($dcdom,$rowtype) = @_; - my $ccrole = Apache::lonnet::plaintext('cc'); - my $selectlink = &courselink($dcdom,$rowtype); - my $output = ''. - ''. - ''.$ccrole.''. - ' '.$selectlink.''. - ' from '.&mt('Domain').' '.$dcdom. - ''."\n"; + my $output = &Apache::loncommon::continue_data_table_row() + .' ' + .'' + .'' + .'' + .'' + .'
' + .&mt('[_1]Ad hoc[_2] roles in domain [_3] --' + ,'','',$dcdom) + .''; + my $selectcclink = &courselink($dcdom,$rowtype); + my $ccrole = &Apache::lonnet::plaintext('cc'); + my $carole = &Apache::lonnet::plaintext('ca'); + my $selectcalink = &coauthorlink($dcdom,$rowtype); + $output.=&mt('[_1]: [_2]',$ccrole,$selectcclink) + .'
  '.&mt('[_1]: [_2]',$carole,$selectcalink).'
' + .'' + .&Apache::loncommon::end_data_table_row(); return $output; } sub recent_filename { my $area=shift; - return 'nohist_recent_'.&Apache::lonnet::escape($area); -} - -sub set_privileges { - my ($dcdom,$pickedcourse) = @_; - my $area = '/'.$dcdom.'/'.$pickedcourse; - my $role = 'cc'; - my $spec = $role.'.'.$area; - my $userroles = &Apache::lonnet::set_arearole($role,$area,'','',$dcdom,$env{'user.name'}); - my %ccrole = (); - &Apache::lonnet::standard_roleprivs(\%ccrole,$role,$dcdom,$spec,$pickedcourse,$area); - my ($author,$adv)= &Apache::lonnet::set_userprivs(\$userroles,\%ccrole); - my @newprivs = split/\n/,$userroles; - my %newccroles = (); - foreach (@newprivs) { - my ($key,$val) = split/=/,$_; - $newccroles{$key} = $val; - } - &Apache::lonnet::appenv(%newccroles); - &Apache::lonnet::log($env{'user.domain'}, - $env{'user.name'}, - $env{'user.home'}, - "Role ".$role); - &Apache::lonnet::appenv( - 'request.role' => $spec, - 'request.role.domain' => $dcdom, - 'request.course.sec' => ''); - my $tadv=0; - if (&Apache::lonnet::allowed('adv') eq 'F') { $tadv=1; } - &Apache::lonnet::appenv('request.role.adv' => $tadv); + return 'nohist_recent_'.&escape($area); } sub courseloadpage {