Diff for /loncom/interface/loncreatecourse.pm between versions 1.95 and 1.96

version 1.95, 2006/07/20 22:09:36 version 1.96, 2006/08/11 22:00:08
Line 37  use Apache::lonratedt; Line 37  use Apache::lonratedt;
 use Apache::londocs;  use Apache::londocs;
 use Apache::lonlocal;  use Apache::lonlocal;
 use Apache::londropadd;  use Apache::londropadd;
   use Apache::lonclonecourse;
 use LONCAPA::batchcreatecourse;  use LONCAPA::batchcreatecourse;
 use lib '/home/httpd/lib/perl';  
 use LONCAPA;  use LONCAPA;
   
 # ================================================ Get course directory listing  
   
 my @output=();  
   
 sub crsdirlist {  
     my ($courseid,$which)=@_;  
     @output=();  
     return &innercrsdirlist($courseid,$which);  
 }  
   
 sub innercrsdirlist {  
     my ($courseid,$which,$path)=@_;  
     my $dirptr=16384;  
     unless ($which) { $which=''; } else { $which.='/'; }  
     unless ($path)  { $path=''; } else { $path.='/'; }  
     my %crsdata=&Apache::lonnet::coursedescription($courseid);  
     my @listing=&Apache::lonnet::dirlist  
  ($which,$crsdata{'domain'},$crsdata{'num'},  
  &propath($crsdata{'domain'},$crsdata{'num'}));  
     foreach (@listing) {  
  unless ($_=~/^\./) {  
     my @unpackline = split (/\&/,$_);  
     if ($unpackline[3]&$dirptr) {  
 # is a directory, recurse  
  &innercrsdirlist($courseid,$which.$unpackline[0],  
             $path.$unpackline[0]);  
     } else {   
 # is a file, put into output  
  push (@output,$path.$unpackline[0]);  
     }  
  }  
     }  
     return @output;  
 }  
   
 # ============================================================= Read a userfile  
   
 sub readfile {  
     my ($courseid,$which)=@_;  
     my %crsdata=&Apache::lonnet::coursedescription($courseid);  
     return &Apache::lonnet::getfile('/uploaded/'.$crsdata{'domain'}.'/'.  
     $crsdata{'num'}.'/'.$which);  
 }  
   
 # ============================================================ Write a userfile  
   
 sub writefile {  
     (my $courseid, my $which,$env{'form.output'})=@_;  
     my %crsdata=&Apache::lonnet::coursedescription($courseid);  
     return &Apache::lonnet::finishuserfileupload(  
   $crsdata{'num'},$crsdata{'domain'},  
   'output',$which);  
 }  
   
 # ===================================================================== Rewrite  
   
 sub rewritefile {  
     my ($contents,%rewritehash)=@_;  
     foreach (keys %rewritehash) {  
  my $pattern=$_;  
  $pattern=~s/(\W)/\\$1/gs;  
  my $new=$rewritehash{$_};  
  $contents=~s/$pattern/$new/gs;  
     }  
     return $contents;  
 }  
   
 # ============================================================= Copy a userfile  
   
 sub copyfile {  
     my ($origcrsid,$newcrsid,$which)=@_;  
     unless ($which=~/\.sequence$/) {  
  return &writefile($newcrsid,$which,  
       &readfile($origcrsid,$which));  
     } else {  
  my %origcrsdata=&Apache::lonnet::coursedescription($origcrsid);  
  my %newcrsdata= &Apache::lonnet::coursedescription($newcrsid);  
  return &writefile($newcrsid,$which,  
  &rewritefile(  
                      &readfile($origcrsid,$which),  
     (  
        '/uploaded/'.$origcrsdata{'domain'}.'/'.$origcrsdata{'num'}.'/'  
     => '/uploaded/'. $newcrsdata{'domain'}.'/'. $newcrsdata{'num'}.'/',  
        '/public/'.$origcrsdata{'domain'}.'/'.$origcrsdata{'num'}.'/'  
     => '/public/'. $newcrsdata{'domain'}.'/'. $newcrsdata{'num'}.'/'  
             )));  
     }  
 }  
   
 # =============================================================== Copy a dbfile  
   
 sub copydb {  
     my ($origcrsid,$newcrsid,$which)=@_;  
     $which=~s/\.db$//;  
     my %origcrsdata=&Apache::lonnet::coursedescription($origcrsid);  
     my %newcrsdata= &Apache::lonnet::coursedescription($newcrsid);  
     my %data=&Apache::lonnet::dump  
  ($which,$origcrsdata{'domain'},$origcrsdata{'num'});  
     foreach my $key (keys(%data)) {  
  if ($key=~/^internal./) { delete($data{$key}); }  
     }  
     return &Apache::lonnet::put  
  ($which,\%data,$newcrsdata{'domain'},$newcrsdata{'num'});  
 }  
   
 # ========================================================== Copy resourcesdata  
   
 sub copyresourcedb {  
     my ($origcrsid,$newcrsid)=@_;  
     my %origcrsdata=&Apache::lonnet::coursedescription($origcrsid);  
     my %newcrsdata= &Apache::lonnet::coursedescription($newcrsid);  
     my %data=&Apache::lonnet::dump  
  ('resourcedata',$origcrsdata{'domain'},$origcrsdata{'num'});  
     $origcrsid=~s/^\///;  
     $origcrsid=~s/\//\_/;  
     $newcrsid=~s/^\///;  
     $newcrsid=~s/\//\_/;  
     my %newdata=();  
     undef %newdata;  
     my $startdate=$data{$origcrsid.'.0.opendate'};  
     if (!$startdate) {  
  # now global start date for assements try the enrollment start  
  my %start=&Apache::lonnet::get('environment',  
    ['default_enrollment_start_date'],  
    $origcrsdata{'domain'},$origcrsdata{'num'});  
   
  $startdate = $start{'default_enrollment_start_date'};  
     }  
     my $today=time;  
     my $delta=0;  
     if ($startdate) {  
  my $oneday=60*60*24;  
  $delta=$today-$startdate;  
  $delta=int($delta/$oneday)*$oneday;  
     }  
 # ugly retro fix for broken version of types  
     foreach (keys %data) {  
  if ($_=~/\wtype$/) {  
     my $newkey=$_;  
     $newkey=~s/type$/\.type/;  
     $data{$newkey}=$data{$_};  
     delete $data{$_};  
  }  
     }  
 # adjust symbs  
     my $pattern='uploaded/'.$origcrsdata{'domain'}.'/'.$origcrsdata{'num'}.'/';  
     $pattern=~s/(\W)/\\$1/gs;  
     my $new=    'uploaded/'. $newcrsdata{'domain'}.'/'. $newcrsdata{'num'}.'/';  
     foreach (keys %data) {  
  if ($_=~/$pattern/) {  
     my $newkey=$_;  
     $newkey=~s/$pattern/$new/;  
     $data{$newkey}=$data{$_};  
     delete $data{$_};  
  }  
     }  
 # adjust dates  
     foreach (keys %data) {  
  my $thiskey=$_;  
  $thiskey=~s/^$origcrsid/$newcrsid/;  
  $newdata{$thiskey}=$data{$_};  
  if ($data{$_.'.type'}=~/^date_(start|end)$/) {  
     if ($delta > 0) {  
  $newdata{$thiskey}=$newdata{$thiskey}+$delta;  
     } else {  
  # no delta, it's unlikely we want the old dates and times  
  delete($newdata{$thiskey});  
  delete($newdata{$thiskey.'.type'});  
     }  
  }  
     }  
     return &Apache::lonnet::put  
  ('resourcedata',\%newdata,$newcrsdata{'domain'},$newcrsdata{'num'});  
 }  
   
 # ========================================================== Copy all userfiles  
   
 sub copyuserfiles {  
     my ($origcrsid,$newcrsid)=@_;  
     foreach (&crsdirlist($origcrsid,'userfiles')) {  
  if ($_ !~m|^scantron_|) {  
     &copyfile($origcrsid,$newcrsid,$_);  
  }  
     }  
 }  
 # ========================================================== Copy all userfiles  
   
 sub copydbfiles {  
     my ($origcrsid,$newcrsid)=@_;  
   
     my ($origcrs_discussion) = ($origcrsid=~m|^/(.*)|);  
     $origcrs_discussion=~s|/|_|g;  
     foreach (&crsdirlist($origcrsid)) {  
  if ($_=~/\.db$/) {  
     unless   
              ($_=~/^(nohist\_|discussiontimes|classlist|versionupdate|resourcedata|\Q$origcrs_discussion\E|slots|slot_reservations|gradingqueue|reviewqueue|CODEs|groupmembership)/) {  
  &copydb($origcrsid,$newcrsid,$_);  
      }  
  }  
     }  
 }  
   
 # ======================================================= Copy all course files  
   
 sub copycoursefiles {  
     my ($origcrsid,$newcrsid)=@_;  
     &copyuserfiles($origcrsid,$newcrsid);  
     &copydbfiles($origcrsid,$newcrsid);  
     &copyresourcedb($origcrsid,$newcrsid);  
 }  
   
 # ===================================================== Phase one: fill-in form  # ===================================================== Phase one: fill-in form
   
 sub print_course_creation_page {  sub print_course_creation_page {
Line 884  sub create_course { Line 673  sub create_course {
         return;          return;
     }      }
     my ($courseid,$crsudom,$crsunum);      my ($courseid,$crsudom,$crsunum);
     $r->print(&construct_course($args,\$logmsg,\$courseid,\$crsudom,\$crsunum,$env{'user.domain'},$env{'user.name'}));      $r->print(&Apache::loncommon::construct_course($args,\$logmsg,\$courseid,\$crsudom,\$crsunum,$env{'user.domain'},$env{'user.name'}));
   
 #  #
 # Make the requested user a course coordinator or group coordinator  # Make the requested user a course coordinator or group coordinator
Line 907  sub create_course { Line 696  sub create_course {
       &Apache::loncommon::end_page());        &Apache::loncommon::end_page());
 }  }
   
 sub construct_course {  
     my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname) = @_;  
     my $outcome;  
   
 #  
 # Open course  
 #  
     my $crstype = lc($args->{'crstype'});  
     my %cenv=();  
     $$courseid=&Apache::lonnet::createcourse($args->{'course_domain'},  
                                              $args->{'cdescr'},  
                                              $args->{'curl'},  
                                              $args->{'course_home'},  
                                              $args->{'nonstandard'},  
                                              $args->{'crscode'},  
                                              $args->{'ccuname'}.':'.  
                                              $args->{'ccdomain'},  
                                              $args->{'crstype'});  
   
     # Note: The testing routines depend on this being output; see   
     # Utils::Course. This needs to at least be output as a comment  
     # if anyone ever decides to not show this, and Utils::Course::new  
     # will need to be suitably modified.  
     $outcome .= &mt('New LON-CAPA [_1] ID: [_2]<br />',$crstype,$$courseid);  
 #  
 # Check if created correctly  
 #  
     ($$crsudom,$$crsunum)=($$courseid=~/^\/(\w+)\/(\w+)$/);  
     my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom);  
     $outcome .= &mt('Created on').': '.$crsuhome.'<br>';  
 #  
 # Are we cloning?  
 #  
     my $cloneid='';  
     if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {  
  $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};  
         my ($clonecrsudom,$clonecrsunum)=($cloneid=~/^\/(\w+)\/(\w+)$/);  
  my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);  
  if ($clonehome eq 'no_host') {  
     $outcome .=  
     '<br /><font color="red">'.&mt('Attempting to clone non-existing [_1]',$crstype).' '.$cloneid.'</font>';  
  } else {  
     $outcome .=   
     '<br /><font color="green">'.&mt('Cloning [_1] from [_2]',$crstype,$clonehome).'</font>';  
     my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);  
 # Copy all files  
     &copycoursefiles($cloneid,$$courseid);  
 # Restore URL  
     $cenv{'url'}=$oldcenv{'url'};  
 # Restore title  
     $cenv{'description'}=$oldcenv{'description'};  
 # restore grading mode  
     if (defined($oldcenv{'grading'})) {  
  $cenv{'grading'}=$oldcenv{'grading'};  
     }  
 # Mark as cloned  
     $cenv{'clonedfrom'}=$cloneid;  
     delete($cenv{'default_enrollment_start_date'});  
     delete($cenv{'default_enrollment_end_date'});  
  }  
     }  
 #  
 # Set environment (will override cloned, if existing)  
 #  
     my @sections = ();  
     my @xlists = ();  
     if ($args->{'crstype'}) {  
         $cenv{'type'}=$args->{'crstype'};  
     }  
     if ($args->{'crsid'}) {  
         $cenv{'courseid'}=$args->{'crsid'};  
     }  
     if ($args->{'crscode'}) {  
         $cenv{'internal.coursecode'}=$args->{'crscode'};  
     }  
     if ($args->{'crsquota'} ne '') {  
         $cenv{'internal.coursequota'}=$args->{'crsquota'};  
     } else {  
         $cenv{'internal.coursequota'}=$args->{'crsquota'} = 20;  
     }  
     if ($args->{'ccuname'}) {  
         $cenv{'internal.courseowner'} = $args->{'ccuname'}.  
                                         ':'.$args->{'ccdomain'};  
     } else {  
         $cenv{'internal.courseowner'} = $args->{'curruser'};  
     }  
   
     my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.  
     if ($args->{'crssections'}) {  
         $cenv{'internal.sectionnums'} = '';  
         if ($args->{'crssections'} =~ m/,/) {  
             @sections = split/,/,$args->{'crssections'};  
         } else {  
             $sections[0] = $args->{'crssections'};  
         }  
         if (@sections > 0) {  
             foreach my $item (@sections) {  
                 my ($sec,$gp) = split/:/,$item;  
                 my $class = $args->{'crscode'}.$sec;  
                 my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'});  
                 $cenv{'internal.sectionnums'} .= $item.',';  
                 unless ($addcheck eq 'ok') {  
                     push @badclasses, $class;  
                 }  
             }  
             $cenv{'internal.sectionnums'} =~ s/,$//;  
         }  
     }  
 # do not hide course coordinator from staff listing,   
 # even if privileged  
     $cenv{'nothideprivileged'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};  
 # add crosslistings  
     if ($args->{'crsxlist'}) {  
         $cenv{'internal.crosslistings'}='';  
         if ($args->{'crsxlist'} =~ m/,/) {  
             @xlists = split/,/,$args->{'crsxlist'};  
         } else {  
             $xlists[0] = $args->{'crsxlist'};  
         }  
         if (@xlists > 0) {  
             foreach my $item (@xlists) {  
                 my ($xl,$gp) = split/:/,$item;  
                 my $addcheck =  &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'});  
                 $cenv{'internal.crosslistings'} .= $item.',';  
                 unless ($addcheck eq 'ok') {  
                     push @badclasses, $xl;  
                 }  
             }  
             $cenv{'internal.crosslistings'} =~ s/,$//;  
         }  
     }  
     if ($args->{'autoadds'}) {  
         $cenv{'internal.autoadds'}=$args->{'autoadds'};  
     }  
     if ($args->{'autodrops'}) {  
         $cenv{'internal.autodrops'}=$args->{'autodrops'};  
     }  
 # check for notification of enrollment changes  
     my @notified = ();  
     if ($args->{'notify_owner'}) {  
         if ($args->{'ccuname'} ne '') {  
             push(@notified,$args->{'ccuname'}.':'.$args->{'ccdomain'});  
         }  
     }  
     if ($args->{'notify_dc'}) {  
         if ($uname ne '') {   
             push(@notified,$uname.'@'.$udom);  
         }  
     }  
     if (@notified > 0) {  
         my $notifylist;  
         if (@notified > 1) {  
             $notifylist = join(',',@notified);  
         } else {  
             $notifylist = $notified[0];  
         }  
         $cenv{'internal.notifylist'} = $notifylist;  
     }  
     if (@badclasses > 0) {  
         my %lt=&Apache::lonlocal::texthash(  
                 'tclb' => 'The courses listed below were included as sections or crosslistings affiliated with your new LON-CAPA course.  However, if automated course roster updates are enabled for this class, these particular sections/crosslistings will not contribute towards enrollment, because the user identified as the course owner for this LON-CAPA course',  
                 'dnhr' => 'does not have rights to access enrollment in these classes',  
                 'adby' => 'as determined by the policies of your institution on access to official classlists'  
         );  
         $outcome .= '<font color="red">'.$lt{'tclb'}.' ('.$cenv{'internal.courseowner'}.') - '.$lt{'dnhr'}.' ('.$lt{'adby'}.').<br /><ul>'."\n";  
         foreach (@badclasses) {  
             $outcome .= "<li>$_</li>\n";  
         }  
         $outcome .= "</ul><br /><br /></font>\n";  
     }  
     if ($args->{'no_end_date'}) {  
         $args->{'endaccess'} = 0;  
     }  
     $cenv{'internal.autostart'}=$args->{'enrollstart'};  
     $cenv{'internal.autoend'}=$args->{'enrollend'};  
     $cenv{'default_enrollment_start_date'}=$args->{'startaccess'};  
     $cenv{'default_enrollment_end_date'}=$args->{'endaccess'};  
     if ($args->{'showphotos'}) {  
       $cenv{'internal.showphotos'}=$args->{'showphotos'};  
     }  
     $cenv{'internal.authtype'} = $args->{'authtype'};  
     $cenv{'internal.autharg'} = $args->{'autharg'};   
     if ( ($cenv{'internal.authtype'} =~ /^krb/) && ($cenv{'internal.autoadds'} == 1)) {  
         if (! defined($cenv{'internal.autharg'}) || $cenv{'internal.autharg'}  eq '') {  
             $outcome .= '<font color="red" size="+1">'.  
                       &mt('As you did not include the default Kerberos domain to be used for authentication in this class, the institutional data used by the automated enrollment process must include the Kerberos domain for each new student').'</font></p>';  
         }  
     }  
     if (($args->{'ccdomain'}) && ($args->{'ccuname'})) {  
        if ($args->{'setpolicy'}) {  
            $cenv{'policy.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};  
        }  
        if ($args->{'setcontent'}) {  
            $cenv{'question.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};  
        }  
     }  
     if ($args->{'reshome'}) {  
  $cenv{'reshome'}=$args->{'reshome'}.'/';  
  $cenv{'reshome'}=~s/\/+$/\//;  
     }  
 #  
 # course has keyed access  
 #  
     if ($args->{'setkeys'}) {  
        $cenv{'keyaccess'}='yes';  
     }  
 # if specified, key authority is not course, but user  
 # only active if keyaccess is yes  
     if ($args->{'keyauth'}) {  
  $args->{'keyauth'}=~s/[^\w\@]//g;  
  if ($args->{'keyauth'}) {  
     $cenv{'keyauth'}=$args->{'keyauth'};  
  }  
     }  
   
     if ($args->{'disresdis'}) {  
         $cenv{'pch.roles.denied'}='st';  
     }  
     if ($args->{'disablechat'}) {  
         $cenv{'plc.roles.denied'}='st';  
     }  
   
     # Record we've not yet viewed the Course Initialization Helper for this   
     # course  
     $cenv{'course.helper.not.run'} = 1;  
     #  
     # Use new Randomseed  
     #  
     $cenv{'rndseed'}=&Apache::lonnet::latest_rnd_algorithm_id();;  
     $cenv{'receiptalg'}=&Apache::lonnet::latest_receipt_algorithm_id();;  
     #  
     # The encryption code and receipt prefix for this course  
     #  
     $cenv{'internal.encseed'}=$Apache::lonnet::perlvar{'lonReceipt'}.$$.time.int(rand(9999));  
     $cenv{'internal.encpref'}=100+int(9*rand(99));  
     #  
     # By default, use standard grading  
     if (!defined($cenv{'grading'})) { $cenv{'grading'} = 'standard'; }  
   
     $outcome .= ('<br />'.&mt('Setting environment').': '.                   
           &Apache::lonnet::put('environment',\%cenv,$$crsudom,$$crsunum).'<br>');  
 #  
 # Open all assignments  
 #  
     if ($args->{'openall'}) {  
        my $storeunder=$$crsudom.'_'.$$crsunum.'.0.opendate';  
        my %storecontent = ($storeunder         => time,  
                            $storeunder.'.type' => 'date_start');  
          
        $outcome .= &mt('Opening all assignments').': '.&Apache::lonnet::cput  
                  ('resourcedata',\%storecontent,$$crsudom,$$crsunum).'<br>';  
    }  
 #  
 # Set first page  
 #  
     unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank')  
     || ($cloneid)) {  
  $outcome .= &mt('Setting first resource').': ';  
         my ($errtext,$fatal)=  
            &Apache::londocs::mapread($$crsunum,$$crsudom,'default.sequence');  
         $outcome .= ($fatal?$errtext:'read ok').' - ';  
         my $title; my $url;  
         if ($args->{'firstres'} eq 'syl') {  
     $title='Syllabus';  
             $url='/public/'.$$crsudom.'/'.$$crsunum.'/syllabus';  
         } else {  
             $title='Navigate Contents';  
             $url='/adm/navmaps';  
         }  
         $Apache::lonratedt::resources[1]=$title.':'.$url.':false:start:res';  
         ($errtext,$fatal)=  
            &Apache::londocs::storemap($$crsunum,$$crsudom,'default.sequence');  
         $outcome .= ($fatal?$errtext:'write ok').'<br>';  
     }  
     return $outcome;  
 }  
   
 sub print_intro_page {  sub print_intro_page {
     my $r = shift;      my $r = shift;
     my $start_page =      my $start_page =

Removed from v.1.95  
changed lines
  Added in v.1.96


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