--- loncom/interface/londocs.pm 2016/11/23 01:28:50 1.612 +++ 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.612 2016/11/23 01:28:50 raeburn Exp $ +# $Id: londocs.pm,v 1.681 2022/09/29 03:59:29 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -45,6 +45,8 @@ use Apache::lontemplate(); use Apache::lonsimplepage(); use Apache::lonhomework(); use Apache::lonpublisher(); +use Apache::lonparmset(); +use Apache::loncourserespicker(); use HTML::Entities; use HTML::TokeParser; use GDBM_File; @@ -52,6 +54,7 @@ use File::MMagic; use File::Copy; use Apache::lonlocal; use Cwd; +use UUID::Tiny ':std'; use LONCAPA qw(:DEFAULT :match); my $iconpath; @@ -142,7 +145,82 @@ sub clean { 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 $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) = @_; @@ -567,9 +645,9 @@ sub recurse_html { } else { $relfile = $dependency; $depurl = $currurlpath; - $depurl =~ s{[^/]+$}{}; + $depurl =~ s{[^/]+$}{}; $depurl .= $dependency; - ($newcontainer) = ($depurl =~ m{^\Q$prefix\E(.+)$}); + ($newcontainer) = ($depurl =~ m{^\Q$prefix\E(.+)$}); } next if ($relfile eq ''); my $newname = $replacehash->{$container}; @@ -618,11 +696,12 @@ sub group_import { } } if ($url) { - if ($url =~ m{^(/adm/$coursedom/$coursenum/(\d+)/exttool)s?\:?(.*)$}) { + if ($url =~ m{^(/adm/$coursedom/$coursenum/(\d+)/ext\.tool)\:?(.*)$}) { $url = $1; my $marker = $2; my $info = $3; my ($toolid,%toolhash,%toolsettings); + my @extras = ('linktext','explanation','crslabel','crstitle','crsappend'); my @toolinfo = split(/:/,$info); if ($residx) { %toolsettings=&Apache::lonnet::dump('exttool_'.$marker,$coursedom,$coursenum); @@ -632,28 +711,42 @@ sub group_import { } $toolid =~ s/\D//g; ($toolhash{'target'},$toolhash{'width'},$toolhash{'height'}, - $toolhash{'crslabel'},$toolhash{'crstitle'}) = @toolinfo; - $toolhash{'crslabel'} = &unescape($toolhash{'crslabel'}); - $toolhash{'crstitle'} = &unescape($toolhash{'crstitle'}); + $toolhash{'linktext'},$toolhash{'explanation'},$toolhash{'crslabel'}, + $toolhash{'crstitle'},$toolhash{'crsappend'},$toolhash{'gradable'}) = @toolinfo; + foreach my $item (@extras) { + $toolhash{$item} = &unescape($toolhash{$item}); + } + if ($folder =~ /^supplemental/) { + delete($toolhash{'gradable'}); + } else { + $toolhash{'gradable'} =~ s/\D+//g; + } if (ref($ltitoolsref) eq 'HASH') { - my @deleted; if (ref($ltitoolsref->{$toolid}) eq 'HASH') { - if ($ltitoolsref->{$toolid}->{'url'} =~ m{^https://}) { - $url =~ s/exttool$/exttools/; - } + my @deleted; $toolhash{'id'} = $toolid; - if (($toolhash{'target'} eq 'iframe') || ($toolhash{'target'} eq 'window')) { + if (($toolhash{'target'} eq 'iframe') || ($toolhash{'target'} eq 'tab') || + ($toolhash{'target'} eq 'window')) { if ($toolhash{'target'} eq 'window') { foreach my $item ('width','height') { $toolhash{$item} =~ s/^\s+//; $toolhash{$item} =~ s/\s+$//; + if ($toolhash{$item} =~ /\D/) { + delete($toolhash{$item}); + if ($residx) { + if ($toolsettings{$item}) { + push(@deleted,$item); + } + } + } } } } elsif ($residx) { $toolhash{'target'} = $toolsettings{'target'}; if ($toolhash{'target'} eq 'window') { - $toolhash{'width'} = $toolsettings{'width'}; - $toolhash{'height'} = $toolsettings{'height'}; + foreach my $item ('width','height') { + $toolhash{$item} = $toolsettings{$item}; + } } } elsif (ref($ltitoolsref->{$toolid}->{'display'}) eq 'HASH') { $toolhash{'target'} = $ltitoolsref->{$toolid}->{'display'}->{'target'}; @@ -663,40 +756,93 @@ sub group_import { } } if ($toolhash{'target'} eq 'iframe') { - delete($toolhash{'width'}); - delete($toolhash{'height'}); - if ($residx) { - if ($toolsettings{'width'}) { - push(@deleted,'width'); + foreach my $item ('width','height','linktext','explanation') { + delete($toolhash{$item}); + if ($residx) { + if ($toolsettings{$item}) { + push(@deleted,$item); + } } - if ($toolsettings{'height'}) { - push(@deleted,'height'); + } + } elsif ($toolhash{'target'} eq 'tab') { + foreach my $item ('width','height') { + delete($toolhash{$item}); + if ($residx) { + if ($toolsettings{$item}) { + push(@deleted,$item); + } } } } if (ref($ltitoolsref->{$toolid}->{'crsconf'}) eq 'HASH') { - foreach my $item ('label','title') { + foreach my $item ('label','title','linktext','explanation') { + my $crsitem; + if (($item eq 'label') || ($item eq 'title')) { + $crsitem = 'crs'.$item; + } else { + $crsitem = $item; + } if ($ltitoolsref->{$toolid}->{'crsconf'}->{$item}) { - $toolhash{'crs'.$item} =~ s/^\s+//; - $toolhash{'crs'.$item} =~ s/\s+$//; - if ($toolhash{'crs'.$item} eq '') { - delete($toolhash{'crs'.$item}); + $toolhash{$crsitem} =~ s/^\s+//; + $toolhash{$crsitem} =~ s/\s+$//; + if ($toolhash{$crsitem} eq '') { + delete($toolhash{$crsitem}); } } else { - delete($toolhash{'crs'.$item}); + delete($toolhash{$crsitem}); } - if (($residx) && (exists($toolsettings{'crs'.$item}))) { - unless (exists($toolhash{'crs'.$item})) { - push(@deleted,'crs'.$item); + if (($residx) && (exists($toolsettings{$crsitem}))) { + unless (exists($toolhash{$crsitem})) { + push(@deleted,$crsitem); } } } } + if ($toolhash{'passback'}) { + my $gradesecret = UUID::Tiny::create_uuid_as_string(UUID_V4); + $toolhash{'gradesecret'} = $gradesecret; + $toolhash{'gradesecretdate'} = time; + } + if ($toolhash{'roster'}) { + my $rostersecret = UUID::Tiny::create_uuid_as_string(UUID_V4); + $toolhash{'rostersecret'} = $rostersecret; + $toolhash{'rostersecretdate'} = time; + } + my $changegradable; + if (($residx) && ($folder =~ /^default/)) { + if ($toolsettings{'gradable'}) { + unless (($toolhash{'gradable'}) || (defined($LONCAPA::map::zombies[$residx]))) { + push(@deleted,'gradable'); + $changegradable = 1; + } + } elsif ($toolhash{'gradable'}) { + $changegradable = 1; + } + if (($caller eq 'londocs') && (defined($LONCAPA::map::zombies[$residx]))) { + $changegradable = 1; + if ($toolsettings{'gradable'}) { + $toolhash{'gradable'} = 1; + } + } + } my $putres = &Apache::lonnet::put('exttool_'.$marker,\%toolhash,$coursedom,$coursenum); if ($putres eq 'ok') { if (@deleted) { &Apache::lonnet::del('exttool_'.$marker,\@deleted,$coursedom,$coursenum); - } + } + if (($changegradable) && ($folder =~ /^default/)) { + my $val; + if ($toolhash{'gradable'}) { + $val = 'yes'; + } else { + $val = 'no'; + } + &LONCAPA::map::storeparameter($residx,'parameter_0_gradable',$val, + 'string_yesno'); + &remember_parms($residx,'gradable','set',$val); + } + } else { + return (&mt('Failed to save update to external tool.'),1); } } } @@ -712,8 +858,8 @@ sub group_import { $donechk = 1; } if ($url =~ m{^/uploaded/\Q$coursedom\E/\Q$coursenum\E/(default_\d+\.)(page|sequence)$}) { - &contained_map_check($url,$folder,\%removefrommap,\%removeparam, - \%addedmaps,\%hierarchy,\%titles,$allmaps); + &contained_map_check($url,$folder,$coursenum,$coursedom,\%removefrommap, + \%removeparam,\%addedmaps,\%hierarchy,\%titles,$allmaps); $importuploaded = 1; } elsif ($url =~ m{^/res/.+\.(page|sequence)$}) { next if ($allmaps->{$url}); @@ -726,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 = <<END; <html> <head> -<title>$name</title> +<title>$title</title> </head> <body bgcolor="#ffffff"> $initialtext @@ -753,7 +900,7 @@ $initialtext </html> END $env{'form.output'}=$newhtml; - my $result = + my $result = &Apache::lonnet::finishuserfileupload($coursenum,$coursedom, 'output', "$filepath/$residx/$fname.html"); @@ -767,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')); @@ -879,11 +1027,12 @@ sub log_docs { sub docs_change_log { my ($r,$coursenum,$coursedom,$folder,$allowed,$crstype,$iconpath,$canedit)=@_; my $supplementalflag=($env{'form.folderpath'}=~/^supplemental/); + my $navmap; my $js = '<script type="text/javascript">'."\n". '// <![CDATA['."\n". &Apache::loncommon::display_filter_js('docslog')."\n". &editing_js($env{'user.domain'},$env{'user.name'},$supplementalflag, - $coursedom,$coursenum,'','',$canedit)."\n". + $coursedom,$coursenum,'','',$canedit,'',\$navmap)."\n". &history_tab_js()."\n". &Apache::lonratedt::editscript('simple')."\n". '// ]]>'."\n". @@ -899,8 +1048,9 @@ sub docs_change_log { } my $folderpath=$env{'form.folderpath'}; if ($folderpath eq '') { - $folderpath = 'default&'.&escape(&mt('Main Content').':::::'); + $folderpath = &default_folderpath($coursenum,$coursedom,\$navmap); } + undef($navmap); $pathitem = '<input type="hidden" name="folderpath" value="'. &HTML::Entities::encode($folderpath,'<>&"').'" />'; my $readfile="/uploaded/$coursedom/$coursenum/$folder.$container"; @@ -910,7 +1060,7 @@ sub docs_change_log { if ($supplementalflag) { $tid = 2; } - my ($breadcrumbtrail) = + my ($breadcrumbtrail) = &Apache::lonhtmlcommon::docs_breadcrumbs($allowed,$crstype,1); $r->print($breadcrumbtrail. &generate_edit_table($tid,\%orderhash,undef,$iconpath,$jumpto, @@ -932,6 +1082,7 @@ sub docs_change_log { 'encrypturl' => 'URL hidden', 'randompick' => 'Randomly pick', 'randomorder' => 'Randomly ordered', + 'gradable' => 'Grade can be assigned to External Tool', 'set' => 'set to', 'del' => 'deleted'); my $filter = &Apache::loncommon::display_filter('docslog')."\n". @@ -1039,7 +1190,7 @@ sub docs_change_log { $r->print('</ul>'); if ($docslog{$id}{'logentry'}{'parameter_res'}) { $r->print(&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'parameter_res'}))[0]).':<ul>'); - foreach my $parameter ('randompick','hiddenresource','encrypturl','randomorder') { + foreach my $parameter ('randompick','hiddenresource','encrypturl','randomorder','gradable') { if ($docslog{$id}{'logentry'}{'parameter_action_'.$parameter}) { # FIXME: internationalization seems wrong here $r->print('<li>'. @@ -1107,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; + } + } } } @@ -1122,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); @@ -1135,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 '') { @@ -1162,8 +1325,8 @@ sub update_paste_buffer { $subdir = $prefix; } my (%addedmaps,%removefrommap,%removeparam,%hierarchy,%titles,%allmaps); - &contained_map_check($url,$folder,\%removefrommap,\%removeparam,\%addedmaps, - \%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); @@ -1241,7 +1404,7 @@ sub print_paste_buffer { 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+/exttools?$}) { + } elsif ($url =~ m{^/adm/$match_domain/$match_courseid/\d+/ext\.tool$}) { $is_exttool = 1; } if ($folder =~ /^supplemental/) { @@ -1275,26 +1438,34 @@ sub print_paste_buffer { $is_uploaded_map = 1; } } elsif (($url =~ m{^/res/lib/templates/\w+\.problem$}) || - ($url =~ m{^/adm/($match_domain)/($match_username)/\d+/(bulletinboard|smppg)$})) { + ($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/) { - $othercrs = '<br />'.&mt('(from another course)'); + if (($is_exttool) && ($srcdom ne $coursedom)) { + $canpaste = 0; + $nopaste = &mt('Paste from another domain unavailable.'); + } else { + $othercrs = '<br />'.&mt('(from another course)'); + } } else { $canpaste = 0; $nopaste = &mt('Paste from another course unavailable.'); - } + } } } if ($canpaste) { push(@pasteable,$suffix); - } + } } my $buffer; - if (($is_external) || ($is_exttool)) { + 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' && @@ -1324,7 +1495,7 @@ sub print_paste_buffer { } $pasteitems .= '<label><input type="checkbox" name="pasting" id="pasting_'.$suffix.'" value="'.$suffix.'" '.$onclick.'/>'.$buffer.'</label>'; if ($nopaste) { - $pasteitems .= $nopaste; + $pasteitems .= ' <span class="LC_cusr_emph">'.$nopaste.'</span>'; } else { if ($othercrs) { $pasteitems .= $othercrs; @@ -1452,7 +1623,7 @@ sub supp_pasteable { ($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+/exttools?$})) { + ($url =~ m{^/adm/$match_domain/$match_courseid/\d+/ext\.tool$})) { return 1; } return; @@ -1574,7 +1745,7 @@ sub do_paste_from_buffer { return(); } - my (%msgs,%before,%after,@dopaste,%is_map,%notinsupp,%notincrs,%duplicate, + my (%msgs,%before,%after,@dopaste,%is_map,%notinsupp,%notincrs,%notindom,%duplicate, %prefixchg,%srcdom,%srcnum,%srcmapidx,%marktomove,$save_err,$lockerrors,$allresult); foreach my $suffix (@topaste) { @@ -1603,7 +1774,8 @@ sub do_paste_from_buffer { $srcdom{$suffix} = $srcd; $srcnum{$suffix} = $srcn; } elsif (($url =~ m{^/res/lib/templates/\w+\.problem$}) || - ($url =~ m{^/adm/$match_domain/$match_username/\d+/(bulletinboard|smppg)$})) { + ($url =~ m{^/adm/$match_domain/$match_username/\d+/(bulletinboard|smppg)$}) || + ($url =~ m{^/adm/$match_domain/$match_courseid/\d+/ext\.tool$})) { my ($srcd,$srcn) = split(/_/,$cid); # When paste buffer was populated using an active role in a different course # check for mdc privilege in the course from which the resource was pasted @@ -1613,6 +1785,12 @@ sub do_paste_from_buffer { next; } } +# When buffer was populated using an active role in a different course +# disallow pasting of External Tool if course is in a different domain. + if (($url =~ m{/ext\.tool$}) && ($srcd ne $coursedom)) { + $notindom{$suffix} = 1; + next; + } $srcdom{$suffix} = $srcd; $srcnum{$suffix} = $srcn; } @@ -1621,7 +1799,6 @@ sub do_paste_from_buffer { if ($url=~/\.(page|sequence)$/) { $is_map{$suffix} = 1; } - if ($url =~ m{^/uploaded/$match_domain/$match_courseid/([^/]+)}) { my $oldprefix = $1; # When pasting content from Main Content to Supplemental Content and vice versa @@ -1666,6 +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 domain.', duplicate => 'Paste failed: only one instance of a particular published sequence or page is allowed within each course.', ); @@ -1694,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) { @@ -1719,8 +1890,16 @@ sub do_paste_from_buffer { if ($is_map{$suffix}) { # If pasting a map, check if map contains other maps my (%hierarchy,%titles); - &contained_map_check($url,$folder,\%removefrommap,\%removeparam, - \%addedmaps,\%hierarchy,\%titles,$allmaps); + 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') { @@ -1773,15 +1952,20 @@ sub do_paste_from_buffer { } } } - if ($url=~ m{/(bulletinboard|smppg)$}) { + if ($url=~ m{/(bulletinboard|smppg|ext\.tool)$}) { my $prefix = $1; - my $fromothercrs; + 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; @@ -1790,7 +1974,7 @@ sub do_paste_from_buffer { } } unless (($env{'form.docs.markedcopy_options_'.$suffix} eq 'move') && (!$fromothercrs)) { - my (%lockerr,$msg); + my (%lockerr,$msg); my ($newurl,$result,$errtext) = &dbcopy(\%info,$coursedom,$coursenum,\%lockerr); if ($result eq 'ok') { @@ -1801,6 +1985,8 @@ sub do_paste_from_buffer { $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; @@ -1847,8 +2033,8 @@ sub do_paste_from_buffer { if ($newdocsdir eq '') { $newdocsdir = 'default'; } - if (($prefixchg{$suffix}) || - ($srcdom{$suffix} ne $coursedom) || + 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"; @@ -1871,6 +2057,18 @@ sub do_paste_from_buffer { ©_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'; @@ -2060,8 +2258,11 @@ sub dbcopy { my ($url,$result,$errtext); if (ref($dbref) eq 'HASH') { $url = $dbref->{'src'}; - if ($url =~ m{/(smppg|bulletinboard)$}) { + 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; @@ -2072,6 +2273,8 @@ sub dbcopy { &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; } @@ -2082,6 +2285,8 @@ sub dbcopy { 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); } @@ -2112,10 +2317,13 @@ sub dbcopy { } } $db_name =~ s{_\d*$ }{_$suffix}x; + if (($prefix eq 'exttool') && ($dbref->{'delgradable'}) && ($contents{'gradable'})) { + delete($contents{'gradable'}); + } $result=&Apache::lonnet::put($db_name,\%contents, $coursedom,$coursenum); if ($result eq 'ok') { - $url =~ s{/(\d*)/(smppg|bulletinboard)$}{/$suffix/$2}x; + $url =~ s{/(\d*)/(smppg|bulletinboard|ext\.tool)$}{/$suffix/$2}x; } } if (($freedlock ne 'ok') && (ref($lockerrorsref) eq 'HASH')) { @@ -2125,6 +2333,9 @@ sub dbcopy { 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.'); } @@ -2171,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; @@ -2254,8 +2467,8 @@ sub uniqueness_check { } sub contained_map_check { - my ($url,$folder,$removefrommap,$removeparam,$addedmaps,$hierarchy,$titles, - $allmaps) = @_; + 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); @@ -2265,7 +2478,13 @@ sub contained_map_check { if ($token->[1] eq 'resource') { next if ($token->[2]->{'type'} eq 'zombie'); my $ressrc = $token->[2]->{'src'}; - if ($folder =~ /^supplemental/) { + if ($ressrc =~ m{^/adm/($match_domain)/$match_courseid/\d+/ext\.tool$}) { + my $srcdom = $1; + unless ($srcdom eq $coursedom) { + $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc; + next; + } + } elsif ($folder =~ /^supplemental/) { unless (&supp_pasteable($ressrc)) { $removefrommap->{$url}{$token->[2]->{'id'}} = $ressrc; next; @@ -2284,8 +2503,8 @@ sub contained_map_check { $addedmaps->{$ressrc} = [$url]; } } - &contained_map_check($ressrc,$folder,$removefrommap,$removeparam, - $addedmaps,$hierarchy,$titles,$allmaps); + &contained_map_check($ressrc,$folder,$coursenum,$coursedom,$removefrommap, + $removeparam,$addedmaps,$hierarchy,$titles,$allmaps); } } elsif ($token->[1] eq 'param') { if ($folder =~ /^supplemental/) { @@ -2387,16 +2606,38 @@ sub url_paste_fixups { $changed = 1; } } - } elsif ($ressrc =~ m{^/adm/($match_domain)/($match_courseid)/.+$}) { + } 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 (($rem =~ m{\d+/ext\.tool$}) && + ($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) || @@ -2559,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 = '<map>'."\n". + '<resource id="1" src="" type="start" />'."\n". + '<link from="1" to="2" index="1" />'."\n". + '<resource id="2" src="" type="finish" />'."\n". + '</map>'; + } if ($mapcontent eq '-1') { if (ref($errors) eq 'HASH') { $errors->{$key} = 1; @@ -2617,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'}; @@ -2629,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); } @@ -2660,7 +2911,8 @@ sub apply_fixups { } } } - for (my $i=0; $i<@LONCAPA::map::order; $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; @@ -2670,7 +2922,7 @@ sub apply_fixups { splice(@LONCAPA::map::order,$i,1); if (ref($currparam{$idx}) eq 'ARRAY') { foreach my $name (@{$currparam{$idx}}) { - &LONCAPA::map::delparameter($idx,'parameter_'.$name); + &LONCAPA::map::delparameter($idx,$name); } } next; @@ -2712,7 +2964,7 @@ sub apply_fixups { foreach my $idx (keys(%remparam)) { if (ref($remparam{$idx}) eq 'ARRAY') { foreach my $name (@{$remparam{$idx}}) { - &LONCAPA::map::delparameter($idx,'parameter_'.$name); + &LONCAPA::map::delparameter($idx,$name); } } } @@ -2820,7 +3072,7 @@ sub update_parameter { 'randomorder' => {}, ); foreach my $which (keys(%allchecked)) { - $env{'form.all'.$which} =~ s/,$//; + $env{'form.all'.$which} =~ s/,$//; if ($which eq 'randompick') { foreach my $item (split(/,/,$env{'form.all'.$which})) { my ($res,$value) = split(/:/,$item); @@ -2923,8 +3175,9 @@ sub update_parameter { sub handle_edit_cmd { my ($coursenum,$coursedom) =@_; + my $haschanges = 0; if ($env{'form.cmd'} eq '') { - return 0; + return $haschanges; } my ($cmd,$idx)=split('_',$env{'form.cmd'}); @@ -2939,19 +3192,19 @@ sub handle_edit_cmd { &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/) { @@ -2961,16 +3214,32 @@ sub handle_edit_cmd { # Devalidate title cache my $renamed_url=&LONCAPA::map::qtescape($url); &Apache::lonnet::devalidate_title_cache($renamed_url); - - } else { - return 0; + $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; + } } - return 1; + return $haschanges; } sub editor { my ($r,$coursenum,$coursedom,$folder,$allowed,$upload_output,$crstype, - $supplementalflag,$orderhash,$iconpath,$pathitem,$ltitoolsref,$canedit)=@_; + $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, @@ -2993,9 +3262,21 @@ sub editor { $randompick = -1; } - my ($errtext,$fatal) = &mapread($coursenum,$coursedom, - $folder.'.'.$container); - return $errtext if ($fatal); + 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(); @@ -3076,7 +3357,7 @@ sub editor { # Rename, cut, copy or remove a single resource if (&handle_edit_cmd($coursenum,$coursedom)) { my $contentchg; - if ($env{'form.cmd'} =~ m{^(remove|cut)_}) { + if ($env{'form.cmd'} =~ m{^(remove|cut|setalias|delalias)_}) { $contentchg = 1; } ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container,$contentchg); @@ -3169,7 +3450,7 @@ sub editor { } else { return $errortxt; } - } elsif ($url =~ m{^/adm/$coursedom/$coursenum/new/exttool}) { + } elsif ($url =~ m{^/adm/$coursedom/$coursenum/new/ext\.tool}) { my ($suffix,$errortxt,$locknotfreed) = &new_timebased_suffix($coursedom,$coursenum,'exttool'); if ($locknotfreed) { @@ -3284,10 +3565,12 @@ sub editor { if ($url =~ m{/uploaded/.+\.(page|sequence)$}) { push(@allmapidx,$res); } + $output .= &entryline($idx,$name,$url,$folder,$allowed,$res, $coursenum,$coursedom,$crstype, $pathitem,$supplementalflag,$container, - \%filters,\%curr_groups,$ltitoolsref,$canedit,$isencrypted); + \%filters,\%curr_groups,$ltitoolsref,$canedit, + $isencrypted,$navmapref,$hostname); $idx++; $shown++; } @@ -3314,10 +3597,10 @@ sub editor { .&Apache::loncommon::start_data_table(undef,'contentlist') .&Apache::loncommon::start_data_table_header_row() .'<th colspan="2">'.&mt('Move').'</th>' - .'<th colspan="2">'.&mt('Actions').'</th>' + .'<th colspan="3">'.&mt('Actions').'</th>' .'<th>'.&mt('Document').'</th>'; if ($folder !~ /^supplemental/) { - $to_show .= '<th colspan="4">'.&mt('Settings').'</th>'; + $to_show .= '<th colspan="2">'.&mt('Settings').'</th>'; } $to_show .= &Apache::loncommon::end_data_table_header_row(); if ($folder !~ /^supplemental/) { @@ -3335,19 +3618,18 @@ sub editor { if (@allidx > 0) { my $path; if ($env{'form.folderpath'}) { - $path = + $path = &HTML::Entities::encode($env{'form.folderpath'},'<>&"'); } if (@allidx > 1) { - $to_show .= + $to_show .= &Apache::loncommon::continue_data_table_row(). '<td colspan="2"> </td>'. '<td>'. &multiple_check_form('actions',\%lists,$canedit). '</td>'. - '<td> </td>'. - '<td> </td>'. - '<td colspan="4">'. + '<td colspan="3"> </td>'. + '<td colspan="2">'. &multiple_check_form('settings',\%lists,$canedit). '</td>'. &Apache::loncommon::end_data_table_row(); @@ -3369,9 +3651,15 @@ sub editor { 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') .'<div class="LC_info" id="contentlist">' - .&mt('Currently empty') + .$noresmsg .'</div>' .&Apache::loncommon::end_scrollbox(); } @@ -3581,7 +3869,7 @@ sub process_file_upload { my $uploadphase = 'upload_embedded'; my $primaryurl = &HTML::Entities::encode($url,'<>&"'); my $state = &embedded_form_elems($uploadphase,$primaryurl,$newidx); - my ($embedded,$num) = + my ($embedded,$num) = &Apache::loncommon::ask_for_embedded_content( '/adm/coursedocs',$state,$allfiles,$codebase,{'docs_url' => $url}); if ($embedded) { @@ -3662,7 +3950,7 @@ sub is_supplemental_title { sub entryline { my ($index,$title,$url,$folder,$allowed,$residx,$coursenum,$coursedom, $crstype,$pathitem,$supplementalflag,$container,$filtersref,$currgroups, - $ltitoolsref,$canedit,$isencrypted)=@_; + $ltitoolsref,$canedit,$isencrypted,$navmapref,$hostname)=@_; my ($foldertitle,$renametitle,$oldtitle); if (&is_supplemental_title($title)) { ($title,$foldertitle,$renametitle) = &Apache::loncommon::parse_supplemental_title($title); @@ -3689,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); + my ($esc_path, $path, $symb, $shownsymb, $curralias); if ($env{'form.folderpath'}) { $esc_path=&escape($env{'form.folderpath'}); $path = &HTML::Entities::encode($env{'form.folderpath'},'<>&"'); @@ -3758,6 +4046,8 @@ END 'ct' => 'Cut', 'rn' => 'Rename', 'cp' => 'Copy', + 'da' => 'Unset alias', + 'sa' => 'Set alias', 'ex' => 'External Resource', 'et' => 'External Tool', 'ed' => 'Edit', @@ -3765,7 +4055,7 @@ END 'sv' => 'Save', 'ul' => 'URL', 'ti' => 'Title', - 'er' => 'Editing rights unavailable for your current role', + 'er' => 'Editing rights unavailable for your current role.', ); my %denied = &action_restrictions($coursenum,$coursedom,$url, $env{'form.folderpath'}, @@ -3779,7 +4069,7 @@ END |/aboutme$ |/navmaps$ |/bulletinboard$ - |/exttools?$ + |/ext\.tool$ |\.html$)}x) || $isexternal) { $skip_confirm = 1; @@ -3788,6 +4078,9 @@ END ($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=(<<ENDCOPY) @@ -3888,6 +4181,7 @@ END my $isfolder; my $ispage; my $containerarg; + my $folderurl; if ($uploaded) { if (($extension eq 'sequence') || ($extension eq 'page')) { $url=~/\Q$coursenum\E\/([\/\w]+)\.\Q$extension\E$/; @@ -3899,6 +4193,7 @@ END $icon=$iconpath.'page.gif'; $ispage=1; } + $folderurl = &Apache::lonnet::declutter($url); if ($allowed) { $url='/adm/coursedocs?'; } else { @@ -3909,14 +4204,22 @@ END } } - my ($editlink,$extresform,$anchor); + 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); @@ -3927,46 +4230,106 @@ END } elsif ($url!~/\.(sequence|page)$/) { $url='/adm/coursedocs/showdoc'.$url; } - } elsif ($url=~m|^/ext/|) { - $url='/adm/wrapper'.$url; - } elsif ($url=~m{^/adm/$coursedom/$coursenum/\d+/exttools?$}) { + } 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; - } - 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; + } 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,$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)) { + $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; } } } - $url.=(($url=~/\?/)?'&':'?').'symb='.&HTML::Entities::encode($shownsymb,'"<>&'); - } elsif ((!$env{'request.role.adv'}) && - (((&LONCAPA::map::getparameter($orderidx,'parameter_encrypturl'))[0]=~/^yes$/i) || - $isencrypted)) { - my $shownsymb = &Apache::lonenc::encrypted($symb); - my $shownurl = &Apache::lonenc::encrypted($url); - if (&Apache::lonnet::symbverify($shownsymb,$shownurl)) { - $url = $shownurl.(($shownurl=~/\?/)?'&':'?').'symb='.&HTML::Entities::encode($shownsymb,'"<>&'); + } + 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) { + } 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; } } } - my ($rand_pick_text,$rand_order_text); + 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'}; @@ -3975,26 +4338,48 @@ END $folderpath.=$containerarg.'&'.$foldername; $url.='folderpath='.&escape($folderpath); } 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. - ':'.(&LONCAPA::map::getparameter($orderidx, - 'parameter_randompick'))[0] - .':'.((&LONCAPA::map::getparameter($orderidx, - 'parameter_hiddenresource'))[0]=~/^yes$/i) - .':'.((&LONCAPA::map::getparameter($orderidx, - 'parameter_encrypturl'))[0]=~/^yes$/i) - .':'.((&LONCAPA::map::getparameter($orderidx, - 'parameter_randomorder'))[0]=~/^yes$/i) - .':'.$ispage; - if ($env{'request.role.adv'} || - (&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]!~/^yes$/i) { + ':'.$rpicknum.':'.$hiddenmap.':'.$encryptmap.':'.$randorder.':'.$ispage; + unless ($url eq '') { $url.='folderpath='.&escape($folderpath); - } else { - $url = ''; } - my $rpicknum = (&LONCAPA::map::getparameter($orderidx, - 'parameter_randompick'))[0]; my $rpckchk; if ($rpicknum) { $rpckchk = ' checked="checked"'; @@ -4014,7 +4399,7 @@ $form_common."\n". $rand_pick_text .= '</span></span>'. $form_end; my $ro_set; - if ((&LONCAPA::map::getparameter($orderidx,'parameter_randomorder'))[0]=~/^yes$/i) { + if ($randorder) { $ro_set = 'checked="checked"'; if (($ishash) && (ref($filtersref->{'randomorder'}) eq 'ARRAY')) { push(@{$filtersref->{'randomorder'}},$orderidx); @@ -4030,7 +4415,7 @@ $form_end; } } elsif ($supplementalflag && !$allowed) { my $isexttool; - if ($url=~m{^/adm/$coursedom/$coursenum/\d+/exttools?$}) { + if ($url=~m{^/adm/$coursedom/$coursenum/\d+/ext\.tool$}) { $url='/adm/wrapper'.$url; $isexttool = 1; } @@ -4048,14 +4433,14 @@ $form_end; } my ($tdalign,$tdwidth); if ($allowed) { - my $fileloc = + my $fileloc = &Apache::lonnet::declutter(&Apache::lonnet::filelocation('',$orig_url)); if ($isexternal) { - ($editlink,$extresform) = + ($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+/exttools?$}) { + } 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, @@ -4068,13 +4453,14 @@ $form_end; if ($supplementalflag) { $suppanchor = $anchor; } - my $jscall = + my $jscall = &Apache::lonhtmlcommon::jump_to_editres($cfile,$home, $switchserver, $forceedit, - undef,$symb, + undef,$symb,$shownsymb, &escape($env{'form.folderpath'}), - $renametitle,'','',1,$suppanchor); + $renametitle,$hostname, + '','',1,$suppanchor); if ($jscall) { $editlink = '<a class="LC_docs_ext_edit" href="javascript:'. $jscall.'" >'.&mt('Edit').'</a> '."\n"; @@ -4091,6 +4477,18 @@ $form_end; $reinit = &mt('(re-initialize course to access)'); } $line.='<td class="LC_docs_entry_commands"'.$tdalign.'><span class="LC_nobreak">'.$editlink.$renamelink; + if ($orig_url =~ /$LONCAPA::assess_re/) { + $line.= '<br />'; + if ($curralias ne '') { + $line.='<span class="LC_nobreak"><a href="javascript:delalias('."'$esc_path','$orderidx'".');" class="LC_docs_alias">'. + $lt{'da'}.'</a></span>'; + } else { + $line.='<span class="LC_nobreak"><a href="javascript:setalias('."'$esc_path','$orderidx'".');" class="LC_docs_alias">'. + $lt{'sa'}.'</a></span>'; + } + } + $line.='</td><td>'; + my $link; if (($url=~m{/adm/(coursedocs|supplemental)}) || (!$allowed && $url)) { $line.='<a href="'.$url.'"><img src="'.$icon.'" alt="" class="LC_icon" /></a>'; } elsif ($url) { @@ -4101,9 +4499,19 @@ $form_end; $anchor = '#'.&HTML::Entities::encode($anchor,'"<>&'); } } - $line.=&Apache::loncommon::modal_link($url.(($url=~/\?/)?'&':'?').'inhibitmenu=yes'. - (($anchor ne '')?$anchor:''), - '<img src="'.$icon.'" alt="" class="LC_icon" />',600,500); + if ((!$supplementalflag) && ($nomodal) && ($hostname ne '')) { + $link = 'http://'.$hostname.$url; + } else { + $link = $url; + } + $link = &js_escape($link.(($url=~/\?/)?'&':'?').'inhibitmenu=yes'.$anchor); + if ($nomodal) { + $line.='<a href="#" onclick="javascript:window.open('."'$link','syllabuspreview','height=400,width=500,scrollbars=1,resizable=1,menubar=0,location=1')".'; return false;" />'. + '<img src="'.$icon.'" alt="" class="LC_icon" border="0" /></a>'; + } else { + $line.=&Apache::loncommon::modal_link($link, + '<img src="'.$icon.'" alt="" class="LC_icon" />',600,500); + } } else { $line.='<img src="'.$icon.'" alt="" class="LC_icon" />'; } @@ -4111,13 +4519,23 @@ $form_end; if (($url=~m{/adm/(coursedocs|supplemental)}) || (!$allowed && $url)) { $line.='<a href="'.$url.'">'.$title.'</a>'; } elsif ($url) { - $line.=&Apache::loncommon::modal_link($url.(($url=~/\?/)?'&':'?').'inhibitmenu=yes'. - (($anchor ne '')?$anchor:''), - $title,600,500); + if ($nomodal) { + $line.='<a href="#" onclick="javascript:window.open('."'$link','syllabuspreview','height=400,width=500,scrollbars=1,resizable=1,menubar=0,location=1')".'; return false;" />'. + $title.'</a>'; + } else { + $line.=&Apache::loncommon::modal_link($link,$title,600,500); + } + } elsif (($hiddenfolder) || ($hiddenres)) { + $line.=$title.' <span class="LC_warning LC_docs_reinit_warn">('.&mt('Hidden').')</span>'; } else { $line.=$title.' <span class="LC_docs_reinit_warn">'.$reinit.'</span>'; } - $line.="$extresform</td>"; + if (($allowed) && ($curralias ne '')) { + $line .= '<br /><span class="LC_docs_alias_name">('.$curralias.')</span>'; + } else { + $line .= $extresform; + } + $line .= '</td>'; $rand_pick_text = ' ' if ($rand_pick_text eq ''); $rand_order_text = ' ' if ($rand_order_text eq ''); if (($allowed) && ($folder!~/^supplemental/)) { @@ -4252,6 +4670,8 @@ sub new_timebased_suffix { $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.'); } @@ -4260,7 +4680,7 @@ sub new_timebased_suffix { } } if ($freedlock ne 'ok') { - $locknotfreed = + $locknotfreed = '<div class="LC_error">'. &mt('There was a problem removing a lockfile.').' '; if ($type eq 'paste') { @@ -4280,6 +4700,9 @@ sub new_timebased_suffix { } 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.'); @@ -4330,7 +4753,7 @@ sub untiehash { sub checkonthis { - my ($r,$url,$level,$title)=@_; + my ($r,$url,$level,$title,$checkstale)=@_; $url=&unescape($url); $alreadyseen{$url}=1; $r->rflush(); @@ -4345,10 +4768,22 @@ sub checkonthis { $r->print('<a href="'.$url.'" target="cat">'. ($title?$title:$url).'</a> '); 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 eq 'ok') { $r->print('<span class="LC_success">'.&mt('ok').'</span>'); + if ($updated) { + $r->print('<br />'); + for (my $i=0;$i<=$level*5;$i++) { + $r->print(' '); + } + $r->print('- '.&mt('Outdated copy removed')); + } $r->rflush(); &Apache::lonnet::countacc($url); $url=~/\.(\w+)$/; @@ -4382,7 +4817,7 @@ sub checkonthis { &Apache::lonnet::metadata($url,'dependencies'); foreach my $dep (split(/\,/,$dependencies)) { if (($dep=~/^\/res\//) && (!$alreadyseen{$dep})) { - &checkonthis($r,$dep,$level+1); + &checkonthis($r,$dep,$level+1,'',$checkstale); } } } elsif ($result eq 'unavailable') { @@ -4396,6 +4831,9 @@ sub checkonthis { } else { $r->print('<span class="LC_error">'.&mt('access denied').'</span>'); } + if (($updated) && ($result ne 'ok')) { + $r->print('<br />'.&mt('Outdated copy removed')); + } } } } @@ -4448,13 +4886,75 @@ 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('<h4 class="LC_info">'.&mt('Tiny URLs for deep-linking into course').'</h4>'."\n"); + $r->rflush(); + my $readonly; + if ($canedit) { + my ($numnew,$errors) = &Apache::loncommon::get_requested_shorturls($cdom,$cnum,$navmap); + if ($numnew) { + $r->print('<p class="LC_info">'.&mt('Created [quant,_1,URL]',$numnew).'</p>'); + } + if ((ref($errors) eq 'ARRAY') && (@{$errors} > 0)) { + $r->print(&mt('The following errors occurred when processing your request to create shortened URLs:').'<br /><ul>'); + foreach my $error (@{$errors}) { + $r->print('<li>'.$error.'</li>'); + } + $r->print('</ul><br />'); + } + } 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 verifycontent { +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('<h4 class="LC_info">'.&mt($crstype.' content verification').'</h4>'); + $r->print('<form method="post" action="/adm/coursedocs"><p>'. + &mt('Include a check if files copied from elsewhere are up to date (will increase verification time)?'). + ' <span class="LC_nobreak">'. + '<label><input type="radio" name="checkstale" value="0" checked="checked" />'. + &mt('No').'</label>'.(' 'x2). + '<label><input type="radio" name="checkstale" value="1" />'. + &mt('Yes').'</label></span></p><p>'. + '<input type="submit" value="'.&mt('Verify Content').' "/>'. + '<input type="hidden" value="1" name="tools" />'. + '<input type="hidden" value="1" name="verify" /></p></form>'); + $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('<h4 class="LC_info">'.&mt($crstype.' content verification').'</h4>'); $hashtied=0; undef %alreadyseen; @@ -4471,7 +4971,7 @@ sub verifycontent { } } if (($key=~/^src\_(.+)$/) && (!$alreadyseen{&unescape($hash{$key})})) { - &checkonthis($r,$hash{$key},0,$hash{'title_'.$1}); + &checkonthis($r,$hash{$key},0,$hash{'title_'.$1},$checkstale); } } &untiehash(); @@ -4479,7 +4979,6 @@ sub verifycontent { $r->print(&endContentScreen()); } - sub devalidateversioncache { my $src=shift; &Apache::lonnet::devalidate_cache_new('courseresversion',$env{'request.course.id'}.'_'. @@ -4799,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". '<script type="text/javascript">'."\n". '// <![CDATA['."\n". 'function reinit(tf) { tf.submit();'.$postexec.' }'."\n". '// ]]>'."\n". '</script>'."\n". -'<form name="reinitform" method="post" action="/adm/roles" target="loncapaclient">'. +'<form name="reinitform" method="post" action="/adm/roles" target="'.$windowname.'">'. '<input type="hidden" name="orgurl" value="'.$url. '" /><input type="hidden" name="selectrole" value="1" /><p class="LC_warning">'. &mt($message,' <input type="hidden" name="'. @@ -4905,12 +5408,12 @@ sub handler { # # --------------------------------------------- Initialize help topics for this foreach my $topic ('Adding_Course_Doc','Main_Course_Documents', - 'Adding_External_Resource','Navigate_Content', - 'Adding_Folders','Docs_Overview', 'Load_Map', - 'Supplemental','Score_Upload_Form','Adding_Pages', - 'Importing_LON-CAPA_Resource','Importing_IMS_Course', - 'Uploading_From_Harddrive','Course_Roster','Web_Page', - 'Dropbox','Simple_Problem') { + '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') { $help{$topic}=&Apache::loncommon::help_open_topic('Docs_'.$topic); } # Composite help files @@ -4942,12 +5445,31 @@ sub handler { $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'); - &verifycontent($r); + 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'}; @@ -5011,6 +5533,8 @@ sub handler { $r->internal_redirect($redirect); return OK; } + } else { + $r->internal_redirect($redirect); } } } @@ -5024,6 +5548,26 @@ sub handler { '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 @@ -5046,6 +5590,14 @@ sub handler { my $toolsflag=0; if ($env{'form.tools'}) { $toolsflag=1; } + if ($env{'form.folderpath'} ne '') { + &validate_folderpath($supplementalflag); + } + + if ($env{'form.supppath'} ne '') { + &validate_suppath(); + } + my $script=''; my $showdoc=0; my $addentries = {}; @@ -5053,13 +5605,15 @@ sub handler { my $containertag; my $pathitem; my %ltitools; + my $hiddentop; + my $navmap; + my $filterFunc = sub { my $res = shift; return (!$res->randomout() && !$res->is_map()) }; # Do we directly jump somewhere? - if (($env{'form.command'} eq 'direct') || ($env{'form.command'} eq 'directnav')) { if ($env{'form.symb'} ne '') { $env{'form.folderpath'}= - &Apache::loncommon::symb_to_docspath($env{'form.symb'}); + &Apache::loncommon::symb_to_docspath($env{'form.symb'},\$navmap); &Apache::lonnet::appenv({'docs.exit.'.$env{'request.course.id'} => $env{'form.command'}.'_'.$env{'form.symb'}}); } elsif ($env{'form.supppath'} ne '') { @@ -5068,12 +5622,10 @@ sub handler { $env{'form.command'}.'_'.$env{'form.supppath'}}); } } elsif ($env{'form.command'} eq 'editdocs') { - $env{'form.folderpath'} = 'default&'. - &escape(&mt('Main Content').':::::'); + $env{'form.folderpath'} = &default_folderpath($coursenum,$coursedom,\$navmap); &Apache::lonnet::appenv({'docs.exit.'.$env{'request.course.id'} => $env{'form.command'}}); } elsif ($env{'form.command'} eq 'editsupp') { - $env{'form.folderpath'} = 'supplemental&'. - &escape('Supplemental Content'); + $env{'form.folderpath'} = &supplemental_base(); &Apache::lonnet::appenv({'docs.exit.'.$env{'request.course.id'} => '/adm/supplemental'}); } elsif ($env{'form.command'} eq 'contents') { &Apache::lonnet::appenv({'docs.exit.'.$env{'request.course.id'} => '/adm/navmaps'}); @@ -5092,9 +5644,19 @@ sub handler { if ((!$env{'form.folderpath'}) && $allowed) { &Apache::loncommon::restore_course_settings($stored_folderpath, {'folderpath' => 'scalar'}); - unless (&unescape($env{'form.folderpath'}) =~ m{^(default|supplemental)&}) { + + if (&unescape($env{'form.folderpath'}) =~ m{^(default|supplemental)&}) { + if ($supplementalflag) { + undef($env{'form.folderpath'}) if ($1 eq 'default'); + } else { + undef($env{'form.folderpath'}) if ($1 eq 'supplemental'); + } + } else { undef($env{'form.folderpath'}); } + if ($env{'form.folderpath'} ne '') { + &validate_folderpath($supplementalflag); + } } # If we are not allowed to make changes, all we can see are supplemental docs @@ -5109,19 +5671,48 @@ sub handler { .'&'. $env{'form.folderpath'}; } +# If allowed and user's role is not advanced check folderpath is not hidden + if (($allowed) && (!$env{'request.role.adv'}) && + ($env{'form.folderpath'} ne '') && (!$supplementalflag)) { + my $folderurl; + my @pathitems = split(/\&/,$env{'form.folderpath'}); + my $folder = $pathitems[-2]; + if ($folder eq '') { + undef($env{'form.folderpath'}); + } else { + $folderurl = "uploaded/$coursedom/$coursenum/$folder"; + if ((split(/\:/,$pathitems[-1]))[5]) { + $folderurl .= '.page'; + } else { + $folderurl .= '.sequence'; + } + unless (ref($navmap)) { + $navmap = Apache::lonnavmaps::navmap->new(); + } + if (ref($navmap)) { + if (lc($navmap->get_mapparam(undef,$folderurl,"0.hiddenresource")) eq 'yes') { + my @resources = $navmap->retrieveResources($folderurl,$filterFunc,1,1); + unless (@resources) { + undef($env{'form.folderpath'}); + } + } + } + } + } + + # If after all of this, we still don't have any paths, make them unless ($env{'form.folderpath'}) { if ($supplementalflag) { $env{'form.folderpath'}=&supplemental_base(); - } else { - $env{'form.folderpath'}='default&'.&escape(&mt('Main Content'). - ':::::'); + } elsif ($allowed) { + ($env{'form.folderpath'},$hiddentop) = &default_folderpath($coursenum,$coursedom,\$navmap); } } # Store this unless ($toolsflag) { - if ($allowed) { + if (($allowed) && ($env{'form.folderpath'} ne '')) { &Apache::loncommon::store_course_settings($stored_folderpath, {'folderpath' => 'scalar'}); } @@ -5139,8 +5730,12 @@ sub handler { } else { if ($env{'form.folder'} eq '' || $env{'form.folder'} eq 'supplemental') { - $folderpath='default&'. - &escape(&mt('Main Content').':::::'); + if ($env{'form.folder'} eq 'supplemental') { + $folderpath=&supplemental_base(); + } elsif (!$hiddentop) { + $folderpath='default&'. + &escape(&mt('Main Content').':::::'); + } } } $containertag = '<input type="hidden" name="folderpath" value="" />'; @@ -5180,7 +5775,7 @@ sub handler { my $tid = 1; my @tabids; if ($supplementalflag) { - @tabids = ('002','ee2','ff2'); + @tabids = ('002','dd2','ee2','ff2'); $tid = 2; } else { @tabids = ('aa1','bb1','cc1','ff1'); @@ -5190,10 +5785,11 @@ sub handler { } } my $tabidstr = join("','",@tabids); - %ltitools = &Apache::lonnet::get_domain_ltitools($coursedom); + %ltitools = &Apache::lonnet::get_domain_lti($coursedom,'consumer'); my $posslti = keys(%ltitools); + my $hostname = $r->hostname(); $script .= &editing_js($udom,$uname,$supplementalflag,$coursedom,$coursenum,$posslti, - $londocroot,$canedit). + $londocroot,$canedit,$hostname,\$navmap). &history_tab_js(). &inject_data_js(). &Apache::lonhtmlcommon::resize_scrollbox_js('docs',$tabidstr,$tid). @@ -5225,7 +5821,7 @@ sub handler { {'force_register' => $showdoc,})); } elsif ($toolsflag) { my ($breadtext,$breadtitle); - $breadtext = "$crstype Contents"; + $breadtext = "$crstype Editor"; if ($canedit) { $breadtitle = 'Editing '.$crstype.' Contents'; } else { @@ -5245,7 +5841,7 @@ sub handler { {'bread_crumbs' => $brcrum,})); } else { my ($breadtext,$breadtitle,$helpitem); - $breadtext = "$crstype Contents"; + $breadtext = "$crstype Editor"; if ($canedit) { $breadtitle = 'Editing '.$crstype.' Contents'; $helpitem = 'Docs_Adding_Course_Doc'; @@ -5277,6 +5873,7 @@ sub handler { undef($hadchanges); $uploadphase = &process_file_upload(\$upload_output,$coursenum,$coursedom, \%allfiles,\%codebase,$context,$crstype); + undef($navmap); if ($hadchanges) { &mark_hash_old(); } @@ -5292,7 +5889,7 @@ sub handler { my ($destination,$dir_root) = &embedded_destination(); my $url_root = '/uploaded/'.$docudom.'/'.$docuname; my $actionurl = '/adm/coursedocs'; - my ($result,$flag) = + my ($result,$flag) = &Apache::loncommon::upload_embedded('coursedoc',$destination, $docuname,$docudom,$dir_root,$url_root,undef,undef,undef,$state, $actionurl); @@ -5303,11 +5900,11 @@ sub handler { 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 = + my $result = &Apache::loncommon::modify_html_refs('coursedoc',$destination, $docuname,$docudom,undef, $dir_root); - $r->print($result.&return_to_editor()); + $r->print($result.&return_to_editor()); } elsif ($env{'form.phase'} eq 'decompress_uploaded') { $uploadphase = 'decompress_phase_one'; $r->print(&decompression_phase_one(). @@ -5333,7 +5930,7 @@ sub handler { 'impo' => 'Import', 'lnks' => 'Import from Stored Links', 'impm' => 'Import from Assembled Map', - 'imcr' => 'Import from Course Resources', + 'imcr' => 'Import from Course Resources', 'extr' => 'External Resource', 'extt' => 'External Tool', 'selm' => 'Select Map', @@ -5344,7 +5941,7 @@ sub handler { 'navc' => 'Table of Contents', 'sipa' => 'Simple Course Page', 'sipr' => 'Simple Problem', - 'webp' => 'Blank Web Page (editable)', + 'webp' => 'Blank Web Page (editable)', 'stpr' => 'Standard Problem', 'news' => 'New sub-directory', 'crpr' => 'Create Problem', @@ -5376,7 +5973,7 @@ sub handler { 'webctce4' => 'WebCT 4 Campus Edition', 'yes' => 'Yes', 'no' => 'No', - 'er' => 'Editing rights unavailable for your current role', + 'er' => 'Editing rights unavailable for your current role.', ); # ----------------------------------------------------------------------------- @@ -5406,7 +6003,7 @@ sub handler { if ($disk_quota == 0) { $percent = 100.0; } else { - $percent = 100*($current_disk_usage/$disk_quota); + $percent = 100*($usage/$disk_quota); } $usage = sprintf("%.2f",$usage); $quota = sprintf("%.2f",$quota); @@ -5417,8 +6014,8 @@ sub handler { my $fileupload=(<<FIUP); $quotainfo $lt{'file'}:<br /> - <input type="file" name="uploaddoc" class="flUpload" size="40" $disabled /> - <input type="hidden" id="free_space" value="$free_space" /> + <input type="file" name="uploaddoc" class="LC_flUpload" size="40" $disabled /> + <input type="hidden" id="LC_free_space" value="$free_space" /> FIUP my $checkbox=(<<CHBO); @@ -5559,9 +6156,11 @@ CRSFORM if ($folder eq '') { $folder='default'; } - my $output = &update_paste_buffer($coursenum,$coursedom,$folder); - if ($output) { - $r->print($output); + if ($canedit) { + my $output = &update_paste_buffer($coursenum,$coursedom,$folder); + if ($output) { + $r->print($output); + } } $r->print(<<HIDDENFORM); <form name="renameform" method="post" action="/adm/coursedocs"> @@ -5571,6 +6170,11 @@ CRSFORM <input type="hidden" name="copyfolder" /> $containertag </form> + <form name="aliasform" method="post" action="/adm/coursedocs"> + <input type="hidden" name="alias" /> + <input type="hidden" name="cmd" /> + $containertag + </form> HIDDENFORM $r->print(&makesimpleeditform($pathitem)."\n". @@ -5593,12 +6197,12 @@ HIDDENFORM } # - + my $hostname = $r->hostname(); my $savefolderpath; if ($allowed) { my $folder=$env{'form.folder'}; - if ($folder eq '' || $supplementalflag) { + if ((($folder eq '') && (!$hiddentop)) || ($supplementalflag)) { $folder='default'; $savefolderpath = $env{'form.folderpath'}; $env{'form.folderpath'}='default&'.&escape(&mt('Main Content')); @@ -5607,9 +6211,13 @@ HIDDENFORM } my $postexec=''; if ($folder eq 'default') { + my $windowname = 'loncapaclient'; + if ($env{'request.lti.login'}) { + $windowname .= 'lti'; + } $r->print('<script type="text/javascript">'."\n" .'// <![CDATA['."\n" - .'this.window.name="loncapaclient";'."\n" + .'this.window.name="'.$windowname.'";'."\n" .'// ]]>'."\n" .'</script>'."\n" ); @@ -5622,7 +6230,7 @@ HIDDENFORM my $newnavform=(<<NNFORM); <form action="/adm/coursedocs" method="post" name="newnav"> - <input type="hidden" name="active" value="ee" /> + <input type="hidden" name="active" value="ff" /> $pathitem <input type="hidden" name="importdetail" value="$lt{'navc'}=/adm/navmaps" /> @@ -5632,7 +6240,7 @@ HIDDENFORM NNFORM my $newsmppageform=(<<NSPFORM); <form action="/adm/coursedocs" method="post" name="newsmppg"> - <input type="hidden" name="active" value="ee" /> + <input type="hidden" name="active" value="ff" /> $pathitem <input type="hidden" name="importdetail" value="" /> <a class="LC_menubuttons_link" href="javascript:makesmppage();"> $lt{'sipa'}</a> @@ -5642,7 +6250,7 @@ NSPFORM my $newsmpproblemform=(<<NSPROBFORM); <form action="/adm/coursedocs" method="post" name="newsmpproblem"> - <input type="hidden" name="active" value="cc" /> + <input type="hidden" name="active" value="dd" /> $pathitem <input type="hidden" name="importdetail" value="" /> <a class="LC_menubuttons_link" href="javascript:makesmpproblem();">$lt{'sipr'}</a> @@ -5653,7 +6261,7 @@ NSPROBFORM my $newdropboxform=(<<NDBFORM); <form action="/adm/coursedocs" method="post" name="newdropbox"> - <input type="hidden" name="active" value="cc" /> + <input type="hidden" name="active" value="dd" /> $pathitem <input type="hidden" name="importdetail" value="" /> <a class="LC_menubuttons_link" href="javascript:makedropbox();">$lt{'drbx'}</a> @@ -5663,7 +6271,7 @@ NDBFORM my $newexuploadform=(<<NEXUFORM); <form action="/adm/coursedocs" method="post" name="newexamupload"> - <input type="hidden" name="active" value="cc" /> + <input type="hidden" name="active" value="dd" /> $pathitem <input type="hidden" name="importdetail" value="" /> <a class="LC_menubuttons_link" href="javascript:makeexamupload();">$lt{'scuf'}</a> @@ -5673,7 +6281,7 @@ NEXUFORM my $newbulform=(<<NBFORM); <form action="/adm/coursedocs" method="post" name="newbul"> - <input type="hidden" name="active" value="dd" /> + <input type="hidden" name="active" value="ee" /> $pathitem <input type="hidden" name="importdetail" value="" /> <a class="LC_menubuttons_link" href="javascript:makebulboard();" >$lt{'bull'}</a> @@ -5683,7 +6291,7 @@ NBFORM my $newaboutmeform=(<<NAMFORM); <form action="/adm/coursedocs" method="post" name="newaboutme"> - <input type="hidden" name="active" value="dd" /> + <input type="hidden" name="active" value="ee" /> $pathitem <input type="hidden" name="importdetail" value="$plainname=/adm/$udom/$uname/aboutme" /> @@ -5694,7 +6302,7 @@ NAMFORM my $newaboutsomeoneform=(<<NASOFORM); <form action="/adm/coursedocs" method="post" name="newaboutsomeone"> - <input type="hidden" name="active" value="dd" /> + <input type="hidden" name="active" value="ee" /> $pathitem <input type="hidden" name="importdetail" value="" /> <a class="LC_menubuttons_link" href="javascript:makeabout();">$lt{'abou'}</a> @@ -5703,7 +6311,7 @@ NASOFORM my $newrosterform=(<<NROSTFORM); <form action="/adm/coursedocs" method="post" name="newroster"> - <input type="hidden" name="active" value="dd" /> + <input type="hidden" name="active" value="ee" /> $pathitem <input type="hidden" name="importdetail" value="$lt{'rost'}=/adm/viewclasslist" /> @@ -5724,7 +6332,7 @@ NROSTFORM } my $newwebpageform =(<<NWEBFORM); <form action="/adm/coursedocs" method="post" name="newwebpage"> - <input type="hidden" name="active" value="ee" /> + <input type="hidden" name="active" value="ff" /> $pathitem <input type="hidden" name="importdetail" value="$newwebpage" /> <a class="LC_menubuttons_link" href="javascript:makewebpage();">$lt{'webp'}</a> @@ -5791,7 +6399,7 @@ NWEBFORM $numauthor ++; } } - my ($pickdir,$showtitle);; + my ($pickdir,$showtitle); if ($numauthor) { my @order; my $defrole; @@ -5907,7 +6515,7 @@ NWEBFORM <form action="/adm/coursedocs" method="post" name="courseresform"> <fieldset id="crsresform" style="display:none;"> <legend>$lt{'stpr'}</legend> - <input type="hidden" name="active" value="ee" /> + <input type="hidden" name="active" value="bb" /> <p> $pickdir <span class="LC_nobreak">$lt{'news'}? @@ -5995,7 +6603,7 @@ NSYLFORM my $newgroupfileform=(<<NGFFORM); <form action="/adm/coursedocs" method="post" name="newgroupfiles"> - <input type="hidden" name="active" value="dd" /> + <input type="hidden" name="active" value="ee" /> $pathitem <input type="hidden" name="importdetail" value="$lt{'grpo'}=/adm/$coursedom/$coursenum/aboutme" /> @@ -6003,24 +6611,32 @@ NSYLFORM $help{'Group Portfolio'} </form> NGFFORM - @specialdocumentsforma=( + if ($container eq 'page') { + @specialdocumentsforma=( + {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/webpage.png" alt="'.$lt{webp}.'" onclick="javascript:makewebpage();" />'=>$newwebpageform}, + ); + } else { + @specialdocumentsforma=( {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/page.png" alt="'.$lt{newp}.'" onclick="javascript:makenewpage(document.newpage,\''.$pageseq.'\');" />'=>$newpageform}, - {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/syllabus.png" alt="'.$lt{syll}.'" onclick="makenew(document.newsyl);" />'=>$newsylform}, + {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/syllabus.png" alt="'.$lt{syll}.'" onclick="javascript:makenew(document.newsyl);" />'=>$newsylform}, {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/navigation.png" alt="'.$lt{navc}.'" onclick="javascript:makenew(document.newnav);" />'=>$newnavform}, {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/simple.png" alt="'.$lt{sipa}.'" onclick="javascript:makesmppage();" />'=>$newsmppageform}, {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/webpage.png" alt="'.$lt{webp}.'" onclick="javascript:makewebpage();" />'=>$newwebpageform}, - ); + ); + } $specialdocumentsform = &create_form_ul(&create_list_elements(@specialdocumentsforma)); - - my @importdoc = ( - {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/extres.png" alt="'.$lt{extr}.'" onclick="toggleUpload(\'ext\');" />'=>$extresourcesform} + my @external = ( + {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/extres.png" alt="'.$lt{extr}.'" onclick="toggleExternal(\'ext\');" />'=>$extresourcesform} ); if (keys(%ltitools)) { - push(@importdoc, - {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/extres.png" alt="'.$lt{extt}.'" onclick="toggleUpload(\'tool\');" />'=>$exttoolform}, - ); + push(@external, + {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/exttool.png" alt="'.$lt{extt}.'" onclick="toggleExternal(\'tool\');" />'=>$exttoolform}, + ); } + my $externalform = &create_form_ul(&create_list_elements(@external)); + + my @importdoc = (); unless ($container eq 'page') { push(@importdoc, {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/ims.png" alt="'.$lt{imsf}.'" onclick="javascript:toggleUpload(\'ims\');" />'=>$imspform} @@ -6051,24 +6667,29 @@ NGFFORM my %orderhash = ( 'aa' => ['Upload',$fileuploadform], 'bb' => ['Import',$importpubform], - 'cc' => ['Grading',$gradingform], + 'cc' => ['External',$externalform], + 'dd' => ['Grading',$gradingform], + 'ff' => ['Other',$specialdocumentsform], ); unless ($container eq 'page') { $orderhash{'00'} = ['Newfolder',$newfolderform]; - $orderhash{'dd'} = ['Collaboration',$communityform]; - $orderhash{'ee'} = ['Other',$specialdocumentsform]; + $orderhash{'ee'} = ['Collaboration',$communityform]; } $hadchanges=0; unless (($supplementalflag || $toolsflag)) { my $error = &editor($r,$coursenum,$coursedom,$folder,$allowed,'',$crstype, - $supplementalflag,\%orderhash,$iconpath,$pathitem,\%ltitools,$canedit); + $supplementalflag,\%orderhash,$iconpath,$pathitem, + \%ltitools,$canedit,$hostname,\$navmap,$hiddentop); + undef($navmap); if ($error) { $r->print('<p><span class="LC_error">'.$error.'</span></p>'); } if ($hadchanges) { - &mark_hash_old(); - } + unless (&is_hash_old()) { + &mark_hash_old(); + } + } &changewarning($r,''); } @@ -6098,7 +6719,7 @@ unless ($container eq 'page') { <form action="/adm/coursedocs" method="post" name="supuploaddocument" enctype="multipart/form-data"> <fieldset id="uploadsuppdocform" style="display: none;"> <legend>$lt{'upfi'}</legend> - <input type="hidden" name="active" value="ee" /> + <input type="hidden" name="active" value="ee" /> $fileupload <br /> <br /> @@ -6181,22 +6802,22 @@ SWEBFORM my @specialdocs = ( - {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/syllabus.png" alt="'.$lt{syll}.'" onclick="makenew(document.supnewsyl);" />' + {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/syllabus.png" alt="'.$lt{syll}.'" onclick="javascript:makenew(document.supnewsyl);" />' =>$supnewsylform}, {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/myaboutme.png" alt="'.$lt{mypi}.'" onclick="javascript:makenew(document.supnewaboutme);" />' =>$supnewaboutmeform}, {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/webpage.png" alt="'.$lt{webp}.'" onclick="javascript:makewebpage('."'supp'".');" />'=>$supwebpageform}, ); -my @supimportdoc = ( - {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/extres.png" alt="'.$lt{extr}.'" onclick="javascript:toggleUpload(\'suppext\')" />' - =>$supextform}); + my @supexternal = ( + {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/extres.png" alt="'.$lt{extr}.'" onclick="javascript:toggleExternal(\'suppext\')" />' + =>$supextform}); if (keys(%ltitools)) { - push(@supimportdoc, - {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/extres.png" alt="'.$lt{extt}.'" onclick="javascript:toggleUpload(\'supptool\')" />' + push(@supexternal, + {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/exttool.png" alt="'.$lt{extt}.'" onclick="javascript:toggleExternal(\'supptool\')" />' =>$supexttoolform}); } - push(@supimportdoc, + my @supimportdoc = ( {'<img class="LC_noBorder LC_middle" src="/res/adm/pages/pdfupload.png" alt="'.$lt{upl}.'" onclick="javascript:toggleUpload(\'suppdoc\');" />' =>$supupdocform}, ); @@ -6204,12 +6825,14 @@ my @supimportdoc = ( $supupdocform = &create_form_ul(&create_list_elements(@supimportdoc)); my %suporderhash = ( '00' => ['Supnewfolder', $supnewfolderform], - 'ee' => ['Upload',$supupdocform], + 'dd' => ['Upload',$supupdocform], + 'ee' => ['External',&create_form_ul(&create_list_elements(@supexternal))], 'ff' => ['Other',&create_form_ul(&create_list_elements(@specialdocs))] ); if ($supplementalflag) { my $error = &editor($r,$coursenum,$coursedom,$folder,$allowed,'',$crstype, - $supplementalflag,\%suporderhash,$iconpath,$pathitem,\%ltitools,$canedit); + $supplementalflag,\%suporderhash,$iconpath,$pathitem, + \%ltitools,$canedit,$hostname); if ($error) { $r->print('<p><span class="LC_error">'.$error.'</span></p>'); } else { @@ -6224,12 +6847,12 @@ my %suporderhash = ( } &Apache::lonnet::get_numsuppfiles($coursenum,$coursedom,1); undef($suppchanges); - } - } + } + } } } elsif ($supplementalflag) { my $error = &editor($r,$coursenum,$coursedom,$folder,$allowed,'',$crstype, - $supplementalflag,'',$iconpath,$pathitem,$canedit); + $supplementalflag,'',$iconpath,$pathitem,'','',$hostname); if ($error) { $r->print('<p><span class="LC_error">'.$error.'</span></p>'); } @@ -6256,7 +6879,7 @@ my %suporderhash = ( &entryline(0,&mt("Click to download or use your browser's Save Link function"),$showdoc).'</table>'); } } - unless ($noendpage) { + unless ($noendpage) { $r->print(&Apache::loncommon::end_page()); } return OK; @@ -6265,6 +6888,7 @@ my %suporderhash = ( sub embedded_form_elems { my ($phase,$primaryurl,$newidx) = @_; my $folderpath = &HTML::Entities::encode($env{'form.folderpath'},'<>&"'); + $newidx =~s /\D+//g; return <<STATE; <input type="hidden" name="folderpath" value="$folderpath" /> <input type="hidden" name="cmd" value="upload_embedded" /> @@ -6285,7 +6909,11 @@ sub embedded_destination { } elsif ($folder =~ /^(default|supplemental)_(\d+)$/) { $destination .= $2.'/'; } - $destination .= $env{'form.newidx'}; + my $newidx = $env{'form.newidx'}; + $newidx =~s /\D+//g; + if ($newidx) { + $destination .= $newidx; + } my $dir_root = '/userfiles'; return ($destination,$dir_root); } @@ -6311,6 +6939,9 @@ sub decompression_info { } unshift(@hiddens,$pathitem); foreach my $item (@hiddens) { + if ($item eq 'newidx') { + next if ($env{'form.'.$item} =~ /\D/); + } if ($env{'form.'.$item}) { $hiddenelem .= '<input type="hidden" name="'.$item.'" value="'. &HTML::Entities::encode($env{'form.'.$item},'<>&"').'" />'."\n"; @@ -6328,7 +6959,7 @@ sub decompression_phase_one { $error = &mt('Archive file "[_1]" not in the expected location.',$env{'form.archiveurl'}); } else { my $file = $1; - $output = + $output = &Apache::loncommon::process_decompression($docudom,$docuname,$file, $destination,$dir_root, $hiddenelem); @@ -6423,6 +7054,7 @@ sub generate_admin_menu { 'vc' => 'Verify Content', 'cv' => 'Check/Set Resource Versions', 'ls' => 'List Resource Identifiers', + 'ct' => 'Display/Set Shortened URLs for Deep-linking', 'imse' => 'Export contents to IMS Archive', 'dcd' => "Copy $crstype Content to Authoring Space", ); @@ -6473,6 +7105,13 @@ sub generate_admin_menu { icon => 'symbs.png', linktitle => "List the unique identifier used for each resource instance in your $lc_crstype" }, + { linktext => $lt{'ct'}, + url => "javascript:injectData(document.courseverify,'dummy','shorturls','$lt{'ct'}')", + permission => 'F', + help => 'Docs_Short_URLs', + icon => 'shorturls.png', + linktitle => "Set shortened URLs for a resource or folder in your $lc_crstype for use in deep-linking" + }, ] }); if ($canedit) { @@ -6603,7 +7242,8 @@ END } sub editing_js { - my ($udom,$uname,$supplementalflag,$coursedom,$coursenum,$posslti,$londocroot,$canedit) = @_; + my ($udom,$uname,$supplementalflag,$coursedom,$coursenum,$posslti, + $londocroot,$canedit,$hostname,$navmapref) = @_; my %js_lt = &Apache::lonlocal::texthash( p_mnf => 'Name of New Folder', t_mnf => 'New Folder', @@ -6634,6 +7274,8 @@ sub editing_js { p_ctr2b => '?', p_ctr3a => 'Cut those', p_ctr3b => 'items?', + setal => 'Enter a (unique) alias', + delal => 'Are you sure you want to eliminate the alias?', rpck => 'Enter number to pick (e.g., 3)', imsfile => 'You must choose an IMS package for import', imscms => 'You must select which Course Management System was the source of the IMS package', @@ -6647,7 +7289,7 @@ sub editing_js { nofi => 'No file selected', tinc => 'Title in course', sunm => 'Sub-directory name', - edri => 'Editing rights unavailable for your current role', + edri => 'Editing rights unavailable for your current role.', ); &js_escape(\%js_lt); my $crstype = &Apache::loncommon::course_type(); @@ -6656,11 +7298,10 @@ sub editing_js { if (&HTML::Entities::decode($env{'environment.internal.'.$env{'request.course.id'}.'.docs_folderpath.folderpath'}) =~ /\:1$/) { $main_container_page = 1; } - my $toplevelmain = - &escape(&mt('Main Content').':::::'); + my $backtourl; + my $toplevelmain = &escape(&default_folderpath($coursenum,$coursedom,$navmapref)); my $toplevelsupp = &supplemental_base(); - my $backtourl; if ($env{'docs.exit.'.$env{'request.course.id'}} =~ /^direct_(.+)$/) { my $caller = $1; if ($caller =~ /^supplemental/) { @@ -6676,9 +7317,36 @@ sub editing_js { if (($caller =~ m{^([^#]+)\Q#$anchor\E$})) { $caller = $1.&escape('#').$anchor; } + } else { + $url = $res; + } + $backtourl = &HTML::Entities::encode(&Apache::lonnet::clutter($url),'<>&"'); + if ($backtourl =~ m{^\Q/uploaded/$coursedom/$coursenum/\Edefault_\d+\.sequence$}) { + $backtourl .= '?navmap=1'; + } else { + $backtourl .= '?symb='. + &HTML::Entities::encode($caller,'<>&"'); + } + if ($backtourl =~ 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 '') { + $backtourl = 'http://'.$hostname.$backtourl; + } + $backtourl .= (($backtourl =~ /\?/) ? '&':'?').'usehttp=1'; + } + } + } elsif ($backtourl =~ m{^/adm/wrapper/ext/(?!https:)}) { + if (($ENV{'SERVER_PORT'} == 443) && ($hostname ne '')) { + unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) { + if ($hostname ne '') { + $backtourl = 'http://'.$hostname.$backtourl; + } + $backtourl .= (($backtourl =~ /\?/) ? '&':'?').'usehttp=1'; + } + } } - $backtourl = &HTML::Entities::encode(&Apache::lonnet::clutter($url),'<>&"').'?symb='. - &HTML::Entities::encode($caller,'<>&"'); if ($anchor ne '') { $backtourl .= '#'.&HTML::Entities::encode($anchor,'<>&"'); } @@ -6695,27 +7363,29 @@ sub editing_js { $backtourl = '/adm/navmaps'; } - my $fieldsets = "'ext','doc'"; - if ($posslti) { - $fieldsets .= ",'tool'"; - } + my $fieldsets = "'doc'"; unless ($main_container_page) { $fieldsets .=",'ims'"; } + my $extfieldsets = "'ext'"; + if ($posslti) { + $extfieldsets .= ",'tool'"; + } if ($supplementalflag) { - $fieldsets = "'suppext','suppdoc'"; + $fieldsets = "'suppdoc'"; + $extfieldsets = "'suppext'"; if ($posslti) { - $fieldsets .= ",'supptool'"; + $extfieldsets .= ",'supptool'"; } } - + my $jsmakefunctions; if ($canedit) { $jsmakefunctions = <<ENDNEWSCRIPT; function makenewfolder(targetform,folderseq) { var foldername=prompt('$js_lt{"p_mnf"}','$js_lt{"t_mnf"}'); if (foldername) { - targetform.importdetail.value=escape(foldername)+"="+folderseq; + targetform.importdetail.value=encodeURIComponent(foldername)+"="+folderseq; targetform.submit(); } } @@ -6723,7 +7393,7 @@ function makenewfolder(targetform,folder function makenewpage(targetform,folderseq) { var pagename=prompt('$js_lt{"p_mnp"}','$js_lt{"t_mnp"}'); if (pagename) { - targetform.importdetail.value=escape(pagename)+"="+folderseq; + targetform.importdetail.value=encodeURIComponent(pagename)+"="+folderseq; targetform.submit(); } } @@ -6732,7 +7402,7 @@ function makeexamupload() { var title=prompt('$js_lt{"p_mxu"}'); if (title) { this.document.forms.newexamupload.importdetail.value= - escape(title)+'=/res/lib/templates/examupload.problem'; + encodeURIComponent(title)+'=/res/lib/templates/examupload.problem'; this.document.forms.newexamupload.submit(); } } @@ -6741,7 +7411,7 @@ function makesmppage() { var title=prompt('$js_lt{"p_msp"}'); if (title) { this.document.forms.newsmppg.importdetail.value= - escape(title)+'=/adm/$udom/$uname/new/smppg'; + encodeURIComponent(title)+'=/adm/$udom/$uname/new/smppg'; this.document.forms.newsmppg.submit(); } } @@ -6756,7 +7426,7 @@ function makewebpage(type) { } if (title) { var webpage = formname.importdetail.value; - formname.importdetail.value = escape(title)+'='+webpage; + formname.importdetail.value = encodeURIComponent(title)+'='+webpage; formname.submit(); } } @@ -6765,7 +7435,7 @@ function makesmpproblem() { var title=prompt('$js_lt{"p_msb"}'); if (title) { this.document.forms.newsmpproblem.importdetail.value= - escape(title)+'=/res/lib/templates/simpleproblem.problem'; + encodeURIComponent(title)+'=/res/lib/templates/simpleproblem.problem'; this.document.forms.newsmpproblem.submit(); } } @@ -6774,7 +7444,7 @@ function makedropbox() { var title=prompt('$js_lt{"p_mdb"}'); if (title) { this.document.forms.newdropbox.importdetail.value= - escape(title)+'=/res/lib/templates/DropBox.problem'; + encodeURIComponent(title)+'=/res/lib/templates/DropBox.problem'; this.document.forms.newdropbox.submit(); } } @@ -6783,7 +7453,7 @@ function makebulboard() { var title=prompt('$js_lt{"p_mbb"}'); if (title) { this.document.forms.newbul.importdetail.value= - escape(title)+'=/adm/$udom/$uname/new/bulletinboard'; + encodeURIComponent(title)+'=/adm/$udom/$uname/new/bulletinboard'; this.document.forms.newbul.submit(); } } @@ -6822,6 +7492,24 @@ function changename(folderpath,index,old } } +function setalias(folderpath,index) { + var alias = prompt('$js_lt{"setal"}'); + if ((alias != null) && (alias != '')) { + this.document.forms.aliasform.alias.value=alias; + this.document.forms.aliasform.cmd.value='setalias_'+index; + this.document.forms.aliasform.folderpath.value=folderpath; + this.document.forms.aliasform.submit(); + } +} + +function delalias(folderpath,index) { + if (confirm('$js_lt{"delal"}')) { + this.document.forms.aliasform.cmd.value='delalias_'+index; + this.document.forms.aliasform.folderpath.value=folderpath; + this.document.forms.aliasform.submit(); + } +} + ENDNEWSCRIPT } else { $jsmakefunctions = <<ENDNEWSCRIPT; @@ -6866,6 +7554,14 @@ function changename() { alert("$js_lt{'edri'}"); } +function setalias() { + alert("$js_lt{'edri'}"); +} + +function delalias() { + alert("$js_lt{'edri'}"); +} + function makenew() { alert("$js_lt{'edri'}"); } @@ -6903,16 +7599,32 @@ function toggleUpload(caller) { } } document.getElementById('upload'+blocks[i]+'form').style.display=disp; + } + resize_scrollbox('contentscroll','1','1'); + return; +} + +function toggleExternal(caller) { + var blocks = Array($extfieldsets); + for (var i=0; i<blocks.length; i++) { + var disp = 'none'; + if (caller == blocks[i]) { + var curr = document.getElementById('external'+caller+'form').style.display; + if (curr == 'none') { + disp='block'; + } + } + document.getElementById('external'+blocks[i]+'form').style.display=disp; if ((caller == 'tool') || (caller == 'supptool')) { if (disp == 'block') { - if (document.getElementById('LC_exttoolid')) { - var toolselector = document.getElementById('LC_exttoolid'); + if (document.getElementById('LC_exttoolid')) { + var toolselector = document.getElementById('LC_exttoolid'); var suppflag = 0; if (caller == 'supptool') { suppflag = 1; } currForm = document.getElementById('new'+caller); - updateExttool(toolselector,currForm,suppflag); + updateExttool(toolselector,currForm,suppflag); } } } @@ -7469,6 +8181,7 @@ function showPage(current, pageId, nav, current.className = 'right'; } activeTab = ''; + toggleExternal(); toggleUpload(); toggleMap(); toggleCrsRes(); @@ -7481,6 +8194,7 @@ function showPage(current, pageId, nav, currentData = document.getElementById(pageId); currentData.style.display = 'block'; activeTab = pageId; + toggleExternal(); toggleUpload(); toggleMap(); toggleCrsRes(); @@ -7863,7 +8577,7 @@ function validImportCrsRes() { url += fname; } var title = document.crsresimportform.crsrestitle.value; - document.crsresimportform.importdetail.value=escape(title)+'='+escape(url); + document.crsresimportform.importdetail.value=encodeURIComponent(title)+'='+encodeURIComponent(url); return true; } @@ -8014,7 +8728,7 @@ sub makenewproblem { if ($env{'form.newsubdir'}) { if ($env{'form.newsubdirname'} ne '') { $newsubdir = $env{'form.newsubdirname'}; - } + } } if ($env{'form.newresourcename'}) { $filename = $env{'form.newresourcename'}; @@ -8097,61 +8811,34 @@ END <subject></subject> <title></title> END - close($fh); - } - if ((-e $sourcerights) && (-e "$sourcerights.meta")) { - if (!-e "$docroot/res/$coursedom") { - mkdir("$docroot/res/$coursedom",0755); - } - if (!-e "$docroot/res/$coursedom/$coursenum") { - mkdir("$docroot/res/$coursedom/$coursenum",0755); - } - if ((-e "$docroot/res/$coursedom/$coursenum") && (!-e $targetrights)) { - my $nokeyref = &Apache::lonpublisher::getnokey($r->dir_config('lonIncludes')); - my $output = &Apache::lonpublisher::batchpublish($r,$sourcerights,$targetrights,$nokeyref,1); - } + close($fh); } } - if ($env{'form.newresourceadd'}) { - my $template = $env{'form.template'}; - my $source = $docroot.$redirect; - my $target = $redirect; - $target =~ s{^/priv/}{/res/}; - $target = $docroot.$target; - if (!-e $source) { - my $copyfrom; - if ($template) { - my %templates; - my @files = &Apache::lonhomework::get_template_list('problem'); - foreach my $poss (@files) { - if (ref($poss) eq 'ARRAY') { - if ($template eq $poss->[0]) { - $templates{$template} = 1; - last; - } - } - } - if ($templates{$template}) { - $copyfrom = $template; - } - } - unless ($copyfrom) { - $copyfrom = $r->dir_config('lonIncludes').'/templates/blank.problem'; - } - &File::Copy::copy($copyfrom,$source); + if ((-e $sourcerights) && (-e "$sourcerights.meta")) { + if (!-e "$docroot/res/$coursedom") { + mkdir("$docroot/res/$coursedom",0755); + } + if (!-e "$docroot/res/$coursedom/$coursenum") { + mkdir("$docroot/res/$coursedom/$coursenum",0755); + } + if ((-e "$docroot/res/$coursedom/$coursenum") && (!-e $targetrights)) { + my $nokeyref = &Apache::lonpublisher::getnokey($r->dir_config('lonIncludes')); + my $output = &Apache::lonpublisher::batchpublish($r,$sourcerights,$targetrights,$nokeyref,1); } - if (!-e "$source.meta") { - my $cid = $coursedom.'_'.$coursenum; - my $now = time; - if (open(my $fh,">$source.meta")) { - my $author=$env{'environment.firstname'}.' '. - $env{'environment.middlename'}.' '. - $env{'environment.lastname'}.' '. - $env{'environment.generation'}; - $author =~ s/\s+$//; - my $title = $env{'form.newresourcetitle'}; - $title =~ s/^\s+|\s+$//g; - print $fh <<END; + } + my $source = $docroot.$redirect; + if (!-e "$source.meta") { + my $cid = $coursedom.'_'.$coursenum; + my $now = time; + if (open(my $fh,">$source.meta")) { + my $author=$env{'environment.firstname'}.' '. + $env{'environment.middlename'}.' '. + $env{'environment.lastname'}.' '. + $env{'environment.generation'}; + $author =~ s/\s+$//; + my $title = $env{'form.newresourcetitle'}; + $title =~ s/^\s+|\s+$//g; + print $fh <<END; <abstract></abstract> <author>$author</author> @@ -8177,8 +8864,7 @@ END <subject></subject> <title>$title</title> END - close($fh); - } + close($fh); } } } @@ -8206,7 +8892,7 @@ END } sub finishnewprob { - my ($url,$path,$subdir,$newsubdir,$filename) = @_; + my ($url,$path,$subdir,$newsubdir,$filename,$context) = @_; unless (-d $path) { unless (mkdir($path,02770)) { return; @@ -8249,6 +8935,31 @@ sub finishnewprob { $redirect = "$url/$filename"; } } + if ((!-e $dest) && ($context ne 'upload')) { + my $template = $env{'form.template'}; + my $copyfrom; + if ($template ne '') { + my %templates; + my @files = &Apache::lonhomework::get_template_list('problem'); + foreach my $poss (@files) { + if (ref($poss) eq 'ARRAY') { + if ($template eq $poss->[0]) { + $templates{$template} = 1; + last; + } + } + } + if ($templates{$template}) { + $copyfrom = $template; + } + } + if ($filename =~ /\.problem$/) { + unless ($copyfrom) { + $copyfrom = $Apache::lonnet::perlvar{'lonIncludes'}.'/templates/blank.problem'; + } + &File::Copy::copy($copyfrom,$dest); + } + } return $redirect; } @@ -8360,7 +9071,9 @@ check on this Verify Content -=item devalidateversioncache() & checkversions() +=item devalidateversioncache() + +=item checkversions() Check Versions