# The LearningOnline Network with CAPA
# User Roles Screen
#
# $Id: lonroles.pm,v 1.240.2.5 2009/12/24 18:28:54 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
###
=pod
=head1 NAME
Apache::lonroles - User Roles Screen
=head1 SYNOPSIS
Invoked by /etc/httpd/conf/srm.conf:
$msg '.&mt('The following problems occurred:').
' '
.&mt('Could not initialize [_1] at this time.',
$env{'course.'.$cdom.'_'.$cnum.'.description'})
.' '.&mt('Please try again.').' '.$ferr.' '
.&mt('This LON-CAPA server is version [_1]',$r->dir_config('lonVersion'))
.'
Use the tabs to navigate the WebCenter and...
'.
$error.
'
'.&mt('Continue').''
);
$r->print(&Apache::loncommon::end_page());
}
sub handler {
my $r = shift;
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'}) {
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($refresh,$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 or author space and needs privs to be created
if ($numdc > 0) {
foreach my $envkey (keys %env) {
# Is this an ad-hoc Coordinator role?
if (my ($ccrole,$domain,$coursenum) =
($envkey =~ m-^form\.(cc|co)\./($match_domain)/($match_courseid)$-)) {
if ($dcroles{$domain}) {
&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)$-)) {
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')) {
&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?'
.'otherserver='.$home.'&role='.$trolecode;
$r->internal_redirect($switchserver);
}
} else {
delete($env{$envkey});
}
} else {
delete($env{$envkey});
}
last;
}
}
}
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);
&Apache::lonnet::role_status($envkey,$then,$refresh,$now,\$role,\$where,
\$trolecode,\$tstatus,\$tstart,\$tend);
if ($env{'form.'.$trolecode}) {
if ($tstatus eq 'is') {
$where=~s/^\///;
my ($cdom,$cnum,$csec)=split(/\//,$where);
# check for course groups
my %coursegroups = &Apache::lonnet::get_active_groups(
$env{'user.domain'},$env{'user.name'},$cdom, $cnum);
my $cgrps = join(':',keys(%coursegroups));
# 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,' ',$frozen_roles{$trolecode});
}
# check for keyed access
if (($role eq 'st') &&
($env{'course.'.$cdom.'_'.$cnum.'.keyaccess'} eq 'yes')) {
# who is key authority?
my $authdom=$cdom;
my $authnum=$cnum;
if ($env{'course.'.$cdom.'_'.$cnum.'.keyauth'}) {
($authnum,$authdom)=
split(/:/,$env{'course.'.$cdom.'_'.$cnum.'.keyauth'});
}
# check with key authority
unless (&Apache::lonnet::validate_access_key(
$env{'environment.key.'.$cdom.'_'.$cnum},
$authdom,$authnum)) {
# there is no valid key
if ($env{'form.newkey'}) {
# student attempts to register a new key
&Apache::loncommon::content_type($r,'text/html');
&Apache::loncommon::no_cache($r);
$r->send_http_header;
my $swinfo=&Apache::lonmenu::rawconfig();
my $start_page=&Apache::loncommon::start_page
('Verifying Access Key to Unlock this Course');
my $end_page=&Apache::loncommon::end_page();
my $buttontext=&mt('Enter Course');
my $message=&mt('Successfully registered key');
my $assignresult=
&Apache::lonnet::assign_access_key(
$env{'form.newkey'},
$authdom,$authnum,
$cdom,$cnum,
$env{'user.domain'},
$env{'user.name'},
&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).
'
'.
&mt('Logout').'';
$buttontext=&mt('Re-Enter Key');
}
$r->print(<
'.&mt('As this is not the case, most functionality in the system will be unavailable.').'
';
if ($custommenu) {
my $start_page = &Apache::loncommon::start_page('Main Menu',undef,
{'bread_crumbs' => 1});
$r->print(<<"ENDCUSTOM");
$start_page
ENDCUSTOM
} else {
$crumbtext = 'User Roles';
$pagetitle = 'My Roles';
$recent = &mt('Recent Roles');
$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($pagetitle,undef,{bread_crumbs=>$brcrum});
my $standby=&mt('Role selected. Please stand by.');
$standby=~s/\n/\\n/g;
$r->print(<".&mt('LON-CAPA Access Control')."
");
$r->print("");
if ($priv ne '') {
$r->print(&mt('Access : ').&Apache::lonnet::plaintext($priv)."\n");
}
if ($fn ne '') {
$r->print(&mt('Resource: ').&Apache::lonenc::check_encrypt($fn)."\n");
}
if ($msg ne '') {
$r->print(&mt('Action : ').$msg."\n");
}
$r->print("
");
my $url=$fn;
my $last;
if (tie(my %hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db',
&GDBM_READER(),0640)) {
$last=$hash{'last_known'};
untie(%hash);
}
if ($last) { $fn.='?symb='.&escape($last); }
&Apache::londocs::changewarning($r,undef,'You have modified your course recently, [_1] may fix this access problem.',
&Apache::lonenc::check_encrypt($fn));
} else {
if ($env{'user.error.msg'}) {
if ($reinit) {
$r->print(
''.
&mt('As your session file for the course or community has expired, you will need to re-select it.').'
');
} else {
$r->print(
''.
&mt('You need to choose another user role or enter a specific course or community for this function.').
'
');
}
}
}
# -------------------------------------------------------- Choice or no choice?
if ($nochoose) {
$r->print("".&mt('Sorry ...')."
\n".
&mt('This action is currently not authorized.').''.
&Apache::loncommon::end_page());
return OK;
} else {
if (($ENV{'REDIRECT_QUERY_STRING'}) && ($fn)) {
$fn.='?'.$ENV{'REDIRECT_QUERY_STRING'};
}
unless ($custommenu) {
$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;
} elsif ($countactive==1) { # Is there only one choice?
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.").'
');
}
}
# ----------------------------------------------------------------------- Table
unless ((!&Apache::loncommon::show_course()) || ($nochoose) || ($countactive==1)) {
$r->print("".&mt('Select a Course to Enter')."
\n");
}
if ($env{'form.destinationurl'}) {
$r->print('');
if ($env{'form.destsymb'} ne '') {
$r->print('');
}
}
my $doheaders = &roletable_headers($r,\%roleclass,\%sortrole,$nochoose);
if ($env{'environment.recentroles'}) {
my %recent_roles =
&Apache::lonhtmlcommon::get_recent('roles',$env{'environment.recentrolesn'});
my $output='';
foreach (sort(keys(%recent_roles))) {
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');
}
} elsif ($numdc > 0) {
unless ($_ =~/^error\:/) {
$output.=&display_cc_role('user.role.'.$_);
}
}
}
if ($output) {
$r->print(&Apache::loncommon::start_data_table_empty_row()
.''
.$recent
.' '
.&Apache::loncommon::end_data_table_empty_row()
);
$r->print($output);
$doheaders ++;
}
}
if ($numdc > 0) {
$r->print(&coursepick_jscript());
$r->print(&Apache::loncommon::coursebrowser_javascript().
&Apache::loncommon::authorbrowser_javascript());
}
&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(''
.&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(''.&mt('Current Privileges').'
');
$r->print(&privileges_info());
}
$r->print(&Apache::lonnet::getannounce());
if ($advanced) {
my $esc_dom = &HTML::Entities::encode($env{'user.domain'},'"<>&');
$r->print('
'
.''.&mt('Logout').' '
.''
.&mt('Course/Community Catalog')
.'Welcome to the Geoscience Concept Inventory WebCenter
For more information about writing and reviewing Concept Inventory questions
please refer to the GCI Workbook.
END
}
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('
'
.&Apache::loncommon::start_data_table()
.&Apache::loncommon::start_data_table_header_row()
);
if (!$nochoose) { $r->print('
'.&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.').'
'.&mt('You have rights to request the creation of courses and/or communities in the following domain(s):').'
The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.
More information about this error may be available in the server error log.