--- loncom/interface/londocs.pm 2024/12/27 02:32:55 1.714 +++ loncom/interface/londocs.pm 2025/01/07 03:51:55 1.720 @@ -1,7 +1,7 @@ # The LearningOnline Network # Documents # -# $Id: londocs.pm,v 1.714 2024/12/27 02:32:55 raeburn Exp $ +# $Id: londocs.pm,v 1.720 2025/01/07 03:51:55 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -579,7 +579,8 @@ $contents{webreferences}.' $title=~s/[\/\s]+/\_/gs; $title=&clean($title); my $formname = 'dumpdoc'; - my $preamble = &authorspace_selector($r,$formname,$home,$title,%outhash); + my $preamble = &authorspace_selector($r,$formname,$home,$title,%outhash). + '<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n"; my %uploadedfiles; &tiehash(); foreach my $file (&Apache::lonclonecourse::crsdirlist($origcrsid,'userfiles')) { @@ -643,8 +644,8 @@ sub authorspace_selector { } $preamble .= '<div class="LC_left_float">'. '<fieldset><legend>'.&mt('Folder in Authoring Space').'</legend>'. - '<input type="text" size="50" name="authorfolder" value="'.$title.'" />'."\n". - '</fieldset></div><div style="padding:0;clear:both;margin:0;border:0"></div>'."\n"; + '<input type="text" size="30" name="authorfolder" value="'.$title.'" />'."\n". + '</fieldset></div>'."\n"; return $preamble; } @@ -694,9 +695,70 @@ sub recurse_html { sub copycrsauthored { my ($r,$coursenum,$coursedom,$coursehome,$readonly) = @_; - my ($starthash,$js); + my ($starthash,$js,$title,$formname); + my %origcrsdata=&Apache::lonnet::coursedescription($env{'request.course.id'}); + $title=$origcrsdata{'description'}; + $title=~s/[\/\s]+/\_/gs; + $title=&clean($title); + my ($home,$other,%outhash)=&authorhosts(); unless (($env{'form.authorspace'}) && ($env{'form.authorfolder'}=~/\w/)) { - $js = <<"ENDJS"; + my %js_lt; + $formname = 'copycrsauthored'; + if ($home) { + %js_lt = + &Apache::lonlocal::texthash( + yomu => 'You must select an Authoring Space', + whco => 'When Copyright set to "custom", URL of a published rights file is needed.', + ); + &js_escape(\%js_lt); + } + if ($home > 1) { + $js = <<"ENDJS"; +<script type="text/javascript"> +// <![CDATA[ + +function validCrsCopy() { + var dest = document.$formname.authorspace.options[document.$formname.authorspace.selectedIndex].value; + if (dest == '') { + alert("$js_lt{'yomu'}"); + return false; + } + var dist = document.$formname.copyright.options[document.$formname.copyright.selectedIndex].value; + if (dist == 'custom') { + if (document.$formname.customrights.value == '') { + alert("$js_lt{'whco'}"); + return false; + } + } + return true; +} + +function init_copycrs_form() { + document.$formname.authorspace.selectedIndex = "0"; + document.$formname.authorfolder.value = '$title'; + document.$formname.copyright.selectedIndex = "0"; +} + +// ]]> +</script> + +ENDJS + } elsif ($home) { + $js = <<"ENDJS"; +<script type="text/javascript"> +// <![CDATA[ + +function init_copycrs_form() { + document.$formname.authorfolder.value = '$title'; + document.$formname.copyright.selectedIndex = "0"; +} + +// ]]> +</script> + +ENDJS + } + $js .= <<"ENDJS"; <script type="text/javascript"> // <![CDATA[ @@ -707,31 +769,45 @@ function hide_searching() { return; } +function showHideCustom(caller,divid) { + if (document.getElementById(divid)) { + if (caller.options[caller.selectedIndex].value == 'custom') { + document.getElementById(divid).style.display="inline-block"; + } else { + document.getElementById(divid).style.display="none"; + } + } + return; +} + // ]]> </script> ENDJS + + $js .= "\n".&Apache::lonhtmlcommon::scripttag(&Apache::loncommon::browser_and_searcher_javascript())."\n"; $starthash = { - add_entries => {'onload' => "hide_searching();"}, + add_entries => {'onload' => "hide_searching(); init_copycrs_form();"}, }; } $r->print(&Apache::loncommon::start_page('Copy from Course Authoring to User Authoring',$js,$starthash)."\n". &Apache::lonhtmlcommon::breadcrumbs('Copy from Course Authoring Space')."\n"); $r->print(&startContentScreen('tools')); - my ($home,$other,%outhash)=&authorhosts(); unless ($home) { $r->print('<p class="LC_info">'.&mt('No author or co-author roles on this server.').'</p>'); $r->print(&endContentScreen()); return ''; } + my $docroot = $r->dir_config('lonDocRoot'); my $is_course_home; my @ids=&Apache::lonnet::current_machine_ids(); if (($coursehome ne '') && (grep(/^\Q$coursehome\E$/,@ids))) { $is_course_home = 1; } - my %origcrsdata=&Apache::lonnet::coursedescription($env{'request.course.id'}); my $exclude = &Apache::lonnet::priv_exclude(); my $srcurl = "/priv/$coursedom/$coursenum"; - my $srctop = $r->dir_config('lonDocRoot').$srcurl; + my $srctop = $docroot.$srcurl; + my $resurl = "/res/$coursedom/$coursenum"; + my $res_exclude = &Apache::lonnet::res_exclude(); if (($env{'form.authorspace'}) && ($env{'form.authorfolder'}=~/\w/)) { $r->print('<h3>'.&mt('Copying Files and/or Sub-directories').'</h3>'); if ($readonly) { @@ -748,7 +824,8 @@ ENDJS } my ($ca,$cd)=split(/\:/,$env{'form.authorspace'}); my $desturl = "/priv/$cd/$ca"; - my $desttop = $r->dir_config('lonDocRoot').$desturl; + my $destresurl = "/res/$cd/$ca"; + my $desttop = $docroot.$desturl; my $subdir = &clean($env{'form.authorfolder'}); $subdir = &cleandir($subdir); if ($subdir eq '') { @@ -806,10 +883,8 @@ ENDJS } if (keys(%tocopy)) { my (%resdirs,%resfiles); - my $resurl = "/res/$coursedom/$coursenum"; - my $res_exclude = &Apache::lonnet::res_exclude(); &Apache::lonnet::recursedirs($is_course_home,1,undef,$res_exclude,0,0,$resurl,'',\%resdirs,\%resfiles); - my ($notopdir,%newdir,%newfile,%checkdeps); + my ($notopdir,%newdir,%newfile,%checkdeps,%newresfile); $r->print('<p>'.&mt('Copy to: [_1]', '<span class="LC_filename">'.$desturl.'/'.$subdir.'</span>'). '</p>'."\n"); @@ -851,6 +926,39 @@ ENDJS } if (-e $desttop.'/'.$subdir) { my $num = 0; + my ($copyright,$customdistfile); + if ($env{'form.copyright'} eq 'default' || $env{'form.copyright'} eq 'domain' || $env{'form.copyright'} eq 'public') { + $copyright = $env{'form.copyright'}; + } elsif ($env{'form.copyright'} eq 'custom') { + if ($env{'form.customrights'} =~ m{^/res/$match_domain/$match_username/.+\.rights$}) { + my ($rightsdom,$rightsuname) = ($1,$2); + my $rightshome = &Apache::lonnet::homeserver($rightsdom,$rightsuname); + if (($rightshome eq 'no_host') || ($rightshome eq '')) { + $copyright = 'default'; + } elsif (grep(/^\Q$rightshome\E$/,@ids)) { + if (-e $docroot.$env{'form.customrights'}) { + $copyright = 'custom'; + $customdistfile = $env{'form.customrights'}; + } else { + $copyright = 'default'; + } + } else { + my $rightsfile = &Apache::lonnet::filelocation('',$env{'form.customrights'}); + unless (&Apache::lonnet::getfile($rightsfile) eq '-1') { + $customdistfile = $env{'form.customrights'}; + } + } + } + } + my $sourceavail; + if ($env{'form.sourceavail'} =~ /^(open|closed)$/) { + $sourceavail = $env{'form.sourceavail'}; + } + my $respublish; + if ($env{'form.respublish'}) { + $respublish = 1; + } + my $nokeyref = &Apache::lonpublisher::getnokey($r->dir_config('lonIncludes')); foreach my $file (keys(%files_to_copy)) { my ($fail,$dup,$dir_is_file,$src,$dest,$path,$fname); if ($file =~ m{/}) { @@ -887,212 +995,164 @@ ENDJS '<span class="LC_filename">'.$desturl.'/'.$subdir.'/'.$file.'</span>'). '</p>'."\n"); } elsif (($src ne '') && ($dest ne '')) { - if ($is_course_home) { - if (&File::Copy::copy($src,$dest)) { - $newfile{$file} = 1; - } - } else { - if (&Apache::lonnet::repcopy_crsprivfile($srcurl.'/'.$file,$dest) eq 'ok') { - $newfile{$file} = 1; + my $ressrc = $docroot.$resurl.'/'.$file; + my $ressrcmeta = $ressrc.'.meta'; + my ($ext) = ($file =~ /\.(\w+)$/); + my $embstyle=&Apache::loncommon::fileembstyle($ext); + my ($getres,$getresmeta); + if ($respublish) { + if ($path eq '') { + if ((ref($resfiles{'/'}) eq 'HASH') && + (exists($resfiles{'/'}{$fname}))) { + $getres = 1; + $getresmeta = 1; + } + } elsif ((ref($resfiles{$path}) eq 'HASH') && + (exists($resfiles{$path}{$fname}))) { + $getres = 1; + $getresmeta = 1; } } - if ($newfile{$file}) { - my $gotmeta; - if ($is_course_home) { - if ((-e $src.'.meta') && (!-e $dest.'.meta')) { - if (&File::Copy::copy($src.'.meta',$dest.'.meta')) { - $gotmeta = 1; + if ($is_course_home) { + my ($needpriv,$needprivmeta); + if ($respublish) { + if ($getres) { + if (&Apache::londiff::are_different_files($src,$ressrc)) { + $needpriv = 1; + if (&File::Copy::copy($ressrc,$dest)) { + if ($embstyle eq 'ssi') { + &crsres_fixup($dest,$coursenum,$coursedom,$ca,$cd); + } + } + } else { + if (&File::Copy::copy($src,$dest)) { + $newfile{$file} = $desturl.'/'.$subdir.'/'.$file; + if ($embstyle eq 'ssi') { + &crsres_fixup($dest,$coursenum,$coursedom,$ca,$cd,$subdir); + } + } } + } else { + $needpriv = 1; } - } else { - if (&Apache::lonnet::repcopy_crsprivfile($srcurl.'/'.$file.'.meta',$dest.'.meta') eq 'ok') { - $gotmeta = 1; - } - } - if ($gotmeta) { - if (open(my $fh,'<',$dest.'.meta')) { - my ($output,$now); - $now = time; - while (my $line=<$fh>) { - chomp($line); - if ($line eq "<authorspace>$coursenum:$coursedom</authorspace>") { - $output .= "<authorspace>$ca:$cd</authorspace>\n"; - } elsif ($line eq '<copyright>custom</copyright>') { - $output .= "<copyright>default</copyright>\n"; - } elsif ($line =~ m{^<creationdate>\d+</creationdate>$}) { - $output .= "<creationdate>$now</creationdate>\n"; - } elsif ($line eq "<customdistributionfile>/res/$coursedom/$coursenum/default.rights</customdistributionfile>") { - $output .= "<customdistributionfile></customdistributionfile>\n"; - } elsif ($line eq "<domain>$coursedom</domain>") { - $output .= "<domain>$cd</domain>\n"; - } elsif ($line =~ m{^<lastrevisiondate>\d+</lastrevisiondate>$}) { - $output .= "<lastrevisiondate>$now</lastrevisiondate>\n"; - } elsif ($line =~ m{^<modifyinguser>$match_username:$match_domain</modifyinguser>$}) { - $output .= "<modifyinguser>$env{'user.name'}:$env{'user.domain'}</modifyinguser>\n"; - } elsif ($line eq "<owner>$coursenum:$coursedom</owner>") { - $output .= "<owner>$ca:$cd</owner>\n"; - } elsif ($line =~ m{^<dependencies>(.+)</dependencies>$}) { - my @deps = split(/\s*,\s*/,$1); - my @newdeps; - my $changed = 0; - foreach my $dep (@deps) { - if ($dep =~ m{^/res/$coursedom/$coursenum/(.+)$}) { - my $rest = $1; - push(@newdeps,"/res/$cd/$ca/$rest"); - $checkdeps{$rest} = 1; - $changed ++; - } else { - push(@newdeps,$dep); - } - } - if ($changed) { - $output .= '<dependencies>'.join(',',@newdeps).'</dependencies>'."\n"; + if ($getresmeta) { + if ((-e $src.'.meta') && (!-e $dest.'.meta')) { + if (&Apache::londiff::are_different_files($src.'.meta',$ressrc.'.meta')) { + if (&File::Copy::copy($ressrc.'.meta',$dest.'.meta')) { + &crsres_fixup_meta($dest,$coursenum,$coursedom,$ca,$cd,$copyright, + $customdistfile,$sourceavail,\%checkdeps); } + $needprivmeta = 1; } else { - $output .= "$line\n"; + if (&File::Copy::copy($src.'.meta',$dest.'.meta')) { + &crsres_fixup_meta($dest,$coursenum,$coursedom,$ca,$cd,$copyright, + $customdistfile,$sourceavail,\%checkdeps); + } } } - close($fh); - if (open(my $fh,'>',$dest.'.meta')) { - print $fh $output; - close($fh); + } + if ($getres) { + my $destresfile = $docroot.$destresurl.'/'.$subdir.'/'.$file; + if (-e $dest) { + my $output = &Apache::lonpublisher::batchpublish($r,$dest,$destresfile,$nokeyref,1); + if (-e $destresfile) { + $newresfile{$file} = $destresurl.'/'.$subdir.'/'.$file; + } } } + } else { + $needpriv = 1; + if ((-e $src.'.meta') && (!-e $dest.'.meta')) { + $needprivmeta = 1; + } } - my ($ext) = ($file =~ /\.(\w+)$/); - my $embstyle=&Apache::loncommon::fileembstyle($ext); - if ($embstyle eq 'ssi') { - my $outstring=''; - my $changes = 0; - my @parser; - $parser[0]=HTML::LCParser->new($dest); - $parser[-1]->xml_mode(1); - my $token; - while (@parser) { - while ($token=$parser[-1]->get_token) { - if ($token->[0] eq 'S') { - my $tag=$token->[1]; - my $lctag=lc($tag); - my %parms=%{$token->[2]}; - foreach my $type ('src','href','background','bgimg') { - foreach my $key (keys(%parms)) { - if ($key =~ /^$type$/i) { - next if (($lctag eq 'img') && ($type eq 'src') && - ($parms{$key} =~ m{^data\:image/gif;base64,})); - if ($parms{$key} =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { - $parms{$key} =~ s{^\Q/res/$coursedom/$coursenum/\E}{/res/$cd/$ca/$subdir/}si; - $changes ++; - } - } - } - } - # probably a <randomlabel> image type <label> - # or a <image> tag inside <imageresponse> or <drawimage> - if (($lctag eq 'label' && defined($parms{'description'})) - || ($lctag eq 'image') || ($lctag eq 'import')) { - my $next_token=$parser[-1]->get_token(); - if ($next_token->[0] eq 'T') { - $next_token->[1] =~ s/[\n\r\f]+//g; - if ($next_token->[1] =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { - $next_token->[1] =~ s{^\Q/res/$coursedom/$coursenum/\E}{/res/$cd/$ca/$subdir/}si; - $changes ++; - } - } - $parser[-1]->unget_token($next_token); - } - if ($lctag eq 'applet') { - my $havecodebase=0; - foreach my $key (keys(%parms)) { - if (lc($key) eq 'codebase') { - if ($parms{$key} =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { - $parms{$key} =~ s{^\Q/res/$coursedom/$coursenum/\E}{/res/$cd/$ca/$subdir/}si; - $changes ++; - } - $havecodebase = 1; - } - } - unless ($havecodebase) { - foreach my $key (keys(%parms)) { - if ($key =~ /(archive|code|object)/i) { - if ($parms{$key} =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { - $parms{$key} =~ s{^\Q/res/$coursedom/$coursenum/\E}{/res/$cd/$ca/$subdir/si}; - $changes ++; - } - } - } - } - } - my $newparmstring=''; - my $endtag=''; - foreach my $parkey (keys(%parms)) { - if ($parkey eq '/') { - $endtag=' /'; - } else { - my $quote=($parms{$parkey}=~/\"/?"'":'"'); - $newparmstring.=' '.$parkey.'='.$quote.$parms{$parkey}.$quote; + if ($needpriv) { + if (&File::Copy::copy($src,$dest)) { + $newfile{$file} = $desturl.'/'.$subdir.'/'.$file; + if ($embstyle eq 'ssi') { + &crsres_fixup($dest,$coursenum,$coursedom,$ca,$cd,$subdir); + } + } + } + if ($needprivmeta) { + if (&File::Copy::copy($src.'.meta',$dest.'.meta')) { + &crsres_fixup_meta($dest,$coursenum,$coursedom,$ca,$cd,$copyright, + $customdistfile,$sourceavail,\%checkdeps); + } + } + } else { + my ($needpriv,$needprivmeta); + if ($respublish) { + if ($getres) { + &Apache::lonnet::repcopy($docroot.$resurl.'/'.$file); + } + if ($getresmeta) { + &Apache::lonnet::repcopy($docroot.$resurl.'/'.$file.'.meta'); + } + if (-e $docroot.$resurl.'/'.$file) { + if (&Apache::lonnet::repcopy_crsprivfile($srcurl.'/'.$file,$dest) eq 'ok') { + if (&Apache::londiff::are_different_files($docroot.$resurl.'/'.$file,$dest)) { + $needpriv = 1; + if (&File::Copy::copy($docroot.$resurl.'/'.$file,$dest)) { + if ($embstyle eq 'ssi') { + &crsres_fixup($dest,$coursenum,$coursedom,$ca,$cd); } } - if (!$endtag) { if ($token->[4]=~m:/>$:) { $endtag=' /'; }; } - $outstring.='<'.$tag.$newparmstring.$endtag.'>'; - if ($lctag eq 'm' || $lctag eq 'answer' || $lctag eq 'display' || - $lctag eq 'tex') { - $outstring.=&Apache::lonxml::get_all_text_unbalanced('/'.$lctag,\@parser); - } elsif ($lctag eq 'script') { - if ($parms{'type'} eq 'loncapa/perl') { - $outstring.=&Apache::lonxml::get_all_text_unbalanced('/'.$lctag,\@parser); - } else { - my $needsupdate; - my $script = &Apache::lonxml::get_all_text_unbalanced('/'.$lctag,\@parser); - if ($script =~ m{\.addMediaSrc\((["'])((?!\1).+)\1\);}) { - my $src = $2; - if ($src =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { - $needsupdate = 1; - } - } - if ($script =~ /\(document,\s*(['"])script\1,\s*\[([^\]]+)\]\);/s) { - my $scriptslist = $2; - my $needsupdate = 1; - my @srcs = split(/\s*,\s*/,$scriptslist); - foreach my $src (@srcs) { - if ($src =~ /(["'])(?:(?!\1).)+\.js\1/) { - my $quote = $1; - my ($url) = ($src =~ m/\Q$quote\E([^$quote]+)\Q$quote\E/); - if ($url =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { - $needsupdate = 1; - } - } - } - } - if ($script =~ m{loadScript\(\s*(['"])((?:(?!\1).)+\.js)\1,\s*function}is) { - my $src = $2; - if ($src =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { - $needsupdate = 1; - } - } - if ($needsupdate) { - $script =~ s{^\Q/res/$coursedom/$coursenum/\E}{/res/$cd/$ca/$subdir/gsi}; - $changes ++; - } - $outstring .= $script; - } + } else { + if ($embstyle eq 'ssi') { + &crsres_fixup($dest,$coursenum,$coursedom,$ca,$cd,$subdir); } - } elsif ($token->[0] eq 'E') { - if ($token->[2]) { - unless ($token->[1] eq 'allow') { - $outstring.='</'.$token->[1].'>'; - } + $newfile{$file} = $desturl.'/'.$subdir.'/'.$file; + } + } + } else { + $needpriv = 1; + } + if (-e $docroot.$resurl.'/'.$file.'.meta') { + if (&Apache::lonnet::repcopy_crsprivfile($srcurl.'/'.$file.'.meta',$dest.'.meta') eq 'ok') { + if (&Apache::londiff::are_different_files($docroot.$resurl.'/'.$file.'.meta',$dest.'.meta')) { + $needprivmeta = 1; + if (&File::Copy::copy($docroot.$resurl.'/'.$file.'.meta',$dest.'.meta')) { + &crsres_fixup_meta($dest,$coursenum,$coursedom,$ca,$cd,$copyright, + $customdistfile,$sourceavail,\%checkdeps); } } else { - $outstring.=$token->[1]; + &crsres_fixup_meta($dest,$coursenum,$coursedom,$ca,$cd,$copyright, + $customdistfile,$sourceavail,\%checkdeps); } } - pop(@parser); + } else { + if (!-e $dest.'.meta') { + $needprivmeta = 1; + } } - if ($changes) { - if (open(my $fh,'>',$dest)) { - print $fh $outstring; - close($fh); + if ($getres) { + my $destresfile = $docroot.$destresurl.'/'.$subdir.'/'.$file; + if (-e $dest) { + my $output = &Apache::lonpublisher::batchpublish($r,$dest,$destresfile,$nokeyref,1); + if (-e $destresfile) { + $newresfile{$file} = $destresurl.'/'.$subdir.'/'.$file; + } + } + } + } else { + $needpriv = 1; + if (!-e $dest.'.meta') { + $needprivmeta = 1; + } + } + if ($needpriv) { + if (&Apache::lonnet::repcopy_crsprivfile($srcurl.'/'.$file,$dest) eq 'ok') { + if ($embstyle eq 'ssi') { + &crsres_fixup($dest,$coursenum,$coursedom,$ca,$cd,$subdir); } + $newfile{$file} = $desturl.'/'.$subdir.'/'.$file; + } + } + if ($needprivmeta) { + if (&Apache::lonnet::repcopy_crsprivfile($srcurl.'/'.$file.'.meta',$dest.'.meta') eq 'ok') { + &crsres_fixup_meta($dest,$coursenum,$coursedom,$ca,$cd,$copyright, + $customdistfile,$sourceavail,\%checkdeps); } } } @@ -1117,6 +1177,16 @@ ENDJS $r->print('<p>'.&mt('Copied the following files to [_1]:','<span class="LC_filename">'.$desturl.'/'.$subdir.'</span>'). '</p>'."\n". '<ul><li>'.join('</li><li>',sort(keys(%newfile))).'</li></ul></p>'."\n"); + foreach my $key (keys(%newfile)) { + my %storehash = ( + 'priv' => $newfile{$key}, + 'who' => $env{'user.name'}.':'.$env{'user.domain'}, + ); + if (exists($newresfile{$file})) { + $storehash{'res'} = 1; + } + &Apache::lonnet::store_userdata(\%storehash,$file,'copycourseauthor',$coursedom,$coursenum); + } } if (keys(%checkdeps)) { my %missingdep; @@ -1138,7 +1208,6 @@ ENDJS return ''; } } else { - my $formname = 'copycrsauthored'; my $chkname = 'copytouser'; my $context = 'crsauthored'; my (%subdirs,%files,@dirs_by_depth,@files_by_depth,%parent,%children,%hierarchy,@checked_maps); @@ -1172,9 +1241,19 @@ ENDJS } my ($info,$display,$onsubmit,$togglebuttons,$disabled); my (%resdirs,%resfiles); - my $resurl = "/res/$coursedom/$coursenum"; - my $resexclude = &Apache::lonnet::res_exclude(); - &Apache::lonnet::recursedirs($is_course_home,1,undef,$resexclude,0,0,$resurl,'',\%resdirs,\%resfiles); + &Apache::lonnet::recursedirs($is_course_home,1,undef,$res_exclude,0,0,$resurl,'',\%resdirs,\%resfiles); + my $numpub = 0; + if (keys(%resfiles)) { + foreach my $dir (keys(%resfiles)) { + if (ref($resfiles{$dir}) eq 'HASH') { + foreach my $file (keys(%{$resfiles{$dir}})) { + if (exists($files{$dir}{$file})) { + $numpub ++; + } + } + } + } + } if ($readonly) { $disabled = ' disabled="disabled"'; } @@ -1186,11 +1265,10 @@ ENDJS ' <input type="button" value="'.&mt('uncheck all').'"'. ' onclick="javascript:uncheckAll(document.'.$formname.'.'.$chkname.')" />'; } - my $title=$origcrsdata{'description'}; - $title=~s/[\/\s]+/\_/gs; - $title=&clean($title); - my $preamble = &authorspace_selector($r,$formname,$home,$title,%outhash); - my $display = '<form name="'.$formname.'" action="" method="post">'."\n". + my $preamble = &authorspace_selector($r,$formname,$home,$title,%outhash). + &courseresource_options($formname,$numpub). + '<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n"; + my $display = '<form name="'.$formname.'" action="" method="post" onsubmit="return validCrsCopy();">'."\n". $preamble."\n". '<div class="LC_float_left">'."\n". '<fieldset>'."\n". @@ -1326,6 +1404,246 @@ sub recurse_crsauthored { return $count; } +sub courseresource_options { + my ($formname,$numpub) = @_; + my %lt = &Apache::lonlocal::texthash( + 'default' => 'System wide - can be used for any courses system wide', + 'domain' => 'Domain only - use limited to courses in the domain', + 'custom' => 'Customized right of use ...', + 'public' => 'Public - no authentication or authorization required for use', + 'closed' => 'Closed - XML source is closed to everyone', + 'open' => 'Open - XML source is open to people who want to use it', + 'sel' => 'Select', + ); + my $output; + if ($numpub) { + $output .= '<div class="LC_left_float">'. + '<fieldset><legend>'.&mt('Published Resources').'</legend>'. + &mt('[quant,_1,file] in Course Authoring Space also exist in Resource Space.', + $numpub).'</br />'. + &mt('Publish copied files in selected Authoring Space?').': '."\n". + '<label><input type="radio" name="respublish" checked="checked" value="1" />'. + &mt('Yes').'</label>'."\n". + '<label><input type="radio" name="respublish" value="0" />'. + &mt('No').'</label>'."\n". + '</fieldset></div>'."\n"; + } + $output .= '<div class="LC_left_float">'. + '<fieldset><legend>'.&mt('Distribution to set in metadata').'</legend>'. + &mt('Copyright').': '. + '<select name="copyright" onchange="showHideCustom(this,'."'LC_customfile'".');">'."\n". + '<option value="default" selected="selected">'.$lt{'default'}.'</option>'."\n". + '<option value="domain">'.$lt{'domain'}.'</option>'."\n". + '<option value="public">'.$lt{'public'}.'</option>'."\n". + '<option value="custom">'.$lt{'custom'}.'</option>'."\n". + '</select><div id="LC_customfile" style="padding:0;clear:both;margin:0;border:0;display:none">'."\n". + '<input type="text" name="customrights" size="60" value="" />'. + '<a href="javascript:openbrowser('."'$formname','customrights','rights'".');">'. + $lt{'sel'}.'</a></div><br />'."\n". + &mt('Source').' :'. + '<select name="sourceavail">'."\n". + '<option value="closed" selected="selected">'.$lt{'closed'}.'</option>'."\n". + '<option value="open">'.$lt{'open'}.'</option>'."\n". + '</select><br />'."\n". + '</fieldset></div>'."\n"; + return $output; +} + +sub crsres_fixup_meta { + my ($dest,$coursenum,$coursedom,$ca,$cd,$copyright,$customdistfile,$sourceavail,$checkdeps) = @_; + return unless (ref($checkdeps) eq 'HASH'); + if (open(my $fh,'<',$dest.'.meta')) { + my ($output,$now,$setsourceavail); + $now = time; + if (($dest =~ /\.(xml|html|htm|xhtml|xhtm)$/i) || ($dest =~ /$LONCAPA::assess_re/)) { + $setsourceavail = 1; + } + while (my $line=<$fh>) { + chomp($line); + if ($line eq "<authorspace>$coursenum:$coursedom</authorspace>") { + $output .= "<authorspace>$ca:$cd</authorspace>\n"; + } elsif ($line eq '<copyright>custom</copyright>') { + $output .= "<copyright>$copyright</copyright>\n"; + } elsif ($line =~ m{^<creationdate>\d+</creationdate>$}) { + $output .= "<creationdate>$now</creationdate>\n"; + } elsif ($line eq "<customdistributionfile>/res/$coursedom/$coursenum/default.rights</customdistributionfile>") { + $output .= "<customdistributionfile>$customdistfile</customdistributionfile>\n"; + } elsif ($line =~ m{^<sourceavail>(open|closed)</sourceavail>$}) { + if ($setsourceavail) { + $output .= "<sourceavail>$sourceavail</sourceavail>\n"; + } + } elsif ($line eq "<domain>$coursedom</domain>") { + $output .= "<domain>$cd</domain>\n"; + } elsif ($line =~ m{^<lastrevisiondate>\d+</lastrevisiondate>$}) { + $output .= "<lastrevisiondate>$now</lastrevisiondate>\n"; + } elsif ($line =~ m{^<modifyinguser>$match_username:$match_domain</modifyinguser>$}) { + $output .= "<modifyinguser>$env{'user.name'}:$env{'user.domain'}</modifyinguser>\n"; + } elsif ($line eq "<owner>$coursenum:$coursedom</owner>") { + $output .= "<owner>$ca:$cd</owner>\n"; + } elsif ($line =~ m{^<dependencies>(.+)</dependencies>$}) { + my @deps = split(/\s*,\s*/,$1); + my @newdeps; + my $changed = 0; + foreach my $dep (@deps) { + if ($dep =~ m{^/res/$coursedom/$coursenum/(.+)$}) { + my $rest = $1; + push(@newdeps,"/res/$cd/$ca/$rest"); + $checkdeps->{$rest} = 1; + $changed ++; + } else { + push(@newdeps,$dep); + } + } + if ($changed) { + $output .= '<dependencies>'.join(',',@newdeps).'</dependencies>'."\n"; + } + } else { + $output .= "$line\n"; + } + } + close($fh); + if (open(my $fh,'>',$dest.'.meta')) { + print $fh $output; + close($fh); + } + } +} + +sub crsres_fixup { + my ($dest,$coursenum,$coursedom,$ca,$cd,$subdir) = @_; + my $outstring=''; + my $changes = 0; + my @parser; + $parser[0]=HTML::LCParser->new($dest); + $parser[-1]->xml_mode(1); + my $token; + while (@parser) { + while ($token=$parser[-1]->get_token) { + if ($token->[0] eq 'S') { + my $tag=$token->[1]; + my $lctag=lc($tag); + my %parms=%{$token->[2]}; + foreach my $type ('src','href','background','bgimg') { + foreach my $key (keys(%parms)) { + if ($key =~ /^$type$/i) { + next if (($lctag eq 'img') && ($type eq 'src') && + ($parms{$key} =~ m{^data\:image/gif;base64,})); + if ($parms{$key} =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { + $parms{$key} =~ s{^\Q/res/$coursedom/$coursenum/\E}{/res/$cd/$ca/$subdir/}si; + $changes ++; + } + } + } + } + # probably a <randomlabel> image type <label> + # or a <image> tag inside <imageresponse> or <drawimage> + if (($lctag eq 'label' && defined($parms{'description'})) + || ($lctag eq 'image') || ($lctag eq 'import')) { + my $next_token=$parser[-1]->get_token(); + if ($next_token->[0] eq 'T') { + $next_token->[1] =~ s/[\n\r\f]+//g; + if ($next_token->[1] =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { + $next_token->[1] =~ s{^\Q/res/$coursedom/$coursenum/\E}{/res/$cd/$ca/$subdir/}si; + $changes ++; + } + } + $parser[-1]->unget_token($next_token); + } + if ($lctag eq 'applet') { + my $havecodebase=0; + foreach my $key (keys(%parms)) { + if (lc($key) eq 'codebase') { + if ($parms{$key} =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { + $parms{$key} =~ s{^\Q/res/$coursedom/$coursenum/\E}{/res/$cd/$ca/$subdir/}si; + $changes ++; + } + $havecodebase = 1; + } + } + unless ($havecodebase) { + foreach my $key (keys(%parms)) { + if ($key =~ /(archive|code|object)/i) { + if ($parms{$key} =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { + $parms{$key} =~ s{^\Q/res/$coursedom/$coursenum/\E}{/res/$cd/$ca/$subdir/si}; + $changes ++; + } + } + } + } + } + my $newparmstring=''; + my $endtag=''; + foreach my $parkey (keys(%parms)) { + if ($parkey eq '/') { + $endtag=' /'; + } else { + my $quote=($parms{$parkey}=~/\"/?"'":'"'); + $newparmstring.=' '.$parkey.'='.$quote.$parms{$parkey}.$quote; + } + } + if (!$endtag) { if ($token->[4]=~m:/>$:) { $endtag=' /'; }; } + $outstring.='<'.$tag.$newparmstring.$endtag.'>'; + if ($lctag eq 'm' || $lctag eq 'answer' || $lctag eq 'display' || + $lctag eq 'tex') { + $outstring.=&Apache::lonxml::get_all_text_unbalanced('/'.$lctag,\@parser); + } elsif ($lctag eq 'script') { + if ($parms{'type'} eq 'loncapa/perl') { + $outstring.=&Apache::lonxml::get_all_text_unbalanced('/'.$lctag,\@parser); + } else { + my $needsupdate; + my $script = &Apache::lonxml::get_all_text_unbalanced('/'.$lctag,\@parser); + if ($script =~ m{\.addMediaSrc\((["'])((?!\1).+)\1\);}) { + my $src = $2; + if ($src =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { + $needsupdate = 1; + } + } + if ($script =~ /\(document,\s*(['"])script\1,\s*\[([^\]]+)\]\);/s) { + my $scriptslist = $2; + my @srcs = split(/\s*,\s*/,$scriptslist); + foreach my $src (@srcs) { + if ($src =~ /(["'])(?:(?!\1).)+\.js\1/) { + my $quote = $1; + my ($url) = ($src =~ m/\Q$quote\E([^$quote]+)\Q$quote\E/); + if ($url =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { + $needsupdate = 1; + } + } + } + } + if ($script =~ m{loadScript\(\s*(['"])((?:(?!\1).)+\.js)\1,\s*function}is) { + my $src = $2; + if ($src =~ m{^\Q/res/$coursedom/$coursenum/\E}si) { + $needsupdate = 1; + } + } + if ($needsupdate) { + $script =~ s{^\Q/res/$coursedom/$coursenum/\E}{/res/$cd/$ca/$subdir/gsi}; + $changes ++; + } + $outstring .= $script; + } + } + } elsif ($token->[0] eq 'E') { + if ($token->[2]) { + unless ($token->[1] eq 'allow') { + $outstring.='</'.$token->[1].'>'; + } + } + } else { + $outstring.=$token->[1]; + } + } + pop(@parser); + } + if ($changes) { + if (open(my $fh,'>',$dest)) { + print $fh $outstring; + close($fh); + } + } +} + sub group_import { my ($coursenum, $coursedom, $folder, $container, $caller, $ltitoolsref, @files) = @_; my ($donechk,$allmaps,%hierarchy,%titles,%addedmaps,%removefrommap, @@ -8341,10 +8659,12 @@ sub generate_admin_menu { if (grep(/^\Q$crshome\E$/,@ids)) { $linkurl = $crsauthorurl; } else { - $linkurl = - &Apache::lonhtmlcommon::jump_to_editres($crsauthorurl,$crshome,1); + my $jscall = &Apache::lonhtmlcommon::jump_to_editres($crsauthorurl,$crshome,1); + if ($jscall) { + $linkurl = 'javascript:'.$jscall; + } } - if ((ref($menu[0]) eq 'HASH') && (ref($menu[0]->{'items'}) eq 'ARRAY')) { + if ((ref($menu[0]) eq 'HASH') && (ref($menu[0]->{'items'}) eq 'ARRAY') && ($linkurl)) { push(@{$menu[0]->{items}}, { linktext => $lt{'ca'}, url => $linkurl,