--- loncom/auth/lonroles.pm 2000/10/02 21:34:58 1.9
+++ loncom/auth/lonroles.pm 2021/11/28 19:18:00 1.357
@@ -1,299 +1,3646 @@
# The LearningOnline Network with CAPA
# User Roles Screen
-# (Directory Indexer
-# (Login Screen
-# 5/21/99,5/22,5/25,5/26,5/31,6/2,6/10,7/12,7/14 Gerd Kortemeyer)
-# 11/23 Gerd Kortemeyer)
-# 1/14,03/06,06/01,07/22,07/24,07/25,
-# 09/04,09/06,09/28,09/29,09/30,10/2 Gerd Kortemeyer
#
+# $Id: lonroles.pm,v 1.357 2021/11/28 19:18:00 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:
+
+
+ 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.
+
+=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;
-use Apache::lonnet();
+use Apache::lonnet;
use Apache::lonuserstate();
-use Apache::Constants qw(:common);
+use Apache::Constants qw(:common REDIRECT);
use Apache::File();
+use Apache::lonmenu;
+use Apache::loncommon;
+use Apache::lonhtmlcommon;
+use Apache::lonannounce;
+use Apache::lonlocal;
+use Apache::lonpageflip();
+use Apache::lonnavdisplay();
+use Apache::loncoursequeueadmin;
+use Apache::longroup;
+use Apache::lonrss;
+use Apache::lonplacementtest;
+use GDBM_File;
+use LONCAPA qw(:DEFAULT :match);
+use HTML::Entities;
+
+my $registered_cleanup;
+my $rosterupdates;
+
+sub start_loading_course {
+ my ($r,$title) = @_;
+ &Apache::loncommon::content_type($r,'text/html');
+ &Apache::loncommon::no_cache($r);
+ $r->send_http_header;
+ my $swinfo=&Apache::lonmenu::rawconfig();
+ # Breadcrumbs
+ my $brcrum = [{'href' => '',
+ 'text' => $title},];
+ my $start_page = &Apache::loncommon::start_page($title,undef,
+ {'bread_crumbs' => $brcrum,
+ 'bread_crumbs_nomenu' => 1,
+ 'links_disabled' => 1});
+ $r->print(<
+//
+
+ENDREDIR
+ return;
+}
+
+sub finish_loading_course {
+ my ($r,$msg,$url) = @_;
+ my $link = '';
+ my $end_page = &Apache::loncommon::end_page();
+ my $js_url = &js_escape($url);
+ $r->print(<
+// a').removeAttr("aria-disabled");
+ \$('.isDisabled').removeClass("isDisabled");
+ var url = "$js_url";
+ \$(location).attr('href',url);
+});
+
+$link
+$end_page
+END
+ return;
+}
+
+sub redirect_user {
+ my ($r,$title,$url,$msg) = @_;
+ $msg = $title if (! defined($msg));
+ &Apache::loncommon::content_type($r,'text/html');
+ &Apache::loncommon::no_cache($r);
+ $r->send_http_header;
+
+ my $start_page;
+ if ($env{'request.lti.login'}) {
+ $start_page = &Apache::loncommon::start_page(undef,undef,
+ {'redirect' => [0,$url],}).$msg;
+ } else {
+ # Breadcrumbs
+ my $brcrum = [{'href' => $url,
+ 'text' => 'Switching Role'},];
+ $start_page = &Apache::loncommon::start_page('Switching Role',undef,
+ {'redirect' => [1,$url],
+ 'bread_crumbs' => $brcrum,}).
+ "\n$msg
";
+ }
+ my $end_page = &Apache::loncommon::end_page();
+
+# Note to style police:
+# This must only replace the spaces, nothing else, or it bombs elsewhere.
+ $url=~s/ /\%20/g;
+ $r->print(< 'Problems during Course Initialization',
+ tfp => 'The following problems occurred:',
+ con => 'Continue',
+ );
+ my $end_page = &Apache::loncommon::end_page();
+ $dest = &HTML::Entities::encode($dest,'"<>&');
+ $r->print(<$lt{'pdc'}
+$lt{'tfp'}
+
+$error
+
$lt{'con'}
+$end_page
+END
+ return;
+}
sub handler {
+
my $r = shift;
- $r->content_type('text/html');
- $r->send_http_header;
- return OK if $r->header_only;
-# ---------------------------------------------------------------- Print Header
- $r->print(<
-
-LON-CAPA User Roles
-ENDHEADER
- if ($ENV{'form.orgurl'}) {
- $r->print('');
+ # Check for critical messages and redirect if present.
+ my ($redirect,$url) = &Apache::loncommon::critical_redirect(300,'roles');
+ if ($redirect) {
+ &Apache::loncommon::content_type($r,'text/html');
+ $r->header_out(Location => $url);
+ return REDIRECT;
}
- $r->print('');
my $now=time;
- my $then=$ENV{'user.login.time'};
+ my $then=$env{'user.login.time'};
+ my $refresh=$env{'user.refresh.time'};
+ my $update=$env{'user.update.time'};
+ if (!$refresh) {
+ $refresh = $then;
+ }
+ if (!$update) {
+ $update = $then;
+ }
+
+ my ($norolelist,$blocked_by_ip,$blocked_type,$blocked_ipaddr);
+ if (($env{'request.course.id'}) && ($env{'request.deeplink.login'})) {
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
+ my $deeplink_symb = &Apache::loncommon::deeplink_login_symb($cnum,$cdom);
+ if ($deeplink_symb) {
+ my ($menucoll,$deeplinkmenu,$menuref) = &Apache::loncommon::menucoll_in_effect();
+ if (ref($menuref) eq 'HASH') {
+ unless (($menuref->{'role'}) || ($env{'request.role.adv'})) {
+ foreach my $envkey (keys(%env)) {
+ next unless ($envkey =~ /^form\./);
+ if ($envkey =~ m{\./($match_domain)/($match_courseid)(?:/(\w+)|$)}) {
+ unless (($1 eq $cdom) && ($2 eq $cnum)) {
+ delete($env{$envkey});
+ }
+ }
+ }
+ if ($env{'form.selectrole'}) {
+ if ($env{'form.switchrole'} =~ m{\./($match_domain)/($match_courseid)(?:/(\w+)|$)}) {
+ unless (($1 eq $cdom) && ($2 eq $cnum)) {
+ delete($env{'form.selectrole'});
+ delete($env{'form.switchrole'});
+ }
+ } elsif ($env{'form.newrole'} =~ m{\./($match_domain)/($match_courseid)(?:/(\w+)|$)}) {
+ unless (($1 eq $cdom) && ($2 eq $cnum)) {
+ delete($env{'form.selectrole'});
+ delete($env{'form.newrole'});
+ }
+ }
+ }
+ $norolelist = 1;
+ }
+ }
+ }
+ }
+
+ if ($env{'form.selectrole'}) {
+ my ($role,$cdom,$cnum,$rest);
+ if ($env{'form.switchrole'} =~ m{^(co|cc|in|ta|ep|ad|st|cr).*?\./($match_domain)/($match_courseid)(/(\w+)|$)}) {
+ ($role,$cdom,$cnum,$rest) = ($1,$2,$3,$4);
+ } elsif ($env{'form.newrole'} =~ m{^(co|cc|in|ta|ep|ad|st|cr).*?\./($match_domain)/($match_courseid)(/(\w+)|$)}) {
+ ($role,$cdom,$cnum,$rest) = ($1,$2,$3,$4);
+ }
+ if ($cdom ne '') {
+ my ($has_evb,$check_ipaccess,$showrole);
+ $showrole = 1;
+ my $checkrole = "cm./$cdom/$cnum";
+ if ($rest ne '') {
+ $checkrole .= "/$rest";
+ }
+ if ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) &&
+ ($role ne 'st')) {
+ $has_evb = 1;
+ }
+ unless ($has_evb) {
+ my @machinedoms = &Apache::lonnet::current_machine_domains();
+ my $udom = $env{'user.domain'};
+ if ($udom eq $cdom) {
+ $check_ipaccess = 1;
+ } elsif (($udom ne '') && (grep(/^\Q$udom\E$/,@machinedoms))) {
+ $check_ipaccess = 1;
+ } else {
+ my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};
+ my $internet_names = &Apache::lonnet::get_internet_names($lonhost);
+ my $cprim = &Apache::lonnet::domain($cdom,'primary');
+ my $cintdom = &Apache::lonnet::internet_dom($cprim);
+ if (($cintdom ne '') && (ref($internet_names) eq 'ARRAY')) {
+ if (grep(/^\Q$cintdom\E$/,@{$internet_names})) {
+ $check_ipaccess = 1;
+ }
+ }
+ }
+ if ($check_ipaccess) {
+ my ($ipaccessref,$cached)=&Apache::lonnet::is_cached_new('ipaccess',$cdom);
+ unless (defined($cached)) {
+ my %domconfig =
+ &Apache::lonnet::get_dom('configuration',['ipaccess'],$cdom);
+ $ipaccessref = &do_cache_new('ipaccess',$cdom,$domconfig{'ipaccess'},1800);
+ }
+ if (ref($ipaccessref) eq 'HASH') {
+ my $remote_ip = &Apache::lonnet::get_requestor_ip();
+ foreach my $id (keys(%{$ipaccessref})) {
+ if (ref($ipaccessref->{$id}) eq 'HASH') {
+ my $range = $ipaccessref->{$id}->{'ip'};
+ if ($range) {
+ my $type = 'exclude';
+ if (&Apache::lonnet::ip_match($remote_ip,$range)) {
+ $type = 'include';
+ }
+ if (ref($ipaccessref->{$id}->{'courses'}) eq 'HASH') {
+ if ($ipaccessref->{$id}->{'courses'}{$cdom.'_'.$cnum}) {
+ if ($type eq 'include') {
+ $showrole = 1;
+ last;
+ } else {
+ $showrole = 0;
+ }
+ } else {
+ if ($type eq 'include') {
+ $showrole = 0;
+ } else {
+ $showrole = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ unless ($showrole) {
+ $blocked_ipaddr = $remote_ip;
+ }
+ }
+ }
+ }
+ unless ($showrole) {
+ $blocked_by_ip = 1;
+ $blocked_type = &Apache::loncommon::course_type($cdom.'_'.$cnum);
+ delete($env{'form.selectrole'});
+ delete($env{'form.newrole'});
+ }
+ }
+ }
+
+ $registered_cleanup=0;
+ @{$rosterupdates}=();
+ &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'});
+
+# -------------------------------------------------- Check if setting hot list
+ my $hotlist;
+ if ($env{'form.action'} eq 'verify_and_change_rolespref') {
+ $hotlist = &Apache::lonpreferences::verify_and_change_rolespref($r);
+ }
+
+# -------------------------------------------------------- Check for new roles
+ my $updateresult;
+ if ($env{'form.state'} eq 'doupdate') {
+ my $show_course=&Apache::loncommon::show_course();
+ my $checkingtxt;
+ if ($show_course) {
+ $checkingtxt = &mt('Checking for new courses ...');
+ } else {
+ $checkingtxt = &mt('Checking for new roles ...');
+ }
+ $updateresult = $checkingtxt;
+ $updateresult .= &update_session_roles();
+ &Apache::lonnet::appenv({'user.update.time' => $now});
+ $update = $now;
+ &Apache::loncoursequeueadmin::reqauthor_check();
+ }
+
+# -------------------------------------------------- Check for author requests
+ my $reqauthor;
+ if ($env{'form.state'} eq 'requestauthor') {
+ $reqauthor = &Apache::loncoursequeueadmin::process_reqauthor(\$update);
+ }
+
my $envkey;
+ my %dcroles = ();
+ my %helpdeskroles = ();
+ my ($numdc,$numhelpdesk,$numadhoc) =
+ &check_for_adhoc(\%dcroles,\%helpdeskroles,$update,$then);
+ my $loncaparev = $r->dir_config('lonVersion');
# ================================================================== Roles Init
+ if ($env{'form.selectrole'}) {
+ if (($env{'request.lti.login'}) && ($env{'request.lti.target'} eq '')) {
+ if ($env{'form.ltitarget'} eq 'iframe') {
+ &Apache::lonnet::appenv({'request.lti.target' => 'iframe'});
+ delete($env{'form.ltitarget'});
+ }
+ }
- if ($ENV{'form.selectrole'}) {
- foreach $envkey (keys %ENV) {
- if ($envkey=~/^user\.role\./) {
- my ($dum1,$dum2,$role,@pwhere)=split(/\./,$envkey);
- my $where=join('.',@pwhere);
- my $trolecode=$role.'.'.$where;
- if ($ENV{'form.'.$trolecode}) {
- my ($tstart,$tend)=split(/\./,$ENV{$envkey});
- my $tstatus='is';
- if ($tstart) {
- if ($tstart>$then) {
- $tstatus='future';
- }
- }
- if ($tend) {
- if ($tend<$then) { $tstatus='expired'; }
- if ($tend>$now) { $tstatus='will_not'; }
- }
- if ($tstatus eq 'is') {
- &Apache::lonnet::appenv('request.role' => $trolecode);
- my ($cdom,$cnum)=split(/\//,$where);
- if ($cnum) {
- &Apache::lonuserstate::readmap($where);
- $r->print('Role initialized