--- loncom/interface/londocs.pm 2012/05/15 01:23:04 1.486
+++ loncom/interface/londocs.pm 2012/07/13 13:36:24 1.491
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Documents
#
-# $Id: londocs.pm,v 1.486 2012/05/15 01:23:04 raeburn Exp $
+# $Id: londocs.pm,v 1.491 2012/07/13 13:36:24 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -40,7 +40,9 @@ use Apache::lonxml;
use Apache::lonclonecourse;
use Apache::lonnavmaps;
use Apache::lonnavdisplay();
+use Apache::lonuserstate();
use HTML::Entities;
+use HTML::TokeParser;
use GDBM_File;
use Apache::lonlocal;
use Cwd;
@@ -436,7 +438,7 @@ sub docs_change_log {
''."\n";
$r->print(&Apache::loncommon::start_page('Content Change Log',$js));
$r->print(&Apache::lonhtmlcommon::breadcrumbs('Content Change Log'));
- $r->print(&startContentScreen('docs'));
+ $r->print(&startContentScreen(($supplementalflag?'suppdocs':'docs')));
my %orderhash;
my $container='sequence';
my $pathitem;
@@ -455,6 +457,9 @@ sub docs_change_log {
my $jumpto = $readfile;
$jumpto =~ s{^/}{};
my $tid = 1;
+ if ($supplementalflag) {
+ $tid = 2;
+ }
my ($breadcrumbtrail) = &breadcrumbs($allowed,$crstype);
$r->print($breadcrumbtrail.
&generate_edit_table($tid,\%orderhash,undef,$iconpath,$jumpto,
@@ -529,18 +534,30 @@ sub docs_change_log {
':'.$docslog{$id}{'exe_udom'}.''.
$send_msg_link.'
'.
$docslog{$id}{'logentry'}{'folder'}.' | ');
+ my $is_supp = 0;
+ if ($docslog{$id}{'logentry'}{'currentfolder'} =~ /^supplemental/) {
+ $is_supp = 1;
+ }
# Before
for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
my $oldname=(split(/\:/,$docslog{$id}{'logentry'}{'before_resources_'.$idx}))[0];
my $newname=(split(/\:/,$docslog{$id}{'logentry'}{'after_resources_'.$idx}))[0];
if ($oldname ne $newname) {
- $r->print(&LONCAPA::map::qtescape($oldname));
+ my $shown = &LONCAPA::map::qtescape($oldname);
+ if ($is_supp) {
+ $shown = &Apache::loncommon::parse_supplemental_title($shown);
+ }
+ $r->print($shown);
}
}
$r->print('');
for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
if ($docslog{$id}{'logentry'}{'before_order_res_'.$idx}) {
- $r->print('- '.&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'before_order_res_'.$idx}))[0]).'
');
+ my $shown = &LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'before_order_res_'.$idx}))[0]);
+ if ($is_supp) {
+ $shown = &Apache::loncommon::parse_supplemental_title($shown);
+ }
+ $r->print('- '.$shown.'
');
}
}
$r->print(' ');
@@ -551,13 +568,21 @@ sub docs_change_log {
my $oldname=(split(/\:/,$docslog{$id}{'logentry'}{'before_resources_'.$idx}))[0];
my $newname=(split(/\:/,$docslog{$id}{'logentry'}{'after_resources_'.$idx}))[0];
if ($oldname ne '' && $oldname ne $newname) {
- $r->print(&LONCAPA::map::qtescape($newname));
+ my $shown = &LONCAPA::map::qtescape($newname);
+ if ($is_supp) {
+ $shown = &Apache::loncommon::parse_supplemental_title(&LONCAPA::map::qtescape($newname));
+ }
+ $r->print($shown);
}
}
$r->print('');
for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
if ($docslog{$id}{'logentry'}{'after_order_res_'.$idx}) {
- $r->print('- '.&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'after_order_res_'.$idx}))[0]).'
');
+ my $shown = &LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'after_order_res_'.$idx}))[0]);
+ if ($is_supp) {
+ $shown = &Apache::loncommon::parse_supplemental_title($shown);
+ }
+ $r->print('- '.$shown.'
');
}
}
$r->print(' ');
@@ -602,7 +627,7 @@ sub update_paste_buffer {
my ($title,$url)=split(':',$LONCAPA::map::resources[$LONCAPA::map::order[$env{'form.markcopy'}]]);
if (&is_supplemental_title($title)) {
&Apache::lonnet::appenv({'docs.markedcopy_supplemental' => $title});
- ($title) = &parse_supplemental_title($title);
+ ($title) = &Apache::loncommon::parse_supplemental_title($title);
} elsif ($env{'docs.markedcopy_supplemental'}) {
&Apache::lonnet::delenv('docs.markedcopy_supplemental');
}
@@ -614,23 +639,42 @@ sub update_paste_buffer {
}
sub print_paste_buffer {
- my ($r,$container) = @_;
+ my ($r,$container,$folder) = @_;
return if (!defined($env{'docs.markedcopy_url'}));
+ my $is_external;
+ my $extension = (split(/\./,$env{'docs.markedcopy_url'}))[-1];
+ if ($env{'docs.markedcopy_url'} =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//} ) {
+ $is_external = 1;
+ }
+
+ my $canpaste;
+ if ($folder =~ /^supplemental/) {
+ $canpaste = &supp_pasteable($env{'docs.markedcopy_url'});
+ } else {
+ $canpaste = 1;
+ }
+
+ my $pasteinfo;
+ if ($canpaste) {
+ $pasteinfo = '');
+ $r->print('');
+}
+
+sub supp_pasteable {
+ my ($url) = @_;
+ if (($url =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//}) ||
+ (($url =~ /\.sequence$/) && ($url =~ m{^/uploaded/})) ||
+ ($url =~ m{^/uploaded/$match_domain/$match_courseid/(docs|supplemental)/(default|\d+)/\d+/}) ||
+ ($url =~ m{^/adm/$match_domain/$match_username/aboutme}) ||
+ ($url =~ m{^/public/$match_domain/$match_courseid/syllabus})) {
+ return 1;
+ }
+ return;
}
sub do_paste_from_buffer {
- my ($coursenum,$coursedom,$folder) = @_;
+ my ($coursenum,$coursedom,$folder,$errors) = @_;
if (!$env{'form.pastemarked'}) {
return;
}
-# paste resource to end of list
+# Preparing to paste resource at end of list
my $url=&LONCAPA::map::qtescape($env{'docs.markedcopy_url'});
my $title=&LONCAPA::map::qtescape($env{'docs.markedcopy_title'});
+
+ my ($is_map,$srcdom,$srcnum,$prefixchg,%before,%after,%mapchanges);
+ if ($url=~/\.(page|sequence)$/) {
+ $is_map = 1;
+ }
+ if ($url =~ m{^/uploaded/($match_domain)/($match_courseid)/([^/]+)}) {
+ $srcdom = $1;
+ $srcnum = $2;
+ my $oldprefix = $3;
+ if (($srcdom ne $coursedom) || ($srcnum ne $coursenum)) {
+ unless ($env{"user.priv.cm./$srcdom/$srcnum"} =~ /\Q:mdc&F\E/) {
+ return &mt('Paste failed: Item is from a different course which you do not have rights to edit.');
+ }
+ }
+ if (($folder =~ /^supplemental/) && (($oldprefix =~ /^default/) || ($oldprefix eq 'docs'))) {
+ $prefixchg = 1;
+ %before = ( map => 'default',
+ doc => 'docs');
+ %after = ( map => 'supplemental',
+ doc => 'supplemental' );
+ } elsif (($folder =~ /^default/) && ($oldprefix =~ /^supplemental/)) {
+ $prefixchg = 1;
+ %before = ( map => 'supplemental',
+ doc => 'supplemental');
+ %after = ( map => 'default',
+ doc => 'docs');
+ }
+ }
+
+# Supplemental content may only include certain types of content
+ if ($folder =~ /^supplemental/) {
+ unless (&supp_pasteable($env{'docs.markedcopy_url'})) {
+ return &mt('Paste failed: content type is not supported within Supplemental Content');
+ }
+ }
+
# Maps need to be copied first
- if (($url=~/\.(page|sequence)$/) && ($url=~/^\/uploaded\//)) {
- $title=&mt('Copy of').' '.$title;
- my $newid=$$.int(rand(100)).time;
+ my ($oldurl,%removefrommap,%addedmaps,%rewrites,%retitles,%copies,%dbcopies,%zombies,
+ %params,%docmoves,%mapmoves);
+ $oldurl = $url;
+ if ($is_map) {
+# If pasting a map, check if map contains other maps
+ my %allmaps;
+ &contained_map_check($url,$folder,\%removefrommap,\%addedmaps);
+ if ($folder =~ /^default/) {
+ if (keys(%addedmaps) > 0) {
+ &reinit_role($coursedom,$coursenum,$env{"course.$env{'request.course.id'}.home"});
+ }
+ my $navmap = Apache::lonnavmaps::navmap->new();
+ if (defined($navmap)) {
+ foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_map() },1,0,1)) {
+ $allmaps{$res->src()} = 1;
+ }
+ }
+ }
+ if ($url=~ m{^/uploaded/}) {
+ $title=&mt('Copy of').' '.$title;
+ }
+ my $now = time;
+ my $suffix=$$.int(rand(100)).$now;
my ($oldid,$ext) = ($url=~/^(.+)\.(\w+)$/);
- if ($oldid =~ m{^(/uploaded/\Q$coursedom\E/\Q$coursenum\E/)(\D+)(\d+)$}) {
+ if ($oldid =~ m{^(/uploaded/$match_domain/$match_courseid/)(\D+)(\d+)$}) {
my $path = $1;
my $prefix = $2;
my $ancestor = $3;
if (length($ancestor) > 10) {
$ancestor = substr($ancestor,-10,10);
}
- $oldid = $path.$prefix.$ancestor;
- }
- my $counter = 0;
- my $newurl=$oldid.$newid.'.'.$ext;
- my $is_unique = &uniqueness_check($newurl);
- while (!$is_unique && $counter < 100) {
- $counter ++;
- $newid ++;
- $newurl = $oldid.$newid;
- $is_unique = &uniqueness_check($newurl);
- }
- if (!$is_unique) {
- if ($url=~/\.page$/) {
- return &mt('Paste failed: an error occurred creating a unique URL for the composite page');
+ my ($newurl,$newid);
+ if ($prefixchg) {
+ if ($folder =~ /^supplemental/) {
+ $prefix =~ s/^default/supplemental/;
+ } else {
+ $prefix =~ s/^supplemental/default/;
+ }
+ }
+ if (($srcdom eq $coursedom) && ($srcnum eq $coursenum)) {
+ $newurl = $path.$prefix.$ancestor.$suffix.'.'.$ext;
} else {
- return &mt('Paste failed: an error occurred creating a unique URL for the folder');
+ $newurl = "/uploaded/$coursedom/$coursenum/$prefix".$now.'.'.$ext;
}
- }
- my $storefn=$newurl;
- $storefn=~s{^/\w+/$match_domain/$match_username/}{};
- my $paste_map_result =
- &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn,
- &Apache::lonnet::getfile($url));
- if ($paste_map_result eq '/adm/notfound.html') {
- if ($url=~/\.page$/) {
- return &mt('Paste failed: an error occurred saving the composite page');
+ my $counter = 0;
+ my $is_unique = &uniqueness_check($newurl);
+ if ($folder =~ /^default/) {
+ if ($allmaps{$newurl}) {
+ $is_unique = 0;
+ }
+ }
+ while (!$is_unique && $allmaps{$newurl} && $counter < 100) {
+ $counter ++;
+ $suffix ++;
+ if (($srcdom eq $coursedom) && ($srcnum eq $coursenum)) {
+ $newurl = $path.$prefix.$ancestor.$suffix.'.'.$ext;
+ } else {
+ $newurl = "/uploaded/$coursedom/$coursenum/$prefix".$ancestor.$suffix.'.'.$ext;
+ }
+ $is_unique = &uniqueness_check($newurl);
+ }
+ if ($is_unique) {
+ if ($newurl ne $oldurl) {
+ $mapchanges{$oldurl} = 1;
+ }
+ if (($srcdom ne $coursedom) || ($srcnum ne $coursenum) || ($prefixchg)) {
+ &url_paste_fixups($url,$prefixchg,$coursedom,$coursenum,\%allmaps,
+ \%rewrites,\%retitles,\%copies,\%dbcopies,\%zombies,
+ \%params,\%mapmoves,\%mapchanges);
+ }
} else {
- return &mt('Paste failed: an error occurred saving the folder');
+ if ($url=~/\.page$/) {
+ return &mt('Paste failed: an error occurred creating a unique URL for the composite page');
+ } else {
+ return &mt('Paste failed: an error occurred creating a unique URL for the folder');
+ }
}
- }
- $url = $newurl;
- }
+ my $storefn=$newurl;
+ $storefn=~s{^/\w+/$match_domain/$match_username/}{};
+ my $paste_map_result =
+ &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn,
+ &Apache::lonnet::getfile($url));
+ if ($paste_map_result eq '/adm/notfound.html') {
+ if ($url=~/\.page$/) {
+ return &mt('Paste failed: an error occurred saving the composite page.');
+ } else {
+ return &mt('Paste failed: an error occurred saving the folder.');
+ }
+ }
+ $url = $newurl;
+ } elsif ($url=~m {^/res/}) {
# published maps can only exists once, so remove it from paste buffer when done
- if (($url=~/\.(page|sequence)$/) && ($url=~m {^/res/})) {
- &Apache::lonnet::delenv('docs.markedcopy');
+ &Apache::lonnet::delenv('docs.markedcopy');
+ if ($folder =~ /^default/) {
+ if ($allmaps{$url}) {
+ return &mt('Paste failed: only one instance of a particular published sequence or page is allowed within each course.');
+ }
+ }
+ }
}
if ($url=~ m{/smppg$}) {
my $db_name = &Apache::lonsimplepage::get_db_name($url);
@@ -718,10 +868,14 @@ sub do_paste_from_buffer {
my %contents=&Apache::lonnet::dump($db_name,$coursedom,$coursenum);
my $now = time();
$db_name =~ s{_\d*$ }{_$now}x;
- my $result=&Apache::lonnet::put($db_name,\%contents,
+ my $dbresult=&Apache::lonnet::put($db_name,\%contents,
$coursedom,$coursenum);
- $url =~ s{/(\d*)/smppg$ }{/$now/smppg}x;
- $title=&mt('Copy of').' '.$title;
+ if ($dbresult eq 'ok') {
+ $url =~ s{/(\d*)/smppg$ }{/$now/smppg}x;
+ $title=&mt('Copy of').' '.$title;
+ } else {
+ return &mt('Paste failed: An error occurred when copying the simple page.');
+ }
}
}
$title = &LONCAPA::map::qtunescape($title);
@@ -730,24 +884,79 @@ sub do_paste_from_buffer {
$url = &LONCAPA::map::qtunescape($url);
# Now insert the URL at the bottom
my $newidx = &LONCAPA::map::getresidx($url);
- if ($env{'docs.markedcopy_supplemental'}) {
- if ($folder =~ /^supplemental/) {
- $title = $env{'docs.markedcopy_supplemental'};
- } else {
- (undef,undef,$title) =
- &parse_supplemental_title($env{'docs.markedcopy_supplemental'});
+
+# For uploaded files (excluding pages/sequences) path in copied file is changed
+# if paste is from Main to Supplemental (or vice versa), or if pasting between
+# courses.
+
+ unless ($is_map) {
+ if ($url =~ m{^/uploaded/$match_domain/$match_courseid/(?:docs|supplemental)/(.+)$}) {
+ my $relpath = $1;
+ if ($relpath ne '') {
+ my ($prefix,$subdir,$rem) = ($relpath =~ m{^(default|\d+)/(\d+)/(.+)$});
+ my ($newloc,$newsubdir) = ($folder =~ /^(default|supplemental)_?(\d*)/);
+ my $newprefix = $newloc;
+ if ($newloc eq 'default') {
+ $newprefix = 'docs';
+ }
+ if ($newsubdir eq '') {
+ $newsubdir = 'default';
+ }
+ if (($prefixchg) || ($srcdom ne $coursedom) || ($srcnum ne $coursenum)) {
+ my $newpath = "$newprefix/$newsubdir/$newidx/$rem";
+ $url =
+ &Apache::lonclonecourse::writefile($env{'request.course.id'},$newpath,
+ &Apache::lonnet::getfile($oldurl));
+ if ($url eq '/adm/notfound.html') {
+ return &mt('Paste failed: an error occurred saving the file.');
+ } else {
+ my ($newsubpath) = ($newpath =~ m{^(.*/)[^/]*$});
+ $newsubpath =~ s{/+$}{/};
+ $docmoves{$oldurl} = $newsubpath;
+ }
+ }
+ }
}
- } else {
- if ($folder=~/^supplemental/) {
- $title=time.'___&&&___'.$env{'user.name'}.'___&&&___'.
- $env{'user.domain'}.'___&&&___'.$title;
+ }
+ my $result =
+ &apply_fixups($is_map,$prefixchg,$coursedom,$coursenum,$oldurl,$url,
+ \%removefrommap,\%rewrites,\%retitles,\%copies,\%dbcopies,
+ \%zombies,\%params,\%docmoves,\%mapmoves,$errors,\%before,\%after);
+ if ($result eq 'ok') {
+ if ($env{'docs.markedcopy_supplemental'}) {
+ if ($folder =~ /^supplemental/) {
+ $title = $env{'docs.markedcopy_supplemental'};
+ } else {
+ (undef,undef,$title) =
+ &Apache::loncommon::parse_supplemental_title($env{'docs.markedcopy_supplemental'});
+ }
+ } else {
+ if ($folder=~/^supplemental/) {
+ $title=time.'___&&&___'.$env{'user.name'}.'___&&&___'.
+ $env{'user.domain'}.'___&&&___'.$title;
+ }
}
+ $LONCAPA::map::resources[$newidx]= $title.':'.$url.':'.$ext.':normal:res';
+ push(@LONCAPA::map::order, $newidx);
}
+ return $result;
+}
- $LONCAPA::map::resources[$newidx]= $title.':'.$url.':'.$ext.':normal:res';
- push(@LONCAPA::map::order, $newidx);
- return 'ok';
-# Store the result
+sub dbcopy {
+ my ($url,$coursedom,$coursenum) = @_;
+ if ($url=~ m{/smppg$}) {
+ my $db_name = &Apache::lonsimplepage::get_db_name($url);
+ if ($db_name =~ /^smppage_/) {
+ #simple pages, need to copy the db contents to a new one.
+ my %contents=&Apache::lonnet::dump($db_name,$coursedom,$coursenum);
+ my $now = time();
+ $db_name =~ s{_\d*$ }{_$now}x;
+ my $result=&Apache::lonnet::put($db_name,\%contents,
+ $coursedom,$coursenum);
+ $url =~ s{/(\d*)/smppg$ }{/$now/smppg}x;
+ }
+ }
+ return $url;
}
sub uniqueness_check {
@@ -764,6 +973,408 @@ sub uniqueness_check {
return $unique;
}
+sub contained_map_check {
+ my ($url,$folder,$removefrommap,$addedmaps) = @_;
+ my $content = &Apache::lonnet::getfile($url);
+ unless ($content eq '-1') {
+ my $parser = HTML::TokeParser->new(\$content);
+ $parser->attr_encoded(1);
+ while (my $token = $parser->get_token) {
+ next if ($token->[0] ne 'S');
+ if ($token->[1] eq 'resource') {
+ next if ($token->[2]->{'type'} eq 'zombie');
+ my $ressrc = $token->[2]->{'src'};
+ if ($folder =~ /^supplemental/) {
+ unless (&supp_pasteable($ressrc)) {
+ $removefrommap->{$url}{$token->[2]->{'id'}};
+ next;
+ }
+ }
+ if ($ressrc =~ /\.(sequence|page)$/) {
+ if (ref($addedmaps->{$ressrc}) eq 'ARRAY') {
+ push(@{$addedmaps->{$ressrc}},$url);
+ } else {
+ $addedmaps->{$ressrc} = [$url];
+ }
+ &contained_map_check($ressrc,$folder,$removefrommap,$addedmaps);
+ }
+ } elsif ($token->[1] !~ /^resource|map|link$/) {
+ if ($folder =~ /^supplemental/) {
+ $removefrommap->{$url}{$token->[1]};
+ }
+ }
+ }
+ }
+ return;
+}
+
+sub reinit_role {
+ my ($cdom,$cnum,$chome) = @_;
+ my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum");
+ unless ($ferr) {
+ &Apache::loncommon::update_content_constraints($cdom,$cnum,$chome,$cdom.'_'.$cnum);
+ }
+ return;
+}
+
+sub url_paste_fixups {
+ my ($oldurl,$prefixchg,$cdom,$cnum,$allmaps,$rewrites,$retitles,$copies,
+ $dbcopies,$zombies,$params,$mapmoves,$mapchanges) = @_;
+ my $checktitle;
+ if (($prefixchg) &&
+ ($oldurl =~ m{^/uploaded/($match_domain)/($match_courseid)/supplemental})) {
+ $checktitle = 1;
+ }
+ my $file = &Apache::lonnet::getfile($oldurl);
+ return if ($file eq '-1');
+ my $parser = HTML::TokeParser->new(\$file);
+ $parser->attr_encoded(1);
+ my $changed = 0;
+ while (my $token = $parser->get_token) {
+ next if ($token->[0] ne 'S');
+ if ($token->[1] eq 'resource') {
+ my $ressrc = $token->[2]->{'src'};
+ next if ($ressrc eq '');
+ my $id = $token->[2]->{'id'};
+ if ($checktitle) {
+ my $title = $token->[2]->{'title'};
+ if ($title =~ m{\d+\Q___&&&___\E$match_username\Q___&&&___\E$match_domain\Q___&&&___\E(.+)$}) {
+ $retitles->{$oldurl}{$ressrc} = $id;
+
+ }
+ }
+ next if ($token->[2]->{'type'} eq 'external');
+ if ($token->[2]->{'type'} eq 'zombie') {
+ $zombies->{$oldurl}{$ressrc} = $id;
+ $changed = 1;
+ } elsif ($ressrc =~ m{^/uploaded/($match_domain)/($match_courseid)/(.+)$}) {
+ my $srccdom = $1;
+ my $srccnum = $2;
+ my $rem = $3;
+ if (($srccdom ne $cdom) || ($srccnum ne $cnum) || ($prefixchg) ||
+ ($mapchanges->{$oldurl})) {
+ if ($rem =~ /^(default|supplemental)(_?\d*).(sequence|page)$/) {
+ $rewrites->{$oldurl}{$ressrc} = $id;
+ $mapchanges->{$ressrc} = 1;
+ unless (&url_paste_fixups($ressrc,$prefixchg,$cdom,$cnum,$allmaps,
+ $rewrites,$retitles,$copies,$dbcopies,$zombies,
+ $params,$mapmoves,$mapchanges)) {
+ $mapmoves->{$ressrc} = 1;
+ }
+ $changed = 1;
+ } else {
+ $rewrites->{$oldurl}{$ressrc} = $id;
+ $copies->{$oldurl}{$ressrc} = $id;
+ $changed = 1;
+ }
+ }
+ } elsif ($ressrc =~ m{^/adm/($match_domain)/($match_courseid)/(.+)$}) {
+ my $srccdom = $1;
+ my $srccnum = $2;
+ if (($srccdom ne $cdom) || ($srccnum ne $cnum)) {
+ $rewrites->{$oldurl}{$ressrc} = $id;
+ $dbcopies->{$oldurl}{$ressrc} = $id;
+ $changed = 1;
+ }
+ } elsif ($ressrc =~ m{^/public/($match_domain)/($match_courseid)/(.+)$}) {
+ my $srccdom = $1;
+ my $srccnum = $2;
+ if (($srccdom ne $cdom) || ($srccnum ne $cnum)) {
+ $rewrites->{$oldurl}{$ressrc} = $id;
+ $dbcopies->{$oldurl}{$ressrc} = $id;
+ $changed = 1;
+ }
+ }
+ } elsif ($token->[1] eq 'param') {
+ my $to = $token->[2]->{'to'};
+ if ($to ne '') {
+ if (ref($params->{$oldurl}{$to}) eq 'ARRAY') {
+ push (@{$params->{$oldurl}{$to}},$token->[2]->{'name'});
+ } else {
+ @{$params->{$oldurl}{$to}} = ($token->[2]->{'name'});
+ }
+ }
+ }
+ }
+ return $changed;
+}
+
+sub apply_fixups {
+ my ($is_map,$prefixchg,$cdom,$cnum,$oldurl,$url,$removefrommap,$rewrites,
+ $retitles,$copies,$dbcopies,$zombies,$params,$docmoves,$mapmoves,$errors,
+ $before,$after) = @_;
+ my ($oldsubdir,$newsubdir,$subdirchg);
+ if ($is_map) {
+ ($oldsubdir) =
+ ($oldurl =~ m{^/uploaded/$match_domain/$match_courseid/(?:default|supplemental)_?(\d*)});
+ if ($oldsubdir eq '') {
+ $oldsubdir = 'default';
+ }
+ ($newsubdir) =
+ ($url =~ m{^/uploaded/$match_domain/$match_courseid/(?:default|supplemental)_?(\d*)});
+ if ($newsubdir eq '') {
+ $newsubdir = 'default';
+ }
+ if ($oldsubdir ne $newsubdir) {
+ $subdirchg = 1;
+ }
+ }
+ foreach my $key (keys(%{$copies}),keys(%{$docmoves})) {
+ my @allcopies;
+ if (ref($copies->{$key}) eq 'HASH') {
+ my %added;
+ foreach my $innerkey (keys(%{$copies->{$key}})) {
+ if (($innerkey ne '') && (!$added{$innerkey})) {
+ push(@allcopies,$innerkey);
+ $added{$innerkey} = 1;
+ }
+ }
+ undef(%added);
+ }
+ if ($key eq $oldurl) {
+ if ((exists($docmoves->{$key}))) {
+ unless (grep(/^\Q$oldurl\E/,@allcopies)) {
+ push(@allcopies,$oldurl);
+ }
+ }
+ }
+ if (@allcopies > 0) {
+ foreach my $item (@allcopies) {
+ my ($relpath,$fname) =
+ ($item =~ m{^(/uploaded/$match_domain/$match_courseid/(?:docs|supplemental)/(?:default|\d+)/.*/)([^/]+)$});
+ if ($fname ne '') {
+ my $content = &Apache::lonnet::getfile($item);
+ unless ($content eq '-1') {
+ my $storefn;
+ if (($key eq $oldurl) && (ref($docmoves) eq 'HASH') && (exists($docmoves->{$key}))) {
+ $storefn = $docmoves->{$key};
+ } else {
+ $storefn = $relpath;
+ $storefn =~s{^/uploaded/$match_domain/$match_courseid/}{};
+ if ($prefixchg) {
+ $storefn =~ s/^\Q$before->{'doc'}\E/$after->{'doc'}/;
+ }
+ if (($key eq $oldurl) && ($subdirchg)) {
+ $storefn =~ s{^(docs|supplemental)/\Q$oldsubdir\E/}{$1/$newsubdir/};
+ }
+ }
+ ©_dependencies($item,$storefn,$relpath,$errors,\$content);
+ my $copyurl =
+ &Apache::lonclonecourse::writefile($env{'request.course.id'},
+ $storefn.$fname,$content);
+ if ($copyurl eq '/adm/notfound.html') {
+ if ((ref($docmoves) eq 'HASH') && (exists($docmoves->{$oldurl}))) {
+ return &mt('Paste failed: an error occurred copying the file.');
+ } elsif (ref($errors) eq 'HASH') {
+ $errors->{$item} = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ foreach my $key (keys(%{$mapmoves})) {
+ my $storefn=$key;
+ $storefn=~s{^/uploaded/$match_domain/$match_courseid/}{};
+ if ($prefixchg) {
+ $storefn =~ s/^\Q$before->{'map'}\E/$after->{'map'}/;
+ }
+ my $mapcontent = &Apache::lonnet::getfile($key);
+ if ($mapcontent eq '-1') {
+ if (ref($errors) eq 'HASH') {
+ $errors->{$key} = 1;
+ }
+ } else {
+ my $newmap =
+ &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn,
+ $mapcontent);
+ if ($newmap eq '/adm/notfound.html') {
+ if (ref($errors) eq 'HASH') {
+ $errors->{$key} = 1;
+ }
+ }
+ }
+ }
+ my %updates;
+ if ($is_map) {
+ foreach my $key (keys(%{$rewrites})) {
+ $updates{$key} = 1;
+ }
+ foreach my $key (keys(%{$zombies})) {
+ $updates{$key} = 1;
+ }
+ foreach my $key (keys(%{$removefrommap})) {
+ $updates{$key} = 1;
+ }
+ foreach my $key (keys(%{$dbcopies})) {
+ $updates{$key} = 1;
+ }
+ foreach my $key (keys(%{$retitles})) {
+ $updates{$key} = 1;
+ }
+ foreach my $key (keys(%updates)) {
+ my (%torewrite,%toretitle,%toremove,%zombie,%newdb);
+ if (ref($rewrites->{$key}) eq 'HASH') {
+ %torewrite = %{$rewrites->{$key}};
+ }
+ if (ref($retitles->{$key}) eq 'HASH') {
+ %toretitle = %{$retitles->{$key}};
+ }
+ if (ref($removefrommap->{$key}) eq 'HASH') {
+ %toremove = %{$removefrommap->{$key}};
+ }
+ if (ref($zombies->{$key}) eq 'HASH') {
+ %zombie = %{$zombies->{$key}};
+ }
+ if (ref($dbcopies->{$key}) eq 'HASH') {
+ foreach my $item (keys(%{$dbcopies->{$key}})) {
+ $newdb{$item} = &dbcopy($item);
+ }
+ }
+ my $map = &Apache::lonnet::getfile($key);
+ my $newcontent;
+ if ($map eq '-1') {
+ return &mt('Paste failed: an error occurred reading a folder or page: [_1].',$key);
+ } else {
+ my $parser = HTML::TokeParser->new(\$map);
+ $parser->attr_encoded(1);
+ while (my $token = $parser->get_token) {
+ if ($token->[0] eq 'S') {
+ if ($token->[2]->{'type'} eq 'zombie') {
+ next if (($token->[2]->{'src'} ne '') &&
+ ($zombie{$token->[2]->{'src'}} eq $token->[2]->{'id'}));
+ }
+ if ($token->[1] eq 'resource') {
+ my $src = $token->[2]->{'src'};
+ my $id = $token->[2]->{'id'};
+ my $title = $token->[2]->{'title'};
+ my $changed;
+ if ((exists($toretitle{$src})) && ($toretitle{$src} eq $id)) {
+ if ($title =~ m{^\d+\Q___&&&___\E$match_username\Q___&&&___\E$match_domain\Q___&&&___\E(.+)$}) {
+ $token->[2]->{'title'} = $1;
+ $changed = 1;
+ }
+ }
+ if ((exists($torewrite{$src})) && ($torewrite{$src} eq $id)) {
+ $src =~ s{^/(uploaded|adm|public)/$match_domain/$match_courseid/}{/$1/$cdom/$cnum/};
+ if ($src =~ m{^/uploaded/}) {
+ if ($prefixchg) {
+ if ($src =~ /\.(page|sequence)$/) {
+ $src =~ s#^(/uploaded/$match_domain/$match_courseid/)\Q$before->{'map'}\E#$1$after->{'map'}#;
+ } else {
+ $src =~ s#^(/uploaded/$match_domain/$match_courseid/)\Q$before->{'doc'}\E#$1$after->{'doc'}#;
+ }
+ }
+ if (($key eq $oldurl) && ($src !~ /\.(page|sequence)$/) && ($subdirchg)) {
+ $src =~ s{^(/uploaded/$match_domain/$match_courseid/\w+/)\Q$oldsubdir\E}{$1$newsubdir};
+ }
+ }
+ $token->[2]->{'src'} = $src;
+ $changed = 1;
+ } elsif ($newdb{$src} ne '') {
+ $token->[2]->{'src'} = $newdb{$src};
+ $changed = 1;
+ }
+ if ($changed) {
+ $newcontent .= "<$token->[1]";
+ foreach my $attr (@{$token->[3]}) {
+ if ($attr =~ /^\w+$/) {
+ $newcontent .= ' '.$attr.'="'.$token->[2]->{$attr}.'"';
+ }
+ }
+ $newcontent .= ' />'."\n";
+ } else {
+ $newcontent .= $token->[4]."\n";
+ }
+ } elsif (($token->[2]->{'id'} ne '') &&
+ (exists($toremove{$token->[2]->{'id'}}))) {
+ next;
+ } else {
+ $newcontent .= $token->[4]."\n";
+ }
+ } elsif ($token->[0] eq 'E') {
+ $newcontent .= $token->[2]."\n";
+ }
+ }
+ }
+ my $storefn;
+ if ($key eq $oldurl) {
+ $storefn = $url;
+ $storefn=~s{^/uploaded/$match_domain/$match_courseid/}{};
+ } else {
+ $storefn = $key;
+ $storefn=~s{^/uploaded/$match_domain/$match_courseid/}{};
+ if ($prefixchg) {
+ $storefn =~ s/^\Q$before->{'map'}\E/$after->{'map'}/;
+ }
+ }
+ my $newmapurl =
+ &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn,
+ $newcontent);
+ if ($newmapurl eq '/adm/notfound.html') {
+ return &mt('Paste failed: an error occurred saving the folder or page.');
+ }
+ }
+ }
+ return 'ok';
+}
+
+sub copy_dependencies {
+ my ($item,$storefn,$relpath,$errors,$contentref) = @_;
+ my $content;
+ if (ref($contentref)) {
+ $content = $$contentref;
+ } else {
+ $content = &Apache::lonnet::getfile($item);
+ }
+ unless ($content eq '-1') {
+ my $mm = new File::MMagic;
+ my $mimetype = $mm->checktype_contents($content);
+ if ($mimetype eq 'text/html') {
+ my (%allfiles,%codebase,$state);
+ my $res = &Apache::lonnet::extract_embedded_items(undef,\%allfiles,\%codebase,\$content);
+ if ($res eq 'ok') {
+ my ($numexisting,$numpathchanges,$existing);
+ (undef,$numexisting,$numpathchanges,$existing) =
+ &Apache::loncommon::ask_for_embedded_content(
+ '/adm/coursedocs',$state,\%allfiles,\%codebase,
+ {'error_on_invalid_names' => 1,
+ 'ignore_remote_references' => 1,
+ 'docs_url' => $item,
+ 'context' => 'paste'});
+ if ($numexisting > 0) {
+ if (ref($existing) eq 'HASH') {
+ foreach my $dep (keys(%{$existing})) {
+ my $depfile = $dep;
+ unless ($depfile =~ m{^\Q$relpath\E}) {
+ $depfile = $relpath.$dep;
+ }
+ my $depcontent = &Apache::lonnet::getfile($depfile);
+ unless ($depcontent eq '-1') {
+ my $storedep = $dep;
+ $storedep =~ s{^\Q$relpath\E}{};
+ my $dep_url =
+ &Apache::lonclonecourse::writefile(
+ $env{'request.course.id'},
+ $storefn.$storedep,$depcontent);
+ if ($dep_url eq '/adm/notfound.html') {
+ if (ref($errors) eq 'HASH') {
+ $errors->{$depfile} = 1;
+ }
+ } else {
+ ©_dependencies($depfile,$storefn,$relpath,$errors,\$depcontent);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
my %parameter_type = ( 'randompick' => 'int_pos',
'hiddenresource' => 'string_yesno',
'encrypturl' => 'string_yesno',
@@ -884,14 +1495,25 @@ sub editor {
}
if ($env{'form.pastemarked'}) {
+ my %paste_errors;
my $paste_res =
- &do_paste_from_buffer($coursenum,$coursedom,$folder);
+ &do_paste_from_buffer($coursenum,$coursedom,$folder,\%paste_errors);
if ($paste_res eq 'ok') {
+# Store the result
($errtext,$fatal) = &storemap($coursenum,$coursedom,$folder.'.'.$container);
return $errtext if ($fatal);
} elsif ($paste_res ne '') {
$r->print(''.$paste_res.' ');
}
+ if (keys(%paste_errors) > 0) {
+ $r->print(''."\n".
+ &mt('The following files are either dependencies of a web page or references within a folder and/or composite page which could not be copied during the paste operation:')."\n".
+ ' '."\n");
+ foreach my $key (sort(keys(%paste_errors))) {
+ $r->print('- '.$key.'
'."\n");
+ }
+ $r->print(' '."\n");
+ }
}
$r->print($upload_output);
@@ -1016,7 +1638,7 @@ sub editor {
my $readfile="/uploaded/$coursedom/$coursenum/$folder.$container";
$r->print(&generate_edit_table($tid,$orderhash,$to_show,$iconpath,$jumpto,
$readfile));
- &print_paste_buffer($r,$container);
+ &print_paste_buffer($r,$container,$folder);
} else {
if (&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) {
#Function Box for Supplemental Content for users with mdc priv.
@@ -1192,36 +1814,13 @@ sub is_supplemental_title {
return scalar($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/);
}
-sub parse_supplemental_title {
- my ($title) = @_;
-
- my ($foldertitle,$renametitle);
- if ($title =~ /&&&/) {
- $title = &HTML::Entites::decode($title);
- }
- if ($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/) {
- $renametitle=$4;
- my ($time,$uname,$udom) = ($1,$2,$3);
- $foldertitle=&Apache::lontexconvert::msgtexconverted($4);
- my $name = &Apache::loncommon::plainname($uname,$udom);
- $name = &HTML::Entities::encode($name,'"<>&\'');
- $renametitle = &HTML::Entities::encode($renametitle,'"<>&\'');
- $title=''.&Apache::lonlocal::locallocaltime($time).' '.
- $name.': '.$foldertitle;
- }
- if (wantarray) {
- return ($title,$foldertitle,$renametitle);
- }
- return $title;
-}
-
# --------------------------------------------------------------- An entry line
sub entryline {
my ($index,$title,$url,$folder,$allowed,$residx,$coursenum,$crstype)=@_;
my ($foldertitle,$pagetitle,$renametitle);
if (&is_supplemental_title($title)) {
- ($title,$foldertitle,$renametitle) = &parse_supplemental_title($title);
+ ($title,$foldertitle,$renametitle) = &Apache::loncommon::parse_supplemental_title($title);
$pagetitle = $foldertitle;
} else {
$title=&HTML::Entities::encode($title,'"<>&\'');
@@ -2543,7 +3142,7 @@ sub handler {
'upld' => 'Import Document',
'srch' => 'Search',
'impo' => 'Import',
- 'wish' => 'Import from Wishlist',
+ 'lnks' => 'Import from Stored Links',
'selm' => 'Select Map',
'load' => 'Load Map',
'reco' => 'Recover Deleted Documents',
@@ -2611,7 +3210,7 @@ SEDFFORM
my @simpleeditdefaultforma = (
{ '' => "$uploadtag" },
{ '' => "$help{'Importing_LON-CAPA_Resource'}" },
- { '' => "" },
+ { '' => "" },
);
$simpleeditdefaultform .= &create_form_ul(&create_list_elements(@simpleeditdefaultforma));
$simpleeditdefaultform .=(< ['Import Documents',$fileuploadform],
- 'bb' => ['Published Resources',$simpleeditdefaultform],
+ 'aa' => ['Import Content',$fileuploadform],
+ 'bb' => ['Published Content',$simpleeditdefaultform],
'cc' => ['Grading Resources',$gradingform],
);
unless ($env{'form.pagepath'}) {
@@ -2998,7 +3597,7 @@ my @supimportdoc = (
$supupdocform = &create_form_ul(&create_list_elements(@supimportdoc)) . ' ' . $supupdocform;
my %suporderhash = (
'00' => ['Supnewfolder', $supnewfolderform],
- 'ee' => ['Import Documents',$supupdocform],
+ 'ee' => ['Import Content',$supupdocform],
'ff' => ['Special Documents',&create_form_ul(&create_list_elements(@specialdocs))]
);
if ($supplementalflag) {
@@ -3104,7 +3703,7 @@ sub decompression_phase_one {
my ($dir,$file,$warning,$error,$output);
my ($destination,$dir_root,$londocroot,$docudom,$docuname,$container,$hiddenelem)=
&decompression_info();
- if ($env{'form.archiveurl'} !~ m{^/uploaded/\Q$docudom/$docuname/docs/\E(?:default|supplemental|\d+).*/([^/]+)$}) {
+ if ($env{'form.archiveurl'} !~ m{^/uploaded/\Q$docudom/$docuname/\E(?:docs|supplemental)/(?:default|\d+).*/([^/]+)$}) {
$error = &mt('Archive file "[_1]" not in the expected location.',$env{'form.archiveurl'});
} else {
my $file = $1;
@@ -3283,26 +3882,24 @@ sub generate_edit_table {
my $backicon = $iconpath.'clickhere.gif';
my $backtext = &mt('To Overview');
$form = ' |