--- loncom/interface/londocs.pm 2018/04/29 17:29:23 1.484.2.77 +++ loncom/interface/londocs.pm 2017/08/27 02:36:49 1.637 @@ -1,7 +1,7 @@ # The LearningOnline Network # Documents # -# $Id: londocs.pm,v 1.484.2.77 2018/04/29 17:29:23 raeburn Exp $ +# $Id: londocs.pm,v 1.637 2017/08/27 02:36:49 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -43,10 +43,13 @@ use Apache::lonnavdisplay(); use Apache::lonextresedit(); use Apache::lontemplate(); use Apache::lonsimplepage(); +use Apache::lonhomework(); +use Apache::lonpublisher(); use HTML::Entities; use HTML::TokeParser; use GDBM_File; use File::MMagic; +use File::Copy; use Apache::lonlocal; use Cwd; use LONCAPA qw(:DEFAULT :match); @@ -232,7 +235,7 @@ ENDJS } else { &Apache::loncourserespicker::enumerate_course_contents($navmap,\%maps,\%resources,\%titles, 'dumpdocs',$cdom,$cnum); - } + } my @todump = &Apache::loncommon::get_env_multiple('form.archive'); my (%tocopy,%replacehash,%lookup,%deps,%display,%result,%depresult,%simpleproblems,%simplepages, %newcontent,%has_simpleprobs); @@ -243,7 +246,7 @@ ENDJS if ($res =~ m{^uploaded/$cdom/$cnum/\E((?:docs|supplemental)/.+)$}) { $tocopy{$1} = $name; $display{$item} = $1; - $lookup{$1} = $item; + $lookup{$1} = $item; } elsif ($res eq 'lib/templates/simpleproblem.problem') { $simpleproblems{$item} = { symb => $resources{$item}, @@ -343,7 +346,7 @@ $contents{content}.' '; } if ($contents{webreferences}) { - $content .= ' + $content .= '

'.&mt('Web References').'

'. $contents{webreferences}.' @@ -353,10 +356,10 @@ $contents{webreferences}.' '; - $newcontent{'/'.$simplepages{$item}{res}} = $content; + $newcontent{'/'.$simplepages{$item}{res}} = $content; } } - foreach my $item (keys(%tocopy)) { + foreach my $item (keys(%tocopy)) { unless ($item=~/\.(sequence|page)$/) { my $currurlpath = $prefix.$item; my $currdirpath = &Apache::lonnet::filelocation('',$currurlpath); @@ -387,39 +390,39 @@ $contents{webreferences}.' if ($simpleproblems{$num}) { $newfilename=$title.'/'.$simpleproblems{$num}{'name'}; } else { - $newfilename=$title.'/'.$replacehash{$item}; + $newfilename=$title.'/'.$replacehash{$item}; } - $newfilename=~s/\.(\w+)$//; - my $ext=$1; - $newfilename=&clean($newfilename); - $newfilename.='.'.$ext; - my ($newrelpath) = ($newfilename =~ m{^\Q$title/\E(.+)$}); + $newfilename=~s/\.(\w+)$//; + my $ext=$1; + $newfilename=&clean($newfilename); + $newfilename.='.'.$ext; + my ($newrelpath) = ($newfilename =~ m{^\Q$title/\E(.+)$}); if ($newrelpath ne $replacehash{$item}) { $replacehash{$item} = $newrelpath; } - my @dirs=split(/\//,$newfilename); - my $path=$r->dir_config('lonDocRoot')."/priv/$cd/$ca"; - my $makepath=$path; - my $fail; + my @dirs=split(/\//,$newfilename); + my $path=$r->dir_config('lonDocRoot')."/priv/$cd/$ca"; + my $makepath=$path; + my $fail; my $origin; - for (my $i=0;$i<$#dirs;$i++) { - $makepath.='/'.$dirs[$i]; - unless (-e $makepath) { - unless(mkdir($makepath,0755)) { + for (my $i=0;$i<$#dirs;$i++) { + $makepath.='/'.$dirs[$i]; + unless (-e $makepath) { + unless(mkdir($makepath,0755)) { $fail = &mt('Directory creation failed.'); } - } - } + } + } if ($i == 0) { - $result = '
'.$item.' => '.$newfilename.': '; + $result = '
'.$item.' => '.$newfilename.': '; } else { $depresult .= '
  • '.$item.' => '.$newfilename.' '. ''. &mt('(dependency)').': '; } if (-e $path.'/'.$newfilename) { - $fail = &mt('Destination already exists -- not overwriting.'); - } else { + $fail = &mt('Destination already exists -- not overwriting.'); + } else { if (my $fh=Apache::File->new('>'.$path.'/'.$newfilename)) { if (($item =~ m{^/adm/$match_domain/$match_username/\d+/smppg}) || ($item =~ /^simpleproblem_/)) { @@ -441,18 +444,18 @@ $contents{webreferences}.' while (my $token = $parser->get_token) { if ($token->[0] eq 'S') { if (($token->[1] eq 'resource') && - ($token->[2]->{'src'} eq '/res/lib/templates/simpleproblem.problem') && + ($token->[2]->{'src'} eq '/res/lib/templates/simpleproblem.problem') && ($changes{$token->[2]->{'id'}})) { my $id = $token->[2]->{'id'}; $updatedcontent .= '<'.$token->[1]; foreach my $attrib (@{$token->[3]}) { - next unless ($attrib =~ /^(src|type|title|id)$/); + next unless ($attrib =~ /^(src|type|title|id)$/); if ($attrib eq 'src') { - my ($file) = ($display{$changes{$id}} =~ /^\Qsimpleproblem_\E(.+)$/); + my ($file) = ($display{$changes{$id}} =~ /^\Qsimpleproblem_\E(.+)$/); if ($file) { $updatedcontent .= ' '.$attrib.'="'.$file.'"'; } else { - $updatedcontent .= ' '.$attrib.'="'.$token->[2]->{$attrib}.'"'; + $updatedcontent .= ' '.$attrib.'="'.$token->[2]->{$attrib}.'"'; } } else { $updatedcontent .= ' '.$attrib.'="'.$token->[2]->{$attrib}.'"'; @@ -467,36 +470,36 @@ $contents{webreferences}.' } } print $fh $updatedcontent; - } else { - print $fh &Apache::lonclonecourse::rewritefile( + } else { + print $fh &Apache::lonclonecourse::rewritefile( &Apache::lonclonecourse::readfile($env{'request.course.id'},$item), - (%replacehash,$crs => '') - ); + (%replacehash,$crs => '') + ); } } else { - print $fh + print $fh &Apache::lonclonecourse::readfile($env{'request.course.id'},$item); - } + } } else { - $fail = &mt('Source does not exist.'); + $fail = &mt('Source does not exist.'); } } $fh->close(); - } else { - $fail = &mt('Could not write to destination.'); + } else { + $fail = &mt('Could not write to destination.'); } - } + } my $text; - if ($fail) { + if ($fail) { $text = ''.&mt('fail').(' 'x3).$fail.''; - } else { + } else { $text = ''.&mt('ok').''; } if ($i == 0) { $result .= $text; } else { $depresult .= $text.'
  • '; - } + } } $r->print($result); if ($depresult) { @@ -513,63 +516,63 @@ $contents{webreferences}.' $r->rflush(); my ($preamble,$formname); $formname = 'dumpdoc'; - unless ($home==1) { - $preamble = '
    '. - '
    '. + unless ($home==1) { + $preamble = '
    '. + '
    '. &mt('Select the Authoring Space'). ''; - } else { - $preamble .= ''; - } - } - unless ($home==1) { - $preamble .= '
    '."\n"; - } - my $title=$origcrsdata{'description'}; - $title=~s/[\/\s]+/\_/gs; - $title=&clean($title); - $preamble .= '
    '. + if ($home==1) { + $preamble .= ''; + } else { + $preamble .= ''; + } + } + unless ($home==1) { + $preamble .= '
    '."\n"; + } + my $title=$origcrsdata{'description'}; + $title=~s/[\/\s]+/\_/gs; + $title=&clean($title); + $preamble .= '
    '. '
    '.&mt('Folder in Authoring Space').''. ''. '
    '."\n"; my %uploadedfiles; - &tiehash(); - foreach my $file (&Apache::lonclonecourse::crsdirlist($origcrsid,'userfiles')) { - my ($ext)=($file=~/\.(\w+)$/); + &tiehash(); + foreach my $file (&Apache::lonclonecourse::crsdirlist($origcrsid,'userfiles')) { + my ($ext)=($file=~/\.(\w+)$/); # FIXME Check supplemental here - my $title=$hash{'title_'.$hash{ - 'ids_/uploaded/'.$origcrsdata{'domain'}.'/'.$origcrsdata{'num'}.'/'.$file}}; - if (!$title) { - $title=$file; - } else { - $title=~s|/|_|g; - } - $title=~s/\.(\w+)$//; - $title=&clean($title); - $title.='.'.$ext; -# $r->print("\n" + my $title=$hash{'title_'.$hash{ + 'ids_/uploaded/'.$origcrsdata{'domain'}.'/'.$origcrsdata{'num'}.'/'.$file}}; + if (!$title) { + $title=$file; + } else { + $title=~s|/|_|g; + } + $title=~s/\.(\w+)$//; + $title=&clean($title); + $title.='.'.$ext; +# $r->print("\n" $uploadedfiles{$file} = $title; - } - &untiehash(); + } + &untiehash(); $r->print(&Apache::loncourserespicker::create_picker($navmap,'dumpdocs',$formname,$crstype,undef, undef,undef,$preamble,$home,\%uploadedfiles)); } @@ -600,7 +603,7 @@ sub recurse_html { } else { $relfile = $dependency; $depurl = $currurlpath; - $depurl =~ s{[^/]+$}{}; + $depurl =~ s{[^/]+$}{}; $depurl .= $dependency; ($newcontainer) = ($depurl =~ m{^\Q$prefix\E(.+)$}); } @@ -609,7 +612,7 @@ sub recurse_html { $newname =~ s{[^/]+$}{}; $replacehash->{$newcontainer} = $newname.$relfile; $deps->{$item}{$newcontainer} = 1; - my ($newurlpath) = ($depurl =~ m{^(.*)/[^/]+$}); + my ($newurlpath) = ($depurl =~ m{^(.*)/[^/]+$}); my $depfile = &Apache::lonnet::filelocation('',$depurl); my $type = $mm->checktype_filename($depfile); if ($type eq 'text/html') { @@ -622,7 +625,7 @@ sub recurse_html { } sub group_import { - my ($coursenum, $coursedom, $folder, $container, $caller, @files) = @_; + my ($coursenum, $coursedom, $folder, $container, $caller, $ltitoolsref, @files) = @_; my ($donechk,$allmaps,%hierarchy,%titles,%addedmaps,%removefrommap, %removeparam,$importuploaded,$fixuperrors); $allmaps = {}; @@ -651,6 +654,112 @@ sub group_import { } } if ($url) { + 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'); + my @toolinfo = split(/:/,$info); + if ($residx) { + %toolsettings=&Apache::lonnet::dump('exttool_'.$marker,$coursedom,$coursenum); + $toolid = $toolsettings{'id'}; + } else { + $toolid = shift(@toolinfo); + } + $toolid =~ s/\D//g; + ($toolhash{'target'},$toolhash{'width'},$toolhash{'height'}, + $toolhash{'linktext'},$toolhash{'explanation'}, + $toolhash{'crslabel'},$toolhash{'crstitle'}) = @toolinfo; + foreach my $item (@extras) { + $toolhash{$item} = &unescape($toolhash{$item}); + } + if (ref($ltitoolsref) eq 'HASH') { + my @deleted; + if (ref($ltitoolsref->{$toolid}) eq 'HASH') { + $toolhash{'id'} = $toolid; + 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') { + foreach my $item ('width','height') { + $toolhash{$item} = $toolsettings{$item}; + } + } + } elsif (ref($ltitoolsref->{$toolid}->{'display'}) eq 'HASH') { + $toolhash{'target'} = $ltitoolsref->{$toolid}->{'display'}->{'target'}; + if ($toolhash{'target'} eq 'window') { + $toolhash{'width'} = $ltitoolsref->{$toolid}->{'display'}->{'width'}; + $toolhash{'height'} = $ltitoolsref->{$toolid}->{'display'}->{'height'}; + } + } + if ($toolhash{'target'} eq 'iframe') { + foreach my $item ('width','height','linktext','explanation') { + delete($toolhash{$item}); + if ($residx) { + if ($toolsettings{$item}) { + push(@deleted,$item); + } + } + } + } 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','linktext','explanation') { + my $crsitem; + if (($item eq 'label') || ($item eq 'title')) { + $crsitem = 'crs'.$item; + } else { + $crsitem = $item; + } + if ($ltitoolsref->{$toolid}->{'crsconf'}->{$item}) { + $toolhash{$crsitem} =~ s/^\s+//; + $toolhash{$crsitem} =~ s/\s+$//; + if ($toolhash{$crsitem} eq '') { + delete($toolhash{$crsitem}); + } + } else { + delete($toolhash{$crsitem}); + } + if (($residx) && (exists($toolsettings{$crsitem}))) { + unless (exists($toolhash{$crsitem})) { + push(@deleted,$crsitem); + } + } + } + } + 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 (($caller eq 'londocs') && ($folder =~ /^default/)) { if (($url =~ /\.(page|sequence)$/) && (!$donechk)) { @@ -662,8 +771,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}); @@ -728,7 +837,7 @@ END removefrommap => \%removefrommap, removeparam => \%removeparam, ); - my ($result,$msgsarray,$lockerror) = + my ($result,$msgsarray,$lockerror) = &apply_fixups($folder,1,$coursedom,$coursenum,\%import_errors,\%updated); if (keys(%import_errors) > 0) { $fixuperrors = @@ -829,12 +938,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 $navmap; my $js = ''."\n"; + .''."\n" + .''."\n"; # Breadcrumbs &Apache::lonhtmlcommon::clear_breadcrumbs(); @@ -5142,7 +5678,6 @@ sub handler { undef($hadchanges); $uploadphase = &process_file_upload(\$upload_output,$coursenum,$coursedom, \%allfiles,\%codebase,$context,$crstype); - undef($navmap); if ($hadchanges) { &mark_hash_old(); } @@ -5158,7 +5693,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); @@ -5169,11 +5704,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(). @@ -5199,6 +5734,9 @@ sub handler { 'impo' => 'Import', 'lnks' => 'Import from Stored Links', 'impm' => 'Import from Assembled Map', + 'imcr' => 'Import from Course Resources', + 'extr' => 'External Resource', + 'extt' => 'External Tool', 'selm' => 'Select Map', 'load' => 'Load Map', 'newf' => 'New Folder', @@ -5208,6 +5746,9 @@ sub handler { 'sipa' => 'Simple Course Page', 'sipr' => 'Simple Problem', 'webp' => 'Blank Web Page (editable)', + 'stpr' => 'Standard Problem', + 'news' => 'New sub-directory', + 'crpr' => 'Create Problem', 'drbx' => 'Drop Box', 'scuf' => 'External Scores (handgrade, upload, clicker)', 'bull' => 'Discussion Board', @@ -5221,19 +5762,32 @@ sub handler { 'se' => 'Select', 'file' => 'File', 'title' => 'Title', + 'addp' => 'Add Placeholder to course?', + 'uste' => 'Use Template?', + 'fnam' => 'File Name:', + 'loca' => 'Location:', + 'dire' => 'Directory:', + 'cate' => 'Category:', + 'tmpl' => 'Template:', 'comment' => 'Comment', 'parse' => 'Upload embedded images/multimedia files if HTML file', 'bb5' => 'Blackboard 5', 'bb6' => 'Blackboard 6', 'angel5' => 'ANGEL 5.5', 'webctce4' => 'WebCT 4 Campus Edition', + 'yes' => 'Yes', + 'no' => 'No', 'er' => 'Editing rights unavailable for your current role.', ); # ----------------------------------------------------------------------------- - # Calculate free quota space for a user or course. + + # Calculate free quota space for a user or course. A javascript function checks + # file size to determine if upload should be allowed. my $quotatype = 'unofficial'; if ($crstype eq 'Community') { $quotatype = 'community'; + } elsif ($crstype eq 'Placement') { + $quotatype = 'placement'; } elsif ($env{'course.'.$coursedom.'_'.$coursenum.'.internal.coursecode'}) { $quotatype = 'official'; } elsif ($env{'course.'.$coursedom.'_'.$coursenum.'.internal.textbook'}) { @@ -5264,7 +5818,8 @@ sub handler { my $fileupload=(< - + + FIUP my $checkbox=(<