--- loncom/interface/londocs.pm 2011/10/31 01:22:25 1.462 +++ loncom/interface/londocs.pm 2016/11/30 18:05:43 1.484.2.68 @@ -1,7 +1,7 @@ # The LearningOnline Network # Documents # -# $Id: londocs.pm,v 1.462 2011/10/31 01:22:25 raeburn Exp $ +# $Id: londocs.pm,v 1.484.2.68 2016/11/30 18:05:43 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -26,8 +26,6 @@ # http://www.lon-capa.org/ # - - package Apache::londocs; use strict; @@ -41,8 +39,14 @@ use Apache::lonratedt(); use Apache::lonxml; use Apache::lonclonecourse; use Apache::lonnavmaps; +use Apache::lonnavdisplay(); +use Apache::lonextresedit(); +use Apache::lontemplate(); +use Apache::lonsimplepage(); use HTML::Entities; +use HTML::TokeParser; use GDBM_File; +use File::MMagic; use Apache::lonlocal; use Cwd; use LONCAPA qw(:DEFAULT :match); @@ -55,6 +59,7 @@ my $hashtied; my %alreadyseen=(); my $hadchanges; +my $suppchanges; my %help=(); @@ -68,13 +73,21 @@ sub mapread { } sub storemap { - my ($coursenum,$coursedom,$map)=@_; + my ($coursenum,$coursedom,$map,$contentchg)=@_; + my $report; + if (($contentchg) && ($map =~ /^default/)) { + $report = 1; + } my ($outtext,$errtext)= &LONCAPA::map::storemap('/uploaded/'.$coursedom.'/'.$coursenum.'/'. - $map,1); + $map,1,$report); if ($errtext) { return ($errtext,2); } - $hadchanges=1; + if ($map =~ /^default/) { + $hadchanges=1; + } else { + $suppchanges=1; + } return ($errtext,0); } @@ -101,12 +114,17 @@ sub authorhosts { my $allowed=0; my $myhome=&Apache::lonnet::homeserver($ca,$cd); my @ids=&Apache::lonnet::current_machine_ids(); - foreach my $id (@ids) { if ($id eq $myhome) { $allowed=1; } } + foreach my $id (@ids) { + if ($id eq $myhome) { + $allowed=1; + last; + } + } if ($allowed) { $home++; - $outhash{'home_'.$ca.'@'.$cd}=1; + $outhash{'home_'.$ca.':'.$cd}=1; } else { - $outhash{'otherhome_'.$ca.'@'.$cd}=$myhome; + $outhash{'otherhome_'.$ca.':'.$cd}=$myhome; $other++; } } @@ -115,961 +133,499 @@ sub authorhosts { } -sub dumpbutton { - my ($home,$other,%outhash)=&authorhosts(); - my $crstype = &Apache::loncommon::course_type(); - if ($home+$other==0) { return ''; } - if ($home) { - my $link = - "" - .&mt('Dump '.$crstype.' Documents to Construction Space') - .''; - return - $link.' ' - .&Apache::loncommon::help_open_topic('Docs_Dump_Course_Docs') - .'
'; - } else { - return - &mt('Dump '.$crstype.' Documents to Construction Space: available on other servers'); - } -} - sub clean { my ($title)=@_; $title=~s/[^\w\/\!\$\%\^\*\-\_\=\+\;\:\,\\\|\`\~]+/\_/gs; return $title; } - - -sub dumpcourse { - my ($r) = @_; - my $crstype = &Apache::loncommon::course_type(); - $r->print(&Apache::loncommon::start_page('Dump '.$crstype.' Documents to Construction Space'). - '
'); - $r->print(&Apache::lonhtmlcommon::breadcrumbs('Dump '.$crstype.' Documents to Construction Space')); - my ($home,$other,%outhash)=&authorhosts(); - unless ($home) { return ''; } - my $origcrsid=$env{'request.course.id'}; - my %origcrsdata=&Apache::lonnet::coursedescription($origcrsid); - if (($env{'form.authorspace'}) && ($env{'form.authorfolder'}=~/\w/)) { -# Do the dumping - unless ($outhash{'home_'.$env{'form.authorspace'}}) { return ''; } - my ($ca,$cd)=split(/\@/,$env{'form.authorspace'}); - $r->print('

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

'); - my $title=$env{'form.authorfolder'}; - $title=&clean($title); - my %replacehash=(); - foreach my $key (keys(%env)) { - if ($key=~/^form\.namefor\_(.+)/) { - $replacehash{$1}=$env{$key}; - } - } - my $crs='/uploaded/'.$env{'request.course.id'}.'/'; - $crs=~s/\_/\//g; - foreach my $item (keys(%replacehash)) { - my $newfilename=$title.'/'.$replacehash{$item}; - $newfilename=~s/\.(\w+)$//; - my $ext=$1; - $newfilename=&clean($newfilename); - $newfilename.='.'.$ext; - my @dirs=split(/\//,$newfilename); - my $path=$r->dir_config('lonDocRoot')."/priv/$cd/$ca"; - my $makepath=$path; - my $fail=0; - for (my $i=0;$i<$#dirs;$i++) { - $makepath.='/'.$dirs[$i]; - unless (-e $makepath) { - unless(mkdir($makepath,0777)) { $fail=1; } - } - } - $r->print('
'.$item.' => '.$newfilename.': '); - if (my $fh=Apache::File->new('>'.$path.'/'.$newfilename)) { - if ($item=~/\.(sequence|page|html|htm|xml|xhtml)$/) { - print $fh &Apache::lonclonecourse::rewritefile( - &Apache::lonclonecourse::readfile($env{'request.course.id'},$item), - (%replacehash,$crs => '') - ); - } else { - print $fh - &Apache::lonclonecourse::readfile($env{'request.course.id'},$item); - } - $fh->close(); - } else { - $fail=1; - } - if ($fail) { - $r->print(''.&mt('fail').''); - } else { - $r->print(''.&mt('ok').''); - } - } - } else { -# Input form - unless ($home==1) { - $r->print( - '

'.&mt('Select the Construction Space').'

'); - } else { - $r->print(''); - } - } - } - unless ($home==1) { - $r->print(''); - } - my $title=$origcrsdata{'description'}; - $title=~s/[\/\s]+/\_/gs; - $title=&clean($title); - $r->print('

'.&mt('Folder in Construction Space').'

' - .'
'); - &tiehash(); - $r->print('

'.&mt('Filenames in Construction Space').'

' - .&Apache::loncommon::start_data_table() - .&Apache::loncommon::start_data_table_header_row() - .''.&mt('Internal Filename').'' - .''.&mt('Title').'' - .''.&mt('Save as ...').'' - .&Apache::loncommon::end_data_table_header_row()); - foreach my $file (&Apache::lonclonecourse::crsdirlist($origcrsid,'userfiles')) { - $r->print(&Apache::loncommon::start_data_table_row() - .''.$file.''); - my ($ext)=($file=~/\.(\w+)$/); - my $title=$hash{'title_'.$hash{ - 'ids_/uploaded/'.$origcrsdata{'domain'}.'/'.$origcrsdata{'num'}.'/'.$file}}; - $r->print(''.($title?$title:' ').''); - if (!$title) { - $title=$file; - } else { - $title=~s|/|_|g; - } - $title=~s/\.(\w+)$//; - $title=&clean($title); - $title.='.'.$ext; - $r->print("\n" - .&Apache::loncommon::end_data_table_row()); - } - $r->print(&Apache::loncommon::end_data_table()); - &untiehash(); - $r->print( - '

'); - } -} - - - -sub exportbutton { - my $crstype = &Apache::loncommon::course_type(); - return "".&mt('IMS Export')."". - &Apache::loncommon::help_open_topic('Docs_Export_Course_Docs').'
'; -} - - - -sub exportcourse { - my $r=shift; - my $crstype = &Apache::loncommon::course_type(); - my %discussiontime = &Apache::lonnet::dump('discussiontimes', - $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'}); - my $numdisc = keys(%discussiontime); - my $numprobs = 0; - my $navmap = Apache::lonnavmaps::navmap->new(); - if (!defined($navmap)) { - $r->print(&Apache::loncommon::start_page('Export '.$crstype.' to IMS Package'). - '

'.&mt('IMS Export Failed').'

'. - '
'); - if ($crstype eq 'Community') { - $r->print(&mt('Unable to retrieve information about community contents')); - } else { - $r->print(&mt('Unable to retrieve information about course contents')); - } - $r->print('
'); - if ($crstype eq 'Community') { - $r->print(&mt('Return to Community Editor')); - } else { - $r->print(&mt('Return to Course Editor')); - } - $r->print(''); - &Apache::lonnet::logthis('IMS export failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'}); - return; - } - my $it=$navmap->getIterator(undef,undef,undef,1,undef,undef); - my $curRes; - my $outcome; - - &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, - ['finishexport']); - if ($env{'form.finishexport'}) { - &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, - ['archive','discussion']); - - my $format = $env{'form.format'}; - my @exportitems = &Apache::loncommon::get_env_multiple('form.archive'); - my @discussions = &Apache::loncommon::get_env_multiple('form.discussion'); - if (@exportitems == 0 && @discussions == 0) { - $outcome = - '

' - .&mt('As you did not select any content items or discussions' - .' for export, an IMS package has not been created.') - .'

' - .'

' - .&mt('Please [_1]go back[_2] to select either content items' - .' or discussions for export.' - ,'' - ,'') - .'

'; - } else { - my $now = time; - my %symbs; - my $manifestok = 0; - my $imsresources; - my $tempexport; - my $copyresult; - my $testbank; - my $ims_manifest = &create_ims_store($now,\$manifestok,\$outcome,\$tempexport,$format,\$testbank); - if ($manifestok) { - &build_package($now,$navmap,\@exportitems,\@discussions,\$outcome,$tempexport,\$copyresult,$ims_manifest,$format,$testbank); - close($ims_manifest); - -#Create zip file in prtspool - my $imszipfile = '/prtspool/'. - $env{'user.name'}.'_'.$env{'user.domain'}.'_'. - time.'_'.rand(1000000000).'.zip'; - my $cwd = &Cwd::getcwd(); - my $imszip = '/home/httpd/'.$imszipfile; - chdir $tempexport; - open(OUTPUT, "zip -r $imszip * 2> /dev/null |"); - close(OUTPUT); - chdir $cwd; - $outcome .= '

' - .&mt('[_1]Your IMS package[_2] is ready for download.' - ,'','') - .'

'; - if ($copyresult) { - $outcome .= '

' - .&mt('The following errors occurred during export - [_1]' - ,$copyresult) - .'

'; - } - } else { - $outcome = '

' - .&mt('Unfortunately you will not be able to retrieve' - .' an IMS archive of your course at this time,' - .' because there was a problem creating a' - .' manifest file.') - .'

' - .'

' - .&mt('Go Back') - .'

'; - } - } - $r->print(&Apache::loncommon::start_page('Export '.$crstype.' to IMS Package')); - $r->print(&Apache::lonhtmlcommon::breadcrumbs('IMS Export')); - $r->print($outcome); - $r->print(&Apache::loncommon::end_page()); - } else { - my $display='
'."\n". - '

'. - &mt('Choose which items you wish to export from your '.$crstype.'.'). - '

'. - '
'. - ''.&mt('Content items').''. - ''. - '  
'; - if ($numdisc > 0) { - $display .= '
'. - ''.&mt('Discussion posts').''. - ''. - '  '. - '
'; - } - $display .= '
'; - my $curRes; - my $depth = 0; - my $count = 0; - my $boards = 0; - my $startcount = 5; - my %parent = (); - my %children = (); - my $lastcontainer = $startcount; - $display .= &Apache::loncommon::start_data_table() - .&Apache::loncommon::start_data_table_header_row() - .''.&mt('Export content item?').''; - if ($numdisc > 0) { - $display .= ''.&mt('Export discussion posts?').''; - } - $display .= &Apache::loncommon::end_data_table_header_row(); - while ($curRes = $it->next()) { - if (ref($curRes)) { - $count ++; - } - if ($curRes == $it->BEGIN_MAP()) { - $depth++; - $parent{$depth} = $lastcontainer; - } - if ($curRes == $it->END_MAP()) { - $depth--; - $lastcontainer = $parent{$depth}; - } - if (ref($curRes)) { - my $symb = $curRes->symb(); - my $ressymb = $symb; - if ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) { - unless ($ressymb =~ m|adm/wrapper/adm|) { - $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard'; - } - } - my $currelem = $count+$boards+$startcount; - $display .= &Apache::loncommon::start_data_table_row() - .''."\n" - .'is_sequence()) || ($curRes->is_page())) { - $lastcontainer = $currelem; - $display .= 'onclick="javascript:propagateCheck('."'$currelem'".')"'; - } elsif ($curRes->is_problem()) { - $numprobs ++; - } - $display .= ' />'."\n"; - for (my $i=0; $i<$depth; $i++) { - $display .= ('' x2)."\n"; - } - if ($curRes->is_sequence()) { - $display .= ' '."\n"; - } elsif ($curRes->is_page()) { - $display .= ' '."\n"; - } - $children{$parent{$depth}} .= $currelem.':'; - $display .= ' '.$curRes->title().''."\n"; - - # Existing discussion posts? - if ($discussiontime{$ressymb} > 0) { - $boards ++; - $display .= '' - .'' - .''."\n"; - } elsif ($numdisc > 0) { - $display .= ' '."\n"; +sub default_folderpath { + my ($coursenum,$coursedom,$navmapref) = @_; + return unless ($coursenum && $coursedom && ref($navmapref)); +# Check if entire course is hidden and/or encrypted + my ($hiddenmap,$encryptmap,$folderpath,$hiddentop); + my $toplevel = "uploaded/$coursedom/$coursenum/default.sequence"; + unless (ref($$navmapref)) { + $$navmapref = Apache::lonnavmaps::navmap->new(); + } + if (ref($$navmapref)) { + if (lc($$navmapref->get_mapparam(undef,$toplevel,"0.hiddenresource")) eq 'yes') { + my $filterFunc = sub { my $res = shift; return (!$res->randomout() && !$res->is_map()) }; + my @resources = $$navmapref->retrieveResources($toplevel,$filterFunc,1,1); + unless (@resources) { + $hiddenmap = 1; + unless ($env{'request.role.adv'}) { + $hiddentop = 1; + if ($env{'form.folder'}) { + undef($env{'form.folder'}); + } } - $display .= &Apache::loncommon::end_data_table_row(); } } - $display .= &Apache::loncommon::end_data_table(); - my $scripttag = qq| - - |; - $r->print(&Apache::loncommon::start_page('Export '.$crstype.' to IMS Package', - $scripttag)); - $r->print(&Apache::lonhtmlcommon::breadcrumbs('IMS Export')); - if ($numprobs > 0) { - $display .= '

'. - &mt('Export format for LON-CAPA problems:'). - ''.(' ' x3). - ''.(' ' x3). - '

'; - } - $r->print($display. - '

'. - '

'); - } -} - -sub create_ims_store { - my ($now,$manifestok,$outcome,$tempexport,$format,$testbank) = @_; - $$tempexport = $Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/ims_exports'; - my $ims_manifest; - if (!-e $$tempexport) { - mkdir($$tempexport,0700); - } - $$tempexport .= '/'.$now; - if (!-e $$tempexport) { - mkdir($$tempexport,0700); - } - $$tempexport .= '/'.$env{'user.domain'}.'_'.$env{'user.name'}; - if (!-e $$tempexport) { - mkdir($$tempexport,0700); - } - if (!-e "$$tempexport/resources") { - mkdir("$$tempexport/resources",0700); - } -# open manifest file - my $manifest = '/imsmanifest.xml'; - my $manifestfilename = $$tempexport.$manifest; - if ($ims_manifest = Apache::File->new('>'.$manifestfilename)) { - $$manifestok=1; - print $ims_manifest -''."\n". -''."\n". -' - - - - '.$env{'request.course.id'}.' - - '.$env{'course.'.$env{'request.course.id'}.'.description'}.' - - - - '."\n". -' '."\n". -' '."\n". -' '.$env{'course.'.$env{'request.course.id'}.'.description'}.''; - if ($format eq 'plaintext') { - my $testbankfilename = $$tempexport.'/testbank.txt'; - $$testbank = Apache::File->new('>'.$testbankfilename); - } - } else { - $$outcome .= 'An error occurred opening the IMS manifest file.
' -; +ENDJS + $starthash = { + add_entries => {'onload' => "hide_searching();"}, + }; + } + $r->print(&Apache::loncommon::start_page('Copy '.$crstype.' Content to Authoring Space',$js,$starthash)."\n". + &Apache::lonhtmlcommon::breadcrumbs('Copy '.$crstype.' Content to Authoring Space')."\n"); + $r->print(&startContentScreen('tools')); + my ($home,$other,%outhash)=&authorhosts(); + unless ($home) { + $r->print(&endContentScreen()); + return ''; } - return $ims_manifest; -} - -sub build_package { - my ($now,$navmap,$exportitems,$discussions,$outcome,$tempexport,$copyresult, - $ims_manifest,$format,$testbank) = @_; -# first iterator to look for dependencies - my $it = $navmap->getIterator(undef,undef,undef,1,undef,undef); - my $curRes; - my $count = 0; - my $depth = 0; - my $lastcontainer = 0; - my %parent = (); - my @dependencies = (); - my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; - my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; - while ($curRes = $it->next()) { - if (ref($curRes)) { - $count ++; - } - if ($curRes == $it->BEGIN_MAP()) { - $depth++; - $parent{$depth} = $lastcontainer; - } - if ($curRes == $it->END_MAP()) { - $depth--; - $lastcontainer = $parent{$depth}; - } - if (ref($curRes)) { - if ($curRes->is_sequence() || $curRes->is_page()) { - $lastcontainer = $count; - } - if (grep(/^$count$/,@$exportitems)) { - &get_dependencies($exportitems,\%parent,$depth,\@dependencies); - } + my $origcrsid=$env{'request.course.id'}; + my %origcrsdata=&Apache::lonnet::coursedescription($origcrsid); + if (($env{'form.authorspace'}) && ($env{'form.authorfolder'}=~/\w/)) { +# Do the dumping + unless ($outhash{'home_'.$env{'form.authorspace'}}) { + $r->print(&endContentScreen()); + return ''; } - } -# second iterator to build manifest and store resources - $it = $navmap->getIterator(undef,undef,undef,1,undef,undef); - $depth = 0; - my $prevdepth; - $count = 0; - my $imsresources; - my $pkgdepth; - my $currdirpath = 'Top'; - while ($curRes = $it->next()) { - if ($curRes == $it->BEGIN_MAP()) { - $prevdepth = $depth; - $depth++; - } - if ($curRes == $it->END_MAP()) { - $prevdepth = $depth; - $depth--; + my ($ca,$cd)=split(/\:/,$env{'form.authorspace'}); + $r->print('

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

'); + my $title=$env{'form.authorfolder'}; + $title=&clean($title); + my ($navmap,$errormsg) = + &Apache::loncourserespicker::get_navmap_object($crstype,'dumpdocs'); + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my (%maps,%resources,%titles); + if (!ref($navmap)) { + $r->print($errormsg. + &endContentScreen()); + return ''; + } else { + &Apache::loncourserespicker::enumerate_course_contents($navmap,\%maps,\%resources,\%titles, + 'dumpdocs',$cdom,$cnum); } - - if (ref($curRes)) { - $count ++; - if ((grep(/^$count$/,@$exportitems)) || (grep(/^$count$/,@dependencies))) { - my $symb = $curRes->symb(); - my $isvisible = 'true'; - my $resourceref; - if ($curRes->randomout()) { - $isvisible = 'false'; - } - unless ($curRes->is_sequence()) { - $resourceref = 'identifierref="RES-'.$env{'request.course.id'}.'-'.$count.'"'; - } - my $step = $prevdepth - $depth; - if (($step >= 0) && ($count > 1)) { - while ($step >= 0) { - print $ims_manifest "\n".' '."\n"; - $step --; - } - } - $prevdepth = $depth; - - my $itementry = - ''. - ''.$curRes->title().''; - print $ims_manifest "\n".$itementry; - - if ($curRes->is_sequence()) { - $currdirpath = 'Top'; - my $pcslist = $curRes->map_hierarchy(); - if ($pcslist ne '') { - foreach my $pc (split(/,/,$pcslist),$curRes->map_pc()) { - next if ($pc <= 1); - my $res = $navmap->getByMapPc($pc); - if (ref($res)) { - my $encloser = $res->title(); - if ($encloser) { - if ($currdirpath) { - $currdirpath .= ' -> '; - } - $currdirpath .= $encloser; - } - } - } + my @todump = &Apache::loncommon::get_env_multiple('form.archive'); + my (%tocopy,%replacehash,%lookup,%deps,%display,%result,%depresult,%simpleproblems,%simplepages, + %newcontent,%has_simpleprobs); + foreach my $item (sort {$a <=> $b} (@todump)) { + my $name = $env{'form.namefor_'.$item}; + if ($resources{$item}) { + my ($map,$id,$res) = &Apache::lonnet::decode_symb($resources{$item}); + if ($res =~ m{^uploaded/$cdom/$cnum/\E((?:docs|supplemental)/.+)$}) { + $tocopy{$1} = $name; + $display{$item} = $1; + $lookup{$1} = $item; + } elsif ($res eq 'lib/templates/simpleproblem.problem') { + $simpleproblems{$item} = { + symb => $resources{$item}, + name => $name, + }; + $display{$item} = 'simpleproblem_'.$name; + if ($map =~ m{^\Quploaded/$cdom/$cnum/\E(.+)$}) { + $has_simpleprobs{$1}{$id} = $item; } - } else { - my $content_file; - my @hrefs = (); - &process_content($count,$curRes,$cdom,$cnum,$symb,\$content_file,\@hrefs,$copyresult,$tempexport,$format,$currdirpath,$testbank); - if ($content_file) { - $imsresources .= "\n". - ' '."\n". - ' '."\n"; - foreach my $item (@hrefs) { - $imsresources .= - ' '."\n"; - } - if (grep(/^$count$/,@$discussions)) { - my $ressymb = $symb; - my $mode; - if ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) { - unless ($ressymb =~ m|adm/wrapper/adm|) { - $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard'; - } - $mode = 'board'; - } - my %extras = ( - caller => 'imsexport', - tempexport => $tempexport.'/resources', - count => $count - ); - my $discresult = &Apache::lonfeedback::list_discussion($mode,undef,$ressymb,\%extras); - } - $imsresources .= ' '."\n"; - } - } - $pkgdepth = $depth; - } - } - } - while ($pkgdepth > 0) { - print $ims_manifest " \n"; - $pkgdepth --; - } - my $resource_text = qq| -
-
- - $imsresources - -
- |; - print $ims_manifest $resource_text; -} - -sub get_dependencies { - my ($exportitems,$parent,$depth,$dependencies) = @_; - if ($depth > 1) { - if ((!grep(/^$$parent{$depth}$/,@$exportitems)) && (!grep(/^$$parent{$depth}$/,@$dependencies))) { - push(@{$dependencies},$$parent{$depth}); - if ($depth > 2) { - &get_dependencies($exportitems,$parent,$depth-1,$dependencies); - } - } - } -} - -sub process_content { - my ($count,$curRes,$cdom,$cnum,$symb,$content_file,$href,$copyresult,$tempexport,$format,$currdirpath,$testbank) = @_; - my $content_type; - my $message; - my @uploads = (); - if ($curRes->is_sequence()) { - $content_type = 'sequence'; - } elsif ($curRes->is_page()) { - $content_type = 'page'; # need to handle individual items in pages. - } elsif ($symb =~ m-public/$cdom/$cnum/syllabus$-) { - $content_type = 'syllabus'; - my $contents = &Apache::imsexport::templatedpage($content_type); - if ($contents) { - $$content_file = &store_template($contents,$tempexport,$count,$content_type); - } - } elsif ($symb =~ m-\.sequence___\d+___ext-) { - $content_type = 'external'; - my $title = $curRes->title; - my $contents = &Apache::imsexport::external($symb,$title); - if ($contents) { - $$content_file = &store_template($contents,$tempexport,$count,$content_type); - } - } elsif ($symb =~ m-adm/navmaps$-) { - $content_type = 'navmap'; - } elsif ($symb =~ m-adm/[^/]+/[^/]+/(\d+)/smppg$-) { - $content_type = 'simplepage'; - my $contents = &Apache::imsexport::templatedpage($content_type,$1,$count,\@uploads); - if ($contents) { - $$content_file = &store_template($contents,$tempexport,$count,$content_type); - } - } elsif ($symb =~ m-lib/templates/simpleproblem\.problem$-) { - $content_type = 'simpleproblem'; - my $contents = &Apache::imsexport::simpleproblem($symb); - if ($contents) { - $$content_file = &store_template($contents,$tempexport,$count,$content_type); - } - } elsif ($symb =~ m-lib/templates/examupload\.problem$-) { - $content_type = 'examupload'; - } elsif ($symb =~ m-adm/($match_domain)/($match_username)/(\d+)/bulletinboard$-) { - $content_type = 'bulletinboard'; - my $contents = &Apache::imsexport::templatedpage($content_type,$3,$count,\@uploads,$1,$2); - if ($contents) { - $$content_file = &store_template($contents,$tempexport,$count,$content_type); - } - } elsif ($symb =~ m-adm/([^/]+)/([^/]+)/aboutme$-) { - $content_type = 'aboutme'; - my $contents = &Apache::imsexport::templatedpage($content_type,undef,$count,\@uploads,$1,$2); - if ($contents) { - $$content_file = &store_template($contents,$tempexport,$count,$content_type); - } - } elsif ($symb =~ m-\.(sequence|page)___\d+___uploaded/$cdom/$cnum/-) { - $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'uploaded'); - } elsif ($symb =~ m-\.(sequence|page)___\d+___([^/]+)/([^/]+)-) { - my $canedit = 0; - if ($2 eq $env{'user.domain'} && $3 eq $env{'user.name'}) { - $canedit= 1; - } -# only include problem code where current user is author - if (($format eq 'html') || ($format eq 'plaintext')) { - my $title = $curRes->title; - $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,$format,$currdirpath,$title,$testbank); - } elsif ($format eq 'xml') { - if ($canedit) { - $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'resource'); + } elsif ($res =~ m{^adm/$match_domain/$match_username/(\d+)/smppg}) { + my $marker = $1; + my $db_name = &Apache::lonsimplepage::get_db_name($res,$marker,$cdom,$cnum); + $simplepages{$item} = { + res => $res, + title => $titles{$item}, + db => $db_name, + marker => $marker, + symb => $resources{$item}, + name => $name, + }; + $display{$item} = '/'.$res; + } + } elsif ($maps{$item}) { + if ($maps{$item} =~ m{^\Quploaded/$cdom/$cnum/\E((?:default|supplemental)_\d+\.(?:sequence|page))$}) { + $tocopy{$1} = $name; + $display{$item} = $1; + $lookup{$1} = $item; + } } else { - $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'noedit'); + next; } } - } elsif ($symb =~ m-uploaded/$cdom/$cnum-) { - $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'uploaded'); - } - if (@uploads > 0) { - foreach my $item (@uploads) { - my $uploadmsg = ''; - &replicate_content($cdom,$cnum,$tempexport,$item,$count,\$uploadmsg,$href,'templateupload'); - if ($uploadmsg) { - $$copyresult .= $uploadmsg."\n"; + my $crs='/uploaded/'.$env{'request.course.id'}.'/'; + $crs=~s/\_/\//g; + my $mm = new File::MMagic; + my $prefix = "/uploaded/$cdom/$cnum/"; + %replacehash = %tocopy; + foreach my $item (sort(keys(%simpleproblems))) { + my $content = &Apache::imsexport::simpleproblem($simpleproblems{$item}{'symb'}); + $newcontent{$display{$item}} = $content; + } + my $gateway = Apache::lonhtmlgateway->new('web'); + foreach my $item (sort(keys(%simplepages))) { + if (ref($simplepages{$item}) eq 'HASH') { + my $pagetitle = $simplepages{$item}{'title'}; + my %fields = &Apache::lonnet::dump($simplepages{$item}{'db'},$cdom,$cnum); + my %contents; + foreach my $field (keys(%fields)) { + if ($field =~ /^(?:aaa|bbb|ccc)_(\w+)$/) { + my $name = $1; + my $msg = $fields{$field}; + if ($name eq 'webreferences') { + if ($msg =~ m{^https?://}) { + $contents{$name} = ''.$msg.''; + } + } else { + $msg = &Encode::decode('utf8',$msg); + $msg = $gateway->process_outgoing_html($msg,1); + $contents{$name} = $msg; + } + } elsif ($field eq 'uploaded.photourl') { + my $marker = $simplepages{$item}{marker}; + if ($fields{$field} =~ m{^\Q$prefix\E(simplepage/$marker/.+)$}) { + my $filepath = $1; + my ($relpath,$fname) = ($filepath =~ m{^(.+/)([^/]+)$}); + if ($fname ne '') { + $fname=~s/\.(\w+)$//; + my $ext=$1; + $fname = &clean($fname); + $fname.='.'.$ext; + $contents{image} = 'Image'; + $replacehash{$filepath} = $relpath.$fname; + $deps{$item}{$filepath} = 1; + } + } + } + } + $replacehash{'/'.$simplepages{$item}{'res'}} = $simplepages{$item}{'name'}; + $lookup{'/'.$simplepages{$item}{'res'}} = $item; + my $content = ' + + +'.$pagetitle.' + +'; + if ($contents{title}) { + $content .= "\n".'

'.$contents{title}.'

'; + } + if ($contents{image}) { + $content .= "\n".$contents{image}; + } + if ($contents{content}) { + $content .= ' +
+

'.&mt('Content').'

'. +$contents{content}.' +
'; + } + if ($contents{webreferences}) { + $content .= ' +
+

'.&mt('Web References').'

'. +$contents{webreferences}.' +
'; + } + $content .= ' + + +'; + $newcontent{'/'.$simplepages{$item}{res}} = $content; + } + } + foreach my $item (keys(%tocopy)) { + unless ($item=~/\.(sequence|page)$/) { + my $currurlpath = $prefix.$item; + my $currdirpath = &Apache::lonnet::filelocation('',$currurlpath); + &recurse_html($mm,$prefix,$currdirpath,$currurlpath,$item,$lookup{$item},\%replacehash,\%deps); + } + } + foreach my $num (sort {$a <=> $b} (@todump)) { + my $src = $display{$num}; + next if ($src eq ''); + my @needcopy = (); + if ($replacehash{$src}) { + push(@needcopy,$src); + if (ref($deps{$num}) eq 'HASH') { + foreach my $dep (sort(keys(%{$deps{$num}}))) { + if ($replacehash{$dep}) { + push(@needcopy,$dep); + } + } + } + } elsif ($src =~ /^simpleproblem_/) { + push(@needcopy,$src); } - } - } - if ($message) { - $$copyresult .= $message."\n"; - } -} - -sub replicate_content { - my ($cdom,$cnum,$tempexport,$symb,$count,$message,$href,$caller,$currdirpath, - $title,$testbank) = @_; - my ($map,$ind,$url); - if ($caller eq 'templateupload') { - $url = $symb; - $url =~ s#//#/#g; - } else { - ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb); - } - my $content; - my $filename; - my $repstatus; - my $content_name; - if ($url =~ m-/([^/]+)$-) { - $filename = $1; - if (!-e $tempexport.'/resources') { - mkdir($tempexport.'/resources',0700); - } - if (!-e $tempexport.'/resources/'.$count) { - mkdir($tempexport.'/resources/'.$count,0700); - } - my $destination = $tempexport.'/resources/'.$count.'/'.$filename; - my $copiedfile; - if ($copiedfile = Apache::File->new('>'.$destination)) { - my $content; - if ($caller eq 'resource') { - my $respath = $Apache::lonnet::perlvar{'lonDocRoot'}.'/res'; - my $filepath = &Apache::lonnet::filelocation($respath,$url); - $content = &Apache::lonnet::getfile($filepath); - if ($content eq -1) { - $$message = 'Could not copy file '.$filename; + next if (@needcopy == 0); + my ($result,$depresult); + for (my $i=0; $i<@needcopy; $i++) { + my $item = $needcopy[$i]; + my $newfilename; + if ($simpleproblems{$num}) { + $newfilename=$title.'/'.$simpleproblems{$num}{'name'}; } else { - &extract_media($url,$cdom,$cnum,\$content,$count,$tempexport,$href,$message,'resource'); - $repstatus = 'ok'; + $newfilename=$title.'/'.$replacehash{$item}; } - } elsif ($caller eq 'uploaded' || $caller eq 'templateupload') { - my $rtncode; - $repstatus = &Apache::lonnet::getuploaded('GET',$url,$cdom,$cnum,\$content,$rtncode); - if ($repstatus eq 'ok') { - if ($url =~ /\.html?$/i) { - &extract_media($url,$cdom,$cnum,\$content,$count,$tempexport,$href,$message,'uploaded'); + $newfilename=~s/\.(\w+)$//; + my $ext=$1; + $newfilename=&clean($newfilename); + $newfilename.='.'.$ext; + my ($newrelpath) = ($newfilename =~ m{^\Q$title/\E(.+)$}); + if ($newrelpath ne $replacehash{$item}) { + $replacehash{$item} = $newrelpath; + } + my @dirs=split(/\//,$newfilename); + my $path=$r->dir_config('lonDocRoot')."/priv/$cd/$ca"; + my $makepath=$path; + my $fail; + my $origin; + for (my $i=0;$i<$#dirs;$i++) { + $makepath.='/'.$dirs[$i]; + unless (-e $makepath) { + unless(mkdir($makepath,0755)) { + $fail = &mt('Directory creation failed.'); + } } + } + if ($i == 0) { + $result = '
'.$item.' => '.$newfilename.': '; } else { - $$message = 'Could not render '.$url.' server message - '.$rtncode."
\n"; + $depresult .= '
  • '.$item.' => '.$newfilename.' '. + ''. + &mt('(dependency)').': '; } - } elsif (($caller eq 'noedit') || ($caller eq 'html') || - ($caller eq 'plaintext')) { -# Need to render the resource without the LON-CAPA Internal header and the Post discussion footer, and then set $content equal to this. - my %form = ( - grade_symb => $symb, - grade_courseid => $cdom.'_'.$cnum, - grade_domain => $env{'user.domain'}, - grade_username => $env{'user.name'}, - grade_imsexport => 1, - instructor_comments => 'hide', - ); - my $feedurl=&Apache::lonnet::clutter($url); - my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form); - if (ref($response)) { - if ($response->is_success) { - $content = $userview; - $content =~ s/\Qonchange="javascript:setSubmittedPart('\E[^\']+\Q');"\E//g; - $content =~ s/^\s*[\n\r]+$//; - if ($caller eq 'plaintext') { - my @lines = split(/[\n\r]+/,$content); - my @tosave; - my $foilcounter = 0; - my @alphabet = ('a'..'z'); - my $mc_answer; - foreach my $line (@lines) { - next if ($line =~ /^\s*$/); - if ($line =~ m{(|\Q<\label>\E)\Q
    Incorrect:\E)\Q
    Correct:\E(|\Q\E)\Q
    \E}) { - $line =~ s/^(\s+|\s+)$//g; - $line =~ s{^\Q\E([^<]+)\Q\E$}{1}; - $tosave[$foilcounter] .= $line.' '; - } - $content = join("\t",@tosave); - if ($mc_answer) { - $content .= "\t".$mc_answer."\n"; - } - } - if (@tosave) { - my $qtype; - if ($mc_answer) { - $qtype = 'MC'; + if (-e $path.'/'.$newfilename) { + $fail = &mt('Destination already exists -- not overwriting.'); + } else { + if (my $fh=Apache::File->new('>'.$path.'/'.$newfilename)) { + if (($item =~ m{^/adm/$match_domain/$match_username/\d+/smppg}) || + ($item =~ /^simpleproblem_/)) { + print $fh $newcontent{$item}; + } else { + my $fileloc = &Apache::lonnet::filelocation('',$prefix.$item); + if (-e $fileloc) { + if ($item=~/\.(sequence|page|html|htm|xml|xhtml)$/) { + if ((($1 eq 'sequence') || ($1 eq 'page')) && + (ref($has_simpleprobs{$item}) eq 'HASH')) { + my %changes = %{$has_simpleprobs{$item}}; + my $content = &Apache::lonclonecourse::rewritefile( + &Apache::lonclonecourse::readfile($env{'request.course.id'},$item), + (%replacehash,$crs => '') + ); + my $updatedcontent = ''; + my $parser = HTML::TokeParser->new(\$content); + $parser->attr_encoded(1); + while (my $token = $parser->get_token) { + if ($token->[0] eq 'S') { + if (($token->[1] eq 'resource') && + ($token->[2]->{'src'} eq '/res/lib/templates/simpleproblem.problem') && + ($changes{$token->[2]->{'id'}})) { + my $id = $token->[2]->{'id'}; + $updatedcontent .= '<'.$token->[1]; + foreach my $attrib (@{$token->[3]}) { + next unless ($attrib =~ /^(src|type|title|id)$/); + if ($attrib eq 'src') { + my ($file) = ($display{$changes{$id}} =~ /^\Qsimpleproblem_\E(.+)$/); + if ($file) { + $updatedcontent .= ' '.$attrib.'="'.$file.'"'; + } else { + $updatedcontent .= ' '.$attrib.'="'.$token->[2]->{$attrib}.'"'; + } + } else { + $updatedcontent .= ' '.$attrib.'="'.$token->[2]->{$attrib}.'"'; + } + } + $updatedcontent .= ' />'."\n"; + } else { + $updatedcontent .= $token->[4]."\n"; + } + } else { + $updatedcontent .= $token->[2]; + } + } + print $fh $updatedcontent; + } else { + print $fh &Apache::lonclonecourse::rewritefile( + &Apache::lonclonecourse::readfile($env{'request.course.id'},$item), + (%replacehash,$crs => '') + ); + } + } else { + print $fh + &Apache::lonclonecourse::readfile($env{'request.course.id'},$item); } - $content = $currdirpath."\t".$title."\t$qtype\t".join("\t",@tosave); - if ($mc_answer) { - $content .= "\t".$mc_answer; - } - $content .= "\n"; + } else { + $fail = &mt('Source does not exist.'); } - } else { - $content = ''.$content.''; - } - if (($caller eq 'plaintext') && ($testbank)) { - print $testbank $content; } + $fh->close(); } else { - $content = 'Not the owner of this resource'; + $fail = &mt('Could not write to destination.'); } + } + my $text; + if ($fail) { + $text = ''.&mt('fail').(' 'x3).$fail.''; } else { - $content = 'Not the owner of this resource'; + $text = ''.&mt('ok').''; + } + if ($i == 0) { + $result .= $text; + } else { + $depresult .= $text.'
  • '; } - $repstatus = 'ok'; } - if ($repstatus eq 'ok') { - print $copiedfile $content; + $r->print($result); + if ($depresult) { + $r->print(''); } - close($copiedfile); - } else { - $$message = 'Could not open destination file for '.$filename."
    \n"; } } else { - $$message = 'Could not determine name of file for '.$symb."
    \n"; - } - if ($repstatus eq 'ok') { - $content_name = 'resources/'.$count.'/'.$filename; - } - return $content_name; -} - -sub extract_media { - my ($url,$cdom,$cnum,$content,$count,$tempexport,$href,$message,$caller) = @_; - my ($dirpath,$container); - my %allfiles = (); - my %codebase = (); - if ($url =~ m-(.*/)([^/]+)$-) { - $dirpath = $1; - $container = $2; - } else { - $dirpath = $url; - $container = ''; - } - &Apache::lonnet::extract_embedded_items(undef,\%allfiles,\%codebase,$content); - foreach my $embed_file (keys(%allfiles)) { - my $filename; - if ($embed_file =~ m#([^/]+)$#) { - $filename = $1; - } else { - $filename = $embed_file; - } - my $newname = 'res/'.$filename; - my ($rtncode,$embed_content,$repstatus); - my $embed_url; - if ($embed_file =~ m-^/-) { - $embed_url = $embed_file; # points to absolute path + my ($navmap,$errormsg) = + &Apache::loncourserespicker::get_navmap_object($crstype,'dumpdocs'); + if (!ref($navmap)) { + $r->print($errormsg); } else { - if ($embed_file =~ m-https?://-) { - next; # points to url - } else { - $embed_url = $dirpath.$embed_file; # points to relative path + $r->print('
    '.&mt('Searching ...').'
    '); + $r->rflush(); + my ($preamble,$formname); + $formname = 'dumpdoc'; + unless ($home==1) { + $preamble = '
    '. + '
    '. + &mt('Select the Authoring Space'). + ''; } else { - $attrib_regexp = $allfiles{$embed_file}[0]; - } - $$content =~ s#($attrib_regexp\s*=\s*['"]?)\Q$embed_file\E(['"]?)#$1$newname$2#gi; - if ($caller eq 'resource' && $container =~ /\.(problem|library)$/) { - $$content =~ s#\Q$embed_file\E#$newname#gi; + $preamble .= ''; } } - } else { - $$message .= 'replication of embedded file - '.$embed_file.' in '.$url.' failed, reason -'.$rtncode."
    \n"; - } - } - return; -} - -sub store_template { - my ($contents,$tempexport,$count,$content_type) = @_; - if ($contents) { - if ($tempexport) { - if (!-e $tempexport.'/resources') { - mkdir($tempexport.'/resources',0700); - } - if (!-e $tempexport.'/resources/'.$count) { - mkdir($tempexport.'/resources/'.$count,0700); - } - my $destination = $tempexport.'/resources/'.$count.'/'.$content_type.'.xml'; - my $storetemplate; - if ($storetemplate = Apache::File->new('>'.$destination)) { - print $storetemplate $contents; - close($storetemplate); + unless ($home==1) { + $preamble .= '
    '."\n"; } - if ($content_type eq 'external') { - return 'resources/'.$count.'/'.$content_type.'.html'; - } else { - return 'resources/'.$count.'/'.$content_type.'.xml'; + my $title=$origcrsdata{'description'}; + $title=~s/[\/\s]+/\_/gs; + $title=&clean($title); + $preamble .= '
    '. + '
    '.&mt('Folder in Authoring Space').''. + ''. + '
    '."\n"; + my %uploadedfiles; + &tiehash(); + foreach my $file (&Apache::lonclonecourse::crsdirlist($origcrsid,'userfiles')) { + my ($ext)=($file=~/\.(\w+)$/); +# FIXME Check supplemental here + my $title=$hash{'title_'.$hash{ + 'ids_/uploaded/'.$origcrsdata{'domain'}.'/'.$origcrsdata{'num'}.'/'.$file}}; + if (!$title) { + $title=$file; + } else { + $title=~s|/|_|g; + } + $title=~s/\.(\w+)$//; + $title=&clean($title); + $title.='.'.$ext; +# $r->print("\n" + $uploadedfiles{$file} = $title; + } + &untiehash(); + $r->print(&Apache::loncourserespicker::create_picker($navmap,'dumpdocs',$formname,$crstype,undef, + undef,undef,$preamble,$home,\%uploadedfiles)); + } + } + $r->print(&endContentScreen()); +} + +sub recurse_html { + my ($mm,$prefix,$currdirpath,$currurlpath,$container,$item,$replacehash,$deps) = @_; + return unless ((ref($replacehash) eq 'HASH') && (ref($deps) eq 'HASH')); + my (%allfiles,%codebase); + if (&Apache::lonnet::extract_embedded_items($currdirpath,\%allfiles,\%codebase) eq 'ok') { + if (keys(%allfiles)) { + foreach my $dependency (keys(%allfiles)) { + next if (($dependency =~ m{^/(res|adm)/}) || ($dependency =~ m{^https?://})); + my ($depurl,$relfile,$newcontainer); + if ($dependency =~ m{^/}) { + if ($dependency =~ m{^\Q$currurlpath/\E(.+)$}) { + $relfile = $1; + if ($dependency =~ m{^\Q$prefix\E(.+)$}) { + $newcontainer = $1; + next if ($replacehash->{$newcontainer}); + } + $depurl = $dependency; + } else { + next; + } + } else { + $relfile = $dependency; + $depurl = $currurlpath; + $depurl =~ s{[^/]+$}{}; + $depurl .= $dependency; + ($newcontainer) = ($depurl =~ m{^\Q$prefix\E(.+)$}); + } + next if ($relfile eq ''); + my $newname = $replacehash->{$container}; + $newname =~ s{[^/]+$}{}; + $replacehash->{$newcontainer} = $newname.$relfile; + $deps->{$item}{$newcontainer} = 1; + my ($newurlpath) = ($depurl =~ m{^(.*)/[^/]+$}); + my $depfile = &Apache::lonnet::filelocation('',$depurl); + my $type = $mm->checktype_filename($depfile); + if ($type eq 'text/html') { + &recurse_html($mm,$prefix,$depfile,$newurlpath,$newcontainer,$item,$replacehash,$deps); + } } } } + return; } - sub group_import { my ($coursenum, $coursedom, $folder, $container, $caller, @files) = @_; - + my ($donechk,$allmaps,%hierarchy,%titles,%addedmaps,%removefrommap, + %removeparam,$importuploaded,$fixuperrors); + $allmaps = {}; while (@files) { my ($name, $url, $residx) = @{ shift(@files) }; if (($url =~ m{^/uploaded/\Q$coursedom\E/\Q$coursenum\E/(default_\d+\.)(page|sequence)$}) @@ -1086,7 +642,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; } @@ -1095,6 +651,24 @@ sub group_import { } } if ($url) { + if (($caller eq 'londocs') && + ($folder =~ /^default/)) { + if (($url =~ /\.(page|sequence)$/) && (!$donechk)) { + my $chome = &Apache::lonnet::homeserver($coursenum,$coursedom); + my $cid = $coursedom.'_'.$coursenum; + $allmaps = + &Apache::loncommon::allmaps_incourse($coursedom,$coursenum, + $chome,$cid); + $donechk = 1; + } + if ($url =~ m{^/uploaded/\Q$coursedom\E/\Q$coursenum\E/(default_\d+\.)(page|sequence)$}) { + &contained_map_check($url,$folder,\%removefrommap,\%removeparam, + \%addedmaps,\%hierarchy,\%titles,$allmaps); + $importuploaded = 1; + } elsif ($url =~ m{^/res/.+\.(page|sequence)$}) { + next if ($allmaps->{$url}); + } + } if (!$residx || defined($LONCAPA::map::zombies[$residx])) { $residx = &LONCAPA::map::getresidx($url,$residx); @@ -1102,76 +676,97 @@ sub group_import { } my $ext = 'false'; if ($url=~m{^http://} || $url=~m{^https://}) { $ext = 'true'; } - $url = &LONCAPA::map::qtunescape($url); $name = &LONCAPA::map::qtunescape($name); + if ($name eq '') { + $name = &LONCAPA::map::qtunescape(&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); + } + } + $url = &LONCAPA::map::qtunescape($url); $LONCAPA::map::resources[$residx] = join(':', ($name, $url, $ext, 'normal', 'res')); } } - return &storemap($coursenum, $coursedom, $folder.'.'.$container); -} - -sub breadcrumbs { - my ($allowed,$crstype)=@_; - &Apache::lonhtmlcommon::clear_breadcrumbs(); - my (@folders); - if ($env{'form.pagepath'}) { - @folders = split('&',$env{'form.pagepath'}); - } else { - @folders=split('&',$env{'form.folderpath'}); + if ($importuploaded) { + my %import_errors; + my %updated = ( + removefrommap => \%removefrommap, + removeparam => \%removeparam, + ); + my ($result,$msgsarray,$lockerror) = + &apply_fixups($folder,1,$coursedom,$coursenum,\%import_errors,\%updated); + if (keys(%import_errors) > 0) { + $fixuperrors = + '

    '."\n". + &mt('The following files are either dependencies of a web page or references within a folder and/or composite page for which errors occurred during import:')."\n". + '

    '."\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); + unless ($fatal) { + if ($folder =~ /^supplemental/) { + &Apache::lonnet::get_numsuppfiles($coursenum,$coursedom,1); + my ($errtext,$fatal) = &mapread($coursenum,$coursedom, + $folder.'.'.$container); + } } - my $folderpath; - my $cpinfo=''; - my $plain=''; - my $randompick=-1; - my $isencrypted=0; - my $ishidden=0; - my $is_random_order=0; - if (!$allowed) { - my $description = $env{'course.'.$env{'request.course.id'}.'.description'}; - &Apache::lonhtmlcommon::add_breadcrumb( - {'href' => '/adm/menu', - 'title'=> 'Go to main menu', - 'text' => $description, - }); - $plain .= $description.' >'; - } - while (@folders) { - my $folder=shift(@folders); - my $foldername=shift(@folders); - if ($folderpath) {$folderpath.='&';} - $folderpath.=$folder.'&'.$foldername; - my $url='/adm/coursedocs?folderpath='. - &escape($folderpath); - my $name=&unescape($foldername); -# randompick number, hidden, encrypted, random order, is appended with ":"s to the foldername - $name=~s/\:(\d*)\:(\w*)\:(\w*):(\d*)$//; - if ($1 ne '') { - $randompick=$1; - } else { - $randompick=-1; - } - if ($2) { $ishidden=1; } - if ($3) { $isencrypted=1; } - if ($4 ne '') { $is_random_order = 1; } - if ($folder eq 'supplemental') { - $name = &mt('Supplemental '.$crstype.' Documents'); - } - &Apache::lonhtmlcommon::add_breadcrumb( - {'href'=>$url.$cpinfo, - 'title'=>$name, - 'text'=>$name, - 'no_mt'=>1, - }); - $plain.=$name.' > '; - } - $plain=~s/\>\;\s*$//; - return (&Apache::lonhtmlcommon::breadcrumbs(undef,undef,0,'nohelp', - undef, undef, 1 ),$randompick,$ishidden,$isencrypted,$plain,$is_random_order); + return ($errtext,$fatal,$fixuperrors); } sub log_docs { - return &Apache::lonnet::instructor_log('docslog',@_); + return &Apache::lonnet::write_log('course','docslog',@_); } { @@ -1231,24 +826,53 @@ sub log_docs { } } - - - - sub docs_change_log { - my ($r)=@_; - my $folder=$env{'form.folder'}; - $r->print(&Apache::loncommon::start_page('Course Document Change Log')); - $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Document Change Log')); + my ($r,$coursenum,$coursedom,$folder,$allowed,$crstype,$iconpath,$canedit)=@_; + my $supplementalflag=($env{'form.folderpath'}=~/^supplemental/); + my $navmap; + my $js = ''."\n"; + $r->print(&Apache::loncommon::start_page('Content Change Log',$js)); + $r->print(&Apache::lonhtmlcommon::breadcrumbs('Content Change Log')); + $r->print(&startContentScreen(($supplementalflag?'suppdocs':'docs'))); + my %orderhash; + my $container='sequence'; + my $pathitem; + if ($env{'form.folderpath'} =~ /\:1$/) { + $container='page'; + } + my $folderpath=$env{'form.folderpath'}; + if ($folderpath eq '') { + $folderpath = &default_folderpath($coursenum,$coursedom,\$navmap); + } + undef($navmap); + $pathitem = ''; + my $readfile="/uploaded/$coursedom/$coursenum/$folder.$container"; + my $jumpto = $readfile; + $jumpto =~ s{^/}{}; + my $tid = 1; + if ($supplementalflag) { + $tid = 2; + } + my ($breadcrumbtrail) = + &Apache::lonhtmlcommon::docs_breadcrumbs($allowed,$crstype,1); + $r->print($breadcrumbtrail. + &generate_edit_table($tid,\%orderhash,undef,$iconpath,$jumpto, + $readfile)); my %docslog=&Apache::lonnet::dump('nohist_docslog', $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'}); if ((keys(%docslog))[0]=~/^error\:/) { undef(%docslog); } - $r->print('
    '. - ''); - my %saveable_parameters = ('show' => 'scalar',); &Apache::loncommon::store_course_settings('docs_log', \%saveable_parameters); @@ -1262,9 +886,14 @@ sub docs_change_log { 'randomorder' => 'Randomly ordered', 'set' => 'set to', 'del' => 'deleted'); - $r->print(&Apache::loncommon::display_filter(). - ''. - '
    '); + my $filter = &Apache::loncommon::display_filter('docslog')."\n". + $pathitem."\n". + ''. + (' 'x2).''; + $r->print('
    '. + '
    '.&mt('Display of Content Changes').''."\n". + &makedocslogform($filter,1). + '

    '); $r->print(&Apache::loncommon::start_data_table().&Apache::loncommon::start_data_table_header_row(). ''.&mt('Time').''.&mt('User').''.&mt('Folder').''.&mt('Before').''. &mt('After').''. @@ -1308,18 +937,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(''); @@ -1330,13 +971,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(''); @@ -1359,171 +1008,1047 @@ sub docs_change_log { if (!($env{'form.show'} eq &mt('all') || $shown<=$env{'form.show'})) { last; } } - $r->print(&Apache::loncommon::end_data_table()); + $r->print(&Apache::loncommon::end_data_table()."\n". + &makesimpleeditform($pathitem)."\n". + ''); + $r->print(&endContentScreen()); } sub update_paste_buffer { - my ($coursenum,$coursedom) = @_; + my ($coursenum,$coursedom,$folder) = @_; + my (@possibles,%removals,%cuts,$output); + if ($env{'form.multiremove'}) { + $env{'form.multiremove'} =~ s/,$//; + map { $removals{$_} = 1; } split(/,/,$env{'form.multiremove'}); + } + if (($env{'form.multicopy'}) || ($env{'form.multicut'})) { + if ($env{'form.multicut'}) { + $env{'form.multicut'} =~ s/,$//; + foreach my $item (split(/,/,$env{'form.multicut'})) { + unless ($removals{$item}) { + $cuts{$item} = 1; + push(@possibles,$item.':cut'); + } + } + } + if ($env{'form.multicopy'}) { + $env{'form.multicopy'} =~ s/,$//; + foreach my $item (split(/,/,$env{'form.multicopy'})) { + unless ($removals{$item} || $cuts{$item}) { + push(@possibles,$item.':copy'); + } + } + } + } elsif ($env{'form.markcopy'}) { + @possibles = split(/,/,$env{'form.markcopy'}); + } - return if (!defined($env{'form.markcopy'})); + return if (@possibles == 0); return if (!defined($env{'form.copyfolder'})); - return if ($env{'form.markcopy'} < 0); my ($errtext,$fatal) = &mapread($coursenum,$coursedom, $env{'form.copyfolder'}); - return if ($fatal); -# Mark for copying - 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); - } elsif ($env{'docs.markedcopy_supplemental'}) { - &Apache::lonnet::delenv('docs.markedcopy_supplemental'); + my %curr_groups = &Apache::longroup::coursegroups(); + +# Retrieve current paste buffer suffixes. + my @currpaste = split(/,/,$env{'docs.markedcopies'}); + my (%pasteurls,@newpaste); + +# Construct identifiers for current contents of user's paste buffer + if (@currpaste) { + foreach my $suffix (@currpaste) { + my $cid = $env{'docs.markedcopy_crs_'.$suffix}; + my $url = $env{'docs.markedcopy_url_'.$suffix}; + if (($cid =~ /^$match_domain(?:_)$match_courseid$/) && + ($url ne '')) { + $pasteurls{$cid.'_'.$url} = 1; + } + } } - $url=~s{http(:|:)//https(:|:)//}{https$2//}; - &Apache::lonnet::appenv({'docs.markedcopy_title' => $title, - 'docs.markedcopy_url' => $url}); +# Mark items for copying (skip any items already in user's paste buffer) + my %addtoenv; + + foreach my $item (@possibles) { + my ($orderidx,$cmd) = split(/:/,$item); + next if ($orderidx =~ /\D/); + next unless (($cmd eq 'cut') || ($cmd eq 'copy') || ($cmd eq 'remove')); + my ($title,$url)=split(':',$LONCAPA::map::resources[$orderidx]); + my %denied = &action_restrictions($coursenum,$coursedom, + &LONCAPA::map::qtescape($url), + $env{'form.folderpath'},\%curr_groups); + next if ($denied{'copy'}); + $url=~s{http(:|:)//https(:|:)//}{https$2//}; + next if (exists($pasteurls{$coursedom.'_'.$coursenum.'_'.$url})); + my ($suffix,$errortxt,$locknotfreed) = + &new_timebased_suffix($env{'user.domain'},$env{'user.name'},'paste'); + if ($suffix ne '') { + push(@newpaste,$suffix); + } else { + if ($locknotfreed) { + return $locknotfreed; + } + } + if (&is_supplemental_title($title)) { + &Apache::lonnet::appenv({'docs.markedcopy_supplemental_'.$suffix => $title}); + ($title) = &Apache::loncommon::parse_supplemental_title($title); + } + + $addtoenv{'docs.markedcopy_title_'.$suffix} = $title, + $addtoenv{'docs.markedcopy_url_'.$suffix} = $url, + $addtoenv{'docs.markedcopy_cmd_'.$suffix} = $cmd, + $addtoenv{'docs.markedcopy_crs_'.$suffix} = $env{'request.course.id'}; + + if ($url =~ m{^/uploaded/$match_domain/$match_courseid/(default|supplemental)_?(\d*)\.(page|sequence)$}) { + my $prefix = $1; + my $subdir =$2; + if ($subdir eq '') { + $subdir = $prefix; + } + my (%addedmaps,%removefrommap,%removeparam,%hierarchy,%titles,%allmaps); + &contained_map_check($url,$folder,\%removefrommap,\%removeparam,\%addedmaps, + \%hierarchy,\%titles,\%allmaps); + if (ref($hierarchy{$url}) eq 'HASH') { + my ($nested,$nestednames); + &recurse_uploaded_maps($url,$subdir,\%hierarchy,\%titles,\$nested,\$nestednames); + $nested =~ s/\&$//; + $nestednames =~ s/\Q___&&&___\E$//; + if ($nested ne '') { + $addtoenv{'docs.markedcopy_nested_'.$suffix} = $nested; + } + if ($nestednames ne '') { + $addtoenv{'docs.markedcopy_nestednames_'.$suffix} = $nestednames; + } + } + } + if ($locknotfreed) { + $output = $locknotfreed; + last; + } + } + if (@newpaste) { + $addtoenv{'docs.markedcopies'} = join(',',(@currpaste,@newpaste)); + } + &Apache::lonnet::appenv(\%addtoenv); delete($env{'form.markcopy'}); + return $output; +} + +sub recurse_uploaded_maps { + my ($url,$dir,$hierarchy,$titlesref,$nestref,$namesref) = @_; + if (ref($hierarchy->{$url}) eq 'HASH') { + my @maps = map { $hierarchy->{$url}{$_}; } sort { $a <=> $b } (keys(%{$hierarchy->{$url}})); + my @titles = map { $titlesref->{$url}{$_}; } sort { $a <=> $b } (keys(%{$titlesref->{$url}})); + my (@uploaded,@names,%shorter); + for (my $i=0; $i<@maps; $i++) { + my ($inner) = ($maps[$i] =~ m{^/uploaded/$match_domain/$match_courseid/(?:default|supplemental)_(\d+)\.(?:page|sequence)$}); + if ($inner ne '') { + push(@uploaded,$inner); + push(@names,&escape($titles[$i])); + $shorter{$maps[$i]} = $inner; + } + } + $$nestref .= "$dir:".join(',',@uploaded).'&'; + $$namesref .= "$dir:".(join(',',@names)).'___&&&___'; + foreach my $map (@maps) { + if ($shorter{$map} ne '') { + &recurse_uploaded_maps($map,$shorter{$map},$hierarchy,$titlesref,$nestref,$namesref); + } + } + } + return; } sub print_paste_buffer { - my ($r,$container) = @_; - return if (!defined($env{'docs.markedcopy_url'})); + my ($r,$container,$folder,$coursedom,$coursenum) = @_; + return if (!defined($env{'docs.markedcopies'})); - $r->print('
    ' - .''.&mt('Clipboard').'' - .'
    ' - .' ' - ); + unless (($env{'form.pastemarked'}) || ($env{'form.clearmarked'})) { + return if ($env{'docs.markedcopies'} eq ''); + } - my $type; - if ($env{'docs.markedcopy_url'} =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//} ) { - $type = &mt('External Resource'); - $r->print($type.': '. - &LONCAPA::map::qtescape($env{'docs.markedcopy_title'}).' ('. - &LONCAPA::map::qtescape($env{'docs.markedcopy_url'}).')'); - } else { - my $extension = (split(/\./,$env{'docs.markedcopy_url'}))[-1]; - my $icon = &Apache::loncommon::icon($extension); - if ($extension eq 'sequence' && - $env{'docs.markedcopy_url'} =~ m{/default_\d+\.sequence$ }x) { - $icon = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL')); - $icon .= '/navmap.folder.closed.gif'; - } - $icon = ''; - $r->print($icon.$type.': '. &parse_supplemental_title(&LONCAPA::map::qtescape($env{'docs.markedcopy_title'}))); + my @currpaste = split(/,/,$env{'docs.markedcopies'}); + my ($pasteitems,@pasteable); + my $clipboardcount = 0; + +# Construct identifiers for current contents of user's paste buffer + foreach my $suffix (@currpaste) { + next if ($suffix =~ /\D/); + my $cid = $env{'docs.markedcopy_crs_'.$suffix}; + my $url = $env{'docs.markedcopy_url_'.$suffix}; + if (($cid =~ /^$match_domain\_$match_courseid$/) && + ($url ne '')) { + $clipboardcount ++; + my ($is_external,$othercourse,$fromsupp,$is_uploaded_map,$parent, + $canpaste,$nopaste,$othercrs,$areachange); + my $extension = (split(/\./,$env{'docs.markedcopy_url_'.$suffix}))[-1]; + if ($url =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//} ) { + $is_external = 1; + } + if ($folder =~ /^supplemental/) { + $canpaste = &supp_pasteable($env{'docs.markedcopy_url_'.$suffix}); + unless ($canpaste) { + $nopaste = &mt('Paste into Supplemental Content unavailable.'); + } + } else { + $canpaste = 1; + } + if ($canpaste) { + if ($url =~ m{^/uploaded/($match_domain)/($match_courseid)/(.+)$}) { + my $srcdom = $1; + my $srcnum = $2; + my $rem = $3; + if (($srcdom ne $coursedom) || ($srcnum ne $coursenum)) { + $othercourse = 1; + if ($env{"user.priv.cm./$srcdom/$srcnum"} =~ /\Q:mdc&F\E/) { + if ($canpaste) { + $othercrs = '
    '.&mt('(from another course)'); + } + } else { + $canpaste = 0; + $nopaste = &mt('Paste from another course unavailable.'); + } + } + if ($rem =~ m{^(default|supplemental)_?(\d*)\.(?:page|sequence)$}) { + my $prefix = $1; + $parent = $2; + if ($folder !~ /^\Q$prefix\E/) { + $areachange = 1; + } + $is_uploaded_map = 1; + } + } + } + if ($canpaste) { + push(@pasteable,$suffix); + } + my $buffer; + if ($is_external) { + $buffer = &mt('External Resource').': '. + &LONCAPA::map::qtescape($env{'docs.markedcopy_title_'.$suffix}).' ('. + &LONCAPA::map::qtescape($url).')'; + } else { + my $icon = &Apache::loncommon::icon($extension); + if ($extension eq 'sequence' && + $url =~ m{/default_\d+\.sequence$}x) { + $icon = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL')); + $icon .= '/navmap.folder.closed.gif'; + } + my $title = $env{'docs.markedcopy_title_'.$suffix}; + if ($title eq '') { + ($title) = ($url =~ m{/([^/]+)$}); + } + $buffer = ''. + ': '. + &Apache::loncommon::parse_supplemental_title( + &LONCAPA::map::qtescape($title)); + } + $pasteitems .= '
    '; + my ($options,$onclick); + if (($canpaste) && (!$areachange) && (!$othercourse) && + ($env{'docs.markedcopy_cmd_'.$suffix} eq 'cut')) { + if (($is_uploaded_map) || + ($url =~ /(bulletinboard|smppg)$/) || + ($url =~ m{^/uploaded/$coursedom/$coursenum/(?:docs|supplemental)/(.+)$})) { + $options = &paste_options($suffix,$is_uploaded_map,$parent); + $onclick= 'onclick="showOptions(this,'."'$suffix'".');" '; + } + } + $pasteitems .= ''; + if ($nopaste) { + $pasteitems .= $nopaste; + } else { + if ($othercrs) { + $pasteitems .= $othercrs; + } + if ($options) { + $pasteitems .= $options; + } + } + $pasteitems .= '
    '; + } } - if ($container eq 'page') { - $r->print(' - - -'); + if ($pasteitems eq '') { + &Apache::lonnet::delenv('docs.markedcopies'); + } + my ($pasteform,$form_start,$buttons,$form_end); + if ($pasteitems) { + $pasteitems .= '
    '; + $form_start = ''; + if (@pasteable) { + my $value = &mt('Paste to current folder'); + if ($container eq 'page') { + $value = &mt('Paste to current page'); + } + $buttons = ''.(' 'x2); + } + $buttons .= ''.(' 'x2); + if ($clipboardcount > 1) { + $buttons .= + ''.(' 'x20).''.(' 'x2). + ''. + (' 'x2). + ''. + (' 'x2); + } + $form_end = ''. + '
    '; } else { - $r->print(' - -'); + $pasteitems = &mt('Clipboard is empty'); + } + $r->print($form_start + .'
    ' + .''.&mt('Clipboard').(' ' x2).$buttons.'' + .$pasteitems + .'
    ' + .$form_end); +} + +sub paste_options { + my ($suffix,$is_uploaded_map,$parent) = @_; + my ($copytext,$movetext); + if ($is_uploaded_map) { + $copytext = &mt('Copy to new folder'); + $movetext = &mt('Move old'); + } elsif ($env{'docs.markedcopy_url_'.$suffix} =~ /bulletinboard$/) { + $copytext = &mt('Copy to new board'); + $movetext = &mt('Move (not posts)'); + } elsif ($env{'docs.markedcopy_url_'.$suffix} =~ /smppg$/) { + $copytext = &mt('Copy to new page'); + $movetext = &mt('Move'); + } else { + $copytext = &mt('Copy to new file'); + $movetext = &mt('Move'); + } + my $output = '
    '. + ''. + ''; + return $output; +} + +sub recurse_print { + my ($outputref,$dir,$deps,$display) = @_; + $$outputref .= $display->{$dir}."\n"; + if (ref($deps->{$dir}) eq 'ARRAY') { + foreach my $subdir (@{$deps->{$dir}}) { + &recurse_print($outputref,$subdir,$deps,$display); + } + } +} + +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 paste_popup_js { + my %html_js_lt = &Apache::lonlocal::texthash( + show => 'Show Options', + hide => 'Hide Options', + ); + my %js_lt = &Apache::lonlocal::texthash( + none => 'No items selected from clipboard.', + ); + &html_escape(\%html_js_lt); + &js_escape(\%html_js_lt); + &js_escape(\%js_lt); + return <<"END"; + +function showPasteOptions(suffix) { + document.getElementById('pasteoptions_'+suffix).style.display='block'; + document.getElementById('pasteoptionstext_'+suffix).innerHTML = '    $html_js_lt{'hide'}'; + return; +} + +function hidePasteOptions(suffix) { + document.getElementById('pasteoptions_'+suffix).style.display='none'; + document.getElementById('pasteoptionstext_'+suffix).innerHTML ='    $html_js_lt{'show'}'; + return; +} + +function showOptions(caller,suffix) { + if (document.getElementById('pasteoptionstext_'+suffix)) { + if (caller.checked) { + document.getElementById('pasteoptionstext_'+suffix).innerHTML ='    $html_js_lt{'show'}'; + } else { + document.getElementById('pasteoptionstext_'+suffix).innerHTML =''; + } + if (document.getElementById('pasteoptions_'+suffix)) { + document.getElementById('pasteoptions_'+suffix).style.display='none'; + } + } + return; +} + +function validateClipboard() { + var numchk = 0; + if (document.pasteform.pasting.length > 1) { + for (var i=0; i 0) { + return true; + } else { + alert("$js_lt{'none'}"); + return false; + } +} + +function checkClipboard() { + if (document.pasteform.pasting.length > 1) { + for (var i=0; i1) { + for (var i=0; iprint('
    '); + return; +} + +END + } sub do_paste_from_buffer { - my ($coursenum,$coursedom,$folder) = @_; + my ($coursenum,$coursedom,$folder,$container,$errors) = @_; - if (!$env{'form.pastemarked'}) { - return; +# Array of items in paste buffer + my (@currpaste,%pastebuffer,%allerrors); + @currpaste = split(/,/,$env{'docs.markedcopies'}); + +# Early out if paste buffer is empty + if (@currpaste == 0) { + return (); + } + map { $pastebuffer{$_} = 1; } @currpaste; + +# Array of items selected items to paste + my @reqpaste = &Apache::loncommon::get_env_multiple('form.pasting'); + +# Early out if nothing selected to paste + if (@reqpaste == 0) { + return(); + } + my @topaste; + foreach my $suffix (@reqpaste) { + next if ($suffix =~ /\D/); + next unless (exists($pastebuffer{$suffix})); + push(@topaste,$suffix); + } + +# Early out if nothing available to paste + if (@topaste == 0) { + return(); } -# paste resource to end of list - my $url=&LONCAPA::map::qtescape($env{'docs.markedcopy_url'}); - my $title=&LONCAPA::map::qtescape($env{'docs.markedcopy_title'}); + my (%msgs,%before,%after,@dopaste,%is_map,%notinsupp,%notincrs,%duplicate, + %prefixchg,%srcdom,%srcnum,%marktomove,$save_err,$lockerrors,$allresult); + + foreach my $suffix (@topaste) { + my $url=&LONCAPA::map::qtescape($env{'docs.markedcopy_url_'.$suffix}); +# Supplemental content may only include certain types of content +# Early out if pasted content is not supported in Supplemental area + if ($folder =~ /^supplemental/) { + unless (&supp_pasteable($url)) { + $notinsupp{$suffix} = 1; + next; + } + } + if ($url =~ m{^/uploaded/($match_domain)/($match_courseid)/}) { + my $srcd = $1; + my $srcn = $2; +# When paste buffer was populated using an active role in a different course +# check for mdc privilege in the course from which the resource was pasted + if (($srcd ne $coursedom) || ($srcn ne $coursenum)) { + unless ($env{"user.priv.cm./$srcd/$srcn"} =~ /\Q:mdc&F\E/) { + $notincrs{$suffix} = 1; + next; + } + } + $srcdom{$suffix} = $srcd; + $srcnum{$suffix} = $srcn; + } + + push(@dopaste,$suffix); + if ($url=~/\.(page|sequence)$/) { + $is_map{$suffix} = 1; + } + + if ($url =~ m{^/uploaded/$match_domain/$match_courseid/([^/]+)}) { + my $oldprefix = $1; +# When pasting content from Main Content to Supplemental Content and vice versa +# URLs will contain different paths (which depend on whether pasted item is +# a folder/page or a document. + if (($folder =~ /^supplemental/) && (($oldprefix =~ /^default/) || ($oldprefix eq 'docs'))) { + $prefixchg{$suffix} = 'docstosupp'; + } elsif (($folder =~ /^default/) && ($oldprefix =~ /^supplemental/)) { + $prefixchg{$suffix} = 'supptodocs'; + } + +# If pasting an uploaded map, get list of contained uploaded maps. + if ($env{'docs.markedcopy_nested_'.$suffix}) { + my @nested; + my ($type) = ($oldprefix =~ /^(default|supplemental)/); + my @items = split(/\&/,$env{'docs.markedcopy_nested_'.$suffix}); + my @deps = map { /\d+:([\d,]+$)/ } @items; + foreach my $dep (@deps) { + if ($dep =~ /,/) { + push(@nested,split(/,/,$dep)); + } else { + push(@nested,$dep); + } + } + foreach my $item (@nested) { + if ($env{'form.docs.markedcopy_'.$suffix.'_'.$item} eq 'move') { + push(@{$marktomove{$suffix}},$type.'_'.$item); + } + } + } + } + } + +# Early out if nothing available to paste + if (@dopaste == 0) { + return (); + } + +# Populate message hash and hashes used for main content <=> supplemental content +# changes + + %msgs = &Apache::lonlocal::texthash ( + notinsupp => 'Paste failed: content type is not supported within Supplemental Content', + notincrs => 'Paste failed: Item is from a different course which you do not have rights to edit.', + duplicate => 'Paste failed: only one instance of a particular published sequence or page is allowed within each course.', + ); + + %before = ( + docstosupp => { + map => 'default', + doc => 'docs', + }, + supptodocs => { + map => 'supplemental', + doc => 'supplemental', + }, + ); + + %after = ( + docstosupp => { + map => 'supplemental', + doc => 'supplemental' + }, + supptodocs => { + map => 'default', + doc => 'docs', + }, + ); + +# Retrieve information about all course maps in main content area + + my $allmaps = {}; + if ($folder =~ /^default/) { + $allmaps = + &Apache::loncommon::allmaps_incourse($coursedom,$coursenum, + $env{"course.$env{'request.course.id'}.home"}, + $env{'request.course.id'}); + } + + my (@toclear,%mapurls,%lockerrs,%msgerrs,%results); + +# Loop over the items to paste + foreach my $suffix (@dopaste) { # Maps need to be copied first - if (($url=~/\.(page|sequence)$/) && ($url=~/^\/uploaded\//)) { - $title=&mt('Copy of').' '.$title; - my $newid=$$.int(rand(100)).time; - my ($oldid,$ext) = ($url=~/^(.+)\.(\w+)$/); - if ($oldid =~ m{^(/uploaded/\Q$coursedom\E/\Q$coursenum\E/)(\D+)(\d+)$}) { - my $path = $1; - my $prefix = $2; - my $ancestor = $3; - if (length($ancestor) > 10) { - $ancestor = substr($ancestor,-10,10); + my (%removefrommap,%removeparam,%addedmaps,%rewrites,%retitles,%copies, + %dbcopies,%zombies,%params,%docmoves,%mapmoves,%mapchanges,%newsubdir, + %newurls,%tomove); + if (ref($marktomove{$suffix}) eq 'ARRAY') { + map { $tomove{$_} = 1; } @{$marktomove{$suffix}}; + } + my $url=&LONCAPA::map::qtescape($env{'docs.markedcopy_url_'.$suffix}); + my $title=&LONCAPA::map::qtescape($env{'docs.markedcopy_title_'.$suffix}); + my $oldurl = $url; + if ($is_map{$suffix}) { +# If pasting a map, check if map contains other maps + my (%hierarchy,%titles); + &contained_map_check($url,$folder,\%removefrommap,\%removeparam, + \%addedmaps,\%hierarchy,\%titles,$allmaps); + if ($url=~ m{^/uploaded/}) { + my $newurl; + unless ($env{'form.docs.markedcopy_options_'.$suffix} eq 'move') { + ($newurl,my $error) = + &get_newmap_url($url,$folder,$prefixchg{$suffix},$coursedom, + $coursenum,$srcdom{$suffix},$srcnum{$suffix}, + \$title,$allmaps,\%newurls); + if ($error) { + $allerrors{$suffix} = $error; + next; + } + if ($newurl ne '') { + if ($newurl ne $url) { + if ($newurl =~ /(?:default|supplemental)_(\d+).(?:sequence|page)$/) { + $newsubdir{$url} = $1; + } + $mapchanges{$url} = 1; + } + } + } + if (($srcdom{$suffix} ne $coursedom) || + ($srcnum{$suffix} ne $coursenum) || + ($prefixchg{$suffix}) || (($newurl ne '') && ($newurl ne $url))) { + unless (&url_paste_fixups($url,$folder,$prefixchg{$suffix}, + $coursedom,$coursenum,$srcdom{$suffix}, + $srcnum{$suffix},$allmaps,\%rewrites, + \%retitles,\%copies,\%dbcopies, + \%zombies,\%params,\%mapmoves, + \%mapchanges,\%tomove,\%newsubdir, + \%newurls)) { + $mapmoves{$url} = 1; + } + $url = $newurl; + } elsif ($env{'docs.markedcopy_nested_'.$suffix}) { + &url_paste_fixups($url,$folder,$prefixchg{$suffix},$coursedom, + $coursenum,$srcdom{$suffix},$srcnum{$suffix}, + $allmaps,\%rewrites,\%retitles,\%copies,\%dbcopies, + \%zombies,\%params,\%mapmoves,\%mapchanges, + \%tomove,\%newsubdir,\%newurls); + } + } elsif ($url=~m {^/res/}) { +# published map can only exists once, so remove from paste buffer when done + push(@toclear,$suffix); +# if pasting published map (main content area only) check map not already in course + if ($folder =~ /^default/) { + if ((ref($allmaps) eq 'HASH') && ($allmaps->{$url})) { + $duplicate{$suffix} = 1; + next; + } + } + } + } + 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, + ); + unless ($env{'form.docs.markedcopy_options_'.$suffix} eq 'move') { + my (%lockerr,$msg); + my ($newurl,$result,$errtext) = + &dbcopy(\%info,$coursedom,$coursenum,\%lockerr); + if ($result eq 'ok') { + $url = $newurl; + $title=&mt('Copy of').' '.$title; + } else { + 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 discussion board.').' '.$errtext; + } + $results{$suffix} = $result; + $msgerrs{$suffix} = $msg; + $lockerrs{$suffix} = $lockerr{$prefix}; + next; + } + if ($lockerr{$prefix}) { + $lockerrs{$suffix} = $lockerr{$prefix}; + } + } + } + $title = &LONCAPA::map::qtunescape($title); + my $ext='false'; + if ($url=~m{^http(|s)://}) { $ext='true'; } + if ($env{'docs.markedcopy_supplemental_'.$suffix}) { + if ($folder !~ /^supplemental/) { + (undef,undef,$title) = + &Apache::loncommon::parse_supplemental_title($env{'docs.markedcopy_supplemental_'.$suffix}); + } + } else { + if ($folder=~/^supplemental/) { + $title=time.'___&&&___'.$env{'user.name'}.'___&&&___'. + $env{'user.domain'}.'___&&&___'.$title; + } + } + +# 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{$suffix}) { + my $newidx; +# Now insert the URL at the bottom + $newidx = &LONCAPA::map::getresidx(&LONCAPA::map::qtunescape($url)); + 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,$newdocsdir) = ($folder =~ /^(default|supplemental)_?(\d*)/); + my $newprefix = $newloc; + if ($newloc eq 'default') { + $newprefix = 'docs'; + } + if ($newdocsdir eq '') { + $newdocsdir = 'default'; + } + if (($prefixchg{$suffix}) || + ($srcdom{$suffix} ne $coursedom) || + ($srcnum{$suffix} ne $coursenum) || + ($env{'form.docs.markedcopy_options_'.$suffix} ne 'move')) { + my $newpath = "$newprefix/$newdocsdir/$newidx/$rem"; + $url = + &Apache::lonclonecourse::writefile($env{'request.course.id'},$newpath, + &Apache::lonnet::getfile($oldurl)); + if ($url eq '/adm/notfound.html') { + $msgs{$suffix} = &mt('Paste failed: an error occurred saving the file.'); + next; + } else { + my ($newsubpath) = ($newpath =~ m{^(.*/)[^/]*$}); + $newsubpath =~ s{/+$}{/}; + $docmoves{$oldurl} = $newsubpath; + } + } + } + } + $LONCAPA::map::resources[$newidx]=$title.':'.&LONCAPA::map::qtunescape($url). + ':'.$ext.':normal:res'; + push(@LONCAPA::map::order,$newidx); +# Store the result + my ($errtext,$fatal) = + &storemap($coursenum,$coursedom,$folder.'.'.$container,1); + if ($fatal) { + $save_err .= $errtext; + $allresult = 'fail'; + } + } + +# Apply any changes to maps, or copy dependencies for uploaded HTML pages + unless ($allresult eq 'fail') { + my %updated = ( + rewrites => \%rewrites, + zombies => \%zombies, + removefrommap => \%removefrommap, + removeparam => \%removeparam, + dbcopies => \%dbcopies, + retitles => \%retitles, + ); + my %info = ( + newsubdir => \%newsubdir, + params => \%params, + ); + if ($prefixchg{$suffix}) { + $info{'before'} = $before{$prefixchg{$suffix}}; + $info{'after'} = $after{$prefixchg{$suffix}}; + } + my %moves = ( + copies => \%copies, + docmoves => \%docmoves, + mapmoves => \%mapmoves, + ); + (my $result,$msgs{$suffix},my $lockerror) = + &apply_fixups($folder,$is_map{$suffix},$coursedom,$coursenum,$errors, + \%updated,\%info,\%moves,$prefixchg{$suffix},$oldurl, + $url,'paste'); + $lockerrors .= $lockerror; + if ($result eq 'ok') { + if ($is_map{$suffix}) { + my ($errtext,$fatal) = &mapread($coursenum,$coursedom, + $folder.'.'.$container); + if ($fatal) { + $allresult = 'failread'; + } else { + if ($#LONCAPA::map::order<1) { + my $idx=&LONCAPA::map::getresidx(); + if ($idx<=0) { $idx=1; } + $LONCAPA::map::order[0]=$idx; + $LONCAPA::map::resources[$idx]=''; + } + my $newidx = &LONCAPA::map::getresidx(&LONCAPA::map::qtunescape($url)); + $LONCAPA::map::resources[$newidx]=$title.':'.&LONCAPA::map::qtunescape($url). + ':'.$ext.':normal:res'; + push(@LONCAPA::map::order,$newidx); + +# Store the result + my ($errtext,$fatal) = + &storemap($coursenum,$coursedom,$folder.'.'.$container,1); + if ($fatal) { + $save_err .= $errtext; + $allresult = 'failstore'; + } + } + } + if ($env{'form.docs.markedcopy_options_'.$suffix} eq 'move') { + push(@toclear,$suffix); + } + } + } + } + &clear_from_buffer(\@toclear,\@currpaste); + my $msgsarray; + foreach my $suffix (keys(%msgs)) { + if (ref($msgs{$suffix}) eq 'ARRAY') { + $msgsarray .= join(',',@{$msgs{$suffix}}); + } + } + return ($allresult,$save_err,$msgsarray,$lockerrors); +} + +sub do_buffer_empty { + my @currpaste = split(/,/,$env{'docs.markedcopies'}); + if (@currpaste == 0) { + return &mt('Clipboard is already empty'); + } + my @toclear = &Apache::loncommon::get_env_multiple('form.pasting'); + if (@toclear == 0) { + return &mt('Nothing selected to clear from clipboard'); + } + my $numdel = &clear_from_buffer(\@toclear,\@currpaste); + if ($numdel) { + return &mt('[quant,_1,item] cleared from clipboard',$numdel); + } else { + return &mt('Clipboard unchanged'); + } + return; +} + +sub clear_from_buffer { + my ($toclear,$currpaste) = @_; + return unless ((ref($toclear) eq 'ARRAY') && (ref($currpaste) eq 'ARRAY')); + my %pastebuffer; + map { $pastebuffer{$_} = 1; } @{$currpaste}; + my $numdel = 0; + foreach my $suffix (@{$toclear}) { + next if ($suffix =~ /\D/); + next unless (exists($pastebuffer{$suffix})); + my $regexp = 'docs.markedcopy_[a-z]+_'.$suffix; + if (&Apache::lonnet::delenv($regexp,1) eq 'ok') { + delete($pastebuffer{$suffix}); + $numdel ++; + } + } + my $newbuffer = join(',',sort(keys(%pastebuffer))); + &Apache::lonnet::appenv({'docs.markedcopies' => $newbuffer}); + return $numdel; +} + +sub get_newmap_url { + my ($url,$folder,$prefixchg,$coursedom,$coursenum,$srcdom,$srcnum, + $titleref,$allmaps,$newurls) = @_; + my $newurl; + if ($url=~ m{^/uploaded/}) { + $$titleref=&mt('Copy of').' '.$$titleref; + } + my $now = time; + my $suffix=$$.int(rand(100)).$now; + my ($oldid,$ext) = ($url=~/^(.+)\.(\w+)$/); + 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); + } + my $newid; + if ($prefixchg) { + if ($folder =~ /^supplemental/) { + $prefix =~ s/^default/supplemental/; + } else { + $prefix =~ s/^supplemental/default/; } - $oldid = $path.$prefix.$ancestor; + } + if (($srcdom eq $coursedom) && ($srcnum eq $coursenum)) { + $newurl = $path.$prefix.$ancestor.$suffix.'.'.$ext; + } else { + $newurl = "/uploaded/$coursedom/$coursenum/$prefix".$now.'.'.$ext; } 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 ($folder =~ /^default/) { + if ($allmaps->{$newurl}) { + $is_unique = 0; + } } - if (!$is_unique) { - if ($url=~/\.page$/) { - return &mt('Paste failed: an error occurred creating a unique URL for the composite page'); + while ((!$is_unique || $allmaps->{$newurl} || $newurls->{$newurl}) && ($counter < 100)) { + $counter ++; + $suffix ++; + 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".$ancestor.$suffix.'.'.$ext; } + $is_unique = &uniqueness_check($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 ($is_unique) { + $newurls->{$newurl} = 1; + } else { if ($url=~/\.page$/) { - return &mt('Paste failed: an error occurred saving the composite page'); + return (undef,&mt('Paste failed: an error occurred creating a unique URL for the composite page')); } else { - return &mt('Paste failed: an error occurred saving the folder'); + return (undef,&mt('Paste failed: an error occurred creating a unique URL for the folder')); } } - $url = $newurl; } -# 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'); - } - 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; - $title=&mt('Copy of').' '.$title; - } - } - $title = &LONCAPA::map::qtunescape($title); - my $ext='false'; - if ($url=~m{^http(|s)://}) { $ext='true'; } - $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'}); - } - } else { - if ($folder=~/^supplemental/) { - $title=time.'___&&&___'.$env{'user.name'}.'___&&&___'. - $env{'user.domain'}.'___&&&___'.$title; + return ($newurl); +} + +sub dbcopy { + my ($dbref,$coursedom,$coursenum,$lockerrorsref) = @_; + my ($url,$result,$errtext); + $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 discussion 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 discussion boards in this course.'); + } + $lockerrorsref->{$prefix} .= ' '.&mt('Please contact the [_1]helpdesk[_2] for assistance.', + '',''). + '
    '; + } + } + } 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); + } + } } } - - $LONCAPA::map::resources[$newidx]= $title.':'.$url.':'.$ext.':normal:res'; - push(@LONCAPA::map::order, $newidx); - return 'ok'; -# Store the result + return ($url,$result,$errtext); } sub uniqueness_check { @@ -1540,6 +2065,519 @@ sub uniqueness_check { return $unique; } +sub contained_map_check { + my ($url,$folder,$removefrommap,$removeparam,$addedmaps,$hierarchy,$titles, + $allmaps) = @_; + 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'}} = $ressrc; + next; + } + } + if ($ressrc =~ m{^/(res|uploaded)/.+\.(sequence|page)$}) { + if ($1 eq 'uploaded') { + $hierarchy->{$url}{$token->[2]->{'id'}} = $ressrc; + $titles->{$url}{$token->[2]->{'id'}} = $token->[2]->{'title'}; + } else { + if ($allmaps->{$ressrc}) { + $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc; + } elsif (ref($addedmaps->{$ressrc}) eq 'ARRAY') { + $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc; + } else { + $addedmaps->{$ressrc} = [$url]; + } + } + &contained_map_check($ressrc,$folder,$removefrommap,$removeparam, + $addedmaps,$hierarchy,$titles,$allmaps); + } + } elsif ($token->[1] eq 'param') { + if ($folder =~ /^supplemental/) { + if (ref($removeparam->{$url}{$token->[2]->{'to'}}) eq 'ARRAY') { + push(@{$removeparam->{$url}{$token->[2]->{'to'}}},$token->[2]->{'name'}); + } else { + $removeparam->{$url}{$token->[2]->{'to'}} = [$token->[2]->{'name'}]; + } + } + } + } + } + return; +} + +sub url_paste_fixups { + 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})) { + $checktitle = 1; + } + my $skip; + if ($oldurl =~ m{^\Q/uploaded/$cdom/$cnum/\E(default|supplemental)(_?\d*)\.(?:page|sequence)$}) { + my $mapid = $1.$2; + if ($tomove->{$mapid}) { + $skip = 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'}; + my $title = $token->[2]->{'title'}; + if ($checktitle) { + if ($title =~ m{\d+\Q___&&&___\E$match_username\Q___&&&___\E$match_domain\Q___&&&___\E(.+)$}) { + $retitles->{$oldurl}{$id} = $ressrc; + } + } + next if ($token->[2]->{'type'} eq 'external'); + if ($token->[2]->{'type'} eq 'zombie') { + next if ($skip); + $zombies->{$oldurl}{$id} = $ressrc; + $changed = 1; + } elsif ($ressrc =~ m{^/uploaded/($match_domain)/($match_courseid)/(.+)$}) { + my $srcdom = $1; + my $srcnum = $2; + my $rem = $3; + my $newurl; + my $mapname; + if ($rem =~ /^(default|supplemental)(_?\d*).(sequence|page)$/) { + my $prefix = $1; + $mapname = $prefix.$2; + if ($tomove->{$mapname}) { + &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) = + &get_newmap_url($ressrc,$folder,$prefixchg,$cdom,$cnum, + $srcdom,$srcnum,\$title,$allmaps,$newurls); + if ($newurl =~ /(?:default|supplemental)_(\d+)\.(?:sequence|page)$/) { + $newsubdir->{$ressrc} = $1; + } + if ($error) { + next; + } + } + } + if (($srcdom ne $cdom) || ($srcnum ne $cnum) || ($prefixchg) || + ($mapchanges->{$oldurl}) || (($newurl ne '') && ($newurl ne $oldurl))) { + + if ($rem =~ /^(default|supplemental)(_?\d*).(sequence|page)$/) { + $rewrites->{$oldurl}{$id} = $ressrc; + $mapchanges->{$ressrc} = 1; + 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}{$id} = $ressrc; + $copies->{$oldurl}{$ressrc} = $id; + $changed = 1; + } + } + } 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}{$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)/(.+)$}) { + next if ($skip); + my $srcdom = $1; + my $srcnum = $2; + if (($srcdom ne $cdom) || ($srcnum ne $cnum)) { + $dbcopies->{$oldurl}{$id}{'src'} = $ressrc; + $dbcopies->{$oldurl}{$id}{'cdom'} = $srcdom; + $dbcopies->{$oldurl}{$id}{'cnum'} = $srcnum; + $changed = 1; + } + } + } elsif ($token->[1] eq 'param') { + next if ($skip); + 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 ($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,@msgs, + %lockerrors,$lockmsg); + if (ref($updated) eq 'HASH') { + if (ref($updated->{'rewrites'}) eq 'HASH') { + %rewrites = %{$updated->{'rewrites'}}; + } + if (ref($updated->{'zombies'}) eq 'HASH') { + %zombies = %{$updated->{'zombies'}}; + } + if (ref($updated->{'removefrommap'}) eq 'HASH') { + %removefrommap = %{$updated->{'removefrommap'}}; + } + if (ref($updated->{'removeparam'}) eq 'HASH') { + %removeparam = %{$updated->{'removeparam'}}; + } + if (ref($updated->{'dbcopies'}) eq 'HASH') { + %dbcopies = %{$updated->{'dbcopies'}}; + } + if (ref($updated->{'retitles'}) eq 'HASH') { + %retitles = %{$updated->{'retitles'}}; + } + } + if (ref($info) eq 'HASH') { + if (ref($info->{'newsubdir'}) eq 'HASH') { + %newsubdir = %{$info->{'newsubdir'}}; + } + if (ref($info->{'params'}) eq 'HASH') { + %params = %{$info->{'params'}}; + } + if (ref($info->{'before'}) eq 'HASH') { + %before = %{$info->{'before'}}; + } + if (ref($info->{'after'}) eq 'HASH') { + %after = %{$info->{'after'}}; + } + } + if (ref($moves) eq 'HASH') { + if (ref($moves->{'copies'}) eq 'HASH') { + %copies = %{$moves->{'copies'}}; + } + if (ref($moves->{'docmoves'}) eq 'HASH') { + %docmoves = %{$moves->{'docmoves'}}; + } + if (ref($moves->{'mapmoves'}) eq 'HASH') { + %mapmoves = %{$moves->{'mapmoves'}}; + } + } + foreach my $key (keys(%copies),keys(%docmoves)) { + my @allcopies; + if (exists($copies{$key})) { + 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,$oldsubdir,$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) && (exists($docmoves{$key}))) { + $storefn = $docmoves{$key}; + } else { + $storefn = $relpath; + $storefn =~s{^/uploaded/$match_domain/$match_courseid/}{}; + if ($prefixchg && $before{'doc'} && $after{'doc'}) { + $storefn =~ s/^\Q$before{'doc'}\E/$after{'doc'}/; + } + if ($newsubdir{$key}) { + $storefn =~ s#^(docs|supplemental)/\Q$oldsubdir\E/#$1/$newsubdir{$key}/#; + } + } + ©_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 (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 && $before{'map'} && $after{'map'}) { + $storefn =~ s/^\Q$before{'map'}\E/$after{'map'}/; + } + if ($newsubdir{$key}) { + $storefn =~ s/^((?:default|supplemental)_)(\d+)/$1$newsubdir{$key}/; + } + 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) { + if (ref($updated) eq 'HASH') { + foreach my $type (keys(%{$updated})) { + if (ref($updated->{$type}) eq 'HASH') { + foreach my $key (keys(%{$updated->{$type}})) { + $updates{$key} = 1; + } + } + } + } + foreach my $key (keys(%updates)) { + my (%torewrite,%toretitle,%toremove,%remparam,%currparam,%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($removeparam{$key}) eq 'HASH') { + %remparam = %{$removeparam{$key}}; + } + if (ref($zombies{$key}) eq 'HASH') { + %zombie = %{$zombies{$key}}; + } + if (ref($dbcopies{$key}) eq 'HASH') { + 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') { + %currparam = %{$params{$key}}; + } + my ($errtext,$fatal) = &LONCAPA::map::mapread($key); + if ($fatal) { + 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{$i} eq $src) { + undef($LONCAPA::map::zombies[$i]); + } + } + } + for (my $i=0; $i<@LONCAPA::map::order; $i++) { + my $idx = $LONCAPA::map::order[$i]; + if (defined($LONCAPA::map::resources[$idx])) { + my $changed; + my ($title,$src,$ext,$type)=split(/\:/,$LONCAPA::map::resources[$idx]); + if ((exists($toremove{$idx})) && + ($toremove{$idx} eq &LONCAPA::map::qtescape($src))) { + splice(@LONCAPA::map::order,$i,1); + if (ref($currparam{$idx}) eq 'ARRAY') { + foreach my $name (@{$currparam{$idx}}) { + &LONCAPA::map::delparameter($idx,'parameter_'.$name); + } + } + next; + } + my $origsrc = $src; + 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{$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'}) { + 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 ($origsrc =~ /\.(page|sequence)$/) { + if ($newsubdir{$origsrc}) { + $src =~ s#^(/uploaded/$match_domain/$match_courseid/(?:default|supplemental)_)(\d+)#$1$newsubdir{$origsrc}#; + } + } elsif ($newsubdir{$key}) { + $src =~ s#^(/uploaded/$match_domain/$match_courseid/\w+/)(\d+)#$1$newsubdir{$key}#; + } + } + $changed = 1; + } elsif ($newdb{$idx} ne '') { + $src = $newdb{$idx}; + $changed = 1; + } + if ($changed) { + $LONCAPA::map::resources[$idx] = join(':',($title,&LONCAPA::map::qtunescape($src),$ext,$type)); + } + } + } + foreach my $idx (keys(%remparam)) { + if (ref($remparam{$idx}) eq 'ARRAY') { + foreach my $name (@{$remparam{$idx}}) { + &LONCAPA::map::delparameter($idx,'parameter_'.$name); + } + } + } + if (values(%lockerrors) > 0) { + $lockmsg = join('
    ',values(%lockerrors)); + } + 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 && $before{'map'} && $after{'map'}) { + $storefn =~ s/^\Q$before{'map'}\E/$after{'map'}/; + } + if ($newsubdir{$key}) { + $storefn =~ s/^((?:default|supplemental)_)(\d+)/$1$newsubdir{$key}/; + } + } + my $report; + if ($folder !~ /^supplemental/) { + $report = 1; + } + (my $outtext,$errtext) = + &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 ('ok',\@msgs,$lockmsg); +} + +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', @@ -1547,37 +2585,130 @@ 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 { + if ($env{'form.all'.$which}) { + 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); + my $haschanges = 0; + return $haschanges if ($env{'form.changeparms'} !~ /^($valid_parameters_re)$/); - &remember_parms($idx,$which,'del'); + my $which = $env{'form.changeparms'}; + my $idx = $env{'form.setparms'}; + my $oldvalue = 0; + my $newvalue = 0; + my $current = (&LONCAPA::map::getparameter($idx,'parameter_'.$which))[0]; + if ($which eq 'randompick') { + if ($current =~ /^(\d+)$/) { + $oldvalue = $1; + } + } elsif ($current =~ /^yes$/i) { + $oldvalue = 1; + } + if ($env{'form.'.$which.'_'.$idx}) { + $newvalue = ($which eq 'randompick') ? $env{'form.rpicknum_'.$idx} + : 1; + } + if ($oldvalue ne $newvalue) { + $haschanges = 1; + if ($newvalue) { + my $storeval = 'yes'; + if ($which eq 'randompick') { + $storeval = $newvalue; + } + &LONCAPA::map::storeparameter($idx, 'parameter_'.$which, $storeval, + $parameter_type{$which}); + &remember_parms($idx,$which,'set',$storeval); + } else { + &LONCAPA::map::delparameter($idx,'parameter_'.$which); + &remember_parms($idx,$which,'del'); + } + } + return $haschanges; } - return 1; + return; } - sub handle_edit_cmd { my ($coursenum,$coursedom) =@_; - + if ($env{'form.cmd'} eq '') { + return 0; + } my ($cmd,$idx)=split('_',$env{'form.cmd'}); my $ratstr = $LONCAPA::map::resources[$LONCAPA::map::order[$idx]]; my ($title, $url, @rrest) = split(':', $ratstr); - if ($cmd eq 'del') { + if ($cmd eq 'remove') { if (($url=~m|/+uploaded/\Q$coursedom\E/\Q$coursenum\E/|) && - ($url!~/\.(page|sequence|problem|exam|quiz|assess|survey|form|library|task)$/)) { + ($url!~/$LONCAPA::assess_page_seq_re/)) { &Apache::lonnet::removeuploadedurl($url); } else { &LONCAPA::map::makezombie($LONCAPA::map::order[$idx]); @@ -1597,7 +2728,6 @@ sub handle_edit_cmd { @LONCAPA::map::order[$idx+1,$idx] = @LONCAPA::map::order[$idx,$idx+1]; } elsif ($cmd eq 'rename') { - my $comment = &LONCAPA::map::qtunescape($env{'form.title'}); if ($comment=~/\S/) { $LONCAPA::map::resources[$LONCAPA::map::order[$idx]]= @@ -1606,6 +2736,7 @@ sub handle_edit_cmd { # Devalidate title cache my $renamed_url=&LONCAPA::map::qtescape($url); &Apache::lonnet::devalidate_title_cache($renamed_url); + } else { return 0; } @@ -1614,13 +2745,45 @@ sub handle_edit_cmd { sub editor { my ($r,$coursenum,$coursedom,$folder,$allowed,$upload_output,$crstype, - $supplementalflag,$orderhash)=@_; - my $container= ($env{'form.pagepath'}) ? 'page' - : 'sequence'; + $supplementalflag,$orderhash,$iconpath,$pathitem,$canedit,$navmapref, + $hiddentop)=@_; + my ($randompick,$ishidden,$isencrypted,$plain,$is_random_order,$container); + if ($allowed) { + (my $breadcrumbtrail,$randompick,$ishidden,$isencrypted,$plain, + $is_random_order,$container) = + &Apache::lonhtmlcommon::docs_breadcrumbs($allowed,$crstype,1); + $r->print($breadcrumbtrail); + } elsif ($env{'form.folderpath'} =~ /\:1$/) { + $container = 'page'; + } else { + $container = 'sequence'; + } - my ($errtext,$fatal) = &mapread($coursenum,$coursedom, - $folder.'.'.$container); - return $errtext if ($fatal); + my $jumpto; + + unless ($supplementalflag) { + $jumpto = "uploaded/$coursedom/$coursenum/$folder.$container"; + } + + unless ($allowed) { + $randompick = -1; + } + + my ($errtext,$fatal); + if (($folder eq '') && (!$supplementalflag)) { + if (@LONCAPA::map::order) { + undef(@LONCAPA::map::order); + undef(@LONCAPA::map::resources); + undef(@LONCAPA::map::resparms); + undef(@LONCAPA::map::zombies); + } + $folder = 'default'; + $container = 'sequence'; + } else { + ($errtext,$fatal) = &mapread($coursenum,$coursedom, + $folder.'.'.$container); + return $errtext if ($fatal); + } if ($#LONCAPA::map::order<1) { my $idx=&LONCAPA::map::getresidx(); @@ -1629,23 +2792,15 @@ sub editor { $LONCAPA::map::resources[$idx]=''; } - my ($breadcrumbtrail,$randompick,$ishidden,$isencrypted,$plain,$is_random_order) = - &breadcrumbs($allowed,$crstype); - $r->print($breadcrumbtrail); - - unless ($allowed) { - $randompick = -1; - } - # ------------------------------------------------------------ Process commands # ---------------- if they are for this folder and user allowed to make changes - if (($allowed) && ($env{'form.folder'} eq $folder)) { + if (($allowed && $canedit) && ($env{'form.folder'} eq $folder)) { # set parameters and change order &snapshotbefore(); if (&update_parameter()) { - ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container); + ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container,1); return $errtext if ($fatal); } @@ -1659,35 +2814,176 @@ sub editor { } if ($env{'form.pastemarked'}) { - my $paste_res = - &do_paste_from_buffer($coursenum,$coursedom,$folder); - if ($paste_res eq 'ok') { - ($errtext,$fatal) = &storemap($coursenum,$coursedom,$folder.'.'.$container); - return $errtext if ($fatal); - } elsif ($paste_res ne '') { - $r->print('

    '.$paste_res.'

    '); + my %paste_errors; + 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; + } + if ($paste_res) { + my %errortext = &Apache::lonlocal::texthash ( + fail => 'Storage of folder contents failed', + failread => 'Reading folder contents failed', + failstore => 'Storage of folder contents failed', + ); + if ($errortext{$paste_res}) { + $r->print('

    '.$errortext{$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"); + } + } elsif ($env{'form.clearmarked'}) { + my $output = &do_buffer_empty(); + if ($output) { + $r->print('

    '.$output.'

    '); + } + } $r->print($upload_output); - if (&handle_edit_cmd()) { - ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container); +# Rename, cut, copy or remove a single resource + if (&handle_edit_cmd($coursenum,$coursedom)) { + my $contentchg; + if ($env{'form.cmd'} =~ m{^(remove|cut)_}) { + $contentchg = 1; + } + ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container,$contentchg); return $errtext if ($fatal); } + +# Cut, copy and/or remove multiple resources + if ($env{'form.multichange'}) { + my %allchecked = ( + cut => {}, + remove => {}, + ); + my $needsupdate; + foreach my $which (keys(%allchecked)) { + $env{'form.multi'.$which} =~ s/,$//; + if ($env{'form.multi'.$which}) { + map { $allchecked{$which}{$_} = 1; } split(/,/,$env{'form.multi'.$which}); + if (ref($allchecked{$which}) eq 'HASH') { + $needsupdate += scalar(keys(%{$allchecked{$which}})); + } + } + } + if ($needsupdate) { + my $haschanges = 0; + my %curr_groups = &Apache::longroup::coursegroups(); + my $total = scalar(@LONCAPA::map::order) - 1; + for (my $i=$total; $i>=0; $i--) { + my $res = $LONCAPA::map::order[$i]; + my ($name,$url)=split(/\:/,$LONCAPA::map::resources[$res]); + $name=&LONCAPA::map::qtescape($name); + $url=&LONCAPA::map::qtescape($url); + next unless $url; + my %denied = + &action_restrictions($coursenum,$coursedom,$url, + $env{'form.folderpath'},\%curr_groups); + foreach my $which (keys(%allchecked)) { + next if ($denied{$which}); + next unless ($allchecked{$which}{$res}); + if ($which eq 'remove') { + if (($url=~m|/+uploaded/\Q$coursedom\E/\Q$coursenum\E/|) && + ($url!~/$LONCAPA::assess_page_seq_re/)) { + &Apache::lonnet::removeuploadedurl($url); + } else { + &LONCAPA::map::makezombie($res); + } + splice(@LONCAPA::map::order,$i,1); + $haschanges ++; + } elsif ($which eq 'cut') { + &LONCAPA::map::makezombie($res); + splice(@LONCAPA::map::order,$i,1); + $haschanges ++; + } + } + } + if ($haschanges) { + ($errtext,$fatal) = + &storemap($coursenum,$coursedom,$folder.'.'.$container,1); + return $errtext if ($fatal); + } + } + } + # Group import/search if ($env{'form.importdetail'}) { my @imports; foreach my $item (split(/\&/,$env{'form.importdetail'})) { if (defined($item)) { my ($name,$url,$residx)= - map {&unescape($_)} split(/\=/,$item); + map { &unescape($_); } split(/\=/,$item); + if ($url =~ m{^\Q/uploaded/$coursedom/$coursenum/\E(default|supplemental)_new\.(sequence|page)$}) { + my ($suffix,$errortxt,$locknotfreed) = + &new_timebased_suffix($coursedom,$coursenum,'map',$1,$2); + if ($locknotfreed) { + $r->print($locknotfreed); + } + if ($suffix) { + $url =~ s/_new\./_$suffix./; + } 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]); } } - ($errtext,$fatal)=&group_import($coursenum, $coursedom, $folder, - $container,'londocs',@imports); + ($errtext,$fatal,my $fixuperrors) = + &group_import($coursenum, $coursedom, $folder,$container, + 'londocs',@imports); return $errtext if ($fatal); + if ($fixuperrors) { + $r->print($fixuperrors); + } } # Loading a complete map if ($env{'form.loadmap'}) { @@ -1699,7 +2995,7 @@ sub editor { $LONCAPA::map::order[$#LONCAPA::map::order+1]=$idx; } ($errtext,$fatal)=&storemap($coursenum,$coursedom, - $folder.'.'.$container); + $folder.'.'.$container,1); return $errtext if ($fatal); } else { $r->print('

    '.&mt('No map selected.').'

    '); @@ -1743,8 +3039,17 @@ sub editor { $r->print(''); } - my ($to_show,$output); - + my ($to_show,$output,@allidx,@allmapidx,%filters,%lists,%curr_groups); + %filters = ( + canremove => [], + cancut => [], + cancopy => [], + hiddenresource => [], + encrypturl => [], + randomorder => [], + randompick => [], + ); + %curr_groups = &Apache::longroup::coursegroups(); &Apache::loncommon::start_data_table_count(); #setup a row counter foreach my $res (@LONCAPA::map::order) { my ($name,$url)=split(/\:/,$LONCAPA::map::resources[$res]); @@ -1752,53 +3057,235 @@ 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,$crstype); + $coursenum,$coursedom,$crstype, + $pathitem,$supplementalflag,$container, + \%filters,\%curr_groups,$canedit,$isencrypted,$navmapref); $idx++; $shown++; } &Apache::loncommon::end_data_table_count(); - - if ($shown) { - $to_show = &Apache::loncommon::start_scrollbox('900px','880px','400px','contentscroll') - .&Apache::loncommon::start_data_table(undef,'contentlist'); + + my $need_save; + if ($allowed || ($supplementalflag && $folder eq 'supplemental')) { + my $toolslink; if ($allowed) { - $to_show .= &Apache::loncommon::start_data_table_header_row() - .''.&mt('Move').'' - .''.&mt('Actions').'' - .''.&mt('Document').''; - if ($folder !~ /^supplemental/) { - $to_show .= ''.&mt('Settings').''; + $toolslink = '' + .'
    ' + .&Apache::loncommon::help_open_menu('Navigation Screen', + 'Navigation_Screen',undef,'RAT') + .''.&mt('Tools:').'

    '; + } + if ($shown) { + if ($allowed) { + $to_show = &Apache::loncommon::start_scrollbox('900px','880px','400px','contentscroll') + .&Apache::loncommon::start_data_table(undef,'contentlist') + .&Apache::loncommon::start_data_table_header_row() + .''.&mt('Move').'' + .''.&mt('Actions').'' + .''.&mt('Document').''; + if ($folder !~ /^supplemental/) { + $to_show .= ''.&mt('Settings').''; + } + $to_show .= &Apache::loncommon::end_data_table_header_row(); + if ($folder !~ /^supplemental/) { + $lists{'canhide'} = join(',',@allidx); + $lists{'canrandomlyorder'} = join(',',@allmapidx); + my @possfilters = ('canremove','cancut','cancopy','hiddenresource','encrypturl', + 'randomorder','randompick'); + foreach my $item (@possfilters) { + if (ref($filters{$item}) eq 'ARRAY') { + if (@{$filters{$item}} > 0) { + $lists{$item} = join(',',@{$filters{$item}}); + } + } + } + if (@allidx > 0) { + my $path; + if ($env{'form.folderpath'}) { + $path = + &HTML::Entities::encode($env{'form.folderpath'},'<>&"'); + } + if (@allidx > 1) { + $to_show .= + &Apache::loncommon::continue_data_table_row(). + ' '. + ''. + &multiple_check_form('actions',\%lists,$canedit). + ''. + ' '. + ' '. + ''. + &multiple_check_form('settings',\%lists,$canedit). + ''. + &Apache::loncommon::end_data_table_row(); + $need_save = 1; + } + } + } + $to_show .= $output.' ' + .&Apache::loncommon::end_data_table() + .'
    ' + .&Apache::loncommon::end_scrollbox(); + } else { + $to_show .= $toolslink + .&Apache::loncommon::start_data_table('LC_tableOfContent') + .$output.' ' + .&Apache::loncommon::end_data_table(); + } + } else { + if (!$allowed) { + $to_show .= $toolslink; + } + my $noresmsg; + if ($allowed && $hiddentop && !$supplementalflag) { + $noresmsg = &mt('Main Content Hidden'); + } else { + $noresmsg = &mt('Currently empty'); } - $to_show .= &Apache::loncommon::end_data_table_header_row(); + $to_show .= &Apache::loncommon::start_scrollbox('400px','380px','200px','contentscroll') + .'
    ' + .$noresmsg + .'
    ' + .&Apache::loncommon::end_scrollbox(); } - $to_show .= $output.' ' - .&Apache::loncommon::end_data_table() - .'
    ' - .&Apache::loncommon::end_scrollbox(); } else { - $to_show .= &Apache::loncommon::start_scrollbox('400px','380px','200px','contentscroll') - .'
    ' - .&mt('Currently no documents.') - .'
    ' - .&Apache::loncommon::end_scrollbox(); + if ($shown) { + $to_show = '
    ' + .&Apache::loncommon::start_data_table('LC_tableOfContent') + .$output + .&Apache::loncommon::end_data_table() + .'
    '; + } else { + $to_show = '
    ' + .&mt('Currently empty') + .'
    ' + } } my $tid = 1; if ($supplementalflag) { $tid = 2; } if ($allowed) { - $r->print(&generate_edit_table($tid,$orderhash,$to_show)); - &print_paste_buffer($r,$container); + my $readfile="/uploaded/$coursedom/$coursenum/$folder.$container"; + $r->print(&generate_edit_table($tid,$orderhash,$to_show,$iconpath, + $jumpto,$readfile,$need_save,"$folder.$container",$canedit)); + if ($canedit) { + &print_paste_buffer($r,$container,$folder,$coursedom,$coursenum); + } } else { $r->print($to_show); } return; } +sub multiple_check_form { + my ($caller,$listsref,$canedit) = @_; + return unless (ref($listsref) eq 'HASH'); + my $disabled; + unless ($canedit) { + $disabled = 'disabled="disabled"'; + } + my $output = + '
    '. + ''. + ''.(' 'x2).'
    '. + ''; + return $output; +} + sub process_file_upload { - my ($upload_output,$coursenum,$coursedom,$allfiles,$codebase,$uploadcmd) = @_; + my ($upload_output,$coursenum,$coursedom,$allfiles,$codebase,$uploadcmd,$crstype) = @_; # upload a file, if present + my $filesize = length($env{'form.uploaddoc'}); + if (!$filesize) { + $$upload_output = '
    '. + &mt('Unable to upload [_1]. (size = [_2] bytes)', + ''.$env{'form.uploaddoc.filename'}.'', + $filesize).'
    '. + &mt('Either the file you attempted to upload was empty, or your web browser was unable to read its contents.').'
    '. + '
    '; + return; + } + my $quotatype = 'unofficial'; + if ($crstype eq 'Community') { + $quotatype = 'community'; + } elsif ($env{'course.'.$coursedom.'_'.$coursenum.'.internal.coursecode'}) { + $quotatype = 'official'; + } elsif ($env{'course.'.$coursedom.'_'.$coursenum.'.internal.textbook'}) { + $quotatype = 'textbook'; + } + if (&Apache::loncommon::get_user_quota($coursenum,$coursedom,'course',$quotatype)) { + $filesize = int($filesize/1000); #expressed in kb + $$upload_output = &Apache::loncommon::excess_filesize_warning($coursenum,$coursedom,'course', + $env{'form.uploaddoc.filename'},$filesize, + 'upload',$quotatype); + return if ($$upload_output); + } my ($parseaction,$showupload,$nextphase,$mimetype); if ($env{'form.parserflag'}) { $parseaction = 'parse'; @@ -1811,19 +3298,15 @@ sub process_file_upload { my $errtext=''; my $fatal=0; my $container='sequence'; - if ($env{'form.pagepath'}) { + if ($env{'form.folderpath'} =~ /:1$/) { $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/'; @@ -1833,6 +3316,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; @@ -1864,7 +3351,7 @@ sub process_file_upload { $comment.':'.$url.':'.$ext.':normal:res'; $LONCAPA::map::order[$#LONCAPA::map::order+1]= $newidx; ($errtext,$fatal)=&storemap($coursenum,$coursedom, - $folder.'.'.$container); + $folder.'.'.$container,1); if ($fatal) { $$upload_output = '
    '.$errtext.'
    '; return; @@ -1894,84 +3381,140 @@ sub process_file_upload { $$upload_output .= &mt('No embedded items identified').'
    '; } $$upload_output = '
    '.$$upload_output.'
    '; + } elsif ((&Apache::loncommon::is_archive_file($mimetype)) && + ($env{'form.uploaddoc.filename'} =~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/i)) { + $nextphase = 'decompress_uploaded'; + my $position = scalar(@LONCAPA::map::order)-1; + my $noextract = &return_to_editor(); + my $archiveurl = &HTML::Entities::encode($url,'<>&"'); + my %archiveitems = ( + folderpath => $env{'form.folderpath'}, + cmd => $nextphase, + newidx => $newidx, + position => $position, + phase => $nextphase, + comment => $comment, + ); + my ($destination,$dir_root) = &embedded_destination($coursenum,$coursedom); + my @current = &get_dir_list($url,$coursenum,$coursedom,$newidx); + $$upload_output = $showupload. + &Apache::loncommon::decompress_form($mimetype, + $archiveurl,'/adm/coursedocs',$noextract, + \%archiveitems,\@current); } } } return $nextphase; } -sub is_supplemental_title { - my ($title) = @_; - return scalar($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/); +sub get_dir_list { + my ($url,$coursenum,$coursedom,$newidx) = @_; + my ($destination,$dir_root) = &embedded_destination(); + my ($dirlistref,$listerror) = + &Apache::lonnet::dirlist("$dir_root/$destination/$newidx",$coursedom,$coursenum,1); + my @dir_lines; + my $dirptr=16384; + if (ref($dirlistref) eq 'ARRAY') { + foreach my $dir_line (sort + { + my ($afile)=split('&',$a,2); + my ($bfile)=split('&',$b,2); + return (lc($afile) cmp lc($bfile)); + } (@{$dirlistref})) { + my ($filename,$dom,undef,$testdir,undef,undef,undef,undef,$size,undef,$mtime,undef,undef,undef,$obs,undef)=split(/\&/,$dir_line,16); + $filename =~ s/\s+$//; + next if ($filename =~ /^\.\.?$/); + my $isdir = 0; + if ($dirptr&$testdir) { + $isdir = 1; + } + push(@dir_lines, [$filename,$dom,$isdir,$size,$mtime,$obs]); + } + } + return @dir_lines; } -sub parse_supplemental_title { +sub is_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; + return scalar($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/); } # --------------------------------------------------------------- An entry line sub entryline { - my ($index,$title,$url,$folder,$allowed,$residx,$coursenum,$crstype)=@_; - my ($foldertitle,$pagetitle,$renametitle); + my ($index,$title,$url,$folder,$allowed,$residx,$coursenum,$coursedom, + $crstype,$pathitem,$supplementalflag,$container,$filtersref,$currgroups, + $canedit,$isencrypted,$navmapref)=@_; + my ($foldertitle,$renametitle,$oldtitle); if (&is_supplemental_title($title)) { - ($title,$foldertitle,$renametitle) = &parse_supplemental_title($title); - $pagetitle = $foldertitle; + ($title,$foldertitle,$renametitle) = &Apache::loncommon::parse_supplemental_title($title); } else { $title=&HTML::Entities::encode($title,'"<>&\''); $renametitle=$title; $foldertitle=$title; - $pagetitle=$title; } - my $orderidx=$LONCAPA::map::order[$index]; + my ($disabled,$readonly,$js_lt); + unless ($canedit) { + $disabled = 'disabled="disabled"'; + $readonly = 1; + } + my $orderidx=$LONCAPA::map::order[$index]; $renametitle=~s/\\/\\\\/g; $renametitle=~s/\"\;/\\\"/g; + $renametitle=~s/"/%22/g; $renametitle=~s/ /%20/g; + $oldtitle = $renametitle; + $renametitle=~s/\'\;/\\\'/g; my $line=&Apache::loncommon::start_data_table_row(); - my ($form_start,$form_end); + my ($form_start,$form_end,$form_common,$form_param); # Edit commands - my ($container, $type, $esc_path, $path, $symb); + my ($esc_path, $path, $symb); if ($env{'form.folderpath'}) { - $type = 'folder'; - $container = 'sequence'; $esc_path=&escape($env{'form.folderpath'}); $path = &HTML::Entities::encode($env{'form.folderpath'},'<>&"'); # $htmlfoldername=&HTML::Entities::encode($env{'form.foldername'},'<>&"'); } - if ($env{'form.pagepath'}) { - $type = $container = 'page'; - $esc_path=&escape($env{'form.pagepath'}); - $path = &HTML::Entities::encode($env{'form.pagepath'},'<>&"'); - $symb=&escape($env{'form.pagesymb'}); + my $isexternal; + if ($residx) { + my $currurl = $url; + $currurl =~ s{^http(|s)(:|:)//}{/adm/wrapper/ext/}; + if ($currurl =~ m{^/adm/wrapper/ext/}) { + $isexternal = 1; + } + if (!$supplementalflag) { + my $path = 'uploaded/'. + $env{'course.'.$env{'request.course.id'}.'.domain'}.'/'. + $env{'course.'.$env{'request.course.id'}.'.num'}.'/'; + $symb = &Apache::lonnet::encode_symb($path.$folder.".$container", + $residx, + &Apache::lonnet::declutter($currurl)); + } + } + my ($renamelink,%lt,$ishash); + if (ref($filtersref) eq 'HASH') { + $ishash = 1; } - my $cpinfo=''; + if ($allowed) { + $form_start = ' +
    +'; + $form_common=(< + +END + $form_param=(< + +END + $form_end = ''; + my $incindex=$index+1; my $selectbox=''; - if (($folder!~/^supplemental/) && - ($#LONCAPA::map::order>0) && + if (($#LONCAPA::map::order>0) && ((split(/\:/, $LONCAPA::map::resources[$LONCAPA::map::order[0]]))[1] ne '') && @@ -1980,7 +3523,7 @@ sub entryline { ne '')) { $selectbox= ''. - ''; for (my $i=1;$i<=$#LONCAPA::map::order+1;$i++) { if ($i==$incindex) { $selectbox.=''; @@ -1990,249 +3533,585 @@ sub entryline { } $selectbox.=''; } - my %lt=&Apache::lonlocal::texthash( + %lt=&Apache::lonlocal::texthash( 'up' => 'Move Up', 'dw' => 'Move Down', 'rm' => 'Remove', 'ct' => 'Cut', 'rn' => 'Rename', - 'cp' => 'Copy'); - my $nocopy=0; - my $nocut=0; - if ($url=~/\.(page|sequence)$/) { - if ($url =~ m{/res/}) { - # no copy for published maps - $nocopy = 1; - } else { - foreach my $item (&Apache::lonsequence::attemptread(&Apache::lonnet::filelocation('',$url),1)) { - my ($title,$url,$ext,$type)=split(/\:/,$item); - if (($url=~/\.(page|sequence)/) && ($type ne 'zombie')) { - $nocopy=1; - last; - } - } - } - } - if ($url=~/^\/res\/lib\/templates\//) { - $nocopy=1; - $nocut=1; - } - my $copylink=' '; - my $cutlink=' '; - + 'cp' => 'Copy', + 'ex' => 'External Resource', + 'ed' => 'Edit', + 'pr' => 'Preview', + 'sv' => 'Save', + 'ul' => 'URL', + 'ti' => 'Title', + 'er' => 'Editing rights unavailable for your current role.', + ); + my %denied = &action_restrictions($coursenum,$coursedom,$url, + $env{'form.folderpath'}, + $currgroups); + my ($copylink,$cutlink,$removelink); my $skip_confirm = 0; + my $confirm_removal = 0; if ( $folder =~ /^supplemental/ || ($url =~ m{( /smppg$ |/syllabus$ |/aboutme$ |/navmaps$ |/bulletinboard$ - |\.html$ - |^/adm/wrapper/ext)}x)) { + |\.html$)}x) + || $isexternal) { $skip_confirm = 1; } + if (($url=~m|/+uploaded/\Q$coursedom\E/\Q$coursenum\E/|) && + ($url!~/$LONCAPA::assess_page_seq_re/)) { + $confirm_removal = 1; + } - if (!$nocopy) { + if ($denied{'copy'}) { + $copylink=(<$lt{'cp'} +ENDCOPY + } else { + my $formname = 'edit_copy_'.$orderidx; + my $js = "javascript:checkForSubmit(document.forms.renameform,'copy','actions','$orderidx','$esc_path','$index','$renametitle',$skip_confirm,'$container','$folder');"; $copylink=(<$lt{'cp'} +
    +$form_common +$lt{'cp'} +$form_end ENDCOPY + if (($ishash) && (ref($filtersref->{'cancopy'}) eq 'ARRAY')) { + push(@{$filtersref->{'cancopy'}},$orderidx); + } } - if (!$nocut) { + if ($denied{'cut'}) { + $cutlink=(<$lt{'ct'} +ENDCUT + } else { + my $formname = 'edit_cut_'.$orderidx; + my $js = "javascript:checkForSubmit(document.forms.renameform,'cut','actions','$orderidx','$esc_path','$index','$renametitle',$skip_confirm,'$container','$folder');"; $cutlink=(<$lt{'ct'} + +$form_common + +$lt{'ct'} +$form_end ENDCUT + if (($ishash) && (ref($filtersref->{'cancut'}) eq 'ARRAY')) { + push(@{$filtersref->{'cancut'}},$orderidx); + } + } + if ($denied{'remove'}) { + $removelink=(<$lt{'rm'} +ENDREM + } else { + my $formname = 'edit_remove_'.$orderidx; + my $js = "javascript:checkForSubmit(document.forms.renameform,'remove','actions','$orderidx','$esc_path','$index','$renametitle',$skip_confirm,'$container','$folder',$confirm_removal);"; + $removelink=(< +$form_common + + +$lt{'rm'} +$form_end +ENDREM + if (($ishash) && (ref($filtersref->{'canremove'}) eq 'ARRAY')) { + push(@{$filtersref->{'canremove'}},$orderidx); + } + } + $renamelink=(<$lt{'rn'} +ENDREN + my ($uplink,$downlink); + if ($canedit) { + $uplink = "/adm/coursedocs?cmd=up_$index&folderpath=$esc_path&symb=$symb"; + $downlink = "/adm/coursedocs?cmd=down_$index&folderpath=$esc_path&symb=$symb"; + } else { + $uplink = "javascript:alert('".&js_escape($lt{'er'})."');"; + $downlink = $uplink; } - $form_start = (< - - - - -END - $form_end = ''; $line.=(<
    - - $lt{ + + $lt{'up'}
    - - $lt{ + + $lt{'dw'}
    $form_start + $form_param + $form_common $selectbox $form_end - - $lt{'rm'} + +$removelink $cutlink - $lt{'rn'} $copylink END - } # Figure out what kind of a resource this is my ($extension)=($url=~/\.(\w+)$/); my $uploaded=($url=~/^\/*uploaded\//); my $icon=&Apache::loncommon::icon($url); - my $isfolder=0; - my $ispage=0; - my $folderarg; - my $pagearg; - my $pagefile; + my $isfolder; + my $ispage; + my $containerarg; + my $folderurl; if ($uploaded) { - if ($extension eq 'sequence') { - $icon=$iconpath.'/navmap.folder.closed.gif'; - $url=~/\Q$coursenum\E\/([\/\w]+)\.sequence$/; - $url='/adm/coursedocs?'; - $folderarg=$1; - $isfolder=1; - } elsif ($extension eq 'page') { - $icon=$iconpath.'/page.gif'; - $url=~/\Q$coursenum\E\/([\/\w]+)\.page$/; - $pagearg=$1; - $url='/adm/coursedocs?'; - $ispage=1; + if (($extension eq 'sequence') || ($extension eq 'page')) { + $url=~/\Q$coursenum\E\/([\/\w]+)\.\Q$extension\E$/; + $containerarg = $1; + if ($extension eq 'sequence') { + $icon=$iconpath.'navmap.folder.closed.gif'; + $isfolder=1; + } else { + $icon=$iconpath.'page.gif'; + $ispage=1; + } + $folderurl = &Apache::lonnet::declutter($url); + if ($allowed) { + $url='/adm/coursedocs?'; + } else { + $url='/adm/supplemental?'; + } } else { &Apache::lonnet::allowuploaded('/adm/coursedoc',$url); } } + my ($editlink,$extresform,$anchor,$hiddenres); my $orig_url = $url; $orig_url=~s{http(:|:)//https(:|:)//}{https$2//}; - my $external = ($url=~s{^http(|s)(:|:)//}{/adm/wrapper/ext/}); - if ((!$isfolder) && ($residx) && ($folder!~/supplemental/) && (!$ispage)) { - my $symb=&Apache::lonnet::symbclean( - &Apache::lonnet::declutter('uploaded/'. - $env{'course.'.$env{'request.course.id'}.'.domain'}.'/'. - $env{'course.'.$env{'request.course.id'}.'.num'}.'/'.$folder. - '.sequence'). - '___'.$residx.'___'. - &Apache::lonnet::declutter($url)); - (undef,undef,$url)=&Apache::lonnet::decode_symb($symb); - $url=&Apache::lonnet::clutter($url); - if ($url=~/^\/*uploaded\//) { - $url=~/\.(\w+)$/; - my $embstyle=&Apache::loncommon::fileembstyle($1); - if (($embstyle eq 'img') || ($embstyle eq 'emb')) { - $url='/adm/wrapper'.$url; - } elsif ($embstyle eq 'ssi') { - #do nothing with these - } elsif ($url!~/\.(sequence|page)$/) { - $url='/adm/coursedocs/showdoc'.$url; + $url=~s{^http(|s)(:|:)//}{/adm/wrapper/ext/}; + if (!$supplementalflag && $residx && $symb) { + if ((!$isfolder) && (!$ispage)) { + (undef,undef,$url)=&Apache::lonnet::decode_symb($symb); + $url=&Apache::lonnet::clutter($url); + if ($url=~/^\/*uploaded\//) { + $url=~/\.(\w+)$/; + my $embstyle=&Apache::loncommon::fileembstyle($1); + if (($embstyle eq 'img') || ($embstyle eq 'emb')) { + $url='/adm/wrapper'.$url; + } elsif ($embstyle eq 'ssi') { + #do nothing with these + } elsif ($url!~/\.(sequence|page)$/) { + $url='/adm/coursedocs/showdoc'.$url; + } + } elsif ($url=~m|^/ext/|) { + $url='/adm/wrapper'.$url; } - } elsif ($url=~m|^/ext/|) { - $url='/adm/wrapper'.$url; - $external = 1; + if (&Apache::lonnet::symbverify($symb,$url)) { + my $shownsymb = $symb; + if ($isexternal) { + if ($url =~ /^([^#]+)#([^#]+)$/) { + $url = $1; + $anchor = $2; + if ($symb =~ m{^([^#]+)\Q#$anchor\E$}) { + $shownsymb = $1.&escape('#').$anchor; + } + } + } + unless ($env{'request.role.adv'}) { + if ((&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i) { + $url = ''; + } + if (&Apache::lonnet::EXT('resource.0.hiddenresource',$symb) =~ /^yes$/i) { + $url = ''; + $hiddenres = 1; + } + } + if ($url ne '') { + $url.=(($url=~/\?/)?'&':'?').'symb='.&HTML::Entities::encode($shownsymb,'"<>&'); + } + } elsif (!$env{'request.role.adv'}) { + my $checkencrypt; + if (((&LONCAPA::map::getparameter($orderidx,'parameter_encrypturl'))[0]=~/^yes$/i) || + $isencrypted || (&Apache::lonnet::EXT('resource.0.encrypturl',$symb) =~ /^yes$/i)) { + $checkencrypt = 1; + } else { + unless (ref($$navmapref)) { + $$navmapref = Apache::lonnavmaps::navmap->new(); + } + if (ref($$navmapref)) { + if (lc($$navmapref->get_mapparam($symb,undef,"0.encrypturl")) eq 'yes') { + $checkencrypt = 1; + } + } + } + if ($checkencrypt) { + my $shownsymb = &Apache::lonenc::encrypted($symb); + my $shownurl = &Apache::lonenc::encrypted($url); + if (&Apache::lonnet::symbverify($shownsymb,$shownurl)) { + $url = $shownurl.(($shownurl=~/\?/)?'&':'?').'symb='.&HTML::Entities::encode($shownsymb,'"<>&'); + if ($env{'request.enc'} ne '') { + delete($env{'request.enc'}); + } + } else { + $url=''; + } + } else { + $url=''; + } + } else { + $url=''; + } } - if (&Apache::lonnet::symbverify($symb,$url)) { - $url.=(($url=~/\?/)?'&':'?').'symb='.&escape($symb); - } else { - $url=''; + } elsif ($supplementalflag) { + if ($isexternal) { + if ($url =~ /^([^#]+)#([^#]+)$/) { + $url = $1; + $anchor = $2; + } } - if ($container eq 'page') { - my $symb=$env{'form.pagesymb'}; - - $url=&Apache::lonnet::clutter((&Apache::lonnet::decode_symb($symb))[2]); - $url.=(($url=~/\?/)?'&':'?').'symb='.&escape($symb); - } } - my ($parameterset,$rand_order_text) = (' ', ' '); - if ($isfolder || $extension eq 'sequence') { + my ($rand_pick_text,$rand_order_text,$hiddenfolder); + my $filterFunc = sub { my $res = shift; return (!$res->randomout() && !$res->is_map()) }; + if ($isfolder || $ispage || $extension eq 'sequence' || $extension eq 'page') { my $foldername=&escape($foldertitle); my $folderpath=$env{'form.folderpath'}; if ($folderpath) { $folderpath.='&' }; + if (!$allowed && $supplementalflag) { + $folderpath.=$containerarg.'&'.$foldername; + $url.='folderpath='.&escape($folderpath); + } else { + my $rpicknum = (&LONCAPA::map::getparameter($orderidx, + 'parameter_randompick'))[0]; + my $randorder = ((&LONCAPA::map::getparameter($orderidx, + 'parameter_randomorder'))[0]=~/^yes$/i); + my $hiddenmap = ((&LONCAPA::map::getparameter($orderidx, + 'parameter_hiddenresource'))[0]=~/^yes$/i); + my $encryptmap = ((&LONCAPA::map::getparameter($orderidx, + 'parameter_encrypturl'))[0]=~/^yes$/i); + unless ($hiddenmap) { + unless (ref($$navmapref)) { + $$navmapref = Apache::lonnavmaps::navmap->new(); + } + if (ref($$navmapref)) { + if (lc($$navmapref->get_mapparam(undef,$folderurl,"0.hiddenresource")) eq 'yes') { + my @resources = $$navmapref->retrieveResources($folderurl,$filterFunc,1,1); + unless (@resources) { + $hiddenmap = 1; + unless ($env{'request.role.adv'}) { + $url = ''; + $hiddenfolder = 1; + } + } + } + } + } + unless ($encryptmap) { + if (lc($$navmapref->get_mapparam(undef,$folderurl,"0.encrypturl")) eq 'yes') { + $encryptmap = 1; + } + } + # Append randompick number, hidden, and encrypted with ":" to foldername, # so it gets transferred between levels - $folderpath.=$folderarg.'&'.$foldername.':'.(&LONCAPA::map::getparameter($orderidx, - 'parameter_randompick'))[0] - .':'.((&LONCAPA::map::getparameter($orderidx, - 'parameter_hiddenresource'))[0]=~/^yes$/i) - .':'.((&LONCAPA::map::getparameter($orderidx, - 'parameter_encrypturl'))[0]=~/^yes$/i) - .':'.((&LONCAPA::map::getparameter($orderidx, - 'parameter_randomorder'))[0]=~/^yes$/i); - $url.='folderpath='.&escape($folderpath).$cpinfo; - $parameterset=''; - my $ro_set= - ((&LONCAPA::map::getparameter($orderidx,'parameter_randomorder'))[0]=~/^yes$/i?' checked="checked"':''); - $rand_order_text =' -'; - } - if ($ispage) { - my $pagename=&escape($pagetitle); - my $pagepath; - my $folderpath=$env{'form.folderpath'}; - if ($folderpath) { $pagepath = $folderpath.'&' }; - $pagepath.=$pagearg.'&'.$pagename; - my $symb=$env{'form.pagesymb'}; - if (!$symb) { - my $path='uploaded/'. - $env{'course.'.$env{'request.course.id'}.'.domain'}.'/'. - $env{'course.'.$env{'request.course.id'}.'.num'}.'/'; - $symb=&Apache::lonnet::encode_symb($path.$folder.'.sequence', - $residx, - $path.$pagearg.'.page'); - } - $url.='pagepath='.&escape($pagepath). - '&pagesymb='.&escape($symb).$cpinfo; + $folderpath.=$containerarg.'&'.$foldername. + ':'.$rpicknum.':'.$hiddenmap.':'.$encryptmap.':'.$randorder.':'.$ispage; + unless ($url eq '') { + $url.='folderpath='.&escape($folderpath); + } + my $rpckchk; + if ($rpicknum) { + $rpckchk = ' checked="checked"'; + if (($ishash) && (ref($filtersref->{'randompick'}) eq 'ARRAY')) { + push(@{$filtersref->{'randompick'}},$orderidx.':'.$rpicknum); + } + } + my $formname = 'edit_randompick_'.$orderidx; + $rand_pick_text = +'
    '."\n". +$form_param."\n". +$form_common."\n". +''; + if ($rpicknum ne '') { + $rand_pick_text .= ': '.$rpicknum.''; + } + $rand_pick_text .= ''. + $form_end; + my $ro_set; + if ($randorder) { + $ro_set = 'checked="checked"'; + if (($ishash) && (ref($filtersref->{'randomorder'}) eq 'ARRAY')) { + push(@{$filtersref->{'randomorder'}},$orderidx); + } + } + $formname = 'edit_rorder_'.$orderidx; + $rand_order_text = +''."\n". +$form_param."\n". +$form_common."\n". +''. +$form_end; + } + } elsif ($supplementalflag && !$allowed) { + $url .= ($url =~ /\?/) ? '&':'?'; + $url .= 'folderpath='.&HTML::Entities::encode($esc_path,'<>&"'); + if ($title) { + $url .= '&title='.&HTML::Entities::encode($renametitle,'<>&"'); + } + if ($isexternal && $orderidx) { + $url .= '&idx='.$orderidx; + } + if ($anchor ne '') { + $url .= '&anchor='.&HTML::Entities::encode($anchor,'"<>&'); + } } - if (($external) && ($allowed)) { - my $form = ($folder =~ /^default/)? 'newext' : 'supnewext'; - $external = ' '.&mt('Edit').''; - } else { - undef($external); + my ($tdalign,$tdwidth); + if ($allowed) { + my $fileloc = + &Apache::lonnet::declutter(&Apache::lonnet::filelocation('',$orig_url)); + if ($isexternal) { + ($editlink,$extresform) = + &Apache::lonextresedit::extedit_form(0,$residx,$orig_url,$title,$pathitem, + undef,undef,undef,$disabled); + } elsif (!$isfolder && !$ispage) { + my ($cfile,$home,$switchserver,$forceedit,$forceview) = + &Apache::lonnet::can_edit_resource($fileloc,$coursenum,$coursedom,$orig_url); + if (($cfile ne '') && ($symb ne '' || $supplementalflag)) { + my $suppanchor; + if ($supplementalflag) { + $suppanchor = $anchor; + } + my $jscall = + &Apache::lonhtmlcommon::jump_to_editres($cfile,$home, + $switchserver, + $forceedit, + undef,$symb, + &escape($env{'form.folderpath'}), + $renametitle,'','',1,$suppanchor); + if ($jscall) { + $editlink = ''.&mt('Edit').' '."\n"; + } + } + } + $tdalign = ' align="right" valign="top"'; + $tdwidth = ' width="80%"'; } my $reinit; if ($crstype eq 'Community') { $reinit = &mt('(re-initialize community to access)'); } else { $reinit = &mt('(re-initialize course to access)'); - } - $line.=' - - '.($url?'':'').''.($url?'':'').' - - - '.($url?"":'').$title.($url?'':' '.$reinit.'').$external." - "; + } + $line.=''.$editlink.$renamelink; + if (($url=~m{/adm/(coursedocs|supplemental)}) || (!$allowed && $url)) { + $line.=''; + } elsif ($url) { + if ($anchor ne '') { + if ($supplementalflag) { + $anchor = '&anchor='.&HTML::Entities::encode($anchor,'"<>&'); + } else { + $anchor = '#'.&HTML::Entities::encode($anchor,'"<>&'); + } + } + $line.=&Apache::loncommon::modal_link(&js_escape($url.(($url=~/\?/)?'&':'?').'inhibitmenu=yes'. + (($anchor ne '')?$anchor:'')), + '',600,500); + } else { + $line.=''; + } + $line.=''; + if (($url=~m{/adm/(coursedocs|supplemental)}) || (!$allowed && $url)) { + $line.=''.$title.''; + } elsif ($url) { + $line.=&Apache::loncommon::modal_link(&js_escape($url.(($url=~/\?/)?'&':'?').'inhibitmenu=yes'. + (($anchor ne '')?$anchor:'')), + $title,600,500); + } elsif (($hiddenfolder) || ($hiddenres)) { + $line.=$title.' '.&mt('(Hidden)').''; + } else { + $line.=$title.' '.$reinit.''; + } + $line.="$extresform"; + $rand_pick_text = ' ' if ($rand_pick_text eq ''); + $rand_order_text = ' ' if ($rand_order_text eq ''); if (($allowed) && ($folder!~/^supplemental/)) { my %lt=&Apache::lonlocal::texthash( 'hd' => 'Hidden', 'ec' => 'URL hidden'); - my $enctext= - ((&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 ($enctext,$hidtext); + if ((&LONCAPA::map::getparameter($orderidx,'parameter_encrypturl'))[0]=~/^yes$/i) { + $enctext = ' checked="checked"'; + if (($ishash) && (ref($filtersref->{'encrypturl'}) eq 'ARRAY')) { + push(@{$filtersref->{'encrypturl'}},$orderidx); + } + } + if ((&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i) { + $hidtext = ' checked="checked"'; + if (($ishash) && (ref($filtersref->{'randomorder'}) eq 'ARRAY')) { + push(@{$filtersref->{'hiddenresource'}},$orderidx); + } + } + my $formhidden = 'edit_hiddenresource_'.$orderidx; + my $formurlhidden = 'edit_encrypturl_'.$orderidx; $line.=(< - $form_start - + + $form_param + $form_common + $form_end
    - $form_start - + + $form_param + $form_common + $form_end - $form_start $parameterset $form_end
    - $form_start $rand_order_text $form_end + $rand_pick_text
    + $rand_order_text ENDPARMS } $line.=&Apache::loncommon::end_data_table_row(); return $line; } +sub action_restrictions { + my ($cnum,$cdom,$url,$folderpath,$currgroups) = @_; + my %denied = ( + cut => 0, + copy => 0, + remove => 0, + ); + if ($url=~ m{^/res/.+\.(page|sequence)$}) { + # no copy for published maps + $denied{'copy'} = 1; + } elsif ($url=~m{^/res/lib/templates/}) { + $denied{'copy'} = 1; + $denied{'cut'} = 1; + } elsif ($url eq "/uploaded/$cdom/$cnum/group_allfolders.sequence") { + if ($folderpath =~ /^default&[^\&]+$/) { + if ((ref($currgroups) eq 'HASH') && (keys(%{$currgroups}) > 0)) { + $denied{'remove'} = 1; + } + $denied{'cut'} = 1; + $denied{'copy'} = 1; + } + } elsif ($url =~ m{^\Q/uploaded/$cdom/$cnum/group_folder_\E(\w+)\.sequence$}) { + my $group = $1; + if ($folderpath =~ /^default&[^\&]+\&group_allfolders\&[^\&]+$/) { + if ((ref($currgroups) eq 'HASH') && (exists($currgroups->{$group}))) { + $denied{'remove'} = 1; + } + } + $denied{'cut'} = 1; + $denied{'copy'} = 1; + } elsif ($url =~ m{^\Q/adm/$cdom/$cnum/\E(\w+)/smppg$}) { + my $group = $1; + if ($folderpath =~ /^default&[^\&]+\&group_allfolders\&[^\&]+\&\Qgroup_folder_$group\E\&[^\&]+$/) { + if ((ref($currgroups) eq 'HASH') && (exists($currgroups->{$group}))) { + my %groupsettings = &Apache::longroup::get_group_settings($currgroups->{$group}); + if (keys(%groupsettings) > 0) { + $denied{'remove'} = 1; + } + $denied{'cut'} = 1; + $denied{'copy'} = 1; + } + } + } elsif ($folderpath =~ /^default&[^\&]+\&group_allfolders\&[^\&]+\&group_folder_(\w+)\&/) { + my $group = $1; + if ($url =~ /group_boards_\Q$group\E/) { + if ((ref($currgroups) eq 'HASH') && (exists($currgroups->{$group}))) { + my %groupsettings = &Apache::longroup::get_group_settings($currgroups->{$group}); + if (keys(%groupsettings) > 0) { + if (ref($groupsettings{'functions'}) eq 'HASH') { + if ($groupsettings{'functions'}{'discussion'} eq 'on') { + $denied{'remove'} = 1; + } + } + } + $denied{'cut'} = 1; + $denied{'copy'} = 1; + } + } + } + return %denied; +} + +sub new_timebased_suffix { + my ($dom,$num,$type,$area,$container) = @_; + my ($prefix,$namespace,$idtype,$errtext,$locknotfreed); + if ($type eq 'paste') { + $prefix = $type; + $namespace = 'courseeditor'; + $idtype = 'addcode'; + } elsif ($type eq 'map') { + $prefix = 'docs'; + if ($area eq 'supplemental') { + $prefix = 'supp'; + } + $prefix .= $container; + $namespace = 'uploadedmaps'; + } else { + $prefix = $type; + $namespace = 'templated'; + } + my ($suffix,$freedlock,$error) = + &Apache::lonnet::get_timebased_id($prefix,'num',$namespace,$dom,$num,$idtype); + if (!$suffix) { + if ($type eq 'paste') { + $errtext = &mt('Failed to acquire a unique timestamp-based suffix when adding to the paste buffer.'); + } elsif ($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 discussion board.'); + } + if ($error) { + $errtext .= '
    '.$error; + } + } + if ($freedlock ne 'ok') { + $locknotfreed = + '
    '. + &mt('There was a problem removing a lockfile.').' '; + if ($type eq 'paste') { + if ($freedlock eq 'nolock') { + $locknotfreed = + '
    '. + &mt('A lockfile was not released when you added content to the clipboard earlier in this session.').' '. + + &mt('As a result addition of items to the clipboard will be unavailable until your next log-in.'); + } else { + $locknotfreed .= + &mt('This will prevent addition of items to the clipboard until your next log-in.'); + } + } elsif ($type eq 'map') { + $locknotfreed .= + &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 discussion boards in this course.'); + } + unless ($type eq 'paste') { + $locknotfreed .= + ' '.&mt('Please contact the [_1]helpdesk[_2] for assistance.', + '',''); + } + $locknotfreed .= '
    '; + } + return ($suffix,$errtext,$locknotfreed); +} + =pod =item tiehash() @@ -2328,7 +4207,7 @@ sub checkonthis { $r->print(''.&mt('connection down').''); } elsif ($result eq 'not_found') { unless ($url=~/\$/) { - $r->print(''.&mt('not found').''); + $r->print(''.&mt('not found').''); } else { $r->print(''.&mt('unable to verify variable URL').''); } @@ -2345,7 +4224,7 @@ sub checkonthis { =item list_symbs() -List Symbs +List Content Identifiers =cut @@ -2353,9 +4232,9 @@ sub list_symbs { my ($r) = @_; my $crstype = &Apache::loncommon::course_type(); - $r->print(&Apache::loncommon::start_page('Symb List')); - $r->print(&Apache::lonhtmlcommon::breadcrumbs('Symb List')); - &startContentScreen($r,'tools'); + $r->print(&Apache::loncommon::start_page('List of Content Identifiers')); + $r->print(&Apache::lonhtmlcommon::breadcrumbs('Content Identifiers')); + $r->print(&startContentScreen('tools')); my $navmap = Apache::lonnavmaps::navmap->new(); if (!defined($navmap)) { $r->print('

    '.&mt('Retrieval of List Failed').'

    '. @@ -2364,25 +4243,42 @@ sub list_symbs { '
    '); &Apache::lonnet::logthis('Symb list failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'}); } else { - $r->print("
    \n");
    +        $r->print('

    '.&mt("$crstype Content Identifiers").'

    '. + &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_header_row(). + ''.&mt('Title').''.&mt('Identifier').''. + &Apache::loncommon::end_data_table_header_row()."\n"); + my $count; foreach my $res ($navmap->retrieveResources()) { - $r->print($res->compTitle()."\t".$res->symb()."\n"); + $r->print(&Apache::loncommon::start_data_table_row(). + ''.$res->compTitle().''. + ''.$res->symb().''. + &Apache::loncommon::end_data_table_row()); + $count ++; + } + if (!$count) { + $r->print(&Apache::loncommon::start_data_table_row(). + ''.&mt("$crstype is empty").''. + &Apache::loncommon::end_data_table_row()); } - $r->print("\n
    \n"); + $r->print(&Apache::loncommon::end_data_table()); } + $r->print(&endContentScreen()); } sub verifycontent { my ($r) = @_; my $crstype = &Apache::loncommon::course_type(); - $r->print(&Apache::loncommon::start_page('Verify '.$crstype.' Documents')); - $r->print(&Apache::lonhtmlcommon::breadcrumbs('Verify '.$crstype.' Documents')); - &startContentScreen($r,'tools'); + $r->print(&Apache::loncommon::start_page('Verify '.$crstype.' Content')); + $r->print(&Apache::lonhtmlcommon::breadcrumbs('Verify '.$crstype.' Content')); + $r->print(&startContentScreen('tools')); + $r->print('

    '.&mt($crstype.' content verification').'

    '); $hashtied=0; undef %alreadyseen; %alreadyseen=(); &tiehash(); + foreach my $key (keys(%hash)) { if ($hash{$key}=~/\.(page|sequence)$/) { if (($key=~/^src_/) && ($alreadyseen{&unescape($hash{$key})})) { @@ -2398,6 +4294,7 @@ sub verifycontent { } &untiehash(); $r->print('

    '.&mt('Done').'

    '); + $r->print(&endContentScreen()); } @@ -2408,11 +4305,11 @@ sub devalidateversioncache { } sub checkversions { - my ($r) = @_; + my ($r,$canedit) = @_; my $crstype = &Apache::loncommon::course_type(); - $r->print(&Apache::loncommon::start_page("Check $crstype Document Versions")); - $r->print(&Apache::lonhtmlcommon::breadcrumbs("Check $crstype Document Versions")); - &startContentScreen($r,'tools'); + $r->print(&Apache::loncommon::start_page("Check $crstype Resource Versions")); + $r->print(&Apache::lonhtmlcommon::breadcrumbs("Check $crstype Resource Versions")); + $r->print(&startContentScreen('tools')); my $header=''; my $startsel=''; @@ -2429,53 +4326,57 @@ sub checkversions { $hashtied=0; &tiehash(); - my %newsetversions=(); - if ($env{'form.setmostrecent'}) { - $haschanged=1; - foreach my $key (keys(%hash)) { - if ($key=~/^ids\_(\/res\/.+)$/) { - $newsetversions{$1}='mostrecent'; - &devalidateversioncache($1); + if ($canedit) { + my %newsetversions=(); + if ($env{'form.setmostrecent'}) { + $haschanged=1; + foreach my $key (keys(%hash)) { + if ($key=~/^ids\_(\/res\/.+)$/) { + $newsetversions{$1}='mostrecent'; + &devalidateversioncache($1); + } } - } - } elsif ($env{'form.setcurrent'}) { - $haschanged=1; - foreach my $key (keys(%hash)) { - if ($key=~/^ids\_(\/res\/.+)$/) { - my $getvers=&Apache::lonnet::getversion($1); - if ($getvers>0) { - $newsetversions{$1}=$getvers; - &devalidateversioncache($1); - } + } elsif ($env{'form.setcurrent'}) { + $haschanged=1; + foreach my $key (keys(%hash)) { + if ($key=~/^ids\_(\/res\/.+)$/) { + my $getvers=&Apache::lonnet::getversion($1); + if ($getvers>0) { + $newsetversions{$1}=$getvers; + &devalidateversioncache($1); + } + } } - } - } elsif ($env{'form.setversions'}) { - $haschanged=1; - foreach my $key (keys(%env)) { - if ($key=~/^form\.set_version_(.+)$/) { - my $src=$1; - if (($env{$key}) && ($env{$key} ne $setversions{$src})) { - $newsetversions{$src}=$env{$key}; - &devalidateversioncache($src); - } + } elsif ($env{'form.setversions'}) { + $haschanged=1; + foreach my $key (keys(%env)) { + if ($key=~/^form\.set_version_(.+)$/) { + my $src=$1; + if (($env{$key}) && ($env{$key} ne $setversions{$src})) { + $newsetversions{$src}=$env{$key}; + &devalidateversioncache($src); + } + } } - } - } - if ($haschanged) { - if (&Apache::lonnet::put('resourceversions',\%newsetversions, - $env{'course.'.$env{'request.course.id'}.'.domain'}, - $env{'course.'.$env{'request.course.id'}.'.num'}) eq 'ok') { - $r->print('

    '.&mt('Your Version Settings have been Saved').'

    '); - } else { - $r->print('

    '.&mt('An Error Occured while Attempting to Save your Version Settings').'

    '); - } - &mark_hash_old(); + } + if ($haschanged) { + if (&Apache::lonnet::put('resourceversions',\%newsetversions, + $env{'course.'.$env{'request.course.id'}.'.domain'}, + $env{'course.'.$env{'request.course.id'}.'.num'}) eq 'ok') { + $r->print(&Apache::loncommon::confirmwrapper( + &Apache::lonhtmlcommon::confirm_success(&mt('Your Version Settings have been Saved')))); + } else { + $r->print(&Apache::loncommon::confirmwrapper( + &Apache::lonhtmlcommon::confirm_success(&mt('An Error Occured while Attempting to Save your Version Settings'),1))); + } + &mark_hash_old(); + } + &changewarning($r,''); } - &changewarning($r,''); if ($env{'form.timerange'} eq 'all') { # show all documents - $header=&mt('All Documents in '.$crstype); - $allsel=1; + $header=&mt('All content in '.$crstype); + $allsel=' selected="selected"'; foreach my $key (keys(%hash)) { if ($key=~/^ids\_(\/res\/.+)$/) { my $src=$1; @@ -2496,19 +4397,19 @@ sub checkversions { .&mt('seconds'); if ($env{'form.timerange'}==-1) { $seltext='since start of course'; - $startsel='selected'; + $startsel=' selected="selected"'; $env{'form.timerange'}=time; } $starttime=time-$env{'form.timerange'}; if ($env{'form.timerange'}==2592000) { $seltext=&mt('during the last month').' ('.&Apache::lonlocal::locallocaltime($starttime).')'; - $monthsel='selected'; + $monthsel=' selected="selected"'; } elsif ($env{'form.timerange'}==604800) { $seltext=&mt('during the last week').' ('.&Apache::lonlocal::locallocaltime($starttime).')'; - $weeksel='selected'; + $weeksel=' selected="selected"'; } elsif ($env{'form.timerange'}==86400) { $seltext=&mt('since yesterday').' ('.&Apache::lonlocal::locallocaltime($starttime).')'; - $daysel='selected'; + $daysel=' selected="selected"'; } $header=&mt('Content changed').' '.$seltext; } else { @@ -2524,6 +4425,7 @@ sub checkversions { 'lw' => 'Version changes since last Week', 'sy' => 'Version changes since Yesterday', 'al' => 'All Resources (possibly large output)', + 'cd' => 'Change display', 'sd' => 'Display', 'fi' => 'File', 'md' => 'Modification Date', @@ -2533,125 +4435,151 @@ sub checkversions { 'sv' => 'Set Versions to be used in '.$crstype.' according to Selections below', 'sm' => 'Keep all Resources up-to-date with most recent Versions (default)', 'sc' => 'Set all Resource Versions to current Version (Fix Versions)', - 'di' => 'Differences'); + 'di' => 'Differences', + 'save' => 'Save changes', + 'vers' => 'Version choice(s) for specific resources', + 'act' => 'Actions'); + my ($disabled,$readonly); + unless ($canedit) { + $disabled = 'disabled="disabled"'; + $readonly = 1; + } $r->print(<$header - -
    +
    +
    +$lt{'cd'} -

    $header

    - - + + +
    +
    +$lt{'act'} +$lt{'sm'}:
    +$lt{'sc'}: +
    +
    +
    +
    +

    $lt{'vers'}

    ENDHEADERS - foreach my $key (sort(keys(%changes))) { - if ($changes{$key}>$starttime) { - my ($root,$extension)=($key=~/^(.*)\.(\w+)$/); - my $currentversion=&Apache::lonnet::getversion($key); - if ($currentversion<0) { - $currentversion=&mt('Could not be determined.'); - } - my $linkurl=&Apache::lonnet::clutter($key); - $r->print( - ''. - ''. - ''. - ''. - ''. - ''. - ''); - my $lastold=1; - for (my $prevvers=1;$prevvers<$currentversion;$prevvers++) { - my $url=$root.'.'.$prevvers.'.'.$extension; - if (&Apache::lonnet::metadata($url,'lastrevisiondate')< - $starttime) { - $lastold=$prevvers; - } - } - # - # Code to figure out how many version entries should go in - # each of the four columns - my $entries_per_col = 0; - my $num_entries = ($currentversion-$lastold); - if ($num_entries % 4 == 0) { - $entries_per_col = $num_entries/4; + #number of columns for version history + my %changedbytime; + foreach my $key (keys(%changes)) { + #excludes not versionable problems from resource version history: + next if ($key =~ /^\/res\/lib\/templates/); + my $chg; + if ($env{'form.timerange'} eq 'all') { + my ($root,$extension)=($key=~/^(.*)\.(\w+)$/); + $chg = &Apache::lonnet::metadata($root.'.'.$extension,'lastrevisiondate'); + } else { + $chg = $changes{$key}; + next if ($chg < $starttime); + } + push(@{$changedbytime{$chg}},$key); + } + if (keys(%changedbytime) == 0) { + &untiehash(); + $r->print(&mt('No content changes in imported content in specified time frame'). + &endContentScreen()); + return; + } + $r->print( + ''. + &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_header_row(). + ''. + "". + "". + "". + ''. + &Apache::loncommon::end_data_table_header_row() + ); + foreach my $chg (sort {$b <=> $a } keys(%changedbytime)) { + foreach my $key (sort(@{$changedbytime{$chg}})) { + my ($root,$extension)=($key=~/^(.*)\.(\w+)$/); + my $currentversion=&Apache::lonnet::getversion($key); + if ($currentversion<0) { + $currentversion=''.&mt('Could not be determined.').''; + } + my $linkurl=&Apache::lonnet::clutter($key); + $r->print( + &Apache::loncommon::start_data_table_row(). + ''. + ''. + ''); + # List all available versions + $r->print(''); - if ($cols_output != 4) { - $r->print(''."\n"); - } + $r->print(''.&Apache::loncommon::end_data_table_row()); + } } - $r->print('


    '. - &Apache::lonnet::gettitle($linkurl). - '
       '. - ''.$linkurl. - '
    '. - &Apache::lonlocal::locallocaltime( - &Apache::lonnet::metadata($root.'.'.$extension, - 'lastrevisiondate') - ). - 'Most Recent: '. - ''.$currentversion.''. - 'In '.$crstype.': '. - ''); -# Used in course - my $usedversion=$hash{'version_'.$linkurl}; - if (($usedversion) && ($usedversion ne 'mostrecent')) { - $r->print($usedversion); - } else { - $r->print($currentversion); - } - $r->print(''. - 'Use: '); -# Set version - $r->print(&Apache::loncommon::select_form($setversions{$linkurl}, - 'set_version_'.$linkurl, - {'select_form_order' => - ['',1..$currentversion,'mostrecent'], - '' => '', - 'mostrecent' => &mt('most recent'), - map {$_,$_} (1..$currentversion)})); - $r->print('
    '.&mt('Resources').'$lt{'mr'}$lt{'ve'}$lt{'vu'}'.&mt('History').''.&Apache::lonnet::gettitle($linkurl).'
    '. + ''.$linkurl.'
    '.$currentversion.'
    ('. + &Apache::lonlocal::locallocaltime($chg).')
    ' + ); + # Used in course + my $usedversion=$hash{'version_'.$linkurl}; + if (($usedversion) && ($usedversion ne 'mostrecent')) { + if ($usedversion != $currentversion) { + $r->print(''.$usedversion.''); + } else { + $r->print($usedversion); + } } else { - $entries_per_col = $num_entries/4 + 1; + $r->print($currentversion); + } + $r->print(''); + # Set version + $r->print(&Apache::loncommon::select_form( + $setversions{$linkurl}, + 'set_version_'.$linkurl, + {'select_form_order' => ['',1..$currentversion,'mostrecent'], + '' => '', + 'mostrecent' => &mt('most recent'), + map {$_,$_} (1..$currentversion)},'',$readonly)); + my $lastold=1; + for (my $prevvers=1;$prevvers<$currentversion;$prevvers++) { + my $url=$root.'.'.$prevvers.'.'.$extension; + if (&Apache::lonnet::metadata($url,'lastrevisiondate')<$starttime) { + $lastold=$prevvers; + } } - my $entries_count = 0; - $r->print(''); - my $cols_output = 1; + $r->print(''); for (my $prevvers=$lastold;$prevvers<$currentversion;$prevvers++) { - my $url=$root.'.'.$prevvers.'.'.$extension; - $r->print(''.&mt('Version').' '.$prevvers.' ('. - &Apache::lonlocal::locallocaltime( - &Apache::lonnet::metadata($url, - 'lastrevisiondate') - ). - ')'); - if (&Apache::loncommon::fileembstyle($extension) eq 'ssi') { - $r->print(' '.&mt('Diffs').''); - } - $r->print('
    '); - if (++$entries_count % $entries_per_col == 0) { - $r->print('
    '); - $cols_output++; - } + my $url=$root.'.'.$prevvers.'.'.$extension; + $r->print( + '' + .'' + .&mt('Version [_1]',$prevvers).'' + .' ('.&Apache::lonlocal::locallocaltime( + &Apache::lonnet::metadata($url,'lastrevisiondate')) + .')'); + if (&Apache::loncommon::fileembstyle($extension) eq 'ssi') { + $r->print( + ' &'). + '" target="diffs">'.&mt('Diffs').''); } - } - while($cols_output++ < 4) { - $r->print('') + $r->print('
    '); } - $r->print('
    '); - $r->print('

    '.&mt('Done').'

    '); + $r->print( + &Apache::loncommon::end_data_table(). + ''. + '' + ); &untiehash(); + $r->print(&endContentScreen()); + return; } sub mark_hash_old { @@ -2683,11 +4611,6 @@ sub changewarning { my $pathvar='folderpath'; my $path=&escape($env{'form.folderpath'}); if (!defined($url)) { - if (defined($env{'form.pagepath'})) { - $pathvar='pagepath'; - $path=&escape($env{'form.pagepath'}); - $path.='&pagesymb='.&escape($env{'form.pagesymb'}); - } $url='/adm/coursedocs?'.$pathvar.'='.$path; } my $course_type = &Apache::loncommon::course_type(); @@ -2711,13 +4634,13 @@ $help{'Caching'}.'

    '."\n\n"); sub init_breadcrumbs { - my ($form,$text)=@_; + my ($form,$text,$help)=@_; &Apache::lonhtmlcommon::clear_breadcrumbs(); - &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/coursedocs", + &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/coursedocs?tools=1", text=>&Apache::loncommon::course_type().' Editor', faq=>273, bug=>'Instructor Interface', - help => 'Docs_Adding_Course_Doc'}); + help => $help}); &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/coursedocs?".$form.'=1', text=>$text, faq=>273, @@ -2728,9 +4651,9 @@ sub init_breadcrumbs { sub create_list_elements { my @formarr = @_; my $list = ''; - for my $button (@formarr){ - for my $picture(keys %$button) { - $list .= &Apache::lonhtmlcommon::htmltag('li', $picture.' '.$button->{$picture}, {class => 'LC_menubuttons_inline_text'}); + foreach my $button (@formarr){ + foreach my $picture (keys(%{$button})) { + $list .= &Apache::lonhtmlcommon::htmltag('li', $picture.' '.$button->{$picture}, {class => 'LC_menubuttons_inline_text', id => ''}); } } return $list; @@ -2748,29 +4671,23 @@ sub create_form_ul { # sub startContentScreen { - my ($r,$mode)=@_; - $r->print(''); - $r->print('
    ' - .'
    '); - $r->print('
    '); + my ($mode) = @_; + my $output = ''."\n"; + $output .= '
    '. + '
    '. + '
    '; + return $output; } # @@ -2778,12 +4695,11 @@ sub startContentScreen { # sub endContentScreen { - my ($r)=@_; - $r->print('
    '); + return '
    '; } sub supplemental_base { - return 'supplemental&'.&escape(&mt('Supplemental '.&Apache::loncommon::course_type().' Documents')); + return 'supplemental&'.&escape(&mt('Supplemental Content')); } sub handler { @@ -2791,7 +4707,14 @@ sub handler { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; return OK if $r->header_only; + +# get course data my $crstype = &Apache::loncommon::course_type(); + my $coursenum=$env{'course.'.$env{'request.course.id'}.'.num'}; + my $coursedom=$env{'course.'.$env{'request.course.id'}.'.domain'}; + +# graphics settings + $iconpath = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL').'/'); # # --------------------------------------------- Initialize help topics for this @@ -2799,8 +4722,9 @@ sub handler { 'Adding_External_Resource','Navigate_Content', 'Adding_Folders','Docs_Overview', 'Load_Map', 'Supplemental','Score_Upload_Form','Adding_Pages', - 'Importing_LON-CAPA_Resource','Uploading_From_Harddrive', - 'Check_Resource_Versions','Verify_Content') { + 'Importing_LON-CAPA_Resource','Importing_IMS_Course', + 'Uploading_From_Harddrive','Course_Roster','Web_Page', + 'Dropbox','Simple_Problem') { $help{$topic}=&Apache::loncommon::help_open_topic('Docs_'.$topic); } # Composite help files @@ -2808,183 +4732,283 @@ sub handler { 'Docs_About_Syllabus,Docs_Editing_Templated_Pages'); $help{'Simple Page'} = &Apache::loncommon::help_open_topic( 'Docs_About_Simple_Page,Docs_Editing_Templated_Pages'); - $help{'Simple Problem'} = &Apache::loncommon::help_open_topic( - 'Option_Response_Simple'); $help{'Bulletin Board'} = &Apache::loncommon::help_open_topic( 'Docs_About_Bulletin_Board,Docs_Editing_Templated_Pages'); $help{'My Personal Information Page'} = &Apache::loncommon::help_open_topic( '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'); - -# does this user have privileges to modify docs - my $allowed=&Apache::lonnet::allowed('mdc',$env{'request.course.id'}); + + my ($allowed,$canedit,$canview,$disabled); +# URI is /adm/supplemental when viewing supplemental docs in non-edit mode. + unless ($r->uri eq '/adm/supplemental') { + # does this user have privileges to modify content. + if (&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) { + $allowed = 1; + $canedit = 1; + $canview = 1; + } elsif (&Apache::lonnet::allowed('cev',$env{'request.course.id'})) { + $allowed = 1; + $canview = 1; + } + } + unless ($canedit) { + $disabled = ' disabled="disabled"'; + } + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['inhibitmenu']); if ($allowed && $env{'form.verify'}) { - &init_breadcrumbs('verify','Verify Content'); + &init_breadcrumbs('verify','Verify Content','Docs_Verify_Content'); &verifycontent($r); } elsif ($allowed && $env{'form.listsymbs'}) { - &init_breadcrumbs('listsymbs','List Symbs'); + &init_breadcrumbs('listsymbs','List Content IDs'); &list_symbs($r); } elsif ($allowed && $env{'form.docslog'}) { &init_breadcrumbs('docslog','Show Log'); - &docs_change_log($r); + my $folder = $env{'form.folder'}; + if ($folder eq '') { + $folder='default'; + } + &docs_change_log($r,$coursenum,$coursedom,$folder,$allowed,$crstype,$iconpath,$canedit); } elsif ($allowed && $env{'form.versions'}) { - &init_breadcrumbs('versions','Check/Set Resource Versions'); - &checkversions($r); - } elsif ($allowed && $env{'form.dumpcourse'}) { - &init_breadcrumbs('dumpcourse','Dump '.&Apache::loncommon::course_type().' Documents to Construction Space'); + &init_breadcrumbs('versions','Check/Set Resource Versions','Docs_Check_Resource_Versions'); + &checkversions($r,$canedit); + } elsif ($canedit && $env{'form.dumpcourse'}) { + &init_breadcrumbs('dumpcourse','Copy '.&Apache::loncommon::course_type().' Content to Authoring Space'); &dumpcourse($r); } elsif ($allowed && $env{'form.exportcourse'}) { &init_breadcrumbs('exportcourse','IMS Export'); - &exportcourse($r); + &Apache::imsexport::exportcourse($r); } else { # # Done catching special calls -# The whole rest is for course and supplemental documents +# The whole rest is for course and supplemental documents and utilities menu # Get the parameters that may be needed # &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, - ['folderpath','pagepath', - 'pagesymb','forcesupplement','forcestandard']); + ['folderpath', + 'forcesupplement','forcestandard', + 'tools','symb','command','supppath']); # standard=1: this is a "new-style" course with an uploaded map as top level # standard=2: this is a "old-style" course, and there is nothing we can do my $standard=($env{'request.course.uri'}=~/^\/uploaded\//); -# Decide whether this should display supplemental or main content +# Decide whether this should display supplemental or main content or utilities # supplementalflag=1: show supplemental documents # supplementalflag=0: show standard documents +# toolsflag=1: show utilities - - my $supplementalflag=($env{'form.folderpath'}=~/^supplemental/); - if (($env{'form.folderpath'}=~/^default/) || $env{'form.folderpath'} eq "" || ($env{'form.pagepath'})) { + my $unesc_folderpath = &unescape($env{'form.folderpath'}); + my $supplementalflag=($unesc_folderpath=~/^supplemental/); + if (($unesc_folderpath=~/^default/) || ($unesc_folderpath eq "")) { $supplementalflag=0; } if ($env{'form.forcesupplement'}) { $supplementalflag=1; } if ($env{'form.forcestandard'}) { $supplementalflag=0; } unless ($allowed) { $supplementalflag=1; } unless ($standard) { $supplementalflag=1; } + my $toolsflag=0; + if ($env{'form.tools'}) { $toolsflag=1; } my $script=''; my $showdoc=0; my $addentries = {}; + my $container; my $containertag; - my $uploadtag; + my $pathitem; + my $hiddentop; + my $navmap; + my $filterFunc = sub { my $res = shift; return (!$res->randomout() && !$res->is_map()) }; + +# Do we directly jump somewhere? + if (($env{'form.command'} eq 'direct') || ($env{'form.command'} eq 'directnav')) { + if ($env{'form.symb'} ne '') { + $env{'form.folderpath'}= + &Apache::loncommon::symb_to_docspath($env{'form.symb'},\$navmap); + &Apache::lonnet::appenv({'docs.exit.'.$env{'request.course.id'} => + $env{'form.command'}.'_'.$env{'form.symb'}}); + } elsif ($env{'form.supppath'} ne '') { + $env{'form.folderpath'}=$env{'form.supppath'}; + &Apache::lonnet::appenv({'docs.exit.'.$env{'request.course.id'} => + $env{'form.command'}.'_'.$env{'form.supppath'}}); + } + } elsif ($env{'form.command'} eq 'editdocs') { + $env{'form.folderpath'} = &default_folderpath($coursenum,$coursedom,\$navmap); + &Apache::lonnet::appenv({'docs.exit.'.$env{'request.course.id'} => $env{'form.command'}}); + } elsif ($env{'form.command'} eq 'editsupp') { + $env{'form.folderpath'} = &supplemental_base(); + &Apache::lonnet::appenv({'docs.exit.'.$env{'request.course.id'} => '/adm/supplemental'}); + } elsif ($env{'form.command'} eq 'contents') { + &Apache::lonnet::appenv({'docs.exit.'.$env{'request.course.id'} => '/adm/navmaps'}); + } elsif ($env{'form.command'} eq 'home') { + &Apache::lonnet::appenv({'docs.exit.'.$env{'request.course.id'} => '/adm/menu'}); + } + # Where do we store these for when we come back? my $stored_folderpath='docs_folderpath'; if ($supplementalflag) { $stored_folderpath='docs_sup_folderpath'; } - -# No folderpath, no pagepath, see if we have something stored - if ((!$env{'form.folderpath'}) && (!$env{'form.pagepath'})) { + +# No folderpath, and in edit mode, see if we have something stored + if ((!$env{'form.folderpath'}) && $allowed) { &Apache::loncommon::restore_course_settings($stored_folderpath, - {'folderpath' => 'scalar'}); + {'folderpath' => 'scalar'}); + + if (&unescape($env{'form.folderpath'}) =~ m{^(default|supplemental)&}) { + if ($supplementalflag) { + undef($env{'form.folderpath'}) if ($1 eq 'default'); + } else { + undef($env{'form.folderpath'}) if ($1 eq 'supplemental'); + } + } else { + undef($env{'form.folderpath'}); + } } # If we are not allowed to make changes, all we can see are supplemental docs if (!$allowed) { - $env{'form.pagepath'}=''; unless ($env{'form.folderpath'} =~ /^supplemental/) { $env{'form.folderpath'} = &supplemental_base(); } } -# If we still not have a folderpath, see if we can resurrect at pagepath - if (!$env{'form.folderpath'} && $allowed) { - &Apache::loncommon::restore_course_settings($stored_folderpath, - {'pagepath' => 'scalar'}); - } # Make the zeroth entry in supplemental docs page paths, so we can get to top level if ($env{'form.folderpath'} =~ /^supplemental_\d+/) { $env{'form.folderpath'} = &supplemental_base() .'&'. $env{'form.folderpath'}; } +# If allowed and user's role is not advanced check folderpath is not hidden + if (($allowed) && (!$env{'request.role.adv'}) && + ($env{'form.folderpath'} ne '') && (!$supplementalflag)) { + my $folderurl; + my @pathitems = split(/\&/,$env{'form.folderpath'}); + my $folder = $pathitems[-2]; + if ($folder eq '') { + undef($env{'form.folderpath'}); + } else { + $folderurl = "uploaded/$coursedom/$coursenum/$folder"; + if ((split(/\:/,$pathitems[-1]))[4]) { + $folderurl .= '.page'; + } else { + $folderurl .= '.sequence'; + } + unless (ref($navmap)) { + $navmap = Apache::lonnavmaps::navmap->new(); + } + if (ref($navmap)) { + if (lc($navmap->get_mapparam(undef,$folderurl,"0.hiddenresource")) eq 'yes') { + my @resources = $navmap->retrieveResources($folderurl,$filterFunc,1,1); + unless (@resources) { + undef($env{'form.folderpath'}); + } + } + } + } + } + + # If after all of this, we still don't have any paths, make them - unless (($env{'form.pagepath'}) || ($env{'form.folderpath'})) { + unless ($env{'form.folderpath'}) { if ($supplementalflag) { $env{'form.folderpath'}=&supplemental_base(); - } else { - $env{'form.folderpath'}='default'; + } elsif ($allowed) { + ($env{'form.folderpath'},$hiddentop) = &default_folderpath($coursenum,$coursedom,\$navmap); } - } + } # Store this - &Apache::loncommon::store_course_settings($stored_folderpath, - {'pagepath' => 'scalar', - 'folderpath' => 'scalar'}); - - if ($env{'form.folderpath'}) { - my (@folderpath)=split('&',$env{'form.folderpath'}); - $env{'form.foldername'}=&unescape(pop(@folderpath)); - $env{'form.folder'}=pop(@folderpath); - } - if ($env{'form.pagepath'}) { - my (@pagepath)=split('&',$env{'form.pagepath'}); - $env{'form.pagename'}=&unescape(pop(@pagepath)); - $env{'form.folder'}=pop(@pagepath); - $containertag = ''. - ''; - $uploadtag = - ''. - ''. - ''; - } else { - my $folderpath=$env{'form.folderpath'}; - if (!$folderpath) { + unless ($toolsflag) { + if (($allowed) && ($env{'form.folderpath'} ne '')) { + &Apache::loncommon::store_course_settings($stored_folderpath, + {'folderpath' => 'scalar'}); + } + my $folderpath; + if ($env{'form.folderpath'}) { + $folderpath = $env{'form.folderpath'}; + my (@folders)=split('&',$env{'form.folderpath'}); + $env{'form.foldername'}=&unescape(pop(@folders)); + if ($env{'form.foldername'} =~ /\:1$/) { + $container = 'page'; + } else { + $container = 'sequence'; + } + $env{'form.folder'}=pop(@folders); + } else { if ($env{'form.folder'} eq '' || $env{'form.folder'} eq 'supplemental') { - $folderpath='default&'. - &escape(&mt('Main '.$crstype.' Documents')); + if ($env{'form.folder'} eq 'supplemental') { + $folderpath=&supplemental_base(); + } elsif (!$hiddentop) { + $folderpath='default&'. + &escape(&mt('Main Content').':::::'); + } } } $containertag = ''; - $uploadtag = ''; - } - if ($r->uri=~/^\/adm\/coursedocs\/showdoc\/(.*)$/) { - $showdoc='/'.$1; - } - if ($showdoc) { # got called in sequence from course - $allowed=0; - } else { - if ($allowed) { - &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['cmd']); - $script=&Apache::lonratedt::editscript('simple'); - } + $pathitem = ''; + if ($r->uri=~/^\/adm\/coursedocs\/showdoc\/(.*)$/) { + $showdoc='/'.$1; + } + if ($showdoc) { # got called in sequence from course + $allowed=0; + } else { + if ($canedit) { + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['cmd']); + $script=&Apache::lonratedt::editscript('simple'); + } + } } -# get course data - my $coursenum=$env{'course.'.$env{'request.course.id'}.'.num'}; - my $coursedom=$env{'course.'.$env{'request.course.id'}.'.domain'}; - # get personal data my $uname=$env{'user.name'}; my $udom=$env{'user.domain'}; my $plainname=&escape(&Apache::loncommon::plainname($uname,$udom)); -# graphics settings - - $iconpath = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL') . "/"); - if ($allowed) { - my @tabids; - if ($supplementalflag) { - @tabids = ('002','ee2','ff2'); + if ($toolsflag) { + $script .= &inject_data_js(); + my ($home,$other,%outhash)=&authorhosts(); + if (!$home && $other) { + my @hosts; + foreach my $aurole (keys(%outhash)) { + unless(grep(/^\Q$outhash{$aurole}\E/,@hosts)) { + push(@hosts,$outhash{$aurole}); + } + } + $script .= &dump_switchserver_js(@hosts); + } } else { - @tabids = ('aa1','bb1','cc1','ff1'); - unless ($env{'form.pagepath'}) { - unshift(@tabids,'001'); - push(@tabids,('dd1','ee1')); + my $tid = 1; + my @tabids; + if ($supplementalflag) { + @tabids = ('002','ee2','ff2'); + $tid = 2; + } else { + @tabids = ('aa1','bb1','cc1','ff1'); + unless ($env{'form.folderpath'} =~ /\:1$/) { + unshift(@tabids,'001'); + push(@tabids,('dd1','ee1')); + } } - } - my $tabidstr = join("','",@tabids); - $script .= &editing_js($udom,$uname). - &resize_contentdiv_js($tabidstr); - $addentries = { - onload => "javascript:resize_contentdiv('contentscroll','1','1');", - }; + my $tabidstr = join("','",@tabids); + $script .= &editing_js($udom,$uname,$supplementalflag,$coursedom,$coursenum, + $canedit,\$navmap). + &history_tab_js(). + &inject_data_js(). + &Apache::lonhtmlcommon::resize_scrollbox_js('docs',$tabidstr,$tid). + &Apache::lonextresedit::extedit_javascript(); + $addentries = { + onload => "javascript:resize_scrollbox('contentscroll','1','1');", + }; + } + $script .= &paste_popup_js(); + my $confirm_switch = &mt("Editing requires switching to the resource's home server.").'\n'. + &mt('Switch server?'); + + } # -------------------------------------------------------------------- Body tag $script = ' + +ENDSWJS + + my $startpage = &Apache::loncommon::start_page('Choose server',$js, + {'only_body' => 1, + 'js_ready' => 1,}); + my $endpage = &Apache::loncommon::end_page({'js_ready' => 1}); + + my $hostpicker; + my $count = 0; + foreach my $host (sort(@hosts)) { + my $checked; + if ($count == 0) { + $checked = ' checked="checked"'; + } + $hostpicker .= '  '; + $count++; + } + + return <<"ENDSWITCHJS"; + +function dump_needs_switchserver(url) { + if (url!='' && url!= null) { + if (confirm("$js_lt{'dump'}\\n$js_lt{'swit'}")) { + go(url); } } return; } -function resizeContentEditor() { - var timer; - clearTimeout(timer) - timer=setTimeout('resize_contentdiv("contentscroll","1","1")',500); +function choose_switchserver_window() { + newWindow = window.open('','ChooseServer','height=400,width=500,scrollbars=yes') + newWindow.document.open(); + newWindow.document.writeln('$startpage'); + newWindow.document.write('

    $html_js_lt{'duco'}<\\/h3>\\n'+ + '

    $html_js_lt{'yone'}<\\/p>\\n'+ + '

    $html_js_lt{'chos'}<\\/legend>\\n'+ + '
    \\n'+ + '$hostpicker\\n'+ + '

    \\n'+ + '\\n'+ + '<\\/form><\\/fieldset><\\/div>
    \\n'); + newWindow.document.writeln('$endpage'); + newWindow.document.close(); + newWindow.focus(); +} + +ENDSWITCHJS +} + +sub makedocslogform { + my ($formelems,$docslog) = @_; + return <<"LOGSFORM"; + + + $formelems +
    +LOGSFORM } -ENDRESIZESCRIPT - return; +sub makesimpleeditform { + my ($formelems) = @_; + return <<"SIMPFORM"; +
    + + $formelems +
    +SIMPFORM } 1; @@ -4243,37 +7322,12 @@ sets @resources - array with the resourc Return hash with valid author names -=item dumpbutton() - -Generate "dump" button - =item clean() =item dumpcourse() Actually dump course - -=item exportbutton() - - Generate "export" button - -=item exportcourse() - -=item create_ims_store() - -=item build_package() - -=item get_dependencies() - -=item process_content() - -=item replicate_content() - -=item extract_media() - -=item store_template() - =item group_import() Imports the given (name, url) resources into the course @@ -4291,6 +7345,24 @@ Generate "dump" button =item do_paste_from_buffer() +=item do_buffer_empty() + +=item clear_from_buffer() + +=item get_newmap_url() + +=item dbcopy() + +=item uniqueness_check() + +=item contained_map_check() + +=item url_paste_fixups() + +=item apply_fixups() + +=item copy_dependencies() + =item update_parameter() =item handle_edit_cmd() @@ -4303,8 +7375,6 @@ Generate "dump" button =item is_supplemental_title() -=item parse_supplemental_title() - =item entryline() =item tiehash() @@ -4333,6 +7403,48 @@ Check Versions Breadcrumbs for special functions +=item create_list_elements() + +=item create_form_ul() + +=item startContentScreen() + +=item endContentScreen() + +=item supplemental_base() + +=item embedded_form_elems() + +=item embedded_destination() + +=item return_to_editor() + +=item decompression_info() + +=item decompression_phase_one() + +=item decompression_phase_two() + +=item remove_archive() + +=item generate_admin_menu() + +=item generate_edit_table() + +=item editing_js() + +=item history_tab_js() + +=item inject_data_js() + +=item dump_switchserver_js() + +=item resize_scrollbox_js() + +=item makedocslogform() + +=item makesimpleeditform() + =back =cut