--- loncom/interface/londocs.pm 2003/09/09 19:39:04 1.77
+++ loncom/interface/londocs.pm 2025/01/07 21:01:37 1.722
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Documents
#
-# $Id: londocs.pm,v 1.77 2003/09/09 19:39:04 www Exp $
+# $Id: londocs.pm,v 1.722 2025/01/07 21:01:37 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -30,14 +30,32 @@ 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::loncreatecourse;
+use Apache::lonclonecourse;
+use Apache::lonnavmaps;
+use Apache::lonnavdisplay();
+use Apache::lonextresedit();
+use Apache::lontemplate();
+use Apache::lonsimplepage();
+use Apache::lonhomework();
+use Apache::lonpublisher();
+use Apache::loncourserespicker();
use HTML::Entities;
+use HTML::TokeParser;
+use HTML::LCParser;
use GDBM_File;
+use File::MMagic;
+use File::Copy;
+use Apache::lonlocal;
+use Cwd;
+use UUID::Tiny ':std';
+use LONCAPA qw(:DEFAULT :match);
my $iconpath;
@@ -47,395 +65,6189 @@ my $hashtied;
my %alreadyseen=();
my $hadchanges;
+my $suppchanges;
-# 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)=@_;
- $hadchanges=1;
- return
- &Apache::lonratedt::storemap('/uploaded/'.$coursedom.'/'.$coursenum.'/'.
- $map,1);
+ 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); }
+
+ if ($map =~ /^default/) {
+ $hadchanges=1;
+ } elsif ($contentchg) {
+ $suppchanges=1;
+ }
+ return ($errtext,0);
}
-# ----------------------------------------- Return hash with valid author names
+
sub authorhosts {
my %outhash=();
my $home=0;
my $other=0;
- foreach (keys %ENV) {
- if ($_=~/^user\.role\.(au|ca)\.(.+)$/) {
+ my @ids=&Apache::lonnet::current_machine_ids();
+ foreach my $key (keys(%env)) {
+ if ($key=~/^user\.role\.(au|ca)\.(.+)$/) {
my $role=$1;
my $realm=$2;
- my ($start,$end)=split(/\./,$ENV{$_});
+ my ($start,$end)=split(/\./,$env{$key});
if (($start) && ($start>time)) { next; }
if (($end) && (time>$end)) { next; }
- my $ca; my $cd;
+ my ($ca,$cd);
if ($1 eq 'au') {
- $ca=$ENV{'user.name'};
- $cd=$ENV{'user.domain'};
+ $ca=$env{'user.name'};
+ $cd=$env{'user.domain'};
} else {
- ($cd,$ca)=($realm=~/^\/(\w+)\/(\w+)$/);
+ ($cd,$ca)=($realm=~/^\/($match_domain)\/($match_username)$/);
}
- if (&Apache::lonnet::homeserver($ca,$cd) eq
- $Apache::lonnet::perlvar{'lonHostID'}) {
+ my $allowed=0;
+ my $myhome=&Apache::lonnet::homeserver($ca,$cd);
+ foreach my $id (@ids) {
+ if ($id eq $myhome) {
+ $allowed=1;
+ last;
+ }
+ }
+ if ($allowed) {
$home++;
- $outhash{'home_'.$ca.'@'.$cd}=1;
+ $outhash{'home_'.$ca.':'.$cd}=1;
} else {
- $outhash{'otherhome_'.$ca.'@'.$cd}=
- &Apache::lonnet::homeserver($ca,$cd);
+ $outhash{'otherhome_'.$ca.':'.$cd}=$myhome;
$other++;
}
}
}
return ($home,$other,%outhash);
}
-# ------------------------------------------------------ Generate "dump" button
-sub dumpbutton {
- my ($home,$other,%outhash)=&authorhosts();
- if ($home+$other==0) { return ''; }
- my $output='
';
- if ($home) {
- return ' '.
- ' ';
+
+sub clean {
+ my ($title)=@_;
+ $title=~s/[^\w\/\!\$\%\^\*\-\_\=\+\;\:\,\\\|\`\~]+/\_/gs;
+ return $title;
+}
+
+sub default_folderpath {
+ my ($coursenum,$coursedom,$navmapref) = @_;
+ return unless ($coursenum && $coursedom && ref($navmapref));
+# Check if entire course is hidden and/or encrypted
+ my ($hiddenmap,$encryptmap,$folderpath,$hiddentop);
+ my $toplevel = "uploaded/$coursedom/$coursenum/default.sequence";
+ unless (ref($$navmapref)) {
+ $$navmapref = Apache::lonnavmaps::navmap->new();
+ }
+ if (ref($$navmapref)) {
+ if (lc($$navmapref->get_mapparam(undef,$toplevel,"0.hiddenresource")) eq 'yes') {
+ my $filterFunc = sub { my $res = shift; return (!$res->randomout() && !$res->is_map()) };
+ my @resources = $$navmapref->retrieveResources($toplevel,$filterFunc,1,1);
+ unless (@resources) {
+ $hiddenmap = 1;
+ unless ($env{'request.role.adv'}) {
+ $hiddentop = 1;
+ if ($env{'form.folder'}) {
+ undef($env{'form.folder'});
+ }
+ }
+ }
+ }
+ if (lc($$navmapref->get_mapparam(undef,$toplevel,"0.encrypturl")) eq 'yes') {
+ $encryptmap = 1;
+ }
+ }
+ unless ($hiddentop) {
+ $folderpath='default&'.&escape(&mt('Main Content')).
+ '::'.$hiddenmap.':'.$encryptmap.'::';
+ }
+ if (wantarray) {
+ return ($folderpath,$hiddentop);
} else {
- return' '.
- 'Dump Course DOCS to Construction Space: available on other servers';
+ return $folderpath;
}
}
-# -------------------------------------------------------- Actually dump course
+sub validate_supppath {
+ my ($coursenum,$coursedom) = @_;
+ my $backto;
+ if ($env{'form.supppath'} ne '') {
+ my @items = split(/\&/,$env{'form.supppath'});
+ my ($badpath,$got_supp,$supppath,%supphidden,%suppids);
+ for (my $i=0; $i<@items; $i++) {
+ my $odd = $i%2;
+ if ((!$odd) && ($items[$i] !~ /^supplemental(|_\d+)$/)) {
+ $badpath = 1;
+ last;
+ } elsif ($odd) {
+ my $suffix;
+ my $idx = $i-1;
+ if ($items[$i] =~ /^([^:]*)::(|1):::$/) {
+ $backto .= '&'.$1;
+ } elsif ($items[$idx] eq 'supplemental') {
+ $backto .= '&'.$items[$i];
+ } else {
+ $backto .= '&'.$items[$i];
+ my $is_hidden;
+ unless ($got_supp) {
+ my ($supplemental) = &Apache::loncommon::get_supplemental($coursenum,$coursedom);
+ if (ref($supplemental) eq 'HASH') {
+ if (ref($supplemental->{'hidden'}) eq 'HASH') {
+ %supphidden = %{$supplemental->{'hidden'}};
+ }
+ if (ref($supplemental->{'ids'}) eq 'HASH') {
+ %suppids = %{$supplemental->{'ids'}};
+ }
+ }
+ $got_supp = 1;
+ }
+ if (ref($suppids{"/uploaded/$coursedom/$coursenum/$items[$idx].sequence"}) eq 'ARRAY') {
+ my $mapid = $suppids{"/uploaded/$coursedom/$coursenum/$items[$idx].sequence"}->[0];
+ if ($supphidden{$mapid}) {
+ $is_hidden = 1;
+ }
+ }
+ $suffix = '::'.$is_hidden.':::';
+ }
+ $supppath .= '&'.$items[$i].$suffix;
+ } else {
+ $supppath .= '&'.$items[$i];
+ $backto .= '&'.$items[$i];
+ }
+ }
+ if ($badpath) {
+ delete($env{'form.supppath'});
+ } else {
+ $supppath =~ s/^\&//;
+ $backto =~ s/^\&//;
+ $env{'form.supppath'} = $supppath;
+ }
+ }
+ return $backto;
+}
sub dumpcourse {
- my $r=shift;
- $r->print('Dump DOCS '.
- &Apache::loncommon::bodytag('Dump Course DOCS to Construction Space').
- '');
+ 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('');
+ for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
+ if ($docslog{$id}{'logentry'}{'before_order_res_'.$idx}) {
+ my $shown = &LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'before_order_res_'.$idx}))[0]);
+ 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('');
+ for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
+ if ($docslog{$id}{'logentry'}{'after_order_res_'.$idx}) {
+ my $shown = &LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'after_order_res_'.$idx}))[0]);
+ if ($is_supp) {
+ $shown = &Apache::loncommon::parse_supplemental_title($shown);
+ }
+ $r->print(''.$shown.' ');
+ }
+ }
+ $r->print(' ');
+ if ($docslog{$id}{'logentry'}{'parameter_res'}) {
+ my ($title,$url) = split(/\:/,$docslog{$id}{'logentry'}{'parameter_res'},3);
+ if ($title eq '') {
+ ($title) = ($url =~ m{/([^/]+)$});
+ } elsif ($is_supp) {
+ $title = &Apache::loncommon::parse_supplemental_title($title);
+ }
+ $r->print(&LONCAPA::map::qtescape($title).':');
+ foreach my $parameter ('randompick','hiddenresource','encrypturl','randomorder','gradable') {
+ if ($docslog{$id}{'logentry'}{'parameter_action_'.$parameter}) {
+# FIXME: internationalization seems wrong here
+ $r->print(''.
+ &mt($lt{$parameter}.' '.$lt{$docslog{$id}{'logentry'}{'parameter_action_'.$parameter}}.' [_1]',
+ $docslog{$id}{'logentry'}{'parameter_value_'.$parameter})
+ .' ');
+ }
+ }
+ $r->print(' ');
+ }
+# 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,$folder) = @_;
+ my (@possibles,%removals,%cuts,$output);
+ if ($env{'form.multiremove'}) {
+ $env{'form.multiremove'} =~ s/,$//;
+ map { $removals{$_} = 1; } split(/,/,$env{'form.multiremove'});
+ }
+ if (($env{'form.multicopy'}) || ($env{'form.multicut'})) {
+ if ($env{'form.multicut'}) {
+ $env{'form.multicut'} =~ s/,$//;
+ foreach my $item (split(/,/,$env{'form.multicut'})) {
+ unless ($removals{$item}) {
+ $cuts{$item} = 1;
+ push(@possibles,$item.':cut');
+ }
+ }
+ }
+ if ($env{'form.multicopy'}) {
+ $env{'form.multicopy'} =~ s/,$//;
+ foreach my $item (split(/,/,$env{'form.multicopy'})) {
+ unless ($removals{$item} || $cuts{$item}) {
+ push(@possibles,$item.':copy');
+ }
+ }
+ }
+ } elsif ($env{'form.markcopy'}) {
+ @possibles = split(/,/,$env{'form.markcopy'});
+ }
-# Imports the given (name, url) resources into the course
-# coursenum, coursedom, and folder must precede the list
-sub group_import {
- my $coursenum = shift;
- my $coursedom = shift;
- my $folder = shift;
- while (@_) {
- my $name = shift;
- my $url = shift;
- 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] =
- join ':', ($name, $url, $ext, 'normal', 'res');
+ return if (@possibles == 0);
+ return if (!defined($env{'form.copyfolder'}));
+
+ my ($errtext,$fatal) = &mapread($coursenum,$coursedom,
+ $env{'form.copyfolder'});
+ return if ($fatal);
+
+ my %curr_groups = &Apache::longroup::coursegroups();
+
+# Retrieve current paste buffer suffixes.
+ my @currpaste = split(/,/,$env{'docs.markedcopies'});
+ my (%pasteurls,@newpaste);
+
+# Construct identifiers for current contents of user's paste buffer
+ if (@currpaste) {
+ foreach my $suffix (@currpaste) {
+ my $cid = $env{'docs.markedcopy_crs_'.$suffix};
+ my $url = $env{'docs.markedcopy_url_'.$suffix};
+ my $mapidx = $env{'docs.markedcopy_map_'.$suffix};
+ if (($cid =~ /^$match_domain(?:_)$match_courseid$/) &&
+ ($url ne '')) {
+ if ($url eq '/res/lib/templates/simpleproblem.problem') {
+ $pasteurls{$cid.'_'.$mapidx} = 1;
+ } elsif ($url =~ m{^/res/$match_domain/$match_username/}) {
+ $pasteurls{$url} = 1;
+ } else {
+ $pasteurls{$cid.'_'.$url} = 1;
+ }
+ }
+ }
+ }
+
+# Mark items for copying (skip any items already in user's paste buffer)
+ my %addtoenv;
+
+ my @pathitems = split(/\&/,$env{'form.folderpath'});
+ my @folderconf = split(/\:/,$pathitems[-1]);
+ my $ispage = $folderconf[5];
+
+ foreach my $item (@possibles) {
+ my ($orderidx,$cmd) = split(/:/,$item);
+ next if ($orderidx =~ /\D/);
+ next unless (($cmd eq 'cut') || ($cmd eq 'copy') || ($cmd eq 'remove'));
+ my $mapidx = $folder.':'.$orderidx.':'.$ispage;
+ my ($title,$url)=split(':',$LONCAPA::map::resources[$orderidx]);
+ my %denied = &action_restrictions($coursenum,$coursedom,
+ &LONCAPA::map::qtescape($url),
+ $env{'form.folderpath'},\%curr_groups);
+ next if ($denied{'copy'});
+ $url=~s{http(:|:)//https(:|:)//}{https$2//};
+ if ($url eq '/res/lib/templates/simpleproblem.problem') {
+ next if (exists($pasteurls{$coursedom.'_'.$coursenum.'_'.$mapidx}));
+ } elsif ($url =~ m{^/res/$match_domain/$match_username/}) {
+ next if (exists($pasteurls{$url}));
+ } else {
+ next if (exists($pasteurls{$coursedom.'_'.$coursenum.'_'.$url}));
+ }
+ my ($suffix,$errortxt,$locknotfreed) =
+ &new_timebased_suffix($env{'user.domain'},$env{'user.name'},'paste');
+ if ($suffix ne '') {
+ push(@newpaste,$suffix);
+ } else {
+ if ($locknotfreed) {
+ return $locknotfreed;
+ }
+ }
+ if (&is_supplemental_title($title)) {
+ &Apache::lonnet::appenv({'docs.markedcopy_supplemental_'.$suffix => $title});
+ ($title) = &Apache::loncommon::parse_supplemental_title($title);
+ }
+
+ $addtoenv{'docs.markedcopy_title_'.$suffix} = $title,
+ $addtoenv{'docs.markedcopy_url_'.$suffix} = $url,
+ $addtoenv{'docs.markedcopy_cmd_'.$suffix} = $cmd,
+ $addtoenv{'docs.markedcopy_crs_'.$suffix} = $env{'request.course.id'};
+ $addtoenv{'docs.markedcopy_map_'.$suffix} = $mapidx;
+ 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,$coursenum,$coursedom,\%removefrommap,
+ \%removeparam,\%addedmaps,\%hierarchy,\%titles,\%allmaps);
+ if (ref($hierarchy{$url}) eq 'HASH') {
+ my ($nested,$nestednames);
+ &recurse_uploaded_maps($url,$subdir,\%hierarchy,\%titles,\$nested,\$nestednames);
+ $nested =~ s/\&$//;
+ $nestednames =~ s/\Q___&&&___\E$//;
+ if ($nested ne '') {
+ $addtoenv{'docs.markedcopy_nested_'.$suffix} = $nested;
+ }
+ if ($nestednames ne '') {
+ $addtoenv{'docs.markedcopy_nestednames_'.$suffix} = $nestednames;
+ }
+ }
+ }
+ if ($locknotfreed) {
+ $output = $locknotfreed;
+ last;
+ }
+ }
+ if (@newpaste) {
+ $addtoenv{'docs.markedcopies'} = join(',',(@currpaste,@newpaste));
+ }
+ &Apache::lonnet::appenv(\%addtoenv);
+ delete($env{'form.markcopy'});
+ return $output;
+}
+
+sub recurse_uploaded_maps {
+ my ($url,$dir,$hierarchy,$titlesref,$nestref,$namesref) = @_;
+ if (ref($hierarchy->{$url}) eq 'HASH') {
+ my @maps = map { $hierarchy->{$url}{$_}; } sort { $a <=> $b } (keys(%{$hierarchy->{$url}}));
+ my @titles = map { $titlesref->{$url}{$_}; } sort { $a <=> $b } (keys(%{$titlesref->{$url}}));
+ my (@uploaded,@names,%shorter);
+ for (my $i=0; $i<@maps; $i++) {
+ my ($inner) = ($maps[$i] =~ m{^/uploaded/$match_domain/$match_courseid/(?:default|supplemental)_(\d+)\.(?:page|sequence)$});
+ if ($inner ne '') {
+ push(@uploaded,$inner);
+ push(@names,&escape($titles[$i]));
+ $shorter{$maps[$i]} = $inner;
+ }
+ }
+ $$nestref .= "$dir:".join(',',@uploaded).'&';
+ $$namesref .= "$dir:".(join(',',@names)).'___&&&___';
+ foreach my $map (@maps) {
+ if ($shorter{$map} ne '') {
+ &recurse_uploaded_maps($map,$shorter{$map},$hierarchy,$titlesref,$nestref,$namesref);
+ }
+ }
+ }
+ return;
+}
+
+sub print_paste_buffer {
+ my ($r,$container,$folder,$coursedom,$coursenum) = @_;
+ return if (!defined($env{'docs.markedcopies'}));
+
+ unless (($env{'form.pastemarked'}) || ($env{'form.clearmarked'})) {
+ return if ($env{'docs.markedcopies'} eq '');
+ }
+
+ my @currpaste = split(/,/,$env{'docs.markedcopies'});
+ my ($pasteitems,@pasteable,$same_institution,$checkedsameinst);
+ my $clipboardcount = 0;
+
+# Construct identifiers for current contents of user's paste buffer
+ foreach my $suffix (@currpaste) {
+ next if ($suffix =~ /\D/);
+ my $cid = $env{'docs.markedcopy_crs_'.$suffix};
+ my $url = $env{'docs.markedcopy_url_'.$suffix};
+ my $mapidx = $env{'docs.markedcopy_map_'.$suffix};
+ if (($cid =~ /^$match_domain\_$match_courseid$/) &&
+ ($url ne '')) {
+ $clipboardcount ++;
+ my ($is_external,$othercourse,$fromsupp,$is_uploaded_map,$parent,
+ $canpaste,$nopaste,$othercrs,$areachange,$is_exttool,$toolcdom,
+ $toolcnum,$marker);
+ my $extension = (split(/\./,$env{'docs.markedcopy_url_'.$suffix}))[-1];
+ if ($url =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//} ) {
+ $is_external = 1;
+ } elsif ($url =~ m{^/adm/($match_domain)/($match_courseid)/(\d+)/ext\.tool$}) {
+ ($toolcdom,$toolcnum,$marker) = ($1,$2,$3);
+ $is_exttool = 1;
+ }
+ if ($folder =~ /^supplemental/) {
+ $canpaste = &supp_pasteable($env{'docs.markedcopy_url_'.$suffix});
+ unless ($canpaste) {
+ $nopaste = &mt('Paste into Supplemental Content unavailable.');
+ }
+ } else {
+ $canpaste = 1;
+ }
+ if ($canpaste) {
+ if ($url =~ m{^/uploaded/($match_domain)/($match_courseid)/(.+)$}) {
+ my $srcdom = $1;
+ my $srcnum = $2;
+ my $rem = $3;
+ if (($srcdom ne $coursedom) || ($srcnum ne $coursenum)) {
+ $othercourse = 1;
+ if ($env{"user.priv.cm./$srcdom/$srcnum"} =~ /\Q:mdc&F\E/) {
+ $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;
+ }
+ } elsif (($url =~ m{^/res/lib/templates/\w+\.problem$}) ||
+ ($url =~ m{^/adm/($match_domain)/($match_username)/\d+/(bulletinboard|smppg|ext\.tool)$})) {
+ if ($cid ne $env{'request.course.id'}) {
+ my ($srcdom,$srcnum) = split(/_/,$cid);
+ if ($env{"user.priv.cm./$srcdom/$srcnum"} =~ /\Q:mdc&F\E/) {
+ if ($is_exttool) {
+ if ($toolcdom ne $coursedom) {
+ $canpaste = 0;
+ $nopaste = &mt('Paste from another domain unavailable.');
+ } elsif ($toolcnum ne $coursenum) {
+ my %toolsettings =
+ &Apache::lonnet::dump('exttool_'.$marker,$toolcdom,$toolcnum);
+ my %tooltypes = &Apache::loncommon::usable_exttools();
+ if ((($toolsettings{'id'} =~ /^c\d+$/) && (!$tooltypes{'crs'})) ||
+ (($toolsettings{'id'} =~ /^\d+$/) && (!$tooltypes{'dom'}))) {
+ $canpaste = 0;
+ $nopaste = &mt('Paste from another course unavailable.');
+ } elsif ($toolsettings{'id'} =~ /^c\d+$/) {
+ unless ($checkedsameinst) {
+ my $primary_id = &Apache::lonnet::domain($coursedom,'primary');
+ my $intdom = &Apache::lonnet::internet_dom($primary_id);
+ if ($intdom ne '') {
+ my $internet_names =
+ &Apache::lonnet::get_internet_names($Apache::lonnet::perlvar{'lonHostID'});
+ if (ref($internet_names) eq 'ARRAY') {
+ if (grep(/^\Q$intdom\E$/,@{$internet_names})) {
+ $same_institution = 1;
+ }
+ }
+ }
+ $checkedsameinst = 1;
+ }
+ if ($same_institution) {
+ $othercrs = ' '.&mt('(from another course)');
+ } else {
+ $nopaste = &mt('Paste from another course unavailable.');
+ }
+ } else {
+ $othercrs = ' '.&mt('(from another course)');
+ }
+ }
+ }
+ } else {
+ $canpaste = 0;
+ $nopaste = &mt('Paste from another course unavailable.');
+ }
+ }
+ } elsif ($url =~ m{/res/($match_domain)/($match_username)/}) {
+ my ($audom,$auname) = ($1,$2);
+ unless (($auname eq $coursenum) && ($audom eq $coursedom)) {
+ if (&Apache::lonnet::is_course($audom,$auname)) {
+ $canpaste = 0;
+ $nopaste = &mt('Paste from another course unavailable.');
+ }
+ }
+ }
+ if ($canpaste) {
+ push(@pasteable,$suffix);
+ }
+ }
+ my $buffer;
+ if ($is_external) {
+ $buffer = &mt('External Resource').': '.
+ &LONCAPA::map::qtescape($env{'docs.markedcopy_title_'.$suffix}).' ('.
+ &LONCAPA::map::qtescape($url).')';
+ } elsif ($is_exttool) {
+ $buffer = &mt('External Tool').': '.
+ &LONCAPA::map::qtescape($env{'docs.markedcopy_title_'.$suffix});
+ } else {
+ my $icon = &Apache::loncommon::icon($extension);
+ if ($extension eq 'sequence' &&
+ $url =~ m{/default_\d+\.sequence$}x) {
+ $icon = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL'));
+ $icon .= '/navmap.folder.closed.gif';
+ }
+ my $title = $env{'docs.markedcopy_title_'.$suffix};
+ if ($title eq '') {
+ ($title) = ($url =~ m{/([^/]+)$});
+ }
+ $buffer = ' '.
+ ': '.
+ &Apache::loncommon::parse_supplemental_title(
+ &LONCAPA::map::qtescape($title));
+ }
+ $pasteitems .= '';
+ my ($options,$onclick);
+ if (($canpaste) && (!$areachange) && (!$othercourse) &&
+ ($env{'docs.markedcopy_cmd_'.$suffix} eq 'cut')) {
+ if (($is_uploaded_map) ||
+ ($url =~ /(bulletinboard|smppg)$/) ||
+ ($url =~ m{^/uploaded/$coursedom/$coursenum/(?:docs|supplemental)/(.+)$})) {
+ $options = &paste_options($suffix,$is_uploaded_map,$parent);
+ $onclick= 'onclick="showOptions(this,'."'$suffix'".');" ';
+ }
+ }
+ $pasteitems .= ' '.$buffer.' ';
+ if ($nopaste) {
+ $pasteitems .= ' '.$nopaste.' ';
+ } else {
+ if ($othercrs) {
+ $pasteitems .= $othercrs;
+ }
+ if ($options) {
+ $pasteitems .= $options;
+ }
+ }
+ $pasteitems .= '
';
+ }
+ }
+ if ($pasteitems eq '') {
+ &Apache::lonnet::delenv('docs.markedcopies');
+ }
+ my ($pasteform,$form_start,$buttons,$form_end);
+ if ($pasteitems) {
+ $pasteitems .= '
';
+ $form_start = '';
+ if (@pasteable) {
+ my $value = &mt('Paste to current folder');
+ if ($container eq 'page') {
+ $value = &mt('Paste to current page');
+ }
+ $buttons = ' '.(' 'x2);
+ }
+ $buttons .= ' '.(' 'x2);
+ if ($clipboardcount > 1) {
+ $buttons .=
+ ''.(' 'x20).' '.(' 'x2).
+ ' '.
+ (' 'x2).
+ ' '.
+ (' 'x2);
+ }
+ $form_end = ' '.
+ ' ';
+ } else {
+ $pasteitems = &mt('Clipboard is empty');
+ }
+ $r->print($form_start
+ .''
+ .''.&mt('Clipboard').(' ' x2).$buttons.' '
+ .$pasteitems
+ .' '
+ .$form_end);
+}
+
+sub paste_options {
+ my ($suffix,$is_uploaded_map,$parent) = @_;
+ my ($copytext,$movetext);
+ if ($is_uploaded_map) {
+ $copytext = &mt('Copy to new folder');
+ $movetext = &mt('Move old');
+ } elsif ($env{'docs.markedcopy_url_'.$suffix} =~ /bulletinboard$/) {
+ $copytext = &mt('Copy to new board');
+ $movetext = &mt('Move (not posts)');
+ } elsif ($env{'docs.markedcopy_url_'.$suffix} =~ /smppg$/) {
+ $copytext = &mt('Copy to new page');
+ $movetext = &mt('Move');
+ } else {
+ $copytext = &mt('Copy to new file');
+ $movetext = &mt('Move');
+ }
+ my $output = ' '.
+ ' '.
+ ''.(' 'x 4).
+ ''.
+ ' '.
+ $copytext.' '.(' 'x2).' '.
+ '
'.
+ ' '.
+ $movetext.' ';
+ if (($is_uploaded_map) && ($env{'docs.markedcopy_nested_'.$suffix})) {
+ $output .= '
'.&mt('Folder to paste contains sub-folders').
+ ' ';
+ my @pastemaps = split(/\&/,$env{'docs.markedcopy_nested_'.$suffix});
+ my @titles = split(/\Q___&&&___\E/,$env{'docs.markedcopy_nestednames_'.$suffix});
+ my $lastdir = $parent;
+ my %depths = (
+ $lastdir => 0,
+ );
+ my (%display,%deps);
+ for (my $i=0; $i<@pastemaps; $i++) {
+ ($lastdir,my $subfolderstr) = split(/\:/,$pastemaps[$i]);
+ my ($namedir,$esctitlestr) = split(/\:/,$titles[$i]);
+ my @subfolders = split(/,/,$subfolderstr);
+ $deps{$lastdir} = \@subfolders;
+ my @subfoldertitles = map { &unescape($_); } split(/,/,$esctitlestr);
+ my $depth = $depths{$lastdir} + 1;
+ my $offset = int($depth * 4);
+ my $indent = (' ' x $offset);
+ for (my $j=0; $j<@subfolders; $j++) {
+ $depths{$subfolders[$j]} = $depth;
+ $display{$subfolders[$j]} =
+ ''.$indent.$subfoldertitles[$j].' '.
+ ''.
+ ' '.&mt('Copy to new').' '.(' ' x2).
+ ''.
+ ' '.
+ &mt('Move old').' '.
+ ' ';
+ }
+ }
+ &recurse_print(\$output,$parent,\%deps,\%display);
+ $output .= '
';
+ }
+ $output .= '
';
+ return $output;
+}
+
+sub recurse_print {
+ my ($outputref,$dir,$deps,$display) = @_;
+ $$outputref .= $display->{$dir}."\n";
+ if (ref($deps->{$dir}) eq 'ARRAY') {
+ foreach my $subdir (@{$deps->{$dir}}) {
+ &recurse_print($outputref,$subdir,$deps,$display);
+ }
+ }
+}
+
+sub supp_pasteable {
+ my ($url) = @_;
+ if (($url =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//}) ||
+ (($url =~ /\.sequence$/) && ($url =~ m{^/uploaded/})) ||
+ ($url =~ m{^/uploaded/$match_domain/$match_courseid/(docs|supplemental)/(default|\d+)/\d+/}) ||
+ ($url =~ m{^/adm/$match_domain/$match_username/aboutme}) ||
+ ($url =~ m{^/public/$match_domain/$match_courseid/syllabus}) ||
+ ($url =~ m{^/adm/$match_domain/$match_courseid/\d+/ext\.tool$})) {
+ return 1;
+ }
+ return;
+}
+
+sub paste_popup_js {
+ my %html_js_lt = &Apache::lonlocal::texthash(
+ show => 'Show Options',
+ hide => 'Hide Options',
+ );
+ my %js_lt = &Apache::lonlocal::texthash(
+ none => 'No items selected from clipboard.',
+ );
+ &html_escape(\%html_js_lt);
+ &js_escape(\%html_js_lt);
+ &js_escape(\%js_lt);
+ return <<"END";
+
+function showPasteOptions(suffix) {
+ document.getElementById('pasteoptions_'+suffix).style.display='block';
+ document.getElementById('pasteoptionstext_'+suffix).innerHTML = ' ';
+ return;
+}
+
+function hidePasteOptions(suffix) {
+ document.getElementById('pasteoptions_'+suffix).style.display='none';
+ document.getElementById('pasteoptionstext_'+suffix).innerHTML =' ';
+ return;
+}
+
+function showOptions(caller,suffix) {
+ if (document.getElementById('pasteoptionstext_'+suffix)) {
+ if (caller.checked) {
+ document.getElementById('pasteoptionstext_'+suffix).innerHTML =' ';
+ } else {
+ document.getElementById('pasteoptionstext_'+suffix).innerHTML ='';
+ }
+ if (document.getElementById('pasteoptions_'+suffix)) {
+ document.getElementById('pasteoptions_'+suffix).style.display='none';
+ }
+ }
+ return;
+}
+
+function validateClipboard() {
+ var numchk = 0;
+ if (document.pasteform.pasting.length > 1) {
+ for (var i=0; i 0) {
+ return true;
+ } else {
+ alert("$js_lt{'none'}");
+ return false;
+ }
+}
+
+function checkClipboard() {
+ if (document.pasteform.pasting.length > 1) {
+ for (var i=0; i1) {
+ for (var i=0; i supplemental content
+# changes
+
+ %msgs = &Apache::lonlocal::texthash (
+ notinsupp => 'Paste failed: content type is not supported within Supplemental Content',
+ notincrs => 'Paste failed: Item is from a different course which you do not have rights to edit.',
+ notindom => 'Paste failed: Item is an external tool from a course in a different domain.',
+ othcrstool => 'Paste failed: Item is an external tool from a different course, for which use is not allowed in this course.',
+ othcrsres => 'Paste failed: Item is a course-authored resource from a different course',
+ duplicate => 'Paste failed: only one instance of a particular published sequence or page is allowed within each course.',
+ );
+
+ %before = (
+ docstosupp => {
+ map => 'default',
+ doc => 'docs',
+ },
+ supptodocs => {
+ map => 'supplemental',
+ doc => 'supplemental',
+ },
+ );
+
+ %after = (
+ docstosupp => {
+ map => 'supplemental',
+ doc => 'supplemental'
+ },
+ supptodocs => {
+ map => 'default',
+ doc => 'docs',
+ },
+ );
+
+# Retrieve information about all course maps in main content area
+
+ my $allmaps = {};
+ my (@toclear,%mapurls,%lockerrs,%msgerrs,%results,$donechk,
+ @updatetoolsenc,$updatetoolscache,$checkedsameinst,
+ $same_institution);
+
+# Loop over the items to paste
+ foreach my $suffix (@dopaste) {
+# Maps need to be copied first
+ my (%removefrommap,%removeparam,%addedmaps,%rewrites,%retitles,%copies,
+ %dbcopies,%zombies,%params,%docmoves,%mapmoves,%mapchanges,%newsubdir,
+ %newurls,%tomove,%resdatacopy);
+ if (ref($marktomove{$suffix}) eq 'ARRAY') {
+ map { $tomove{$_} = 1; } @{$marktomove{$suffix}};
+ }
+ my $url=&LONCAPA::map::qtescape($env{'docs.markedcopy_url_'.$suffix});
+ my $title=&LONCAPA::map::qtescape($env{'docs.markedcopy_title_'.$suffix});
+ my $cid=&LONCAPA::map::qtescape($env{'docs.markedcopy_crs_'.$suffix});
+ my $oldurl = $url;
+ if ($is_map{$suffix}) {
+# If pasting a map, check if map contains other maps
+ my (%hierarchy,%titles);
+ if (($folder =~ /^default/) && (!$donechk)) {
+ $allmaps =
+ &Apache::loncommon::allmaps_incourse($coursedom,$coursenum,
+ $env{"course.$env{'request.course.id'}.home"},
+ $env{'request.course.id'});
+ $donechk = 1;
+ }
+ &contained_map_check($url,$folder,$coursenum,$coursedom,
+ \%removefrommap,\%removeparam,\%addedmaps,
+ \%hierarchy,\%titles,$allmaps);
+ if ($url=~ m{^/uploaded/}) {
+ my $newurl;
+ unless ($env{'form.docs.markedcopy_options_'.$suffix} eq 'move') {
+ ($newurl,my $error) =
+ &get_newmap_url($url,$folder,$prefixchg{$suffix},$coursedom,
+ $coursenum,$srcdom{$suffix},$srcnum{$suffix},
+ \$title,$allmaps,\%newurls);
+ if ($error) {
+ $allerrors{$suffix} = $error;
+ next;
+ }
+ if ($newurl ne '') {
+ if ($newurl ne $url) {
+ if ($newurl =~ /(?:default|supplemental)_(\d+).(?:sequence|page)$/) {
+ $newsubdir{$url} = $1;
+ }
+ $mapchanges{$url} = 1;
+ }
+ }
+ }
+ if (($srcdom{$suffix} ne $coursedom) ||
+ ($srcnum{$suffix} ne $coursenum) ||
+ ($prefixchg{$suffix}) || (($newurl ne '') && ($newurl ne $url))) {
+ unless (&url_paste_fixups($url,$folder,$prefixchg{$suffix},
+ $coursedom,$coursenum,$srcdom{$suffix},
+ $srcnum{$suffix},$allmaps,\%rewrites,
+ \%retitles,\%copies,\%dbcopies,
+ \%zombies,\%params,\%mapmoves,
+ \%mapchanges,\%tomove,\%newsubdir,
+ \%newurls,\%resdatacopy)) {
+ $mapmoves{$url} = 1;
+ }
+ $url = $newurl;
+ } elsif ($env{'docs.markedcopy_nested_'.$suffix}) {
+ &url_paste_fixups($url,$folder,$prefixchg{$suffix},$coursedom,
+ $coursenum,$srcdom{$suffix},$srcnum{$suffix},
+ $allmaps,\%rewrites,\%retitles,\%copies,\%dbcopies,
+ \%zombies,\%params,\%mapmoves,\%mapchanges,
+ \%tomove,\%newsubdir,\%newurls,\%resdatacopy);
+ }
+ } elsif ($url=~m {^/res/}) {
+# published map can only exist once, so remove from paste buffer when done
+ push(@toclear,$suffix);
+# if pasting published map (main content area only) check map not already in course
+ if ($folder =~ /^default/) {
+ if ((ref($allmaps) eq 'HASH') && ($allmaps->{$url})) {
+ $duplicate{$suffix} = 1;
+ next;
+ }
+ }
+ }
+ }
+ if ($url=~ m{/(bulletinboard|smppg|ext\.tool)$}) {
+ my $prefix = $1;
+ my $fromothercrs;
+ #need to copy the db contents to a new one, unless this is a move.
+ my %info = (
+ src => $url,
+ cdom => $coursedom,
+ cnum => $coursenum,
+ );
+ if ($prefix eq 'ext.tool') {
+ if ($prefixchg{$suffix} eq 'docstosupp') {
+ $info{'delgradable'} = 1;
+ }
+ }
+ if (($srcdom{$suffix} =~ /^$match_domain$/) && ($srcnum{$suffix} =~ /^$match_courseid$/)) {
+ unless (($srcdom{$suffix} eq $coursedom) && ($srcnum{$suffix} eq $coursenum)) {
+ $fromothercrs = 1;
+ $info{'cdom'} = $srcdom{$suffix};
+ $info{'cnum'} = $srcnum{$suffix};
+ unless ($checkedsameinst) {
+ my $primary_id = &Apache::lonnet::domain($coursedom,'primary');
+ my $intdom = &Apache::lonnet::internet_dom($primary_id);
+ if ($intdom ne '') {
+ my $internet_names =
+ &Apache::lonnet::get_internet_names($Apache::lonnet::perlvar{'lonHostID'});
+ if (ref($internet_names) eq 'ARRAY') {
+ if (grep(/^\Q$intdom\E$/,@{$internet_names})) {
+ $same_institution = 1;
+ }
+ }
+ }
+ $checkedsameinst = 1;
+ }
+ }
+ }
+ unless (($env{'form.docs.markedcopy_options_'.$suffix} eq 'move') && (!$fromothercrs)) {
+ my (%lockerr,$msg);
+ my ($newurl,$result,$errtext) =
+ &dbcopy(\%info,$coursedom,$coursenum,\%lockerr,\%currltititles,
+ \$currltimax,\@updatetoolsenc,\$updatetoolscache,$same_institution);
+ if ($result eq 'ok') {
+ $url = $newurl;
+ $title=&mt('Copy of').' '.$title;
+ } else {
+ if ($prefix eq 'smppg') {
+ $msg = &mt('Paste failed: An error occurred when copying the simple page.').' '.$errtext;
+ } elsif ($prefix eq 'bulletinboard') {
+ $msg = &mt('Paste failed: An error occurred when copying the discussion board.').' '.$errtext;
+ } elsif ($prefix eq 'ext.tool') {
+ $msg = &mt('Paste failed: An error occurred when copying the external tool.').' '.$errtext;
+ }
+ $results{$suffix} = $result;
+ $msgerrs{$suffix} = $msg;
+ $lockerrs{$suffix} = $lockerr{$prefix};
+ next;
+ }
+ if ($lockerr{$prefix}) {
+ $lockerrs{$suffix} = $lockerr{$prefix};
+ }
+ }
+ }
+ $title = &LONCAPA::map::qtunescape($title);
+ my $ext='false';
+ if ($url=~m{^http(|s)://}) { $ext='true'; }
+ if ($env{'docs.markedcopy_supplemental_'.$suffix}) {
+ if ($folder !~ /^supplemental/) {
+ (undef,undef,$title) =
+ &Apache::loncommon::parse_supplemental_title($env{'docs.markedcopy_supplemental_'.$suffix});
+ }
+ } else {
+ if ($folder=~/^supplemental/) {
+ $title=time.'___&&&___'.$env{'user.name'}.'___&&&___'.
+ $env{'user.domain'}.'___&&&___'.$title;
+ }
+ }
+
+# For uploaded files (excluding pages/sequences) path in copied file is changed
+# if paste is from Main to Supplemental (or vice versa), or if pasting between
+# courses.
+
+ unless ($is_map{$suffix}) {
+ my $newidx;
+# Now insert the URL at the bottom
+ $newidx = &LONCAPA::map::getresidx(&LONCAPA::map::qtunescape($url));
+ if ($url =~ m{^/uploaded/$match_domain/$match_courseid/(?:docs|supplemental)/(.+)$}) {
+ my $relpath = $1;
+ if ($relpath ne '') {
+ my ($prefix,$subdir,$rem) = ($relpath =~ m{^(default|\d+)/(\d+)/(.+)$});
+ my ($newloc,$newdocsdir) = ($folder =~ /^(default|supplemental)_?(\d*)/);
+ my $newprefix = $newloc;
+ if ($newloc eq 'default') {
+ $newprefix = 'docs';
+ }
+ if ($newdocsdir eq '') {
+ $newdocsdir = 'default';
+ }
+ if (($prefixchg{$suffix}) ||
+ ($srcdom{$suffix} ne $coursedom) ||
+ ($srcnum{$suffix} ne $coursenum) ||
+ ($env{'form.docs.markedcopy_options_'.$suffix} ne 'move')) {
+ my $newpath = "$newprefix/$newdocsdir/$newidx/$rem";
+ $url =
+ &Apache::lonclonecourse::writefile($env{'request.course.id'},$newpath,
+ &Apache::lonnet::getfile($oldurl));
+ if ($url eq '/adm/notfound.html') {
+ $msgs{$suffix} = &mt('Paste failed: an error occurred saving the file.');
+ next;
+ } else {
+ my ($newsubpath) = ($newpath =~ m{^(.*/)[^/]*$});
+ $newsubpath =~ s{/+$}{/};
+ $docmoves{$oldurl} = $newsubpath;
+ }
+ }
+ }
+ } elsif ($url =~ m{^/res/lib/templates/(\w+)\.problem$}) {
+ my $template = $1;
+ if ($newidx) {
+ ©_templated_files($url,$srcdom{$suffix},$srcnum{$suffix},$srcmapidx{$suffix},
+ $coursedom,$coursenum,$template,$newidx,"$folder.$container");
+ }
+ } elsif ($url =~ /ext\.tool$/) {
+ if (($newidx) && ($folder=~/^default/)) {
+ my $marker = (split(m{/},$url))[4];
+ my %toolsettings = &Apache::lonnet::dump('exttool_'.$marker,$coursedom,$coursenum);
+ my $val = 'no';
+ if ($toolsettings{'gradable'}) {
+ $val = 'yes';
+ }
+ &LONCAPA::map::storeparameter($newidx,'parameter_0_gradable',$val,
+ 'string_yesno');
+ &remember_parms($newidx,'gradable','set',$val);
+ }
+ }
+ $LONCAPA::map::resources[$newidx]=$title.':'.&LONCAPA::map::qtunescape($url).
+ ':'.$ext.':normal:res';
+ push(@LONCAPA::map::order,$newidx);
+# Store the result
+ my ($errtext,$fatal) =
+ &storemap($coursenum,$coursedom,$folder.'.'.$container,1);
+ if ($fatal) {
+ $save_err .= $errtext;
+ $allresult = 'fail';
+ }
+ }
+
+# Apply any changes to maps, or copy dependencies for uploaded HTML pages, or update
+# resourcedata for simpleproblems copied from another course
+ unless ($allresult eq 'fail') {
+ my %updated = (
+ rewrites => \%rewrites,
+ zombies => \%zombies,
+ removefrommap => \%removefrommap,
+ removeparam => \%removeparam,
+ dbcopies => \%dbcopies,
+ resdatacopy => \%resdatacopy,
+ retitles => \%retitles,
+ );
+ my %info = (
+ newsubdir => \%newsubdir,
+ params => \%params,
+ );
+ if ($prefixchg{$suffix}) {
+ $info{'before'} = $before{$prefixchg{$suffix}};
+ $info{'after'} = $after{$prefixchg{$suffix}};
+ }
+ my %moves = (
+ copies => \%copies,
+ docmoves => \%docmoves,
+ mapmoves => \%mapmoves,
+ );
+ (my $result,$msgs{$suffix},my $lockerror) =
+ &apply_fixups($folder,$is_map{$suffix},$coursedom,$coursenum,$errors,
+ \%updated,\%info,\%moves,$prefixchg{$suffix},$oldurl,
+ $url,'paste');
+ $lockerrors .= $lockerror;
+ if ($result eq 'ok') {
+ if ($is_map{$suffix}) {
+ my ($errtext,$fatal) = &mapread($coursenum,$coursedom,
+ $folder.'.'.$container);
+ if ($fatal) {
+ $allresult = 'failread';
+ } else {
+ if ($#LONCAPA::map::order<1) {
+ my $idx=&LONCAPA::map::getresidx();
+ if ($idx<=0) { $idx=1; }
+ $LONCAPA::map::order[0]=$idx;
+ $LONCAPA::map::resources[$idx]='';
+ }
+ my $newidx = &LONCAPA::map::getresidx(&LONCAPA::map::qtunescape($url));
+ $LONCAPA::map::resources[$newidx]=$title.':'.&LONCAPA::map::qtunescape($url).
+ ':'.$ext.':normal:res';
+ push(@LONCAPA::map::order,$newidx);
+
+# Store the result
+ my ($errtext,$fatal) =
+ &storemap($coursenum,$coursedom,$folder.'.'.$container,1);
+ if ($fatal) {
+ $save_err .= $errtext;
+ $allresult = 'failstore';
+ }
+ }
+ }
+ if ($env{'form.docs.markedcopy_options_'.$suffix} eq 'move') {
+ push(@toclear,$suffix);
+ }
+ }
+ }
+ }
+ if (($updatetoolscache) || (@updatetoolsenc)) {
+ &update_ltitools_caches($coursedom,$coursenum,$updatetoolscache,
+ \@updatetoolsenc);
+ }
+ &clear_from_buffer(\@toclear,\@currpaste);
+ my $msgsarray;
+ foreach my $suffix (keys(%msgs)) {
+ if (ref($msgs{$suffix}) eq 'ARRAY') {
+ $msgsarray .= join(',',@{$msgs{$suffix}});
+ }
+ }
+ return ($allresult,$save_err,$msgsarray,$lockerrors);
+}
+
+sub do_buffer_empty {
+ my @currpaste = split(/,/,$env{'docs.markedcopies'});
+ if (@currpaste == 0) {
+ return &mt('Clipboard is already empty');
+ }
+ my @toclear = &Apache::loncommon::get_env_multiple('form.pasting');
+ if (@toclear == 0) {
+ return &mt('Nothing selected to clear from clipboard');
+ }
+ my $numdel = &clear_from_buffer(\@toclear,\@currpaste);
+ if ($numdel) {
+ return &mt('[quant,_1,item] cleared from clipboard',$numdel);
+ } else {
+ return &mt('Clipboard unchanged');
+ }
+ return;
+}
+
+sub clear_from_buffer {
+ my ($toclear,$currpaste) = @_;
+ return unless ((ref($toclear) eq 'ARRAY') && (ref($currpaste) eq 'ARRAY'));
+ my %pastebuffer;
+ map { $pastebuffer{$_} = 1; } @{$currpaste};
+ my $numdel = 0;
+ foreach my $suffix (@{$toclear}) {
+ next if ($suffix =~ /\D/);
+ next unless (exists($pastebuffer{$suffix}));
+ my $regexp = 'docs.markedcopy_[a-z]+_'.$suffix;
+ if (&Apache::lonnet::delenv($regexp,1) eq 'ok') {
+ delete($pastebuffer{$suffix});
+ $numdel ++;
+ }
+ }
+ my $newbuffer = join(',',sort(keys(%pastebuffer)));
+ &Apache::lonnet::appenv({'docs.markedcopies' => $newbuffer});
+ return $numdel;
+}
+
+sub update_ltitools_caches {
+ my ($coursedom,$coursenum,$updatetoolscache,$updatetoolsenc) = @_;
+ my $hashid=$coursedom.'_'.$coursenum;
+ if ($updatetoolscache) {
+ &Apache::lonnet::devalidate_cache_new('courseltitools',$hashid);
+ }
+ if ((ref($updatetoolsenc) eq 'ARRAY') &&
+ (@{$updatetoolsenc})) {
+ my @ids=&Apache::lonnet::current_machine_ids();
+ my $updatedone;
+ foreach my $lonhost (@{$updatetoolsenc}) {
+ if (grep(/^\Q$lonhost\E$/,@ids)) {
+ unless ($updatedone) {
+ &Apache::lonnet::devalidate_cache_new('crsltitoolsenc',$hashid);
+ }
+ $updatedone = 1;
+ } else {
+ &Apache::lonnet::remote_devalidate_cache($lonhost,["crsltitoolsenc:$hashid"]);
+ }
+ }
+ }
+ return;
+}
+
+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,$currltititles,
+ $currltimax,$updatetoolsenc,$updatetoolscache,$same_institution) = @_;
+ my ($url,$result,$errtext);
+ if (ref($dbref) eq 'HASH') {
+ $url = $dbref->{'src'};
+ if ($url =~ m{/(smppg|bulletinboard|ext\.tool)$}) {
+ my $prefix = $1;
+ if ($prefix eq 'ext.tool') {
+ $prefix = 'exttool';
+ }
+ 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'});
+ } elsif ($dbref->{'src'} =~ m{/ext\.tool$}) {
+ $db_name = 'exttool_'.$marker;
+ } 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);
+ } elsif ($prefix eq 'exttool') {
+ $errtext = &mt('Failed to acquire a unique timestamp-based suffix when copying an external tool [_1].',$url);
+ } else {
+ $errtext = &mt('Failed to acquire a unique timestamp-based suffix when copying a discussion board [_1].',$url);
+ }
+ if ($error) {
+ $errtext .= ' '.$error;
+ }
+ } else {
+ #need to copy the db contents to a new one.
+ my %contents=&Apache::lonnet::dump($db_name,
+ $dbref->{'cdom'},
+ $dbref->{'cnum'});
+ my ($toolcopyerror,$toolpassback,$toolroster,%toolinfo,$oldtoolid,$defincrs);
+ if ($url eq '/adm/'.$dbref->{'cdom'}.'/'.$dbref->{'cnum'}."/$marker/ext.tool") {
+ if ($contents{'id'} =~ /^(|c)(\d+)$/) {
+ $oldtoolid = $2;
+ if ($1 eq 'c') {
+ $defincrs = 1;
+ %toolinfo =
+ &Apache::lonnet::get('ltitools',[$oldtoolid],$dbref->{'cdom'},$dbref->{'cnum'});
+ } else {
+ %toolinfo= &Apache::lonnet::get_domain_lti($dbref->{'cdom'},'consumer');
+ }
+ if (ref($toolinfo{$oldtoolid}) eq 'HASH') {
+ if ($toolinfo{$oldtoolid}{'passback'}) {
+ $toolpassback = 1;
+ }
+ if ($toolinfo{$oldtoolid}{'roster'}) {
+ $toolroster = 1;
+ }
+ } else {
+ $toolcopyerror = 1;
+ $errtext = &mt('Could not retrieve original settings for pasted external tool.');
+ }
+ }
+ unless (($dbref->{'cnum'} eq $coursenum) && ($dbref->{'cdom'} eq $coursedom)) {
+ $url = "/adm/$coursedom/$coursenum/$marker/ext.tool";
+ if ($contents{'crstitle'} ne '') {
+ $contents{'crstitle'} = $env{'course.'.$coursedom.'_'.$coursenum.'.description'};
+ }
+ if (($defincrs) && (!$toolcopyerror)) {
+ my %newtool;
+ my $oldcdom = $dbref->{'cdom'};
+ my $oldcnum = $dbref->{'cnum'};
+ my $title = $toolinfo{$oldtoolid}{'title'};
+ if (ref($currltititles) eq 'HASH') {
+ if (exists($currltititles->{$title})) {
+ $title .= ' (copied from another course)';
+ }
+ }
+ my ($newid,$iderror) =
+ &Apache::lonnet::get_ltitools_id('course',$coursedom,$coursenum,$title);
+ if ($newid =~ /^\d+$/) {
+ %{$newtool{$newid}} = %{$toolinfo{$oldtoolid}};
+ $newtool{$newid}{'title'} = $title;
+ if (ref($currltimax)) {
+ $newtool{$newid}{'order'} = $$currltimax;
+ }
+ if ($newtool{$newid}{'image'} =~ m{^\Q/uploaded/$oldcdom/$oldcnum/toollogo/$oldtoolid/\E([^/]+)$}) {
+ my $fname = $1;
+ my $content = &Apache::lonnet::getfile($newtool{$newid}{'image'});
+ if ($content eq '-1') {
+ delete($newtool{$newid}{'image'});
+ } else {
+ $env{'form.'.$suffix.'.image'} = $content;
+ my $newlogo =
+ &Apache::lonnet::finishuserfileupload($coursenum,$coursedom,$suffix.'.image',"toollogo/$newid/$fname");
+ delete($env{'form.'.$suffix.'.image'});
+ if ($newlogo =~ m{^/uploaded/}) {
+ $newtool{$newid}{'image'} = $newlogo;
+ } else {
+ delete($newtool{$newid}{'image'});
+ }
+ }
+ }
+ my $newusable;
+ if ($same_institution) {
+ my %oldtoolsenc = &Apache::lonnet::eget('nohist_toolsenc',[$oldtoolid],$oldcdom,$oldcnum);
+ if (ref($oldtoolsenc{$oldtoolid}) eq 'HASH') {
+ my %newtoolsenc;
+ %{$newtoolsenc{$newid}} = %{$oldtoolsenc{$oldtoolid}};
+ my $putres = &Apache::lonnet::put('nohist_toolsenc',\%newtoolsenc,$coursedom,$coursenum,1);
+ if ($putres eq 'ok') {
+ if (ref($updatetoolsenc) eq 'ARRAY') {
+ my $newhome = &Apache::lonnet::homeserver($coursenum,$coursedom);
+ unless (grep(/^\Q$newhome\E$/,@{$updatetoolsenc})) {
+ push(@{$updatetoolsenc},$newhome);
+ }
+ }
+ $newusable = 1;
+ }
+ }
+ }
+ if ($newtool{$newid}{'usable'}) {
+ unless ($newusable) {
+ delete($newtool{$newid}{'usable'});
+ }
+ }
+ my $putres = &Apache::lonnet::put('ltitools',\%newtool,$coursedom,$coursenum);
+ if ($putres eq 'ok') {
+ $contents{'id'} = "c$newid";
+ if (ref($updatetoolscache)) {
+ $$updatetoolscache ++;
+ }
+ if (ref($currltititles->{$title}) eq 'ARRAY') {
+ push(@{$currltititles->{$title}},$newid);
+ } else {
+ $currltititles->{$title} = [$newid];
+ }
+ if (ref($currltimax)) {
+ $$currltimax ++;
+ }
+ } else {
+ $toolcopyerror = 1;
+ $errtext = &mt('Unable to save external tool definition in Course Settings.');
+ }
+ } else {
+ $toolcopyerror = 1;
+ $errtext = &mt('Unable to retrieve new tool ID when adding external tool definition to Course Settings.');
+ }
+ }
+ }
+ }
+ 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;
+ if ($prefix eq 'exttool') {
+ unless ($toolcopyerror) {
+ foreach my $key ('oldgradesecret','gradesecret','gradesecretdate','oldrostersecret','rostersecret','rostersecretdate') {
+ if (exists($contents{$key})) {
+ delete($contents{$key});
+ }
+ }
+ if ($dbref->{'delgradable'}) {
+ if (exists($contents{'gradable'})) {
+ delete($contents{'gradable'});
+ }
+ }
+ if ($toolpassback) {
+ if ($contents{'gradable'}) {
+ my $gradesecret = UUID::Tiny::create_uuid_as_string(UUID_V4);
+ $contents{'gradesecret'} = $gradesecret;
+ $contents{'gradesecretdate'} = time;
+ }
+ }
+ if ($toolroster) {
+ my $rostersecret = UUID::Tiny::create_uuid_as_string(UUID_V4);
+ $contents{'rostersecret'} = $rostersecret;
+ $contents{'rostersecretdate'} = time;
+ }
+ }
+ }
+ if (($prefix eq 'exttool') && ($toolcopyerror)) {
+ $result = 'error';
+ } else {
+ $result=&Apache::lonnet::put($db_name,\%contents,
+ $coursedom,$coursenum);
+ if ($result eq 'ok') {
+ $url =~ s{/(\d*)/(smppg|bulletinboard|ext\.tool)$}{/$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.');
+ } elsif ($prefix eq 'exttool') {
+ $lockerrorsref->{$prefix} .=
+ ' '.&mt('This will prevent addition of more external tools to this course.');
+ } else {
+ $lockerrorsref->{$prefix} .= ' '.&mt('This will prevent creation of additional discussion boards in this course.');
+ }
+ $lockerrorsref->{$prefix} .= ' '.&mt('Please contact the [_1]helpdesk[_2] for assistance.',
+ '
',' ').
+ '
';
+ }
+ }
+ } elsif ($url =~ m{/syllabus$}) {
+ if (($dbref->{'cdom'} =~ /^$match_domain$/) &&
+ ($dbref->{'cnum'} =~ /^$match_courseid$/)) {
+ if (($dbref->{'cdom'} ne $coursedom) ||
+ ($dbref->{'cnum'} ne $coursenum)) {
+ my %contents=&Apache::lonnet::dump('syllabus',
+ $dbref->{'cdom'},
+ $dbref->{'cnum'});
+ $result=&Apache::lonnet::put('syllabus',\%contents,
+ $coursedom,$coursenum);
+ }
+ }
+ }
+ }
+ return ($url,$result,$errtext);
+}
+
+sub copy_templated_files {
+ my ($srcurl,$srcdom,$srcnum,$srcmapinfo,$coursedom,$coursenum,$template,$newidx,$newmapname) = @_;
+ my ($srcfolder,$srcid,$srcwaspage) = split(/:/,$srcmapinfo);
+ my $srccontainer = 'sequence';
+ if ($srcwaspage) {
+ $srccontainer = 'page';
+ }
+ my $srcsymb = "uploaded/$srcdom/$srcnum/$srcfolder.$srccontainer".
+ '___'.$srcid.'___'.&Apache::lonnet::declutter($srcurl);
+ my $srcprefix = $srcdom.'_'.$srcnum.'.'.$srcsymb;
+ my %srcparms=&Apache::lonnet::dump('resourcedata',$srcdom,$srcnum,$srcprefix);
+ my $newsymb = "uploaded/$coursedom/$coursenum/$newmapname".'___'.$newidx.'___lib/templates/'.
+ $template.'.problem';
+ my $newprefix = $coursedom.'_'.$coursenum.'.'.$newsymb;
+ if ($template eq 'simpleproblem') {
+ $srcprefix .= '.0.';
+ my $weightprefix = $newprefix;
+ $newprefix .= '.0.';
+ my @simpleprobqtypes = qw(radio option string essay numerical);
+ my $qtype=$srcparms{$srcprefix.'questiontype'};
+ if (grep(/^\Q$qtype\E$/,@simpleprobqtypes)) {
+ my %newdata = (
+ $newprefix.'questiontype' => $qtype,
+ );
+ foreach my $type (@simpleprobqtypes) {
+ if ($type eq $qtype) {
+ $newdata{"$weightprefix.$type.weight"}=1;
+ } else {
+ $newdata{"$weightprefix.$type.weight"}=0;
+ }
+ }
+ $newdata{$newprefix.'hiddenparts'} = '!'.$qtype;
+ $newdata{$newprefix.'questiontext'} = $srcparms{$srcprefix.'questiontext'};
+ $newdata{$newprefix.'hinttext'} = $srcparms{$srcprefix.'hinttext'};
+ if ($qtype eq 'numerical') {
+ $newdata{$newprefix.'numericalscript'} = $srcparms{$srcprefix.'numericalscript'};
+ $newdata{$newprefix.'numericalanswer'} = $srcparms{$srcprefix.'numericalanswer'};
+ $newdata{$newprefix.'numericaltolerance'} = $srcparms{$srcprefix.'numericaltolerance'};
+ $newdata{$newprefix.'numericalsigfigs'} = $srcparms{$srcprefix.'numericalsigfigs'};
+ } elsif (($qtype eq 'option') || ($qtype eq 'radio')) {
+ my $maxfoils=$srcparms{$srcprefix.'maxfoils'};
+ unless (defined($maxfoils)) { $maxfoils=10; }
+ unless ($maxfoils=~/^\d+$/) { $maxfoils=10; }
+ if ($maxfoils<=0) { $maxfoils=10; }
+ my $randomize=$srcparms{$srcprefix.'randomize'};
+ unless (defined($randomize)) { $randomize='yes'; }
+ unless ($randomize eq 'no') { $randomize='yes'; }
+ $newdata{$newprefix.'maxfoils'} = $maxfoils;
+ $newdata{$newprefix.'randomize'} = $randomize;
+ if ($qtype eq 'option') {
+ $newdata{$newprefix.'options'} = $srcparms{$srcprefix.'options'};
+ }
+ for (my $i=1; $i<=10; $i++) {
+ $newdata{$newprefix.'value'.$i} = $srcparms{$srcprefix.'value'.$i};
+ $newdata{$newprefix.'position'.$i} = $srcparms{$srcprefix.'position'.$i};
+ $newdata{$newprefix.'text'.$i} = $srcparms{$srcprefix.'text'.$i};
+ }
+
+ } elsif (($qtype eq 'option') || ($qtype eq 'radio')) {
+ my $maxfoils=$srcparms{$srcprefix.'maxfoils'};
+ unless (defined($maxfoils)) { $maxfoils=10; }
+ unless ($maxfoils=~/^\d+$/) { $maxfoils=10; }
+ if ($maxfoils<=0) { $maxfoils=10; }
+ my $randomize=$srcparms{$srcprefix.'randomize'};
+ unless (defined($randomize)) { $randomize='yes'; }
+ unless ($randomize eq 'no') { $randomize='yes'; }
+ $newdata{$newprefix.'maxfoils'} = $maxfoils;
+ $newdata{$newprefix.'randomize'} = $randomize;
+ if ($qtype eq 'option') {
+ $newdata{$newprefix.'options'} = $srcparms{$srcprefix.'options'};
+ }
+ for (my $i=1; $i<=10; $i++) {
+ $newdata{$newprefix.'value'.$i} = $srcparms{$srcprefix.'value'.$i};
+ $newdata{$newprefix.'position'.$i} = $srcparms{$srcprefix.'position'.$i};
+ $newdata{$newprefix.'text'.$i} = $srcparms{$srcprefix.'text'.$i};
+ }
+ } elsif ($qtype eq 'string') {
+ $newdata{$newprefix.'stringanswer'} = $srcparms{$srcprefix.'stringanswer'};
+ $newdata{$newprefix.'stringtype'} = $srcparms{$srcprefix.'stringtype'};
+ }
+ if (keys(%newdata)) {
+ my $putres = &Apache::lonnet::cput('resourcedata',\%newdata,$coursedom,
+ $coursenum);
+ if ($putres eq 'ok') {
+ &Apache::lonnet::devalidatecourseresdata($coursenum,$coursedom);
+ }
+ }
+ }
+ }
+}
+
+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,$coursenum,$coursedom,$removefrommap,$removeparam,$addedmaps,
+ $hierarchy,$titles,$allmaps) = @_;
+ my $content = &Apache::lonnet::getfile($url);
+ unless ($content eq '-1') {
+ my $parser = HTML::TokeParser->new(\$content);
+ $parser->attr_encoded(1);
+ while (my $token = $parser->get_token) {
+ next if ($token->[0] ne 'S');
+ if ($token->[1] eq 'resource') {
+ next if ($token->[2]->{'type'} eq 'zombie');
+ my $ressrc = $token->[2]->{'src'};
+ if ($ressrc =~ m{^/adm/($match_domain)/($match_courseid)/(\d+)/ext\.tool$}) {
+ my ($srcdom,$srcnum,$marker) = ($1,$2,$3);
+ unless ($srcdom eq $coursedom) {
+ $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc;
+ next;
+ }
+ unless ($srcnum eq $coursenum) {
+ my %toolsettings =
+ &Apache::lonnet::dump('exttool_'.$marker,$srcdom,$srcnum);
+ my %tooltypes = &Apache::loncommon::usable_exttools();
+ if ((($toolsettings{'id'} =~ /^c\d+$/) && (!$tooltypes{'crs'})) ||
+ (($toolsettings{'id'} =~ /^\d+$/) && (!$tooltypes{'dom'}))) {
+ $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc;
+ next;
+ }
+ }
+ } elsif ($folder =~ /^supplemental/) {
+ unless (&supp_pasteable($ressrc)) {
+ $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc;
+ next;
+ }
+ }
+ if ($ressrc =~ m{^/res/($match_domain)/($match_courseid)/}) {
+ my ($srcdom,$srcnum) = ($1,$2);
+ unless (($srcnum eq $coursenum) && ($srcdom eq $coursedom)) {
+ if (&Apache::lonnet::is_course($srcdom,$srcnum)) {
+ $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc;
+ next;
+ }
+ }
+ }
+ if ($ressrc =~ m{^/(res|uploaded)/.+\.(sequence|page)$}) {
+ if ($1 eq 'uploaded') {
+ $hierarchy->{$url}{$token->[2]->{'id'}} = $ressrc;
+ $titles->{$url}{$token->[2]->{'id'}} = $token->[2]->{'title'};
+ } else {
+ if ($allmaps->{$ressrc}) {
+ $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc;
+ } elsif (ref($addedmaps->{$ressrc}) eq 'ARRAY') {
+ $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc;
+ } else {
+ $addedmaps->{$ressrc} = [$url];
+ }
+ }
+ &contained_map_check($ressrc,$folder,$coursenum,$coursedom,$removefrommap,
+ $removeparam,$addedmaps,$hierarchy,$titles,$allmaps);
+ }
+ } elsif ($token->[1] eq 'param') {
+ if ($folder =~ /^supplemental/) {
+ if (ref($removeparam->{$url}{$token->[2]->{'to'}}) eq 'ARRAY') {
+ push(@{$removeparam->{$url}{$token->[2]->{'to'}}},$token->[2]->{'name'});
+ } else {
+ $removeparam->{$url}{$token->[2]->{'to'}} = [$token->[2]->{'name'}];
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+sub url_paste_fixups {
+ my ($oldurl,$folder,$prefixchg,$cdom,$cnum,$fromcdom,$fromcnum,$allmaps,
+ $rewrites,$retitles,$copies,$dbcopies,$zombies,$params,$mapmoves,
+ $mapchanges,$tomove,$newsubdir,$newurls,$resdatacopy) = @_;
+ my $checktitle;
+ if (($prefixchg) &&
+ ($oldurl =~ m{^/uploaded/$match_domain/$match_courseid/supplemental})) {
+ $checktitle = 1;
+ }
+ my $skip;
+ if ($oldurl =~ m{^\Q/uploaded/$cdom/$cnum/\E(default|supplemental)(_?\d*)\.(?:page|sequence)$}) {
+ my $mapid = $1.$2;
+ if ($tomove->{$mapid}) {
+ $skip = 1;
+ }
+ }
+ my $file = &Apache::lonnet::getfile($oldurl);
+ return if ($file eq '-1');
+ my $parser = HTML::TokeParser->new(\$file);
+ $parser->attr_encoded(1);
+ my $changed = 0;
+ while (my $token = $parser->get_token) {
+ next if ($token->[0] ne 'S');
+ if ($token->[1] eq 'resource') {
+ my $ressrc = $token->[2]->{'src'};
+ next if ($ressrc eq '');
+ my $id = $token->[2]->{'id'};
+ my $title = $token->[2]->{'title'};
+ if ($checktitle) {
+ if ($title =~ m{\d+\Q___&&&___\E$match_username\Q___&&&___\E$match_domain\Q___&&&___\E(.+)$}) {
+ $retitles->{$oldurl}{$id} = $ressrc;
+ }
+ }
+ next if ($token->[2]->{'type'} eq 'external');
+ if ($token->[2]->{'type'} eq 'zombie') {
+ next if ($skip);
+ $zombies->{$oldurl}{$id} = $ressrc;
+ $changed = 1;
+ } elsif ($ressrc =~ m{^/uploaded/($match_domain)/($match_courseid)/(.+)$}) {
+ my $srcdom = $1;
+ my $srcnum = $2;
+ my $rem = $3;
+ my $newurl;
+ my $mapname;
+ if ($rem =~ /^(default|supplemental)(_?\d*).(sequence|page)$/) {
+ my $prefix = $1;
+ $mapname = $prefix.$2;
+ if ($tomove->{$mapname}) {
+ &url_paste_fixups($ressrc,$folder,$prefixchg,$cdom,$cnum,
+ $srcdom,$srcnum,$allmaps,$rewrites,
+ $retitles,$copies,$dbcopies,$zombies,
+ $params,$mapmoves,$mapchanges,$tomove,
+ $newsubdir,$newurls,$resdatacopy);
+ next;
+ } else {
+ ($newurl,my $error) =
+ &get_newmap_url($ressrc,$folder,$prefixchg,$cdom,$cnum,
+ $srcdom,$srcnum,\$title,$allmaps,$newurls);
+ if ($newurl =~ /(?:default|supplemental)_(\d+)\.(?:sequence|page)$/) {
+ $newsubdir->{$ressrc} = $1;
+ }
+ if ($error) {
+ next;
+ }
+ }
+ }
+ if (($srcdom ne $cdom) || ($srcnum ne $cnum) || ($prefixchg) ||
+ ($mapchanges->{$oldurl}) || (($newurl ne '') && ($newurl ne $oldurl))) {
+
+ if ($rem =~ /^(default|supplemental)(_?\d*).(sequence|page)$/) {
+ $rewrites->{$oldurl}{$id} = $ressrc;
+ $mapchanges->{$ressrc} = 1;
+ unless (&url_paste_fixups($ressrc,$folder,$prefixchg,$cdom,
+ $cnum,$srcdom,$srcnum,$allmaps,
+ $rewrites,$retitles,$copies,$dbcopies,
+ $zombies,$params,$mapmoves,$mapchanges,
+ $tomove,$newsubdir,$newurls,$resdatacopy)) {
+ $mapmoves->{$ressrc} = 1;
+ }
+ $changed = 1;
+ } else {
+ $rewrites->{$oldurl}{$id} = $ressrc;
+ $copies->{$oldurl}{$ressrc} = $id;
+ $changed = 1;
+ }
+ }
+ } elsif ($ressrc =~ m{^/adm/($match_domain)/($match_courseid)/(.+)$}) {
+ next if ($skip);
+ my $srcdom = $1;
+ my $srcnum = $2;
+ my $rem = $3;
+ my ($is_exttool,$exttoolchg);
+ if ($rem =~ m{\d+/ext\.tool$}) {
+ $is_exttool = 1;
+ }
+ if (($srcdom ne $cdom) || ($srcnum ne $cnum)) {
+ $rewrites->{$oldurl}{$id} = $ressrc;
+ $dbcopies->{$oldurl}{$id}{'src'} = $ressrc;
+ $dbcopies->{$oldurl}{$id}{'cdom'} = $srcdom;
+ $dbcopies->{$oldurl}{$id}{'cnum'} = $srcnum;
+ $changed = 1;
+ if ($is_exttool) {
+ $exttoolchg = 1;
+ }
+ } elsif (($is_exttool) &&
+ ($env{'form.docs.markedcopy_options'} ne 'move')) {
+ $dbcopies->{$oldurl}{$id}{'src'} = $ressrc;
+ $dbcopies->{$oldurl}{$id}{'cdom'} = $srcdom;
+ $dbcopies->{$oldurl}{$id}{'cnum'} = $srcnum;
+ $changed = 1;
+ $exttoolchg = 1;
+ }
+ if (($is_exttool) && ($prefixchg)) {
+ if ($oldurl =~ m{^/uploaded/$match_domain/$match_courseid/default}) {
+ if ($exttoolchg) {
+ $dbcopies->{$oldurl}{$id}{'delgradable'} = 1;
+ }
+ }
+ }
+ } elsif ($ressrc =~ m{^/adm/$match_domain/$match_username/\d+/(smppg|bulletinboard)$}) {
+ if (($fromcdom ne $cdom) || ($fromcnum ne $cnum) ||
+ ($env{'form.docs.markedcopy_options'} ne 'move')) {
+ $dbcopies->{$oldurl}{$id}{'src'} = $ressrc;
+ $dbcopies->{$oldurl}{$id}{'cdom'} = $fromcdom;
+ $dbcopies->{$oldurl}{$id}{'cnum'} = $fromcnum;
+ $changed = 1;
+ }
+ } elsif ($ressrc eq '/res/lib/templates/simpleproblem.problem') {
+ if (($fromcdom ne $cdom) || ($fromcnum ne $cnum)) {
+ $resdatacopy->{$oldurl}{$id}{'src'} = $ressrc;
+ $resdatacopy->{$oldurl}{$id}{'cdom'} = $fromcdom;
+ $resdatacopy->{$oldurl}{$id}{'cnum'} = $fromcnum;
+ }
+ } elsif ($ressrc =~ m{^/public/($match_domain)/($match_courseid)/(.+)$}) {
+ next if ($skip);
+ my $srcdom = $1;
+ my $srcnum = $2;
+ if (($srcdom ne $cdom) || ($srcnum ne $cnum)) {
+ $dbcopies->{$oldurl}{$id}{'src'} = $ressrc;
+ $dbcopies->{$oldurl}{$id}{'cdom'} = $srcdom;
+ $dbcopies->{$oldurl}{$id}{'cnum'} = $srcnum;
+ $changed = 1;
+ }
+ }
+ } elsif ($token->[1] eq 'param') {
+ next if ($skip);
+ my $to = $token->[2]->{'to'};
+ if ($to ne '') {
+ if (ref($params->{$oldurl}{$to}) eq 'ARRAY') {
+ push(@{$params->{$oldurl}{$to}},$token->[2]->{'name'});
+ } else {
+ @{$params->{$oldurl}{$to}} = ($token->[2]->{'name'});
+ }
+ }
+ }
+ }
+ return $changed;
+}
+
+sub apply_fixups {
+ my ($folder,$is_map,$cdom,$cnum,$errors,$updated,$info,$moves,$prefixchg,
+ $oldurl,$url,$caller) = @_;
+ my (%rewrites,%zombies,%removefrommap,%removeparam,%dbcopies,%retitles,
+ %params,%newsubdir,%before,%after,%copies,%docmoves,%mapmoves,@msgs,
+ %resdatacopy,%lockerrors,$lockmsg,%currcrsltitools,$gotcrsltitools,
+ %currltititles,$currltimax);
+ $currltimax = 0;
+ if (ref($updated) eq 'HASH') {
+ if (ref($updated->{'rewrites'}) eq 'HASH') {
+ %rewrites = %{$updated->{'rewrites'}};
+ }
+ if (ref($updated->{'zombies'}) eq 'HASH') {
+ %zombies = %{$updated->{'zombies'}};
+ }
+ if (ref($updated->{'removefrommap'}) eq 'HASH') {
+ %removefrommap = %{$updated->{'removefrommap'}};
+ }
+ if (ref($updated->{'removeparam'}) eq 'HASH') {
+ %removeparam = %{$updated->{'removeparam'}};
+ }
+ if (ref($updated->{'dbcopies'}) eq 'HASH') {
+ %dbcopies = %{$updated->{'dbcopies'}};
+ }
+ if (ref($updated->{'retitles'}) eq 'HASH') {
+ %retitles = %{$updated->{'retitles'}};
+ }
+ if (ref($updated->{'resdatacopy'}) eq 'HASH') {
+ %resdatacopy = %{$updated->{'resdatacopy'}};
+ }
+ }
+ if (ref($info) eq 'HASH') {
+ if (ref($info->{'newsubdir'}) eq 'HASH') {
+ %newsubdir = %{$info->{'newsubdir'}};
+ }
+ if (ref($info->{'params'}) eq 'HASH') {
+ %params = %{$info->{'params'}};
+ }
+ if (ref($info->{'before'}) eq 'HASH') {
+ %before = %{$info->{'before'}};
+ }
+ if (ref($info->{'after'}) eq 'HASH') {
+ %after = %{$info->{'after'}};
+ }
+ }
+ if (ref($moves) eq 'HASH') {
+ if (ref($moves->{'copies'}) eq 'HASH') {
+ %copies = %{$moves->{'copies'}};
+ }
+ if (ref($moves->{'docmoves'}) eq 'HASH') {
+ %docmoves = %{$moves->{'docmoves'}};
+ }
+ if (ref($moves->{'mapmoves'}) eq 'HASH') {
+ %mapmoves = %{$moves->{'mapmoves'}};
+ }
+ }
+ foreach my $key (keys(%copies),keys(%docmoves)) {
+ my @allcopies;
+ if (exists($copies{$key})) {
+ if (ref($copies{$key}) eq 'HASH') {
+ my %added;
+ foreach my $innerkey (keys(%{$copies{$key}})) {
+ if (($innerkey ne '') && (!$added{$innerkey})) {
+ push(@allcopies,$innerkey);
+ $added{$innerkey} = 1;
+ }
+ }
+ undef(%added);
+ }
+ }
+ if ($key eq $oldurl) {
+ if ((exists($docmoves{$key}))) {
+ unless (grep(/^\Q$oldurl\E$/,@allcopies)) {
+ push(@allcopies,$oldurl);
+ }
+ }
+ }
+ if (@allcopies > 0) {
+ foreach my $item (@allcopies) {
+ my ($relpath,$oldsubdir,$fname) =
+ ($item =~ m{^(/uploaded/$match_domain/$match_courseid/(?:docs|supplemental)/(default|\d+)/.*/)([^/]+)$});
+ if ($fname ne '') {
+ my $content = &Apache::lonnet::getfile($item);
+ unless ($content eq '-1') {
+ my $storefn;
+ if (($key eq $oldurl) && (exists($docmoves{$key}))) {
+ $storefn = $docmoves{$key};
+ } else {
+ $storefn = $relpath;
+ $storefn =~s{^/uploaded/$match_domain/$match_courseid/}{};
+ if ($prefixchg && $before{'doc'} && $after{'doc'}) {
+ $storefn =~ s/^\Q$before{'doc'}\E/$after{'doc'}/;
+ }
+ if ($newsubdir{$key}) {
+ $storefn =~ s#^(docs|supplemental)/\Q$oldsubdir\E/#$1/$newsubdir{$key}/#;
+ }
+ }
+ ©_dependencies($item,$storefn,$relpath,$errors,\$content);
+ my $copyurl =
+ &Apache::lonclonecourse::writefile($env{'request.course.id'},
+ $storefn.$fname,$content);
+ if ($copyurl eq '/adm/notfound.html') {
+ if (exists($docmoves{$oldurl})) {
+ return &mt('Paste failed: an error occurred copying the file.');
+ } elsif (ref($errors) eq 'HASH') {
+ $errors->{$item} = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ foreach my $key (keys(%mapmoves)) {
+ my $storefn=$key;
+ $storefn=~s{^/uploaded/$match_domain/$match_courseid/}{};
+ if ($prefixchg && $before{'map'} && $after{'map'}) {
+ $storefn =~ s/^\Q$before{'map'}\E/$after{'map'}/;
+ }
+ if ($newsubdir{$key}) {
+ $storefn =~ s/^((?:default|supplemental)_)(\d+)/$1$newsubdir{$key}/;
+ }
+ my $mapcontent = &Apache::lonnet::getfile($key);
+ if (($mapcontent eq '-1') && ($before{'map'} eq 'supplemental') &&
+ ($after{'map'} eq 'default') &&
+ ($key =~ m{^/uploaded/$match_domain/$match_courseid/supplemental_\d+\.sequence$})) {
+ $mapcontent = ''."\n".
+ ' '."\n".
+ ' '."\n".
+ ' '."\n".
+ ' ';
+ }
+ if ($mapcontent eq '-1') {
+ if (ref($errors) eq 'HASH') {
+ $errors->{$key} = 1;
+ }
+ } else {
+ my $newmap =
+ &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn,
+ $mapcontent);
+ if ($newmap eq '/adm/notfound.html') {
+ if (ref($errors) eq 'HASH') {
+ $errors->{$key} = 1;
+ }
+ }
+ }
+ }
+ my %updates;
+ if ($is_map) {
+ if (ref($updated) eq 'HASH') {
+ foreach my $type (keys(%{$updated})) {
+ if (ref($updated->{$type}) eq 'HASH') {
+ foreach my $key (keys(%{$updated->{$type}})) {
+ $updates{$key} = 1;
+ }
+ }
+ }
+ }
+ my ($updatetoolscache,@updatetoolsenc,$same_institution,$checkedsameinst);
+ foreach my $key (keys(%updates)) {
+ my (%torewrite,%toretitle,%toremove,%remparam,%currparam,%zombie,%newdb);
+ if (ref($rewrites{$key}) eq 'HASH') {
+ %torewrite = %{$rewrites{$key}};
+ }
+ if (ref($retitles{$key}) eq 'HASH') {
+ %toretitle = %{$retitles{$key}};
+ }
+ if (ref($removefrommap{$key}) eq 'HASH') {
+ %toremove = %{$removefrommap{$key}};
+ }
+ if (ref($removeparam{$key}) eq 'HASH') {
+ %remparam = %{$removeparam{$key}};
+ }
+ if (ref($zombies{$key}) eq 'HASH') {
+ %zombie = %{$zombies{$key}};
+ }
+ if (ref($dbcopies{$key}) eq 'HASH') {
+ foreach my $idx (keys(%{$dbcopies{$key}})) {
+ if (ref($dbcopies{$key}{$idx}) eq 'HASH') {
+ my $oldurl = $dbcopies{$key}{$idx}{'src'};
+ my $oldcdom = $dbcopies{$key}{$idx}{'cdom'};
+ my $oldcnum = $dbcopies{$key}{$idx}{'cnum'};
+ my $oldmarker;
+ if ($oldurl =~ m{^\Q/adm/$oldcdom/$oldcnum/\E(\d+)/ext\.tool$}) {
+ $oldmarker = $1;
+ unless (($gotcrsltitools) ||
+ (($oldcnum eq $cnum) && ($oldcdom eq $cdom))) {
+ my %oldtoolsettings=&Apache::lonnet::dump('exttool_'.$oldmarker,$oldcdom,$oldcnum);
+ if ($oldtoolsettings{'id'} =~ /^c\d+$/) {
+ unless ($gotcrsltitools) {
+ %currcrsltitools =
+ &Apache::lonnet::get_course_lti($cnum,$cdom,'consumer');
+ foreach my $item (sort(keys(%currcrsltitools))) {
+ if (ref($currcrsltitools{$item}) eq 'HASH') {
+ $currltimax ++;
+ if (ref($currltititles{$currcrsltitools{$item}{'title'}}) eq 'ARRAY') {
+ push(@{$currltititles{$currcrsltitools{$item}{'title'}}},$item);
+ } else {
+ $currltititles{$currcrsltitools{$item}{'title'}} = [$item];
+ }
+ }
+ }
+ $gotcrsltitools = 1;
+ }
+ unless ($checkedsameinst) {
+ my $primary_id = &Apache::lonnet::domain($cdom,'primary');
+ my $intdom = &Apache::lonnet::internet_dom($primary_id);
+ if ($intdom ne '') {
+ my $internet_names =
+ &Apache::lonnet::get_internet_names($Apache::lonnet::perlvar{'lonHostID'});
+ if (ref($internet_names) eq 'ARRAY') {
+ if (grep(/^\Q$intdom\E$/,@{$internet_names})) {
+ $same_institution = 1;
+ }
+ }
+ }
+ $checkedsameinst = 1;
+ }
+ }
+ }
+ }
+ my ($newurl,$result,$errtext) =
+ &dbcopy($dbcopies{$key}{$idx},$cdom,$cnum,\%lockerrors,\%currltititles,
+ \$currltimax,\@updatetoolsenc,\$updatetoolscache,$same_institution);
+ if ($result eq 'ok') {
+ $newdb{$idx} = $newurl;
+ if ($newurl =~ /ext\.tool$/) {
+ if ($torewrite{$idx} eq "/adm/$oldcdom/$oldcnum/$oldmarker/ext.tool") {
+ if ($newurl =~ m{^\Q/adm/$cdom/$cnum/\E(\d+)/ext.tool$}) {
+ my $newmarker = $1;
+ unless ($oldmarker eq $newmarker) {
+ $torewrite{$idx} = "/adm/$oldcdom/$oldcnum/$newmarker/ext.tool";
+ }
+ }
+ }
+ }
+ } elsif (ref($errors) eq 'HASH') {
+ $errors->{$key} = 1;
+ }
+ push(@msgs,$errtext);
+ }
+ }
+ }
+ if (ref($resdatacopy{$key}) eq 'HASH') {
+ my ($gotnewmapname,$newmapname,$srcfolder,$srccontainer);
+ foreach my $idx (keys(%{$resdatacopy{$key}})) {
+ if (ref($resdatacopy{$key}{$idx}) eq 'HASH') {
+ my $srcurl = $resdatacopy{$key}{$idx}{'src'};
+ if ($srcurl =~ m{^/res/lib/templates/(\w+)\.problem$}) {
+ my $template = $1;
+ if (($resdatacopy{$key}{$idx}{'cdom'} =~ /^$match_domain$/) &&
+ ($resdatacopy{$key}{$idx}{'cnum'} =~ /^$match_courseid$/)) {
+ my $srcdom = $resdatacopy{$key}{$idx}{'cdom'};
+ my $srcnum = $resdatacopy{$key}{$idx}{'cnum'};
+ unless ($gotnewmapname) {
+ ($newmapname) = ($key =~ m{/([^/]+)$});
+ ($srcfolder,$srccontainer) = split(/\./,$newmapname);
+ if ($newsubdir{$key}) {
+ $newmapname =~ s/^((?:default|supplemental)_)(\d+)/$1$newsubdir{$key}/;
+ }
+ $gotnewmapname = 1;
+ }
+ my $srcmapinfo = $srcfolder.':'.$idx;
+ if ($srccontainer eq 'page') {
+ $srcmapinfo .= ':1';
+ }
+ ©_templated_files($srcurl,$srcdom,$srcnum,$srcmapinfo,$cdom,
+ $cnum,$template,$idx,$newmapname);
+ }
+ }
+ }
+ }
+ }
+ if (ref($params{$key}) eq 'HASH') {
+ %currparam = %{$params{$key}};
+ }
+ my ($errtext,$fatal) = &LONCAPA::map::mapread($key);
+ if ($fatal) {
+ return ($errtext);
+ }
+ for (my $i=0; $i<@LONCAPA::map::zombies; $i++) {
+ if (defined($LONCAPA::map::zombies[$i])) {
+ my ($title,$src,$ext,$type)=split(/\:/,$LONCAPA::map::zombies[$i]);
+ if ($zombie{$i} eq $src) {
+ undef($LONCAPA::map::zombies[$i]);
+ }
+ }
+ }
+ my $total = scalar(@LONCAPA::map::order) - 1;
+ for (my $i=$total; $i>=0; $i--) {
+ my $idx = $LONCAPA::map::order[$i];
+ if (defined($LONCAPA::map::resources[$idx])) {
+ my $changed;
+ my ($title,$src,$ext,$type)=split(/\:/,$LONCAPA::map::resources[$idx]);
+ if ((exists($toremove{$idx})) &&
+ ($toremove{$idx} eq &LONCAPA::map::qtescape($src))) {
+ splice(@LONCAPA::map::order,$i,1);
+ if (ref($currparam{$idx}) eq 'ARRAY') {
+ foreach my $name (@{$currparam{$idx}}) {
+ &LONCAPA::map::delparameter($idx,$name);
+ }
+ }
+ next;
+ }
+ my $origsrc = $src;
+ if ((exists($toretitle{$idx})) && ($toretitle{$idx} eq $src)) {
+ if ($title =~ m{^\d+\Q___&&&___\E$match_username\Q___&&&___\E$match_domain\Q___&&&___\E(.+)$}) {
+ $changed = 1;
+ }
+ }
+ if ((exists($torewrite{$idx})) && ($torewrite{$idx} eq $src)) {
+ $src =~ s{^/(uploaded|adm|public)/$match_domain/$match_courseid/}{/$1/$cdom/$cnum/};
+ if ($origsrc =~ m{^/uploaded/}) {
+ if ($prefixchg && $before{'map'} && $after{'map'}) {
+ if ($src =~ /\.(page|sequence)$/) {
+ $src =~ s#^(/uploaded/$match_domain/$match_courseid/)\Q$before{'map'}\E#$1$after{'map'}#;
+ } else {
+ $src =~ s#^(/uploaded/$match_domain/$match_courseid/)\Q$before{'doc'}\E#$1$after{'doc'}#;
+ }
+ }
+ if ($origsrc =~ /\.(page|sequence)$/) {
+ if ($newsubdir{$origsrc}) {
+ $src =~ s#^(/uploaded/$match_domain/$match_courseid/(?:default|supplemental)_)(\d+)#$1$newsubdir{$origsrc}#;
+ }
+ } elsif ($newsubdir{$key}) {
+ $src =~ s#^(/uploaded/$match_domain/$match_courseid/\w+/)(\d+)#$1$newsubdir{$key}#;
+ }
+ }
+ $changed = 1;
+ } elsif ($newdb{$idx} ne '') {
+ $src = $newdb{$idx};
+ $changed = 1;
+ }
+ if ($changed) {
+ $LONCAPA::map::resources[$idx] = join(':',($title,&LONCAPA::map::qtunescape($src),$ext,$type));
+ }
+ }
+ }
+ foreach my $idx (keys(%remparam)) {
+ if (ref($remparam{$idx}) eq 'ARRAY') {
+ foreach my $name (@{$remparam{$idx}}) {
+ &LONCAPA::map::delparameter($idx,$name);
+ }
+ }
+ }
+ if (values(%lockerrors) > 0) {
+ $lockmsg = join(' ',values(%lockerrors));
+ }
+ my $storefn;
+ if ($key eq $oldurl) {
+ $storefn = $url;
+ $storefn=~s{^/uploaded/$match_domain/$match_courseid/}{};
+ } else {
+ $storefn = $key;
+ $storefn=~s{^/uploaded/$match_domain/$match_courseid/}{};
+ if ($prefixchg && $before{'map'} && $after{'map'}) {
+ $storefn =~ s/^\Q$before{'map'}\E/$after{'map'}/;
+ }
+ if ($newsubdir{$key}) {
+ $storefn =~ s/^((?:default|supplemental)_)(\d+)/$1$newsubdir{$key}/;
+ }
+ }
+ my $report;
+ if ($folder !~ /^supplemental/) {
+ $report = 1;
+ }
+ (my $outtext,$errtext) =
+ &LONCAPA::map::storemap("/uploaded/$cdom/$cnum/$storefn",1,$report);
+ if ($errtext) {
+ if ($caller eq 'paste') {
+ return (&mt('Paste failed: an error occurred saving the folder or page.'));
+ }
+ }
+ }
+ if (($updatetoolscache) || (@updatetoolsenc)) {
+ &update_ltitools_caches($cdom,$cnum,$updatetoolscache,
+ \@updatetoolsenc);
+ }
+ }
+ return ('ok',\@msgs,$lockmsg);
+}
+
+sub copy_dependencies {
+ my ($item,$storefn,$relpath,$errors,$contentref) = @_;
+ my $content;
+ if (ref($contentref)) {
+ $content = $$contentref;
+ } else {
+ $content = &Apache::lonnet::getfile($item);
+ }
+ unless ($content eq '-1') {
+ my $mm = new File::MMagic;
+ my $mimetype = $mm->checktype_contents($content);
+ if ($mimetype eq 'text/html') {
+ my (%allfiles,%codebase,$state);
+ my $res = &Apache::lonnet::extract_embedded_items(undef,\%allfiles,\%codebase,\$content);
+ if ($res eq 'ok') {
+ my ($numexisting,$numpathchanges,$existing);
+ (undef,$numexisting,$numpathchanges,$existing) =
+ &Apache::loncommon::ask_for_embedded_content(
+ '/adm/coursedocs',$state,\%allfiles,\%codebase,
+ {'error_on_invalid_names' => 1,
+ 'ignore_remote_references' => 1,
+ 'docs_url' => $item,
+ 'context' => 'paste'});
+ if ($numexisting > 0) {
+ if (ref($existing) eq 'HASH') {
+ foreach my $dep (keys(%{$existing})) {
+ my $depfile = $dep;
+ unless ($depfile =~ m{^\Q$relpath\E}) {
+ $depfile = $relpath.$dep;
+ }
+ my $depcontent = &Apache::lonnet::getfile($depfile);
+ unless ($depcontent eq '-1') {
+ my $storedep = $dep;
+ $storedep =~ s{^\Q$relpath\E}{};
+ my $dep_url =
+ &Apache::lonclonecourse::writefile(
+ $env{'request.course.id'},
+ $storefn.$storedep,$depcontent);
+ if ($dep_url eq '/adm/notfound.html') {
+ if (ref($errors) eq 'HASH') {
+ $errors->{$depfile} = 1;
+ }
+ } else {
+ ©_dependencies($depfile,$storefn,$relpath,$errors,\$depcontent);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return;
+}
+
+my %parameter_type = ( 'randompick' => 'int_pos',
+ 'hiddenresource' => 'string_yesno',
+ 'encrypturl' => 'string_yesno',
+ 'randomorder' => 'string_yesno',);
+my $valid_parameters_re = join('|',keys(%parameter_type));
+# set parameters
+sub update_parameter {
+ if ($env{'form.changeparms'} eq 'all') {
+ my (@allidx,@allmapidx,%allchecked,%currchecked);
+ %allchecked = (
+ 'hiddenresource' => {},
+ 'encrypturl' => {},
+ 'randompick' => {},
+ 'randomorder' => {},
+ );
+ foreach my $which (keys(%allchecked)) {
+ $env{'form.all'.$which} =~ s/,$//;
+ if ($which eq 'randompick') {
+ foreach my $item (split(/,/,$env{'form.all'.$which})) {
+ my ($res,$value) = split(/:/,$item);
+ if ($value =~ /^\d+$/) {
+ $allchecked{$which}{$res} = $value;
+ }
+ }
+ } else {
+ if ($env{'form.all'.$which}) {
+ map { $allchecked{$which}{$_} = 1; } split(/,/,$env{'form.all'.$which});
+ }
+ }
+ }
+ my $haschanges = 0;
+ foreach my $res (@LONCAPA::map::order) {
+ my ($name,$url)=split(/\:/,$LONCAPA::map::resources[$res]);
+ $name=&LONCAPA::map::qtescape($name);
+ $url=&LONCAPA::map::qtescape($url);
+ next unless $url;
+ my $is_map;
+ if ($url =~ m{/uploaded/.+\.(page|sequence)$}) {
+ $is_map = 1;
+ }
+ foreach my $which (keys(%allchecked)) {
+ if (($which eq 'randompick' || $which eq 'randomorder')) {
+ next if (!$is_map);
+ }
+ my $oldvalue = 0;
+ my $newvalue = 0;
+ if ($allchecked{$which}{$res}) {
+ $newvalue = $allchecked{$which}{$res};
+ }
+ my $current = (&LONCAPA::map::getparameter($res,'parameter_'.$which))[0];
+ if ($which eq 'randompick') {
+ if ($current =~ /^(\d+)$/) {
+ $oldvalue = $1;
+ }
+ } else {
+ if ($current =~ /^yes$/i) {
+ $oldvalue = 1;
+ }
+ }
+ if ($oldvalue ne $newvalue) {
+ $haschanges = 1;
+ if ($newvalue) {
+ my $storeval = 'yes';
+ if ($which eq 'randompick') {
+ $storeval = $newvalue;
+ }
+ &LONCAPA::map::storeparameter($res,'parameter_'.$which,
+ $storeval,
+ $parameter_type{$which});
+ &remember_parms($res,$which,'set',$storeval);
+ } elsif ($oldvalue) {
+ &LONCAPA::map::delparameter($res,'parameter_'.$which);
+ &remember_parms($res,$which,'del');
+ }
+ }
+ }
+ }
+ return $haschanges;
+ } else {
+ my $haschanges = 0;
+ return $haschanges if ($env{'form.changeparms'} !~ /^($valid_parameters_re)$/);
+
+ my $which = $env{'form.changeparms'};
+ my $idx = $env{'form.setparms'};
+ my $oldvalue = 0;
+ my $newvalue = 0;
+ my $current = (&LONCAPA::map::getparameter($idx,'parameter_'.$which))[0];
+ if ($which eq 'randompick') {
+ if ($current =~ /^(\d+)$/) {
+ $oldvalue = $1;
+ }
+ } elsif ($current =~ /^yes$/i) {
+ $oldvalue = 1;
+ }
+ if ($env{'form.'.$which.'_'.$idx}) {
+ $newvalue = ($which eq 'randompick') ? $env{'form.rpicknum_'.$idx}
+ : 1;
+ }
+ if ($oldvalue ne $newvalue) {
+ $haschanges = 1;
+ if ($newvalue) {
+ my $storeval = 'yes';
+ if ($which eq 'randompick') {
+ $storeval = $newvalue;
+ }
+ &LONCAPA::map::storeparameter($idx, 'parameter_'.$which, $storeval,
+ $parameter_type{$which});
+ &remember_parms($idx,$which,'set',$storeval);
+ } else {
+ &LONCAPA::map::delparameter($idx,'parameter_'.$which);
+ &remember_parms($idx,$which,'del');
+ }
+ }
+ return $haschanges;
+ }
+}
+
+sub handle_edit_cmd {
+ my ($coursenum,$coursedom) =@_;
+ my $haschanges = 0;
+ if ($env{'form.cmd'} eq '') {
+ return $haschanges;
+ }
+ 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 'remove') {
+ if (($url=~m|/+uploaded/\Q$coursedom\E/\Q$coursenum\E/|) &&
+ ($url!~/$LONCAPA::assess_page_seq_re/)) {
+ &Apache::lonnet::removeuploadedurl($url);
+ } else {
+ &LONCAPA::map::makezombie($LONCAPA::map::order[$idx]);
}
+ splice(@LONCAPA::map::order, $idx, 1);
+ $haschanges = 1;
+ } elsif ($cmd eq 'cut') {
+ &LONCAPA::map::makezombie($LONCAPA::map::order[$idx]);
+ splice(@LONCAPA::map::order, $idx, 1);
+ $haschanges = 1;
+ } elsif ($cmd eq 'up'
+ && ($idx) && (defined($LONCAPA::map::order[$idx-1]))) {
+ @LONCAPA::map::order[$idx-1,$idx] = @LONCAPA::map::order[$idx,$idx-1];
+ $haschanges = 1;
+ } elsif ($cmd eq 'down'
+ && defined($LONCAPA::map::order[$idx+1])) {
+ @LONCAPA::map::order[$idx+1,$idx] = @LONCAPA::map::order[$idx,$idx+1];
+ $haschanges = 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);
+ $haschanges = 1;
+ } elsif ($cmd eq 'setalias') {
+ my $newvalue = $env{'form.alias'};
+ if ($newvalue ne '') {
+ unless (Apache::lonnet::get_symb_from_alias($newvalue)) {
+ &LONCAPA::map::storeparameter($idx,'parameter_0_mapalias',$newvalue,
+ 'string');
+ &remember_parms($idx,'mapalias','set',$newvalue);
+ $haschanges = 1;
+ }
+ }
+ } elsif ($cmd eq 'delalias') {
+ my $current = (&LONCAPA::map::getparameter($idx,'parameter_0_mapalias'))[0];
+ if ($current ne '') {
+ &LONCAPA::map::delparameter($idx,'parameter_0_mapalias');
+ &remember_parms($idx,'mapalias','del');
+ $haschanges = 1;
+ }
}
- &storemap($coursenum, $coursedom, $folder);
+ return $haschanges;
}
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]='';
+ my ($r,$coursenum,$coursedom,$folder,$allowed,$upload_output,$crstype,
+ $supplementalflag,$orderhash,$iconpath,$pathitem,$ltitoolsref,
+ $canedit,$hostname,$navmapref,$hiddentop)=@_;
+ my ($randompick,$ishidden,$isencrypted,$plain,$is_random_order,$container);
+ if ($allowed) {
+ (my $breadcrumbtrail,$randompick,$ishidden,$isencrypted,$plain,
+ $is_random_order,$container) =
+ &Apache::lonhtmlcommon::docs_breadcrumbs($allowed,$crstype,1);
+ $r->print($breadcrumbtrail);
+ } elsif ($env{'form.folderpath'} =~ /\:1$/) {
+ $container = 'page';
+ } else {
+ $container = 'sequence';
}
- if ($fatal) {
- $r->print(''.$errtext.'
');
+
+ my $jumpto;
+
+ unless ($supplementalflag) {
+ $jumpto = "uploaded/$coursedom/$coursenum/$folder.$container";
+ }
+
+ unless ($allowed) {
+ $randompick = -1;
+ }
+
+ my ($errtext,$fatal);
+ if (($folder eq '') && (!$supplementalflag)) {
+ if (@LONCAPA::map::order) {
+ undef(@LONCAPA::map::order);
+ undef(@LONCAPA::map::resources);
+ undef(@LONCAPA::map::resparms);
+ undef(@LONCAPA::map::zombies);
+ }
+ $folder = 'default';
+ $container = 'sequence';
} else {
+ ($errtext,$fatal) = &mapread($coursenum,$coursedom,
+ $folder.'.'.$container);
+ return $errtext if ($fatal);
+ }
+
+ if ($#LONCAPA::map::order<1) {
+ my $idx=&LONCAPA::map::getresidx();
+ 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;
- $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;
- $comment=~s/\:/\:/g;
- $Apache::lonratedt::resources[
- $Apache::lonratedt::order[$idx]]=
- $comment.':'.join(':',@rrest);
-
+ if (($allowed && $canedit) && ($env{'form.folder'} eq $folder)) {
+# set parameters and change order
+ &snapshotbefore();
+
+ if (&update_parameter()) {
+ ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container,1);
+ 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_errors;
+ my ($paste_res,$save_error,$pastemsgarray,$lockerror) =
+ &do_paste_from_buffer($coursenum,$coursedom,$folder,$container,
+ \%paste_errors);
+ if (ref($pastemsgarray) eq 'ARRAY') {
+ if (@{$pastemsgarray} > 0) {
+ $r->print(''.
+ join(' ',@{$pastemsgarray}).
+ '
');
+ }
+ }
+ if ($lockerror) {
+ $r->print(''.
+ $lockerror.
+ '
');
+ }
+ if ($save_error ne '') {
+ return $save_error;
+ }
+ if ($paste_res) {
+ my %errortext = &Apache::lonlocal::texthash (
+ fail => 'Storage of folder contents failed',
+ failread => 'Reading folder contents failed',
+ failstore => 'Storage of folder contents failed',
+ );
+ if ($errortext{$paste_res}) {
+ $r->print(''.$errortext{$paste_res}.'
');
+ }
+ }
+ if (keys(%paste_errors) > 0) {
+ $r->print(''."\n".
+ &mt('The following files are either dependencies of a web page or references within a folder and/or composite page which could not be copied during the paste operation:')."\n".
+ '
'."\n");
+ foreach my $key (sort(keys(%paste_errors))) {
+ $r->print(''.$key.' '."\n");
}
-# Store the changed version
- &storemap($coursenum,$coursedom,$folder.'.sequence');
+ $r->print(' '."\n");
+ }
+ } elsif ($env{'form.clearmarked'}) {
+ my $output = &do_buffer_empty();
+ if ($output) {
+ $r->print(''.$output.'
');
}
+ }
+
+ $r->print($upload_output);
+
+# Rename, cut, copy or remove a single resource
+ if (&handle_edit_cmd($coursenum,$coursedom)) {
+ my $contentchg;
+ if ($env{'form.cmd'} =~ m{^(remove|cut|setalias|delalias)_}) {
+ $contentchg = 1;
+ }
+ ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container,$contentchg);
+ return $errtext if ($fatal);
+ }
+
+# Cut, copy and/or remove multiple resources
+ if ($env{'form.multichange'}) {
+ my %allchecked = (
+ cut => {},
+ remove => {},
+ );
+ my $needsupdate;
+ foreach my $which (keys(%allchecked)) {
+ $env{'form.multi'.$which} =~ s/,$//;
+ if ($env{'form.multi'.$which}) {
+ map { $allchecked{$which}{$_} = 1; } split(/,/,$env{'form.multi'.$which});
+ if (ref($allchecked{$which}) eq 'HASH') {
+ $needsupdate += scalar(keys(%{$allchecked{$which}}));
+ }
+ }
+ }
+ if ($needsupdate) {
+ my $haschanges = 0;
+ my %curr_groups = &Apache::longroup::coursegroups();
+ my $total = scalar(@LONCAPA::map::order) - 1;
+ for (my $i=$total; $i>=0; $i--) {
+ my $res = $LONCAPA::map::order[$i];
+ my ($name,$url)=split(/\:/,$LONCAPA::map::resources[$res]);
+ $name=&LONCAPA::map::qtescape($name);
+ $url=&LONCAPA::map::qtescape($url);
+ next unless $url;
+ my %denied =
+ &action_restrictions($coursenum,$coursedom,$url,
+ $env{'form.folderpath'},\%curr_groups);
+ foreach my $which (keys(%allchecked)) {
+ next if ($denied{$which});
+ next unless ($allchecked{$which}{$res});
+ if ($which eq 'remove') {
+ if (($url=~m|/+uploaded/\Q$coursedom\E/\Q$coursenum\E/|) &&
+ ($url!~/$LONCAPA::assess_page_seq_re/)) {
+ &Apache::lonnet::removeuploadedurl($url);
+ } else {
+ &LONCAPA::map::makezombie($res);
+ }
+ splice(@LONCAPA::map::order,$i,1);
+ $haschanges ++;
+ } elsif ($which eq 'cut') {
+ &LONCAPA::map::makezombie($res);
+ splice(@LONCAPA::map::order,$i,1);
+ $haschanges ++;
+ }
+ }
+ }
+ if ($haschanges) {
+ ($errtext,$fatal) =
+ &storemap($coursenum,$coursedom,$folder.'.'.$container,1);
+ return $errtext if ($fatal);
+ }
+ }
+ }
+
# Group import/search
- if ($ENV{'form.importdetail'}) {
- my @imports;
- foreach (split(/\&/,$ENV{'form.importdetail'})) {
- if (defined($_)) {
- my ($name,$url)=split(/\=/,$_);
- $name=&Apache::lonnet::unescape($name);
- $url=&Apache::lonnet::unescape($url);
- push @imports, $name, $url;
- }
+ 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{^/adm/$coursedom/$coursenum/new/ext\.tool}) {
+ my ($suffix,$errortxt,$locknotfreed) =
+ &new_timebased_suffix($coursedom,$coursenum,'exttool');
+ if ($locknotfreed) {
+ $r->print($locknotfreed);
+ }
+ if ($suffix) {
+ $url =~ s{^(/adm/$coursedom/$coursenum)/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]);
}
-# Store the changed version
- group_import($coursenum, $coursedom, $folder, @imports);
+ }
+ ($errtext,$fatal,my $fixuperrors) =
+ &group_import($coursenum, $coursedom, $folder,$container,
+ 'londocs',$ltitoolsref,@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('');
- 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(''.
+ '
'.&mt('Parameters:').' '.
+ ($randompick>=0?''.&mt('randomly pick [quant,_1,resource]',$randompick).' ':'').
+ ($ishidden?''.&mt('contents hidden').' ':'').
+ ($isencrypted?''.&mt('URLs hidden').' ':'').
+ ($is_random_order?''.&mt('random order').' ':'').
+ '');
+ 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('
');
+ }
+
+ if ((!$allowed) && ($folder =~ /^supplemental_\d+$/)) {
+ my ($supplemental) = &Apache::loncommon::get_supplemental($coursenum,$coursedom);
+ if (ref($supplemental) eq 'HASH') {
+ if ((ref($supplemental->{'hidden'}) eq 'HASH') &&
+ (ref($supplemental->{'ids'}) eq 'HASH')) {
+ if (ref($supplemental->{'ids'}->{"/uploaded/$coursedom/$coursenum/$folder.$container"}) eq 'ARRAY') {
+ my $mapnum = $supplemental->{'ids'}->{"/uploaded/$coursedom/$coursenum/$folder.$container"}->[0];
+ if ($supplemental->{'hidden'}->{$mapnum}) {
+ $ishidden = 1;
+ }
+ }
+ }
+ }
+ }
+
+ my ($to_show,$output,@allidx,@allmapidx,%filters,%lists,%curr_groups);
+ %filters = (
+ canremove => [],
+ cancut => [],
+ cancopy => [],
+ hiddenresource => [],
+ encrypturl => [],
+ randomorder => [],
+ randompick => [],
+ );
+ %curr_groups = &Apache::longroup::coursegroups();
+ &Apache::loncommon::start_data_table_count(); #setup a row counter
+ foreach my $res (@LONCAPA::map::order) {
+ my ($name,$url)=split(/\:/,$LONCAPA::map::resources[$res]);
+ $name=&LONCAPA::map::qtescape($name);
+ $url=&LONCAPA::map::qtescape($url);
+ unless ($name) { $name=(split(/\//,$url))[-1]; }
+ unless ($name) { $idx++; next; }
+ push(@allidx,$res);
+ if ($url =~ m{/uploaded/.+\.(page|sequence)$}) {
+ push(@allmapidx,$res);
+ }
+
+ if (($supplementalflag) && (!$allowed) && (!$env{'request.role.adv'})) {
+ if (($ishidden) || ((&LONCAPA::map::getparameter($res,'parameter_hiddenresource'))[0]=~/^yes$/i)) {
+ $idx++;
+ next;
+ }
}
- $r->print('
');
+ $output .= &entryline($idx,$name,$url,$folder,$allowed,$res,
+ $coursenum,$coursedom,$crstype,
+ $pathitem,$supplementalflag,$container,
+ \%filters,\%curr_groups,$ltitoolsref,$canedit,
+ $isencrypted,$ishidden,$navmapref,$hostname);
+ $idx++;
+ $shown++;
}
+ &Apache::loncommon::end_data_table_count();
+
+ my $need_save;
+ if ($allowed || ($supplementalflag && $folder eq 'supplemental')) {
+ my $toolslink;
+ if ($allowed || $canedit) {
+ my $helpitem = 'Navigation_Screen';
+ if (!$allowed) {
+ $helpitem = 'Supplemental_Navigation';
+ }
+ $toolslink = ''
+ .&Apache::loncommon::help_open_menu('Navigation Screen',
+ $helpitem,undef,'RAT')
+ .' '.&mt('Tools:').' '
+ .'
';
+ }
+ if ($shown) {
+ if ($allowed) {
+ $to_show = &Apache::loncommon::start_scrollbox('900px','880px','400px','contentscroll')
+ .&Apache::loncommon::start_data_table(undef,'contentlist')
+ .&Apache::loncommon::start_data_table_header_row()
+ .''.&mt('Move').' '
+ .''.&mt('Actions').' '
+ .''.&mt('Document').' '
+ .''.&mt('Settings').' '
+ .&Apache::loncommon::end_data_table_header_row();
+ if ($folder !~ /^supplemental/) {
+ $lists{'canhide'} = join(',',@allidx);
+ $lists{'canrandomlyorder'} = join(',',@allmapidx);
+ my @possfilters = ('canremove','cancut','cancopy','hiddenresource','encrypturl',
+ 'randomorder','randompick');
+ foreach my $item (@possfilters) {
+ if (ref($filters{$item}) eq 'ARRAY') {
+ if (@{$filters{$item}} > 0) {
+ $lists{$item} = join(',',@{$filters{$item}});
+ }
+ }
+ }
+ if (@allidx > 0) {
+ my $path;
+ if ($env{'form.folderpath'}) {
+ $path =
+ &HTML::Entities::encode($env{'form.folderpath'},'<>&"');
+ }
+ if (@allidx > 1) {
+ $to_show .=
+ &Apache::loncommon::continue_data_table_row().
+ ' '.
+ ''.
+ &multiple_check_form('actions',\%lists,$canedit).
+ ' '.
+ ' '.
+ ''.
+ &multiple_check_form('settings',\%lists,$canedit).
+ ' '.
+ &Apache::loncommon::end_data_table_row();
+ $need_save = 1;
+ }
+ }
+ }
+ $to_show .= $output.' '
+ .&Apache::loncommon::end_data_table()
+ .' '
+ .&Apache::loncommon::end_scrollbox();
+ } else {
+ $to_show .= $toolslink
+ .&Apache::loncommon::start_data_table('LC_tableOfContent')
+ .$output.' '
+ .&Apache::loncommon::end_data_table();
+ }
+ } else {
+ if (!$allowed) {
+ $to_show .= $toolslink;
+ }
+ my $noresmsg;
+ if ($allowed && $hiddentop && !$supplementalflag) {
+ $noresmsg = &mt('Main Content Hidden');
+ } else {
+ $noresmsg = &mt('Currently empty');
+ }
+ $to_show .= &Apache::loncommon::start_scrollbox('400px','380px','200px','contentscroll')
+ .''
+ .$noresmsg
+ .'
'
+ .&Apache::loncommon::end_scrollbox();
+ }
+ } else {
+ if ($shown) {
+ $to_show = ''
+ .&Apache::loncommon::start_data_table('LC_tableOfContent')
+ .$output
+ .&Apache::loncommon::end_data_table()
+ .'
';
+ } else {
+ $to_show = ''
+ .&mt('Currently empty')
+ .'
'
+ }
+ }
+ my $tid = 1;
+ if ($supplementalflag) {
+ $tid = 2;
+ }
+ if ($allowed) {
+ my $readfile="/uploaded/$coursedom/$coursenum/$folder.$container";
+ $r->print(&generate_edit_table($tid,$orderhash,$to_show,$iconpath,
+ $jumpto,$readfile,$need_save,"$folder.$container",$canedit));
+ if ($canedit) {
+ &print_paste_buffer($r,$container,$folder,$coursedom,$coursenum);
+ }
+ } else {
+ $r->print($to_show);
+ }
+ return;
+}
+
+sub multiple_check_form {
+ my ($caller,$listsref,$canedit) = @_;
+ return unless (ref($listsref) eq 'HASH');
+ my $disabled;
+ unless ($canedit) {
+ $disabled = ' disabled="disabled"';
+ }
+ my $output =
+ ''.
+ ''.
+ ' '.&mt('one').' '.(' 'x2).' '.&mt('multiple').' '.
+ ''.
+ '
'."\n".
+ ''.&mt('check/uncheck all').' '."\n";
+ if ($caller eq 'settings') {
+ $output .=
+ ''."\n";
+ } else {
+ $output .=
+ ''."\n";
+ }
+ $output .=
+ ' '.
+ ' ';
+ if ($caller eq 'settings') {
+ $output .=
+ ' '."\n".
+ ' '."\n".
+ ' '."\n".
+ ' '."\n".
+ ' '."\n";
+ } elsif ($caller eq 'actions') {
+ $output .=
+ ' '.
+ ' '.
+ ' ';
+ }
+ $output .=
+ ' '.
+ '
';
+ return $output;
+}
+
+sub process_file_upload {
+ my ($upload_output,$coursenum,$coursedom,$allfiles,$codebase,$uploadcmd,$crstype) = @_;
+# upload a file, if present
+ my $filesize = length($env{'form.uploaddoc'});
+ if (!$filesize) {
+ $$upload_output = ''.
+ &mt('Unable to upload [_1]. (size = [_2] bytes)',
+ ''.$env{'form.uploaddoc.filename'}.' ',
+ $filesize).' '.
+ &mt('Either the file you attempted to upload was empty, or your web browser was unable to read its contents.').' '.
+ '
';
+ return;
+ }
+ my $quotatype = 'unofficial';
+ if ($crstype eq 'Community') {
+ $quotatype = 'community';
+ } elsif ($crstype eq 'Placement') {
+ $quotatype = 'placement';
+ } elsif ($env{'course.'.$coursedom.'_'.$coursenum.'.internal.coursecode'}) {
+ $quotatype = 'official';
+ } elsif ($env{'course.'.$coursedom.'_'.$coursenum.'.internal.textbook'}) {
+ $quotatype = 'textbook';
+ }
+ if (&Apache::loncommon::get_user_quota($coursenum,$coursedom,'course',$quotatype)) {
+ $filesize = int($filesize/1000); #expressed in kb
+ $$upload_output = &Apache::loncommon::excess_filesize_warning($coursenum,$coursedom,'course',
+ $env{'form.uploaddoc.filename'},$filesize,
+ 'upload',$quotatype);
+ return if ($$upload_output);
+ }
+ my ($parseaction,$showupload,$nextphase,$mimetype);
+ if ($env{'form.parserflag'}) {
+ $parseaction = 'parse';
+ }
+ 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 = ''.&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,1);
+ 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)) &&
+ ($env{'form.uploaddoc.filename'} =~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/i)) {
+ $nextphase = 'decompress_uploaded';
+ my $position = scalar(@LONCAPA::map::order)-1;
+ my $noextract = &return_to_editor();
+ my $archiveurl = &HTML::Entities::encode($url,'<>&"');
+ my %archiveitems = (
+ folderpath => $env{'form.folderpath'},
+ cmd => $nextphase,
+ newidx => $newidx,
+ position => $position,
+ phase => $nextphase,
+ comment => $comment,
+ );
+ my ($destination,$dir_root) = &embedded_destination($coursenum,$coursedom);
+ my @current = &get_dir_list($url,$coursenum,$coursedom,$newidx);
+ $$upload_output = $showupload.
+ &Apache::loncommon::decompress_form($mimetype,
+ $archiveurl,'/adm/coursedocs',$noextract,
+ \%archiveitems,\@current);
+ }
+ }
+ }
+ return $nextphase;
+}
+
+sub get_dir_list {
+ my ($url,$coursenum,$coursedom,$newidx) = @_;
+ my ($destination,$dir_root) = &embedded_destination();
+ my ($dirlistref,$listerror) =
+ &Apache::lonnet::dirlist("$dir_root/$destination/$newidx",$coursedom,$coursenum,1);
+ my @dir_lines;
+ my $dirptr=16384;
+ if (ref($dirlistref) eq 'ARRAY') {
+ foreach my $dir_line (sort
+ {
+ my ($afile)=split('&',$a,2);
+ my ($bfile)=split('&',$b,2);
+ return (lc($afile) cmp lc($bfile));
+ } (@{$dirlistref})) {
+ my ($filename,$dom,undef,$testdir,undef,undef,undef,undef,$size,undef,$mtime,undef,undef,undef,$obs,undef)=split(/\&/,$dir_line,16);
+ $filename =~ s/\s+$//;
+ next if ($filename =~ /^\.\.?$/);
+ my $isdir = 0;
+ if ($dirptr&$testdir) {
+ $isdir = 1;
+ }
+ push(@dir_lines, [$filename,$dom,$isdir,$size,$mtime,$obs]);
+ }
+ }
+ return @dir_lines;
+}
+
+sub 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,$coursedom,
+ $crstype,$pathitem,$supplementalflag,$container,$filtersref,$currgroups,
+ $ltitoolsref,$canedit,$isencrypted,$ishidden,$navmapref,$hostname)=@_;
+ my ($foldertitle,$renametitle,$oldtitle,$encodedtitle);
+ if (&is_supplemental_title($title)) {
+ ($title,$foldertitle,$renametitle) = &Apache::loncommon::parse_supplemental_title($title);
+ $encodedtitle=$title;
+ } else {
+ $title=&HTML::Entities::encode($title,'"<>&\'');
+ $encodedtitle=$title;
+ $renametitle=$title;
+ $foldertitle=$title;
+ }
+
+ my ($disabled,$readonly,$js_lt);
+ unless ($canedit) {
+ $disabled = 'disabled="disabled"';
+ $readonly = 1;
+ }
+
+ my $orderidx=$LONCAPA::map::order[$index];
+
+ $renametitle=~s/\\/\\\\/g;
$renametitle=~s/\"\;/\\\"/g;
- my $line='';
+ $renametitle=~s/"/%22/g;
+ $renametitle=~s/ /%20/g;
+ $oldtitle = $renametitle;
+ $renametitle=~s/\'/\\\'/g;
+ my $line=&Apache::loncommon::start_data_table_row();
+ my ($form_start,$form_end,$form_common,$form_param);
# Edit commands
+ my ($esc_path, $path, $symb, $shownsymb, $curralias);
+ if ($env{'form.folderpath'}) {
+ $esc_path=&escape($env{'form.folderpath'});
+ $path = &HTML::Entities::encode($env{'form.folderpath'},'<>&"');
+ # $htmlfoldername=&HTML::Entities::encode($env{'form.foldername'},'<>&"');
+ }
+ my $isexternal;
+ if ($residx) {
+ my $currurl = $url;
+ $currurl =~ s{^http(|s)(:|:)//}{/adm/wrapper/ext/};
+ if ($currurl =~ m{^/adm/wrapper/ext/}) {
+ $isexternal = 1;
+ }
+ if (!$supplementalflag) {
+ my $path = 'uploaded/'.
+ $env{'course.'.$env{'request.course.id'}.'.domain'}.'/'.
+ $env{'course.'.$env{'request.course.id'}.'.num'}.'/';
+ $symb = &Apache::lonnet::encode_symb($path.$folder.".$container",
+ $residx,
+ &Apache::lonnet::declutter($currurl));
+ }
+ }
+ my ($renamelink,%lt,$ishash);
+ if (ref($filtersref) eq 'HASH') {
+ $ishash = 1;
+ }
+
if ($allowed) {
- $line.=(<
-
-
-
-
-
-
-
-
-Remove
-
-Rename
+ $form_start = '
+
+';
+ $form_common=(<
+
+END
+ $form_param=(<
+
+END
+ $form_end = ' ';
+
+ 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=
+ ' '.
+ '';
+ for (my $i=1;$i<=$#LONCAPA::map::order+1;$i++) {
+ if ($i==$incindex) {
+ $selectbox.='('.$i.') ';
+ } else {
+ $selectbox.=''.$i.' ';
+ }
+ }
+ $selectbox.=' ';
+ }
+ %lt=&Apache::lonlocal::texthash(
+ 'up' => 'Move Up',
+ 'dw' => 'Move Down',
+ 'rm' => 'Remove',
+ 'ct' => 'Cut',
+ 'rn' => 'Rename',
+ 'cp' => 'Copy',
+ 'da' => 'Unset alias',
+ 'sa' => 'Set alias',
+ 'ex' => 'External Resource',
+ 'et' => 'External Tool',
+ 'ed' => 'Edit',
+ 'pr' => 'Preview',
+ 'sv' => 'Save',
+ 'ul' => 'URL',
+ 'ti' => 'Title',
+ 'er' => 'Editing rights unavailable for your current role.',
+ );
+ my %denied = &action_restrictions($coursenum,$coursedom,$url,
+ $env{'form.folderpath'},
+ $currgroups);
+ my ($copylink,$cutlink,$removelink);
+ my $skip_confirm = 0;
+ my $confirm_removal = 0;
+ if ( $folder =~ /^supplemental/
+ || ($url =~ m{( /smppg$
+ |/syllabus$
+ |/aboutme$
+ |/navmaps$
+ |/bulletinboard$
+ |/ext\.tool$
+ |\.html$)}x)
+ || $isexternal) {
+ $skip_confirm = 1;
+ }
+ if (($url=~m|/+uploaded/\Q$coursedom\E/\Q$coursenum\E/|) &&
+ ($url!~/$LONCAPA::assess_page_seq_re/)) {
+ $confirm_removal = 1;
+ }
+ if ($url =~ /$LONCAPA::assess_re/) {
+ $curralias = (&LONCAPA::map::getparameter($orderidx,'parameter_0_mapalias'))[0];
+ }
+
+ if ($denied{'copy'}) {
+ $copylink=(<$lt{'cp'}
+ENDCOPY
+ } else {
+ my $formname = 'edit_copy_'.$orderidx;
+ my $js = "javascript:checkForSubmit(document.forms.renameform,'copy','actions','$orderidx','$esc_path','$index','$renametitle',$skip_confirm,'$container','$folder');";
+ $copylink=(<
+$form_common
+$lt{'cp'}
+$form_end
+ENDCOPY
+ if (($ishash) && (ref($filtersref->{'cancopy'}) eq 'ARRAY')) {
+ push(@{$filtersref->{'cancopy'}},$orderidx);
+ }
+ }
+ if ($denied{'cut'}) {
+ $cutlink=(<$lt{'ct'}
+ENDCUT
+ } else {
+ my $formname = 'edit_cut_'.$orderidx;
+ my $js = "javascript:checkForSubmit(document.forms.renameform,'cut','actions','$orderidx','$esc_path','$index','$renametitle',$skip_confirm,'$container','$folder');";
+ $cutlink=(<
+$form_common
+
+$lt{'ct'}
+$form_end
+ENDCUT
+ if (($ishash) && (ref($filtersref->{'cancut'}) eq 'ARRAY')) {
+ push(@{$filtersref->{'cancut'}},$orderidx);
+ }
+ }
+ if ($denied{'remove'}) {
+ $removelink=(<$lt{'rm'}
+ENDREM
+ } else {
+ my $formname = 'edit_remove_'.$orderidx;
+ my $js = "javascript:checkForSubmit(document.forms.renameform,'remove','actions','$orderidx','$esc_path','$index','$renametitle',$skip_confirm,'$container','$folder',$confirm_removal);";
+ $removelink=(<
+$form_common
+
+
+$lt{'rm'}
+$form_end
+ENDREM
+ if (($ishash) && (ref($filtersref->{'canremove'}) eq 'ARRAY')) {
+ push(@{$filtersref->{'canremove'}},$orderidx);
+ }
+ }
+ $renamelink=(<$lt{'rn'}
+ENDREN
+ my ($uplink,$downlink);
+ if ($canedit) {
+ $uplink = "/adm/coursedocs?cmd=up_$index&folderpath=$esc_path&symb=$symb";
+ $downlink = "/adm/coursedocs?cmd=down_$index&folderpath=$esc_path&symb=$symb";
+ } else {
+ $uplink = "javascript:alert('".&js_escape($lt{'er'})."');";
+ $downlink = $uplink;
+ }
+ $line.=(<
+
+
+
+
+
+
+
+
+
+
+
+
+ $form_start
+ $form_param
+ $form_common
+ $selectbox
+ $form_end
+
+
+$removelink
+$cutlink
+$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 $isfolder=0;
+ my $icon=&Apache::loncommon::icon($url);
+ my $isfolder;
+ my $ispage;
+ my $containerarg;
+ my $folderurl;
+ my $plainurl;
if ($uploaded) {
- if ($extension eq 'sequence') {
- $icon='folder_closed';
- $url=~/\/(\w+)\.sequence/;
- $url='/adm/coursedocs?folder='.$1;
- $isfolder=1;
+ if (($extension eq 'sequence') || ($extension eq 'page')) {
+ $url=~/\Q$coursenum\E\/([\/\w]+)\.\Q$extension\E$/;
+ $containerarg = $1;
+ if ($extension eq 'sequence') {
+ $icon=$iconpath.'navmap.folder.closed.gif';
+ $isfolder=1;
+ } else {
+ $icon=$iconpath.'page.gif';
+ $ispage=1;
+ }
+ $folderurl = &Apache::lonnet::declutter($url);
+ if ($allowed) {
+ $url='/adm/coursedocs?';
+ } else {
+ $url='/adm/supplemental?';
+ }
+ } else {
+ $plainurl = $url;
+ }
+ }
+
+ my ($editlink,$extresform,$anchor,$hiddenres,$nomodal);
+ my $orig_url = $url;
+ $orig_url=~s{http(:|:)//https(:|:)//}{https$2//};
+ if ($container eq 'page') {
+ $url=~s{^http(|s)(:|:)//}{/ext/};
+ } else {
+ $url=~s{^http(|s)(:|:)//}{/adm/wrapper/ext/};
+ }
+ if (!$supplementalflag && $residx && $symb) {
+ if ((!$isfolder) && (!$ispage)) {
+ (undef,undef,$url)=&Apache::lonnet::decode_symb($symb);
+ if (($url =~ m{^ext/}) && ($container eq 'page')) {
+ $url=&Apache::lonnet::clutter_with_no_wrapper($url);
+ } else {
+ $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{^(|/adm/wrapper)/ext/([^#]+)}) {
+ my $wrapped = $1;
+ my $exturl = $2;
+ if (($wrapped eq '') && ($container ne 'page')) {
+ $url='/adm/wrapper'.$url;
+ }
+ if (($ENV{'SERVER_PORT'} == 443) && ($exturl !~ /^https:/)) {
+ $nomodal = 1;
+ }
+ } elsif ($url=~m{^/adm/$coursedom/$coursenum/\d+/ext\.tool$}) {
+ $url='/adm/wrapper'.$url;
+ } elsif ($url eq "/public/$coursedom/$coursenum/syllabus") {
+ if (($ENV{'SERVER_PORT'} == 443) &&
+ ($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'} =~ m{^http://})) {
+ unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) {
+ $url .= '?usehttp=1';
+ }
+ $nomodal = 1;
+ }
+ }
+ my $checkencrypt;
+ if (!$env{'request.role.adv'}) {
+ if (((&LONCAPA::map::getparameter($orderidx,'parameter_encrypturl'))[0]=~/^yes$/i) ||
+ ($isencrypted) || (&Apache::lonnet::EXT('resource.0.encrypturl',$symb) =~ /^yes$/i)) {
+ $checkencrypt = 1;
+ } elsif (ref($navmapref)) {
+ unless (ref($$navmapref)) {
+ $$navmapref = Apache::lonnavmaps::navmap->new();
+ }
+ if (ref($$navmapref)) {
+ if (lc($$navmapref->get_mapparam($symb,undef,"0.encrypturl")) eq 'yes') {
+ $checkencrypt = 1;
+ }
+ }
+ }
+ }
+ if ($checkencrypt) {
+ my $currenc = $env{'request.enc'};
+ $env{'request.enc'} = 1;
+ $shownsymb = &Apache::lonenc::encrypted($symb);
+ my $shownurl = &Apache::lonenc::encrypted($url);
+ if (&Apache::lonnet::symbverify($symb,$url)) {
+ $url = $shownurl;
+ } else {
+ $url = '';
+ }
+ $env{'request.enc'} = $currenc;
+ } elsif (&Apache::lonnet::symbverify($symb,$url)) {
+ $shownsymb = $symb;
+ if ($isexternal) {
+ $url =~ s/\#[^#]+$//;
+ if ($container eq 'page') {
+ $url = &Apache::lonnet::clutter($url);
+ }
+ }
+ } else {
+ $url = '';
+ }
+ unless ($env{'request.role.adv'}) {
+ if ((&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i) {
+ $url = '';
+ }
+ if (&Apache::lonnet::EXT('resource.0.hiddenresource',$symb) =~ /^yes$/i) {
+ $url = '';
+ $hiddenres = 1;
+ }
+ }
+ if (($url ne '') && ($shownsymb ne '')) {
+ $url .= (($url=~/\?/)?'&':'?').'symb='.&escape($shownsymb);
+ }
+ }
+ } elsif ($supplementalflag) {
+ if ($isexternal) {
+ if ($url =~ /^([^#]+)#([^#]+)$/) {
+ $url = $1;
+ $anchor = $2;
+ if (($url =~ m{^(|/adm/wrapper)/ext/(?!https:)}) && ($ENV{'SERVER_PORT'} == 443)) {
+ unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) {
+ if ($hostname ne '') {
+ $url = 'http://'.$hostname.$url;
+ }
+ $url .= (($url =~ /\?/) ? '&':'?').'usehttp=1';
+ }
+ $nomodal = 1;
+ }
+ }
+ } elsif ($url =~ m{^\Q/public/$coursedom/$coursenum/syllabus\E}) {
+ if (($ENV{'SERVER_PORT'} == 443) &&
+ ($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'} =~ m{^http://})) {
+ unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) {
+ if ($hostname ne '') {
+ $url = 'http://'.$hostname.$url;
+ }
+ $url .= (($url =~ /\?/) ? '&':'?').'usehttp=1';
+ }
+ $nomodal = 1;
+ }
+ } elsif (($uploaded) && ($url ne '/adm/supplemental?') && ($url ne '/adm/coursedocs?')) {
+ my $embstyle=&Apache::loncommon::fileembstyle($extension);
+ unless ($embstyle eq 'ssi') {
+ if (($embstyle eq 'img')
+ || ($embstyle eq 'emb')
+ || ($embstyle eq 'wrp')) {
+ $url='/adm/wrapper'.$url;
+ } elsif ($url !~ /\.(sequence|page)$/) {
+ $url='/adm/coursedocs/showdoc'.$url;
+ }
+ }
+ }
+ unless ($allowed && $env{'request.role.adv'}) {
+ if ($ishidden || (&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i) {
+ $hiddenres = 1;
+ }
+ }
+ }
+ my ($rand_pick_text,$rand_order_text,$hiddenfolder);
+ my $filterFunc = sub { my $res = shift; return (!$res->randomout() && !$res->is_map()) };
+ if ($isfolder || $ispage || $extension eq 'sequence' || $extension eq 'page') {
+ my $foldername=&escape($foldertitle);
+ my $folderpath=$env{'form.folderpath'};
+ if ($folderpath) { $folderpath.='&' };
+ if (!$allowed && $supplementalflag) {
+ $folderpath.=$containerarg.'&'.$foldername;
+ $url.='folderpath='.&escape($folderpath);
+ if ($ishidden || (&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i) {
+ $hiddenfolder = 1;
+ }
+ } else {
+ my $rpicknum = (&LONCAPA::map::getparameter($orderidx,
+ 'parameter_randompick'))[0];
+ my $randorder = ((&LONCAPA::map::getparameter($orderidx,
+ 'parameter_randomorder'))[0]=~/^yes$/i);
+ my $hiddenmap = ((&LONCAPA::map::getparameter($orderidx,
+ 'parameter_hiddenresource'))[0]=~/^yes$/i);
+ my $encryptmap = ((&LONCAPA::map::getparameter($orderidx,
+ 'parameter_encrypturl'))[0]=~/^yes$/i);
+ unless ($hiddenmap) {
+ if (ref($navmapref)) {
+ unless (ref($$navmapref)) {
+ $$navmapref = Apache::lonnavmaps::navmap->new();
+ }
+ if (ref($$navmapref)) {
+ if (lc($$navmapref->get_mapparam(undef,$folderurl,"0.hiddenresource")) eq 'yes') {
+ my @resources = $$navmapref->retrieveResources($folderurl,$filterFunc,1,1);
+ unless (@resources) {
+ $hiddenmap = 1;
+ unless ($env{'request.role.adv'}) {
+ $url = '';
+ $hiddenfolder = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ unless ($encryptmap) {
+ if ((ref($navmapref)) && (ref($$navmapref))) {
+ if (lc($$navmapref->get_mapparam(undef,$folderurl,"0.encrypturl")) eq 'yes') {
+ $encryptmap = 1;
+ }
+ }
+ }
+
+# Append randompick number, hidden, and encrypted with ":" to foldername,
+# so it gets transferred between levels
+ $folderpath.=$containerarg.'&'.$foldername.
+ ':'.$rpicknum.':'.$hiddenmap.':'.$encryptmap.':'.$randorder.':'.$ispage;
+ unless ($url eq '') {
+ $url.='folderpath='.&escape($folderpath);
+ }
+ my $rpckchk;
+ if ($rpicknum) {
+ $rpckchk = ' checked="checked"';
+ if (($ishash) && (ref($filtersref->{'randompick'}) eq 'ARRAY')) {
+ push(@{$filtersref->{'randompick'}},$orderidx.':'.$rpicknum);
+ }
+ }
+ my $formname = 'edit_randompick_'.$orderidx;
+ $rand_pick_text =
+''."\n".
+$form_param."\n".
+$form_common."\n".
+' '.&mt('Randomly Pick').'';
+ if ($rpicknum ne '') {
+ $rand_pick_text .= ': '.$rpicknum.' ';
+ }
+ $rand_pick_text .= ' '.
+ $form_end;
+ my $ro_set;
+ if ($randorder) {
+ $ro_set = 'checked="checked"';
+ if (($ishash) && (ref($filtersref->{'randomorder'}) eq 'ARRAY')) {
+ push(@{$filtersref->{'randomorder'}},$orderidx);
+ }
+ }
+ $formname = 'edit_rorder_'.$orderidx;
+ $rand_order_text =
+' '."\n".
+$form_param."\n".
+$form_common."\n".
+' '.&mt('Random Order').' '.
+$form_end;
+ }
+ } elsif ($supplementalflag) {
+ my $isexttool;
+ if ($url=~m{^/adm/$coursedom/$coursenum/\d+/ext\.tool$}) {
+ $url='/adm/wrapper'.$url;
+ $isexttool = 1;
+ }
+ $url .= ($url =~ /\?/) ? '&':'?';
+ $url .= 'folderpath='.&HTML::Entities::encode($esc_path,'<>&"');
+ if ($title) {
+ $url .= '&title='.$encodedtitle;
+ }
+ if ((($isexternal) || ($isexttool)) && $orderidx) {
+ $url .= '&idx='.$orderidx;
+ }
+ if ($anchor ne '') {
+ $url .= '&anchor='.&HTML::Entities::encode($anchor,'"<>&');
+ }
+ }
+ my ($tdalign,$tdwidth);
+ if ($allowed) {
+ my $fileloc =
+ &Apache::lonnet::declutter(&Apache::lonnet::filelocation('',$orig_url));
+ if ($isexternal) {
+ ($editlink,$extresform) =
+ &Apache::lonextresedit::extedit_form(0,$residx,$orig_url,$title,$pathitem,
+ undef,undef,undef,undef,undef,undef,
+ undef,$disabled);
+ } elsif ($orig_url =~ m{^/adm/$coursedom/$coursenum/\d+/ext\.tool$}) {
+ ($editlink,$extresform) =
+ &Apache::lonextresedit::extedit_form(0,$residx,$orig_url,$title,$pathitem,
+ undef,undef,undef,'tool',$coursedom,
+ $coursenum,$ltitoolsref,$disabled);
+ } elsif (!$isfolder && !$ispage) {
+ my ($cfile,$home,$switchserver,$forceedit,$forceview) =
+ &Apache::lonnet::can_edit_resource($fileloc,$coursenum,$coursedom,$orig_url);
+ if (($cfile ne '') && ($symb ne '' || $supplementalflag)) {
+ my $suppanchor;
+ if ($supplementalflag) {
+ $suppanchor = $anchor;
+ }
+ my $jscall =
+ &Apache::lonhtmlcommon::jump_to_editres($cfile,$home,
+ $switchserver,
+ $forceedit,
+ undef,$symb,$shownsymb,
+ &escape($env{'form.folderpath'}),
+ $renametitle,$hostname,
+ '','',1,$suppanchor);
+ if ($jscall) {
+ $editlink = ''.&mt('Edit').' '."\n";
+ }
+ }
+ }
+ $tdalign = ' align="right" valign="top"';
+ $tdwidth = ' width="80%"';
+ }
+ my $reinit;
+ if ($crstype eq 'Community') {
+ $reinit = &mt('(re-initialize community to access)');
+ } else {
+ $reinit = &mt('(re-initialize course to access)');
+ }
+ $line.=''.$editlink.$renamelink.' ';
+ if ($orig_url =~ /$LONCAPA::assess_re/) {
+ $line.= ' ';
+ if ($curralias ne '') {
+ $line.=''.
+ $lt{'da'}.' ';
+ } else {
+ $line.=''.
+ $lt{'sa'}.' ';
+ }
+ }
+ $line.='';
+ my ($link,$nolink);
+ if (($url=~m{/adm/(coursedocs|supplemental)}) || (!$allowed && $url)) {
+ if ($allowed && !$env{'request.role.adv'} && !$isfolder && !$ispage) {
+ if ((&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i) {
+ $nolink = 1;
+ }
+ }
+ if ($nolink) {
+ $line .= ' ';
+ } else {
+ $line.=' ';
+ }
+ } elsif ($url) {
+ if ($anchor ne '') {
+ if ($supplementalflag) {
+ $anchor = '&anchor='.&HTML::Entities::encode($anchor,'"<>&');
+ } else {
+ $anchor = '#'.&HTML::Entities::encode($anchor,'"<>&');
+ }
+ }
+ if (($nomodal) && ($hostname ne '')) {
+ $link = 'http://'.$hostname.$url;
} else {
- $url=&Apache::lonnet::tokenwrapper($url);
- }
+ $link = $url;
+ }
+ my $inhibitmenu;
+ if ((($supplementalflag) && ($allowed) && ($url =~ m{^/adm/wrapper/})) ||
+ (($allowed) && (($url =~ m{^/adm/(viewclasslist|$match_domain/$match_username/aboutme)(\?|$)}) ||
+ ($url =~ m{^/public/$match_domain/$match_courseid/syllabus(\?|$)})))) {
+ $inhibitmenu = 'only_body=1';
+ } else {
+ $inhibitmenu = 'inhibitmenu=yes';
+ }
+ $link = &js_escape($link.(($url=~/\?/)?'&':'?').$inhibitmenu.$anchor);
+ if ($allowed && !$env{'request.role.adv'} && !$isfolder && !$ispage && !$uploaded) {
+ if ((&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i) {
+ $nolink = 1;
+ }
+ }
+ if ($nolink) {
+ $line.=' ';
+ } elsif ($nomodal) {
+ $line.=' '.
+ ' ';
+ } else {
+ $line.=&Apache::loncommon::modal_link($link,
+ ' ',600,500);
+ }
+ } else {
+ $line.=' ';
+ }
+ $line.=' ';
+ if (($url=~m{/adm/(coursedocs|supplemental)}) || (!$allowed && $url)) {
+ if ($nolink) {
+ $line.=$title;
+ } else {
+ $line.=''.$title.' ';
+ }
+ if (!$allowed && $supplementalflag && $canedit && $isfolder) {
+ my $editicon = &Apache::loncommon::lonhttpdurl('/res/adm/pages').'/editmap.png';
+ my $editurl = $url;
+ $editurl =~ s{^\Q/adm/supplemental?\E}{/adm/coursedocs?command=direct&forcesupplement=1&};
+ $line .= ' '.''.
+ ' '.
+ ' ';
+ }
+ if ((($hiddenfolder) || ($hiddenres)) && (!$allowed) && ($supplementalflag)) {
+ $line.= ' ('.&mt('hidden').') ';
+ }
+ } elsif ($url) {
+ if ($nolink) {
+ $line.=$title;
+ } elsif ($nomodal) {
+ $line.=' '.
+ $title.'';
+ } else {
+ $line.=&Apache::loncommon::modal_link($link,$title,600,500);
+ }
+ } elsif (($hiddenfolder) || ($hiddenres)) {
+ $line.=$title.' ('.&mt('Hidden').') ';
+ } else {
+ $line.=$title.' '.$reinit.' ';
+ }
+ if (($allowed) && ($curralias ne '')) {
+ $line .= '('.$curralias.') ';
+ } else {
+ $line .= $extresform;
}
- $url=~s/^http\&colon\;\/\//\/adm\/wrapper\/ext\//;
- if (($residx) && ($folder!~/supplemental/)) {
- $url.=(($url=~/\?/)?'&':'?').'symb='.
- &Apache::lonnet::escape(&Apache::lonnet::symbclean(
- &Apache::lonnet::declutter('uploaded/'.
- $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}.'/'.
- $ENV{'course.'.$ENV{'request.course.id'}.'.num'}.'/'.$folder.
- '.sequence').
- '___'.$residx.'___'.
- &Apache::lonnet::declutter($url)));
- }
- if ($isfolder) { $url.='&foldername='.
- &Apache::lonnet::escape($foldertitle); }
- $line.=' '.
- "$title ";
+ $line .= '';
+ $rand_pick_text = ' ' if ($rand_pick_text eq '');
+ $rand_order_text = ' ' if ($rand_order_text eq '');
+ if ($uploaded && $url && !$isfolder && !$ispage) {
+ if (($plainurl ne '') && ($env{'request.role.adv'} || $allowed || !$hiddenres)) {
+ &Apache::lonnet::allowuploaded('/adm/coursedoc',$plainurl);
+ }
+ }
+ if ($allowed) {
+ my %lt=&Apache::lonlocal::texthash(
+ 'hd' => 'Hidden',
+ 'ec' => 'URL hidden');
+ my ($enctext,$hidtext,$formhidden,$formurlhidden);
+ if ((&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i) {
+ $hidtext = ' checked="checked"';
+ if (($ishash) && (ref($filtersref->{'hiddenresource'}) eq 'ARRAY')) {
+ push(@{$filtersref->{'hiddenresource'}},$orderidx);
+ }
+ }
+ $formhidden = 'edit_hiddenresource_'.$orderidx;
+ $line.=(<
+
+ $form_param
+ $form_common
+ $lt{'hd'}
+ $form_end
+ENDPARMS
+ if ($folder =~/^supplemental/) {
+ $line.= "\n ";
+ } else {
+ if ((&LONCAPA::map::getparameter($orderidx,'parameter_encrypturl'))[0]=~/^yes$/i) {
+ $enctext = ' checked="checked"';
+ if (($ishash) && (ref($filtersref->{'encrypturl'}) eq 'ARRAY')) {
+ push(@{$filtersref->{'encrypturl'}},$orderidx);
+ }
+ }
+ $formurlhidden = 'edit_encrypturl_'.$orderidx;
+ $line.=(<
+
+ $form_param
+ $form_common
+ $lt{'ec'}
+ $form_end
+
+ $rand_pick_text
+ $rand_order_text
+ENDPARMS
+ }
+ }
+ $line.=&Apache::loncommon::end_data_table_row();
return $line;
}
-# ---------------------------------------------------------------- tie the hash
+sub action_restrictions {
+ my ($cnum,$cdom,$url,$folderpath,$currgroups) = @_;
+ my %denied = (
+ cut => 0,
+ copy => 0,
+ remove => 0,
+ );
+ if ($url=~ m{^/res/.+\.(page|sequence)$}) {
+ # no copy for published maps
+ $denied{'copy'} = 1;
+ } elsif ($url=~m{^/res/lib/templates/([^/]+)\.problem$}) {
+ unless ($1 eq 'simpleproblem') {
+ $denied{'copy'} = 1;
+ }
+ $denied{'cut'} = 1;
+ } elsif ($url eq "/uploaded/$cdom/$cnum/group_allfolders.sequence") {
+ if ($folderpath =~ /^default&[^\&]+$/) {
+ if ((ref($currgroups) eq 'HASH') && (keys(%{$currgroups}) > 0)) {
+ $denied{'remove'} = 1;
+ }
+ $denied{'cut'} = 1;
+ $denied{'copy'} = 1;
+ }
+ } elsif ($url =~ m{^\Q/uploaded/$cdom/$cnum/group_folder_\E(\w+)\.sequence$}) {
+ my $group = $1;
+ if ($folderpath =~ /^default&[^\&]+\&group_allfolders\&[^\&]+$/) {
+ if ((ref($currgroups) eq 'HASH') && (exists($currgroups->{$group}))) {
+ $denied{'remove'} = 1;
+ }
+ }
+ $denied{'cut'} = 1;
+ $denied{'copy'} = 1;
+ } elsif ($url =~ m{^\Q/adm/$cdom/$cnum/\E(\w+)/smppg$}) {
+ my $group = $1;
+ if ($folderpath =~ /^default&[^\&]+\&group_allfolders\&[^\&]+\&\Qgroup_folder_$group\E\&[^\&]+$/) {
+ if ((ref($currgroups) eq 'HASH') && (exists($currgroups->{$group}))) {
+ my %groupsettings = &Apache::longroup::get_group_settings($currgroups->{$group});
+ if (keys(%groupsettings) > 0) {
+ $denied{'remove'} = 1;
+ }
+ $denied{'cut'} = 1;
+ $denied{'copy'} = 1;
+ }
+ }
+ } elsif ($folderpath =~ /^default&[^\&]+\&group_allfolders\&[^\&]+\&group_folder_(\w+)\&/) {
+ my $group = $1;
+ if ($url =~ /group_boards_\Q$group\E/) {
+ if ((ref($currgroups) eq 'HASH') && (exists($currgroups->{$group}))) {
+ my %groupsettings = &Apache::longroup::get_group_settings($currgroups->{$group});
+ if (keys(%groupsettings) > 0) {
+ if (ref($groupsettings{'functions'}) eq 'HASH') {
+ if ($groupsettings{'functions'}{'discussion'} eq 'on') {
+ $denied{'remove'} = 1;
+ }
+ }
+ }
+ $denied{'cut'} = 1;
+ $denied{'copy'} = 1;
+ }
+ }
+ }
+ return %denied;
+}
+
+sub new_timebased_suffix {
+ my ($dom,$num,$type,$area,$container) = @_;
+ my ($prefix,$namespace,$idtype,$errtext,$locknotfreed);
+ if ($type eq 'paste') {
+ $prefix = $type;
+ $namespace = 'courseeditor';
+ $idtype = 'addcode';
+ } elsif ($type eq 'map') {
+ $prefix = 'docs';
+ if ($area eq 'supplemental') {
+ $prefix = 'supp';
+ }
+ $prefix .= $container;
+ $namespace = 'uploadedmaps';
+ } else {
+ $prefix = $type;
+ $namespace = 'templated';
+ }
+ my ($suffix,$freedlock,$error) =
+ &Apache::lonnet::get_timebased_id($prefix,'num',$namespace,$dom,$num,$idtype);
+ if (!$suffix) {
+ if ($type eq 'paste') {
+ $errtext = &mt('Failed to acquire a unique timestamp-based suffix when adding to the paste buffer.');
+ } elsif ($type eq 'map') {
+ $errtext = &mt('Failed to acquire a unique timestamp-based suffix for the new folder/page.');
+ } elsif ($type eq 'smppg') {
+ $errtext = &mt('Failed to acquire a unique timestamp-based suffix for the new simple page.');
+ } elsif ($type eq 'exttool') {
+ $errtext = &mt('Failed to acquire a unique timestamp-based suffix for the new external tool.');
+ } else {
+ $errtext = &mt('Failed to acquire a unique timestamp-based suffix for the new discussion board.');
+ }
+ if ($error) {
+ $errtext .= ' '.$error;
+ }
+ }
+ if ($freedlock ne 'ok') {
+ $locknotfreed =
+ ''.
+ &mt('There was a problem removing a lockfile.').' ';
+ if ($type eq 'paste') {
+ if ($freedlock eq 'nolock') {
+ $locknotfreed =
+ '
'.
+ &mt('A lockfile was not released when you added content to the clipboard earlier in this session.').' '.
+
+ &mt('As a result addition of items to the clipboard will be unavailable until your next log-in.');
+ } else {
+ $locknotfreed .=
+ &mt('This will prevent addition of items to the clipboard until your next log-in.');
+ }
+ } elsif ($type eq 'map') {
+ $locknotfreed .=
+ &mt('This will prevent creation of additional folders or composite pages in this course.');
+ } elsif ($type eq 'smppg') {
+ $locknotfreed .=
+ &mt('This will prevent creation of additional simple pages in this course.');
+ } elsif ($type eq 'exttool') {
+ $locknotfreed .=
+ &mt('This will prevent creation of additional external tools in this course.');
+ } else {
+ $locknotfreed .=
+ &mt('This will prevent creation of additional discussion boards in this course.');
+ }
+ unless ($type eq 'paste') {
+ $locknotfreed .=
+ ' '.&mt('Please contact the [_1]helpdesk[_2] for assistance.',
+ '
',' ');
+ }
+ $locknotfreed .= '
';
+ }
+ return ($suffix,$errtext,$locknotfreed);
+}
+
+=pod
+
+=item tiehash()
+
+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)=@_;
+ my ($r,$url,$level,$title,$checkstale)=@_;
+ $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(' ');
}
$r->print('
'.
($title?$title:$url).' ');
if ($url=~/^\/res\//) {
+ my $updated;
+ if (($checkstale) && ($url !~ m{^/res/lib/templates/}) &&
+ ($url !~ /\.\d+\.\w+$/)) {
+ $updated = &Apache::lonnet::remove_stale_resfile($url);
+ }
my $result=&Apache::lonnet::repcopy(
&Apache::lonnet::filelocation('',$url));
- if ($result==OK) {
- $r->print('
ok ');
+ if ($result eq 'ok') {
+ $r->print('
'.&mt('ok').' ');
+ if ($updated) {
+ $r->print('
');
+ for (my $i=0;$i<=$level*5;$i++) {
+ $r->print(' ');
+ }
+ $r->print('- '.&mt('Outdated copy removed'));
+ }
$r->rflush();
&Apache::lonnet::countacc($url);
$url=~/\.(\w+)$/;
@@ -445,182 +6257,632 @@ 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,'',$checkstale);
}
}
- } 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').' ');
}
- }
- }
+ if (($updated) && ($result ne 'ok')) {
+ $r->print('
'.&mt('Outdated copy removed'));
+ }
+ }
+ }
}
-#
-# -------------------------------------------------------------- Verify Content
-#
-sub verifycontent {
- my $r=shift;
- my $loaderror=&Apache::lonnet::overloaderror($r);
- if ($loaderror) { return $loaderror; }
- $r->print('
Verify Content '.
- &Apache::loncommon::bodytag('Verify Course Documents'));
+=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::end_data_table_row());
+ $count ++;
+ }
+ if (!$count) {
+ $r->print(&Apache::loncommon::start_data_table_row().
+ '
'.&mt("$crstype is empty").' '.
+ &Apache::loncommon::end_data_table_row());
+ }
+ $r->print(&Apache::loncommon::end_data_table());
+ }
+ $r->print(&endContentScreen());
+}
+
+sub short_urls {
+ my ($r,$canedit) = @_;
+ my $crstype = &Apache::loncommon::course_type();
+ my $formname = 'shortenurl';
+ $r->print(&Apache::loncommon::start_page('Display/Set Shortened URLs'));
+ $r->print(&Apache::lonhtmlcommon::breadcrumbs('Shortened URLs'));
+ $r->print(&startContentScreen('tools'));
+ my ($navmap,$errormsg) =
+ &Apache::loncourserespicker::get_navmap_object($crstype,'shorturls');
+ my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+ my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+ my (%maps,%resources,%titles);
+ if (!ref($navmap)) {
+ $r->print($errormsg.
+ &endContentScreen());
+ return '';
+ } else {
+ $r->print('
'.&mt('Tiny URLs for deep-linking into course').' '."\n");
+ $r->rflush();
+ my $readonly;
+ if ($canedit) {
+ my ($numnew,$errors) = &Apache::loncommon::get_requested_shorturls($cdom,$cnum,$navmap);
+ if ($numnew) {
+ $r->print('
'.&mt('Created [quant,_1,URL]',$numnew).'
');
+ }
+ if ((ref($errors) eq 'ARRAY') && (@{$errors} > 0)) {
+ $r->print(&mt('The following errors occurred when processing your request to create shortened URLs:').'
');
+ foreach my $error (@{$errors}) {
+ $r->print(''.$error.' ');
+ }
+ $r->print(' ');
+ }
+ } else {
+ $readonly = 1;
+ }
+ my %currtiny = &Apache::lonnet::dump('tiny',$cdom,$cnum);
+ $r->print(&Apache::loncourserespicker::create_picker($navmap,'shorturls',$formname,$crstype,undef,
+ undef,undef,undef,undef,undef,\%currtiny,undef,$readonly));
+ }
+ $r->print(&endContentScreen());
+}
+
+sub contentverifyform {
+ my ($r) = @_;
+ my $crstype = &Apache::loncommon::course_type();
+ $r->print(&Apache::loncommon::start_page('Verify '.$crstype.' Content'));
+ $r->print(&Apache::lonhtmlcommon::breadcrumbs('Verify '.$crstype.' Content'));
+ $r->print(&startContentScreen('tools'));
+ $r->print('
'.&mt($crstype.' content verification').' ');
+ $r->print('
'.
+ &mt('Include a check if files copied from elsewhere are up to date (will increase verification time)?').
+ ' '.
+ ' '.
+ &mt('No').' '.(' 'x2).
+ ' '.
+ &mt('Yes').'
'.
+ ' '.
+ ' '.
+ '
');
+ $r->print(&endContentScreen());
+ return;
+}
+
+sub verifycontent {
+ my ($r,$checkstale) = @_;
+ my $crstype = &Apache::loncommon::course_type();
+ $r->print(&Apache::loncommon::start_page('Verify '.$crstype.' Content'));
+ $r->print(&Apache::lonhtmlcommon::breadcrumbs('Verify '.$crstype.' Content'));
+ $r->print(&startContentScreen('tools'));
+ $r->print('
'.&mt($crstype.' content verification').' ');
$hashtied=0;
undef %alreadyseen;
%alreadyseen=();
&tiehash();
- foreach (keys %hash) {
- if (($_=~/^src\_(.+)$/) && (!$alreadyseen{$hash{$_}})) {
- &checkonthis($r,$hash{$_},0,$hash{'title_'.$1});
+
+ foreach my $key (keys(%hash)) {
+ if ($hash{$key}=~/\.(page|sequence)$/) {
+ if (($key=~/^src_/) && ($alreadyseen{&unescape($hash{$key})})) {
+ $r->print('
'.
+ &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},$checkstale);
}
}
&untiehash();
- $r->print('
Done. ');
+ $r->print('
'.&mt('Done').'
');
+ $r->print(&endContentScreen());
}
-# -------------------------------------------------------------- Check Versions
+sub devalidateversioncache {
+ my $src=shift;
+ &Apache::lonnet::devalidate_cache_new('courseresversion',$env{'request.course.id'}.'_'.
+ &Apache::lonnet::clutter($src));
+}
sub checkversions {
- my $r=shift;
- $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';
- }
+ my ($r,$canedit) = @_;
+ my $crstype = &Apache::loncommon::course_type();
+ $r->print(&Apache::loncommon::start_page("Check $crstype Resource Versions"));
+ $r->print(&Apache::lonhtmlcommon::breadcrumbs("Check $crstype Resource Versions"));
+ $r->print(&startContentScreen('tools'));
+
+ my $header='';
+ my $startsel='';
+ 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'});
- $r->print(<
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 content 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');
+ my ($disabled,$readonly);
+ unless ($canedit) {
+ $disabled = 'disabled="disabled"';
+ $readonly = 1;
+ }
+ $r->print(<$header
+
+
+
+$lt{'cd'}
-Since Start of Course
-Last Month
-Last Week
-Since Yesterday
+$lt{'al'}
+$lt{'st'}
+$lt{'lm'}
+$lt{'lw'}
+$lt{'sy'}
-
-
-Content changed $seltext
-
-
-File Modification Date
-Version Differences
+
+
+
+
+
+$lt{'act'}
+$lt{'sm'}:
+$lt{'sc'}:
+
+
+
+
+$lt{'vers'}
ENDHEADERS
- foreach (keys %changes) {
- if ($changes{$_}>$starttime) {
- my ($root,$extension)=($_=~/^(.*)\.(\w+)$/);
- my $currentversion=&Apache::lonnet::getversion($_);
- my $linkurl=&Apache::lonnet::clutter($_);
- $r->print(
- ''.$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;
- }
- }
+ #number of columns for version history
+ my %changedbytime;
+ foreach my $key (keys(%changes)) {
+ #excludes not versionable problems from resource version history:
+ next if ($key =~ /^\/res\/lib\/templates/);
+ my $chg;
+ if ($env{'form.timerange'} eq 'all') {
+ my ($root,$extension)=($key=~/^(.*)\.(\w+)$/);
+ $chg = &Apache::lonnet::metadata($root.'.'.$extension,'lastrevisiondate');
+ } else {
+ $chg = $changes{$key};
+ next if ($chg < $starttime);
+ }
+ push(@{$changedbytime{$chg}},$key);
+ }
+ if (keys(%changedbytime) == 0) {
+ &untiehash();
+ $r->print(&mt('No content changes in imported content in specified time frame').
+ &endContentScreen());
+ return;
+ }
+ $r->print(
+ ' '.
+ &Apache::loncommon::start_data_table().
+ &Apache::loncommon::start_data_table_header_row().
+ ' '.&mt('Resources').' '.
+ "$lt{'mr'} ".
+ "$lt{'ve'} ".
+ "$lt{'vu'} ".
+ ''.&mt('History').' '.
+ &Apache::loncommon::end_data_table_header_row()
+ );
+ foreach my $chg (sort {$b <=> $a } keys(%changedbytime)) {
+ foreach my $key (sort(@{$changedbytime{$chg}})) {
+ my ($root,$extension)=($key=~/^(.*)\.(\w+)$/);
+ my $currentversion=&Apache::lonnet::getversion($key);
+ if ($currentversion<0) {
+ $currentversion=''.&mt('Could not be determined.').' ';
+ }
+ my $linkurl=&Apache::lonnet::clutter($key);
+ $r->print(
+ &Apache::loncommon::start_data_table_row().
+ ''.&Apache::lonnet::gettitle($linkurl).' '.
+ ''.$linkurl.' '.
+ ''.$currentversion.' ('.
+ &Apache::lonlocal::locallocaltime($chg).') '.
+ ''
+ );
+ # Used in course
+ my $usedversion=$hash{'version_'.$linkurl};
+ if (($usedversion) && ($usedversion ne 'mostrecent')) {
+ if ($usedversion != $currentversion) {
+ $r->print(''.$usedversion.' ');
+ } else {
+ $r->print($usedversion);
+ }
+ } else {
+ $r->print($currentversion);
+ }
+ $r->print(' ');
+ # Set version
+ $r->print(&Apache::loncommon::select_form(
+ $setversions{$linkurl},
+ 'set_version_'.$linkurl,
+ {'select_form_order' => ['',1..$currentversion,'mostrecent'],
+ '' => '',
+ 'mostrecent' => &mt('most recent'),
+ map {$_,$_} (1..$currentversion)},'',$readonly));
+ my $lastold=1;
+ for (my $prevvers=1;$prevvers<$currentversion;$prevvers++) {
+ my $url=$root.'.'.$prevvers.'.'.$extension;
+ if (&Apache::lonnet::metadata($url,'lastrevisiondate')<$starttime) {
+ $lastold=$prevvers;
+ }
+ }
+ $r->print(' ');
+ # List all available versions
+ $r->print('');
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(' ');
- }
- }
- $r->print('
');
- $r->print('Done. ');
- } else {
- $r->print('No content modifications yet.
');
+ my $url=$root.'.'.$prevvers.'.'.$extension;
+ $r->print(
+ ''
+ .''
+ .&mt('Version [_1]',$prevvers).' '
+ .' ('.&Apache::lonlocal::locallocaltime(
+ &Apache::lonnet::metadata($url,'lastrevisiondate'))
+ .')');
+ if (&Apache::loncommon::fileembstyle($extension) eq 'ssi') {
+ $r->print(
+ ' &').
+ '" target="diffs">'.&mt('Diffs').' ');
+ }
+ $r->print(' ');
+ }
+ $r->print(''.&Apache::loncommon::end_data_table_row());
+ }
+ }
+ $r->print(
+ &Apache::loncommon::end_data_table().
+ ' '.
+ ''
+ );
+
+ &untiehash();
+ $r->print(&endContentScreen());
+ return;
+}
+
+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.';
+ }
+ my $windowname = 'loncapaclient';
+ if ($env{'request.lti.login'}) {
+ $windowname .= 'lti';
+ }
+ $r->print("\n\n".
+''."\n".
+''.
+''.
+&mt($message,' ').
+$help{'Caching'}.'
'."\n\n");
+}
+
+
+sub init_breadcrumbs {
+ my ($form,$text,$help)=@_;
+ &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 => $help});
+ &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 => ''});
+ }
}
- &untiehash();
+ 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 = '';
+ if (($mode eq 'navmaps') || ($mode eq 'supplemental')) {
+ $output .= ' '.&mt('Content Overview').' '."\n";
+ $output .= ' '.&mt('Content Search').' '."\n";
+ $output .= ' '.&mt('Content Index').' '."\n";
+ $output .= ''.&mt('Supplemental Content').' ';
+ } else {
+ $output .= ' '.&mt('Main Content Editor').' '."\n";
+ $output .= ''.&mt('Supplemental Content Editor').' '."\n";
+ $output .= ' '.&mt('Content Utilities').' '."\n";
+ '> '.&mt('Content Utilities').' ';
+ }
+ $output .= "\n".' '."\n";
+ $output .= ''.
+ '
'.
+ '
';
+ return $output;
+}
+
+#
+# End tabs
+#
+
+sub endContentScreen {
+ return '
';
+}
+
+sub supplemental_base {
+ return 'supplemental&'.&escape(&mt('Supplemental 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'};
+ my $coursehome=$env{'course.'.$env{'request.course.id'}.'.home'};
+
+# get docroot
+ my $londocroot = $r->dir_config('lonDocRoot');
+
+# 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', 'Load_Map',
- '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','Adding_External_Tool',
+ 'Navigate_Content','Adding_Folders','Docs_Overview',
+ 'Load_Map','Supplemental','Score_Upload_Form',
+ 'Adding_Pages','Importing_LON-CAPA_Resource',
+ 'Importing_IMS_Course','Uploading_From_Harddrive',
+ 'Course_Roster','Web_Page','Dropbox','Simple_Problem',
+ 'Standard_Problem','Course_Resources',
+ 'Search_LON-CAPA_Resource','Import_Stored_Links') {
+ $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');
@@ -628,457 +6890,4003 @@ sub handler {
'Docs_About_Simple_Page,Docs_Editing_Templated_Pages');
$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'}) {
- &verifycontent($r);
- } elsif ($ENV{'form.versions'}) {
- &checkversions($r);
- } elsif ($ENV{'form.dumpcourse'}) {
+ my ($allowed,$canedit,$canview,$noendpage,$disabled);
+# does this user have privileges to modify content.
+ if (&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) {
+# URI is /adm/supplemental when viewing supplemental docs in non-edit mode.
+ unless ($r->uri eq '/adm/supplemental') {
+ $allowed = 1;
+ }
+ $canedit = 1;
+ $canview = 1;
+ } elsif (&Apache::lonnet::allowed('cev',$env{'request.course.id'})) {
+# URI is /adm/supplemental when viewing supplemental docs in non-edit mode.
+ unless ($r->uri eq '/adm/supplemental') {
+ $allowed = 1;
+ }
+ $canview = 1;
+ }
+ unless ($canedit) {
+ $disabled = ' disabled="disabled"';
+ }
+ &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['inhibitmenu']);
+ if ($env{'form.inhibitmenu'}) {
+ unless ($env{'form.inhibitmenu'} eq 'yes') {
+ delete($env{'form.inhibitmenu'});
+ }
+ }
+
+ if ($allowed && $env{'form.verify'}) {
+ &init_breadcrumbs('verify','Verify Content','Docs_Verify_Content');
+ if (!$canedit) {
+ &verifycontent($r);
+ } elsif (($env{'form.checkstale'} ne '') && ($env{'form.checkstale'} =~ /^\d$/)) {
+ &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/coursedocs?tools=1&verify=1&checkstale=$env{'form.checkstale'}",
+ text=>'Results',
+ faq=>273,
+ bug=>'Instructor Interface'});
+ &verifycontent($r,$env{'form.checkstale'});
+ } else {
+ &contentverifyform($r);
+ }
+ } elsif ($allowed && $env{'form.listsymbs'}) {
+ &init_breadcrumbs('listsymbs','List Content IDs');
+ &list_symbs($r);
+ } elsif ($allowed && $env{'form.shorturls'}) {
+ &init_breadcrumbs('shorturls','Set/Display Shortened URLs','Docs_Short_URLs');
+ &short_urls($r,$canedit);
+ } 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,$canedit);
+ } elsif ($allowed && $env{'form.versions'}) {
+ &init_breadcrumbs('versions','Check/Set Resource Versions','Docs_Check_Resource_Versions');
+ &checkversions($r,$canedit);
+ } elsif ($canedit && $env{'form.dumpcourse'}) {
+ &init_breadcrumbs('dumpcourse','Copy uploaded content to Authoring Space');
&dumpcourse($r);
+ } elsif (($canedit || $canview) && ($env{'form.copyauthored'})) {
+ &init_breadcrumbs('copyauthored','Copy from Course Authoring to User Authoring');
+ my $readonly;
+ if (!$canedit) {
+ $readonly = 1;
+ }
+ ©crsauthored($r,$coursenum,$coursedom,$coursehome,$readonly);
+ } elsif ($canedit && $env{'form.exportcourse'}) {
+ &init_breadcrumbs('exportcourse','IMS Export');
+ &Apache::imsexport::exportcourse($r);
} else {
-# is this a standard course?
+ if ($canedit && $env{'form.authorrole'}) {
+ $noendpage = 1;
+ my ($redirect,$error) = &makenewproblem($r,$coursedom,$coursenum);
+ if ($redirect) {
+ if (($env{'form.newresourceadd'}) && ($env{'form.folderpath'})) {
+ my $container = 'sequence';
+ my ($breadcrumbtrail,$randompick,$ishidden,$isencrypted,$plain,
+ $is_random_order,$container) =
+ &Apache::lonhtmlcommon::docs_breadcrumbs($allowed,$crstype,1);
+ my (@folders)=split('&',$env{'form.folderpath'});
+ $env{'form.foldername'}=&unescape(pop(@folders));
+ my $folder=pop(@folders);
+ my ($errtext,$fatal) = &mapread($coursenum,$coursedom,
+ $folder.'.'.$container);
+ my $warning;
+ if ($fatal) {
+ if ($container eq 'page') {
+ $warning = &mt('An error occurred retrieving the contents of the current page.');
+ } else {
+ $warning = &mt('An error occurred retrieving the contents of the current folder.');
+ }
+ } else {
+ my $url = $redirect;
+ my $srcfile = $londocroot.$url;
+ $url =~ s{^/priv/}{/res/};
+ my $targetfile = $londocroot.$url;
+ my $nokeyref = &Apache::lonpublisher::getnokey($r->dir_config('lonIncludes'));
+ my $output = &Apache::lonpublisher::batchpublish($r,$srcfile,$targetfile,$nokeyref,1);
+ $env{'form.folder'} = $folder;
+ &snapshotbefore();
+ my $title = &LONCAPA::map::qtunescape($env{'form.newresourcetitle'});
+ my $ext = 'false';
+ my $newidx = &LONCAPA::map::getresidx(&LONCAPA::map::qtunescape($url));
+ $LONCAPA::map::resources[$newidx]=$title.':'.&LONCAPA::map::qtunescape($url).
+ ':'.$ext.':normal:res';
+ push(@LONCAPA::map::order,$newidx);
+ &LONCAPA::map::storeparameter($newidx,'parameter_hiddenresource','yes',
+ 'string_yesno');
+ &remember_parms($newidx,'hiddenresource','set','yes');
+ ($errtext,$fatal) =
+ &storemap($coursenum, $coursedom, $folder.'.'.$container,1);
+ &log_differences($plain);
+ &mark_hash_old();
+ $r->internal_redirect($redirect);
+ return OK;
+ }
+ } else {
+ $r->internal_redirect($redirect);
+ }
+ }
+ }
+#
+# 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','title',
+ 'forcesupplement','forcestandard',
+ 'tools','symb','command','supppath']);
+
+ foreach my $item ('forcesupplement','forcestandard','tools') {
+ next if ($env{'form.'.$item} eq '');
+ unless ($env{'form.'.$item} eq '1') {
+ delete($env{'form.'.$item});
+ }
+ }
+
+ if ($env{'form.command'}) {
+ unless ($env{'form.command'} =~ /^(direct|directnav|editdocs|editsupp|contents|home)$/) {
+ delete($env{'form.command'});
+ }
+ }
+
+ if ($env{'form.symb'}) {
+ my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($env{'form.symb'});
+ unless (($id =~ /^\d+$/) && (&Apache::lonnet::is_on_map($resurl))) {
+ delete($env{'form.symb'});
+ }
+ }
+
+# 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 $unesc_folderpath = &unescape($env{'form.folderpath'});
+ my $supplementalflag=($unesc_folderpath=~/^supplemental/);
+ if (($unesc_folderpath=~/^default/) || ($unesc_folderpath eq "")) {
+ $supplementalflag=0;
+ }
+ if ($env{'form.forcesupplement'}) { $supplementalflag=1; }
+ if ($env{'form.forcestandard'}) { $supplementalflag=0; }
+ unless (($supplementalflag) ||
+ ($r->uri =~ m{^/adm/coursedocs/showdoc/uploaded/\Q$coursedom\E/\Q$coursenum\E/docs/})) {
+ unless ($allowed) { $supplementalflag=1; }
+ unless ($standard) { $supplementalflag=1; }
+ }
+ my $toolsflag=0;
+ if ($env{'form.tools'}) { $toolsflag=1; }
+
+ if ($env{'form.folderpath'} ne '') {
+ &Apache::loncommon::validate_folderpath($supplementalflag,$allowed,$coursenum,$coursedom);
+ }
+
+ my $backto_supppath;
+ if ($env{'form.supppath'} ne '') {
+ if ($supplementalflag && $allowed) {
+ $backto_supppath = &validate_supppath($coursenum,$coursedom);
+ }
+ }
- my $standard=($ENV{'request.course.uri'}=~/^\/uploaded\//);
- my $forcestandard;
- my $forcesupplement;
my $script='';
- my $allowed;
- my $events='';
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('mdc',$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).''."\n"
+ .''."\n";
+
+ # Breadcrumbs
+ &Apache::lonhtmlcommon::clear_breadcrumbs();
+
+ if ($showdoc) {
+ my $args;
+ if ($supplementalflag) {
+ my $title = &HTML::Entities::encode($env{'form.title'},'\'"<>&');
+ my $brcrum = &Apache::lonhtmlcommon::docs_breadcrumbs(undef,$crstype,undef,$title,1);
+ $args = {'bread_crumbs' => $brcrum,
+ 'bread_crumbs_nomenu' => 1};
+ } else {
+ $args = {'force_register' => $showdoc};
+ }
+ $r->print(&Apache::loncommon::start_page("$crstype documents",undef,$args));
+ } elsif ($toolsflag) {
+ my ($breadtext,$breadtitle);
+ $breadtext = "$crstype Editor";
+ if ($canedit) {
+ $breadtitle = 'Editing '.$crstype.' Contents';
+ } else {
+ $breadtext .= ' (View-only mode)';
+ $breadtitle = 'Viewing '.$crstype.' Contents';
+ }
+ &Apache::lonhtmlcommon::add_breadcrumb({
+ href=>"/adm/coursedocs",text=>$breadtext});
+ $r->print(&Apache::loncommon::start_page("$crstype Contents", $script)
+ .&Apache::loncommon::help_open_menu('','',273,'RAT')
+ .&Apache::lonhtmlcommon::breadcrumbs(
+ $breadtitle)
+ );
+ } elsif ($r->uri eq '/adm/supplemental') {
+ unless ($env{'request.role.adv'}) {
+ unless (&Apache::lonnet::has_unhidden_suppfiles($coursenum,$coursedom)) {
+ $r->internal_redirect('/adm/navmaps');
+ return OK;
+ }
+ }
+ my $brcrum = &Apache::lonhtmlcommon::docs_breadcrumbs(undef,$crstype);
+ my $args = {'bread_crumbs' => $brcrum};
+ unless (($env{'form.folderpath'} eq '') ||
+ ($env{'form.folder'} eq 'supplemental')) {
+ $args->{'bread_crumbs_nomenu'} = 1;
+ }
+ $r->print(&Apache::loncommon::start_page("Supplemental $crstype Content",undef,
+ $args));
+ } else {
+ my ($breadtext,$breadtitle,$helpitem);
+ $breadtext = "$crstype Editor";
+ if ($canedit) {
+ $breadtitle = 'Editing '.$crstype.' Contents';
+ $helpitem = 'Docs_Adding_Course_Doc';
+ } else {
+ $breadtext .= ' (View-only mode)';
+ $breadtitle = 'Viewing '.$crstype.' Contents';
+ $helpitem = 'Docs_Viewing_Course_Doc';
+ }
+ &Apache::lonhtmlcommon::add_breadcrumb({
+ href=>"/adm/coursedocs",text=>$breadtext});
+ $r->print(&Apache::loncommon::start_page("$crstype Contents", $script,
+ {'add_entries' => $addentries}
+ )
+ .&Apache::loncommon::help_open_menu('','',273,'RAT')
+ .&Apache::lonhtmlcommon::breadcrumbs(
+ $breadtitle,
+ $helpitem)
+ );
+ }
- $iconpath = $r->dir_config('lonIconsURL') . "/";
+ my %allfiles = ();
+ my %codebase = ();
+ my ($upload_result,$upload_output,$uploadphase);
+ if ($canedit) {
+ undef($suppchanges);
+ 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,$crstype);
+ undef($navmap);
+ if ($hadchanges) {
+ &mark_hash_old();
+ }
+ if ($suppchanges) {
+ &Apache::lonnet::update_supp_caches($coursedom,$coursenum);
+ undef($suppchanges);
+ }
+ $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());
+ }
+ }
- my $now=time;
+ if ($allowed && $toolsflag) {
+ $r->print(&startContentScreen('tools'));
+ $r->print(&generate_admin_menu($crstype,$canedit,$coursenum,$coursedom));
+ $r->print(&endContentScreen());
+ } elsif ((!$showdoc) && (!$uploadphase)) {
+# -----------------------------------------------------------------------------
+ my %lt=&Apache::lonlocal::texthash(
+ 'copm' => 'All documents out of a published map into this folder',
+ 'upfi' => 'Upload File',
+ 'upld' => 'Upload Content',
+ 'srch' => 'Search Repository',
+ 'impo' => 'Import from Repository',
+ 'lnks' => 'Import from Stored Links',
+ 'impm' => 'Import from Assembled Map',
+ 'imcr' => 'Import from Course Resources',
+ 'extr' => 'External Resource',
+ 'extt' => 'External Tool',
+ 'selm' => 'Select Map',
+ 'load' => 'Load Map',
+ 'newf' => 'New Folder',
+ 'newp' => 'New Composite Page',
+ 'syll' => 'Syllabus',
+ 'navc' => 'Table of Contents',
+ 'sipa' => 'Simple Course Page',
+ 'sipr' => 'Simple Problem',
+ 'webp' => 'Blank Web Page (editable)',
+ 'stpr' => 'Standard Problem',
+ 'news' => 'New sub-directory',
+ 'crpr' => 'Create Problem',
+ 'swit' => 'Switch Server',
+ '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 Upload',
+ 'imsl' => 'Upload IMS package',
+ 'cms' => 'Origin of IMS package',
+ 'se' => 'Select',
+ 'file' => 'File',
+ 'title' => 'Title',
+ 'addp' => 'Add Placeholder to course?',
+ 'uste' => 'Use Template?',
+ 'fnam' => 'File Name:',
+ 'loca' => 'Location:',
+ 'dire' => 'Directory:',
+ 'cate' => 'Category:',
+ 'tmpl' => 'Template:',
+ 'empd' => 'No resources found',
+ 'comment' => 'Comment',
+ 'parse' => 'Upload embedded images/multimedia files if HTML file',
+ 'bb5' => 'Blackboard 5',
+ 'bb6' => 'Blackboard 6',
+ 'angel5' => 'ANGEL 5.5',
+ 'webctce4' => 'WebCT 4 Campus Edition',
+ 'yes' => 'Yes',
+ 'no' => 'No',
+ 'er' => 'Editing rights unavailable for your current role.',
+ );
+# -----------------------------------------------------------------------------
+
+ # Calculate free quota space for a user or course. A javascript function checks
+ # file size to determine if upload should be allowed.
+ my $quotatype = 'unofficial';
+ if ($crstype eq 'Community') {
+ $quotatype = 'community';
+ } elsif ($crstype eq 'Placement') {
+ $quotatype = 'placement';
+ } elsif ($env{'course.'.$coursedom.'_'.$coursenum.'.internal.coursecode'}) {
+ $quotatype = 'official';
+ } elsif ($env{'course.'.$coursedom.'_'.$coursenum.'.internal.textbook'}) {
+ $quotatype = 'textbook';
+ }
+ my $disk_quota = &Apache::loncommon::get_user_quota($coursenum,$coursedom,
+ 'course',$quotatype); # expressed in MB
+ my $current_disk_usage = 0;
+ foreach my $subdir ('docs','supplemental') {
+ $current_disk_usage += &Apache::lonnet::diskusage($coursedom,$coursenum,
+ "userfiles/$subdir",1); # expressed in kB
+ }
+ my $free_space = 1024 * ((1024 * $disk_quota) - $current_disk_usage);
+ my $usage = $current_disk_usage/1024; # in MB
+ my $quota = $disk_quota;
+ my $percent;
+ if ($disk_quota == 0) {
+ $percent = 100.0;
+ } else {
+ $percent = 100*($usage/$disk_quota);
+ }
+ $usage = sprintf("%.2f",$usage);
+ $quota = sprintf("%.2f",$quota);
+ $percent = sprintf("%.0f",$percent);
+ my $quotainfo = ''.&mt('Currently using [_1] of the [_2] available.',
+ $percent.'%',$quota.' MB').'
';
+
+ my $fileupload=(<
+FIUP
+ my $checkbox=(<$lt{'parse'}?
+
+ -->
+
+ $lt{'parse'}
+
+CHBO
+ my $imsfolder = $env{'form.folder'};
+ if ($imsfolder eq '') {
+ $imsfolder = 'default';
+ }
+ my $imspform=(<