--- loncom/auth/lonroles.pm 2008/07/14 10:21:52 1.201
+++ loncom/auth/lonroles.pm 2009/12/20 04:11:27 1.240.2.4
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# User Roles Screen
#
-# $Id: lonroles.pm,v 1.201 2008/07/14 10:21:52 raeburn Exp $
+# $Id: lonroles.pm,v 1.240.2.4 2009/12/20 04:11:27 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;
@@ -41,6 +138,7 @@ use Apache::lonannounce;
use Apache::lonlocal;
use Apache::lonpageflip();
use Apache::lonnavdisplay();
+use Apache::lonmainmenu();
use GDBM_File;
use LONCAPA qw(:DEFAULT :match);
use HTML::Entities;
@@ -60,8 +158,13 @@ sub redirect_user {
} else {
$navwindow.=&Apache::lonnavmaps::close();
}
+
+ # Breadcrumbs
+ my $brcrum = [{'href' => $url,
+ 'text' => 'Switching Role'},];
my $start_page = &Apache::loncommon::start_page('Switching Role',undef,
- {'redirect' => [1,$url],});
+ {'redirect' => [1,$url],
+ 'bread_crumbs' => $brcrum,});
my $end_page = &Apache::loncommon::end_page();
# Note to style police:
@@ -70,10 +173,12 @@ sub redirect_user {
$r->print(<
+//
$navwindow
-
$msg
+
$msg
$end_page
ENDREDIR
return;
@@ -85,13 +190,25 @@ sub error_page {
&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:').
+ # Breadcrumbs
+ my $brcrum = [{'href' => $dest,
+ 'text' => 'Problems during Course Initialization'},];
+ $r->print(&Apache::loncommon::start_page('Problems during Course Initialization',
+ undef,
+ {'bread_crumbs' => $brcrum,})
+ );
+ $r->print(
+ ''.
+ '
'.&mt('The following problems occurred:').
+ ' '.
$error.
- '
'.&mt('Continue').''
+ );
+ $r->print(&Apache::loncommon::end_page());
}
sub handler {
@@ -100,10 +217,15 @@ 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);
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});
+ my $custommenu = &Apache::loncommon::needs_gci_custom();
# ================================================================== Roles Init
if ($env{'form.selectrole'}) {
@@ -118,7 +240,7 @@ sub handler {
# 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);
+ &adhoc_course_role($refresh,$then);
}
}
my %temp=('logout_'.$env{'request.course.id'} => time);
@@ -135,28 +257,53 @@ sub handler {
# 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\./($match_domain)/($match_courseid)$-)) {
+# Is this an ad-hoc Coordinator role?
+ if (my ($ccrole,$domain,$coursenum) =
+ ($envkey =~ m-^form\.(cc|co)\./($match_domain)/($match_courseid)$-)) {
if ($dcroles{$domain}) {
- &check_privs($domain,$coursenum,$then,$now,'cc');
+ &Apache::lonnet::check_adhoc_privs($domain,$coursenum,
+ $then,$refresh,$now,$ccrole);
}
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
+ 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;
+ 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,
+ $refresh,$now,'ca');
if ($server_status eq 'switchserver') {
my $trolecode = 'ca./'.$domain.'/'.$user;
my $switchserver = '/adm/switchserver?'
@@ -173,11 +320,14 @@ sub handler {
}
}
}
-
+ if (($env{'form.cm'}) && ($env{'form.orgurl'})) {
+ $r->internal_redirect($env{'form.orgurl'});
+ }
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/^\///;
@@ -229,8 +379,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).
@@ -241,12 +394,14 @@ sub handler {
$r->print(<
+//
-
$end_page
@@ -264,9 +419,11 @@ ENDENTEREDKEY
$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.").' ');
+ }
+ }
+# ----------------------------------------------------------------------- Table
+ unless ((!&Apache::loncommon::show_course()) || ($nochoose) || ($countactive==1)) {
+ $r->print("
');
+ }
+ $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 $roletext;
- my $sortkey;
+ my ($role_text,$role_text_end,$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);
+ 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=' ';
- $tfont='#000000';
if ($tstart) {
- $tpstart=&Apache::lonlocal::locallocaltime($tstart);
+ $tpstart=&Apache::lonlocal::locallocaltime($tstart,$timezone);
}
if ($tend) {
- $tpend=&Apache::lonlocal::locallocaltime($tend);
+ $tpend=&Apache::lonlocal::locallocaltime($tend,$timezone);
}
if ($env{'request.role'} eq $trolecode) {
- $tstatus='selected';
+ $tstatus='selected';
}
my $tbg;
- if (($tstatus eq 'is')
- || ($tstatus eq 'selected')
- || ($tstatus eq 'will')
- || ($tstatus eq 'future')
+ if (($tstatus eq 'is')
+ || ($tstatus eq 'selected')
+ || ($tstatus eq 'future')
|| ($env{'form.showall'})) {
if ($tstatus eq 'is') {
- $tbg='#77FF77';
- $tfont='#003300';
- $possiblerole=$trolecode;
- $countactive++;
+ $tbg='LC_roles_is';
+ $possiblerole=$trolecode;
+ $countactive++;
} elsif ($tstatus eq 'future') {
- $tbg='#FFFF77';
+ $tbg='LC_roles_future';
$button=0;
- $futureroles{$trolecode} = $tstart.':'.$tend;
+ $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';
+ $tbg='LC_roles_expired';
$button=0;
} elsif ($tstatus eq 'will_not') {
- $tbg='#AAFF77';
- $tremark.=&mt('Expired after logout. ');
+ $tbg='LC_roles_will_not';
+ $tremark.=&mt('Expired after logout.').' ';
} elsif ($tstatus eq 'selected') {
- $tbg='#11CC55';
- $tfont='#002200';
- $inrole=1;
- $countactive++;
- $tremark.=&mt('Currently 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 ').$rauthor.
- &mt(' at ').$rdomain.'.';
- }
- $trole=Apache::lonnet::plaintext($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)=
@@ -582,239 +1002,163 @@ ENDHEADER
# 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; } }
+ my $allowed=0;
+ my @ids=&Apache::lonnet::current_machine_ids();
+ foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
if (!$allowed) {
- $button=0;
+ $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.' '.
+ ': '.$tdom.' '.
' '.&mt('Server').': '.$home;
$env{'course.'.$tdom.'_'.$trest.'.description'}='ca';
- $tremark.=&Apache::lonhtmlcommon::authorbombs('/res/'.$tdom.'/'.$trest.'/');
- $sortkey=$role."$trest:$tdom";
+ $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; } }
+ my $allowed=0;
+ my @ids=&Apache::lonnet::current_machine_ids();
+ foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
if (!$allowed) {
- $button=0;
+ $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;
+ ': '.$home;
$env{'course.'.$tdom.'_'.$trest.'.description'}='ca';
- $tremark.=&Apache::lonhtmlcommon::authorbombs('/res/'.$tdom.'/'.$env{'user.name'}.'/');
- $sortkey=$role;
+ $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;
+ $sortkey=$role."\0".$tdom."\0".$twhere."\0".$envkey;
unless ($twhere eq &mt('Currently not available')) {
- $twhere.=' '.
- &Apache::loncommon::syllabuswrapper(&mt('Syllabus'),$trest,$tdom,$tfont).
- '';
- }
+ $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;
+ $sortkey=$role."\0".$tdom."\0".$newhash{'description'}.
+ "\0".$envkey;
$twhere=$newhash{'description'}.
- ' '.
- &Apache::loncommon::syllabuswrapper(&mt('Syllabus'),$trest,$tdom,$tfont).
- '';
+ ' '.
+ &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;
+ $sortkey=$role."\0".$tdom."\0".$twhere."\0".$envkey;
$ttype = 'Unavailable';
}
}
if ($tsection) {
$twhere.=' '.&mt('Section').': '.$tsection;
- }
- if ($role ne 'st') { $twhere.=" ".&mt('Domain').":".$tdom; }
+ }
+ if ($role ne 'st') { $twhere.=" ".&mt('Domain').":".$tdom; }
} elsif ($tdom) {
$ttype='Domain';
$twhere=$tdom;
- $sortkey=$role.$twhere;
+ $sortkey=$role.$twhere;
} else {
$ttype='System';
$twhere=&mt('system wide');
- $sortkey=$role.$twhere;
+ $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;
- }
- }
- }
- if ($env{'user.adv'}) {
- $r->print(
- ' ');
- } else {
- if ($countactive > 0) {
- 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.','','').'
');
- }
- }
-
-# No active roles
- if ($countactive==0) {
- if ($inrole) {
- $r->print('
'.&mt('Currently no additional roles or courses').'
');
- } else {
- $r->print('
'.&mt('Currently no active roles or courses').'
');
- }
- &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 $tfont='#003300';
- if ($env{'request.role'} eq 'cm') {
- $r->print('
'
+ .&Apache::loncommon::end_data_table_empty_row()
+ );
}
$r->print($output);
}
@@ -883,8 +1237,106 @@ sub findcourse_advice {
} 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.').'
');
+ $r->print('
'.&mt('Self-Enrollment').'
'.
+ '
'.&mt('The [_1]Course/Community Catalog[_2] provides information about all [_3] classes for which LON-CAPA courses have been created, as well as any communities in the domain.','','',$domdesc).' ');
+ $r->print(&mt('You can search for courses and communities which permit self-enrollment, if you would like to enroll in one.').'
');
+ &queued_selfenrollment($r);
+ return;
+}
+
+sub requestcourse_advice {
+ my ($r) = @_;
+ my $domdesc = &Apache::lonnet::domain($env{'user.domain'},'description');
+ my $esc_dom = &HTML::Entities::encode($env{'user.domain'},'"<>&');
+ my (%can_request,%request_doms);
+ &Apache::lonnet::check_can_request($env{'user.domain'},\%can_request,\%request_doms);
+ if (keys(%request_doms) > 0) {
+ my ($types,$typename) = &Apache::loncommon::course_types();
+ if ((ref($types) eq 'ARRAY') && (ref($typename) eq 'HASH')) {
+ $r->print('
'.&mt('Request creation of a course or community').'
'.
+ '
'.&mt('You have rights to request the creation of courses and/or communities in the following domain(s):').'
');
+ my (@reqdoms,@reqtypes);
+ foreach my $type (sort(keys(%request_doms))) {
+ push(@reqtypes,$type);
+ if (ref($request_doms{$type}) eq 'ARRAY') {
+ my $domstr = join(', ',map { &Apache::lonnet::domain($_) } sort(@{$request_doms{$type}}));
+ $r->print(
+ '