--- loncom/interface/loncommon.pm 2010/08/14 00:00:29 1.975 +++ loncom/interface/loncommon.pm 2011/07/04 09:24:58 1.1014 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.975 2010/08/14 00:00:29 raeburn Exp $ +# $Id: loncommon.pm,v 1.1014 2011/07/04 09:24:58 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -409,7 +409,7 @@ sub studentbrowser_javascript { <script type="text/javascript" language="Javascript"> // <![CDATA[ var stdeditbrowser; - function openstdbrowser(formname,uname,udom,roleflag,ignorefilter,courseadvonly) { + function openstdbrowser(formname,uname,udom,clicker,roleflag,ignorefilter,courseadvonly) { var url = '/adm/pickstudent?'; var filter; if (!ignorefilter) { @@ -421,7 +421,8 @@ sub studentbrowser_javascript { } } url += 'form=' + formname + '&unameelement='+uname+ - '&udomelement='+udom; + '&udomelement='+udom+ + '&clicker='+clicker; if (roleflag) { url+="&roles=1"; } if (courseadvonly) { url+="&courseadvonly=1"; } var title = 'Student_Browser'; @@ -435,15 +436,37 @@ sub studentbrowser_javascript { ENDSTDBRW } +sub resourcebrowser_javascript { + unless ($env{'request.course.id'}) { return ''; } + return (<<'ENDRESBRW'); +<script type="text/javascript" language="Javascript"> +// <![CDATA[ + var reseditbrowser; + function openresbrowser(formname,reslink) { + var url = '/adm/pickresource?form='+formname+'&reslink='+reslink; + var title = 'Resource_Browser'; + var options = 'scrollbars=1,resizable=1,menubar=0'; + options += ',width=700,height=500'; + reseditbrowser = open(url,title,options,'1'); + reseditbrowser.focus(); + } +// ]]> +</script> +ENDRESBRW +} + sub selectstudent_link { - my ($form,$unameele,$udomele,$courseadvonly)=@_; - my $callargs = "'".$form."','".$unameele."','".$udomele."'"; + my ($form,$unameele,$udomele,$courseadvonly,$clickerid)=@_; + my $callargs = "'".&Apache::lonhtmlcommon::entity_encode($form)."','". + &Apache::lonhtmlcommon::entity_encode($unameele)."','". + &Apache::lonhtmlcommon::entity_encode($udomele)."'"; if ($env{'request.course.id'}) { if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'}) && !&Apache::lonnet::allowed('srm',$env{'request.course.id'}. '/'.$env{'request.course.sec'})) { return ''; } + $callargs.=",'".&Apache::lonhtmlcommon::entity_encode($clickerid)."'"; if ($courseadvonly) { $callargs .= ",'',1,1"; } @@ -452,7 +475,7 @@ sub selectstudent_link { &mt('Select User').'</a></span>'; } if ($env{'request.role'}=~/^(au|dc|su)/) { - $callargs .= ",1"; + $callargs .= ",'',1"; return '<span class="LC_nobreak">'. '<a href="javascript:openstdbrowser('.$callargs.');">'. &mt('Select User').'</a></span>'; @@ -460,6 +483,19 @@ sub selectstudent_link { return ''; } +sub selectresource_link { + my ($form,$reslink,$arg)=@_; + + my $callargs = "'".&Apache::lonhtmlcommon::entity_encode($form)."','". + &Apache::lonhtmlcommon::entity_encode($reslink)."'"; + unless ($env{'request.course.id'}) { return $arg; } + return '<span class="LC_nobreak">'. + '<a href="javascript:openresbrowser('.$callargs.');">'. + $arg.'</a></span>'; +} + + + sub authorbrowser_javascript { return <<"ENDAUTHORBRW"; <script type="text/javascript" language="JavaScript"> @@ -1722,7 +1758,7 @@ sub create_workbook { return (undef); } # - $workbook->set_tempdir('/home/httpd/perl/tmp'); + $workbook->set_tempdir(LONCAPA::tempdir()); # my $format = &Apache::loncommon::define_excel_formats($workbook); return ($workbook,$filename,$format); @@ -2274,12 +2310,16 @@ function changed_text(choice,currentform } function set_auth_radio_buttons(newvalue,currentform) { + var numauthchoices = currentform.login.length; + if (typeof numauthchoices == "undefined") { + return; + } var i=0; - while (i < currentform.login.length) { + while (i < numauthchoices) { if (currentform.login[i].value == newvalue) { break; } i++; } - if (i == currentform.login.length) { + if (i == numauthchoices) { return; } current.radiovalue = newvalue; @@ -3411,22 +3451,24 @@ sub get_previous_attempt { } $prevattempts=&start_data_table().&start_data_table_header_row(); $prevattempts.='<th>'.&mt('History').'</th>'; - my %typeparts; + my (%typeparts,%lasthidden); my $showsurv=&Apache::lonnet::allowed('vas',$env{'request.course.id'}); foreach my $key (sort(keys(%lasthash))) { my ($ign,@parts) = split(/\./,$key); if ($#parts > 0) { my $data=$parts[-1]; + next if ($data eq 'foilorder'); pop(@parts); + $prevattempts.='<th>'.&mt('Part ').join('.',@parts).'<br />'.$data.' </th>'; if ($data eq 'type') { unless ($showsurv) { my $id = join(',',@parts); $typeparts{$ign.'.'.$id} = $lasthash{$key}; + if (($lasthash{$key} eq 'anonsurvey') || ($lasthash{$key} eq 'anonsurveycred')) { + $lasthidden{$ign.'.'.$id} = 1; + } } - delete($lasthash{$key}); - } else { - $prevattempts.='<th>'.&mt('Part ').join('.',@parts).'<br />'.$data.' </th>'; - } + } } else { if ($#parts == 0) { $prevattempts.='<th>'.$parts[0].'</th>'; @@ -3436,7 +3478,6 @@ sub get_previous_attempt { } } $prevattempts.=&end_data_table_header_row(); - my %lasthidden; if ($getattempt eq '') { for ($version=1;$version<=$returnhash{'version'};$version++) { my @hidden; @@ -3444,11 +3485,6 @@ sub get_previous_attempt { foreach my $id (keys(%typeparts)) { if (($returnhash{$version.':'.$id.'.type'} eq 'anonsurvey') || ($returnhash{$version.':'.$id.'.type'} eq 'anonsurveycred')) { push(@hidden,$id); - $lasthidden{$id} = 1; - } elsif ($lasthidden{$id}) { - if (exists($returnhash{$version.':'.$id.'.award'})) { - delete($lasthidden{$id}); - } } } } @@ -3456,6 +3492,7 @@ sub get_previous_attempt { '<td>'.&mt('Transaction [_1]',$version).'</td>'; if (@hidden) { foreach my $key (sort(keys(%lasthash))) { + next if ($key =~ /\.foilorder$/); my $hide; foreach my $id (@hidden) { if ($key =~ /^\Q$id\E/) { @@ -3484,6 +3521,7 @@ sub get_previous_attempt { } } else { foreach my $key (sort(keys(%lasthash))) { + next if ($key =~ /\.foilorder$/); my $value = &format_previous_attempt_value($key, $returnhash{$version.':'.$key}); $prevattempts.='<td>'.$value.' </td>'; @@ -3495,6 +3533,7 @@ sub get_previous_attempt { my @currhidden = keys(%lasthidden); $prevattempts.=&start_data_table_row().'<td>'.&mt('Current').'</td>'; foreach my $key (sort(keys(%lasthash))) { + next if ($key =~ /\.foilorder$/); if (%typeparts) { my $hidden; foreach my $id (@currhidden) { @@ -3546,10 +3585,33 @@ sub get_previous_attempt { sub format_previous_attempt_value { my ($key,$value) = @_; - if ($key =~ /timestamp/) { + if (($key =~ /timestamp/) || ($key=~/duedate/)) { $value = &Apache::lonlocal::locallocaltime($value); } elsif (ref($value) eq 'ARRAY') { $value = '('.join(', ', @{ $value }).')'; + } elsif ($key =~ /answerstring$/) { + my %answers = &Apache::lonnet::str2hash($value); + my @anskeys = sort(keys(%answers)); + if (@anskeys == 1) { + my $answer = $answers{$anskeys[0]}; + if ($answer =~ m{\0}) { + $answer =~ s{\0}{,}g; + } + my $tag_internal_answer_name = 'INTERNAL'; + if ($anskeys[0] eq $tag_internal_answer_name) { + $value = $answer; + } else { + $value = $anskeys[0].'='.$answer; + } + } else { + foreach my $ans (@anskeys) { + my $answer = $answers{$ans}; + if ($answer =~ m{\0}) { + $answer =~ s{\0}{,}g; + } + $value .= $ans.'='.$answer.'<br />';; + } + } } else { $value = &unescape($value); } @@ -3828,7 +3890,9 @@ sub findallcourses { $udom = $env{'user.domain'}; } if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) { - my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname); + my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1}); + my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname,'.',undef, + $extra); if (!%roles) { %roles = ( cc => 1, @@ -4242,8 +4306,7 @@ sub get_domainconf { if (ref($domconfig{'login'}{$key}) eq 'HASH') { if ($key eq 'loginvia') { if (ref($domconfig{'login'}{'loginvia'}) eq 'HASH') { - my @ids = &Apache::lonnet::current_machine_ids(); - foreach my $hostname (@ids) { + foreach my $hostname (keys(%{$domconfig{'login'}{'loginvia'}})) { if (ref($domconfig{'login'}{'loginvia'}{$hostname}) eq 'HASH') { if ($domconfig{'login'}{'loginvia'}{$hostname}{'server'}) { my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'}; @@ -4252,7 +4315,7 @@ sub get_domainconf { $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'custompath'}; } else { - $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'}; + $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'}; } if ($domconfig{'login'}{'loginvia'}{$hostname}{'exempt'}) { $designhash{$udom.'.login.loginvia_exempt_'.$hostname} = $domconfig{'login'}{'loginvia'}{$hostname}{'exempt'}; @@ -4456,7 +4519,7 @@ Returns: HTML div with $content sub head_subbox { my ($content)=@_; my $output = - '<div id="LC_head_subbox">' + '<div class="LC_head_subbox">' .$content .'</div>' } @@ -4702,7 +4765,7 @@ sub bodytag { sub dc_courseid_toggle { my ($dc_info) = @_; - return ' <span id="dccidtext" class="LC_cusr_subheading">'. + return ' <span id="dccidtext" class="LC_cusr_subheading LC_nobreak">'. '<a href="javascript:showCourseID();">'. &mt('(More ...)').'</a></span>'. '<div id="dccid" class="LC_dccid">'.$dc_info.'</div>'; @@ -4895,6 +4958,10 @@ form, .inline { text-decoration:none; } +.LC_setting { + text-decoration:underline; +} + .LC_error { color: red; font-size: larger; @@ -5059,14 +5126,16 @@ td.LC_table_cell_checkbox { overflow: hidden; margin: 0; padding: 0; + text-align: left; } -#LC_head_subbox { +.LC_head_subbox { clear:both; background: #F8F8F8; /* $sidebg; */ border: 1px solid $sidebg; margin: 0 0 10px 0; padding: 3px; + text-align: left; } .LC_fontsize_medium { @@ -5089,6 +5158,7 @@ td.LC_table_cell_checkbox { li.LC_menubuttons_inline_text img,a { cursor:pointer; + text-decoration: none; } .LC_menubuttons_link { @@ -5136,14 +5206,6 @@ table.LC_nested { width: 100%; } -.ui-accordion, -.ui-accordion table.LC_data_table, -.ui-accordion table.LC_nested_outer{ - border: 0px; - border-spacing: 0px; - margin: 3px; -} - table.LC_data_table tr th, table.LC_calendar tr th, table.LC_prior_tries tr th, @@ -5259,22 +5321,6 @@ table.LC_nested tr td.LC_right_item { text-align: right; } -.ui-accordion table.LC_nested tr.LC_odd_row td.LC_left_item, -.ui-accordion table.LC_nested tr.LC_even_row td.LC_left_item { - text-align: right; - width: 40%; - padding-right:10px; - vertical-align: top; - padding: 5px; -} - -.ui-accordion table.LC_nested tr.LC_odd_row td.LC_right_item, -.ui-accordion table.LC_nested tr.LC_even_row td.LC_right_item { - text-align: left; - width: 60%; - padding: 2px 4px; -} - table.LC_nested tr.LC_odd_row td { background-color: #EEEEEE; } @@ -5433,6 +5479,14 @@ span.LC_parm_symb { color: #AAAAAA; } +ul.LC_parm_parmlist li { + display: inline-block; + padding: 0.3em 0.8em; + vertical-align: top; + width: 150px; + border-top:1px solid $lg_border_color; +} + td.LC_parm_overview_level_menu, td.LC_parm_overview_map_menu, td.LC_parm_overview_parm_selectors, @@ -6026,6 +6080,7 @@ fieldset > legend { #LC_nav_bar { float: left; + background-color: $pgbg_or_bgcolor; margin: 0 0 2px 0; } @@ -6034,6 +6089,7 @@ fieldset > legend { padding: 0; font-weight: bold; text-align: center; + background-color: $pgbg_or_bgcolor; } #LC_nav_bar em { @@ -6041,14 +6097,10 @@ fieldset > legend { font-style: normal; } -/* Preliminary fix to hide nav_bar inside bookmarks window */ -#LC_bookmarks #LC_nav_bar { - display:none; -} - ol.LC_primary_menu { float: right; margin: 0; + background-color: $pgbg_or_bgcolor; } ol#LC_PathBreadcrumbs { @@ -6088,6 +6140,18 @@ ol.LC_docs_parameters li { display: inline; } +ol.LC_docs_parameters li:before { + content: "\\002022 \\0020"; +} + +li.LC_docs_parameters_title { + font-weight: bold; +} + +ol.LC_docs_parameters li.LC_docs_parameters_title:before { + content: ""; +} + ul#LC_secondary_menu { clear: both; color: $fontmenu; @@ -6096,6 +6160,7 @@ ul#LC_secondary_menu { padding: 0; margin: 0; width: 100%; + text-align: left; } ul#LC_secondary_menu li { @@ -6229,7 +6294,6 @@ ul.LC_TabContentBigger li.active b { background:url('/adm/lonIcons/tabbgright.gif') right top no-repeat; color:$font; border: 0; - cursor:default; } @@ -6485,12 +6549,6 @@ ul.LC_funclist li { line-height: 150%; } -.ui-accordion .LC_advanced_toggle { - float: right; - font-size: 90%; - padding: 0px 4px -} - .LC_hidden { display: none; } @@ -6668,7 +6726,7 @@ $args - additional optional args support should it have jsmath forced on by the current page bread_crumbs -> Array containing breadcrumbs - bread_crumbs_components -> if exists show it as headline else show only the breadcrumbs + bread_crumbs_component -> if exists show it as headline else show only the breadcrumbs =back @@ -6832,6 +6890,19 @@ sub validate_page { } } + +sub start_scrollbox { + my ($outerwidth,$width,$height)=@_; + unless ($outerwidth) { $outerwidth='520px'; } + unless ($width) { $width='500px'; } + unless ($height) { $height='200px'; } + return "<table style='width: $outerwidth; border: 1px solid black;'><tr><td style='width: $width;' bgcolor='#FFFFFF'><div style='overflow:auto; width:$width; height: $height;'>"; +} + +sub end_scrollbox { + return '</td></tr></table>'; +} + sub simple_error_page { my ($r,$title,$msg) = @_; my $page = @@ -7047,7 +7118,8 @@ role status: active, previous or future. sub check_user_status { my ($udom,$uname,$cdom,$crs,$role,$sec) = @_; - my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname); + my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1}); + my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname,'.',undef,$extra); my @uroles = keys %userinfo; my $srchstr; my $active_chk = 'none'; @@ -7630,7 +7702,7 @@ sub get_secgrprole_info { } sub user_picker { - my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype) = @_; + my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype,$context) = @_; my $currdom = $dom; my %curr_selected = ( srchin => 'dom', @@ -7721,10 +7793,15 @@ sub user_picker { $srchtypesel .= "\n </select>\n"; my ($newuserscript,$new_user_create); - + my $context_dom = $env{'request.role.domain'}; + if ($context eq 'requestcrs') { + if ($env{'form.coursedom'} ne '') { + $context_dom = $env{'form.coursedom'}; + } + } if ($forcenewuser) { if (ref($srch) eq 'HASH') { - if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $env{'request.role.domain'}) { + if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $context_dom) { if ($cancreate) { $new_user_create = '<p> <input type="submit" name="forcenew" value="'.&HTML::Entities::encode(&mt('Make new user "[_1]"',$srchterm),'<>&"').'" onclick="javascript:setSearch(\'1\','.$caller.');" /> </p>'; } else { @@ -7763,7 +7840,7 @@ function setSearch(createnew,callingForm } } for (var i=0; i<callingForm.srchdomain.length; i++) { - if (callingForm.srchdomain.options[i].value == '$env{'request.role.domain'}') { + if (callingForm.srchdomain.options[i].value == '$context_dom') { callingForm.srchdomain.selectedIndex = i; } } @@ -8281,68 +8358,307 @@ sub get_env_multiple { sub ask_for_embedded_content { my ($actionurl,$state,$allfiles,$codebase,$args)=@_; - my $upload_output = ' - <form name="upload_embedded" action="'.$actionurl.'" - method="post" enctype="multipart/form-data">'; - $upload_output .= $state; - $upload_output .= '<b>Upload embedded files</b>:<br />'.&start_data_table(); - + my (%subdependencies,%dependencies,%mapping,%existing,%newfiles,%pathchanges); my $num = 0; - foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%{$allfiles})) { + my $numremref = 0; + my $numinvalid = 0; + my $numpathchg = 0; + my $numexisting = 0; + my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath); + if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { + my $current_path='/'; + if ($env{'form.currentpath'}) { + $current_path = $env{'form.currentpath'}; + } + if ($actionurl eq '/adm/coursegrp_portfolio') { + $udom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + $uname = $env{'course.'.$env{'request.course.id'}.'.num'}; + $url = '/userfiles/groups/'.$env{'form.group'}.'/portfolio'; + } else { + $udom = $env{'user.domain'}; + $uname = $env{'user.name'}; + $url = '/userfiles/portfolio'; + } + $toplevel = $url.'/'; + $url .= $current_path; + $getpropath = 1; + } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') || + ($actionurl eq '/adm/imsimport')) { + ($uname,my $rest) = ($args->{'current_path'} =~ m{/priv/($match_username)/?(.*)$}); + $url = '/home/'.$uname.'/public_html/'; + $toplevel = $url; + if ($rest ne '') { + $url .= $rest; + } + } elsif ($actionurl eq '/adm/coursedocs') { + if (ref($args) eq 'HASH') { + $url = $args->{'docs_url'}; + $toplevel = $url; + } + } + my $now = time(); + foreach my $embed_file (keys(%{$allfiles})) { + my $absolutepath; + if ($embed_file =~ m{^\w+://}) { + $newfiles{$embed_file} = 1; + $mapping{$embed_file} = $embed_file; + } else { + if ($embed_file =~ m{^/}) { + $absolutepath = $embed_file; + $embed_file =~ s{^(/+)}{}; + } + if ($embed_file =~ m{/}) { + my ($path,$fname) = ($embed_file =~ m{^(.+)/([^/]*)$}); + $path = &check_for_traversal($path,$url,$toplevel); + my $item = $fname; + if ($path ne '') { + $item = $path.'/'.$fname; + $subdependencies{$path}{$fname} = 1; + } else { + $dependencies{$item} = 1; + } + if ($absolutepath) { + $mapping{$item} = $absolutepath; + } else { + $mapping{$item} = $embed_file; + } + } else { + $dependencies{$embed_file} = 1; + if ($absolutepath) { + $mapping{$embed_file} = $absolutepath; + } else { + $mapping{$embed_file} = $embed_file; + } + } + } + } + foreach my $path (keys(%subdependencies)) { + my %currsubfile; + if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { + my @subdir_list = &Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath); + foreach my $line (@subdir_list) { + my ($file_name,$rest) = split(/\&/,$line,2); + $currsubfile{$file_name} = 1; + } + } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) { + if (opendir(my $dir,$url.'/'.$path)) { + my @subdir_list = grep(!/^\./,readdir($dir)); + map {$currsubfile{$_} = 1;} @subdir_list; + } + } + foreach my $file (keys(%{$subdependencies{$path}})) { + if ($currsubfile{$file}) { + my $item = $path.'/'.$file; + unless ($mapping{$item} eq $item) { + $pathchanges{$item} = 1; + } + $existing{$item} = 1; + $numexisting ++; + } else { + $newfiles{$path.'/'.$file} = 1; + } + } + } + my %currfile; + if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { + my @dir_list = &Apache::lonnet::dirlist($url,$udom,$uname,$getpropath); + foreach my $line (@dir_list) { + my ($file_name,$rest) = split(/\&/,$line,2); + $currfile{$file_name} = 1; + } + } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) { + if (opendir(my $dir,$url)) { + my @dir_list = grep(!/^\./,readdir($dir)); + map {$currfile{$_} = 1;} @dir_list; + } + } + foreach my $file (keys(%dependencies)) { + if ($currfile{$file}) { + unless ($mapping{$file} eq $file) { + $pathchanges{$file} = 1; + } + $existing{$file} = 1; + $numexisting ++; + } else { + $newfiles{$file} = 1; + } + } + foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) { $upload_output .= &start_data_table_row(). - '<td>'.$embed_file.'</td><td>'; + '<td><span class="LC_filename">'.$embed_file.'</span>'; + unless ($mapping{$embed_file} eq $embed_file) { + $upload_output .= '<br /><span class="LC_info" style="font-size:smaller;">'.&mt('changed from: [_1]',$mapping{$embed_file}).'</span>'; + } + $upload_output .= '</td><td>'; if ($args->{'ignore_remote_references'} && $embed_file =~ m{^\w+://}) { $upload_output.='<span class="LC_warning">'.&mt("URL points to other server.").'</span>'; + $numremref++; } elsif ($args->{'error_on_invalid_names'} && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) { - $upload_output.='<span class="LC_warning">'.&mt("Invalid characters").'</span>'; - + $upload_output.='<span class="LC_warning">'.&mt('Invalid characters').'</span>'; + $numinvalid++; } else { - $upload_output .=' - <input name="embedded_item_'.$num.'" type="file" value="" /> - <input name="embedded_orig_'.$num.'" type="hidden" value="'.&escape($embed_file).'" />'; - my $attrib = join(':',@{$$allfiles{$embed_file}}); - $upload_output .= - "\n\t\t". - '<input name="embedded_attrib_'.$num.'" type="hidden" value="'. - $attrib.'" />'; - if (exists($$codebase{$embed_file})) { - $upload_output .= - "\n\t\t". - '<input name="codebase_'.$num.'" type="hidden" value="'. - &escape($$codebase{$embed_file}).'" />'; - } - } - $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row(); - $num++; - } - $upload_output .= &Apache::loncommon::end_data_table().'<br /> - <input type ="hidden" name="number_embedded_items" value="'.$num.'" /> - <input type ="submit" value="'.&mt('Upload Listed Files').'" /> - '.&mt('(only files for which a location has been provided will be uploaded)').' - </form>'; - return $upload_output; + $upload_output .= &embedded_file_element('upload_embedded',$num, + $embed_file,\%mapping, + $allfiles,$codebase); + $num++; + } + $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row()."\n"; + } + foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%existing)) { + $upload_output .= &start_data_table_row(). + '<td><span class="LC_filename">'.$embed_file.'</span></td>'. + '<td><span class="LC_warning">'.&mt('Already exists').'</span></td>'. + &Apache::loncommon::end_data_table_row()."\n"; + } + if ($upload_output) { + $upload_output = &start_data_table(). + $upload_output. + &end_data_table()."\n"; + } + my $applies = 0; + if ($numremref) { + $applies ++; + } + if ($numinvalid) { + $applies ++; + } + if ($numexisting) { + $applies ++; + } + if ($num) { + $output = '<form name="upload_embedded" action="'.$actionurl.'"'. + ' method="post" enctype="multipart/form-data">'."\n". + $state. + '<h3>'.&mt('Upload embedded files'). + ':</h3>'.$upload_output.'<br />'."\n". + '<input type ="hidden" name="number_embedded_items" value="'. + $num.'" />'."\n"; + if ($actionurl eq '') { + $output .= '<input type="hidden" name="phase" value="three" />'; + } + } elsif ($applies) { + $output = '<b>'.&mt('Referenced files').'</b>:<br />'; + if ($applies > 1) { + $output .= + &mt('No files need to be uploaded, as one of the following applies to each reference:').'<ul>'; + if ($numremref) { + $output .= '<li>'.&mt('reference is to a URL which points to another server').'</li>'."\n"; + } + if ($numinvalid) { + $output .= '<li>'.&mt('reference is to file with a name containing invalid characters').'</li>'."\n"; + } + if ($numexisting) { + $output .= '<li>'.&mt('reference is to an existing file at the specified location').'</li>'."\n"; + } + $output .= '</ul><br />'; + } elsif ($numremref) { + $output .= '<p>'.&mt('None to upload, as all references are to URLs pointing to another server.').'</p>'; + } elsif ($numinvalid) { + $output .= '<p>'.&mt('None to upload, as all references are to files with names containing invalid characters.').'</p>'; + } elsif ($numexisting) { + $output .= '<p>'.&mt('None to upload, as all references are to existing files.').'</p>'; + } + $output .= $upload_output.'<br />'; + } + my ($pathchange_output,$chgcount); + $chgcount = $num; + if (keys(%pathchanges) > 0) { + foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%pathchanges)) { + if ($num) { + $output .= &embedded_file_element('pathchange',$chgcount, + $embed_file,\%mapping, + $allfiles,$codebase); + } else { + $pathchange_output .= + &start_data_table_row(). + '<td><input type ="checkbox" name="namechange" value="'. + $chgcount.'" checked="checked" /></td>'. + '<td>'.$mapping{$embed_file}.'</td>'. + '<td>'.$embed_file. + &embedded_file_element('pathchange',$numpathchg,$embed_file, + \%mapping,$allfiles,$codebase). + '</td>'.&end_data_table_row(); + } + $numpathchg ++; + $chgcount ++; + } + } + if ($num) { + if ($numpathchg) { + $output .= '<input type ="hidden" name="number_pathchange_items" value="'. + $numpathchg.'" />'."\n"; + } + if (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') || + ($actionurl eq '/adm/imsimport')) { + $output .= '<input type="hidden" name="phase" value="three" />'."\n"; + } elsif ($actionurl eq '/adm/portfolio' || $actionurl eq '/adm/coursegrp_portfolio') { + $output .= '<input type="hidden" name="action" value="upload_embedded" />'; + } + $output .= '<input type ="submit" value="'.&mt('Upload Listed Files').'" />'."\n". + &mt('(only files for which a location has been provided will be uploaded)').'</form>'."\n"; + } elsif ($numpathchg) { + my %pathchange = (); + $output .= &modify_html_form('pathchange',$actionurl,$state,\%pathchange,$pathchange_output); + if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { + $output .= '<p>'.&mt('or').'</p>'; + } + } + return ($output,$num,$numpathchg); +} + +sub embedded_file_element { + my ($context,$num,$embed_file,$mapping,$allfiles,$codebase) = @_; + return unless ((ref($mapping) eq 'HASH') && (ref($allfiles) eq 'HASH') && + (ref($codebase) eq 'HASH')); + my $output; + if ($context eq 'upload_embedded') { + $output = '<input name="embedded_item_'.$num.'" type="file" value="" />'."\n"; + } + $output .= '<input name="embedded_orig_'.$num.'" type="hidden" value="'. + &escape($embed_file).'" />'; + unless (($context eq 'upload_embedded') && + ($mapping->{$embed_file} eq $embed_file)) { + $output .=' + <input name="embedded_ref_'.$num.'" type="hidden" value="'.&escape($mapping->{$embed_file}).'" />'; + } + my $attrib; + if (ref($allfiles->{$mapping->{$embed_file}}) eq 'ARRAY') { + $attrib = &escape(join(':',@{$allfiles->{$mapping->{$embed_file}}})); + } + $output .= + "\n\t\t". + '<input name="embedded_attrib_'.$num.'" type="hidden" value="'. + $attrib.'" />'; + if (exists($codebase->{$mapping->{$embed_file}})) { + $output .= + "\n\t\t". + '<input name="codebase_'.$num.'" type="hidden" value="'. + &escape($codebase->{$mapping->{$embed_file}}).'" />'; + } + return $output; } sub upload_embedded { my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota, - $current_disk_usage) = @_; - my $output; + $current_disk_usage,$hiddenstate,$actionurl) = @_; + my (%pathchange,$output,$modifyform,$footer,$returnflag); for (my $i=0; $i<$env{'form.number_embedded_items'}; $i++) { next if (!exists($env{'form.embedded_item_'.$i.'.filename'})); my $orig_uploaded_filename = $env{'form.embedded_item_'.$i.'.filename'}; - - $env{'form.embedded_orig_'.$i} = - &unescape($env{'form.embedded_orig_'.$i}); + foreach my $type ('orig','ref','attrib','codebase') { + if ($env{'form.embedded_'.$type.'_'.$i} ne '') { + $env{'form.embedded_'.$type.'_'.$i} = + &unescape($env{'form.embedded_'.$type.'_'.$i}); + } + } my ($path,$fname) = ($env{'form.embedded_orig_'.$i} =~ m{(.*/)([^/]*)}); # no path, whole string is fname if (!$fname) { $fname = $env{'form.embedded_orig_'.$i} }; - - $path = $env{'form.currentpath'}.$path; $fname = &Apache::lonnet::clean_filename($fname); # See if there is anything left next if ($fname eq ''); @@ -8354,12 +8670,12 @@ sub upload_embedded { if ($group ne '') { $port_path = "groups/$group/$port_path"; } - ($state,$msg) = &check_for_upload($path,$fname,$group,'embedded_item_'.$i, + ($state,$msg) = &check_for_upload($env{'form.currentpath'}.$path, + $fname,$group,'embedded_item_'.$i, $dir_root,$port_path,$disk_quota, $current_disk_usage,$uname,$udom); if ($state eq 'will_exceed_quota' - || $state eq 'file_locked' - || $state eq 'file_exists' ) { + || $state eq 'file_locked') { $output .= $msg; next; } @@ -8373,31 +8689,53 @@ sub upload_embedded { # Check if extension is valid if (($fname =~ /\.(\w+)$/) && (&Apache::loncommon::fileembstyle($1) eq 'hdn')) { - $output .= &mt('Invalid file extension ([_1]) - reserved for LONCAPA use - rename the file with a different extension and re-upload. ',$1); + $output .= &mt('Invalid file extension ([_1]) - reserved for LONCAPA use - rename the file with a different extension and re-upload. ',$1).'<br />'; next; } elsif (($fname =~ /\.(\w+)$/) && (!defined(&Apache::loncommon::fileembstyle($1)))) { - $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1); + $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1).'<br />'; next; } elsif ($fname=~/\.(\d+)\.(\w+)$/) { - $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2); + $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2).'<br />'; next; } $env{'form.embedded_item_'.$i.'.filename'}=$fname; if ($context eq 'portfolio') { - my $result= - &Apache::lonnet::userfileupload('embedded_item_'.$i,'', - $dirpath.$path); + my $result; + if ($state eq 'existingfile') { + $result= + &Apache::lonnet::userfileupload('embedded_item_'.$i,'existingfile', + $dirpath.$env{'form.currentpath'}.$path); + } else { + $result= + &Apache::lonnet::userfileupload('embedded_item_'.$i,'', + $dirpath. + $env{'form.currentpath'}.$path); + if ($result !~ m|^/uploaded/|) { + $output .= '<span class="LC_error">' + .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].' + ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}) + .'</span><br />'; + next; + } else { + $output .= &mt('Uploaded [_1]','<span class="LC_filename">'. + $path.$fname.'</span>').'<br />'; + } + } + } elsif ($context eq 'coursedoc') { + my $result = + &Apache::lonnet::userfileupload('embedded_item_'.$i,'coursedoc', + $dirpath.'/'.$path); if ($result !~ m|^/uploaded/|) { $output .= '<span class="LC_error">' - .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].' + .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].' ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}) - .'</span><br />'; - next; + .'</span><br />'; + next; } else { - $output .= '<p>'.&mt('Uploaded [_1]','<span class="LC_filename">'. - $path.$fname.'</span>').'</p>'; + $output .= &mt('Uploaded [_1]','<span class="LC_filename">'. + $path.$fname.'</span>').'<br />'; } } else { # Save the file @@ -8427,19 +8765,190 @@ sub upload_embedded { &mt('An error occurred while writing the file [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}). '</span><br />'; } else { - if ($context eq 'testbank') { - $output .= &mt('Embedded file uploaded successfully:'). - ' <a href="'.$url.'">'. - $orig_uploaded_filename.'</a><br />'; - } else { - $output .= '<span class=\"LC_fontsize_large\">'. - &mt('View embedded file: [_1]','<a href="'.$url.'">'. - $orig_uploaded_filename.'</a>').'</span><br />'; + $output .= &mt('Uploaded [_1]','<span class="LC_filename">'. + $url.'</span>').'<br />'; + unless ($context eq 'testbank') { + $footer .= &mt('View embedded file: [_1]', + '<a href="'.$url.'">'.$fname.'</a>').'<br />'; } } close($fh); } } + if ($env{'form.embedded_ref_'.$i}) { + $pathchange{$i} = 1; + } + } + if ($output) { + $output = '<p>'.$output.'</p>'; + } + $output .= &modify_html_form('upload_embedded',$actionurl,$hiddenstate,\%pathchange); + $returnflag = 'ok'; + if (keys(%pathchange) > 0) { + if ($context eq 'portfolio') { + $output .= '<p>'.&mt('or').'</p>'; + } elsif ($context eq 'testbank') { + $output .= '<p>'.&mt('Or [_1]continue[_2] the testbank import without modifying the reference(s).','<a href="javascript:document.testbankForm.submit();">','</a>').'</p>'; + $returnflag = 'modify_orightml'; + } + } + return ($output.$footer,$returnflag); +} + +sub modify_html_form { + my ($context,$actionurl,$hiddenstate,$pathchange,$pathchgtable) = @_; + my $end = 0; + my $modifyform; + if ($context eq 'upload_embedded') { + return unless (ref($pathchange) eq 'HASH'); + if ($env{'form.number_embedded_items'}) { + $end += $env{'form.number_embedded_items'}; + } + if ($env{'form.number_pathchange_items'}) { + $end += $env{'form.number_pathchange_items'}; + } + if ($end) { + for (my $i=0; $i<$end; $i++) { + if ($i < $env{'form.number_embedded_items'}) { + next unless($pathchange->{$i}); + } + $modifyform .= + &start_data_table_row(). + '<td><input type ="checkbox" name="namechange" value="'.$i.'" '. + 'checked="checked" /></td>'. + '<td>'.$env{'form.embedded_ref_'.$i}. + '<input type="hidden" name="embedded_ref_'.$i.'" value="'. + &escape($env{'form.embedded_ref_'.$i}).'" />'. + '<input type="hidden" name="embedded_codebase_'.$i.'" value="'. + &escape($env{'form.embedded_codebase_'.$i}).'" />'. + '<input type="hidden" name="embedded_attrib_'.$i.'" value="'. + &escape($env{'form.embedded_attrib_'.$i}).'" /></td>'. + '<td>'.$env{'form.embedded_orig_'.$i}. + '<input type="hidden" name="embedded_orig_'.$i.'" value="'. + &escape($env{'form.embedded_orig_'.$i}).'" /></td>'. + &end_data_table_row(); + } + } + } else { + $modifyform = $pathchgtable; + if (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) { + $hiddenstate .= '<input type="hidden" name="phase" value="four" />'; + } elsif (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { + $hiddenstate .= '<input type="hidden" name="action" value="modify_orightml" />'; + } + } + if ($modifyform) { + return '<h3>'.&mt('Changes in content of HTML file required').'</h3>'."\n". + '<p>'.&mt('Changes need to be made to the reference(s) used for one or more of the dependencies, if your HTML file is to work correctly:').'<ol>'."\n". + '<li>'.&mt('For consistency between the reference(s) and the location of the corresponding stored file within LON-CAPA.').'</li>'."\n". + '<li>'.&mt('To change absolute paths to relative paths, or replace directory traversal via "../" within the original reference.').'</li>'."\n". + '</ol></p>'."\n".'<p>'. + &mt('LON-CAPA can make the required changes to your HTML file.').'</p>'."\n". + '<form method="post" name="refchanger" action="'.$actionurl.'">'. + &start_data_table()."\n". + &start_data_table_header_row(). + '<th>'.&mt('Change?').'</th>'. + '<th>'.&mt('Current reference').'</th>'. + '<th>'.&mt('Required reference').'</th>'. + &end_data_table_header_row()."\n". + $modifyform. + &end_data_table().'<br />'."\n".$hiddenstate. + '<input type="submit" name="pathchanges" value="'.&mt('Modify HTML file').'" />'. + '</form>'."\n"; + } + return; +} + +sub modify_html_refs { + my ($context,$dirpath,$uname,$udom,$dir_root) = @_; + my $container; + if ($context eq 'portfolio') { + $container = $env{'form.container'}; + } elsif ($context eq 'coursedoc') { + $container = $env{'form.primaryurl'}; + } else { + $container = $env{'form.filename'}; + $container =~ s{^/priv/(\Q$uname\E)/(.*)}{/home/$1/public_html/$2}; + } + my (%allfiles,%codebase,$output,$content); + my @changes = &get_env_multiple('form.namechange'); + return unless (@changes > 0); + if (($context eq 'portfolio') || ($context eq 'coursedoc')) { + return unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/}); + $content = &Apache::lonnet::getfile($container); + return if ($content eq '-1'); + } else { + return unless ($container =~ /^\Q$dir_root\E/); + if (open(my $fh,"<$container")) { + $content = join('', <$fh>); + close($fh); + } else { + return; + } + } + my ($count,$codebasecount) = (0,0); + my $mm = new File::MMagic; + my $mime_type = $mm->checktype_contents($content); + if ($mime_type eq 'text/html') { + my $parse_result = + &Apache::lonnet::extract_embedded_items($container,\%allfiles, + \%codebase,\$content); + if ($parse_result eq 'ok') { + foreach my $i (@changes) { + my $orig = &unescape($env{'form.embedded_orig_'.$i}); + my $ref = &unescape($env{'form.embedded_ref_'.$i}); + if ($allfiles{$ref}) { + my $newname = $orig; + my ($attrib_regexp,$codebase); + $attrib_regexp = &unescape($env{'form.embedded_attrib_'.$i}); + if ($attrib_regexp =~ /:/) { + $attrib_regexp =~ s/\:/|/g; + } + if ($content =~ m{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}) { + my $numchg = ($content =~ s{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi); + $count += $numchg; + } + if ($env{'form.embedded_codebase_'.$i} ne '') { + $codebase = &unescape($env{'form.embedded_codebase_'.$i}); + my $numchg = ($content =~ s/(codebase\s*=\s*["']?)\Q$codebase\E(["']?)/$1.$2/i); #' stupid emacs + $codebasecount ++; + } + } + } + if ($count || $codebasecount) { + my $saveresult; + if ($context eq 'portfolio' || $context eq 'coursedoc') { + my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult); + if ($url eq $container) { + my ($fname) = ($container =~ m{/([^/]+)$}); + $output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].', + $count,'<span class="LC_filename">'. + $fname.'</span>').'</p>'; + } else { + $output = '<p class="LC_error">'. + &mt('Error: update failed for: [_1].', + '<span class="LC_filename">'. + $container.'</span>').'</p>'; + } + } else { + if (open(my $fh,">$container")) { + print $fh $content; + close($fh); + $output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].', + $count,'<span class="LC_filename">'. + $container.'</span>').'</p>'; + } else { + $output = '<p class="LC_error">'. + &mt('Error: could not update [_1].', + '<span class="LC_filename">'. + $container.'</span>').'</p>'; + } + } + } + } else { + &logthis('Failed to parse '.$container. + ' to modify references: '.$parse_result); + } } return $output; } @@ -8463,22 +8972,71 @@ sub check_for_existing { sub check_for_upload { my ($path,$fname,$group,$element,$portfolio_root,$port_path, $disk_quota,$current_disk_usage,$uname,$udom) = @_; - my $filesize = (length($env{'form.'.$element})) / 1000; #express in k (1024?) + my $filesize = length($env{'form.'.$element}); + if (!$filesize) { + my $msg = '<span class="LC_error">'. + &mt('Unable to upload [_1]. (size = [_2] bytes)', + '<span class="LC_filename">'.$fname.'</span>', + $filesize).'<br />'. + &mt('Either the file you attempted to upload was empty, or your web browser was unable to read its contents.').'<br />'. + '</span>'; + return ('zero_bytes',$msg); + } + $filesize = $filesize/1000; #express in k (1024?) my $getpropath = 1; my @dir_list = &Apache::lonnet::dirlist($portfolio_root.$path,$udom,$uname, $getpropath); my $found_file = 0; my $locked_file = 0; + my @lockers; + my $navmap; + if ($env{'request.course.id'}) { + $navmap = Apache::lonnavmaps::navmap->new(); + } foreach my $line (@dir_list) { - my ($file_name)=split(/\&/,$line,2); + my ($file_name,$rest)=split(/\&/,$line,2); if ($file_name eq $fname){ $file_name = $path.$file_name; if ($group ne '') { $file_name = $group.$file_name; } $found_file = 1; - if (&Apache::lonnet::is_locked($file_name,$udom,$uname) eq 'true') { - $locked_file = 1; + if (&Apache::lonnet::is_locked($file_name,$udom,$uname,\@lockers) eq 'true') { + foreach my $lock (@lockers) { + if (ref($lock) eq 'ARRAY') { + my ($symb,$crsid) = @{$lock}; + if ($crsid eq $env{'request.course.id'}) { + if (ref($navmap)) { + my $res = $navmap->getBySymb($symb); + foreach my $part (@{$res->parts()}) { + my ($slot_status,$slot_time,$slot_name)=$res->check_for_slot($part); + unless (($slot_status == $res->RESERVED) || + ($slot_status == $res->RESERVED_LOCATION)) { + $locked_file = 1; + } + } + } else { + $locked_file = 1; + } + } else { + $locked_file = 1; + } + } + } + } else { + my @info = split(/\&/,$rest); + my $currsize = $info[6]/1000; + if ($currsize < $filesize) { + my $extra = $filesize - $currsize; + if (($current_disk_usage + $extra) > $disk_quota) { + my $msg = '<span class="LC_error">'. + &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded if existing (smaller) file with same name (size = [_3] kilobytes) is replaced.', + '<span class="LC_filename">'.$fname.'</span>',$filesize,$currsize).'</span>'. + '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.', + $disk_quota,$current_disk_usage); + return ('will_exceed_quota',$msg); + } + } } } } @@ -8496,15 +9054,55 @@ sub check_for_upload { return ('file_locked',$msg); } else { my $msg = '<span class="LC_error">'; - $msg .= &mt('Unable to upload [_1]. A file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$port_path.$env{'form.currentpath'}); + $msg .= &mt(' A file by that name: [_1] was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$port_path.$env{'form.currentpath'}); $msg .= '</span>'; - $msg .= '<br />'; - $msg .= &mt('To upload, rename or delete existing [_1] in [_2].','<span class="LC_filename">'.$fname.'</span>', $port_path.$env{'form.currentpath'}); - return ('file_exists',$msg); + return ('existingfile',$msg); } } } +sub check_for_traversal { + my ($path,$url,$toplevel) = @_; + my @parts=split(/\//,$path); + my $cleanpath; + my $fullpath = $url; + for (my $i=0;$i<@parts;$i++) { + next if ($parts[$i] eq '.'); + if ($parts[$i] eq '..') { + $fullpath =~ s{([^/]+/)$}{}; + } else { + $fullpath .= $parts[$i].'/'; + } + } + if ($fullpath =~ /^\Q$url\E(.*)$/) { + $cleanpath = $1; + } elsif ($fullpath =~ /^\Q$toplevel\E(.*)$/) { + my $curr_toprel = $1; + my @parts = split(/\//,$curr_toprel); + my ($url_toprel) = ($url =~ /^\Q$toplevel\E(.*)$/); + my @urlparts = split(/\//,$url_toprel); + my $doubledots; + my $startdiff = -1; + for (my $i=0; $i<@urlparts; $i++) { + if ($startdiff == -1) { + unless ($urlparts[$i] eq $parts[$i]) { + $startdiff = $i; + $doubledots .= '../'; + } + } else { + $doubledots .= '../'; + } + } + if ($startdiff > -1) { + $cleanpath = $doubledots; + for (my $i=$startdiff; $i<@parts; $i++) { + $cleanpath .= $parts[$i].'/'; + } + } + } + $cleanpath =~ s{(/)$}{}; + return $cleanpath; +} =pod @@ -10637,15 +11235,20 @@ sub init_user_environment { $env{'browser.interface'}=$form->{'interface'}; } + my %is_adv = ( is_adv => $env{'user.adv'} ); + my %domdef = &Apache::lonnet::get_domain_defaults($domain); + foreach my $tool ('aboutme','blog','portfolio') { $userenv{'availabletools.'.$tool} = - &Apache::lonnet::usertools_access($username,$domain,$tool,'reload'); + &Apache::lonnet::usertools_access($username,$domain,$tool,'reload', + undef,\%userenv,\%domdef,\%is_adv); } foreach my $crstype ('official','unofficial','community') { $userenv{'canrequest.'.$crstype} = &Apache::lonnet::usertools_access($username,$domain,$crstype, - 'reload','requestcourses'); + 'reload','requestcourses', + \%userenv,\%domdef,\%is_adv); } $env{'user.environment'} = "$lonids/$cookie.id"; @@ -10724,6 +11327,36 @@ sub clean_symb { return ($symb,$enc); } +sub build_release_hashes { + my ($checkparms,$checkresponsetypes,$checkcrstypes,$anonsurvey,$randomizetry) = @_; + return unless((ref($checkparms) eq 'HASH') && (ref($checkresponsetypes) eq 'HASH') && + (ref($checkcrstypes) eq 'HASH') && (ref($anonsurvey) eq 'HASH') && + (ref($randomizetry) eq 'HASH')); + foreach my $key (keys(%Apache::lonnet::needsrelease)) { + my ($item,$name,$value) = split(/:/,$key); + if ($item eq 'parameter') { + if (ref($checkparms->{$name}) eq 'ARRAY') { + unless(grep(/^\Q$name\E$/,@{$checkparms->{$name}})) { + push(@{$checkparms->{$name}},$value); + } + } else { + push(@{$checkparms->{$name}},$value); + } + } elsif ($item eq 'resourcetag') { + if ($name eq 'responsetype') { + $checkresponsetypes->{$value} = $Apache::lonnet::needsrelease{$key} + } + } elsif ($item eq 'course') { + if ($name eq 'crstype') { + $checkcrstypes->{$value} = $Apache::lonnet::needsrelease{$key}; + } + } + } + ($anonsurvey->{major},$anonsurvey->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:anonsurvey'}); + ($randomizetry->{major},$randomizetry->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:randomizetry'}); + return; +} + =pod =back