--- loncom/lonnet/perl/lonnet.pm 2009/10/24 03:24:25 1.1035 +++ loncom/lonnet/perl/lonnet.pm 2010/03/21 21:05:51 1.1058 @@ -1,7 +1,7 @@ # The LearningOnline Network # TCP networking package # -# $Id: lonnet.pm,v 1.1035 2009/10/24 03:24:25 raeburn Exp $ +# $Id: lonnet.pm,v 1.1058 2010/03/21 21:05:51 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -99,8 +99,6 @@ use LONCAPA::Configuration; my $readit; my $max_connection_retries = 10; # Or some such value. -my $upload_photo_form = 0; #Variable to check when user upload a photo 0=not 1=true - require Exporter; our @ISA = qw (Exporter); @@ -1353,7 +1351,8 @@ sub get_domain_defaults { my %domdefaults; my %domconfig = &Apache::lonnet::get_dom('configuration',['defaults','quotas', - 'requestcourses','inststatus'],$domain); + 'requestcourses','inststatus', + 'coursedefaults'],$domain); if (ref($domconfig{'defaults'}) eq 'HASH') { $domdefaults{'lang_def'} = $domconfig{'defaults'}{'lang_def'}; $domdefaults{'auth_def'} = $domconfig{'defaults'}{'auth_def'}; @@ -1388,6 +1387,11 @@ sub get_domain_defaults { $domdefaults{$item} = $domconfig{'inststatus'}{$item}; } } + if (ref($domconfig{'coursedefaults'}) eq 'HASH') { + foreach my $item ('canuse_pdfforms') { + $domdefaults{$item} = $domconfig{'coursedefaults'}{$item}; + } + } &Apache::lonnet::do_cache_new('domdefaults',$domain,\%domdefaults, $cachetime); return %domdefaults; @@ -1722,6 +1726,9 @@ sub userenvironment { unless ($uhome eq 'no_host') { my @answer=split(/\&/, &reply('get:'.$udom.':'.$unam.':environment:'.$items,$uhome)); + if ($#answer==0 && $answer[0] =~ /^(con_lost|error:|no_such_host)/i) { + return %returnhash; + } my $i; for ($i=0;$i<=$#what;$i++) { $returnhash{$what[$i]}=&unescape($answer[$i]); @@ -2147,31 +2154,42 @@ sub clean_filename { $fname=~s/\.(\d+)(?=\.)/_$1/g; return $fname; } -#This Function check if a Image max 400px width and height 500px. If not then scale the image down +# This Function checks if an Image's dimensions exceed either $resizewidth (width) +# or $resizeheight (height) - both pixels. If so, the image is scaled to produce an +# image with the same aspect ratio as the original, but with dimensions which do +# not exceed $resizewidth and $resizeheight. + sub resizeImage { - my($img_url) = @_; - my $ima = Image::Magick->new; - $ima->Read($img_url); - if($ima->Get('width') > 400) - { - my $factor = $ima->Get('width')/400; - $ima->Scale( width=>400, height=>$ima->Get('height')/$factor ); - } - if($ima->Get('height') > 500) - { - my $factor = $ima->Get('height')/500; - $ima->Scale( width=>$ima->Get('width')/$factor, height=>500); - } - - $ima->Write($img_url); -} - -#Wrapper function for userphotoupload -sub userphotoupload -{ - my($formname,$subdir) = @_; - $upload_photo_form = 1; - return &userfileupload($formname,undef,$subdir); + my ($img_path,$resizewidth,$resizeheight) = @_; + my $ima = Image::Magick->new; + my $resized; + if (-e $img_path) { + $ima->Read($img_path); + if (($resizewidth =~ /^\d+$/) && ($resizeheight > 0)) { + my $width = $ima->Get('width'); + my $height = $ima->Get('height'); + if ($width > $resizewidth) { + my $factor = $width/$resizewidth; + my $newheight = $height/$factor; + $ima->Scale(width=>$resizewidth,height=>$newheight); + $resized = 1; + } + } + if (($resizeheight =~ /^\d+$/) && ($resizeheight > 0)) { + my $width = $ima->Get('width'); + my $height = $ima->Get('height'); + if ($height > $resizeheight) { + my $factor = $height/$resizeheight; + my $newwidth = $width/$factor; + $ima->Scale(width=>$newwidth,height=>$resizeheight); + $resized = 1; + } + } + if ($resized) { + $ima->Write($img_path); + } + } + return; } # --------------- Take an uploaded file and put it into the userfiles directory @@ -2187,14 +2205,15 @@ sub userphotoupload # $dsetudom - domain for permanaent storage of uploaded file # $thumbwidth - width (pixels) of thumbnail to make for uploaded image # $thumbheight - height (pixels) of thumbnail to make for uploaded image +# $resizewidth - width (pixels) to which to resize uploaded image +# $resizeheight - height (pixels) to which to resize uploaded image # # output: url of file in userspace, or error: # or /adm/notfound.html if failure to upload occurse - sub userfileupload { my ($formname,$coursedoc,$subdir,$parser,$allfiles,$codebase,$destuname, - $destudom,$thumbwidth,$thumbheight)=@_; + $destudom,$thumbwidth,$thumbheight,$resizewidth,$resizeheight)=@_; if (!defined($subdir)) { $subdir='unknown'; } my $fname=$env{'form.'.$formname.'.filename'}; $fname=&clean_filename($fname); @@ -2244,7 +2263,8 @@ sub userfileupload { if ($env{'form.folder'} =~ m/^(default|supplemental)/) { return &finishuserfileupload($docuname,$docudom, $formname,$fname,$parser,$allfiles, - $codebase,$thumbwidth,$thumbheight); + $codebase,$thumbwidth,$thumbheight, + $resizewidth,$resizeheight); } else { $fname=$env{'form.folder'}.'/'.$fname; return &process_coursefile('uploaddoc',$docuname,$docudom, @@ -2256,7 +2276,8 @@ sub userfileupload { my $docudom=$destudom; return &finishuserfileupload($docuname,$docudom,$formname,$fname, $parser,$allfiles,$codebase, - $thumbwidth,$thumbheight); + $thumbwidth,$thumbheight, + $resizewidth,$resizeheight); } else { my $docuname=$env{'user.name'}; @@ -2267,13 +2288,14 @@ sub userfileupload { } return &finishuserfileupload($docuname,$docudom,$formname,$fname, $parser,$allfiles,$codebase, - $thumbwidth,$thumbheight); + $thumbwidth,$thumbheight, + $resizewidth,$resizeheight); } } sub finishuserfileupload { my ($docuname,$docudom,$formname,$fname,$parser,$allfiles,$codebase, - $thumbwidth,$thumbheight) = @_; + $thumbwidth,$thumbheight,$resizewidth,$resizeheight) = @_; my $path=$docudom.'/'.$docuname.'/'; my $filepath=$perlvar{'lonDocRoot'}; @@ -2305,10 +2327,12 @@ sub finishuserfileupload { return '/adm/notfound.html'; } close(FH); - if($upload_photo_form==1) - { - resizeImage($filepath.'/'.$file); - $upload_photo_form = 0; + if ($resizewidth && $resizeheight) { + my $mm = new File::MMagic; + my $mime_type = $mm->checktype_filename($filepath.'/'.$file); + if ($mime_type =~ m{^image/}) { + &resizeImage($filepath.'/'.$file,$resizewidth,$resizeheight); + } } } if ($parser eq 'parse') { @@ -2729,7 +2753,7 @@ sub userrolelog { if (($trole=~/^ca/) || ($trole=~/^aa/) || ($trole=~/^in/) || ($trole=~/^cc/) || ($trole=~/^ep/) || ($trole=~/^cr/) || - ($trole=~/^ta/)) { + ($trole=~/^ta/) || ($trole=~/^co/)) { my (undef,$rudom,$runame,$rsec)=split(/\//,$area); $userrolehash {$trole.':'.$username.':'.$domain.':'.$runame.':'.$rudom.':'.$rsec} @@ -2738,7 +2762,8 @@ sub userrolelog { if (($env{'request.role'} =~ /dc\./) && (($trole=~/^au/) || ($trole=~/^in/) || ($trole=~/^cc/) || ($trole=~/^ep/) || - ($trole=~/^cr/) || ($trole=~/^ta/))) { + ($trole=~/^cr/) || ($trole=~/^ta/) || + ($trole=~/^co/))) { $userrolehash {$trole.':'.$username.':'.$domain.':'.$env{'user.name'}.':'.$env{'user.domain'}.':'} =$tend.':'.$tstart; @@ -2759,7 +2784,8 @@ sub courserolelog { if (($trole eq 'cc') || ($trole eq 'in') || ($trole eq 'ep') || ($trole eq 'ad') || ($trole eq 'ta') || ($trole eq 'st') || - ($trole=~/^cr/) || ($trole eq 'gr')) { + ($trole=~/^cr/) || ($trole eq 'gr') || + ($trole eq 'co')) { if ($area =~ m-^/($match_domain)/($match_courseid)/?([^/]*)-) { my $cdom = $1; my $cnum = $2; @@ -2993,6 +3019,7 @@ sub getannounce { sub courseidput { my ($domain,$storehash,$coursehome,$caller) = @_; + return unless (ref($storehash) eq 'HASH'); my $outcome; if ($caller eq 'timeonly') { my $cids = ''; @@ -3077,6 +3104,49 @@ sub courseiddump { return %returnhash; } +sub courselastaccess { + my ($cdom,$cnum,$hostidref) = @_; + my %returnhash; + if ($cdom && $cnum) { + my $chome = &homeserver($cnum,$cdom); + if ($chome ne 'no_host') { + my $rep = &reply('courselastaccess:'.$cdom.':'.$cnum,$chome); + &extract_lastaccess(\%returnhash,$rep); + } + } else { + if (!$cdom) { $cdom=''; } + my %libserv = &all_library(); + foreach my $tryserver (keys(%libserv)) { + if (ref($hostidref) eq 'ARRAY') { + next unless (grep(/^\Q$tryserver\E$/,@{$hostidref})); + } + if (($cdom eq '') || (&host_domain($tryserver) eq $cdom)) { + my $rep = &reply('courselastaccess:'.&host_domain($tryserver).':',$tryserver); + &extract_lastaccess(\%returnhash,$rep); + } + } + } + return %returnhash; +} + +sub extract_lastaccess { + my ($returnhash,$rep) = @_; + if (ref($returnhash) eq 'HASH') { + unless ($rep eq 'unknown_command' || $rep eq 'no_such_host' || + $rep eq 'con_lost' || $rep eq 'rejected' || $rep eq 'refused' || + $rep eq '') { + my @pairs=split(/\&/,$rep); + foreach my $item (@pairs) { + my ($key,$value)=split(/\=/,$item,2); + $key = &unescape($key); + next if ($key =~ /^error: 2 /); + $returnhash->{$key} = &thaw_unescape($value); + } + } + } + return; +} + # ---------------------------------------------------------- DC e-mail sub dcmailput { @@ -3137,7 +3207,7 @@ sub get_domain_roles { return %personnel; } -# ----------------------------------------------------------- Check out an item +# ----------------------------------------------------------- Interval timing sub get_first_access { my ($type,$argsymb)=@_; @@ -3173,91 +3243,6 @@ sub set_first_access { return 'already_set'; } -sub checkout { - my ($symb,$tuname,$tudom,$tcrsid)=@_; - my $now=time; - my $lonhost=$perlvar{'lonHostID'}; - my $infostr=&escape( - 'CHECKOUTTOKEN&'. - $tuname.'&'. - $tudom.'&'. - $tcrsid.'&'. - $symb.'&'. - $now.'&'.$ENV{'REMOTE_ADDR'}); - my $token=&reply('tmpput:'.$infostr,$lonhost); - if ($token=~/^error\:/) { - &logthis("WARNING: ". - "Checkout tmpput failed ".$tudom.' - '.$tuname.' - '.$symb. - ""); - return ''; - } - - $token=~s/^(\d+)\_.*\_(\d+)$/$1\*$2\*$lonhost/; - $token=~tr/a-z/A-Z/; - - my %infohash=('resource.0.outtoken' => $token, - 'resource.0.checkouttime' => $now, - 'resource.0.outremote' => $ENV{'REMOTE_ADDR'}); - - unless (&cstore(\%infohash,$symb,$tcrsid,$tudom,$tuname) eq 'ok') { - return ''; - } else { - &logthis("WARNING: ". - "Checkout cstore failed ".$tudom.' - '.$tuname.' - '.$symb. - ""); - } - - if (&log($tudom,$tuname,&homeserver($tuname,$tudom), - &escape('Checkout '.$infostr.' - '. - $token)) ne 'ok') { - return ''; - } else { - &logthis("WARNING: ". - "Checkout log failed ".$tudom.' - '.$tuname.' - '.$symb. - ""); - } - return $token; -} - -# ------------------------------------------------------------ Check in an item - -sub checkin { - my $token=shift; - my $now=time; - my ($ta,$tb,$lonhost)=split(/\*/,$token); - $lonhost=~tr/A-Z/a-z/; - my $dtoken=$ta.'_'.&hostname($lonhost).'_'.$tb; - $dtoken=~s/\W/\_/g; - my ($dummy,$tuname,$tudom,$tcrsid,$symb,$chtim,$rmaddr)= - split(/\&/,&unescape(&reply('tmpget:'.$dtoken,$lonhost))); - - unless (($tuname) && ($tudom)) { - &logthis('Check in '.$token.' ('.$dtoken.') failed'); - return ''; - } - - unless (&allowed('mgr',$tcrsid)) { - &logthis('Check in '.$token.' ('.$dtoken.') unauthorized: '. - $env{'user.name'}.' - '.$env{'user.domain'}); - return ''; - } - - my %infohash=('resource.0.intoken' => $token, - 'resource.0.checkintime' => $now, - 'resource.0.inremote' => $ENV{'REMOTE_ADDR'}); - - unless (&cstore(\%infohash,$symb,$tcrsid,$tudom,$tuname) eq 'ok') { - return ''; - } - - if (&log($tudom,$tuname,&homeserver($tuname,$tudom), - &escape('Checkin - '.$token)) ne 'ok') { - return ''; - } - - return ($symb,$tuname,$tudom,$tcrsid); -} - # --------------------------------------------- Set Expire Date for Spreadsheet sub expirespread { @@ -3907,6 +3892,9 @@ sub custom_roleprivs { if (($rdummy ne 'con_lost') && ($roledef ne '')) { my ($syspriv,$dompriv,$coursepriv)=split(/\_/,$roledef); if (defined($syspriv)) { + if ($trest =~ /^$match_community$/) { + $syspriv =~ s/bre\&S//; + } $$allroles{'cm./'}.=':'.$syspriv; $$allroles{$spec.'./'}.=':'.$syspriv; } @@ -4024,13 +4012,6 @@ sub role_status { ); my $spec=$$role.'.'.$$where; my ($tdummy,$tdomain,$trest)=split(/\//,$$where); - if ($$role eq 'gr') { - my %rolehash = &get('roles',[$$where.'_'.$$role],$env{'user.domain'}, - $env{'user.name'})=@_; - my ($trole) = split('_',$role,1); - (undef,my $group_privs) = split(/\//,$trole); - $group_privs = &unescape($group_privs); - } if ($$role =~ /^cr\//) { &custom_roleprivs(\%allroles,$$role,$tdomain,$trest,$spec,$$where); } elsif ($$role eq 'gr') { @@ -4806,6 +4787,27 @@ sub usertools_access { } } +sub is_course_owner { + my ($cdom,$cnum,$udom,$uname) = @_; + if (($udom eq '') || ($uname eq '')) { + $udom = $env{'user.domain'}; + $uname = $env{'user.name'}; + } + unless (($udom eq '') || ($uname eq '')) { + if (exists($env{'course.'.$cdom.'_'.$cnum.'.internal.courseowner'})) { + if ($env{'course.'.$cdom.'_'.$cnum.'.internal.courseowner'} eq $uname.':'.$udom) { + return 1; + } else { + my %courseinfo = &Apache::lonnet::coursedescription($cdom.'/'.$cnum); + if ($courseinfo{'internal.courseowner'} eq $uname.':'.$udom) { + return 1; + } + } + } + } + return; +} + sub is_advanced_user { my ($udom,$uname) = @_; my %roleshash = &get_my_roles($uname,$udom,'userroles',undef,undef,undef,1); @@ -4842,7 +4844,7 @@ sub is_advanced_user { } sub check_can_request { - my ($dom,$can_request) = @_; + my ($dom,$can_request,$request_domains) = @_; my $canreq = 0; my ($types,$typename) = &Apache::loncommon::course_types(); my @options = ('approval','validate','autolimit'); @@ -4853,6 +4855,9 @@ sub check_can_request { $env{'user.domain'}, $type,undef,'requestcourses')) { $canreq ++; + if (ref($request_domains) eq 'HASH') { + push(@{$request_domains->{$type}},$env{'user.domain'}); + } if ($dom eq $env{'user.domain'}) { $can_request->{$type} = 1; } @@ -4860,8 +4865,22 @@ sub check_can_request { if ($env{'environment.reqcrsotherdom.'.$type} ne '') { my @curr = split(',',$env{'environment.reqcrsotherdom.'.$type}); if (@curr > 0) { - $canreq ++; - unless ($dom eq $env{'user.domain'}) { + foreach my $item (@curr) { + if (ref($request_domains) eq 'HASH') { + my ($otherdom) = ($item =~ /^($match_domain):($optregex)(=?\d*)$/); + if ($otherdom ne '') { + if (ref($request_domains->{$type}) eq 'ARRAY') { + unless (grep(/^\Q$otherdom\E$/,@{$request_domains->{$type}})) { + push(@{$request_domains->{$type}},$otherdom); + } + } else { + push(@{$request_domains->{$type}},$otherdom); + } + } + } + } + unless($dom eq $env{'user.domain'}) { + $canreq ++; if (grep(/^\Q$dom\E:($optregex)(=?\d*)$/,@curr)) { $can_request->{$type} = 1; } @@ -5027,17 +5046,68 @@ sub allowed { my $statecond=0; my $courseprivid=''; + my $ownaccess; + # Community Coordinator or Assistant Co-author browsing resource space. + if (($priv eq 'bro') && ($env{'user.author'})) { + if ($uri eq '') { + $ownaccess = 1; + } else { + if (($env{'user.domain'} ne '') && ($env{'user.name'} ne '')) { + my $udom = $env{'user.domain'}; + my $uname = $env{'user.name'}; + if ($uri =~ m{^\Q$udom\E/?$}) { + $ownaccess = 1; + } elsif ($uri =~ m{^\Q$udom\E/\Q$uname\E/?}) { + unless ($uri =~ m{\.\./}) { + $ownaccess = 1; + } + } elsif (($udom ne 'public') && ($uname ne 'public')) { + my $now = time; + if ($uri =~ m{^([^/]+)/?$}) { + my $adom = $1; + foreach my $key (keys(%env)) { + if ($key =~ m{^user\.role\.(ca|aa)/\Q$adom\E}) { + my ($start,$end) = split('.',$env{$key}); + if (($now >= $start) && (!$end || $end < $now)) { + $ownaccess = 1; + last; + } + } + } + } elsif ($uri =~ m{^([^/]+)/([^/]+)/?}) { + my $adom = $1; + my $aname = $2; + foreach my $role ('ca','aa') { + if ($env{"user.role.$role./$adom/$aname"}) { + my ($start,$end) = + split('.',$env{"user.role.$role./$adom/$aname"}); + if (($now >= $start) && (!$end || $end < $now)) { + $ownaccess = 1; + last; + } + } + } + } + } + } + } + } + # Course if ($env{'user.priv.'.$env{'request.role'}.'./'}=~/\Q$priv\E\&([^\:]*)/) { - $thisallowed.=$1; + unless (($priv eq 'bro') && (!$ownaccess)) { + $thisallowed.=$1; + } } # Domain if ($env{'user.priv.'.$env{'request.role'}.'./'.(split(/\//,$uri))[0].'/'} =~/\Q$priv\E\&([^\:]*)/) { - $thisallowed.=$1; + unless (($priv eq 'bro') && (!$ownaccess)) { + $thisallowed.=$1; + } } # Course: uri itself is a course @@ -5047,7 +5117,9 @@ sub allowed { if ($env{'user.priv.'.$env{'request.role'}.'.'.$courseuri} =~/\Q$priv\E\&([^\:]*)/) { - $thisallowed.=$1; + unless (($priv eq 'bro') && (!$ownaccess)) { + $thisallowed.=$1; + } } # URI is an uploaded document for this course, default permissions don't matter @@ -6067,30 +6139,37 @@ sub devalidate_getgroups_cache { sub plaintext { my ($short,$type,$cid,$forcedefault) = @_; - if ($short =~ /^cr/) { + if ($short =~ m{^cr/}) { return (split('/',$short))[-1]; } if (!defined($cid)) { $cid = $env{'request.course.id'}; } - if (defined($cid) && ($env{'course.'.$cid.'.'.$short.'.plaintext'} ne '')) { - unless ($forcedefault) { - my $roletext = $env{'course.'.$cid.'.'.$short.'.plaintext'}; - &Apache::lonlocal::mt_escape(\$roletext); - return &Apache::lonlocal::mt($roletext); - } - } my %rolenames = ( Course => 'std', Community => 'alt1', ); - if (defined($type) && - defined($rolenames{$type}) && - defined($prp{$short}{$rolenames{$type}})) { + if ($cid ne '') { + if ($env{'course.'.$cid.'.'.$short.'.plaintext'} ne '') { + unless ($forcedefault) { + my $roletext = $env{'course.'.$cid.'.'.$short.'.plaintext'}; + &Apache::lonlocal::mt_escape(\$roletext); + return &Apache::lonlocal::mt($roletext); + } + } + } + if ((defined($type)) && (defined($rolenames{$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'}); + } elsif ($cid ne '') { + my $crstype = $env{'course.'.$cid.'.type'}; + if (($crstype ne '') && (defined($rolenames{$crstype})) && + (defined($prp{$short}{$rolenames{$crstype}}))) { + return &Apache::lonlocal::mt($prp{$short}{$rolenames{$crstype}}); + } } + return &Apache::lonlocal::mt($prp{$short}{'std'}); } # ----------------------------------------------------------------- Assign Role @@ -6149,16 +6228,45 @@ sub assignrole { $refused = 1; } if ($refused) { - if (($selfenroll == 1) && ($role eq 'st') && ($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'})) { + my ($cdom,$cnum) = ($cwosec =~ m{^/?($match_domain)/($match_courseid)$}); + if (!$selfenroll && $context eq 'course') { + my %crsenv; + if ($role eq 'cc' || $role eq 'co') { + %crsenv = &userenvironment($cdom,$cnum,('internal.courseowner')); + if (($role eq 'cc') && ($cnum !~ /^$match_community$/)) { + + if ($env{'request.role'} eq 'cc./'.$cdom.'/'.$cnum) { + if ($crsenv{'internal.courseowner'} eq + $env{'user.name'}.':'.$env{'user.domain'}) { + $refused = ''; + } + } + } elsif (($role eq 'co') && ($cnum =~ /^$match_community$/)) { + if ($env{'request.role'} eq 'co./'.$cdom.'/'.$cnum) { + if ($crsenv{'internal.courseowner'} eq + $env{'user.name'}.':'.$env{'user.domain'}) { + $refused = ''; + } + } + } + } + } elsif (($selfenroll == 1) && ($role eq 'st') && ($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'})) { $refused = ''; } elsif ($context eq 'requestcourses') { - my @possroles = ('st','ta','ep','in','cc'); + my @possroles = ('st','ta','ep','in','cc','co'); if ((grep(/^\Q$role\E$/,@possroles)) && ($env{'user.name'} ne '' && $env{'user.domain'} ne '')) { - my ($cdom,$cnum) = ($cwosec =~ m{^/?($match_domain)/($match_courseid)$}); - my %crsenv = &userenvironment($cdom,$cnum,('internal.courseowner')); - if ($crsenv{'internal.courseowner'} eq - $env{'user.name'}.':'.$env{'user.domain'}) { - $refused = ''; + my $wrongcc; + if ($cnum =~ /^$match_community$/) { + $wrongcc = 1 if ($role eq 'cc'); + } else { + $wrongcc = 1 if ($role eq 'co'); + } + unless ($wrongcc) { + my %crsenv = &userenvironment($cdom,$cnum,('internal.courseowner')); + if ($crsenv{'internal.courseowner'} eq + $env{'user.name'}.':'.$env{'user.domain'}) { + $refused = ''; + } } } } @@ -6209,10 +6317,97 @@ sub assignrole { &Apache::longroup::group_changes($udom,$uname,$url,$role,$origend, $origstart,$selfenroll,$context); } + if ($role eq 'cc') { + &autoupdate_coowners($url,$end,$start,$uname,$udom); + } } return $answer; } +sub autoupdate_coowners { + my ($url,$end,$start,$uname,$udom) = @_; + my ($cdom,$cnum) = ($url =~ m{^/($match_domain)/($match_courseid)}); + if (($cdom ne '') && ($cnum ne '')) { + my $now = time; + my %domdesign = &Apache::loncommon::get_domainconf($cdom); + if ($domdesign{$cdom.'.autoassign.co-owners'}) { + my %coursehash = &coursedescription($cdom.'_'.$cnum); + my $instcode = $coursehash{'internal.coursecode'}; + if ($instcode ne '') { + if (($start && $start <= $now) && ($end == 0) || ($end > $now)) { + unless ($coursehash{'internal.courseowner'} eq $uname.':'.$udom) { + my ($delcoowners,@newcoowners,$putresult,$delresult,$coowners); + my ($result,$desc) = &auto_validate_instcode($cnum,$cdom,$instcode,$uname.':'.$udom); + if ($result eq 'valid') { + if ($coursehash{'internal.co-owners'}) { + foreach my $coowner (split(',',$coursehash{'internal.co-owners'})) { + push(@newcoowners,$coowner); + } + unless (grep(/^\Q$uname\E:\Q$udom\E$/,@newcoowners)) { + push(@newcoowners,$uname.':'.$udom); + } + @newcoowners = sort(@newcoowners); + } else { + push(@newcoowners,$uname.':'.$udom); + } + } else { + if ($coursehash{'internal.co-owners'}) { + foreach my $coowner (split(',',$coursehash{'internal.co-owners'})) { + unless ($coowner eq $uname.':'.$udom) { + push(@newcoowners,$coowner); + } + } + unless (@newcoowners > 0) { + $delcoowners = 1; + $coowners = ''; + } + } + } + if (@newcoowners || $delcoowners) { + &store_coowners($cdom,$cnum,$coursehash{'home'}, + $delcoowners,@newcoowners); + } + } + } + } + } + } +} + +sub store_coowners { + my ($cdom,$cnum,$chome,$delcoowners,@newcoowners) = @_; + my $cid = $cdom.'_'.$cnum; + my ($coowners,$delresult,$putresult); + if (@newcoowners) { + $coowners = join(',',@newcoowners); + my %coownershash = ( + 'internal.co-owners' => $coowners, + ); + $putresult = &put('environment',\%coownershash,$cdom,$cnum); + if ($putresult eq 'ok') { + if ($env{'course.'.$cid.'.num'} eq $cnum) { + &appenv({'course.'.$cid.'.internal.co-owners' => $coowners}); + } + } + } + if ($delcoowners) { + $delresult = &Apache::lonnet::del('environment',['internal.co-owners'],$cdom,$cnum); + if ($delresult eq 'ok') { + if ($env{'course.'.$cid.'.internal.co-owners'}) { + &Apache::lonnet::delenv('course.'.$cid.'.internal.co-owners'); + } + } + } + if (($putresult eq 'ok') || ($delresult eq 'ok')) { + my %crsinfo = + &Apache::lonnet::courseiddump($cdom,'.',1,'.','.',$cnum,undef,undef,'.'); + if (ref($crsinfo{$cid}) eq 'HASH') { + $crsinfo{$cid}{'co-owners'} = \@newcoowners; + my $cidput = &Apache::lonnet::courseidput($cdom,\%crsinfo,$chome,'notime'); + } + } +} + # -------------------------------------------------- Modify user authentication # Overrides without validation @@ -6245,12 +6440,12 @@ sub modifyuser { my ($udom, $uname, $uid, $umode, $upass, $first, $middle, $last, $gene, - $forceid, $desiredhome, $email, $inststatus)=@_; + $forceid, $desiredhome, $email, $inststatus, $candelete)=@_; $udom= &LONCAPA::clean_domain($udom); $uname=&LONCAPA::clean_username($uname); &logthis('Call to modify user '.$udom.', '.$uname.', '.$uid.', '. $umode.', '.$first.', '.$middle.', '. - $last.', '.$gene.'(forceid: '.$forceid.')'. + $last.', '.$gene.'(forceid: '.$forceid.'; candelete: '.$candelete.')'. (defined($desiredhome) ? ' desiredhome = '.$desiredhome : ' desiredhome not specified'). ' by '.$env{'user.name'}.' at '.$env{'user.domain'}. @@ -6315,9 +6510,33 @@ sub modifyuser { %names = @tmp; } # -# Make sure to not trash student environment if instructor does not bother -# to supply name and email information -# +# If name, email and/or uid are blank (e.g., because an uploaded file +# of users did not contain them), do not overwrite existing values +# unless field is in $candelete array ref. +# + + my @fields = ('firstname','middlename','lastname','generation', + 'permanentemail','id'); + my %newvalues; + if (ref($candelete) eq 'ARRAY') { + foreach my $field (@fields) { + if (grep(/^\Q$field\E$/,@{$candelete})) { + if ($field eq 'firstname') { + $names{$field} = $first; + } elsif ($field eq 'middlename') { + $names{$field} = $middle; + } elsif ($field eq 'lastname') { + $names{$field} = $last; + } elsif ($field eq 'generation') { + $names{$field} = $gene; + } elsif ($field eq 'permanentemail') { + $names{$field} = $email; + } elsif ($field eq 'id') { + $names{$field} = $uid; + } + } + } + } if ($first) { $names{'firstname'} = $first; } if (defined($middle)) { $names{'middlename'} = $middle; } if ($last) { $names{'lastname'} = $last; } @@ -6530,16 +6749,24 @@ sub createcourse { if (($chome eq '') || ($chome eq 'no_host')) { $uname = $cnum; } else { - $uname = &generate_coursenum($udom); + $uname = &generate_coursenum($udom,$crstype); } } else { - $uname = &generate_coursenum($udom); + $uname = &generate_coursenum($udom,$crstype); } return $uname if ($uname =~ /^error/); # -------------------------------------------------- Check supplied server name - $course_server = $env{'user.homeserver'} if (! defined($course_server)); - if (! &is_library($course_server)) { - return 'error:bad server name '.$course_server; + if (!defined($course_server)) { + if (defined(&domain($udom,'primary'))) { + $course_server = &domain($udom,'primary'); + } else { + $course_server = $env{'user.home'}; + } + } + my %host_servers = + &Apache::lonnet::get_servers($udom,'library'); + unless ($host_servers{$course_server}) { + return 'error: invalid home server for course: '.$course_server; } # ------------------------------------------------------------- Make the course my $reply=&reply('encrypt:makeuser:'.$udom.':'.$uname.':none::', @@ -6586,24 +6813,40 @@ ENDINITMAP } # ----------------------------------------------------------- Write preferences &writecoursepref($udom.'_'.$uname, - ('description' => $description, - 'url' => $topurl)); + ('description' => $description, + 'url' => $topurl, + 'internal.creator' => $env{'user.name'}.':'. + $env{'user.domain'}, + 'internal.created' => $now, + 'internal.creationcontext' => $context) + ); return '/'.$udom.'/'.$uname; } # ------------------------------------------------------------------- Create ID sub generate_coursenum { - my ($udom) = @_; + my ($udom,$crstype) = @_; my $domdesc = &domain($udom); return 'error: invalid domain' if ($domdesc eq ''); - my $uname=int(1+rand(9)). + my $first; + if ($crstype eq 'Community') { + $first = '0'; + } else { + $first = int(1+rand(9)); + } + my $uname=$first. ('a'..'z','A'..'Z','0'..'9')[int(rand(62))]. substr($$.time,0,5).unpack("H8",pack("I32",time)). unpack("H2",pack("I32",int(rand(255)))).$perlvar{'lonHostID'}; # ----------------------------------------------- Make sure that does not exist my $uhome=&homeserver($uname,$udom,'true'); unless (($uhome eq '') || ($uhome eq 'no_host')) { - $uname=int(1+rand(9)). + if ($crstype eq 'Community') { + $first = '0'; + } else { + $first = int(1+rand(9)); + } + $uname=$first. ('a'..'z','A'..'Z','0'..'9')[int(rand(62))]. substr($$.time,0,5).unpack("H8",pack("I32",time)). unpack("H2",pack("I32",int(rand(255)))).$perlvar{'lonHostID'}; @@ -10020,9 +10263,16 @@ modifyuserauth($udom,$uname,$umode,$upas =item * -modifyuser($udom,$uname,$uid,$umode,$upass,$first,$middle,$last,$gene, - $forceid,$desiredhome,$email,$inststatus) : -modify user +modifyuser($udom,$uname,$uid,$umode,$upass,$first,$middle,$last, $gene, + $forceid,$desiredhome,$email,$inststatus,$candelete) : + +will update user information (firstname,middlename,lastname,generation, +permanentemail), and if forceid is true, student/employee ID also. +A user's institutional affiliation(s) can also be updated. +User information fields will not be overwritten with empty entries +unless the field is included in the $candelete array reference. +This array is included when a single user is modified via "Manage Users", +or when Autoupdate.pl is run by cron in a domain. =item * @@ -10187,7 +10437,7 @@ createcourse($udom,$description,$url,$co =item * -generate_coursenum($udom) : get a unique (unused) course number in domain $udom +generate_coursenum($udom,$crstype) : get a unique (unused) course number in domain $udom for course type $crstype (Course or Community). =back