--- loncom/interface/londocs.pm 2003/08/05 12:47:21 1.71
+++ loncom/interface/londocs.pm 2013/03/13 00:10:13 1.535
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Documents
#
-# $Id: londocs.pm,v 1.71 2003/08/05 12:47:21 www Exp $
+# $Id: londocs.pm,v 1.535 2013/03/13 00:10:13 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::lonextresedit();
use HTML::Entities;
+use HTML::TokeParser;
use GDBM_File;
+use Apache::lonlocal;
+use Cwd;
+use LONCAPA qw(:DEFAULT :match);
my $iconpath;
@@ -47,268 +57,2870 @@ 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 ($coursenum,$coursedom,$map,$contentchg)=@_;
+ my $report;
+ if (($contentchg) && ($map =~ /^default/)) {
+ $report = 1;
+ }
+ my ($outtext,$errtext)=
+ &LONCAPA::map::storemap('/uploaded/'.$coursedom.'/'.$coursenum.'/'.
+ $map,1,$report);
+ 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('');
+ }
+ $r->print(&endContentScreen());
+}
+
+sub group_import {
+ my ($coursenum, $coursedom, $folder, $container, $caller, @files) = @_;
+ my ($donechk,$allmaps,%hierarchy,%titles,%addedmaps,%removefrommap,
+ %removeparam,$importuploaded,$fixuperrors);
+ $allmaps = {};
+ while (@files) {
+ my ($name, $url, $residx) = @{ shift(@files) };
+ if (($url =~ m{^/uploaded/\Q$coursedom\E/\Q$coursenum\E/(default_\d+\.)(page|sequence)$})
+ && ($caller eq 'londocs')
+ && (!&Apache::lonnet::stat_file($url))) {
+
+ my $errtext = '';
+ my $fatal = 0;
+ my $newmapstr = '';
+ $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 (($caller eq 'londocs') &&
+ ($folder =~ /^default/)) {
+ if (($url =~ /\.(page|sequence)$/) && (!$donechk)) {
+ my $chome = &Apache::lonnet::homeserver($coursenum,$coursedom);
+ my $cid = $coursedom.'_'.$coursenum;
+ $allmaps =
+ &Apache::loncommon::allmaps_incourse($coursedom,$coursenum,
+ $chome,$cid);
+ $donechk = 1;
+ }
+ if ($url =~ m{^/uploaded/\Q$coursedom\E/\Q$coursenum\E/(default_\d+\.)(page|sequence)$}) {
+ &contained_map_check($url,$folder,\%removefrommap,\%removeparam,
+ \%addedmaps,\%hierarchy,\%titles,$allmaps);
+ $importuploaded = 1;
+ } elsif ($url =~ m{^/res/.+\.(page|sequence)$}) {
+ next if ($allmaps->{$url});
+ }
+ }
+ if (!$residx
+ || defined($LONCAPA::map::zombies[$residx])) {
+ $residx = &LONCAPA::map::getresidx($url,$residx);
+ 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);
+ if ($name eq '') {
+ $name = &mt('Web Page');
+ }
+ if ($url =~ m{^/uploaded/$coursedom/$coursenum/((?:docs|supplemental)/(?:default|\d+))/new\.html$}) {
+ my $filepath = $1;
+ my $fname = $name;
+ if ($fname =~ /^\W+$/) {
+ $fname = 'web';
+ } else {
+ $fname =~ s/\W/_/g;
+ }
+ if (length($fname > 15)) {
+ $fname = substr($fname,0,14);
+ }
+ my $initialtext = &mt('Replace with your own content.');
+ my $newhtml = <
+
+
+
+$name
+
+
+$initialtext
+
+
+END
+ $env{'form.output'}=$newhtml;
+ my $result =
+ &Apache::lonnet::finishuserfileupload($coursenum,$coursedom,
+ 'output',
+ "$filepath/$residx/$fname.html");
+ if ($result =~ m{^/uploaded/}) {
+ $url = $result;
+ if ($filepath =~ /^supplemental/) {
+ $name = time.'___&&&___'.$env{'user.name'}.'___&&&___'.
+ $env{'user.domain'}.'___&&&___'.$name;
+ }
+ } else {
+ return (&mt('Failed to save new web page.'),1);
+ }
+ }
+ $LONCAPA::map::resources[$residx] =
+ join(':', ($name, $url, $ext, 'normal', 'res'));
+ }
+ }
+ if ($importuploaded) {
+ my %import_errors;
+ my %updated = (
+ removefrommap => \%removefrommap,
+ removeparam => \%removeparam,
+ );
+ my ($result,$msgsarray,$lockerror) =
+ &apply_fixups($folder,1,$coursedom,$coursenum,\%import_errors,\%updated);
+ if (keys(%import_errors) > 0) {
+ $fixuperrors =
+ '
'."\n".
+ &mt('The following files are either dependencies of a web page or references within a folder and/or composite page for which errors occurred during import:')."\n".
+ '
'.&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,$folder) = @_;
+
+ 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//};
+
+ (my $cmd,undef)=split('_',$env{'form.cmd'});
+
+ my %addtoenv = (
+ 'docs.markedcopy_title' => $title,
+ 'docs.markedcopy_url' => $url,
+ 'docs.markedcopy_cmd' => $cmd,
+ );
+ &Apache::lonnet::delenv('docs.markedcopy_nested');
+ &Apache::lonnet::delenv('docs.markedcopy_nestednames');
+ if ($url =~ m{^/uploaded/$match_domain/$match_courseid/(default|supplemental)_?(\d*)\.(page|sequence)$}) {
+ my $prefix = $1;
+ my $subdir =$2;
+ if ($subdir eq '') {
+ $subdir = $prefix;
+ }
+ my (%addedmaps,%removefrommap,%removeparam,%hierarchy,%titles,%allmaps);
+ &contained_map_check($url,$folder,\%removefrommap,\%removeparam,\%addedmaps,
+ \%hierarchy,\%titles,\%allmaps);
+ if (ref($hierarchy{$url}) eq 'HASH') {
+ my ($nested,$nestednames);
+ &recurse_uploaded_maps($url,$subdir,\%hierarchy,\%titles,\$nested,\$nestednames);
+ $nested =~ s/\&$//;
+ $nestednames =~ s/\Q___&&&___\E$//;
+ if ($nested ne '') {
+ $addtoenv{'docs.markedcopy_nested'} = $nested;
+ }
+ if ($nestednames ne '') {
+ $addtoenv{'docs.markedcopy_nestednames'} = $nestednames;
+ }
+ }
+ }
+ &Apache::lonnet::appenv(\%addtoenv);
+ delete($env{'form.markcopy'});
+}
+
+sub recurse_uploaded_maps {
+ my ($url,$dir,$hierarchy,$titlesref,$nestref,$namesref) = @_;
+ if (ref($hierarchy->{$url}) eq 'HASH') {
+ my @maps = map { $hierarchy->{$url}{$_}; } sort { $a <=> $b } (keys(%{$hierarchy->{$url}}));
+ my @titles = map { $titlesref->{$url}{$_}; } sort { $a <=> $b } (keys(%{$titlesref->{$url}}));
+ my (@uploaded,@names,%shorter);
+ for (my $i=0; $i<@maps; $i++) {
+ my ($inner) = ($maps[$i] =~ m{^/uploaded/$match_domain/$match_courseid/(?:default|supplemental)_(\d+)\.(?:page|sequence)$});
+ if ($inner ne '') {
+ push(@uploaded,$inner);
+ push(@names,&escape($titles[$i]));
+ $shorter{$maps[$i]} = $inner;
+ }
+ }
+ $$nestref .= "$dir:".join(',',@uploaded).'&';
+ $$namesref .= "$dir:".(join(',',@names)).'___&&&___';
+ foreach my $map (@maps) {
+ if ($shorter{$map} ne '') {
+ &recurse_uploaded_maps($map,$shorter{$map},$hierarchy,$titlesref,$nestref,$namesref);
+ }
+ }
+ }
+ return;
+}
+
+sub print_paste_buffer {
+ my ($r,$container,$folder,$coursedom,$coursenum) = @_;
+ return if (!defined($env{'docs.markedcopy_url'}));
+
+ my ($is_external,$othercourse,$fromsupp,$is_uploaded_map,$parent);
+ my $extension = (split(/\./,$env{'docs.markedcopy_url'}))[-1];
+ if ($env{'docs.markedcopy_url'} =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//} ) {
+ $is_external = 1;
+ }
+
+ my ($canpaste,$nopaste,$othercrs,$areachange);
+ if ($folder =~ /^supplemental/) {
+ $canpaste = &supp_pasteable($env{'docs.markedcopy_url'});
+ unless ($canpaste) {
+ $nopaste = &mt('Paste into Supplemental Content unavailable for this type of content.');
+ }
+ } else {
+ $canpaste = 1;
+ }
+
+ if ($canpaste) {
+ if ($env{'docs.markedcopy_url'} =~ m{^/uploaded/($match_domain)/($match_courseid)/(.+)$}) {
+ my $srcdom = $1;
+ my $srcnum = $2;
+ my $rem = $3;
+ if (($srcdom ne $coursedom) || ($srcnum ne $coursenum)) {
+ $othercourse = 1;
+ if ($env{"user.priv.cm./$srcdom/$srcnum"} =~ /\Q:mdc&F\E/) {
+ if ($canpaste) {
+ $othercrs = ' '.&mt('(from another course).');
+ }
+ } else {
+ $canpaste = 0;
+ $nopaste = &mt('Paste from another course unavailable.')
+ }
+ }
+ if ($rem =~ m{^(default|supplemental)_?(\d*)\.(?:page|sequence)$}) {
+ my $prefix = $1;
+ $parent = $2;
+ if ($folder !~ /^\Q$prefix\E/) {
+ $areachange = 1;
+ }
+ $is_uploaded_map = 1;
+ }
+ }
+ }
+
+ $r->print('');
+}
+
+sub recurse_print {
+ my ($r,$dir,$deps,$display) = @_;
+ $r->print($display->{$dir}."\n");
+ if (ref($deps->{$dir}) eq 'ARRAY') {
+ foreach my $subdir (@{$deps->{$dir}}) {
+ &recurse_print($r,$subdir,$deps,$display);
+ }
+ }
+}
+
+sub supp_pasteable {
+ my ($url) = @_;
+ if (($url =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//}) ||
+ (($url =~ /\.sequence$/) && ($url =~ m{^/uploaded/})) ||
+ ($url =~ m{^/uploaded/$match_domain/$match_courseid/(docs|supplemental)/(default|\d+)/\d+/}) ||
+ ($url =~ m{^/adm/$match_domain/$match_username/aboutme}) ||
+ ($url =~ m{^/public/$match_domain/$match_courseid/syllabus})) {
+ return 1;
+ }
+ return;
+}
+
+sub paste_popup_js {
+ my %lt = &Apache::lonlocal::texthash(
+ show => 'Show Paste Options',
+ hide => 'Hide Paste Options',
+ );
+ return <<"END";
+
+function showPasteOptions() {
+ document.getElementById('pasteoptions').style.display='block';
+ document.getElementById('pasteoptions').style.textAlign='left';
+ document.getElementById('pasteoptions').style.textFace='normal';
+ document.getElementById('pasteoptionstext').innerHTML ='$lt{'hide'} ';
+ return;
+}
+
+function hidePasteOptions() {
+ document.getElementById('pasteoptions').style.display='none';
+ document.getElementById('pasteoptionstext').innerHTML ='$lt{'show'}';
+ return;
+}
+
+END
+
+}
+
+
+sub do_paste_from_buffer {
+ my ($coursenum,$coursedom,$folder,$container,$errors) = @_;
+
+# Early out if paste buffer is empty
+ if (!$env{'form.pastemarked'}) {
+ return ();
+ }
+
+# Supplemental content may only include certain types of content
+# Early out if pasted content is not supported in Supplemental area
+ if ($folder =~ /^supplemental/) {
+ unless (&supp_pasteable($env{'docs.markedcopy_url'})) {
+ return (&mt('Paste failed: content type is not supported within Supplemental Content'));
+ }
+ }
+
+# Prepare to paste resource at end of list
+ my $url=&LONCAPA::map::qtescape($env{'docs.markedcopy_url'});
+ my $title=&LONCAPA::map::qtescape($env{'docs.markedcopy_title'});
+
+ my ($is_map,$srcdom,$srcnum,$prefixchg,%before,%after,%mapchanges,%tomove);
+ if ($url=~/\.(page|sequence)$/) {
+ $is_map = 1;
+ }
+ if ($url =~ m{^/uploaded/($match_domain)/($match_courseid)/([^/]+)}) {
+ $srcdom = $1;
+ $srcnum = $2;
+ my $oldprefix = $3;
+# When paste buffer was populated using an active role in a different course
+# check for mdc privilege in the course from which the resource was pasted
+ if (($srcdom ne $coursedom) || ($srcnum ne $coursenum)) {
+ unless ($env{"user.priv.cm./$srcdom/$srcnum"} =~ /\Q:mdc&F\E/) {
+ return (&mt('Paste failed: Item is from a different course which you do not have rights to edit.'));
+ }
+ }
+# When pasting content from Main Content to Supplemental Content and vice versa
+# URLs will contain different paths (which depend on whether pasted item is
+# a folder/page or a document.
+ if (($folder =~ /^supplemental/) && (($oldprefix =~ /^default/) || ($oldprefix eq 'docs'))) {
+ $prefixchg = 1;
+ %before = ( map => 'default',
+ doc => 'docs');
+ %after = ( map => 'supplemental',
+ doc => 'supplemental' );
+ } elsif (($folder =~ /^default/) && ($oldprefix =~ /^supplemental/)) {
+ $prefixchg = 1;
+ %before = ( map => 'supplemental',
+ doc => 'supplemental');
+ %after = ( map => 'default',
+ doc => 'docs');
+ }
+
+# If pasting an uploaded map, get list of contained uploaded maps.
+ my @nested;
+ if ($env{'docs.markedcopy_nested'}) {
+ my ($type) = ($oldprefix =~ /^(default|supplemental)/);
+ my @items = split(/\&/,$env{'docs.markedcopy_nested'});
+ my @deps = map { /\d+:([\d,]+$)/ } @items;
+ foreach my $dep (@deps) {
+ if ($dep =~ /,/) {
+ push(@nested,split(/,/,$dep));
+ } else {
+ push(@nested,$dep);
+ }
+ }
+ foreach my $item (@nested) {
+ if ($env{'form.docs.markedcopy_'.$item} eq 'move') {
+ $tomove{$type.'_'.$item} = 1;
+ }
+ }
+ }
+ }
+
+# Maps need to be copied first
+ my ($oldurl,%removefrommap,%removeparam,%addedmaps,%rewrites,%retitles,%copies,
+ %dbcopies,%zombies,%params,%docmoves,%mapmoves,%newsubdir,%newurls);
+ $oldurl = $url;
+ if ($is_map) {
+# If pasting a map, check if map contains other maps
+ my ($allmaps,%hierarchy,%titles);
+ $allmaps = {};
+ if ($folder =~ /^default/) {
+ $allmaps =
+ &Apache::loncommon::allmaps_incourse($coursedom,$coursenum,
+ $env{"course.$env{'request.course.id'}.home"},
+ $env{'request.course.id'});
+ }
+ &contained_map_check($url,$folder,\%removefrommap,\%removeparam,
+ \%addedmaps,\%hierarchy,\%titles,$allmaps);
+ if ($url=~ m{^/uploaded/}) {
+ my $newurl;
+ unless ($env{'form.docs.markedcopy_options'} eq 'move') {
+ ($newurl,my $error) =
+ &get_newmap_url($url,$folder,$prefixchg,$coursedom,$coursenum,
+ $srcdom,$srcnum,\$title,$allmaps,\%newurls);
+ if ($error) {
+ return ($error);
+ }
+ if ($newurl ne '') {
+ if ($newurl ne $url) {
+ if ($newurl =~ /(?:default|supplemental)_(\d+).(?:sequence|page)$/) {
+ $newsubdir{$url} = $1;
+ }
+ $mapchanges{$url} = 1;
+ }
+ }
+ }
+ if (($srcdom ne $coursedom) || ($srcnum ne $coursenum) || ($prefixchg) ||
+ (($newurl ne '') && ($newurl ne $url))) {
+ unless (&url_paste_fixups($url,$folder,$prefixchg,$coursedom,
+ $coursenum,$srcdom,$srcnum,$allmaps,
+ \%rewrites,\%retitles,\%copies,\%dbcopies,
+ \%zombies,\%params,\%mapmoves,\%mapchanges,\%tomove,
+ \%newsubdir,\%newurls)) {
+ $mapmoves{$url} = 1;
+ }
+ $url = $newurl;
+ } elsif ($env{'docs.markedcopy_nested'}) {
+ &url_paste_fixups($url,$folder,$prefixchg,$coursedom,$coursenum,
+ $srcdom,$srcnum,$allmaps,\%rewrites,
+ \%retitles,\%copies,\%dbcopies,\%zombies,\%params,\%mapmoves,
+ \%mapchanges,\%tomove,\%newsubdir,\%newurls);
+ }
+ } elsif ($url=~m {^/res/}) {
+# published maps can only exists once, so remove it from paste buffer when done
+ &Apache::lonnet::delenv('docs.markedcopy');
+# if pasting published map (main content are only) check map is not already in course
+ if ($folder =~ /^default/) {
+ if ((ref($allmaps) eq 'HASH') && ($allmaps->{$url})) {
+ return (&mt('Paste failed: only one instance of a particular published sequence or page is allowed within each course.'));
+ }
+ }
+ }
+ }
+ my $lockerrors;
+ if ($url=~ m{/(bulletinboard|smppg)$}) {
+ my $prefix = $1;
+ #need to copy the db contents to a new one, unless this is a move.
+ my %info = (
+ src => $url,
+ cdom => $coursedom,
+ cnum => $coursenum,
+ );
+ my (%lockerr,$msg);
+ unless ($env{'form.docs.markedcopy_options'} eq 'move') {
+ my ($newurl,$result,$errtext) =
+ &dbcopy(\%info,$coursedom,$coursenum,\%lockerr);
+ if ($result eq 'ok') {
+ $url = $newurl;
+ $title=&mt('Copy of').' '.$title;
+ } else {
+ if ($prefix eq 'smppg') {
+ $msg = &mt('Paste failed: An error occurred when copying the simple page.').' '.$errtext;
+ } elsif ($prefix eq 'bulletinboard') {
+ $msg = &mt('Paste failed: An error occurred when copying the bulletin board.').' '.$errtext;
+ }
+ return ($result,undef,[$msg],$lockerr{$prefix});
+ }
+ if ($lockerr{$prefix}) {
+ $lockerrors = $lockerr{$prefix};
+ }
+ }
+ }
+ $title = &LONCAPA::map::qtunescape($title);
+ my $ext='false';
+ if ($url=~m{^http(|s)://}) { $ext='true'; }
+ $url = &LONCAPA::map::qtunescape($url);
+
+# For uploaded files (excluding pages/sequences) path in copied file is changed
+# if paste is from Main to Supplemental (or vice versa), or if pasting between
+# courses.
+
+ my $newidx;
+ unless ($is_map) {
+# Now insert the URL at the bottom
+ $newidx = &LONCAPA::map::getresidx($url);
+ if ($url =~ m{^/uploaded/$match_domain/$match_courseid/(?:docs|supplemental)/(.+)$}) {
+ my $relpath = $1;
+ if ($relpath ne '') {
+ my ($prefix,$subdir,$rem) = ($relpath =~ m{^(default|\d+)/(\d+)/(.+)$});
+ my ($newloc,$newdocsdir) = ($folder =~ /^(default|supplemental)_?(\d*)/);
+ my $newprefix = $newloc;
+ if ($newloc eq 'default') {
+ $newprefix = 'docs';
+ }
+ if ($newdocsdir eq '') {
+ $newdocsdir = 'default';
+ }
+ if (($prefixchg) ||
+ ($srcdom ne $coursedom) || ($srcnum ne $coursenum) ||
+ ($env{'form.docs.markedcopy_options'} ne 'move')) {
+ my $newpath = "$newprefix/$newdocsdir/$newidx/$rem";
+ $url =
+ &Apache::lonclonecourse::writefile($env{'request.course.id'},$newpath,
+ &Apache::lonnet::getfile($oldurl));
+ if ($url eq '/adm/notfound.html') {
+ return (&mt('Paste failed: an error occurred saving the file.'));
+ } else {
+ my ($newsubpath) = ($newpath =~ m{^(.*/)[^/]*$});
+ $newsubpath =~ s{/+$}{/};
+ $docmoves{$oldurl} = $newsubpath;
+ }
+ }
+ }
+ }
+ }
+# Apply any changes to maps, or copy dependencies for uploaded HTML pages
+ my ($result,$save_err);
+ my %updated = (
+ rewrites => \%rewrites,
+ zombies => \%zombies,
+ removefrommap => \%removefrommap,
+ removeparam => \%removeparam,
+ dbcopies => \%dbcopies,
+ retitles => \%retitles,
+ );
+ my %info = (
+ newsubdir => \%newsubdir,
+ params => \%params,
+ before => \%before,
+ after => \%after,
+ );
+ my %moves = (
+ copies => \%copies,
+ docmoves => \%docmoves,
+ mapmoves => \%mapmoves,
+ );
+ ($result,my $msgsarray,my $lockerror) =
+ &apply_fixups($folder,$is_map,$coursedom,$coursenum,$errors,
+ \%updated,\%info,\%moves,$prefixchg,$oldurl,$url,'paste');
+ $lockerrors .= $lockerror;
+ if ($result eq 'ok') {
+ if ($is_map) {
+ my ($errtext,$fatal) = &mapread($coursenum,$coursedom,
+ $folder.'.'.$container);
+ return ($errtext,$save_err,$msgsarray,$lockerrors) 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]='';
+ }
+ $newidx = &LONCAPA::map::getresidx($url);
+ }
+ if ($env{'docs.markedcopy_supplemental'}) {
+ if ($folder !~ /^supplemental/) {
+ (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);
+
+# Store the result
+ my ($errtext,$fatal) =
+ &storemap($coursenum,$coursedom,$folder.'.'.$container,1);
+ if ($fatal) {
+ $save_err = $errtext;
+ }
+ }
+
+ if ($env{'form.docs.markedcopy_options'} eq 'move') {
+ &Apache::lonnet::delenv('docs.markedcopy');
+ &Apache::lonnet::delenv('docs.markedcopy_nested');
+ &Apache::lonnet::delenv('docs.markedcopy_nestednames');
+ }
+ return ($result,$save_err,$msgsarray,$lockerrors);
+}
+
+sub get_newmap_url {
+ my ($url,$folder,$prefixchg,$coursedom,$coursenum,$srcdom,$srcnum,
+ $titleref,$allmaps,$newurls) = @_;
+ my $newurl;
+ if ($url=~ m{^/uploaded/}) {
+ $$titleref=&mt('Copy of').' '.$$titleref;
+ }
+ my $now = time;
+ my $suffix=$$.int(rand(100)).$now;
+ my ($oldid,$ext) = ($url=~/^(.+)\.(\w+)$/);
+ if ($oldid =~ m{^(/uploaded/$match_domain/$match_courseid/)(\D+)(\d+)$}) {
+ my $path = $1;
+ my $prefix = $2;
+ my $ancestor = $3;
+ if (length($ancestor) > 10) {
+ $ancestor = substr($ancestor,-10,10);
+ }
+ my $newid;
+ if ($prefixchg) {
+ if ($folder =~ /^supplemental/) {
+ $prefix =~ s/^default/supplemental/;
+ } else {
+ $prefix =~ s/^supplemental/default/;
+ }
+ }
+ if (($srcdom eq $coursedom) && ($srcnum eq $coursenum)) {
+ $newurl = $path.$prefix.$ancestor.$suffix.'.'.$ext;
+ } else {
+ $newurl = "/uploaded/$coursedom/$coursenum/$prefix".$now.'.'.$ext;
+ }
+ my $counter = 0;
+ my $is_unique = &uniqueness_check($newurl);
+ if ($folder =~ /^default/) {
+ if ($allmaps->{$newurl}) {
+ $is_unique = 0;
+ }
+ }
+ while ((!$is_unique || $allmaps->{$newurl} || $newurls->{$newurl}) && ($counter < 100)) {
+ $counter ++;
+ $suffix ++;
+ if (($srcdom eq $coursedom) && ($srcnum eq $coursenum)) {
+ $newurl = $path.$prefix.$ancestor.$suffix.'.'.$ext;
+ } else {
+ $newurl = "/uploaded/$coursedom/$coursenum/$prefix".$ancestor.$suffix.'.'.$ext;
+ }
+ $is_unique = &uniqueness_check($newurl);
+ }
+ if ($is_unique) {
+ $newurls->{$newurl} = 1;
+ } else {
+ if ($url=~/\.page$/) {
+ return (undef,&mt('Paste failed: an error occurred creating a unique URL for the composite page'));
+ } else {
+ return (undef,&mt('Paste failed: an error occurred creating a unique URL for the folder'));
+ }
+ }
+ }
+ return ($newurl);
+}
+
+sub dbcopy {
+ my ($dbref,$coursedom,$coursenum,$lockerrorsref) = @_;
+ my ($url,$result,$errtext);
+ my $url = $dbref->{'src'};
+ if (ref($dbref) eq 'HASH') {
+ if ($url =~ m{/(smppg|bulletinboard)$}) {
+ my $prefix = $1;
+ if (($dbref->{'cdom'} =~ /^$match_domain$/) &&
+ ($dbref->{'cnum'} =~ /^$match_courseid$/)) {
+ my $db_name;
+ my $marker = (split(m{/},$url))[4];
+ $marker=~s/\D//g;
+ if ($dbref->{'src'} =~ m{/smppg$}) {
+ $db_name =
+ &Apache::lonsimplepage::get_db_name($url,$marker,
+ $dbref->{'cdom'},
+ $dbref->{'cnum'});
+ } else {
+ $db_name = 'bulletinpage_'.$marker;
+ }
+ my ($suffix,$freedlock,$error) =
+ &Apache::lonnet::get_timebased_id($prefix,'num','templated',
+ $coursedom,$coursenum,
+ 'concat');
+ if (!$suffix) {
+ if ($prefix eq 'smppg') {
+ $errtext = &mt('Failed to acquire a unique timestamp-based suffix when copying a simple page [_1].',$url);
+ } else {
+ $errtext = &mt('Failed to acquire a unique timestamp-based suffix when copying a bulletin board [_1].',$url);
+ }
+ if ($error) {
+ $errtext .= ' '.$error;
+ }
+ } else {
+ #need to copy the db contents to a new one.
+ my %contents=&Apache::lonnet::dump($db_name,
+ $dbref->{'cdom'},
+ $dbref->{'cnum'});
+ if (exists($contents{'uploaded.photourl'})) {
+ my $photo = $contents{'uploaded.photourl'};
+ my ($subdir,$fname) =
+ ($photo =~ m{^/uploaded/$match_domain/$match_courseid/+(bulletin|simplepage)/(?:|\d+/)([^/]+)$});
+ my $newphoto;
+ if ($fname ne '') {
+ my $content = &Apache::lonnet::getfile($photo);
+ unless ($content eq '-1') {
+ $env{'form.'.$suffix.'.photourl'} = $content;
+ $newphoto =
+ &Apache::lonnet::finishuserfileupload($coursenum,$coursedom,$suffix.'.photourl',"$subdir/$suffix/$fname");
+ delete($env{'form.'.$suffix.'.photourl'});
+ }
+ }
+ if ($newphoto =~ m{^/uploaded/}) {
+ $contents{'uploaded.photourl'} = $newphoto;
+ }
+ }
+ $db_name =~ s{_\d*$ }{_$suffix}x;
+ $result=&Apache::lonnet::put($db_name,\%contents,
+ $coursedom,$coursenum);
+ if ($result eq 'ok') {
+ $url =~ s{/(\d*)/(smppg|bulletinboard)$}{/$suffix/$2}x;
+ }
+ }
+ if (($freedlock ne 'ok') && (ref($lockerrorsref) eq 'HASH')) {
+ $lockerrorsref->{$prefix} =
+ '
'.
+ &mt('There was a problem removing a lockfile.');
+ if ($prefix eq 'smppg') {
+ $lockerrorsref->{$prefix} .=
+ &mt('This will prevent creation of additional simple pages in this course.');
+ } else {
+ $lockerrorsref->{$prefix} .= &mt('This will prevent creation of additional bulletin boards in this course.');
+ }
+ $lockerrorsref->{$prefix} .= &mt('Please contact the domain coordinator for your LON-CAPA domain.').'
'."\n".
+ &mt('The following files are either dependencies of a web page or references within a folder and/or composite page which could not be copied during the paste operation:')."\n".
+ '
'."\n");
+ foreach my $key (sort(keys(%paste_errors))) {
+ $r->print('
'.$key.'
'."\n");
}
-# Store the changed version
- &storemap($coursenum,$coursedom,$folder.'.sequence');
+ $r->print('
'."\n");
+ }
+ }
+
+ $r->print($upload_output);
+
+ if (&handle_edit_cmd()) {
+ my $contentchg;
+ if ($env{'form.cmd'} =~ /^(del|cut)_/) {
+ $contentchg = 1;
}
+ ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container,$contentchg);
+ 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);
+ if ($url =~ m{^\Q/uploaded/$coursedom/$coursenum/\E(default|supplemental)_new\.(sequence|page)$}) {
+ my ($suffix,$errortxt,$locknotfreed) =
+ &new_timebased_suffix($coursedom,$coursenum,'map',$1,$2);
+ if ($locknotfreed) {
+ $r->print($locknotfreed);
+ }
+ if ($suffix) {
+ $url =~ s/_new\./_$suffix./;
+ } else {
+ return $errortxt;
+ }
+ } elsif ($url =~ m{^/adm/$match_domain/$match_username/new/(smppg|bulletinboard)$}) {
+ my $type = $1;
+ my ($suffix,$errortxt,$locknotfreed) =
+ &new_timebased_suffix($coursedom,$coursenum,$type);
+ if ($locknotfreed) {
+ $r->print($locknotfreed);
+ }
+ if ($suffix) {
+ $url =~ s{^(/adm/$match_domain/$match_username)/new}{$1/$suffix};
+ } else {
+ return $errortxt;
+ }
+ } elsif ($url =~ m{^/uploaded/$coursedom/$coursenum/(docs|supplemental)/(default|\d+)/new.html$}) {
+ if ($supplementalflag) {
+ next unless ($1 eq 'supplemental');
+ if ($folder eq 'supplemental') {
+ next unless ($2 eq 'default');
+ } else {
+ next unless ($folder eq 'supplemental_'.$2);
+ }
+ } else {
+ next unless ($1 eq 'docs');
+ if ($folder eq 'default') {
+ next unless ($2 eq 'default');
+ } else {
+ next unless ($folder eq 'default_'.$2);
+ }
+ }
+ }
+ push(@imports, [$name, $url, $residx]);
+ }
+ }
+ ($errtext,$fatal,my $fixuperrors) =
+ &group_import($coursenum, $coursedom, $folder,$container,
+ 'londocs',@imports);
+ return $errtext if ($fatal);
+ if ($fixuperrors) {
+ $r->print($fixuperrors);
}
+ }
# Loading a complete map
- if (($ENV{'form.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,1);
+ 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('
':'').
+ '');
+ 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.')
+ .'
'
+ .&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.')
+ .'
');
}
+ 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,$coursedom,$coursenum);
+ } else {
+ $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.folderpath'} =~ /:1$/) {
+ $container='page';
+ }
+ ($errtext,$fatal)=
+ &mapread($coursenum,$coursedom,$folder.'.'.$container);
+ if ($#LONCAPA::map::order<1) {
+ $LONCAPA::map::order[0]=1;
+ $LONCAPA::map::resources[1]='';
+ }
+ my $destination = 'docs/';
+ if ($folder =~ /^supplemental/) {
+ $destination = 'supplemental/';
+ }
+ if (($folder eq 'default') || ($folder eq 'supplemental')) {
+ $destination .= 'default/';
+ } elsif ($folder =~ /^(default|supplemental)_(\d+)$/) {
+ $destination .= $2.'/';
+ }
+ if ($fatal) {
+ $$upload_output = '
'.&mt('The uploaded file has not been stored as an error occurred reading the contents of the current folder.').'
';
+ return;
+ }
+# this is for a course, not a user, so set context to coursedoc.
+ my $newidx=&LONCAPA::map::getresidx();
+ $destination .= $newidx;
+ 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 = '
+ENDPARMS
+ }
+ $line.=&Apache::loncommon::end_data_table_row();
return $line;
}
-# ---------------------------------------------------------------- tie the hash
+sub new_timebased_suffix {
+ my ($coursedom,$coursenum,$type,$area,$container) = @_;
+ my ($prefix,$namespace,$idtype,$errtext,$locknotfreed);
+ if ($type eq 'map') {
+ $prefix = 'docs';
+ if ($area eq 'supplemental') {
+ $prefix = 'supp';
+ }
+ $prefix .= $container;
+ $namespace = 'uploadedmaps';
+ } else {
+ $prefix = $type;
+ $namespace = 'templated';
+ }
+ $idtype = 'concat';
+ my ($suffix,$freedlock,$error) =
+ &Apache::lonnet::get_timebased_id($prefix,'num',$namespace,
+ $coursedom,$coursenum);
+ if (!$suffix) {
+ if ($type eq 'map') {
+ $errtext = &mt('Failed to acquire a unique timestamp-based suffix for the new folder/page.');
+ } elsif ($type eq 'smppg') {
+ $errtext = &mt('Failed to acquire a unique timestamp-based suffix for the new simple page.');
+ } else {
+ $errtext = &mt('Failed to acquire a unique timestamp-based suffix for the new bulletin board.');
+ }
+ if ($error) {
+ $errtext .= ' '.$error;
+ }
+ }
+ if ($freedlock ne 'ok') {
+ $locknotfreed =
+ '
'.
+ &mt('There was a problem removing a lockfile.').' ';
+ if ($type eq 'map') {
+ &mt('This will prevent creation of additional folders or composite pages in this course.');
+ } elsif ($type eq 'smppg') {
+ $locknotfreed .=
+ &mt('This will prevent creation of additional simple pages in this course.');
+ } else {
+ $locknotfreed .=
+ &mt('This will prevent creation of additional bulletin boards in this course.');
+ }
+ $locknotfreed .=
+ ' '.&mt('Please contact the domain coordinator for your LON-CAPA domain.').
+ '
';
+ }
+ return ($suffix,$errtext,$locknotfreed);
+}
+
+=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 +2929,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,619 +2940,2397 @@ sub checkonthis {
for (my $i=0;$i<=$level*5;$i++) {
$r->print(' ');
}
- $r->print('- Rendering: ');
- my $oldpath=$ENV{'request.filename'};
- $ENV{'request.filename'}=&Apache::lonnet::filelocation('',$url);
- &Apache::lonxml::xmlparse($r,'web',
- &Apache::lonnet::getfile(
- &Apache::lonnet::filelocation('',$url)));
- $ENV{'request.filename'}=$oldpath;
- 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('[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('
');
+ $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').'
');
+ $r->print(&endContentScreen());
+}
+
+
+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=' selected="selected"';
+ 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="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="selected"';
+ } elsif ($env{'form.timerange'}==604800) {
+ $seltext=&mt('during the last week').' ('.&Apache::lonlocal::locallocaltime($starttime).')';
+ $weeksel=' selected="selected"';
+ } elsif ($env{'form.timerange'}==86400) {
+ $seltext=&mt('since yesterday').' ('.&Apache::lonlocal::locallocaltime($starttime).')';
+ $daysel=' selected="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
+'
+ );
+
+ &untiehash();
+ $r->print(&endContentScreen());
+}
+
+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)) {
+ $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".
+''."\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 = '';
+ foreach my $button (@formarr){
+ foreach my $picture (keys(%{$button})) {
+ $list .= &Apache::lonhtmlcommon::htmltag('li', $picture.' '.$button->{$picture}, {class => 'LC_menubuttons_inline_text', id => ''});
+ }
+ }
+ return $list;
+}
+
+# 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 = '