--- loncom/interface/londocs.pm 2003/07/16 19:36:02 1.67 +++ loncom/interface/londocs.pm 2012/07/05 21:33:39 1.489 @@ -1,7 +1,7 @@ # The LearningOnline Network # Documents # -# $Id: londocs.pm,v 1.67 2003/07/16 19:36:02 www Exp $ +# $Id: londocs.pm,v 1.489 2012/07/05 21:33:39 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -30,13 +30,23 @@ 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 Apache::lonnavdisplay(); +use Apache::lonuserstate(); use HTML::Entities; +use HTML::TokeParser; use GDBM_File; +use Apache::lonlocal; +use Cwd; +use LONCAPA qw(:DEFAULT :match); my $iconpath; @@ -47,268 +57,1908 @@ my %alreadyseen=(); my $hadchanges; -# Available help topics my %help=(); -# 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 -# 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)=@_; + my ($outtext,$errtext)= + &LONCAPA::map::storemap('/uploaded/'.$coursedom.'/'.$coursenum.'/'. + $map,1); + if ($errtext) { return ($errtext,2); } + $hadchanges=1; - return - &Apache::lonratedt::storemap('/uploaded/'.$coursedom.'/'.$coursenum.'/'. - $map,1); + return ($errtext,0); } -sub editor { - my ($r,$coursenum,$coursedom,$folder,$allowed)=@_; - if ($ENV{'form.foldername'}) { - $r->print('

Folder: '.$ENV{'form.foldername'}.'

'); - } - 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]=''; + + +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; + last; + } + } + if ($allowed) { + $home++; + $outhash{'home_'.$ca.':'.$cd}=1; + } else { + $outhash{'otherhome_'.$ca.':'.$cd}=$myhome; + $other++; + } + } } - if ($fatal) { - $r->print('

'.$errtext.'

'); + return ($home,$other,%outhash); +} + + +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.' Content to Authoring Space')."\n". + &Apache::lonhtmlcommon::breadcrumbs('Dump '.$crstype.' Content to Authoring Space')."\n"); + $r->print(&startContentScreen('tools')); + my ($home,$other,%outhash)=&authorhosts(); + unless ($home) { + $r->print(&endContentScreen()); + 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'}}) { + $r->print(&endContentScreen()); + return ''; + } + my ($ca,$cd)=split(/\@/,$env{'form.authorspace'}); + $r->print('

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

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

'."\n"); + &tiehash(); + $r->print('

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

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

'); + } + $r->print(&endContentScreen()); +} + +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 = ''."\n". + ''."\n". + ''."\n". + ''."\n". + ''; + $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; + while (@folders) { + my $folder=shift(@folders); + my $foldername=shift(@folders); + if ($folderpath) {$folderpath.='&';} + $folderpath.=$folder.'&'.$foldername; + my $url; + if ($allowed) { + $url = '/adm/coursedocs?folderpath='; + } else { + $url = '/adm/supplemental?folderpath='; + } + $url .= &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.' Content'); + } + &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,$coursenum,$coursedom,$folder,$allowed,$crstype,$iconpath)=@_; + my $supplementalflag=($env{'form.folderpath'}=~/^supplemental/); + my $js = ''."\n"; + $r->print(&Apache::loncommon::start_page('Content Change Log',$js)); + $r->print(&Apache::lonhtmlcommon::breadcrumbs('Content Change Log')); + $r->print(&startContentScreen(($supplementalflag?'suppdocs':'docs'))); + my %orderhash; + my $container='sequence'; + my $pathitem; + if ($env{'form.pagepath'}) { + $container='page'; + $pathitem = ''; + } else { + my $folderpath=$env{'form.folderpath'}; + if ($folderpath eq '') { + $folderpath = 'default&'.&escape(&mt('Main '.$crstype.' Documents')); + } + $pathitem = ''; + } + my $readfile="/uploaded/$coursedom/$coursenum/$folder.$container"; + my $jumpto = $readfile; + $jumpto =~ s{^/}{}; + my $tid = 1; + if ($supplementalflag) { + $tid = 2; + } + my ($breadcrumbtrail) = &breadcrumbs($allowed,$crstype); + $r->print($breadcrumbtrail. + &generate_edit_table($tid,\%orderhash,undef,$iconpath,$jumpto, + $readfile)); + my %docslog=&Apache::lonnet::dump('nohist_docslog', + $env{'course.'.$env{'request.course.id'}.'.domain'}, + $env{'course.'.$env{'request.course.id'}.'.num'}); + + if ((keys(%docslog))[0]=~/^error\:/) { undef(%docslog); } + + 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; } +# FIXME: internationalization seems wrong here + my %lt=('hiddenresource' => 'Resources hidden', + 'encrypturl' => 'URL hidden', + 'randompick' => 'Randomly pick', + 'randomorder' => 'Randomly ordered', + 'set' => 'set to', + 'del' => 'deleted'); + my $filter = &Apache::loncommon::display_filter('docslog')."\n". + $pathitem."\n". + ''. + (' 'x2).''; + $r->print('
'. + '
'.&mt('Display of Content Changes').''."\n". + &makedocslogform($filter,1). + '

'); + $r->print(&Apache::loncommon::start_data_table().&Apache::loncommon::start_data_table_header_row(). + ''.&mt('Time').''.&mt('User').''.&mt('Folder').''.&mt('Before').''. + &mt('After').''. + &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 ='
'. + &Apache::loncommon::messagewrapper(&mt('Send message'), + $docslog{$id}{'exe_uname'}, + $docslog{$id}{'exe_udom'}); + } + $r->print(&Apache::loncommon::start_data_table_row()); + $r->print(''.$time.' + '.$about_me_link. + '
'.$docslog{$id}{'exe_uname'}. + ':'.$docslog{$id}{'exe_udom'}.''. + $send_msg_link.''. + $docslog{$id}{'logentry'}{'folder'}.''); + my $is_supp = 0; + if ($docslog{$id}{'logentry'}{'currentfolder'} =~ /^supplemental/) { + $is_supp = 1; + } +# Before + for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) { + my $oldname=(split(/\:/,$docslog{$id}{'logentry'}{'before_resources_'.$idx}))[0]; + my $newname=(split(/\:/,$docslog{$id}{'logentry'}{'after_resources_'.$idx}))[0]; + if ($oldname ne $newname) { + my $shown = &LONCAPA::map::qtescape($oldname); + if ($is_supp) { + $shown = &Apache::loncommon::parse_supplemental_title($shown); + } + $r->print($shown); + } + } + $r->print(''); +# After + $r->print(''); + + 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) { + my $shown = &LONCAPA::map::qtescape($newname); + if ($is_supp) { + $shown = &Apache::loncommon::parse_supplemental_title(&LONCAPA::map::qtescape($newname)); + } + $r->print($shown); + } + } + $r->print(''); + if ($docslog{$id}{'logentry'}{'parameter_res'}) { + $r->print(&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'parameter_res'}))[0]).':'); + } +# End + $r->print(''.&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()."\n". + &makesimpleeditform($pathitem)."\n". + ''); + $r->print(&endContentScreen()); +} + +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) = &Apache::loncommon::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,$folder) = @_; + return if (!defined($env{'docs.markedcopy_url'})); + + my $is_external; + my $extension = (split(/\./,$env{'docs.markedcopy_url'}))[-1]; + if ($env{'docs.markedcopy_url'} =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//} ) { + $is_external = 1; + } + + my $canpaste; + if ($folder =~ /^supplemental/) { + $canpaste = &supp_pasteable($env{'docs.markedcopy_url'}); + } else { + $canpaste = 1; + } + + my $pasteinfo; + if ($canpaste) { + $pasteinfo = '
' + .' '; + } else { + $pasteinfo = &mt('Paste buffer contains:').' '; + } + + $r->print('
' + .''.&mt('Clipboard').'' + .$pasteinfo + ); + + my $type; + if ($is_external) { + $type = &mt('External Resource'); + $r->print($type.': '. + &LONCAPA::map::qtescape($env{'docs.markedcopy_title'}).' ('. + &LONCAPA::map::qtescape($env{'docs.markedcopy_url'}).')'); + } else { + my $icon = &Apache::loncommon::icon($extension); + if ($extension eq 'sequence' && + $env{'docs.markedcopy_url'} =~ m{/default_\d+\.sequence$ }x) { + $icon = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL')); + $icon .= '/navmap.folder.closed.gif'; + } + $icon = ''; + $r->print($icon.$type.': '. &Apache::loncommon::parse_supplemental_title(&LONCAPA::map::qtescape($env{'docs.markedcopy_title'}))); + } + if ($canpaste) { + if ($container eq 'page') { + $r->print(' + + +'); + } else { + $r->print(' + +'); + } + $r->print(''); + } else { + $r->print('

'.&mt('Paste into Supplemental Content unavailable for this type of content.').'

'); + } + $r->print('
'); +} + +sub supp_pasteable { + my ($url) = @_; + if (($url =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//}) || + (($url =~ /\.sequence$/) && ($url =~ m{^/uploaded/})) || + ($url =~ m{^/uploaded/$match_domain/$match_courseid/(docs|supplemental)/(default|\d+)/\d+/}) || + ($url =~ m{^/adm/$match_domain/$match_username/aboutme}) || + ($url =~ m{^/public/$match_domain/$match_courseid/syllabus})) { + return 1; + } + return; +} + +sub do_paste_from_buffer { + my ($coursenum,$coursedom,$folder) = @_; + + if (!$env{'form.pastemarked'}) { + return; + } + +# Supplemental content may only include certain types of content + if ($folder =~ /^supplemental/) { + unless (&supp_pasteable($env{'docs.markedcopy_url'})) { + return &mt('Paste failed: content type is not supported within Supplemental Content'); + } + } + +# 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 + my ($oldurl,%removefrommap,%addedmaps,%rewrites,%copies,%dbcopies,%zombies,%params, + %moves,$srcdom,$srcnum); + $oldurl = $url; + if ($url=~/\.(page|sequence)$/) { + # If pasting a map, check if map contains other maps + &contained_map_check($url,$folder,\%removefrommap,\%addedmaps); + if (keys(%addedmaps) > 0) { + &reinit_role($coursedom,$coursenum,$env{"course.$env{'request.course.id'}.home"}); + } + my %allmaps; + my $navmap = Apache::lonnavmaps::navmap->new(); + if (defined($navmap)) { + foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_map() },1,0,1)) { + $allmaps{$res->src()} = 1; + } + } + if ($url=~ m{^/uploaded/}) { + $title=&mt('Copy of').' '.$title; + } + my $newid=$$.int(rand(100)).time; + my ($oldid,$ext) = ($url=~/^(.+)\.(\w+)$/); + if ($oldid =~ m{^(/uploaded/$match_domain/$match_courseid/)(\D+)(\d+)$}) { + my $path = $1; + my $prefix = $2; + my $ancestor = $3; + if (length($ancestor) > 10) { + $ancestor = substr($ancestor,-10,10); + } + $oldid = $path.$prefix.$ancestor; + my $counter = 0; + my $newurl=$oldid.$newid.'.'.$ext; + my $is_unique = &uniqueness_check($newurl); + if ($allmaps{$newurl}) { + $is_unique = 0; + } + while (!$is_unique && $allmaps{$newurl} && $counter < 100) { + $counter ++; + $newid ++; + $newurl = $oldid.$newid; + $is_unique = &uniqueness_check($newurl); + } + if ($is_unique) { + if ($path =~ m{^/uploaded/($match_domain)/($match_courseid)/$}) { + $srcdom = $1; + $srcnum = $2; + if (($1 ne $coursedom) && ($2 ne $coursenum)) { + my $srcdom = $1; + my $srcnum = $2; + if ($env{"user.priv.cm./$srcdom/$srcnum"} =~ /\Q:mdc&F\E/) { + &url_paste_fixups($oldid,$ext,$coursedom,$coursenum, + \%allmaps, \%rewrites,\%copies,\%dbcopies,\%zombies,\%params); + } else { + return &mt('Paste failed: Item is from a different course which you do not have rights to edit'); + } + } + } + } else { + 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; + } elsif ($url=~m {^/res/}) { +# published maps can only exists once, so remove it from paste buffer when done + &Apache::lonnet::delenv('docs.markedcopy'); + if ($allmaps{$url}) { + return &mt('Paste failed: only one instance of a particular published sequence or page is allowed within each course.'); + } + } + } elsif ($url =~ m{^/uploaded/($match_domain)/($match_courseid)/}) { + if (($1 ne $coursedom) || ($2 ne $coursenum)) { + $srcdom = $1; + $srcnum = $2; + unless ($env{"user.priv.cm./$srcdom/$srcnum"} =~ /\Q:mdc&F\E/) { + return &mt('Paste failed: Item is from a different course which you do not have rights to edit'); + } + } + } + if ($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; + } + } + my ($relpath,$oldprefix,$prefixchg); + if ($url =~ m{^/uploaded/$match_domain/$match_courseid/(docs|supplemental)/(.+)$}) { + $oldprefix = $1; + $relpath = $2; + if (($folder =~ /^supplemental/) && ($oldprefix eq 'docs')) { + $prefixchg = 1; + } elsif (($folder =~ /^default/) && ($oldprefix eq 'supplemental')) { + $prefixchg = 1; + } + } + $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 ($relpath ne '') { + my ($prefix,$subdir,$rem) = ($relpath =~ m{^(default|\d+)/(\d+)/(.+)$}); + my ($newloc,$newsubdir) = ($folder =~ /^(default|supplemental)_?(\d*)/); + my $newprefix = $newloc; + if ($newloc eq 'default') { + $newprefix = 'docs'; + } + if ($newsubdir eq '') { + $newsubdir = 'default'; + } + if (($prefixchg) || ($srcdom ne '') && ($srcnum ne '')) { + my $newpath = "$newprefix/$newsubdir/$newidx/$rem"; + $url = + &Apache::lonclonecourse::writefile($env{'request.course.id'},$newpath, + &Apache::lonnet::getfile($oldurl)); + if ($url eq '/adm/notfound.html') { + return &mt('Paste failed: an error occurred saving the file.'); + } else { + my ($newsubpath) = ($newpath =~ m{^(.*/)[^/]*$}); + $newsubpath =~ s{/+$}{/}; + $moves{$oldurl} = $newsubpath; + } + } + } + my $noparams = 0; + if ((ref($params{$oldurl}) eq 'HASH') && ($relpath ne '') && ($folder =~ /^supplemental/)) { + $noparams = 1; + } + &apply_fixups($coursedom,$coursenum,$oldurl,$url,$noparams,\%rewrites,\%copies, + \%dbcopies,\%zombies,\%params,\%moves); + if ($env{'docs.markedcopy_supplemental'}) { + if ($folder =~ /^supplemental/) { + $title = $env{'docs.markedcopy_supplemental'}; + } else { + (undef,undef,$title) = + &Apache::loncommon::parse_supplemental_title($env{'docs.markedcopy_supplemental'}); + } + } else { + if ($folder=~/^supplemental/) { + $title=time.'___&&&___'.$env{'user.name'}.'___&&&___'. + $env{'user.domain'}.'___&&&___'.$title; + } + } + + $LONCAPA::map::resources[$newidx]= $title.':'.$url.':'.$ext.':normal:res'; + push(@LONCAPA::map::order, $newidx); + return 'ok'; +# Store the result +} + +sub dbcopy { + my ($url,$coursedom,$coursenum) = @_; + if ($url=~ m{/smppg$}) { + my $db_name = &Apache::lonsimplepage::get_db_name($url); + if ($db_name =~ /^smppage_/) { + #simple pages, need to copy the db contents to a new one. + my %contents=&Apache::lonnet::dump($db_name,$coursedom,$coursenum); + my $now = time(); + $db_name =~ s{_\d*$ }{_$now}x; + my $result=&Apache::lonnet::put($db_name,\%contents, + $coursedom,$coursenum); + $url =~ s{/(\d*)/smppg$ }{/$now/smppg}x; + } + } + return $url; +} + +sub uniqueness_check { + 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; +} + +sub contained_map_check { + my ($url,$folder,$removefrommap,$addedmaps) = @_; + my $content = &Apache::lonnet::getfile($url); + unless ($content eq '-1') { + my $parser = HTML::TokeParser->new(\$content); + $parser->attr_encoded(1); + while (my $token = $parser->get_token) { + next if ($token->[0] ne 'S'); + if ($token->[1] eq 'resource') { + next if ($token->[2]->{'type'} eq 'zombie'); + my $ressrc = $token->[2]->{'src'}; + if ($folder =~ /^supplemental/) { + unless (&supp_pasteable($ressrc)) { + $removefrommap->{$url}{$token->[2]->{'id'}}; + next; + } + } + if ($ressrc =~ /\.(sequence|page)$/) { + if (ref($addedmaps->{$ressrc}) eq 'ARRAY') { + push(@{$addedmaps->{$ressrc}},$url); + } else { + $addedmaps->{$ressrc} = [$url]; + } + &contained_map_check($ressrc,$folder,$removefrommap,$addedmaps); + } + } elsif ($token->[1] !~ /^resource|map|link$/) { + if ($folder =~ /^supplemental/) { + $removefrommap->{$url}{$token->[1]}; + } + } + } + } + return; +} + +sub reinit_role { + my ($cdom,$cnum,$chome) = @_; + my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum"); + unless ($ferr) { + &Apache::loncommon::update_content_constraints($cdom,$cnum,$chome,$cdom.'_'.$cnum); + } + return; +} + +sub url_paste_fixups { + my ($oldurl,$ext,$cdom,$cnum,$allmaps,$rewrites,$copies,$dbcopies,$zombies,$params) = @_; + my $file = &Apache::lonnet::getfile("$oldurl.$ext"); + return if ($file eq '-1'); + my $parser = HTML::TokeParser->new(\$file); + $parser->attr_encoded(1); + while (my $token = $parser->get_token) { + next if ($token->[0] ne 'S'); + if ($token->[1] eq 'resource') { + my $ressrc = $token->[2]->{'src'}; + next if ($ressrc eq ''); + next if ($token->[2]->{'type'} eq 'external'); + my $id = $token->[2]->{'id'}; + if ($token->[2]->{'type'} eq 'zombie') { + $zombies->{$oldurl}{$ressrc} = $id; + } elsif ($ressrc =~ m{^/uploaded/($match_domain)/($match_courseid)/(.+)}) { + my $srccdom = $1; + my $srccnum = $2; + my $rem = $3; + if (($srccdom ne $cdom) || ($srccnum ne $cnum)) { + if ($rem =~ /^(default|supplemental)(_?\d*).(sequence|page)$/) { + $rewrites->{$oldurl}{$ressrc} = $id; + &url_paste_fixups($ressrc,$3,$cdom,$cnum,$allmaps,$rewrites,$copies,$dbcopies,$zombies,$params); + } else { + $rewrites->{$oldurl}{$ressrc} = $id; + $copies->{$oldurl}{$ressrc} = $id; + } + } + } elsif ($ressrc =~ m{^/adm/($match_domain)/($match_courseid)/(.+)$}) { + my $srccdom = $1; + my $srccnum = $2; + if (($srccdom ne $cdom) || ($srccnum ne $cnum)) { + $rewrites->{$oldurl}{$ressrc} = $id; + $dbcopies->{$oldurl}{$ressrc} = $id; + } + } elsif ($ressrc =~ m{^/public/($match_domain)/($match_courseid)/(.+)$}) { + my $srccdom = $1; + my $srccnum = $2; + if (($srccdom ne $cdom) || ($srccnum ne $cnum)) { + $rewrites->{$oldurl}{$ressrc} = $id; + $dbcopies->{$oldurl}{$ressrc} = $id; + } + } + } elsif ($token->[1] eq 'param') { + my $to = $token->[2]->{'to'}; + if ($to ne '') { + if (ref($params->{$oldurl}{$to}) eq 'ARRAY') { + push (@{$params->{$oldurl}{$to}},$token->[2]->{'name'}); + } else { + @{$params->{$oldurl}{$to}} = ($token->[2]->{'name'}); + } + } + } + } + return; +} + +sub apply_fixups { + my ($cdom,$cnum,$oldurl,$url,$noparams,$rewrites,$copies,$dbcopies,$zombies,$params, + $moves) = @_; + my (%newdb,%newdoc); + if (ref($dbcopies->{$oldurl}) eq 'HASH') { + foreach my $item (keys(%{$dbcopies->{$oldurl}})) { + $newdb{$item} = &dbcopy($item); + } + } + my @allcopies; + if (ref($copies->{$oldurl}) eq 'HASH') { + push(@allcopies,keys(%{$copies->{$oldurl}})); + } + if ((ref($moves) eq 'HASH') && (exists($moves->{$oldurl}))) { + push(@allcopies,$oldurl); + } + if (@allcopies > 0) { + foreach my $item (@allcopies) { + my $content = &Apache::lonnet::getfile($item); + unless ($content eq '-1') { + my $mm = new File::MMagic; + my $mimetype = $mm->checktype_contents($content); + if ($mimetype eq 'text/html') { + my (%allfiles,%codebase,$state); + if (&Apache::lonnet::extract_embedded_items(undef,\%allfiles,\%codebase,\$content) eq 'ok') { + my ($numexisting,$numpathchanges,$existing); + (undef,$numexisting,$numpathchanges,$existing) = + &Apache::loncommon::ask_for_embedded_content( + '/adm/coursedocs',$state,\%allfiles,\%codebase, + {'error_on_invalid_names' => 1, + 'ignore_remote_references' => 1, + 'docs_url' => $oldurl, + 'context' => 'paste'}); + if ($numexisting > 0) { + if (ref($existing) eq 'HASH') { + my ($relpath) = ($item =~ m{^(/uploaded/$match_domain/$match_courseid/(?:docs|supplemental)/(?:default|\d+)/.*/)[^/]+$}); + foreach my $dep (keys(%{$existing})) { + $dep =~ s{^\Q$relpath\E}{}; + my $depfile = $relpath.$dep; + my $depstorefn; + if ((ref($copies->{$oldurl}) eq 'HASH') && + ($copies->{$oldurl}{$item})) { + $depstorefn = $relpath; + $depstorefn =~s{^/\w+/$match_domain/$match_courseid/}{}; + } elsif ((ref($moves) eq 'HASH') && + (exists($moves->{$oldurl}))) { + $depstorefn = $moves->{$oldurl}; + } + $depstorefn .= $dep; + my $depcontent = &Apache::lonnet::getfile($depfile); + unless ($depcontent eq '-1') { + &Apache::lonclonecourse::writefile($env{'request.course.id'},$depstorefn,$depcontent); + } + } + } + } + } + } + my $storefn=$item; + unless (exists($moves->{$oldurl})) { + $storefn=~s{^/\w+/$match_domain/$match_courseid/}{}; + $newdoc{$item} = &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn,$content); + } + } + } + } + if (((ref($rewrites->{$oldurl}) eq 'HASH') || (ref($zombies->{$oldurl}) eq 'HASH')) || + ($noparams) || (keys(%newdb) > 0) || (keys(%newdoc) > 0)) { + my $map = &Apache::lonnet::getfile($url); + my $newcontent; + unless ($map eq '-1') { + my $parser = HTML::TokeParser->new(\$map); + $parser->attr_encoded(1); + while (my $token = $parser->get_token) { + if ($token->[0] eq 'S') { + next if ($token->[2]->{'type'} eq 'zombie'); + next if (($token->[1] eq 'param') && $noparams); + if ($token->[1] eq 'resource') { + my $src = $token->[2]->{'src'}; + my $id = $token->[2]->{'id'}; + if (($rewrites->{$oldurl}{$src} eq $id) || ($newdb{$src} ne '') + || ($newdoc{$src} ne '')) { + if (ref($rewrites->{$oldurl}) eq 'HASH') { + if ($rewrites->{$oldurl}{$src} eq $id) { + $token->[2]->{'src'} =~ s{^(/uploaded|adm|public)/$match_domain/$match_courseid/}{$1/$cdom/$cnum}; + } + } elsif ($newdb{$src} ne '') { + $token->[2]->{'src'} = $newdb{$src}; + } + $newcontent .= "<$token->[1] "; + foreach my $attr (@{$token->[3]}) { + $newcontent .= ' '.$attr.'="'.$token->[2]->{$attr},'"' + } + $newcontent .= ' />'; + } else { + $newcontent .= $token->[4]."\n"; + } + } + } elsif ($token->[0] eq 'E') { + $newcontent .= $token->[2]."\n"; + } + } + } + my $storefn=$url; + $storefn=~s{^/\w+/$match_domain/$match_courseid/}{}; + my $storeres = + &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn, + $newcontent); + } + return; +} + +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!~/$LONCAPA::assess_page_seq_re/)) { + &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,$upload_output,$crstype, + $supplementalflag,$orderhash,$iconpath)=@_; + my $container= ($env{'form.pagepath'}) ? 'page' + : 'sequence'; + + my ($breadcrumbtrail,$randompick,$ishidden,$isencrypted,$plain,$is_random_order) = + &breadcrumbs($allowed,$crstype); + $r->print($breadcrumbtrail); + + my $jumpto = "uploaded/$coursedom/$coursenum/$folder.$container"; + + unless ($allowed) { + $randompick = -1; + } + + 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]=''; + } + # ------------------------------------------------------------ Process commands + # ---------------- if they are for this folder and user allowed to make changes - if (($allowed) && ($ENV{'form.folder'} eq $folder)) { -# upload a file, if present - if (($ENV{'form.uploaddoc.filename'}) && - ($ENV{'form.cmd'}=~/^upload_(\w+)/)) { - if ($folder=~/^$1/) { -# 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; - 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') { - if (($idx) && (defined($Apache::lonratedt::order[$idx-1]))) { - 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') { - if (defined($Apache::lonratedt::order[$idx+1])) { - my $i=$Apache::lonratedt::order[$idx+1]; - $Apache::lonratedt::order[$idx+1]= - $Apache::lonratedt::order[$idx]; - $Apache::lonratedt::order[$idx]=$i; - } - } elsif ($cmd eq 'rename') { - my ($rtitle,@rrest)=split(/\:/, - $Apache::lonratedt::resources[ - $Apache::lonratedt::order[$idx]]); - my $comment= - &HTML::Entities::decode($ENV{'form.title'}); - $comment=~s/\/\>\;/g; - $comment=~s/\:/\:/g; - $Apache::lonratedt::resources[ - $Apache::lonratedt::order[$idx]]= - $comment.':'.join(':',@rrest); - - } -# Store the changed version - &storemap($coursenum,$coursedom,$folder.'.sequence'); + 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('

'.$paste_res.'

'); } + } + + $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'}) { - 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; - $name=~s/\:/\:/g; - $Apache::lonratedt::resources[$idx]= - $name.':'.$url.':'.$ext.':normal:res'; - } - } - } -# Store the changed version - &storemap($coursenum,$coursedom,$folder.'.sequence'); - } + 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.importmap'}) && ($ENV{'form.loadmap'})) { - foreach -(&Apache::lonsequence::attemptread(&Apache::lonnet::filelocation('',$ENV{'form.importmap'}))) { - my $idx=$#Apache::lonratedt::resources; - $idx++; - $Apache::lonratedt::resources[$idx]=$_; - $Apache::lonratedt::order - [$#Apache::lonratedt::order+1]=$idx; - } + 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('

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

'); -# Store the changed version - &storemap($coursenum,$coursedom,$folder.'.sequence'); - } - } + } + } + &log_differences($plain); + } # ---------------------------------------------------------------- End commands # ---------------------------------------------------------------- Print screen - my $idx=0; - $r->print(''); - foreach (@Apache::lonratedt::order) { - my ($name,$url)=split(/\:/,$Apache::lonratedt::resources[$_]); - unless ($name) { $name=(split(/\//,$url))[-1]; } - unless ($name) { $name='NO RESOURCE'; $url='/adm/notfound.html'; } - $r->print(&entryline($idx,$name,$url,$folder,$allowed,$_)); - $idx++; + my $idx=0; + my $shown=0; + if (($ishidden) || ($isencrypted) || ($randompick>=0) || ($is_random_order)) { + $r->print('
'. + '
  1. '.&mt('Parameters:').'
  2. '. + ($randompick>=0?'
  3. '.&mt('randomly pick [quant,_1,resource]',$randompick).'
  4. ':''). + ($ishidden?'
  5. '.&mt('contents hidden').'
  6. ':''). + ($isencrypted?'
  7. '.&mt('URLs hidden').'
  8. ':''). + ($is_random_order?'
  9. '.&mt('random order').'
  10. ':''). + '
'); + if ($randompick>=0) { + $r->print('

' + .&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.') + .'

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

' + .&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.') + .'

' + ); + } + $r->print('
'); + } + + my ($to_show,$output); + + &Apache::loncommon::start_data_table_count(); #setup a row counter + 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++; + } + &Apache::loncommon::end_data_table_count(); + + if ($shown) { + $to_show = &Apache::loncommon::start_scrollbox('900px','880px','400px','contentscroll') + .&Apache::loncommon::start_data_table(undef,'contentlist'); + if ($allowed) { + $to_show .= &Apache::loncommon::start_data_table_header_row() + .'' + .'' + .''; + if ($folder !~ /^supplemental/) { + $to_show .= ''; + } + $to_show .= &Apache::loncommon::end_data_table_header_row(); + } + $to_show .= $output.' ' + .&Apache::loncommon::end_data_table() + .'
' + .&Apache::loncommon::end_scrollbox(); + } else { + $to_show .= &Apache::loncommon::start_scrollbox('400px','380px','200px','contentscroll') + .'
' + .&mt('Currently no documents.') + .'
' + .&Apache::loncommon::end_scrollbox(); + } + my $tid = 1; + if ($supplementalflag) { + $tid = 2; + } + if ($allowed) { + my $readfile="/uploaded/$coursedom/$coursenum/$folder.$container"; + $r->print(&generate_edit_table($tid,$orderhash,$to_show,$iconpath,$jumpto, + $readfile)); + &print_paste_buffer($r,$container,$folder); + } else { + if (&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) { + #Function Box for Supplemental Content for users with mdc priv. + my $funcname = &mt('Folder Editor'); + $r->print( + &Apache::loncommon::head_subbox( + &Apache::lonhtmlcommon::start_funclist(). + &Apache::lonhtmlcommon::add_item_funclist( + ''. + ''.$funcname.''. + ''.$funcname.''). + &Apache::lonhtmlcommon::end_funclist())); + } + $r->print($to_show); + } + return; +} + +sub process_file_upload { + my ($upload_output,$coursenum,$coursedom,$allfiles,$codebase,$uploadcmd) = @_; +# upload a file, if present + my ($parseaction,$showupload,$nextphase,$mimetype); + if ($env{'form.parserflag'}) { + $parseaction = 'parse'; + } + 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) { + $$upload_output = '
'.&mt('The uploaded file has not been stored as an error occurred reading the contents of the current folder.').'
'; + return; + } + my $destination = 'docs/'; + if ($folder =~ /^supplemental/) { + $destination = 'supplemental/'; + } + 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 context to coursedoc. + my $newidx=&LONCAPA::map::getresidx(); + $destination .= $newidx; + my $url=&Apache::lonnet::userfileupload('uploaddoc','coursedoc',$destination, + $parseaction,$allfiles, + $codebase,undef,undef,undef,undef, + undef,undef,\$mimetype); + if ($url =~ m{^/uploaded/\Q$coursedom\E/\Q$coursenum\E.*/([^/]+)$}) { + my $stored = $1; + $showupload = '

'.&mt('Uploaded [_1]',''. + $stored.'').'

'; + } else { + my ($filename) = ($env{'form.uploaddoc.filename'} =~ m{([^/]+)$}); + + $$upload_output = '
'.&mt('Unable to save file [_1].',''.$filename.'').'
'; + return; + } + 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 = '
'.$errtext.'
'; + return; + } else { + if ($parseaction eq 'parse' && $mimetype eq 'text/html') { + $$upload_output = $showupload; + my $total_embedded = scalar(keys(%{$allfiles})); + if ($total_embedded > 0) { + my $uploadphase = 'upload_embedded'; + my $primaryurl = &HTML::Entities::encode($url,'<>&"'); + my $state = &embedded_form_elems($uploadphase,$primaryurl,$newidx); + my ($embedded,$num) = + &Apache::loncommon::ask_for_embedded_content( + '/adm/coursedocs',$state,$allfiles,$codebase,{'docs_url' => $url}); + if ($embedded) { + if ($num) { + $$upload_output .= + '

'.&mt('This file contains embedded multimedia objects, which need to be uploaded.').'

'.$embedded; + $nextphase = $uploadphase; + } else { + $$upload_output .= $embedded; + } + } else { + $$upload_output .= &mt('Embedded item(s) already present, so no additional upload(s) required').'
'; + } + } else { + $$upload_output .= &mt('No embedded items identified').'
'; + } + $$upload_output = '
'.$$upload_output.'
'; + } elsif (&Apache::loncommon::is_archive_file($mimetype)) { + $nextphase = 'decompress_uploaded'; + my $position = scalar(@LONCAPA::map::order)-1; + my $noextract = &return_to_editor(); + my $archiveurl = &HTML::Entities::encode($url,'<>&"'); + my %archiveitems = ( + folderpath => $env{'form.folderpath'}, + pagepath => $env{'form.pagepath'}, + cmd => $nextphase, + newidx => $newidx, + position => $position, + phase => $nextphase, + comment => $comment, + ); + my ($destination,$dir_root) = &embedded_destination($coursenum,$coursedom); + my @current = &get_dir_list($url,$coursenum,$coursedom,$newidx); + $$upload_output = $showupload. + &Apache::loncommon::decompress_form($mimetype, + $archiveurl,'/adm/coursedocs',$noextract, + \%archiveitems,\@current); + } + } + } + return $nextphase; +} + +sub get_dir_list { + my ($url,$coursenum,$coursedom,$newidx) = @_; + my ($destination,$dir_root) = &embedded_destination(); + my ($dirlistref,$listerror) = + &Apache::lonnet::dirlist("$dir_root/$destination/$newidx",$coursedom,$coursenum,1); + my @dir_lines; + my $dirptr=16384; + if (ref($dirlistref) eq 'ARRAY') { + foreach my $dir_line (sort + { + my ($afile)=split('&',$a,2); + my ($bfile)=split('&',$b,2); + return (lc($afile) cmp lc($bfile)); + } (@{$dirlistref})) { + my ($filename,$dom,undef,$testdir,undef,undef,undef,undef,$size,undef,$mtime,undef,undef,undef,$obs,undef)=split(/\&/,$dir_line,16); + $filename =~ s/\s+$//; + next if ($filename =~ /^\.\.?$/); + my $isdir = 0; + if ($dirptr&$testdir) { + $isdir = 1; + } + push(@dir_lines, [$filename,$dom,$isdir,$size,$mtime,$obs]); } - $r->print('
'.&mt('Move').''.&mt('Actions').''.&mt('Document').''.&mt('Settings').'
'); } + return @dir_lines; +} + +sub is_supplemental_title { + my ($title) = @_; + return scalar($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/); } # --------------------------------------------------------------- An entry line sub entryline { - my ($index,$title,$url,$folder,$allowed,$residx)=@_; - $title=~s/\&colon\;/\:/g; - $title=&HTML::Entities::encode(&HTML::Entities::decode( - &Apache::lonnet::unescape($title)),'\"\<\>\&\''); - my $renametitle=$title; - my $foldertitle=$title; - if ($title=~ - /^(\d+)\_\_\_\&\;\&\;\&\;\_\_\_(\w+)\_\_\_\&\;\&\;\&\;\_\_\_(\w+)\_\_\_\&\;\&\;\&\;\_\_\_(.*)$/ - ) { - $foldertitle=&Apache::lontexconvert::msgtexconverted($4); - $renametitle=$4; - $title=''.localtime($1).' '. - &Apache::loncommon::plainname($2,$3).':
'. - $foldertitle; - } + my ($index,$title,$url,$folder,$allowed,$residx,$coursenum,$crstype)=@_; + my ($foldertitle,$pagetitle,$renametitle); + if (&is_supplemental_title($title)) { + ($title,$foldertitle,$renametitle) = &Apache::loncommon::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; - my $line=''; + $renametitle=~s/ /%20/g; + my $line=&Apache::loncommon::start_data_table_row(); + my ($form_start,$form_end,$form_common); # 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($env{'form.pagepath'}); + $path = &HTML::Entities::encode($env{'form.pagepath'},'<>&"'); + $symb=&escape($env{'form.pagesymb'}); + } + my $cpinfo=''; if ($allowed) { - $line.=(< - - -
- -UP
- -DOWN
- -Remove - -Rename + my $incindex=$index+1; + my $selectbox=''; + if (($#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= + ''. + ''; + } + 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=(<$lt{'cp'} +ENDCOPY + } + if (!$nocut) { + $cutlink=(<$lt{'ct'} +ENDCUT + } + $form_start = ' +
+'; + $form_common=(< + + + END + $form_end = ''; + $line.=(< +
+ + $lt{ + +
+
+ + $lt{ + +
+ + + $form_start + $form_common + $selectbox + $form_end + + + $lt{'rm'} +$cutlink + $lt{'rn'} +$copylink + +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') || ($extension eq 'page')) { + $url=~/\Q$coursenum\E\/([\/\w]+)\.\Q$extension\E$/; + my $containerarg = $1; + if ($extension eq 'sequence') { + $icon=$iconpath.'navmap.folder.closed.gif'; + $folderarg=$containerarg; + $isfolder=1; + } else { + $icon=$iconpath.'page.gif'; + $pagearg=$containerarg; + $ispage=1; + } + if ($allowed) { + $url='/adm/coursedocs?'; + } else { + $url='/adm/supplemental?'; + } + } else { + &Apache::lonnet::allowuploaded('/adm/coursedoc',$url); + } } - $url=~s/^http\&colon\;\/\//\/adm\/wrapper\/ext\//; - if ($residx) { - $url.=(($url=~/\?/)?'&':'?').'symb='. - &Apache::lonnet::escape(&Apache::lonnet::symbclean( + + 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. + $env{'course.'.$env{'request.course.id'}.'.domain'}.'/'. + $env{'course.'.$env{'request.course.id'}.'.num'}.'/'.$folder. '.sequence'). '___'.$residx.'___'. - &Apache::lonnet::declutter($url))); + &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 ($rand_pick_text,$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; + my $rpicknum = (&LONCAPA::map::getparameter($orderidx, + 'parameter_randompick'))[0]; + my $rpckchk; + if ($rpicknum) { + $rpckchk = ' checked="checked"'; + } + my $formname = 'edit_rpick_'.$orderidx; + $rand_pick_text = +'
'."\n". +$form_common."\n". +''; + if ($rpicknum ne '') { + $rand_pick_text .= ': '.$rpicknum.''; + } + $rand_pick_text .= '
'; + my $ro_set= + ((&LONCAPA::map::getparameter($orderidx,'parameter_randomorder'))[0]=~/^yes$/i?' checked="checked"':''); + $rand_order_text = +$form_start. +$form_common.' +'; + } + 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 ($isfolder) { $url.='&foldername='. - &Apache::lonnet::escape($foldertitle); } - $line.=''. - "$title"; + if (($external) && ($allowed)) { + my $form = ($folder =~ /^default/)? 'newext' : 'supnewext'; + $external = ' '.&mt('Edit').''; + } else { + undef($external); + } + my $reinit; + if ($crstype eq 'Community') { + $reinit = &mt('(re-initialize community to access)'); + } else { + $reinit = &mt('(re-initialize course to access)'); + } + $line.=''; + if (($url=~m{/adm/(coursedocs|supplemental)}) || (!$allowed && $url)) { + $line.=''; + } elsif ($url) { + $line.=&Apache::loncommon::modal_link($url.(($url=~/\?/)?'&':'?').'inhibitmenu=yes', + '',600,500); + } else { + $line.=''; + } + $line.=''; + if (($url=~m{/adm/(coursedocs|supplemental)}) || (!$allowed && $url)) { + $line.=''.$title.''; + } elsif ($url) { + $line.=&Apache::loncommon::modal_link($url.(($url=~/\?/)?'&':'?').'inhibitmenu=yes', + $title,600,500); + } else { + $line.=$title.' '.$reinit.''; + } + $line.=$external.""; + $rand_pick_text = ' ' if ($rand_pick_text eq ''); + $rand_order_text = ' ' if ($rand_order_text eq ''); + if (($allowed) && ($folder!~/^supplemental/)) { + my %lt=&Apache::lonlocal::texthash( + 'hd' => 'Hidden', + 'ec' => 'URL hidden'); + my $enctext= + ((&LONCAPA::map::getparameter($orderidx,'parameter_encrypturl'))[0]=~/^yes$/i?' checked="checked"':''); + my $hidtext= + ((&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i?' checked="checked"':''); + $line.=(< + $form_start + $form_common + + $form_end +
+ $form_start + $form_common + + $form_end + + $rand_pick_text
+ $rand_order_text +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) && ($url!~/^\/uploaded\//) && ($url!~/\*$/)) { - $r->print('
'); + $r->print("\n
"); + if ($level==0) { + $r->print("
"); + } for (my $i=0;$i<=$level*5;$i++) { $r->print(' '); } @@ -317,8 +1967,8 @@ sub checkonthis { if ($url=~/^\/res\//) { my $result=&Apache::lonnet::repcopy( &Apache::lonnet::filelocation('',$url)); - if ($result==OK) { - $r->print('ok'); + if ($result eq 'ok') { + $r->print(''.&mt('ok').''); $r->rflush(); &Apache::lonnet::countacc($url); $url=~/\.(\w+)$/; @@ -328,613 +1978,2345 @@ sub checkonthis { 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))); - if (($Apache::lonxml::errorcount) || - ($Apache::lonxml::warningcount)) { - if ($Apache::lonxml::errorcount) { - $r->print(''. - $Apache::lonxml::errorcount.' error(s) '); + $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(''.&mt('bomb').''. + &mt('[quant,_1,error]',$errorcount).''); } - if ($Apache::lonxml::warningcount) { - $r->print(''. - $Apache::lonxml::warningcount.' warning(s)'); + if ($warningcount) { + $r->print(''. + &mt('[quant,_1,warning]',$warningcount).''); } } else { - $r->print('ok'); + $r->print(''.&mt('ok').''); } $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('connection down'); - } elsif ($result==HTTP_NOT_FOUND) { - $r->print('not found'); + } elsif ($result eq 'unavailable') { + $r->print(''.&mt('connection down').''); + } elsif ($result eq 'not_found') { + unless ($url=~/\$/) { + $r->print(''.&mt('not found').''); + } else { + $r->print(''.&mt('unable to verify variable URL').''); + } } else { - $r->print('access denied'); + $r->print(''.&mt('access denied').''); } - } + } + } +} + + + +=pod + +=item list_symbs() + +List Content Identifiers + +=cut + +sub list_symbs { + my ($r) = @_; + + my $crstype = &Apache::loncommon::course_type(); + $r->print(&Apache::loncommon::start_page('List of Content Identifiers')); + $r->print(&Apache::lonhtmlcommon::breadcrumbs('Content Identifiers')); + $r->print(&startContentScreen('tools')); + my $navmap = Apache::lonnavmaps::navmap->new(); + if (!defined($navmap)) { + $r->print('

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

'. + '
'. + &mt('Unable to retrieve information about course contents'). + '
'); + &Apache::lonnet::logthis('Symb list failed - could not create navmap object in '.lc($crstype).':'.$env{'request.course.id'}); + } else { + $r->print('

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

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

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

'); + $hashtied=0; + undef %alreadyseen; + %alreadyseen=(); + &tiehash(); + + foreach my $key (keys(%hash)) { + if ($hash{$key}=~/\.(page|sequence)$/) { + if (($key=~/^src_/) && ($alreadyseen{&unescape($hash{$key})})) { + $r->print('
'. + &mt('The following sequence or page is included more than once in your '.$crstype.':').' '. + &unescape($hash{$key}).'
'. + &mt('Note that grading records for problems included in this sequence or folder will overlap.').'
'); + } + } + if (($key=~/^src\_(.+)$/) && (!$alreadyseen{&unescape($hash{$key})})) { + &checkonthis($r,$hash{$key},0,$hash{'title_'.$1}); + } } + &untiehash(); + $r->print('

'.&mt('Done').'

'); +} + + +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")); + $r->print(&startContentScreen('tools')); + + 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(&Apache::loncommon::confirmwrapper( + &Apache::lonhtmlcommon::confirm_success(&mt('Your Version Settings have been Saved')))); + } else { + $r->print(&Apache::loncommon::confirmwrapper( + &Apache::lonhtmlcommon::confirm_success(&mt('An Error Occured while Attempting to Save your Version Settings'),1))); + } + &mark_hash_old(); + } + &changewarning($r,''); + 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)', + 'cd' => 'Change display', + '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', + 'save' => 'Save changes', + 'vers' => 'Version choice(s) for specific resources', + 'act' => 'Actions'); + $r->print(<$header +
+ +
+
+$lt{'cd'} + + +
+
+
+
+$lt{'act'} +$lt{'sm'}:
+$lt{'sc'}: +
+
+
+
+

$lt{'vers'}

+ + +ENDHEADERS + #number of columns for version history + my $num_ver_col = 1; + $r->print( + &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_header_row(). + ''. + "". + "". + "". + ''. + ''); + 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( + &Apache::loncommon::end_data_table_header_row(). + &Apache::loncommon::start_data_table_row(). + ''. + ''. + ''); + if ($cols_output != $num_ver_col) { + $r->print(''.&Apache::loncommon::end_data_table_row(). + &Apache::loncommon::end_data_table(). + ''); + + &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". +''."\n". +''. +'

'. +&mt($message,' '). +$help{'Caching'}.'

'."\n\n"); +} + + +sub init_breadcrumbs { + my ($form,$text)=@_; + &Apache::lonhtmlcommon::clear_breadcrumbs(); + &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/coursedocs?tools=1", + text=>&Apache::loncommon::course_type().' Editor', + faq=>273, + bug=>'Instructor Interface', + help => 'Docs_Adding_Course_Doc'}); + &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/coursedocs?".$form.'=1', + text=>$text, + faq=>273, + bug=>'Instructor Interface'}); +} + +# subroutine to list form elements +sub create_list_elements { + my @formarr = @_; + my $list = ''; + for my $button (@formarr){ + for my $picture(keys %$button) { + $list .= &Apache::lonhtmlcommon::htmltag('li', $picture.' '.$button->{$picture}, {class => 'LC_menubuttons_inline_text'}); + } + } + 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; +} + +# +# Start tabs +# + +sub startContentScreen { + my ($mode) = @_; + my $output = ''."\n"; + $output .= '
'. + '
'. + '
'; + return $output; +} + +# +# End tabs +# + +sub endContentScreen { + return '
'; +} + +sub supplemental_base { + return 'supplemental&'.&escape(&mt('Supplemental '.&Apache::loncommon::course_type().' Content')); } -# ================================================================ Main Handler sub handler { my $r = shift; - $r->content_type('text/html'); + &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; return OK if $r->header_only; +# get course data + my $crstype = &Apache::loncommon::course_type(); + my $coursenum=$env{'course.'.$env{'request.course.id'}.'.num'}; + my $coursedom=$env{'course.'.$env{'request.course.id'}.'.domain'}; + +# graphics settings + $iconpath = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL').'/'); + +# # --------------------------------------------- Initialize help topics for this - foreach ('Adding_Course_Doc','Main_Course_Documents', - 'Adding_External_Resource','Navigate_Content', - 'Adding_Folders','Docs_Overview', - 'Supplemental', 'Score_Upload_Form', - 'Importing_LON-CAPA_Resource','Uploading_From_Harddrive') { - $help{$_}=&Apache::loncommon::help_open_topic('Docs_'.$_); - } + 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 Info'} = &Apache::loncommon::help_open_topic( + $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'); - - if ($ENV{'form.verify'}) { - - my $loaderror=&Apache::lonnet::overloaderror($r); - if ($loaderror) { return $loaderror; } - $r->print('Verify Content'. - &Apache::loncommon::bodytag('Verify Course Documents')); - $hashtied=0; - undef %alreadyseen; - %alreadyseen=(); - &tiehash(); - foreach (keys %hash) { - if (($_=~/^src\_(.+)$/) && (!$alreadyseen{$hash{$_}})) { - &checkonthis($r,$hash{$_},0,$hash{'title_'.$1}); + + my $allowed; +# URI is /adm/supplemental when viewing supplemental docs in non-edit mode. + unless ($r->uri eq '/adm/supplemental') { + # does this user have privileges to modify content. + $allowed = &Apache::lonnet::allowed('mdc',$env{'request.course.id'}); + } + + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['chooseserver', + 'inhibitmenu']); + if ($allowed && $env{'form.chooseserver'}) { + &choose_dump_server($r); + return OK; + } elsif ($allowed && $env{'form.verify'}) { + &init_breadcrumbs('verify','Verify Content'); + &verifycontent($r); + } elsif ($allowed && $env{'form.listsymbs'}) { + &init_breadcrumbs('listsymbs','List Content IDs'); + &list_symbs($r); + } elsif ($allowed && $env{'form.docslog'}) { + &init_breadcrumbs('docslog','Show Log'); + my $folder = $env{'form.folder'}; + if ($folder eq '') { + $folder='default'; + } + &docs_change_log($r,$coursenum,$coursedom,$folder,$allowed,$crstype,$iconpath); + } 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().' Content to Authoring Space'); + &dumpcourse($r); + } elsif ($allowed && $env{'form.exportcourse'}) { + &init_breadcrumbs('exportcourse','IMS Export'); + &Apache::imsexport::exportcourse($r); + } else { +# +# Done catching special calls +# The whole rest is for course and supplemental documents and utilities menu +# Get the parameters that may be needed +# + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, + ['folderpath','pagepath', + 'pagesymb','forcesupplement','forcestandard', + 'tools','symb','command']); + +# standard=1: this is a "new-style" course with an uploaded map as top level +# standard=2: this is a "old-style" course, and there is nothing we can do + + my $standard=($env{'request.course.uri'}=~/^\/uploaded\//); + +# Decide whether this should display supplemental or main content or utilities +# supplementalflag=1: show supplemental documents +# supplementalflag=0: show standard documents +# toolsflag=1: show utilities + + + my $supplementalflag=($env{'form.folderpath'}=~/^supplemental/); + if (($env{'form.folderpath'}=~/^default/) || $env{'form.folderpath'} eq "" || ($env{'form.pagepath'})) { + $supplementalflag=0; + } + if ($env{'form.forcesupplement'}) { $supplementalflag=1; } + if ($env{'form.forcestandard'}) { $supplementalflag=0; } + unless ($allowed) { $supplementalflag=1; } + unless ($standard) { $supplementalflag=1; } + my $toolsflag=0; + if ($env{'form.tools'}) { $toolsflag=1; } + + my $script=''; + my $showdoc=0; + my $addentries = {}; + my $container; + my $containertag; + my $uploadtag; + +# Do we directly jump somewhere? + + if ($env{'form.command'} eq 'direct') { + my ($mapurl,$id,$resurl); + if ($env{'form.symb'} ne '') { + ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($env{'form.symb'}); + if ($resurl=~/\.(sequence|page)$/) { + $mapurl=$resurl; + } elsif ($resurl eq 'adm/navmaps') { + $mapurl=$env{'course.'.$env{'request.course.id'}.'.url'}; + } + my $mapresobj; + my $navmap = Apache::lonnavmaps::navmap->new(); + if (ref($navmap)) { + $mapresobj = $navmap->getResourceByUrl($mapurl); + } + $mapurl=~s{^.*/([^/]+)\.(\w+)$}{$1}; + my $type=$2; + my $path; + if (ref($mapresobj)) { + my $pcslist = $mapresobj->map_hierarchy(); + if ($pcslist ne '') { + foreach my $pc (split(/,/,$pcslist)) { + next if ($pc <= 1); + my $res = $navmap->getByMapPc($pc); + if (ref($res)) { + my $thisurl = $res->src(); + $thisurl=~s{^.*/([^/]+)\.\w+$}{$1}; + my $thistitle = $res->title(); + $path .= '&'. + &Apache::lonhtmlcommon::entity_encode($thisurl).'&'. + &Apache::lonhtmlcommon::entity_encode($thistitle). + ':'.$res->randompick(). + ':'.$res->randomout(). + ':'.$res->encrypted(). + ':'.$res->randomorder(); + } + } + } + $path .= '&'.&Apache::lonhtmlcommon::entity_encode($mapurl).'&'. + &Apache::lonhtmlcommon::entity_encode($mapresobj->title()). + ':'.$mapresobj->randompick(). + ':'.$mapresobj->randomout(). + ':'.$mapresobj->encrypted(). + ':'.$mapresobj->randomorder(); + } else { + my $maptitle = &Apache::lonnet::gettitle($mapurl); + $path = '&default&...::::'. + '&'.&Apache::lonhtmlcommon::entity_encode($mapurl).'&'. + &Apache::lonhtmlcommon::entity_encode($maptitle).'::::'; + } + $path = 'default&'. + &Apache::lonhtmlcommon::entity_encode('Main Course Documents'). + $path; + if ($type eq 'sequence') { + $env{'form.folderpath'}=$path; + $env{'form.pagepath'}=''; + } else { + $env{'form.pagepath'}=$path; + $env{'form.folderpath'}=''; + } + } elsif ($env{'form.supppath'} ne '') { + $env{'form.folderpath'}=$env{'form.supppath'}; } + } elsif ($env{'form.command'} eq 'editdocs') { + $env{'form.folderpath'} = 'default&'. + &Apache::lonhtmlcommon::entity_encode('Main Course Content'); + $env{'form.pagepath'}=''; + } elsif ($env{'form.command'} eq 'editsupp') { + $env{'form.folderpath'} = 'default&'. + &Apache::lonhtmlcommon::entity_encode('Supplemental Content'); + $env{'form.pagepath'}=''; } - &untiehash(); - } elsif ($ENV{'form.versions'}) { - $r->print('Check Versions'. - &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'; + +# Where do we store these for when we come back? + my $stored_folderpath='docs_folderpath'; + if ($supplementalflag) { + $stored_folderpath='docs_sup_folderpath'; + } + +# No folderpath, no pagepath, see if we have something stored + if ((!$env{'form.folderpath'}) && (!$env{'form.pagepath'})) { + &Apache::loncommon::restore_course_settings($stored_folderpath, + {'folderpath' => 'scalar'}); + } + +# If we are not allowed to make changes, all we can see are supplemental docs + if (!$allowed) { + $env{'form.pagepath'}=''; + unless ($env{'form.folderpath'} =~ /^supplemental/) { + $env{'form.folderpath'} = &supplemental_base(); + } + } +# If we still not have a folderpath, see if we can resurrect at pagepath + if (!$env{'form.folderpath'} && $allowed) { + &Apache::loncommon::restore_course_settings($stored_folderpath, + {'pagepath' => 'scalar'}); + } +# Make the zeroth entry in supplemental docs page paths, so we can get to top level + if ($env{'form.folderpath'} =~ /^supplemental_\d+/) { + $env{'form.folderpath'} = &supplemental_base() + .'&'. + $env{'form.folderpath'}; + } +# If after all of this, we still don't have any paths, make them + unless (($env{'form.pagepath'}) || ($env{'form.folderpath'})) { + if ($supplementalflag) { + $env{'form.folderpath'}=&supplemental_base(); + } else { + $env{'form.folderpath'}='default'; } - - $r->print(< - - - -

Content changed $seltext

-
'.&mt('Resources').'$lt{'mr'}$lt{'ve'}$lt{'vu'}'.&mt('History').''.&Apache::lonnet::gettitle($linkurl).'
'. + ''.$linkurl.'
'.$currentversion.'
('. + &Apache::lonlocal::locallocaltime(&Apache::lonnet::metadata($root.'.'.$extension,'lastrevisiondate')).')
'); +# Used in course + my $usedversion=$hash{'version_'.$linkurl}; + if (($usedversion) && ($usedversion ne 'mostrecent')) { + if($usedversion != $currentversion){ + $r->print(''.$usedversion.''); + }else{ + $r->print($usedversion); + } + } else { + $r->print($currentversion); + } + $r->print(''); +# Set version + $r->print(&Apache::loncommon::select_form($setversions{$linkurl}, + 'set_version_'.$linkurl, + {'select_form_order' => + ['',1..$currentversion,'mostrecent'], + '' => '', + 'mostrecent' => &mt('most recent'), + map {$_,$_} (1..$currentversion)})); + 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 % $num_ver_col == 0) { + $entries_per_col = $num_entries/$num_ver_col; + } else { + $entries_per_col = $num_entries/$num_ver_col + 1; + } + my $entries_count = 0; + $r->print(''); + my $cols_output = 1; + for (my $prevvers=$lastold;$prevvers<$currentversion;$prevvers++) { + my $url=$root.'.'.$prevvers.'.'.$extension; + $r->print(''.&mt('Version').' '.$prevvers.' ('. + &Apache::lonlocal::locallocaltime( + &Apache::lonnet::metadata($url, + 'lastrevisiondate') + ). + ')'); + if (&Apache::loncommon::fileembstyle($extension) eq 'ssi') { + $r->print(' '.&mt('Diffs').''); + } + $r->print('
'); + if (++$entries_count % $entries_per_col == 0) { + $r->print('
'); + $cols_output++; + } + } + } + while($cols_output++ < $num_ver_col) { + $r->print(''); + } + } + } + $r->print('
- - - -ENDHEADERS - foreach (keys %changes) { - if ($changes{$_}>$starttime) { - my ($root,$extension)=($_=~/^(.*)\.(\w+)$/); - my $currentversion=&Apache::lonnet::getversion($_); - my $linkurl=&Apache::lonnet::clutter($_); - $r->print( - ''. - ''); + } + +# Store this + unless ($toolsflag) { + &Apache::loncommon::store_course_settings($stored_folderpath, + {'pagepath' => 'scalar', + 'folderpath' => 'scalar'}); + if ($env{'form.folderpath'}) { + my (@folderpath)=split('&',$env{'form.folderpath'}); + $env{'form.foldername'}=&unescape(pop(@folderpath)); + $env{'form.folder'}=pop(@folderpath); + $container='sequence'; + } + if ($env{'form.pagepath'}) { + my (@pagepath)=split('&',$env{'form.pagepath'}); + $env{'form.pagename'}=&unescape(pop(@pagepath)); + $env{'form.folder'}=pop(@pagepath); + $container='page'; + $containertag = ''. + ''; + $uploadtag = + ''. + ''. + ''; + } else { + my $folderpath=$env{'form.folderpath'}; + if (!$folderpath) { + if ($env{'form.folder'} eq '' || + $env{'form.folder'} eq 'supplemental') { + $folderpath='default&'. + &escape(&mt('Main '.$crstype.' Documents')); + } + } + $containertag = ''; + $uploadtag = ''; + } + if ($r->uri=~/^\/adm\/coursedocs\/showdoc\/(.*)$/) { + $showdoc='/'.$1; + } + if ($showdoc) { # got called in sequence from course + $allowed=0; + } else { + if ($allowed) { + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['cmd']); + $script=&Apache::lonratedt::editscript('simple'); + } + } + } + +# get personal data + my $uname=$env{'user.name'}; + my $udom=$env{'user.domain'}; + my $plainname=&escape(&Apache::loncommon::plainname($uname,$udom)); + + if ($allowed) { + if ($toolsflag) { + $script .= &inject_data_js(); + my ($home,$other,%outhash)=&authorhosts(); + if (!$home && $other) { + my @hosts; + foreach my $aurole (keys(%outhash)) { + unless(grep(/^\Q$outhash{$aurole}\E/,@hosts)) { + push(@hosts,$outhash{$aurole}); + } + } + $script .= &dump_switchserver_js(@hosts); + } + } else { + my @tabids; + if ($supplementalflag) { + @tabids = ('002','ee2','ff2'); + } else { + @tabids = ('aa1','bb1','cc1','ff1'); + unless ($env{'form.pagepath'}) { + unshift(@tabids,'001'); + push(@tabids,('dd1','ee1')); + } + } + my $tabidstr = join("','",@tabids); + $script .= &editing_js($udom,$uname,$supplementalflag). + &history_tab_js(). + &inject_data_js(). + &Apache::lonhtmlcommon::resize_scrollbox_js('docs',$tabidstr); + $addentries = { + onload => "javascript:resize_scrollbox('contentscroll','1','1');", + }; + } + } +# -------------------------------------------------------------------- Body tag + $script = ''."\n"; + + # Breadcrumbs + &Apache::lonhtmlcommon::clear_breadcrumbs(); + unless ($showdoc) { + &Apache::lonhtmlcommon::add_breadcrumb({ + href=>"/adm/coursedocs",text=>"$crstype Contents"}); + + $r->print(&Apache::loncommon::start_page("$crstype Contents", $script, + {'force_register' => $showdoc, + 'add_entries' => $addentries, + }) + .&Apache::loncommon::help_open_menu('','',273,'RAT') + .&Apache::lonhtmlcommon::breadcrumbs( + 'Editing '.$crstype.' Contents', + 'Docs_Adding_Course_Doc') + ); + } else { + $r->print(&Apache::loncommon::start_page("$crstype documents",undef, + {'force_register' => $showdoc,})); + } + + my %allfiles = (); + my %codebase = (); + my ($upload_result,$upload_output,$uploadphase); + if ($allowed) { + if (($env{'form.uploaddoc.filename'}) && + ($env{'form.cmd'}=~/^upload_(\w+)/)) { + my $context = $1; + # Process file upload - phase one - upload and parse primary file. + undef($hadchanges); + $uploadphase = &process_file_upload(\$upload_output,$coursenum,$coursedom, + \%allfiles,\%codebase,$context); + if ($hadchanges) { + &mark_hash_old(); + } + $r->print($upload_output); + } elsif ($env{'form.phase'} eq 'upload_embedded') { + # Process file upload - phase two - upload embedded objects + $uploadphase = 'check_embedded'; + my $primaryurl = &HTML::Entities::encode($env{'form.primaryurl'},'<>&"'); + my $state = &embedded_form_elems($uploadphase,$primaryurl, + $env{'form.newidx'}); + my $docuname=$env{'course.'.$env{'request.course.id'}.'.num'}; + my $docudom=$env{'course.'.$env{'request.course.id'}.'.domain'}; + my ($destination,$dir_root) = &embedded_destination(); + my $url_root = '/uploaded/'.$docudom.'/'.$docuname; + my $actionurl = '/adm/coursedocs'; + my ($result,$flag) = + &Apache::loncommon::upload_embedded('coursedoc',$destination, + $docuname,$docudom,$dir_root,$url_root,undef,undef,undef,$state, + $actionurl); + $r->print($result.&return_to_editor()); + } elsif ($env{'form.phase'} eq 'check_embedded') { + # Process file upload - phase three - modify references in HTML file + $uploadphase = 'modified_orightml'; + my $docuname=$env{'course.'.$env{'request.course.id'}.'.num'}; + my $docudom=$env{'course.'.$env{'request.course.id'}.'.domain'}; + my ($destination,$dir_root) = &embedded_destination(); + my $result = + &Apache::loncommon::modify_html_refs('coursedoc',$destination, + $docuname,$docudom,undef, + $dir_root); + $r->print($result.&return_to_editor()); + } elsif ($env{'form.phase'} eq 'decompress_uploaded') { + $uploadphase = 'decompress_phase_one'; + $r->print(&decompression_phase_one(). + &return_to_editor()); + } elsif ($env{'form.phase'} eq 'decompress_cleanup') { + $uploadphase = 'decompress_phase_two'; + $r->print(&decompression_phase_two(). + &return_to_editor()); + } + } + + if ($allowed && $toolsflag) { + $r->print(&startContentScreen('tools')); + $r->print(&generate_admin_menu($crstype)); + $r->print(&endContentScreen()); + } elsif ((!$showdoc) && (!$uploadphase)) { +# ----------------------------------------------------------------------------- + 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' => 'Import Document', + 'srch' => 'Search', + 'impo' => 'Import', + 'lnks' => 'Import from Stored Links', + 'selm' => 'Select Map', + 'load' => 'Load Map', + 'reco' => 'Recover Deleted Documents', + 'newf' => 'New Folder', + 'newp' => 'New Composite Page', + 'extr' => 'External Resource', + 'syll' => 'Syllabus', + 'navc' => 'Table of Contents', + 'sipa' => 'Simple Course Page', + 'sipr' => 'Simple Problem', + 'drbx' => 'Drop Box', + 'scuf' => 'External Scores (handgrade, upload, clicker)', + '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 + + my $checkbox=(<$lt{'parse'}? + + --> + +CHBO + + my $fileuploada = "
$help{'Uploading_From_Harddrive'}"; + my $fileuploadform=(< + + $fileupload +
+ $lt{'title'}:
+ + $uploadtag + +
+ + $checkbox + +FUFORM + $fileuploadform .= $fileuploada.''; + + my $simpleeditdefaultform=(< + +SEDFFORM + my @simpleeditdefaultforma = ( + { ''.$lt{srch}.'' => "$uploadtag$lt{'srch'}" }, + { ''.$lt{impo}.'' => "$lt{'impo'}$help{'Importing_LON-CAPA_Resource'}" }, + { ''.$lt{lnks}.'' => "$lt{'lnks'}" }, + ); + $simpleeditdefaultform .= &create_form_ul(&create_list_elements(@simpleeditdefaultforma)); + $simpleeditdefaultform .=(< + $lt{'copm'}
+
+ + $help{'Load_Map'} + +SEDFFORM + + my $extresourcesform=(< + $uploadtag + + $lt{'extr'}$help{'Adding_External_Resource'} + +ERFORM + + + if ($allowed) { + &update_paste_buffer($coursenum,$coursedom); + $r->print(< + + + + + $containertag + + +HIDDENFORM + $r->print(&makesimpleeditform($uploadtag)."\n". + &makedocslogform($uploadtag."\n". + ''."\n")); + } + +# Generate the tabs + my $mode; + if (($supplementalflag) && (!$allowed)) { + &Apache::lonnavdisplay::startContentScreen($r,'supplemental'); + } else { + $r->print(&startContentScreen(($supplementalflag?'suppdocs':'docs'))); + } + +# + + my $savefolderpath; + + if ($allowed) { + my $folder=$env{'form.folder'}; + if ($folder eq '' || $supplementalflag) { + $folder='default'; + $savefolderpath = $env{'form.folderpath'}; + $env{'form.folderpath'}='default&'.&escape(&mt('Content')); + $uploadtag = ''; + } + my $postexec=''; + if ($folder eq 'default') { + $r->print(''."\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 $imspform=(< + + $lt{'imsf'} + +IMSPFORM + + my $newnavform=(< + + $uploadtag + + $lt{'navc'} + $help{'Navigate_Content'} + +NNFORM + my $newsmppageform=(< + + $uploadtag + + $lt{'sipa'} + $help{'Simple Page'} + +NSPFORM + + my $newsmpproblemform=(< + + $uploadtag + + $lt{'sipr'} + $help{'Simple Problem'} + + +NSPROBFORM + + my $newdropboxform=(< + + $uploadtag + + $lt{'drbx'} + +NDBFORM + + my $newexuploadform=(< + + $uploadtag + + $lt{'scuf'} + $help{'Score_Upload_Form'} + +NEXUFORM + + my $newbulform=(< + + $uploadtag + + $lt{'bull'} + $help{'Bulletin Board'} + +NBFORM + + my $newaboutmeform=(< + + $uploadtag + + $lt{'mypi'} + $help{'My Personal Information Page'} + +NAMFORM + + my $newaboutsomeoneform=(< + + $uploadtag + + $lt{'abou'} + +NASOFORM + + + my $newrosterform=(< + + $uploadtag + + $lt{'rost'} + $help{'Course Roster'} + +NROSTFORM + +my $specialdocumentsform; +my @specialdocumentsforma; +my $gradingform; +my @gradingforma; +my $communityform; +my @communityforma; +my $newfolderform; +my $newfolderb; + + my $path = &HTML::Entities::encode($env{'form.folderpath'},'<>&"'); + + my $newpageform=(< + + + + $lt{'newp'} + $help{'Adding_Pages'} + +NPFORM + + + $newfolderform=(< + + + + $lt{'newf'}$help{'Adding_Folders'} + +NFFORM + + my $newsylform=(< + + $uploadtag + + $lt{'syll'} + $help{'Syllabus'} + + +NSYLFORM + + my $newgroupfileform=(< + + $uploadtag + + $lt{'grpo'} + $help{'Group Portfolio'} + +NGFFORM + @specialdocumentsforma=( + {''.$lt{newp}.''=>$newpageform}, + {''.$lt{syll}.''=>$newsylform}, + {''.$lt{navc}.''=>$newnavform}, + {''.$lt{sipa}.''=>$newsmppageform}, + ); + $specialdocumentsform = &create_form_ul(&create_list_elements(@specialdocumentsforma)); + + + my @importdoc = ( + {''.$lt{extr}.''=>$extresourcesform}, + {''.$lt{imsf}.''=>$imspform},); + $fileuploadform = &create_form_ul(&create_list_elements(@importdoc)) . '
' . $fileuploadform; + + @gradingforma=( + {''.$lt{sipr}.''=>$newsmpproblemform}, + {''.$lt{drbx}.''=>$newdropboxform}, + {''.$lt{scuf}.''=>$newexuploadform}, + + ); + $gradingform = &create_form_ul(&create_list_elements(@gradingforma)); + + @communityforma=( + {''.$lt{bull}.''=>$newbulform}, + {''.$lt{mypi}.''=>$newaboutmeform}, + {''.$lt{abou}.''=>$newaboutsomeoneform}, + {''.$lt{rost}.''=>$newrosterform}, + {''.$lt{grpo}.''=>$newgroupfileform}, + ); + $communityform = &create_form_ul(&create_list_elements(@communityforma)); + +my %orderhash = ( + 'aa' => ['Import Content',$fileuploadform], + 'bb' => ['Published Content',$simpleeditdefaultform], + 'cc' => ['Grading Resources',$gradingform], + ); +unless ($env{'form.pagepath'}) { + $orderhash{'00'} = ['Newfolder',$newfolderform]; + $orderhash{'dd'} = ['Collaboration',$communityform]; + $orderhash{'ee'} = ['Special Documents',$specialdocumentsform]; +} + + $hadchanges=0; + unless (($supplementalflag || $toolsflag)) { + my $error = &editor($r,$coursenum,$coursedom,$folder,$allowed,'',$crstype, + $supplementalflag,\%orderhash,$iconpath); + if ($error) { + $r->print('

'.$error.'

'); } + if ($hadchanges) { + &mark_hash_old(); + } + + &changewarning($r,''); + } + } + +# Supplemental documents start here + + my $folder=$env{'form.folder'}; + unless ($supplementalflag) { + $folder='supplemental'; } - $r->print('
FileModification DateVersionDifferences
'.$linkurl. - ''. - localtime($changes{$_}).''.$currentversion.''); - my $lastold=1; - for (my $prevvers=1;$prevvers<$currentversion;$prevvers++) { - my $url=$root.'.'.$prevvers.'.'.$extension; - if (&Apache::lonnet::metadata($url,'lastrevisiondate')< - $starttime) { - $lastold=$prevvers; - } - } - for (my $prevvers=$lastold;$prevvers<$currentversion;$prevvers++) { - my $url=$root.'.'.$prevvers.'.'.$extension; - $r->print('Version '.$prevvers.' ('. - localtime(&Apache::lonnet::metadata($url,'lastrevisiondate')). - ')'); - if (&Apache::loncommon::fileembstyle($extension) eq 'ssi') { - $r->print(' Diffs'); - } - $r->print('
'); - } - $r->print('
'); - } else { - $r->print('

No content modifications yet.

'); - } - &untiehash(); - } else { -# is this a standard course? + if ($folder =~ /^supplemental$/ && + (($env{'form.folderpath'} =~ /^default\&/) || ($env{'form.folderpath'} eq ''))) { + $env{'form.folderpath'} = &supplemental_base(); + } 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 = "$help{'Uploading_From_Harddrive'}"; + my $supupdocform=(< + + $fileupload +
+
+ + $checkbox + +

+ $lt{'comment'}:
+ +
+ + +SUPDOCFORM + $supupdocform .= &create_form_ul(&Apache::lonhtmlcommon::htmltag('li',$supupdocformbtn,{class => 'LC_menubuttons_inline_text'})).""; + + my $supnewfolderform=(< + + + + $lt{'newf'} + $help{'Adding_Folders'} + +SNFFORM + + + my $supnewextform=(< + + + + $lt{'extr'} $help{'Adding_External_Resource'} + +SNEFORM + + my $supnewsylform=(< + + + + $lt{'syll'} + $help{'Syllabus'} + +SNSFORM + + my $supnewaboutmeform=(< + + + + $lt{'mypi'} + $help{'My Personal Information Page'} + +SNAMFORM + + +my @specialdocs = ( + {''.$lt{syll}.'' + =>$supnewsylform}, + {''.$lt{mypi}.'' + =>$supnewaboutmeform}, + ); +my @supimportdoc = ( + {''.$lt{extr}.'' + =>$supnewextform}, + ); +$supupdocform = &create_form_ul(&create_list_elements(@supimportdoc)) . '
' . $supupdocform; +my %suporderhash = ( + '00' => ['Supnewfolder', $supnewfolderform], + 'ee' => ['Import Content',$supupdocform], + 'ff' => ['Special Documents',&create_form_ul(&create_list_elements(@specialdocs))] + ); + if ($supplementalflag) { + my $error = &editor($r,$coursenum,$coursedom,$folder,$allowed,'',$crstype, + $supplementalflag,\%suporderhash,$iconpath); + if ($error) { + $r->print('

'.$error.'

'); + } + } + } elsif ($supplementalflag) { + my $error = &editor($r,$coursenum,$coursedom,$folder,$allowed,'',$crstype, + $supplementalflag,'',$iconpath); + if ($error) { + $r->print('

'.$error.'

'); + } + } - my $standard=($ENV{'request.course.uri'}=~/^\/uploaded\//); - my $forcestandard; - my $forcesupplement; - my $script=''; - my $allowed; - my $events=''; - my $buttons=''; - my $showdoc=0; - &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, - ['folder','foldername']); - if ($r->uri=~/^\/adm\/coursedocs\/showdoc\/(.*)$/) { - $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) { - &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['cmd']); - $script=&Apache::lonratedt::editscript('simple'); - } - } else { # got called in sequence from course - $allowed=0; - $script=''.&Apache::lonmenu::registerurl(1,undef).' -ENDDOCUMENT - if ($allowed) { - $r->print(< +sub decompression_phase_two { + my ($destination,$dir_root,$londocroot,$docudom,$docuname,$container,$hiddenelem)= + &decompression_info(); + my $output; + if ($env{'form.archivedelete'}) { + $output = &remove_archive($docudom,$docuname,$container); + } + $output .= + &Apache::loncommon::process_extracted_files('coursedocs',$docudom,$docuname, + $destination,$dir_root,$hiddenelem); + return $output; +} + +sub remove_archive { + my ($docudom,$docuname,$container) = @_; + my $map = $env{'form.folder'}.'.'.$container; + my ($output,$delwarning,$delresult,$url); + my ($errtext,$fatal) = &mapread($docuname,$docudom,$map); + if ($fatal) { + if ($container eq 'page') { + $delwarning = &mt('An error occurred retrieving the contents of the current page.'); + } else { + $delwarning = &mt('An error occurred retrieving the contents of the current folder.'); + } + $delwarning .= &mt('As a result the archive file has not been removed.'); + } else { + my $currcmd = $env{'form.cmd'}; + my $position = $env{'form.position'}; + if ($position > 0) { + $env{'form.cmd'} = 'del_'.$position; + my ($title,$url,@rrest) = + split(/:/,$LONCAPA::map::resources[$LONCAPA::map::order[$position]]); + if (&handle_edit_cmd($docuname,$docudom)) { + ($errtext,$fatal) = &storemap($docuname,$docudom,$map); + if ($fatal) { + if ($container eq 'page') { + $delwarning = &mt('An error occurred updating the contents of the current page.'); + } else { + $delwarning = &mt('An error occurred updating the contents of the current folder.'); + } + } else { + $delresult = &mt('Archive file removed.'); + } + } + } + $env{'form.cmd'} = $currcmd; + } + if ($delwarning) { + $output = '

'. + $delwarning. + '

'; + } + if ($delresult) { + $output .= '

'. + $delresult. + '

'; + } + return $output; +} + +sub generate_admin_menu { + my ($crstype) = @_; + my $lc_crstype = lc($crstype); + my ($home,$other,%outhash)=&authorhosts(); + my %lt=&Apache::lonlocal::texthash ( + 'vc' => 'Verify Content', + 'cv' => 'Check/Set Resource Versions', + 'ls' => 'List Resource Identifiers', + 'imse' => 'Export contents to IMS Archive', + 'dcd' => "Dump $crstype Content to Authoring Space", + ); + my ($candump,$dumpurl); + if ($home + $other > 0) { + $candump = 'F'; + if ($home) { + $dumpurl = "javascript:injectData(document.courseverify,'dummy','dumpcourse','$lt{'dcd'}')"; + } else { + my @hosts; + foreach my $aurole (keys(%outhash)) { + unless(grep(/^\Q$outhash{$aurole}\E/,@hosts)) { + push(@hosts,$outhash{$aurole}); + } + } + if (@hosts == 1) { + my $switchto = '/adm/switchserver?otherserver='.$hosts[0]. + '&role='. + &HTML::Entities::encode($env{'request.role'},'"<>&').'&origurl='. + &HTML::Entities::encode('/adm/coursedocs?dumpcourse=1','"<>&'); + $dumpurl = "javascript:dump_needs_switchserver('$switchto')"; + } else { + $dumpurl = "javascript:choose_switchserver_window()"; + } + } + } + my @menu= + ({ categorytitle=>'Administration', + items =>[ + { linktext => $lt{'vc'}, + url => "javascript:injectData(document.courseverify,'dummy','verify','$lt{'vc'}')", + permission => 'F', + help => 'Verify_Content', + icon => 'verify.png', + linktitle => 'Verify contents can be retrieved/rendered', + }, + { linktext => $lt{'cv'}, + url => "javascript:injectData(document.courseverify,'dummy','versions','$lt{'cv'}')", + permission => 'F', + help => 'Check_Resource_Versions', + icon => 'resversion.png', + linktitle => "View version information for resources in your $lc_crstype, and fix/unfix use of specific versions", + }, + { linktext => $lt{'ls'}, + url => "javascript:injectData(document.courseverify,'dummy','listsymbs','$lt{'ls'}')", + permission => 'F', + #help => '', + icon => 'symbs.png', + linktitle => "List the unique identifier used for each resource instance in your $lc_crstype" + }, + ] + }, + { categorytitle=>'Export', + items =>[ + { linktext => $lt{'imse'}, + url => "javascript:injectData(document.courseverify,'dummy','exportcourse','$lt{'imse'}')", + permission => 'F', + help => 'Docs_Export_Course_Docs', + icon => 'imsexport.png', + linktitle => $lt{'imse'}, + }, + { linktext => $lt{'dcd'}, + url => $dumpurl, + permission => $candump, + #help => '', + icon => 'dump.png', + linktitle => $lt{'dcd'}, + }, + ] + }); + return '
'."\n". + ''."\n". + &Apache::lonhtmlcommon::generate_menu(@menu)."\n". + '
'; +} + +sub generate_edit_table { + my ($tid,$orderhash_ref,$to_show,$iconpath,$jumpto,$readfile) = @_; + 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'}; + } + my $backicon = $iconpath.'clickhere.gif'; + my $backtext = &mt('To Overview'); + $form = '
'. + ''."\n"; + $form .= '
'."\n"; + + if ($to_show ne '') { + $form .= '
'.$to_show.'
'."\n"; + } + foreach my $field (keys(%orderhash)){ + if($field ne '00'){ + if($activetab eq '' || $activetab ne $field){ + $active = 'style="display: none;float:left"'; + }elsif($activetab eq $field){ + $active = 'style="display:block;float:left"'; + } + $form .= '
'.${$orderhash{$field}}[1] + .'
'."\n"; + } + } + unless ($env{'form.docslog'}) { + $form .= '
'."\n"; + } + return $form; +} + +sub editing_js { + my ($udom,$uname,$supplementalflag) = @_; + my $now = time(); + my %lt = &Apache::lonlocal::texthash( + p_mnf => 'Name of New Folder', + t_mnf => 'New Folder', + p_mnp => 'Name of New Page', + t_mnp => 'New Page', + p_mxu => 'Title for the External 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]', + rpck => 'Enter number to pick (e.g., 3)', + ); + + my $crstype = &Apache::loncommon::course_type(); + my $docs_folderpath = &HTML::Entities::encode($env{'environment.internal.'.$env{'request.course.id'}.'.docs_folderpath.folderpath'},'<>&"'); + my $docs_pagepath = &HTML::Entities::encode($env{'environment.internal.'.$env{'request.course.id'}.'.docs_folderpath.pagepath'},'<>&"'); + my $main_container_page; + if ($docs_folderpath eq '') { + if ($docs_pagepath ne '') { + $main_container_page = 1; + } + } + my $toplevelmain = 'default&Main%20'.$crstype.'%20Documents'; + my $toplevelsupp = &supplemental_base(); + + my $backtourl = '/adm/navmaps'; + if ($supplementalflag) { + $backtourl = '/adm/supplemental'; + } + + return < 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('"'); + if(tab.length < 2) { + 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'; + activeTab = pageId; + if (nav == 'mainnav') { + var storedpath = "$docs_folderpath"; + if (storedpath == '') { + storedpath = "$docs_pagepath"; + } + var storedpage = "$main_container_page"; + var reg = new RegExp("^supplemental"); + if (pageId == 'mainCourseDocuments') { + if (storedpage == 1) { + document.simpleedit.folderpath.value = ''; + document.uploaddocument.folderpath.value = ''; + } else { + if (reg.test(storedpath)) { + document.simpleedit.folderpath.value = '$toplevelmain'; + document.uploaddocument.folderpath.value = '$toplevelmain'; + document.newext.folderpath.value = '$toplevelmain'; + } else { + document.simpleedit.folderpath.value = storedpath; + document.uploaddocument.folderpath.value = storedpath; + document.newext.folderpath.value = storedpath; + } + } + } else { + if (reg.test(storedpath)) { + document.simpleedit.folderpath.value = storedpath; + document.supuploaddocument.folderpath.value = storedpath; + document.supnewext.folderpath.value = storedpath; + } else { + document.simpleedit.folderpath.value = '$toplevelsupp'; + document.supuploaddocument.folderpath.value = '$toplevelsupp'; + document.supnewext.folderpath.value = '$toplevelsupp'; + } + } + } + resize_scrollbox('contentscroll','1','0'); + return false; +} + +function toContents(jumpto) { + var newurl = '$backtourl'; + if (jumpto != '') { + newurl = newurl+'?postdata='+jumpto; +; } + location.href=newurl; } - ENDNEWSCRIPT - } -# -------------------------------------------------------------------- Body tag - $r->print(''. - &Apache::loncommon::bodytag('Course Documents','',$events). - $buttons); - unless ($showdoc) { - if ($allowed) { - $r->print(&Apache::loncommon::help_open_topic('Docs_Adding_Course_Doc', - 'Editing the Table of Contents for your Course')); - $r->print(< - - - - -
- - -
-
- - -
-ENDCOURSEVERIFY - } -# --------------------------------------------------------- Standard documents - $r->print(''); - if (($standard) && ($allowed) && (!$forcesupplement)) { - $r->print(' - - - - - - -

Main Course Documents'. - ($allowed?' '.$help{'Main_Course_Documents'}:'').'

'); - my $folder=$ENV{'form.folder'}; - unless ($folder=~/^default/) { $folder='default'; } - my $postexec=''; - if ($folder eq 'default') { - $r->print(''); - } else { - $postexec='self.close();'; - } - $hadchanges=0; - &editor($r,$coursenum,$coursedom,$folder,$allowed); - if ($hadchanges) { - $r->print( -''. -'
'. -'

Changes will become active for your current session after , or the next time you log in.'. -$help{'Caching'}.'

'); - } - my $folderseq='/uploaded/'.$coursedom.'/'.$coursenum.'/default_'.time. - '.sequence'; +} - $r->print(<
Upload a new main course documentImport a published documentSpecial documents
-File:
-
- -
-Title:
- - - - - - - $help{'Uploading_From_Harddrive'} - -
-
-
- - - - - -$help{'Importing_LON-CAPA_Resource'} - -

-


- - -

-
-
-
- - - - -$help{'Adding_Folders'} - -
-
- - - - - $help{'Adding_External_Resource'} - -
-
- - - - - - $help{'Syllabus'} - -
-
- - - - - -$help{'Navigate_Content'} - -
-
- - - - - $help{'Simple Page'} - -
-
- - - - -$help{'Simple Problem'} - -
-
- - - - - -$help{'Score_Upload_Form'} - -
-
- - - - - -$help{'Bulletin Board'} - -
-
- - - - - -$help{'My Personal Info'} - -
-
-ENDFORM - $r->print(''); - } -# ----------------------------------------------------- Supplemental documents - if (!$forcestandard) { - $r->print( - '

Supplemental Course Documents'. - ($allowed?' '.$help{'Supplemental'}:'').'

'); - 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'; +sub history_tab_js { + return <<"ENDHIST"; +function toggleHistoryDisp(choice) { + document.docslogform.docslog.value = choice; + document.docslogform.submit(); + return; +} - $r->print(< -Upload a new supplemental course document -Import a published document -Special documents - - -
- -
Comment:
- - - - - - - $help{'Uploading_From_Harddrive'} - -
- - -
- - - - -$help{'Importing_LON-CAPA_Resource'} -

-


- - -

-
- -
- - - - - $help{'Adding_Folders'} - -
-
- - - - - $help{'Adding_External_Resource'} - -
-
- - - - - -$help{'Syllabus'} - -
-
- - - - - -$help{'My Personal Info'} - -
- - -ENDSUPFORM +ENDHIST +} + +sub inject_data_js { + return < 'Dumping to Authoring Space requires switching server.', + swit => 'Switch server?', + duco => 'Dump content to Authoring Space', + yone => 'You need to switch to a server housing an Authoring Space for which you are author or co-author.', + chos => 'Choose server', + ); + my $role = $env{'request.role'}; + my $js = <<"ENDSWJS"; + + +ENDSWJS + + my $startpage = &Apache::loncommon::start_page('Choose server',$js, + {'only_body' => 1, + 'js_ready' => 1,}); + my $endpage = &Apache::loncommon::end_page({'js_ready' => 1}); + + my $hostpicker; + my $count = 0; + foreach my $host (sort(@hosts)) { + my $checked; + if ($count == 0) { + $checked = ' checked="checked"'; + } + $hostpicker .= '  '; + $count++; } - $r->print(''); - } else { -# -------------------------------------------------------- This is showdoc mode - $r->print("

Uploaded Document

It is recommended that you use an up-to-date virus scanner before handling this file.

". - &entryline(0,"Click to download or use your browser's Save Link function",$showdoc).'

'); - } - } - $r->print(''); - return OK; -} + + return <<"ENDSWITCHJS"; + +function dump_needs_switchserver(url) { + if (url!='' && url!= null) { + if (confirm("$lt{'dump'}\\n$lt{'swit'}")) { + go(url); + } + } + return; +} + +function choose_switchserver_window() { + newWindow = window.open('','ChooseServer','height=400,width=500,scrollbars=yes') + newWindow.document.open(); + newWindow.document.writeln('$startpage'); + newWindow.document.write('

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

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

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

\\n'+ + '\\n'+ + '<\\/form><\\/fieldset><\\/div>
\\n'); + newWindow.document.writeln('$endpage'); + newWindow.document.close(); + newWindow.focus(); +} + +ENDSWITCHJS +} + +sub makedocslogform { + my ($formelems,$docslog) = @_; + return <<"LOGSFORM"; + + + $formelems +
+LOGSFORM +} + +sub makesimpleeditform { + my ($formelems) = @_; + return <<"SIMPFORM"; +
+ + $formelems +
+SIMPFORM +} 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 clean() + +=item dumpcourse() + + Actually dump course + +=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 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 + +=item create_list_elements() + +=item create_form_ul() + +=item startContentScreen() + +=item endContentScreen() + +=item supplemental_base() + +=item embedded_form_elems() + +=item embedded_destination() + +=item return_to_editor() + +=item decompression_info() + +=item decompression_phase_one() + +=item decompression_phase_two() + +=item remove_archive() + +=item generate_admin_menu() + +=item generate_edit_table() + +=item editing_js() + +=item history_tab_js() + +=item inject_data_js() + +=item dump_switchserver_js() + +=item resize_scrollbox_js() + +=item makedocslogform() + +=item makesimpleeditform() + +=back + +=cut