--- loncom/interface/londocs.pm 2002/10/20 18:42:53 1.34 +++ loncom/interface/londocs.pm 2010/01/21 23:19:17 1.416 @@ -1,7 +1,7 @@ # The LearningOnline Network # Documents # -# $Id: londocs.pm,v 1.34 2002/10/20 18:42:53 www Exp $ +# $Id: londocs.pm,v 1.416 2010/01/21 23:19:17 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -26,16 +26,26 @@ # http://www.lon-capa.org/ # + + package Apache::londocs; use strict; use Apache::Constants qw(:common :http); +use Apache::imsexport; use Apache::lonnet; use Apache::loncommon; -use Apache::lonratedt; -use Apache::lonratsrv; +use Apache::lonhtmlcommon; +use LONCAPA::map(); +use Apache::lonratedt(); use Apache::lonxml; +use Apache::lonclonecourse; +use Apache::lonnavmaps; +use HTML::Entities; use GDBM_File; +use Apache::lonlocal; +use Cwd; +use LONCAPA qw(:DEFAULT :match); my $iconpath; @@ -44,211 +54,2108 @@ my %hash; my $hashtied; my %alreadyseen=(); -# Mapread read maps into lonratedt::global arrays -# @order and @resources, determines status -# sets @order - pointer to resources in right order -# sets @resources - array with the resources with correct idx -# +my $hadchanges; + + +my %help=(); + sub mapread { my ($coursenum,$coursedom,$map)=@_; return - &Apache::lonratedt::mapread('/uploaded/'.$coursedom.'/'.$coursenum.'/'. - $map); + &LONCAPA::map::mapread('/uploaded/'.$coursedom.'/'.$coursenum.'/'. + $map); } sub storemap { my ($coursenum,$coursedom,$map)=@_; - return - &Apache::lonratedt::storemap('/uploaded/'.$coursedom.'/'.$coursenum.'/'. - $map,1); + my ($outtext,$errtext)= + &LONCAPA::map::storemap('/uploaded/'.$coursedom.'/'.$coursenum.'/'. + $map,1); + if ($errtext) { return ($errtext,2); } + + $hadchanges=1; + return ($errtext,0); +} + + + +sub authorhosts { + my %outhash=(); + my $home=0; + my $other=0; + foreach my $key (keys(%env)) { + if ($key=~/^user\.role\.(au|ca)\.(.+)$/) { + my $role=$1; + my $realm=$2; + my ($start,$end)=split(/\./,$env{$key}); + if (($start) && ($start>time)) { next; } + if (($end) && (time>$end)) { next; } + my ($ca,$cd); + if ($1 eq 'au') { + $ca=$env{'user.name'}; + $cd=$env{'user.domain'}; + } else { + ($cd,$ca)=($realm=~/^\/($match_domain)\/($match_username)$/); + } + 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; } } + if ($allowed) { + $home++; + $outhash{'home_'.$ca.'@'.$cd}=1; + } else { + $outhash{'otherhome_'.$ca.'@'.$cd}=$myhome; + $other++; + } + } + } + return ($home,$other,%outhash); +} + + +sub dumpbutton { + my ($home,$other,%outhash)=&authorhosts(); + my $crstype = &Apache::loncommon::course_type(); + if ($home+$other==0) { return ''; } + if ($home) { + my $link = "<a onclick='javascript:injectData(document.courseverify, \"dummy\", \"dumpcourse\", \"".&mt('Dump '.$crstype.' DOCS to Construction Space')."\")'>".&mt('Dump '.$crstype.' DOCS to Construction Space')."</a>"; + return $link.' '. + &Apache::loncommon::help_open_topic('Docs_Dump_Course_Docs').'<br />'; + } else { + return '<div>'. + &mt('Dump '.$crstype. + ' DOCS to Construction Space: available on other servers'). + '</div>'; + } +} + +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.' DOCS to Construction Space'). + '<form name="dumpdoc" action="" method="post">'); + $r->print(&Apache::lonhtmlcommon::breadcrumbs('Dump '.$crstype.' DOCS 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('<h3>'.&mt('Copying Files').'</h3>'); + 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='/home/'.$ca.'/public_html'; + 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('<br /><tt>'.$item.'</tt> => <tt>'.$newfilename.'</tt>: '); + 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('<span class="LC_error">'.&mt('fail').'</span>'); + } else { + $r->print('<span class="LC_success">'.&mt('ok').'</span>'); + } + } + } else { +# Input form + unless ($home==1) { + $r->print( + '<h3>'.&mt('Select the Construction Space').'</h3><select name="authorspace">'); + } + foreach my $key (sort(keys(%outhash))) { + if ($key=~/^home_(.+)$/) { + if ($home==1) { + $r->print( + '<input type="hidden" name="authorspace" value="'.$1.'" />'); + } else { + $r->print('<option value="'.$1.'">'.$1.' - '. + &Apache::loncommon::plainname(split(/\@/,$1)).'</option>'); + } + } + } + unless ($home==1) { + $r->print('</select>'); + } + my $title=$origcrsdata{'description'}; + $title=~s/[\/\s]+/\_/gs; + $title=&clean($title); + $r->print('<h3>'.&mt('Folder in Construction Space').'</h3>' + .'<input type="text" size="50" name="authorfolder" value="'.$title.'" /><br />'); + &tiehash(); + $r->print('<h3>'.&mt('Filenames in Construction Space').'</h3>' + .&Apache::loncommon::start_data_table() + .&Apache::loncommon::start_data_table_header_row() + .'<th>'.&mt('Internal Filename').'</th>' + .'<th>'.&mt('Title').'</th>' + .'<th>'.&mt('Save as ...').'</th>' + .&Apache::loncommon::end_data_table_header_row()); + foreach my $file (&Apache::lonclonecourse::crsdirlist($origcrsid,'userfiles')) { + $r->print(&Apache::loncommon::start_data_table_row() + .'<td>'.$file.'</td>'); + my ($ext)=($file=~/\.(\w+)$/); + my $title=$hash{'title_'.$hash{ + 'ids_/uploaded/'.$origcrsdata{'domain'}.'/'.$origcrsdata{'num'}.'/'.$file}}; + $r->print('<td>'.($title?$title:' ').'</td>'); + if (!$title) { + $title=$file; + } else { + $title=~s|/|_|g; + } + $title=~s/\.(\w+)$//; + $title=&clean($title); + $title.='.'.$ext; + $r->print("\n<td><input type='text' size='60' name='namefor_".$file."' value='".$title."' /></td>" + .&Apache::loncommon::end_data_table_row()); + } + $r->print(&Apache::loncommon::end_data_table()); + &untiehash(); + $r->print( + '<p><input type="submit" name="dumpcourse" value="'.&mt("Dump $crstype DOCS").'" /></p></form>'); + } +} + + + +sub exportbutton { + my $crstype = &Apache::loncommon::course_type(); + return "<a onclick='javascript:injectData(document.courseverify, \"dummy\", \"exportcourse\", \"".&mt('IMS Export')."\")'>".&mt('IMS Export')."</a>". + &Apache::loncommon::help_open_topic('Docs_Export_Course_Docs').'<br />'; +} + + + +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 $navmap = Apache::lonnavmaps::navmap->new(); + if (!defined($navmap)) { + $r->print(&Apache::loncommon::start_page('Export '.$crstype.' to IMS Package'). + '<h2>'.&mt('IMS Export Failed').'</h2>'. + '<div class="LC_error">'); + 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('</div><a href="/adm/coursedocs">'); + if ($crstype eq 'Community') { + $r->print(&mt('Return to Community Editor')); + } else { + $r->print(&mt('Return to Course Editor')); + } + $r->print('</a>'); + &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 @exportitems = &Apache::loncommon::get_env_multiple('form.archive'); + my @discussions = &Apache::loncommon::get_env_multiple('form.discussion'); + if (@exportitems == 0 && @discussions == 0) { + $outcome = + '<p class="LC_warning">' + .&mt('As you did not select any content items or discussions' + .' for export, an IMS package has not been created.') + .'</p>' + .'<p>' + .&mt('Please [_1]go back[_2] to select either content items' + .' or discussions for export.' + ,'<a href="javascript:history.go(-1)">' + ,'</a>') + .'</p>'; + } else { + my $now = time; + my %symbs; + my $manifestok = 0; + my $imsresources; + my $tempexport; + my $copyresult; + my $ims_manifest = &create_ims_store($now,\$manifestok,\$outcome,\$tempexport); + if ($manifestok) { + &build_package($now,$navmap,\@exportitems,\@discussions,\$outcome,$tempexport,\$copyresult,$ims_manifest); + 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 .= '<p>' + .&mt('[_1]Your IMS package[_2] is ready for download.' + ,'<a href="'.$imszipfile.'">','</a>') + .'</p>'; + if ($copyresult) { + $outcome .= '<p class="LC_error">' + .&mt('The following errors occurred during export - [_1]' + ,$copyresult) + .'</p>'; + } + } else { + $outcome = '<p class="LC_error">' + .&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.') + .'</p>' + .'<p><a href="javascript:history.go(-1)">' + .&mt('Go Back') + .'</a></p>'; + } + } + $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='<form name="exportdoc" action="" method="post">'."\n". + '<p>'. + &mt('Choose which items you wish to export from your '.$crstype.'.'). + '</p>'. + '<div class="LC_columnSection"><fieldset>'. + '<legend>'.&mt('Content items').'</legend>'. + '<input type="button" value="'.&mt('check all').'" '. + 'onclick="javascript:checkAll(document.exportdoc.archive)" />'. + ' <input type="button" value="'.&mt('uncheck all').'"'. + ' onclick="javascript:uncheckAll(document.exportdoc.archive)" /></fieldset>'; + if ($numdisc > 0) { + $display .= '<fieldset>'. + '<legend>'.&mt('Discussion posts').'</legend>'. + '<input type="button" value="'.&mt('check all').'"'. + ' onclick="javascript:checkAll(document.exportdoc.discussion)" />'. + ' <input type="button" value="'.&mt('uncheck all').'"'. + ' onclick="javascript:uncheckAll(document.exportdoc.discussion)" />'. + '</fieldset>'; + } + $display .= '</div>'; + 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() + .'<th>'.&mt('Export content item?').'</th>'; + if ($numdisc > 0) { + $display .= '<th>'.&mt('Export discussion posts?').'</th>'; + } + $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() + .'<td>'."\n" + .'<input type="checkbox" name="archive" value="'.$count.'" '; + if (($curRes->is_sequence()) || ($curRes->is_page())) { + $lastcontainer = $currelem; + $display .= 'onclick="javascript:propagateCheck('."'$currelem'".')"'; + } + $display .= ' />'."\n"; + for (my $i=0; $i<$depth; $i++) { + $display .= ('<img src="/adm/lonIcons/whitespace1.gif" class="LC_docs_spacer" alt="" />' x2)."\n"; + } + if ($curRes->is_sequence()) { + $display .= '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" /> '."\n"; + } elsif ($curRes->is_page()) { + $display .= '<img src="/adm/lonIcons/navmap.page.open.gif" alt="" /> '."\n"; + } + $children{$parent{$depth}} .= $currelem.':'; + $display .= ' '.$curRes->title().'</td>'."\n"; + + # Existing discussion posts? + if ($discussiontime{$ressymb} > 0) { + $boards ++; + $display .= '<td align="right">' + .'<input type="checkbox" name="discussion" value="'.$count.'" />' + .'</td>'."\n"; + } elsif ($numdisc > 0) { + $display .= '<td> </td>'."\n"; + } + $display .= &Apache::loncommon::end_data_table_row(); + } + } + $display .= &Apache::loncommon::end_data_table(); + my $scripttag = qq| +<script type="text/javascript"> +// <![CDATA[ +function checkAll(field) { + if (field.length > 0) { + for (i = 0; i < field.length; i++) { + field[i].checked = true ; + } + } else { + field.checked = true + } +} + +function uncheckAll(field) { + if (field.length > 0) { + for (i = 0; i < field.length; i++) { + field[i].checked = false ; + } + } else { + field.checked = false ; + } +} + +function propagateCheck(item) { + if (document.exportdoc.elements[item].checked == true) { + containerCheck(item) + } +} + +function containerCheck(item) { + document.exportdoc.elements[item].checked = true + var numitems = $count + $boards + $startcount + var parents = new Array(numitems) + for (var i=$startcount; i<numitems; i++) { + parents[i] = new Array + } + |; + + foreach my $container (sort { $a <=> $b } (keys(%children))) { + my @contents = split(/:/,$children{$container}); + for (my $i=0; $i<@contents; $i ++) { + $scripttag .= ' parents['.$container.']['.$i.'] = '.$contents[$i]."\n"; + } + } + + $scripttag .= qq| + if (parents[item].length > 0) { + for (var j=0; j<parents[item].length; j++) { + containerCheck(parents[item][j]) + } + } +} +// ]]> +</script> + |; + $r->print(&Apache::loncommon::start_page('Export '.$crstype.' to IMS Package', + $scripttag)); + $r->print(&Apache::lonhtmlcommon::breadcrumbs('IMS Export')); + $r->print($display. + '<p><input type="hidden" name="finishexport" value="1" />'. + '<input type="submit" name="exportcourse" value="'. + &mt('Export').'" /></p></form>'); + } +} + +sub create_ims_store { + my ($now,$manifestok,$outcome,$tempexport) = @_; + $$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 +'<?xml version="1.0" encoding="UTF-8"?>'."\n". +'<manifest xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"'. +' xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2"'. +' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'. +' identifier="MANIFEST-'.$env{'request.course.id'}.'-'.$now.'"'. +' xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1imscp_v1p1.xsd'. +' http://www.imsglobal.org/xsd/imsmd_v1p2 imsmd_v1p2p2.xsd">'."\n". +' <metadata> + <schema></schema> + <imsmd:lom> + <imsmd:general> + <imsmd:identifier>'.$env{'request.course.id'}.'</imsmd:identifier> + <imsmd:title> + <imsmd:langstring xml:lang="en">'.$env{'course.'.$env{'request.course.id'}.'.description'}.'</imsmd:langstring> + </imsmd:title> + </imsmd:general> + </imsmd:lom> + </metadata>'."\n". +' <organizations default="ORG-'.$env{'request.course.id'}.'-'.$now.'">'."\n". +' <organization identifier="ORG-'.$env{'request.course.id'}.'-'.$now.'"'. +' structure="hierarchical">'."\n". +' <title>'.$env{'course.'.$env{'request.course.id'}.'.description'}.'</title>' + } else { + $$outcome .= 'An error occurred opening the IMS manifest file.<br />' +; + } + return $ims_manifest; +} + +sub build_package { + my ($now,$navmap,$exportitems,$discussions,$outcome,$tempexport,$copyresult,$ims_manifest) = @_; +# 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); + } + } + } +# 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; + while ($curRes = $it->next()) { + if ($curRes == $it->BEGIN_MAP()) { + $prevdepth = $depth; + $depth++; + } + if ($curRes == $it->END_MAP()) { + $prevdepth = $depth; + $depth--; + } + + 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".' </item>'."\n"; + $step --; + } + } + $prevdepth = $depth; + + my $itementry = + '<item identifier="ITEM-'.$env{'request.course.id'}.'-'.$count. + '" isvisible="'.$isvisible.'" '.$resourceref.'>'. + '<title>'.$curRes->title().'</title>'; + print $ims_manifest "\n".$itementry; + + unless ($curRes->is_sequence()) { + my $content_file; + my @hrefs = (); + &process_content($count,$curRes,$cdom,$cnum,$symb,\$content_file,\@hrefs,$copyresult,$tempexport); + if ($content_file) { + $imsresources .= "\n". + ' <resource identifier="RES-'.$env{'request.course.id'}.'-'.$count. + '" type="webcontent" href="'.$content_file.'">'."\n". + ' <file href="'.$content_file.'" />'."\n"; + foreach my $item (@hrefs) { + $imsresources .= + ' <file href="'.$item.'" />'."\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 .= ' </resource>'."\n"; + } + } + $pkgdepth = $depth; + } + } + } + while ($pkgdepth > 0) { + print $ims_manifest " </item>\n"; + $pkgdepth --; + } + my $resource_text = qq| + </organization> + </organizations> + <resources> + $imsresources + </resources> +</manifest> + |; + 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) = @_; + 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 ($canedit) { + $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'resource'); + } else { + $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'noedit'); + } + } 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"; + } + } + } + if ($message) { + $$copyresult .= $message."\n"; + } +} + +sub replicate_content { + my ($cdom,$cnum,$tempexport,$symb,$count,$message,$href,$caller) = @_; + 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; + } else { + &extract_media($url,$cdom,$cnum,\$content,$count,$tempexport,$href,$message,'resource'); + $repstatus = 'ok'; + } + } 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'); + } + } else { + $$message = 'Could not render '.$url.' server message - '.$rtncode."<br />\n"; + } + } elsif ($caller eq 'noedit') { +# Need to render the resource without the LON-CAPA Internal header and the Post discussion footer, and then set $content equal to this. + $repstatus = 'ok'; + $content = 'Not the owner of this resource'; + } + if ($repstatus eq 'ok') { + print $copiedfile $content; + } + close($copiedfile); + } else { + $$message = 'Could not open destination file for '.$filename."<br />\n"; + } + } else { + $$message = 'Could not determine name of file for '.$symb."<br />\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 + } else { + if ($embed_file =~ m-https?://-) { + next; # points to url + } else { + $embed_url = $dirpath.$embed_file; # points to relative path + } + } + if ($caller eq 'resource') { + my $respath = $Apache::lonnet::perlvar{'lonDocRoot'}.'/res'; + my $embed_path = &Apache::lonnet::filelocation($respath,$embed_url); + $embed_content = &Apache::lonnet::getfile($embed_path); + unless ($embed_content eq -1) { + $repstatus = 'ok'; + } + } elsif ($caller eq 'uploaded') { + + $repstatus = &Apache::lonnet::getuploaded('GET',$embed_url,$cdom,$cnum,\$embed_content,$rtncode); + } + if ($repstatus eq 'ok') { + my $destination = $tempexport.'/resources/'.$count.'/res'; + if (!-e "$destination") { + mkdir($destination,0755); + } + $destination .= '/'.$filename; + my $copiedfile; + if ($copiedfile = Apache::File->new('>'.$destination)) { + print $copiedfile $embed_content; + push(@{$href},'resources/'.$count.'/res/'.$filename); + my $attrib_regexp = ''; + if (@{$allfiles{$embed_file}} > 1) { + $attrib_regexp = join('|',@{$allfiles{$embed_file}}); + } 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; + } + } + } else { + $$message .= 'replication of embedded file - '.$embed_file.' in '.$url.' failed, reason -'.$rtncode."<br />\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); + } + if ($content_type eq 'external') { + return 'resources/'.$count.'/'.$content_type.'.html'; + } else { + return 'resources/'.$count.'/'.$content_type.'.xml'; + } + } + } +} + + +sub group_import { + my ($coursenum, $coursedom, $folder, $container, $caller, @files) = @_; + + while (@files) { + my ($name, $url, $residx) = @{ shift(@files) }; + if (($url =~ m{^/uploaded/\Q$coursedom\E/\Q$coursenum\E/(default_\d+\.)(page|sequence)$}) + && ($caller eq 'londocs') + && (!&Apache::lonnet::stat_file($url))) { + + my $errtext = ''; + my $fatal = 0; + my $newmapstr = '<map>'."\n". + '<resource id="1" src="" type="start"></resource>'."\n". + '<link from="1" to="2" index="1"></link>'."\n". + '<resource id="2" src="" type="finish"></resource>'."\n". + '</map>'; + $env{'form.output'}=$newmapstr; + my $result=&Apache::lonnet::finishuserfileupload($coursenum,$coursedom, + 'output',$1.$2); + if ($result != m|^/uploaded/|) { + $errtext.='Map not saved: A network error occurred when trying to save the new map. '; + $fatal = 2; + } + if ($fatal) { + return ($errtext,$fatal); + } + } + if ($url) { + if (!$residx + || defined($LONCAPA::map::zombies[$residx])) { + $residx = &LONCAPA::map::getresidx($url,$residx); + push(@LONCAPA::map::order, $residx); + } + my $ext = 'false'; + if ($url=~m{^http://} || $url=~m{^https://}) { $ext = 'true'; } + $url = &LONCAPA::map::qtunescape($url); + $name = &LONCAPA::map::qtunescape($name); + $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'}); + } + 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); +} + +sub log_docs { + return &Apache::lonnet::instructor_log('docslog',@_); +} + +{ + my @oldresources=(); + my @oldorder=(); + my $parmidx; + my %parmaction=(); + my %parmvalue=(); + my $changedflag; + + sub snapshotbefore { + @oldresources=@LONCAPA::map::resources; + @oldorder=@LONCAPA::map::order; + $parmidx=undef; + %parmaction=(); + %parmvalue=(); + $changedflag=0; + } + + sub remember_parms { + my ($idx,$parameter,$action,$value)=@_; + $parmidx=$idx; + $parmaction{$parameter}=$action; + $parmvalue{$parameter}=$value; + $changedflag=1; + } + + sub log_differences { + my ($plain)=@_; + my %storehash=('folder' => $plain, + 'currentfolder' => $env{'form.folder'}); + if ($parmidx) { + $storehash{'parameter_res'}=$oldresources[$parmidx]; + foreach my $parm (keys(%parmaction)) { + $storehash{'parameter_action_'.$parm}=$parmaction{$parm}; + $storehash{'parameter_value_'.$parm}=$parmvalue{$parm}; + } + } + my $maxidx=$#oldresources; + if ($#LONCAPA::map::resources>$#oldresources) { + $maxidx=$#LONCAPA::map::resources; + } + for (my $idx=0; $idx<=$maxidx; $idx++) { + if ($LONCAPA::map::resources[$idx] ne $oldresources[$idx]) { + $storehash{'before_resources_'.$idx}=$oldresources[$idx]; + $storehash{'after_resources_'.$idx}=$LONCAPA::map::resources[$idx]; + $changedflag=1; + } + if ($LONCAPA::map::order[$idx] ne $oldorder[$idx]) { + $storehash{'before_order_res_'.$idx}=$oldresources[$oldorder[$idx]]; + $storehash{'after_order_res_'.$idx}=$LONCAPA::map::resources[$LONCAPA::map::order[$idx]]; + $changedflag=1; + } + } + $storehash{'maxidx'}=$maxidx; + if ($changedflag) { &log_docs(\%storehash); } + } +} + + + + + +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 %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('<form action="/adm/coursedocs" method="post" name="docslog">'. + '<input type="hidden" name="docslog" value="1" />'); + + my %saveable_parameters = ('show' => 'scalar',); + &Apache::loncommon::store_course_settings('docs_log', + \%saveable_parameters); + &Apache::loncommon::restore_course_settings('docs_log', + \%saveable_parameters); + if (!$env{'form.show'}) { $env{'form.show'}=10; } + my %lt=('hiddenresource' => 'Resources hidden', + 'encrypturl' => 'URL hidden', + 'randompick' => 'Randomly pick', + 'randomorder' => 'Randomly ordered', + 'set' => 'set to', + 'del' => 'deleted'); + $r->print(&Apache::loncommon::display_filter(). + '<input type="hidden" name="folder" value="'.$folder.'" />'. + '<input type="submit" value="'.&mt('Display').'" /></form>'); + $r->print(&Apache::loncommon::start_data_table().&Apache::loncommon::start_data_table_header_row(). + '<th>'.&mt('Time').'</th><th>'.&mt('User').'</th><th>'.&mt('Folder').'</th><th>'.&mt('Before').'</th><th>'. + &mt('After').'</th>'. + &Apache::loncommon::end_data_table_header_row()); + my $shown=0; + foreach my $id (sort { $docslog{$b}{'exe_time'}<=>$docslog{$a}{'exe_time'} } (keys(%docslog))) { + if ($env{'form.displayfilter'} eq 'currentfolder') { + if ($docslog{$id}{'logentry'}{'currentfolder'} ne $folder) { next; } + } + my @changes=keys(%{$docslog{$id}{'logentry'}}); + if ($env{'form.displayfilter'} eq 'containing') { + my $wholeentry=$docslog{$id}{'exe_uname'}.':'.$docslog{$id}{'exe_udom'}.':'. + &Apache::loncommon::plainname($docslog{$id}{'exe_uname'},$docslog{$id}{'exe_udom'}); + foreach my $key (@changes) { + $wholeentry.=':'.$docslog{$id}{'logentry'}{$key}; + } + if ($wholeentry!~/\Q$env{'form.containingphrase'}\E/i) { next; } + } + my $count = 0; + my $time = + &Apache::lonlocal::locallocaltime($docslog{$id}{'exe_time'}); + my $plainname = + &Apache::loncommon::plainname($docslog{$id}{'exe_uname'}, + $docslog{$id}{'exe_udom'}); + my $about_me_link = + &Apache::loncommon::aboutmewrapper($plainname, + $docslog{$id}{'exe_uname'}, + $docslog{$id}{'exe_udom'}); + my $send_msg_link=''; + if ((($docslog{$id}{'exe_uname'} ne $env{'user.name'}) + || ($docslog{$id}{'exe_udom'} ne $env{'user.domain'}))) { + $send_msg_link ='<br />'. + &Apache::loncommon::messagewrapper(&mt('Send message'), + $docslog{$id}{'exe_uname'}, + $docslog{$id}{'exe_udom'}); + } + $r->print(&Apache::loncommon::start_data_table_row()); + $r->print('<td>'.$time.'</td> + <td>'.$about_me_link. + '<br /><tt>'.$docslog{$id}{'exe_uname'}. + ':'.$docslog{$id}{'exe_udom'}.'</tt>'. + $send_msg_link.'</td><td>'. + $docslog{$id}{'logentry'}{'folder'}.'</td><td>'); +# 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)); + } + } + $r->print('<ul>'); + for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) { + if ($docslog{$id}{'logentry'}{'before_order_res_'.$idx}) { + $r->print('<li>'.&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'before_order_res_'.$idx}))[0]).'</li>'); + } + } + $r->print('</ul>'); +# After + $r->print('</td><td>'); + + 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 '' && $oldname ne $newname) { + $r->print(&LONCAPA::map::qtescape($newname)); + } + } + $r->print('<ul>'); + for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) { + if ($docslog{$id}{'logentry'}{'after_order_res_'.$idx}) { + $r->print('<li>'.&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'after_order_res_'.$idx}))[0]).'</li>'); + } + } + $r->print('</ul>'); + if ($docslog{$id}{'logentry'}{'parameter_res'}) { + $r->print(&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'parameter_res'}))[0]).':<ul>'); + foreach my $parameter ('randompick','hiddenresource','encrypturl','randomorder') { + if ($docslog{$id}{'logentry'}{'parameter_action_'.$parameter}) { + $r->print('<li>'. + &mt($lt{$parameter}.' '.$lt{$docslog{$id}{'logentry'}{'parameter_action_'.$parameter}}.' [_1]', + $docslog{$id}{'logentry'}{'parameter_value_'.$parameter}) + .'</li>'); + } + } + $r->print('</ul>'); + } +# End + $r->print('</td>'.&Apache::loncommon::end_data_table_row()); + $shown++; + if (!($env{'form.show'} eq &mt('all') + || $shown<=$env{'form.show'})) { last; } + } + $r->print(&Apache::loncommon::end_data_table()); +} + +sub update_paste_buffer { + my ($coursenum,$coursedom) = @_; + + return if (!defined($env{'form.markcopy'})); + 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'); + } + $url=~s{http(:|:)//https(:|:)//}{https$2//}; + + &Apache::lonnet::appenv({'docs.markedcopy_title' => $title, + 'docs.markedcopy_url' => $url}); + delete($env{'form.markcopy'}); +} + +sub print_paste_buffer { + my ($r,$container) = @_; + return if (!defined($env{'docs.markedcopy_url'})); + + $r->print('<fieldset>' + .'<legend>'.&mt('Clipboard').'</legend>' + .'<form name="pasteform" action="/adm/coursedocs" method="post">' + .'<input type="submit" name="pastemarked" value="'.&mt('Paste').'" /> ' + ); + + 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 = '<img src="'.$icon.'" alt="" class="LC_icon" />'; + $r->print($icon.$type.': '. &parse_supplemental_title(&LONCAPA::map::qtescape($env{'docs.markedcopy_title'}))); + } + if ($container eq 'page') { + $r->print(' + <input type="hidden" name="pagepath" value="'.&HTML::Entities::encode($env{'form.pagepath'},'<>&"').'" /> + <input type="hidden" name="pagesymb" value="'.&HTML::Entities::encode($env{'form.pagesymb'},'<>&"').'" /> +'); + } else { + $r->print(' + <input type="hidden" name="folderpath" value="'.&HTML::Entities::encode($env{'form.folderpath'},'<>&"').'" /> +'); + } + $r->print('</form></fieldset>'); +} + +sub do_paste_from_buffer { + my ($coursenum,$coursedom,$folder) = @_; + + if (!$env{'form.pastemarked'}) { + 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'}); +# 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); + } + $oldid = $path.$prefix.$ancestor; + } + my $counter = 0; + my $newurl=$oldid.$newid.'.'.$ext; + my $is_unique = &uniqueness_check($newurl); + while (!$is_unique && $counter < 100) { + $counter ++; + $newid ++; + $newurl = $oldid.$newid; + $is_unique = &uniqueness_check($newurl); + } + if (!$is_unique) { + if ($url=~/\.page$/) { + return &mt('Paste failed: an error occurred creating a unique URL for the composite page'); + } else { + return &mt('Paste failed: an error occurred creating a unique URL for the folder'); + } + } + my $storefn=$newurl; + $storefn=~s{^/\w+/$match_domain/$match_username/}{}; + my $paste_map_result = + &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn, + &Apache::lonnet::getfile($url)); + if ($paste_map_result eq '/adm/notfound.html') { + if ($url=~/\.page$/) { + return &mt('Paste failed: an error occurred saving the composite page'); + } else { + return &mt('Paste failed: an error occurred saving the folder'); + } + } + $url = $newurl; + } +# 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; + } + } + + $LONCAPA::map::resources[$newidx]= $title.':'.$url.':'.$ext.':normal:res'; + push(@LONCAPA::map::order, $newidx); + return 'ok'; +# Store the result +} + +sub uniqueness_check { + my ($newurl) = @_; + my $unique = 1; + foreach my $res (@LONCAPA::map::order) { + my ($name,$url)=split(/\:/,$LONCAPA::map::resources[$res]); + $url=&LONCAPA::map::qtescape($url); + if ($newurl eq $url) { + $unique = 0; + last; + } + } + return $unique; +} + +my %parameter_type = ( 'randompick' => 'int_pos', + 'hiddenresource' => 'string_yesno', + 'encrypturl' => 'string_yesno', + 'randomorder' => 'string_yesno',); +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); + } else { + &LONCAPA::map::delparameter($idx,'parameter_'.$which); + + &remember_parms($idx,$which,'del'); + } + return 1; +} + + +sub handle_edit_cmd { + my ($coursenum,$coursedom) =@_; + + 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 (($url=~m|/+uploaded/\Q$coursedom\E/\Q$coursenum\E/|) && + ($url!~/\.(page|sequence|problem|exam|quiz|assess|survey|form|library|task)$/)) { + &Apache::lonnet::removeuploadedurl($url); + } else { + &LONCAPA::map::makezombie($LONCAPA::map::order[$idx]); + } + splice(@LONCAPA::map::order, $idx, 1); + + } elsif ($cmd eq 'cut') { + &LONCAPA::map::makezombie($LONCAPA::map::order[$idx]); + splice(@LONCAPA::map::order, $idx, 1); + + } elsif ($cmd eq 'up' + && ($idx) && (defined($LONCAPA::map::order[$idx-1]))) { + @LONCAPA::map::order[$idx-1,$idx] = @LONCAPA::map::order[$idx,$idx-1]; + + } elsif ($cmd eq 'down' + && defined($LONCAPA::map::order[$idx+1])) { + @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]]= + $comment.':'.join(':', $url, @rrest); + } +# Devalidate title cache + my $renamed_url=&LONCAPA::map::qtescape($url); + &Apache::lonnet::devalidate_title_cache($renamed_url); + } else { + return 0; + } + return 1; } sub editor { - my ($r,$coursenum,$coursedom,$folder,$allowed)=@_; - if ($ENV{'form.foldername'}) { - $r->print('<h3>Folder: '.$ENV{'form.foldername'}.'</h3>'); - } - my $errtext=''; - my $fatal=0; - ($errtext,$fatal)= - &mapread($coursenum,$coursedom,$folder.'.sequence'); - if ($#Apache::lonratedt::order<1) { - $Apache::lonratedt::order[0]=1; - $Apache::lonratedt::resources[1]=''; + my ($r,$coursenum,$coursedom,$folder,$allowed,$upload_output,$crstype)=@_; + my $container= ($env{'form.pagepath'}) ? 'page' + : 'sequence'; + + my ($errtext,$fatal) = &mapread($coursenum,$coursedom, + $folder.'.'.$container); + return $errtext if ($fatal); + + if ($#LONCAPA::map::order<1) { + my $idx=&LONCAPA::map::getresidx(); + if ($idx<=0) { $idx=1; } + $LONCAPA::map::order[0]=$idx; + $LONCAPA::map::resources[$idx]=''; } - if ($fatal) { - $r->print('<p><font color="red">'.$errtext.'</font></p>'); + + my ($breadcrumbtrail,$randompick,$ishidden,$isencrypted,$plain,$is_random_order); + if ($allowed) { + ($breadcrumbtrail,$randompick,$ishidden,$isencrypted,$plain,$is_random_order) = + &breadcrumbs($allowed,$crstype); + $r->print($breadcrumbtrail); } else { + $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) && ($env{'form.folder'} eq $folder)) { +# set parameters and change order + &snapshotbefore(); + + if (&update_parameter()) { + ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container); + return $errtext if ($fatal); + } + + if ($env{'form.newpos'} && $env{'form.currentpos'}) { +# change order + my $res = splice(@LONCAPA::map::order,$env{'form.currentpos'}-1,1); + splice(@LONCAPA::map::order,$env{'form.newpos'}-1,0,$res); + + ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container); + return $errtext if ($fatal); + } + + 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('<p><span class="LC_error">'.$paste_res.'</span></p>'); + } + } + + $r->print($upload_output); + + if (&handle_edit_cmd()) { + ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container); + 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); + push(@imports, [$name, $url, $residx]); + } + } + ($errtext,$fatal)=&group_import($coursenum, $coursedom, $folder, + $container,'londocs',@imports); + return $errtext if ($fatal); + } +# Loading a complete map + if ($env{'form.loadmap'}) { + if ($env{'form.importmap'}=~/\w/) { + foreach my $res (&Apache::lonsequence::attemptread(&Apache::lonnet::filelocation('',$env{'form.importmap'}))) { + my ($title,$url,$ext,$type)=split(/\:/,$res); + my $idx=&LONCAPA::map::getresidx($url); + $LONCAPA::map::resources[$idx]=$res; + $LONCAPA::map::order[$#LONCAPA::map::order+1]=$idx; + } + ($errtext,$fatal)=&storemap($coursenum,$coursedom, + $folder.'.'.$container); + return $errtext if ($fatal); + } else { + $r->print('<p><span class="LC_error">'.&mt('No map selected.').'</span></p>'); + + } + } + &log_differences($plain); + } +# ---------------------------------------------------------------- End commands +# ---------------------------------------------------------------- Print screen + my $idx=0; + my $shown=0; + if (($ishidden) || ($isencrypted) || ($randompick>=0) || ($is_random_order)) { + $r->print('<div class="LC_Box">'. + '<p>'.&mt('Parameters:'). + '<ul>'. + ($randompick>=0?'<li>'.&mt('randomly pick [quant,_1,resource]',$randompick).'</li>':''). + ($ishidden?'<li>'.&mt('contents hidden').'</li>':''). + ($isencrypted?'<li>'.&mt('URLs hidden').'</li>':''). + ($is_random_order?'<li>'.&mt('random order').'</li>':''). + '</ul></p>'); + if ($randompick>=0) { + $r->print('<p class="LC_warning">' + .&mt('Caution: this folder is set to randomly pick a subset' + .' of resources. Adding or removing resources from this' + .' folder will change the set of resources that the' + .' students see, resulting in spurious or missing credit' + .' for completed problems, not limited to ones you' + .' modify. Do not modify the contents of this folder if' + .' it is in active student use.') + .'</p>' + ); + } + if ($is_random_order) { + $r->print('<p class="LC_warning">' + .&mt('Caution: this folder is set to randomly order its' + .' contents. Adding or removing resources from this folder' + .' will change the order of resources shown.') + .'</p>' + ); + } + $r->print('</div>'); + } + + my $output; + foreach my $res (@LONCAPA::map::order) { + my ($name,$url)=split(/\:/,$LONCAPA::map::resources[$res]); + $name=&LONCAPA::map::qtescape($name); + $url=&LONCAPA::map::qtescape($url); + unless ($name) { $name=(split(/\//,$url))[-1]; } + unless ($name) { $idx++; next; } + $output .= &entryline($idx,$name,$url,$folder,$allowed,$res, + $coursenum,$crstype); + $idx++; + $shown++; + } + if ($shown) { + $r->print(&Apache::loncommon::start_data_table()); + if ($allowed) { + $r->print(&Apache::loncommon::start_data_table_header_row() + .'<th colspan="2">'.&mt('Move').'</th>' + .'<th>'.&mt('Actions').'</th>' + .'<th colspan="2">'.&mt('Document').'</th>'); + if ($folder !~ /^supplemental/) { + $->print('<th colspan="4">'.&mt('Settings').'</th>'); + } + $r->print(&Apache::loncommon::end_data_table_header_row()); + } + $r->print($output + .&Apache::loncommon::end_data_table() + ); + } else { + $r->print('<p class="LC_info">' + .&mt('Currently no documents.') + .'</p>' + ); + } + if ($allowed) { + &print_paste_buffer($r,$container); + } + return; +} + +sub process_file_upload { + my ($upload_output,$coursenum,$coursedom,$allfiles,$codebase,$uploadcmd) = @_; # upload a file, if present - if (($ENV{'form.uploaddoc.filename'}) && - ($ENV{'form.cmd'}=~/^upload_(\w+)/)) { - if ($folder=~/^$1/) { + my $parseaction; + if ($env{'form.parserflag'}) { + $parseaction = 'parse'; + } + my $phase_status; + my $folder=$env{'form.folder'}; + if ($folder eq '') { + $folder='default'; + } + if ( ($folder=~/^$uploadcmd/) || ($uploadcmd eq 'default') ) { + my $errtext=''; + my $fatal=0; + my $container='sequence'; + if ($env{'form.pagepath'}) { + $container='page'; + } + ($errtext,$fatal)= + &mapread($coursenum,$coursedom,$folder.'.'.$container); + if ($#LONCAPA::map::order<1) { + $LONCAPA::map::order[0]=1; + $LONCAPA::map::resources[1]=''; + } + if ($fatal) { + return 'failed'; + } + my $destination = 'docs/'; + if ($folder =~ /^supplemental/) { + $destination = 'supplemental/'; + } + if (($folder eq 'default') || ($folder eq 'supplemental')) { + $destination .= 'default/'; + } elsif ($folder =~ /^(default|supplemental)_(\d+)$/) { + $destination .= $2.'/'; + } # this is for a course, not a user, so set coursedoc flag # probably the only place in the system where this should be "1" - my $url=&Apache::lonnet::userfileupload('uploaddoc',1); - my $ext='false'; - if ($url=~/^http\:\/\//) { $ext='true'; } - $url=~s/\:/\:/g; - my $comment=$ENV{'form.comment'}; - $comment=~s/\</\<\;/g; - $comment=~s/\>/\>\;/g; - $comment=~s/\:/\:/g; - if ($folder=~/^supplemental/) { - $comment=time.'___&&&___'.$ENV{'user.name'}.'___&&&___'. - $ENV{'user.domain'}.'___&&&___'.$comment; - } - my $newidx=$#Apache::lonratedt::resources+1; - $Apache::lonratedt::resources[$newidx]= - $comment.':'.$url.':'.$ext.':normal:res'; - $Apache::lonratedt::order[$#Apache::lonratedt::order+1]= - $newidx; - &storemap($coursenum,$coursedom,$folder.'.sequence'); - } - } - if ($ENV{'form.cmd'}) { - my ($cmd,$idx)=split(/\_/,$ENV{'form.cmd'}); - if ($cmd eq 'del') { - for (my $i=$idx;$i<$#Apache::lonratedt::order;$i++) { - $Apache::lonratedt::order[$i]= - $Apache::lonratedt::order[$i+1]; - } - $#Apache::lonratedt::order--; - } elsif ($cmd eq 'up') { - my $i=$Apache::lonratedt::order[$idx-1]; - $Apache::lonratedt::order[$idx-1]= - $Apache::lonratedt::order[$idx]; - $Apache::lonratedt::order[$idx]=$i; - } elsif ($cmd eq 'down') { - my $i=$Apache::lonratedt::order[$idx+1]; - $Apache::lonratedt::order[$idx+1]= - $Apache::lonratedt::order[$idx]; - $Apache::lonratedt::order[$idx]=$i; + my $newidx=&LONCAPA::map::getresidx(); + $destination .= $newidx; + my $url=&Apache::lonnet::userfileupload('uploaddoc',1,$destination, + $parseaction,$allfiles, + $codebase); + my $ext='false'; + if ($url=~m{^http://}) { $ext='true'; } + $url = &LONCAPA::map::qtunescape($url); + my $comment=$env{'form.comment'}; + $comment = &LONCAPA::map::qtunescape($comment); + if ($folder=~/^supplemental/) { + $comment=time.'___&&&___'.$env{'user.name'}.'___&&&___'. + $env{'user.domain'}.'___&&&___'.$comment; + } + + $LONCAPA::map::resources[$newidx]= + $comment.':'.$url.':'.$ext.':normal:res'; + $LONCAPA::map::order[$#LONCAPA::map::order+1]= $newidx; + ($errtext,$fatal)=&storemap($coursenum,$coursedom, + $folder.'.'.$container); + if ($fatal) { + $$upload_output .= '<p><span class="LC_error">'.$errtext.'</span></p>'; + return 'failed'; + } else { + if ($parseaction eq 'parse') { + my $total_embedded = scalar(keys(%{$allfiles})); + if ($total_embedded > 0) { + my $num = 0; + my $state = ' + <input type="hidden" name="folderpath" value="'.&HTML::Entities::encode($env{'form.folderpath'},'<>&"').'" /> + <input type="hidden" name="cmd" value="upload_embedded" /> + <input type="hidden" name="newidx" value="'.$newidx.'" /> + <input type="hidden" name="primaryurl" value="'.&escape($url).'" /> + <input type="hidden" name="phasetwo" value="'.$total_embedded.'" />'; + $phase_status = 'phasetwo'; + + $$upload_output .= + 'This file contains embedded multimedia objects, which need to be uploaded to LON-CAPA.<br />'. + &Apache::loncommon::ask_for_embedded_content( + '/adm/coursedocs',$state,$allfiles,$codebase); + } else { + $$upload_output .= 'No embedded items identified<br />'; } -# Store the changed version - &storemap($coursenum,$coursedom,$folder.'.sequence'); } -# Group import/search - if ($ENV{'form.importdetail'}) { - foreach (split(/\&/,$ENV{'form.importdetail'})) { - if (defined($_)) { - my ($name,$url)=split(/\=/,$_); - $name=&Apache::lonnet::unescape($name); - $url=&Apache::lonnet::unescape($url); - if ($url) { - my $idx=$#Apache::lonratedt::resources+1; - $Apache::lonratedt::order - [$#Apache::lonratedt::order+1]=$idx; - my $ext='false'; - if ($url=~/^http\:\/\//) { $ext='true'; } - $url=~s/\:/\:/g; - $Apache::lonratedt::resources[$idx]= - $name.':'.$url.':'.$ext.':normal:res'; - } - } - } -# Store the changed version - &storemap($coursenum,$coursedom,$folder.'.sequence'); - } - } -# ---------------------------------------------------------------- End commands -# ---------------------------------------------------------------- Print screen - my $idx=0; - $r->print('<table>'); - foreach (@Apache::lonratedt::order) { - my ($name,$url)=split(/\:/,$Apache::lonratedt::resources[$_]); - unless ($name) { $name=(split(/\//,$url))[-1]; } - unless ($name) { $name='EMPTY'; } - $r->print(&entryline($idx,$name,$url,$folder,$allowed)); - $idx++; } - $r->print('</table>'); } + return $phase_status; +} + +sub process_secondary_uploads { + my ($upload_output,$coursedom,$coursenum,$formname,$num,$newidx) = @_; + my $folder=$env{'form.folder'}; + my $destination = 'docs/'; + if ($folder =~ /^supplemental/) { + $destination = 'supplemental/'; + } + if (($folder eq 'default') || ($folder eq 'supplemental')) { + $destination .= 'default/'; + } elsif ($folder =~ /^(default|supplemental)_(\d+)$/) { + $destination .= $2.'/'; + } + $destination .= $newidx; + my ($url,$filename); + $url=&Apache::lonnet::userfileupload($formname.$num,1,$destination); + ($filename) = ($url =~ m{^/uploaded/\Q$coursedom\E/\Q$coursenum\E/\Q$destination\E/(.+)$}); + return $filename; +} + +sub is_supplemental_title { + my ($title) = @_; + return scalar($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/); +} + +sub parse_supplemental_title { + my ($title) = @_; + + my ($foldertitle,$renametitle); + if ($title =~ /&&&/) { + $title = &HTML::Entites::decode($title); + } + if ($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/) { + $renametitle=$4; + my ($time,$uname,$udom) = ($1,$2,$3); + $foldertitle=&Apache::lontexconvert::msgtexconverted($4); + my $name = &Apache::loncommon::plainname($uname,$udom); + $name = &HTML::Entities::encode($name,'"<>&\''); + $title='<i>'.&Apache::lonlocal::locallocaltime($time).'</i> '. + $name.': <br />'.$foldertitle; + } + if (wantarray) { + return ($title,$foldertitle,$renametitle); + } + return $title; } # --------------------------------------------------------------- An entry line sub entryline { - my ($index,$title,$url,$folder,$allowed)=@_; - my $line='<tr>'; + my ($index,$title,$url,$folder,$allowed,$residx,$coursenum,$crstype)=@_; + my ($foldertitle,$pagetitle,$renametitle); + if (&is_supplemental_title($title)) { + ($title,$foldertitle,$renametitle) = &parse_supplemental_title($title); + $pagetitle = $foldertitle; + } else { + $title=&HTML::Entities::encode($title,'"<>&\''); + $renametitle=$title; + $foldertitle=$title; + $pagetitle=$title; + } + + my $orderidx=$LONCAPA::map::order[$index]; + + + $renametitle=~s/\\/\\\\/g; + $renametitle=~s/\"\;/\\\"/g; + $renametitle=~s/ /%20/g; + my $line=&Apache::loncommon::start_data_table_row(); + my ($form_start,$form_end); # Edit commands + my ($container, $type, $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($path = $env{'form.pagepath'}); + $path = &HTML::Entities::encode($env{'form.pagepath'},'<>&"'); + $symb=&escape($env{'form.pagesymb'}); + } + my $cpinfo=''; if ($allowed) { - $line.=(<<END); -<td><table border='0' cellspacing='0' cellpadding='0'> -<tr><td><a href='/adm/coursedocs?folder=$folder&cmd=up_$index'> -<img src="${iconpath}move_up.gif" alt='UP' border='0' /></a></td></tr> -<tr><td><a href='/adm/coursedocs?folder=$folder&cmd=down_$index'> -<img src="${iconpath}move_down.gif" alt='DOWN' border='0' /></a></td></tr> -</table></td><td> -<a href='/adm/coursedocs?folder=$folder&cmd=del_$index'>Remove</td> + my $incindex=$index+1; + my $selectbox=''; + if (($folder!~/^supplemental/) && + ($#LONCAPA::map::order>0) && + ((split(/\:/, + $LONCAPA::map::resources[$LONCAPA::map::order[0]]))[1] + ne '') && + ((split(/\:/, + $LONCAPA::map::resources[$LONCAPA::map::order[1]]))[1] + ne '')) { + $selectbox= + '<input type="hidden" name="currentpos" value="'.$incindex.'" />'. + '<select name="newpos" onchange="this.form.submit()">'; + for (my $i=1;$i<=$#LONCAPA::map::order+1;$i++) { + if ($i==$incindex) { + $selectbox.='<option value="" selected="selected">('.$i.')</option>'; + } else { + $selectbox.='<option value="'.$i.'">'.$i.'</option>'; + } + } + $selectbox.='</select>'; + } + my %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=' '; + + my $skip_confirm = 0; + if ( $folder =~ /^supplemental/ + || ($url =~ m{( /smppg$ + |/syllabus$ + |/aboutme$ + |/navmaps$ + |/bulletinboard$ + |\.html$ + |^/adm/wrapper/ext)}x)) { + $skip_confirm = 1; + } + + if (!$nocopy) { + $copylink=(<<ENDCOPY); +<a href='javascript:markcopy("$esc_path","$index","$renametitle","$container","$symb","$folder");' class="LC_docs_copy">$lt{'cp'}</a> +ENDCOPY + } + if (!$nocut) { + $cutlink=(<<ENDCUT); +<a href='javascript:cutres("$esc_path","$index","$renametitle","$container","$symb","$folder",$skip_confirm);' class="LC_docs_cut">$lt{'ct'}</a> +ENDCUT + } + $form_start = (<<END); + <form action="/adm/coursedocs" method="post"> + <input type="hidden" name="${type}path" value="$path" /> + <input type="hidden" name="${type}symb" value="$symb" /> + <input type="hidden" name="setparms" value="$orderidx" /> + <input type="hidden" name="changeparms" value="0" /> +END + $form_end = '</form>'; + $line.=(<<END); +<td> +<div class="LC_docs_entry_move"> + <a href='/adm/coursedocs?cmd=up_$index&${type}path=$esc_path&${type}symb=$symb$cpinfo'> + <img src="${iconpath}move_up.gif" alt='$lt{'up'}' class="LC_icon" /> + </a> +</div> +<div class="LC_docs_entry_move"> + <a href='/adm/coursedocs?cmd=down_$index&${type}path=$esc_path&${type}symb=$symb$cpinfo'> + <img src="${iconpath}move_down.gif" alt='$lt{'dw'}' class="LC_icon" /> + </a> +</div> +</td> +<td> + $form_start + $selectbox + $form_end +</td> +<td class="LC_docs_entry_commands"> + <a href='javascript:removeres("$esc_path","$index","$renametitle","$container","$symb",$skip_confirm);' class="LC_docs_remove">$lt{'rm'}</a> +$cutlink + <a href='javascript:changename("$esc_path","$index","$renametitle","$container","$symb");' class="LC_docs_rename">$lt{'rn'}</a> +$copylink +</td> END + } # Figure out what kind of a resource this is my ($extension)=($url=~/\.(\w+)$/); my $uploaded=($url=~/^\/*uploaded\//); - my $icon='unknown'; - if (-e "/home/httpd/html/adm/lonIcons/$extension.gif") { - $icon=$extension; - } + my $icon=&Apache::loncommon::icon($url); my $isfolder=0; + my $ispage=0; + my $folderarg; + my $pagearg; + my $pagefile; if ($uploaded) { - if ($extension eq 'sequence') { - $icon='folder_closed'; - $url=~/\/(\w+)\.sequence/; - $url='/adm/coursedocs?folder='.$1; - $isfolder=1; - } else { - $url=&Apache::lonnet::tokenwrapper($url); - } + 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; + } else { + &Apache::lonnet::allowuploaded('/adm/coursedoc',$url); + } + } + + 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; + } + } elsif ($url=~m|^/ext/|) { + $url='/adm/wrapper'.$url; + $external = 1; + } + if (&Apache::lonnet::symbverify($symb,$url)) { + $url.=(($url=~/\?/)?'&':'?').'symb='.&escape($symb); + } else { + $url=''; + } + 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 $foldername=&escape($foldertitle); + my $folderpath=$env{'form.folderpath'}; + if ($folderpath) { $folderpath.='&' }; +# 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='<label>'.&mt('Randomly Pick: '). + '<input type="text" size="4" onchange="this.form.changeparms.value='."'randompick'".';this.form.submit()" name="randompick_'.$orderidx.'" value="'. + (&LONCAPA::map::getparameter($orderidx, + 'parameter_randompick'))[0]. + '" />'. +'<a href="javascript:void(0)">'.&mt('Save').'</a></label>'; + my $ro_set= + ((&LONCAPA::map::getparameter($orderidx,'parameter_randomorder'))[0]=~/^yes$/i?' checked="checked"':''); + $rand_order_text =' +<span class="LC_nobreak"><label><input type="checkbox" name="randomorder_'.$orderidx.'" onclick="this.form.changeparms.value=\'randomorder\';this.form.submit()" '.$ro_set.' /> '.&mt('Random Order').' </label></span>'; + } + 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; + } + if (($external) && ($allowed)) { + my $form = ($folder =~ /^default/)? 'newext' : 'supnewext'; + $external = ' <a class="LC_docs_ext_edit" href="javascript:edittext(\''.$form.'\',\''.$residx.'\',\''.&escape($title).'\',\''.&escape($orig_url).'\');" >'.&mt('Edit').'</a>'; + } else { + undef($external); } - $url=~s/^http\&colon\;\/\//\/adm\/wrapper\/ext\//; -# Title - $title=&Apache::lonnet::unescape($title); - my $foldertitle=$title; - if ($title=~ - /^(\d+)\_\_\_\&\&\&\_\_\_(\w+)\_\_\_\&\&\&\_\_\_(\w+)\_\_\_\&\&\&\_\_\_(.*)$/ - ) { - $foldertitle=&Apache::lontexconvert::msgtexconverted($4); - $title='<i>'.localtime($1).'</i> '. - &Apache::loncommon::plainname($2,$3).': <br>'. - $foldertitle; - } - if ($isfolder) { $url.='&foldername='.$foldertitle; } - $line.='<td bgcolor="#FFFFBB"><a href="'.$url.'" target="cat_'.$folder. -'"><img src="/adm/lonIcons/'. - $icon.'.gif" border="0"></a></td>'. - "<td bgcolor='#FFFFBB'><a href='$url' target='cat_$folder'>$title</a></td></tr>"; + my $reinit; + if ($crstype eq 'Community') { + $reinit = &mt('(re-initialize community to access)'); + } else { + $reinit = &mt('(re-initialize course to access)'); + } + $line.=' + <td> + '.($url?'<a href="'.$url.'">':'').'<img src="'.$icon.'" alt="" class="LC_icon" />'.($url?'</a>':'').' + </td> + <td> + '.($url?"<a href=\"$url\">":'').$title.($url?'</a>':' <span class="LC_docs_reinit_warn">'.$reinit.'</span>').$external." + </td>"; + 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"':''); + $line.=(<<ENDPARMS); + <td class="LC_docs_entry_parameter"> + $form_start + <label><input type="checkbox" name="hiddenresource_$orderidx" onclick="this.form.changeparms.value='hiddenresource';this.form.submit()" $hidtext /> $lt{'hd'}</label> + $form_end + </td> + <td class="LC_docs_entry_parameter"> + $form_start + <label><input type="checkbox" name="encrypturl_$orderidx" onclick="this.form.changeparms.value='encrypturl';this.form.submit()" $enctext /> $lt{'ec'}</label> + $form_end + </td> + <td class="LC_docs_entry_parameter">$form_start $rand_order_text $form_end</td> + <td class="LC_docs_entry_parameter">$form_start $parameterset $form_end</td> +ENDPARMS + } + $line.=&Apache::loncommon::end_data_table_row(); return $line; } -# ---------------------------------------------------------------- tie the hash +=pod + +=item tiehash() + +tie the hash + +=cut sub tiehash { + my ($mode)=@_; $hashtied=0; - if ($ENV{'request.course.fn'}) { - if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.".db", - &GDBM_READER(),0640)) { + if ($env{'request.course.fn'}) { + if ($mode eq 'write') { + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.".db", + &GDBM_WRCREAT(),0640)) { + $hashtied=2; + } + } else { + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.".db", + &GDBM_READER(),0640)) { $hashtied=1; - } - } + } + } + } } sub untiehash { if ($hashtied) { untie %hash; } $hashtied=0; + return OK; } -# --------------------------------------------------------------- check on this + + sub checkonthis { my ($r,$url,$level,$title)=@_; + $url=&unescape($url); $alreadyseen{$url}=1; $r->rflush(); - if ($url) { - $r->print('<br />'); + if (($url) && ($url!~/^\/uploaded\//) && ($url!~/\*$/)) { + $r->print("\n<br />"); + if ($level==0) { + $r->print("<br />"); + } for (my $i=0;$i<=$level*5;$i++) { $r->print(' '); } @@ -257,467 +2164,1756 @@ sub checkonthis { if ($url=~/^\/res\//) { my $result=&Apache::lonnet::repcopy( &Apache::lonnet::filelocation('',$url)); - if ($result==OK) { - $r->print('<font color="green">ok</font>'); + if ($result eq 'ok') { + $r->print('<span class="LC_success">'.&mt('ok').'</span>'); $r->rflush(); &Apache::lonnet::countacc($url); $url=~/\.(\w+)$/; if (&Apache::loncommon::fileembstyle($1) eq 'ssi') { $r->print('<br />'); $r->rflush(); - my $default=''; - if ($1=~/(problem|exam|quiz|assess|survey|form|library)/) { - $default=&Apache::lonnet::getfile( - '/home/httpd/html/res/adm/includes/default_homework.lcpm'); - } for (my $i=0;$i<=$level*5;$i++) { $r->print(' '); } - $r->print('- Rendering: '); - &Apache::lonxml::xmlparse($r,'web', - &Apache::lonnet::getfile( - &Apache::lonnet::filelocation('',$url)),$default); - if (($Apache::lonxml::errorcount) || - ($Apache::lonxml::warningcount)) { - if ($Apache::lonxml::errorcount) { - $r->print('<font color="red"><b>'. - $Apache::lonxml::errorcount.' error(s)</b></font> '); + $r->print('- '.&mt('Rendering:').' '); + my ($errorcount,$warningcount)=split(/:/, + &Apache::lonnet::ssi_body($url, + ('grade_target'=>'web', + 'return_only_error_and_warning_counts' => 1))); + if (($errorcount) || + ($warningcount)) { + if ($errorcount) { + $r->print('<img src="/adm/lonMisc/bomb.gif" alt="'.&mt('bomb').'" /><span class="LC_error">'. + &mt('[quant,_1,error]',$errorcount).'</span>'); } - if ($Apache::lonxml::warningcount) { - $r->print('<font color="blue">'. - $Apache::lonxml::warningcount.' warning(s)</font>'); + if ($warningcount) { + $r->print('<span class="LC_warning">'. + &mt('[quant,_1,warning]',$warningcount).'</span>'); } } else { - $r->print('<font color="green">ok</font>'); + $r->print('<span class="LC_success">'.&mt('ok').'</span>'); } $r->rflush(); } my $dependencies= &Apache::lonnet::metadata($url,'dependencies'); - foreach (split(/\,/,$dependencies)) { - if (($_=~/^\/res\//) && (!$alreadyseen{$_})) { - &checkonthis($r,$_,$level+1); + foreach my $dep (split(/\,/,$dependencies)) { + if (($dep=~/^\/res\//) && (!$alreadyseen{$dep})) { + &checkonthis($r,$dep,$level+1); } } - } elsif ($result==HTTP_SERVICE_UNAVAILABLE) { - $r->print('<font color="red"><b>connection down</b></font>'); - } elsif ($result==HTTP_NOT_FOUND) { - $r->print('<font color="red"><b>not found</b></font>'); + } elsif ($result eq 'unavailable') { + $r->print('<span class="LC_error">'.&mt('connection down').'</span>'); + } elsif ($result eq 'not_found') { + unless ($url=~/\$/) { + $r->print('<span class="LC_error">'.&mt('not found').'</b></span>'); + } else { + $r->print('<span class="LC_error">'.&mt('unable to verify variable URL').'</span>'); + } } else { - $r->print('<font color="red"><b>access denied</b></font>'); + $r->print('<span class="LC_error">'.&mt('access denied').'</span>'); } - } - } + } + } } -# ================================================================ Main Handler -sub handler { - my $r = shift; - $r->content_type('text/html'); - $r->send_http_header; - return OK if $r->header_only; - - if ($ENV{'form.verify'}) { - + +=pod + +=item list_symbs() + +List Symbs + +=cut + +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')); + my $navmap = Apache::lonnavmaps::navmap->new(); + if (!defined($navmap)) { + $r->print('<h2>'.&mt('Retrieval of List Failed').'</h2>'. + '<div class="LC_error">'. + &mt('Unable to retrieve information about course contents'). + '</div>'); + &Apache::lonnet::logthis('Symb list failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'}); + } else { + $r->print("<pre>\n"); + foreach my $res ($navmap->retrieveResources()) { + $r->print($res->compTitle()."\t".$res->symb()."\n"); + } + $r->print("\n</pre>\n"); + } + $r->print('<a href="/adm/coursedocs">'.&mt('Return to DOCS').'</a>'); +} + + +sub verifycontent { + my ($r) = @_; + my $crstype = &Apache::loncommon::course_type(); my $loaderror=&Apache::lonnet::overloaderror($r); if ($loaderror) { return $loaderror; } - - $r->print('<html><head><title>Verify Content</title></head>'. - &Apache::loncommon::bodytag('Verify Course Documents')); + $r->print(&Apache::loncommon::start_page('Verify '.$crstype.' Documents')); + $r->print(&Apache::lonhtmlcommon::breadcrumbs('Verify '.$crstype.' Documents')); $hashtied=0; undef %alreadyseen; %alreadyseen=(); &tiehash(); - foreach (keys %hash) { - if (($_=~/^src\_(.+)$/) && (!$alreadyseen{$hash{$_}})) { - &checkonthis($r,$hash{$_},0,$hash{'title_'.$1}); + foreach my $key (keys(%hash)) { + if ($hash{$key}=~/\.(page|sequence)$/) { + if (($key=~/^src_/) && ($alreadyseen{&unescape($hash{$key})})) { + $r->print('<hr /><span class="LC_error">'. + &mt('The following sequence or page is included more than once in your '.$crstype.': '). + &unescape($hash{$key}).'</span><br />'. + &mt('Note that grading records for problems included in this sequence or folder will overlap.<hr />')); + } + } + if (($key=~/^src\_(.+)$/) && (!$alreadyseen{&unescape($hash{$key})})) { + &checkonthis($r,$hash{$key},0,$hash{'title_'.$1}); } } &untiehash(); - } elsif ($ENV{'form.versions'}) { - $r->print('<html><head><title>Check Versions</title></head>'. - &Apache::loncommon::bodytag('Check Course Document Versions')); - $hashtied=0; - &tiehash(); - my %changes=&Apache::lonnet::dump - ('versionupdate',$ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); - my $firstkey=(keys %changes)[0]; - unless ($firstkey=~/^error\:/) { - unless ($ENV{'form.timerange'}) { - $ENV{'form.timerange'}=604800; - } - my $seltext='during the last '.$ENV{'form.timerange'}.' seconds'; - my $startsel=''; - my $monthsel=''; - my $weeksel=''; - my $daysel=''; - if ($ENV{'form.timerange'}==-1) { - $seltext='since start of course'; - $startsel='selected'; - $ENV{'form.timerange'}=time; - } - my $starttime=time-$ENV{'form.timerange'}; - if ($ENV{'form.timerange'}==2592000) { - $seltext='during the last month ('.localtime($starttime).')'; - $monthsel='selected'; - } elsif ($ENV{'form.timerange'}==604800) { - $seltext='during the last week ('.localtime($starttime).')'; - $weeksel='selected'; - } elsif ($ENV{'form.timerange'}==86400) { - $seltext='since yesterday ('.localtime($starttime).')'; - $daysel='selected'; - } - - $r->print(<<ENDHEADERS); + $r->print('<h1>'.&mt('Done').'.</h1>'.'<a href="/adm/coursedocs">'. + &mt('Return to DOCS').'</a>'); +} + + +sub devalidateversioncache { + my $src=shift; + &Apache::lonnet::devalidate_cache_new('courseresversion',$env{'request.course.id'}.'_'. + &Apache::lonnet::clutter($src)); +} + +sub checkversions { + my ($r) = @_; + 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")); + my $header=''; + my $startsel=''; + my $monthsel=''; + my $weeksel=''; + my $daysel=''; + my $allsel=''; + my %changes=(); + my $starttime=0; + my $haschanged=0; + my %setversions=&Apache::lonnet::dump('resourceversions', + $env{'course.'.$env{'request.course.id'}.'.domain'}, + $env{'course.'.$env{'request.course.id'}.'.num'}); + + $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); + } + } + } 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); + } + } + } + } + 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('<h1>'.&mt('Your Version Settings have been Saved').'</h1>'); + } else { + $r->print('<h1><span class="LC_error">'.&mt('An Error Occured while Attempting to Save your Version Settings').'</span></h1>'); + } + &mark_hash_old(); + } + &changewarning($r,''); + if ($env{'form.timerange'} eq 'all') { +# show all documents + $header=&mt('All Documents in '.$crstype); + $allsel=1; + foreach my $key (keys(%hash)) { + if ($key=~/^ids\_(\/res\/.+)$/) { + my $src=$1; + $changes{$src}=1; + } + } + } else { +# show documents which changed + %changes=&Apache::lonnet::dump + ('versionupdate',$env{'course.'.$env{'request.course.id'}.'.domain'}, + $env{'course.'.$env{'request.course.id'}.'.num'}); + my $firstkey=(keys(%changes))[0]; + unless ($firstkey=~/^error\:/) { + unless ($env{'form.timerange'}) { + $env{'form.timerange'}=604800; + } + my $seltext=&mt('during the last').' '.$env{'form.timerange'}.' ' + .&mt('seconds'); + if ($env{'form.timerange'}==-1) { + $seltext='since start of course'; + $startsel='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'; + } elsif ($env{'form.timerange'}==604800) { + $seltext=&mt('during the last week').' ('.&Apache::lonlocal::locallocaltime($starttime).')'; + $weeksel='selected'; + } elsif ($env{'form.timerange'}==86400) { + $seltext=&mt('since yesterday').' ('.&Apache::lonlocal::locallocaltime($starttime).')'; + $daysel='selected'; + } + $header=&mt('Content changed').' '.$seltext; + } else { + $header=&mt('No content modifications yet.'); + } + } + %setversions=&Apache::lonnet::dump('resourceversions', + $env{'course.'.$env{'request.course.id'}.'.domain'}, + $env{'course.'.$env{'request.course.id'}.'.num'}); + my %lt=&Apache::lonlocal::texthash + ('st' => 'Version changes since start of '.$crstype, + 'lm' => 'Version changes since last Month', + 'lw' => 'Version changes since last Week', + 'sy' => 'Version changes since Yesterday', + 'al' => 'All Resources (possibly large output)', + 'sd' => 'Display', + 'fi' => 'File', + 'md' => 'Modification Date', + 'mr' => 'Most recently published Version', + 've' => 'Version used in '.$crstype, + 'vu' => 'Set Version to be used in '.$crstype, +'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'); + $r->print(<<ENDHEADERS); <form action="/adm/coursedocs" method="post"> +<input type="hidden" name="versions" value="1" /> +<input type="submit" name="setmostrecent" value="$lt{'sm'}" /> +<input type="submit" name="setcurrent" value="$lt{'sc'}" /><hr /> <select name="timerange"> -<option value="-1" $startsel>Since Start of Course</option> -<option value="2592000" $monthsel>Last Month</option> -<option value="604800" $weeksel>Last Week</option> -<option value="86400" $daysel>Since Yesterday</option> +<option value='all' $allsel>$lt{'al'}</option> +<option value="-1" $startsel>$lt{'st'}</option> +<option value="2592000" $monthsel>$lt{'lm'}</option> +<option value="604800" $weeksel>$lt{'lw'}</option> +<option value="86400" $daysel>$lt{'sy'}</option> </select> -<input type="submit" name="versions" value="Display" /> -</form> -<h3>Content changed $seltext</h3> -<table border="2"> -<tr> -<th>File</th><th>Modification Date</th> -<th>Version</th><th>Differences</th></tr> +<input type="submit" name="display" value="$lt{'sd'}" /> +<h3>$header</h3> +<input type="submit" name="setversions" value="$lt{'sv'}" /> +<table border="0"> ENDHEADERS - foreach (keys %changes) { - if ($changes{$_}>$starttime) { - my ($root,$extension)=($_=~/^(.*)\.(\w+)$/); - my $currentversion=&Apache::lonnet::getversion($_); - my $linkurl=&Apache::lonnet::clutter($_); - $r->print( - '<tr><td><a href="'.$linkurl.'" target="cat">'.$linkurl. - '</a></td><td>'. - localtime($changes{$_}).'</td><td>'.$currentversion.'</td>'. - '<td>'); - my $lastold=1; - for (my $prevvers=1;$prevvers<$currentversion;$prevvers++) { - my $url=$root.'.'.$prevvers.'.'.$extension; - if (&Apache::lonnet::metadata($url,'lastrevisiondate')< - $starttime) { - $lastold=$prevvers; - } - } + 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( + '<tr><td colspan="5"><br /><br /><font size="+1"><b>'. + &Apache::lonnet::gettitle($linkurl). + '</b></font></td></tr>'. + '<tr><td> </td>'. + '<td colspan="4">'. + '<a href="'.$linkurl.'" target="cat">'.$linkurl. + '</a></td></tr>'. + '<tr><td></td>'. + '<td title="'.$lt{'md'}.'">'. + &Apache::lonlocal::locallocaltime( + &Apache::lonnet::metadata($root.'.'.$extension, + 'lastrevisiondate') + ). + '</td>'. + '<td title="'.$lt{'mr'}.'"><span class="LC_nobreak">Most Recent: '. + '<font size="+1">'.$currentversion.'</font>'. + '</span></td>'. + '<td title="'.$lt{'ve'}.'"><span class="LC_nobreak">In '.$crstype.': '. + '<font size="+1">'); +# Used in course + my $usedversion=$hash{'version_'.$linkurl}; + if (($usedversion) && ($usedversion ne 'mostrecent')) { + $r->print($usedversion); + } else { + $r->print($currentversion); + } + $r->print('</font></span></td><td title="'.$lt{'vu'}.'">'. + '<span class="LC_nobreak">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('</span></td></tr><tr><td></td>'); + 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; + } else { + $entries_per_col = $num_entries/4 + 1; + } + my $entries_count = 0; + $r->print('<td valign="top"><font size="-2">'); + my $cols_output = 1; for (my $prevvers=$lastold;$prevvers<$currentversion;$prevvers++) { - my $url=$root.'.'.$prevvers.'.'.$extension; - $r->print('<a href="'.&Apache::lonnet::clutter($url). - '">Version '.$prevvers.' ('. - localtime(&Apache::lonnet::metadata($url,'lastrevisiondate')). - ')</a>'); - if (&Apache::loncommon::fileembstyle($extension) eq 'ssi') { + my $url=$root.'.'.$prevvers.'.'.$extension; + $r->print('<span class="LC_nobreak"><a href="'.&Apache::lonnet::clutter($url). + '">'.&mt('Version').' '.$prevvers.'</a> ('. + &Apache::lonlocal::locallocaltime( + &Apache::lonnet::metadata($url, + 'lastrevisiondate') + ). + ')'); + if (&Apache::loncommon::fileembstyle($extension) eq 'ssi') { $r->print(' <a href="/adm/diff?filename='. - &Apache::lonnet::clutter($root.'.'.$extension). - '&versionone='.$prevvers. - '">Diffs</a>'); - } - $r->print('<br />'); - } - $r->print('</td></tr>'); - } - } - $r->print('</table>'); - } else { - $r->print('<p>No content modifications yet.</p>'); - } - &untiehash(); + &Apache::lonnet::clutter($root.'.'.$extension). + '&versionone='.$prevvers. + '">'.&mt('Diffs').'</a>'); + } + $r->print('</span><br />'); + if (++$entries_count % $entries_per_col == 0) { + $r->print('</font></td>'); + if ($cols_output != 4) { + $r->print('<td valign="top"><font size="-2">'); + $cols_output++; + } + } + } + while($cols_output++ < 4) { + $r->print('</font></td><td><font>') + } + $r->print('</font></td></tr>'."\n"); + } + } + $r->print('</table></form>'); + $r->print('<h1>'.&mt('Done').'.</h1>'); + + &untiehash(); +} + +sub mark_hash_old { + my $retie_hash=0; + if ($hashtied) { + $retie_hash=1; + &untiehash(); + } + &tiehash('write'); + $hash{'old'}=1; + &untiehash(); + if ($retie_hash) { &tiehash(); } +} + +sub is_hash_old { + my $untie_hash=0; + if (!$hashtied) { + $untie_hash=1; + &tiehash(); + } + my $return=$hash{'old'}; + if ($untie_hash) { &untiehash(); } + return $return; +} + +sub changewarning { + my ($r,$postexec,$message,$url)=@_; + if (!&is_hash_old()) { return; } + 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(); + if (!defined($message)) { + $message='Changes will become active for your current session after [_1], or the next time you log in.'; + } + $r->print("\n\n". +'<script type="text/javascript">'."\n". +'// <![CDATA['."\n". +'function reinit(tf) { tf.submit();'.$postexec.' }'."\n". +'// ]]>'."\n". +'</script>'."\n". +'<form name="reinitform" method="post" action="/adm/roles" target="loncapaclient">'. +'<input type="hidden" name="orgurl" value="'.$url. +'" /><input type="hidden" name="selectrole" value="1" /><p class="LC_warning">'. +&mt($message,' <input type="hidden" name="'. + $env{'request.role'}.'" value="1" /><input type="button" value="'. + &mt('re-initializing '.$course_type).'" onclick="reinit(this.form)" />'). +$help{'Caching'}.'</p></form>'."\n\n"); +} + + +sub init_breadcrumbs { + my ($form,$text)=@_; + &Apache::lonhtmlcommon::clear_breadcrumbs(); + &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/coursedocs", + text=>&Apache::loncommon::course_type().' Editor', + faq=>273, + bug=>'Instructor Interface', + help => 'Docs_Adding_Course_Doc'}); + &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/coursedocs?".$form.'=1', + text=>$text, + faq=>273, + bug=>'Instructor Interface'}); +} + + + + +sub handler { + my $r = shift; + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + return OK if $r->header_only; + my $crstype = &Apache::loncommon::course_type(); + + +# --------------------------------------------- Initialize help topics for this + foreach my $topic ('Adding_Course_Doc','Main_Course_Documents', + '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') { + $help{$topic}=&Apache::loncommon::help_open_topic('Docs_'.$topic); + } + # Composite help files + $help{'Syllabus'} = &Apache::loncommon::help_open_topic( + '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'}); + if ($allowed && $env{'form.verify'}) { + &init_breadcrumbs('verify','Verify Content'); + &verifycontent($r); + } elsif ($allowed && $env{'form.listsymbs'}) { + &init_breadcrumbs('listsymbs','List Symbs'); + &list_symbs($r); + } elsif ($allowed && $env{'form.docslog'}) { + &init_breadcrumbs('docslog','Show Log'); + &docs_change_log($r); + } 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().' DOCS to Construction Space'); + &dumpcourse($r); + } elsif ($allowed && $env{'form.exportcourse'}) { + &init_breadcrumbs('exportcourse','IMS Export'); + &exportcourse($r); } else { # is this a standard course? - my $standard=($ENV{'request.course.uri'}=~/^\/uploaded\//); - my $forcestandard; + my $standard=($env{'request.course.uri'}=~/^\/uploaded\//); + my $forcestandard = 0; my $forcesupplement; my $script=''; - my $allowed; - my $events=''; my $showdoc=0; + my $containertag; + my $uploadtag; + + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, - ['folder','foldername']); + ['folderpath','pagepath', + 'pagesymb']); +# No folderpath, no pagepath, see if we have something stored + if ((!$env{'form.folderpath'}) && (!$env{'form.pagepath'})) { + &Apache::loncommon::restore_course_settings('docs_folderpath', + {'folderpath' => 'scalar'}); + } + if (!$allowed) { + unless($env{'form.folderpath'} =~ /^supplemental/) { + $env{'form.folderpath'} = ''; + } + } + if (!$env{'form.folderpath'} && $allowed) { + &Apache::loncommon::restore_course_settings('docs_folderpath', + {'pagepath' => 'scalar'}); + } + if ($env{'form.pagepath'}) { + $env{'form.folderpath'}=''; + } + if ($env{'form.folderpath'} =~ /^supplemental_\d+/) { + $env{'form.folderpath'} = 'supplemental&'. + &escape(&mt('Supplemental '.$crstype.' Documents')).'&'. + $env{'form.folderpath'}; + } + &Apache::loncommon::store_course_settings('docs_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 = '<input type="hidden" name="pagepath" value="" />'. + '<input type="hidden" name="pagesymb" value="" />'; + $uploadtag = '<input type="hidden" name="pagepath" value="'.&HTML::Entities::encode($env{'form.pagepath'},'<>&"').'" />'. + '<input type="hidden" name="pagesymb" value="'.&HTML::Entities::encode($env{'form.pagesymb'},'<>&"').'" />'; + } if ($r->uri=~/^\/adm\/coursedocs\/showdoc\/(.*)$/) { - $showdoc=$1; + $showdoc='/'.$1; } - unless ($showdoc) { # got called from remote - $forcestandard=($ENV{'form.folder'}=~/^default_/); - $forcesupplement=($ENV{'form.folder'}=~/^supplemental_/); - -# does this user have privileges to post, etc? - $allowed=&Apache::lonnet::allowed('srm',$ENV{'request.course.id'}); - if ($allowed) { + if ($showdoc) { # got called in sequence from course + $allowed=0; + } else { + if (($env{'form.folder'}=~/^(?:group|default)_/) || + ($env{'form.folder'} =~ m:^\d+/(pages|sequences)/:)) { + $forcestandard = 1; + } + $forcesupplement=($env{'form.folder'}=~/^supplemental_/); + + if ($allowed) { &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['cmd']); - $script=&Apache::lonratedt::editscript('simple'); + $script=&Apache::lonratedt::editscript('simple'); } - } else { # got called in sequence from course - $allowed=0; - $script='</script>'.&Apache::lonxml::registerurl(1,undef).'<script>'; - $events='onLoad="'.&Apache::lonxml::loadevents. - '" onUnload="'.&Apache::lonxml::unloadevents.'"'; } +# subroutine to list form elements +sub create_list_elements { + my @formarr = @_; + my $list = ''; + for my $button (@formarr){ + for my $picture(keys %$button) { + #my $link = Apache::lonhtmlcommon::htmltag('a' ,$button->{$picture}, {href => "test"}); + $list .= Apache::lonhtmlcommon::htmltag('li', $picture.' '.$button->{$picture}, {class => 'LC_menubuttons_inline_text'}); + } + } + return $list; +} + +# subroutine to create ul from list elements +sub create_form_ul { + my $list = shift; + my $ul = Apache::lonhtmlcommon::htmltag('ul',$list, {class => 'LC_ListStyleNormal'}); + return $ul; +} + # get course data - my $coursenum=$ENV{'course.'.$ENV{'request.course.id'}.'.num'}; - my $coursedom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'}; + 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=&Apache::lonnet::escape( - &Apache::loncommon::plainname($uname,$udom)); + my $uname=$env{'user.name'}; + my $udom=$env{'user.domain'}; + my $plainname=&escape(&Apache::loncommon::plainname($uname,$udom)); # graphics settings - $iconpath = $r->dir_config('lonIconsURL') . "/"; + $iconpath = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL') . "/"); - my $now=time; + if ($allowed) { + $script .= &editing_js($udom,$uname); + } +# -------------------------------------------------------------------- Body tag + $script = '<script type="text/javascript">'."\n" + .'// <![CDATA['."\n" + .$script."\n" + .'// ]]>'."\n" + .'</script>'."\n"; -# print screen - $r->print(<<ENDDOCUMENT); -<html> -<head> -<title>The LearningOnline Network with CAPA</title> -<script> -$script -</script> -ENDDOCUMENT - if ($allowed) { - $r->print(<<ENDNEWSCRIPT); -<script> + # Breadcrumbs + &Apache::lonhtmlcommon::clear_breadcrumbs(); + if ($allowed) { + &Apache::lonhtmlcommon::add_breadcrumb({ + href=>"/adm/coursedocs",text=>"$crstype Editor"}); + + $r->print(&Apache::loncommon::start_page("$crstype Editor", $script, + {'force_register' => $showdoc,}) + .&Apache::loncommon::help_open_menu('','',273,'RAT') + .&Apache::lonhtmlcommon::breadcrumbs( + 'Editing the Table of Contents for your '.$crstype, + 'Docs_Adding_Course_Doc') + ); + } elsif ($showdoc) { + $r->print(&Apache::loncommon::start_page("$crstype documents",undef, + {'force_register' => $showdoc,})); + } else { + my $folder=$env{'form.folder'}; + if ($folder eq '' || $folder eq 'supplemental') { + $env{'form.folderpath'} = 'supplemental&'. + &escape(&mt('Supplemental '.$crstype.' Documents')); + } + my ($breadcrumbtrail) = &breadcrumbs($allowed,$crstype); + $r->print(&Apache::loncommon::start_page("Supplemental documents"). + $breadcrumbtrail); + } + + my %allfiles = (); + my %codebase = (); + my ($upload_result,$upload_output); + if ($allowed) { + if (($env{'form.uploaddoc.filename'}) && + ($env{'form.cmd'}=~/^upload_(\w+)/)) { +# Process file upload - phase one - upload and parse primary file. + undef($hadchanges); + $upload_result = &process_file_upload(\$upload_output,$coursenum, + $coursedom,\%allfiles, + \%codebase,$1); + if ($hadchanges) { + &mark_hash_old(); + } + if ($upload_result eq 'phasetwo') { + $r->print($upload_output); + } + } elsif ($env{'form.phasetwo'}) { + my %newname = (); + my %origname = (); + my %attribs = (); + my $updateflag = 0; + my $residx = $env{'form.newidx'}; + my $primary_url = &unescape($env{'form.primaryurl'}); +# Process file upload - phase two - gather secondary files. + for (my $i=0; $i<$env{'form.phasetwo'}; $i++) { + if ($env{'form.embedded_item_'.$i.'.filename'}) { + my $javacodebase; + $newname{$i} = &process_secondary_uploads(\$upload_output,$coursedom,$coursenum,'embedded_item_',$i,$residx); + $origname{$i} = &unescape($env{'form.embedded_orig_'.$i}); + if (exists($env{'form.embedded_codebase_'.$i})) { + $javacodebase = &unescape($env{'form.embedded_codebase_'.$i}); + $origname{$i} =~ s#^\Q$javacodebase\E/##; + } + my @attributes = (); + if ($env{'form.embedded_attrib_'.$i} =~ /:/) { + @attributes = split(/:/,$env{'form.embedded_attrib_'.$i}); + } else { + @attributes = ($env{'form.embedded_attrib_'.$i}); + } + foreach my $attr (@attributes) { + push(@{$attribs{$i}},&unescape($attr)); + } + if ($javacodebase) { + $codebase{$i} = $javacodebase; + $codebase{$i} =~ s#/$##; + $updateflag = 1; + } + } + unless ($newname{$i} eq $origname{$i}) { + $updateflag = 1; + } + } +# Process file upload - phase three - modify primary file + if ($updateflag) { + my ($content,$rtncode); + my $updateflag = 0; + my $getstatus = &Apache::lonnet::getuploaded('GET',$primary_url,$coursedom,$coursenum,\$content,\$rtncode); + if ($getstatus eq 'ok') { + foreach my $item (keys(%newname)) { + if ($newname{$item} ne $origname{$item}) { + my $attrib_regexp = ''; + if (@{$attribs{$item}} > 1) { + $attrib_regexp = join('|',@{$attribs{$item}}); + } else { + $attrib_regexp = $attribs{$item}[0]; + } + if ($content =~ m#($attrib_regexp\s*=\s*['"]?)\Q$origname{$item}\E(['"]?)#) { + } + $content =~ s#($attrib_regexp\s*=\s*['"]?)\Q$origname{$item}\E(['"]?)#$1$newname{$item}$2#gi; + } + if (exists($codebase{$item})) { + $content =~ s/(codebase\s*=\s*["']?)\Q$codebase{$item}\E(["']?)/$1.$2/i; #' stupid emacs + } + } +# Save edited file. + my $saveresult; + my $docuname=$env{'course.'.$env{'request.course.id'}.'.num'}; + my $docudom=$env{'course.'.$env{'request.course.id'}.'.domain'}; + my $url = &Apache::lonnet::store_edited_file($primary_url,$content,$docudom,$docuname,\$saveresult); + } else { + &Apache::lonnet::logthis('retrieval of uploaded file - '.$primary_url.' - for editing, failed: '.$getstatus); + } + } + } + } + + unless ($showdoc || $upload_result eq 'phasetwo') { +# ----------------------------------------------------------------------------- + my %lt=&Apache::lonlocal::texthash( + 'uplm' => 'Upload a new main '.lc($crstype).' document', + 'upls' => 'Upload a new supplemental '.lc($crstype).' document', + 'impp' => 'Import a document', + 'copm' => 'All documents out of a published map into this folder', + 'upld' => 'Upload Document', + 'srch' => 'Search', + 'impo' => 'Import', + 'book' => 'Import Bookmarks', + 'selm' => 'Select Map', + 'load' => 'Load Map', + 'reco' => 'Recover Deleted Resources', + 'newf' => 'New Folder', + 'newp' => 'New Composite Page', + 'extr' => 'External Resource', + 'syll' => 'Syllabus', + 'navc' => 'Navigate Contents', + 'sipa' => 'Simple Course Page', + 'sipr' => 'Simple Problem', + 'drbx' => 'Drop Box', + 'scuf' => 'Score Upload Form', + 'bull' => 'Discussion Board', + 'mypi' => 'My Personal Information Page', + 'grpo' => 'Group Portfolio', + 'rost' => 'Course Roster', + 'abou' => 'Personal Information Page for a User', + 'imsf' => 'IMS Import', + 'imsl' => 'Import IMS package', + 'file' => 'File', + 'title' => 'Title', + 'comment' => 'Comment', + 'parse' => 'Upload embedded images/multimedia files if HTML file', + 'nd' => 'Upload Document', + 'pm' => 'Published Map', + 'sd' => 'Special Document', + 'mo' => 'More Options', + ); +# ----------------------------------------------------------------------------- + my $fileupload=(<<FIUP); + $lt{'file'}:<br /> + <input type="file" name="uploaddoc" size="40" /> +FIUP + + my $checkbox=(<<CHBO); + <!-- <label>$lt{'parse'}? + <input type="checkbox" name="parserflag" /> + </label> --> + <label> + <input type="checkbox" name="parserflag" checked="checked" /> $lt{'parse'} + </label> +CHBO + + my $fileuploada = "<input type='submit' value='".$lt{'upld'}."' /> $help{'Uploading_From_Harddrive'}"; + my $fileuploadform=(<<FUFORM); + <form name="uploaddocument" action="/adm/coursedocs" method="post" enctype="multipart/form-data"> + <input type="hidden" name="active" value="aa" /> + $fileupload + <br /> + $lt{'title'}:<br /> + <input type="text" size="50" name="comment" /> + $uploadtag + <input type="hidden" name="cmd" value="upload_default" /> + <br /> + <span class="LC_nobreak"> + $checkbox + </span> +FUFORM + #$list .= Apache::lonhtmlcommon::htmltag('li', $picture.' '.$button->{$picture}, {class => 'LC_menubuttons_inline_text'}); + #$fileuploadform .= create_form_ul(create_list_elements(@fileuploada)); + $fileuploadform .= create_form_ul(Apache::lonhtmlcommon::htmltag('li',$fileuploada,{class => 'LC_menubuttons_inline_text'})); + $fileuploadform .= (<<FUFORM); + </form> +FUFORM + + my $simpleeditdefaultform=(<<SEDFFORM); + <form action="/adm/coursedocs" method="post" name="simpleeditdefault"> + <input type="hidden" name="active" value="bb" /> +SEDFFORM + my @simpleeditdefaultforma = ( + { '<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/src.png" alt="'.$lt{srch}.'" />' => "$uploadtag<a onclick='javascript:groupsearch()'>$lt{'srch'}</a>" }, + { '<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/res.png" alt="'.$lt{impo}.'" />' => "<a onclick='javascript:groupimport();'>$lt{'impo'}</a>$help{'Importing_LON-CAPA_Resource'}" }, + { '<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/vbkm.png" alt="'.$lt{book}.'" />' => "<a onclick='javascript:groupopen(0,1,1);'>$lt{'book'}</a>" }, + ); + $simpleeditdefaultform .= create_form_ul(create_list_elements(@simpleeditdefaultforma)); + $simpleeditdefaultform .=(<<SEDFFORM); + <hr /> + <p> + $lt{'copm'}<br /> + <input type="text" size="40" name="importmap" /><br /> + <span class="LC_nobreak"><input type="button" + onclick="javascript:openbrowser('simpleeditdefault','importmap','sequence,page','')" + value="$lt{'selm'}" /> <input type="submit" name="loadmap" value="$lt{'load'}" /> + $help{'Load_Map'}</span> + </p> + </form> +SEDFFORM + + my $extresourcesform=(<<ERFORM); + <form action="/adm/coursedocs" method="post" name="newext"> + $uploadtag + <input type="hidden" name="importdetail" value="" /> + <a onclick="javascript:makenewext('newext');">$lt{'extr'}</a>$help{'Adding_External_Resource'} + </form> +ERFORM + + if ($allowed) { + &update_paste_buffer($coursenum,$coursedom); + my %lt=&Apache::lonlocal::texthash( + 'vc' => 'Verify Content', + 'cv' => 'Check/Set Resource Versions', + 'ls' => 'List Symbs', + 'sl' => 'Show Log' + ); + + my $folderpath=$env{'form.folderpath'}; + if (!$folderpath) { + if ($env{'form.folder'} eq '' || + $env{'form.folder'} eq 'supplemental') { + $folderpath='default&'. + &escape(&mt('Main '.$crstype.' Documents')); + } + } + unless ($env{'form.pagepath'}) { + $containertag = '<input type="hidden" name="folderpath" value="" />'; + $uploadtag = '<input type="hidden" name="folderpath" value="'.&HTML::Entities::encode($folderpath,'<>&"').'" />'; + } + $r->print(<<HIDDENFORM); + <form name="renameform" method="post" action="/adm/coursedocs"> + <input type="hidden" name="title" /> + <input type="hidden" name="cmd" /> + <input type="hidden" name="markcopy" /> + <input type="hidden" name="copyfolder" /> + $containertag + </form> + <form name="simpleedit" method="post" action="/adm/coursedocs"> + <input type="hidden" name="importdetail" value="" /> + $uploadtag + </form> +HIDDENFORM + } +# --------------------------------------------------------- Main tab structure + + my $activeClass = 1; + my $active = ''; + my %tabtitles = ( + main => { + Course => &mt('Main Course Documents'), + Community => &mt('Main Community Documents'), + }, + supplemental => { + Course => &mt('Supplemental Course Documents'), + Community => &mt('Supplemental Community Documents'), + }, + ); + if ($allowed) { + $r->print('<ul class="LC_TabContentBigger" id="mainnav">'); + if (($standard) && ($allowed) && (!$forcesupplement) && (($env{'form.folderpath'}=~/^default/) || $env{'form.folderpath'}eq"" || ($env{'form.pagepath'}))) { + if($activeClass == 1){ + $active = 'class="active"'; + $activeClass = 0; + } + } + $r->print('<li '.$active.' onclick="javascript:showPage(this,\'mainCourseDocuments\',\'mainnav\',\'maincoursedoc\');"><a href="#"><b>'.$tabtitles{'main'}{$crstype}.'</b></a></li>'); + $active = ''; + if (!$forcestandard || ($env{'form.folderpath'}=~/^supplemental/)) { + if($activeClass == 1){ + $active = 'class="active"'; + } + } + $r->print('<li '.$active.' onclick="javascript:showPage(this,\'supplCourseDocuments\',\'mainnav\',\'maincoursedoc\');"><a href="#"><b>'.$tabtitles{'supplemental'}{$crstype}.'</b></a></li>'); + $r->print('</ul>'); + } else { + $r->print('<br />'); + } + $r->print('<div class="LC_Box" style="clear:both;margin:0;">' + .'<div id="maincoursedoc" style="margin:0 0;padding:0 0;">'); +# --------------------------------------------------------- Standard documents + my $savefolderpath; + $active = 'style="display: none;"'; + if($activeClass == 0){ + $active = 'style="display: block;"'; + } + if ($allowed) { + $r->print('<div class="LC_ContentBox" id="mainCourseDocuments" '.$active.'>'); + my $folder=$env{'form.folder'}; + if ($folder eq '' || $folder=~/^supplemental/) { + $folder='default'; + $savefolderpath = $env{'form.folderpath'}; + $env{'form.folderpath'}='default&'.&escape($tabtitles{'main'}{$crstype}); + $uploadtag = '<input type="hidden" name="folderpath" value="'. + &HTML::Entities::encode($env{'form.folderpath'},'<>&"').'" />'; + } + my $postexec=''; + if ($folder eq 'default') { + $r->print('<script type="text/javascript">'."\n" + .'// <![CDATA['."\n" + .'this.window.name="loncapaclient";'."\n" + .'// ]]>'."\n" + .'</script>'."\n" + ); + } else { + #$postexec='self.close();'; + } + my $folderseq='/uploaded/'.$coursedom.'/'.$coursenum.'/default_'.time. + '.sequence'; + my $pageseq = '/uploaded/'.$coursedom.'/'.$coursenum.'/default_'.time. + '.page'; + my $container='sequence'; + if ($env{'form.pagepath'}) { + $container='page'; + } + my $readfile='/uploaded/'.$coursedom.'/'.$coursenum.'/'.$folder.'.'.$container; + + + + my $recoverform=(<<RFORM); + <form action="/adm/groupsort" method="post" name="recover"> + <a onclick="javascript:groupopen('$readfile',1,0)">$lt{'reco'}</a> + </form> +RFORM + + my $imspform=(<<IMSPFORM); + <form action="/adm/imsimportdocs" method="post" name="ims"> + <input type="hidden" name="folder" value="$folder" /> + <a onclick="javascript:makeims();">$lt{'imsf'}</a> + </form> +IMSPFORM + + my $newnavform=(<<NNFORM); + <form action="/adm/coursedocs" method="post" name="newnav"> + <input type="hidden" name="active" value="cc" /> + $uploadtag + <input type="hidden" name="importdetail" + value="$lt{'navc'}=/adm/navmaps" /> + <a onclick="document.newnav.submit()">$lt{'navc'}</a> + $help{'Navigate_Content'} + </form> +NNFORM + my $newsmppageform=(<<NSPFORM); + <form action="/adm/coursedocs" method="post" name="newsmppg"> + <input type="hidden" name="active" value="cc" /> + $uploadtag + <input type="hidden" name="importdetail" value="" /> + <a onclick="javascript:makesmppage();"> $lt{'sipa'}</a> + $help{'Simple Page'} + </form> +NSPFORM + + my $newsmpproblemform=(<<NSPROBFORM); + <form action="/adm/coursedocs" method="post" name="newsmpproblem"> + <input type="hidden" name="active" value="cc" /> + $uploadtag + <input type="hidden" name="importdetail" value="" /> + <a onclick="javascript:makesmpproblem();">$lt{'sipr'}</a> + $help{'Simple Problem'} + </form> + +NSPROBFORM + + my $newdropboxform=(<<NDBFORM); + <form action="/adm/coursedocs" method="post" name="newdropbox"> + <input type="hidden" name="active" value="cc" /> + $uploadtag + <input type="hidden" name="importdetail" value="" /> + <a onclick="javascript:makedropbox();">$lt{'drbx'}</a> + </form> +NDBFORM + + my $newexuploadform=(<<NEXUFORM); + <form action="/adm/coursedocs" method="post" name="newexamupload"> + <input type="hidden" name="active" value="cc" /> + $uploadtag + <input type="hidden" name="importdetail" value="" /> + <a onclick="javascript:makeexamupload();">$lt{'scuf'}</a> + $help{'Score_Upload_Form'} + </form> +NEXUFORM + + my $newbulform=(<<NBFORM); + <form action="/adm/coursedocs" method="post" name="newbul"> + <input type="hidden" name="active" value="cc" /> + $uploadtag + <input type="hidden" name="importdetail" value="" /> + <a onclick="javascript:makebulboard();" >$lt{'bull'}</a> + $help{'Bulletin Board'} + </form> +NBFORM + + my $newaboutmeform=(<<NAMFORM); + <form action="/adm/coursedocs" method="post" name="newaboutme"> + <input type="hidden" name="active" value="cc" /> + $uploadtag + <input type="hidden" name="importdetail" + value="$plainname=/adm/$udom/$uname/aboutme" /> + <a onclick="document.newaboutme.submit()">$lt{'mypi'}</a> + $help{'My Personal Information Page'} + </form> +NAMFORM + + my $newaboutsomeoneform=(<<NASOFORM); + <form action="/adm/coursedocs" method="post" name="newaboutsomeone"> + <input type="hidden" name="active" value="cc" /> + $uploadtag + <input type="hidden" name="importdetail" value="" /> + <a onclick="javascript:makeabout();">$lt{'abou'}</a> + </form> +NASOFORM + + + my $newrosterform=(<<NROSTFORM); + <form action="/adm/coursedocs" method="post" name="newroster"> + <input type="hidden" name="active" value="cc" /> + $uploadtag + <input type="hidden" name="importdetail" + value="$lt{'rost'}=/adm/viewclasslist" /> + <a onclick="document.newroster.submit()">$lt{'rost'}</a> + $help{'Course Roster'} + </form> +NROSTFORM + +my $specialdocumentsform; +my @specialdocumentsforma; +my $newfolderform; +my $newfolderb; + + unless ($env{'form.pagepath'}) { + my $path = &HTML::Entities::encode($env{'form.folderpath'},'<>&"'); + + my $newpageform=(<<NPFORM); + <form action="/adm/coursedocs" method="post" name="newpage"> + <input type="hidden" name="folderpath" value="$path" /> + <input type="hidden" name="importdetail" value="" /> + <input type="hidden" name="active" value="cc" /> + <a onclick="javascript:makenewpage(document.newpage,'$pageseq');">$lt{'newp'}</a> + $help{'Adding_Pages'} + </form> +NPFORM + + + $newfolderform=(<<NFFORM); + <form action="/adm/coursedocs" method="post" name="newfolder"> + <input type="hidden" name="folderpath" value="$path" /> + <input type="hidden" name="importdetail" value="" /> + <input type="hidden" name="active" value="aa" /> + <a onclick="javascript:makenewfolder(document.newfolder,'$folderseq');">$lt{'newf'}</a>$help{'Adding_Folders'} + </form> +NFFORM + + my $newsylform=(<<NSYLFORM); + <form action="/adm/coursedocs" method="post" name="newsyl"> + <input type="hidden" name="active" value="cc" /> + $uploadtag + <input type="hidden" name="importdetail" + value="$lt{'syll'}=/public/$coursedom/$coursenum/syllabus" /> + <a onclick="document.newsyl.submit()">$lt{'syll'}</a> + $help{'Syllabus'} + + </form> +NSYLFORM + + my $newgroupfileform=(<<NGFFORM); + <form action="/adm/coursedocs" method="post" name="newgroupfiles"> + <input type="hidden" name="active" value="cc" /> + $uploadtag + <input type="hidden" name="importdetail" + value="$lt{'grpo'}=/adm/$coursedom/$coursenum/aboutme" /> + <a onclick="document.newgroupfiles.submit()">$lt{'grpo'}</a> + $help{'Group Portfolio'} + </form> +NGFFORM + @specialdocumentsforma=( + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/page.png" alt="'.$lt{newp}.'" />'=>$newpageform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/syllabus.png" alt="'.$lt{syll}.'" />'=>$newsylform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/groupportfolio.png" alt="'.$lt{grpo}.'" />'=>$newgroupfileform}, + ); + + } + push @specialdocumentsforma, ({'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/navigation.png" alt="'.$lt{navc}.'" />'=>$newnavform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/simple.png" alt="'.$lt{sipa}.'" />'=>$newsmppageform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/simpprob.png" alt="'.$lt{sipr}.'" />'=>$newsmpproblemform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/dropbox.png" alt="'.$lt{drbx}.'" />'=>$newdropboxform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/scoreupfrm.png" alt="'.$lt{scuf}.'" />'=>$newexuploadform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/bchat.png" alt="'.$lt{bull}.'" />'=>$newbulform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/myaboutme.png" alt="'.$lt{mypi}.'" />'=>$newaboutmeform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/aboutme.png" alt="'.$lt{abou}.'" />'=>$newaboutsomeoneform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/chrt.png" alt="'.$lt{rost}.'" />'=>$newrosterform},); + + $specialdocumentsform = create_form_ul(create_list_elements(@specialdocumentsforma)); + +if($env{'form.pagepath'}) { + + @specialdocumentsforma=( + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/simpprob.png" alt="'.&mt('Simple Problem').'" />'=>$newsmpproblemform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/scoreupfrm.png" alt="'.&mt('Score Upload Form').'" />'=>$newexuploadform} + ); + $specialdocumentsform= create_form_ul(create_list_elements(@specialdocumentsforma)); +} + +my @tools = ( + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/extres.png" alt="'.$lt{extr}.'" />'=>$extresourcesform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/ims.png" alt="'.$lt{imsf}.'" />'=>$imspform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/recover.png" alt="'.$lt{reco}.'" />'=>$recoverform}, + ); + +my %orderhash = ( + '00' => ['Newfolder',$newfolderform], + 'aa' => ['Upload Document',$fileuploadform], + 'bb' => ['Published Resources',$simpleeditdefaultform], + 'cc' => ['Special Documents',$specialdocumentsform], + 'dd' => ['Tools', create_form_ul(create_list_elements(@tools)).&generate_admin_options($containertag,$uploadtag,\%help,\%env)], + ); +my $tid='1'; + $hadchanges=0; + my $error = &editor($r,$coursenum,$coursedom,$folder,$allowed,'',$crstype); + if ($error) { + $r->print('<p><span class="LC_error">'.$error.'</span></p>'); + } + if ($hadchanges) { + &mark_hash_old(); + } + + &changewarning($r,''); +$r->print(&generate_edit_table($tid,\%orderhash)); + +$r->print('</div>'); + } + if ($env{'form.pagepath'}) { + } +# ----------------------------------------------------- Supplemental documents + $active = 'style="display: none;"'; + if($activeClass == 1){ + $active = 'style="display: block;"'; + } + $r->print('<div class="LC_ContentBox" id="supplCourseDocuments" '.$active.'>'); + my $folder=$env{'form.folder'}; + unless ($folder=~/^supplemental/) { + $folder='supplemental'; + } + if ($folder =~ /^supplemental$/ && + (($env{'form.folderpath'} =~ /^default\&/) || ($env{'form.folderpath'} eq ''))) { + $env{'form.folderpath'} = 'supplemental&'. + &escape(&mt('Supplemental '.$crstype.' Documents')); + } elsif ($allowed) { + $env{'form.folderpath'} = $savefolderpath; + } + $env{'form.pagepath'} = ''; + if ($allowed) { + my $folderseq= + '/uploaded/'.$coursedom.'/'.$coursenum.'/supplemental_'.time. + '.sequence'; + + my $path = &HTML::Entities::encode($env{'form.folderpath'},'<>&"'); + + my $supupdocformbtn = "<input type='submit' value='".$lt{'upld'}."' />$help{'Uploading_From_Harddrive'}"; + my $supupdocform=(<<SUPDOCFORM); + <form action="/adm/coursedocs" method="post" name="supuploaddocument" enctype="multipart/form-data"> + <input type="hidden" name="active" value="ee" /> + $fileupload + <br /> + <br /> + <span class="LC_nobreak"> + $checkbox + </span> + <br /><br /> + $lt{'comment'}:<br /> + <textarea cols="50" rows="4" name="comment"></textarea> + <br /> + <input type="hidden" name="folderpath" value="$path" /> + <input type="hidden" name="cmd" value="upload_supplemental" /> +SUPDOCFORM + $supupdocform .= create_form_ul(Apache::lonhtmlcommon::htmltag('li',$supupdocformbtn,{class => 'LC_menubuttons_inline_text'}))."</form>"; + + my $supnewfolderform=(<<SNFFORM); + <form action="/adm/coursedocs" method="post" name="supnewfolder"> + <input type="hidden" name="active" value="ee" /> + <input type="hidden" name="folderpath" value="$path" /> + <input type="hidden" name="importdetail" value="" /> + <a onclick="javascript:makenewfolder(document.supnewfolder,'$folderseq');">$lt{'newf'}</a> + $help{'Adding_Folders'} + </form> +SNFFORM + + + my $supnewextform=(<<SNEFORM); + <form action="/adm/coursedocs" method="post" name="supnewext"> + <input type="hidden" name="active" value="ff" /> + <input type="hidden" name="folderpath" value="$path" /> + <input type="hidden" name="importdetail" value="" /> + <a onclick="javascript:makenewext('supnewext');">$lt{'extr'}</a> $help{'Adding_External_Resource'} + </form> +SNEFORM + + my $supnewsylform=(<<SNSFORM); + <form action="/adm/coursedocs" method="post" name="supnewsyl"> + <input type="hidden" name="active" value="ff" /> + <input type="hidden" name="folderpath" value="$path" /> + <input type="hidden" name="importdetail" + value="Syllabus=/public/$coursedom/$coursenum/syllabus" /> + <a onclick="document.supnewsyl.submit()">$lt{'syll'}</a> + $help{'Syllabus'} + </form> +SNSFORM + + my $supnewaboutmeform=(<<SNAMFORM); + <form action="/adm/coursedocs" method="post" name="supnewaboutme"> + <input type="hidden" name="active" value="ff" /> + <input type="hidden" name="folderpath" value="$path" /> + <input type="hidden" name="importdetail" + value="$plainname=/adm/$udom/$uname/aboutme" /> + <a onclick="document.supnewaboutme.submit()">$lt{'mypi'}</a> + $help{'My Personal Information Page'} + </form> +SNAMFORM + + +my @specialdocs = ( + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/extres.png" alt="'.$lt{extr}.'" />'=>$supnewextform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/syllabus.png" alt="'.$lt{syll}.'" />'=>$supnewsylform}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/myaboutme.png" alt="'.$lt{mypi}.'" />'=>$supnewaboutmeform}, + ); +my %suporderhash = ( + '00' => ['Supnewfolder', $supnewfolderform], + 'ee' => ['Upload Document',$supupdocform], + 'ff' => ['Special Documents',create_form_ul(create_list_elements(@specialdocs))] + ); + + my $error = &editor($r,$coursenum,$coursedom,$folder,$allowed,'',$crstype); + if ($error) { + $r->print('<p><span class="LC_error">'.$error.'</span></p>'); + } + my $tid='2'; + $r->print(&generate_edit_table($tid,\%suporderhash)); + } else { + my $error = &editor($r,$coursenum,$coursedom,$folder,$allowed,'',$crstype); + if ($error) { + $r->print('<p><span class="LC_error">'.$error.'</span></p>'); + } + } + + +$r->print('</div>'); +$r->print('</div></div>'); + + + if ($allowed) { + $r->print(' +<form method="post" name="extimport" action="/adm/coursedocs"> + <input type="hidden" name="title" /> + <input type="hidden" name="url" /> + <input type="hidden" name="useform" /> + <input type="hidden" name="residx" /> +</form>'); + } + } else { + unless ($upload_result eq 'phasetwo') { +# -------------------------------------------------------- This is showdoc mode + $r->print("<h1>".&mt('Uploaded Document').' - '. + &Apache::lonnet::gettitle($r->uri).'</h1><p>'. +&mt('It is recommended that you use an up-to-date virus scanner before handling this file.')."</p><table>". + &entryline(0,&mt("Click to download or use your browser's Save Link function"),$showdoc).'</table>'); + } + } + } + $r->print(&Apache::loncommon::end_page()); + return OK; +} + +sub generate_admin_options { + my ($containertag,$uploadtag,$help_ref,$env_ref) = @_; + my %lt=&Apache::lonlocal::texthash( + 'vc' => 'Verify Content', + 'cv' => 'Check/Set Resource Versions', + 'ls' => 'List Symbs', + 'sl' => 'Show Log', + 'imse' => 'IMS Export', + 'dcd' => 'Dump Course DOCS to Construction Space: available on other servers' + ); + my %help = %{$help_ref}; + my %env = %{$env_ref}; + my $dumpbut=&dumpbutton(); + my $exportbut=&exportbutton(); + my @list = ( + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/verify.png" alt="'.$lt{vc}.'" />'=>"<a onclick='javascript:injectData(document.courseverify, \"dummy\", \"verify\", \"$lt{'vc'}\")'>$lt{'vc'}</a>$help{'Verify_Content'}"}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/resversion.png" alt="'.$lt{cv}.'" />'=>"<a onclick='javascript:injectData(document.courseverify, \"dummy\", \"versions\", \"$lt{'cv'}\")'>$lt{'cv'}</a>$help{'Check_Resource_Versions'}"}, + ); + if($dumpbut ne ''){ + push @list, {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/dump.png" alt="'.$lt{dcd}.'" />'=>$dumpbut}; + } + push @list, ({'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/imsexport.png" alt="'.$lt{imse}.'" />'=>$exportbut}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/symbs.png" alt="'.$lt{ls}.'" />'=>"<a onclick='javascript:injectData(document.courseverify, \"dummy\", \"listsymbs\", \"$lt{'ls'}\")'>$lt{'ls'}</a><input type='hidden' name='folder' value='$env{'form.folder'}' />"}, + {'<img class="LC_noBorder LC_middle" align="left" src="/res/adm/pages/log.png" alt="'.$lt{sl}.'" />'=>"<a onclick='javascript:injectData(document.courseverify, \"dummy\", \"docslog\", \"$lt{'sl'}\")'>$lt{'sl'}</a>"}, + ); + return '<form action="/adm/coursedocs" method="post" name="courseverify"><input type="hidden" id="dummy" />'.create_form_ul(create_list_elements(@list)).'</form>'; + +} + + +sub generate_edit_table { + my ($tid,$orderhash_ref) = @_; + return unless(ref($orderhash_ref) eq 'HASH'); + my %orderhash = %{$orderhash_ref}; + my $form; + my $activetab; + my $active; + if($env{'form.active'} ne ''){ + $activetab = $env{'form.active'}; + } + $form = '<div class="LC_Box">'; + $form .= '<ul id="navigation'.$tid.'" class="LC_TabContent">'; + foreach my $name (sort(keys(%orderhash))){ + if($name ne '00'){ + if($activetab eq '' || $activetab ne $name){ + $active = ''; + }elsif($activetab eq $name){ + $active = 'class="active"'; + } + $form .= '<li '.$active.' onclick="javascript:showPage(this, \''.$name.$tid.'\', \'navigation'.$tid.'\',\'content'.$tid.'\');">'.&mt(${$orderhash{$name}}[0]).'</li>'; + } else { + $form .= '<li '.$active.'>'.${$orderhash{$name}}[1].'</li>'; + + } + } + $form .= '</ul>'; + $form .= '<div id="content'.$tid.'" style="padding: 0 0; margin: 0 0; clear: both;">'; + foreach my $field (keys(%orderhash)){ + if($field ne '00'){ + if($activetab eq '' || $activetab ne $field){ + $active = 'style="display: none;"'; + }elsif($activetab eq $field){ + $active = 'style="display:block;"'; + } + $form .= '<div id="'.$field.$tid.'"' + .' class="LC_ContentBox" '.$active.'>'.${$orderhash{$field}}[1] + .'</div>'; + } + } + $form .= '</div></div>'; + + return $form; +} + +sub editing_js { + my ($udom,$uname) = @_; + my $now = time(); + my %lt = &Apache::lonlocal::texthash( + p_mnf => 'Name of New Folder', + t_mnf => 'New Folder', + p_mnp => 'Name of New Page', + t_mnp => 'New Page', + p_mxu => 'Title for the Uploaded Score', + p_msp => 'Name of Simple Course Page', + p_msb => 'Title for the Problem', + p_mdb => 'Title for the Drop Box', + p_mbb => 'Title for the Discussion Board', + p_mab => "Enter user:domain for User's Personal Information Page", + p_mab2 => 'Personal Information Page of ', + p_mab_alrt1 => 'Not a valid user:domain', + p_mab_alrt2 => 'Please enter both user and domain in the format user:domain', + p_chn => 'New Title', + p_rmr1 => 'WARNING: Removing a resource makes associated grades and scores inaccessible!', + p_rmr2a => 'Remove[_99]', + p_rmr2b => '?[_99]', + p_ctr1a => 'WARNING: Cutting a resource makes associated grades and scores inaccessible!', + p_ctr1b => 'Grades remain inaccessible if resource is pasted into another folder.', + p_ctr2a => 'Cut[_98]', + p_ctr2b => '?[_98]' + ); + + return <<ENDNEWSCRIPT; function makenewfolder(targetform,folderseq) { - var foldername=prompt('Name of New Folder','New Folder'); + var foldername=prompt('$lt{"p_mnf"}','$lt{"t_mnf"}'); if (foldername) { - targetform.importdetail.value=foldername+"="+folderseq; + targetform.importdetail.value=escape(foldername)+"="+folderseq; + targetform.submit(); + } +} + +function makenewpage(targetform,folderseq) { + var pagename=prompt('$lt{"p_mnp"}','$lt{"t_mnp"}'); + if (pagename) { + targetform.importdetail.value=escape(pagename)+"="+folderseq; targetform.submit(); } } function makenewext(targetname) { this.document.forms.extimport.useform.value=targetname; + this.document.forms.extimport.title.value=''; + this.document.forms.extimport.url.value=''; + this.document.forms.extimport.residx.value=''; window.open('/adm/rat/extpickframe.html'); } +function edittext(targetname,residx,title,url) { + this.document.forms.extimport.useform.value=targetname; + this.document.forms.extimport.residx.value=residx; + this.document.forms.extimport.url.value=url; + this.document.forms.extimport.title.value=title; + window.open('/adm/rat/extpickframe.html'); +} + +function makeexamupload() { + var title=prompt('$lt{"p_mxu"}'); + if (title) { + this.document.forms.newexamupload.importdetail.value= + escape(title)+'=/res/lib/templates/examupload.problem'; + this.document.forms.newexamupload.submit(); + } +} + function makesmppage() { - var title=prompt('Listed Title for the Page'); + var title=prompt('$lt{"p_msp"}'); + if (title) { this.document.forms.newsmppg.importdetail.value= - title+'=/adm/$udom/$uname/$now/smppg'; + escape(title)+'=/adm/$udom/$uname/$now/smppg'; this.document.forms.newsmppg.submit(); + } +} + +function makesmpproblem() { + var title=prompt('$lt{"p_msb"}'); + if (title) { + this.document.forms.newsmpproblem.importdetail.value= + escape(title)+'=/res/lib/templates/simpleproblem.problem'; + this.document.forms.newsmpproblem.submit(); + } +} + +function makedropbox() { + var title=prompt('$lt{"p_mdb"}'); + if (title) { + this.document.forms.newdropbox.importdetail.value= + escape(title)+'=/res/lib/templates/DropBox.problem'; + this.document.forms.newdropbox.submit(); + } } function makebulboard() { - var title=prompt('Listed Title for the Bulletin Board'); + var title=prompt('$lt{"p_mbb"}'); + if (title) { this.document.forms.newbul.importdetail.value= - title+'=/adm/$udom/$uname/$now/bulletinboard'; + escape(title)+'=/adm/$udom/$uname/$now/bulletinboard'; this.document.forms.newbul.submit(); + } } +function makeabout() { + var user=prompt("$lt{'p_mab'}"); + if (user) { + var comp=new Array(); + comp=user.split(':'); + if ((typeof(comp[0])!=undefined) && (typeof(comp[1])!=undefined)) { + if ((comp[0]) && (comp[1])) { + this.document.forms.newaboutsomeone.importdetail.value= + '$lt{"p_mab2"}'+escape(user)+'=/adm/'+comp[1]+'/'+comp[0]+'/aboutme'; + this.document.forms.newaboutsomeone.submit(); + } else { + alert("$lt{'p_mab_alrt1'}"); + } +} else { + alert("$lt{'p_mab_alrt2'}"); +} +} +} + +function makeims() { +var caller = document.forms.ims.folder.value; +var newlocation = "/adm/imsimportdocs?folder="+caller+"&phase=one"; +newWindow = window.open("","IMSimport","HEIGHT=700,WIDTH=750,scrollbars=yes"); +newWindow.location.href = newlocation; +} + + function finishpick() { - var title=this.document.forms.extimport.title.value; - var url=this.document.forms.extimport.url.value; - var form=this.document.forms.extimport.useform.value; - eval - ('this.document.forms.'+form+'.importdetail.value="'+title+'='+url+ - '";this.document.forms.'+form+'.submit();'); +var title=this.document.forms.extimport.title.value; +var url=this.document.forms.extimport.url.value; +var form=this.document.forms.extimport.useform.value; +var residx=this.document.forms.extimport.residx.value; +eval('this.document.forms.'+form+'.importdetail.value="'+title+'='+url+'='+residx+'";this.document.forms.'+form+'.submit();'); } -</script> -ENDNEWSCRIPT - } -# -------------------------------------------------------------------- Body tag - $r->print('</head>'. - &Apache::loncommon::bodytag('Course Documents','',$events)); - unless ($showdoc) { - if ($allowed) { - $r->print(<<ENDCOURSEVERIFY); -<form action="/adm/coursedocs" method="post" name="courseverify"> -<input type="submit" name="verify" value="Verify Content" /> -<input type="submit" name="versions" value="Check Resource Versions" /> -</form> -ENDCOURSEVERIFY - } -# --------------------------------------------------------- Standard documents - $r->print('<table>'); - if (($standard) && ($allowed) && (!$forcesupplement)) { - $r->print('<tr><td bgcolor="#FFFFBB"><h2>Main Course Documents</h2>'); - my $folder=$ENV{'form.folder'}; - unless ($folder=~/^default/) { $folder='default'; } - &editor($r,$coursenum,$coursedom,$folder,$allowed); - my $folderseq='/uploaded/'.$coursedom.'/'.$coursenum.'/default_'.time. - '.sequence'; - $r->print(<<ENDFORM); -<table cellspacing=2><tr> -<th bgcolor="#DDDDDD">Upload a new main course document</th> -<th bgcolor="#DDDDDD">Import a published document</th> -<th bgcolor="#DDDDDD">Special documents</th> -</tr> -<tr><td bgcolor="#DDDDDD"> -File:<br /> -<form action="/adm/coursedocs" method="post" enctype="multipart/form-data"> -<input type="file" name="uploaddoc" size="50"> -<br /> -Title:<br /> -<input type="text" size="50" name="comment"> -<input type="hidden" name="folder" value="$folder"> -<input type="hidden" name="foldername" value="$ENV{'form.foldername'}"> -<input type="hidden" name="cmd" value="upload_default"> -<input type="submit" value="Upload Document"> -</form> -</td> -<td bgcolor="#DDDDDD"> -<form action="/adm/coursedocs" method="post" name="simpleedit"> -<input type="hidden" name="folder" value="$folder"> -<input type=hidden name="importdetail" value=""> -<input type=button onClick= -"javascript:groupsearch()" value="Search"> -<input type=button onClick= -"javascript:groupimport();" value="Import"> -</form> -</td><td bgcolor="#DDDDDD"> -<form action="/adm/coursedocs" method="post" name="newfolder"> -<input type="hidden" name="folder" value="$folder"> -<input type="hidden" name="foldername" value="$ENV{'form.foldername'}"> -<input type=hidden name="importdetail" value=""> -<input name="newfolder" type="button" -onClick="javascript:makenewfolder(this.form,'$folderseq');" -value="New Folder" /> -</form> -<form action="/adm/coursedocs" method="post" name="newext"> -<input type="hidden" name="folder" value="$folder"> -<input type="hidden" name="foldername" value="$ENV{'form.foldername'}"> -<input type=hidden name="importdetail" value=""> -<input name="newext" type="button" onClick="javascript:makenewext('newext');" -value="External Resource" /> -</form> -<form action="/adm/coursedocs" method="post" name="newsyl"> -<input type="hidden" name="folder" value="$folder"> -<input type="hidden" name="foldername" value="$ENV{'form.foldername'}"> -<input type=hidden name="importdetail" -value="Syllabus=/public/$coursedom/$coursenum/syllabus"> -<input name="newsyl" type="submit" value="Syllabus" /> -</form> -<form action="/adm/coursedocs" method="post" name="newnav"> -<input type="hidden" name="folder" value="$folder"> -<input type="hidden" name="foldername" value="$ENV{'form.foldername'}"> -<input type=hidden name="importdetail" -value="Navigate Content=/adm/navmaps"> -<input name="newnav" type="submit" value="Navigate Content" /> -</form> -<form action="/adm/coursedocs" method="post" name="newsmppg"> -<input type="hidden" name="folder" value="$folder"> -<input type="hidden" name="foldername" value="$ENV{'form.foldername'}"> -<input type=hidden name="importdetail" value=""> -<input name="newsmppg" type="button" value="Simple Page" -onClick="javascript:makesmppage();" /> -</form> -<form action="/adm/coursedocs" method="post" name="newbul"> -<input type="hidden" name="folder" value="$folder"> -<input type="hidden" name="foldername" value="$ENV{'form.foldername'}"> -<input type=hidden name="importdetail" value=""> -<input name="newbulletin" type="button" value="Bulletin Board" -onClick="javascript:makebulboard();" /> -</form> -<form action="/adm/coursedocs" method="post" name="newaboutme"> -<input type="hidden" name="folder" value="$folder"> -<input type="hidden" name="foldername" value="$ENV{'form.foldername'}"> -<input type=hidden name="importdetail" -value="$plainname=/adm/$udom/$uname/aboutme"> -<input name="newaboutme" type="submit" value="My Personal Info" /> -</form> -</td></tr> -</table> -ENDFORM - $r->print('</td></tr>'); - } -# ----------------------------------------------------- Supplemental documents - if (!$forcestandard) { - $r->print( - '<tr><td bgcolor="#BBFFFF"><h2>Supplemental Course Documents</h2>'); - my $folder=$ENV{'form.folder'}; - unless ($folder=~/supplemental/) { $folder='supplemental'; } - &editor($r,$coursenum,$coursedom,$folder,$allowed); - if ($allowed) { - my $folderseq= - '/uploaded/'.$coursedom.'/'.$coursenum.'/supplemental_'.time. - '.sequence'; - $r->print(<<ENDSUPFORM); -<table cellspacing=2><tr> -<th bgcolor="#DDDDDD">Upload a new supplemental course document</th> -<th bgcolor="#DDDDDD">Import a published document</th> -<th bgcolor="#DDDDDD">Special documents</th> -</tr> -<tr><td bgcolor="#DDDDDD"> -<form action="/adm/coursedocs" method="post" enctype="multipart/form-data"> -<input type="file" name="uploaddoc" size="50"> -<br />Comment:<br /> -<textarea cols=50 rows=4 name='comment'> -</textarea> -<input type="hidden" name="folder" value="$folder"> -<input type="hidden" name="foldername" value="$ENV{'form.foldername'}"> -<input type="hidden" name="cmd" value="upload_supplemental"> -<input type="submit" value="Upload Document"> -</form> -</td> -<td bgcolor="#DDDDDD"> -<form action="/adm/coursedocs" method="post" name="simpleedit"> -<input type="hidden" name="folder" value="$folder"> -<input type=hidden name="importdetail" value=""> -<input type=button onClick= -"javascript:groupsearch()" value="Search"> -<input type=button onClick= -"javascript:groupimport();" value="Import"> -</form> -</td><td bgcolor="#DDDDDD"> -<form action="/adm/coursedocs" method="post" name="supnewfolder"> -<input type="hidden" name="folder" value="$folder"> -<input type="hidden" name="foldername" value="$ENV{'form.foldername'}"> -<input type=hidden name="importdetail" value=""> -<input name="newfolder" type="button" -onClick="javascript:makenewfolder(this.form,'$folderseq');" -value="New Folder" /> -</form> -<form action="/adm/coursedocs" method="post" name="supnewext"> -<input type="hidden" name="folder" value="$folder"> -<input type="hidden" name="foldername" value="$ENV{'form.foldername'}"> -<input type=hidden name="importdetail" value=""> -<input name="newext" type="button" -onClick="javascript:makenewext('supnewext');" -value="External Resource" /> -</form> -<form action="/adm/coursedocs" method="post" name="supnewsyl"> -<input type="hidden" name="folder" value="$folder"> -<input type="hidden" name="foldername" value="$ENV{'form.foldername'}"> -<input type=hidden name="importdetail" -value="Syllabus=/public/$coursedom/$coursenum/syllabus"> -<input name="newsyl" type="submit" value="Syllabus" /> -</form> -<form action="/adm/coursedocs" method="post" name="subnewaboutme"> -<input type="hidden" name="folder" value="$folder"> -<input type="hidden" name="foldername" value="$ENV{'form.foldername'}"> -<input type=hidden name="importdetail" -value="$plainname=/adm/$udom/$uname/aboutme"> -<input name="newaboutme" type="submit" value="My Personal Info" /> -</form> -</td></tr> -</table></td></tr> -ENDSUPFORM - } - } - if ($allowed) { - $r->print('<form name="extimport"><input type="hidden" name="title"><input type="hidden" name="url"><input type="hidden" name="useform"></form>'); - } - $r->print('</table>'); - } else { -# -------------------------------------------------------- This is showdoc mode - $r->print("<h1>Uploaded Document</h1><p>It is recommended that you use an up-to-date virus scanner before handling this file.</p><p><table>". - &entryline(0,"Click to download or use your browser's Save Link function",$showdoc).'</table></p>'); - } - } - $r->print('</body></html>'); - return OK; -} +function changename(folderpath,index,oldtitle,container,pagesymb) { +var title=prompt('$lt{"p_chn"}',oldtitle); +if (title) { +this.document.forms.renameform.markcopy.value=-1; +this.document.forms.renameform.title.value=title; +this.document.forms.renameform.cmd.value='rename_'+index; +if (container == 'sequence') { + this.document.forms.renameform.folderpath.value=folderpath; +} +if (container == 'page') { + this.document.forms.renameform.pagepath.value=folderpath; + this.document.forms.renameform.pagesymb.value=pagesymb; +} +this.document.forms.renameform.submit(); +} +} + +function removeres(folderpath,index,oldtitle,container,pagesymb,skip_confirm) { +if (skip_confirm || confirm('$lt{"p_rmr1"}\\n\\n$lt{"p_rmr2a"} "'+oldtitle+'" $lt{"p_rmr2b"}')) { +this.document.forms.renameform.markcopy.value=-1; +this.document.forms.renameform.cmd.value='del_'+index; +if (container == 'sequence') { + this.document.forms.renameform.folderpath.value=folderpath; +} +if (container == 'page') { + this.document.forms.renameform.pagepath.value=folderpath; + this.document.forms.renameform.pagesymb.value=pagesymb; +} +this.document.forms.renameform.submit(); +} +} + +function cutres(folderpath,index,oldtitle,container,pagesymb,folder,skip_confirm) { +if (skip_confirm || confirm('$lt{"p_ctr1a"}\\n$lt{"p_ctr1b"}\\n\\n$lt{"p_ctr2a"} "'+oldtitle+'" $lt{"p_ctr2b"}')) { +this.document.forms.renameform.cmd.value='cut_'+index; +this.document.forms.renameform.markcopy.value=index; +this.document.forms.renameform.copyfolder.value=folder+'.'+container; +if (container == 'sequence') { + this.document.forms.renameform.folderpath.value=folderpath; +} +if (container == 'page') { + this.document.forms.renameform.pagepath.value=folderpath; + this.document.forms.renameform.pagesymb.value=pagesymb; +} +this.document.forms.renameform.submit(); +} +} + +function markcopy(folderpath,index,oldtitle,container,pagesymb,folder) { +this.document.forms.renameform.markcopy.value=index; +this.document.forms.renameform.copyfolder.value=folder+'.'+container; +if (container == 'sequence') { +this.document.forms.renameform.folderpath.value=folderpath; +} +if (container == 'page') { +this.document.forms.renameform.pagepath.value=folderpath; +this.document.forms.renameform.pagesymb.value=pagesymb; +} +this.document.forms.renameform.submit(); +} + +function unselectInactive(nav) { +currentNav = document.getElementById(nav); +currentLis = currentNav.getElementsByTagName('LI'); +for (i = 0; i < currentLis.length; i++) { + if(currentLis[i].className == 'right active' || currentLis[i].className == 'right'){ + currentLis[i].className = 'right'; + }else{ + currentLis[i].className = 'i'; + } +} +} + +function hideAll(current, nav, data) { +unselectInactive(nav); +if(current.className == 'right'){ + current.className = 'right active' + }else{ + current.className = 'active'; +} +currentData = document.getElementById(data); +currentDivs = currentData.getElementsByTagName('DIV'); +for (i = 0; i < currentDivs.length; i++) { + if(currentDivs[i].className == 'LC_ContentBox'){ + currentDivs[i].style.display = 'none'; + } +} +} + +function openTabs(pageId) { + tabnav = document.getElementById(pageId).getElementsByTagName('UL'); + if(tabnav.length > 2 ){ + currentNav = document.getElementById(tabnav[1].id); + currentLis = currentNav.getElementsByTagName('LI'); + for(i = 0; i< currentLis.length; i++){ + if(currentLis[i].className == 'active') { + funcString = currentLis[i].onclick.toString(); + tab = funcString.split('"'); + currentData = document.getElementById(tab[1]); + currentData.style.display = 'block'; + } + } + } +} + +function showPage(current, pageId, nav, data) { + hideAll(current, nav, data); + openTabs(pageId); + unselectInactive(nav); + current.className = 'active'; + currentData = document.getElementById(pageId); + currentData.style.display = 'block'; + return false; +} + +function injectData(current, hiddenField, name, value) { + currentElement = document.getElementById(hiddenField); + currentElement.name = name; + currentElement.value = value; + current.submit(); +} +ENDNEWSCRIPT +} 1; __END__ + + +=head1 NAME + +Apache::londocs.pm + +=head1 SYNOPSIS + +This is part of the LearningOnline Network with CAPA project +described at http://www.lon-capa.org. + +=head1 SUBROUTINES + +=over + +=item %help=() + +Available help topics + +=item mapread() + +Mapread read maps into LONCAPA::map:: global arrays +@order and @resources, determines status +sets @order - pointer to resources in right order +sets @resources - array with the resources with correct idx + +=item authorhosts() + +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 + coursenum, coursedom, and folder must precede the list + +=item breadcrumbs() + +=item log_docs() + +=item docs_change_log() + +=item update_paste_buffer() + +=item print_paste_buffer() + +=item do_paste_from_buffer() + +=item update_parameter() + +=item handle_edit_cmd() + +=item editor() + +=item process_file_upload() + +=item process_secondary_uploads() + +=item is_supplemental_title() + +=item parse_supplemental_title() + +=item entryline() + +=item tiehash() + +=item untiehash() + +=item checkonthis() + +check on this + +=item verifycontent() + +Verify Content + +=item devalidateversioncache() & checkversions() + +Check Versions + +=item mark_hash_old() + +=item is_hash_old() + +=item changewarning() + +=item init_breadcrumbs() + +Breadcrumbs for special functions + +=back + +=cut