--- loncom/interface/loncommon.pm 2012/04/05 13:32:15 1.1065 +++ loncom/interface/loncommon.pm 2012/04/11 15:21:43 1.1069 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.1065 2012/04/05 13:32:15 raeburn Exp $ +# $Id: loncommon.pm,v 1.1069 2012/04/11 15:21:43 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -5014,7 +5014,7 @@ sub bodytag { sub dc_courseid_toggle { my ($dc_info) = @_; return ' '. - ''. + ''. &mt('(More ...)').''. '
'.$dc_info.'
'; } @@ -9931,20 +9931,26 @@ sub decompress_form { my ($mimetype,$archiveurl,$action,$noextract,$hiddenelements,$dirlist) = @_; my %lt = &Apache::lonlocal::texthash ( this => 'This file is an archive file.', + camt => 'This file is a Camtasia archive file.', itsc => 'Its contents are as follows:', youm => 'You may wish to extract its contents.', - camt => 'Extraction of contents is recommended for Camtasia zip files.', extr => 'Extract contents', + auto => 'LON-CAPA can process the files automatically, or you can decide how each should be handled.', + proa => 'Process automatically?', yes => 'Yes', no => 'No', + fold => 'Title for folder containing movie', + movi => 'Title for page containing embedded movie', ); - my $output = '

'.$lt{'this'}; my $fileloc = &Apache::lonnet::filelocation(undef,$archiveurl); - my (%toplevel,@paths); + my ($is_camtasia,$topdir,%toplevel,@paths); my $info = &list_archive_contents($fileloc,\@paths); if (@paths) { foreach my $path (@paths) { $path =~ s{^/}{}; + if ($path =~ m{^([^/]+)/$}) { + $topdir = $1; + } if ($path =~ m{^([^/]+)/}) { $toplevel{$1} = $path; } else { @@ -9952,12 +9958,53 @@ sub decompress_form { } } } - if ($info eq '') { - $output .= ' '.$lt{'youm'}.'

'."\n"; + if ($mimetype =~ m{^application/(x\-)?(compressed|zip)}) { + my @camtasia = ("$topdir/","$topdir/index.html", + "$topdir/media/", + "$topdir/media/$topdir.mp4", + "$topdir/media/FirstFrame.png", + "$topdir/media/player.swf", + "$topdir/media/swfobject.js", + "$topdir/media/expressInstall.swf"); + my @diffs = &compare_arrays(\@paths,\@camtasia); + if (@diffs == 0) { + $is_camtasia = 1; + } + } + my $output; + if ($is_camtasia) { + $output = <<"ENDCAM"; + +

$lt{'camt'}

+ENDCAM } else { - $output .= ' '.$lt{'itsc'}.'

'."\n". - '
'.$info.'
'; + $output = '

'.$lt{'this'}; + if ($info eq '') { + $output .= ' '.$lt{'youm'}.'

'."\n"; + } else { + $output .= ' '.$lt{'itsc'}.'

'."\n". + '
'.$info.'
'; + } } + $output .= '
'."\n"; my $duplicates; my $num = 0; if (ref($dirlist) eq 'ARRAY') { @@ -9993,9 +10040,28 @@ sub decompress_form { } else { $itemcount = 1; } + if ($is_camtasia) { + $output .= $lt{'auto'}.'
'. + ''.$lt{'proa'}.' 
'. + '
'. + &Apache::lonhtmlcommon::start_pick_box(). + &Apache::lonhtmlcommon::row_title($lt{'fold'}). + ''."\n". + &Apache::lonhtmlcommon::row_closure(). + &Apache::lonhtmlcommon::row_title($lt{'movi'}). + ''."\n". + &Apache::lonhtmlcommon::row_closure(1). + &Apache::lonhtmlcommon::end_pick_box(). + '
'; + } $output .= ''. - ''."\n"; + ''. + "\n"; if ($duplicates ne '') { $output .= '

'. &mt('Warning: decompression of the archive will overwrite the following items which already exist:').'
'. @@ -10011,24 +10077,17 @@ sub decompress_form { &end_data_table(). '

'; } - if ($mimetype =~ m{^application/(x\-)?(compressed|zip)}) { - $output .= '

'.$lt{'camt'}.'

'; - } - $output .= <<"START"; -
- - -START + $output .= ''."\n"; if (ref($hiddenelements) eq 'HASH') { foreach my $hidden (sort(keys(%{$hiddenelements}))) { $output .= ''."\n"; } } $output .= <<"END"; +
$noextract -
END return $output; } @@ -10199,8 +10258,11 @@ sub process_decompression { } } if (@contents > 0) { + my $wantform; + unless ($env{'form.autoextract_camtasia'}) { + $wantform = 1; + } my (%children,%parent,%dirorder,%titles); - my $wantform = 1; my ($count,$datatable) = &get_extracted($docudom,$docuname, $currdir,\%is_dir, \%children,\%parent, @@ -10213,6 +10275,50 @@ sub process_decompression { $output .= &archive_javascript($startcount,$count, \%titles,\%children); } + if ($env{'form.autoextract_camtasia'}) { + my %displayed; + my $total = 1; + $env{'form.archive_directory'} = []; + foreach my $i (sort { $a <=> $b } keys(%dirorder)) { + my $path = join('/',map { $titles{$_}; } @{$dirorder{$i}}); + $path =~ s{/$}{}; + my $item; + if ($path ne '') { + $item = "$path/$titles{$i}"; + } else { + $item = $titles{$i}; + } + $env{'form.archive_content_'.$i} = "$dir_root/$destination/$item"; + if ($item eq $contents[0]) { + push(@{$env{'form.archive_directory'}},$i); + $env{'form.archive_'.$i} = 'display'; + $env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'}; + $displayed{'folder'} = $i; + } elsif ($item eq "$contents[0]/index.html") { + $env{'form.archive_'.$i} = 'display'; + $env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'}; + $displayed{'web'} = $i; + } else { + if ($item eq "$contents[0]/media") { + push(@{$env{'form.archive_directory'}},$i); + } + $env{'form.archive_'.$i} = 'dependency'; + } + $total ++; + } + for (my $i=1; $i<$total; $i++) { + next if ($i == $displayed{'web'}); + next if ($i == $displayed{'folder'}); + $env{'form.archive_dependent_on_'.$i} = $displayed{'web'}; + } + $env{'form.phase'} = 'decompress_cleanup'; + $env{'form.archivedelete'} = 1; + $env{'form.archive_count'} = $total-1; + $output .= + &process_extracted_files('coursedocs',$docudom, + $docuname,$destination, + $dir_root,$hiddenelem); + } } else { $warning = &mt('No new items extracted from archive file.'); } @@ -10611,12 +10717,12 @@ END } sub process_extracted_files { - my ($context,$docudom,$docuname,$url,$destination,$dir_root,$hiddenelem) = @_; + my ($context,$docudom,$docuname,$destination,$dir_root,$hiddenelem) = @_; my $numitems = $env{'form.archive_count'}; return unless ($numitems); my @ids=&Apache::lonnet::current_machine_ids(); my ($prefix,$pathtocheck,$dir,$ishome,$error,$warning,%toplevelitems,%is_dir, - %folders,%containers,%mapinner); + %folders,%containers,%mapinner,%prompttofetch); my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom); if (grep(/^\Q$docuhome\E$/,@ids)) { $prefix = &LONCAPA::propath($docudom,$docuname); @@ -10652,13 +10758,13 @@ sub process_extracted_files { } } } - my ($output,%children,%parent,%titles,%dirorder); + my ($output,%children,%parent,%titles,%dirorder,$result); if (keys(%toplevelitems) > 0) { my @contents = sort(keys(%toplevelitems)); (my $count,undef) = &get_extracted($docudom,$docuname,$currdir,\%is_dir,\%children, \%parent,\@contents,\%dirorder,\%titles); } - my (%referrer,%orphaned,%todelete,%newdest,%newseqid); + my (%referrer,%orphaned,%todelete,%todeletedir,%newdest,%newseqid); if ($numitems) { for (my $i=1; $i<=$numitems; $i++) { my $path = $env{'form.archive_content_'.$i}; @@ -10666,7 +10772,12 @@ sub process_extracted_files { if ($env{'form.archive_'.$i} eq 'discard') { if ($prefix ne '' && $path ne '') { if (-e $prefix.$path) { - $todelete{$prefix.$path} = 1; + if ((@archdirs > 0) && + (grep(/^\Q$i\E$/,@archdirs))) { + $todeletedir{$prefix.$path} = 1; + } else { + $todelete{$prefix.$path} = 1; + } } } } elsif ($env{'form.archive_'.$i} eq 'display') { @@ -10708,6 +10819,9 @@ sub process_extracted_files { $docuname.'/'.$folders{$outer}. '.'.$containers{$outer},1); $newseqid{$i} = $newidx; + unless ($errtext) { + $result .= '
  • '.&mt('Folder: [_1] added to course',$docstitle).'
  • '."\n"; + } } } else { if ($context eq 'coursedocs') { @@ -10724,6 +10838,11 @@ sub process_extracted_files { if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") { system("mv $prefix$path $prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title"); $newdest{$i} = "$prefix$dir/$docstype/$mapinner{$outer}/$newidx"; + unless ($ishome) { + my $fetch = "$newdest{$i}/$title"; + $fetch =~ s/^\Q$prefix$dir\E//; + $prompttofetch{$fetch} = 1; + } } $LONCAPA::map::resources[$newidx]= $docstitle.':'.$url.':false:normal:res'; @@ -10732,6 +10851,11 @@ sub process_extracted_files { &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'. $docuname.'/'.$folders{$outer}. '.'.$containers{$outer},1); + unless ($errtext) { + if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title") { + $result .= '
  • '.&mt('File: [_1] added to course',$docstitle).'
  • '."\n"; + } + } } } } elsif ($env{'form.archive_'.$i} eq 'dependency') { @@ -10739,7 +10863,7 @@ sub process_extracted_files { $referrer{$i} = $env{'form.archive_dependent_on_'.$i}; if ($env{'form.archive_'.$referrer{$i}} eq 'display') { if (ref($dirorder{$i}) eq 'ARRAY') { - my ($itemidx,$fullpath); + my ($itemidx,$fullpath,$relpath); for (my $j=0; $j<@{$dirorder{$i}}; $j++) { if (ref($dirorder{$referrer{$i}}) eq 'ARRAY') { my $container = $dirorder{$referrer{$i}}->[-1]; @@ -10758,6 +10882,7 @@ sub process_extracted_files { if (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) { unless (defined($newseqid{$dirorder{$i}->[$j]})) { $fullpath .= '/'.$titles{$dirorder{$i}->[$j]}; + $relpath .= '/'.$titles{$dirorder{$i}->[$j]}; if (!-e $fullpath) { mkdir($fullpath,0755); } @@ -10776,6 +10901,7 @@ sub process_extracted_files { } elsif (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) { unless (defined($newseqid{$dirorder{$i}->[$j]})) { $fullpath .= '/'.$titles{$dirorder{$i}->[$j]}; + $relpath .= '/'.$titles{$dirorder{$i}->[$j]}; if (!-e $fullpath) { mkdir($fullpath,0755); } @@ -10786,7 +10912,23 @@ sub process_extracted_files { } } if ($fullpath ne '') { - system("mv $prefix$path $fullpath/$title"); + if (-e "$prefix$path") { + system("mv $prefix$path $fullpath/$title"); + } + if (-e "$fullpath/$title") { + my $showpath; + if ($relpath ne '') { + $showpath = "$relpath/$title"; + } else { + $showpath = "/$title"; + } + $result .= '
  • '.&mt('[_1] included as a dependency',$showpath).'
  • '."\n"; + } + unless ($ishome) { + my $fetch = "$fullpath/$title"; + $fetch =~ s/^\Q$prefix$dir\E//; + $prompttofetch{$fetch} = 1; + } } } } @@ -10802,9 +10944,36 @@ sub process_extracted_files { if (keys(%todelete)) { foreach my $key (keys(%todelete)) { unlink($key); - unless ($ishome) { - #FIXME Need to notify homeserver to delete files. - } + } + } + if (keys(%todeletedir)) { + foreach my $key (keys(%todeletedir)) { + rmdir($key); + } + } + foreach my $dir (sort(keys(%is_dir))) { + if (($pathtocheck ne '') && ($dir ne '')) { + &cleanup_empty_dirs($prefix."$pathtocheck/$dir"); + } + } + if ($result ne '') { + $output .= ''; + } + unless ($ishome) { + my $replicationfail; + foreach my $item (keys(%prompttofetch)) { + my $fetchresult= &Apache::lonnet::reply('fetchuserfile:'.$item,$docuhome); + unless ($fetchresult eq 'ok') { + $replicationfail .= '
  • '.$item.'
  • '."\n"; + } + } + if ($replicationfail) { + $output .= '

    '. + &mt('Course home server failed to retrieve:').'

    '; } } } else { @@ -10820,6 +10989,90 @@ sub process_extracted_files { return $output; } +sub cleanup_empty_dirs { + my ($path) = @_; + if (($path ne '') && (-d $path)) { + if (opendir(my $dirh,$path)) { + my @dircontents = grep(!/^\./,readdir($dirh)); + my $numitems = 0; + foreach my $item (@dircontents) { + if (-d "$path/$item") { + &recurse_dirs("$path/$item"); + if (-e "$path/$item") { + $numitems ++; + } + } else { + $numitems ++; + } + } + if ($numitems == 0) { + rmdir($path); + } + closedir($dirh); + } + } + return; +} + +=pod + +=item &get_folder_hierarchy() + +Provides hierarchy of names of folders/sub-folders containing the current +item, + +Inputs: 3 + - $navmap - navmaps object + + - $map - url for map (either the trigger itself, or map containing + the resource, which is the trigger). + + - $showitem - 1 => show title for map itself; 0 => do not show. + +Outputs: 1 @pathitems - array of folder/subfolder names. + +=cut + +sub get_folder_hierarchy { + my ($navmap,$map,$showitem) = @_; + my @pathitems; + if (ref($navmap)) { + my $mapres = $navmap->getResourceByUrl($map); + if (ref($mapres)) { + my $pcslist = $mapres->map_hierarchy(); + if ($pcslist ne '') { + my @pcs = split(/,/,$pcslist); + foreach my $pc (@pcs) { + if ($pc == 1) { + push(@pathitems,&mt('Main Course Documents')); + } else { + my $res = $navmap->getByMapPc($pc); + if (ref($res)) { + my $title = $res->compTitle(); + $title =~ s/\W+/_/g; + if ($title ne '') { + push(@pathitems,$title); + } + } + } + } + } + } + if ($showitem) { + if ($mapres->{ID} eq '0.0') { + push(@pathitems,&mt('Main Course Documents')); + } else { + my $maptitle = $mapres->compTitle(); + $maptitle =~ s/\W+/_/g; + if ($maptitle ne '') { + push(@pathitems,$maptitle); + } + } + } + } + return @pathitems; +} + =pod =item * &get_turnedin_filepath()