File:  [LON-CAPA] / loncom / auth / lonslotcheck.pm
Revision 1.2: download - view: text, annotated - select for diffs
Fri Jul 7 03:52:40 2023 UTC (11 months ago) by raeburn
Branches: MAIN
CVS tags: version_2_12_X, version_2_11_4_msu, HEAD
- Bug 6754 LON-CAPA as LTI Consumer
  Support for access control using slots for both "gradable" and "non-gradable"
  external tools.

    1: # Checks slot access settings - disable subsequent 
    2: # PerlHandlers unless access availble
    3: # $Id: lonslotcheck.pm,v 1.2 2023/07/07 03:52:40 raeburn Exp $
    4: #
    5: # Copyright Michigan State University Board of Trustees
    6: #
    7: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    8: #
    9: # LON-CAPA is free software; you can redistribute it and/or modify
   10: # it under the terms of the GNU General Public License as published by
   11: # the Free Software Foundation; either version 2 of the License, or
   12: # (at your option) any later version.
   13: #
   14: # LON-CAPA is distributed in the hope that it will be useful,
   15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17: # GNU General Public License for more details.
   18: #
   19: # You should have received a copy of the GNU General Public License
   20: # along with LON-CAPA; if not, write to the Free Software
   21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22: #
   23: # /home/httpd/html/adm/gpl.txt
   24: #
   25: # http://www.lon-capa.org/
   26: #
   27: 
   28: package Apache::lonslotcheck;
   29: 
   30: use strict;
   31: use Apache::lonnet;
   32: use Apache::lonlocal;
   33: use Apache::loncommon();
   34: use Apache::structuretags();
   35: use Apache::lonhomework();
   36: use Apache::bridgetask();
   37: use Apache::Constants qw(:common :http :methods);
   38: 
   39: sub handler {
   40:     my ($r) = @_;
   41:     if (($r->uri !~ /ext\.tool$/) ||
   42:         (&Apache::lonnet::EXT('resource.0.gradable',$env{'request.symb'}) =~ /^yes$/i)) {
   43:         return DECLINED;
   44:     }
   45:     my ($symb,$courseid,$udom,$uname) = &Apache::lonnet::whichuser();
   46:     my $useslots = &Apache::lonnet::EXT("resource.0.useslots",$symb);
   47:     if ($useslots ne 'resource' && $useslots ne 'map'
   48:         && $useslots ne 'map_map') {
   49:         return DECLINED;
   50:     }
   51:     my ($status,$accessmsg,$slot_name,$slot,$ipused) = 
   52:         &check_slot_access($symb,$courseid,$udom,$uname);
   53: 
   54:     my $output;
   55:     if ($status eq 'CHECKED_IN') {
   56:         if ($slot_name ne '') {
   57:             my $checkin = 'resource.0.checkedin';
   58:             if (($Apache::lonhomework::history{$checkin}) &&
   59:                 ($Apache::lonhomework::history{"$checkin.slot"} eq $slot_name)) {
   60:                 &do_cleanup();
   61:                 return DECLINED;
   62:             } else {
   63:                 my $closedate = &Apache::lonnet::EXT("resource.0.contentclose",$symb,
   64:                                                      $udom,$uname);
   65:                 &Apache::structuretags::selfcheckin_resource($closedate,$slot_name,$slot,$symb);
   66:                 if ($Apache::lonhomework::results{$checkin}) {
   67:                     &Apache::structuretags::finalize_storage();
   68:                     &do_cleanup();
   69:                     return DECLINED;
   70:                 } else {
   71:                     $output = '<p class="LC_error">'.&mt('Error during self-checkin to slot').
   72:                               '</p>';
   73:                 }
   74:             }
   75:         } else {
   76:             $output = '<p class="LC_error">'.&mt('Error no slot available for self-checkin').
   77:                           '</p>';
   78:         }
   79:     } elsif ($status eq 'NEEDS_CHECKIN') {
   80:         if (defined($env{'form.submitted'}) && defined($env{'form.validate'})) {
   81:             if (&Apache::bridgetask::proctor_check_auth($slot_name,$slot)) {
   82:                 &Apache::structuretags::finalize_storage();
   83:                 &do_cleanup();
   84:                 return DECLINED;
   85:             } else {
   86:                 $output =  '<p class="LC_error">'.&mt('Check-in failed').'</p>'.
   87:                            &Apache::bridgetask::proctor_validation_screen($slot);
   88:             }
   89:         } else {
   90:             $output = &Apache::bridgetask::proctor_validation_screen($slot);
   91:         }
   92:     } elsif (( $status eq 'NOT_IN_A_SLOT' ) ||
   93:              ( $status eq 'NOTRESERVABLE') ||
   94:              ( $status eq 'RESERVABLE') ||
   95:              ( $status eq 'RESERVABLE_LATER') ||
   96:              ( $status eq 'NEED_DIFFERENT_IP')) {
   97:         $output = &Apache::structuretags::access_status_msg('tool',$status,$symb,
   98:                                                             'web',$ipused,$accessmsg);
   99:     }
  100: 
  101:     $r->set_handlers('PerlHandler'=>undef);
  102:     &Apache::loncommon::content_type($r,'text/html');
  103:     $r->send_http_header;
  104:     if ($r->header_only) {
  105:         &do_cleanup();
  106:         return OK;
  107:     }
  108: 
  109:     my $target;
  110:     my ($marker,$exttool) = (split(m{/},$r->uri))[4,5];
  111:     $marker=~s/\D//g;
  112:     if (($marker) && ($exttool) && ($env{'request.course.id'})) {
  113:         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
  114:         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
  115:         my ($idx,$crstool,$is_tool,%toolhash,%toolsettings);
  116:         if ($r->uri eq "/adm/$cdom/$cnum/$marker/$exttool") {
  117:             my %toolsettings=&Apache::lonnet::dump('exttool_'.$marker,$cdom,$cnum);
  118:             $target = $toolsettings{'target'};
  119:         }
  120:     }
  121:     my $args = {'bgcolor'        => '#FFFFFF',
  122:                 'force_register' => 1,};
  123:     if ($target eq 'iframe') {
  124:         $args->{'only_body'} = 1;
  125:     }
  126:     my $start_page =
  127:         &Apache::loncommon::start_page('Not Open',undef,$args);
  128:     my $end_page =
  129:         &Apache::loncommon::end_page({'discussion' => 1});
  130:         $r->print($start_page.$output.$end_page);
  131:     &do_cleanup();
  132:     return OK;
  133: }
  134: 
  135: sub check_slot_access {
  136:     my ($symb,$courseid,$udom,$uname) = @_;
  137:     &Apache::structuretags::initialize_storage($symb);
  138:     my $checkin = 'resource.0.checkedin';
  139:     my $checkedin = $Apache::lonhomework::history{$checkin};
  140:     my ($returned_slot,$slot_name,$checkinslot,$ipused,$blockip,$now,$ip,
  141:         $consumed_uniq);
  142:     $now = time;
  143:     $ip=$ENV{'REMOTE_ADDR'} || $env{'request.host'};
  144:     if ($checkedin) {
  145:         $checkinslot = $Apache::lonhomework::history{"$checkin.slot"};
  146:         my %slot=&Apache::lonnet::get_slot($checkinslot);
  147:         $consumed_uniq = $slot{'uniqueperiod'};
  148:         if ($slot{'iptied'}) {
  149:             $ipused = $Apache::lonhomework::history{"$checkin.ip"};
  150:             unless (($ip ne '') && ($ipused eq $ip)) {
  151:                 $blockip = $slot{'iptied'};
  152:                 $slot_name = $checkinslot;
  153:                 $returned_slot = \%slot;
  154:                 return ('NEED_DIFFERENT_IP','',$slot_name,$returned_slot,$ipused);
  155:             }
  156:         }
  157:     }
  158: 
  159:     my $availablestudent = &Apache::lonnet::EXT("resource.0.availablestudent",$symb);
  160:     my $available = &Apache::lonnet::EXT("resource.0.available",$symb);
  161:     my @slots= (split(':',$availablestudent),split(':',$available));
  162: 
  163:     my $slotstatus='NOT_IN_A_SLOT';
  164:     my $num_usable_slots = 0;
  165:     my $datemsg;
  166: 
  167:     foreach my $slot (@slots) {
  168:         $slot =~ s/(^\s*|\s*$)//g;
  169:         my %slot=&Apache::lonnet::get_slot($slot);
  170:         next if ($slot{'endtime'} < $now);
  171:         $num_usable_slots ++;
  172:         if ($slot{'starttime'} < $now &&
  173:             $slot{'endtime'} > $now &&
  174:             &Apache::loncommon::check_ip_acc($slot{'ip'})) {
  175:             if ($slot{'iptied'}) {
  176:                 if ($env{'request.course.id'}) {
  177:                     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
  178:                     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
  179:                     if ($slot eq $checkinslot) {
  180:                         if ($ip eq $ipused) {
  181:                             $slotstatus ='NEEDS_CHECKIN';
  182:                         } else {
  183:                             $slotstatus = 'NEED_DIFFERENT_IP';
  184:                             $slot_name = $slot;
  185:                             $returned_slot = \%slot;
  186:                             last;
  187:                         }
  188:                     } elsif ($ip) {
  189:                         my $uniqkey = "$slot\0$symb\0$ip";
  190:                         my %used_ip = &Apache::lonnet::get('slot_uniqueips',[$uniqkey],$cdom,$cnum);
  191:                         if ($used_ip{$uniqkey}) {
  192:                             $slotstatus = 'NEED_DIFFERENT_IP';
  193:                         } else {
  194:                             $slotstatus ='NEEDS_CHECKIN';
  195:                         }
  196:                     }
  197:                 }
  198:             } else {
  199:                 $slotstatus='NEEDS_CHECKIN';
  200:             }
  201:             if ($slotstatus eq 'NEEDS_CHECKIN') {
  202:                 $returned_slot=\%slot;
  203:                 $slot_name=$slot;
  204:                 last;
  205:             }
  206:         }
  207:     }
  208: 
  209:     if (($slotstatus eq 'NEEDS_CHECKIN') && (ref($returned_slot) eq 'HASH')) {
  210:         if (&Apache::lonhomework::proctor_checked_in($slot_name,$returned_slot,'tool')) {
  211:             $slotstatus = 'CHECKED_IN';
  212:             return ($slotstatus,$datemsg,$slot_name,$returned_slot,$ipused);
  213:         }
  214:     }
  215: 
  216:     # Previously used slot is no longer open, and has been checked in.
  217:     # However, the resource is not closed, and potentially, another slot might be
  218:     # used to gain access to it, until the content close date is reached.
  219:     # Therefore return the slotstatus -
  220:     # (which will be one of: NOT_IN_A_SLOT, RESERVABLE, RESERVABLE_LATER, or NOTRESERVABLE).
  221: 
  222:     if (!defined($slot_name)) {
  223:         if ($slotstatus eq 'NOT_IN_A_SLOT') {
  224:             if (!$num_usable_slots) {
  225:                 ($slotstatus,$datemsg) = &Apache::lonhomework::check_reservable_slot($slotstatus,$symb,$now,
  226:                                                                                      $checkedin,$consumed_uniq);
  227:             }
  228:         }
  229:     }
  230:     return ($slotstatus,$datemsg,$slot_name,$returned_slot,$ipused);
  231: }
  232: 
  233: sub do_cleanup {
  234:     undef(%Apache::lonhomework::results);
  235:     undef(%Apache::lonhomework::history);
  236: }
  237: 
  238: 1;

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>