--- loncom/interface/londocs.pm 2018/01/12 01:54:56 1.650
+++ loncom/interface/londocs.pm 2022/09/29 03:59:29 1.681
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Documents
#
-# $Id: londocs.pm,v 1.650 2018/01/12 01:54:56 raeburn Exp $
+# $Id: londocs.pm,v 1.681 2022/09/29 03:59:29 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -46,6 +46,7 @@ use Apache::lonsimplepage();
use Apache::lonhomework();
use Apache::lonpublisher();
use Apache::lonparmset();
+use Apache::loncourserespicker();
use HTML::Entities;
use HTML::TokeParser;
use GDBM_File;
@@ -182,6 +183,45 @@ sub default_folderpath {
}
}
+sub validate_folderpath {
+ my ($supplementalflag) = @_;
+ if ($env{'form.folderpath'} ne '') {
+ my @items = split(/\&/,$env{'form.folderpath'});
+ my $badpath;
+ for (my $i=0; $i<@items; $i++) {
+ my $odd = $i%2;
+ if (($odd) && (!$supplementalflag) && ($items[$i] !~ /^[^:]*:(|\d+):(|1):(|1):(|1):(|1)$/)) {
+ $badpath = 1;
+ } elsif ((!$odd) && ($items[$i] !~ /^(default|supplemental)(|_\d+)$/)) {
+ $badpath = 1;
+ }
+ last if ($badpath);
+ }
+ if ($badpath) {
+ delete($env{'form.folderpath'});
+ }
+ }
+ return;
+}
+
+sub validate_suppath {
+ if ($env{'form.supppath'} ne '') {
+ my @items = split(/\&/,$env{'form.supppath'});
+ my $badpath;
+ for (my $i=0; $i<@items; $i++) {
+ my $odd = $i%2;
+ if ((!$odd) && ($items[$i] !~ /^supplemental(|_\d+)$/)) {
+ $badpath = 1;
+ }
+ last if ($badpath);
+ }
+ if ($badpath) {
+ delete($env{'form.supppath'});
+ }
+ }
+ return;
+}
+
sub dumpcourse {
my ($r) = @_;
my $crstype = &Apache::loncommon::course_type();
@@ -832,26 +872,27 @@ sub group_import {
}
my $ext = 'false';
if ($url=~m{^http://} || $url=~m{^https://}) { $ext = 'true'; }
- $name = &LONCAPA::map::qtunescape($name);
- if ($name eq '') {
- $name = &LONCAPA::map::qtunescape(&mt('Web Page'));
- }
if ($url =~ m{^/uploaded/$coursedom/$coursenum/((?:docs|supplemental)/(?:default|\d+))/new\.html$}) {
my $filepath = $1;
- my $fname = $name;
- if ($fname =~ /^\W+$/) {
+ my $fname;
+ if ($name eq '') {
+ $name = &mt('Web Page');
$fname = 'web';
} else {
- $fname =~ s/\W/_/g;
- }
- if (length($fname) > 15) {
- $fname = substr($fname,0,14);
+ $fname = $name;
+ $fname=&Apache::lonnet::clean_filename($fname);
+ if ($fname eq '') {
+ $fname = 'web';
+ } elsif (length($fname) > 15) {
+ $fname = substr($fname,0,14);
+ }
}
+ my $title = &Apache::loncommon::cleanup_html($name);
my $initialtext = &mt('Replace with your own content.');
my $newhtml = <
-$name
+$title
$initialtext
@@ -873,6 +914,7 @@ END
return (&mt('Failed to save new web page.'),1);
}
}
+ $name = &LONCAPA::map::qtunescape($name);
$url = &LONCAPA::map::qtunescape($url);
$LONCAPA::map::resources[$residx] =
join(':', ($name, $url, $ext, 'normal', 'res'));
@@ -1216,13 +1258,19 @@ sub update_paste_buffer {
# 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 '')) {
- $pasteurls{$cid.'_'.$url.'_'.$mapidx} = 1;
- }
+ 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;
+ }
+ }
}
}
@@ -1231,7 +1279,7 @@ sub update_paste_buffer {
my @pathitems = split(/\&/,$env{'form.folderpath'});
my @folderconf = split(/\:/,$pathitems[-1]);
- my $ispage = $folderconf[4];
+ my $ispage = $folderconf[5];
foreach my $item (@possibles) {
my ($orderidx,$cmd) = split(/:/,$item);
@@ -1244,7 +1292,13 @@ sub update_paste_buffer {
$env{'form.folderpath'},\%curr_groups);
next if ($denied{'copy'});
$url=~s{http(:|:)//https(:|:)//}{https$2//};
- next if (exists($pasteurls{$coursedom.'_'.$coursenum.'_'.$mapidx}));
+ 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 '') {
@@ -1441,7 +1495,7 @@ sub print_paste_buffer {
}
$pasteitems .= ' '.$buffer.' ';
if ($nopaste) {
- $pasteitems .= $nopaste;
+ $pasteitems .= ' '.$nopaste.' ';
} else {
if ($othercrs) {
$pasteitems .= $othercrs;
@@ -1789,7 +1843,7 @@ sub do_paste_from_buffer {
%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 donain.',
+ notindom => 'Paste failed: Item is an external tool from a course in a different domain.',
duplicate => 'Paste failed: only one instance of a particular published sequence or page is allowed within each course.',
);
@@ -1818,14 +1872,7 @@ sub do_paste_from_buffer {
# Retrieve information about all course maps in main content area
my $allmaps = {};
- if ($folder =~ /^default/) {
- $allmaps =
- &Apache::loncommon::allmaps_incourse($coursedom,$coursenum,
- $env{"course.$env{'request.course.id'}.home"},
- $env{'request.course.id'});
- }
-
- my (@toclear,%mapurls,%lockerrs,%msgerrs,%results);
+ my (@toclear,%mapurls,%lockerrs,%msgerrs,%results,$donechk);
# Loop over the items to paste
foreach my $suffix (@dopaste) {
@@ -1843,6 +1890,13 @@ sub do_paste_from_buffer {
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);
@@ -1908,7 +1962,7 @@ sub do_paste_from_buffer {
cnum => $coursenum,
);
if ($prefix eq 'ext.tool') {
- if ($prefixchg{$suffix} eq 'docstosupp') {
+ if ($prefixchg{$suffix} eq 'docstosupp') {
$info{'delgradable'} = 1;
}
}
@@ -2004,7 +2058,7 @@ sub do_paste_from_buffer {
$coursedom,$coursenum,$template,$newidx,"$folder.$container");
}
} elsif ($url =~ /ext\.tool$/) {
- if (($newidx) && ($folder=~/^default/)) {
+ if (($newidx) && ($folder=~/^default/)) {
my $marker = (split(m{/},$url))[4];
my %toolsettings = &Apache::lonnet::dump('exttool_'.$marker,$coursedom,$coursenum);
my $val = 'no';
@@ -2328,7 +2382,9 @@ sub copy_templated_files {
my @simpleprobqtypes = qw(radio option string essay numerical);
my $qtype=$srcparms{$srcprefix.'questiontype'};
if (grep(/^\Q$qtype\E$/,@simpleprobqtypes)) {
- my %newdata;
+ my %newdata = (
+ $newprefix.'questiontype' => $qtype,
+ );
foreach my $type (@simpleprobqtypes) {
if ($type eq $qtype) {
$newdata{"$weightprefix.$type.weight"}=1;
@@ -2557,7 +2613,7 @@ sub url_paste_fixups {
my $rem = $3;
my ($is_exttool,$exttoolchg);
if ($rem =~ m{\d+/ext\.tool$}) {
- $is_exttool = 1;
+ $is_exttool = 1;
}
if (($srcdom ne $cdom) || ($srcnum ne $cnum)) {
$rewrites->{$oldurl}{$id} = $ressrc;
@@ -2744,6 +2800,15 @@ sub apply_fixups {
$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;
@@ -2802,9 +2867,7 @@ sub apply_fixups {
}
}
if (ref($resdatacopy{$key}) eq 'HASH') {
- if ($newsubdir{$key}) {
-
- }
+ my ($gotnewmapname,$newmapname,$srcfolder,$srccontainer);
foreach my $idx (keys(%{$resdatacopy{$key}})) {
if (ref($resdatacopy{$key}{$idx}) eq 'HASH') {
my $srcurl = $resdatacopy{$key}{$idx}{'src'};
@@ -2814,15 +2877,18 @@ sub apply_fixups {
($resdatacopy{$key}{$idx}{'cnum'} =~ /^$match_courseid$/)) {
my $srcdom = $resdatacopy{$key}{$idx}{'cdom'};
my $srcnum = $resdatacopy{$key}{$idx}{'cnum'};
- my ($newmapname) = ($key =~ m{/([^/]+)$});
- my ($srcfolder,$srccontainer) = split(/\./,$newmapname);
+ 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';
}
- if ($newsubdir{$key}) {
- $newmapname =~ s/^((?:default|supplemental)_)(\d+)/$1$newsubdir{$key}/;
- }
©_templated_files($srcurl,$srcdom,$srcnum,$srcmapinfo,$cdom,
$cnum,$template,$idx,$newmapname);
}
@@ -3911,7 +3977,7 @@ sub entryline {
my $line=&Apache::loncommon::start_data_table_row();
my ($form_start,$form_end,$form_common,$form_param);
# Edit commands
- my ($esc_path, $path, $symb, $curralias);
+ my ($esc_path, $path, $symb, $shownsymb, $curralias);
if ($env{'form.folderpath'}) {
$esc_path=&escape($env{'form.folderpath'});
$path = &HTML::Entities::encode($env{'form.folderpath'},'<>&"');
@@ -4141,11 +4207,19 @@ END
my ($editlink,$extresform,$anchor,$hiddenres,$nomodal);
my $orig_url = $url;
$orig_url=~s{http(:|:)//https(:|:)//}{https$2//};
- $url=~s{^http(|s)(:|:)//}{/adm/wrapper/ext/};
+ 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);
- $url=&Apache::lonnet::clutter($url);
+ 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);
@@ -4159,7 +4233,7 @@ END
} elsif ($url=~m{^(|/adm/wrapper)/ext/([^#]+)}) {
my $wrapped = $1;
my $exturl = $2;
- if ($wrapped eq '') {
+ if (($wrapped eq '') && ($container ne 'page')) {
$url='/adm/wrapper'.$url;
}
if (($ENV{'SERVER_PORT'} == 443) && ($exturl !~ /^https:/)) {
@@ -4170,37 +4244,16 @@ END
} elsif ($url eq "/public/$coursedom/$coursenum/syllabus") {
if (($ENV{'SERVER_PORT'} == 443) &&
($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'} =~ m{^http://})) {
- $url .= '?usehttp=1';
+ unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) {
+ $url .= '?usehttp=1';
+ }
$nomodal = 1;
}
}
- if (&Apache::lonnet::symbverify($symb,$url)) {
- my $shownsymb = $symb;
- if ($isexternal) {
- if ($url =~ /^([^#]+)#([^#]+)$/) {
- $url = $1;
- $anchor = $2;
- if ($symb =~ m{^([^#]+)\Q#$anchor\E$}) {
- $shownsymb = $1.&escape('#').$anchor;
- }
- }
- }
- unless ($env{'request.role.adv'}) {
- if ((&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i) {
- $url = '';
- }
- if (&Apache::lonnet::EXT('resource.0.hiddenresource',$symb) =~ /^yes$/i) {
- $url = '';
- $hiddenres = 1;
- }
- }
- if ($url ne '') {
- $url.=(($url=~/\?/)?'&':'?').'symb='.&escape($shownsymb);
- }
- } elsif (!$env{'request.role.adv'}) {
- my $checkencrypt;
+ my ($checkencrypt,$shownurl);
+ 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)) {
+ ($isencrypted) || (&Apache::lonnet::EXT('resource.0.encrypturl',$symb) =~ /^yes$/i)) {
$checkencrypt = 1;
} elsif (ref($navmapref)) {
unless (ref($$navmapref)) {
@@ -4208,26 +4261,43 @@ END
}
if (ref($$navmapref)) {
if (lc($$navmapref->get_mapparam($symb,undef,"0.encrypturl")) eq 'yes') {
- $checkencrypt = 1;
+ $checkencrypt = 1;
}
}
}
- if ($checkencrypt) {
- my $shownsymb = &Apache::lonenc::encrypted($symb);
- my $shownurl = &Apache::lonenc::encrypted($url);
- if (&Apache::lonnet::symbverify($shownsymb,$shownurl)) {
- $url = $shownurl.(($shownurl=~/\?/)?'&':'?').'symb='.&escape($shownsymb);
- if ($env{'request.enc'} ne '') {
- delete($env{'request.enc'});
- }
- } else {
- $url='';
- }
+ }
+ if ($checkencrypt) {
+ my $currenc = $env{'request.enc'};
+ $env{'request.enc'} = 1;
+ $shownsymb = &Apache::lonenc::encrypted($symb);
+ $shownurl = &Apache::lonenc::encrypted($url);
+ if (&Apache::lonnet::symbverify($symb,$url)) {
+ $url = $shownurl;
} else {
- $url='';
+ $url = '';
}
- } 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);
+ }
+ }
+ $shownurl = $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 '') {
+ $url = $shownurl.(($shownurl=~/\?/)?'&':'?').'symb='.&escape($shownsymb);
}
}
} elsif ($supplementalflag) {
@@ -4236,8 +4306,11 @@ END
$url = $1;
$anchor = $2;
if (($url =~ m{^(|/adm/wrapper)/ext/(?!https:)}) && ($ENV{'SERVER_PORT'} == 443)) {
- if ($hostname ne '') {
- $url = 'http://'.$hostname.$url;
+ unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) {
+ if ($hostname ne '') {
+ $url = 'http://'.$hostname.$url;
+ }
+ $url .= (($url =~ /\?/) ? '&':'?').'usehttp=1';
}
$nomodal = 1;
}
@@ -4245,10 +4318,12 @@ END
} elsif ($url =~ m{^\Q/public/$coursedom/$coursenum/syllabus\E}) {
if (($ENV{'SERVER_PORT'} == 443) &&
($env{'course.'.$env{'request.course.id'}.'.externalsyllabus'} =~ m{^http://})) {
- if ($hostname ne '') {
- $url = 'http://'.$hostname.$url;
+ unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) {
+ if ($hostname ne '') {
+ $url = 'http://'.$hostname.$url;
+ }
+ $url .= (($url =~ /\?/) ? '&':'?').'usehttp=1';
}
- $url .= (($url =~ /\?/) ? '&':'?').'usehttp=1';
$nomodal = 1;
}
}
@@ -4382,7 +4457,7 @@ $form_end;
&Apache::lonhtmlcommon::jump_to_editres($cfile,$home,
$switchserver,
$forceedit,
- undef,$symb,
+ undef,$symb,$shownsymb,
&escape($env{'form.folderpath'}),
$renametitle,$hostname,
'','',1,$suppanchor);
@@ -4429,8 +4504,7 @@ $form_end;
} else {
$link = $url;
}
- $link = &js_escape($link.(($url=~/\?/)?'&':'?').'inhibitmenu=yes'.
- (($anchor ne '')?$anchor:''));
+ $link = &js_escape($link.(($url=~/\?/)?'&':'?').'inhibitmenu=yes'.$anchor);
if ($nomodal) {
$line.=' '.
' ';
@@ -4812,6 +4886,48 @@ sub list_symbs {
$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,$readonly));
+ }
+ $r->print(&endContentScreen());
+}
+
sub contentverifyform {
my ($r) = @_;
my $crstype = &Apache::loncommon::course_type();
@@ -4826,7 +4942,7 @@ sub contentverifyform {
&mt('No').''.(' 'x2).
' '.
&mt('Yes').'
'.
- ' '.
+ ' '.
' '.
'
');
$r->print(&endContentScreen());
@@ -5182,13 +5298,17 @@ sub changewarning {
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".
-'