--- loncom/auth/lonroles.pm 2008/09/02 02:56:52 1.205 +++ loncom/auth/lonroles.pm 2009/06/12 09:19:21 1.227 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # User Roles Screen # -# $Id: lonroles.pm,v 1.205 2008/09/02 02:56:52 raeburn Exp $ +# $Id: lonroles.pm,v 1.227 2009/06/12 09:19:21 bisitz 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; @@ -70,10 +167,12 @@ sub redirect_user { $r->print(< +// $navwindow -

$msg

+

$msg

$end_page ENDREDIR return; @@ -86,9 +185,12 @@ sub error_page { $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:'). + ''. + '

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


'.&mt('Continue').''. &Apache::loncommon::end_page()); @@ -100,6 +202,10 @@ sub handler { my $now=time; my $then=$env{'user.login.time'}; + my $refresh=$env{'user.refresh.time'}; + if (!$refresh) { + $refresh = $then; + } my $envkey; my %dcroles = (); my $numdc = &check_fordc(\%dcroles,$then); @@ -139,27 +245,49 @@ sub handler { if (my ($domain,$coursenum) = ($envkey =~ m-^form\.cc\./($match_domain)/($match_courseid)$-)) { if ($dcroles{$domain}) { - &check_privs($domain,$coursenum,$then,$now,'cc'); + &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)$-)) { - # Check if author blocked ca-access - my %blocked=&Apache::lonnet::get('environment',['domcoord.author'],$domain,$user); - if ($blocked{'domcoord.author'} eq 'blocked') { - my %roleshash = &Apache::lonnet::get_my_roles($user,$domain); - if (!defined($roleshash{$env{'user.name'}.':'.$env{'user.domain'}.':ca'})) { - delete($env{$envkey}); - $env{'user.error.msg'}=':::1:User '.$user.' in domain '.$domain.' blocked domain coordinator access'; + 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}) { my ($server_status,$home) = &check_author_homeserver($user,$domain); if (($server_status eq 'ok') || ($server_status eq 'switchserver')) { - &check_privs($domain,$user,$then,$now,'ca'); + &Apache::lonnet::check_adhoc_privs($domain,$user,$then, + $now,'ca'); if ($server_status eq 'switchserver') { my $trolecode = 'ca./'.$domain.'/'.$user; my $switchserver = '/adm/switchserver?' @@ -180,7 +308,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,$refresh,$now,\$role,\$where, + \$trolecode,\$tstatus,\$tstart,\$tend); if ($env{'form.'.$trolecode}) { if ($tstatus eq 'is') { $where=~s/^\///; @@ -247,12 +376,14 @@ sub handler { $r->print(< +// -
+ -$message
+$message
$end_page @@ -270,9 +401,11 @@ ENDENTEREDKEY $r->print(< +// -
+ @@ -303,6 +436,14 @@ ENDENTERKEY 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}); if (($ferr) && ($tadv)) { @@ -316,11 +457,12 @@ ENDENTERKEY &Apache::lonnet::appenv( {"request.course.id" => $cdom.'_'.$cnum}); $furl='/adm/roles?tryagain=1'; - $msg= - '

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

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

'.$ferr; + $msg='

' + .&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}); @@ -405,6 +547,12 @@ ENDENTERKEY $redirect_url); return OK; } + if ($role eq 'sc') { + my $redirect_url = '/adm/grades?command=scantronupload'; + &redirect_user($r,&mt('Loading Data Upload Page'), + $redirect_url); + return OK; + } } } } @@ -418,8 +566,18 @@ ENDENTERKEY $r->send_http_header; return OK if $r->header_only; + my $crumbtext = 'User Roles'; + my $pagetitle = 'My Roles'; + my $recent = &mt('Recent Roles'); + my $show_course=&Apache::loncommon::show_course(); + if ($show_course) { + $crumbtext = 'Courses'; + $pagetitle = 'My Courses'; + $recent = &mt('Recent Courses'); + } + my $brcrum =[{href=>"/adm/roles",text=>$crumbtext}]; my $swinfo=&Apache::lonmenu::rawconfig(); - my $start_page=&Apache::loncommon::start_page('User Roles'); + my $start_page=&Apache::loncommon::start_page($pagetitle,undef,{bread_crumbs=>$brcrum}); my $standby=&mt('Role selected. Please stand by.'); $standby=~s/\n/\\n/g; 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.').'

'; @@ -431,6 +589,7 @@ $start_page $noscript ENDHEADER @@ -463,6 +623,8 @@ ENDHEADER my $advanced=$env{'user.adv'}; &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['tryagain']); my $tryagain=$env{'form.tryagain'}; + my $reinit=$env{'user.reinit'}; + delete $env{'user.reinit'}; # -------------------------------------------------------- Generate Page Output # --------------------------------------------------------------- Error Header? @@ -492,10 +654,16 @@ ENDHEADER &Apache::lonenc::check_encrypt($fn)); } else { if ($env{'user.error.msg'}) { - $r->print( + if ($reinit) { + $r->print( + '

'. + &mt('As your session file for the course has expired, you will need to re-select the course.').'

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

'. &mt('You need to choose another user role or enter a specific course for this function').'

'); - } + } + } } # -------------------------------------------------------- Choice or no choice? if ($nochoose) { @@ -512,178 +680,22 @@ ENDHEADER $r->print(''); $r->print(''); } - my (%roletext,%sortrole,%roleclass); - my $countactive=0; - my $countfuture=0; - my $countwill=0; - my $inrole=0; - my $possiblerole=''; - my %futureroles; - my %roles_nextlogin; - foreach $envkey (sort keys %env) { - my $button = 1; - my $switchserver=''; - my $roletext; - my $sortkey; - if ($envkey=~/^user\.role\./) { - my ($role,$where,$trolecode,$tstart,$tend,$tremark,$tstatus,$tpstart,$tpend,$tfont); - &role_status($envkey,$then,$now,\$role,\$where,\$trolecode,\$tstatus,\$tstart,\$tend); - next if (!defined($role) || $role eq '' || $role =~ /^gr/); - $tremark=''; - $tpstart=' '; - $tpend=' '; - $tfont='#000000'; - if ($tstart) { - $tpstart=&Apache::lonlocal::locallocaltime($tstart); - } - if ($tend) { - $tpend=&Apache::lonlocal::locallocaltime($tend); - } - if ($env{'request.role'} eq $trolecode) { - $tstatus='selected'; - } - my $tbg; - if (($tstatus eq 'is') - || ($tstatus eq 'selected') - || ($tstatus eq 'will') - || ($tstatus eq 'future') - || ($env{'form.showall'})) { - if ($tstatus eq 'is') { - $tbg='#77FF77'; - $tfont='#003300'; - $possiblerole=$trolecode; - $countactive++; - } elsif ($tstatus eq 'future') { - $tbg='#FFFF77'; - $button=0; - $futureroles{$trolecode} = $tstart.':'.$tend; - $countfuture ++; - } elsif ($tstatus eq 'will') { - $tbg='#FFAA77'; - $tremark.=&mt('Active at next login.').' '; - $roles_nextlogin{$trolecode} = $tstart.':'.$tend; - $countwill ++; - } elsif ($tstatus eq 'expired') { - $tbg='#FF7777'; - $tfont='#330000'; - $button=0; - } elsif ($tstatus eq 'will_not') { - $tbg='#AAFF77'; - $tremark.=&mt('Expired after logout.').' '; - } elsif ($tstatus eq 'selected') { - $tbg='#11CC55'; - $tfont='#002200'; - $inrole=1; - $countactive++; - $tremark.=&mt('Currently selected.').' '; - } - my $trole; - if ($role =~ /^cr\//) { - my ($rdummy,$rdomain,$rauthor,$rrole)=split(/\//,$role); - if ($tremark) { $tremark.='
'; } - $tremark.=&mt('Defined by [_1] at [_2].',$rauthor,$rdomain); - } - $trole=Apache::lonnet::plaintext($role); - my $ttype; - my $twhere; - my ($tdom,$trest,$tsection)= - split(/\//,Apache::lonnet::declutter($where)); - # First, Co-Authorship roles - if (($role eq 'ca') || ($role eq 'aa')) { - my $home = &Apache::lonnet::homeserver($trest,$tdom); - my $allowed=0; - my @ids=&Apache::lonnet::current_machine_ids(); - foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } } - if (!$allowed) { - $button=0; - $switchserver='otherserver='.$home.'&role='.$trolecode; - } - #next if ($home eq 'no_host'); - $home = &Apache::lonnet::hostname($home); - $ttype='Construction Space'; - $twhere=&mt('User').': '.$trest.'
'.&mt('Domain'). - ': '.$tdom.'
'. - ' '.&mt('Server').': '.$home; - $env{'course.'.$tdom.'_'.$trest.'.description'}='ca'; - $tremark.=&Apache::lonhtmlcommon::authorbombs('/res/'.$tdom.'/'.$trest.'/'); - $sortkey=$role."$trest:$tdom"; - } elsif ($role eq 'au') { - # Authors - my $home = &Apache::lonnet::homeserver - ($env{'user.name'},$env{'user.domain'}); - my $allowed=0; - my @ids=&Apache::lonnet::current_machine_ids(); - foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } } - if (!$allowed) { - $button=0; - $switchserver='otherserver='.$home.'&role='.$trolecode; - } - #next if ($home eq 'no_host'); - $home = &Apache::lonnet::hostname($home); - $ttype='Construction Space'; - $twhere=&mt('Domain').': '.$tdom.'
'.&mt('Server'). - ': '.$home; - $env{'course.'.$tdom.'_'.$trest.'.description'}='ca'; - $tremark.=&Apache::lonhtmlcommon::authorbombs('/res/'.$tdom.'/'.$env{'user.name'}.'/'); - $sortkey=$role; - } elsif ($trest) { - my $tcourseid=$tdom.'_'.$trest; - $ttype = &Apache::loncommon::course_type($tcourseid); - $trole = &Apache::lonnet::plaintext($role,$ttype); - if ($env{'course.'.$tcourseid.'.description'}) { - $twhere=$env{'course.'.$tcourseid.'.description'}; - $sortkey=$role."\0".$tdom."\0".$twhere."\0".$envkey; - unless ($twhere eq &mt('Currently not available')) { - $twhere.=' '. - &Apache::loncommon::syllabuswrapper(&mt('Syllabus'),$trest,$tdom,$tfont). - ''; - } - } else { - my %newhash=&Apache::lonnet::coursedescription($tcourseid); - if (%newhash) { - $sortkey=$role."\0".$tdom."\0".$newhash{'description'}. - "\0".$envkey; - $twhere=$newhash{'description'}. - ' '. - &Apache::loncommon::syllabuswrapper(&mt('Syllabus'),$trest,$tdom,$tfont). - ''; - $ttype = $newhash{'type'}; - $trole = &Apache::lonnet::plaintext($role,$ttype); - } else { - $twhere=&mt('Currently not available'); - $env{'course.'.$tcourseid.'.description'}=$twhere; - $sortkey=$role."\0".$tdom."\0".$twhere."\0".$envkey; - $ttype = 'Unavailable'; - } - } - if ($tsection) { - $twhere.='
'.&mt('Section').': '.$tsection; - } - if ($role ne 'st') { $twhere.="
".&mt('Domain').":".$tdom; } - } elsif ($tdom) { - $ttype='Domain'; - $twhere=$tdom; - $sortkey=$role.$twhere; - } else { - $ttype='System'; - $twhere=&mt('system wide'); - $sortkey=$role.$twhere; - } - $roletext.=&build_roletext($trolecode,$tdom,$trest,$tstatus,$tryagain,$advanced,$tremark,$tbg,$tfont,$trole,$twhere,$tpstart,$tpend,$nochoose,$button,$switchserver); - $roletext{$envkey}=$roletext; - if (!$sortkey) {$sortkey=$twhere."\0".$envkey;} - $sortrole{$sortkey}=$envkey; - $roleclass{$envkey}=$ttype; - } - } - } + + my (%roletext,%sortrole,%roleclass,%futureroles,%timezones); + my ($countactive,$countfuture,$inrole,$possiblerole) = + &gather_roles($then,$refresh,$now,$reinit,$nochoose,\%roletext,\%sortrole,\%roleclass, + \%futureroles,\%timezones); + + $refresh = $now; + &Apache::lonnet::appenv({'user.refresh.time' => $refresh}); if ($env{'user.adv'}) { $r->print( - '
'); + $r->print(' />

'); } else { if ($countactive > 0) { + &queued_selfenrollment($r); my $domdesc = &Apache::lonnet::domain($env{'user.domain'},'description'); my $esc_dom = &HTML::Entities::encode($env{'user.domain'},'"<>&'); $r->print('

'.&mt('[_1]Visit the [_2]Course Catalog[_3] to view all [_4] LON-CAPA courses.','','','',$domdesc).'
'.&mt('If a course is [_1]not[_2] in your list of current courses below, you may be able to enroll if self-enrollment is permitted.','','').'

'); @@ -706,48 +718,29 @@ ENDHEADER &print_rolerows($r,$doheaders,\%roleclass,\%sortrole,\%dcroles, \%roletext); my $tremark=''; - my $tfont='#003300'; + my $tbg; if ($env{'request.role'} eq 'cm') { - $r->print(''); + $tbg="LC_roles_selected"; $tremark=&mt('Currently selected.').' '; - $tfont='#002200'; } else { - $r->print(''); + $tbg="LC_roles_is"; } - $r->print(''.&mt('No role specified'). - ''.$tremark. - ' '."\n"); + $r->print(&Apache::loncommon::start_data_table_row() + .' ' + .'' + .&mt('No role specified') + .'' + .''.$tremark.' ' + .&Apache::loncommon::end_data_table_row() + ); - $r->print(''); + $r->print(&Apache::loncommon::end_data_table()); } $r->print(&Apache::loncommon::end_page()); return OK; -# Is there only one choice? - } elsif ($countactive==1) { - my $needs_switchserver; - if ($env{'user.author'}) { - $needs_switchserver = &check_needs_switchserver($possiblerole); - } - if ((!$needs_switchserver) && ($env{'request.role'} eq 'cm')) { - $r->print('

'.&mt('Please stand by.').'

'. - ''. - ''); - $r->print("
\n"); - $r->rflush(); - $r->print(''); - $r->print(&Apache::loncommon::end_page()); - return OK; - } - if ($needs_switchserver) { - $r->print("

".&mt('Server Switch Required')."

\n". - &mt('Construction Space access is only available from '. - 'the home server of the corresponding Author.').'
'. - &mt("Click the 'Switch Server' link to go there.").'
'); - } } -# More than one possible role # ----------------------------------------------------------------------- Table - unless ((!&Apache::lonmenu::show_course()) || ($nochoose) || ($countactive==1)) { + unless ((!&Apache::loncommon::show_course()) || ($nochoose) || ($countactive==1)) { $r->print("

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

\n"); } my $doheaders = &roletable_headers($r,\%roleclass,\%sortrole,$nochoose); @@ -756,8 +749,13 @@ ENDHEADER &Apache::lonhtmlcommon::get_recent('roles',$env{'environment.recentrolesn'}); my $output=''; foreach (sort(keys(%recent_roles))) { - if (defined($roletext{'user.role.'.$_})) { - $output.=$roletext{'user.role.'.$_}; + if (ref($roletext{'user.role.'.$_}) eq 'ARRAY') { + $output.= &Apache::loncommon::start_data_table_row(). + $roletext{'user.role.'.$_}->[0]. + &Apache::loncommon::end_data_table_row(). + &Apache::loncommon::continue_data_table_row(). + $roletext{'user.role.'.$_}->[1]. + &Apache::loncommon::end_data_table_row(); if ($_ =~ m-dc\./($match_domain)/- && $dcroles{$1}) { $output .= &adhoc_roles_row($1,'recent'); @@ -769,8 +767,12 @@ ENDHEADER } } if ($output) { - $r->print("". - &mt('Recent Roles').""); + $r->print(&Apache::loncommon::start_data_table_empty_row() + .'' + .$recent + .'' + .&Apache::loncommon::end_data_table_empty_row() + ); $r->print($output); $doheaders ++; } @@ -784,33 +786,36 @@ ENDHEADER &print_rolerows($r,$doheaders,\%roleclass,\%sortrole,\%dcroles,\%roletext); if ($countactive > 1) { my $tremark=''; - my $tfont='#003300'; + my $tbg; if ($env{'request.role'} eq 'cm') { - $r->print(''); + $tbg="LC_roles_selected"; $tremark=&mt('Currently selected.').' '; - $tfont='#002200'; } else { - $r->print(''); + $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(' '); } } - $r->print(''.&mt('No role specified'). - ''.$tremark. - ' '."\n"); + $r->print('' + .&mt('No role specified') + .'' + .''.$tremark.' ' + .&Apache::loncommon::end_data_table_row() + ); } - $r->print(''); + $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

'); + $r->print('

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

'); $r->print(&privileges_info()); } $r->print(&Apache::lonnet::getannounce()); @@ -822,21 +827,236 @@ ENDHEADER .''.&mt('Logout').'  ' .'' .&mt('Course Catalog') - .'

'); + .'

'); } $r->print(&Apache::loncommon::end_page()); return OK; } +sub gather_roles { + my ($then,$refresh,$now,$reinit,$nochoose,$roletext,$sortrole,$roleclass,$futureroles,$timezones) = @_; + my ($countactive,$countfuture,$inrole,$possiblerole) = (0,0,0,''); + my $advanced = $env{'user.adv'}; + my $tryagain = $env{'form.tryagain'}; + foreach my $envkey (sort(keys(%env))) { + my $button = 1; + my $switchserver=''; + my ($role_text,$role_text_end,$sortkey); + if ($envkey=~/^user\.role\./) { + my ($role,$where,$trolecode,$tstart,$tend,$tremark,$tstatus,$tpstart,$tpend); + &Apache::lonnet::role_status($envkey,$then,$refresh,$now,\$role,\$where, + \$trolecode,\$tstatus,\$tstart,\$tend); + next if (!defined($role) || $role eq '' || $role =~ /^gr/); + my $timezone = &role_timezone($where,$timezones); + $tremark=''; + $tpstart=' '; + $tpend=' '; + if ($tstart) { + $tpstart=&Apache::lonlocal::locallocaltime($tstart,$timezone); + } + if ($tend) { + $tpend=&Apache::lonlocal::locallocaltime($tend,$timezone); + } + if ($env{'request.role'} eq $trolecode) { + $tstatus='selected'; + } + my $tbg; + if (($tstatus eq 'is') + || ($tstatus eq 'selected') + || ($tstatus eq 'future') + || ($env{'form.showall'})) { + if ($tstatus eq 'is') { + $tbg='LC_roles_is'; + $possiblerole=$trolecode; + $countactive++; + } elsif ($tstatus eq 'future') { + $tbg='LC_roles_future'; + $button=0; + $futureroles->{$trolecode} = $tstart.':'.$tend; + $countfuture ++; + } elsif ($tstatus eq 'expired') { + $tbg='LC_roles_expired'; + $button=0; + } elsif ($tstatus eq 'will_not') { + $tbg='LC_roles_will_not'; + $tremark.=&mt('Expired after logout.').' '; + } elsif ($tstatus eq 'selected') { + $tbg='LC_roles_selected'; + $inrole=1; + $countactive++; + $tremark.=&mt('Currently selected.').' '; + } + my $trole; + if ($role =~ /^cr\//) { + my ($rdummy,$rdomain,$rauthor,$rrole)=split(/\//,$role); + if ($tremark) { $tremark.='
'; } + $tremark.=&mt('Defined by [_1] at [_2].',$rauthor,$rdomain); + } + $trole=Apache::lonnet::plaintext($role); + my $ttype; + my $twhere; + my ($tdom,$trest,$tsection)= + split(/\//,Apache::lonnet::declutter($where)); + # First, Co-Authorship roles + if (($role eq 'ca') || ($role eq 'aa')) { + my $home = &Apache::lonnet::homeserver($trest,$tdom); + my $allowed=0; + my @ids=&Apache::lonnet::current_machine_ids(); + foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } } + if (!$allowed) { + $button=0; + $switchserver='otherserver='.$home.'&role='.$trolecode; + } + #next if ($home eq 'no_host'); + $home = &Apache::lonnet::hostname($home); + $ttype='Construction Space'; + $twhere=&mt('User').': '.$trest.'
'.&mt('Domain'). + ': '.$tdom.'
'. + ' '.&mt('Server').': '.$home; + $env{'course.'.$tdom.'_'.$trest.'.description'}='ca'; + $tremark.=&Apache::lonhtmlcommon::authorbombs('/res/'.$tdom.'/'.$trest.'/'); + $sortkey=$role."$trest:$tdom"; + } elsif ($role eq 'au') { + # Authors + my $home = &Apache::lonnet::homeserver + ($env{'user.name'},$env{'user.domain'}); + my $allowed=0; + my @ids=&Apache::lonnet::current_machine_ids(); + foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } } + if (!$allowed) { + $button=0; + $switchserver='otherserver='.$home.'&role='.$trolecode; + } + #next if ($home eq 'no_host'); + $home = &Apache::lonnet::hostname($home); + $ttype='Construction Space'; + $twhere=&mt('Domain').': '.$tdom.'
'.&mt('Server'). + ': '.$home; + $env{'course.'.$tdom.'_'.$trest.'.description'}='ca'; + $tremark.=&Apache::lonhtmlcommon::authorbombs('/res/'.$tdom.'/'.$env{'user.name'}.'/'); + $sortkey=$role; + } elsif ($trest) { + my $tcourseid=$tdom.'_'.$trest; + $ttype = &Apache::loncommon::course_type($tcourseid); + $trole = &Apache::lonnet::plaintext($role,$ttype); + if ($env{'course.'.$tcourseid.'.description'}) { + $twhere=$env{'course.'.$tcourseid.'.description'}; + $sortkey=$role."\0".$tdom."\0".$twhere."\0".$envkey; + unless ($twhere eq &mt('Currently not available')) { + $twhere.=' '. + &Apache::loncommon::syllabuswrapper(&mt('Syllabus'),$trest,$tdom). + ''; + } + } else { + my %newhash=&Apache::lonnet::coursedescription($tcourseid); + if (%newhash) { + $sortkey=$role."\0".$tdom."\0".$newhash{'description'}. + "\0".$envkey; + $twhere=$newhash{'description'}. + ' '. + &Apache::loncommon::syllabuswrapper(&mt('Syllabus'),$trest,$tdom). + ''; + $ttype = $newhash{'type'}; + $trole = &Apache::lonnet::plaintext($role,$ttype); + } else { + $twhere=&mt('Currently not available'); + $env{'course.'.$tcourseid.'.description'}=$twhere; + $sortkey=$role."\0".$tdom."\0".$twhere."\0".$envkey; + $ttype = 'Unavailable'; + } + } + if ($tsection) { + $twhere.='
'.&mt('Section').': '.$tsection; + } + if ($role ne 'st') { $twhere.="
".&mt('Domain').":".$tdom; } + } elsif ($tdom) { + $ttype='Domain'; + $twhere=$tdom; + $sortkey=$role.$twhere; + } else { + $ttype='System'; + $twhere=&mt('system wide'); + $sortkey=$role.$twhere; + } + ($role_text,$role_text_end) = + &build_roletext($trolecode,$tdom,$trest,$tstatus,$tryagain, + $advanced,$tremark,$tbg,$trole,$twhere,$tpstart, + $tpend,$nochoose,$button,$switchserver,$reinit); + $roletext->{$envkey}=[$role_text,$role_text_end]; + if (!$sortkey) {$sortkey=$twhere."\0".$envkey;} + $sortrole->{$sortkey}=$envkey; + $roleclass->{$envkey}=$ttype; + } + } + } + return ($countactive,$countfuture,$inrole,$possiblerole); +} + +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('
'); + $r->print('
' + .&Apache::loncommon::start_data_table() + .&Apache::loncommon::start_data_table_header_row() + ); if (!$nochoose) { $r->print(''); } - $r->print(''."\n"); + $r->print('' + .'' + .'' + .'' + .&Apache::loncommon::end_data_table_header_row() + ); $doheaders=-1; my @roletypes = &roletypes(); foreach my $type (@roletypes) { @@ -866,7 +1086,14 @@ sub print_rolerows { 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 (ref($roletext->{$sortrole->{$which}}) eq 'ARRAY') { + $output.= &Apache::loncommon::start_data_table_row(). + $roletext->{$sortrole->{$which}}->[0]. + &Apache::loncommon::end_data_table_row(). + &Apache::loncommon::continue_data_table_row(). + $roletext->{$sortrole->{$which}}->[1]. + &Apache::loncommon::end_data_table_row(); + } if ($sortrole->{$which} =~ m-dc\./($match_domain)/-) { if (ref($dcroles) eq 'HASH') { if ($dcroles->{$1}) { @@ -879,9 +1106,12 @@ sub print_rolerows { } if ($output) { if ($doheaders > 0) { - $r->print("". - ""); + $r->print(&Apache::loncommon::start_data_table_empty_row() + .'' + .&Apache::loncommon::end_data_table_empty_row() + ); } $r->print($output); } @@ -907,6 +1137,50 @@ sub findcourse_advice { } $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(). + ''. + ''. + &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::loncommon::end_data_table_row()); + } + } + } + $r->print(&Apache::loncommon::end_data_table()); + } return; } @@ -965,34 +1239,9 @@ sub privileges_info { return $output; } -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'; } - } - if ($$tend) { - if ($$tend<$then) { - $$tstatus='expired'; - } elsif ($$tend<$now) { - $$tstatus='will_not'; - } - } - } - } -} - sub build_roletext { - my ($trolecode,$tdom,$trest,$tstatus,$tryagain,$advanced,$tremark,$tbg,$tfont,$trole,$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,$roletext_end); my $is_dc=($trolecode =~ m/^dc\./); my $rowspan=($is_dc) ? '' : ' rowspan="2" '; @@ -1002,43 +1251,58 @@ 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.=''. + ''; } elsif ($tryagain) { $roletext.= - ''. + ''; } elsif ($advanced) { $roletext.= - ''. + ''; + } elsif ($reinit) { + $roletext.= + ''. + ''; } else { - $roletext.=' '; + $roletext.= + ''. + ''; } } if ($trolecode !~ m/^(dc|ca|au|aa)\./) { $tremark.=&Apache::lonannounce::showday(time,1, &Apache::lonannounce::readcalendar($tdom.'_'.$trest)); } - $roletext.=''; + $roletext.='' + .'' + .'' + .''; if (!$is_dc) { - $roletext.=''."\n"; + $roletext_end = ''; } - return $roletext; + return ($roletext,$roletext_end); } sub check_needs_switchserver { @@ -1076,20 +1340,6 @@ sub check_author_homeserver { } } -sub check_privs { - my ($cdom,$cnum,$then,$now,$checkrole) = @_; - my $cckey = 'user.role.'.$checkrole.'./'.$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,$checkrole); - } - } else { - &set_privileges($cdom,$cnum,$checkrole); - } -} - sub check_fordc { my ($dcroles,$then) = @_; my $numdc = 0; @@ -1139,7 +1389,15 @@ sub adhoc_course_role { return; } } - my (%userroles,%newrole,%newgroups); + 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 '') { @@ -1147,7 +1405,7 @@ sub adhoc_course_role { $area .= '/'.$usec; } &Apache::lonnet::standard_roleprivs(\%newrole,$role,$cdom,$spec,$cnum,$area); - &Apache::lonnet::set_userprivs(\%userroles,\%newrole,%newgroups); + &Apache::lonnet::set_userprivs(\%userroles,\%newrole,\%newgroups); my $adhocstart = $then-1; $userroles{'user.role.'.$spec} = $adhocstart.'.'; &Apache::lonnet::appenv(\%userroles,[$role,'cm']); @@ -1194,6 +1452,7 @@ sub coursepick_jscript { ); my $verify_script = <<"END"; END return $verify_script; @@ -1236,7 +1496,7 @@ sub coauthorlink { sub display_cc_role { my $rolekey = shift; - my $roletext; + my ($roletext,$roletext_end); my $advanced = $env{'user.adv'}; my $tryagain = $env{'form.tryagain'}; unless ($rolekey =~/^error\:/) { @@ -1245,14 +1505,13 @@ sub display_cc_role { my $trolecode = 'cc./'.$1.'/'.$2; my $twhere; my $ttype; - my $tbg='#77FF77'; - my $tfont='#003300'; + 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'); @@ -1260,28 +1519,26 @@ sub display_cc_role { } my $trole = &Apache::lonnet::plaintext('cc',$ttype); $twhere.="
".&mt('Domain').":".$1; - $roletext = &build_roletext($trolecode,$1,$2,'is',$tryagain,$advanced,'',$tbg,$tfont,$trole,$twhere,'','','',1,''); + ($roletext,$roletext_end) = &build_roletext($trolecode,$1,$2,'is',$tryagain,$advanced,'',$tbg,$trole,$twhere,'','','',1,''); } } - return ($roletext); + return ($roletext,$roletext_end); } sub adhoc_roles_row { my ($dcdom,$rowtype) = @_; - my $output = ''. - ' '. - ''."\n"; + $output.=$ccrole.': '.$selectcclink + .' | '.$carole.': '.$selectcalink + .&Apache::loncommon::end_data_table_row(); return $output; } @@ -1290,32 +1547,6 @@ sub recent_filename { return 'nohist_recent_'.&escape($area); } -sub set_privileges { -# role can be cc or ca - my ($dcdom,$pickedcourse,$role) = @_; - my $area = '/'.$dcdom.'/'.$pickedcourse; - my $spec = $role.'.'.$area; - my %userroles = &Apache::lonnet::set_arearole($role,$area,'','', - $env{'user.domain'}, - $env{'user.name'}); - my %ccrole = (); - &Apache::lonnet::standard_roleprivs(\%ccrole,$role,$dcdom,$spec,$pickedcourse,$area); - my ($author,$adv)= &Apache::lonnet::set_userprivs(\%userroles,\%ccrole); - &Apache::lonnet::appenv(\%userroles,[$role,'cm']); - - &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}); -} - sub courseloadpage { my ($courseid) = @_; my $startpage;
 '.&mt('User Role').''.&mt('Extent') - .''.&mt('Start').''.&mt('End') - .'
'.&mt('User Role').''.&mt('Extent').''.&mt('Start').''.&mt('End').'
". - &mt($type)."
' + .&mt($type) + .''.&mt('Date requested').''.&mt('Course title').''.&mt('User role').''.&mt('Section').''.&Apache::lonlocal::locallocaltime($item).''.$courseinfo{'description'}.''.$rolename.''.$usec.'
'.$trole. - ''.$twhere. - ''.$tpstart. - ''.$tpend. - '
'.$trole.''.$twhere.''.$tpstart.''.$tpend.'
'.$tremark. - ' 
'. + $tremark.' '. + '
' - .&mt('[_1]Ad hoc[_2] roles in domain [_3] --', - '','',$dcdom).''; + 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). - '