--- loncom/lonnet/perl/lonnet.pm 2006/05/18 01:08:54 1.739 +++ loncom/lonnet/perl/lonnet.pm 2006/06/07 21:15:10 1.746 @@ -1,7 +1,7 @@ # The LearningOnline Network # TCP networking package # -# $Id: lonnet.pm,v 1.739 2006/05/18 01:08:54 raeburn Exp $ +# $Id: lonnet.pm,v 1.746 2006/06/07 21:15:10 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -38,7 +38,7 @@ use vars qw(%perlvar %hostname %badServerCache %iphost %spareid %hostdom %libserv %pr %prp $memcache %packagetab %courselogs %accesshash %userrolehash %domainrolehash $processmarker $dumpcount - %coursedombuf %coursenumbuf %coursehombuf %coursedescrbuf %courseinstcodebuf %courseownerbuf + %coursedombuf %coursenumbuf %coursehombuf %coursedescrbuf %courseinstcodebuf %courseownerbuf %coursetypebuf %domaindescription %domain_auth_def %domain_auth_arg_def %domain_lang_def %domain_city %domain_longi %domain_lati %domain_primary $tmpdir $_64bit %env); @@ -52,6 +52,9 @@ use Storable qw(lock_store lock_nstore l use Time::HiRes qw( gettimeofday tv_interval ); use Cache::Memcached; use Digest::MD5; +use lib '/home/httpd/lib/perl'; +use LONCAPA; +use LONCAPA::Configuration; my $readit; my $max_connection_retries = 10; # Or some such value. @@ -1384,7 +1387,22 @@ sub userfileupload { open(my $fh,'>'.$fullpath.'/'.$fname); print $fh $env{'form.'.$formname}; close($fh); - return $fullpath.'/'.$fname; + return $fullpath.'/'.$fname; + } elsif (($formname eq 'coursecreatorxml') && ($subdir eq 'batchupload')) { #files uploaded to create course page are handled differently + my $filepath = 'tmp/addcourse/'.$destudom.'/web/'.$env{'user.name'}. + '_'.$env{'user.domain'}.'/pending'; + my @parts=split(/\//,$filepath); + my $fullpath = $perlvar{'lonDaemons'}; + for (my $i=0;$i<@parts;$i++) { + $fullpath .= '/'.$parts[$i]; + if ((-e $fullpath)!=1) { + mkdir($fullpath,0777); + } + } + open(my $fh,'>'.$fullpath.'/'.$fname); + print $fh $env{'form.'.$formname}; + close($fh); + return $fullpath.'/'.$fname; } # Create the directory if not present @@ -1648,11 +1666,11 @@ sub flushcourselogs { if ($courseidbuffer{$coursehombuf{$crsid}}) { $courseidbuffer{$coursehombuf{$crsid}}.='&'. &escape($crsid).'='.&escape($coursedescrbuf{$crsid}). - ':'.&escape($courseinstcodebuf{$crsid}).':'.&escape($courseownerbuf{$crsid}); + ':'.&escape($courseinstcodebuf{$crsid}).':'.&escape($courseownerbuf{$crsid}).':'.&escape($coursetypebuf{$crsid}); } else { $courseidbuffer{$coursehombuf{$crsid}}= &escape($crsid).'='.&escape($coursedescrbuf{$crsid}). - ':'.&escape($courseinstcodebuf{$crsid}).':'.&escape($courseownerbuf{$crsid}); + ':'.&escape($courseinstcodebuf{$crsid}).':'.&escape($courseownerbuf{$crsid}).':'.&escape($coursetypebuf{$crsid}); } } # @@ -1755,6 +1773,8 @@ sub courselog { $env{'course.'.$env{'request.course.id'}.'.internal.coursecode'}; $courseownerbuf{$env{'request.course.id'}}= $env{'course.'.$env{'request.course.id'}.'.internal.courseowner'}; + $coursetypebuf{$env{'request.course.id'}}= + $env{'course.'.$env{'request.course.id'}.'.type'}; if (defined $courselogs{$env{'request.course.id'}}) { $courselogs{$env{'request.course.id'}}.='&'.$what; } else { @@ -1925,7 +1945,7 @@ sub courseidput { } sub courseiddump { - my ($domfilter,$descfilter,$sincefilter,$instcodefilter,$ownerfilter,$coursefilter,$hostidflag,$hostidref)=@_; + my ($domfilter,$descfilter,$sincefilter,$instcodefilter,$ownerfilter,$coursefilter,$hostidflag,$hostidref,$typefilter)=@_; my %returnhash=(); unless ($domfilter) { $domfilter=''; } foreach my $tryserver (keys %libserv) { @@ -1934,7 +1954,7 @@ sub courseiddump { foreach ( split(/\&/,&reply('courseiddump:'.$hostdom{$tryserver}.':'. $sincefilter.':'.&escape($descfilter).':'. - &escape($instcodefilter).':'.&escape($ownerfilter).':'.&escape($coursefilter), + &escape($instcodefilter).':'.&escape($ownerfilter).':'.&escape($coursefilter).':'.&escape($typefilter), $tryserver))) { my ($key,$value)=split(/\=/,$_); if (($key) && ($value)) { @@ -1952,8 +1972,8 @@ sub courseiddump { sub dcmailput { my ($domain,$msgid,$message,$server)=@_; my $status = &Apache::lonnet::critical( - 'dcmailput:'.$domain.':'.&Apache::lonnet::escape($msgid).'='. - &Apache::lonnet::escape($message),$server); + 'dcmailput:'.$domain.':'.&escape($msgid).'='. + &escape($message),$server); return $status; } @@ -2637,6 +2657,9 @@ sub coursedescription { $returnhash{'home'}= $chome; $returnhash{'domain'} = $cdomain; $returnhash{'num'} = $cnum; + if (!defined($returnhash{'type'})) { + $returnhash{'type'} = 'Course'; + } while (my ($name,$value) = each %returnhash) { $envhash{'course.'.$normalid.'.'.$name}=$value; } @@ -2693,7 +2716,7 @@ sub rolesinit { my %allroles=(); my %allgroups=(); my $now=time; - my $userroles="user.login.time=$now\n"; + my %userroles = ('user.login.time' => $now); my $group_privs; if ($rolesdump ne '') { @@ -2716,7 +2739,9 @@ sub rolesinit { } else { ($trole,$tend,$tstart)=split(/_/,$role); } - $userroles.=&set_arearole($trole,$area,$tstart,$tend,$domain,$username); + my %new_role = &set_arearole($trole,$area,$tstart,$tend,$domain, + $username); + @userroles{keys(%new_role)} = @new_role{keys(%new_role)}; if (($tend!=0) && ($tend<$now)) { $trole=''; } if (($tstart!=0) && ($tstart>$now)) { $trole=''; } if (($area ne '') && ($trole ne '')) { @@ -2732,19 +2757,19 @@ sub rolesinit { } } } - my ($author,$adv) = &set_userprivs(\$userroles,\%allroles,\%allgroups); - $userroles.='user.adv='.$adv."\n". - 'user.author='.$author."\n"; + my ($author,$adv) = &set_userprivs(\%userroles,\%allroles,\%allgroups); + $userroles{'user.adv'} = $adv; + $userroles{'user.author'} = $author; $env{'user.adv'}=$adv; } - return $userroles; + return \%userroles; } sub set_arearole { my ($trole,$area,$tstart,$tend,$domain,$username) = @_; # log the associated role with the area &userrolelog($trole,$username,$domain,$area,$tstart,$tend); - return 'user.role.'.$trole.'.'.$area.'='.$tstart.'.'.$tend."\n"; + return ('user.role.'.$trole.'.'.$area => $tstart.'.'.$tend); } sub custom_roleprivs { @@ -2846,7 +2871,7 @@ sub set_userprivs { } my $thesestr=''; foreach (keys %thesepriv) { $thesestr.=':'.$_.'&'.$thesepriv{$_}; } - $$userroles.='user.priv.'.$_.'='.$thesestr."\n"; + $userroles->{'user.priv.'.$_} = $thesestr; } return ($author,$adv); } @@ -4074,8 +4099,25 @@ sub devalidate_getgroups_cache { # ------------------------------------------------------------------ Plain Text sub plaintext { - my $short=shift; - return &Apache::lonlocal::mt($prp{$short}); + my ($short,$type,$cid) = @_; + if (!defined($cid)) { + $cid = $env{'request.course.id'}; + } + if (defined($cid) && defined($env{'course.'.$cid.'.'.$short.'.plaintext'})) { + return &Apache::lonlocal::mt($env{'course.'.$cid.'.'.$short. + '.plaintext'}); + } + my %rolenames = ( + Course => 'std', + Group => 'alt1', + ); + if (defined($type) && + defined($rolenames{$type}) && + defined($prp{$short}{$rolenames{$type}})) { + return &Apache::lonlocal::mt($prp{$short}{$rolenames{$type}}); + } else { + return &Apache::lonlocal::mt($prp{$short}{'std'}); + } } # ----------------------------------------------------------------- Assign Role @@ -4404,7 +4446,8 @@ sub writecoursepref { # ---------------------------------------------------------- Make/modify course sub createcourse { - my ($udom,$description,$url,$course_server,$nonstandard,$inst_code,$course_owner)=@_; + my ($udom,$description,$url,$course_server,$nonstandard,$inst_code, + $course_owner,$crstype)=@_; $url=&declutter($url); my $cid=''; unless (&allowed('ccc',$udom)) { @@ -4441,7 +4484,8 @@ sub createcourse { # ----------------------------------------------------------------- Course made # log existence &courseidput($udom,&escape($udom.'_'.$uname).'='.&escape($description). - ':'.&escape($inst_code).':'.&escape($course_owner),$uhome); + ':'.&escape($inst_code).':'.&escape($course_owner).':'. + &escape($crstype),$uhome); &flushcourselogs(); # set toplevel url my $topurl=$url; @@ -4511,9 +4555,15 @@ sub is_locked { $env{'user.domain'},$env{'user.name'}); my ($tmp)=keys(%locked); if ($tmp=~/^error:/) { undef(%locked); } - + if (ref($locked{$file_name}) eq 'ARRAY') { - $is_locked = 'true'; + $is_locked = 'false'; + foreach my $entry (@{$locked{$file_name}}) { + if (ref($entry) eq 'ARRAY') { + $is_locked = 'true'; + last; + } + } } else { $is_locked = 'false'; } @@ -4602,48 +4652,113 @@ sub files_not_in_path { return (@return_files); } -#--------------------------------------------------------------Get Marked as Read Only +#----------------------------------------------Get portfolio file permissions - -sub get_marked_as_readonly { - my ($domain,$user,$what) = @_; +sub get_portfile_permissions { + # returns a reference to a hash containing contents of file_permissions.db + my ($domain,$user) = @_; my %current_permissions = &dump('file_permissions',$domain,$user); my ($tmp)=keys(%current_permissions); if ($tmp=~/^error:/) { undef(%current_permissions); } + return \%current_permissions; +} + +#---------------------------------------------Get portfolio file access controls + +sub get_access_controls { + # returns a hash containing access control information retrieved from + # file_permissions.db. The hash contains key=value pairs where key is + # the control type, end date and start date, in the form type_end_start + # and value is a string containing access control settings (in XML), + # + # Internally access_controls are stored in file_permissions.db in an + # array of arrays and a hash, where arrays are locks set when a portfolio + # file has been uploaded to an essayresponse problem in a course, and + # the hash contains other data. Two keys are currently defined in the hash: + # access and accesscount. The value for accesscount is a scalar - equal to + # the next number to use as the first part of an access control key + # when defining a new control. The value for access is an anonymous hash + # where keys are access controls and values are settings. + # + my ($current_permissions,$group,$file) = @_; + my @access_checks = (); + my %access; + if (defined($file)) { + @access_checks = ($file); + } else { + @access_checks = keys(%{$current_permissions}); + } + foreach my $file_name (@access_checks) { + my $value = $$current_permissions{$file_name}; + if (defined($group)) { + if ($file_name !~ m-^\Q$group\E/-) { + next; + } + } + if (ref($value) eq "ARRAY") { + foreach my $stored_what (@{$value}) { + if (ref($stored_what) eq 'HASH') { + $access{$file_name} = $$stored_what{'access'}; + } + } + } + } + return %access; +} + +#------------------------------------------------------Get Marked as Read Only + +sub get_marked_as_readonly { + my ($domain,$user,$what,$group) = @_; + my $current_permissions = &get_portfile_permissions($domain,$user); my @readonly_files; my $cmp1=$what; if (ref($what)) { $cmp1=join('',@{$what}) }; - while (my ($file_name,$value) = each(%current_permissions)) { + while (my ($file_name,$value) = each(%{$current_permissions})) { + if (defined($group)) { + if ($file_name !~ m-^\Q$group\E/-) { + next; + } + } if (ref($value) eq "ARRAY"){ foreach my $stored_what (@{$value}) { my $cmp2=$stored_what; - if (ref($stored_what)) { $cmp2=join('',@{$stored_what}) }; + if (ref($stored_what eq 'HASH')) { + next; + } elsif (ref($stored_what eq 'ARRAY')) { + $cmp2=join('',@{$stored_what}); + } if ($cmp1 eq $cmp2) { push(@readonly_files, $file_name); + last; } elsif (!defined($what)) { push(@readonly_files, $file_name); + last; } } - } + } } return @readonly_files; } #-----------------------------------------------------------Get Marked as Read Only Hash sub get_marked_as_readonly_hash { - my ($domain,$user,$what) = @_; - my %current_permissions = &dump('file_permissions',$domain,$user); - my ($tmp)=keys(%current_permissions); - if ($tmp=~/^error:/) { undef(%current_permissions); } - + my ($current_permissions,$group,$what) = @_; my %readonly_files; - while (my ($file_name,$value) = each(%current_permissions)) { + while (my ($file_name,$value) = each(%{$current_permissions})) { + if (defined($group)) { + if ($file_name !~ m-^\Q$group\E/-) { + next; + } + } if (ref($value) eq "ARRAY"){ foreach my $stored_what (@{$value}) { - if ($stored_what eq $what) { - $readonly_files{$file_name} = 'locked'; - } elsif (!defined($what)) { - $readonly_files{$file_name} = 'locked'; + if (ref($stored_what) eq 'ARRAY') { + if ($stored_what eq $what) { + $readonly_files{$file_name} = 'locked'; + } elsif (!defined($what)) { + $readonly_files{$file_name} = 'locked'; + } } } } @@ -4655,13 +4770,13 @@ sub get_marked_as_readonly_hash { sub unmark_as_readonly { # unmarks $file_name (if $file_name is defined), or all files locked by $what # for portfolio submissions, $what contains [$symb,$crsid] - my ($domain,$user,$what,$file_name) = @_; + my ($domain,$user,$what,$file_name,$group) = @_; my $symb_crs = $what; if (ref($what)) { $symb_crs=join('',@$what); } - my %current_permissions = &dump('file_permissions',$domain,$user); + my %current_permissions = &dump('file_permissions',$domain,$user,$group); my ($tmp)=keys(%current_permissions); if ($tmp=~/^error:/) { undef(%current_permissions); } - my @readonly_files = &get_marked_as_readonly($domain,$user,$what); + my @readonly_files = &get_marked_as_readonly($domain,$user,$what,$group); foreach my $file (@readonly_files) { if (defined($file_name) && ($file_name ne $file)) { next; } my $current_locks = $current_permissions{$file}; @@ -4670,9 +4785,13 @@ sub unmark_as_readonly { if (ref($current_locks) eq "ARRAY"){ foreach my $locker (@{$current_locks}) { my $compare=$locker; - if (ref($locker)) { $compare=join('',@{$locker}) }; - if ($compare ne $symb_crs) { - push(@new_locks, $locker); + if (!ref($locker) eq 'ARRAY') { + push(@new_locks,$locker); + } else { + $compare=join('',@{$locker}); + if ($compare ne $symb_crs) { + push(@new_locks, $locker); + } } } if (scalar(@new_locks) > 0) { @@ -4824,7 +4943,7 @@ sub stat_file { ($udom,$uname,$file) = ($uri =~ m-/(?:uploaded|editupload)/?([^/]*)/?([^/]*)/?(.*)-); $file = 'userfiles/'.$file; - $dir = &Apache::loncommon::propath($udom,$uname); + $dir = &propath($udom,$uname); } if ($uri =~ m-^/res/-) { ($udom,$uname) = @@ -5073,8 +5192,14 @@ sub EXT { if ( (defined($Apache::lonhomework::parsing_a_problem) || defined($Apache::lonhomework::parsing_a_task)) && - ($symbparm eq &symbread()) ) { - return $Apache::lonhomework::history{$qualifierrest}; + ($symbparm eq &symbread()) ) { + # if we are in the middle of processing the resource the + # get the value we are planning on committing + if (defined($Apache::lonhomework::results{$qualifierrest})) { + return $Apache::lonhomework::results{$qualifierrest}; + } else { + return $Apache::lonhomework::history{$qualifierrest}; + } } else { my %restored; if ($publicuser || $env{'request.state'} eq 'construct') { @@ -6460,7 +6585,7 @@ sub filelocation { my @ids=¤t_machine_ids(); foreach my $id (@ids) { if ($id eq $home) { $is_me=1; } } if ($is_me) { - $location=&Apache::loncommon::propath($udom,$uname). + $location=&propath($udom,$uname). '/userfiles/'.$filename; } else { $location=$Apache::lonnet::perlvar{'lonDocRoot'}.'/userfiles/'. @@ -6581,21 +6706,6 @@ sub freeze_escape { return &escape($value); } -# -------------------------------------------------------- Escape Special Chars - -sub escape { - my $str=shift; - $str =~ s/(\W)/"%".unpack('H2',$1)/eg; - return $str; -} - -# ----------------------------------------------------- Un-Escape Special Chars - -sub unescape { - my $str=shift; - $str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; - return $str; -} sub thaw_unescape { my ($value)=@_; @@ -6769,8 +6879,14 @@ sub get_iphost { while (my $configline=<$config>) { chomp($configline); if ($configline) { - my ($short,$plain)=split(/:/,$configline); - if ($plain ne '') { $prp{$short}=$plain; } + my ($short,@plain)=split(/:/,$configline); + %{$prp{$short}} = (); + if (@plain > 0) { + $prp{$short}{'std'} = $plain[0]; + for (my $i=1; $i<@plain; $i++) { + $prp{$short}{'alt'.$i} = $plain[$i]; + } + } } } close($config);