--- loncom/interface/londocs.pm 2013/01/09 17:23:58 1.484.2.23 +++ loncom/interface/londocs.pm 2013/03/17 23:55:01 1.484.2.29 @@ -1,7 +1,7 @@ # The LearningOnline Network # Documents # -# $Id: londocs.pm,v 1.484.2.23 2013/01/09 17:23:58 raeburn Exp $ +# $Id: londocs.pm,v 1.484.2.29 2013/03/17 23:55:01 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -152,7 +152,7 @@ sub dumpcourse { $r->print(&endContentScreen()); return ''; } - my ($ca,$cd)=split(/\@/,$env{'form.authorspace'}); + my ($ca,$cd)=split(/\:/,$env{'form.authorspace'}); $r->print('

'.&mt('Copying Files').'

'); my $title=$env{'form.authorfolder'}; $title=&clean($title); @@ -289,7 +289,7 @@ sub group_import { $env{'form.output'}=$newmapstr; my $result=&Apache::lonnet::finishuserfileupload($coursenum,$coursedom, 'output',$1.$2); - if ($result != m|^/uploaded/|) { + if ($result !~ m{^/uploaded/}) { $errtext.='Map not saved: A network error occurred when trying to save the new map. '; $fatal = 2; } @@ -300,7 +300,7 @@ sub group_import { if ($url) { if (($caller eq 'londocs') && ($folder =~ /^default/)) { - unless ($donechk) { + if (($url =~ /\.(page|sequence)$/) && (!$donechk)) { my $chome = &Apache::lonnet::homeserver($coursenum,$coursedom); my $cid = $coursedom.'_'.$coursenum; $allmaps = @@ -325,6 +325,48 @@ sub group_import { if ($url=~m{^http://} || $url=~m{^https://}) { $ext = 'true'; } $url = &LONCAPA::map::qtunescape($url); $name = &LONCAPA::map::qtunescape($name); + if ($name eq '') { + $name = &mt('Web Page'); + } + if ($url =~ m{^/uploaded/$coursedom/$coursenum/((?:docs|supplemental)/(?:default|\d+))/new\.html$}) { + my $filepath = $1; + my $fname = $name; + if ($fname =~ /^\W+$/) { + $fname = 'web'; + } else { + $fname =~ s/\W/_/g; + } + if (length($fname > 15)) { + $fname = substr($fname,0,14); + } + my $initialtext = &mt('Replace with your own content.'); + my $newhtml = < + + + +$name + + +$initialtext + + +END + $env{'form.output'}=$newhtml; + my $result = + &Apache::lonnet::finishuserfileupload($coursenum,$coursedom, + 'output', + "$filepath/$residx/$fname.html"); + if ($result =~ m{^/uploaded/}) { + $url = $result; + if ($filepath =~ /^supplemental/) { + $name = time.'___&&&___'.$env{'user.name'}.'___&&&___'. + $env{'user.domain'}.'___&&&___'.$name; + } + } else { + return (&mt('Failed to save new web page.'),1); + } + } $LONCAPA::map::resources[$residx] = join(':', ($name, $url, $ext, 'normal', 'res')); } @@ -335,7 +377,8 @@ sub group_import { removefrommap => \%removefrommap, removeparam => \%removeparam, ); - &apply_fixups($folder,1,$coursedom,$coursenum,\%import_errors,\%updated); + my ($result,$msgsarray,$lockerror) = + &apply_fixups($folder,1,$coursedom,$coursenum,\%import_errors,\%updated); if (keys(%import_errors) > 0) { $fixuperrors = '

'."\n". @@ -346,6 +389,18 @@ sub group_import { } $fixuperrors .= '

'."\n"; } + if (ref($msgsarray) eq 'ARRAY') { + if (@{$msgsarray} > 0) { + $fixuperrors .= '

'. + join('
',@{$msgsarray}). + '

'; + } + } + if ($lockerror) { + $fixuperrors .= '

'. + $lockerror. + '

'; + } } my ($errtext,$fatal) = &storemap($coursenum, $coursedom, $folder.'.'.$container,1); @@ -735,7 +790,7 @@ sub print_paste_buffer { $buffer = $type.': '. &LONCAPA::map::qtescape($env{'docs.markedcopy_title'}).' ('. &LONCAPA::map::qtescape($env{'docs.markedcopy_url'}).')'; - } else { + } else { my $icon = &Apache::loncommon::icon($extension); if ($extension eq 'sequence' && $env{'docs.markedcopy_url'} =~ m{/default_\d+\.sequence$ }x) { @@ -747,19 +802,36 @@ sub print_paste_buffer { } if ($canpaste) { $r->print('
'.$buffer); - if (($is_uploaded_map) && (!$areachange)) { - if ((!$othercourse) && ($env{'docs.markedcopy_cmd'} eq 'cut')) { + if ((!$areachange) && (!$othercourse) && + ($env{'docs.markedcopy_cmd'} eq 'cut')) { + if (($is_uploaded_map) || + ($env{'docs.markedcopy_url'} =~ /(bulletinboard|smppg)$/) || + ($env{'docs.markedcopy_url'} =~ m{^/uploaded/$coursedom/$coursenum/(?:docs|supplemental)/(.+)$})) { + my ($copytext,$movetext); + if ($is_uploaded_map) { + $copytext = &mt('Copy to new folder'); + $movetext = &mt('Move old folder'); + } elsif ($env{'docs.markedcopy_url'} =~ /bulletinboard$/) { + $copytext = &mt('Copy to new bulletin board (not posts)'); + $movetext = &mt('Move old bulletin board (not posts)'); + } elsif ($env{'docs.markedcopy_url'} =~ /smppg$/) { + $copytext = &mt('Copy to new simple page'); + $movetext = &mt('Move old simple page'); + } else { + $copytext = &mt('Copy to new uploaded document'); + $movetext = &mt('Move old uploaded document'); + } $r->print((' 'x 4).''. ''. &mt('Show Paste Options').'
'. '
'.(' 'x 4). ''.(' ' x2). + $copytext.''.(' ' x2). '
'); - if ($env{'docs.markedcopy_nested'}) { + $movetext.'
'); + if (($is_uploaded_map) && ($env{'docs.markedcopy_nested'})) { $r->print('
'.&mt('Folder to paste contains sub-folders'). '
'); my @pastemaps = split(/\&/,$env{'docs.markedcopy_nested'}); @@ -965,17 +1037,19 @@ sub do_paste_from_buffer { } if (($srcdom ne $coursedom) || ($srcnum ne $coursenum) || ($prefixchg) || (($newurl ne '') && ($newurl ne $url))) { - unless (&url_paste_fixups($url,$folder,$prefixchg,$coursedom,$coursenum, - $allmaps,\%rewrites,\%retitles,\%copies,\%dbcopies, + unless (&url_paste_fixups($url,$folder,$prefixchg,$coursedom, + $coursenum,$srcdom,$srcnum,$allmaps, + \%rewrites,\%retitles,\%copies,\%dbcopies, \%zombies,\%params,\%mapmoves,\%mapchanges,\%tomove, \%newsubdir,\%newurls)) { $mapmoves{$url} = 1; } $url = $newurl; } elsif ($env{'docs.markedcopy_nested'}) { - &url_paste_fixups($url,$folder,$prefixchg,$coursedom,$coursenum,$allmaps,\%rewrites, + &url_paste_fixups($url,$folder,$prefixchg,$coursedom,$coursenum, + $srcdom,$srcnum,$allmaps,\%rewrites, \%retitles,\%copies,\%dbcopies,\%zombies,\%params,\%mapmoves, - \%mapchanges,\%tomove,\%newsubdir,\%newurls); + \%mapchanges,\%tomove,\%newsubdir,\%newurls); } } elsif ($url=~m {^/res/}) { # published maps can only exists once, so remove it from paste buffer when done @@ -988,22 +1062,34 @@ sub do_paste_from_buffer { } } } - 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 $dbresult=&Apache::lonnet::put($db_name,\%contents, - $coursedom,$coursenum); - if ($dbresult eq 'ok') { - $url =~ s{/(\d*)/smppg$ }{/$now/smppg}x; + my $lockerrors; + if ($url=~ m{/(bulletinboard|smppg)$}) { + my $prefix = $1; + #need to copy the db contents to a new one, unless this is a move. + my %info = ( + src => $url, + cdom => $coursedom, + cnum => $coursenum, + ); + my (%lockerr,$msg); + unless ($env{'form.docs.markedcopy_options'} eq 'move') { + my ($newurl,$result,$errtext) = + &dbcopy(\%info,$coursedom,$coursenum,\%lockerr); + if ($result eq 'ok') { + $url = $newurl; $title=&mt('Copy of').' '.$title; } else { - return (&mt('Paste failed: An error occurred when copying the simple page.')); + if ($prefix eq 'smppg') { + $msg = &mt('Paste failed: An error occurred when copying the simple page.').' '.$errtext; + } elsif ($prefix eq 'bulletinboard') { + $msg = &mt('Paste failed: An error occurred when copying the bulletin board.').' '.$errtext; + } + return ($result,undef,[$msg],$lockerr{$prefix}); } - } + if ($lockerr{$prefix}) { + $lockerrors = $lockerr{$prefix}; + } + } } $title = &LONCAPA::map::qtunescape($title); my $ext='false'; @@ -1030,7 +1116,9 @@ sub do_paste_from_buffer { if ($newdocsdir eq '') { $newdocsdir = 'default'; } - if (($prefixchg) || ($srcdom ne $coursedom) || ($srcnum ne $coursenum)) { + if (($prefixchg) || + ($srcdom ne $coursedom) || ($srcnum ne $coursenum) || + ($env{'form.docs.markedcopy_options'} ne 'move')) { my $newpath = "$newprefix/$newdocsdir/$newidx/$rem"; $url = &Apache::lonclonecourse::writefile($env{'request.course.id'},$newpath, @@ -1067,14 +1155,15 @@ sub do_paste_from_buffer { docmoves => \%docmoves, mapmoves => \%mapmoves, ); - $result = + ($result,my $msgsarray,my $lockerror) = &apply_fixups($folder,$is_map,$coursedom,$coursenum,$errors, \%updated,\%info,\%moves,$prefixchg,$oldurl,$url,'paste'); + $lockerrors .= $lockerror; if ($result eq 'ok') { if ($is_map) { my ($errtext,$fatal) = &mapread($coursenum,$coursedom, $folder.'.'.$container); - return $errtext if ($fatal); + return ($errtext,$save_err,$msgsarray,$lockerrors) if ($fatal); if ($#LONCAPA::map::order<1) { my $idx=&LONCAPA::map::getresidx(); @@ -1111,7 +1200,7 @@ sub do_paste_from_buffer { &Apache::lonnet::delenv('docs.markedcopy_nested'); &Apache::lonnet::delenv('docs.markedcopy_nestednames'); } - return ($result,$save_err); + return ($result,$save_err,$msgsarray,$lockerrors); } sub get_newmap_url { @@ -1175,20 +1264,96 @@ sub get_newmap_url { } 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; + my ($dbref,$coursedom,$coursenum,$lockerrorsref) = @_; + my ($url,$result,$errtext); + my $url = $dbref->{'src'}; + if (ref($dbref) eq 'HASH') { + if ($url =~ m{/(smppg|bulletinboard)$}) { + my $prefix = $1; + if (($dbref->{'cdom'} =~ /^$match_domain$/) && + ($dbref->{'cnum'} =~ /^$match_courseid$/)) { + my $db_name; + my $marker = (split(m{/},$url))[4]; + $marker=~s/\D//g; + if ($dbref->{'src'} =~ m{/smppg$}) { + $db_name = + &Apache::lonsimplepage::get_db_name($url,$marker, + $dbref->{'cdom'}, + $dbref->{'cnum'}); + } else { + $db_name = 'bulletinpage_'.$marker; + } + my ($suffix,$freedlock,$error) = + &Apache::lonnet::get_timebased_id($prefix,'num','templated', + $coursedom,$coursenum, + 'concat'); + if (!$suffix) { + if ($prefix eq 'smppg') { + $errtext = &mt('Failed to acquire a unique timestamp-based suffix when copying a simple page [_1].',$url); + } else { + $errtext = &mt('Failed to acquire a unique timestamp-based suffix when copying a bulletin board [_1].',$url); + } + if ($error) { + $errtext .= '
'.$error; + } + } else { + #need to copy the db contents to a new one. + my %contents=&Apache::lonnet::dump($db_name, + $dbref->{'cdom'}, + $dbref->{'cnum'}); + if (exists($contents{'uploaded.photourl'})) { + my $photo = $contents{'uploaded.photourl'}; + my ($subdir,$fname) = + ($photo =~ m{^/uploaded/$match_domain/$match_courseid/+(bulletin|simplepage)/(?:|\d+/)([^/]+)$}); + my $newphoto; + if ($fname ne '') { + my $content = &Apache::lonnet::getfile($photo); + unless ($content eq '-1') { + $env{'form.'.$suffix.'.photourl'} = $content; + $newphoto = + &Apache::lonnet::finishuserfileupload($coursenum,$coursedom,$suffix.'.photourl',"$subdir/$suffix/$fname"); + delete($env{'form.'.$suffix.'.photourl'}); + } + } + if ($newphoto =~ m{^/uploaded/}) { + $contents{'uploaded.photourl'} = $newphoto; + } + } + $db_name =~ s{_\d*$ }{_$suffix}x; + $result=&Apache::lonnet::put($db_name,\%contents, + $coursedom,$coursenum); + if ($result eq 'ok') { + $url =~ s{/(\d*)/(smppg|bulletinboard)$}{/$suffix/$2}x; + } + } + if (($freedlock ne 'ok') && (ref($lockerrorsref) eq 'HASH')) { + $lockerrorsref->{$prefix} = + '
'. + &mt('There was a problem removing a lockfile.'); + if ($prefix eq 'smppg') { + $lockerrorsref->{$prefix} .= + &mt('This will prevent creation of additional simple pages in this course.'); + } else { + $lockerrorsref->{$prefix} .= &mt('This will prevent creation of additional bulletin boards in this course.'); + } + $lockerrorsref->{$prefix} .= &mt('Please contact the domain coordinator for your LON-CAPA domain.').'
'; + } + } + } elsif ($url =~ m{/syllabus$}) { + if (($dbref->{'cdom'} =~ /^$match_domain$/) && + ($dbref->{'cnum'} =~ /^$match_courseid$/)) { + if (($dbref->{'cdom'} ne $coursedom) || + ($dbref->{'cnum'} ne $coursenum)) { + my %contents=&Apache::lonnet::dump('syllabus', + $dbref->{'cdom'}, + $dbref->{'cnum'}); + $result=&Apache::lonnet::put('syllabus',\%contents, + $coursedom,$coursenum); + } + } } } - return $url; + return ($url,$result,$errtext); } sub uniqueness_check { @@ -1254,8 +1419,9 @@ sub contained_map_check { } sub url_paste_fixups { - my ($oldurl,$folder,$prefixchg,$cdom,$cnum,$allmaps,$rewrites,$retitles,$copies, - $dbcopies,$zombies,$params,$mapmoves,$mapchanges,$tomove,$newsubdir,$newurls) = @_; + my ($oldurl,$folder,$prefixchg,$cdom,$cnum,$fromcdom,$fromcnum,$allmaps, + $rewrites,$retitles,$copies,$dbcopies,$zombies,$params,$mapmoves, + $mapchanges,$tomove,$newsubdir,$newurls) = @_; my $checktitle; if (($prefixchg) && ($oldurl =~ m{^/uploaded/$match_domain/$match_courseid/supplemental})) { @@ -1282,13 +1448,13 @@ sub url_paste_fixups { my $title = $token->[2]->{'title'}; if ($checktitle) { if ($title =~ m{\d+\Q___&&&___\E$match_username\Q___&&&___\E$match_domain\Q___&&&___\E(.+)$}) { - $retitles->{$oldurl}{$ressrc} = $id; + $retitles->{$oldurl}{$id} = $ressrc; } } next if ($token->[2]->{'type'} eq 'external'); if ($token->[2]->{'type'} eq 'zombie') { next if ($skip); - $zombies->{$oldurl}{$ressrc} = $id; + $zombies->{$oldurl}{$id} = $ressrc; $changed = 1; } elsif ($ressrc =~ m{^/uploaded/($match_domain)/($match_courseid)/(.+)$}) { my $srcdom = $1; @@ -1300,10 +1466,11 @@ sub url_paste_fixups { my $prefix = $1; $mapname = $prefix.$2; if ($tomove->{$mapname}) { - &url_paste_fixups($ressrc,$folder,$prefixchg,$cdom,$cnum,$allmaps, - $rewrites,$retitles,$copies,$dbcopies,$zombies, - $params,$mapmoves,$mapchanges,$tomove,$newsubdir, - $newurls); + &url_paste_fixups($ressrc,$folder,$prefixchg,$cdom,$cnum, + $srcdom,$srcnum,$allmaps,$rewrites, + $retitles,$copies,$dbcopies,$zombies, + $params,$mapmoves,$mapchanges,$tomove, + $newsubdir,$newurls); next; } else { ($newurl,my $error) = @@ -1321,28 +1488,39 @@ sub url_paste_fixups { ($mapchanges->{$oldurl}) || (($newurl ne '') && ($newurl ne $oldurl))) { if ($rem =~ /^(default|supplemental)(_?\d*).(sequence|page)$/) { - $rewrites->{$oldurl}{$ressrc} = $id; + $rewrites->{$oldurl}{$id} = $ressrc; $mapchanges->{$ressrc} = 1; - unless (&url_paste_fixups($ressrc,$folder,$prefixchg,$cdom,$cnum,$allmaps, - $rewrites,$retitles,$copies,$dbcopies,$zombies, - $params,$mapmoves,$mapchanges,$tomove,$newsubdir, - $newurls)) { + unless (&url_paste_fixups($ressrc,$folder,$prefixchg,$cdom, + $cnum,$srcdom,$srcnum,$allmaps, + $rewrites,$retitles,$copies,$dbcopies, + $zombies,$params,$mapmoves,$mapchanges, + $tomove,$newsubdir,$newurls)) { $mapmoves->{$ressrc} = 1; } $changed = 1; } else { - $rewrites->{$oldurl}{$ressrc} = $id; + $rewrites->{$oldurl}{$id} = $ressrc; $copies->{$oldurl}{$ressrc} = $id; $changed = 1; } } - } elsif ($ressrc =~ m{^/adm/($match_domain)/($match_courseid)/(.+)$}) { + } elsif ($ressrc =~ m{^/adm/($match_domain)/($match_courseid)/.+$}) { next if ($skip); my $srcdom = $1; my $srcnum = $2; if (($srcdom ne $cdom) || ($srcnum ne $cnum)) { - $rewrites->{$oldurl}{$ressrc} = $id; - $dbcopies->{$oldurl}{$ressrc} = $id; + $rewrites->{$oldurl}{$id} = $ressrc; + $dbcopies->{$oldurl}{$id}{'src'} = $ressrc; + $dbcopies->{$oldurl}{$id}{'cdom'} = $srcdom; + $dbcopies->{$oldurl}{$id}{'cnum'} = $srcnum; + $changed = 1; + } + } elsif ($ressrc =~ m{^/adm/$match_domain/$match_username/\d+/(smppg|bulletinboard)$}) { + if (($fromcdom ne $cdom) || ($fromcnum ne $cnum) || + ($env{'form.docs.markedcopy_options'} ne 'move')) { + $dbcopies->{$oldurl}{$id}{'src'} = $ressrc; + $dbcopies->{$oldurl}{$id}{'cdom'} = $fromcdom; + $dbcopies->{$oldurl}{$id}{'cnum'} = $fromcnum; $changed = 1; } } elsif ($ressrc =~ m{^/public/($match_domain)/($match_courseid)/(.+)$}) { @@ -1350,8 +1528,9 @@ sub url_paste_fixups { my $srcdom = $1; my $srcnum = $2; if (($srcdom ne $cdom) || ($srcnum ne $cnum)) { - $rewrites->{$oldurl}{$ressrc} = $id; - $dbcopies->{$oldurl}{$ressrc} = $id; + $dbcopies->{$oldurl}{$id}{'src'} = $ressrc; + $dbcopies->{$oldurl}{$id}{'cdom'} = $srcdom; + $dbcopies->{$oldurl}{$id}{'cnum'} = $srcnum; $changed = 1; } } @@ -1374,7 +1553,8 @@ sub apply_fixups { my ($folder,$is_map,$cdom,$cnum,$errors,$updated,$info,$moves,$prefixchg, $oldurl,$url,$caller) = @_; my (%rewrites,%zombies,%removefrommap,%removeparam,%dbcopies,%retitles, - %params,%newsubdir,%before,%after,%copies,%docmoves,%mapmoves); + %params,%newsubdir,%before,%after,%copies,%docmoves,%mapmoves,@msgs, + %lockerrors,$lockmsg); if (ref($updated) eq 'HASH') { if (ref($updated->{'rewrites'}) eq 'HASH') { %rewrites = %{$updated->{'rewrites'}}; @@ -1436,7 +1616,7 @@ sub apply_fixups { } if ($key eq $oldurl) { if ((exists($docmoves{$key}))) { - unless (grep(/^\Q$oldurl\E/,@allcopies)) { + unless (grep(/^\Q$oldurl\E$/,@allcopies)) { push(@allcopies,$oldurl); } } @@ -1458,7 +1638,7 @@ sub apply_fixups { $storefn =~ s/^\Q$before{'doc'}\E/$after{'doc'}/; } if ($newsubdir{$key}) { - $storefn =~ s#^(docs|supplemental)/\Q$oldsubdir\E/#$1/$newsubdir{$key}#; + $storefn =~ s#^(docs|supplemental)/\Q$oldsubdir\E/#$1/$newsubdir{$key}/#; } } ©_dependencies($item,$storefn,$relpath,$errors,\$content); @@ -1531,8 +1711,17 @@ sub apply_fixups { %zombie = %{$zombies{$key}}; } if (ref($dbcopies{$key}) eq 'HASH') { - foreach my $item (keys(%{$dbcopies{$key}})) { - $newdb{$item} = &dbcopy($item); + foreach my $idx (keys(%{$dbcopies{$key}})) { + if (ref($dbcopies{$key}{$idx}) eq 'HASH') { + my ($newurl,$result,$errtext) = + &dbcopy($dbcopies{$key}{$idx},$cdom,$cnum,\%lockerrors); + if ($result eq 'ok') { + $newdb{$idx} = $newurl; + } elsif (ref($errors) eq 'HASH') { + $errors->{$key} = 1; + } + push(@msgs,$errtext); + } } } if (ref($params{$key}) eq 'HASH') { @@ -1540,12 +1729,12 @@ sub apply_fixups { } my ($errtext,$fatal) = &LONCAPA::map::mapread($key); if ($fatal) { - return $errtext; + return ($errtext); } for (my $i=0; $i<@LONCAPA::map::zombies; $i++) { if (defined($LONCAPA::map::zombies[$i])) { my ($title,$src,$ext,$type)=split(/\:/,$LONCAPA::map::zombies[$i]); - if ($zombie{$src} eq $i) { + if ($zombie{$i} eq $src) { undef($LONCAPA::map::zombies[$i]); } } @@ -1565,12 +1754,12 @@ sub apply_fixups { next; } my $origsrc = $src; - if ((exists($toretitle{$src})) && ($toretitle{$src} eq $idx)) { + if ((exists($toretitle{$idx})) && ($toretitle{$idx} eq $src)) { if ($title =~ m{^\d+\Q___&&&___\E$match_username\Q___&&&___\E$match_domain\Q___&&&___\E(.+)$}) { $changed = 1; } } - if ((exists($torewrite{$src})) && ($torewrite{$src} eq $idx)) { + if ((exists($torewrite{$idx})) && ($torewrite{$idx} eq $src)) { $src =~ s{^/(uploaded|adm|public)/$match_domain/$match_courseid/}{/$1/$cdom/$cnum/}; if ($origsrc =~ m{^/uploaded/}) { if ($prefixchg && $before{'map'} && $after{'map'}) { @@ -1580,17 +1769,17 @@ sub apply_fixups { $src =~ s#^(/uploaded/$match_domain/$match_courseid/)\Q$before{'doc'}\E#$1$after{'doc'}#; } } - if ($newsubdir{$origsrc}) { - if ($src =~ /\.(page|sequence)$/) { + if ($origsrc =~ /\.(page|sequence)$/) { + if ($newsubdir{$origsrc}) { $src =~ s#^(/uploaded/$match_domain/$match_courseid/(?:default|supplemental)_)(\d+)#$1$newsubdir{$origsrc}#; - } else { - $src =~ s#^(/uploaded/$match_domain/$match_courseid/\w+/)(\d+)#$1$newsubdir{$origsrc}#; } + } elsif ($newsubdir{$key}) { + $src =~ s#^(/uploaded/$match_domain/$match_courseid/\w+/)(\d+)#$1$newsubdir{$key}#; } } $changed = 1; - } elsif ($newdb{$src} ne '') { - $src = $newdb{$src}; + } elsif ($newdb{$idx} ne '') { + $src = $newdb{$idx}; $changed = 1; } if ($changed) { @@ -1605,6 +1794,9 @@ sub apply_fixups { } } } + if (values(%lockerrors) > 0) { + $lockmsg = join('
',values(%lockerrors)); + } my $storefn; if ($key eq $oldurl) { $storefn = $url; @@ -1627,12 +1819,12 @@ sub apply_fixups { &LONCAPA::map::storemap("/uploaded/$cdom/$cnum/$storefn",1,$report); if ($errtext) { if ($caller eq 'paste') { - return &mt('Paste failed: an error occurred saving the folder or page.'); + return (&mt('Paste failed: an error occurred saving the folder or page.')); } } } } - return 'ok'; + return ('ok',\@msgs,$lockmsg); } sub copy_dependencies { @@ -1697,23 +1889,93 @@ my %parameter_type = ( 'randompick' my $valid_parameters_re = join('|',keys(%parameter_type)); # set parameters sub update_parameter { - - return 0 if ($env{'form.changeparms'} !~ /^($valid_parameters_re)$/); - - my $which = $env{'form.changeparms'}; - my $idx = $env{'form.setparms'}; - if ($env{'form.'.$which.'_'.$idx}) { - my $value = ($which eq 'randompick') ? $env{'form.'.$which.'_'.$idx} - : 'yes'; - &LONCAPA::map::storeparameter($idx, 'parameter_'.$which, $value, - $parameter_type{$which}); - &remember_parms($idx,$which,'set',$value); + if ($env{'form.changeparms'} eq 'all') { + my (@allidx,@allmapidx,%allchecked,%currchecked); + %allchecked = ( + 'hiddenresource' => {}, + 'encrypturl' => {}, + 'randompick' => {}, + 'randomorder' => {}, + ); + foreach my $which (keys(%allchecked)) { + $env{'form.all'.$which} =~ s/,$//; + if ($which eq 'randompick') { + foreach my $item (split(/,/,$env{'form.all'.$which})) { + my ($res,$value) = split(/:/,$item); + if ($value =~ /^\d+$/) { + $allchecked{$which}{$res} = $value; + } + } + } else { + map { $allchecked{$which}{$_} = 1; } split(/,/,$env{'form.all'.$which}); + } + } + my $haschanges = 0; + foreach my $res (@LONCAPA::map::order) { + my ($name,$url)=split(/\:/,$LONCAPA::map::resources[$res]); + $name=&LONCAPA::map::qtescape($name); + $url=&LONCAPA::map::qtescape($url); + next unless ($name && $url); + my $is_map; + if ($url =~ m{/uploaded/.+\.(page|sequence)$}) { + $is_map = 1; + } + foreach my $which (keys(%allchecked)) { + if (($which eq 'randompick' || $which eq 'randomorder')) { + next if (!$is_map); + } + my $oldvalue = 0; + my $newvalue = 0; + if ($allchecked{$which}{$res}) { + $newvalue = $allchecked{$which}{$res}; + } + my $current = (&LONCAPA::map::getparameter($res,'parameter_'.$which))[0]; + if ($which eq 'randompick') { + if ($current =~ /^(\d+)$/) { + $oldvalue = $1; + } + } else { + if ($current =~ /^yes$/i) { + $oldvalue = 1; + } + } + if ($oldvalue ne $newvalue) { + $haschanges = 1; + if ($newvalue) { + my $storeval = 'yes'; + if ($which eq 'randompick') { + $storeval = $newvalue; + } + &LONCAPA::map::storeparameter($res,'parameter_'.$which, + $storeval, + $parameter_type{$which}); + &remember_parms($res,$which,'set',$storeval); + } elsif ($oldvalue) { + &LONCAPA::map::delparameter($res,'parameter_'.$which); + &remember_parms($res,$which,'del'); + } + } + } + } + return $haschanges; } else { - &LONCAPA::map::delparameter($idx,'parameter_'.$which); + return 0 if ($env{'form.changeparms'} !~ /^($valid_parameters_re)$/); + + my $which = $env{'form.changeparms'}; + my $idx = $env{'form.setparms'}; + if ($env{'form.'.$which.'_'.$idx}) { + my $value = ($which eq 'randompick') ? $env{'form.rpicknum_'.$idx} + : 'yes'; + &LONCAPA::map::storeparameter($idx, 'parameter_'.$which, $value, + $parameter_type{$which}); + &remember_parms($idx,$which,'set',$value); + } else { + &LONCAPA::map::delparameter($idx,'parameter_'.$which); - &remember_parms($idx,$which,'del'); + &remember_parms($idx,$which,'del'); + } + return 1; } - return 1; } @@ -1820,9 +2082,22 @@ sub editor { if ($env{'form.pastemarked'}) { my %paste_errors; - my ($paste_res,$save_error) = + my ($paste_res,$save_error,$pastemsgarray,$lockerror) = &do_paste_from_buffer($coursenum,$coursedom,$folder,$container, \%paste_errors); + if (ref($pastemsgarray) eq 'ARRAY') { + if (@{$pastemsgarray} > 0) { + + $r->print('

'. + join('
',@{$pastemsgarray}). + '

'); + } + } + if ($lockerror) { + $r->print('

'. + $lockerror. + '

'); + } if ($save_error ne '') { return $save_error; } @@ -1856,10 +2131,10 @@ sub editor { foreach my $item (split(/\&/,$env{'form.importdetail'})) { if (defined($item)) { my ($name,$url,$residx)= - map {&unescape($_)} split(/\=/,$item); - if ($url=~ m{^\Q/uploaded/$coursedom/$coursenum/\E(default|supplemental)_new\.(sequence|page)$}) { + map { &unescape($_); } split(/\=/,$item); + if ($url =~ m{^\Q/uploaded/$coursedom/$coursenum/\E(default|supplemental)_new\.(sequence|page)$}) { my ($suffix,$errortxt,$locknotfreed) = - &newmap_suffix($1,$2,$coursedom,$coursenum); + &new_timebased_suffix($coursedom,$coursenum,'map',$1,$2); if ($locknotfreed) { $r->print($locknotfreed); } @@ -1868,6 +2143,34 @@ sub editor { } else { return $errortxt; } + } elsif ($url =~ m{^/adm/$match_domain/$match_username/new/(smppg|bulletinboard)$}) { + my $type = $1; + my ($suffix,$errortxt,$locknotfreed) = + &new_timebased_suffix($coursedom,$coursenum,$type); + if ($locknotfreed) { + $r->print($locknotfreed); + } + if ($suffix) { + $url =~ s{^(/adm/$match_domain/$match_username)/new}{$1/$suffix}; + } else { + return $errortxt; + } + } elsif ($url =~ m{^/uploaded/$coursedom/$coursenum/(docs|supplemental)/(default|\d+)/new.html$}) { + if ($supplementalflag) { + next unless ($1 eq 'supplemental'); + if ($folder eq 'supplemental') { + next unless ($2 eq 'default'); + } else { + next unless ($folder eq 'supplemental_'.$2); + } + } else { + next unless ($1 eq 'docs'); + if ($folder eq 'default') { + next unless ($2 eq 'default'); + } else { + next unless ($folder eq 'default_'.$2); + } + } } push(@imports, [$name, $url, $residx]); } @@ -1934,7 +2237,7 @@ sub editor { $r->print(''); } - my ($to_show,$output); + my ($to_show,$output,@allidx,@allmapidx); &Apache::loncommon::start_data_table_count(); #setup a row counter foreach my $res (@LONCAPA::map::order) { @@ -1943,6 +2246,10 @@ sub editor { $url=&LONCAPA::map::qtescape($url); unless ($name) { $name=(split(/\//,$url))[-1]; } unless ($name) { $idx++; next; } + push(@allidx,$res); + if ($url =~ m{/uploaded/.+\.(page|sequence)$}) { + push(@allmapidx,$res); + } $output .= &entryline($idx,$name,$url,$folder,$allowed,$res, $coursenum,$coursedom,$crstype, $pathitem,$supplementalflag,$container); @@ -1973,8 +2280,48 @@ sub editor { if ($folder !~ /^supplemental/) { $to_show .= ''; } - $to_show .= &Apache::loncommon::end_data_table_header_row() - .$output.' ' + $to_show .= &Apache::loncommon::end_data_table_header_row(); + if ($folder !~ /^supplemental/) { + my $idxlist = join(',',@allidx); + my $mapidxlist = join(',',@allmapidx); + if (@allidx > 0) { + my $path; + if ($env{'form.folderpath'}) { + $path = + &HTML::Entities::encode($env{'form.folderpath'},'<>&"'); + } + $to_show .= + &Apache::loncommon::continue_data_table_row(). + ''. + ''. + &Apache::loncommon::end_data_table_row(); + } + } + $to_show .= $output.' ' .&Apache::loncommon::end_data_table() .'
' .&Apache::loncommon::end_scrollbox(); @@ -2041,15 +2388,11 @@ sub process_file_upload { $container='page'; } ($errtext,$fatal)= - &mapread($coursenum,$coursedom,$folder.'.'.$container); + &mapread($coursenum,$coursedom,$folder.'.'.$container); if ($#LONCAPA::map::order<1) { $LONCAPA::map::order[0]=1; $LONCAPA::map::resources[1]=''; } - if ($fatal) { - $$upload_output = '
'.&mt('The uploaded file has not been stored as an error occurred reading the contents of the current folder.').'
'; - return; - } my $destination = 'docs/'; if ($folder =~ /^supplemental/) { $destination = 'supplemental/'; @@ -2059,6 +2402,10 @@ sub process_file_upload { } elsif ($folder =~ /^(default|supplemental)_(\d+)$/) { $destination .= $2.'/'; } + if ($fatal) { + $$upload_output = '
'.&mt('The uploaded file has not been stored as an error occurred reading the contents of the current folder.').'
'; + return; + } # this is for a course, not a user, so set context to coursedoc. my $newidx=&LONCAPA::map::getresidx(); $destination .= $newidx; @@ -2199,12 +2546,7 @@ sub entryline { my $line=&Apache::loncommon::start_data_table_row(); my ($form_start,$form_end,$form_common); # Edit commands - my ($type, $esc_path, $path, $symb); - if ($container eq 'page') { - $type = 'page'; - } else { - $type = 'folder'; - } + my ($esc_path, $path, $symb); if ($env{'form.folderpath'}) { $esc_path=&escape($env{'form.folderpath'}); $path = &HTML::Entities::encode($env{'form.folderpath'},'<>&"'); @@ -2372,8 +2714,8 @@ ENDREN '; $form_common=(< - + + END @@ -2381,12 +2723,12 @@ END $line.=(<
- + $lt{'up'}
- + $lt{'dw'}
@@ -2490,21 +2832,24 @@ END if ($rpicknum) { $rpckchk = ' checked="checked"'; } - my $formname = 'edit_rpick_'.$orderidx; + my $formname = 'edit_randompick_'.$orderidx; $rand_pick_text = ''."\n". $form_common."\n". -''; +''; if ($rpicknum ne '') { $rand_pick_text .= ': '.$rpicknum.''; } - $rand_pick_text .= ''; + $rand_pick_text .= ''. + $form_end; my $ro_set= ((&LONCAPA::map::getparameter($orderidx,'parameter_randomorder'))[0]=~/^yes$/i?' checked="checked"':''); + my $formname = 'edit_rorder_'.$orderidx; $rand_order_text = -$form_start. -$form_common.' -'; +'
'."\n". +$form_common."\n". +''. +$form_end; } } elsif ($supplementalflag && !$allowed) { $url .= ($url =~ /\?/) ? '&':'?'; @@ -2578,16 +2923,18 @@ $form_common.' ((&LONCAPA::map::getparameter($orderidx,'parameter_encrypturl'))[0]=~/^yes$/i?' checked="checked"':''); my $hidtext= ((&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i?' checked="checked"':''); + my $formhidden = 'edit_hiddenresource_'.$orderidx; + my $formurlhidden = 'edit_encrypturl_'.$orderidx; $line.=(< - $form_start + $form_common - + $form_end
- $form_start + $form_common - + $form_end
'.&mt('Settings').' '. + ''. + ''.&mt('Select:').' '. + ''.(' 'x2).''. + ''. + + '
$rand_pick_text
@@ -2598,26 +2945,52 @@ ENDPARMS return $line; } -sub newmap_suffix { - my ($area,$container,$coursedom,$coursenum) = @_; - my ($prefix,$idtype,$errtext,$locknotfreed); - $prefix = 'docs'; - if ($area eq 'supplemental') { - $prefix = 'supp'; +sub new_timebased_suffix { + my ($coursedom,$coursenum,$type,$area,$container) = @_; + my ($prefix,$namespace,$idtype,$errtext,$locknotfreed); + if ($type eq 'map') { + $prefix = 'docs'; + if ($area eq 'supplemental') { + $prefix = 'supp'; + } + $prefix .= $container; + $namespace = 'uploadedmaps'; + } else { + $prefix = $type; + $namespace = 'templated'; } - $prefix .= $container; $idtype = 'concat'; my ($suffix,$freedlock,$error) = - &Apache::lonnet::get_timebased_id($prefix,'num','uploadedmaps', + &Apache::lonnet::get_timebased_id($prefix,'num',$namespace, $coursedom,$coursenum); if (!$suffix) { - $errtext = &mt('Failed to acquire a unique timestamp-based suffix for the new folder/page.'); + if ($type eq 'map') { + $errtext = &mt('Failed to acquire a unique timestamp-based suffix for the new folder/page.'); + } elsif ($type eq 'smppg') { + $errtext = &mt('Failed to acquire a unique timestamp-based suffix for the new simple page.'); + } else { + $errtext = &mt('Failed to acquire a unique timestamp-based suffix for the new bulletin board.'); + } if ($error) { $errtext .= '
'.$error; } } if ($freedlock ne 'ok') { - $locknotfreed = '
'.&mt('There was a problem removing a lockfile. This will prevent creation of additional folders or composite pages in this course. Please contact the domain coordinator for your LON-CAPA domain.').'
'; + $locknotfreed = + '
'. + &mt('There was a problem removing a lockfile.').' '; + if ($type eq 'map') { + &mt('This will prevent creation of additional folders or composite pages in this course.'); + } elsif ($type eq 'smppg') { + $locknotfreed .= + &mt('This will prevent creation of additional simple pages in this course.'); + } else { + $locknotfreed .= + &mt('This will prevent creation of additional bulletin boards in this course.'); + } + $locknotfreed .= + ' '.&mt('Please contact the domain coordinator for your LON-CAPA domain.'). + '
'; } return ($suffix,$errtext,$locknotfreed); } @@ -3222,7 +3595,8 @@ sub handler { 'Docs_About_My_Personal_Info,Docs_Editing_Templated_Pages'); $help{'Group Portfolio'} = &Apache::loncommon::help_open_topic('Docs_About_Group_Files'); $help{'Caching'} = &Apache::loncommon::help_open_topic('Caching'); - + $help{'Course Roster'} = &Apache::loncommon::help_open_topic('Docs_Course_Roster'); + $help{'Web Page'} = &Apache::loncommon::help_open_topic('Docs_Web_Page'); my $allowed; # URI is /adm/supplemental when viewing supplemental docs in non-edit mode. @@ -3557,6 +3931,7 @@ sub handler { 'navc' => 'Table of Contents', 'sipa' => 'Simple Course Page', 'sipr' => 'Simple Problem', + 'webp' => 'Blank Web Page (editable)', 'drbx' => 'Drop Box', 'scuf' => 'External Scores (handgrade, upload, clicker)', 'bull' => 'Discussion Board', @@ -3809,7 +4184,6 @@ NAMFORM NASOFORM - my $newrosterform=(< @@ -3821,6 +4195,27 @@ NASOFORM NROSTFORM + my $newwebpage; + if ($folder =~ /^default_?(\d*)$/) { + $newwebpage = "/uploaded/$coursedom/$coursenum/docs/"; + if ($1) { + $newwebpage .= $1; + } else { + $newwebpage .= 'default'; + } + $newwebpage .= '/new.html'; + } + my $newwebpageform =(< + + $pathitem + + $lt{'webp'} + $help{'Web Page'} + +NWEBFORM + + my $specialdocumentsform; my @specialdocumentsforma; my $gradingform; @@ -3879,6 +4274,7 @@ NGFFORM {''.$lt{syll}.''=>$newsylform}, {''.$lt{navc}.''=>$newnavform}, {''.$lt{sipa}.''=>$newsmppageform}, + {''.$lt{webp}.''=>$newwebpageform}, ); $specialdocumentsform = &create_form_ul(&create_list_elements(@specialdocumentsforma)); @@ -4016,12 +4412,34 @@ SNSFORM SNAMFORM + my $supwebpage; + if ($folder =~ /^supplemental_?(\d*)$/) { + $supwebpage = "/uploaded/$coursedom/$coursenum/supplemental/"; + if ($1) { + $supwebpage .= $1; + } else { + $supwebpage .= 'default'; + } + $supwebpage .= '/new.html'; + } + my $supwebpageform =(< + + $pathitem + + $lt{'webp'} + $help{'Web Page'} + +SWEBFORM + my @specialdocs = ( {''.$lt{syll}.'' =>$supnewsylform}, {''.$lt{mypi}.'' =>$supnewaboutmeform}, + {''.$lt{webp}.''=>$supwebpageform}, + ); my @supimportdoc = ( {''.$lt{extr}.'' @@ -4376,7 +4794,6 @@ sub generate_edit_table { sub editing_js { my ($udom,$uname,$supplementalflag) = @_; - my $now = time(); my %lt = &Apache::lonlocal::texthash( p_mnf => 'Name of New Folder', t_mnf => 'New Folder', @@ -4387,6 +4804,7 @@ sub editing_js { p_msb => 'Title for the Problem', p_mdb => 'Title for the Drop Box', p_mbb => 'Title for the Discussion Board', + p_mwp => 'Title for Web Page', p_mab => "Enter user:domain for User's Personal Information Page", p_mab2 => 'Personal Information Page of ', p_mab_alrt1 => 'Not a valid user:domain', @@ -4474,11 +4892,26 @@ function makesmppage() { var title=prompt('$lt{"p_msp"}'); if (title) { this.document.forms.newsmppg.importdetail.value= - escape(title)+'=/adm/$udom/$uname/$now/smppg'; + escape(title)+'=/adm/$udom/$uname/new/smppg'; this.document.forms.newsmppg.submit(); } } +function makewebpage(type) { + var title=prompt('$lt{"p_mwp"}'); + var formname; + if (type == 'supp') { + formname = this.document.forms.supwebpage; + } else { + formname = this.document.forms.newwebpage; + } + if (title) { + var webpage = formname.importdetail.value; + formname.importdetail.value = escape(title)+'='+webpage; + formname.submit(); + } +} + function makesmpproblem() { var title=prompt('$lt{"p_msb"}'); if (title) { @@ -4501,7 +4934,7 @@ function makebulboard() { var title=prompt('$lt{"p_mbb"}'); if (title) { this.document.forms.newbul.importdetail.value= - escape(title)+'=/adm/$udom/$uname/$now/bulletinboard'; + escape(title)+'=/adm/$udom/$uname/new/bulletinboard'; this.document.forms.newbul.submit(); } } @@ -4607,34 +5040,154 @@ this.document.forms.renameform.submit(); } function updatePick(targetform,index,caller) { - var pickitem = document.getElementById('rpick_'+index); - var picknumitem = document.getElementById('rpicknum_'+index); + var pickitem; + var picknumitem; + var picknumtext; + if (index == 'all') { + pickitem = document.getElementById('randompickall'); + picknumitem = document.getElementById('rpicknumall'); + picknumtext = document.getElementById('rpicktextall'); + } else { + pickitem = document.getElementById('randompick_'+index); + picknumitem = document.getElementById('rpicknum_'+index); + picknumtext = document.getElementById('randompicknum_'+index); + } if (pickitem.checked) { var picknum=prompt('$lt{"rpck"}',picknumitem.value); if (picknum == '' || picknum == null) { if (caller == 'check') { pickitem.checked=false; - return; + if (index == 'all') { + picknumtext.innerHTML = ''; + if (caller == 'link') { + propagateState(targetform,'rpicknum'); + } + } else { + checkForSubmit(targetform,'randompick'); + } } } else { picknum.toString(); var regexdigit=/^\\d+\$/; if (regexdigit.test(picknum)) { picknumitem.value = picknum; - targetform.changeparms.value='randompick'; - targetform.submit(); + if (index == 'all') { + picknumtext.innerHTML = ' '+picknum+''; + if (caller == 'link') { + propagateState(targetform,'rpicknum'); + } + } else { + picknumtext.innerHTML = ' '+picknum+''; + checkForSubmit(targetform,'randompick'); + } } else { if (caller == 'check') { - pickitem.checked=false; + if (index == 'all') { + picknumtext.innerHTML = ''; + if (caller == 'link') { + propagateState(targetform,'rpicknum'); + } + } else { + pickitem.checked=false; + checkForSubmit(targetform,'randompick'); + } } return; } } } else { - picknumitem.value = 0; - targetform.changeparms.value='randompick'; - targetform.submit(); + picknumitem.value = ''; + picknumtext.innerHTML = ''; + if (index == 'all') { + if (caller == 'link') { + propagateState(targetform,'rpicknum'); + } + } else { + checkForSubmit(targetform,'randompick'); + } + } +} + +function propagateState(form,param) { + if (document.getElementById(param+'all')) { + var setcheck = 0; + var rpick = 0; + if (param == 'rpicknum') { + if (document.getElementById('randompickall')) { + if (document.getElementById('randompickall').checked) { + if (document.getElementById('rpicknumall')) { + rpick = document.getElementById('rpicknumall').value; + } + } + } + } else { + if (document.getElementById(param+'all').checked) { + setcheck = 1; + } + } + if ((param == 'encrypturl') || (param == 'hiddenresource')) { + var allidxlist = form.allidx.value; + if (allidxlist != '') { + var allidxs = allidxlist.split(','); + if (allidxs.length > 1) { + for (var i=0; i 1) { + for (var i=0; i 0) { + document.getElementById('randompicknum_'+allmapidxs[i]).innerHTML = ': '+rpick+''; + } else { + document.getElementById('randompicknum_'+allmapidxs[i]).innerHTML = ''; + } + } + } + } else { + if (setcheck == 1) { + document.getElementById(param+'_'+allmapidxs[i]).checked = true; + } else { + document.getElementById(param+'_'+allmapidxs[i]).checked = false; + } + } + } + } + } + } + } + } + return; +} + +function checkForSubmit(targetform,param) { + if (document.togglemultchecks.showmultpick.length) { + for (var i=0; i 1) { + for (var i=0; i